]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/usb/ubser.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / usb / ubser.c
1 /*-
2  * Copyright (c) 2004 Bernd Walter <ticso@freebsd.org>
3  *
4  * $URL: https://devel.bwct.de/svn/projects/ubser/ubser.c $
5  * $Date: 2004-02-29 01:53:10 +0100 (Sun, 29 Feb 2004) $
6  * $Author: ticso $
7  * $Rev: 1127 $
8  */
9
10 /*-
11  * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
12  * All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 /*-
37  * Copyright (c) 2000 The NetBSD Foundation, Inc.
38  * All rights reserved.
39  *
40  * This code is derived from software contributed to The NetBSD Foundation
41  * by Lennart Augustsson (lennart@augustsson.net).
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. All advertising materials mentioning features or use of this software
52  *    must display the following acknowledgement:
53  *        This product includes software developed by the NetBSD
54  *        Foundation, Inc. and its contributors.
55  * 4. Neither the name of The NetBSD Foundation nor the names of its
56  *    contributors may be used to endorse or promote products derived
57  *    from this software without specific prior written permission.
58  *
59  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
60  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
63  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
64  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
65  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
66  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
67  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
69  * POSSIBILITY OF SUCH DAMAGE.
70  */
71
72 #include <sys/cdefs.h>
73 __FBSDID("$FreeBSD$");
74
75 /*
76  * BWCT serial adapter driver
77  */
78
79 #include <sys/cdefs.h>
80
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/kernel.h>
84 #include <sys/module.h>
85 #include <sys/malloc.h>
86 #include <sys/bus.h>
87 #include <sys/ioccom.h>
88 #include <sys/fcntl.h>
89 #include <sys/conf.h>
90 #include <sys/serial.h>
91 #include <sys/tty.h>
92 #include <sys/clist.h>
93 #include <sys/file.h>
94
95 #include <sys/selinfo.h>
96
97 #include <sys/sysctl.h>
98
99 #include <dev/usb/usb.h>
100 #include <dev/usb/usbhid.h>
101
102 #include <dev/usb/usbdi.h>
103 #include <dev/usb/usbdi_util.h>
104 #include "usbdevs.h"
105
106 #include <dev/usb/ubser.h>
107
108 #ifdef USB_DEBUG
109 static int ubserdebug = 0;
110 SYSCTL_NODE(_hw_usb, OID_AUTO, ubser, CTLFLAG_RW, 0, "USB ubser");
111 SYSCTL_INT(_hw_usb_ubser, OID_AUTO, debug, CTLFLAG_RW,
112            &ubserdebug, 0, "ubser debug level");
113 #define DPRINTF(x)      do { \
114                                 if (ubserdebug) \
115                                         printf x; \
116                         } while (0)
117
118 #define DPRINTFN(n, x)  do { \
119                                 if (ubserdebug > (n)) \
120                                         printf x; \
121                         } while (0)
122 #else
123 #define DPRINTF(x)
124 #define DPRINTFN(n,x)
125 #endif
126
127 #define ISSET(t, f)     ((t) & (f))
128 #define SET(t, f)       (t) |= (f)
129 #define CLR(t, f)       (t) &= ~((unsigned)(f))
130
131 struct ubser_port {
132         int                      p_port;
133         struct ubser_softc      *p_sc;
134         usbd_xfer_handle         p_oxfer;       /* write request */
135         u_char                  *p_obuf;        /* write buffer */
136         struct tty              *p_tty;
137 };
138
139 struct ubser_softc {
140         device_t                sc_dev;
141         usbd_device_handle      sc_udev;
142         usbd_interface_handle   sc_iface;       /* data interface */
143         int                     sc_ifaceno;
144
145         int                     sc_refcnt;
146         u_char                  sc_dying;
147         u_char                  sc_opening;
148         int                     sc_state;
149         uint8_t                 sc_numser;
150
151         int                     sc_bulkin_no;   /* bulk in endpoint address */
152         usbd_pipe_handle        sc_bulkin_pipe; /* bulk in pipe */
153         usbd_xfer_handle        sc_ixfer;       /* read request */
154         u_char                  *sc_ibuf;       /* read buffer */
155         u_int                   sc_ibufsize;    /* read buffer size */
156         u_int                   sc_ibufsizepad; /* read buffer size padded */
157
158         int                     sc_bulkout_no;  /* bulk out endpoint address */
159         usbd_pipe_handle        sc_bulkout_pipe;/* bulk out pipe */
160         u_int                   sc_obufsize;    /* write buffer size */
161         u_int                   sc_opkthdrlen;  /* header length of
162                                                    output packet */
163
164         struct ubser_port       *sc_port;
165 };
166
167 static int ubserparam(struct tty *, struct termios *);
168 static void ubserstart(struct tty *);
169 static void ubserstop(struct tty *, int);
170 static usbd_status ubserstartread(struct ubser_softc *);
171 static void ubserreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
172 static void ubserwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
173 static void ubser_cleanup(struct ubser_softc *sc);
174
175 static t_break_t        ubserbreak;
176 static t_open_t         ubseropen;
177 static t_close_t        ubserclose;
178 static t_modem_t        ubsermodem;
179
180 static device_probe_t ubser_match;
181 static device_attach_t ubser_attach;
182 static device_detach_t ubser_detach;
183
184 static device_method_t ubser_methods[] = {
185         /* Device interface */
186         DEVMETHOD(device_probe,         ubser_match),
187         DEVMETHOD(device_attach,        ubser_attach),
188         DEVMETHOD(device_detach,        ubser_detach),
189
190         { 0, 0 }
191 };
192
193 static driver_t ubser_driver = {
194         "ubser",
195         ubser_methods,
196         sizeof(struct ubser_softc)
197 };
198
199 static devclass_t ubser_devclass;
200
201 static int
202 ubser_match(device_t self)
203 {
204         struct usb_attach_arg *uaa = device_get_ivars(self);
205         usb_string_descriptor_t us;
206         usb_interface_descriptor_t *id;
207         usb_device_descriptor_t *dd;
208         int err, size;
209
210         if (uaa->iface == NULL)
211                 return (UMATCH_NONE);
212
213         DPRINTFN(20,("ubser: vendor=0x%x, product=0x%x\n",
214                      uaa->vendor, uaa->product));
215
216         dd = usbd_get_device_descriptor(uaa->device);
217         if (dd == NULL) {
218                 printf("ubser: failed to get device descriptor\n");
219                 return (UMATCH_NONE);
220         }
221
222         id = usbd_get_interface_descriptor(uaa->iface);
223         if (id == NULL) {
224                 printf("ubser: failed to get interface descriptor\n");
225                 return (UMATCH_NONE);
226         }
227
228         err = usbd_get_string_desc(uaa->device, dd->iManufacturer, 0, &us,
229             &size);
230         if (err != 0)
231                 return (UMATCH_NONE);
232
233         /* check if this is a BWCT vendor specific ubser interface */
234         if (strcmp((char*)us.bString, "B\0W\0C\0T\0") == 0 &&
235             id->bInterfaceClass == 0xff && id->bInterfaceSubClass == 0x00)
236                 return (UMATCH_VENDOR_IFACESUBCLASS);
237
238         return (UMATCH_NONE);
239 }
240
241 static int
242 ubser_attach(device_t self)
243 {
244         struct ubser_softc *sc = device_get_softc(self);
245         struct usb_attach_arg *uaa = device_get_ivars(self);
246         usbd_device_handle udev = uaa->device;
247         usb_endpoint_descriptor_t *ed;
248         usb_interface_descriptor_t *id;
249         usb_device_request_t req;
250         struct tty *tp;
251         usbd_status err;
252         int i;
253         int alen;
254         uint8_t epcount;
255         struct ubser_port *pp;
256
257         sc->sc_dev = self;
258
259         DPRINTFN(10,("\nubser_attach: sc=%p\n", sc));
260
261         sc->sc_udev = udev = uaa->device;
262         sc->sc_iface = uaa->iface;
263         sc->sc_numser = 0;
264         sc->sc_port = NULL;
265
266         /* get interface index */
267         id = usbd_get_interface_descriptor(uaa->iface);
268         if (id == NULL) {
269                 printf("ubser: failed to get interface descriptor\n");
270                 return (UMATCH_NONE);
271         }
272         sc->sc_ifaceno = id->bInterfaceNumber;
273
274         /* get number of serials */
275         req.bmRequestType = UT_READ_VENDOR_INTERFACE;
276         req.bRequest = VENDOR_GET_NUMSER;
277         USETW(req.wValue, 0);
278         USETW(req.wIndex, sc->sc_ifaceno);
279         USETW(req.wLength, 1);
280         err = usbd_do_request_flags(udev, &req, &sc->sc_numser,
281             USBD_SHORT_XFER_OK, &alen, USBD_DEFAULT_TIMEOUT);
282         if (err) {
283                 device_printf(self, "failed to get number of serials\n");
284                 goto bad;
285         } else if (alen != 1) {
286                 device_printf(self, "bogus answer on get_numser\n");
287                 goto bad;
288         }
289         if (sc->sc_numser > MAX_SER)
290                 sc->sc_numser = MAX_SER;
291         device_printf(self, "found %i serials\n", sc->sc_numser);
292
293         sc->sc_port = malloc(sizeof(*sc->sc_port) * sc->sc_numser,
294             M_USBDEV, M_WAITOK);
295
296         /* find our bulk endpoints */
297         epcount = 0;
298         (void)usbd_endpoint_count(sc->sc_iface, &epcount);
299         sc->sc_bulkin_no = -1;
300         sc->sc_bulkout_no = -1;
301         for (i = 0; i < epcount; i++) {
302                 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
303                 if (ed == NULL) {
304                         device_printf(self, "couldn't get ep %d\n", i);
305                         return ENXIO;
306                 }
307                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
308                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
309                         sc->sc_bulkin_no = ed->bEndpointAddress;
310                         sc->sc_ibufsizepad = UGETW(ed->wMaxPacketSize);
311                         sc->sc_ibufsizepad = UGETW(ed->wMaxPacketSize) - 1;
312                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
313                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
314                         sc->sc_bulkout_no = ed->bEndpointAddress;
315                         sc->sc_obufsize = UGETW(ed->wMaxPacketSize) - 1;
316                         sc->sc_opkthdrlen = 1;
317                 }
318         }
319         if (sc->sc_bulkin_no == -1 || sc->sc_bulkout_no == -1) {
320                 device_printf(self, "could not find bulk in/out endpoint\n");
321                 sc->sc_dying = 1;
322                 goto bad;
323         }
324
325         /* Open the bulk pipes */
326         /* Bulk-in pipe */
327         err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
328                              &sc->sc_bulkin_pipe);
329         if (err) {
330                 device_printf(self, "open bulk in error (addr %d): %s\n",
331                     sc->sc_bulkin_no, usbd_errstr(err));
332                 goto fail_0;
333         }
334         /* Bulk-out pipe */
335         err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
336                              USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
337         if (err) {
338                 device_printf(self, "open bulk out error (addr %d): %s\n",
339                     sc->sc_bulkout_no, usbd_errstr(err));
340                 goto fail_1;
341         }
342
343         /* Allocate a request and an input buffer */
344         sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
345         if (sc->sc_ixfer == NULL) {
346                 goto fail_2;
347         }
348
349         sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
350                                         sc->sc_ibufsizepad);
351         if (sc->sc_ibuf == NULL) {
352                 goto fail_3;
353         }
354
355         for (i = 0; i < sc->sc_numser; i++) {
356                 pp = &sc->sc_port[i];
357                 pp->p_port = i;
358                 pp->p_sc = sc;
359                 tp = pp->p_tty = ttyalloc();
360                 tp->t_sc = pp;
361                 DPRINTF(("ubser_attach: tty_attach tp = %p\n", tp));
362                 tp->t_oproc = ubserstart;
363                 tp->t_param = ubserparam;
364                 tp->t_stop = ubserstop;
365                 tp->t_break = ubserbreak;
366                 tp->t_open = ubseropen;
367                 tp->t_close = ubserclose;
368                 tp->t_modem = ubsermodem;
369                 ttycreate(tp, 0, "y%r%r", device_get_unit(sc->sc_dev), i);
370         }
371
372
373         for (i = 0; i < sc->sc_numser; i++) {
374                 sc->sc_port[i].p_oxfer = NULL;
375                 sc->sc_port[i].p_obuf = NULL;
376         }
377         for (i = 0; i < sc->sc_numser; i++) {
378                 sc->sc_port[i].p_oxfer = usbd_alloc_xfer(sc->sc_udev);
379                 if (sc->sc_port[i].p_oxfer == NULL) {
380                         goto fail_4;
381                 }
382
383                 sc->sc_port[i].p_obuf = usbd_alloc_buffer(sc->sc_port[i].p_oxfer,
384                                                 sc->sc_obufsize +
385                                                 sc->sc_opkthdrlen);
386                 if (sc->sc_port[i].p_obuf == NULL) {
387                         goto fail_4;
388                 }
389         }
390
391         ubserstartread(sc);
392         return 0;
393
394 fail_4:
395         for (i = 0; i < sc->sc_numser; i++) {
396                 if (sc->sc_port[i].p_oxfer != NULL) {
397                         usbd_free_xfer(sc->sc_port[i].p_oxfer);
398                         sc->sc_port[i].p_oxfer = NULL;
399                 }
400         }
401 fail_3:
402         usbd_free_xfer(sc->sc_ixfer);
403         sc->sc_ixfer = NULL;
404 fail_2:
405         usbd_close_pipe(sc->sc_bulkout_pipe);
406         sc->sc_bulkout_pipe = NULL;
407 fail_1:
408         usbd_close_pipe(sc->sc_bulkin_pipe);
409         sc->sc_bulkin_pipe = NULL;
410 fail_0:
411         sc->sc_opening = 0;
412         wakeup(&sc->sc_opening);
413
414 bad:
415         ubser_cleanup(sc);
416         if (sc->sc_port != NULL) {
417                 for (i = 0; i < sc->sc_numser; i++) {
418                         pp = &sc->sc_port[i];
419                         if (pp->p_tty != NULL)
420                                 ttyfree(pp->p_tty);
421                 }
422                 free(sc->sc_port, M_USBDEV);
423                 sc->sc_port = NULL;
424         }
425
426         DPRINTF(("ubser_attach: ATTACH ERROR\n"));
427         return ENXIO;
428 }
429
430 static int
431 ubser_detach(device_t self)
432 {
433         struct ubser_softc *sc = device_get_softc(self);
434         int i;
435         struct ubser_port *pp;
436
437         DPRINTF(("ubser_detach: sc=%p\n", sc));
438
439         sc->sc_dying = 1;
440         for (i = 0; i < sc->sc_numser; i++) {
441                 pp = &sc->sc_port[i];
442                 if (pp->p_tty != NULL)
443                         ttygone(pp->p_tty);
444         }
445
446         if (sc->sc_bulkin_pipe != NULL)
447                 usbd_abort_pipe(sc->sc_bulkin_pipe);
448         if (sc->sc_bulkout_pipe != NULL)
449                 usbd_abort_pipe(sc->sc_bulkout_pipe);
450
451         if (sc->sc_port != NULL) {
452                 for (i = 0; i < sc->sc_numser; i++) {
453                         pp = &sc->sc_port[i];
454                         if (pp->p_tty != NULL)
455                                 ttyfree(pp->p_tty);
456                 }
457                 free(sc->sc_port, M_USBDEV);
458                 sc->sc_port = NULL;
459         }
460
461         if (--sc->sc_refcnt >= 0) {
462                 /* Wait for processes to go away. */
463                 usb_detach_wait(sc->sc_dev);
464         }
465
466         return (0);
467 }
468
469 static int
470 ubserparam(struct tty *tp, struct termios *t)
471 {
472         struct ubser_softc *sc;
473         struct ubser_port *pp;
474
475         pp = tp->t_sc;
476         sc = pp->p_sc;
477
478         if (sc->sc_dying)
479                 return (EIO);
480
481         DPRINTF(("ubserparam: sc = %p\n", sc));
482
483         /*
484          * The firmware on our devices can only do 8n1@9600bps
485          * without handshake.
486          * We refuse to accept other configurations.
487          */
488
489         /* enshure 9600bps */
490         switch (t->c_ospeed) {
491         case 9600:
492                 break;
493         default:
494                 return (EINVAL);
495         }
496
497         /* 2 stop bits not possible */
498         if (ISSET(t->c_cflag, CSTOPB))
499                 return (EINVAL);
500
501         /* XXX parity handling not possible with current firmware */
502         if (ISSET(t->c_cflag, PARENB))
503                 return (EINVAL);
504
505         /* we can only do 8 data bits */
506         switch (ISSET(t->c_cflag, CSIZE)) {
507         case CS8:
508                 break;
509         default:
510                 return (EINVAL);
511         }
512
513         /* we can't do any kind of hardware handshaking */
514         if ((t->c_cflag &
515             (CRTS_IFLOW | CDTR_IFLOW |CDSR_OFLOW |CCAR_OFLOW)) != 0)
516                 return (EINVAL);
517
518         /*
519          * XXX xon/xoff not supported by the firmware!
520          * This is handled within FreeBSD only and may overflow buffers
521          * because of delayed reaction due to device buffering.
522          */
523
524         ttsetwater(tp);
525
526         return (0);
527 }
528
529 static void
530 ubserstart(struct tty *tp)
531 {
532         struct ubser_softc *sc;
533         struct ubser_port *pp;
534         struct cblock *cbp;
535         usbd_status err;
536         u_char *data;
537         int cnt;
538         uint8_t serial;
539
540         pp = tp->t_sc;
541         sc = pp->p_sc;
542         serial = pp->p_port;
543         DPRINTF(("ubserstart: sc = %p, tp = %p\n", sc, tp));
544
545         if (sc->sc_dying)
546                 return;
547
548         if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
549                 ttwwakeup(tp);
550                 DPRINTF(("ubserstart: stopped\n"));
551                 return;
552         }
553
554         if (tp->t_outq.c_cc <= tp->t_olowat) {
555                 if (ISSET(tp->t_state, TS_SO_OLOWAT)) {
556                         CLR(tp->t_state, TS_SO_OLOWAT);
557                         wakeup(TSA_OLOWAT(tp));
558                 }
559                 selwakeuppri(&tp->t_wsel, TTIPRI);
560                 if (tp->t_outq.c_cc == 0) {
561                         if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
562                             TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
563                                 CLR(tp->t_state, TS_SO_OCOMPLETE);
564                                 wakeup(TSA_OCOMPLETE(tp));
565                         }
566                         return;
567                 }
568         }
569
570         /* Grab the first contiguous region of buffer space. */
571         data = tp->t_outq.c_cf;
572         cbp = (struct cblock *) ((intptr_t) tp->t_outq.c_cf & ~CROUND);
573         cnt = min((char *) (cbp+1) - tp->t_outq.c_cf, tp->t_outq.c_cc);
574
575         if (cnt == 0) {
576                 DPRINTF(("ubserstart: cnt == 0\n"));
577                 return;
578         }
579
580         SET(tp->t_state, TS_BUSY);
581
582         if (cnt + sc->sc_opkthdrlen > sc->sc_obufsize) {
583                 DPRINTF(("ubserstart: big buffer %d chars\n", cnt));
584                 cnt = sc->sc_obufsize;
585         }
586         sc->sc_port[serial].p_obuf[0] = serial;
587         memcpy(sc->sc_port[serial].p_obuf + sc->sc_opkthdrlen, data, cnt);
588
589
590         DPRINTF(("ubserstart: %d chars\n", cnt));
591         usbd_setup_xfer(sc->sc_port[serial].p_oxfer, sc->sc_bulkout_pipe,
592                         (usbd_private_handle)tp, sc->sc_port[serial].p_obuf,
593                         cnt + sc->sc_opkthdrlen,
594                         USBD_NO_COPY, USBD_NO_TIMEOUT, ubserwritecb);
595         /* What can we do on error? */
596         err = usbd_transfer(sc->sc_port[serial].p_oxfer);
597         if (err != USBD_IN_PROGRESS)
598                 printf("ubserstart: err=%s\n", usbd_errstr(err));
599
600         ttwwakeup(tp);
601 }
602
603 static void
604 ubserstop(struct tty *tp, int flag)
605 {
606         struct ubser_softc *sc;
607
608         sc = tp->t_sc;
609
610         DPRINTF(("ubserstop: %d\n", flag));
611
612         if (flag & FWRITE) {
613                 DPRINTF(("ubserstop: write\n"));
614                 if (ISSET(tp->t_state, TS_BUSY)) {
615                         /* XXX do what? */
616                         if (!ISSET(tp->t_state, TS_TTSTOP))
617                                 SET(tp->t_state, TS_FLUSH);
618                 }
619         }
620
621         DPRINTF(("ubserstop: done\n"));
622 }
623
624 static void
625 ubserwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
626 {
627         struct tty *tp;
628         struct ubser_softc *sc;
629         struct ubser_port *pp;
630         u_int32_t cc;
631
632         tp = (struct tty *)p;
633         pp = tp->t_sc;
634         sc = pp->p_sc;
635
636         DPRINTF(("ubserwritecb: status = %d\n", status));
637
638         if (status == USBD_CANCELLED || sc->sc_dying)
639                 goto error;
640
641         if (status != USBD_NORMAL_COMPLETION) {
642                 device_printf(sc->sc_dev, "ubserwritecb: %s\n",
643                     usbd_errstr(status));
644                 if (status == USBD_STALLED)
645                         usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
646                 /* XXX we should restart after some delay. */
647                 goto error;
648         }
649
650         usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
651         DPRINTF(("ubserwritecb: cc = %d\n", cc));
652         if (cc <= sc->sc_opkthdrlen) {
653                 device_printf(sc->sc_dev, "sent size too small, cc = %d\n",
654                     cc);
655                 goto error;
656         }
657
658         /* convert from USB bytes to tty bytes */
659         cc -= sc->sc_opkthdrlen;
660
661         CLR(tp->t_state, TS_BUSY);
662         if (ISSET(tp->t_state, TS_FLUSH))
663                 CLR(tp->t_state, TS_FLUSH);
664         else
665                 ndflush(&tp->t_outq, cc);
666         ttyld_start(tp);
667
668         return;
669
670 error:
671         CLR(tp->t_state, TS_BUSY);
672         return;
673 }
674
675 static usbd_status
676 ubserstartread(struct ubser_softc *sc)
677 {
678         usbd_status err;
679
680         DPRINTF(("ubserstartread: start\n"));
681
682         if (sc->sc_bulkin_pipe == NULL)
683                 return (USBD_NORMAL_COMPLETION);
684
685         usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
686                         (usbd_private_handle)sc,
687                         sc->sc_ibuf, sc->sc_ibufsizepad,
688                         USBD_SHORT_XFER_OK | USBD_NO_COPY,
689                         USBD_NO_TIMEOUT, ubserreadcb);
690
691         err = usbd_transfer(sc->sc_ixfer);
692         if (err != USBD_IN_PROGRESS) {
693                 DPRINTF(("ubserstartread: err = %s\n", usbd_errstr(err)));
694                 return (err);
695         }
696
697         return (USBD_NORMAL_COMPLETION);
698 }
699
700 static void
701 ubserreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
702 {
703         struct ubser_softc *sc = (struct ubser_softc *)p;
704         struct tty *tp;
705         usbd_status err;
706         u_int32_t cc;
707         u_char *cp;
708         int lostcc;
709
710         if (status == USBD_IOERROR) {
711                 device_printf(sc->sc_dev, "ubserreadcb: %s - restarting\n",
712                     usbd_errstr(status));
713                 goto resubmit;
714         }
715
716         DPRINTF(("ubserreadcb: status = %d\n", status));
717
718         if (status != USBD_NORMAL_COMPLETION) {
719                 if (status != USBD_CANCELLED) {
720                         device_printf(sc->sc_dev, "ubserreadcb: %s\n",
721                             usbd_errstr(status));
722                 }
723                 if (status == USBD_STALLED)
724                         usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
725                 return;
726         }
727
728         usbd_get_xfer_status(xfer, NULL, (void **)&cp, &cc, NULL);
729
730         DPRINTF(("ubserreadcb: got %d bytes from device\n", cc));
731         if (cc == 0)
732                 goto resubmit;
733
734         if (cc > sc->sc_ibufsizepad) {
735                 device_printf(sc->sc_dev, "invalid receive data size, %d chars\n",
736                     cc);
737                 goto resubmit;
738         }
739
740         /* parse header */
741         if (cc < 1)
742                 goto resubmit;
743         DPRINTF(("ubserreadcb: got %d chars for serial %d\n", cc - 1, *cp));
744         tp = sc->sc_port[*cp].p_tty;
745         cp++;
746         cc--;
747
748         if (cc < 1)
749                 goto resubmit;
750
751         if (!(tp->t_state & TS_ISOPEN)) /* drop data for unused serials */
752                 goto resubmit;
753
754         if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
755                 if (tp->t_rawq.c_cc + cc > tp->t_ihiwat
756                     && (tp->t_iflag & IXOFF)
757                     && !(tp->t_state & TS_TBLOCK))
758                         ttyblock(tp);
759                 lostcc = b_to_q((char *)cp, cc, &tp->t_rawq);
760                 tp->t_rawcc += cc;
761                 ttwakeup(tp);
762                 if (tp->t_state & TS_TTSTOP
763                     && (tp->t_iflag & IXANY
764                         || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
765                         tp->t_state &= ~TS_TTSTOP;
766                         tp->t_lflag &= ~FLUSHO;
767                         ubserstart(tp);
768                 }
769                 if (lostcc > 0)
770                         device_printf(sc->sc_dev, "lost %d chars\n", lostcc);
771         } else {
772                 /* Give characters to tty layer. */
773                 while (cc > 0) {
774                         DPRINTFN(7, ("ubserreadcb: char = 0x%02x\n", *cp));
775                         if (ttyld_rint(tp, *cp) == -1) {
776                                 /* XXX what should we do? */
777                                 device_printf(sc->sc_dev, "lost %d chars\n",
778                                     cc);
779                                 break;
780                         }
781                         cc--;
782                         cp++;
783                 }
784         }
785
786 resubmit:
787         err = ubserstartread(sc);
788         if (err) {
789                 device_printf(sc->sc_dev, "read start failed\n");
790                 /* XXX what should we do now? */
791         }
792
793 }
794
795 static void
796 ubser_cleanup(struct ubser_softc *sc)
797 {
798         int i;
799         struct ubser_port *pp;
800
801         DPRINTF(("ubser_cleanup: closing pipes\n"));
802
803         if (sc->sc_bulkin_pipe != NULL) {
804                 usbd_abort_pipe(sc->sc_bulkin_pipe);
805                 usbd_close_pipe(sc->sc_bulkin_pipe);
806                 sc->sc_bulkin_pipe = NULL;
807         }
808         if (sc->sc_bulkout_pipe != NULL) {
809                 usbd_abort_pipe(sc->sc_bulkout_pipe);
810                 usbd_close_pipe(sc->sc_bulkout_pipe);
811                 sc->sc_bulkout_pipe = NULL;
812         }
813         if (sc->sc_ixfer != NULL) {
814                 usbd_free_xfer(sc->sc_ixfer);
815                 sc->sc_ixfer = NULL;
816         }
817         for (i = 0; i < sc->sc_numser; i++) {
818                 pp = &sc->sc_port[i];
819                 if (pp->p_oxfer != NULL) {
820                         usbd_free_xfer(pp->p_oxfer);
821                         pp->p_oxfer = NULL;
822                 }
823         }
824 }
825
826 static int
827 ubseropen(struct tty *tp, struct cdev *dev)
828 {
829         struct ubser_softc *sc;
830         struct ubser_port *pp;
831
832         pp = tp->t_sc;
833         sc = pp->p_sc;
834
835         sc->sc_refcnt++;        /* XXX: wrong refcnt on error later on */
836         return (0);
837 }
838
839 static void
840 ubserclose(struct tty *tp)
841 {
842         struct ubser_softc *sc;
843         struct ubser_port *pp;
844
845         pp = tp->t_sc;
846         sc = pp->p_sc;
847         if (--sc->sc_refcnt < 0)
848                 usb_detach_wakeup(sc->sc_dev);
849 }
850
851 static void
852 ubserbreak(struct tty *tp, int sig)
853 {
854         usb_device_request_t req;
855         struct ubser_softc *sc;
856         struct ubser_port *pp;
857         int error;
858         int alen;
859
860         pp = tp->t_sc;
861         sc = pp->p_sc;
862         if (sig) {
863                 DPRINTF(("ubser_break: TIOCSBRK\n"));
864                 req.bmRequestType = UT_READ_VENDOR_INTERFACE;
865                 req.bRequest = VENDOR_SET_BREAK;
866                 USETW(req.wValue, pp->p_port);
867                 USETW(req.wIndex, sc->sc_ifaceno);
868                 USETW(req.wLength, 0);
869                 error = usbd_do_request_flags(sc->sc_udev, &req, &sc->sc_numser,
870                     USBD_SHORT_XFER_OK, &alen, USBD_DEFAULT_TIMEOUT);
871         }
872 }
873
874 static int
875 ubsermodem(struct tty *tp, int sigon, int sigoff)
876 {
877
878         return (SER_DTR | SER_RTS | SER_DCD);
879 }
880
881 MODULE_DEPEND(ubser, usb, 1, 1, 1);
882 DRIVER_MODULE(ubser, uhub, ubser_driver, ubser_devclass, usbd_driver_load, 0);