2 * Copyright (c) 2006-2007 Dmitry Komissaroff <dxi@mail.ru>.
3 * Copyright (c) 2007 Hasso Tepper <hasso@estpak.ee>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $DragonFly: src/sys/dev/usbmisc/uticom/uticom.c,v 1.2 2008/01/06 16:55:51 swildner Exp $
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
34 #include <sys/ioccom.h>
35 #include <sys/fcntl.h>
39 #include <sys/select.h>
42 #include <sys/sysctl.h>
43 #include <sys/taskqueue.h>
45 #include <bus/usb/usb.h>
46 #include <bus/usb/usbcdc.h>
47 #include <bus/usb/usbdi.h>
48 #include <bus/usb/usbdi_util.h>
49 #include <bus/usb/usbdivar.h>
50 #include <bus/usb/usb_quirks.h>
52 #include "../ucom/ucomvar.h"
54 #include "uticom_fw3410.h"
56 SYSCTL_NODE(_hw_usb
, OID_AUTO
, uticom
, CTLFLAG_RW
, 0, "USB uticom");
59 static int uticomdebug
= 0;
60 SYSCTL_INT(_hw_usb_uticom
, OID_AUTO
, debug
, CTLFLAG_RW
, &uticomdebug
, 0,
61 "uticom debug level");
63 #define DPRINTFN(n, x) do { if (uticomdebug > (n)) kprintf x; } while (0)
65 #define DPRINTFN(n, x)
68 #define DPRINTF(x) DPRINTFN(0, x)
70 #define UTICOM_CONFIG_INDEX 1
71 #define UTICOM_ACTIVE_INDEX 2
73 #define UTICOM_IFACE_INDEX 0
76 * These are the maximum number of bytes transferred per frame.
77 * The output buffer size cannot be increased due to the size encoding.
79 #define UTICOM_IBUFSZ 64
80 #define UTICOM_OBUFSZ 64
82 #define UTICOM_FW_BUFSZ 16284
84 #define UTICOM_INTR_INTERVAL 100 /* ms */
86 #define UTICOM_RQ_LINE 0
87 /* Used to sync data0/1-toggle on reopen bulk pipe. */
88 #define UTICOM_RQ_SOF 1
89 #define UTICOM_RQ_SON 2
91 #define UTICOM_RQ_BAUD 3
92 #define UTICOM_RQ_LCR 4
93 #define UTICOM_RQ_FCR 5
94 #define UTICOM_RQ_RTS 6
95 #define UTICOM_RQ_DTR 7
96 #define UTICOM_RQ_BREAK 8
97 #define UTICOM_RQ_CRTSCTS 9
99 #define UTICOM_BRATE_REF 923077
101 #define UTICOM_SET_DATA_BITS(x) (x - 5)
103 #define UTICOM_STOP_BITS_1 0x00
104 #define UTICOM_STOP_BITS_2 0x40
106 #define UTICOM_PARITY_NONE 0x00
107 #define UTICOM_PARITY_ODD 0x08
108 #define UTICOM_PARITY_EVEN 0x18
110 #define UTICOM_LCR_OVR 0x1
111 #define UTICOM_LCR_PTE 0x2
112 #define UTICOM_LCR_FRE 0x4
113 #define UTICOM_LCR_BRK 0x8
115 #define UTICOM_MCR_CTS 0x1
116 #define UTICOM_MCR_DSR 0x2
117 #define UTICOM_MCR_CD 0x4
118 #define UTICOM_MCR_RI 0x8
121 struct uticom_fw_header
{
124 } __attribute__((packed
));
127 unsigned int buf_size
;
133 struct uticom_softc
{
134 struct ucom_softc sc_ucom
;
136 int sc_iface_number
; /* interface number */
138 usbd_interface_handle sc_intr_iface
; /* interrupt interface */
139 int sc_intr_number
; /* interrupt number */
140 usbd_pipe_handle sc_intr_pipe
; /* interrupt pipe */
141 u_char
*sc_intr_buf
; /* interrupt buffer */
144 u_char sc_dtr
; /* current DTR state */
145 u_char sc_rts
; /* current RTS state */
148 u_char sc_lsr
; /* Local status register */
149 u_char sc_msr
; /* uticom status register */
152 static usbd_status
uticom_reset(struct uticom_softc
*);
153 static usbd_status
uticom_set_crtscts(struct uticom_softc
*);
154 static void uticom_intr(usbd_xfer_handle
, usbd_private_handle
, usbd_status
);
156 static void uticom_set(void *, int, int, int);
157 static void uticom_dtr(struct uticom_softc
*, int);
158 static void uticom_rts(struct uticom_softc
*, int);
159 static void uticom_break(struct uticom_softc
*, int);
160 static void uticom_get_status(void *, int, u_char
*, u_char
*);
162 static int uticom_ioctl(void *, int, u_long
, caddr_t
, int, usb_proc_ptr
);
164 static int uticom_param(void *, int, struct termios
*);
165 static int uticom_open(void *, int);
166 static void uticom_close(void *, int);
168 static int uticom_download_fw(struct uticom_softc
*sc
, unsigned int pipeno
,
169 usbd_device_handle dev
, unsigned char *firmware
,
170 unsigned int firmware_size
);
172 struct ucom_callback uticom_callback
= {
176 NULL
, /* uticom_ioctl, TODO */
183 static const struct usb_devno uticom_devs
[] = {
184 { USB_DEVICE(0x0451, 0x3410) } /* TI TUSB3410 chip */
187 static device_probe_t uticom_match
;
188 static device_attach_t uticom_attach
;
189 static device_detach_t uticom_detach
;
191 static device_method_t uticom_methods
[] = {
192 DEVMETHOD(device_probe
, uticom_match
),
193 DEVMETHOD(device_attach
, uticom_attach
),
194 DEVMETHOD(device_detach
, uticom_detach
),
198 static driver_t uticom_driver
= {
201 sizeof (struct uticom_softc
)
204 DRIVER_MODULE(uticom
, uhub
, uticom_driver
, ucom_devclass
, usbd_driver_load
, 0);
205 MODULE_DEPEND(uticom
, usb
, 1, 1, 1);
206 MODULE_DEPEND(uticom
, ucom
, UCOM_MINVER
, UCOM_PREFVER
, UCOM_MAXVER
);
207 MODULE_VERSION(uticom
, 1);
209 /* Sticky DSR level sysctl handling. */
210 static int uticomstickdsr
= 0;
212 sysctl_hw_usb_uticom_stickdsr(SYSCTL_HANDLER_ARGS
)
216 val
= uticomstickdsr
;
217 err
= sysctl_handle_int(oidp
, &val
, sizeof(val
), req
);
218 if (err
!= 0 || req
->newptr
== NULL
)
220 if (val
== 0 || val
== 1)
221 uticomstickdsr
= val
;
227 SYSCTL_PROC(_hw_usb_uticom
, OID_AUTO
, stickdsr
, CTLTYPE_INT
| CTLFLAG_RW
,
228 0, sizeof(int), sysctl_hw_usb_uticom_stickdsr
,
229 "I", "uticom sticky dsr level");
232 uticom_match(device_t self
)
234 struct usb_attach_arg
*uaa
= device_get_ivars(self
);
236 if (uaa
->iface
!= NULL
)
237 return (UMATCH_NONE
);
239 return (usb_lookup(uticom_devs
, uaa
->vendor
, uaa
->product
) != NULL
?
240 UMATCH_VENDOR_PRODUCT
: UMATCH_NONE
);
244 uticom_attach(device_t self
)
246 struct uticom_softc
*sc
= device_get_softc(self
);
247 struct usb_attach_arg
*uaa
= device_get_ivars(self
);
249 usbd_device_handle dev
= uaa
->device
;
250 struct ucom_softc
*ucom
;
251 usb_config_descriptor_t
*cdesc
;
252 usb_interface_descriptor_t
*id
;
253 usb_endpoint_descriptor_t
*ed
;
256 usb_device_descriptor_t
*dd
;
259 bzero(sc
, sizeof (struct uticom_softc
));
262 ucom
->sc_iface
= uaa
->iface
;
264 /* Initialize endpoints. */
265 ucom
->sc_bulkin_no
= ucom
->sc_bulkout_no
= -1;
266 sc
->sc_intr_number
= -1;
267 sc
->sc_intr_pipe
= NULL
;
269 dd
= usbd_get_device_descriptor(dev
);
270 DPRINTF(("%s: uticom_attach: num of configurations %d\n",
271 device_get_nameunit(self
), dd
->bNumConfigurations
));
273 /* The device without firmware has single configuration with single
274 * bulk out interface. */
275 if (dd
->bNumConfigurations
> 1)
278 /* Loading firmware. */
279 DPRINTF(("%s: uticom_attach: starting loading firmware\n",
280 device_get_nameunit(self
)));
282 err
= usbd_set_config_index(dev
, UTICOM_CONFIG_INDEX
, 1);
284 device_printf(self
, "failed to set configuration: %s\n",
290 /* Get the config descriptor. */
291 cdesc
= usbd_get_config_descriptor(ucom
->sc_udev
);
294 device_printf(self
, "failed to get configuration descriptor\n");
299 err
= usbd_device2interface_handle(dev
, UTICOM_IFACE_INDEX
,
302 device_printf(self
, "failed to get interface: %s\n",
308 /* Find the bulk out interface used to upload firmware. */
309 id
= usbd_get_interface_descriptor(ucom
->sc_iface
);
310 sc
->sc_iface_number
= id
->bInterfaceNumber
;
312 for (i
= 0; i
< id
->bNumEndpoints
; i
++) {
313 ed
= usbd_interface2endpoint_descriptor(ucom
->sc_iface
, i
);
316 "no endpoint descriptor for %d\n", i
);
321 if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_OUT
&&
322 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
323 ucom
->sc_bulkout_no
= ed
->bEndpointAddress
;
324 DPRINTF(("%s: uticom_attach: data bulk out num: %d\n",
325 device_get_nameunit(self
),
326 ed
->bEndpointAddress
));
329 if (ucom
->sc_bulkout_no
== -1) {
330 device_printf(self
, "could not find data bulk out\n");
336 status
= uticom_download_fw(sc
, ucom
->sc_bulkout_no
, dev
,
337 uticom_fw_3410
, sizeof(uticom_fw_3410
));
340 device_printf(self
, "firmware download failed\n");
344 device_printf(self
, "firmware download succeeded\n");
347 status
= usbd_reload_device_desc(dev
);
349 device_printf(self
, "error reloading device descriptor\n");
355 dd
= usbd_get_device_descriptor(dev
);
356 DPRINTF(("%s: uticom_attach: num of configurations %d\n",
357 device_get_nameunit(self
), dd
->bNumConfigurations
));
359 err
= usbd_set_config_index(dev
, UTICOM_ACTIVE_INDEX
, 1);
361 device_printf(self
, "failed to set configuration: %s\n",
367 /* Get the config descriptor. */
368 cdesc
= usbd_get_config_descriptor(ucom
->sc_udev
);
370 device_printf(self
, "failed to get configuration descriptor\n");
375 /* Get the interface (XXX: multiport chips are not supported yet). */
376 err
= usbd_device2interface_handle(dev
, UTICOM_IFACE_INDEX
,
379 device_printf(self
, "failed to get interface: %s\n",
385 /* Find the interrupt endpoints. */
386 id
= usbd_get_interface_descriptor(ucom
->sc_iface
);
387 sc
->sc_iface_number
= id
->bInterfaceNumber
;
389 for (i
= 0; i
< id
->bNumEndpoints
; i
++) {
390 ed
= usbd_interface2endpoint_descriptor(ucom
->sc_iface
, i
);
393 "no endpoint descriptor for %d\n", i
);
398 if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
&&
399 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_INTERRUPT
) {
400 sc
->sc_intr_number
= ed
->bEndpointAddress
;
401 sc
->sc_isize
= UGETW(ed
->wMaxPacketSize
);
405 if (sc
->sc_intr_number
== -1) {
406 device_printf(self
, "could not find interrupt in\n");
411 /* Keep interface for interrupt. */
412 sc
->sc_intr_iface
= ucom
->sc_iface
;
414 /* Find the bulk{in,out} endpoints. */
415 id
= usbd_get_interface_descriptor(ucom
->sc_iface
);
416 sc
->sc_iface_number
= id
->bInterfaceNumber
;
418 for (i
= 0; i
< id
->bNumEndpoints
; i
++) {
419 ed
= usbd_interface2endpoint_descriptor(ucom
->sc_iface
, i
);
422 "no endpoint descriptor for %d\n", i
);
427 if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
&&
428 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
429 ucom
->sc_bulkin_no
= ed
->bEndpointAddress
;
430 } else if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_OUT
&&
431 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
432 ucom
->sc_bulkout_no
= ed
->bEndpointAddress
;
436 if (ucom
->sc_bulkin_no
== -1) {
437 device_printf(self
, "could not find data bulk in\n");
442 if (ucom
->sc_bulkout_no
== -1) {
443 device_printf(self
, "could not find data bulk out\n");
448 sc
->sc_dtr
= sc
->sc_rts
= -1;
449 ucom
->sc_parent
= sc
;
450 ucom
->sc_portno
= UCOM_UNK_PORTNO
;
451 ucom
->sc_ibufsize
= UTICOM_IBUFSZ
;
452 ucom
->sc_obufsize
= UTICOM_OBUFSZ
;
453 ucom
->sc_ibufsizepad
= UTICOM_IBUFSZ
;
454 ucom
->sc_opkthdrlen
= 0;
455 ucom
->sc_callback
= &uticom_callback
;
457 err
= uticom_reset(sc
);
459 device_printf(self
, "reset failed: %s\n", usbd_errstr(err
));
464 DPRINTF(("%s: uticom_attach: in = 0x%x, out = 0x%x, intr = 0x%x\n",
465 device_get_nameunit(self
), ucom
->sc_bulkin_no
,
466 ucom
->sc_bulkout_no
, sc
->sc_intr_number
));
468 ucom_attach(&sc
->sc_ucom
);
473 uticom_detach(device_t self
)
475 struct uticom_softc
*sc
= device_get_softc(self
);
477 DPRINTF(("%s: uticom_detach: sc = %p\n",
478 device_get_nameunit(self
), sc
));
480 if (sc
->sc_intr_pipe
!= NULL
) {
481 usbd_abort_pipe(sc
->sc_intr_pipe
);
482 usbd_close_pipe(sc
->sc_intr_pipe
);
483 kfree(sc
->sc_intr_buf
, M_USBDEV
);
484 sc
->sc_intr_pipe
= NULL
;
487 sc
->sc_ucom
.sc_dying
= 1;
488 return (ucom_detach(&sc
->sc_ucom
));
492 uticom_reset(struct uticom_softc
*sc
)
494 usb_device_request_t req
;
496 device_t dev
= sc
->sc_ucom
.sc_dev
;
498 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
499 req
.bRequest
= UTICOM_RQ_SON
;
500 USETW(req
.wValue
, 0);
501 USETW(req
.wIndex
, 0);
502 USETW(req
.wLength
, 0);
504 err
= usbd_do_request(sc
->sc_ucom
.sc_udev
, &req
, NULL
);
506 device_printf(dev
, "uticom_reset: %s\n", usbd_errstr(err
));
510 DPRINTF(("%s: uticom_reset: done\n", device_get_nameunit(dev
)));
515 uticom_set(void *addr
, int portno
, int reg
, int onoff
)
517 struct uticom_softc
*sc
= addr
;
521 uticom_dtr(sc
, onoff
);
524 uticom_rts(sc
, onoff
);
527 uticom_break(sc
, onoff
);
535 uticom_dtr(struct uticom_softc
*sc
, int onoff
)
537 usb_device_request_t req
;
539 device_t dev
= sc
->sc_ucom
.sc_dev
;
541 DPRINTF(("%s: uticom_dtr: onoff = %d\n", device_get_nameunit(dev
),
544 if (sc
->sc_dtr
== onoff
)
548 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
549 req
.bRequest
= UTICOM_RQ_DTR
;
550 USETW(req
.wValue
, sc
->sc_dtr
? UCDC_LINE_DTR
: 0);
551 USETW(req
.wIndex
, 0);
552 USETW(req
.wLength
, 0);
554 err
= usbd_do_request(sc
->sc_ucom
.sc_udev
, &req
, NULL
);
556 device_printf(dev
, "uticom_dtr: %s\n", usbd_errstr(err
));
560 uticom_rts(struct uticom_softc
*sc
, int onoff
)
562 usb_device_request_t req
;
564 device_t dev
= sc
->sc_ucom
.sc_dev
;
566 DPRINTF(("%s: uticom_rts: onoff = %d\n", device_get_nameunit(dev
),
569 if (sc
->sc_rts
== onoff
)
572 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
573 req
.bRequest
= UTICOM_RQ_RTS
;
574 USETW(req
.wValue
, sc
->sc_rts
? UCDC_LINE_RTS
: 0);
575 USETW(req
.wIndex
, 0);
576 USETW(req
.wLength
, 0);
578 err
= usbd_do_request(sc
->sc_ucom
.sc_udev
, &req
, NULL
);
580 device_printf(dev
, "uticom_rts: %s\n", usbd_errstr(err
));
584 uticom_break(struct uticom_softc
*sc
, int onoff
)
586 usb_device_request_t req
;
588 device_t dev
= sc
->sc_ucom
.sc_dev
;
590 DPRINTF(("%s: uticom_break: onoff = %d\n", device_get_nameunit(dev
),
593 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
594 req
.bRequest
= UTICOM_RQ_BREAK
;
595 USETW(req
.wValue
, onoff
? 1 : 0);
596 USETW(req
.wIndex
, 0);
597 USETW(req
.wLength
, 0);
599 err
= usbd_do_request(sc
->sc_ucom
.sc_udev
, &req
, NULL
);
601 device_printf(dev
, "uticom_break: %s\n", usbd_errstr(err
));
605 uticom_set_crtscts(struct uticom_softc
*sc
)
607 usb_device_request_t req
;
609 device_t dev
= sc
->sc_ucom
.sc_dev
;
611 DPRINTF(("%s: uticom_set_crtscts: on\n", device_get_nameunit(dev
)));
613 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
614 req
.bRequest
= UTICOM_RQ_CRTSCTS
;
615 USETW(req
.wValue
, 1);
616 USETW(req
.wIndex
, 0);
617 USETW(req
.wLength
, 0);
619 err
= usbd_do_request(sc
->sc_ucom
.sc_udev
, &req
, NULL
);
621 device_printf(dev
, "uticom_set_crtscts: %s\n",
626 return (USBD_NORMAL_COMPLETION
);
630 uticom_param(void *vsc
, int portno
, struct termios
*t
)
632 struct uticom_softc
*sc
= (struct uticom_softc
*)vsc
;
633 device_t dev
= sc
->sc_ucom
.sc_dev
;
634 usb_device_request_t req
;
638 DPRINTF(("%s: uticom_param\n", device_get_nameunit(dev
)));
640 switch (t
->c_ospeed
) {
654 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
655 req
.bRequest
= UTICOM_RQ_BAUD
;
656 USETW(req
.wValue
, (UTICOM_BRATE_REF
/ t
->c_ospeed
));
657 USETW(req
.wIndex
, 0);
658 USETW(req
.wLength
, 0);
660 err
= usbd_do_request(sc
->sc_ucom
.sc_udev
, &req
, 0);
662 device_printf(dev
, "uticom_param: %s\n",
668 device_printf(dev
, "uticom_param: unsupported baud rate %d\n",
673 switch (ISSET(t
->c_cflag
, CSIZE
)) {
675 data
= UTICOM_SET_DATA_BITS(5);
678 data
= UTICOM_SET_DATA_BITS(6);
681 data
= UTICOM_SET_DATA_BITS(7);
684 data
= UTICOM_SET_DATA_BITS(8);
690 if (ISSET(t
->c_cflag
, CSTOPB
))
691 data
|= UTICOM_STOP_BITS_2
;
693 data
|= UTICOM_STOP_BITS_1
;
695 if (ISSET(t
->c_cflag
, PARENB
)) {
696 if (ISSET(t
->c_cflag
, PARODD
))
697 data
|= UTICOM_PARITY_ODD
;
699 data
|= UTICOM_PARITY_EVEN
;
701 data
|= UTICOM_PARITY_NONE
;
703 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
704 req
.bRequest
= UTICOM_RQ_LCR
;
705 USETW(req
.wIndex
, 0);
706 USETW(req
.wLength
, 0);
707 USETW(req
.wValue
, data
);
709 err
= usbd_do_request(sc
->sc_ucom
.sc_udev
, &req
, NULL
);
711 device_printf(dev
, "uticom_param: %s\n", usbd_errstr(err
));
715 if (ISSET(t
->c_cflag
, CRTSCTS
)) {
716 err
= uticom_set_crtscts(sc
);
725 uticom_open(void *addr
, int portno
)
727 struct uticom_softc
*sc
= addr
;
728 device_t dev
= sc
->sc_ucom
.sc_dev
;
731 if (sc
->sc_ucom
.sc_dying
)
734 DPRINTF(("%s: uticom_open\n", device_get_nameunit(dev
)));
736 sc
->sc_status
= 0; /* clear status bit */
738 if (sc
->sc_intr_number
!= -1 && sc
->sc_intr_pipe
== NULL
) {
739 sc
->sc_intr_buf
= kmalloc(sc
->sc_isize
, M_USBDEV
, M_WAITOK
);
740 err
= usbd_open_pipe_intr(sc
->sc_intr_iface
, sc
->sc_intr_number
,
741 USBD_SHORT_XFER_OK
, &sc
->sc_intr_pipe
,
742 sc
, sc
->sc_intr_buf
, sc
->sc_isize
,
743 uticom_intr
, UTICOM_INTR_INTERVAL
);
745 device_printf(dev
, "cannot open interrupt pipe "
746 "(addr %d)\n", sc
->sc_intr_number
);
751 DPRINTF(("%s: uticom_open: port opened\n", device_get_nameunit(dev
)));
756 uticom_close(void *addr
, int portno
)
758 struct uticom_softc
*sc
= addr
;
759 device_t dev
= sc
->sc_ucom
.sc_dev
;
760 usb_device_request_t req
;
763 if (sc
->sc_ucom
.sc_dying
)
766 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
767 req
.bRequest
= UTICOM_RQ_SON
;
768 USETW(req
.wValue
, 0);
769 USETW(req
.wIndex
, 0);
770 USETW(req
.wLength
, 0);
772 /* Try to reset UART part of chip. */
773 err
= usbd_do_request(sc
->sc_ucom
.sc_udev
, &req
, NULL
);
775 device_printf(dev
, "uticom_close: %s\n", usbd_errstr(err
));
779 DPRINTF(("%s: uticom_close: close\n",
780 device_get_nameunit(sc
->sc_ucom
.sc_dev
)));
782 if (sc
->sc_intr_pipe
!= NULL
) {
783 err
= usbd_abort_pipe(sc
->sc_intr_pipe
);
785 device_printf(dev
, "abort interrupt pipe failed: %s\n",
787 err
= usbd_close_pipe(sc
->sc_intr_pipe
);
789 device_printf(dev
, "close interrupt pipe failed: %s\n",
791 kfree(sc
->sc_intr_buf
, M_USBDEV
);
792 sc
->sc_intr_pipe
= NULL
;
797 uticom_intr(usbd_xfer_handle xfer
, usbd_private_handle priv
, usbd_status status
)
799 struct uticom_softc
*sc
= priv
;
800 u_char
*buf
= sc
->sc_intr_buf
;
802 if (sc
->sc_ucom
.sc_dying
)
805 if (status
!= USBD_NORMAL_COMPLETION
) {
806 if (status
== USBD_NOT_STARTED
|| status
== USBD_CANCELLED
) {
807 DPRINTF(("%s: uticom_intr: int status: %s\n",
808 device_get_nameunit(sc
->sc_ucom
.sc_dev
),
809 usbd_errstr(status
)));
813 DPRINTF(("%s: uticom_intr: abnormal status: %s\n",
814 device_get_nameunit(sc
->sc_ucom
.sc_dev
),
815 usbd_errstr(status
)));
816 usbd_clear_endpoint_stall_async(sc
->sc_intr_pipe
);
823 DPRINTF(("%s: xfer_length = %d\n",
824 device_get_nameunit(sc
->sc_ucom
.sc_dev
), xfer
->actlen
));
826 sc
->sc_lsr
= sc
->sc_msr
= 0;
830 if (buf
[1] & UTICOM_MCR_CTS
)
831 sc
->sc_msr
|= UMSR_CTS
;
832 if (buf
[1] & UTICOM_MCR_DSR
)
833 sc
->sc_msr
|= UMSR_DSR
;
834 if (buf
[1] & UTICOM_MCR_CD
)
835 sc
->sc_msr
|= UMSR_DCD
;
836 if (buf
[1] & UTICOM_MCR_RI
)
837 sc
->sc_msr
|= UMSR_RI
;
840 if (buf
[0] & UTICOM_LCR_OVR
)
841 sc
->sc_lsr
|= ULSR_OE
;
842 if (buf
[0] & UTICOM_LCR_PTE
)
843 sc
->sc_lsr
|= ULSR_PE
;
844 if (buf
[0] & UTICOM_LCR_FRE
)
845 sc
->sc_lsr
|= ULSR_FE
;
846 if (buf
[0] & UTICOM_LCR_BRK
)
847 sc
->sc_lsr
|= ULSR_BI
;
851 sc
->sc_msr
|= UMSR_DSR
;
853 ucom_status_change(&sc
->sc_ucom
);
857 uticom_get_status(void *addr
, int portno
, u_char
*lsr
, u_char
*msr
)
860 struct uticom_softc
*sc
= addr
;
862 DPRINTF(("uticom_get_status:\n"));
874 uticom_ioctl(void *addr
, int portno
, u_long cmd
, caddr_t data
, int flag
,
877 struct uticom_softc
*sc
= addr
;
880 if (sc
->sc_ucom
.sc_dying
)
883 DPRINTF(("uticom_ioctl: cmd = 0x%08lx\n", cmd
));
889 case USB_GET_CM_OVER_DATA
:
890 case USB_SET_CM_OVER_DATA
:
894 DPRINTF(("uticom_ioctl: unknown\n"));
903 static int uticom_download_fw(struct uticom_softc
*sc
, unsigned int pipeno
,
904 usbd_device_handle dev
, unsigned char *firmware
,
905 unsigned int firmware_size
)
912 struct uticom_fw_header
*header
;
914 buffer_size
= UTICOM_FW_BUFSZ
+ sizeof(struct uticom_fw_header
);
915 buffer
= kmalloc(buffer_size
, M_USBDEV
, M_WAITOK
);
917 memcpy(buffer
, firmware
, firmware_size
);
918 memset(buffer
+ firmware_size
, 0xff, buffer_size
- firmware_size
);
920 for (pos
= sizeof(struct uticom_fw_header
); pos
< buffer_size
; pos
++)
921 cs
= (uint8_t)(cs
+ buffer
[pos
]);
923 header
= (struct uticom_fw_header
*)buffer
;
924 header
->length
= (uint16_t)(buffer_size
-
925 sizeof(struct uticom_fw_header
));
926 header
->checkSum
= cs
;
928 DPRINTF(("%s: downloading firmware ...\n",
929 device_get_nameunit(sc
->sc_ucom
.sc_dev
)));
931 usbd_xfer_handle oxfer
= 0;
933 usbd_status error
= 0;
934 usbd_pipe_handle pipe
;
936 err
= usbd_open_pipe(sc
->sc_ucom
.sc_iface
, pipeno
, USBD_EXCLUSIVE_USE
,
939 device_printf(sc
->sc_ucom
.sc_dev
, "open bulk out error "
940 "(addr %d): %s\n", pipeno
, usbd_errstr(err
));
945 oxfer
= usbd_alloc_xfer(dev
);
951 obuf
= usbd_alloc_buffer(oxfer
, buffer_size
);
957 memcpy(obuf
, buffer
, buffer_size
);
959 usbd_setup_xfer(oxfer
, pipe
, (usbd_private_handle
)sc
, obuf
, buffer_size
,
960 USBD_NO_COPY
|| USBD_SYNCHRONOUS
, USBD_NO_TIMEOUT
, 0);
961 err
= usbd_sync_transfer(oxfer
);
963 if (err
!= USBD_NORMAL_COMPLETION
)
964 device_printf(sc
->sc_ucom
.sc_dev
, "uticom_download_fw: "
965 "error: %s\n", usbd_errstr(err
));
968 usbd_free_buffer(oxfer
);
969 usbd_free_xfer(oxfer
);
971 usbd_abort_pipe(pipe
);
972 usbd_close_pipe(pipe
);
973 kfree(buffer
, M_USBDEV
);