xref: /freebsd/sys/dev/usb/serial/umoscom.c (revision b3aaa0cc21c63d388230c7ef2a80abd631ff20d5)
1 /* $FreeBSD$ */
2 /*	$OpenBSD: umoscom.c,v 1.2 2006/10/26 06:02:43 jsg Exp $	*/
3 
4 /*
5  * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "usbdevs.h"
21 #include <dev/usb/usb.h>
22 #include <dev/usb/usb_mfunc.h>
23 #include <dev/usb/usb_error.h>
24 #include <dev/usb/usb_cdc.h>
25 
26 #define	USB_DEBUG_VAR umoscom_debug
27 
28 #include <dev/usb/usb_core.h>
29 #include <dev/usb/usb_debug.h>
30 #include <dev/usb/usb_process.h>
31 #include <dev/usb/usb_request.h>
32 #include <dev/usb/usb_lookup.h>
33 #include <dev/usb/usb_util.h>
34 #include <dev/usb/usb_busdma.h>
35 
36 #include <dev/usb/serial/usb_serial.h>
37 
38 #if USB_DEBUG
39 static int umoscom_debug = 0;
40 
41 SYSCTL_NODE(_hw_usb2, OID_AUTO, umoscom, CTLFLAG_RW, 0, "USB umoscom");
42 SYSCTL_INT(_hw_usb2_umoscom, OID_AUTO, debug, CTLFLAG_RW,
43     &umoscom_debug, 0, "Debug level");
44 #endif
45 
46 #define	UMOSCOM_BUFSIZE	       1024	/* bytes */
47 
48 #define	UMOSCOM_CONFIG_INDEX	0
49 #define	UMOSCOM_IFACE_INDEX	0
50 
51 /* interrupt packet */
52 #define	UMOSCOM_IIR_RLS		0x06
53 #define	UMOSCOM_IIR_RDA		0x04
54 #define	UMOSCOM_IIR_CTI		0x0c
55 #define	UMOSCOM_IIR_THR		0x02
56 #define	UMOSCOM_IIR_MS		0x00
57 
58 /* registers */
59 #define	UMOSCOM_READ		0x0d
60 #define	UMOSCOM_WRITE		0x0e
61 #define	UMOSCOM_UART_REG	0x0300
62 #define	UMOSCOM_VEND_REG	0x0000
63 
64 #define	UMOSCOM_TXBUF		0x00	/* Write */
65 #define	UMOSCOM_RXBUF		0x00	/* Read */
66 #define	UMOSCOM_INT		0x01
67 #define	UMOSCOM_FIFO		0x02	/* Write */
68 #define	UMOSCOM_ISR		0x02	/* Read */
69 #define	UMOSCOM_LCR		0x03
70 #define	UMOSCOM_MCR		0x04
71 #define	UMOSCOM_LSR		0x05
72 #define	UMOSCOM_MSR		0x06
73 #define	UMOSCOM_SCRATCH		0x07
74 #define	UMOSCOM_DIV_LO		0x08
75 #define	UMOSCOM_DIV_HI		0x09
76 #define	UMOSCOM_EFR		0x0a
77 #define	UMOSCOM_XON1		0x0b
78 #define	UMOSCOM_XON2		0x0c
79 #define	UMOSCOM_XOFF1		0x0d
80 #define	UMOSCOM_XOFF2		0x0e
81 
82 #define	UMOSCOM_BAUDLO		0x00
83 #define	UMOSCOM_BAUDHI		0x01
84 
85 #define	UMOSCOM_INT_RXEN	0x01
86 #define	UMOSCOM_INT_TXEN	0x02
87 #define	UMOSCOM_INT_RSEN	0x04
88 #define	UMOSCOM_INT_MDMEM	0x08
89 #define	UMOSCOM_INT_SLEEP	0x10
90 #define	UMOSCOM_INT_XOFF	0x20
91 #define	UMOSCOM_INT_RTS		0x40
92 
93 #define	UMOSCOM_FIFO_EN		0x01
94 #define	UMOSCOM_FIFO_RXCLR	0x02
95 #define	UMOSCOM_FIFO_TXCLR	0x04
96 #define	UMOSCOM_FIFO_DMA_BLK	0x08
97 #define	UMOSCOM_FIFO_TXLVL_MASK	0x30
98 #define	UMOSCOM_FIFO_TXLVL_8	0x00
99 #define	UMOSCOM_FIFO_TXLVL_16	0x10
100 #define	UMOSCOM_FIFO_TXLVL_32	0x20
101 #define	UMOSCOM_FIFO_TXLVL_56	0x30
102 #define	UMOSCOM_FIFO_RXLVL_MASK	0xc0
103 #define	UMOSCOM_FIFO_RXLVL_8	0x00
104 #define	UMOSCOM_FIFO_RXLVL_16	0x40
105 #define	UMOSCOM_FIFO_RXLVL_56	0x80
106 #define	UMOSCOM_FIFO_RXLVL_80	0xc0
107 
108 #define	UMOSCOM_ISR_MDM		0x00
109 #define	UMOSCOM_ISR_NONE	0x01
110 #define	UMOSCOM_ISR_TX		0x02
111 #define	UMOSCOM_ISR_RX		0x04
112 #define	UMOSCOM_ISR_LINE	0x06
113 #define	UMOSCOM_ISR_RXTIMEOUT	0x0c
114 #define	UMOSCOM_ISR_RX_XOFF	0x10
115 #define	UMOSCOM_ISR_RTSCTS	0x20
116 #define	UMOSCOM_ISR_FIFOEN	0xc0
117 
118 #define	UMOSCOM_LCR_DBITS(x)	((x) - 5)
119 #define	UMOSCOM_LCR_STOP_BITS_1	0x00
120 #define	UMOSCOM_LCR_STOP_BITS_2	0x04	/* 2 if 6-8 bits/char or 1.5 if 5 */
121 #define	UMOSCOM_LCR_PARITY_NONE	0x00
122 #define	UMOSCOM_LCR_PARITY_ODD	0x08
123 #define	UMOSCOM_LCR_PARITY_EVEN	0x18
124 #define	UMOSCOM_LCR_BREAK	0x40
125 #define	UMOSCOM_LCR_DIVLATCH_EN	0x80
126 
127 #define	UMOSCOM_MCR_DTR		0x01
128 #define	UMOSCOM_MCR_RTS		0x02
129 #define	UMOSCOM_MCR_LOOP	0x04
130 #define	UMOSCOM_MCR_INTEN	0x08
131 #define	UMOSCOM_MCR_LOOPBACK	0x10
132 #define	UMOSCOM_MCR_XONANY	0x20
133 #define	UMOSCOM_MCR_IRDA_EN	0x40
134 #define	UMOSCOM_MCR_BAUD_DIV4	0x80
135 
136 #define	UMOSCOM_LSR_RXDATA	0x01
137 #define	UMOSCOM_LSR_RXOVER	0x02
138 #define	UMOSCOM_LSR_RXPAR_ERR	0x04
139 #define	UMOSCOM_LSR_RXFRM_ERR	0x08
140 #define	UMOSCOM_LSR_RXBREAK	0x10
141 #define	UMOSCOM_LSR_TXEMPTY	0x20
142 #define	UMOSCOM_LSR_TXALLEMPTY	0x40
143 #define	UMOSCOM_LSR_TXFIFO_ERR	0x80
144 
145 #define	UMOSCOM_MSR_CTS_CHG	0x01
146 #define	UMOSCOM_MSR_DSR_CHG	0x02
147 #define	UMOSCOM_MSR_RI_CHG	0x04
148 #define	UMOSCOM_MSR_CD_CHG	0x08
149 #define	UMOSCOM_MSR_CTS		0x10
150 #define	UMOSCOM_MSR_RTS		0x20
151 #define	UMOSCOM_MSR_RI		0x40
152 #define	UMOSCOM_MSR_CD		0x80
153 
154 #define	UMOSCOM_BAUD_REF	115200
155 
156 enum {
157 	UMOSCOM_BULK_DT_WR,
158 	UMOSCOM_BULK_DT_RD,
159 	UMOSCOM_INTR_DT_RD,
160 	UMOSCOM_N_TRANSFER,
161 };
162 
163 struct umoscom_softc {
164 	struct usb2_com_super_softc sc_super_ucom;
165 	struct usb2_com_softc sc_ucom;
166 
167 	struct usb2_xfer *sc_xfer[UMOSCOM_N_TRANSFER];
168 	struct usb2_device *sc_udev;
169 
170 	uint8_t	sc_mcr;
171 	uint8_t	sc_lcr;
172 };
173 
174 /* prototypes */
175 
176 static device_probe_t umoscom_probe;
177 static device_attach_t umoscom_attach;
178 static device_detach_t umoscom_detach;
179 
180 static usb2_callback_t umoscom_write_callback;
181 static usb2_callback_t umoscom_read_callback;
182 static usb2_callback_t umoscom_intr_callback;
183 
184 static void	umoscom_cfg_open(struct usb2_com_softc *);
185 static void	umoscom_cfg_close(struct usb2_com_softc *);
186 static void	umoscom_cfg_set_break(struct usb2_com_softc *, uint8_t);
187 static void	umoscom_cfg_set_dtr(struct usb2_com_softc *, uint8_t);
188 static void	umoscom_cfg_set_rts(struct usb2_com_softc *, uint8_t);
189 static int	umoscom_pre_param(struct usb2_com_softc *, struct termios *);
190 static void	umoscom_cfg_param(struct usb2_com_softc *, struct termios *);
191 static void	umoscom_cfg_get_status(struct usb2_com_softc *, uint8_t *,
192 		    uint8_t *);
193 static void	umoscom_cfg_write(struct umoscom_softc *, uint16_t, uint16_t);
194 static uint8_t	umoscom_cfg_read(struct umoscom_softc *, uint16_t);
195 static void	umoscom_start_read(struct usb2_com_softc *);
196 static void	umoscom_stop_read(struct usb2_com_softc *);
197 static void	umoscom_start_write(struct usb2_com_softc *);
198 static void	umoscom_stop_write(struct usb2_com_softc *);
199 
200 static const struct usb2_config umoscom_config_data[UMOSCOM_N_TRANSFER] = {
201 
202 	[UMOSCOM_BULK_DT_WR] = {
203 		.type = UE_BULK,
204 		.endpoint = UE_ADDR_ANY,
205 		.direction = UE_DIR_OUT,
206 		.mh.bufsize = UMOSCOM_BUFSIZE,
207 		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
208 		.mh.callback = &umoscom_write_callback,
209 	},
210 
211 	[UMOSCOM_BULK_DT_RD] = {
212 		.type = UE_BULK,
213 		.endpoint = UE_ADDR_ANY,
214 		.direction = UE_DIR_IN,
215 		.mh.bufsize = UMOSCOM_BUFSIZE,
216 		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
217 		.mh.callback = &umoscom_read_callback,
218 	},
219 
220 	[UMOSCOM_INTR_DT_RD] = {
221 		.type = UE_INTERRUPT,
222 		.endpoint = UE_ADDR_ANY,
223 		.direction = UE_DIR_IN,
224 		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
225 		.mh.bufsize = 0,	/* use wMaxPacketSize */
226 		.mh.callback = &umoscom_intr_callback,
227 	},
228 };
229 
230 static const struct usb2_com_callback umoscom_callback = {
231 	/* configuration callbacks */
232 	.usb2_com_cfg_get_status = &umoscom_cfg_get_status,
233 	.usb2_com_cfg_set_dtr = &umoscom_cfg_set_dtr,
234 	.usb2_com_cfg_set_rts = &umoscom_cfg_set_rts,
235 	.usb2_com_cfg_set_break = &umoscom_cfg_set_break,
236 	.usb2_com_cfg_param = &umoscom_cfg_param,
237 	.usb2_com_cfg_open = &umoscom_cfg_open,
238 	.usb2_com_cfg_close = &umoscom_cfg_close,
239 
240 	/* other callbacks */
241 	.usb2_com_pre_param = &umoscom_pre_param,
242 	.usb2_com_start_read = &umoscom_start_read,
243 	.usb2_com_stop_read = &umoscom_stop_read,
244 	.usb2_com_start_write = &umoscom_start_write,
245 	.usb2_com_stop_write = &umoscom_stop_write,
246 };
247 
248 static device_method_t umoscom_methods[] = {
249 	DEVMETHOD(device_probe, umoscom_probe),
250 	DEVMETHOD(device_attach, umoscom_attach),
251 	DEVMETHOD(device_detach, umoscom_detach),
252 	{0, 0}
253 };
254 
255 static devclass_t umoscom_devclass;
256 
257 static driver_t umoscom_driver = {
258 	.name = "umoscom",
259 	.methods = umoscom_methods,
260 	.size = sizeof(struct umoscom_softc),
261 };
262 
263 DRIVER_MODULE(umoscom, ushub, umoscom_driver, umoscom_devclass, NULL, 0);
264 MODULE_DEPEND(umoscom, ucom, 1, 1, 1);
265 MODULE_DEPEND(umoscom, usb, 1, 1, 1);
266 
267 static const struct usb2_device_id umoscom_devs[] = {
268 	{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7703, 0)}
269 };
270 
271 static int
272 umoscom_probe(device_t dev)
273 {
274 	struct usb2_attach_arg *uaa = device_get_ivars(dev);
275 
276 	if (uaa->usb2_mode != USB_MODE_HOST) {
277 		return (ENXIO);
278 	}
279 	if (uaa->info.bConfigIndex != UMOSCOM_CONFIG_INDEX) {
280 		return (ENXIO);
281 	}
282 	if (uaa->info.bIfaceIndex != UMOSCOM_IFACE_INDEX) {
283 		return (ENXIO);
284 	}
285 	return (usb2_lookup_id_by_uaa(umoscom_devs, sizeof(umoscom_devs), uaa));
286 }
287 
288 static int
289 umoscom_attach(device_t dev)
290 {
291 	struct usb2_attach_arg *uaa = device_get_ivars(dev);
292 	struct umoscom_softc *sc = device_get_softc(dev);
293 	int error;
294 	uint8_t iface_index;
295 
296 	sc->sc_udev = uaa->device;
297 	sc->sc_mcr = 0x08;		/* enable interrupts */
298 
299 	/* XXX the device doesn't provide any ID string, so set a static one */
300 	device_set_desc(dev, "MOSCHIP USB Serial Port Adapter");
301 	device_printf(dev, "<MOSCHIP USB Serial Port Adapter>\n");
302 
303 	iface_index = UMOSCOM_IFACE_INDEX;
304 	error = usb2_transfer_setup(uaa->device, &iface_index,
305 	    sc->sc_xfer, umoscom_config_data,
306 	    UMOSCOM_N_TRANSFER, sc, &Giant);
307 
308 	if (error) {
309 		goto detach;
310 	}
311 	/* clear stall at first run */
312 	usb2_transfer_set_stall(sc->sc_xfer[UMOSCOM_BULK_DT_WR]);
313 	usb2_transfer_set_stall(sc->sc_xfer[UMOSCOM_BULK_DT_RD]);
314 
315 	error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
316 	    &umoscom_callback, &Giant);
317 	if (error) {
318 		goto detach;
319 	}
320 	return (0);
321 
322 detach:
323 	device_printf(dev, "attach error: %s\n", usb2_errstr(error));
324 	umoscom_detach(dev);
325 	return (ENXIO);
326 }
327 
328 static int
329 umoscom_detach(device_t dev)
330 {
331 	struct umoscom_softc *sc = device_get_softc(dev);
332 
333 	mtx_lock(&Giant);
334 
335 	mtx_unlock(&Giant);
336 
337 	usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
338 
339 	usb2_transfer_unsetup(sc->sc_xfer, UMOSCOM_N_TRANSFER);
340 
341 	return (0);
342 }
343 
344 static void
345 umoscom_cfg_open(struct usb2_com_softc *ucom)
346 {
347 	struct umoscom_softc *sc = ucom->sc_parent;
348 
349 	DPRINTF("\n");
350 
351 	/* Purge FIFOs or odd things happen */
352 	umoscom_cfg_write(sc, UMOSCOM_FIFO, 0x00 | UMOSCOM_UART_REG);
353 
354 	/* Enable FIFO */
355 	umoscom_cfg_write(sc, UMOSCOM_FIFO, UMOSCOM_FIFO_EN |
356 	    UMOSCOM_FIFO_RXCLR | UMOSCOM_FIFO_TXCLR |
357 	    UMOSCOM_FIFO_DMA_BLK | UMOSCOM_FIFO_RXLVL_MASK |
358 	    UMOSCOM_UART_REG);
359 
360 	/* Enable Interrupt Registers */
361 	umoscom_cfg_write(sc, UMOSCOM_INT, 0x0C | UMOSCOM_UART_REG);
362 
363 	/* Magic */
364 	umoscom_cfg_write(sc, 0x01, 0x08);
365 
366 	/* Magic */
367 	umoscom_cfg_write(sc, 0x00, 0x02);
368 }
369 
370 static void
371 umoscom_cfg_close(struct usb2_com_softc *ucom)
372 {
373 	return;
374 }
375 
376 static void
377 umoscom_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
378 {
379 	struct umoscom_softc *sc = ucom->sc_parent;
380 	uint16_t val;
381 
382 	val = sc->sc_lcr;
383 	if (onoff)
384 		val |= UMOSCOM_LCR_BREAK;
385 
386 	umoscom_cfg_write(sc, UMOSCOM_LCR, val | UMOSCOM_UART_REG);
387 }
388 
389 static void
390 umoscom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
391 {
392 	struct umoscom_softc *sc = ucom->sc_parent;
393 
394 	if (onoff)
395 		sc->sc_mcr |= UMOSCOM_MCR_DTR;
396 	else
397 		sc->sc_mcr &= ~UMOSCOM_MCR_DTR;
398 
399 	umoscom_cfg_write(sc, UMOSCOM_MCR, sc->sc_mcr | UMOSCOM_UART_REG);
400 }
401 
402 static void
403 umoscom_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
404 {
405 	struct umoscom_softc *sc = ucom->sc_parent;
406 
407 	if (onoff)
408 		sc->sc_mcr |= UMOSCOM_MCR_RTS;
409 	else
410 		sc->sc_mcr &= ~UMOSCOM_MCR_RTS;
411 
412 	umoscom_cfg_write(sc, UMOSCOM_MCR, sc->sc_mcr | UMOSCOM_UART_REG);
413 }
414 
415 static int
416 umoscom_pre_param(struct usb2_com_softc *ucom, struct termios *t)
417 {
418 	if ((t->c_ospeed <= 1) || (t->c_ospeed > 115200))
419 		return (EINVAL);
420 
421 	return (0);
422 }
423 
424 static void
425 umoscom_cfg_param(struct usb2_com_softc *ucom, struct termios *t)
426 {
427 	struct umoscom_softc *sc = ucom->sc_parent;
428 	uint16_t data;
429 
430 	DPRINTF("speed=%d\n", t->c_ospeed);
431 
432 	data = ((uint32_t)UMOSCOM_BAUD_REF) / ((uint32_t)t->c_ospeed);
433 
434 	if (data == 0) {
435 		DPRINTF("invalid baud rate!\n");
436 		return;
437 	}
438 	umoscom_cfg_write(sc, UMOSCOM_LCR,
439 	    UMOSCOM_LCR_DIVLATCH_EN | UMOSCOM_UART_REG);
440 
441 	umoscom_cfg_write(sc, UMOSCOM_BAUDLO,
442 	    (data & 0xFF) | UMOSCOM_UART_REG);
443 
444 	umoscom_cfg_write(sc, UMOSCOM_BAUDHI,
445 	    ((data >> 8) & 0xFF) | UMOSCOM_UART_REG);
446 
447 	if (t->c_cflag & CSTOPB)
448 		data = UMOSCOM_LCR_STOP_BITS_2;
449 	else
450 		data = UMOSCOM_LCR_STOP_BITS_1;
451 
452 	if (t->c_cflag & PARENB) {
453 		if (t->c_cflag & PARODD)
454 			data |= UMOSCOM_LCR_PARITY_ODD;
455 		else
456 			data |= UMOSCOM_LCR_PARITY_EVEN;
457 	} else
458 		data |= UMOSCOM_LCR_PARITY_NONE;
459 
460 	switch (t->c_cflag & CSIZE) {
461 	case CS5:
462 		data |= UMOSCOM_LCR_DBITS(5);
463 		break;
464 	case CS6:
465 		data |= UMOSCOM_LCR_DBITS(6);
466 		break;
467 	case CS7:
468 		data |= UMOSCOM_LCR_DBITS(7);
469 		break;
470 	case CS8:
471 		data |= UMOSCOM_LCR_DBITS(8);
472 		break;
473 	}
474 
475 	sc->sc_lcr = data;
476 	umoscom_cfg_write(sc, UMOSCOM_LCR, data | UMOSCOM_UART_REG);
477 }
478 
479 static void
480 umoscom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *p_lsr, uint8_t *p_msr)
481 {
482 	struct umoscom_softc *sc = ucom->sc_parent;
483 	uint8_t lsr;
484 	uint8_t msr;
485 
486 	DPRINTFN(5, "\n");
487 
488 	/* read status registers */
489 
490 	lsr = umoscom_cfg_read(sc, UMOSCOM_LSR);
491 	msr = umoscom_cfg_read(sc, UMOSCOM_MSR);
492 
493 	/* translate bits */
494 
495 	if (msr & UMOSCOM_MSR_CTS)
496 		*p_msr |= SER_CTS;
497 
498 	if (msr & UMOSCOM_MSR_CD)
499 		*p_msr |= SER_DCD;
500 
501 	if (msr & UMOSCOM_MSR_RI)
502 		*p_msr |= SER_RI;
503 
504 	if (msr & UMOSCOM_MSR_RTS)
505 		*p_msr |= SER_DSR;
506 }
507 
508 static void
509 umoscom_cfg_write(struct umoscom_softc *sc, uint16_t reg, uint16_t val)
510 {
511 	struct usb2_device_request req;
512 
513 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
514 	req.bRequest = UMOSCOM_WRITE;
515 	USETW(req.wValue, val);
516 	USETW(req.wIndex, reg);
517 	USETW(req.wLength, 0);
518 
519 	usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
520 	    &req, NULL, 0, 1000);
521 }
522 
523 static uint8_t
524 umoscom_cfg_read(struct umoscom_softc *sc, uint16_t reg)
525 {
526 	struct usb2_device_request req;
527 	uint8_t val;
528 
529 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
530 	req.bRequest = UMOSCOM_READ;
531 	USETW(req.wValue, 0);
532 	USETW(req.wIndex, reg);
533 	USETW(req.wLength, 1);
534 
535 	usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
536 	    &req, &val, 0, 1000);
537 
538 	DPRINTF("reg=0x%04x, val=0x%02x\n", reg, val);
539 
540 	return (val);
541 }
542 
543 static void
544 umoscom_start_read(struct usb2_com_softc *ucom)
545 {
546 	struct umoscom_softc *sc = ucom->sc_parent;
547 
548 #if 0
549 	/* start interrupt endpoint */
550 	usb2_transfer_start(sc->sc_xfer[UMOSCOM_INTR_DT_RD]);
551 #endif
552 	/* start read endpoint */
553 	usb2_transfer_start(sc->sc_xfer[UMOSCOM_BULK_DT_RD]);
554 }
555 
556 static void
557 umoscom_stop_read(struct usb2_com_softc *ucom)
558 {
559 	struct umoscom_softc *sc = ucom->sc_parent;
560 
561 	/* stop interrupt transfer */
562 	usb2_transfer_stop(sc->sc_xfer[UMOSCOM_INTR_DT_RD]);
563 
564 	/* stop read endpoint */
565 	usb2_transfer_stop(sc->sc_xfer[UMOSCOM_BULK_DT_RD]);
566 }
567 
568 static void
569 umoscom_start_write(struct usb2_com_softc *ucom)
570 {
571 	struct umoscom_softc *sc = ucom->sc_parent;
572 
573 	usb2_transfer_start(sc->sc_xfer[UMOSCOM_BULK_DT_WR]);
574 }
575 
576 static void
577 umoscom_stop_write(struct usb2_com_softc *ucom)
578 {
579 	struct umoscom_softc *sc = ucom->sc_parent;
580 
581 	usb2_transfer_stop(sc->sc_xfer[UMOSCOM_BULK_DT_WR]);
582 }
583 
584 static void
585 umoscom_write_callback(struct usb2_xfer *xfer)
586 {
587 	struct umoscom_softc *sc = xfer->priv_sc;
588 	uint32_t actlen;
589 
590 	switch (USB_GET_STATE(xfer)) {
591 	case USB_ST_SETUP:
592 	case USB_ST_TRANSFERRED:
593 tr_setup:
594 		DPRINTF("\n");
595 
596 		if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0,
597 		    UMOSCOM_BUFSIZE, &actlen)) {
598 
599 			xfer->frlengths[0] = actlen;
600 			usb2_start_hardware(xfer);
601 		}
602 		return;
603 
604 	default:			/* Error */
605 		if (xfer->error != USB_ERR_CANCELLED) {
606 			DPRINTFN(0, "transfer failed\n");
607 			/* try to clear stall first */
608 			xfer->flags.stall_pipe = 1;
609 			goto tr_setup;
610 		}
611 		return;
612 	}
613 }
614 
615 static void
616 umoscom_read_callback(struct usb2_xfer *xfer)
617 {
618 	struct umoscom_softc *sc = xfer->priv_sc;
619 
620 	switch (USB_GET_STATE(xfer)) {
621 	case USB_ST_TRANSFERRED:
622 		DPRINTF("got %d bytes\n", xfer->actlen);
623 		usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen);
624 
625 	case USB_ST_SETUP:
626 tr_setup:
627 		DPRINTF("\n");
628 
629 		xfer->frlengths[0] = xfer->max_data_length;
630 		usb2_start_hardware(xfer);
631 		return;
632 
633 	default:			/* Error */
634 		if (xfer->error != USB_ERR_CANCELLED) {
635 			DPRINTFN(0, "transfer failed\n");
636 			/* try to clear stall first */
637 			xfer->flags.stall_pipe = 1;
638 			goto tr_setup;
639 		}
640 		return;
641 	}
642 }
643 
644 static void
645 umoscom_intr_callback(struct usb2_xfer *xfer)
646 {
647 	struct umoscom_softc *sc = xfer->priv_sc;
648 
649 	switch (USB_GET_STATE(xfer)) {
650 	case USB_ST_TRANSFERRED:
651 		if (xfer->actlen < 2) {
652 			DPRINTF("too short message\n");
653 			goto tr_setup;
654 		}
655 		usb2_com_status_change(&sc->sc_ucom);
656 
657 	case USB_ST_SETUP:
658 tr_setup:
659 		xfer->frlengths[0] = xfer->max_data_length;
660 		usb2_start_hardware(xfer);
661 		return;
662 
663 	default:			/* Error */
664 		if (xfer->error != USB_ERR_CANCELLED) {
665 			DPRINTFN(0, "transfer failed\n");
666 			/* try to clear stall first */
667 			xfer->flags.stall_pipe = 1;
668 			goto tr_setup;
669 		}
670 		return;
671 	}
672 }
673