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