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