umoscom.c revision 188413
11638Srgrimes/* $FreeBSD: head/sys/dev/usb2/serial/umoscom2.c 188413 2009-02-09 22:05:25Z thompsa $ */
21638Srgrimes/*	$OpenBSD: umoscom.c,v 1.2 2006/10/26 06:02:43 jsg Exp $	*/
31638Srgrimes
41638Srgrimes/*
51638Srgrimes * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
61638Srgrimes *
71638Srgrimes * Permission to use, copy, modify, and distribute this software for any
81638Srgrimes * purpose with or without fee is hereby granted, provided that the above
91638Srgrimes * copyright notice and this permission notice appear in all copies.
101638Srgrimes *
111638Srgrimes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
121638Srgrimes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
131638Srgrimes * 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 <dev/usb2/include/usb2_devid.h>
21#include <dev/usb2/include/usb2_standard.h>
22#include <dev/usb2/include/usb2_mfunc.h>
23#include <dev/usb2/include/usb2_error.h>
24#include <dev/usb2/include/usb2_cdc.h>
25
26#define	USB_DEBUG_VAR umoscom_debug
27
28#include <dev/usb2/core/usb2_core.h>
29#include <dev/usb2/core/usb2_debug.h>
30#include <dev/usb2/core/usb2_process.h>
31#include <dev/usb2/core/usb2_request.h>
32#include <dev/usb2/core/usb2_lookup.h>
33#include <dev/usb2/core/usb2_util.h>
34#include <dev/usb2/core/usb2_busdma.h>
35
36#include <dev/usb2/serial/usb2_serial.h>
37
38#if USB_DEBUG
39static int umoscom_debug = 0;
40
41SYSCTL_NODE(_hw_usb2, OID_AUTO, umoscom, CTLFLAG_RW, 0, "USB umoscom");
42SYSCTL_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
156enum {
157	UMOSCOM_BULK_DT_WR,
158	UMOSCOM_BULK_DT_RD,
159	UMOSCOM_INTR_DT_RD,
160	UMOSCOM_N_TRANSFER,
161};
162
163struct 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
176static device_probe_t umoscom_probe;
177static device_attach_t umoscom_attach;
178static device_detach_t umoscom_detach;
179
180static usb2_callback_t umoscom_write_callback;
181static usb2_callback_t umoscom_read_callback;
182static usb2_callback_t umoscom_intr_callback;
183
184static void	umoscom_cfg_open(struct usb2_com_softc *);
185static void	umoscom_cfg_close(struct usb2_com_softc *);
186static void	umoscom_cfg_set_break(struct usb2_com_softc *, uint8_t);
187static void	umoscom_cfg_set_dtr(struct usb2_com_softc *, uint8_t);
188static void	umoscom_cfg_set_rts(struct usb2_com_softc *, uint8_t);
189static int	umoscom_pre_param(struct usb2_com_softc *, struct termios *);
190static void	umoscom_cfg_param(struct usb2_com_softc *, struct termios *);
191static void	umoscom_cfg_get_status(struct usb2_com_softc *, uint8_t *,
192		    uint8_t *);
193static void	umoscom_cfg_write(struct umoscom_softc *, uint16_t, uint16_t);
194static uint8_t	umoscom_cfg_read(struct umoscom_softc *, uint16_t);
195static void	umoscom_start_read(struct usb2_com_softc *);
196static void	umoscom_stop_read(struct usb2_com_softc *);
197static void	umoscom_start_write(struct usb2_com_softc *);
198static void	umoscom_stop_write(struct usb2_com_softc *);
199
200static 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
230static 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
248static 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
255static devclass_t umoscom_devclass;
256
257static driver_t umoscom_driver = {
258	.name = "umoscom",
259	.methods = umoscom_methods,
260	.size = sizeof(struct umoscom_softc),
261};
262
263DRIVER_MODULE(umoscom, ushub, umoscom_driver, umoscom_devclass, NULL, 0);
264MODULE_DEPEND(umoscom, usb2_serial, 1, 1, 1);
265MODULE_DEPEND(umoscom, usb2_core, 1, 1, 1);
266
267static const struct usb2_device_id umoscom_devs[] = {
268	{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7703, 0)}
269};
270
271static int
272umoscom_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
288static int
289umoscom_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
322detach:
323	device_printf(dev, "attach error: %s\n", usb2_errstr(error));
324	umoscom_detach(dev);
325	return (ENXIO);
326}
327
328static int
329umoscom_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
344static void
345umoscom_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
370static void
371umoscom_cfg_close(struct usb2_com_softc *ucom)
372{
373	return;
374}
375
376static void
377umoscom_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
389static void
390umoscom_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
402static void
403umoscom_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
415static int
416umoscom_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
424static void
425umoscom_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
479static void
480umoscom_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
508static void
509umoscom_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
523static uint8_t
524umoscom_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
543static void
544umoscom_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
556static void
557umoscom_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
568static void
569umoscom_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
576static void
577umoscom_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
584static void
585umoscom_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:
593tr_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
615static void
616umoscom_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:
626tr_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
644static void
645umoscom_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:
658tr_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