uslcom.c revision 190734
1188413Sthompsa/*	$OpenBSD: uslcom.c,v 1.17 2007/11/24 10:52:12 jsg Exp $	*/
2188413Sthompsa
3188413Sthompsa#include <sys/cdefs.h>
4188413Sthompsa__FBSDID("$FreeBSD: head/sys/dev/usb/serial/uslcom.c 190734 2009-04-05 18:20:38Z thompsa $");
5188413Sthompsa
6188413Sthompsa/*
7188413Sthompsa * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
8188413Sthompsa *
9188413Sthompsa * Permission to use, copy, modify, and distribute this software for any
10188413Sthompsa * purpose with or without fee is hereby granted, provided that the above
11188413Sthompsa * copyright notice and this permission notice appear in all copies.
12188413Sthompsa *
13188413Sthompsa * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14188413Sthompsa * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15188413Sthompsa * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16188413Sthompsa * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17188413Sthompsa * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18188413Sthompsa * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19188413Sthompsa * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20188413Sthompsa */
21188413Sthompsa
22188746Sthompsa#include "usbdevs.h"
23188942Sthompsa#include <dev/usb/usb.h>
24188942Sthompsa#include <dev/usb/usb_mfunc.h>
25188942Sthompsa#include <dev/usb/usb_error.h>
26188413Sthompsa
27188413Sthompsa#define	USB_DEBUG_VAR uslcom_debug
28188413Sthompsa
29188942Sthompsa#include <dev/usb/usb_core.h>
30188942Sthompsa#include <dev/usb/usb_debug.h>
31188942Sthompsa#include <dev/usb/usb_process.h>
32188942Sthompsa#include <dev/usb/usb_request.h>
33188942Sthompsa#include <dev/usb/usb_lookup.h>
34188942Sthompsa#include <dev/usb/usb_util.h>
35188942Sthompsa#include <dev/usb/usb_busdma.h>
36188413Sthompsa
37188942Sthompsa#include <dev/usb/serial/usb_serial.h>
38188413Sthompsa
39188413Sthompsa#if USB_DEBUG
40188413Sthompsastatic int uslcom_debug = 0;
41188413Sthompsa
42188664SthompsaSYSCTL_NODE(_hw_usb2, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom");
43188664SthompsaSYSCTL_INT(_hw_usb2_uslcom, OID_AUTO, debug, CTLFLAG_RW,
44188413Sthompsa    &uslcom_debug, 0, "Debug level");
45188413Sthompsa#endif
46188413Sthompsa
47188413Sthompsa#define	USLCOM_BULK_BUF_SIZE		1024
48188413Sthompsa#define	USLCOM_CONFIG_INDEX	0
49188413Sthompsa#define	USLCOM_IFACE_INDEX	0
50188413Sthompsa
51188413Sthompsa#define	USLCOM_SET_DATA_BITS(x)	((x) << 8)
52188413Sthompsa
53188413Sthompsa#define	USLCOM_WRITE		0x41
54188413Sthompsa#define	USLCOM_READ		0xc1
55188413Sthompsa
56188413Sthompsa#define	USLCOM_UART		0x00
57188413Sthompsa#define	USLCOM_BAUD_RATE	0x01
58188413Sthompsa#define	USLCOM_DATA		0x03
59188413Sthompsa#define	USLCOM_BREAK		0x05
60188413Sthompsa#define	USLCOM_CTRL		0x07
61188413Sthompsa
62188413Sthompsa#define	USLCOM_UART_DISABLE	0x00
63188413Sthompsa#define	USLCOM_UART_ENABLE	0x01
64188413Sthompsa
65188413Sthompsa#define	USLCOM_CTRL_DTR_ON	0x0001
66188413Sthompsa#define	USLCOM_CTRL_DTR_SET	0x0100
67188413Sthompsa#define	USLCOM_CTRL_RTS_ON	0x0002
68188413Sthompsa#define	USLCOM_CTRL_RTS_SET	0x0200
69188413Sthompsa#define	USLCOM_CTRL_CTS		0x0010
70188413Sthompsa#define	USLCOM_CTRL_DSR		0x0020
71188413Sthompsa#define	USLCOM_CTRL_DCD		0x0080
72188413Sthompsa
73188413Sthompsa#define	USLCOM_BAUD_REF		0x384000
74188413Sthompsa
75188413Sthompsa#define	USLCOM_STOP_BITS_1	0x00
76188413Sthompsa#define	USLCOM_STOP_BITS_2	0x02
77188413Sthompsa
78188413Sthompsa#define	USLCOM_PARITY_NONE	0x00
79188413Sthompsa#define	USLCOM_PARITY_ODD	0x10
80188413Sthompsa#define	USLCOM_PARITY_EVEN	0x20
81188413Sthompsa
82188413Sthompsa#define	USLCOM_PORT_NO		0xFFFF /* XXX think this should be 0 --hps */
83188413Sthompsa
84188413Sthompsa#define	USLCOM_BREAK_OFF	0x00
85188413Sthompsa#define	USLCOM_BREAK_ON		0x01
86188413Sthompsa
87188413Sthompsaenum {
88188413Sthompsa	USLCOM_BULK_DT_WR,
89188413Sthompsa	USLCOM_BULK_DT_RD,
90188413Sthompsa	USLCOM_N_TRANSFER,
91188413Sthompsa};
92188413Sthompsa
93188413Sthompsastruct uslcom_softc {
94188413Sthompsa	struct usb2_com_super_softc sc_super_ucom;
95188413Sthompsa	struct usb2_com_softc sc_ucom;
96188413Sthompsa
97188413Sthompsa	struct usb2_xfer *sc_xfer[USLCOM_N_TRANSFER];
98188413Sthompsa	struct usb2_device *sc_udev;
99189265Sthompsa	struct mtx sc_mtx;
100188413Sthompsa
101188413Sthompsa	uint8_t		 sc_msr;
102188413Sthompsa	uint8_t		 sc_lsr;
103188413Sthompsa};
104188413Sthompsa
105188413Sthompsastatic device_probe_t uslcom_probe;
106188413Sthompsastatic device_attach_t uslcom_attach;
107188413Sthompsastatic device_detach_t uslcom_detach;
108188413Sthompsa
109188413Sthompsastatic usb2_callback_t uslcom_write_callback;
110188413Sthompsastatic usb2_callback_t uslcom_read_callback;
111188413Sthompsa
112188413Sthompsastatic void uslcom_open(struct usb2_com_softc *);
113188413Sthompsastatic void uslcom_close(struct usb2_com_softc *);
114188413Sthompsastatic void uslcom_set_dtr(struct usb2_com_softc *, uint8_t);
115188413Sthompsastatic void uslcom_set_rts(struct usb2_com_softc *, uint8_t);
116188413Sthompsastatic void uslcom_set_break(struct usb2_com_softc *, uint8_t);
117188413Sthompsastatic int uslcom_pre_param(struct usb2_com_softc *, struct termios *);
118188413Sthompsastatic void uslcom_param(struct usb2_com_softc *, struct termios *);
119188413Sthompsastatic void uslcom_get_status(struct usb2_com_softc *, uint8_t *, uint8_t *);
120188413Sthompsastatic void uslcom_start_read(struct usb2_com_softc *);
121188413Sthompsastatic void uslcom_stop_read(struct usb2_com_softc *);
122188413Sthompsastatic void uslcom_start_write(struct usb2_com_softc *);
123188413Sthompsastatic void uslcom_stop_write(struct usb2_com_softc *);
124188413Sthompsa
125188413Sthompsastatic const struct usb2_config uslcom_config[USLCOM_N_TRANSFER] = {
126188413Sthompsa
127188413Sthompsa	[USLCOM_BULK_DT_WR] = {
128188413Sthompsa		.type = UE_BULK,
129188413Sthompsa		.endpoint = UE_ADDR_ANY,
130188413Sthompsa		.direction = UE_DIR_OUT,
131190734Sthompsa		.bufsize = USLCOM_BULK_BUF_SIZE,
132190734Sthompsa		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
133190734Sthompsa		.callback = &uslcom_write_callback,
134188413Sthompsa	},
135188413Sthompsa
136188413Sthompsa	[USLCOM_BULK_DT_RD] = {
137188413Sthompsa		.type = UE_BULK,
138188413Sthompsa		.endpoint = UE_ADDR_ANY,
139188413Sthompsa		.direction = UE_DIR_IN,
140190734Sthompsa		.bufsize = USLCOM_BULK_BUF_SIZE,
141190734Sthompsa		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
142190734Sthompsa		.callback = &uslcom_read_callback,
143188413Sthompsa	},
144188413Sthompsa};
145188413Sthompsa
146188413Sthompsastruct usb2_com_callback uslcom_callback = {
147188413Sthompsa	.usb2_com_cfg_open = &uslcom_open,
148188413Sthompsa	.usb2_com_cfg_close = &uslcom_close,
149188413Sthompsa	.usb2_com_cfg_get_status = &uslcom_get_status,
150188413Sthompsa	.usb2_com_cfg_set_dtr = &uslcom_set_dtr,
151188413Sthompsa	.usb2_com_cfg_set_rts = &uslcom_set_rts,
152188413Sthompsa	.usb2_com_cfg_set_break = &uslcom_set_break,
153188413Sthompsa	.usb2_com_cfg_param = &uslcom_param,
154188413Sthompsa	.usb2_com_pre_param = &uslcom_pre_param,
155188413Sthompsa	.usb2_com_start_read = &uslcom_start_read,
156188413Sthompsa	.usb2_com_stop_read = &uslcom_stop_read,
157188413Sthompsa	.usb2_com_start_write = &uslcom_start_write,
158188413Sthompsa	.usb2_com_stop_write = &uslcom_stop_write,
159188413Sthompsa};
160188413Sthompsa
161188413Sthompsastatic const struct usb2_device_id uslcom_devs[] = {
162188413Sthompsa    { USB_VPI(USB_VENDOR_BALTECH,	USB_PRODUCT_BALTECH_CARDREADER, 0) },
163188413Sthompsa    { USB_VPI(USB_VENDOR_DYNASTREAM,	USB_PRODUCT_DYNASTREAM_ANTDEVBOARD, 0) },
164188413Sthompsa    { USB_VPI(USB_VENDOR_JABLOTRON,	USB_PRODUCT_JABLOTRON_PC60B, 0) },
165188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_ARGUSISP, 0) },
166188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_CRUMB128, 0) },
167188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_DEGREE, 0) },
168188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_BURNSIDE, 0) },
169188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_HELICOM, 0) },
170188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_LIPOWSKY_HARP, 0) },
171188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_LIPOWSKY_JTAG, 0) },
172188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_LIPOWSKY_LIN, 0) },
173188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_POLOLU, 0) },
174188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_CP2102, 0) },
175188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_CP210X_2, 0) },
176188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_SUUNTO, 0) },
177188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_TRAQMATE, 0) },
178188413Sthompsa    { USB_VPI(USB_VENDOR_SILABS2,	USB_PRODUCT_SILABS2_DCU11CLONE, 0) },
179188413Sthompsa    { USB_VPI(USB_VENDOR_USI,		USB_PRODUCT_USI_MC60, 0) },
180188413Sthompsa};
181188413Sthompsa
182188413Sthompsastatic device_method_t uslcom_methods[] = {
183188413Sthompsa	DEVMETHOD(device_probe, uslcom_probe),
184188413Sthompsa	DEVMETHOD(device_attach, uslcom_attach),
185188413Sthompsa	DEVMETHOD(device_detach, uslcom_detach),
186188413Sthompsa	{0, 0}
187188413Sthompsa};
188188413Sthompsa
189188413Sthompsastatic devclass_t uslcom_devclass;
190188413Sthompsa
191188413Sthompsastatic driver_t uslcom_driver = {
192188664Sthompsa	.name = "uslcom",
193188413Sthompsa	.methods = uslcom_methods,
194188413Sthompsa	.size = sizeof(struct uslcom_softc),
195188413Sthompsa};
196188413Sthompsa
197189275SthompsaDRIVER_MODULE(uslcom, uhub, uslcom_driver, uslcom_devclass, NULL, 0);
198188942SthompsaMODULE_DEPEND(uslcom, ucom, 1, 1, 1);
199188942SthompsaMODULE_DEPEND(uslcom, usb, 1, 1, 1);
200188664SthompsaMODULE_VERSION(uslcom, 1);
201188413Sthompsa
202188413Sthompsastatic int
203188413Sthompsauslcom_probe(device_t dev)
204188413Sthompsa{
205188413Sthompsa	struct usb2_attach_arg *uaa = device_get_ivars(dev);
206188413Sthompsa
207188413Sthompsa	DPRINTFN(11, "\n");
208188413Sthompsa
209188413Sthompsa	if (uaa->usb2_mode != USB_MODE_HOST) {
210188413Sthompsa		return (ENXIO);
211188413Sthompsa	}
212188413Sthompsa	if (uaa->info.bConfigIndex != USLCOM_CONFIG_INDEX) {
213188413Sthompsa		return (ENXIO);
214188413Sthompsa	}
215188413Sthompsa	if (uaa->info.bIfaceIndex != USLCOM_IFACE_INDEX) {
216188413Sthompsa		return (ENXIO);
217188413Sthompsa	}
218188413Sthompsa	return (usb2_lookup_id_by_uaa(uslcom_devs, sizeof(uslcom_devs), uaa));
219188413Sthompsa}
220188413Sthompsa
221188413Sthompsastatic int
222188413Sthompsauslcom_attach(device_t dev)
223188413Sthompsa{
224188413Sthompsa	struct usb2_attach_arg *uaa = device_get_ivars(dev);
225188413Sthompsa	struct uslcom_softc *sc = device_get_softc(dev);
226188413Sthompsa	int error;
227188413Sthompsa
228188413Sthompsa	DPRINTFN(11, "\n");
229188413Sthompsa
230188413Sthompsa	device_set_usb2_desc(dev);
231189265Sthompsa	mtx_init(&sc->sc_mtx, "uslcom", NULL, MTX_DEF);
232188413Sthompsa
233188413Sthompsa	sc->sc_udev = uaa->device;
234188413Sthompsa
235188413Sthompsa	error = usb2_transfer_setup(uaa->device,
236188413Sthompsa	    &uaa->info.bIfaceIndex, sc->sc_xfer, uslcom_config,
237189265Sthompsa	    USLCOM_N_TRANSFER, sc, &sc->sc_mtx);
238188413Sthompsa	if (error) {
239188413Sthompsa		DPRINTF("one or more missing USB endpoints, "
240188413Sthompsa		    "error=%s\n", usb2_errstr(error));
241188413Sthompsa		goto detach;
242188413Sthompsa	}
243188413Sthompsa	/* clear stall at first run */
244189265Sthompsa	mtx_lock(&sc->sc_mtx);
245188413Sthompsa	usb2_transfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_WR]);
246188413Sthompsa	usb2_transfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_RD]);
247189265Sthompsa	mtx_unlock(&sc->sc_mtx);
248188413Sthompsa
249188413Sthompsa	error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
250189265Sthompsa	    &uslcom_callback, &sc->sc_mtx);
251188413Sthompsa	if (error) {
252188413Sthompsa		goto detach;
253188413Sthompsa	}
254188413Sthompsa	return (0);
255188413Sthompsa
256188413Sthompsadetach:
257188413Sthompsa	uslcom_detach(dev);
258188413Sthompsa	return (ENXIO);
259188413Sthompsa}
260188413Sthompsa
261188413Sthompsastatic int
262188413Sthompsauslcom_detach(device_t dev)
263188413Sthompsa{
264188413Sthompsa	struct uslcom_softc *sc = device_get_softc(dev);
265188413Sthompsa
266188413Sthompsa	DPRINTF("sc=%p\n", sc);
267188413Sthompsa
268188413Sthompsa	usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
269188413Sthompsa	usb2_transfer_unsetup(sc->sc_xfer, USLCOM_N_TRANSFER);
270189265Sthompsa	mtx_destroy(&sc->sc_mtx);
271188413Sthompsa
272188413Sthompsa	return (0);
273188413Sthompsa}
274188413Sthompsa
275188413Sthompsastatic void
276188413Sthompsauslcom_open(struct usb2_com_softc *ucom)
277188413Sthompsa{
278188413Sthompsa	struct uslcom_softc *sc = ucom->sc_parent;
279188413Sthompsa	struct usb2_device_request req;
280188413Sthompsa
281188413Sthompsa	req.bmRequestType = USLCOM_WRITE;
282188413Sthompsa	req.bRequest = USLCOM_UART;
283188413Sthompsa	USETW(req.wValue, USLCOM_UART_ENABLE);
284188413Sthompsa	USETW(req.wIndex, USLCOM_PORT_NO);
285188413Sthompsa	USETW(req.wLength, 0);
286188413Sthompsa
287188413Sthompsa        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
288188413Sthompsa	    &req, NULL, 0, 1000)) {
289188413Sthompsa		DPRINTF("UART enable failed (ignored)\n");
290188413Sthompsa	}
291188413Sthompsa}
292188413Sthompsa
293188413Sthompsastatic void
294188413Sthompsauslcom_close(struct usb2_com_softc *ucom)
295188413Sthompsa{
296188413Sthompsa	struct uslcom_softc *sc = ucom->sc_parent;
297188413Sthompsa	struct usb2_device_request req;
298188413Sthompsa
299188413Sthompsa	req.bmRequestType = USLCOM_WRITE;
300188413Sthompsa	req.bRequest = USLCOM_UART;
301188413Sthompsa	USETW(req.wValue, USLCOM_UART_DISABLE);
302188413Sthompsa	USETW(req.wIndex, USLCOM_PORT_NO);
303188413Sthompsa	USETW(req.wLength, 0);
304188413Sthompsa
305188413Sthompsa        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
306188413Sthompsa	    &req, NULL, 0, 1000)) {
307188413Sthompsa		DPRINTF("UART disable failed (ignored)\n");
308188413Sthompsa	}
309188413Sthompsa}
310188413Sthompsa
311188413Sthompsastatic void
312188413Sthompsauslcom_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
313188413Sthompsa{
314188413Sthompsa        struct uslcom_softc *sc = ucom->sc_parent;
315188413Sthompsa	struct usb2_device_request req;
316188413Sthompsa	uint16_t ctl;
317188413Sthompsa
318188413Sthompsa        DPRINTF("onoff = %d\n", onoff);
319188413Sthompsa
320188413Sthompsa	ctl = onoff ? USLCOM_CTRL_DTR_ON : 0;
321188413Sthompsa	ctl |= USLCOM_CTRL_DTR_SET;
322188413Sthompsa
323188413Sthompsa	req.bmRequestType = USLCOM_WRITE;
324188413Sthompsa	req.bRequest = USLCOM_CTRL;
325188413Sthompsa	USETW(req.wValue, ctl);
326188413Sthompsa	USETW(req.wIndex, USLCOM_PORT_NO);
327188413Sthompsa	USETW(req.wLength, 0);
328188413Sthompsa
329188413Sthompsa        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
330188413Sthompsa	    &req, NULL, 0, 1000)) {
331188413Sthompsa		DPRINTF("Setting DTR failed (ignored)\n");
332188413Sthompsa	}
333188413Sthompsa}
334188413Sthompsa
335188413Sthompsastatic void
336188413Sthompsauslcom_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
337188413Sthompsa{
338188413Sthompsa        struct uslcom_softc *sc = ucom->sc_parent;
339188413Sthompsa	struct usb2_device_request req;
340188413Sthompsa	uint16_t ctl;
341188413Sthompsa
342188413Sthompsa        DPRINTF("onoff = %d\n", onoff);
343188413Sthompsa
344188413Sthompsa	ctl = onoff ? USLCOM_CTRL_RTS_ON : 0;
345188413Sthompsa	ctl |= USLCOM_CTRL_RTS_SET;
346188413Sthompsa
347188413Sthompsa	req.bmRequestType = USLCOM_WRITE;
348188413Sthompsa	req.bRequest = USLCOM_CTRL;
349188413Sthompsa	USETW(req.wValue, ctl);
350188413Sthompsa	USETW(req.wIndex, USLCOM_PORT_NO);
351188413Sthompsa	USETW(req.wLength, 0);
352188413Sthompsa
353188413Sthompsa        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
354188413Sthompsa	    &req, NULL, 0, 1000)) {
355188413Sthompsa		DPRINTF("Setting DTR failed (ignored)\n");
356188413Sthompsa	}
357188413Sthompsa}
358188413Sthompsa
359188413Sthompsastatic int
360188413Sthompsauslcom_pre_param(struct usb2_com_softc *ucom, struct termios *t)
361188413Sthompsa{
362188413Sthompsa	if (t->c_ospeed <= 0 || t->c_ospeed > 921600)
363188413Sthompsa		return (EINVAL);
364188413Sthompsa	return (0);
365188413Sthompsa}
366188413Sthompsa
367188413Sthompsastatic void
368188413Sthompsauslcom_param(struct usb2_com_softc *ucom, struct termios *t)
369188413Sthompsa{
370188413Sthompsa	struct uslcom_softc *sc = ucom->sc_parent;
371188413Sthompsa	struct usb2_device_request req;
372188413Sthompsa	uint16_t data;
373188413Sthompsa
374188413Sthompsa	DPRINTF("\n");
375188413Sthompsa
376188413Sthompsa	req.bmRequestType = USLCOM_WRITE;
377188413Sthompsa	req.bRequest = USLCOM_BAUD_RATE;
378188413Sthompsa	USETW(req.wValue, USLCOM_BAUD_REF / t->c_ospeed);
379188413Sthompsa	USETW(req.wIndex, USLCOM_PORT_NO);
380188413Sthompsa	USETW(req.wLength, 0);
381188413Sthompsa
382188413Sthompsa        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
383188413Sthompsa	    &req, NULL, 0, 1000)) {
384188413Sthompsa		DPRINTF("Set baudrate failed (ignored)\n");
385188413Sthompsa	}
386188413Sthompsa
387188413Sthompsa	if (t->c_cflag & CSTOPB)
388188413Sthompsa		data = USLCOM_STOP_BITS_2;
389188413Sthompsa	else
390188413Sthompsa		data = USLCOM_STOP_BITS_1;
391188413Sthompsa	if (t->c_cflag & PARENB) {
392188413Sthompsa		if (t->c_cflag & PARODD)
393188413Sthompsa			data |= USLCOM_PARITY_ODD;
394188413Sthompsa		else
395188413Sthompsa			data |= USLCOM_PARITY_EVEN;
396188413Sthompsa	} else
397188413Sthompsa		data |= USLCOM_PARITY_NONE;
398188413Sthompsa	switch (t->c_cflag & CSIZE) {
399188413Sthompsa	case CS5:
400188413Sthompsa		data |= USLCOM_SET_DATA_BITS(5);
401188413Sthompsa		break;
402188413Sthompsa	case CS6:
403188413Sthompsa		data |= USLCOM_SET_DATA_BITS(6);
404188413Sthompsa		break;
405188413Sthompsa	case CS7:
406188413Sthompsa		data |= USLCOM_SET_DATA_BITS(7);
407188413Sthompsa		break;
408188413Sthompsa	case CS8:
409188413Sthompsa		data |= USLCOM_SET_DATA_BITS(8);
410188413Sthompsa		break;
411188413Sthompsa	}
412188413Sthompsa
413188413Sthompsa	req.bmRequestType = USLCOM_WRITE;
414188413Sthompsa	req.bRequest = USLCOM_DATA;
415188413Sthompsa	USETW(req.wValue, data);
416188413Sthompsa	USETW(req.wIndex, USLCOM_PORT_NO);
417188413Sthompsa	USETW(req.wLength, 0);
418188413Sthompsa
419188413Sthompsa        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
420188413Sthompsa	    &req, NULL, 0, 1000)) {
421188413Sthompsa		DPRINTF("Set format failed (ignored)\n");
422188413Sthompsa	}
423188413Sthompsa	return;
424188413Sthompsa}
425188413Sthompsa
426188413Sthompsastatic void
427188413Sthompsauslcom_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
428188413Sthompsa{
429188413Sthompsa	struct uslcom_softc *sc = ucom->sc_parent;
430188413Sthompsa
431188413Sthompsa	DPRINTF("\n");
432188413Sthompsa
433188413Sthompsa	*lsr = sc->sc_lsr;
434188413Sthompsa	*msr = sc->sc_msr;
435188413Sthompsa}
436188413Sthompsa
437188413Sthompsastatic void
438188413Sthompsauslcom_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
439188413Sthompsa{
440188413Sthompsa        struct uslcom_softc *sc = ucom->sc_parent;
441188413Sthompsa	struct usb2_device_request req;
442188413Sthompsa	uint16_t brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF;
443188413Sthompsa
444188413Sthompsa	req.bmRequestType = USLCOM_WRITE;
445188413Sthompsa	req.bRequest = USLCOM_BREAK;
446188413Sthompsa	USETW(req.wValue, brk);
447188413Sthompsa	USETW(req.wIndex, USLCOM_PORT_NO);
448188413Sthompsa	USETW(req.wLength, 0);
449188413Sthompsa
450188413Sthompsa        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
451188413Sthompsa	    &req, NULL, 0, 1000)) {
452188413Sthompsa		DPRINTF("Set BREAK failed (ignored)\n");
453188413Sthompsa	}
454188413Sthompsa}
455188413Sthompsa
456188413Sthompsastatic void
457188413Sthompsauslcom_write_callback(struct usb2_xfer *xfer)
458188413Sthompsa{
459188413Sthompsa	struct uslcom_softc *sc = xfer->priv_sc;
460188413Sthompsa	uint32_t actlen;
461188413Sthompsa
462188413Sthompsa	switch (USB_GET_STATE(xfer)) {
463188413Sthompsa	case USB_ST_SETUP:
464188413Sthompsa	case USB_ST_TRANSFERRED:
465188413Sthompsatr_setup:
466188413Sthompsa		if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0,
467188413Sthompsa		    USLCOM_BULK_BUF_SIZE, &actlen)) {
468188413Sthompsa
469188413Sthompsa			DPRINTF("actlen = %d\n", actlen);
470188413Sthompsa
471188413Sthompsa			xfer->frlengths[0] = actlen;
472188413Sthompsa			usb2_start_hardware(xfer);
473188413Sthompsa		}
474188413Sthompsa		return;
475188413Sthompsa
476188413Sthompsa	default:			/* Error */
477188413Sthompsa		if (xfer->error != USB_ERR_CANCELLED) {
478188413Sthompsa			/* try to clear stall first */
479188413Sthompsa			xfer->flags.stall_pipe = 1;
480188413Sthompsa			goto tr_setup;
481188413Sthompsa		}
482188413Sthompsa		return;
483188413Sthompsa	}
484188413Sthompsa}
485188413Sthompsa
486188413Sthompsastatic void
487188413Sthompsauslcom_read_callback(struct usb2_xfer *xfer)
488188413Sthompsa{
489188413Sthompsa	struct uslcom_softc *sc = xfer->priv_sc;
490188413Sthompsa
491188413Sthompsa	switch (USB_GET_STATE(xfer)) {
492188413Sthompsa	case USB_ST_TRANSFERRED:
493188413Sthompsa		usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen);
494188413Sthompsa
495188413Sthompsa	case USB_ST_SETUP:
496188413Sthompsatr_setup:
497188413Sthompsa		xfer->frlengths[0] = xfer->max_data_length;
498188413Sthompsa		usb2_start_hardware(xfer);
499188413Sthompsa		return;
500188413Sthompsa
501188413Sthompsa	default:			/* Error */
502188413Sthompsa		if (xfer->error != USB_ERR_CANCELLED) {
503188413Sthompsa			/* try to clear stall first */
504188413Sthompsa			xfer->flags.stall_pipe = 1;
505188413Sthompsa			goto tr_setup;
506188413Sthompsa		}
507188413Sthompsa		return;
508188413Sthompsa	}
509188413Sthompsa}
510188413Sthompsa
511188413Sthompsastatic void
512188413Sthompsauslcom_start_read(struct usb2_com_softc *ucom)
513188413Sthompsa{
514188413Sthompsa	struct uslcom_softc *sc = ucom->sc_parent;
515188413Sthompsa
516188413Sthompsa	/* start read endpoint */
517188413Sthompsa	usb2_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_RD]);
518188413Sthompsa}
519188413Sthompsa
520188413Sthompsastatic void
521188413Sthompsauslcom_stop_read(struct usb2_com_softc *ucom)
522188413Sthompsa{
523188413Sthompsa	struct uslcom_softc *sc = ucom->sc_parent;
524188413Sthompsa
525188413Sthompsa	/* stop read endpoint */
526188413Sthompsa	usb2_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_RD]);
527188413Sthompsa}
528188413Sthompsa
529188413Sthompsastatic void
530188413Sthompsauslcom_start_write(struct usb2_com_softc *ucom)
531188413Sthompsa{
532188413Sthompsa	struct uslcom_softc *sc = ucom->sc_parent;
533188413Sthompsa
534188413Sthompsa	usb2_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_WR]);
535188413Sthompsa}
536188413Sthompsa
537188413Sthompsastatic void
538188413Sthompsauslcom_stop_write(struct usb2_com_softc *ucom)
539188413Sthompsa{
540188413Sthompsa	struct uslcom_softc *sc = ucom->sc_parent;
541188413Sthompsa
542188413Sthompsa	usb2_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_WR]);
543188413Sthompsa}
544