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