carp: add carp_group_demote_adj()
[dragonfly.git] / sys / dev / usbmisc / uvscom / uvscom.c
1 /*-
2  * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
3  * All rights reserved.
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  * $NetBSD: usb/uvscom.c,v 1.1 2002/03/19 15:08:42 augustss Exp $
27  * $FreeBSD: src/sys/dev/usb/uvscom.c,v 1.19 2003/11/16 12:26:10 akiyama Exp $
28  * $DragonFly: src/sys/dev/usbmisc/uvscom/uvscom.c,v 1.20 2008/01/16 12:24:31 matthias Exp $
29  */
30
31 /*
32  * uvscom: SUNTAC Slipper U VS-10U driver.
33  * Slipper U is a PC card to USB converter for data communication card
34  * adapter.  It supports DDI Pocket's Air H" C@rd, C@rd H" 64, NTT's P-in,
35  * P-in m@ater and various data communication card adapters.
36  */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/fcntl.h>
43 #include <sys/conf.h>
44 #include <sys/tty.h>
45 #include <sys/file.h>
46 #include <sys/bus.h>
47 #include <sys/select.h>
48 #include <sys/proc.h>
49 #include <sys/poll.h>
50 #include <sys/sysctl.h>
51
52 #include <bus/usb/usb.h>
53 #include <bus/usb/usbcdc.h>
54
55 #include <bus/usb/usbdi.h>
56 #include <bus/usb/usbdi_util.h>
57 #include <bus/usb/usb_quirks.h>
58
59 #include "../ucom/ucomvar.h"
60
61 #ifdef USB_DEBUG
62 static int      uvscomdebug = 0;
63 SYSCTL_NODE(_hw_usb, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom");
64 SYSCTL_INT(_hw_usb_uvscom, OID_AUTO, debug, CTLFLAG_RW,
65            &uvscomdebug, 0, "uvscom debug level");
66
67 #define DPRINTFN(n, x) do { \
68                                 if (uvscomdebug > (n)) \
69                                         kprintf x; \
70                         } while (0)
71 #else
72 #define DPRINTFN(n, x)
73 #endif
74 #define DPRINTF(x) DPRINTFN(0, x)
75
76 #define UVSCOM_MODVER           1       /* module version */
77
78 #define UVSCOM_CONFIG_INDEX     0
79 #define UVSCOM_IFACE_INDEX      0
80
81 #define UVSCOM_INTR_INTERVAL    100     /* mS */
82
83 #define UVSCOM_UNIT_WAIT        5
84
85 /* Request */
86 #define UVSCOM_SET_SPEED        0x10
87 #define UVSCOM_LINE_CTL         0x11
88 #define UVSCOM_SET_PARAM        0x12
89 #define UVSCOM_READ_STATUS      0xd0
90 #define UVSCOM_SHUTDOWN         0xe0
91
92 /* UVSCOM_SET_SPEED parameters */
93 #define UVSCOM_SPEED_150BPS     0x00
94 #define UVSCOM_SPEED_300BPS     0x01
95 #define UVSCOM_SPEED_600BPS     0x02
96 #define UVSCOM_SPEED_1200BPS    0x03
97 #define UVSCOM_SPEED_2400BPS    0x04
98 #define UVSCOM_SPEED_4800BPS    0x05
99 #define UVSCOM_SPEED_9600BPS    0x06
100 #define UVSCOM_SPEED_19200BPS   0x07
101 #define UVSCOM_SPEED_38400BPS   0x08
102 #define UVSCOM_SPEED_57600BPS   0x09
103 #define UVSCOM_SPEED_115200BPS  0x0a
104
105 /* UVSCOM_LINE_CTL parameters */
106 #define UVSCOM_BREAK            0x40
107 #define UVSCOM_RTS              0x02
108 #define UVSCOM_DTR              0x01
109 #define UVSCOM_LINE_INIT        0x08
110
111 /* UVSCOM_SET_PARAM parameters */
112 #define UVSCOM_DATA_MASK        0x03
113 #define UVSCOM_DATA_BIT_8       0x03
114 #define UVSCOM_DATA_BIT_7       0x02
115 #define UVSCOM_DATA_BIT_6       0x01
116 #define UVSCOM_DATA_BIT_5       0x00
117
118 #define UVSCOM_STOP_MASK        0x04
119 #define UVSCOM_STOP_BIT_2       0x04
120 #define UVSCOM_STOP_BIT_1       0x00
121
122 #define UVSCOM_PARITY_MASK      0x18
123 #define UVSCOM_PARITY_EVEN      0x18
124 #if 0
125 #define UVSCOM_PARITY_UNK       0x10
126 #endif
127 #define UVSCOM_PARITY_ODD       0x08
128 #define UVSCOM_PARITY_NONE      0x00
129
130 /* Status bits */
131 #define UVSCOM_TXRDY            0x04
132 #define UVSCOM_RXRDY            0x01
133
134 #define UVSCOM_DCD              0x08
135 #define UVSCOM_NOCARD           0x04
136 #define UVSCOM_DSR              0x02
137 #define UVSCOM_CTS              0x01
138 #define UVSCOM_USTAT_MASK       (UVSCOM_NOCARD | UVSCOM_DSR | UVSCOM_CTS)
139
140 struct  uvscom_softc {
141         struct ucom_softc       sc_ucom;
142
143         int                     sc_iface_number;/* interface number */
144
145         usbd_interface_handle   sc_intr_iface;  /* interrupt interface */
146         int                     sc_intr_number; /* interrupt number */
147         usbd_pipe_handle        sc_intr_pipe;   /* interrupt pipe */
148         u_char                  *sc_intr_buf;   /* interrupt buffer */
149         int                     sc_isize;
150
151         u_char                  sc_dtr;         /* current DTR state */
152         u_char                  sc_rts;         /* current RTS state */
153
154         u_char                  sc_lsr;         /* Local status register */
155         u_char                  sc_msr;         /* uvscom status register */
156
157         uint16_t                sc_lcr;         /* Line control */
158         u_char                  sc_usr;         /* unit status */
159 };
160
161 /*
162  * These are the maximum number of bytes transferred per frame.
163  * The output buffer size cannot be increased due to the size encoding.
164  */
165 #define UVSCOMIBUFSIZE 512
166 #define UVSCOMOBUFSIZE 64
167
168 static  usbd_status uvscom_shutdown(struct uvscom_softc *);
169 static  usbd_status uvscom_reset(struct uvscom_softc *);
170 static  usbd_status uvscom_set_line_coding(struct uvscom_softc *,
171                                            uint16_t, uint16_t);
172 static  usbd_status uvscom_set_line(struct uvscom_softc *, uint16_t);
173 static  usbd_status uvscom_set_crtscts(struct uvscom_softc *);
174 static  void uvscom_get_status(void *, int, u_char *, u_char *);
175 static  void uvscom_dtr(struct uvscom_softc *, int);
176 static  void uvscom_rts(struct uvscom_softc *, int);
177 static  void uvscom_break(struct uvscom_softc *, int);
178
179 static  void uvscom_set(void *, int, int, int);
180 static  void uvscom_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
181 #if TODO
182 static  int  uvscom_ioctl(void *, int, u_long, caddr_t, int, struct thread *);
183 #endif
184 static  int  uvscom_param(void *, int, struct termios *);
185 static  int  uvscom_open(void *, int);
186 static  void uvscom_close(void *, int);
187
188 struct ucom_callback uvscom_callback = {
189         uvscom_get_status,
190         uvscom_set,
191         uvscom_param,
192         NULL, /* uvscom_ioctl, TODO */
193         uvscom_open,
194         uvscom_close,
195         NULL,
196         NULL
197 };
198
199 static const struct usb_devno uvscom_devs [] = {
200         { USB_DEVICE(0x05db, 0x0003) }, /* SUNTAC U-Cable type D2 */
201         { USB_DEVICE(0x05db, 0x0005) }, /* SUNTAC U-Cable type P1 */
202         { USB_DEVICE(0x05db, 0x0009) }, /* SUNTAC Slipper U */
203         { USB_DEVICE(0x05db, 0x000a) }, /* SUNTAC Ir-Trinity */
204         { USB_DEVICE(0x05db, 0x0011) }, /* SUNTAC U-Cable type */
205 };
206
207 static device_probe_t uvscom_match;
208 static device_attach_t uvscom_attach;
209 static device_detach_t uvscom_detach;
210
211 static device_method_t uvscom_methods[] = {
212         /* Device interface */
213         DEVMETHOD(device_probe, uvscom_match),
214         DEVMETHOD(device_attach, uvscom_attach),
215         DEVMETHOD(device_detach, uvscom_detach),
216         { 0, 0 }
217 };
218
219 static driver_t uvscom_driver = {
220         "ucom",
221         uvscom_methods,
222         sizeof (struct uvscom_softc)
223 };
224
225 DRIVER_MODULE(uvscom, uhub, uvscom_driver, ucom_devclass, usbd_driver_load, 0);
226 MODULE_DEPEND(uvscom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
227 MODULE_VERSION(uvscom, UVSCOM_MODVER);
228
229 static int
230 uvscom_match(device_t self)
231 {
232         struct usb_attach_arg *uaa = device_get_ivars(self);
233
234         if (uaa->iface != NULL)
235                 return (UMATCH_NONE);
236
237         return (usb_lookup(uvscom_devs, uaa->vendor, uaa->product) != NULL ?
238                 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
239 }
240
241 static int
242 uvscom_attach(device_t self)
243 {
244         struct uvscom_softc *sc = device_get_softc(self);
245         struct usb_attach_arg *uaa = device_get_ivars(self);
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         const char *devname;
252         usbd_status err;
253         int i;
254
255         ucom = &sc->sc_ucom;
256
257         bzero(sc, sizeof (struct uvscom_softc));
258
259         ucom->sc_dev = self;
260         ucom->sc_udev = dev;
261         ucom->sc_iface = uaa->iface;
262
263         devname = device_get_nameunit(ucom->sc_dev);
264
265         DPRINTF(("uvscom attach: sc = %p\n", sc));
266
267         /* initialize endpoints */
268         ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
269         sc->sc_intr_number = -1;
270         sc->sc_intr_pipe = NULL;
271
272         /* Move the device into the configured state. */
273         err = usbd_set_config_index(dev, UVSCOM_CONFIG_INDEX, 1);
274         if (err) {
275                 kprintf("%s: failed to set configuration, err=%s\n",
276                         devname, usbd_errstr(err));
277                 goto error;
278         }
279
280         /* get the config descriptor */
281         cdesc = usbd_get_config_descriptor(ucom->sc_udev);
282
283         if (cdesc == NULL) {
284                 kprintf("%s: failed to get configuration descriptor\n",
285                         device_get_nameunit(ucom->sc_dev));
286                 goto error;
287         }
288
289         /* get the common interface */
290         err = usbd_device2interface_handle(dev, UVSCOM_IFACE_INDEX,
291                                            &ucom->sc_iface);
292         if (err) {
293                 kprintf("%s: failed to get interface, err=%s\n",
294                         devname, usbd_errstr(err));
295                 goto error;
296         }
297
298         id = usbd_get_interface_descriptor(ucom->sc_iface);
299         sc->sc_iface_number = id->bInterfaceNumber;
300
301         /* Find endpoints */
302         for (i = 0; i < id->bNumEndpoints; i++) {
303                 ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
304                 if (ed == NULL) {
305                         kprintf("%s: no endpoint descriptor for %d\n",
306                                 device_get_nameunit(ucom->sc_dev), i);
307                         goto error;
308                 }
309
310                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
311                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
312                         ucom->sc_bulkin_no = ed->bEndpointAddress;
313                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
314                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
315                         ucom->sc_bulkout_no = ed->bEndpointAddress;
316                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
317                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
318                         sc->sc_intr_number = ed->bEndpointAddress;
319                         sc->sc_isize = UGETW(ed->wMaxPacketSize);
320                 }
321         }
322
323         if (ucom->sc_bulkin_no == -1) {
324                 kprintf("%s: Could not find data bulk in\n",
325                         device_get_nameunit(ucom->sc_dev));
326                 goto error;
327         }
328         if (ucom->sc_bulkout_no == -1) {
329                 kprintf("%s: Could not find data bulk out\n",
330                         device_get_nameunit(ucom->sc_dev));
331                 goto error;
332         }
333         if (sc->sc_intr_number == -1) {
334                 kprintf("%s: Could not find interrupt in\n",
335                         device_get_nameunit(ucom->sc_dev));
336                 goto error;
337         }
338
339         sc->sc_dtr = sc->sc_rts = 0;
340         sc->sc_lcr = UVSCOM_LINE_INIT;
341
342         ucom->sc_parent = sc;
343         ucom->sc_portno = UCOM_UNK_PORTNO;
344         /* bulkin, bulkout set above */
345         ucom->sc_ibufsize = UVSCOMIBUFSIZE;
346         ucom->sc_obufsize = UVSCOMOBUFSIZE;
347         ucom->sc_ibufsizepad = UVSCOMIBUFSIZE;
348         ucom->sc_opkthdrlen = 0;
349         ucom->sc_callback = &uvscom_callback;
350
351         err = uvscom_reset(sc);
352
353         if (err) {
354                 kprintf("%s: reset failed, %s\n", device_get_nameunit(ucom->sc_dev),
355                         usbd_errstr(err));
356                 goto error;
357         }
358
359         DPRINTF(("uvscom: in = 0x%x out = 0x%x intr = 0x%x\n",
360                  ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number));
361
362         ucom_attach(&sc->sc_ucom);
363
364         return 0;
365
366 error:
367         ucom->sc_dying = 1;
368         return ENXIO;
369 }
370
371 static int
372 uvscom_detach(device_t self)
373 {
374         struct uvscom_softc *sc = device_get_softc(self);
375         int rv = 0;
376
377         DPRINTF(("uvscom_detach: sc = %p\n", sc));
378
379         sc->sc_ucom.sc_dying = 1;
380
381         if (sc->sc_intr_pipe != NULL) {
382                 usbd_abort_pipe(sc->sc_intr_pipe);
383                 usbd_close_pipe(sc->sc_intr_pipe);
384                 kfree(sc->sc_intr_buf, M_USBDEV);
385                 sc->sc_intr_pipe = NULL;
386         }
387
388         rv = ucom_detach(&sc->sc_ucom);
389
390         return (rv);
391 }
392
393 static usbd_status
394 uvscom_readstat(struct uvscom_softc *sc)
395 {
396         usb_device_request_t req;
397         usbd_status err;
398         uint16_t r;
399
400         DPRINTF(("%s: send readstat\n", device_get_nameunit(sc->sc_ucom.sc_dev)));
401
402         req.bmRequestType = UT_READ_VENDOR_DEVICE;
403         req.bRequest = UVSCOM_READ_STATUS;
404         USETW(req.wValue, 0);
405         USETW(req.wIndex, 0);
406         USETW(req.wLength, 2);
407
408         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, &r);
409         if (err) {
410                 kprintf("%s: uvscom_readstat: %s\n",
411                        device_get_nameunit(sc->sc_ucom.sc_dev), usbd_errstr(err));
412                 return (err);
413         }
414
415         DPRINTF(("%s: uvscom_readstat: r = %d\n",
416                  device_get_nameunit(sc->sc_ucom.sc_dev), r));
417
418         return (USBD_NORMAL_COMPLETION);
419 }
420
421 static usbd_status
422 uvscom_shutdown(struct uvscom_softc *sc)
423 {
424         usb_device_request_t req;
425         usbd_status err;
426
427         DPRINTF(("%s: send shutdown\n", device_get_nameunit(sc->sc_ucom.sc_dev)));
428
429         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
430         req.bRequest = UVSCOM_SHUTDOWN;
431         USETW(req.wValue, 0);
432         USETW(req.wIndex, 0);
433         USETW(req.wLength, 0);
434
435         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
436         if (err) {
437                 kprintf("%s: uvscom_shutdown: %s\n",
438                        device_get_nameunit(sc->sc_ucom.sc_dev), usbd_errstr(err));
439                 return (err);
440         }
441
442         return (USBD_NORMAL_COMPLETION);
443 }
444
445 static usbd_status
446 uvscom_reset(struct uvscom_softc *sc)
447 {
448         DPRINTF(("%s: uvscom_reset\n", device_get_nameunit(sc->sc_ucom.sc_dev)));
449
450         return (USBD_NORMAL_COMPLETION);
451 }
452
453 static usbd_status
454 uvscom_set_crtscts(struct uvscom_softc *sc)
455 {
456         DPRINTF(("%s: uvscom_set_crtscts\n", device_get_nameunit(sc->sc_ucom.sc_dev)));
457
458         return (USBD_NORMAL_COMPLETION);
459 }
460
461 static usbd_status
462 uvscom_set_line(struct uvscom_softc *sc, uint16_t line)
463 {
464         usb_device_request_t req;
465         usbd_status err;
466
467         DPRINTF(("%s: uvscom_set_line: %04x\n",
468                  device_get_nameunit(sc->sc_ucom.sc_dev), line));
469
470         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
471         req.bRequest = UVSCOM_LINE_CTL;
472         USETW(req.wValue, line);
473         USETW(req.wIndex, 0);
474         USETW(req.wLength, 0);
475
476         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
477         if (err) {
478                 kprintf("%s: uvscom_set_line: %s\n",
479                        device_get_nameunit(sc->sc_ucom.sc_dev), usbd_errstr(err));
480                 return (err);
481         }
482
483         return (USBD_NORMAL_COMPLETION);
484 }
485
486 static usbd_status
487 uvscom_set_line_coding(struct uvscom_softc *sc, uint16_t lsp, uint16_t ls)
488 {
489         usb_device_request_t req;
490         usbd_status err;
491
492         DPRINTF(("%s: uvscom_set_line_coding: %02x %02x\n",
493                  device_get_nameunit(sc->sc_ucom.sc_dev), lsp, ls));
494
495         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
496         req.bRequest = UVSCOM_SET_SPEED;
497         USETW(req.wValue, lsp);
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                 kprintf("%s: uvscom_set_line_coding: %s\n",
504                        device_get_nameunit(sc->sc_ucom.sc_dev), usbd_errstr(err));
505                 return (err);
506         }
507
508         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
509         req.bRequest = UVSCOM_SET_PARAM;
510         USETW(req.wValue, ls);
511         USETW(req.wIndex, 0);
512         USETW(req.wLength, 0);
513
514         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
515         if (err) {
516                 kprintf("%s: uvscom_set_line_coding: %s\n",
517                        device_get_nameunit(sc->sc_ucom.sc_dev), usbd_errstr(err));
518                 return (err);
519         }
520
521         return (USBD_NORMAL_COMPLETION);
522 }
523
524 static void
525 uvscom_dtr(struct uvscom_softc *sc, int onoff)
526 {
527         DPRINTF(("%s: uvscom_dtr: onoff = %d\n",
528                  device_get_nameunit(sc->sc_ucom.sc_dev), onoff));
529
530         if (sc->sc_dtr == onoff)
531                 return;                 /* no change */
532
533         sc->sc_dtr = onoff;
534
535         if (onoff)
536                 SET(sc->sc_lcr, UVSCOM_DTR);
537         else
538                 CLR(sc->sc_lcr, UVSCOM_DTR);
539
540         uvscom_set_line(sc, sc->sc_lcr);
541 }
542
543 static void
544 uvscom_rts(struct uvscom_softc *sc, int onoff)
545 {
546         DPRINTF(("%s: uvscom_rts: onoff = %d\n",
547                  device_get_nameunit(sc->sc_ucom.sc_dev), onoff));
548
549         if (sc->sc_rts == onoff)
550                 return;                 /* no change */
551
552         sc->sc_rts = onoff;
553
554         if (onoff)
555                 SET(sc->sc_lcr, UVSCOM_RTS);
556         else
557                 CLR(sc->sc_lcr, UVSCOM_RTS);
558
559         uvscom_set_line(sc, sc->sc_lcr);
560 }
561
562 static void
563 uvscom_break(struct uvscom_softc *sc, int onoff)
564 {
565         DPRINTF(("%s: uvscom_break: onoff = %d\n",
566                  device_get_nameunit(sc->sc_ucom.sc_dev), onoff));
567
568         if (onoff)
569                 uvscom_set_line(sc, SET(sc->sc_lcr, UVSCOM_BREAK));
570 }
571
572 static void
573 uvscom_set(void *addr, int portno, int reg, int onoff)
574 {
575         struct uvscom_softc *sc = addr;
576
577         switch (reg) {
578         case UCOM_SET_DTR:
579                 uvscom_dtr(sc, onoff);
580                 break;
581         case UCOM_SET_RTS:
582                 uvscom_rts(sc, onoff);
583                 break;
584         case UCOM_SET_BREAK:
585                 uvscom_break(sc, onoff);
586                 break;
587         default:
588                 break;
589         }
590 }
591
592 static int
593 uvscom_param(void *addr, int portno, struct termios *t)
594 {
595         struct uvscom_softc *sc = addr;
596         usbd_status err;
597         uint16_t lsp;
598         uint16_t ls;
599
600         DPRINTF(("%s: uvscom_param: sc = %p\n",
601                  device_get_nameunit(sc->sc_ucom.sc_dev), sc));
602
603         ls = 0;
604
605         switch (t->c_ospeed) {
606         case B150:
607                 lsp = UVSCOM_SPEED_150BPS;
608                 break;
609         case B300:
610                 lsp = UVSCOM_SPEED_300BPS;
611                 break;
612         case B600:
613                 lsp = UVSCOM_SPEED_600BPS;
614                 break;
615         case B1200:
616                 lsp = UVSCOM_SPEED_1200BPS;
617                 break;
618         case B2400:
619                 lsp = UVSCOM_SPEED_2400BPS;
620                 break;
621         case B4800:
622                 lsp = UVSCOM_SPEED_4800BPS;
623                 break;
624         case B9600:
625                 lsp = UVSCOM_SPEED_9600BPS;
626                 break;
627         case B19200:
628                 lsp = UVSCOM_SPEED_19200BPS;
629                 break;
630         case B38400:
631                 lsp = UVSCOM_SPEED_38400BPS;
632                 break;
633         case B57600:
634                 lsp = UVSCOM_SPEED_57600BPS;
635                 break;
636         case B115200:
637                 lsp = UVSCOM_SPEED_115200BPS;
638                 break;
639         default:
640                 return (EIO);
641         }
642
643         if (ISSET(t->c_cflag, CSTOPB))
644                 SET(ls, UVSCOM_STOP_BIT_2);
645         else
646                 SET(ls, UVSCOM_STOP_BIT_1);
647
648         if (ISSET(t->c_cflag, PARENB)) {
649                 if (ISSET(t->c_cflag, PARODD))
650                         SET(ls, UVSCOM_PARITY_ODD);
651                 else
652                         SET(ls, UVSCOM_PARITY_EVEN);
653         } else
654                 SET(ls, UVSCOM_PARITY_NONE);
655
656         switch (ISSET(t->c_cflag, CSIZE)) {
657         case CS5:
658                 SET(ls, UVSCOM_DATA_BIT_5);
659                 break;
660         case CS6:
661                 SET(ls, UVSCOM_DATA_BIT_6);
662                 break;
663         case CS7:
664                 SET(ls, UVSCOM_DATA_BIT_7);
665                 break;
666         case CS8:
667                 SET(ls, UVSCOM_DATA_BIT_8);
668                 break;
669         default:
670                 return (EIO);
671         }
672
673         err = uvscom_set_line_coding(sc, lsp, ls);
674         if (err)
675                 return (EIO);
676
677         if (ISSET(t->c_cflag, CRTSCTS)) {
678                 err = uvscom_set_crtscts(sc);
679                 if (err)
680                         return (EIO);
681         }
682
683         return (0);
684 }
685
686 static int
687 uvscom_open(void *addr, int portno)
688 {
689         struct uvscom_softc *sc = addr;
690         int err;
691         int i;
692
693         if (sc->sc_ucom.sc_dying)
694                 return (ENXIO);
695
696         DPRINTF(("uvscom_open: sc = %p\n", sc));
697
698         if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
699                 DPRINTF(("uvscom_open: open interrupt pipe.\n"));
700
701                 sc->sc_usr = 0;         /* clear unit status */
702
703                 err = uvscom_readstat(sc);
704                 if (err) {
705                         DPRINTF(("%s: uvscom_open: readstat faild\n",
706                                  device_get_nameunit(sc->sc_ucom.sc_dev)));
707                         return (ENXIO);
708                 }
709
710                 sc->sc_intr_buf = kmalloc(sc->sc_isize, M_USBDEV, M_WAITOK);
711                 err = usbd_open_pipe_intr(sc->sc_ucom.sc_iface,
712                                           sc->sc_intr_number,
713                                           USBD_SHORT_XFER_OK,
714                                           &sc->sc_intr_pipe,
715                                           sc,
716                                           sc->sc_intr_buf,
717                                           sc->sc_isize,
718                                           uvscom_intr,
719                                           UVSCOM_INTR_INTERVAL);
720                 if (err) {
721                         kprintf("%s: cannot open interrupt pipe (addr %d)\n",
722                                  device_get_nameunit(sc->sc_ucom.sc_dev),
723                                  sc->sc_intr_number);
724                         return (ENXIO);
725                 }
726         } else {
727                 DPRINTF(("uvscom_open: did not open interrupt pipe.\n"));
728         }
729
730         if ((sc->sc_usr & UVSCOM_USTAT_MASK) == 0) {
731                 /* unit is not ready */
732
733                 for (i = UVSCOM_UNIT_WAIT; i > 0; --i) {
734                         tsleep(&err, 0, "uvsop", hz);   /* XXX */
735                         if (ISSET(sc->sc_usr, UVSCOM_USTAT_MASK))
736                                 break;
737                 }
738                 if (i == 0) {
739                         DPRINTF(("%s: unit is not ready\n",
740                                  device_get_nameunit(sc->sc_ucom.sc_dev)));
741                         return (ENXIO);
742                 }
743
744                 /* check PC card was inserted */
745                 if (ISSET(sc->sc_usr, UVSCOM_NOCARD)) {
746                         DPRINTF(("%s: no card\n",
747                                  device_get_nameunit(sc->sc_ucom.sc_dev)));
748                         return (ENXIO);
749                 }
750         }
751
752         return (0);
753 }
754
755 static void
756 uvscom_close(void *addr, int portno)
757 {
758         struct uvscom_softc *sc = addr;
759         int err;
760
761         if (sc->sc_ucom.sc_dying)
762                 return;
763
764         DPRINTF(("uvscom_close: close\n"));
765
766         uvscom_shutdown(sc);
767
768         if (sc->sc_intr_pipe != NULL) {
769                 err = usbd_abort_pipe(sc->sc_intr_pipe);
770                 if (err)
771                         kprintf("%s: abort interrupt pipe failed: %s\n",
772                                 device_get_nameunit(sc->sc_ucom.sc_dev),
773                                            usbd_errstr(err));
774                 err = usbd_close_pipe(sc->sc_intr_pipe);
775                 if (err)
776                         kprintf("%s: close interrupt pipe failed: %s\n",
777                                 device_get_nameunit(sc->sc_ucom.sc_dev),
778                                            usbd_errstr(err));
779                 kfree(sc->sc_intr_buf, M_USBDEV);
780                 sc->sc_intr_pipe = NULL;
781         }
782 }
783
784 static void
785 uvscom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
786 {
787         struct uvscom_softc *sc = priv;
788         u_char *buf = sc->sc_intr_buf;
789         u_char pstatus;
790
791         if (sc->sc_ucom.sc_dying)
792                 return;
793
794         if (status != USBD_NORMAL_COMPLETION) {
795                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
796                         return;
797
798                 kprintf("%s: uvscom_intr: abnormal status: %s\n",
799                         device_get_nameunit(sc->sc_ucom.sc_dev),
800                         usbd_errstr(status));
801                 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
802                 return;
803         }
804
805         DPRINTFN(2, ("%s: uvscom status = %02x %02x\n",
806                  device_get_nameunit(sc->sc_ucom.sc_dev), buf[0], buf[1]));
807
808         sc->sc_lsr = sc->sc_msr = 0;
809         sc->sc_usr = buf[1];
810
811         pstatus = buf[0];
812         if (ISSET(pstatus, UVSCOM_TXRDY))
813                 SET(sc->sc_lsr, ULSR_TXRDY);
814         if (ISSET(pstatus, UVSCOM_RXRDY))
815                 SET(sc->sc_lsr, ULSR_RXRDY);
816
817         pstatus = buf[1];
818         if (ISSET(pstatus, UVSCOM_CTS))
819                 SET(sc->sc_msr, UMSR_CTS);
820         if (ISSET(pstatus, UVSCOM_DSR))
821                 SET(sc->sc_msr, UMSR_DSR);
822         if (ISSET(pstatus, UVSCOM_DCD))
823                 SET(sc->sc_msr, UMSR_DCD);
824
825         ucom_status_change(&sc->sc_ucom);
826 }
827
828 static void
829 uvscom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
830 {
831         struct uvscom_softc *sc = addr;
832
833         if (lsr != NULL)
834                 *lsr = sc->sc_lsr;
835         if (msr != NULL)
836                 *msr = sc->sc_msr;
837 }
838
839 #if TODO
840 static int
841 uvscom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
842              struct thread *p)
843 {
844         struct uvscom_softc *sc = addr;
845         int error = 0;
846
847         if (sc->sc_ucom.sc_dying)
848                 return (EIO);
849
850         DPRINTF(("uvscom_ioctl: cmd = 0x%08lx\n", cmd));
851
852         switch (cmd) {
853         case TIOCNOTTY:
854         case TIOCMGET:
855         case TIOCMSET:
856                 break;
857
858         default:
859                 DPRINTF(("uvscom_ioctl: unknown\n"));
860                 error = ENOTTY;
861                 break;
862         }
863
864         return (error);
865 }
866 #endif