Annotation of sys/dev/usb/uslcom.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: uslcom.c,v 1.13 2007/06/14 10:11:16 mbalmer Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: #include <sys/param.h>
! 20: #include <sys/systm.h>
! 21: #include <sys/kernel.h>
! 22: #include <sys/conf.h>
! 23: #include <sys/tty.h>
! 24: #include <sys/device.h>
! 25:
! 26: #include <dev/usb/usb.h>
! 27: #include <dev/usb/usbdi.h>
! 28: #include <dev/usb/usbdi_util.h>
! 29: #include <dev/usb/usbdevs.h>
! 30:
! 31: #include <dev/usb/usbdevs.h>
! 32: #include <dev/usb/ucomvar.h>
! 33:
! 34: #ifdef USLCOM_DEBUG
! 35: #define DPRINTFN(n, x) do { if (uslcomdebug > (n)) printf x; } while (0)
! 36: int uslcomdebug = 0;
! 37: #else
! 38: #define DPRINTFN(n, x)
! 39: #endif
! 40: #define DPRINTF(x) DPRINTFN(0, x)
! 41:
! 42: #define USLCOMBUFSZ 256
! 43: #define USLCOM_CONFIG_NO 0
! 44: #define USLCOM_IFACE_NO 0
! 45:
! 46: #define USLCOM_SET_DATA_BITS(x) (x << 8)
! 47:
! 48: #define USLCOM_WRITE 0x41
! 49: #define USLCOM_READ 0xc1
! 50:
! 51: #define USLCOM_UART 0x00
! 52: #define USLCOM_BAUD_RATE 0x01
! 53: #define USLCOM_DATA 0x03
! 54: #define USLCOM_BREAK 0x05
! 55: #define USLCOM_CTRL 0x07
! 56:
! 57: #define USLCOM_UART_DISABLE 0x00
! 58: #define USLCOM_UART_ENABLE 0x01
! 59:
! 60: #define USLCOM_CTRL_DTR_ON 0x0001
! 61: #define USLCOM_CTRL_DTR_SET 0x0100
! 62: #define USLCOM_CTRL_RTS_ON 0x0002
! 63: #define USLCOM_CTRL_RTS_SET 0x0200
! 64: #define USLCOM_CTRL_CTS 0x0010
! 65: #define USLCOM_CTRL_DSR 0x0020
! 66: #define USLCOM_CTRL_DCD 0x0080
! 67:
! 68:
! 69: #define USLCOM_BAUD_REF 0x384000
! 70:
! 71: #define USLCOM_STOP_BITS_1 0x00
! 72: #define USLCOM_STOP_BITS_2 0x02
! 73:
! 74: #define USLCOM_PARITY_NONE 0x00
! 75: #define USLCOM_PARITY_ODD 0x10
! 76: #define USLCOM_PARITY_EVEN 0x20
! 77:
! 78: #define USLCOM_BREAK_OFF 0x00
! 79: #define USLCOM_BREAK_ON 0x01
! 80:
! 81:
! 82: struct uslcom_softc {
! 83: struct device sc_dev;
! 84: usbd_device_handle sc_udev;
! 85: usbd_interface_handle sc_iface;
! 86: struct device *sc_subdev;
! 87:
! 88: u_char sc_msr;
! 89: u_char sc_lsr;
! 90:
! 91: u_char sc_dying;
! 92: };
! 93:
! 94: void uslcom_get_status(void *, int portno, u_char *lsr, u_char *msr);
! 95: void uslcom_set(void *, int, int, int);
! 96: int uslcom_param(void *, int, struct termios *);
! 97: int uslcom_open(void *sc, int portno);
! 98: void uslcom_close(void *, int);
! 99: void uslcom_break(void *sc, int portno, int onoff);
! 100:
! 101: struct ucom_methods uslcom_methods = {
! 102: uslcom_get_status,
! 103: uslcom_set,
! 104: uslcom_param,
! 105: NULL,
! 106: uslcom_open,
! 107: uslcom_close,
! 108: NULL,
! 109: NULL,
! 110: };
! 111:
! 112: static const struct usb_devno uslcom_devs[] = {
! 113: { USB_VENDOR_BALTECH, USB_PRODUCT_BALTECH_CARDREADER },
! 114: { USB_VENDOR_DYNASTREAM, USB_PRODUCT_DYNASTREAM_ANTDEVBOARD },
! 115: { USB_VENDOR_JABLOTRON, USB_PRODUCT_JABLOTRON_PC60B },
! 116: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_ARGUSISP },
! 117: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CRUMB128 },
! 118: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_DEGREECONT },
! 119: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_DESKTOPMOBILE },
! 120: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_IPLINK1220 },
! 121: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_HARP },
! 122: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_JTAG },
! 123: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_LIN },
! 124: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_POLOLU },
! 125: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CP210X_1 },
! 126: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CP210X_2 },
! 127: { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_SUNNTO },
! 128: { USB_VENDOR_SILABS2, USB_PRODUCT_SILABS2_DCU11CLONE },
! 129: { USB_VENDOR_USI, USB_PRODUCT_USI_MC60 }
! 130: };
! 131:
! 132: int uslcom_match(struct device *, void *, void *);
! 133: void uslcom_attach(struct device *, struct device *, void *);
! 134: int uslcom_detach(struct device *, int);
! 135: int uslcom_activate(struct device *, enum devact);
! 136:
! 137: struct cfdriver uslcom_cd = {
! 138: NULL, "uslcom", DV_DULL
! 139: };
! 140:
! 141: const struct cfattach uslcom_ca = {
! 142: sizeof(struct uslcom_softc),
! 143: uslcom_match,
! 144: uslcom_attach,
! 145: uslcom_detach,
! 146: uslcom_activate,
! 147: };
! 148:
! 149: int
! 150: uslcom_match(struct device *parent, void *match, void *aux)
! 151: {
! 152: struct usb_attach_arg *uaa = aux;
! 153:
! 154: if (uaa->iface != NULL)
! 155: return UMATCH_NONE;
! 156:
! 157: return (usb_lookup(uslcom_devs, uaa->vendor, uaa->product) != NULL) ?
! 158: UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
! 159: }
! 160:
! 161: void
! 162: uslcom_attach(struct device *parent, struct device *self, void *aux)
! 163: {
! 164: struct uslcom_softc *sc = (struct uslcom_softc *)self;
! 165: struct usb_attach_arg *uaa = aux;
! 166: struct ucom_attach_args uca;
! 167: usb_interface_descriptor_t *id;
! 168: usb_endpoint_descriptor_t *ed;
! 169: usbd_status error;
! 170: char *devinfop;
! 171: int i;
! 172:
! 173: bzero(&uca, sizeof(uca));
! 174: sc->sc_udev = uaa->device;
! 175: devinfop = usbd_devinfo_alloc(uaa->device, 0);
! 176: printf("\n%s: %s\n", sc->sc_dev.dv_xname, devinfop);
! 177: usbd_devinfo_free(devinfop);
! 178:
! 179: if (usbd_set_config_index(sc->sc_udev, USLCOM_CONFIG_NO, 1) != 0) {
! 180: printf("%s: could not set configuration no\n",
! 181: sc->sc_dev.dv_xname);
! 182: sc->sc_dying = 1;
! 183: return;
! 184: }
! 185:
! 186: /* get the first interface handle */
! 187: error = usbd_device2interface_handle(sc->sc_udev, USLCOM_IFACE_NO,
! 188: &sc->sc_iface);
! 189: if (error != 0) {
! 190: printf("%s: could not get interface handle\n",
! 191: sc->sc_dev.dv_xname);
! 192: sc->sc_dying = 1;
! 193: return;
! 194: }
! 195:
! 196: id = usbd_get_interface_descriptor(sc->sc_iface);
! 197:
! 198: uca.bulkin = uca.bulkout = -1;
! 199: for (i = 0; i < id->bNumEndpoints; i++) {
! 200: ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
! 201: if (ed == NULL) {
! 202: printf("%s: no endpoint descriptor found for %d\n",
! 203: sc->sc_dev.dv_xname, i);
! 204: sc->sc_dying = 1;
! 205: return;
! 206: }
! 207:
! 208: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 209: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
! 210: uca.bulkin = ed->bEndpointAddress;
! 211: else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
! 212: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
! 213: uca.bulkout = ed->bEndpointAddress;
! 214: }
! 215:
! 216: if (uca.bulkin == -1 || uca.bulkout == -1) {
! 217: printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
! 218: sc->sc_dying = 1;
! 219: return;
! 220: }
! 221:
! 222: uca.ibufsize = USLCOMBUFSZ;
! 223: uca.obufsize = USLCOMBUFSZ;
! 224: uca.ibufsizepad = USLCOMBUFSZ;
! 225: uca.opkthdrlen = 0;
! 226: uca.device = sc->sc_udev;
! 227: uca.iface = sc->sc_iface;
! 228: uca.methods = &uslcom_methods;
! 229: uca.arg = sc;
! 230: uca.info = NULL;
! 231:
! 232: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
! 233: &sc->sc_dev);
! 234:
! 235: sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
! 236: }
! 237:
! 238: int
! 239: uslcom_detach(struct device *self, int flags)
! 240: {
! 241: struct uslcom_softc *sc = (struct uslcom_softc *)self;
! 242: int rv = 0;
! 243:
! 244: sc->sc_dying = 1;
! 245: if (sc->sc_subdev != NULL) {
! 246: rv = config_detach(sc->sc_subdev, flags);
! 247: sc->sc_subdev = NULL;
! 248: }
! 249:
! 250: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 251: &sc->sc_dev);
! 252:
! 253: return (rv);
! 254: }
! 255:
! 256: int
! 257: uslcom_activate(struct device *self, enum devact act)
! 258: {
! 259: struct uslcom_softc *sc = (struct uslcom_softc *)self;
! 260: int rv = 0;
! 261:
! 262: switch (act) {
! 263: case DVACT_ACTIVATE:
! 264: break;
! 265:
! 266: case DVACT_DEACTIVATE:
! 267: if (sc->sc_subdev != NULL)
! 268: rv = config_deactivate(sc->sc_subdev);
! 269: sc->sc_dying = 1;
! 270: break;
! 271: }
! 272: return (rv);
! 273: }
! 274:
! 275: int
! 276: uslcom_open(void *vsc, int portno)
! 277: {
! 278: struct uslcom_softc *sc = vsc;
! 279: usb_device_request_t req;
! 280: usbd_status err;
! 281:
! 282: if (sc->sc_dying)
! 283: return (EIO);
! 284:
! 285: req.bmRequestType = USLCOM_WRITE;
! 286: req.bRequest = USLCOM_UART;
! 287: USETW(req.wValue, USLCOM_UART_ENABLE);
! 288: USETW(req.wIndex, portno);
! 289: USETW(req.wLength, 0);
! 290: err = usbd_do_request(sc->sc_udev, &req, NULL);
! 291: if (err)
! 292: return (EIO);
! 293:
! 294: return (0);
! 295: }
! 296:
! 297: void
! 298: uslcom_close(void *vsc, int portno)
! 299: {
! 300: struct uslcom_softc *sc = vsc;
! 301: usb_device_request_t req;
! 302:
! 303: if (sc->sc_dying)
! 304: return;
! 305:
! 306: req.bmRequestType = USLCOM_WRITE;
! 307: req.bRequest = USLCOM_UART;
! 308: USETW(req.wValue, USLCOM_UART_DISABLE);
! 309: USETW(req.wIndex, portno);
! 310: USETW(req.wLength, 0);
! 311: usbd_do_request(sc->sc_udev, &req, NULL);
! 312: }
! 313:
! 314: void
! 315: uslcom_set(void *vsc, int portno, int reg, int onoff)
! 316: {
! 317: struct uslcom_softc *sc = vsc;
! 318: usb_device_request_t req;
! 319: int ctl;
! 320:
! 321: switch (reg) {
! 322: case UCOM_SET_DTR:
! 323: ctl = onoff ? USLCOM_CTRL_DTR_ON : 0;
! 324: ctl |= USLCOM_CTRL_DTR_SET;
! 325: break;
! 326: case UCOM_SET_RTS:
! 327: ctl = onoff ? USLCOM_CTRL_RTS_ON : 0;
! 328: ctl |= USLCOM_CTRL_RTS_SET;
! 329: break;
! 330: case UCOM_SET_BREAK:
! 331: uslcom_break(sc, portno, onoff);
! 332: return;
! 333: default:
! 334: return;
! 335: }
! 336: req.bmRequestType = USLCOM_WRITE;
! 337: req.bRequest = USLCOM_CTRL;
! 338: USETW(req.wValue, ctl);
! 339: USETW(req.wIndex, portno);
! 340: USETW(req.wLength, 0);
! 341: usbd_do_request(sc->sc_udev, &req, NULL);
! 342: }
! 343:
! 344: int
! 345: uslcom_param(void *vsc, int portno, struct termios *t)
! 346: {
! 347: struct uslcom_softc *sc = (struct uslcom_softc *)vsc;
! 348: usbd_status err;
! 349: usb_device_request_t req;
! 350: int data;
! 351:
! 352: switch (t->c_ospeed) {
! 353: case 600:
! 354: case 1200:
! 355: case 1800:
! 356: case 2400:
! 357: case 4800:
! 358: case 9600:
! 359: case 19200:
! 360: case 38400:
! 361: case 57600:
! 362: case 115200:
! 363: case 460800:
! 364: case 921600:
! 365: req.bmRequestType = USLCOM_WRITE;
! 366: req.bRequest = USLCOM_BAUD_RATE;
! 367: USETW(req.wValue, USLCOM_BAUD_REF / t->c_ospeed);
! 368: USETW(req.wIndex, portno);
! 369: USETW(req.wLength, 0);
! 370: err = usbd_do_request(sc->sc_udev, &req, NULL);
! 371: if (err)
! 372: return (EIO);
! 373: break;
! 374: default:
! 375: return (EINVAL);
! 376: }
! 377:
! 378: if (ISSET(t->c_cflag, CSTOPB))
! 379: data = USLCOM_STOP_BITS_2;
! 380: else
! 381: data = USLCOM_STOP_BITS_1;
! 382: if (ISSET(t->c_cflag, PARENB)) {
! 383: if (ISSET(t->c_cflag, PARODD))
! 384: data |= USLCOM_PARITY_ODD;
! 385: else
! 386: data |= USLCOM_PARITY_EVEN;
! 387: } else
! 388: data |= USLCOM_PARITY_NONE;
! 389: switch (ISSET(t->c_cflag, CSIZE)) {
! 390: case CS5:
! 391: data |= USLCOM_SET_DATA_BITS(5);
! 392: break;
! 393: case CS6:
! 394: data |= USLCOM_SET_DATA_BITS(6);
! 395: break;
! 396: case CS7:
! 397: data |= USLCOM_SET_DATA_BITS(7);
! 398: break;
! 399: case CS8:
! 400: data |= USLCOM_SET_DATA_BITS(8);
! 401: break;
! 402: }
! 403:
! 404: req.bmRequestType = USLCOM_WRITE;
! 405: req.bRequest = USLCOM_DATA;
! 406: USETW(req.wValue, data);
! 407: USETW(req.wIndex, portno);
! 408: USETW(req.wLength, 0);
! 409: err = usbd_do_request(sc->sc_udev, &req, NULL);
! 410: if (err)
! 411: return (EIO);
! 412:
! 413: #if 0
! 414: /* XXX flow control */
! 415: if (ISSET(t->c_cflag, CRTSCTS))
! 416: /* rts/cts flow ctl */
! 417: } else if (ISSET(t->c_iflag, IXON|IXOFF)) {
! 418: /* xon/xoff flow ctl */
! 419: } else {
! 420: /* disable flow ctl */
! 421: }
! 422: #endif
! 423:
! 424: return (0);
! 425: }
! 426:
! 427: void
! 428: uslcom_get_status(void *vsc, int portno, u_char *lsr, u_char *msr)
! 429: {
! 430: struct uslcom_softc *sc = vsc;
! 431:
! 432: if (msr != NULL)
! 433: *msr = sc->sc_msr;
! 434: if (lsr != NULL)
! 435: *lsr = sc->sc_lsr;
! 436: }
! 437:
! 438: void
! 439: uslcom_break(void *vsc, int portno, int onoff)
! 440: {
! 441: struct uslcom_softc *sc = vsc;
! 442: usb_device_request_t req;
! 443: int brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF;
! 444:
! 445: req.bmRequestType = USLCOM_WRITE;
! 446: req.bRequest = USLCOM_BREAK;
! 447: USETW(req.wValue, brk);
! 448: USETW(req.wIndex, portno);
! 449: USETW(req.wLength, 0);
! 450: usbd_do_request(sc->sc_udev, &req, NULL);
! 451: }
CVSweb