xref: /dragonfly/sys/bus/u4b/serial/uslcom.c (revision 82730a9c)
1 /*	$OpenBSD: uslcom.c,v 1.17 2007/11/24 10:52:12 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/stdint.h>
20 #include <sys/param.h>
21 #include <sys/queue.h>
22 #include <sys/types.h>
23 #include <sys/systm.h>
24 #include <sys/kernel.h>
25 #include <sys/bus.h>
26 #include <sys/module.h>
27 #include <sys/lock.h>
28 #include <sys/condvar.h>
29 #include <sys/sysctl.h>
30 #include <sys/unistd.h>
31 #include <sys/callout.h>
32 #include <sys/malloc.h>
33 #include <sys/priv.h>
34 
35 #include <bus/u4b/usb.h>
36 #include <bus/u4b/usbdi.h>
37 #include <bus/u4b/usbdi_util.h>
38 #include <bus/u4b/usb_ioctl.h>
39 #include <bus/u4b/usbdevs.h>
40 
41 #define	USB_DEBUG_VAR uslcom_debug
42 #include <bus/u4b/usb_debug.h>
43 #include <bus/u4b/usb_process.h>
44 
45 #include <bus/u4b/serial/usb_serial.h>
46 
47 #ifdef USB_DEBUG
48 static int uslcom_debug = 0;
49 
50 static SYSCTL_NODE(_hw_usb, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom");
51 SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RW,
52     &uslcom_debug, 0, "Debug level");
53 #endif
54 
55 #define	USLCOM_BULK_BUF_SIZE		1024
56 #define	USLCOM_CONFIG_INDEX	0
57 #define	USLCOM_IFACE_INDEX	0
58 
59 #define	USLCOM_SET_DATA_BITS(x)	((x) << 8)
60 
61 /* Request types */
62 #define	USLCOM_WRITE		0x41
63 #define	USLCOM_READ		0xc1
64 
65 /* Request codes */
66 #define	USLCOM_UART		0x00
67 #define	USLCOM_BAUD_RATE	0x01
68 #define	USLCOM_DATA		0x03
69 #define	USLCOM_BREAK		0x05
70 #define	USLCOM_CTRL		0x07
71 #define	USLCOM_RCTRL            0x08
72 #define	USLCOM_SET_FLOWCTRL     0x13
73 #define	USLCOM_VENDOR_SPECIFIC	0xff
74 
75 /* USLCOM_UART values */
76 #define	USLCOM_UART_DISABLE	0x00
77 #define	USLCOM_UART_ENABLE	0x01
78 
79 /* USLCOM_CTRL/USLCOM_RCTRL values */
80 #define	USLCOM_CTRL_DTR_ON	0x0001
81 #define	USLCOM_CTRL_DTR_SET	0x0100
82 #define	USLCOM_CTRL_RTS_ON	0x0002
83 #define	USLCOM_CTRL_RTS_SET	0x0200
84 #define	USLCOM_CTRL_CTS		0x0010
85 #define	USLCOM_CTRL_DSR		0x0020
86 #define	USLCOM_CTRL_RI          0x0040
87 #define	USLCOM_CTRL_DCD		0x0080
88 
89 /* USLCOM_BAUD_RATE values */
90 #define	USLCOM_BAUD_REF		0x384000
91 
92 /* USLCOM_DATA values */
93 #define	USLCOM_STOP_BITS_1	0x00
94 #define	USLCOM_STOP_BITS_2	0x02
95 #define	USLCOM_PARITY_NONE	0x00
96 #define	USLCOM_PARITY_ODD	0x10
97 #define	USLCOM_PARITY_EVEN	0x20
98 
99 #define	USLCOM_PORT_NO		0x0000
100 
101 /* USLCOM_BREAK values */
102 #define	USLCOM_BREAK_OFF	0x00
103 #define	USLCOM_BREAK_ON		0x01
104 
105 /* USLCOM_SET_FLOWCTRL values - 1st word */
106 #define	USLCOM_FLOW_DTR_ON      0x00000001 /* DTR static active */
107 #define	USLCOM_FLOW_CTS_HS      0x00000008 /* CTS handshake */
108 /* USLCOM_SET_FLOWCTRL values - 2nd word */
109 #define	USLCOM_FLOW_RTS_ON      0x00000040 /* RTS static active */
110 #define	USLCOM_FLOW_RTS_HS      0x00000080 /* RTS handshake */
111 
112 /* USLCOM_VENDOR_SPECIFIC values */
113 #define	USLCOM_WRITE_LATCH	0x37E1
114 #define	USLCOM_READ_LATCH	0x00C2
115 
116 enum {
117 	USLCOM_BULK_DT_WR,
118 	USLCOM_BULK_DT_RD,
119 	USLCOM_CTRL_DT_RD,
120 	USLCOM_N_TRANSFER,
121 };
122 
123 struct uslcom_softc {
124 	struct ucom_super_softc sc_super_ucom;
125 	struct ucom_softc sc_ucom;
126 	struct usb_callout sc_watchdog;
127 
128 	struct usb_xfer *sc_xfer[USLCOM_N_TRANSFER];
129 	struct usb_device *sc_udev;
130 	struct lock sc_lock;
131 
132 	uint8_t		 sc_msr;
133 	uint8_t		 sc_lsr;
134 };
135 
136 static device_probe_t uslcom_probe;
137 static device_attach_t uslcom_attach;
138 static device_detach_t uslcom_detach;
139 
140 static usb_callback_t uslcom_write_callback;
141 static usb_callback_t uslcom_read_callback;
142 static usb_callback_t uslcom_control_callback;
143 
144 static void uslcom_open(struct ucom_softc *);
145 static void uslcom_close(struct ucom_softc *);
146 static void uslcom_set_dtr(struct ucom_softc *, uint8_t);
147 static void uslcom_set_rts(struct ucom_softc *, uint8_t);
148 static void uslcom_set_break(struct ucom_softc *, uint8_t);
149 static int uslcom_ioctl(struct ucom_softc *, uint32_t, caddr_t, int,
150 		struct thread *);
151 static int uslcom_pre_param(struct ucom_softc *, struct termios *);
152 static void uslcom_param(struct ucom_softc *, struct termios *);
153 static void uslcom_get_status(struct ucom_softc *, uint8_t *, uint8_t *);
154 static void uslcom_start_read(struct ucom_softc *);
155 static void uslcom_stop_read(struct ucom_softc *);
156 static void uslcom_start_write(struct ucom_softc *);
157 static void uslcom_stop_write(struct ucom_softc *);
158 static void uslcom_poll(struct ucom_softc *ucom);
159 
160 static const struct usb_config uslcom_config[USLCOM_N_TRANSFER] = {
161 
162 	[USLCOM_BULK_DT_WR] = {
163 		.type = UE_BULK,
164 		.endpoint = UE_ADDR_ANY,
165 		.direction = UE_DIR_OUT,
166 		.bufsize = USLCOM_BULK_BUF_SIZE,
167                .flags = {.pipe_bof = 1,},
168 		.callback = &uslcom_write_callback,
169 	},
170 
171 	[USLCOM_BULK_DT_RD] = {
172 		.type = UE_BULK,
173 		.endpoint = UE_ADDR_ANY,
174 		.direction = UE_DIR_IN,
175 		.bufsize = USLCOM_BULK_BUF_SIZE,
176 		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
177 		.callback = &uslcom_read_callback,
178 	},
179 	[USLCOM_CTRL_DT_RD] = {
180 		.type = UE_CONTROL,
181 		.endpoint = 0x00,
182 		.direction = UE_DIR_ANY,
183 		.bufsize = sizeof(struct usb_device_request) + 8,
184 		.flags = {.pipe_bof = 1,},
185 		.callback = &uslcom_control_callback,
186 		.timeout = 1000,	/* 1 second timeout */
187 	},
188 };
189 
190 static struct ucom_callback uslcom_callback = {
191 	.ucom_cfg_open = &uslcom_open,
192 	.ucom_cfg_close = &uslcom_close,
193 	.ucom_cfg_get_status = &uslcom_get_status,
194 	.ucom_cfg_set_dtr = &uslcom_set_dtr,
195 	.ucom_cfg_set_rts = &uslcom_set_rts,
196 	.ucom_cfg_set_break = &uslcom_set_break,
197 	.ucom_ioctl = &uslcom_ioctl,
198 	.ucom_cfg_param = &uslcom_param,
199 	.ucom_pre_param = &uslcom_pre_param,
200 	.ucom_start_read = &uslcom_start_read,
201 	.ucom_stop_read = &uslcom_stop_read,
202 	.ucom_start_write = &uslcom_start_write,
203 	.ucom_stop_write = &uslcom_stop_write,
204 	.ucom_poll = &uslcom_poll,
205 };
206 
207 static const STRUCT_USB_HOST_ID uslcom_devs[] = {
208 #define	USLCOM_DEV(v,p)  { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
209     USLCOM_DEV(BALTECH, CARDREADER),
210     USLCOM_DEV(CLIPSAL, 5500PCU),
211     USLCOM_DEV(DATAAPEX, MULTICOM),
212     USLCOM_DEV(DELL, DW700),
213     USLCOM_DEV(DIGIANSWER, ZIGBEE802154),
214     USLCOM_DEV(DYNASTREAM, ANTDEVBOARD),
215     USLCOM_DEV(DYNASTREAM, ANTDEVBOARD2),
216     USLCOM_DEV(DYNASTREAM, ANT2USB),
217     USLCOM_DEV(ELV, USBI2C),
218     USLCOM_DEV(FOXCONN, PIRELLI_DP_L10),
219     USLCOM_DEV(FOXCONN, TCOM_TC_300),
220     USLCOM_DEV(GEMALTO, PROXPU),
221     USLCOM_DEV(JABLOTRON, PC60B),
222     USLCOM_DEV(MEI, CASHFLOW_SC),
223     USLCOM_DEV(MEI, S2000),
224     USLCOM_DEV(JABLOTRON, PC60B),
225     USLCOM_DEV(OWEN, AC4),
226     USLCOM_DEV(PHILIPS, ACE1001),
227     USLCOM_DEV(PLX, CA42),
228     USLCOM_DEV(RENESAS, RX610),
229     USLCOM_DEV(SILABS, AEROCOMM),
230     USLCOM_DEV(SILABS, AMBER_AMB2560),
231     USLCOM_DEV(SILABS, ARGUSISP),
232     USLCOM_DEV(SILABS, ARKHAM_DS101_A),
233     USLCOM_DEV(SILABS, ARKHAM_DS101_M),
234     USLCOM_DEV(SILABS, ARYGON_MIFARE),
235     USLCOM_DEV(SILABS, AVIT_USB_TTL),
236     USLCOM_DEV(SILABS, B_G_H3000),
237     USLCOM_DEV(SILABS, BALLUFF_RFID),
238     USLCOM_DEV(SILABS, BEI_VCP),
239     USLCOM_DEV(SILABS, BSM7DUSB),
240     USLCOM_DEV(SILABS, BURNSIDE),
241     USLCOM_DEV(SILABS, C2_EDGE_MODEM),
242     USLCOM_DEV(SILABS, CP2102),
243     USLCOM_DEV(SILABS, CP210X_2),
244     USLCOM_DEV(SILABS, CRUMB128),
245     USLCOM_DEV(SILABS, CYGNAL),
246     USLCOM_DEV(SILABS, CYGNAL_DEBUG),
247     USLCOM_DEV(SILABS, CYGNAL_GPS),
248     USLCOM_DEV(SILABS, DEGREE),
249     USLCOM_DEV(SILABS, EMS_C1007),
250     USLCOM_DEV(SILABS, HELICOM),
251     USLCOM_DEV(SILABS, IMS_USB_RS422),
252     USLCOM_DEV(SILABS, INFINITY_MIC),
253     USLCOM_DEV(SILABS, INSYS_MODEM),
254     USLCOM_DEV(SILABS, KYOCERA_GPS),
255     USLCOM_DEV(SILABS, LIPOWSKY_HARP),
256     USLCOM_DEV(SILABS, LIPOWSKY_JTAG),
257     USLCOM_DEV(SILABS, LIPOWSKY_LIN),
258     USLCOM_DEV(SILABS, MC35PU),
259     USLCOM_DEV(SILABS, MJS_TOSLINK),
260     USLCOM_DEV(SILABS, MSD_DASHHAWK),
261     USLCOM_DEV(SILABS, POLOLU),
262     USLCOM_DEV(SILABS, PROCYON_AVS),
263     USLCOM_DEV(SILABS, SB_PARAMOUNT_ME),
264     USLCOM_DEV(SILABS, SUUNTO),
265     USLCOM_DEV(SILABS, TAMSMASTER),
266     USLCOM_DEV(SILABS, TELEGESIS_ETRX2),
267     USLCOM_DEV(SILABS, TRACIENT),
268     USLCOM_DEV(SILABS, TRAQMATE),
269     USLCOM_DEV(SILABS, USBCOUNT50),
270     USLCOM_DEV(SILABS, USBPULSE100),
271     USLCOM_DEV(SILABS, USBSCOPE50),
272     USLCOM_DEV(SILABS, USBWAVE12),
273     USLCOM_DEV(SILABS, VSTABI),
274     USLCOM_DEV(SILABS, WAVIT),
275     USLCOM_DEV(SILABS, WMRBATT),
276     USLCOM_DEV(SILABS, WMRRIGBLASTER),
277     USLCOM_DEV(SILABS, WMRRIGTALK),
278     USLCOM_DEV(SILABS, ZEPHYR_BIO),
279     USLCOM_DEV(SILABS2, DCU11CLONE),
280     USLCOM_DEV(SILABS3, GPRS_MODEM),
281     USLCOM_DEV(SILABS4, 100EU_MODEM),
282     USLCOM_DEV(SYNTECH, CYPHERLAB100),
283     USLCOM_DEV(USI, MC60),
284     USLCOM_DEV(VAISALA, CABLE),
285     USLCOM_DEV(WAGO, SERVICECABLE),
286     USLCOM_DEV(WAVESENSE, JAZZ),
287     USLCOM_DEV(WIENERPLEINBAUS, PL512),
288     USLCOM_DEV(WIENERPLEINBAUS, RCM),
289     USLCOM_DEV(WIENERPLEINBAUS, MPOD),
290     USLCOM_DEV(WIENERPLEINBAUS, CML),
291 #undef USLCOM_DEV
292 };
293 
294 static device_method_t uslcom_methods[] = {
295 	DEVMETHOD(device_probe, uslcom_probe),
296 	DEVMETHOD(device_attach, uslcom_attach),
297 	DEVMETHOD(device_detach, uslcom_detach),
298 	DEVMETHOD_END
299 };
300 
301 static devclass_t uslcom_devclass;
302 
303 static driver_t uslcom_driver = {
304 	.name = "uslcom",
305 	.methods = uslcom_methods,
306 	.size = sizeof(struct uslcom_softc),
307 };
308 
309 DRIVER_MODULE(uslcom, uhub, uslcom_driver, uslcom_devclass, NULL, 0);
310 MODULE_DEPEND(uslcom, ucom, 1, 1, 1);
311 MODULE_DEPEND(uslcom, usb, 1, 1, 1);
312 MODULE_VERSION(uslcom, 1);
313 
314 static void
315 uslcom_watchdog(void *arg)
316 {
317 	struct uslcom_softc *sc = arg;
318 
319 	KKASSERT(lockowned(&sc->sc_lock));
320 
321 	usbd_transfer_start(sc->sc_xfer[USLCOM_CTRL_DT_RD]);
322 
323 	usb_callout_reset(&sc->sc_watchdog,
324 	    hz / 4, &uslcom_watchdog, sc);
325 }
326 
327 static int
328 uslcom_probe(device_t dev)
329 {
330 	struct usb_attach_arg *uaa = device_get_ivars(dev);
331 
332 	DPRINTFN(11, "\n");
333 
334 	if (uaa->usb_mode != USB_MODE_HOST) {
335 		return (ENXIO);
336 	}
337 	if (uaa->info.bConfigIndex != USLCOM_CONFIG_INDEX) {
338 		return (ENXIO);
339 	}
340 	if (uaa->info.bIfaceIndex != USLCOM_IFACE_INDEX) {
341 		return (ENXIO);
342 	}
343 	return (usbd_lookup_id_by_uaa(uslcom_devs, sizeof(uslcom_devs), uaa));
344 }
345 
346 static int
347 uslcom_attach(device_t dev)
348 {
349 	struct usb_attach_arg *uaa = device_get_ivars(dev);
350 	struct uslcom_softc *sc = device_get_softc(dev);
351 	int error;
352 
353 	DPRINTFN(11, "\n");
354 
355 	device_set_usb_desc(dev);
356 	lockinit(&sc->sc_lock, "uslcom", 0, LK_CANRECURSE);
357 	usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_lock, 0);
358 
359 	sc->sc_udev = uaa->device;
360 
361 	error = usbd_transfer_setup(uaa->device,
362 	    &uaa->info.bIfaceIndex, sc->sc_xfer, uslcom_config,
363 	    USLCOM_N_TRANSFER, sc, &sc->sc_lock);
364 	if (error) {
365 		DPRINTF("one or more missing USB endpoints, "
366 		    "error=%s\n", usbd_errstr(error));
367 		goto detach;
368 	}
369 	/* clear stall at first run */
370 	lockmgr(&sc->sc_lock, LK_EXCLUSIVE);
371 	usbd_xfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_WR]);
372 	usbd_xfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_RD]);
373 	lockmgr(&sc->sc_lock, LK_RELEASE);
374 
375 	error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
376 	    &uslcom_callback, &sc->sc_lock);
377 	if (error) {
378 		goto detach;
379 	}
380 	ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
381 
382 	return (0);
383 
384 detach:
385 	uslcom_detach(dev);
386 	return (ENXIO);
387 }
388 
389 static int
390 uslcom_detach(device_t dev)
391 {
392 	struct uslcom_softc *sc = device_get_softc(dev);
393 
394 	DPRINTF("sc=%p\n", sc);
395 
396 	ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
397 	usbd_transfer_unsetup(sc->sc_xfer, USLCOM_N_TRANSFER);
398 
399 	usb_callout_drain(&sc->sc_watchdog);
400 	lockuninit(&sc->sc_lock);
401 
402 	return (0);
403 }
404 
405 static void
406 uslcom_open(struct ucom_softc *ucom)
407 {
408 	struct uslcom_softc *sc = ucom->sc_parent;
409 	struct usb_device_request req;
410 
411 	req.bmRequestType = USLCOM_WRITE;
412 	req.bRequest = USLCOM_UART;
413 	USETW(req.wValue, USLCOM_UART_ENABLE);
414 	USETW(req.wIndex, USLCOM_PORT_NO);
415 	USETW(req.wLength, 0);
416 
417         if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
418 	    &req, NULL, 0, 1000)) {
419 		DPRINTF("UART enable failed (ignored)\n");
420 	}
421 
422 	/* start polling status */
423 	uslcom_watchdog(sc);
424 }
425 
426 static void
427 uslcom_close(struct ucom_softc *ucom)
428 {
429 	struct uslcom_softc *sc = ucom->sc_parent;
430 	struct usb_device_request req;
431 
432 	/* stop polling status */
433 	usb_callout_stop(&sc->sc_watchdog);
434 
435 	req.bmRequestType = USLCOM_WRITE;
436 	req.bRequest = USLCOM_UART;
437 	USETW(req.wValue, USLCOM_UART_DISABLE);
438 	USETW(req.wIndex, USLCOM_PORT_NO);
439 	USETW(req.wLength, 0);
440 
441 	if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
442 	    &req, NULL, 0, 1000)) {
443 		DPRINTF("UART disable failed (ignored)\n");
444 	}
445 }
446 
447 static void
448 uslcom_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
449 {
450         struct uslcom_softc *sc = ucom->sc_parent;
451 	struct usb_device_request req;
452 	uint16_t ctl;
453 
454         DPRINTF("onoff = %d\n", onoff);
455 
456 	ctl = onoff ? USLCOM_CTRL_DTR_ON : 0;
457 	ctl |= USLCOM_CTRL_DTR_SET;
458 
459 	req.bmRequestType = USLCOM_WRITE;
460 	req.bRequest = USLCOM_CTRL;
461 	USETW(req.wValue, ctl);
462 	USETW(req.wIndex, USLCOM_PORT_NO);
463 	USETW(req.wLength, 0);
464 
465         if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
466 	    &req, NULL, 0, 1000)) {
467 		DPRINTF("Setting DTR failed (ignored)\n");
468 	}
469 }
470 
471 static void
472 uslcom_set_rts(struct ucom_softc *ucom, uint8_t onoff)
473 {
474         struct uslcom_softc *sc = ucom->sc_parent;
475 	struct usb_device_request req;
476 	uint16_t ctl;
477 
478         DPRINTF("onoff = %d\n", onoff);
479 
480 	ctl = onoff ? USLCOM_CTRL_RTS_ON : 0;
481 	ctl |= USLCOM_CTRL_RTS_SET;
482 
483 	req.bmRequestType = USLCOM_WRITE;
484 	req.bRequest = USLCOM_CTRL;
485 	USETW(req.wValue, ctl);
486 	USETW(req.wIndex, USLCOM_PORT_NO);
487 	USETW(req.wLength, 0);
488 
489         if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
490 	    &req, NULL, 0, 1000)) {
491 		DPRINTF("Setting DTR failed (ignored)\n");
492 	}
493 }
494 
495 static int
496 uslcom_pre_param(struct ucom_softc *ucom, struct termios *t)
497 {
498 	if (t->c_ospeed <= 0 || t->c_ospeed > 921600)
499 		return (EINVAL);
500 	return (0);
501 }
502 
503 static void
504 uslcom_param(struct ucom_softc *ucom, struct termios *t)
505 {
506 	struct uslcom_softc *sc = ucom->sc_parent;
507 	struct usb_device_request req;
508 	uint32_t flowctrl[4];
509 	uint16_t data;
510 
511 	DPRINTF("\n");
512 
513 	req.bmRequestType = USLCOM_WRITE;
514 	req.bRequest = USLCOM_BAUD_RATE;
515 	USETW(req.wValue, USLCOM_BAUD_REF / t->c_ospeed);
516 	USETW(req.wIndex, USLCOM_PORT_NO);
517 	USETW(req.wLength, 0);
518 
519         if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
520 	    &req, NULL, 0, 1000)) {
521 		DPRINTF("Set baudrate failed (ignored)\n");
522 	}
523 
524 	if (t->c_cflag & CSTOPB)
525 		data = USLCOM_STOP_BITS_2;
526 	else
527 		data = USLCOM_STOP_BITS_1;
528 	if (t->c_cflag & PARENB) {
529 		if (t->c_cflag & PARODD)
530 			data |= USLCOM_PARITY_ODD;
531 		else
532 			data |= USLCOM_PARITY_EVEN;
533 	} else
534 		data |= USLCOM_PARITY_NONE;
535 	switch (t->c_cflag & CSIZE) {
536 	case CS5:
537 		data |= USLCOM_SET_DATA_BITS(5);
538 		break;
539 	case CS6:
540 		data |= USLCOM_SET_DATA_BITS(6);
541 		break;
542 	case CS7:
543 		data |= USLCOM_SET_DATA_BITS(7);
544 		break;
545 	case CS8:
546 		data |= USLCOM_SET_DATA_BITS(8);
547 		break;
548 	}
549 
550 	req.bmRequestType = USLCOM_WRITE;
551 	req.bRequest = USLCOM_DATA;
552 	USETW(req.wValue, data);
553 	USETW(req.wIndex, USLCOM_PORT_NO);
554 	USETW(req.wLength, 0);
555 
556         if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
557 	    &req, NULL, 0, 1000)) {
558 		DPRINTF("Set format failed (ignored)\n");
559 	}
560 
561 	if (t->c_cflag & CRTSCTS) {
562 		flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON | USLCOM_FLOW_CTS_HS);
563 		flowctrl[1] = htole32(USLCOM_FLOW_RTS_HS);
564 		flowctrl[2] = 0;
565 		flowctrl[3] = 0;
566 	} else {
567 		flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON);
568 		flowctrl[1] = htole32(USLCOM_FLOW_RTS_ON);
569 		flowctrl[2] = 0;
570 		flowctrl[3] = 0;
571 	}
572 	req.bmRequestType = USLCOM_WRITE;
573 	req.bRequest = USLCOM_SET_FLOWCTRL;
574 	USETW(req.wValue, 0);
575 	USETW(req.wIndex, USLCOM_PORT_NO);
576 	USETW(req.wLength, sizeof(flowctrl));
577 
578 	if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
579 	    &req, flowctrl, 0, 1000)) {
580 		DPRINTF("Set flowcontrol failed (ignored)\n");
581 	}
582 }
583 
584 static void
585 uslcom_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
586 {
587 	struct uslcom_softc *sc = ucom->sc_parent;
588 
589 	DPRINTF("\n");
590 
591 	*lsr = sc->sc_lsr;
592 	*msr = sc->sc_msr;
593 }
594 
595 static void
596 uslcom_set_break(struct ucom_softc *ucom, uint8_t onoff)
597 {
598         struct uslcom_softc *sc = ucom->sc_parent;
599 	struct usb_device_request req;
600 	uint16_t brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF;
601 
602 	req.bmRequestType = USLCOM_WRITE;
603 	req.bRequest = USLCOM_BREAK;
604 	USETW(req.wValue, brk);
605 	USETW(req.wIndex, USLCOM_PORT_NO);
606 	USETW(req.wLength, 0);
607 
608         if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
609 	    &req, NULL, 0, 1000)) {
610 		DPRINTF("Set BREAK failed (ignored)\n");
611 	}
612 }
613 
614 static int
615 uslcom_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data,
616     int flag, struct thread *td)
617 {
618 	struct uslcom_softc *sc = ucom->sc_parent;
619 	struct usb_device_request req;
620 	int error = 0;
621 	uint8_t latch;
622 
623 	DPRINTF("cmd=0x%08x\n", cmd);
624 
625 	switch (cmd) {
626 	case USB_GET_GPIO:
627 		req.bmRequestType = USLCOM_READ;
628 		req.bRequest = USLCOM_VENDOR_SPECIFIC;
629 		USETW(req.wValue, USLCOM_READ_LATCH);
630 		USETW(req.wIndex, 0);
631 		USETW(req.wLength, sizeof(latch));
632 
633 		if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
634 		    &req, &latch, 0, 1000)) {
635 			DPRINTF("Get LATCH failed\n");
636 			error = EIO;
637 		}
638 		*(int *)data = latch;
639 		break;
640 
641 	case USB_SET_GPIO:
642 		req.bmRequestType = USLCOM_WRITE;
643 		req.bRequest = USLCOM_VENDOR_SPECIFIC;
644 		USETW(req.wValue, USLCOM_WRITE_LATCH);
645 		USETW(req.wIndex, (*(int *)data));
646 		USETW(req.wLength, 0);
647 
648 		if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
649 		    &req, NULL, 0, 1000)) {
650 			DPRINTF("Set LATCH failed\n");
651 			error = EIO;
652 		}
653 		break;
654 
655 	default:
656 		DPRINTF("Unknown IOCTL\n");
657 		error = ENOIOCTL;
658 		break;
659 	}
660 	return (error);
661 }
662 
663 static void
664 uslcom_write_callback(struct usb_xfer *xfer, usb_error_t error)
665 {
666 	struct uslcom_softc *sc = usbd_xfer_softc(xfer);
667 	struct usb_page_cache *pc;
668 	uint32_t actlen;
669 
670 	switch (USB_GET_STATE(xfer)) {
671 	case USB_ST_SETUP:
672 	case USB_ST_TRANSFERRED:
673 tr_setup:
674 		pc = usbd_xfer_get_frame(xfer, 0);
675 		if (ucom_get_data(&sc->sc_ucom, pc, 0,
676 		    USLCOM_BULK_BUF_SIZE, &actlen)) {
677 
678 			DPRINTF("actlen = %d\n", actlen);
679 
680 			usbd_xfer_set_frame_len(xfer, 0, actlen);
681 			usbd_transfer_submit(xfer);
682 		}
683 		return;
684 
685 	default:			/* Error */
686 		if (error != USB_ERR_CANCELLED) {
687 			/* try to clear stall first */
688 			usbd_xfer_set_stall(xfer);
689 			goto tr_setup;
690 		}
691 		return;
692 	}
693 }
694 
695 static void
696 uslcom_read_callback(struct usb_xfer *xfer, usb_error_t error)
697 {
698 	struct uslcom_softc *sc = usbd_xfer_softc(xfer);
699 	struct usb_page_cache *pc;
700 	int actlen;
701 
702 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
703 
704 	switch (USB_GET_STATE(xfer)) {
705 	case USB_ST_TRANSFERRED:
706 		pc = usbd_xfer_get_frame(xfer, 0);
707 		ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
708 
709 	case USB_ST_SETUP:
710 tr_setup:
711 		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
712 		usbd_transfer_submit(xfer);
713 		return;
714 
715 	default:			/* Error */
716 		if (error != USB_ERR_CANCELLED) {
717 			/* try to clear stall first */
718 			usbd_xfer_set_stall(xfer);
719 			goto tr_setup;
720 		}
721 		return;
722 	}
723 }
724 
725 static void
726 uslcom_control_callback(struct usb_xfer *xfer, usb_error_t error)
727 {
728 	struct uslcom_softc *sc = usbd_xfer_softc(xfer);
729 	struct usb_page_cache *pc;
730 	struct usb_device_request req;
731 	uint8_t msr = 0;
732 	uint8_t buf;
733 
734 	switch (USB_GET_STATE(xfer)) {
735 	case USB_ST_TRANSFERRED:
736 		pc = usbd_xfer_get_frame(xfer, 1);
737 		usbd_copy_out(pc, 0, &buf, sizeof(buf));
738 		if (buf & USLCOM_CTRL_CTS)
739 			msr |= SER_CTS;
740 		if (buf & USLCOM_CTRL_DSR)
741 			msr |= SER_DSR;
742 		if (buf & USLCOM_CTRL_RI)
743 			msr |= SER_RI;
744 		if (buf & USLCOM_CTRL_DCD)
745 			msr |= SER_DCD;
746 
747 		if (msr != sc->sc_msr) {
748 			DPRINTF("status change msr=0x%02x "
749 			    "(was 0x%02x)\n", msr, sc->sc_msr);
750 			sc->sc_msr = msr;
751 			ucom_status_change(&sc->sc_ucom);
752 		}
753 		break;
754 
755 	case USB_ST_SETUP:
756 		req.bmRequestType = USLCOM_READ;
757 		req.bRequest = USLCOM_RCTRL;
758 		USETW(req.wValue, 0);
759 		USETW(req.wIndex, USLCOM_PORT_NO);
760 		USETW(req.wLength, sizeof(buf));
761 
762 		usbd_xfer_set_frames(xfer, 2);
763 		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
764 		usbd_xfer_set_frame_len(xfer, 1, sizeof(buf));
765 
766 		pc = usbd_xfer_get_frame(xfer, 0);
767 		usbd_copy_in(pc, 0, &req, sizeof(req));
768 		usbd_transfer_submit(xfer);
769 		break;
770 
771 	default:		/* error */
772 		if (error != USB_ERR_CANCELLED)
773 			DPRINTF("error=%s\n", usbd_errstr(error));
774 		break;
775 	}
776 }
777 
778 static void
779 uslcom_start_read(struct ucom_softc *ucom)
780 {
781 	struct uslcom_softc *sc = ucom->sc_parent;
782 
783 	/* start read endpoint */
784 	usbd_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_RD]);
785 }
786 
787 static void
788 uslcom_stop_read(struct ucom_softc *ucom)
789 {
790 	struct uslcom_softc *sc = ucom->sc_parent;
791 
792 	/* stop read endpoint */
793 	usbd_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_RD]);
794 }
795 
796 static void
797 uslcom_start_write(struct ucom_softc *ucom)
798 {
799 	struct uslcom_softc *sc = ucom->sc_parent;
800 
801 	usbd_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_WR]);
802 }
803 
804 static void
805 uslcom_stop_write(struct ucom_softc *ucom)
806 {
807 	struct uslcom_softc *sc = ucom->sc_parent;
808 
809 	usbd_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_WR]);
810 }
811 
812 static void
813 uslcom_poll(struct ucom_softc *ucom)
814 {
815 	struct uslcom_softc *sc = ucom->sc_parent;
816 	usbd_transfer_poll(sc->sc_xfer, USLCOM_N_TRANSFER);
817 }
818