xref: /openbsd/sys/dev/usb/uticom.c (revision d415bd75)
1 /*	$OpenBSD: uticom.c,v 1.35 2022/04/09 20:07:44 naddy 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 const 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_close_pipe(sc->sc_intr_pipe);
457 		free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
458 		sc->sc_intr_pipe = NULL;
459 	}
460 
461 	return (0);
462 }
463 
464 static usbd_status
465 uticom_reset(struct uticom_softc *sc)
466 {
467 	usb_device_request_t req;
468 	usbd_status err;
469 
470 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
471 	req.bRequest = UTICOM_RQ_SON;
472 	USETW(req.wValue, 0);
473 	USETW(req.wIndex, 0);
474 	USETW(req.wLength, 0);
475 
476 	err = usbd_do_request(sc->sc_udev, &req, NULL);
477 	if (err){
478 		printf("%s: uticom_reset: %s\n",
479 		    sc->sc_dev.dv_xname, usbd_errstr(err));
480 		return (EIO);
481 	}
482 
483 	DPRINTF(("%s: uticom_reset: done\n", sc->sc_dev.dv_xname));
484 	return (0);
485 }
486 
487 static void
488 uticom_set(void *addr, int portno, int reg, int onoff)
489 {
490 	struct uticom_softc *sc = addr;
491 
492 	switch (reg) {
493 	case UCOM_SET_DTR:
494 		uticom_dtr(sc, onoff);
495 		break;
496 	case UCOM_SET_RTS:
497 		uticom_rts(sc, onoff);
498 		break;
499 	case UCOM_SET_BREAK:
500 		uticom_break(sc, onoff);
501 		break;
502 	default:
503 		break;
504 	}
505 }
506 
507 static void
508 uticom_dtr(struct uticom_softc *sc, int onoff)
509 {
510 	usb_device_request_t req;
511 	usbd_status err;
512 
513 	DPRINTF(("%s: uticom_dtr: onoff = %d\n", sc->sc_dev.dv_xname,
514 	    onoff));
515 
516 	if (sc->sc_dtr == onoff)
517 		return;
518 	sc->sc_dtr = onoff;
519 
520 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
521 	req.bRequest = UTICOM_RQ_DTR;
522 	USETW(req.wValue, sc->sc_dtr ? UCDC_LINE_DTR : 0);
523 	USETW(req.wIndex, 0);
524 	USETW(req.wLength, 0);
525 
526 	err = usbd_do_request(sc->sc_udev, &req, NULL);
527 	if (err)
528 		printf("%s: uticom_dtr: %s\n",
529 		    sc->sc_dev.dv_xname, usbd_errstr(err));
530 }
531 
532 static void
533 uticom_rts(struct uticom_softc *sc, int onoff)
534 {
535 	usb_device_request_t req;
536 	usbd_status err;
537 
538 	DPRINTF(("%s: uticom_rts: onoff = %d\n", sc->sc_dev.dv_xname,
539 	    onoff));
540 
541 	if (sc->sc_rts == onoff)
542 		return;
543 	sc->sc_rts = onoff;
544 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
545 	req.bRequest = UTICOM_RQ_RTS;
546 	USETW(req.wValue, sc->sc_rts ? UCDC_LINE_RTS : 0);
547 	USETW(req.wIndex, 0);
548 	USETW(req.wLength, 0);
549 
550 	err = usbd_do_request(sc->sc_udev, &req, NULL);
551 	if (err)
552 		printf("%s: uticom_rts: %s\n",
553 		    sc->sc_dev.dv_xname, usbd_errstr(err));
554 }
555 
556 static void
557 uticom_break(struct uticom_softc *sc, int onoff)
558 {
559 	usb_device_request_t req;
560 	usbd_status err;
561 
562 	DPRINTF(("%s: uticom_break: onoff = %d\n", sc->sc_dev.dv_xname,
563 	    onoff));
564 
565 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
566 	req.bRequest = UTICOM_RQ_BREAK;
567 	USETW(req.wValue, onoff ? 1 : 0);
568 	USETW(req.wIndex, 0);
569 	USETW(req.wLength, 0);
570 
571 	err = usbd_do_request(sc->sc_udev, &req, NULL);
572 	if (err)
573 		printf("%s: uticom_break: %s\n",
574 		    sc->sc_dev.dv_xname, usbd_errstr(err));
575 }
576 
577 static usbd_status
578 uticom_set_crtscts(struct uticom_softc *sc)
579 {
580 	usb_device_request_t req;
581 	usbd_status err;
582 
583 	DPRINTF(("%s: uticom_set_crtscts: on\n", sc->sc_dev.dv_xname));
584 
585 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
586 	req.bRequest = UTICOM_RQ_CRTSCTS;
587 	USETW(req.wValue, 1);
588 	USETW(req.wIndex, 0);
589 	USETW(req.wLength, 0);
590 
591 	err = usbd_do_request(sc->sc_udev, &req, NULL);
592 	if (err) {
593 		printf("%s: uticom_set_crtscts: %s\n",
594 		    sc->sc_dev.dv_xname, usbd_errstr(err));
595 		return (err);
596 	}
597 
598 	return (USBD_NORMAL_COMPLETION);
599 }
600 
601 static int
602 uticom_param(void *vsc, int portno, struct termios *t)
603 {
604 	struct uticom_softc *sc = (struct uticom_softc *)vsc;
605 	usb_device_request_t req;
606 	usbd_status err;
607 	uint8_t data;
608 
609 	DPRINTF(("%s: uticom_param\n", sc->sc_dev.dv_xname));
610 
611 	switch (t->c_ospeed) {
612 	case 1200:
613 	case 2400:
614 	case 4800:
615 	case 7200:
616 	case 9600:
617 	case 14400:
618 	case 19200:
619 	case 38400:
620 	case 57600:
621 	case 115200:
622 	case 230400:
623 	case 460800:
624 	case 921600:
625 		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
626 		req.bRequest = UTICOM_RQ_BAUD;
627 		USETW(req.wValue, (UTICOM_BRATE_REF / t->c_ospeed));
628 		USETW(req.wIndex, 0);
629 		USETW(req.wLength, 0);
630 
631 		err = usbd_do_request(sc->sc_udev, &req, 0);
632 		if (err) {
633 			printf("%s: uticom_param: %s\n",
634 			    sc->sc_dev.dv_xname, usbd_errstr(err));
635 			return (EIO);
636 		}
637 		break;
638 	default:
639 		printf("%s: uticom_param: unsupported baud rate %d\n",
640 		    sc->sc_dev.dv_xname, t->c_ospeed);
641 		return (EINVAL);
642 	}
643 
644 	switch (ISSET(t->c_cflag, CSIZE)) {
645 	case CS5:
646 		data = UTICOM_SET_DATA_BITS(5);
647 		break;
648 	case CS6:
649 		data = UTICOM_SET_DATA_BITS(6);
650 		break;
651 	case CS7:
652 		data = UTICOM_SET_DATA_BITS(7);
653 		break;
654 	case CS8:
655 		data = UTICOM_SET_DATA_BITS(8);
656 		break;
657 	default:
658 		return (EIO);
659 	}
660 
661 	if (ISSET(t->c_cflag, CSTOPB))
662 		data |= UTICOM_STOP_BITS_2;
663 	else
664 		data |= UTICOM_STOP_BITS_1;
665 
666 	if (ISSET(t->c_cflag, PARENB)) {
667 		if (ISSET(t->c_cflag, PARODD))
668 			data |= UTICOM_PARITY_ODD;
669 		else
670 			data |= UTICOM_PARITY_EVEN;
671 	} else
672 		data |= UTICOM_PARITY_NONE;
673 
674 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
675 	req.bRequest = UTICOM_RQ_LCR;
676 	USETW(req.wIndex, 0);
677 	USETW(req.wLength, 0);
678 	USETW(req.wValue, data);
679 
680 	err = usbd_do_request(sc->sc_udev, &req, NULL);
681 	if (err) {
682 		printf("%s: uticom_param: %s\n",
683 		    sc->sc_dev.dv_xname, usbd_errstr(err));
684 		return (err);
685 	}
686 
687 	if (ISSET(t->c_cflag, CRTSCTS)) {
688 		err = uticom_set_crtscts(sc);
689 		if (err)
690 			return (EIO);
691 	}
692 
693 	return (0);
694 }
695 
696 static int
697 uticom_open(void *addr, int portno)
698 {
699 	struct uticom_softc *sc = addr;
700 	usbd_status err;
701 
702 	if (usbd_is_dying(sc->sc_udev))
703 		return (ENXIO);
704 
705 	DPRINTF(("%s: uticom_open\n", sc->sc_dev.dv_xname));
706 
707 	sc->sc_status = 0; /* clear status bit */
708 
709 	if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
710 		sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
711 		err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number,
712 		    USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_intr_buf,
713 		    sc->sc_isize, uticom_intr, UTICOM_INTR_INTERVAL);
714 		if (err) {
715 			printf("%s: cannot open interrupt pipe (addr %d)\n",
716 			    sc->sc_dev.dv_xname, sc->sc_intr_number);
717 			return (EIO);
718 		}
719 	}
720 
721 	DPRINTF(("%s: uticom_open: port opened\n", sc->sc_dev.dv_xname));
722 	return (0);
723 }
724 
725 static void
726 uticom_close(void *addr, int portno)
727 {
728 	struct uticom_softc *sc = addr;
729 	usb_device_request_t req;
730 	usbd_status err;
731 
732 	if (usbd_is_dying(sc->sc_udev))
733 		return;
734 
735 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
736 	req.bRequest = UTICOM_RQ_SON;
737 	USETW(req.wValue, 0);
738 	USETW(req.wIndex, 0);
739 	USETW(req.wLength, 0);
740 
741 	/* Try to reset UART part of chip. */
742 	err = usbd_do_request(sc->sc_udev, &req, NULL);
743 	if (err) {
744 		printf("%s: uticom_close: %s\n",
745 		    sc->sc_dev.dv_xname, usbd_errstr(err));
746 		return;
747 	}
748 
749 	DPRINTF(("%s: uticom_close: close\n", sc->sc_dev.dv_xname));
750 
751 	if (sc->sc_intr_pipe != NULL) {
752 		err = usbd_close_pipe(sc->sc_intr_pipe);
753 		if (err)
754 			printf("%s: close interrupt pipe failed: %s\n",
755 			    sc->sc_dev.dv_xname, usbd_errstr(err));
756 		free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
757 		sc->sc_intr_pipe = NULL;
758 	}
759 }
760 
761 static void
762 uticom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
763 {
764 	struct uticom_softc *sc = priv;
765 	u_char *buf = sc->sc_intr_buf;
766 
767 	if (usbd_is_dying(sc->sc_udev))
768 		return;
769 
770 	if (status != USBD_NORMAL_COMPLETION) {
771 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
772 			DPRINTF(("%s: uticom_intr: int status: %s\n",
773 			    sc->sc_dev.dv_xname, usbd_errstr(status)));
774 			return;
775 		}
776 
777 		DPRINTF(("%s: uticom_intr: abnormal status: %s\n",
778 		    sc->sc_dev.dv_xname, usbd_errstr(status)));
779 		usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
780 		return;
781 	}
782 
783 	if (!xfer->actlen)
784 		return;
785 
786 	DPRINTF(("%s: xfer_length = %d\n", sc->sc_dev.dv_xname,
787 	    xfer->actlen));
788 
789 	sc->sc_lsr = sc->sc_msr = 0;
790 
791 	if (buf[0] == 0) {
792 		/* msr registers */
793 		if (buf[1] & UTICOM_MCR_CTS)
794 			sc->sc_msr |= UMSR_CTS;
795 		if (buf[1] & UTICOM_MCR_DSR)
796 			sc->sc_msr |= UMSR_DSR;
797 		if (buf[1] & UTICOM_MCR_CD)
798 			sc->sc_msr |= UMSR_DCD;
799 		if (buf[1] & UTICOM_MCR_RI)
800 			sc->sc_msr |= UMSR_RI;
801 	} else {
802 		/* lsr registers */
803 		if (buf[0] & UTICOM_LCR_OVR)
804 			sc->sc_lsr |= ULSR_OE;
805 		if (buf[0] & UTICOM_LCR_PTE)
806 			sc->sc_lsr |= ULSR_PE;
807 		if (buf[0] & UTICOM_LCR_FRE)
808 			sc->sc_lsr |= ULSR_FE;
809 		if (buf[0] & UTICOM_LCR_BRK)
810 			sc->sc_lsr |= ULSR_BI;
811 	}
812 
813 //	if (uticomstickdsr)
814 //		sc->sc_msr |= UMSR_DSR;
815 
816 	ucom_status_change((struct ucom_softc *)sc->sc_subdev);
817 }
818 
819 static void
820 uticom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
821 {
822 #if 0 /* TODO */
823 	struct uticom_softc *sc = addr;
824 
825 	DPRINTF(("uticom_get_status:\n"));
826 
827 	if (lsr != NULL)
828 		*lsr = sc->sc_lsr;
829 	if (msr != NULL)
830 		*msr = sc->sc_msr;
831 #endif
832 	return;
833 }
834 
835 static int
836 uticom_download_fw(struct uticom_softc *sc, int pipeno,
837     struct usbd_device *dev)
838 {
839 	u_char *obuf, *firmware;
840 	size_t firmware_size;
841 	int buffer_size, pos;
842 	uint8_t cs = 0, *buffer;
843 	usbd_status err;
844 	struct uticom_fw_header *header;
845 	struct usbd_xfer *oxfer = 0;
846 	usbd_status error = 0;
847 	struct usbd_pipe *pipe;
848 
849 	error = loadfirmware("tusb3410", &firmware, &firmware_size);
850 	if (error)
851 		return (error);
852 
853 	buffer_size = UTICOM_FW_BUFSZ + sizeof(struct uticom_fw_header);
854 	buffer = malloc(buffer_size, M_USBDEV, M_WAITOK | M_CANFAIL);
855 
856 	if (!buffer) {
857 		printf("%s: uticom_download_fw: out of memory\n",
858 		    sc->sc_dev.dv_xname);
859 		free(firmware, M_DEVBUF, firmware_size);
860 		return ENOMEM;
861 	}
862 
863 	memcpy(buffer, firmware, firmware_size);
864 	memset(buffer + firmware_size, 0xff, buffer_size - firmware_size);
865 
866 	for (pos = sizeof(struct uticom_fw_header); pos < buffer_size; pos++)
867 		cs = (uint8_t)(cs + buffer[pos]);
868 
869 	header = (struct uticom_fw_header*)buffer;
870 	header->length = (uint16_t)(buffer_size -
871 	    sizeof(struct uticom_fw_header));
872 	header->checkSum = cs;
873 
874 	DPRINTF(("%s: downloading firmware ...\n",
875 	    sc->sc_dev.dv_xname));
876 
877 	err = usbd_open_pipe(sc->sc_iface, pipeno, USBD_EXCLUSIVE_USE,
878 	    &pipe);
879 	if (err) {
880 		printf("%s: open bulk out error (addr %d): %s\n",
881 		    sc->sc_dev.dv_xname, pipeno, usbd_errstr(err));
882 		error = EIO;
883 		goto finish;
884 	}
885 
886 	oxfer = usbd_alloc_xfer(dev);
887 	if (oxfer == NULL) {
888 		error = ENOMEM;
889 		goto finish;
890 	}
891 
892 	obuf = usbd_alloc_buffer(oxfer, buffer_size);
893 	if (obuf == NULL) {
894 		error = ENOMEM;
895 		goto finish;
896 	}
897 
898 	memcpy(obuf, buffer, buffer_size);
899 
900 	usbd_setup_xfer(oxfer, pipe, (void *)sc, obuf, buffer_size,
901 	    USBD_NO_COPY | USBD_SYNCHRONOUS, USBD_NO_TIMEOUT, 0);
902 	err = usbd_transfer(oxfer);
903 
904 	if (err != USBD_NORMAL_COMPLETION)
905 		printf("%s: uticom_download_fw: error: %s\n",
906 		    sc->sc_dev.dv_xname, usbd_errstr(err));
907 
908 finish:
909 	free(firmware, M_DEVBUF, firmware_size);
910 	usbd_free_buffer(oxfer);
911 	usbd_free_xfer(oxfer);
912 	oxfer = NULL;
913 	usbd_close_pipe(pipe);
914 	free(buffer, M_USBDEV, buffer_size);
915 	return err;
916 }
917