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