Remove bogus checks after kmalloc(M_WAITOK) which never returns NULL.
[dragonfly.git] / sys / dev / usbmisc / uticom / uticom.c
blob44c2a99b1b48f7b9021e7460bf0a980ee915e106
1 /*
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
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.
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.
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>
33 #include <sys/bus.h>
34 #include <sys/ioccom.h>
35 #include <sys/fcntl.h>
36 #include <sys/conf.h>
37 #include <sys/tty.h>
38 #include <sys/file.h>
39 #include <sys/select.h>
40 #include <sys/proc.h>
41 #include <sys/poll.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");
58 #ifdef USB_DEBUG
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)
64 #else
65 #define DPRINTFN(n, x)
66 #endif
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
120 /* Structures */
121 struct uticom_fw_header {
122 uint16_t length;
123 uint8_t checkSum;
124 } __attribute__((packed));
126 struct uticom_buf {
127 unsigned int buf_size;
128 char *buf_buf;
129 char *buf_get;
130 char *buf_put;
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 */
142 int sc_isize;
144 u_char sc_dtr; /* current DTR state */
145 u_char sc_rts; /* current RTS state */
146 u_char sc_status;
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 *);
161 #if 0 /* TODO */
162 static int uticom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr);
163 #endif
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 = {
173 uticom_get_status,
174 uticom_set,
175 uticom_param,
176 NULL, /* uticom_ioctl, TODO */
177 uticom_open,
178 uticom_close,
179 NULL,
180 NULL
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),
195 { 0, 0 }
198 static driver_t uticom_driver = {
199 "ucom",
200 uticom_methods,
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;
211 static int
212 sysctl_hw_usb_uticom_stickdsr(SYSCTL_HANDLER_ARGS)
214 int err, val;
216 val = uticomstickdsr;
217 err = sysctl_handle_int(oidp, &val, sizeof(val), req);
218 if (err != 0 || req->newptr == NULL)
219 return (err);
220 if (val == 0 || val == 1)
221 uticomstickdsr = val;
222 else
223 err = EINVAL;
225 return (err);
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");
231 static int
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);
243 static int
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;
254 usbd_status err;
255 int status, i;
256 usb_device_descriptor_t *dd;
258 ucom = &sc->sc_ucom;
259 bzero(sc, sizeof (struct uticom_softc));
260 ucom->sc_dev = self;
261 ucom->sc_udev = dev;
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)
276 goto fwload_done;
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);
283 if (err) {
284 device_printf(self, "failed to set configuration: %s\n",
285 usbd_errstr(err));
286 ucom->sc_dying = 1;
287 return ENXIO;
290 /* Get the config descriptor. */
291 cdesc = usbd_get_config_descriptor(ucom->sc_udev);
293 if (cdesc == NULL) {
294 device_printf(self, "failed to get configuration descriptor\n");
295 ucom->sc_dying = 1;
296 return ENXIO;
299 err = usbd_device2interface_handle(dev, UTICOM_IFACE_INDEX,
300 &ucom->sc_iface);
301 if (err) {
302 device_printf(self, "failed to get interface: %s\n",
303 usbd_errstr(err));
304 ucom->sc_dying = 1;
305 return ENXIO;
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);
314 if (ed == NULL) {
315 device_printf(self,
316 "no endpoint descriptor for %d\n", i);
317 ucom->sc_dying = 1;
318 return ENXIO;
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");
331 ucom->sc_dying = 1;
332 return ENXIO;
336 status = uticom_download_fw(sc, ucom->sc_bulkout_no, dev,
337 uticom_fw_3410, sizeof(uticom_fw_3410));
339 if (status) {
340 device_printf(self, "firmware download failed\n");
341 ucom->sc_dying = 1;
342 return ENXIO;
343 } else {
344 device_printf(self, "firmware download succeeded\n");
347 status = usbd_reload_device_desc(dev);
348 if (status) {
349 device_printf(self, "error reloading device descriptor\n");
350 ucom->sc_dying = 1;
351 return ENXIO;
354 fwload_done:
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);
360 if (err) {
361 device_printf(self, "failed to set configuration: %s\n",
362 usbd_errstr(err));
363 ucom->sc_dying = 1;
364 return ENXIO;
367 /* Get the config descriptor. */
368 cdesc = usbd_get_config_descriptor(ucom->sc_udev);
369 if (cdesc == NULL) {
370 device_printf(self, "failed to get configuration descriptor\n");
371 ucom->sc_dying = 1;
372 return ENXIO;
375 /* Get the interface (XXX: multiport chips are not supported yet). */
376 err = usbd_device2interface_handle(dev, UTICOM_IFACE_INDEX,
377 &ucom->sc_iface);
378 if (err) {
379 device_printf(self, "failed to get interface: %s\n",
380 usbd_errstr(err));
381 ucom->sc_dying = 1;
382 return ENXIO;
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);
391 if (ed == NULL) {
392 device_printf(self,
393 "no endpoint descriptor for %d\n", i);
394 ucom->sc_dying = 1;
395 return ENXIO;
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");
407 ucom->sc_dying = 1;
408 return ENXIO;
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);
420 if (ed == NULL) {
421 device_printf(self,
422 "no endpoint descriptor for %d\n", i);
423 ucom->sc_dying = 1;
424 return ENXIO;
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");
438 ucom->sc_dying = 1;
439 return ENXIO;
442 if (ucom->sc_bulkout_no == -1) {
443 device_printf(self, "could not find data bulk out\n");
444 ucom->sc_dying = 1;
445 return ENXIO;
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);
458 if (err) {
459 device_printf(self, "reset failed: %s\n", usbd_errstr(err));
460 ucom->sc_dying = 1;
461 return ENXIO;
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);
469 return 0;
472 static int
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));
491 static usbd_status
492 uticom_reset(struct uticom_softc *sc)
494 usb_device_request_t req;
495 usbd_status err;
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);
505 if (err){
506 device_printf(dev, "uticom_reset: %s\n", usbd_errstr(err));
507 return (EIO);
510 DPRINTF(("%s: uticom_reset: done\n", device_get_nameunit(dev)));
511 return (0);
514 static void
515 uticom_set(void *addr, int portno, int reg, int onoff)
517 struct uticom_softc *sc = addr;
519 switch (reg) {
520 case UCOM_SET_DTR:
521 uticom_dtr(sc, onoff);
522 break;
523 case UCOM_SET_RTS:
524 uticom_rts(sc, onoff);
525 break;
526 case UCOM_SET_BREAK:
527 uticom_break(sc, onoff);
528 break;
529 default:
530 break;
534 static void
535 uticom_dtr(struct uticom_softc *sc, int onoff)
537 usb_device_request_t req;
538 usbd_status err;
539 device_t dev = sc->sc_ucom.sc_dev;
541 DPRINTF(("%s: uticom_dtr: onoff = %d\n", device_get_nameunit(dev),
542 onoff));
544 if (sc->sc_dtr == onoff)
545 return;
546 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);
555 if (err)
556 device_printf(dev, "uticom_dtr: %s\n", usbd_errstr(err));
559 static void
560 uticom_rts(struct uticom_softc *sc, int onoff)
562 usb_device_request_t req;
563 usbd_status err;
564 device_t dev = sc->sc_ucom.sc_dev;
566 DPRINTF(("%s: uticom_rts: onoff = %d\n", device_get_nameunit(dev),
567 onoff));
569 if (sc->sc_rts == onoff)
570 return;
571 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);
579 if (err)
580 device_printf(dev, "uticom_rts: %s\n", usbd_errstr(err));
583 static void
584 uticom_break(struct uticom_softc *sc, int onoff)
586 usb_device_request_t req;
587 usbd_status err;
588 device_t dev = sc->sc_ucom.sc_dev;
590 DPRINTF(("%s: uticom_break: onoff = %d\n", device_get_nameunit(dev),
591 onoff));
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);
600 if (err)
601 device_printf(dev, "uticom_break: %s\n", usbd_errstr(err));
604 static usbd_status
605 uticom_set_crtscts(struct uticom_softc *sc)
607 usb_device_request_t req;
608 usbd_status err;
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);
620 if (err) {
621 device_printf(dev, "uticom_set_crtscts: %s\n",
622 usbd_errstr(err));
623 return (err);
626 return (USBD_NORMAL_COMPLETION);
629 static int
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;
635 usbd_status err;
636 uint8_t data;
638 DPRINTF(("%s: uticom_param\n", device_get_nameunit(dev)));
640 switch (t->c_ospeed) {
641 case 1200:
642 case 2400:
643 case 4800:
644 case 7200:
645 case 9600:
646 case 14400:
647 case 19200:
648 case 38400:
649 case 57600:
650 case 115200:
651 case 230400:
652 case 460800:
653 case 921600:
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);
661 if (err) {
662 device_printf(dev, "uticom_param: %s\n",
663 usbd_errstr(err));
664 return (EIO);
666 break;
667 default:
668 device_printf(dev, "uticom_param: unsupported baud rate %d\n",
669 t->c_ospeed);
670 return (EINVAL);
673 switch (ISSET(t->c_cflag, CSIZE)) {
674 case CS5:
675 data = UTICOM_SET_DATA_BITS(5);
676 break;
677 case CS6:
678 data = UTICOM_SET_DATA_BITS(6);
679 break;
680 case CS7:
681 data = UTICOM_SET_DATA_BITS(7);
682 break;
683 case CS8:
684 data = UTICOM_SET_DATA_BITS(8);
685 break;
686 default:
687 return (EIO);
690 if (ISSET(t->c_cflag, CSTOPB))
691 data |= UTICOM_STOP_BITS_2;
692 else
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;
698 else
699 data |= UTICOM_PARITY_EVEN;
700 } else
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);
710 if (err) {
711 device_printf(dev, "uticom_param: %s\n", usbd_errstr(err));
712 return (err);
715 if (ISSET(t->c_cflag, CRTSCTS)) {
716 err = uticom_set_crtscts(sc);
717 if (err)
718 return (EIO);
721 return (0);
724 static int
725 uticom_open(void *addr, int portno)
727 struct uticom_softc *sc = addr;
728 device_t dev = sc->sc_ucom.sc_dev;
729 usbd_status err;
731 if (sc->sc_ucom.sc_dying)
732 return (ENXIO);
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);
744 if (err) {
745 device_printf(dev, "cannot open interrupt pipe "
746 "(addr %d)\n", sc->sc_intr_number);
747 return (EIO);
751 DPRINTF(("%s: uticom_open: port opened\n", device_get_nameunit(dev)));
752 return (0);
755 static void
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;
761 usbd_status err;
763 if (sc->sc_ucom.sc_dying)
764 return;
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);
774 if (err) {
775 device_printf(dev, "uticom_close: %s\n", usbd_errstr(err));
776 return;
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);
784 if (err)
785 device_printf(dev, "abort interrupt pipe failed: %s\n",
786 usbd_errstr(err));
787 err = usbd_close_pipe(sc->sc_intr_pipe);
788 if (err)
789 device_printf(dev, "close interrupt pipe failed: %s\n",
790 usbd_errstr(err));
791 kfree(sc->sc_intr_buf, M_USBDEV);
792 sc->sc_intr_pipe = NULL;
796 static void
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)
803 return;
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)));
810 return;
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);
817 return;
820 if (!xfer->actlen)
821 return;
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;
828 if (buf[0] == 0) {
829 /* msr registers */
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;
838 } else {
839 /* lsr registers */
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;
850 if (uticomstickdsr)
851 sc->sc_msr |= UMSR_DSR;
853 ucom_status_change(&sc->sc_ucom);
856 static void
857 uticom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
859 #if 0 /* TODO */
860 struct uticom_softc *sc = addr;
862 DPRINTF(("uticom_get_status:\n"));
864 if (lsr != NULL)
865 *lsr = sc->sc_lsr;
866 if (msr != NULL)
867 *msr = sc->sc_msr;
868 #endif
869 return;
872 #if 0 /* TODO */
873 static int
874 uticom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
875 usb_proc_ptr p)
877 struct uticom_softc *sc = addr;
878 int error = 0;
880 if (sc->sc_ucom.sc_dying)
881 return (EIO);
883 DPRINTF(("uticom_ioctl: cmd = 0x%08lx\n", cmd));
885 switch (cmd) {
886 case TIOCNOTTY:
887 case TIOCMGET:
888 case TIOCMSET:
889 case USB_GET_CM_OVER_DATA:
890 case USB_SET_CM_OVER_DATA:
891 break;
893 default:
894 DPRINTF(("uticom_ioctl: unknown\n"));
895 error = ENOTTY;
896 break;
899 return (error);
901 #endif
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)
907 int buffer_size;
908 int pos;
909 uint8_t cs = 0;
910 uint8_t *buffer;
911 usbd_status err;
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;
932 u_char *obuf;
933 usbd_status error = 0;
934 usbd_pipe_handle pipe;
936 err = usbd_open_pipe(sc->sc_ucom.sc_iface, pipeno, USBD_EXCLUSIVE_USE,
937 &pipe);
938 if (err) {
939 device_printf(sc->sc_ucom.sc_dev, "open bulk out error "
940 "(addr %d): %s\n", pipeno, usbd_errstr(err));
941 error = EIO;
942 goto finish;
945 oxfer = usbd_alloc_xfer(dev);
946 if (oxfer == NULL) {
947 error = ENOMEM;
948 goto finish;
951 obuf = usbd_alloc_buffer(oxfer, buffer_size);
952 if (obuf == NULL) {
953 error = ENOMEM;
954 goto finish;
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));
967 finish:
968 usbd_free_buffer(oxfer);
969 usbd_free_xfer(oxfer);
970 oxfer = NULL;
971 usbd_abort_pipe(pipe);
972 usbd_close_pipe(pipe);
973 kfree(buffer, M_USBDEV);
975 return err;