]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/serial/ubsa.c
usb: clean up empty lines in .c and .h files
[FreeBSD/FreeBSD.git] / sys / dev / usb / serial / ubsa.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD
3  *
4  * Copyright (c) 2002, Alexander Kabaev <kan.FreeBSD.org>.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 /*-
32  * Copyright (c) 2001 The NetBSD Foundation, Inc.
33  * All rights reserved.
34  *
35  * This code is derived from software contributed to The NetBSD Foundation
36  * by Ichiro FUKUHARA (ichiro@ichiro.org).
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
48  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
49  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
51  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57  * POSSIBILITY OF SUCH DAMAGE.
58  */
59
60 #include <sys/stdint.h>
61 #include <sys/stddef.h>
62 #include <sys/param.h>
63 #include <sys/queue.h>
64 #include <sys/types.h>
65 #include <sys/systm.h>
66 #include <sys/kernel.h>
67 #include <sys/bus.h>
68 #include <sys/module.h>
69 #include <sys/lock.h>
70 #include <sys/mutex.h>
71 #include <sys/condvar.h>
72 #include <sys/sysctl.h>
73 #include <sys/sx.h>
74 #include <sys/unistd.h>
75 #include <sys/callout.h>
76 #include <sys/malloc.h>
77 #include <sys/priv.h>
78
79 #include <dev/usb/usb.h>
80 #include <dev/usb/usbdi.h>
81 #include <dev/usb/usbdi_util.h>
82 #include "usbdevs.h"
83
84 #define USB_DEBUG_VAR ubsa_debug
85 #include <dev/usb/usb_debug.h>
86 #include <dev/usb/usb_process.h>
87
88 #include <dev/usb/serial/usb_serial.h>
89
90 #ifdef USB_DEBUG
91 static int ubsa_debug = 0;
92
93 static SYSCTL_NODE(_hw_usb, OID_AUTO, ubsa, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
94     "USB ubsa");
95 SYSCTL_INT(_hw_usb_ubsa, OID_AUTO, debug, CTLFLAG_RWTUN,
96     &ubsa_debug, 0, "ubsa debug level");
97 #endif
98
99 #define UBSA_BSIZE             1024     /* bytes */
100
101 #define UBSA_CONFIG_INDEX       0
102 #define UBSA_IFACE_INDEX        0
103
104 #define UBSA_REG_BAUDRATE       0x00
105 #define UBSA_REG_STOP_BITS      0x01
106 #define UBSA_REG_DATA_BITS      0x02
107 #define UBSA_REG_PARITY         0x03
108 #define UBSA_REG_DTR            0x0A
109 #define UBSA_REG_RTS            0x0B
110 #define UBSA_REG_BREAK          0x0C
111 #define UBSA_REG_FLOW_CTRL      0x10
112
113 #define UBSA_PARITY_NONE        0x00
114 #define UBSA_PARITY_EVEN        0x01
115 #define UBSA_PARITY_ODD         0x02
116 #define UBSA_PARITY_MARK        0x03
117 #define UBSA_PARITY_SPACE       0x04
118
119 #define UBSA_FLOW_NONE          0x0000
120 #define UBSA_FLOW_OCTS          0x0001
121 #define UBSA_FLOW_ODSR          0x0002
122 #define UBSA_FLOW_IDSR          0x0004
123 #define UBSA_FLOW_IDTR          0x0008
124 #define UBSA_FLOW_IRTS          0x0010
125 #define UBSA_FLOW_ORTS          0x0020
126 #define UBSA_FLOW_UNKNOWN       0x0040
127 #define UBSA_FLOW_OXON          0x0080
128 #define UBSA_FLOW_IXON          0x0100
129
130 /* line status register */
131 #define UBSA_LSR_TSRE           0x40    /* Transmitter empty: byte sent */
132 #define UBSA_LSR_TXRDY          0x20    /* Transmitter buffer empty */
133 #define UBSA_LSR_BI             0x10    /* Break detected */
134 #define UBSA_LSR_FE             0x08    /* Framing error: bad stop bit */
135 #define UBSA_LSR_PE             0x04    /* Parity error */
136 #define UBSA_LSR_OE             0x02    /* Overrun, lost incoming byte */
137 #define UBSA_LSR_RXRDY          0x01    /* Byte ready in Receive Buffer */
138 #define UBSA_LSR_RCV_MASK       0x1f    /* Mask for incoming data or error */
139
140 /* modem status register */
141 /* All deltas are from the last read of the MSR. */
142 #define UBSA_MSR_DCD            0x80    /* Current Data Carrier Detect */
143 #define UBSA_MSR_RI             0x40    /* Current Ring Indicator */
144 #define UBSA_MSR_DSR            0x20    /* Current Data Set Ready */
145 #define UBSA_MSR_CTS            0x10    /* Current Clear to Send */
146 #define UBSA_MSR_DDCD           0x08    /* DCD has changed state */
147 #define UBSA_MSR_TERI           0x04    /* RI has toggled low to high */
148 #define UBSA_MSR_DDSR           0x02    /* DSR has changed state */
149 #define UBSA_MSR_DCTS           0x01    /* CTS has changed state */
150
151 enum {
152         UBSA_BULK_DT_WR,
153         UBSA_BULK_DT_RD,
154         UBSA_INTR_DT_RD,
155         UBSA_N_TRANSFER,
156 };
157
158 struct ubsa_softc {
159         struct ucom_super_softc sc_super_ucom;
160         struct ucom_softc sc_ucom;
161
162         struct usb_xfer *sc_xfer[UBSA_N_TRANSFER];
163         struct usb_device *sc_udev;
164         struct mtx sc_mtx;
165
166         uint8_t sc_iface_no;            /* interface number */
167         uint8_t sc_iface_index;         /* interface index */
168         uint8_t sc_lsr;                 /* local status register */
169         uint8_t sc_msr;                 /* UBSA status register */
170 };
171
172 static device_probe_t ubsa_probe;
173 static device_attach_t ubsa_attach;
174 static device_detach_t ubsa_detach;
175 static void ubsa_free_softc(struct ubsa_softc *);
176
177 static usb_callback_t ubsa_write_callback;
178 static usb_callback_t ubsa_read_callback;
179 static usb_callback_t ubsa_intr_callback;
180
181 static void     ubsa_cfg_request(struct ubsa_softc *, uint8_t, uint16_t);
182 static void     ubsa_free(struct ucom_softc *);
183 static void     ubsa_cfg_set_dtr(struct ucom_softc *, uint8_t);
184 static void     ubsa_cfg_set_rts(struct ucom_softc *, uint8_t);
185 static void     ubsa_cfg_set_break(struct ucom_softc *, uint8_t);
186 static int      ubsa_pre_param(struct ucom_softc *, struct termios *);
187 static void     ubsa_cfg_param(struct ucom_softc *, struct termios *);
188 static void     ubsa_start_read(struct ucom_softc *);
189 static void     ubsa_stop_read(struct ucom_softc *);
190 static void     ubsa_start_write(struct ucom_softc *);
191 static void     ubsa_stop_write(struct ucom_softc *);
192 static void     ubsa_cfg_get_status(struct ucom_softc *, uint8_t *,
193                     uint8_t *);
194 static void     ubsa_poll(struct ucom_softc *ucom);
195
196 static const struct usb_config ubsa_config[UBSA_N_TRANSFER] = {
197         [UBSA_BULK_DT_WR] = {
198                 .type = UE_BULK,
199                 .endpoint = UE_ADDR_ANY,
200                 .direction = UE_DIR_OUT,
201                 .bufsize = UBSA_BSIZE,  /* bytes */
202                 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
203                 .callback = &ubsa_write_callback,
204         },
205
206         [UBSA_BULK_DT_RD] = {
207                 .type = UE_BULK,
208                 .endpoint = UE_ADDR_ANY,
209                 .direction = UE_DIR_IN,
210                 .bufsize = UBSA_BSIZE,  /* bytes */
211                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
212                 .callback = &ubsa_read_callback,
213         },
214
215         [UBSA_INTR_DT_RD] = {
216                 .type = UE_INTERRUPT,
217                 .endpoint = UE_ADDR_ANY,
218                 .direction = UE_DIR_IN,
219                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
220                 .bufsize = 0,   /* use wMaxPacketSize */
221                 .callback = &ubsa_intr_callback,
222         },
223 };
224
225 static const struct ucom_callback ubsa_callback = {
226         .ucom_cfg_get_status = &ubsa_cfg_get_status,
227         .ucom_cfg_set_dtr = &ubsa_cfg_set_dtr,
228         .ucom_cfg_set_rts = &ubsa_cfg_set_rts,
229         .ucom_cfg_set_break = &ubsa_cfg_set_break,
230         .ucom_cfg_param = &ubsa_cfg_param,
231         .ucom_pre_param = &ubsa_pre_param,
232         .ucom_start_read = &ubsa_start_read,
233         .ucom_stop_read = &ubsa_stop_read,
234         .ucom_start_write = &ubsa_start_write,
235         .ucom_stop_write = &ubsa_stop_write,
236         .ucom_poll = &ubsa_poll,
237         .ucom_free = &ubsa_free,
238 };
239
240 static const STRUCT_USB_HOST_ID ubsa_devs[] = {
241         /* AnyData ADU-500A */
242         {USB_VPI(USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_500A, 0)},
243         /* AnyData ADU-E100A/H */
244         {USB_VPI(USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_E100X, 0)},
245         /* Axesstel MV100H */
246         {USB_VPI(USB_VENDOR_AXESSTEL, USB_PRODUCT_AXESSTEL_DATAMODEM, 0)},
247         /* BELKIN F5U103 */
248         {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U103, 0)},
249         /* BELKIN F5U120 */
250         {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U120, 0)},
251         /* GoHubs GO-COM232 */
252         {USB_VPI(USB_VENDOR_ETEK, USB_PRODUCT_ETEK_1COM, 0)},
253         /* GoHubs GO-COM232 */
254         {USB_VPI(USB_VENDOR_GOHUBS, USB_PRODUCT_GOHUBS_GOCOM232, 0)},
255         /* Peracom */
256         {USB_VPI(USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_SERIAL1, 0)},
257 };
258
259 static device_method_t ubsa_methods[] = {
260         DEVMETHOD(device_probe, ubsa_probe),
261         DEVMETHOD(device_attach, ubsa_attach),
262         DEVMETHOD(device_detach, ubsa_detach),
263         DEVMETHOD_END
264 };
265
266 static devclass_t ubsa_devclass;
267
268 static driver_t ubsa_driver = {
269         .name = "ubsa",
270         .methods = ubsa_methods,
271         .size = sizeof(struct ubsa_softc),
272 };
273
274 DRIVER_MODULE(ubsa, uhub, ubsa_driver, ubsa_devclass, NULL, 0);
275 MODULE_DEPEND(ubsa, ucom, 1, 1, 1);
276 MODULE_DEPEND(ubsa, usb, 1, 1, 1);
277 MODULE_VERSION(ubsa, 1);
278 USB_PNP_HOST_INFO(ubsa_devs);
279
280 static int
281 ubsa_probe(device_t dev)
282 {
283         struct usb_attach_arg *uaa = device_get_ivars(dev);
284
285         if (uaa->usb_mode != USB_MODE_HOST) {
286                 return (ENXIO);
287         }
288         if (uaa->info.bConfigIndex != UBSA_CONFIG_INDEX) {
289                 return (ENXIO);
290         }
291         if (uaa->info.bIfaceIndex != UBSA_IFACE_INDEX) {
292                 return (ENXIO);
293         }
294         return (usbd_lookup_id_by_uaa(ubsa_devs, sizeof(ubsa_devs), uaa));
295 }
296
297 static int
298 ubsa_attach(device_t dev)
299 {
300         struct usb_attach_arg *uaa = device_get_ivars(dev);
301         struct ubsa_softc *sc = device_get_softc(dev);
302         int error;
303
304         DPRINTF("sc=%p\n", sc);
305
306         device_set_usb_desc(dev);
307         mtx_init(&sc->sc_mtx, "ubsa", NULL, MTX_DEF);
308         ucom_ref(&sc->sc_super_ucom);
309
310         sc->sc_udev = uaa->device;
311         sc->sc_iface_no = uaa->info.bIfaceNum;
312         sc->sc_iface_index = UBSA_IFACE_INDEX;
313
314         error = usbd_transfer_setup(uaa->device, &sc->sc_iface_index,
315             sc->sc_xfer, ubsa_config, UBSA_N_TRANSFER, sc, &sc->sc_mtx);
316
317         if (error) {
318                 DPRINTF("could not allocate all pipes\n");
319                 goto detach;
320         }
321         /* clear stall at first run */
322         mtx_lock(&sc->sc_mtx);
323         usbd_xfer_set_stall(sc->sc_xfer[UBSA_BULK_DT_WR]);
324         usbd_xfer_set_stall(sc->sc_xfer[UBSA_BULK_DT_RD]);
325         mtx_unlock(&sc->sc_mtx);
326
327         error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
328             &ubsa_callback, &sc->sc_mtx);
329         if (error) {
330                 DPRINTF("ucom_attach failed\n");
331                 goto detach;
332         }
333         ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
334
335         return (0);
336
337 detach:
338         ubsa_detach(dev);
339         return (ENXIO);
340 }
341
342 static int
343 ubsa_detach(device_t dev)
344 {
345         struct ubsa_softc *sc = device_get_softc(dev);
346
347         DPRINTF("sc=%p\n", sc);
348
349         ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
350         usbd_transfer_unsetup(sc->sc_xfer, UBSA_N_TRANSFER);
351
352         device_claim_softc(dev);
353
354         ubsa_free_softc(sc);
355
356         return (0);
357 }
358
359 UCOM_UNLOAD_DRAIN(ubsa);
360
361 static void
362 ubsa_free_softc(struct ubsa_softc *sc)
363 {
364         if (ucom_unref(&sc->sc_super_ucom)) {
365                 mtx_destroy(&sc->sc_mtx);
366                 device_free_softc(sc);
367         }
368 }
369
370 static void
371 ubsa_free(struct ucom_softc *ucom)
372 {
373         ubsa_free_softc(ucom->sc_parent);
374 }
375
376 static void
377 ubsa_cfg_request(struct ubsa_softc *sc, uint8_t index, uint16_t value)
378 {
379         struct usb_device_request req;
380         usb_error_t err;
381
382         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
383         req.bRequest = index;
384         USETW(req.wValue, value);
385         req.wIndex[0] = sc->sc_iface_no;
386         req.wIndex[1] = 0;
387         USETW(req.wLength, 0);
388
389         err = ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
390             &req, NULL, 0, 1000);
391         if (err) {
392                 DPRINTFN(0, "device request failed, err=%s "
393                     "(ignored)\n", usbd_errstr(err));
394         }
395 }
396
397 static void
398 ubsa_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
399 {
400         struct ubsa_softc *sc = ucom->sc_parent;
401
402         DPRINTF("onoff = %d\n", onoff);
403
404         ubsa_cfg_request(sc, UBSA_REG_DTR, onoff ? 1 : 0);
405 }
406
407 static void
408 ubsa_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
409 {
410         struct ubsa_softc *sc = ucom->sc_parent;
411
412         DPRINTF("onoff = %d\n", onoff);
413
414         ubsa_cfg_request(sc, UBSA_REG_RTS, onoff ? 1 : 0);
415 }
416
417 static void
418 ubsa_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
419 {
420         struct ubsa_softc *sc = ucom->sc_parent;
421
422         DPRINTF("onoff = %d\n", onoff);
423
424         ubsa_cfg_request(sc, UBSA_REG_BREAK, onoff ? 1 : 0);
425 }
426
427 static int
428 ubsa_pre_param(struct ucom_softc *ucom, struct termios *t)
429 {
430
431         DPRINTF("sc = %p\n", ucom->sc_parent);
432
433         switch (t->c_ospeed) {
434         case B0:
435         case B300:
436         case B600:
437         case B1200:
438         case B2400:
439         case B4800:
440         case B9600:
441         case B19200:
442         case B38400:
443         case B57600:
444         case B115200:
445         case B230400:
446                 break;
447         default:
448                 return (EINVAL);
449         }
450         return (0);
451 }
452
453 static void
454 ubsa_cfg_param(struct ucom_softc *ucom, struct termios *t)
455 {
456         struct ubsa_softc *sc = ucom->sc_parent;
457         uint16_t value = 0;
458
459         DPRINTF("sc = %p\n", sc);
460
461         switch (t->c_ospeed) {
462         case B0:
463                 ubsa_cfg_request(sc, UBSA_REG_FLOW_CTRL, 0);
464                 ubsa_cfg_set_dtr(&sc->sc_ucom, 0);
465                 ubsa_cfg_set_rts(&sc->sc_ucom, 0);
466                 break;
467         case B300:
468         case B600:
469         case B1200:
470         case B2400:
471         case B4800:
472         case B9600:
473         case B19200:
474         case B38400:
475         case B57600:
476         case B115200:
477         case B230400:
478                 value = B230400 / t->c_ospeed;
479                 ubsa_cfg_request(sc, UBSA_REG_BAUDRATE, value);
480                 break;
481         default:
482                 return;
483         }
484
485         if (t->c_cflag & PARENB)
486                 value = (t->c_cflag & PARODD) ? UBSA_PARITY_ODD : UBSA_PARITY_EVEN;
487         else
488                 value = UBSA_PARITY_NONE;
489
490         ubsa_cfg_request(sc, UBSA_REG_PARITY, value);
491
492         switch (t->c_cflag & CSIZE) {
493         case CS5:
494                 value = 0;
495                 break;
496         case CS6:
497                 value = 1;
498                 break;
499         case CS7:
500                 value = 2;
501                 break;
502         default:
503         case CS8:
504                 value = 3;
505                 break;
506         }
507
508         ubsa_cfg_request(sc, UBSA_REG_DATA_BITS, value);
509
510         value = (t->c_cflag & CSTOPB) ? 1 : 0;
511
512         ubsa_cfg_request(sc, UBSA_REG_STOP_BITS, value);
513
514         value = 0;
515         if (t->c_cflag & CRTSCTS)
516                 value |= UBSA_FLOW_OCTS | UBSA_FLOW_IRTS;
517
518         if (t->c_iflag & (IXON | IXOFF))
519                 value |= UBSA_FLOW_OXON | UBSA_FLOW_IXON;
520
521         ubsa_cfg_request(sc, UBSA_REG_FLOW_CTRL, value);
522 }
523
524 static void
525 ubsa_start_read(struct ucom_softc *ucom)
526 {
527         struct ubsa_softc *sc = ucom->sc_parent;
528
529         /* start interrupt endpoint */
530         usbd_transfer_start(sc->sc_xfer[UBSA_INTR_DT_RD]);
531
532         /* start read endpoint */
533         usbd_transfer_start(sc->sc_xfer[UBSA_BULK_DT_RD]);
534 }
535
536 static void
537 ubsa_stop_read(struct ucom_softc *ucom)
538 {
539         struct ubsa_softc *sc = ucom->sc_parent;
540
541         /* stop interrupt endpoint */
542         usbd_transfer_stop(sc->sc_xfer[UBSA_INTR_DT_RD]);
543
544         /* stop read endpoint */
545         usbd_transfer_stop(sc->sc_xfer[UBSA_BULK_DT_RD]);
546 }
547
548 static void
549 ubsa_start_write(struct ucom_softc *ucom)
550 {
551         struct ubsa_softc *sc = ucom->sc_parent;
552
553         usbd_transfer_start(sc->sc_xfer[UBSA_BULK_DT_WR]);
554 }
555
556 static void
557 ubsa_stop_write(struct ucom_softc *ucom)
558 {
559         struct ubsa_softc *sc = ucom->sc_parent;
560
561         usbd_transfer_stop(sc->sc_xfer[UBSA_BULK_DT_WR]);
562 }
563
564 static void
565 ubsa_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
566 {
567         struct ubsa_softc *sc = ucom->sc_parent;
568
569         DPRINTF("\n");
570
571         *lsr = sc->sc_lsr;
572         *msr = sc->sc_msr;
573 }
574
575 static void
576 ubsa_write_callback(struct usb_xfer *xfer, usb_error_t error)
577 {
578         struct ubsa_softc *sc = usbd_xfer_softc(xfer);
579         struct usb_page_cache *pc;
580         uint32_t actlen;
581
582         switch (USB_GET_STATE(xfer)) {
583         case USB_ST_SETUP:
584         case USB_ST_TRANSFERRED:
585 tr_setup:
586                 pc = usbd_xfer_get_frame(xfer, 0);
587                 if (ucom_get_data(&sc->sc_ucom, pc, 0,
588                     UBSA_BSIZE, &actlen)) {
589                         usbd_xfer_set_frame_len(xfer, 0, actlen);
590                         usbd_transfer_submit(xfer);
591                 }
592                 return;
593
594         default:                        /* Error */
595                 if (error != USB_ERR_CANCELLED) {
596                         /* try to clear stall first */
597                         usbd_xfer_set_stall(xfer);
598                         goto tr_setup;
599                 }
600                 return;
601         }
602 }
603
604 static void
605 ubsa_read_callback(struct usb_xfer *xfer, usb_error_t error)
606 {
607         struct ubsa_softc *sc = usbd_xfer_softc(xfer);
608         struct usb_page_cache *pc;
609         int actlen;
610
611         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
612
613         switch (USB_GET_STATE(xfer)) {
614         case USB_ST_TRANSFERRED:
615                 pc = usbd_xfer_get_frame(xfer, 0);
616                 ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
617
618         case USB_ST_SETUP:
619 tr_setup:
620                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
621                 usbd_transfer_submit(xfer);
622                 return;
623
624         default:                        /* Error */
625                 if (error != USB_ERR_CANCELLED) {
626                         /* try to clear stall first */
627                         usbd_xfer_set_stall(xfer);
628                         goto tr_setup;
629                 }
630                 return;
631         }
632 }
633
634 static void
635 ubsa_intr_callback(struct usb_xfer *xfer, usb_error_t error)
636 {
637         struct ubsa_softc *sc = usbd_xfer_softc(xfer);
638         struct usb_page_cache *pc;
639         uint8_t buf[4];
640         int actlen;
641
642         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
643
644         switch (USB_GET_STATE(xfer)) {
645         case USB_ST_TRANSFERRED:
646
647                 if (actlen >= (int)sizeof(buf)) {
648                         pc = usbd_xfer_get_frame(xfer, 0);
649                         usbd_copy_out(pc, 0, buf, sizeof(buf));
650
651                         /*
652                          * MSR bits need translation from ns16550 to SER_* values.
653                          * LSR bits are ns16550 in hardware and ucom.
654                          */
655                         sc->sc_msr = 0;
656                         if (buf[3] & UBSA_MSR_CTS)
657                                 sc->sc_msr |= SER_CTS;
658                         if (buf[3] & UBSA_MSR_DCD)
659                                 sc->sc_msr |= SER_DCD;
660                         if (buf[3] & UBSA_MSR_RI)
661                                 sc->sc_msr |= SER_RI;
662                         if (buf[3] & UBSA_MSR_DSR)
663                                 sc->sc_msr |= SER_DSR;
664                         sc->sc_lsr = buf[2];
665
666                         DPRINTF("lsr = 0x%02x, msr = 0x%02x\n",
667                             sc->sc_lsr, sc->sc_msr);
668
669                         ucom_status_change(&sc->sc_ucom);
670                 } else {
671                         DPRINTF("ignoring short packet, %d bytes\n", actlen);
672                 }
673                 /* FALLTHROUGH */
674         case USB_ST_SETUP:
675 tr_setup:
676                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
677                 usbd_transfer_submit(xfer);
678                 return;
679
680         default:                        /* Error */
681                 if (error != USB_ERR_CANCELLED) {
682                         /* try to clear stall first */
683                         usbd_xfer_set_stall(xfer);
684                         goto tr_setup;
685                 }
686                 return;
687         }
688 }
689
690 static void
691 ubsa_poll(struct ucom_softc *ucom)
692 {
693         struct ubsa_softc *sc = ucom->sc_parent;
694         usbd_transfer_poll(sc->sc_xfer, UBSA_N_TRANSFER);
695
696 }