]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/serial/usb_serial.c
Update to zstd 1.3.2
[FreeBSD/FreeBSD.git] / sys / dev / usb / serial / usb_serial.c
1 /*      $NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $  */
2
3 /*-
4  * Copyright (c) 2001-2003, 2005, 2008
5  *      Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 /*-
34  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
35  * All rights reserved.
36  *
37  * This code is derived from software contributed to The NetBSD Foundation
38  * by Lennart Augustsson (lennart@augustsson.net) at
39  * Carlstedt Research & Technology.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60  * POSSIBILITY OF SUCH DAMAGE.
61  */
62
63 #include <sys/stdint.h>
64 #include <sys/stddef.h>
65 #include <sys/param.h>
66 #include <sys/queue.h>
67 #include <sys/types.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
70 #include <sys/bus.h>
71 #include <sys/module.h>
72 #include <sys/lock.h>
73 #include <sys/mutex.h>
74 #include <sys/condvar.h>
75 #include <sys/sysctl.h>
76 #include <sys/sx.h>
77 #include <sys/unistd.h>
78 #include <sys/callout.h>
79 #include <sys/malloc.h>
80 #include <sys/priv.h>
81 #include <sys/cons.h>
82
83 #include <dev/uart/uart_ppstypes.h>
84
85 #include <dev/usb/usb.h>
86 #include <dev/usb/usbdi.h>
87 #include <dev/usb/usbdi_util.h>
88
89 #define USB_DEBUG_VAR ucom_debug
90 #include <dev/usb/usb_debug.h>
91 #include <dev/usb/usb_busdma.h>
92 #include <dev/usb/usb_process.h>
93
94 #include <dev/usb/serial/usb_serial.h>
95
96 #include "opt_gdb.h"
97
98 static SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom");
99
100 static int ucom_pps_mode;
101
102 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, pps_mode, CTLFLAG_RWTUN,
103     &ucom_pps_mode, 0, 
104     "pulse capture mode: 0/1/2=disabled/CTS/DCD; add 0x10 to invert");
105
106 #ifdef USB_DEBUG
107 static int ucom_debug = 0;
108
109 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RWTUN,
110     &ucom_debug, 0, "ucom debug level");
111 #endif
112
113 #define UCOM_CONS_BUFSIZE 1024
114
115 static uint8_t ucom_cons_rx_buf[UCOM_CONS_BUFSIZE];
116 static uint8_t ucom_cons_tx_buf[UCOM_CONS_BUFSIZE];
117
118 static unsigned int ucom_cons_rx_low = 0;
119 static unsigned int ucom_cons_rx_high = 0;
120
121 static unsigned int ucom_cons_tx_low = 0;
122 static unsigned int ucom_cons_tx_high = 0;
123
124 static int ucom_cons_unit = -1;
125 static int ucom_cons_subunit = 0;
126 static int ucom_cons_baud = 9600;
127 static struct ucom_softc *ucom_cons_softc = NULL;
128
129 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RWTUN,
130     &ucom_cons_unit, 0, "console unit number");
131 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RWTUN,
132     &ucom_cons_subunit, 0, "console subunit number");
133 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RWTUN,
134     &ucom_cons_baud, 0, "console baud rate");
135
136 static usb_proc_callback_t ucom_cfg_start_transfers;
137 static usb_proc_callback_t ucom_cfg_open;
138 static usb_proc_callback_t ucom_cfg_close;
139 static usb_proc_callback_t ucom_cfg_line_state;
140 static usb_proc_callback_t ucom_cfg_status_change;
141 static usb_proc_callback_t ucom_cfg_param;
142
143 static int      ucom_unit_alloc(void);
144 static void     ucom_unit_free(int);
145 static int      ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *);
146 static void     ucom_detach_tty(struct ucom_super_softc *, struct ucom_softc *);
147 static void     ucom_queue_command(struct ucom_softc *,
148                     usb_proc_callback_t *, struct termios *pt,
149                     struct usb_proc_msg *t0, struct usb_proc_msg *t1);
150 static void     ucom_shutdown(struct ucom_softc *);
151 static void     ucom_ring(struct ucom_softc *, uint8_t);
152 static void     ucom_break(struct ucom_softc *, uint8_t);
153 static void     ucom_dtr(struct ucom_softc *, uint8_t);
154 static void     ucom_rts(struct ucom_softc *, uint8_t);
155
156 static tsw_open_t ucom_open;
157 static tsw_close_t ucom_close;
158 static tsw_ioctl_t ucom_ioctl;
159 static tsw_modem_t ucom_modem;
160 static tsw_param_t ucom_param;
161 static tsw_outwakeup_t ucom_outwakeup;
162 static tsw_inwakeup_t ucom_inwakeup;
163 static tsw_free_t ucom_free;
164 static tsw_busy_t ucom_busy;
165
166 static struct ttydevsw ucom_class = {
167         .tsw_flags = TF_INITLOCK | TF_CALLOUT,
168         .tsw_open = ucom_open,
169         .tsw_close = ucom_close,
170         .tsw_outwakeup = ucom_outwakeup,
171         .tsw_inwakeup = ucom_inwakeup,
172         .tsw_ioctl = ucom_ioctl,
173         .tsw_param = ucom_param,
174         .tsw_modem = ucom_modem,
175         .tsw_free = ucom_free,
176         .tsw_busy = ucom_busy,
177 };
178
179 MODULE_DEPEND(ucom, usb, 1, 1, 1);
180 MODULE_VERSION(ucom, 1);
181
182 #define UCOM_UNIT_MAX           128     /* maximum number of units */
183 #define UCOM_TTY_PREFIX         "U"
184
185 static struct unrhdr *ucom_unrhdr;
186 static struct mtx ucom_mtx;
187 static int ucom_close_refs;
188
189 static void
190 ucom_init(void *arg)
191 {
192         DPRINTF("\n");
193         ucom_unrhdr = new_unrhdr(0, UCOM_UNIT_MAX - 1, NULL);
194         mtx_init(&ucom_mtx, "UCOM MTX", NULL, MTX_DEF);
195 }
196 SYSINIT(ucom_init, SI_SUB_KLD - 1, SI_ORDER_ANY, ucom_init, NULL);
197
198 static void
199 ucom_uninit(void *arg)
200 {
201         struct unrhdr *hdr;
202         hdr = ucom_unrhdr;
203         ucom_unrhdr = NULL;
204
205         DPRINTF("\n");
206
207         if (hdr != NULL)
208                 delete_unrhdr(hdr);
209
210         mtx_destroy(&ucom_mtx);
211 }
212 SYSUNINIT(ucom_uninit, SI_SUB_KLD - 3, SI_ORDER_ANY, ucom_uninit, NULL);
213
214 /*
215  * Mark a unit number (the X in cuaUX) as in use.
216  *
217  * Note that devices using a different naming scheme (see ucom_tty_name()
218  * callback) still use this unit allocation.
219  */
220 static int
221 ucom_unit_alloc(void)
222 {
223         int unit;
224
225         /* sanity checks */
226         if (ucom_unrhdr == NULL) {
227                 DPRINTF("ucom_unrhdr is NULL\n");
228                 return (-1);
229         }
230         unit = alloc_unr(ucom_unrhdr);
231         DPRINTF("unit %d is allocated\n", unit);
232         return (unit);
233 }
234
235 /*
236  * Mark the unit number as not in use.
237  */
238 static void
239 ucom_unit_free(int unit)
240 {
241         /* sanity checks */
242         if (unit < 0 || unit >= UCOM_UNIT_MAX || ucom_unrhdr == NULL) {
243                 DPRINTF("cannot free unit number\n");
244                 return;
245         }
246         DPRINTF("unit %d is freed\n", unit);
247         free_unr(ucom_unrhdr, unit);
248 }
249
250 /*
251  * Setup a group of one or more serial ports.
252  *
253  * The mutex pointed to by "mtx" is applied before all
254  * callbacks are called back. Also "mtx" must be applied
255  * before calling into the ucom-layer!
256  */
257 int
258 ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
259     int subunits, void *parent,
260     const struct ucom_callback *callback, struct mtx *mtx)
261 {
262         int subunit;
263         int error = 0;
264
265         if ((sc == NULL) ||
266             (subunits <= 0) ||
267             (callback == NULL) ||
268             (mtx == NULL)) {
269                 return (EINVAL);
270         }
271
272         /* allocate a uniq unit number */
273         ssc->sc_unit = ucom_unit_alloc();
274         if (ssc->sc_unit == -1)
275                 return (ENOMEM);
276
277         /* generate TTY name string */
278         snprintf(ssc->sc_ttyname, sizeof(ssc->sc_ttyname),
279             UCOM_TTY_PREFIX "%d", ssc->sc_unit);
280
281         /* create USB request handling process */
282         error = usb_proc_create(&ssc->sc_tq, mtx, "ucom", USB_PRI_MED);
283         if (error) {
284                 ucom_unit_free(ssc->sc_unit);
285                 return (error);
286         }
287         ssc->sc_subunits = subunits;
288         ssc->sc_flag = UCOM_FLAG_ATTACHED |
289             UCOM_FLAG_FREE_UNIT;
290
291         if (callback->ucom_free == NULL)
292                 ssc->sc_flag |= UCOM_FLAG_WAIT_REFS;
293
294         /* increment reference count */
295         ucom_ref(ssc);
296
297         for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
298                 sc[subunit].sc_subunit = subunit;
299                 sc[subunit].sc_super = ssc;
300                 sc[subunit].sc_mtx = mtx;
301                 sc[subunit].sc_parent = parent;
302                 sc[subunit].sc_callback = callback;
303
304                 error = ucom_attach_tty(ssc, &sc[subunit]);
305                 if (error) {
306                         ucom_detach(ssc, &sc[0]);
307                         return (error);
308                 }
309                 /* increment reference count */
310                 ucom_ref(ssc);
311
312                 /* set subunit attached */
313                 sc[subunit].sc_flag |= UCOM_FLAG_ATTACHED;
314         }
315
316         DPRINTF("tp = %p, unit = %d, subunits = %d\n",
317                 sc->sc_tty, ssc->sc_unit, ssc->sc_subunits);
318
319         return (0);
320 }
321
322 /*
323  * The following function will do nothing if the structure pointed to
324  * by "ssc" and "sc" is zero or has already been detached.
325  */
326 void
327 ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
328 {
329         int subunit;
330
331         if (!(ssc->sc_flag & UCOM_FLAG_ATTACHED))
332                 return;         /* not initialized */
333
334         if (ssc->sc_sysctl_ttyname != NULL) {
335                 sysctl_remove_oid(ssc->sc_sysctl_ttyname, 1, 0);
336                 ssc->sc_sysctl_ttyname = NULL;
337         }
338
339         if (ssc->sc_sysctl_ttyports != NULL) {
340                 sysctl_remove_oid(ssc->sc_sysctl_ttyports, 1, 0);
341                 ssc->sc_sysctl_ttyports = NULL;
342         }
343
344         usb_proc_drain(&ssc->sc_tq);
345
346         for (subunit = 0; subunit < ssc->sc_subunits; subunit++) {
347                 if (sc[subunit].sc_flag & UCOM_FLAG_ATTACHED) {
348
349                         ucom_detach_tty(ssc, &sc[subunit]);
350
351                         /* avoid duplicate detach */
352                         sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED;
353                 }
354         }
355         usb_proc_free(&ssc->sc_tq);
356
357         ucom_unref(ssc);
358
359         if (ssc->sc_flag & UCOM_FLAG_WAIT_REFS)
360                 ucom_drain(ssc);
361
362         /* make sure we don't detach twice */
363         ssc->sc_flag &= ~UCOM_FLAG_ATTACHED;
364 }
365
366 void
367 ucom_drain(struct ucom_super_softc *ssc)
368 {
369         mtx_lock(&ucom_mtx);
370         while (ssc->sc_refs > 0) {
371                 printf("ucom: Waiting for a TTY device to close.\n");
372                 usb_pause_mtx(&ucom_mtx, hz);
373         }
374         mtx_unlock(&ucom_mtx);
375 }
376
377 void
378 ucom_drain_all(void *arg)
379 {
380         mtx_lock(&ucom_mtx);
381         while (ucom_close_refs > 0) {
382                 printf("ucom: Waiting for all detached TTY "
383                     "devices to have open fds closed.\n");
384                 usb_pause_mtx(&ucom_mtx, hz);
385         }
386         mtx_unlock(&ucom_mtx);
387 }
388
389 static int
390 ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
391 {
392         struct tty *tp;
393         char buf[32];                   /* temporary TTY device name buffer */
394
395         tp = tty_alloc_mutex(&ucom_class, sc, sc->sc_mtx);
396         if (tp == NULL)
397                 return (ENOMEM);
398
399         /* Check if the client has a custom TTY name */
400         buf[0] = '\0';
401         if (sc->sc_callback->ucom_tty_name) {
402                 sc->sc_callback->ucom_tty_name(sc, buf,
403                     sizeof(buf), ssc->sc_unit, sc->sc_subunit);
404         }
405         if (buf[0] == 0) {
406                 /* Use default TTY name */
407                 if (ssc->sc_subunits > 1) {
408                         /* multiple modems in one */
409                         snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u.%u",
410                             ssc->sc_unit, sc->sc_subunit);
411                 } else {
412                         /* single modem */
413                         snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u",
414                             ssc->sc_unit);
415                 }
416         }
417         tty_makedev(tp, NULL, "%s", buf);
418
419         sc->sc_tty = tp;
420
421         sc->sc_pps.ppscap = PPS_CAPTUREBOTH;
422         sc->sc_pps.driver_abi = PPS_ABI_VERSION;
423         sc->sc_pps.driver_mtx = sc->sc_mtx;
424         pps_init_abi(&sc->sc_pps);
425
426         DPRINTF("ttycreate: %s\n", buf);
427
428         /* Check if this device should be a console */
429         if ((ucom_cons_softc == NULL) && 
430             (ssc->sc_unit == ucom_cons_unit) &&
431             (sc->sc_subunit == ucom_cons_subunit)) {
432
433                 DPRINTF("unit %d subunit %d is console",
434                     ssc->sc_unit, sc->sc_subunit);
435
436                 ucom_cons_softc = sc;
437
438                 tty_init_console(tp, ucom_cons_baud);
439
440                 UCOM_MTX_LOCK(ucom_cons_softc);
441                 ucom_cons_rx_low = 0;
442                 ucom_cons_rx_high = 0;
443                 ucom_cons_tx_low = 0;
444                 ucom_cons_tx_high = 0;
445                 sc->sc_flag |= UCOM_FLAG_CONSOLE;
446                 ucom_open(ucom_cons_softc->sc_tty);
447                 ucom_param(ucom_cons_softc->sc_tty, &tp->t_termios_init_in);
448                 UCOM_MTX_UNLOCK(ucom_cons_softc);
449         }
450
451         return (0);
452 }
453
454 static void
455 ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
456 {
457         struct tty *tp = sc->sc_tty;
458
459         DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty);
460
461         if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
462                 UCOM_MTX_LOCK(ucom_cons_softc);
463                 ucom_close(ucom_cons_softc->sc_tty);
464                 sc->sc_flag &= ~UCOM_FLAG_CONSOLE;
465                 UCOM_MTX_UNLOCK(ucom_cons_softc);
466                 ucom_cons_softc = NULL;
467         }
468
469         /* the config thread has been stopped when we get here */
470
471         UCOM_MTX_LOCK(sc);
472         sc->sc_flag |= UCOM_FLAG_GONE;
473         sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY);
474         UCOM_MTX_UNLOCK(sc);
475
476         if (tp) {
477                 mtx_lock(&ucom_mtx);
478                 ucom_close_refs++;
479                 mtx_unlock(&ucom_mtx);
480
481                 tty_lock(tp);
482
483                 ucom_close(tp); /* close, if any */
484
485                 tty_rel_gone(tp);
486
487                 UCOM_MTX_LOCK(sc);
488                 /*
489                  * make sure that read and write transfers are stopped
490                  */
491                 if (sc->sc_callback->ucom_stop_read)
492                         (sc->sc_callback->ucom_stop_read) (sc);
493                 if (sc->sc_callback->ucom_stop_write)
494                         (sc->sc_callback->ucom_stop_write) (sc);
495                 UCOM_MTX_UNLOCK(sc);
496         }
497 }
498
499 void
500 ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev)
501 {
502         char buf[64];
503         uint8_t iface_index;
504         struct usb_attach_arg *uaa;
505
506         snprintf(buf, sizeof(buf), "ttyname=" UCOM_TTY_PREFIX
507             "%d ttyports=%d", ssc->sc_unit, ssc->sc_subunits);
508
509         /* Store the PNP info in the first interface for the device */
510         uaa = device_get_ivars(dev);
511         iface_index = uaa->info.bIfaceIndex;
512     
513         if (usbd_set_pnpinfo(uaa->device, iface_index, buf) != 0)
514                 device_printf(dev, "Could not set PNP info\n");
515
516         /*
517          * The following information is also replicated in the PNP-info
518          * string which is registered above:
519          */
520         if (ssc->sc_sysctl_ttyname == NULL) {
521                 ssc->sc_sysctl_ttyname = SYSCTL_ADD_STRING(NULL,
522                     SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
523                     OID_AUTO, "ttyname", CTLFLAG_RD, ssc->sc_ttyname, 0,
524                     "TTY device basename");
525         }
526         if (ssc->sc_sysctl_ttyports == NULL) {
527                 ssc->sc_sysctl_ttyports = SYSCTL_ADD_INT(NULL,
528                     SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
529                     OID_AUTO, "ttyports", CTLFLAG_RD,
530                     NULL, ssc->sc_subunits, "Number of ports");
531         }
532 }
533
534 static void
535 ucom_queue_command(struct ucom_softc *sc,
536     usb_proc_callback_t *fn, struct termios *pt,
537     struct usb_proc_msg *t0, struct usb_proc_msg *t1)
538 {
539         struct ucom_super_softc *ssc = sc->sc_super;
540         struct ucom_param_task *task;
541
542         UCOM_MTX_ASSERT(sc, MA_OWNED);
543
544         if (usb_proc_is_gone(&ssc->sc_tq)) {
545                 DPRINTF("proc is gone\n");
546                 return;         /* nothing to do */
547         }
548         /* 
549          * NOTE: The task cannot get executed before we drop the
550          * "sc_mtx" mutex. It is safe to update fields in the message
551          * structure after that the message got queued.
552          */
553         task = (struct ucom_param_task *)
554           usb_proc_msignal(&ssc->sc_tq, t0, t1);
555
556         /* Setup callback and softc pointers */
557         task->hdr.pm_callback = fn;
558         task->sc = sc;
559
560         /* 
561          * Make a copy of the termios. This field is only present if
562          * the "pt" field is not NULL.
563          */
564         if (pt != NULL)
565                 task->termios_copy = *pt;
566
567         /*
568          * Closing the device should be synchronous.
569          */
570         if (fn == ucom_cfg_close)
571                 usb_proc_mwait(&ssc->sc_tq, t0, t1);
572
573         /*
574          * In case of multiple configure requests,
575          * keep track of the last one!
576          */
577         if (fn == ucom_cfg_start_transfers)
578                 sc->sc_last_start_xfer = &task->hdr;
579 }
580
581 static void
582 ucom_shutdown(struct ucom_softc *sc)
583 {
584         struct tty *tp = sc->sc_tty;
585
586         UCOM_MTX_ASSERT(sc, MA_OWNED);
587
588         DPRINTF("\n");
589
590         /*
591          * Hang up if necessary:
592          */
593         if (tp->t_termios.c_cflag & HUPCL) {
594                 ucom_modem(tp, 0, SER_DTR);
595         }
596 }
597
598 /*
599  * Return values:
600  *    0: normal
601  * else: taskqueue is draining or gone
602  */
603 uint8_t
604 ucom_cfg_is_gone(struct ucom_softc *sc)
605 {
606         struct ucom_super_softc *ssc = sc->sc_super;
607
608         return (usb_proc_is_gone(&ssc->sc_tq));
609 }
610
611 static void
612 ucom_cfg_start_transfers(struct usb_proc_msg *_task)
613 {
614         struct ucom_cfg_task *task = 
615             (struct ucom_cfg_task *)_task;
616         struct ucom_softc *sc = task->sc;
617
618         if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
619                 return;
620         }
621         if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
622                 /* TTY device closed */
623                 return;
624         }
625
626         if (_task == sc->sc_last_start_xfer)
627                 sc->sc_flag |= UCOM_FLAG_GP_DATA;
628
629         if (sc->sc_callback->ucom_start_read) {
630                 (sc->sc_callback->ucom_start_read) (sc);
631         }
632         if (sc->sc_callback->ucom_start_write) {
633                 (sc->sc_callback->ucom_start_write) (sc);
634         }
635 }
636
637 static void
638 ucom_start_transfers(struct ucom_softc *sc)
639 {
640         if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
641                 return;
642         }
643         /*
644          * Make sure that data transfers are started in both
645          * directions:
646          */
647         if (sc->sc_callback->ucom_start_read) {
648                 (sc->sc_callback->ucom_start_read) (sc);
649         }
650         if (sc->sc_callback->ucom_start_write) {
651                 (sc->sc_callback->ucom_start_write) (sc);
652         }
653 }
654
655 static void
656 ucom_cfg_open(struct usb_proc_msg *_task)
657 {
658         struct ucom_cfg_task *task = 
659             (struct ucom_cfg_task *)_task;
660         struct ucom_softc *sc = task->sc;
661
662         DPRINTF("\n");
663
664         if (sc->sc_flag & UCOM_FLAG_LL_READY) {
665
666                 /* already opened */
667
668         } else {
669
670                 sc->sc_flag |= UCOM_FLAG_LL_READY;
671
672                 if (sc->sc_callback->ucom_cfg_open) {
673                         (sc->sc_callback->ucom_cfg_open) (sc);
674
675                         /* wait a little */
676                         usb_pause_mtx(sc->sc_mtx, hz / 10);
677                 }
678         }
679 }
680
681 static int
682 ucom_open(struct tty *tp)
683 {
684         struct ucom_softc *sc = tty_softc(tp);
685         int error;
686
687         UCOM_MTX_ASSERT(sc, MA_OWNED);
688
689         if (sc->sc_flag & UCOM_FLAG_GONE) {
690                 return (ENXIO);
691         }
692         if (sc->sc_flag & UCOM_FLAG_HL_READY) {
693                 /* already opened */
694                 return (0);
695         }
696         DPRINTF("tp = %p\n", tp);
697
698         if (sc->sc_callback->ucom_pre_open) {
699                 /*
700                  * give the lower layer a chance to disallow TTY open, for
701                  * example if the device is not present:
702                  */
703                 error = (sc->sc_callback->ucom_pre_open) (sc);
704                 if (error) {
705                         return (error);
706                 }
707         }
708         sc->sc_flag |= UCOM_FLAG_HL_READY;
709
710         /* Disable transfers */
711         sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
712
713         sc->sc_lsr = 0;
714         sc->sc_msr = 0;
715         sc->sc_mcr = 0;
716
717         /* reset programmed line state */
718         sc->sc_pls_curr = 0;
719         sc->sc_pls_set = 0;
720         sc->sc_pls_clr = 0;
721
722         /* reset jitter buffer */
723         sc->sc_jitterbuf_in = 0;
724         sc->sc_jitterbuf_out = 0;
725
726         ucom_queue_command(sc, ucom_cfg_open, NULL,
727             &sc->sc_open_task[0].hdr,
728             &sc->sc_open_task[1].hdr);
729
730         /* Queue transfer enable command last */
731         ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
732             &sc->sc_start_task[0].hdr, 
733             &sc->sc_start_task[1].hdr);
734
735         ucom_modem(tp, SER_DTR | SER_RTS, 0);
736
737         ucom_ring(sc, 0);
738
739         ucom_break(sc, 0);
740
741         ucom_status_change(sc);
742
743         return (0);
744 }
745
746 static void
747 ucom_cfg_close(struct usb_proc_msg *_task)
748 {
749         struct ucom_cfg_task *task = 
750             (struct ucom_cfg_task *)_task;
751         struct ucom_softc *sc = task->sc;
752
753         DPRINTF("\n");
754
755         if (sc->sc_flag & UCOM_FLAG_LL_READY) {
756                 sc->sc_flag &= ~UCOM_FLAG_LL_READY;
757                 if (sc->sc_callback->ucom_cfg_close)
758                         (sc->sc_callback->ucom_cfg_close) (sc);
759         } else {
760                 /* already closed */
761         }
762 }
763
764 static void
765 ucom_close(struct tty *tp)
766 {
767         struct ucom_softc *sc = tty_softc(tp);
768
769         UCOM_MTX_ASSERT(sc, MA_OWNED);
770
771         DPRINTF("tp=%p\n", tp);
772
773         if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
774                 DPRINTF("tp=%p already closed\n", tp);
775                 return;
776         }
777         ucom_shutdown(sc);
778
779         ucom_queue_command(sc, ucom_cfg_close, NULL,
780             &sc->sc_close_task[0].hdr,
781             &sc->sc_close_task[1].hdr);
782
783         sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_RTS_IFLOW);
784
785         if (sc->sc_callback->ucom_stop_read) {
786                 (sc->sc_callback->ucom_stop_read) (sc);
787         }
788 }
789
790 static void
791 ucom_inwakeup(struct tty *tp)
792 {
793         struct ucom_softc *sc = tty_softc(tp);
794         uint16_t pos;
795
796         if (sc == NULL)
797                 return;
798
799         UCOM_MTX_ASSERT(sc, MA_OWNED);
800
801         DPRINTF("tp=%p\n", tp);
802
803         if (ttydisc_can_bypass(tp) != 0 || 
804             (sc->sc_flag & UCOM_FLAG_HL_READY) == 0 ||
805             (sc->sc_flag & UCOM_FLAG_INWAKEUP) != 0) {
806                 return;
807         }
808
809         /* prevent recursion */
810         sc->sc_flag |= UCOM_FLAG_INWAKEUP;
811
812         pos = sc->sc_jitterbuf_out;
813
814         while (sc->sc_jitterbuf_in != pos) {
815                 int c;
816
817                 c = (char)sc->sc_jitterbuf[pos];
818
819                 if (ttydisc_rint(tp, c, 0) == -1)
820                         break;
821                 pos++;
822                 if (pos >= UCOM_JITTERBUF_SIZE)
823                         pos -= UCOM_JITTERBUF_SIZE;
824         }
825
826         sc->sc_jitterbuf_out = pos;
827
828         /* clear RTS in async fashion */
829         if ((sc->sc_jitterbuf_in == pos) && 
830             (sc->sc_flag & UCOM_FLAG_RTS_IFLOW))
831                 ucom_rts(sc, 0);
832
833         sc->sc_flag &= ~UCOM_FLAG_INWAKEUP;
834 }
835
836 static int
837 ucom_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
838 {
839         struct ucom_softc *sc = tty_softc(tp);
840         int error;
841
842         UCOM_MTX_ASSERT(sc, MA_OWNED);
843
844         if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
845                 return (EIO);
846         }
847         DPRINTF("cmd = 0x%08lx\n", cmd);
848
849         switch (cmd) {
850 #if 0
851         case TIOCSRING:
852                 ucom_ring(sc, 1);
853                 error = 0;
854                 break;
855         case TIOCCRING:
856                 ucom_ring(sc, 0);
857                 error = 0;
858                 break;
859 #endif
860         case TIOCSBRK:
861                 ucom_break(sc, 1);
862                 error = 0;
863                 break;
864         case TIOCCBRK:
865                 ucom_break(sc, 0);
866                 error = 0;
867                 break;
868         default:
869                 if (sc->sc_callback->ucom_ioctl) {
870                         error = (sc->sc_callback->ucom_ioctl)
871                             (sc, cmd, data, 0, td);
872                 } else {
873                         error = ENOIOCTL;
874                 }
875                 if (error == ENOIOCTL)
876                         error = pps_ioctl(cmd, data, &sc->sc_pps);
877                 break;
878         }
879         return (error);
880 }
881
882 static int
883 ucom_modem(struct tty *tp, int sigon, int sigoff)
884 {
885         struct ucom_softc *sc = tty_softc(tp);
886         uint8_t onoff;
887
888         UCOM_MTX_ASSERT(sc, MA_OWNED);
889
890         if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
891                 return (0);
892         }
893         if ((sigon == 0) && (sigoff == 0)) {
894
895                 if (sc->sc_mcr & SER_DTR) {
896                         sigon |= SER_DTR;
897                 }
898                 if (sc->sc_mcr & SER_RTS) {
899                         sigon |= SER_RTS;
900                 }
901                 if (sc->sc_msr & SER_CTS) {
902                         sigon |= SER_CTS;
903                 }
904                 if (sc->sc_msr & SER_DCD) {
905                         sigon |= SER_DCD;
906                 }
907                 if (sc->sc_msr & SER_DSR) {
908                         sigon |= SER_DSR;
909                 }
910                 if (sc->sc_msr & SER_RI) {
911                         sigon |= SER_RI;
912                 }
913                 return (sigon);
914         }
915         if (sigon & SER_DTR) {
916                 sc->sc_mcr |= SER_DTR;
917         }
918         if (sigoff & SER_DTR) {
919                 sc->sc_mcr &= ~SER_DTR;
920         }
921         if (sigon & SER_RTS) {
922                 sc->sc_mcr |= SER_RTS;
923         }
924         if (sigoff & SER_RTS) {
925                 sc->sc_mcr &= ~SER_RTS;
926         }
927         onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0;
928         ucom_dtr(sc, onoff);
929
930         onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0;
931         ucom_rts(sc, onoff);
932
933         return (0);
934 }
935
936 static void
937 ucom_cfg_line_state(struct usb_proc_msg *_task)
938 {
939         struct ucom_cfg_task *task = 
940             (struct ucom_cfg_task *)_task;
941         struct ucom_softc *sc = task->sc;
942         uint8_t notch_bits;
943         uint8_t any_bits;
944         uint8_t prev_value;
945         uint8_t last_value;
946         uint8_t mask;
947
948         if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
949                 return;
950         }
951
952         mask = 0;
953         /* compute callback mask */
954         if (sc->sc_callback->ucom_cfg_set_dtr)
955                 mask |= UCOM_LS_DTR;
956         if (sc->sc_callback->ucom_cfg_set_rts)
957                 mask |= UCOM_LS_RTS;
958         if (sc->sc_callback->ucom_cfg_set_break)
959                 mask |= UCOM_LS_BREAK;
960         if (sc->sc_callback->ucom_cfg_set_ring)
961                 mask |= UCOM_LS_RING;
962
963         /* compute the bits we are to program */
964         notch_bits = (sc->sc_pls_set & sc->sc_pls_clr) & mask;
965         any_bits = (sc->sc_pls_set | sc->sc_pls_clr) & mask;
966         prev_value = sc->sc_pls_curr ^ notch_bits;
967         last_value = sc->sc_pls_curr;
968
969         /* reset programmed line state */
970         sc->sc_pls_curr = 0;
971         sc->sc_pls_set = 0;
972         sc->sc_pls_clr = 0;
973
974         /* ensure that we don't lose any levels */
975         if (notch_bits & UCOM_LS_DTR)
976                 sc->sc_callback->ucom_cfg_set_dtr(sc,
977                     (prev_value & UCOM_LS_DTR) ? 1 : 0);
978         if (notch_bits & UCOM_LS_RTS)
979                 sc->sc_callback->ucom_cfg_set_rts(sc,
980                     (prev_value & UCOM_LS_RTS) ? 1 : 0);
981         if (notch_bits & UCOM_LS_BREAK)
982                 sc->sc_callback->ucom_cfg_set_break(sc,
983                     (prev_value & UCOM_LS_BREAK) ? 1 : 0);
984         if (notch_bits & UCOM_LS_RING)
985                 sc->sc_callback->ucom_cfg_set_ring(sc,
986                     (prev_value & UCOM_LS_RING) ? 1 : 0);
987
988         /* set last value */
989         if (any_bits & UCOM_LS_DTR)
990                 sc->sc_callback->ucom_cfg_set_dtr(sc,
991                     (last_value & UCOM_LS_DTR) ? 1 : 0);
992         if (any_bits & UCOM_LS_RTS)
993                 sc->sc_callback->ucom_cfg_set_rts(sc,
994                     (last_value & UCOM_LS_RTS) ? 1 : 0);
995         if (any_bits & UCOM_LS_BREAK)
996                 sc->sc_callback->ucom_cfg_set_break(sc,
997                     (last_value & UCOM_LS_BREAK) ? 1 : 0);
998         if (any_bits & UCOM_LS_RING)
999                 sc->sc_callback->ucom_cfg_set_ring(sc,
1000                     (last_value & UCOM_LS_RING) ? 1 : 0);
1001 }
1002
1003 static void
1004 ucom_line_state(struct ucom_softc *sc,
1005     uint8_t set_bits, uint8_t clear_bits)
1006 {
1007         UCOM_MTX_ASSERT(sc, MA_OWNED);
1008
1009         if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1010                 return;
1011         }
1012
1013         DPRINTF("on=0x%02x, off=0x%02x\n", set_bits, clear_bits);
1014
1015         /* update current programmed line state */
1016         sc->sc_pls_curr |= set_bits;
1017         sc->sc_pls_curr &= ~clear_bits;
1018         sc->sc_pls_set |= set_bits;
1019         sc->sc_pls_clr |= clear_bits;
1020
1021         /* defer driver programming */
1022         ucom_queue_command(sc, ucom_cfg_line_state, NULL,
1023             &sc->sc_line_state_task[0].hdr, 
1024             &sc->sc_line_state_task[1].hdr);
1025 }
1026
1027 static void
1028 ucom_ring(struct ucom_softc *sc, uint8_t onoff)
1029 {
1030         DPRINTF("onoff = %d\n", onoff);
1031
1032         if (onoff)
1033                 ucom_line_state(sc, UCOM_LS_RING, 0);
1034         else
1035                 ucom_line_state(sc, 0, UCOM_LS_RING);
1036 }
1037
1038 static void
1039 ucom_break(struct ucom_softc *sc, uint8_t onoff)
1040 {
1041         DPRINTF("onoff = %d\n", onoff);
1042
1043         if (onoff)
1044                 ucom_line_state(sc, UCOM_LS_BREAK, 0);
1045         else
1046                 ucom_line_state(sc, 0, UCOM_LS_BREAK);
1047 }
1048
1049 static void
1050 ucom_dtr(struct ucom_softc *sc, uint8_t onoff)
1051 {
1052         DPRINTF("onoff = %d\n", onoff);
1053
1054         if (onoff)
1055                 ucom_line_state(sc, UCOM_LS_DTR, 0);
1056         else
1057                 ucom_line_state(sc, 0, UCOM_LS_DTR);
1058 }
1059
1060 static void
1061 ucom_rts(struct ucom_softc *sc, uint8_t onoff)
1062 {
1063         DPRINTF("onoff = %d\n", onoff);
1064
1065         if (onoff)
1066                 ucom_line_state(sc, UCOM_LS_RTS, 0);
1067         else
1068                 ucom_line_state(sc, 0, UCOM_LS_RTS);
1069 }
1070
1071 static void
1072 ucom_cfg_status_change(struct usb_proc_msg *_task)
1073 {
1074         struct ucom_cfg_task *task = 
1075             (struct ucom_cfg_task *)_task;
1076         struct ucom_softc *sc = task->sc;
1077         struct tty *tp;
1078         int onoff;
1079         uint8_t new_msr;
1080         uint8_t new_lsr;
1081         uint8_t msr_delta;
1082         uint8_t lsr_delta;
1083         uint8_t pps_signal;
1084
1085         tp = sc->sc_tty;
1086
1087         UCOM_MTX_ASSERT(sc, MA_OWNED);
1088
1089         if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1090                 return;
1091         }
1092         if (sc->sc_callback->ucom_cfg_get_status == NULL) {
1093                 return;
1094         }
1095         /* get status */
1096
1097         new_msr = 0;
1098         new_lsr = 0;
1099
1100         (sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr);
1101
1102         if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1103                 /* TTY device closed */
1104                 return;
1105         }
1106         msr_delta = (sc->sc_msr ^ new_msr);
1107         lsr_delta = (sc->sc_lsr ^ new_lsr);
1108
1109         sc->sc_msr = new_msr;
1110         sc->sc_lsr = new_lsr;
1111
1112         /*
1113          * Time pulse counting support.
1114          */
1115         switch(ucom_pps_mode & UART_PPS_SIGNAL_MASK) {
1116         case UART_PPS_CTS:
1117                 pps_signal = SER_CTS;
1118                 break;
1119         case UART_PPS_DCD:
1120                 pps_signal = SER_DCD;
1121                 break;
1122         default:
1123                 pps_signal = 0;
1124                 break;
1125         }
1126
1127         if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) &&
1128             (msr_delta & pps_signal)) {
1129                 pps_capture(&sc->sc_pps);
1130                 onoff = (sc->sc_msr & pps_signal) ? 1 : 0;
1131                 if (ucom_pps_mode & UART_PPS_INVERT_PULSE)
1132                         onoff = !onoff;
1133                 pps_event(&sc->sc_pps, onoff ? PPS_CAPTUREASSERT :
1134                     PPS_CAPTURECLEAR);
1135         }
1136
1137         if (msr_delta & SER_DCD) {
1138
1139                 onoff = (sc->sc_msr & SER_DCD) ? 1 : 0;
1140
1141                 DPRINTF("DCD changed to %d\n", onoff);
1142
1143                 ttydisc_modem(tp, onoff);
1144         }
1145
1146         if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) {
1147
1148                 DPRINTF("BREAK detected\n");
1149
1150                 ttydisc_rint(tp, 0, TRE_BREAK);
1151                 ttydisc_rint_done(tp);
1152         }
1153
1154         if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) {
1155
1156                 DPRINTF("Frame error detected\n");
1157
1158                 ttydisc_rint(tp, 0, TRE_FRAMING);
1159                 ttydisc_rint_done(tp);
1160         }
1161
1162         if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) {
1163
1164                 DPRINTF("Parity error detected\n");
1165
1166                 ttydisc_rint(tp, 0, TRE_PARITY);
1167                 ttydisc_rint_done(tp);
1168         }
1169 }
1170
1171 void
1172 ucom_status_change(struct ucom_softc *sc)
1173 {
1174         UCOM_MTX_ASSERT(sc, MA_OWNED);
1175
1176         if (sc->sc_flag & UCOM_FLAG_CONSOLE)
1177                 return;         /* not supported */
1178
1179         if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1180                 return;
1181         }
1182         DPRINTF("\n");
1183
1184         ucom_queue_command(sc, ucom_cfg_status_change, NULL,
1185             &sc->sc_status_task[0].hdr,
1186             &sc->sc_status_task[1].hdr);
1187 }
1188
1189 static void
1190 ucom_cfg_param(struct usb_proc_msg *_task)
1191 {
1192         struct ucom_param_task *task = 
1193             (struct ucom_param_task *)_task;
1194         struct ucom_softc *sc = task->sc;
1195
1196         if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
1197                 return;
1198         }
1199         if (sc->sc_callback->ucom_cfg_param == NULL) {
1200                 return;
1201         }
1202
1203         (sc->sc_callback->ucom_cfg_param) (sc, &task->termios_copy);
1204
1205         /* wait a little */
1206         usb_pause_mtx(sc->sc_mtx, hz / 10);
1207 }
1208
1209 static int
1210 ucom_param(struct tty *tp, struct termios *t)
1211 {
1212         struct ucom_softc *sc = tty_softc(tp);
1213         uint8_t opened;
1214         int error;
1215
1216         UCOM_MTX_ASSERT(sc, MA_OWNED);
1217
1218         opened = 0;
1219         error = 0;
1220
1221         if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1222
1223                 /* XXX the TTY layer should call "open()" first! */
1224                 /*
1225                  * Not quite: Its ordering is partly backwards, but
1226                  * some parameters must be set early in ttydev_open(),
1227                  * possibly before calling ttydevsw_open().
1228                  */
1229                 error = ucom_open(tp);
1230                 if (error)
1231                         goto done;
1232
1233                 opened = 1;
1234         }
1235         DPRINTF("sc = %p\n", sc);
1236
1237         /* Check requested parameters. */
1238         if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) {
1239                 /* XXX c_ospeed == 0 is perfectly valid. */
1240                 DPRINTF("mismatch ispeed and ospeed\n");
1241                 error = EINVAL;
1242                 goto done;
1243         }
1244         t->c_ispeed = t->c_ospeed;
1245
1246         if (sc->sc_callback->ucom_pre_param) {
1247                 /* Let the lower layer verify the parameters */
1248                 error = (sc->sc_callback->ucom_pre_param) (sc, t);
1249                 if (error) {
1250                         DPRINTF("callback error = %d\n", error);
1251                         goto done;
1252                 }
1253         }
1254
1255         /* Disable transfers */
1256         sc->sc_flag &= ~UCOM_FLAG_GP_DATA;
1257
1258         /* Queue baud rate programming command first */
1259         ucom_queue_command(sc, ucom_cfg_param, t,
1260             &sc->sc_param_task[0].hdr,
1261             &sc->sc_param_task[1].hdr);
1262
1263         /* Queue transfer enable command last */
1264         ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
1265             &sc->sc_start_task[0].hdr, 
1266             &sc->sc_start_task[1].hdr);
1267
1268         if (t->c_cflag & CRTS_IFLOW) {
1269                 sc->sc_flag |= UCOM_FLAG_RTS_IFLOW;
1270         } else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) {
1271                 sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW;
1272                 ucom_modem(tp, SER_RTS, 0);
1273         }
1274 done:
1275         if (error) {
1276                 if (opened) {
1277                         ucom_close(tp);
1278                 }
1279         }
1280         return (error);
1281 }
1282
1283 static void
1284 ucom_outwakeup(struct tty *tp)
1285 {
1286         struct ucom_softc *sc = tty_softc(tp);
1287
1288         UCOM_MTX_ASSERT(sc, MA_OWNED);
1289
1290         DPRINTF("sc = %p\n", sc);
1291
1292         if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
1293                 /* The higher layer is not ready */
1294                 return;
1295         }
1296         ucom_start_transfers(sc);
1297 }
1298
1299 static bool
1300 ucom_busy(struct tty *tp)
1301 {
1302         struct ucom_softc *sc = tty_softc(tp);
1303         const uint8_t txidle = ULSR_TXRDY | ULSR_TSRE;
1304
1305         UCOM_MTX_ASSERT(sc, MA_OWNED);
1306
1307         DPRINTFN(3, "sc = %p lsr 0x%02x\n", sc, sc->sc_lsr);
1308
1309         /*
1310          * If the driver maintains the txidle bits in LSR, we can use them to
1311          * determine whether the transmitter is busy or idle.  Otherwise we have
1312          * to assume it is idle to avoid hanging forever on tcdrain(3).
1313          */
1314         if (sc->sc_flag & UCOM_FLAG_LSRTXIDLE)
1315                 return ((sc->sc_lsr & txidle) != txidle);
1316         else
1317                 return (false);
1318 }
1319
1320 /*------------------------------------------------------------------------*
1321  *      ucom_get_data
1322  *
1323  * Return values:
1324  * 0: No data is available.
1325  * Else: Data is available.
1326  *------------------------------------------------------------------------*/
1327 uint8_t
1328 ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1329     uint32_t offset, uint32_t len, uint32_t *actlen)
1330 {
1331         struct usb_page_search res;
1332         struct tty *tp = sc->sc_tty;
1333         uint32_t cnt;
1334         uint32_t offset_orig;
1335
1336         UCOM_MTX_ASSERT(sc, MA_OWNED);
1337
1338         if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1339                 unsigned int temp;
1340
1341                 /* get total TX length */
1342
1343                 temp = ucom_cons_tx_high - ucom_cons_tx_low;
1344                 temp %= UCOM_CONS_BUFSIZE;
1345
1346                 /* limit TX length */
1347
1348                 if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low))
1349                         temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low);
1350
1351                 if (temp > len)
1352                         temp = len;
1353
1354                 /* copy in data */
1355
1356                 usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp);
1357
1358                 /* update counters */
1359
1360                 ucom_cons_tx_low += temp;
1361                 ucom_cons_tx_low %= UCOM_CONS_BUFSIZE;
1362
1363                 /* store actual length */
1364
1365                 *actlen = temp;
1366
1367                 return (temp ? 1 : 0);
1368         }
1369
1370         if (tty_gone(tp) ||
1371             !(sc->sc_flag & UCOM_FLAG_GP_DATA)) {
1372                 actlen[0] = 0;
1373                 return (0);             /* multiport device polling */
1374         }
1375         offset_orig = offset;
1376
1377         while (len != 0) {
1378
1379                 usbd_get_page(pc, offset, &res);
1380
1381                 if (res.length > len) {
1382                         res.length = len;
1383                 }
1384                 /* copy data directly into USB buffer */
1385                 cnt = ttydisc_getc(tp, res.buffer, res.length);
1386
1387                 offset += cnt;
1388                 len -= cnt;
1389
1390                 if (cnt < res.length) {
1391                         /* end of buffer */
1392                         break;
1393                 }
1394         }
1395
1396         actlen[0] = offset - offset_orig;
1397
1398         DPRINTF("cnt=%d\n", actlen[0]);
1399
1400         if (actlen[0] == 0) {
1401                 return (0);
1402         }
1403         return (1);
1404 }
1405
1406 void
1407 ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc,
1408     uint32_t offset, uint32_t len)
1409 {
1410         struct usb_page_search res;
1411         struct tty *tp = sc->sc_tty;
1412         char *buf;
1413         uint32_t cnt;
1414
1415         UCOM_MTX_ASSERT(sc, MA_OWNED);
1416
1417         if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
1418                 unsigned int temp;
1419
1420                 /* get maximum RX length */
1421
1422                 temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_rx_high + ucom_cons_rx_low;
1423                 temp %= UCOM_CONS_BUFSIZE;
1424
1425                 /* limit RX length */
1426
1427                 if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_high))
1428                         temp = (UCOM_CONS_BUFSIZE - ucom_cons_rx_high);
1429
1430                 if (temp > len)
1431                         temp = len;
1432
1433                 /* copy out data */
1434
1435                 usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, temp);
1436
1437                 /* update counters */
1438
1439                 ucom_cons_rx_high += temp;
1440                 ucom_cons_rx_high %= UCOM_CONS_BUFSIZE;
1441
1442                 return;
1443         }
1444
1445         if (tty_gone(tp))
1446                 return;                 /* multiport device polling */
1447
1448         if (len == 0)
1449                 return;                 /* no data */
1450
1451         /* set a flag to prevent recursation ? */
1452
1453         while (len > 0) {
1454
1455                 usbd_get_page(pc, offset, &res);
1456
1457                 if (res.length > len) {
1458                         res.length = len;
1459                 }
1460                 len -= res.length;
1461                 offset += res.length;
1462
1463                 /* pass characters to tty layer */
1464
1465                 buf = res.buffer;
1466                 cnt = res.length;
1467
1468                 /* first check if we can pass the buffer directly */
1469
1470                 if (ttydisc_can_bypass(tp)) {
1471
1472                         /* clear any jitter buffer */
1473                         sc->sc_jitterbuf_in = 0;
1474                         sc->sc_jitterbuf_out = 0;
1475
1476                         if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) {
1477                                 DPRINTF("tp=%p, data lost\n", tp);
1478                         }
1479                         continue;
1480                 }
1481                 /* need to loop */
1482
1483                 for (cnt = 0; cnt != res.length; cnt++) {
1484                         if (sc->sc_jitterbuf_in != sc->sc_jitterbuf_out ||
1485                             ttydisc_rint(tp, buf[cnt], 0) == -1) {
1486                                 uint16_t end;
1487                                 uint16_t pos;
1488
1489                                 pos = sc->sc_jitterbuf_in;
1490                                 end = sc->sc_jitterbuf_out +
1491                                     UCOM_JITTERBUF_SIZE - 1;
1492                                 if (end >= UCOM_JITTERBUF_SIZE)
1493                                         end -= UCOM_JITTERBUF_SIZE;
1494
1495                                 for (; cnt != res.length; cnt++) {
1496                                         if (pos == end)
1497                                                 break;
1498                                         sc->sc_jitterbuf[pos] = buf[cnt];
1499                                         pos++;
1500                                         if (pos >= UCOM_JITTERBUF_SIZE)
1501                                                 pos -= UCOM_JITTERBUF_SIZE;
1502                                 }
1503
1504                                 sc->sc_jitterbuf_in = pos;
1505
1506                                 /* set RTS in async fashion */
1507                                 if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW)
1508                                         ucom_rts(sc, 1);
1509
1510                                 DPRINTF("tp=%p, lost %d "
1511                                     "chars\n", tp, res.length - cnt);
1512                                 break;
1513                         }
1514                 }
1515         }
1516         ttydisc_rint_done(tp);
1517 }
1518
1519 static void
1520 ucom_free(void *xsc)
1521 {
1522         struct ucom_softc *sc = xsc;
1523
1524         if (sc->sc_callback->ucom_free != NULL)
1525                 sc->sc_callback->ucom_free(sc);
1526         else
1527                 ucom_unref(sc->sc_super);
1528
1529         mtx_lock(&ucom_mtx);
1530         ucom_close_refs--;
1531         mtx_unlock(&ucom_mtx);
1532 }
1533
1534 static cn_probe_t ucom_cnprobe;
1535 static cn_init_t ucom_cninit;
1536 static cn_term_t ucom_cnterm;
1537 static cn_getc_t ucom_cngetc;
1538 static cn_putc_t ucom_cnputc;
1539 static cn_grab_t ucom_cngrab;
1540 static cn_ungrab_t ucom_cnungrab;
1541
1542 CONSOLE_DRIVER(ucom);
1543
1544 static void
1545 ucom_cnprobe(struct consdev  *cp)
1546 {
1547         if (ucom_cons_unit != -1)
1548                 cp->cn_pri = CN_NORMAL;
1549         else
1550                 cp->cn_pri = CN_DEAD;
1551
1552         strlcpy(cp->cn_name, "ucom", sizeof(cp->cn_name));
1553 }
1554
1555 static void
1556 ucom_cninit(struct consdev  *cp)
1557 {
1558 }
1559
1560 static void
1561 ucom_cnterm(struct consdev  *cp)
1562 {
1563 }
1564
1565 static void
1566 ucom_cngrab(struct consdev *cp)
1567 {
1568 }
1569
1570 static void
1571 ucom_cnungrab(struct consdev *cp)
1572 {
1573 }
1574
1575 static int
1576 ucom_cngetc(struct consdev *cd)
1577 {
1578         struct ucom_softc *sc = ucom_cons_softc;
1579         int c;
1580
1581         if (sc == NULL)
1582                 return (-1);
1583
1584         UCOM_MTX_LOCK(sc);
1585
1586         if (ucom_cons_rx_low != ucom_cons_rx_high) {
1587                 c = ucom_cons_rx_buf[ucom_cons_rx_low];
1588                 ucom_cons_rx_low ++;
1589                 ucom_cons_rx_low %= UCOM_CONS_BUFSIZE;
1590         } else {
1591                 c = -1;
1592         }
1593
1594         /* start USB transfers */
1595         ucom_outwakeup(sc->sc_tty);
1596
1597         UCOM_MTX_UNLOCK(sc);
1598
1599         /* poll if necessary */
1600         if (USB_IN_POLLING_MODE_FUNC() && sc->sc_callback->ucom_poll)
1601                 (sc->sc_callback->ucom_poll) (sc);
1602
1603         return (c);
1604 }
1605
1606 static void
1607 ucom_cnputc(struct consdev *cd, int c)
1608 {
1609         struct ucom_softc *sc = ucom_cons_softc;
1610         unsigned int temp;
1611
1612         if (sc == NULL)
1613                 return;
1614
1615  repeat:
1616
1617         UCOM_MTX_LOCK(sc);
1618
1619         /* compute maximum TX length */
1620
1621         temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_tx_high + ucom_cons_tx_low;
1622         temp %= UCOM_CONS_BUFSIZE;
1623
1624         if (temp) {
1625                 ucom_cons_tx_buf[ucom_cons_tx_high] = c;
1626                 ucom_cons_tx_high ++;
1627                 ucom_cons_tx_high %= UCOM_CONS_BUFSIZE;
1628         }
1629
1630         /* start USB transfers */
1631         ucom_outwakeup(sc->sc_tty);
1632
1633         UCOM_MTX_UNLOCK(sc);
1634
1635         /* poll if necessary */
1636         if (USB_IN_POLLING_MODE_FUNC() && sc->sc_callback->ucom_poll) {
1637                 (sc->sc_callback->ucom_poll) (sc);
1638                 /* simple flow control */
1639                 if (temp == 0)
1640                         goto repeat;
1641         }
1642 }
1643
1644 /*------------------------------------------------------------------------*
1645  *      ucom_ref
1646  *
1647  * This function will increment the super UCOM reference count.
1648  *------------------------------------------------------------------------*/
1649 void
1650 ucom_ref(struct ucom_super_softc *ssc)
1651 {
1652         mtx_lock(&ucom_mtx);
1653         ssc->sc_refs++;
1654         mtx_unlock(&ucom_mtx);
1655 }
1656
1657 /*------------------------------------------------------------------------*
1658  *      ucom_free_unit
1659  *
1660  * This function will free the super UCOM's allocated unit
1661  * number. This function can be called on a zero-initialized
1662  * structure. This function can be called multiple times.
1663  *------------------------------------------------------------------------*/
1664 static void
1665 ucom_free_unit(struct ucom_super_softc *ssc)
1666 {
1667         if (!(ssc->sc_flag & UCOM_FLAG_FREE_UNIT))
1668                 return;
1669
1670         ucom_unit_free(ssc->sc_unit);
1671
1672         ssc->sc_flag &= ~UCOM_FLAG_FREE_UNIT;
1673 }
1674
1675 /*------------------------------------------------------------------------*
1676  *      ucom_unref
1677  *
1678  * This function will decrement the super UCOM reference count.
1679  *
1680  * Return values:
1681  * 0: UCOM structures are still referenced.
1682  * Else: UCOM structures are no longer referenced.
1683  *------------------------------------------------------------------------*/
1684 int
1685 ucom_unref(struct ucom_super_softc *ssc)
1686 {
1687         int retval;
1688
1689         mtx_lock(&ucom_mtx);
1690         retval = (ssc->sc_refs < 2);
1691         ssc->sc_refs--;
1692         mtx_unlock(&ucom_mtx);
1693
1694         if (retval)
1695                 ucom_free_unit(ssc);
1696
1697         return (retval);
1698 }
1699
1700 #if defined(GDB)
1701
1702 #include <gdb/gdb.h>
1703
1704 static gdb_probe_f ucom_gdbprobe;
1705 static gdb_init_f ucom_gdbinit;
1706 static gdb_term_f ucom_gdbterm;
1707 static gdb_getc_f ucom_gdbgetc;
1708 static gdb_putc_f ucom_gdbputc;
1709
1710 GDB_DBGPORT(sio, ucom_gdbprobe, ucom_gdbinit, ucom_gdbterm, ucom_gdbgetc, ucom_gdbputc);
1711
1712 static int
1713 ucom_gdbprobe(void)
1714 {
1715         return ((ucom_cons_softc != NULL) ? 0 : -1);
1716 }
1717
1718 static void
1719 ucom_gdbinit(void)
1720 {
1721 }
1722
1723 static void
1724 ucom_gdbterm(void)
1725 {
1726 }
1727
1728 static void
1729 ucom_gdbputc(int c)
1730 {
1731         ucom_cnputc(NULL, c);
1732 }
1733
1734 static int
1735 ucom_gdbgetc(void)
1736 {
1737         return (ucom_cngetc(NULL));
1738 }
1739
1740 #endif