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