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