]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/uvscom.c
This commit was generated by cvs2svn to compensate for changes in r107484,
[FreeBSD/FreeBSD.git] / sys / dev / usb / 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$
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 P1 */
212         { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1 },
213         /* SUNTAC Slipper U */
214         { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U },
215 };
216 #define uvscom_lookup(v, p) usb_lookup(uvscom_devs, v, p)
217
218 Static device_probe_t uvscom_match;
219 Static device_attach_t uvscom_attach;
220 Static device_detach_t uvscom_detach;
221
222 Static device_method_t uvscom_methods[] = {
223         /* Device interface */
224         DEVMETHOD(device_probe, uvscom_match),
225         DEVMETHOD(device_attach, uvscom_attach),
226         DEVMETHOD(device_detach, uvscom_detach),
227         { 0, 0 }
228 };
229
230 Static driver_t uvscom_driver = {
231         "ucom",
232         uvscom_methods,
233         sizeof (struct uvscom_softc)
234 };
235
236 DRIVER_MODULE(uvscom, uhub, uvscom_driver, ucom_devclass, usbd_driver_load, 0);
237 MODULE_DEPEND(uvscom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
238 MODULE_VERSION(uvscom, UVSCOM_MODVER);
239
240 USB_MATCH(uvscom)
241 {
242         USB_MATCH_START(uvscom, uaa);
243
244         if (uaa->iface != NULL)
245                 return (UMATCH_NONE);
246
247         return (uvscom_lookup(uaa->vendor, uaa->product) != NULL ?
248                 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
249 }
250
251 USB_ATTACH(uvscom)
252 {
253         USB_ATTACH_START(uvscom, sc, uaa);
254         usbd_device_handle dev = uaa->device;
255         struct ucom_softc *ucom;
256         usb_config_descriptor_t *cdesc;
257         usb_interface_descriptor_t *id;
258         usb_endpoint_descriptor_t *ed;
259         char *devinfo;
260         const char *devname;
261         usbd_status err;
262         int i;
263
264         devinfo = malloc(1024, M_USBDEV, M_WAITOK);
265         ucom = &sc->sc_ucom;
266
267         bzero(sc, sizeof (struct uvscom_softc));
268
269         usbd_devinfo(dev, 0, devinfo);
270         /* USB_ATTACH_SETUP; */
271         ucom->sc_dev = self;
272         device_set_desc_copy(self, devinfo);
273         /* USB_ATTACH_SETUP; */
274
275         ucom->sc_udev = dev;
276         ucom->sc_iface = uaa->iface;
277
278         devname = USBDEVNAME(ucom->sc_dev);
279         printf("%s: %s\n", devname, devinfo);
280
281         DPRINTF(("uvscom attach: sc = %p\n", sc));
282
283         /* initialize endpoints */
284         ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
285         sc->sc_intr_number = -1;
286         sc->sc_intr_pipe = NULL;
287
288         /* Move the device into the configured state. */
289         err = usbd_set_config_index(dev, UVSCOM_CONFIG_INDEX, 1);
290         if (err) {
291                 printf("%s: failed to set configuration, err=%s\n",
292                         devname, usbd_errstr(err));
293                 goto error;
294         }
295
296         /* get the config descriptor */
297         cdesc = usbd_get_config_descriptor(ucom->sc_udev);
298
299         if (cdesc == NULL) {
300                 printf("%s: failed to get configuration descriptor\n",
301                         USBDEVNAME(ucom->sc_dev));
302                 goto error;
303         }
304
305         /* get the common interface */
306         err = usbd_device2interface_handle(dev, UVSCOM_IFACE_INDEX,
307                                            &ucom->sc_iface);
308         if (err) {
309                 printf("%s: failed to get interface, err=%s\n",
310                         devname, usbd_errstr(err));
311                 goto error;
312         }
313
314         id = usbd_get_interface_descriptor(ucom->sc_iface);
315         sc->sc_iface_number = id->bInterfaceNumber;
316
317         /* Find endpoints */
318         for (i = 0; i < id->bNumEndpoints; i++) {
319                 ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
320                 if (ed == NULL) {
321                         printf("%s: no endpoint descriptor for %d\n",
322                                 USBDEVNAME(ucom->sc_dev), i);
323                         goto error;
324                 }
325
326                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
327                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
328                         ucom->sc_bulkin_no = ed->bEndpointAddress;
329                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
330                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
331                         ucom->sc_bulkout_no = ed->bEndpointAddress;
332                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
333                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
334                         sc->sc_intr_number = ed->bEndpointAddress;
335                         sc->sc_isize = UGETW(ed->wMaxPacketSize);
336                 }
337         }
338
339         if (ucom->sc_bulkin_no == -1) {
340                 printf("%s: Could not find data bulk in\n",
341                         USBDEVNAME(ucom->sc_dev));
342                 goto error;
343         }
344         if (ucom->sc_bulkout_no == -1) {
345                 printf("%s: Could not find data bulk out\n",
346                         USBDEVNAME(ucom->sc_dev));
347                 goto error;
348         }
349         if (sc->sc_intr_number == -1) {
350                 printf("%s: Could not find interrupt in\n",
351                         USBDEVNAME(ucom->sc_dev));
352                 goto error;
353         }
354
355         sc->sc_dtr = sc->sc_rts = 0;
356         sc->sc_lcr = UVSCOM_LINE_INIT;
357
358         ucom->sc_parent = sc;
359         ucom->sc_portno = UCOM_UNK_PORTNO;
360         /* bulkin, bulkout set above */
361         ucom->sc_ibufsize = UVSCOMIBUFSIZE;
362         ucom->sc_obufsize = UVSCOMOBUFSIZE;
363         ucom->sc_ibufsizepad = UVSCOMIBUFSIZE;
364         ucom->sc_opkthdrlen = 0;
365         ucom->sc_callback = &uvscom_callback;
366
367         err = uvscom_reset(sc);
368
369         if (err) {
370                 printf("%s: reset failed, %s\n", USBDEVNAME(ucom->sc_dev),
371                         usbd_errstr(err));
372                 goto error;
373         }
374
375         DPRINTF(("uvscom: in = 0x%x out = 0x%x intr = 0x%x\n",
376                  ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number));
377
378         ucom_attach(&sc->sc_ucom);
379
380         free(devinfo, M_USBDEV);
381         USB_ATTACH_SUCCESS_RETURN;
382
383 error:
384         ucom->sc_dying = 1;
385         free(devinfo, M_USBDEV);
386         USB_ATTACH_ERROR_RETURN;
387 }
388
389 USB_DETACH(uvscom)
390 {
391         USB_DETACH_START(uvscom, sc);
392         int rv = 0;
393
394         DPRINTF(("uvscom_detach: sc = %p\n", sc));
395
396         sc->sc_ucom.sc_dying = 1;
397
398         if (sc->sc_intr_pipe != NULL) {
399                 usbd_abort_pipe(sc->sc_intr_pipe);
400                 usbd_close_pipe(sc->sc_intr_pipe);
401                 free(sc->sc_intr_buf, M_USBDEV);
402                 sc->sc_intr_pipe = NULL;
403         }
404
405         rv = ucom_detach(&sc->sc_ucom);
406
407         return (rv);
408 }
409
410 Static usbd_status
411 uvscom_readstat(struct uvscom_softc *sc)
412 {
413         usb_device_request_t req;
414         usbd_status err;
415         uint16_t r;
416
417         DPRINTF(("%s: send readstat\n", USBDEVNAME(sc->sc_ucom.sc_dev)));
418
419         req.bmRequestType = UT_READ_VENDOR_DEVICE;
420         req.bRequest = UVSCOM_READ_STATUS;
421         USETW(req.wValue, 0);
422         USETW(req.wIndex, 0);
423         USETW(req.wLength, 2);
424
425         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, &r);
426         if (err) {
427                 printf("%s: uvscom_readstat: %s\n",
428                        USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
429                 return (err);
430         }
431
432         DPRINTF(("%s: uvscom_readstat: r = %d\n",
433                  USBDEVNAME(sc->sc_ucom.sc_dev), r));
434
435         return (USBD_NORMAL_COMPLETION);
436 }
437
438 Static usbd_status
439 uvscom_shutdown(struct uvscom_softc *sc)
440 {
441         usb_device_request_t req;
442         usbd_status err;
443
444         DPRINTF(("%s: send shutdown\n", USBDEVNAME(sc->sc_ucom.sc_dev)));
445
446         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
447         req.bRequest = UVSCOM_SHUTDOWN;
448         USETW(req.wValue, 0);
449         USETW(req.wIndex, 0);
450         USETW(req.wLength, 0);
451
452         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
453         if (err) {
454                 printf("%s: uvscom_shutdown: %s\n",
455                        USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
456                 return (err);
457         }
458
459         return (USBD_NORMAL_COMPLETION);
460 }
461
462 Static usbd_status
463 uvscom_reset(struct uvscom_softc *sc)
464 {
465         DPRINTF(("%s: uvscom_reset\n", USBDEVNAME(sc->sc_ucom.sc_dev)));
466
467         return (USBD_NORMAL_COMPLETION);
468 }
469
470 Static usbd_status
471 uvscom_set_crtscts(struct uvscom_softc *sc)
472 {
473         DPRINTF(("%s: uvscom_set_crtscts\n", USBDEVNAME(sc->sc_ucom.sc_dev)));
474
475         return (USBD_NORMAL_COMPLETION);
476 }
477
478 Static usbd_status
479 uvscom_set_line(struct uvscom_softc *sc, uint16_t line)
480 {
481         usb_device_request_t req;
482         usbd_status err;
483
484         DPRINTF(("%s: uvscom_set_line: %04x\n",
485                  USBDEVNAME(sc->sc_ucom.sc_dev), line));
486
487         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
488         req.bRequest = UVSCOM_LINE_CTL;
489         USETW(req.wValue, line);
490         USETW(req.wIndex, 0);
491         USETW(req.wLength, 0);
492
493         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
494         if (err) {
495                 printf("%s: uvscom_set_line: %s\n",
496                        USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
497                 return (err);
498         }
499
500         return (USBD_NORMAL_COMPLETION);
501 }
502
503 Static usbd_status
504 uvscom_set_line_coding(struct uvscom_softc *sc, uint16_t lsp, uint16_t ls)
505 {
506         usb_device_request_t req;
507         usbd_status err;
508
509         DPRINTF(("%s: uvscom_set_line_coding: %02x %02x\n",
510                  USBDEVNAME(sc->sc_ucom.sc_dev), lsp, ls));
511
512         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
513         req.bRequest = UVSCOM_SET_SPEED;
514         USETW(req.wValue, lsp);
515         USETW(req.wIndex, 0);
516         USETW(req.wLength, 0);
517
518         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
519         if (err) {
520                 printf("%s: uvscom_set_line_coding: %s\n",
521                        USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
522                 return (err);
523         }
524
525         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
526         req.bRequest = UVSCOM_SET_PARAM;
527         USETW(req.wValue, ls);
528         USETW(req.wIndex, 0);
529         USETW(req.wLength, 0);
530
531         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
532         if (err) {
533                 printf("%s: uvscom_set_line_coding: %s\n",
534                        USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
535                 return (err);
536         }
537
538         return (USBD_NORMAL_COMPLETION);
539 }
540
541 Static void
542 uvscom_dtr(struct uvscom_softc *sc, int onoff)
543 {
544         DPRINTF(("%s: uvscom_dtr: onoff = %d\n",
545                  USBDEVNAME(sc->sc_ucom.sc_dev), onoff));
546
547         if (sc->sc_dtr == onoff)
548                 return;                 /* no change */
549
550         sc->sc_dtr = onoff;
551
552         if (onoff)
553                 SET(sc->sc_lcr, UVSCOM_DTR);
554         else
555                 CLR(sc->sc_lcr, UVSCOM_DTR);
556
557         uvscom_set_line(sc, sc->sc_lcr);
558 }
559
560 Static void
561 uvscom_rts(struct uvscom_softc *sc, int onoff)
562 {
563         DPRINTF(("%s: uvscom_rts: onoff = %d\n",
564                  USBDEVNAME(sc->sc_ucom.sc_dev), onoff));
565
566         if (sc->sc_rts == onoff)
567                 return;                 /* no change */
568
569         sc->sc_rts = onoff;
570
571         if (onoff)
572                 SET(sc->sc_lcr, UVSCOM_RTS);
573         else
574                 CLR(sc->sc_lcr, UVSCOM_RTS);
575
576         uvscom_set_line(sc, sc->sc_lcr);
577 }
578
579 Static void
580 uvscom_break(struct uvscom_softc *sc, int onoff)
581 {
582         DPRINTF(("%s: uvscom_break: onoff = %d\n",
583                  USBDEVNAME(sc->sc_ucom.sc_dev), onoff));
584
585         if (onoff)
586                 uvscom_set_line(sc, SET(sc->sc_lcr, UVSCOM_BREAK));
587 }
588
589 Static void
590 uvscom_set(void *addr, int portno, int reg, int onoff)
591 {
592         struct uvscom_softc *sc = addr;
593
594         switch (reg) {
595         case UCOM_SET_DTR:
596                 uvscom_dtr(sc, onoff);
597                 break;
598         case UCOM_SET_RTS:
599                 uvscom_rts(sc, onoff);
600                 break;
601         case UCOM_SET_BREAK:
602                 uvscom_break(sc, onoff);
603                 break;
604         default:
605                 break;
606         }
607 }
608
609 Static int
610 uvscom_param(void *addr, int portno, struct termios *t)
611 {
612         struct uvscom_softc *sc = addr;
613         usbd_status err;
614         uint16_t lsp;
615         uint16_t ls;
616
617         DPRINTF(("%s: uvscom_param: sc = %p\n",
618                  USBDEVNAME(sc->sc_ucom.sc_dev), sc));
619
620         ls = 0;
621
622         switch (t->c_ospeed) {
623         case B150:
624                 lsp = UVSCOM_SPEED_150BPS;
625                 break;
626         case B300:
627                 lsp = UVSCOM_SPEED_300BPS;
628                 break;
629         case B600:
630                 lsp = UVSCOM_SPEED_600BPS;
631                 break;
632         case B1200:
633                 lsp = UVSCOM_SPEED_1200BPS;
634                 break;
635         case B2400:
636                 lsp = UVSCOM_SPEED_2400BPS;
637                 break;
638         case B4800:
639                 lsp = UVSCOM_SPEED_4800BPS;
640                 break;
641         case B9600:
642                 lsp = UVSCOM_SPEED_9600BPS;
643                 break;
644         case B19200:
645                 lsp = UVSCOM_SPEED_19200BPS;
646                 break;
647         case B38400:
648                 lsp = UVSCOM_SPEED_38400BPS;
649                 break;
650         case B57600:
651                 lsp = UVSCOM_SPEED_57600BPS;
652                 break;
653         case B115200:
654                 lsp = UVSCOM_SPEED_115200BPS;
655                 break;
656         default:
657                 return (EIO);
658         }
659                 
660         if (ISSET(t->c_cflag, CSTOPB))
661                 SET(ls, UVSCOM_STOP_BIT_2);
662         else
663                 SET(ls, UVSCOM_STOP_BIT_1);
664
665         if (ISSET(t->c_cflag, PARENB)) {
666                 if (ISSET(t->c_cflag, PARODD))
667                         SET(ls, UVSCOM_PARITY_ODD);
668                 else
669                         SET(ls, UVSCOM_PARITY_EVEN);
670         } else
671                 SET(ls, UVSCOM_PARITY_NONE);
672
673         switch (ISSET(t->c_cflag, CSIZE)) {
674         case CS5:
675                 SET(ls, UVSCOM_DATA_BIT_5);
676                 break;
677         case CS6:
678                 SET(ls, UVSCOM_DATA_BIT_6);
679                 break;
680         case CS7:
681                 SET(ls, UVSCOM_DATA_BIT_7);
682                 break;
683         case CS8:
684                 SET(ls, UVSCOM_DATA_BIT_8);
685                 break;
686         default:
687                 return (EIO);
688         }
689
690         err = uvscom_set_line_coding(sc, lsp, ls);
691         if (err)
692                 return (EIO);
693
694         if (ISSET(t->c_cflag, CRTSCTS)) {
695                 err = uvscom_set_crtscts(sc);
696                 if (err)
697                         return (EIO);
698         }
699
700         return (0);
701 }
702
703 Static int
704 uvscom_open(void *addr, int portno)
705 {
706         struct uvscom_softc *sc = addr;
707         int err;
708         int i;
709         
710         if (sc->sc_ucom.sc_dying)
711                 return (ENXIO);
712
713         DPRINTF(("uvscom_open: sc = %p\n", sc));
714
715         if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
716                 DPRINTF(("uvscom_open: open interrupt pipe.\n"));
717
718                 sc->sc_usr = 0;         /* clear unit status */
719
720                 err = uvscom_readstat(sc);
721                 if (err) {
722                         DPRINTF(("%s: uvscom_open: readstat faild\n",
723                                  USBDEVNAME(sc->sc_ucom.sc_dev)));
724                         return (ENXIO);
725                 }
726
727                 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
728                 err = usbd_open_pipe_intr(sc->sc_ucom.sc_iface,
729                                           sc->sc_intr_number,
730                                           USBD_SHORT_XFER_OK,
731                                           &sc->sc_intr_pipe,
732                                           sc,
733                                           sc->sc_intr_buf,
734                                           sc->sc_isize,
735                                           uvscom_intr,
736                                           UVSCOM_INTR_INTERVAL);
737                 if (err) {
738                         printf("%s: cannot open interrupt pipe (addr %d)\n",
739                                  USBDEVNAME(sc->sc_ucom.sc_dev),
740                                  sc->sc_intr_number);
741                         return (ENXIO);
742                 }
743         } else {
744                 DPRINTF(("uvscom_open: did not open interrupt pipe.\n"));
745         }
746
747         if ((sc->sc_usr & UVSCOM_USTAT_MASK) == 0) {
748                 /* unit is not ready */
749
750                 for (i = UVSCOM_UNIT_WAIT; i > 0; --i) {
751                         tsleep(&err, TTIPRI, "uvsop", hz);      /* XXX */
752                         if (ISSET(sc->sc_usr, UVSCOM_USTAT_MASK))
753                                 break;
754                 }
755                 if (i == 0) {
756                         DPRINTF(("%s: unit is not ready\n",
757                                  USBDEVNAME(sc->sc_ucom.sc_dev)));
758                         return (ENXIO);
759                 }
760
761                 /* check PC card was inserted */
762                 if (ISSET(sc->sc_usr, UVSCOM_NOCARD)) {
763                         DPRINTF(("%s: no card\n",
764                                  USBDEVNAME(sc->sc_ucom.sc_dev)));
765                         return (ENXIO);
766                 }
767         }
768
769         return (0);
770 }
771
772 Static void
773 uvscom_close(void *addr, int portno)
774 {
775         struct uvscom_softc *sc = addr;
776         int err;
777
778         if (sc->sc_ucom.sc_dying)
779                 return;
780
781         DPRINTF(("uvscom_close: close\n"));
782
783         uvscom_shutdown(sc);
784
785         if (sc->sc_intr_pipe != NULL) {
786                 err = usbd_abort_pipe(sc->sc_intr_pipe);
787                 if (err)
788                         printf("%s: abort interrupt pipe failed: %s\n",
789                                 USBDEVNAME(sc->sc_ucom.sc_dev),
790                                            usbd_errstr(err));
791                 err = usbd_close_pipe(sc->sc_intr_pipe);
792                 if (err)
793                         printf("%s: close interrupt pipe failed: %s\n",
794                                 USBDEVNAME(sc->sc_ucom.sc_dev),
795                                            usbd_errstr(err));
796                 free(sc->sc_intr_buf, M_USBDEV);
797                 sc->sc_intr_pipe = NULL;
798         }
799 }
800
801 Static void
802 uvscom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
803 {
804         struct uvscom_softc *sc = priv;
805         u_char *buf = sc->sc_intr_buf;
806         u_char pstatus;
807
808         if (sc->sc_ucom.sc_dying)
809                 return;
810
811         if (status != USBD_NORMAL_COMPLETION) {
812                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
813                         return;
814
815                 printf("%s: uvscom_intr: abnormal status: %s\n",
816                         USBDEVNAME(sc->sc_ucom.sc_dev),
817                         usbd_errstr(status));
818                 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
819                 return;
820         }
821
822         DPRINTFN(2, ("%s: uvscom status = %02x %02x\n",
823                  USBDEVNAME(sc->sc_ucom.sc_dev), buf[0], buf[1]));
824
825         sc->sc_lsr = sc->sc_msr = 0;
826         sc->sc_usr = buf[1];
827
828         pstatus = buf[0];
829         if (ISSET(pstatus, UVSCOM_TXRDY))
830                 SET(sc->sc_lsr, ULSR_TXRDY);
831         if (ISSET(pstatus, UVSCOM_RXRDY))
832                 SET(sc->sc_lsr, ULSR_RXRDY);
833
834         pstatus = buf[1];
835         if (ISSET(pstatus, UVSCOM_CTS))
836                 SET(sc->sc_msr, UMSR_CTS);
837         if (ISSET(pstatus, UVSCOM_DSR))
838                 SET(sc->sc_msr, UMSR_DSR);
839         if (ISSET(pstatus, UVSCOM_DCD))
840                 SET(sc->sc_msr, UMSR_DCD);
841
842         ucom_status_change(&sc->sc_ucom);
843 }
844
845 Static void
846 uvscom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
847 {
848         struct uvscom_softc *sc = addr;
849
850         if (lsr != NULL)
851                 *lsr = sc->sc_lsr;
852         if (msr != NULL)
853                 *msr = sc->sc_msr;
854 }
855
856 #if TODO
857 Static int
858 uvscom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
859              usb_proc_ptr p)
860 {
861         struct uvscom_softc *sc = addr;
862         int error = 0;
863
864         if (sc->sc_ucom.sc_dying)
865                 return (EIO);
866
867         DPRINTF(("uvscom_ioctl: cmd = 0x%08lx\n", cmd));
868
869         switch (cmd) {
870         case TIOCNOTTY:
871         case TIOCMGET:
872         case TIOCMSET:
873                 break;
874
875         default:
876                 DPRINTF(("uvscom_ioctl: unknown\n"));
877                 error = ENOTTY;
878                 break;
879         }
880
881         return (error);
882 }
883 #endif