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