fd91234a50516e7a525ec7b36b582752974da6cd
[dragonfly.git] / sys / dev / usbmisc / uplcom / uplcom.c
1 /*      $NetBSD: uplcom.c,v 1.20 2001/07/31 12:33:11 ichiro Exp $       */
2 /*      $FreeBSD: src/sys/dev/usb/uplcom.c,v 1.8.2.1 2002/08/08 18:45:04 joe Exp $      */
3 /*      $DragonFly: src/sys/dev/usbmisc/uplcom/uplcom.c,v 1.3 2003/08/07 21:17:15 dillon Exp $  */
4
5 /*-
6  * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 /*
32  * Copyright (c) 2001 The NetBSD Foundation, Inc.
33  * All rights reserved.
34  *
35  * This code is derived from software contributed to The NetBSD Foundation
36  * by Ichiro FUKUHARA (ichiro@ichiro.org).
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *        This product includes software developed by the NetBSD
49  *        Foundation, Inc. and its contributors.
50  * 4. Neither the name of The NetBSD Foundation nor the names of its
51  *    contributors may be used to endorse or promote products derived
52  *    from this software without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
55  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
58  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
64  * POSSIBILITY OF SUCH DAMAGE.
65  */
66
67 /*
68  * Simple datasheet
69  * http://www.prolific.com.tw/download/DataSheet/pl2303_ds11.PDF
70  * http://www.nisseisg.co.jp/jyouhou/_cp/@gif/2303.pdf
71  *      (english)
72  *
73  */
74
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/kernel.h>
78 #include <sys/malloc.h>
79 #include <sys/bus.h>
80 #include <sys/ioccom.h>
81 #include <sys/fcntl.h>
82 #include <sys/conf.h>
83 #include <sys/tty.h>
84 #include <sys/file.h>
85 #if __FreeBSD_version >= 500014
86 #include <sys/selinfo.h>
87 #else
88 #include <sys/select.h>
89 #endif
90 #include <sys/proc.h>
91 #include <sys/vnode.h>
92 #include <sys/poll.h>
93 #include <sys/sysctl.h>
94
95 #include <bus/usb/usb.h>
96 #include <bus/usb/usbcdc.h>
97
98 #include <bus/usb/usbdi.h>
99 #include <bus/usb/usbdi_util.h>
100 #include <bus/usb/usbdevs.h>
101 #include <bus/usb/usb_quirks.h>
102
103 #include "../ucom/ucomvar.h"
104
105 #ifdef USB_DEBUG
106 static int      uplcomdebug = 0;
107 SYSCTL_NODE(_hw_usb, OID_AUTO, uplcom, CTLFLAG_RW, 0, "USB uplcom");
108 SYSCTL_INT(_hw_usb_uplcom, OID_AUTO, debug, CTLFLAG_RW,
109            &uplcomdebug, 0, "uplcom debug level");
110
111 #define DPRINTFN(n, x)  do { \
112                                 if (uplcomdebug > (n)) \
113                                         logprintf x; \
114                         } while (0)
115 #else
116 #define DPRINTFN(n, x)
117 #endif
118 #define DPRINTF(x) DPRINTFN(0, x)
119
120 #define UPLCOM_MODVER                   1       /* module version */
121
122 #define UPLCOM_CONFIG_INDEX             0
123 #define UPLCOM_IFACE_INDEX              0
124 #define UPLCOM_SECOND_IFACE_INDEX       1
125
126 #define UPLCOM_INTR_INTERVAL            100     /* ms */
127
128 #define UPLCOM_SET_REQUEST              0x01
129 #define UPLCOM_SET_CRTSCTS              0x41
130 #define RSAQ_STATUS_DSR                 0x02
131 #define RSAQ_STATUS_DCD                 0x01
132
133 struct  uplcom_softc {
134         struct ucom_softc       sc_ucom;
135
136         int                     sc_iface_number;        /* interface number */
137
138         usbd_interface_handle   sc_intr_iface;  /* interrupt interface */
139         int                     sc_intr_number; /* interrupt number */
140         usbd_pipe_handle        sc_intr_pipe;   /* interrupt pipe */
141         u_char                  *sc_intr_buf;   /* interrupt buffer */
142         int                     sc_isize;
143
144         usb_cdc_line_state_t    sc_line_state;  /* current line state */
145         u_char                  sc_dtr;         /* current DTR state */
146         u_char                  sc_rts;         /* current RTS state */
147         u_char                  sc_status;
148
149         u_char                  sc_lsr;         /* Local status register */
150         u_char                  sc_msr;         /* uplcom status register */
151 };
152
153 /*
154  * These are the maximum number of bytes transferred per frame.
155  * The output buffer size cannot be increased due to the size encoding.
156  */
157 #define UPLCOMIBUFSIZE 256
158 #define UPLCOMOBUFSIZE 256
159
160 Static  usbd_status uplcom_reset(struct uplcom_softc *);
161 Static  usbd_status uplcom_set_line_coding(struct uplcom_softc *,
162                                            usb_cdc_line_state_t *);
163 Static  usbd_status uplcom_set_crtscts(struct uplcom_softc *);
164 Static  void uplcom_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
165
166 Static  void uplcom_set(void *, int, int, int);
167 Static  void uplcom_dtr(struct uplcom_softc *, int);
168 Static  void uplcom_rts(struct uplcom_softc *, int);
169 Static  void uplcom_break(struct uplcom_softc *, int);
170 Static  void uplcom_set_line_state(struct uplcom_softc *);
171 Static  void uplcom_get_status(void *, int, u_char *, u_char *);
172 #if TODO
173 Static  int  uplcom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr);
174 #endif
175 Static  int  uplcom_param(void *, int, struct termios *);
176 Static  int  uplcom_open(void *, int);
177 Static  void uplcom_close(void *, int);
178
179 struct ucom_callback uplcom_callback = {
180         uplcom_get_status,
181         uplcom_set,
182         uplcom_param,
183         NULL, /* uplcom_ioctl, TODO */
184         uplcom_open,
185         uplcom_close,
186         NULL,
187         NULL
188 };
189
190 static const struct uplcom_product {
191         uint16_t        vendor;
192         uint16_t        product;
193 } uplcom_products [] = {
194         /* I/O DATA USB-RSAQ */
195         { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ },
196         /* I/O DATA USB-RSAQ2 */
197         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 },
198         /* PLANEX USB-RS232 URS-03 */
199         { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A },
200         /* IOGEAR/ATEN UC-232A */
201         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
202         /* TDK USB-PHS Adapter UHA6400 */
203         { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 },
204         /* RATOC REX-USB60 */
205         { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 },
206         /* ELECOM UC-SGT */
207         { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT },
208         { 0, 0 }
209 };
210
211 Static device_probe_t uplcom_match;
212 Static device_attach_t uplcom_attach;
213 Static device_detach_t uplcom_detach;
214
215 Static device_method_t uplcom_methods[] = {
216         /* Device interface */
217         DEVMETHOD(device_probe, uplcom_match),
218         DEVMETHOD(device_attach, uplcom_attach),
219         DEVMETHOD(device_detach, uplcom_detach),
220         { 0, 0 }
221 };
222
223 Static driver_t uplcom_driver = {
224         "uplcom",
225         uplcom_methods,
226         sizeof (struct uplcom_softc)
227 };
228
229 DRIVER_MODULE(uplcom, uhub, uplcom_driver, ucom_devclass, usbd_driver_load, 0);
230 MODULE_DEPEND(uplcom, usb, 1, 1, 1);
231 MODULE_DEPEND(uplcom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
232 MODULE_VERSION(uplcom, UPLCOM_MODVER);
233
234 USB_MATCH(uplcom)
235 {
236         USB_MATCH_START(uplcom, uaa);
237         int i;
238
239         if (uaa->iface != NULL)
240                 return (UMATCH_NONE);
241
242         for (i = 0; uplcom_products[i].vendor != 0; i++) {
243                 if (uplcom_products[i].vendor == uaa->vendor &&
244                     uplcom_products[i].product == uaa->product) {
245                         return (UMATCH_VENDOR_PRODUCT);
246                 }
247         }
248         return (UMATCH_NONE);
249 }
250
251 USB_ATTACH(uplcom)
252 {
253         USB_ATTACH_START(uplcom, 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 uplcom_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(("uplcom 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, UPLCOM_CONFIG_INDEX, 1);
290         if (err) {
291                 printf("%s: failed to set configuration: %s\n",
292                         devname, usbd_errstr(err));
293                 ucom->sc_dying = 1;
294                 goto error;
295         }
296
297         /* get the config descriptor */
298         cdesc = usbd_get_config_descriptor(ucom->sc_udev);
299
300         if (cdesc == NULL) {
301                 printf("%s: failed to get configuration descriptor\n",
302                         USBDEVNAME(ucom->sc_dev));
303                 ucom->sc_dying = 1;
304                 goto error;
305         }
306
307         /* get the (first/common) interface */
308         err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX, 
309                                            &ucom->sc_iface);
310         if (err) {
311                 printf("%s: failed to get interface: %s\n",
312                         devname, usbd_errstr(err));
313                 ucom->sc_dying = 1;
314                 goto error;
315         }
316
317         /* Find the interrupt endpoints */
318
319         id = usbd_get_interface_descriptor(ucom->sc_iface);
320         sc->sc_iface_number = id->bInterfaceNumber;
321
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                         ucom->sc_dying = 1;
328                         goto error;
329                 }
330
331                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
332                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
333                         sc->sc_intr_number = ed->bEndpointAddress;
334                         sc->sc_isize = UGETW(ed->wMaxPacketSize);
335                 } 
336         }
337
338         if (sc->sc_intr_number == -1) {
339                 printf("%s: Could not find interrupt in\n",
340                         USBDEVNAME(ucom->sc_dev));
341                 ucom->sc_dying = 1;
342                 goto error;
343         }
344
345         /* keep interface for interrupt */
346         sc->sc_intr_iface = ucom->sc_iface;
347
348         /*
349          * USB-RSAQ1 has two interface
350          *
351          *  USB-RSAQ1       | USB-RSAQ2
352          * -----------------+-----------------
353          * Interface 0      |Interface 0
354          *  Interrupt(0x81) | Interrupt(0x81)
355          * -----------------+ BulkIN(0x02)
356          * Interface 1      | BulkOUT(0x83)
357          *   BulkIN(0x02)   | 
358          *   BulkOUT(0x83)  |
359          */
360         if (cdesc->bNumInterface == 2) {
361                 err = usbd_device2interface_handle(dev, 
362                                                    UPLCOM_SECOND_IFACE_INDEX,
363                                                    &ucom->sc_iface);
364                 if (err) {
365                         printf("%s: failed to get second interface: %s\n",
366                                 devname, usbd_errstr(err));
367                         ucom->sc_dying = 1;
368                         goto error;
369                 }
370         } 
371
372         /* Find the bulk{in,out} endpoints */
373
374         id = usbd_get_interface_descriptor(ucom->sc_iface);
375         sc->sc_iface_number = id->bInterfaceNumber;
376
377         for (i = 0; i < id->bNumEndpoints; i++) {
378                 ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
379                 if (ed == NULL) {
380                         printf("%s: no endpoint descriptor for %d\n",
381                                 USBDEVNAME(ucom->sc_dev), i);
382                         ucom->sc_dying = 1;
383                         goto error;
384                 }
385
386                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
387                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
388                         ucom->sc_bulkin_no = ed->bEndpointAddress;
389                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
390                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
391                         ucom->sc_bulkout_no = ed->bEndpointAddress;
392                 }
393         }
394
395         if (ucom->sc_bulkin_no == -1) {
396                 printf("%s: Could not find data bulk in\n",
397                         USBDEVNAME(ucom->sc_dev));
398                 ucom->sc_dying = 1;
399                 goto error;
400         }
401
402         if (ucom->sc_bulkout_no == -1) {
403                 printf("%s: Could not find data bulk out\n",
404                         USBDEVNAME(ucom->sc_dev));
405                 ucom->sc_dying = 1;
406                 goto error;
407         }
408
409         sc->sc_dtr = sc->sc_rts = -1;
410         ucom->sc_parent = sc;
411         ucom->sc_portno = UCOM_UNK_PORTNO;
412         /* bulkin, bulkout set above */
413         ucom->sc_ibufsize = UPLCOMIBUFSIZE;
414         ucom->sc_obufsize = UPLCOMOBUFSIZE;
415         ucom->sc_ibufsizepad = UPLCOMIBUFSIZE;
416         ucom->sc_opkthdrlen = 0;
417         ucom->sc_callback = &uplcom_callback;
418
419         err = uplcom_reset(sc);
420
421         if (err) {
422                 printf("%s: reset failed: %s\n",
423                        USBDEVNAME(ucom->sc_dev), usbd_errstr(err));
424                 ucom->sc_dying = 1;
425                 goto error;
426         }
427
428         DPRINTF(("uplcom: in = 0x%x, out = 0x%x, intr = 0x%x\n",
429                  ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number));
430
431         ucom_attach(&sc->sc_ucom);
432
433         free(devinfo, M_USBDEV);
434         USB_ATTACH_SUCCESS_RETURN;
435
436 error:
437         free(devinfo, M_USBDEV);
438         USB_ATTACH_ERROR_RETURN;
439 }
440
441 USB_DETACH(uplcom)
442 {
443         USB_DETACH_START(uplcom, sc);
444         int rv = 0;
445
446         DPRINTF(("uplcom_detach: sc = %p\n", sc));
447
448         if (sc->sc_intr_pipe != NULL) {
449                 usbd_abort_pipe(sc->sc_intr_pipe);
450                 usbd_close_pipe(sc->sc_intr_pipe);
451                 free(sc->sc_intr_buf, M_USBDEV);
452                 sc->sc_intr_pipe = NULL;
453         }
454
455         sc->sc_ucom.sc_dying = 1;
456
457         rv = ucom_detach(&sc->sc_ucom);
458
459         return (rv);
460 }
461
462 Static usbd_status
463 uplcom_reset(struct uplcom_softc *sc)
464 {
465         usb_device_request_t req;
466         usbd_status err;
467
468         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
469         req.bRequest = UPLCOM_SET_REQUEST;
470         USETW(req.wValue, 0);
471         USETW(req.wIndex, sc->sc_iface_number);
472         USETW(req.wLength, 0); 
473
474         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0); 
475         if (err) {
476                 printf("%s: uplcom_reset: %s\n",
477                        USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
478                 return (EIO);
479         }
480
481         return (0);
482 }
483
484 Static void
485 uplcom_set_line_state(struct uplcom_softc *sc)
486 {
487         usb_device_request_t req;
488         int ls;
489         usbd_status err;
490
491         ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) |
492                 (sc->sc_rts ? UCDC_LINE_RTS : 0);
493         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
494         req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
495         USETW(req.wValue, ls);
496         USETW(req.wIndex, sc->sc_iface_number);
497         USETW(req.wLength, 0);
498
499         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
500         if (err)
501                 printf("%s: uplcom_set_line_status: %s\n",
502                        USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
503 }
504
505 Static void
506 uplcom_set(void *addr, int portno, int reg, int onoff)
507 {
508         struct uplcom_softc *sc = addr;
509
510         switch (reg) {
511         case UCOM_SET_DTR:
512                 uplcom_dtr(sc, onoff);
513                 break;
514         case UCOM_SET_RTS:
515                 uplcom_rts(sc, onoff);
516                 break;
517         case UCOM_SET_BREAK:
518                 uplcom_break(sc, onoff);
519                 break;
520         default:
521                 break;
522         }
523 }
524
525 Static void
526 uplcom_dtr(struct uplcom_softc *sc, int onoff)
527 {
528         DPRINTF(("uplcom_dtr: onoff = %d\n", onoff));
529
530         if (sc->sc_dtr == onoff)
531                 return;
532         sc->sc_dtr = onoff;
533
534         uplcom_set_line_state(sc);
535 }
536
537 Static void
538 uplcom_rts(struct uplcom_softc *sc, int onoff)
539 {
540         DPRINTF(("uplcom_rts: onoff = %d\n", onoff));
541
542         if (sc->sc_rts == onoff)
543                 return;
544         sc->sc_rts = onoff;
545
546         uplcom_set_line_state(sc);
547 }
548
549 Static void
550 uplcom_break(struct uplcom_softc *sc, int onoff)
551 {
552         usb_device_request_t req;
553         usbd_status err;
554
555         DPRINTF(("uplcom_break: onoff = %d\n", onoff));
556
557         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
558         req.bRequest = UCDC_SEND_BREAK;
559         USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
560         USETW(req.wIndex, sc->sc_iface_number);
561         USETW(req.wLength, 0);
562
563         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
564         if (err)
565                 printf("%s: uplcom_break: %s\n",
566                        USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
567 }
568
569 Static usbd_status
570 uplcom_set_crtscts(struct uplcom_softc *sc)
571 {
572         usb_device_request_t req;
573         usbd_status err;
574
575         DPRINTF(("uplcom_set_crtscts: on\n"));
576
577         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
578         req.bRequest = UPLCOM_SET_REQUEST;
579         USETW(req.wValue, 0);
580         USETW(req.wIndex, UPLCOM_SET_CRTSCTS);
581         USETW(req.wLength, 0);
582
583         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
584         if (err) {
585                 printf("%s: uplcom_set_crtscts: %s\n",
586                        USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
587                 return (err);
588         }
589
590         return (USBD_NORMAL_COMPLETION);
591 }
592
593 Static usbd_status
594 uplcom_set_line_coding(struct uplcom_softc *sc, usb_cdc_line_state_t *state)
595 {
596         usb_device_request_t req;
597         usbd_status err;
598
599         DPRINTF((
600 "uplcom_set_line_coding: rate = %d, fmt = %d, parity = %d bits = %d\n",
601                  UGETDW(state->dwDTERate), state->bCharFormat,
602                  state->bParityType, state->bDataBits));
603
604         if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) {
605                 DPRINTF(("uplcom_set_line_coding: already set\n"));
606                 return (USBD_NORMAL_COMPLETION);
607         }
608
609         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
610         req.bRequest = UCDC_SET_LINE_CODING;
611         USETW(req.wValue, 0);
612         USETW(req.wIndex, sc->sc_iface_number);
613         USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
614
615         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, state);
616         if (err) {
617                 printf("%s: uplcom_set_line_coding: %s\n",
618                        USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
619                 return (err);
620         }
621
622         sc->sc_line_state = *state;
623
624         return (USBD_NORMAL_COMPLETION);
625 }
626
627 Static int
628 uplcom_param(void *addr, int portno, struct termios *t)
629 {
630         struct uplcom_softc *sc = addr;
631         usbd_status err;
632         usb_cdc_line_state_t ls;
633
634         DPRINTF(("uplcom_param: sc = %p\n", sc));
635
636         USETDW(ls.dwDTERate, t->c_ospeed);
637         if (ISSET(t->c_cflag, CSTOPB))
638                 ls.bCharFormat = UCDC_STOP_BIT_2;
639         else
640                 ls.bCharFormat = UCDC_STOP_BIT_1;
641         if (ISSET(t->c_cflag, PARENB)) {
642                 if (ISSET(t->c_cflag, PARODD))
643                         ls.bParityType = UCDC_PARITY_ODD;
644                 else
645                         ls.bParityType = UCDC_PARITY_EVEN;
646         } else
647                 ls.bParityType = UCDC_PARITY_NONE;
648         switch (ISSET(t->c_cflag, CSIZE)) {
649         case CS5:
650                 ls.bDataBits = 5;
651                 break;
652         case CS6:
653                 ls.bDataBits = 6;
654                 break;
655         case CS7:
656                 ls.bDataBits = 7;
657                 break;
658         case CS8:
659                 ls.bDataBits = 8;
660                 break;
661         }
662
663         err = uplcom_set_line_coding(sc, &ls);
664         if (err)
665                 return (EIO);
666
667         if (ISSET(t->c_cflag, CRTSCTS)) {
668                 err = uplcom_set_crtscts(sc);
669                 if (err)
670                         return (EIO);
671         }
672
673         return (0);
674 }
675
676 Static int
677 uplcom_open(void *addr, int portno)
678 {
679         struct uplcom_softc *sc = addr;
680         int err;
681         
682         if (sc->sc_ucom.sc_dying)
683                 return (ENXIO);
684
685         DPRINTF(("uplcom_open: sc = %p\n", sc));
686
687         if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
688                 sc->sc_status = 0; /* clear status bit */
689                 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
690                 err = usbd_open_pipe_intr(sc->sc_intr_iface,
691                                           sc->sc_intr_number,
692                                           USBD_SHORT_XFER_OK,
693                                           &sc->sc_intr_pipe,
694                                           sc,
695                                           sc->sc_intr_buf,
696                                           sc->sc_isize,
697                                           uplcom_intr,
698                                           UPLCOM_INTR_INTERVAL);
699                 if (err) {
700                         printf("%s: cannot open interrupt pipe (addr %d)\n",
701                                USBDEVNAME(sc->sc_ucom.sc_dev),
702                                sc->sc_intr_number);
703                         return (EIO);
704                 }
705         }
706
707         return (0);
708 }
709
710 Static void
711 uplcom_close(void *addr, int portno) 
712 {
713         struct uplcom_softc *sc = addr;
714         int err;
715
716         if (sc->sc_ucom.sc_dying)
717                 return;
718
719         DPRINTF(("uplcom_close: close\n"));
720
721         if (sc->sc_intr_pipe != NULL) {
722                 err = usbd_abort_pipe(sc->sc_intr_pipe);
723                 if (err)
724                         printf("%s: abort interrupt pipe failed: %s\n",
725                                USBDEVNAME(sc->sc_ucom.sc_dev),
726                                usbd_errstr(err));
727                 err = usbd_close_pipe(sc->sc_intr_pipe);
728                 if (err)
729                         printf("%s: close interrupt pipe failed: %s\n",
730                                USBDEVNAME(sc->sc_ucom.sc_dev),
731                                usbd_errstr(err));
732                 free(sc->sc_intr_buf, M_USBDEV);
733                 sc->sc_intr_pipe = NULL;
734         }
735 }
736
737 Static void
738 uplcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
739 {
740         struct uplcom_softc *sc = priv;
741         u_char *buf = sc->sc_intr_buf;
742         u_char pstatus;
743
744         if (sc->sc_ucom.sc_dying)
745                 return;
746
747         if (status != USBD_NORMAL_COMPLETION) {
748                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
749                         return;
750
751                 DPRINTF(("%s: uplcom_intr: abnormal status: %s\n",
752                         USBDEVNAME(sc->sc_ucom.sc_dev),
753                         usbd_errstr(status)));
754                 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
755                 return;
756         }
757
758         DPRINTF(("%s: uplcom status = %02x\n",
759                  USBDEVNAME(sc->sc_ucom.sc_dev), buf[8]));
760
761         sc->sc_lsr = sc->sc_msr = 0;
762         pstatus = buf[8];
763         if (ISSET(pstatus, RSAQ_STATUS_DSR))
764                 sc->sc_msr |= UMSR_DSR;
765         if (ISSET(pstatus, RSAQ_STATUS_DCD))
766                 sc->sc_msr |= UMSR_DCD;
767         ucom_status_change(&sc->sc_ucom);
768 }
769
770 Static void
771 uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
772 {
773         struct uplcom_softc *sc = addr;
774
775         DPRINTF(("uplcom_get_status:\n"));
776
777         if (lsr != NULL)
778                 *lsr = sc->sc_lsr;
779         if (msr != NULL)
780                 *msr = sc->sc_msr;
781 }
782
783 #if TODO
784 Static int
785 uplcom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
786              usb_proc_ptr p)
787 {
788         struct uplcom_softc *sc = addr;
789         int error = 0;
790
791         if (sc->sc_ucom.sc_dying)
792                 return (EIO);
793
794         DPRINTF(("uplcom_ioctl: cmd = 0x%08lx\n", cmd));
795
796         switch (cmd) {
797         case TIOCNOTTY:
798         case TIOCMGET:
799         case TIOCMSET:
800         case USB_GET_CM_OVER_DATA:
801         case USB_SET_CM_OVER_DATA:
802                 break;
803
804         default:
805                 DPRINTF(("uplcom_ioctl: unknown\n"));
806                 error = ENOTTY;
807                 break;
808         }
809
810         return (error);
811 }
812 #endif