xref: /openbsd-src/sys/dev/usb/uticom.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: uticom.c,v 1.33 2018/03/15 00:42:41 kevlo Exp $	*/
2 /*
3  * Copyright (c) 2005 Dmitry Komissaroff <dxi@mail.ru>.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/kernel.h>
30 #include <sys/device.h>
31 #include <sys/malloc.h>
32 #include <sys/conf.h>
33 #include <sys/tty.h>
34 
35 #include <machine/bus.h>
36 
37 #include <dev/usb/usb.h>
38 #include <dev/usb/usbdi.h>
39 #include <dev/usb/usbdivar.h>
40 #include <dev/usb/usbdi_util.h>
41 #include <dev/usb/usbdevs.h>
42 #include <dev/usb/usbcdc.h>
43 
44 #include <dev/usb/ucomvar.h>
45 
46 #ifdef UTICOM_DEBUG
47 static int uticomdebug = 0;
48 #define DPRINTFN(n, x)	do { if (uticomdebug > (n)) printf x; } while (0)
49 #else
50 #define DPRINTFN(n, x)
51 #endif
52 
53 #define DPRINTF(x) DPRINTFN(0, x)
54 
55 #define	UTICOM_CONFIG_INDEX	1
56 #define	UTICOM_ACTIVE_INDEX	2
57 
58 #define	UTICOM_IFACE_INDEX	0
59 
60 /*
61  * These are the maximum number of bytes transferred per frame.
62  * The output buffer size cannot be increased due to the size encoding.
63  */
64 #define UTICOM_IBUFSZ		64
65 #define UTICOM_OBUFSZ		64
66 
67 #define UTICOM_FW_BUFSZ		16284
68 
69 #define UTICOM_INTR_INTERVAL	100	/* ms */
70 
71 #define UTICOM_RQ_LINE		0
72 /* Used to sync data0/1-toggle on reopen bulk pipe. */
73 #define UTICOM_RQ_SOF		1
74 #define UTICOM_RQ_SON		2
75 
76 #define UTICOM_RQ_BAUD		3
77 #define UTICOM_RQ_LCR		4
78 #define UTICOM_RQ_FCR		5
79 #define UTICOM_RQ_RTS		6
80 #define UTICOM_RQ_DTR		7
81 #define UTICOM_RQ_BREAK		8
82 #define UTICOM_RQ_CRTSCTS	9
83 
84 #define UTICOM_BRATE_REF	923077
85 
86 #define UTICOM_SET_DATA_BITS(x)	(x - 5)
87 
88 #define UTICOM_STOP_BITS_1	0x00
89 #define UTICOM_STOP_BITS_2	0x40
90 
91 #define UTICOM_PARITY_NONE	0x00
92 #define UTICOM_PARITY_ODD	0x08
93 #define UTICOM_PARITY_EVEN	0x18
94 
95 #define UTICOM_LCR_OVR		0x1
96 #define UTICOM_LCR_PTE		0x2
97 #define UTICOM_LCR_FRE		0x4
98 #define UTICOM_LCR_BRK		0x8
99 
100 #define UTICOM_MCR_CTS		0x1
101 #define UTICOM_MCR_DSR		0x2
102 #define UTICOM_MCR_CD		0x4
103 #define UTICOM_MCR_RI		0x8
104 
105 /* Structures */
106 struct uticom_fw_header {
107 	uint16_t	length;
108 	uint8_t		checkSum;
109 } __packed;
110 
111 struct uticom_buf {
112 	unsigned int		buf_size;
113 	char			*buf_buf;
114 	char			*buf_get;
115 	char			*buf_put;
116 };
117 
118 struct	uticom_softc {
119 	struct device		 sc_dev;	/* base device */
120 	struct usbd_device	*sc_udev;	/* device */
121 	struct usbd_interface	*sc_iface;	/* interface */
122 
123 	struct usbd_interface	*sc_intr_iface;	/* interrupt interface */
124 	int			sc_intr_number;	/* interrupt number */
125 	struct usbd_pipe	*sc_intr_pipe;	/* interrupt pipe */
126 	u_char			*sc_intr_buf;	/* interrupt buffer */
127 	int			sc_isize;
128 
129 	u_char			sc_dtr;		/* current DTR state */
130 	u_char			sc_rts;		/* current RTS state */
131 	u_char			sc_status;
132 
133 	u_char			sc_lsr;		/* Local status register */
134 	u_char			sc_msr;		/* uticom status register */
135 
136 	struct device		*sc_subdev;
137 };
138 
139 static	usbd_status uticom_reset(struct uticom_softc *);
140 static	usbd_status uticom_set_crtscts(struct uticom_softc *);
141 static	void uticom_intr(struct usbd_xfer *, void *, usbd_status);
142 
143 static	void uticom_set(void *, int, int, int);
144 static	void uticom_dtr(struct uticom_softc *, int);
145 static	void uticom_rts(struct uticom_softc *, int);
146 static	void uticom_break(struct uticom_softc *, int);
147 static	void uticom_get_status(void *, int, u_char *, u_char *);
148 static	int  uticom_param(void *, int, struct termios *);
149 static	int  uticom_open(void *, int);
150 static	void uticom_close(void *, int);
151 
152 void uticom_attach_hook(struct device *);
153 
154 static int uticom_download_fw(struct uticom_softc *sc, int pipeno,
155     struct usbd_device *dev);
156 
157 struct ucom_methods uticom_methods = {
158 	uticom_get_status,
159 	uticom_set,
160 	uticom_param,
161 	NULL,
162 	uticom_open,
163 	uticom_close,
164 	NULL,
165 	NULL
166 };
167 
168 int	uticom_match(struct device *, void *, void *);
169 void	uticom_attach(struct device *, struct device *, void *);
170 int	uticom_detach(struct device *, int);
171 
172 struct cfdriver uticom_cd = {
173 	NULL, "uticom", DV_DULL
174 };
175 
176 const struct cfattach uticom_ca = {
177 	sizeof(struct uticom_softc), uticom_match, uticom_attach, uticom_detach
178 };
179 
180 static const struct usb_devno uticom_devs[] = {
181 	{ USB_VENDOR_TI, USB_PRODUCT_TI_TUSB3410 },
182 	{ USB_VENDOR_TI, USB_PRODUCT_TI_MSP430_JTAG },
183 	{ USB_VENDOR_STARTECH, USB_PRODUCT_STARTECH_ICUSB232X },
184 	{ USB_VENDOR_MOXA, USB_PRODUCT_MOXA_UPORT1110 },
185 	{ USB_VENDOR_ABBOTT, USB_PRODUCT_ABBOTT_STEREO_PLUG }
186 };
187 
188 int
189 uticom_match(struct device *parent, void *match, void *aux)
190 {
191 	struct usb_attach_arg *uaa = aux;
192 
193 	if (uaa->iface != NULL)
194 		return (UMATCH_NONE);
195 
196 	return (usb_lookup(uticom_devs, uaa->vendor, uaa->product) != NULL ?
197 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
198 }
199 
200 void
201 uticom_attach(struct device *parent, struct device *self, void *aux)
202 {
203 	struct uticom_softc	*sc = (struct uticom_softc *)self;
204 	struct usb_attach_arg	*uaa = aux;
205 	struct usbd_device	*dev = uaa->device;
206 
207 	sc->sc_udev = dev;
208 	sc->sc_iface = uaa->iface;
209 
210 	config_mountroot(self, uticom_attach_hook);
211 }
212 
213 void
214 uticom_attach_hook(struct device *self)
215 {
216 	struct uticom_softc		*sc = (struct uticom_softc *)self;
217 	usb_config_descriptor_t		*cdesc;
218 	usb_interface_descriptor_t	*id;
219 	usb_endpoint_descriptor_t	*ed;
220 	usbd_status			 err;
221 	int				 status, i;
222 	usb_device_descriptor_t		*dd;
223 	struct ucom_attach_args		 uca;
224 
225 	/* Initialize endpoints. */
226 	uca.bulkin = uca.bulkout = -1;
227 	sc->sc_intr_number = -1;
228 	sc->sc_intr_pipe = NULL;
229 
230 	dd = usbd_get_device_descriptor(sc->sc_udev);
231 	DPRINTF(("%s: uticom_attach: num of configurations %d\n",
232 	    sc->sc_dev.dv_xname, dd->bNumConfigurations));
233 
234 	/* The device without firmware has single configuration with single
235 	 * bulk out interface. */
236 	if (dd->bNumConfigurations > 1)
237 		goto fwload_done;
238 
239 	/* Loading firmware. */
240 	DPRINTF(("%s: uticom_attach: starting loading firmware\n",
241 	    sc->sc_dev.dv_xname));
242 
243 	err = usbd_set_config_index(sc->sc_udev, UTICOM_CONFIG_INDEX, 1);
244 	if (err) {
245 		printf("%s: failed to set configuration: %s\n",
246 		    sc->sc_dev.dv_xname, usbd_errstr(err));
247 		usbd_deactivate(sc->sc_udev);
248 		return;
249 	}
250 
251 	/* Get the config descriptor. */
252 	cdesc = usbd_get_config_descriptor(sc->sc_udev);
253 
254 	if (cdesc == NULL) {
255 		printf("%s: failed to get configuration descriptor\n",
256 		    sc->sc_dev.dv_xname);
257 		usbd_deactivate(sc->sc_udev);
258 		return;
259 	}
260 
261 	err = usbd_device2interface_handle(sc->sc_udev, UTICOM_IFACE_INDEX,
262 	    &sc->sc_iface);
263 	if (err) {
264 		printf("%s: failed to get interface: %s\n",
265 		    sc->sc_dev.dv_xname, usbd_errstr(err));
266 		usbd_deactivate(sc->sc_udev);
267 		return;
268 	}
269 
270 	/* Find the bulk out interface used to upload firmware. */
271 	id = usbd_get_interface_descriptor(sc->sc_iface);
272 
273 	for (i = 0; i < id->bNumEndpoints; i++) {
274 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
275 		if (ed == NULL) {
276 			printf("%s: no endpoint descriptor for %d\n",
277 			    sc->sc_dev.dv_xname, i);
278 			usbd_deactivate(sc->sc_udev);
279 			return;
280 		}
281 
282 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
283 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
284 			uca.bulkout = ed->bEndpointAddress;
285 			DPRINTF(("%s: uticom_attach: data bulk out num: %d\n",
286 			    sc->sc_dev.dv_xname, ed->bEndpointAddress));
287 		}
288 
289 		if (uca.bulkout == -1) {
290 			printf("%s: could not find data bulk out\n",
291 			    sc->sc_dev.dv_xname);
292 			usbd_deactivate(sc->sc_udev);
293 			return;
294 		}
295 	}
296 
297 	status = uticom_download_fw(sc, uca.bulkout, sc->sc_udev);
298 
299 	if (status) {
300 		printf("%s: firmware download failed\n",
301 		    sc->sc_dev.dv_xname);
302 		usbd_deactivate(sc->sc_udev);
303 		return;
304 	} else {
305 		DPRINTF(("%s: firmware download succeeded\n",
306 		    sc->sc_dev.dv_xname));
307 	}
308 
309 	status = usbd_reload_device_desc(sc->sc_udev);
310 	if (status) {
311 		printf("%s: error reloading device descriptor\n",
312 		    sc->sc_dev.dv_xname);
313 		usbd_deactivate(sc->sc_udev);
314 		return;
315 	}
316 
317 fwload_done:
318 	dd = usbd_get_device_descriptor(sc->sc_udev);
319 	DPRINTF(("%s: uticom_attach: num of configurations %d\n",
320 	    sc->sc_dev.dv_xname, dd->bNumConfigurations));
321 
322 	err = usbd_set_config_index(sc->sc_udev, UTICOM_ACTIVE_INDEX, 1);
323 	if (err) {
324 		printf("%s: failed to set configuration: %s\n",
325 		    sc->sc_dev.dv_xname, usbd_errstr(err));
326 		usbd_deactivate(sc->sc_udev);
327 		return;
328 	}
329 
330 	/* Get the config descriptor. */
331 	cdesc = usbd_get_config_descriptor(sc->sc_udev);
332 	if (cdesc == NULL) {
333 		printf("%s: failed to get configuration descriptor\n",
334 		    sc->sc_dev.dv_xname);
335 		usbd_deactivate(sc->sc_udev);
336 		return;
337 	}
338 
339 	/* Get the interface (XXX: multiport chips are not supported yet). */
340 	err = usbd_device2interface_handle(sc->sc_udev, UTICOM_IFACE_INDEX,
341 	    &sc->sc_iface);
342 	if (err) {
343 		printf("%s: failed to get interface: %s\n",
344 		    sc->sc_dev.dv_xname, usbd_errstr(err));
345 		usbd_deactivate(sc->sc_udev);
346 		return;
347 	}
348 
349 	/* Find the interrupt endpoints. */
350 	id = usbd_get_interface_descriptor(sc->sc_iface);
351 
352 	for (i = 0; i < id->bNumEndpoints; i++) {
353 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
354 		if (ed == NULL) {
355 			printf("%s: no endpoint descriptor for %d\n",
356 			    sc->sc_dev.dv_xname, i);
357 			usbd_deactivate(sc->sc_udev);
358 			return;
359 		}
360 
361 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
362 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
363 			sc->sc_intr_number = ed->bEndpointAddress;
364 			sc->sc_isize = UGETW(ed->wMaxPacketSize);
365 
366 		}
367 	}
368 
369 	if (sc->sc_intr_number == -1) {
370 		printf("%s: could not find interrupt in\n",
371 		    sc->sc_dev.dv_xname);
372 		usbd_deactivate(sc->sc_udev);
373 		return;
374 	}
375 
376 	/* Keep interface for interrupt. */
377 	sc->sc_intr_iface = sc->sc_iface;
378 
379 	/* Find the bulk{in,out} endpoints. */
380 	id = usbd_get_interface_descriptor(sc->sc_iface);
381 
382 	for (i = 0; i < id->bNumEndpoints; i++) {
383 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
384 		if (ed == NULL) {
385 			printf("%s: no endpoint descriptor for %d\n",
386 			    sc->sc_dev.dv_xname, i);
387 			usbd_deactivate(sc->sc_udev);
388 			return;
389 		}
390 
391 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
392 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
393 			uca.bulkin = ed->bEndpointAddress;
394 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
395 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
396 			uca.bulkout = ed->bEndpointAddress;
397 		}
398 	}
399 
400 	if (uca.bulkin == -1) {
401 		printf("%s: could not find data bulk in\n",
402 		    sc->sc_dev.dv_xname);
403 		usbd_deactivate(sc->sc_udev);
404 		return;
405 	}
406 
407 	if (uca.bulkout == -1) {
408 		printf("%s: could not find data bulk out\n",
409 		    sc->sc_dev.dv_xname);
410 		usbd_deactivate(sc->sc_udev);
411 		return;
412 	}
413 
414 	sc->sc_dtr = sc->sc_rts = -1;
415 
416 	uca.portno = UCOM_UNK_PORTNO;
417 	uca.ibufsize = UTICOM_IBUFSZ;
418 	uca.obufsize = UTICOM_OBUFSZ;
419 	uca.ibufsizepad = UTICOM_IBUFSZ;
420 	uca.device = sc->sc_udev;
421 	uca.iface = sc->sc_iface;
422 	uca.opkthdrlen = 0;
423 	uca.methods = &uticom_methods;
424 	uca.arg = sc;
425 	uca.info = NULL;
426 
427 	err = uticom_reset(sc);
428 	if (err) {
429 		printf("%s: reset failed: %s\n",
430 		    sc->sc_dev.dv_xname, usbd_errstr(err));
431 		usbd_deactivate(sc->sc_udev);
432 		return;
433 	}
434 
435 	DPRINTF(("%s: uticom_attach: in = 0x%x, out = 0x%x, intr = 0x%x\n",
436 	    sc->sc_dev.dv_xname, uca.bulkin,
437 	    uca.bulkout, sc->sc_intr_number));
438 
439 	sc->sc_subdev = config_found_sm((struct device *)sc, &uca, ucomprint, ucomsubmatch);
440 }
441 
442 int
443 uticom_detach(struct device *self, int flags)
444 {
445 	struct uticom_softc *sc = (struct uticom_softc *)self;
446 
447 	DPRINTF(("%s: uticom_detach: sc = %p\n",
448 	    sc->sc_dev.dv_xname, sc));
449 
450 	if (sc->sc_subdev != NULL) {
451 		config_detach(sc->sc_subdev, flags);
452 		sc->sc_subdev = NULL;
453 	}
454 
455 	if (sc->sc_intr_pipe != NULL) {
456 		usbd_abort_pipe(sc->sc_intr_pipe);
457 		usbd_close_pipe(sc->sc_intr_pipe);
458 		free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
459 		sc->sc_intr_pipe = NULL;
460 	}
461 
462 	return (0);
463 }
464 
465 static usbd_status
466 uticom_reset(struct uticom_softc *sc)
467 {
468 	usb_device_request_t req;
469 	usbd_status err;
470 
471 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
472 	req.bRequest = UTICOM_RQ_SON;
473 	USETW(req.wValue, 0);
474 	USETW(req.wIndex, 0);
475 	USETW(req.wLength, 0);
476 
477 	err = usbd_do_request(sc->sc_udev, &req, NULL);
478 	if (err){
479 		printf("%s: uticom_reset: %s\n",
480 		    sc->sc_dev.dv_xname, usbd_errstr(err));
481 		return (EIO);
482 	}
483 
484 	DPRINTF(("%s: uticom_reset: done\n", sc->sc_dev.dv_xname));
485 	return (0);
486 }
487 
488 static void
489 uticom_set(void *addr, int portno, int reg, int onoff)
490 {
491 	struct uticom_softc *sc = addr;
492 
493 	switch (reg) {
494 	case UCOM_SET_DTR:
495 		uticom_dtr(sc, onoff);
496 		break;
497 	case UCOM_SET_RTS:
498 		uticom_rts(sc, onoff);
499 		break;
500 	case UCOM_SET_BREAK:
501 		uticom_break(sc, onoff);
502 		break;
503 	default:
504 		break;
505 	}
506 }
507 
508 static void
509 uticom_dtr(struct uticom_softc *sc, int onoff)
510 {
511 	usb_device_request_t req;
512 	usbd_status err;
513 
514 	DPRINTF(("%s: uticom_dtr: onoff = %d\n", sc->sc_dev.dv_xname,
515 	    onoff));
516 
517 	if (sc->sc_dtr == onoff)
518 		return;
519 	sc->sc_dtr = onoff;
520 
521 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
522 	req.bRequest = UTICOM_RQ_DTR;
523 	USETW(req.wValue, sc->sc_dtr ? UCDC_LINE_DTR : 0);
524 	USETW(req.wIndex, 0);
525 	USETW(req.wLength, 0);
526 
527 	err = usbd_do_request(sc->sc_udev, &req, NULL);
528 	if (err)
529 		printf("%s: uticom_dtr: %s\n",
530 		    sc->sc_dev.dv_xname, usbd_errstr(err));
531 }
532 
533 static void
534 uticom_rts(struct uticom_softc *sc, int onoff)
535 {
536 	usb_device_request_t req;
537 	usbd_status err;
538 
539 	DPRINTF(("%s: uticom_rts: onoff = %d\n", sc->sc_dev.dv_xname,
540 	    onoff));
541 
542 	if (sc->sc_rts == onoff)
543 		return;
544 	sc->sc_rts = onoff;
545 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
546 	req.bRequest = UTICOM_RQ_RTS;
547 	USETW(req.wValue, sc->sc_rts ? UCDC_LINE_RTS : 0);
548 	USETW(req.wIndex, 0);
549 	USETW(req.wLength, 0);
550 
551 	err = usbd_do_request(sc->sc_udev, &req, NULL);
552 	if (err)
553 		printf("%s: uticom_rts: %s\n",
554 		    sc->sc_dev.dv_xname, usbd_errstr(err));
555 }
556 
557 static void
558 uticom_break(struct uticom_softc *sc, int onoff)
559 {
560 	usb_device_request_t req;
561 	usbd_status err;
562 
563 	DPRINTF(("%s: uticom_break: onoff = %d\n", sc->sc_dev.dv_xname,
564 	    onoff));
565 
566 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
567 	req.bRequest = UTICOM_RQ_BREAK;
568 	USETW(req.wValue, onoff ? 1 : 0);
569 	USETW(req.wIndex, 0);
570 	USETW(req.wLength, 0);
571 
572 	err = usbd_do_request(sc->sc_udev, &req, NULL);
573 	if (err)
574 		printf("%s: uticom_break: %s\n",
575 		    sc->sc_dev.dv_xname, usbd_errstr(err));
576 }
577 
578 static usbd_status
579 uticom_set_crtscts(struct uticom_softc *sc)
580 {
581 	usb_device_request_t req;
582 	usbd_status err;
583 
584 	DPRINTF(("%s: uticom_set_crtscts: on\n", sc->sc_dev.dv_xname));
585 
586 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
587 	req.bRequest = UTICOM_RQ_CRTSCTS;
588 	USETW(req.wValue, 1);
589 	USETW(req.wIndex, 0);
590 	USETW(req.wLength, 0);
591 
592 	err = usbd_do_request(sc->sc_udev, &req, NULL);
593 	if (err) {
594 		printf("%s: uticom_set_crtscts: %s\n",
595 		    sc->sc_dev.dv_xname, usbd_errstr(err));
596 		return (err);
597 	}
598 
599 	return (USBD_NORMAL_COMPLETION);
600 }
601 
602 static int
603 uticom_param(void *vsc, int portno, struct termios *t)
604 {
605 	struct uticom_softc *sc = (struct uticom_softc *)vsc;
606 	usb_device_request_t req;
607 	usbd_status err;
608 	uint8_t data;
609 
610 	DPRINTF(("%s: uticom_param\n", sc->sc_dev.dv_xname));
611 
612 	switch (t->c_ospeed) {
613 	case 1200:
614 	case 2400:
615 	case 4800:
616 	case 7200:
617 	case 9600:
618 	case 14400:
619 	case 19200:
620 	case 38400:
621 	case 57600:
622 	case 115200:
623 	case 230400:
624 	case 460800:
625 	case 921600:
626 		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
627 		req.bRequest = UTICOM_RQ_BAUD;
628 		USETW(req.wValue, (UTICOM_BRATE_REF / t->c_ospeed));
629 		USETW(req.wIndex, 0);
630 		USETW(req.wLength, 0);
631 
632 		err = usbd_do_request(sc->sc_udev, &req, 0);
633 		if (err) {
634 			printf("%s: uticom_param: %s\n",
635 			    sc->sc_dev.dv_xname, usbd_errstr(err));
636 			return (EIO);
637 		}
638 		break;
639 	default:
640 		printf("%s: uticom_param: unsupported baud rate %d\n",
641 		    sc->sc_dev.dv_xname, t->c_ospeed);
642 		return (EINVAL);
643 	}
644 
645 	switch (ISSET(t->c_cflag, CSIZE)) {
646 	case CS5:
647 		data = UTICOM_SET_DATA_BITS(5);
648 		break;
649 	case CS6:
650 		data = UTICOM_SET_DATA_BITS(6);
651 		break;
652 	case CS7:
653 		data = UTICOM_SET_DATA_BITS(7);
654 		break;
655 	case CS8:
656 		data = UTICOM_SET_DATA_BITS(8);
657 		break;
658 	default:
659 		return (EIO);
660 	}
661 
662 	if (ISSET(t->c_cflag, CSTOPB))
663 		data |= UTICOM_STOP_BITS_2;
664 	else
665 		data |= UTICOM_STOP_BITS_1;
666 
667 	if (ISSET(t->c_cflag, PARENB)) {
668 		if (ISSET(t->c_cflag, PARODD))
669 			data |= UTICOM_PARITY_ODD;
670 		else
671 			data |= UTICOM_PARITY_EVEN;
672 	} else
673 		data |= UTICOM_PARITY_NONE;
674 
675 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
676 	req.bRequest = UTICOM_RQ_LCR;
677 	USETW(req.wIndex, 0);
678 	USETW(req.wLength, 0);
679 	USETW(req.wValue, data);
680 
681 	err = usbd_do_request(sc->sc_udev, &req, NULL);
682 	if (err) {
683 		printf("%s: uticom_param: %s\n",
684 		    sc->sc_dev.dv_xname, usbd_errstr(err));
685 		return (err);
686 	}
687 
688 	if (ISSET(t->c_cflag, CRTSCTS)) {
689 		err = uticom_set_crtscts(sc);
690 		if (err)
691 			return (EIO);
692 	}
693 
694 	return (0);
695 }
696 
697 static int
698 uticom_open(void *addr, int portno)
699 {
700 	struct uticom_softc *sc = addr;
701 	usbd_status err;
702 
703 	if (usbd_is_dying(sc->sc_udev))
704 		return (ENXIO);
705 
706 	DPRINTF(("%s: uticom_open\n", sc->sc_dev.dv_xname));
707 
708 	sc->sc_status = 0; /* clear status bit */
709 
710 	if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
711 		sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
712 		err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number,
713 		    USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_intr_buf,
714 		    sc->sc_isize, uticom_intr, UTICOM_INTR_INTERVAL);
715 		if (err) {
716 			printf("%s: cannot open interrupt pipe (addr %d)\n",
717 			    sc->sc_dev.dv_xname, sc->sc_intr_number);
718 			return (EIO);
719 		}
720 	}
721 
722 	DPRINTF(("%s: uticom_open: port opened\n", sc->sc_dev.dv_xname));
723 	return (0);
724 }
725 
726 static void
727 uticom_close(void *addr, int portno)
728 {
729 	struct uticom_softc *sc = addr;
730 	usb_device_request_t req;
731 	usbd_status err;
732 
733 	if (usbd_is_dying(sc->sc_udev))
734 		return;
735 
736 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
737 	req.bRequest = UTICOM_RQ_SON;
738 	USETW(req.wValue, 0);
739 	USETW(req.wIndex, 0);
740 	USETW(req.wLength, 0);
741 
742 	/* Try to reset UART part of chip. */
743 	err = usbd_do_request(sc->sc_udev, &req, NULL);
744 	if (err) {
745 		printf("%s: uticom_close: %s\n",
746 		    sc->sc_dev.dv_xname, usbd_errstr(err));
747 		return;
748 	}
749 
750 	DPRINTF(("%s: uticom_close: close\n", sc->sc_dev.dv_xname));
751 
752 	if (sc->sc_intr_pipe != NULL) {
753 		usbd_abort_pipe(sc->sc_intr_pipe);
754 		err = usbd_close_pipe(sc->sc_intr_pipe);
755 		if (err)
756 			printf("%s: close interrupt pipe failed: %s\n",
757 			    sc->sc_dev.dv_xname, usbd_errstr(err));
758 		free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
759 		sc->sc_intr_pipe = NULL;
760 	}
761 }
762 
763 static void
764 uticom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
765 {
766 	struct uticom_softc *sc = priv;
767 	u_char *buf = sc->sc_intr_buf;
768 
769 	if (usbd_is_dying(sc->sc_udev))
770 		return;
771 
772 	if (status != USBD_NORMAL_COMPLETION) {
773 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
774 			DPRINTF(("%s: uticom_intr: int status: %s\n",
775 			    sc->sc_dev.dv_xname, usbd_errstr(status)));
776 			return;
777 		}
778 
779 		DPRINTF(("%s: uticom_intr: abnormal status: %s\n",
780 		    sc->sc_dev.dv_xname, usbd_errstr(status)));
781 		usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
782 		return;
783 	}
784 
785 	if (!xfer->actlen)
786 		return;
787 
788 	DPRINTF(("%s: xfer_length = %d\n", sc->sc_dev.dv_xname,
789 	    xfer->actlen));
790 
791 	sc->sc_lsr = sc->sc_msr = 0;
792 
793 	if (buf[0] == 0) {
794 		/* msr registers */
795 		if (buf[1] & UTICOM_MCR_CTS)
796 			sc->sc_msr |= UMSR_CTS;
797 		if (buf[1] & UTICOM_MCR_DSR)
798 			sc->sc_msr |= UMSR_DSR;
799 		if (buf[1] & UTICOM_MCR_CD)
800 			sc->sc_msr |= UMSR_DCD;
801 		if (buf[1] & UTICOM_MCR_RI)
802 			sc->sc_msr |= UMSR_RI;
803 	} else {
804 		/* lsr registers */
805 		if (buf[0] & UTICOM_LCR_OVR)
806 			sc->sc_lsr |= ULSR_OE;
807 		if (buf[0] & UTICOM_LCR_PTE)
808 			sc->sc_lsr |= ULSR_PE;
809 		if (buf[0] & UTICOM_LCR_FRE)
810 			sc->sc_lsr |= ULSR_FE;
811 		if (buf[0] & UTICOM_LCR_BRK)
812 			sc->sc_lsr |= ULSR_BI;
813 	}
814 
815 //	if (uticomstickdsr)
816 //		sc->sc_msr |= UMSR_DSR;
817 
818 	ucom_status_change((struct ucom_softc *)sc->sc_subdev);
819 }
820 
821 static void
822 uticom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
823 {
824 #if 0 /* TODO */
825 	struct uticom_softc *sc = addr;
826 
827 	DPRINTF(("uticom_get_status:\n"));
828 
829 	if (lsr != NULL)
830 		*lsr = sc->sc_lsr;
831 	if (msr != NULL)
832 		*msr = sc->sc_msr;
833 #endif
834 	return;
835 }
836 
837 static int
838 uticom_download_fw(struct uticom_softc *sc, int pipeno,
839     struct usbd_device *dev)
840 {
841 	u_char *obuf, *firmware;
842 	size_t firmware_size;
843 	int buffer_size, pos;
844 	uint8_t cs = 0, *buffer;
845 	usbd_status err;
846 	struct uticom_fw_header *header;
847 	struct usbd_xfer *oxfer = 0;
848 	usbd_status error = 0;
849 	struct usbd_pipe *pipe;
850 
851 	error = loadfirmware("tusb3410", &firmware, &firmware_size);
852 	if (error)
853 		return (error);
854 
855 	buffer_size = UTICOM_FW_BUFSZ + sizeof(struct uticom_fw_header);
856 	buffer = malloc(buffer_size, M_USBDEV, M_WAITOK | M_CANFAIL);
857 
858 	if (!buffer) {
859 		printf("%s: uticom_download_fw: out of memory\n",
860 		    sc->sc_dev.dv_xname);
861 		free(firmware, M_DEVBUF, firmware_size);
862 		return ENOMEM;
863 	}
864 
865 	memcpy(buffer, firmware, firmware_size);
866 	memset(buffer + firmware_size, 0xff, buffer_size - firmware_size);
867 
868 	for (pos = sizeof(struct uticom_fw_header); pos < buffer_size; pos++)
869 		cs = (uint8_t)(cs + buffer[pos]);
870 
871 	header = (struct uticom_fw_header*)buffer;
872 	header->length = (uint16_t)(buffer_size -
873 	    sizeof(struct uticom_fw_header));
874 	header->checkSum = cs;
875 
876 	DPRINTF(("%s: downloading firmware ...\n",
877 	    sc->sc_dev.dv_xname));
878 
879 	err = usbd_open_pipe(sc->sc_iface, pipeno, USBD_EXCLUSIVE_USE,
880 	    &pipe);
881 	if (err) {
882 		printf("%s: open bulk out error (addr %d): %s\n",
883 		    sc->sc_dev.dv_xname, pipeno, usbd_errstr(err));
884 		error = EIO;
885 		goto finish;
886 	}
887 
888 	oxfer = usbd_alloc_xfer(dev);
889 	if (oxfer == NULL) {
890 		error = ENOMEM;
891 		goto finish;
892 	}
893 
894 	obuf = usbd_alloc_buffer(oxfer, buffer_size);
895 	if (obuf == NULL) {
896 		error = ENOMEM;
897 		goto finish;
898 	}
899 
900 	memcpy(obuf, buffer, buffer_size);
901 
902 	usbd_setup_xfer(oxfer, pipe, (void *)sc, obuf, buffer_size,
903 	    USBD_NO_COPY | USBD_SYNCHRONOUS, USBD_NO_TIMEOUT, 0);
904 	err = usbd_transfer(oxfer);
905 
906 	if (err != USBD_NORMAL_COMPLETION)
907 		printf("%s: uticom_download_fw: error: %s\n",
908 		    sc->sc_dev.dv_xname, usbd_errstr(err));
909 
910 finish:
911 	free(firmware, M_DEVBUF, firmware_size);
912 	usbd_free_buffer(oxfer);
913 	usbd_free_xfer(oxfer);
914 	oxfer = NULL;
915 	usbd_abort_pipe(pipe);
916 	usbd_close_pipe(pipe);
917 	free(buffer, M_USBDEV, buffer_size);
918 	return err;
919 }
920