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