Annotation of sys/dev/usb/uftdi.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: uftdi.c,v 1.41 2007/06/14 10:11:15 mbalmer Exp $ */
2: /* $NetBSD: uftdi.c,v 1.14 2003/02/23 04:20:07 simonb Exp $ */
3:
4: /*
5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Lennart Augustsson (lennart@augustsson.net).
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: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*
41: * FTDI FT8U100AX serial adapter driver
42: */
43:
44: /*
45: * XXX This driver will not support multiple serial ports.
46: * XXX The ucom layer needs to be extended first.
47: */
48:
49: #include <sys/param.h>
50: #include <sys/systm.h>
51: #include <sys/kernel.h>
52: #include <sys/device.h>
53: #include <sys/conf.h>
54: #include <sys/tty.h>
55:
56: #include <dev/usb/usb.h>
57: #include <dev/usb/usbhid.h>
58:
59: #include <dev/usb/usbdi.h>
60: #include <dev/usb/usbdi_util.h>
61: #include <dev/usb/usbdevs.h>
62:
63: #include <dev/usb/ucomvar.h>
64:
65: #include <dev/usb/uftdireg.h>
66:
67: #ifdef UFTDI_DEBUG
68: #define DPRINTF(x) do { if (uftdidebug) printf x; } while (0)
69: #define DPRINTFN(n,x) do { if (uftdidebug>(n)) printf x; } while (0)
70: int uftdidebug = 0;
71: #else
72: #define DPRINTF(x)
73: #define DPRINTFN(n,x)
74: #endif
75:
76: #define UFTDI_CONFIG_INDEX 0
77: #define UFTDI_IFACE_INDEX 0
78:
79:
80: /*
81: * These are the maximum number of bytes transferred per frame.
82: * The output buffer size cannot be increased due to the size encoding.
83: */
84: #define UFTDIIBUFSIZE 64
85: #define UFTDIOBUFSIZE 64
86:
87: struct uftdi_softc {
88: struct device sc_dev; /* base device */
89: usbd_device_handle sc_udev; /* device */
90: usbd_interface_handle sc_iface; /* interface */
91:
92: enum uftdi_type sc_type;
93: u_int sc_hdrlen;
94:
95: u_char sc_msr;
96: u_char sc_lsr;
97:
98: struct device *sc_subdev;
99:
100: u_char sc_dying;
101:
102: u_int last_lcr;
103: };
104:
105: void uftdi_get_status(void *, int portno, u_char *lsr, u_char *msr);
106: void uftdi_set(void *, int, int, int);
107: int uftdi_param(void *, int, struct termios *);
108: int uftdi_open(void *sc, int portno);
109: void uftdi_read(void *sc, int portno, u_char **ptr,
110: u_int32_t *count);
111: void uftdi_write(void *sc, int portno, u_char *to, u_char *from,
112: u_int32_t *count);
113: void uftdi_break(void *sc, int portno, int onoff);
114: int uftdi_8u232am_getrate(speed_t speed, int *rate);
115:
116: struct ucom_methods uftdi_methods = {
117: uftdi_get_status,
118: uftdi_set,
119: uftdi_param,
120: NULL,
121: uftdi_open,
122: NULL,
123: uftdi_read,
124: uftdi_write,
125: };
126:
127: int uftdi_match(struct device *, void *, void *);
128: void uftdi_attach(struct device *, struct device *, void *);
129: int uftdi_detach(struct device *, int);
130: int uftdi_activate(struct device *, enum devact);
131:
132: struct cfdriver uftdi_cd = {
133: NULL, "uftdi", DV_DULL
134: };
135:
136: const struct cfattach uftdi_ca = {
137: sizeof(struct uftdi_softc),
138: uftdi_match,
139: uftdi_attach,
140: uftdi_detach,
141: uftdi_activate,
142: };
143:
144: int
145: uftdi_match(struct device *parent, void *match, void *aux)
146: {
147: struct usb_attach_arg *uaa = aux;
148:
149: if (uaa->iface != NULL) {
150: if (uaa->vendor == USB_VENDOR_FTDI &&
151: (uaa->product == USB_PRODUCT_FTDI_SERIAL_2232C))
152: return (UMATCH_VENDOR_IFACESUBCLASS);
153: return (UMATCH_NONE);
154: }
155:
156: DPRINTFN(20,("uftdi: vendor=0x%x, product=0x%x\n",
157: uaa->vendor, uaa->product));
158:
159: if (uaa->vendor == USB_VENDOR_FTDI &&
160: (uaa->product == USB_PRODUCT_FTDI_SERIAL_8U100AX ||
161: uaa->product == USB_PRODUCT_FTDI_SERIAL_8U232AM ||
162: uaa->product == USB_PRODUCT_FTDI_SERIAL_232BM ||
163: uaa->product == USB_PRODUCT_FTDI_SEMC_DSS20 ||
164: uaa->product == USB_PRODUCT_FTDI_MHAM_KW ||
165: uaa->product == USB_PRODUCT_FTDI_MHAM_YS ||
166: uaa->product == USB_PRODUCT_FTDI_MHAM_Y6 ||
167: uaa->product == USB_PRODUCT_FTDI_MHAM_Y8 ||
168: uaa->product == USB_PRODUCT_FTDI_MHAM_IC ||
169: uaa->product == USB_PRODUCT_FTDI_MHAM_DB9 ||
170: uaa->product == USB_PRODUCT_FTDI_MHAM_RS232 ||
171: uaa->product == USB_PRODUCT_FTDI_MHAM_Y9 ||
172: uaa->product == USB_PRODUCT_FTDI_COASTAL_TNCX ||
173: uaa->product == USB_PRODUCT_FTDI_LCD_LK202_24 ||
174: uaa->product == USB_PRODUCT_FTDI_LCD_LK204_24 ||
175: uaa->product == USB_PRODUCT_FTDI_LCD_MX200 ||
176: uaa->product == USB_PRODUCT_FTDI_LCD_CFA_631 ||
177: uaa->product == USB_PRODUCT_FTDI_LCD_CFA_632 ||
178: uaa->product == USB_PRODUCT_FTDI_LCD_CFA_633 ||
179: uaa->product == USB_PRODUCT_FTDI_LCD_CFA_634 ||
180: uaa->product == USB_PRODUCT_FTDI_MJS_SIRIUS_PC))
181: return (UMATCH_VENDOR_PRODUCT);
182: if (uaa->vendor == USB_VENDOR_SIIG2 &&
183: (uaa->product == USB_PRODUCT_SIIG2_US2308))
184: return (UMATCH_VENDOR_PRODUCT);
185: if (uaa->vendor == USB_VENDOR_INTREPIDCS &&
186: (uaa->product == USB_PRODUCT_INTREPIDCS_VALUECAN ||
187: uaa->product == USB_PRODUCT_INTREPIDCS_NEOVI))
188: return (UMATCH_VENDOR_PRODUCT);
189: if (uaa->vendor == USB_VENDOR_BBELECTRONICS &&
190: (uaa->product == USB_PRODUCT_BBELECTRONICS_USOTL4))
191: return (UMATCH_VENDOR_PRODUCT);
192: if (uaa->vendor == USB_VENDOR_FALCOM &&
193: (uaa->product == USB_PRODUCT_FALCOM_TWIST ||
194: uaa->product == USB_PRODUCT_FALCOM_SAMBA))
195: return (UMATCH_VENDOR_PRODUCT);
196: if (uaa->vendor == USB_VENDOR_SEALEVEL &&
197: uaa->product == USB_PRODUCT_SEALEVEL_USBSERIAL)
198: return (UMATCH_VENDOR_PRODUCT);
199:
200: return (UMATCH_NONE);
201: }
202:
203: void
204: uftdi_attach(struct device *parent, struct device *self, void *aux)
205: {
206: struct uftdi_softc *sc = (struct uftdi_softc *)self;
207: struct usb_attach_arg *uaa = aux;
208: usbd_device_handle dev = uaa->device;
209: usbd_interface_handle iface;
210: usb_interface_descriptor_t *id;
211: usb_endpoint_descriptor_t *ed;
212: char *devinfop;
213: char *devname = sc->sc_dev.dv_xname;
214: int i;
215: usbd_status err;
216: struct ucom_attach_args uca;
217:
218: DPRINTFN(10,("\nuftdi_attach: sc=%p\n", sc));
219:
220: if (uaa->iface == NULL) {
221: /* Move the device into the configured state. */
222: err = usbd_set_config_index(dev, UFTDI_CONFIG_INDEX, 1);
223: if (err) {
224: printf("\n%s: failed to set configuration, err=%s\n",
225: devname, usbd_errstr(err));
226: goto bad;
227: }
228:
229: err = usbd_device2interface_handle(dev, UFTDI_IFACE_INDEX, &iface);
230: if (err) {
231: printf("\n%s: failed to get interface, err=%s\n",
232: devname, usbd_errstr(err));
233: goto bad;
234: }
235: } else
236: iface = uaa->iface;
237:
238: devinfop = usbd_devinfo_alloc(dev, 0);
239: printf("\n%s: %s\n", devname, devinfop);
240: usbd_devinfo_free(devinfop);
241:
242: id = usbd_get_interface_descriptor(iface);
243:
244: sc->sc_udev = dev;
245: sc->sc_iface = iface;
246:
247: switch (uaa->vendor) {
248: case USB_VENDOR_FTDI:
249: switch (uaa->product) {
250: case USB_PRODUCT_FTDI_SERIAL_8U100AX:
251: sc->sc_type = UFTDI_TYPE_SIO;
252: sc->sc_hdrlen = 1;
253: break;
254:
255: case USB_PRODUCT_FTDI_SEMC_DSS20:
256: case USB_PRODUCT_FTDI_SERIAL_8U232AM:
257: case USB_PRODUCT_FTDI_SERIAL_2232C:
258: case USB_PRODUCT_FTDI_SERIAL_232BM:
259: case USB_PRODUCT_FTDI_COASTAL_TNCX:
260: case USB_PRODUCT_FTDI_LCD_LK202_24:
261: case USB_PRODUCT_FTDI_LCD_LK204_24:
262: case USB_PRODUCT_FTDI_LCD_MX200:
263: case USB_PRODUCT_FTDI_LCD_CFA_631:
264: case USB_PRODUCT_FTDI_LCD_CFA_632:
265: case USB_PRODUCT_FTDI_LCD_CFA_633:
266: case USB_PRODUCT_FTDI_LCD_CFA_634:
267: case USB_PRODUCT_FTDI_MHAM_KW:
268: case USB_PRODUCT_FTDI_MHAM_YS:
269: case USB_PRODUCT_FTDI_MHAM_Y6:
270: case USB_PRODUCT_FTDI_MHAM_Y8:
271: case USB_PRODUCT_FTDI_MHAM_IC:
272: case USB_PRODUCT_FTDI_MHAM_DB9:
273: case USB_PRODUCT_FTDI_MHAM_RS232:
274: case USB_PRODUCT_FTDI_MHAM_Y9:
275: case USB_PRODUCT_SEALEVEL_USBSERIAL:
276: case USB_PRODUCT_FTDI_MJS_SIRIUS_PC:
277: sc->sc_type = UFTDI_TYPE_8U232AM;
278: sc->sc_hdrlen = 0;
279: break;
280:
281: default: /* Can't happen */
282: goto bad;
283: }
284: break;
285:
286: case USB_VENDOR_INTREPIDCS:
287: switch (uaa->product) {
288: case USB_PRODUCT_INTREPIDCS_VALUECAN:
289: case USB_PRODUCT_INTREPIDCS_NEOVI:
290: sc->sc_type = UFTDI_TYPE_8U232AM;
291: sc->sc_hdrlen = 0;
292: break;
293:
294: default: /* Can't happen */
295: goto bad;
296: }
297: break;
298:
299: case USB_VENDOR_SIIG2:
300: switch (uaa->product) {
301: case USB_PRODUCT_SIIG2_US2308:
302: sc->sc_type = UFTDI_TYPE_8U232AM;
303: sc->sc_hdrlen = 0;
304: break;
305:
306: default: /* Can't happen */
307: goto bad;
308: }
309: break;
310:
311: case USB_VENDOR_BBELECTRONICS:
312: switch( uaa->product ){
313: case USB_PRODUCT_BBELECTRONICS_USOTL4:
314: sc->sc_type = UFTDI_TYPE_8U232AM;
315: sc->sc_hdrlen = 0;
316: break;
317: default: /* Can't happen */
318: goto bad;
319: }
320: break;
321:
322: case USB_VENDOR_FALCOM:
323: switch( uaa->product ){
324: case USB_PRODUCT_FALCOM_TWIST:
325: case USB_PRODUCT_FALCOM_SAMBA:
326: sc->sc_type = UFTDI_TYPE_8U232AM;
327: sc->sc_hdrlen = 0;
328: break;
329: default: /* Can't happen */
330: goto bad;
331: }
332: break;
333: }
334:
335:
336: uca.bulkin = uca.bulkout = -1;
337: for (i = 0; i < id->bNumEndpoints; i++) {
338: int addr, dir, attr;
339: ed = usbd_interface2endpoint_descriptor(iface, i);
340: if (ed == NULL) {
341: printf("%s: could not read endpoint descriptor\n",
342: devname);
343: goto bad;
344: }
345:
346: addr = ed->bEndpointAddress;
347: dir = UE_GET_DIR(ed->bEndpointAddress);
348: attr = ed->bmAttributes & UE_XFERTYPE;
349: if (dir == UE_DIR_IN && attr == UE_BULK)
350: uca.bulkin = addr;
351: else if (dir == UE_DIR_OUT && attr == UE_BULK)
352: uca.bulkout = addr;
353: else {
354: printf("%s: unexpected endpoint\n", devname);
355: goto bad;
356: }
357: }
358: if (uca.bulkin == -1) {
359: printf("%s: Could not find data bulk in\n",
360: sc->sc_dev.dv_xname);
361: goto bad;
362: }
363: if (uca.bulkout == -1) {
364: printf("%s: Could not find data bulk out\n",
365: sc->sc_dev.dv_xname);
366: goto bad;
367: }
368:
369: if (uaa->iface == NULL)
370: uca.portno = FTDI_PIT_SIOA;
371: else
372: uca.portno = FTDI_PIT_SIOA + id->bInterfaceNumber;
373: /* bulkin, bulkout set above */
374: uca.ibufsize = UFTDIIBUFSIZE;
375: uca.obufsize = UFTDIOBUFSIZE - sc->sc_hdrlen;
376: uca.ibufsizepad = UFTDIIBUFSIZE;
377: uca.opkthdrlen = sc->sc_hdrlen;
378: uca.device = dev;
379: uca.iface = iface;
380: uca.methods = &uftdi_methods;
381: uca.arg = sc;
382: uca.info = NULL;
383:
384: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
385: &sc->sc_dev);
386:
387: DPRINTF(("uftdi: in=0x%x out=0x%x\n", uca.bulkin, uca.bulkout));
388: sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
389:
390: return;
391:
392: bad:
393: DPRINTF(("uftdi_attach: ATTACH ERROR\n"));
394: sc->sc_dying = 1;
395: }
396:
397: int
398: uftdi_activate(struct device *self, enum devact act)
399: {
400: struct uftdi_softc *sc = (struct uftdi_softc *)self;
401: int rv = 0;
402:
403: switch (act) {
404: case DVACT_ACTIVATE:
405: break;
406:
407: case DVACT_DEACTIVATE:
408: if (sc->sc_subdev != NULL)
409: rv = config_deactivate(sc->sc_subdev);
410: sc->sc_dying = 1;
411: break;
412: }
413: return (rv);
414: }
415:
416: int
417: uftdi_detach(struct device *self, int flags)
418: {
419: struct uftdi_softc *sc = (struct uftdi_softc *)self;
420:
421: DPRINTF(("uftdi_detach: sc=%p flags=%d\n", sc, flags));
422: sc->sc_dying = 1;
423: if (sc->sc_subdev != NULL) {
424: config_detach(sc->sc_subdev, flags);
425: sc->sc_subdev = NULL;
426: }
427:
428: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
429: &sc->sc_dev);
430:
431: return (0);
432: }
433:
434: int
435: uftdi_open(void *vsc, int portno)
436: {
437: struct uftdi_softc *sc = vsc;
438: usb_device_request_t req;
439: usbd_status err;
440: struct termios t;
441:
442: DPRINTF(("uftdi_open: sc=%p\n", sc));
443:
444: if (sc->sc_dying)
445: return (EIO);
446:
447: /* Perform a full reset on the device */
448: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
449: req.bRequest = FTDI_SIO_RESET;
450: USETW(req.wValue, FTDI_SIO_RESET_SIO);
451: USETW(req.wIndex, portno);
452: USETW(req.wLength, 0);
453: err = usbd_do_request(sc->sc_udev, &req, NULL);
454: if (err)
455: return (EIO);
456:
457: /* Set 9600 baud, 2 stop bits, no parity, 8 bits */
458: t.c_ospeed = 9600;
459: t.c_cflag = CSTOPB | CS8;
460: (void)uftdi_param(sc, portno, &t);
461:
462: /* Turn on RTS/CTS flow control */
463: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
464: req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
465: USETW(req.wValue, 0);
466: USETW2(req.wIndex, FTDI_SIO_RTS_CTS_HS, portno);
467: USETW(req.wLength, 0);
468: err = usbd_do_request(sc->sc_udev, &req, NULL);
469: if (err)
470: return (EIO);
471:
472: return (0);
473: }
474:
475: void
476: uftdi_read(void *vsc, int portno, u_char **ptr, u_int32_t *count)
477: {
478: struct uftdi_softc *sc = vsc;
479: u_char msr, lsr;
480:
481: DPRINTFN(15,("uftdi_read: sc=%p, port=%d count=%d\n", sc, portno,
482: *count));
483:
484: msr = FTDI_GET_MSR(*ptr);
485: lsr = FTDI_GET_LSR(*ptr);
486:
487: #ifdef UFTDI_DEBUG
488: if (*count != 2)
489: DPRINTFN(10,("uftdi_read: sc=%p, port=%d count=%d data[0]="
490: "0x%02x\n", sc, portno, *count, (*ptr)[2]));
491: #endif
492:
493: if (sc->sc_msr != msr ||
494: (sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK)) {
495: DPRINTF(("uftdi_read: status change msr=0x%02x(0x%02x) "
496: "lsr=0x%02x(0x%02x)\n", msr, sc->sc_msr,
497: lsr, sc->sc_lsr));
498: sc->sc_msr = msr;
499: sc->sc_lsr = lsr;
500: ucom_status_change((struct ucom_softc *)sc->sc_subdev);
501: }
502:
503: /* Pick up status and adjust data part. */
504: *ptr += 2;
505: *count -= 2;
506: }
507:
508: void
509: uftdi_write(void *vsc, int portno, u_char *to, u_char *from, u_int32_t *count)
510: {
511: struct uftdi_softc *sc = vsc;
512:
513: DPRINTFN(10,("uftdi_write: sc=%p, port=%d count=%u data[0]=0x%02x\n",
514: vsc, portno, *count, from[0]));
515:
516: /* Make length tag and copy data */
517: if (sc->sc_hdrlen > 0)
518: *to = FTDI_OUT_TAG(*count, portno);
519:
520: memcpy(to + sc->sc_hdrlen, from, *count);
521: *count += sc->sc_hdrlen;
522: }
523:
524: void
525: uftdi_set(void *vsc, int portno, int reg, int onoff)
526: {
527: struct uftdi_softc *sc = vsc;
528: usb_device_request_t req;
529: int ctl;
530:
531: DPRINTF(("uftdi_set: sc=%p, port=%d reg=%d onoff=%d\n", vsc, portno,
532: reg, onoff));
533:
534: switch (reg) {
535: case UCOM_SET_DTR:
536: ctl = onoff ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW;
537: break;
538: case UCOM_SET_RTS:
539: ctl = onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW;
540: break;
541: case UCOM_SET_BREAK:
542: uftdi_break(sc, portno, onoff);
543: return;
544: default:
545: return;
546: }
547: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
548: req.bRequest = FTDI_SIO_MODEM_CTRL;
549: USETW(req.wValue, ctl);
550: USETW(req.wIndex, portno);
551: USETW(req.wLength, 0);
552: DPRINTFN(2,("uftdi_set: reqtype=0x%02x req=0x%02x value=0x%04x "
553: "index=0x%04x len=%d\n", req.bmRequestType, req.bRequest,
554: UGETW(req.wValue), UGETW(req.wIndex), UGETW(req.wLength)));
555: (void)usbd_do_request(sc->sc_udev, &req, NULL);
556: }
557:
558: int
559: uftdi_param(void *vsc, int portno, struct termios *t)
560: {
561: struct uftdi_softc *sc = vsc;
562: usb_device_request_t req;
563: usbd_status err;
564: int rate, data, flow;
565:
566: DPRINTF(("uftdi_param: sc=%p\n", sc));
567:
568: if (sc->sc_dying)
569: return (EIO);
570:
571: switch (sc->sc_type) {
572: case UFTDI_TYPE_SIO:
573: switch (t->c_ospeed) {
574: case 300: rate = ftdi_sio_b300; break;
575: case 600: rate = ftdi_sio_b600; break;
576: case 1200: rate = ftdi_sio_b1200; break;
577: case 2400: rate = ftdi_sio_b2400; break;
578: case 4800: rate = ftdi_sio_b4800; break;
579: case 9600: rate = ftdi_sio_b9600; break;
580: case 19200: rate = ftdi_sio_b19200; break;
581: case 38400: rate = ftdi_sio_b38400; break;
582: case 57600: rate = ftdi_sio_b57600; break;
583: case 115200: rate = ftdi_sio_b115200; break;
584: default:
585: return (EINVAL);
586: }
587: break;
588:
589: case UFTDI_TYPE_8U232AM:
590: if (uftdi_8u232am_getrate(t->c_ospeed, &rate) == -1)
591: return (EINVAL);
592: break;
593: }
594: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
595: req.bRequest = FTDI_SIO_SET_BAUD_RATE;
596: USETW(req.wValue, rate);
597: USETW(req.wIndex, portno);
598: USETW(req.wLength, 0);
599: DPRINTFN(2,("uftdi_param: reqtype=0x%02x req=0x%02x value=0x%04x "
600: "index=0x%04x len=%d\n", req.bmRequestType, req.bRequest,
601: UGETW(req.wValue), UGETW(req.wIndex), UGETW(req.wLength)));
602: err = usbd_do_request(sc->sc_udev, &req, NULL);
603: if (err)
604: return (EIO);
605:
606: if (ISSET(t->c_cflag, CSTOPB))
607: data = FTDI_SIO_SET_DATA_STOP_BITS_2;
608: else
609: data = FTDI_SIO_SET_DATA_STOP_BITS_1;
610: if (ISSET(t->c_cflag, PARENB)) {
611: if (ISSET(t->c_cflag, PARODD))
612: data |= FTDI_SIO_SET_DATA_PARITY_ODD;
613: else
614: data |= FTDI_SIO_SET_DATA_PARITY_EVEN;
615: } else
616: data |= FTDI_SIO_SET_DATA_PARITY_NONE;
617: switch (ISSET(t->c_cflag, CSIZE)) {
618: case CS5:
619: data |= FTDI_SIO_SET_DATA_BITS(5);
620: break;
621: case CS6:
622: data |= FTDI_SIO_SET_DATA_BITS(6);
623: break;
624: case CS7:
625: data |= FTDI_SIO_SET_DATA_BITS(7);
626: break;
627: case CS8:
628: data |= FTDI_SIO_SET_DATA_BITS(8);
629: break;
630: }
631: sc->last_lcr = data;
632:
633: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
634: req.bRequest = FTDI_SIO_SET_DATA;
635: USETW(req.wValue, data);
636: USETW(req.wIndex, portno);
637: USETW(req.wLength, 0);
638: DPRINTFN(2,("uftdi_param: reqtype=0x%02x req=0x%02x value=0x%04x "
639: "index=0x%04x len=%d\n", req.bmRequestType, req.bRequest,
640: UGETW(req.wValue), UGETW(req.wIndex), UGETW(req.wLength)));
641: err = usbd_do_request(sc->sc_udev, &req, NULL);
642: if (err)
643: return (EIO);
644:
645: if (ISSET(t->c_cflag, CRTSCTS)) {
646: flow = FTDI_SIO_RTS_CTS_HS;
647: USETW(req.wValue, 0);
648: } else if (ISSET(t->c_iflag, IXON|IXOFF)) {
649: flow = FTDI_SIO_XON_XOFF_HS;
650: USETW2(req.wValue, t->c_cc[VSTOP], t->c_cc[VSTART]);
651: } else {
652: flow = FTDI_SIO_DISABLE_FLOW_CTRL;
653: USETW(req.wValue, 0);
654: }
655: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
656: req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
657: USETW2(req.wIndex, flow, portno);
658: USETW(req.wLength, 0);
659: err = usbd_do_request(sc->sc_udev, &req, NULL);
660: if (err)
661: return (EIO);
662:
663: return (0);
664: }
665:
666: void
667: uftdi_get_status(void *vsc, int portno, u_char *lsr, u_char *msr)
668: {
669: struct uftdi_softc *sc = vsc;
670:
671: DPRINTF(("uftdi_status: msr=0x%02x lsr=0x%02x\n",
672: sc->sc_msr, sc->sc_lsr));
673:
674: if (msr != NULL)
675: *msr = sc->sc_msr;
676: if (lsr != NULL)
677: *lsr = sc->sc_lsr;
678: }
679:
680: void
681: uftdi_break(void *vsc, int portno, int onoff)
682: {
683: struct uftdi_softc *sc = vsc;
684: usb_device_request_t req;
685: int data;
686:
687: DPRINTF(("uftdi_break: sc=%p, port=%d onoff=%d\n", vsc, portno,
688: onoff));
689:
690: if (onoff) {
691: data = sc->last_lcr | FTDI_SIO_SET_BREAK;
692: } else {
693: data = sc->last_lcr;
694: }
695:
696: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
697: req.bRequest = FTDI_SIO_SET_DATA;
698: USETW(req.wValue, data);
699: USETW(req.wIndex, portno);
700: USETW(req.wLength, 0);
701: (void)usbd_do_request(sc->sc_udev, &req, NULL);
702: }
703:
704: int
705: uftdi_8u232am_getrate(speed_t speed, int *rate)
706: {
707: /* Table of the nearest even powers-of-2 for values 0..15. */
708: static const unsigned char roundoff[16] = {
709: 0, 2, 2, 4, 4, 4, 8, 8,
710: 8, 8, 8, 8, 16, 16, 16, 16,
711: };
712:
713: unsigned int d, freq;
714: int result;
715:
716: if (speed <= 0)
717: return (-1);
718:
719: /* Special cases for 2M and 3M. */
720: if (speed >= 3000000 * 100 / 103 &&
721: speed <= 3000000 * 100 / 97) {
722: result = 0;
723: goto done;
724: }
725: if (speed >= 2000000 * 100 / 103 &&
726: speed <= 2000000 * 100 / 97) {
727: result = 1;
728: goto done;
729: }
730:
731: d = (FTDI_8U232AM_FREQ << 4) / speed;
732: d = (d & ~15) + roundoff[d & 15];
733:
734: if (d < FTDI_8U232AM_MIN_DIV)
735: d = FTDI_8U232AM_MIN_DIV;
736: else if (d > FTDI_8U232AM_MAX_DIV)
737: d = FTDI_8U232AM_MAX_DIV;
738:
739: /*
740: * Calculate the frequency needed for d to exactly divide down
741: * to our target speed, and check that the actual frequency is
742: * within 3% of this.
743: */
744: freq = speed * d;
745: if (freq < (quad_t)(FTDI_8U232AM_FREQ << 4) * 100 / 103 ||
746: freq > (quad_t)(FTDI_8U232AM_FREQ << 4) * 100 / 97)
747: return (-1);
748:
749: /*
750: * Pack the divisor into the resultant value. The lower
751: * 14-bits hold the integral part, while the upper 2 bits
752: * encode the fractional component: either 0, 0.5, 0.25, or
753: * 0.125.
754: */
755: result = d >> 4;
756: if (d & 8)
757: result |= 0x4000;
758: else if (d & 4)
759: result |= 0x8000;
760: else if (d & 2)
761: result |= 0xc000;
762:
763: done:
764: *rate = result;
765: return (0);
766: }
CVSweb