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