uvscom.c revision 192984
1/*	$NetBSD: usb/uvscom.c,v 1.1 2002/03/19 15:08:42 augustss Exp $	*/
2
3#include <sys/cdefs.h>
4__FBSDID("$FreeBSD: head/sys/dev/usb/serial/uvscom.c 192984 2009-05-28 17:36:36Z thompsa $");
5
6/*-
7 * Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 */
32
33/*
34 * uvscom: SUNTAC Slipper U VS-10U driver.
35 * Slipper U is a PC Card to USB converter for data communication card
36 * adapter.  It supports DDI Pocket's Air H" C@rd, C@rd H" 64, NTT's P-in,
37 * P-in m@ater and various data communication card adapters.
38 */
39
40#include "usbdevs.h"
41#include <dev/usb/usb.h>
42#include <dev/usb/usb_mfunc.h>
43#include <dev/usb/usb_error.h>
44#include <dev/usb/usb_cdc.h>
45
46#define	USB_DEBUG_VAR uvscom_debug
47
48#include <dev/usb/usb_core.h>
49#include <dev/usb/usb_debug.h>
50#include <dev/usb/usb_process.h>
51#include <dev/usb/usb_request.h>
52#include <dev/usb/usb_lookup.h>
53#include <dev/usb/usb_util.h>
54#include <dev/usb/usb_busdma.h>
55
56#include <dev/usb/serial/usb_serial.h>
57
58#if USB_DEBUG
59static int uvscom_debug = 0;
60
61SYSCTL_NODE(_hw_usb, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom");
62SYSCTL_INT(_hw_usb_uvscom, OID_AUTO, debug, CTLFLAG_RW,
63    &uvscom_debug, 0, "Debug level");
64#endif
65
66#define	UVSCOM_MODVER		1	/* module version */
67
68#define	UVSCOM_CONFIG_INDEX	0
69#define	UVSCOM_IFACE_INDEX	0
70
71/* Request */
72#define	UVSCOM_SET_SPEED	0x10
73#define	UVSCOM_LINE_CTL		0x11
74#define	UVSCOM_SET_PARAM	0x12
75#define	UVSCOM_READ_STATUS	0xd0
76#define	UVSCOM_SHUTDOWN		0xe0
77
78/* UVSCOM_SET_SPEED parameters */
79#define	UVSCOM_SPEED_150BPS	0x00
80#define	UVSCOM_SPEED_300BPS	0x01
81#define	UVSCOM_SPEED_600BPS	0x02
82#define	UVSCOM_SPEED_1200BPS	0x03
83#define	UVSCOM_SPEED_2400BPS	0x04
84#define	UVSCOM_SPEED_4800BPS	0x05
85#define	UVSCOM_SPEED_9600BPS	0x06
86#define	UVSCOM_SPEED_19200BPS	0x07
87#define	UVSCOM_SPEED_38400BPS	0x08
88#define	UVSCOM_SPEED_57600BPS	0x09
89#define	UVSCOM_SPEED_115200BPS	0x0a
90
91/* UVSCOM_LINE_CTL parameters */
92#define	UVSCOM_BREAK		0x40
93#define	UVSCOM_RTS		0x02
94#define	UVSCOM_DTR		0x01
95#define	UVSCOM_LINE_INIT	0x08
96
97/* UVSCOM_SET_PARAM parameters */
98#define	UVSCOM_DATA_MASK	0x03
99#define	UVSCOM_DATA_BIT_8	0x03
100#define	UVSCOM_DATA_BIT_7	0x02
101#define	UVSCOM_DATA_BIT_6	0x01
102#define	UVSCOM_DATA_BIT_5	0x00
103
104#define	UVSCOM_STOP_MASK	0x04
105#define	UVSCOM_STOP_BIT_2	0x04
106#define	UVSCOM_STOP_BIT_1	0x00
107
108#define	UVSCOM_PARITY_MASK	0x18
109#define	UVSCOM_PARITY_EVEN	0x18
110#define	UVSCOM_PARITY_ODD	0x08
111#define	UVSCOM_PARITY_NONE	0x00
112
113/* Status bits */
114#define	UVSCOM_TXRDY		0x04
115#define	UVSCOM_RXRDY		0x01
116
117#define	UVSCOM_DCD		0x08
118#define	UVSCOM_NOCARD		0x04
119#define	UVSCOM_DSR		0x02
120#define	UVSCOM_CTS		0x01
121#define	UVSCOM_USTAT_MASK	(UVSCOM_NOCARD | UVSCOM_DSR | UVSCOM_CTS)
122
123#define	UVSCOM_BULK_BUF_SIZE	1024	/* bytes */
124
125enum {
126	UVSCOM_BULK_DT_WR,
127	UVSCOM_BULK_DT_RD,
128	UVSCOM_INTR_DT_RD,
129	UVSCOM_N_TRANSFER,
130};
131
132struct uvscom_softc {
133	struct ucom_super_softc sc_super_ucom;
134	struct ucom_softc sc_ucom;
135
136	struct usb_xfer *sc_xfer[UVSCOM_N_TRANSFER];
137	struct usb_device *sc_udev;
138	struct mtx sc_mtx;
139
140	uint16_t sc_line;		/* line control register */
141
142	uint8_t	sc_iface_no;		/* interface number */
143	uint8_t	sc_iface_index;		/* interface index */
144	uint8_t	sc_lsr;			/* local status register */
145	uint8_t	sc_msr;			/* uvscom status register */
146	uint8_t	sc_unit_status;		/* unit status */
147};
148
149/* prototypes */
150
151static device_probe_t uvscom_probe;
152static device_attach_t uvscom_attach;
153static device_detach_t uvscom_detach;
154
155static usb2_callback_t uvscom_write_callback;
156static usb2_callback_t uvscom_read_callback;
157static usb2_callback_t uvscom_intr_callback;
158
159static void	uvscom_cfg_set_dtr(struct ucom_softc *, uint8_t);
160static void	uvscom_cfg_set_rts(struct ucom_softc *, uint8_t);
161static void	uvscom_cfg_set_break(struct ucom_softc *, uint8_t);
162static int	uvscom_pre_param(struct ucom_softc *, struct termios *);
163static void	uvscom_cfg_param(struct ucom_softc *, struct termios *);
164static int	uvscom_pre_open(struct ucom_softc *);
165static void	uvscom_cfg_open(struct ucom_softc *);
166static void	uvscom_cfg_close(struct ucom_softc *);
167static void	uvscom_start_read(struct ucom_softc *);
168static void	uvscom_stop_read(struct ucom_softc *);
169static void	uvscom_start_write(struct ucom_softc *);
170static void	uvscom_stop_write(struct ucom_softc *);
171static void	uvscom_cfg_get_status(struct ucom_softc *, uint8_t *,
172		    uint8_t *);
173static void	uvscom_cfg_write(struct uvscom_softc *, uint8_t, uint16_t);
174static uint16_t	uvscom_cfg_read_status(struct uvscom_softc *);
175
176static const struct usb_config uvscom_config[UVSCOM_N_TRANSFER] = {
177
178	[UVSCOM_BULK_DT_WR] = {
179		.type = UE_BULK,
180		.endpoint = UE_ADDR_ANY,
181		.direction = UE_DIR_OUT,
182		.bufsize = UVSCOM_BULK_BUF_SIZE,
183		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
184		.callback = &uvscom_write_callback,
185	},
186
187	[UVSCOM_BULK_DT_RD] = {
188		.type = UE_BULK,
189		.endpoint = UE_ADDR_ANY,
190		.direction = UE_DIR_IN,
191		.bufsize = UVSCOM_BULK_BUF_SIZE,
192		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
193		.callback = &uvscom_read_callback,
194	},
195
196	[UVSCOM_INTR_DT_RD] = {
197		.type = UE_INTERRUPT,
198		.endpoint = UE_ADDR_ANY,
199		.direction = UE_DIR_IN,
200		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
201		.bufsize = 0,	/* use wMaxPacketSize */
202		.callback = &uvscom_intr_callback,
203	},
204};
205
206static const struct ucom_callback uvscom_callback = {
207	.usb2_com_cfg_get_status = &uvscom_cfg_get_status,
208	.usb2_com_cfg_set_dtr = &uvscom_cfg_set_dtr,
209	.usb2_com_cfg_set_rts = &uvscom_cfg_set_rts,
210	.usb2_com_cfg_set_break = &uvscom_cfg_set_break,
211	.usb2_com_cfg_param = &uvscom_cfg_param,
212	.usb2_com_cfg_open = &uvscom_cfg_open,
213	.usb2_com_cfg_close = &uvscom_cfg_close,
214	.usb2_com_pre_open = &uvscom_pre_open,
215	.usb2_com_pre_param = &uvscom_pre_param,
216	.usb2_com_start_read = &uvscom_start_read,
217	.usb2_com_stop_read = &uvscom_stop_read,
218	.usb2_com_start_write = &uvscom_start_write,
219	.usb2_com_stop_write = &uvscom_stop_write,
220};
221
222static const struct usb_device_id uvscom_devs[] = {
223	/* SUNTAC U-Cable type A4 */
224	{USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4, 0)},
225	/* SUNTAC U-Cable type D2 */
226	{USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_DS96L, 0)},
227	/* SUNTAC Ir-Trinity */
228	{USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_IS96U, 0)},
229	/* SUNTAC U-Cable type P1 */
230	{USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1, 0)},
231	/* SUNTAC Slipper U */
232	{USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U, 0)},
233};
234
235static device_method_t uvscom_methods[] = {
236	DEVMETHOD(device_probe, uvscom_probe),
237	DEVMETHOD(device_attach, uvscom_attach),
238	DEVMETHOD(device_detach, uvscom_detach),
239	{0, 0}
240};
241
242static devclass_t uvscom_devclass;
243
244static driver_t uvscom_driver = {
245	.name = "uvscom",
246	.methods = uvscom_methods,
247	.size = sizeof(struct uvscom_softc),
248};
249
250DRIVER_MODULE(uvscom, uhub, uvscom_driver, uvscom_devclass, NULL, 0);
251MODULE_DEPEND(uvscom, ucom, 1, 1, 1);
252MODULE_DEPEND(uvscom, usb, 1, 1, 1);
253MODULE_VERSION(uvscom, UVSCOM_MODVER);
254
255static int
256uvscom_probe(device_t dev)
257{
258	struct usb_attach_arg *uaa = device_get_ivars(dev);
259
260	if (uaa->usb_mode != USB_MODE_HOST) {
261		return (ENXIO);
262	}
263	if (uaa->info.bConfigIndex != UVSCOM_CONFIG_INDEX) {
264		return (ENXIO);
265	}
266	if (uaa->info.bIfaceIndex != UVSCOM_IFACE_INDEX) {
267		return (ENXIO);
268	}
269	return (usb2_lookup_id_by_uaa(uvscom_devs, sizeof(uvscom_devs), uaa));
270}
271
272static int
273uvscom_attach(device_t dev)
274{
275	struct usb_attach_arg *uaa = device_get_ivars(dev);
276	struct uvscom_softc *sc = device_get_softc(dev);
277	int error;
278
279	device_set_usb2_desc(dev);
280	mtx_init(&sc->sc_mtx, "uvscom", NULL, MTX_DEF);
281
282	sc->sc_udev = uaa->device;
283
284	DPRINTF("sc=%p\n", sc);
285
286	sc->sc_iface_no = uaa->info.bIfaceNum;
287	sc->sc_iface_index = UVSCOM_IFACE_INDEX;
288
289	error = usb2_transfer_setup(uaa->device, &sc->sc_iface_index,
290	    sc->sc_xfer, uvscom_config, UVSCOM_N_TRANSFER, sc, &sc->sc_mtx);
291
292	if (error) {
293		DPRINTF("could not allocate all USB transfers!\n");
294		goto detach;
295	}
296	sc->sc_line = UVSCOM_LINE_INIT;
297
298	/* clear stall at first run */
299	mtx_lock(&sc->sc_mtx);
300	usb2_transfer_set_stall(sc->sc_xfer[UVSCOM_BULK_DT_WR]);
301	usb2_transfer_set_stall(sc->sc_xfer[UVSCOM_BULK_DT_RD]);
302	mtx_unlock(&sc->sc_mtx);
303
304	error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
305	    &uvscom_callback, &sc->sc_mtx);
306	if (error) {
307		goto detach;
308	}
309	/* start interrupt pipe */
310	mtx_lock(&sc->sc_mtx);
311	usb2_transfer_start(sc->sc_xfer[UVSCOM_INTR_DT_RD]);
312	mtx_unlock(&sc->sc_mtx);
313
314	return (0);
315
316detach:
317	uvscom_detach(dev);
318	return (ENXIO);
319}
320
321static int
322uvscom_detach(device_t dev)
323{
324	struct uvscom_softc *sc = device_get_softc(dev);
325
326	DPRINTF("sc=%p\n", sc);
327
328	/* stop interrupt pipe */
329
330	if (sc->sc_xfer[UVSCOM_INTR_DT_RD])
331		usb2_transfer_stop(sc->sc_xfer[UVSCOM_INTR_DT_RD]);
332
333	usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
334	usb2_transfer_unsetup(sc->sc_xfer, UVSCOM_N_TRANSFER);
335	mtx_destroy(&sc->sc_mtx);
336
337	return (0);
338}
339
340static void
341uvscom_write_callback(struct usb_xfer *xfer)
342{
343	struct uvscom_softc *sc = xfer->priv_sc;
344	uint32_t actlen;
345
346	switch (USB_GET_STATE(xfer)) {
347	case USB_ST_SETUP:
348	case USB_ST_TRANSFERRED:
349tr_setup:
350		if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0,
351		    UVSCOM_BULK_BUF_SIZE, &actlen)) {
352
353			xfer->frlengths[0] = actlen;
354			usb2_start_hardware(xfer);
355		}
356		return;
357
358	default:			/* Error */
359		if (xfer->error != USB_ERR_CANCELLED) {
360			/* try to clear stall first */
361			xfer->flags.stall_pipe = 1;
362			goto tr_setup;
363		}
364		return;
365	}
366}
367
368static void
369uvscom_read_callback(struct usb_xfer *xfer)
370{
371	struct uvscom_softc *sc = xfer->priv_sc;
372
373	switch (USB_GET_STATE(xfer)) {
374	case USB_ST_TRANSFERRED:
375		usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen);
376
377	case USB_ST_SETUP:
378tr_setup:
379		xfer->frlengths[0] = xfer->max_data_length;
380		usb2_start_hardware(xfer);
381		return;
382
383	default:			/* Error */
384		if (xfer->error != USB_ERR_CANCELLED) {
385			/* try to clear stall first */
386			xfer->flags.stall_pipe = 1;
387			goto tr_setup;
388		}
389		return;
390	}
391}
392
393static void
394uvscom_intr_callback(struct usb_xfer *xfer)
395{
396	struct uvscom_softc *sc = xfer->priv_sc;
397	uint8_t buf[2];
398
399	switch (USB_GET_STATE(xfer)) {
400	case USB_ST_TRANSFERRED:
401		if (xfer->actlen >= 2) {
402
403			usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf));
404
405			sc->sc_lsr = 0;
406			sc->sc_msr = 0;
407			sc->sc_unit_status = buf[1];
408
409			if (buf[0] & UVSCOM_TXRDY) {
410				sc->sc_lsr |= ULSR_TXRDY;
411			}
412			if (buf[0] & UVSCOM_RXRDY) {
413				sc->sc_lsr |= ULSR_RXRDY;
414			}
415			if (buf[1] & UVSCOM_CTS) {
416				sc->sc_msr |= SER_CTS;
417			}
418			if (buf[1] & UVSCOM_DSR) {
419				sc->sc_msr |= SER_DSR;
420			}
421			if (buf[1] & UVSCOM_DCD) {
422				sc->sc_msr |= SER_DCD;
423			}
424			/*
425			 * the UCOM layer will ignore this call if the TTY
426			 * device is closed!
427			 */
428			usb2_com_status_change(&sc->sc_ucom);
429		}
430	case USB_ST_SETUP:
431tr_setup:
432		xfer->frlengths[0] = xfer->max_data_length;
433		usb2_start_hardware(xfer);
434		return;
435
436	default:			/* Error */
437		if (xfer->error != USB_ERR_CANCELLED) {
438			/* try to clear stall first */
439			xfer->flags.stall_pipe = 1;
440			goto tr_setup;
441		}
442		return;
443	}
444}
445
446static void
447uvscom_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
448{
449	struct uvscom_softc *sc = ucom->sc_parent;
450
451	DPRINTF("onoff = %d\n", onoff);
452
453	if (onoff)
454		sc->sc_line |= UVSCOM_DTR;
455	else
456		sc->sc_line &= ~UVSCOM_DTR;
457
458	uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
459}
460
461static void
462uvscom_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
463{
464	struct uvscom_softc *sc = ucom->sc_parent;
465
466	DPRINTF("onoff = %d\n", onoff);
467
468	if (onoff)
469		sc->sc_line |= UVSCOM_RTS;
470	else
471		sc->sc_line &= ~UVSCOM_RTS;
472
473	uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
474}
475
476static void
477uvscom_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
478{
479	struct uvscom_softc *sc = ucom->sc_parent;
480
481	DPRINTF("onoff = %d\n", onoff);
482
483	if (onoff)
484		sc->sc_line |= UVSCOM_BREAK;
485	else
486		sc->sc_line &= ~UVSCOM_BREAK;
487
488	uvscom_cfg_write(sc, UVSCOM_LINE_CTL, sc->sc_line);
489}
490
491static int
492uvscom_pre_param(struct ucom_softc *ucom, struct termios *t)
493{
494	switch (t->c_ospeed) {
495		case B150:
496		case B300:
497		case B600:
498		case B1200:
499		case B2400:
500		case B4800:
501		case B9600:
502		case B19200:
503		case B38400:
504		case B57600:
505		case B115200:
506		default:
507		return (EINVAL);
508	}
509	return (0);
510}
511
512static void
513uvscom_cfg_param(struct ucom_softc *ucom, struct termios *t)
514{
515	struct uvscom_softc *sc = ucom->sc_parent;
516	uint16_t value;
517
518	DPRINTF("\n");
519
520	switch (t->c_ospeed) {
521	case B150:
522		value = UVSCOM_SPEED_150BPS;
523		break;
524	case B300:
525		value = UVSCOM_SPEED_300BPS;
526		break;
527	case B600:
528		value = UVSCOM_SPEED_600BPS;
529		break;
530	case B1200:
531		value = UVSCOM_SPEED_1200BPS;
532		break;
533	case B2400:
534		value = UVSCOM_SPEED_2400BPS;
535		break;
536	case B4800:
537		value = UVSCOM_SPEED_4800BPS;
538		break;
539	case B9600:
540		value = UVSCOM_SPEED_9600BPS;
541		break;
542	case B19200:
543		value = UVSCOM_SPEED_19200BPS;
544		break;
545	case B38400:
546		value = UVSCOM_SPEED_38400BPS;
547		break;
548	case B57600:
549		value = UVSCOM_SPEED_57600BPS;
550		break;
551	case B115200:
552		value = UVSCOM_SPEED_115200BPS;
553		break;
554	default:
555		return;
556	}
557
558	uvscom_cfg_write(sc, UVSCOM_SET_SPEED, value);
559
560	value = 0;
561
562	if (t->c_cflag & CSTOPB) {
563		value |= UVSCOM_STOP_BIT_2;
564	}
565	if (t->c_cflag & PARENB) {
566		if (t->c_cflag & PARODD) {
567			value |= UVSCOM_PARITY_ODD;
568		} else {
569			value |= UVSCOM_PARITY_EVEN;
570		}
571	} else {
572		value |= UVSCOM_PARITY_NONE;
573	}
574
575	switch (t->c_cflag & CSIZE) {
576	case CS5:
577		value |= UVSCOM_DATA_BIT_5;
578		break;
579	case CS6:
580		value |= UVSCOM_DATA_BIT_6;
581		break;
582	case CS7:
583		value |= UVSCOM_DATA_BIT_7;
584		break;
585	default:
586	case CS8:
587		value |= UVSCOM_DATA_BIT_8;
588		break;
589	}
590
591	uvscom_cfg_write(sc, UVSCOM_SET_PARAM, value);
592}
593
594static int
595uvscom_pre_open(struct ucom_softc *ucom)
596{
597	struct uvscom_softc *sc = ucom->sc_parent;
598
599	DPRINTF("sc = %p\n", sc);
600
601	/* check if PC card was inserted */
602
603	if (sc->sc_unit_status & UVSCOM_NOCARD) {
604		DPRINTF("no PC card!\n");
605		return (ENXIO);
606	}
607	return (0);
608}
609
610static void
611uvscom_cfg_open(struct ucom_softc *ucom)
612{
613	struct uvscom_softc *sc = ucom->sc_parent;
614
615	DPRINTF("sc = %p\n", sc);
616
617	uvscom_cfg_read_status(sc);
618}
619
620static void
621uvscom_cfg_close(struct ucom_softc *ucom)
622{
623	struct uvscom_softc *sc = ucom->sc_parent;
624
625	DPRINTF("sc=%p\n", sc);
626
627	uvscom_cfg_write(sc, UVSCOM_SHUTDOWN, 0);
628}
629
630static void
631uvscom_start_read(struct ucom_softc *ucom)
632{
633	struct uvscom_softc *sc = ucom->sc_parent;
634
635	usb2_transfer_start(sc->sc_xfer[UVSCOM_BULK_DT_RD]);
636}
637
638static void
639uvscom_stop_read(struct ucom_softc *ucom)
640{
641	struct uvscom_softc *sc = ucom->sc_parent;
642
643	usb2_transfer_stop(sc->sc_xfer[UVSCOM_BULK_DT_RD]);
644}
645
646static void
647uvscom_start_write(struct ucom_softc *ucom)
648{
649	struct uvscom_softc *sc = ucom->sc_parent;
650
651	usb2_transfer_start(sc->sc_xfer[UVSCOM_BULK_DT_WR]);
652}
653
654static void
655uvscom_stop_write(struct ucom_softc *ucom)
656{
657	struct uvscom_softc *sc = ucom->sc_parent;
658
659	usb2_transfer_stop(sc->sc_xfer[UVSCOM_BULK_DT_WR]);
660}
661
662static void
663uvscom_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
664{
665	struct uvscom_softc *sc = ucom->sc_parent;
666
667	*lsr = sc->sc_lsr;
668	*msr = sc->sc_msr;
669}
670
671static void
672uvscom_cfg_write(struct uvscom_softc *sc, uint8_t index, uint16_t value)
673{
674	struct usb_device_request req;
675	usb2_error_t err;
676
677	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
678	req.bRequest = index;
679	USETW(req.wValue, value);
680	USETW(req.wIndex, 0);
681	USETW(req.wLength, 0);
682
683	err = usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
684	    &req, NULL, 0, 1000);
685	if (err) {
686		DPRINTFN(0, "device request failed, err=%s "
687		    "(ignored)\n", usb2_errstr(err));
688	}
689}
690
691static uint16_t
692uvscom_cfg_read_status(struct uvscom_softc *sc)
693{
694	struct usb_device_request req;
695	usb2_error_t err;
696	uint8_t data[2];
697
698	req.bmRequestType = UT_READ_VENDOR_DEVICE;
699	req.bRequest = UVSCOM_READ_STATUS;
700	USETW(req.wValue, 0);
701	USETW(req.wIndex, 0);
702	USETW(req.wLength, 2);
703
704	err = usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
705	    &req, data, 0, 1000);
706	if (err) {
707		DPRINTFN(0, "device request failed, err=%s "
708		    "(ignored)\n", usb2_errstr(err));
709	}
710	return (data[0] | (data[1] << 8));
711}
712