net/if_clone: Panic if the same cloner is attached twice
[dragonfly.git] / sys / dev / usbmisc / uticom / uticom.c
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, 0, 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 }