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