Annotation of sys/dev/usb/uftdi.c, Revision 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