1/* $FreeBSD: releng/11.0/sys/dev/usb/serial/umoscom.c 292080 2015-12-11 05:28:00Z imp $ */
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 <sys/stdint.h>
21#include <sys/stddef.h>
22#include <sys/param.h>
23#include <sys/queue.h>
24#include <sys/types.h>
25#include <sys/systm.h>
26#include <sys/kernel.h>
27#include <sys/bus.h>
28#include <sys/module.h>
29#include <sys/lock.h>
30#include <sys/mutex.h>
31#include <sys/condvar.h>
32#include <sys/sysctl.h>
33#include <sys/sx.h>
34#include <sys/unistd.h>
35#include <sys/callout.h>
36#include <sys/malloc.h>
37#include <sys/priv.h>
38
39#include <dev/usb/usb.h>
40#include <dev/usb/usbdi.h>
41#include <dev/usb/usbdi_util.h>
42#include "usbdevs.h"
43
44#define	USB_DEBUG_VAR umoscom_debug
45#include <dev/usb/usb_debug.h>
46#include <dev/usb/usb_process.h>
47
48#include <dev/usb/serial/usb_serial.h>
49
50#ifdef USB_DEBUG
51static int umoscom_debug = 0;
52
53static SYSCTL_NODE(_hw_usb, OID_AUTO, umoscom, CTLFLAG_RW, 0, "USB umoscom");
54SYSCTL_INT(_hw_usb_umoscom, OID_AUTO, debug, CTLFLAG_RWTUN,
55    &umoscom_debug, 0, "Debug level");
56#endif
57
58#define	UMOSCOM_BUFSIZE	       1024	/* bytes */
59
60#define	UMOSCOM_CONFIG_INDEX	0
61#define	UMOSCOM_IFACE_INDEX	0
62
63/* interrupt packet */
64#define	UMOSCOM_IIR_RLS		0x06
65#define	UMOSCOM_IIR_RDA		0x04
66#define	UMOSCOM_IIR_CTI		0x0c
67#define	UMOSCOM_IIR_THR		0x02
68#define	UMOSCOM_IIR_MS		0x00
69
70/* registers */
71#define	UMOSCOM_READ		0x0d
72#define	UMOSCOM_WRITE		0x0e
73#define	UMOSCOM_UART_REG	0x0300
74#define	UMOSCOM_VEND_REG	0x0000
75
76#define	UMOSCOM_TXBUF		0x00	/* Write */
77#define	UMOSCOM_RXBUF		0x00	/* Read */
78#define	UMOSCOM_INT		0x01
79#define	UMOSCOM_FIFO		0x02	/* Write */
80#define	UMOSCOM_ISR		0x02	/* Read */
81#define	UMOSCOM_LCR		0x03
82#define	UMOSCOM_MCR		0x04
83#define	UMOSCOM_LSR		0x05
84#define	UMOSCOM_MSR		0x06
85#define	UMOSCOM_SCRATCH		0x07
86#define	UMOSCOM_DIV_LO		0x08
87#define	UMOSCOM_DIV_HI		0x09
88#define	UMOSCOM_EFR		0x0a
89#define	UMOSCOM_XON1		0x0b
90#define	UMOSCOM_XON2		0x0c
91#define	UMOSCOM_XOFF1		0x0d
92#define	UMOSCOM_XOFF2		0x0e
93
94#define	UMOSCOM_BAUDLO		0x00
95#define	UMOSCOM_BAUDHI		0x01
96
97#define	UMOSCOM_INT_RXEN	0x01
98#define	UMOSCOM_INT_TXEN	0x02
99#define	UMOSCOM_INT_RSEN	0x04
100#define	UMOSCOM_INT_MDMEM	0x08
101#define	UMOSCOM_INT_SLEEP	0x10
102#define	UMOSCOM_INT_XOFF	0x20
103#define	UMOSCOM_INT_RTS		0x40
104
105#define	UMOSCOM_FIFO_EN		0x01
106#define	UMOSCOM_FIFO_RXCLR	0x02
107#define	UMOSCOM_FIFO_TXCLR	0x04
108#define	UMOSCOM_FIFO_DMA_BLK	0x08
109#define	UMOSCOM_FIFO_TXLVL_MASK	0x30
110#define	UMOSCOM_FIFO_TXLVL_8	0x00
111#define	UMOSCOM_FIFO_TXLVL_16	0x10
112#define	UMOSCOM_FIFO_TXLVL_32	0x20
113#define	UMOSCOM_FIFO_TXLVL_56	0x30
114#define	UMOSCOM_FIFO_RXLVL_MASK	0xc0
115#define	UMOSCOM_FIFO_RXLVL_8	0x00
116#define	UMOSCOM_FIFO_RXLVL_16	0x40
117#define	UMOSCOM_FIFO_RXLVL_56	0x80
118#define	UMOSCOM_FIFO_RXLVL_80	0xc0
119
120#define	UMOSCOM_ISR_MDM		0x00
121#define	UMOSCOM_ISR_NONE	0x01
122#define	UMOSCOM_ISR_TX		0x02
123#define	UMOSCOM_ISR_RX		0x04
124#define	UMOSCOM_ISR_LINE	0x06
125#define	UMOSCOM_ISR_RXTIMEOUT	0x0c
126#define	UMOSCOM_ISR_RX_XOFF	0x10
127#define	UMOSCOM_ISR_RTSCTS	0x20
128#define	UMOSCOM_ISR_FIFOEN	0xc0
129
130#define	UMOSCOM_LCR_DBITS(x)	((x) - 5)
131#define	UMOSCOM_LCR_STOP_BITS_1	0x00
132#define	UMOSCOM_LCR_STOP_BITS_2	0x04	/* 2 if 6-8 bits/char or 1.5 if 5 */
133#define	UMOSCOM_LCR_PARITY_NONE	0x00
134#define	UMOSCOM_LCR_PARITY_ODD	0x08
135#define	UMOSCOM_LCR_PARITY_EVEN	0x18
136#define	UMOSCOM_LCR_BREAK	0x40
137#define	UMOSCOM_LCR_DIVLATCH_EN	0x80
138
139#define	UMOSCOM_MCR_DTR		0x01
140#define	UMOSCOM_MCR_RTS		0x02
141#define	UMOSCOM_MCR_LOOP	0x04
142#define	UMOSCOM_MCR_INTEN	0x08
143#define	UMOSCOM_MCR_LOOPBACK	0x10
144#define	UMOSCOM_MCR_XONANY	0x20
145#define	UMOSCOM_MCR_IRDA_EN	0x40
146#define	UMOSCOM_MCR_BAUD_DIV4	0x80
147
148#define	UMOSCOM_LSR_RXDATA	0x01
149#define	UMOSCOM_LSR_RXOVER	0x02
150#define	UMOSCOM_LSR_RXPAR_ERR	0x04
151#define	UMOSCOM_LSR_RXFRM_ERR	0x08
152#define	UMOSCOM_LSR_RXBREAK	0x10
153#define	UMOSCOM_LSR_TXEMPTY	0x20
154#define	UMOSCOM_LSR_TXALLEMPTY	0x40
155#define	UMOSCOM_LSR_TXFIFO_ERR	0x80
156
157#define	UMOSCOM_MSR_CTS_CHG	0x01
158#define	UMOSCOM_MSR_DSR_CHG	0x02
159#define	UMOSCOM_MSR_RI_CHG	0x04
160#define	UMOSCOM_MSR_CD_CHG	0x08
161#define	UMOSCOM_MSR_CTS		0x10
162#define	UMOSCOM_MSR_RTS		0x20
163#define	UMOSCOM_MSR_RI		0x40
164#define	UMOSCOM_MSR_CD		0x80
165
166#define	UMOSCOM_BAUD_REF	115200
167
168enum {
169	UMOSCOM_BULK_DT_WR,
170	UMOSCOM_BULK_DT_RD,
171	UMOSCOM_INTR_DT_RD,
172	UMOSCOM_N_TRANSFER,
173};
174
175struct umoscom_softc {
176	struct ucom_super_softc sc_super_ucom;
177	struct ucom_softc sc_ucom;
178
179	struct usb_xfer *sc_xfer[UMOSCOM_N_TRANSFER];
180	struct usb_device *sc_udev;
181	struct mtx sc_mtx;
182
183	uint8_t	sc_mcr;
184	uint8_t	sc_lcr;
185};
186
187/* prototypes */
188
189static device_probe_t umoscom_probe;
190static device_attach_t umoscom_attach;
191static device_detach_t umoscom_detach;
192static void umoscom_free_softc(struct umoscom_softc *);
193
194static usb_callback_t umoscom_write_callback;
195static usb_callback_t umoscom_read_callback;
196static usb_callback_t umoscom_intr_callback;
197
198static void	umoscom_free(struct ucom_softc *);
199static void	umoscom_cfg_open(struct ucom_softc *);
200static void	umoscom_cfg_close(struct ucom_softc *);
201static void	umoscom_cfg_set_break(struct ucom_softc *, uint8_t);
202static void	umoscom_cfg_set_dtr(struct ucom_softc *, uint8_t);
203static void	umoscom_cfg_set_rts(struct ucom_softc *, uint8_t);
204static int	umoscom_pre_param(struct ucom_softc *, struct termios *);
205static void	umoscom_cfg_param(struct ucom_softc *, struct termios *);
206static void	umoscom_cfg_get_status(struct ucom_softc *, uint8_t *,
207		    uint8_t *);
208static void	umoscom_cfg_write(struct umoscom_softc *, uint16_t, uint16_t);
209static uint8_t	umoscom_cfg_read(struct umoscom_softc *, uint16_t);
210static void	umoscom_start_read(struct ucom_softc *);
211static void	umoscom_stop_read(struct ucom_softc *);
212static void	umoscom_start_write(struct ucom_softc *);
213static void	umoscom_stop_write(struct ucom_softc *);
214static void	umoscom_poll(struct ucom_softc *ucom);
215
216static const struct usb_config umoscom_config_data[UMOSCOM_N_TRANSFER] = {
217
218	[UMOSCOM_BULK_DT_WR] = {
219		.type = UE_BULK,
220		.endpoint = UE_ADDR_ANY,
221		.direction = UE_DIR_OUT,
222		.bufsize = UMOSCOM_BUFSIZE,
223		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
224		.callback = &umoscom_write_callback,
225	},
226
227	[UMOSCOM_BULK_DT_RD] = {
228		.type = UE_BULK,
229		.endpoint = UE_ADDR_ANY,
230		.direction = UE_DIR_IN,
231		.bufsize = UMOSCOM_BUFSIZE,
232		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
233		.callback = &umoscom_read_callback,
234	},
235
236	[UMOSCOM_INTR_DT_RD] = {
237		.type = UE_INTERRUPT,
238		.endpoint = UE_ADDR_ANY,
239		.direction = UE_DIR_IN,
240		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
241		.bufsize = 0,	/* use wMaxPacketSize */
242		.callback = &umoscom_intr_callback,
243	},
244};
245
246static const struct ucom_callback umoscom_callback = {
247	/* configuration callbacks */
248	.ucom_cfg_get_status = &umoscom_cfg_get_status,
249	.ucom_cfg_set_dtr = &umoscom_cfg_set_dtr,
250	.ucom_cfg_set_rts = &umoscom_cfg_set_rts,
251	.ucom_cfg_set_break = &umoscom_cfg_set_break,
252	.ucom_cfg_param = &umoscom_cfg_param,
253	.ucom_cfg_open = &umoscom_cfg_open,
254	.ucom_cfg_close = &umoscom_cfg_close,
255
256	/* other callbacks */
257	.ucom_pre_param = &umoscom_pre_param,
258	.ucom_start_read = &umoscom_start_read,
259	.ucom_stop_read = &umoscom_stop_read,
260	.ucom_start_write = &umoscom_start_write,
261	.ucom_stop_write = &umoscom_stop_write,
262	.ucom_poll = &umoscom_poll,
263	.ucom_free = &umoscom_free,
264};
265
266static device_method_t umoscom_methods[] = {
267	DEVMETHOD(device_probe, umoscom_probe),
268	DEVMETHOD(device_attach, umoscom_attach),
269	DEVMETHOD(device_detach, umoscom_detach),
270	DEVMETHOD_END
271};
272
273static devclass_t umoscom_devclass;
274
275static driver_t umoscom_driver = {
276	.name = "umoscom",
277	.methods = umoscom_methods,
278	.size = sizeof(struct umoscom_softc),
279};
280
281static const STRUCT_USB_HOST_ID umoscom_devs[] = {
282	{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7703, 0)}
283};
284
285DRIVER_MODULE(umoscom, uhub, umoscom_driver, umoscom_devclass, NULL, 0);
286MODULE_DEPEND(umoscom, ucom, 1, 1, 1);
287MODULE_DEPEND(umoscom, usb, 1, 1, 1);
288MODULE_VERSION(umoscom, 1);
289USB_PNP_HOST_INFO(umoscom_devs);
290
291static int
292umoscom_probe(device_t dev)
293{
294	struct usb_attach_arg *uaa = device_get_ivars(dev);
295
296	if (uaa->usb_mode != USB_MODE_HOST) {
297		return (ENXIO);
298	}
299	if (uaa->info.bConfigIndex != UMOSCOM_CONFIG_INDEX) {
300		return (ENXIO);
301	}
302	if (uaa->info.bIfaceIndex != UMOSCOM_IFACE_INDEX) {
303		return (ENXIO);
304	}
305	return (usbd_lookup_id_by_uaa(umoscom_devs, sizeof(umoscom_devs), uaa));
306}
307
308static int
309umoscom_attach(device_t dev)
310{
311	struct usb_attach_arg *uaa = device_get_ivars(dev);
312	struct umoscom_softc *sc = device_get_softc(dev);
313	int error;
314	uint8_t iface_index;
315
316	sc->sc_udev = uaa->device;
317	sc->sc_mcr = 0x08;		/* enable interrupts */
318
319	/* XXX the device doesn't provide any ID string, so set a static one */
320	device_set_desc(dev, "MOSCHIP USB Serial Port Adapter");
321	device_printf(dev, "<MOSCHIP USB Serial Port Adapter>\n");
322
323	mtx_init(&sc->sc_mtx, "umoscom", NULL, MTX_DEF);
324	ucom_ref(&sc->sc_super_ucom);
325
326	iface_index = UMOSCOM_IFACE_INDEX;
327	error = usbd_transfer_setup(uaa->device, &iface_index,
328	    sc->sc_xfer, umoscom_config_data,
329	    UMOSCOM_N_TRANSFER, sc, &sc->sc_mtx);
330
331	if (error) {
332		goto detach;
333	}
334	/* clear stall at first run */
335	mtx_lock(&sc->sc_mtx);
336	usbd_xfer_set_stall(sc->sc_xfer[UMOSCOM_BULK_DT_WR]);
337	usbd_xfer_set_stall(sc->sc_xfer[UMOSCOM_BULK_DT_RD]);
338	mtx_unlock(&sc->sc_mtx);
339
340	error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
341	    &umoscom_callback, &sc->sc_mtx);
342	if (error) {
343		goto detach;
344	}
345	ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
346
347	return (0);
348
349detach:
350	device_printf(dev, "attach error: %s\n", usbd_errstr(error));
351	umoscom_detach(dev);
352	return (ENXIO);
353}
354
355static int
356umoscom_detach(device_t dev)
357{
358	struct umoscom_softc *sc = device_get_softc(dev);
359
360	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
361	usbd_transfer_unsetup(sc->sc_xfer, UMOSCOM_N_TRANSFER);
362
363	device_claim_softc(dev);
364
365	umoscom_free_softc(sc);
366
367	return (0);
368}
369
370UCOM_UNLOAD_DRAIN(umoscom);
371
372static void
373umoscom_free_softc(struct umoscom_softc *sc)
374{
375	if (ucom_unref(&sc->sc_super_ucom)) {
376		mtx_destroy(&sc->sc_mtx);
377		device_free_softc(sc);
378	}
379}
380
381static void
382umoscom_free(struct ucom_softc *ucom)
383{
384	umoscom_free_softc(ucom->sc_parent);
385}
386
387static void
388umoscom_cfg_open(struct ucom_softc *ucom)
389{
390	struct umoscom_softc *sc = ucom->sc_parent;
391
392	DPRINTF("\n");
393
394	/* Purge FIFOs or odd things happen */
395	umoscom_cfg_write(sc, UMOSCOM_FIFO, 0x00 | UMOSCOM_UART_REG);
396
397	/* Enable FIFO */
398	umoscom_cfg_write(sc, UMOSCOM_FIFO, UMOSCOM_FIFO_EN |
399	    UMOSCOM_FIFO_RXCLR | UMOSCOM_FIFO_TXCLR |
400	    UMOSCOM_FIFO_DMA_BLK | UMOSCOM_FIFO_RXLVL_MASK |
401	    UMOSCOM_UART_REG);
402
403	/* Enable Interrupt Registers */
404	umoscom_cfg_write(sc, UMOSCOM_INT, 0x0C | UMOSCOM_UART_REG);
405
406	/* Magic */
407	umoscom_cfg_write(sc, 0x01, 0x08);
408
409	/* Magic */
410	umoscom_cfg_write(sc, 0x00, 0x02);
411}
412
413static void
414umoscom_cfg_close(struct ucom_softc *ucom)
415{
416	return;
417}
418
419static void
420umoscom_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
421{
422	struct umoscom_softc *sc = ucom->sc_parent;
423	uint16_t val;
424
425	val = sc->sc_lcr;
426	if (onoff)
427		val |= UMOSCOM_LCR_BREAK;
428
429	umoscom_cfg_write(sc, UMOSCOM_LCR, val | UMOSCOM_UART_REG);
430}
431
432static void
433umoscom_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
434{
435	struct umoscom_softc *sc = ucom->sc_parent;
436
437	if (onoff)
438		sc->sc_mcr |= UMOSCOM_MCR_DTR;
439	else
440		sc->sc_mcr &= ~UMOSCOM_MCR_DTR;
441
442	umoscom_cfg_write(sc, UMOSCOM_MCR, sc->sc_mcr | UMOSCOM_UART_REG);
443}
444
445static void
446umoscom_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
447{
448	struct umoscom_softc *sc = ucom->sc_parent;
449
450	if (onoff)
451		sc->sc_mcr |= UMOSCOM_MCR_RTS;
452	else
453		sc->sc_mcr &= ~UMOSCOM_MCR_RTS;
454
455	umoscom_cfg_write(sc, UMOSCOM_MCR, sc->sc_mcr | UMOSCOM_UART_REG);
456}
457
458static int
459umoscom_pre_param(struct ucom_softc *ucom, struct termios *t)
460{
461	if ((t->c_ospeed <= 1) || (t->c_ospeed > 115200))
462		return (EINVAL);
463
464	return (0);
465}
466
467static void
468umoscom_cfg_param(struct ucom_softc *ucom, struct termios *t)
469{
470	struct umoscom_softc *sc = ucom->sc_parent;
471	uint16_t data;
472
473	DPRINTF("speed=%d\n", t->c_ospeed);
474
475	data = ((uint32_t)UMOSCOM_BAUD_REF) / ((uint32_t)t->c_ospeed);
476
477	if (data == 0) {
478		DPRINTF("invalid baud rate!\n");
479		return;
480	}
481	umoscom_cfg_write(sc, UMOSCOM_LCR,
482	    UMOSCOM_LCR_DIVLATCH_EN | UMOSCOM_UART_REG);
483
484	umoscom_cfg_write(sc, UMOSCOM_BAUDLO,
485	    (data & 0xFF) | UMOSCOM_UART_REG);
486
487	umoscom_cfg_write(sc, UMOSCOM_BAUDHI,
488	    ((data >> 8) & 0xFF) | UMOSCOM_UART_REG);
489
490	if (t->c_cflag & CSTOPB)
491		data = UMOSCOM_LCR_STOP_BITS_2;
492	else
493		data = UMOSCOM_LCR_STOP_BITS_1;
494
495	if (t->c_cflag & PARENB) {
496		if (t->c_cflag & PARODD)
497			data |= UMOSCOM_LCR_PARITY_ODD;
498		else
499			data |= UMOSCOM_LCR_PARITY_EVEN;
500	} else
501		data |= UMOSCOM_LCR_PARITY_NONE;
502
503	switch (t->c_cflag & CSIZE) {
504	case CS5:
505		data |= UMOSCOM_LCR_DBITS(5);
506		break;
507	case CS6:
508		data |= UMOSCOM_LCR_DBITS(6);
509		break;
510	case CS7:
511		data |= UMOSCOM_LCR_DBITS(7);
512		break;
513	case CS8:
514		data |= UMOSCOM_LCR_DBITS(8);
515		break;
516	}
517
518	sc->sc_lcr = data;
519	umoscom_cfg_write(sc, UMOSCOM_LCR, data | UMOSCOM_UART_REG);
520}
521
522static void
523umoscom_cfg_get_status(struct ucom_softc *ucom, uint8_t *p_lsr, uint8_t *p_msr)
524{
525	struct umoscom_softc *sc = ucom->sc_parent;
526	uint8_t lsr;
527	uint8_t msr;
528
529	DPRINTFN(5, "\n");
530
531	/* read status registers */
532
533	lsr = umoscom_cfg_read(sc, UMOSCOM_LSR);
534	msr = umoscom_cfg_read(sc, UMOSCOM_MSR);
535
536	/* translate bits */
537
538	if (msr & UMOSCOM_MSR_CTS)
539		*p_msr |= SER_CTS;
540
541	if (msr & UMOSCOM_MSR_CD)
542		*p_msr |= SER_DCD;
543
544	if (msr & UMOSCOM_MSR_RI)
545		*p_msr |= SER_RI;
546
547	if (msr & UMOSCOM_MSR_RTS)
548		*p_msr |= SER_DSR;
549}
550
551static void
552umoscom_cfg_write(struct umoscom_softc *sc, uint16_t reg, uint16_t val)
553{
554	struct usb_device_request req;
555
556	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
557	req.bRequest = UMOSCOM_WRITE;
558	USETW(req.wValue, val);
559	USETW(req.wIndex, reg);
560	USETW(req.wLength, 0);
561
562	ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
563	    &req, NULL, 0, 1000);
564}
565
566static uint8_t
567umoscom_cfg_read(struct umoscom_softc *sc, uint16_t reg)
568{
569	struct usb_device_request req;
570	uint8_t val;
571
572	req.bmRequestType = UT_READ_VENDOR_DEVICE;
573	req.bRequest = UMOSCOM_READ;
574	USETW(req.wValue, 0);
575	USETW(req.wIndex, reg);
576	USETW(req.wLength, 1);
577
578	ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
579	    &req, &val, 0, 1000);
580
581	DPRINTF("reg=0x%04x, val=0x%02x\n", reg, val);
582
583	return (val);
584}
585
586static void
587umoscom_start_read(struct ucom_softc *ucom)
588{
589	struct umoscom_softc *sc = ucom->sc_parent;
590
591#if 0
592	/* start interrupt endpoint */
593	usbd_transfer_start(sc->sc_xfer[UMOSCOM_INTR_DT_RD]);
594#endif
595	/* start read endpoint */
596	usbd_transfer_start(sc->sc_xfer[UMOSCOM_BULK_DT_RD]);
597}
598
599static void
600umoscom_stop_read(struct ucom_softc *ucom)
601{
602	struct umoscom_softc *sc = ucom->sc_parent;
603
604	/* stop interrupt transfer */
605	usbd_transfer_stop(sc->sc_xfer[UMOSCOM_INTR_DT_RD]);
606
607	/* stop read endpoint */
608	usbd_transfer_stop(sc->sc_xfer[UMOSCOM_BULK_DT_RD]);
609}
610
611static void
612umoscom_start_write(struct ucom_softc *ucom)
613{
614	struct umoscom_softc *sc = ucom->sc_parent;
615
616	usbd_transfer_start(sc->sc_xfer[UMOSCOM_BULK_DT_WR]);
617}
618
619static void
620umoscom_stop_write(struct ucom_softc *ucom)
621{
622	struct umoscom_softc *sc = ucom->sc_parent;
623
624	usbd_transfer_stop(sc->sc_xfer[UMOSCOM_BULK_DT_WR]);
625}
626
627static void
628umoscom_write_callback(struct usb_xfer *xfer, usb_error_t error)
629{
630	struct umoscom_softc *sc = usbd_xfer_softc(xfer);
631	struct usb_page_cache *pc;
632	uint32_t actlen;
633
634	switch (USB_GET_STATE(xfer)) {
635	case USB_ST_SETUP:
636	case USB_ST_TRANSFERRED:
637tr_setup:
638		DPRINTF("\n");
639
640		pc = usbd_xfer_get_frame(xfer, 0);
641		if (ucom_get_data(&sc->sc_ucom, pc, 0,
642		    UMOSCOM_BUFSIZE, &actlen)) {
643
644			usbd_xfer_set_frame_len(xfer, 0, actlen);
645			usbd_transfer_submit(xfer);
646		}
647		return;
648
649	default:			/* Error */
650		if (error != USB_ERR_CANCELLED) {
651			DPRINTFN(0, "transfer failed\n");
652			/* try to clear stall first */
653			usbd_xfer_set_stall(xfer);
654			goto tr_setup;
655		}
656		return;
657	}
658}
659
660static void
661umoscom_read_callback(struct usb_xfer *xfer, usb_error_t error)
662{
663	struct umoscom_softc *sc = usbd_xfer_softc(xfer);
664	struct usb_page_cache *pc;
665	int actlen;
666
667	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
668
669	switch (USB_GET_STATE(xfer)) {
670	case USB_ST_TRANSFERRED:
671		DPRINTF("got %d bytes\n", actlen);
672		pc = usbd_xfer_get_frame(xfer, 0);
673		ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
674
675	case USB_ST_SETUP:
676tr_setup:
677		DPRINTF("\n");
678
679		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
680		usbd_transfer_submit(xfer);
681		return;
682
683	default:			/* Error */
684		if (error != USB_ERR_CANCELLED) {
685			DPRINTFN(0, "transfer failed\n");
686			/* try to clear stall first */
687			usbd_xfer_set_stall(xfer);
688			goto tr_setup;
689		}
690		return;
691	}
692}
693
694static void
695umoscom_intr_callback(struct usb_xfer *xfer, usb_error_t error)
696{
697	struct umoscom_softc *sc = usbd_xfer_softc(xfer);
698	int actlen;
699
700	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
701
702	switch (USB_GET_STATE(xfer)) {
703	case USB_ST_TRANSFERRED:
704		if (actlen < 2) {
705			DPRINTF("too short message\n");
706			goto tr_setup;
707		}
708		ucom_status_change(&sc->sc_ucom);
709
710	case USB_ST_SETUP:
711tr_setup:
712		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
713		usbd_transfer_submit(xfer);
714		return;
715
716	default:			/* Error */
717		if (error != USB_ERR_CANCELLED) {
718			DPRINTFN(0, "transfer failed\n");
719			/* try to clear stall first */
720			usbd_xfer_set_stall(xfer);
721			goto tr_setup;
722		}
723		return;
724	}
725}
726
727static void
728umoscom_poll(struct ucom_softc *ucom)
729{
730	struct umoscom_softc *sc = ucom->sc_parent;
731	usbd_transfer_poll(sc->sc_xfer, UMOSCOM_N_TRANSFER);
732}
733