Annotation of sys/dev/usb/umct.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: umct.c,v 1.26 2007/06/14 10:11:16 mbalmer Exp $ */
2: /* $NetBSD: umct.c,v 1.10 2003/02/23 04:20:07 simonb Exp $ */
3: /*
4: * Copyright (c) 2001 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Ichiro FUKUHARA (ichiro@ichiro.org).
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
38:
39: /*
40: * MCT USB-RS232 Interface Controller
41: * http://www.mct.com.tw/prod/rs232.html
42: * http://www.dlink.com/products/usb/dsbs25
43: */
44:
45: #include <sys/param.h>
46: #include <sys/systm.h>
47: #include <sys/kernel.h>
48: #include <sys/malloc.h>
49: #include <sys/ioctl.h>
50: #include <sys/conf.h>
51: #include <sys/tty.h>
52: #include <sys/file.h>
53: #include <sys/selinfo.h>
54: #include <sys/proc.h>
55: #include <sys/vnode.h>
56: #include <sys/device.h>
57: #include <sys/poll.h>
58:
59: #include <dev/usb/usb.h>
60: #include <dev/usb/usbcdc.h>
61:
62: #include <dev/usb/usbdi.h>
63: #include <dev/usb/usbdi_util.h>
64: #include <dev/usb/usbdevs.h>
65: #include <dev/usb/usb_quirks.h>
66:
67: #include <dev/usb/usbdevs.h>
68: #include <dev/usb/ucomvar.h>
69:
70: #include <dev/usb/umct.h>
71:
72: #ifdef UMCT_DEBUG
73: #define DPRINTFN(n, x) do { if (umctdebug > (n)) printf x; } while (0)
74: int umctdebug = 0;
75: #else
76: #define DPRINTFN(n, x)
77: #endif
78: #define DPRINTF(x) DPRINTFN(0, x)
79:
80: #define UMCT_CONFIG_INDEX 0
81: #define UMCT_IFACE_INDEX 0
82:
83: struct umct_softc {
84: struct device sc_dev; /* base device */
85: usbd_device_handle sc_udev; /* USB device */
86: usbd_interface_handle sc_iface; /* interface */
87: int sc_iface_number; /* interface number */
88: u_int16_t sc_product;
89:
90: int sc_intr_number; /* interrupt number */
91: usbd_pipe_handle sc_intr_pipe; /* interrupt pipe */
92: u_char *sc_intr_buf; /* interrupt buffer */
93: int sc_isize;
94:
95: usb_cdc_line_state_t sc_line_state; /* current line state */
96: u_char sc_dtr; /* current DTR state */
97: u_char sc_rts; /* current RTS state */
98: u_char sc_break; /* set break */
99:
100: u_char sc_status;
101:
102: struct device *sc_subdev; /* ucom device */
103:
104: u_char sc_dying; /* disconnecting */
105:
106: u_char sc_lsr; /* Local status register */
107: u_char sc_msr; /* umct status register */
108:
109: u_int last_lcr; /* keep lcr register */
110: };
111:
112: /*
113: * These are the maximum number of bytes transferred per frame.
114: * The output buffer size cannot be increased due to the size encoding.
115: */
116: #define UMCTIBUFSIZE 256
117: #define UMCTOBUFSIZE 256
118:
119: void umct_init(struct umct_softc *);
120: void umct_set_baudrate(struct umct_softc *, u_int);
121: void umct_set_lcr(struct umct_softc *, u_int);
122: void umct_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
123:
124: void umct_set(void *, int, int, int);
125: void umct_dtr(struct umct_softc *, int);
126: void umct_rts(struct umct_softc *, int);
127: void umct_break(struct umct_softc *, int);
128: void umct_set_line_state(struct umct_softc *);
129: void umct_get_status(void *, int portno, u_char *lsr, u_char *msr);
130: int umct_param(void *, int, struct termios *);
131: int umct_open(void *, int);
132: void umct_close(void *, int);
133:
134: struct ucom_methods umct_methods = {
135: umct_get_status,
136: umct_set,
137: umct_param,
138: NULL,
139: umct_open,
140: umct_close,
141: NULL,
142: NULL,
143: };
144:
145: static const struct usb_devno umct_devs[] = {
146: /* MCT USB-232 Interface Products */
147: { USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232 },
148: /* Sitecom USB-232 Products */
149: { USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232 },
150: /* D-Link DU-H3SP USB BAY Hub Products */
151: { USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232 },
152: /* BELKIN F5U109 */
153: { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U109 },
154: /* BELKIN F5U409 */
155: { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U409 },
156: };
157: #define umct_lookup(v, p) usb_lookup(umct_devs, v, p)
158:
159: int umct_match(struct device *, void *, void *);
160: void umct_attach(struct device *, struct device *, void *);
161: int umct_detach(struct device *, int);
162: int umct_activate(struct device *, enum devact);
163:
164: struct cfdriver umct_cd = {
165: NULL, "umct", DV_DULL
166: };
167:
168: const struct cfattach umct_ca = {
169: sizeof(struct umct_softc),
170: umct_match,
171: umct_attach,
172: umct_detach,
173: umct_activate,
174: };
175:
176: int
177: umct_match(struct device *parent, void *match, void *aux)
178: {
179: struct usb_attach_arg *uaa = aux;
180:
181: if (uaa->iface != NULL)
182: return (UMATCH_NONE);
183:
184: return (umct_lookup(uaa->vendor, uaa->product) != NULL ?
185: UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
186: }
187:
188: void
189: umct_attach(struct device *parent, struct device *self, void *aux)
190: {
191: struct umct_softc *sc = (struct umct_softc *)self;
192: struct usb_attach_arg *uaa = aux;
193: usbd_device_handle dev = uaa->device;
194: usb_config_descriptor_t *cdesc;
195: usb_interface_descriptor_t *id;
196: usb_endpoint_descriptor_t *ed;
197:
198: char *devinfop;
199: char *devname = sc->sc_dev.dv_xname;
200: usbd_status err;
201: int i;
202: struct ucom_attach_args uca;
203:
204: devinfop = usbd_devinfo_alloc(dev, 0);
205: printf("\n%s: %s\n", devname, devinfop);
206: usbd_devinfo_free(devinfop);
207:
208: sc->sc_udev = dev;
209: sc->sc_product = uaa->product;
210:
211: DPRINTF(("\n\numct attach: sc=%p\n", sc));
212:
213: /* initialize endpoints */
214: uca.bulkin = uca.bulkout = -1;
215: sc->sc_intr_number = -1;
216: sc->sc_intr_pipe = NULL;
217:
218: /* Move the device into the configured state. */
219: err = usbd_set_config_index(dev, UMCT_CONFIG_INDEX, 1);
220: if (err) {
221: printf("\n%s: failed to set configuration, err=%s\n",
222: devname, usbd_errstr(err));
223: sc->sc_dying = 1;
224: return;
225: }
226:
227: /* get the config descriptor */
228: cdesc = usbd_get_config_descriptor(sc->sc_udev);
229:
230: if (cdesc == NULL) {
231: printf("%s: failed to get configuration descriptor\n",
232: sc->sc_dev.dv_xname);
233: sc->sc_dying = 1;
234: return;
235: }
236:
237: /* get the interface */
238: err = usbd_device2interface_handle(dev, UMCT_IFACE_INDEX,
239: &sc->sc_iface);
240: if (err) {
241: printf("\n%s: failed to get interface, err=%s\n",
242: devname, usbd_errstr(err));
243: sc->sc_dying = 1;
244: return;
245: }
246:
247: /* Find the bulk{in,out} and interrupt endpoints */
248:
249: id = usbd_get_interface_descriptor(sc->sc_iface);
250: sc->sc_iface_number = id->bInterfaceNumber;
251:
252: for (i = 0; i < id->bNumEndpoints; i++) {
253: ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
254: if (ed == NULL) {
255: printf("%s: no endpoint descriptor for %d\n",
256: sc->sc_dev.dv_xname, i);
257: sc->sc_dying = 1;
258: return;
259: }
260:
261: /*
262: * The Bulkin endpoint is marked as an interrupt. Since
263: * we can't rely on the endpoint descriptor order, we'll
264: * check the wMaxPacketSize field to differentiate.
265: */
266: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
267: UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT &&
268: UGETW(ed->wMaxPacketSize) != 0x2) {
269: uca.bulkin = ed->bEndpointAddress;
270: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
271: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
272: uca.bulkout = ed->bEndpointAddress;
273: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
274: UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
275: sc->sc_intr_number = ed->bEndpointAddress;
276: sc->sc_isize = UGETW(ed->wMaxPacketSize);
277: }
278: }
279:
280: if (uca.bulkin == -1) {
281: printf("%s: Could not find data bulk in\n",
282: sc->sc_dev.dv_xname);
283: sc->sc_dying = 1;
284: return;
285: }
286:
287: if (uca.bulkout == -1) {
288: printf("%s: Could not find data bulk out\n",
289: sc->sc_dev.dv_xname);
290: sc->sc_dying = 1;
291: return;
292: }
293:
294: if (sc->sc_intr_number== -1) {
295: printf("%s: Could not find interrupt in\n",
296: sc->sc_dev.dv_xname);
297: sc->sc_dying = 1;
298: return;
299: }
300:
301: sc->sc_dtr = sc->sc_rts = 0;
302: uca.portno = UCOM_UNK_PORTNO;
303: /* bulkin, bulkout set above */
304: uca.ibufsize = UMCTIBUFSIZE;
305: if (sc->sc_product == USB_PRODUCT_MCT_SITECOM_USB232)
306: uca.obufsize = 16; /* device is broken */
307: else
308: uca.obufsize = UMCTOBUFSIZE;
309: uca.ibufsizepad = UMCTIBUFSIZE;
310: uca.opkthdrlen = 0;
311: uca.device = dev;
312: uca.iface = sc->sc_iface;
313: uca.methods = &umct_methods;
314: uca.arg = sc;
315: uca.info = NULL;
316:
317: umct_init(sc);
318:
319: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
320: &sc->sc_dev);
321:
322: DPRINTF(("umct: in=0x%x out=0x%x intr=0x%x\n",
323: uca.bulkin, uca.bulkout, sc->sc_intr_number ));
324: sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
325: }
326:
327: int
328: umct_detach(struct device *self, int flags)
329: {
330: struct umct_softc *sc = (struct umct_softc *)self;
331: int rv = 0;
332:
333: DPRINTF(("umct_detach: sc=%p flags=%d\n", sc, flags));
334:
335: if (sc->sc_intr_pipe != NULL) {
336: usbd_abort_pipe(sc->sc_intr_pipe);
337: usbd_close_pipe(sc->sc_intr_pipe);
338: free(sc->sc_intr_buf, M_USBDEV);
339: sc->sc_intr_pipe = NULL;
340: }
341:
342: sc->sc_dying = 1;
343: if (sc->sc_subdev != NULL) {
344: rv = config_detach(sc->sc_subdev, flags);
345: sc->sc_subdev = NULL;
346: }
347:
348: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
349: &sc->sc_dev);
350:
351: return (rv);
352: }
353:
354: int
355: umct_activate(struct device *self, enum devact act)
356: {
357: struct umct_softc *sc = (struct umct_softc *)self;
358: int rv = 0;
359:
360: switch (act) {
361: case DVACT_ACTIVATE:
362: break;
363:
364: case DVACT_DEACTIVATE:
365: if (sc->sc_subdev != NULL)
366: rv = config_deactivate(sc->sc_subdev);
367: sc->sc_dying = 1;
368: break;
369: }
370: return (rv);
371: }
372:
373: void
374: umct_set_line_state(struct umct_softc *sc)
375: {
376: usb_device_request_t req;
377: uByte ls;
378:
379: ls = (sc->sc_dtr ? MCR_DTR : 0) |
380: (sc->sc_rts ? MCR_RTS : 0);
381:
382: DPRINTF(("umct_set_line_state: DTR=%d,RTS=%d,ls=%02x\n",
383: sc->sc_dtr, sc->sc_rts, ls));
384:
385: req.bmRequestType = UMCT_SET_REQUEST;
386: req.bRequest = REQ_SET_MCR;
387: USETW(req.wValue, 0);
388: USETW(req.wIndex, sc->sc_iface_number);
389: USETW(req.wLength, LENGTH_SET_MCR);
390:
391: (void)usbd_do_request(sc->sc_udev, &req, &ls);
392: }
393:
394: void
395: umct_set(void *addr, int portno, int reg, int onoff)
396: {
397: struct umct_softc *sc = addr;
398:
399: switch (reg) {
400: case UCOM_SET_DTR:
401: umct_dtr(sc, onoff);
402: break;
403: case UCOM_SET_RTS:
404: umct_rts(sc, onoff);
405: break;
406: case UCOM_SET_BREAK:
407: umct_break(sc, onoff);
408: break;
409: default:
410: break;
411: }
412: }
413:
414: void
415: umct_dtr(struct umct_softc *sc, int onoff)
416: {
417:
418: DPRINTF(("umct_dtr: onoff=%d\n", onoff));
419:
420: if (sc->sc_dtr == onoff)
421: return;
422: sc->sc_dtr = onoff;
423:
424: umct_set_line_state(sc);
425: }
426:
427: void
428: umct_rts(struct umct_softc *sc, int onoff)
429: {
430: DPRINTF(("umct_rts: onoff=%d\n", onoff));
431:
432: if (sc->sc_rts == onoff)
433: return;
434: sc->sc_rts = onoff;
435:
436: umct_set_line_state(sc);
437: }
438:
439: void
440: umct_break(struct umct_softc *sc, int onoff)
441: {
442: DPRINTF(("umct_break: onoff=%d\n", onoff));
443:
444: umct_set_lcr(sc, onoff ? sc->last_lcr | LCR_SET_BREAK :
445: sc->last_lcr);
446: }
447:
448: void
449: umct_set_lcr(struct umct_softc *sc, u_int data)
450: {
451: usb_device_request_t req;
452: uByte adata;
453:
454: adata = data;
455: req.bmRequestType = UMCT_SET_REQUEST;
456: req.bRequest = REQ_SET_LCR;
457: USETW(req.wValue, 0);
458: USETW(req.wIndex, sc->sc_iface_number);
459: USETW(req.wLength, LENGTH_SET_LCR);
460:
461: /* XXX should check */
462: (void)usbd_do_request(sc->sc_udev, &req, &adata);
463: }
464:
465: void
466: umct_set_baudrate(struct umct_softc *sc, u_int rate)
467: {
468: usb_device_request_t req;
469: uDWord arate;
470: u_int val;
471:
472: if (sc->sc_product == USB_PRODUCT_MCT_SITECOM_USB232 ||
473: sc->sc_product == USB_PRODUCT_BELKIN_F5U109) {
474: switch (rate) {
475: case 300: val = 0x01; break;
476: case 600: val = 0x02; break;
477: case 1200: val = 0x03; break;
478: case 2400: val = 0x04; break;
479: case 4800: val = 0x06; break;
480: case 9600: val = 0x08; break;
481: case 19200: val = 0x09; break;
482: case 38400: val = 0x0a; break;
483: case 57600: val = 0x0b; break;
484: case 115200: val = 0x0c; break;
485: default: val = -1; break;
486: }
487: } else {
488: val = UMCT_BAUD_RATE(rate);
489: }
490: USETDW(arate, val);
491:
492: req.bmRequestType = UMCT_SET_REQUEST;
493: req.bRequest = REQ_SET_BAUD_RATE;
494: USETW(req.wValue, 0);
495: USETW(req.wIndex, sc->sc_iface_number);
496: USETW(req.wLength, LENGTH_BAUD_RATE);
497:
498: /* XXX should check */
499: (void)usbd_do_request(sc->sc_udev, &req, arate);
500: }
501:
502: void
503: umct_init(struct umct_softc *sc)
504: {
505: umct_set_baudrate(sc, 9600);
506: umct_set_lcr(sc, LCR_DATA_BITS_8 | LCR_PARITY_NONE | LCR_STOP_BITS_1);
507: }
508:
509: int
510: umct_param(void *addr, int portno, struct termios *t)
511: {
512: struct umct_softc *sc = addr;
513: u_int data = 0;
514:
515: DPRINTF(("umct_param: sc=%p\n", sc));
516:
517: DPRINTF(("umct_param: BAUDRATE=%d\n", t->c_ospeed));
518:
519: if (ISSET(t->c_cflag, CSTOPB))
520: data |= LCR_STOP_BITS_2;
521: else
522: data |= LCR_STOP_BITS_1;
523: if (ISSET(t->c_cflag, PARENB)) {
524: if (ISSET(t->c_cflag, PARODD))
525: data |= LCR_PARITY_ODD;
526: else
527: data |= LCR_PARITY_EVEN;
528: } else
529: data |= LCR_PARITY_NONE;
530: switch (ISSET(t->c_cflag, CSIZE)) {
531: case CS5:
532: data |= LCR_DATA_BITS_5;
533: break;
534: case CS6:
535: data |= LCR_DATA_BITS_6;
536: break;
537: case CS7:
538: data |= LCR_DATA_BITS_7;
539: break;
540: case CS8:
541: data |= LCR_DATA_BITS_8;
542: break;
543: }
544:
545: umct_set_baudrate(sc, t->c_ospeed);
546:
547: sc->last_lcr = data;
548: umct_set_lcr(sc, data);
549:
550: return (0);
551: }
552:
553: int
554: umct_open(void *addr, int portno)
555: {
556: struct umct_softc *sc = addr;
557: int err, lcr_data;
558:
559: if (sc->sc_dying)
560: return (EIO);
561:
562: DPRINTF(("umct_open: sc=%p\n", sc));
563:
564: /* initialize LCR */
565: lcr_data = LCR_DATA_BITS_8 | LCR_PARITY_NONE |
566: LCR_STOP_BITS_1;
567: umct_set_lcr(sc, lcr_data);
568:
569: if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
570: sc->sc_status = 0; /* clear status bit */
571: sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
572: err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_intr_number,
573: USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc,
574: sc->sc_intr_buf, sc->sc_isize,
575: umct_intr, USBD_DEFAULT_INTERVAL);
576: if (err) {
577: DPRINTF(("%s: cannot open interrupt pipe (addr %d)\n",
578: sc->sc_dev.dv_xname, sc->sc_intr_number));
579: return (EIO);
580: }
581: }
582:
583: return (0);
584: }
585:
586: void
587: umct_close(void *addr, int portno)
588: {
589: struct umct_softc *sc = addr;
590: int err;
591:
592: if (sc->sc_dying)
593: return;
594:
595: DPRINTF(("umct_close: close\n"));
596:
597: if (sc->sc_intr_pipe != NULL) {
598: err = usbd_abort_pipe(sc->sc_intr_pipe);
599: if (err)
600: printf("%s: abort interrupt pipe failed: %s\n",
601: sc->sc_dev.dv_xname, usbd_errstr(err));
602: err = usbd_close_pipe(sc->sc_intr_pipe);
603: if (err)
604: printf("%s: close interrupt pipe failed: %s\n",
605: sc->sc_dev.dv_xname, usbd_errstr(err));
606: free(sc->sc_intr_buf, M_USBDEV);
607: sc->sc_intr_pipe = NULL;
608: }
609: }
610:
611: void
612: umct_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
613: {
614: struct umct_softc *sc = priv;
615: u_char *buf = sc->sc_intr_buf;
616: u_char mstatus;
617:
618: if (sc->sc_dying)
619: return;
620:
621: if (status != USBD_NORMAL_COMPLETION) {
622: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
623: return;
624:
625: DPRINTF(("%s: abnormal status: %s\n", sc->sc_dev.dv_xname,
626: usbd_errstr(status)));
627: usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
628: return;
629: }
630:
631: DPRINTF(("%s: umct status = MSR:%02x, LSR:%02x\n",
632: sc->sc_dev.dv_xname, buf[0],buf[1]));
633:
634: sc->sc_lsr = sc->sc_msr = 0;
635: mstatus = buf[0];
636: if (ISSET(mstatus, MSR_DSR))
637: sc->sc_msr |= UMSR_DSR;
638: if (ISSET(mstatus, MSR_DCD))
639: sc->sc_msr |= UMSR_DCD;
640: ucom_status_change((struct ucom_softc *)sc->sc_subdev);
641: }
642:
643: void
644: umct_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
645: {
646: struct umct_softc *sc = addr;
647:
648: DPRINTF(("umct_get_status:\n"));
649:
650: if (lsr != NULL)
651: *lsr = sc->sc_lsr;
652: if (msr != NULL)
653: *msr = sc->sc_msr;
654: }
CVSweb