Annotation of sys/dev/usb/moscom.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: moscom.c,v 1.10 2007/06/14 10:11:15 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: #define MOSCOMBUFSZ 256
! 35: #define MOSCOM_CONFIG_NO 0
! 36: #define MOSCOM_IFACE_NO 0
! 37:
! 38: #define MOSCOM_READ 0x0d
! 39: #define MOSCOM_WRITE 0x0e
! 40: #define MOSCOM_UART_REG 0x0300
! 41: #define MOSCOM_VEND_REG 0x0000
! 42:
! 43: #define MOSCOM_TXBUF 0x00 /* Write */
! 44: #define MOSCOM_RXBUF 0x00 /* Read */
! 45: #define MOSCOM_INT 0x01
! 46: #define MOSCOM_FIFO 0x02 /* Write */
! 47: #define MOSCOM_ISR 0x02 /* Read */
! 48: #define MOSCOM_LCR 0x03
! 49: #define MOSCOM_MCR 0x04
! 50: #define MOSCOM_LSR 0x05
! 51: #define MOSCOM_MSR 0x06
! 52: #define MOSCOM_SCRATCH 0x07
! 53: #define MOSCOM_DIV_LO 0x08
! 54: #define MOSCOM_DIV_HI 0x09
! 55: #define MOSCOM_EFR 0x0a
! 56: #define MOSCOM_XON1 0x0b
! 57: #define MOSCOM_XON2 0x0c
! 58: #define MOSCOM_XOFF1 0x0d
! 59: #define MOSCOM_XOFF2 0x0e
! 60:
! 61: #define MOSCOM_BAUDLO 0x00
! 62: #define MOSCOM_BAUDHI 0x01
! 63:
! 64: #define MOSCOM_INT_RXEN 0x01
! 65: #define MOSCOM_INT_TXEN 0x02
! 66: #define MOSCOM_INT_RSEN 0x04
! 67: #define MOSCOM_INT_MDMEM 0x08
! 68: #define MOSCOM_INT_SLEEP 0x10
! 69: #define MOSCOM_INT_XOFF 0x20
! 70: #define MOSCOM_INT_RTS 0x40
! 71:
! 72: #define MOSCOM_FIFO_EN 0x01
! 73: #define MOSCOM_FIFO_RXCLR 0x02
! 74: #define MOSCOM_FIFO_TXCLR 0x04
! 75: #define MOSCOM_FIFO_DMA_BLK 0x08
! 76: #define MOSCOM_FIFO_TXLVL_MASK 0x30
! 77: #define MOSCOM_FIFO_TXLVL_8 0x00
! 78: #define MOSCOM_FIFO_TXLVL_16 0x10
! 79: #define MOSCOM_FIFO_TXLVL_32 0x20
! 80: #define MOSCOM_FIFO_TXLVL_56 0x30
! 81: #define MOSCOM_FIFO_RXLVL_MASK 0xc0
! 82: #define MOSCOM_FIFO_RXLVL_8 0x00
! 83: #define MOSCOM_FIFO_RXLVL_16 0x40
! 84: #define MOSCOM_FIFO_RXLVL_56 0x80
! 85: #define MOSCOM_FIFO_RXLVL_80 0xc0
! 86:
! 87: #define MOSCOM_ISR_MDM 0x00
! 88: #define MOSCOM_ISR_NONE 0x01
! 89: #define MOSCOM_ISR_TX 0x02
! 90: #define MOSCOM_ISR_RX 0x04
! 91: #define MOSCOM_ISR_LINE 0x06
! 92: #define MOSCOM_ISR_RXTIMEOUT 0x0c
! 93: #define MOSCOM_ISR_RX_XOFF 0x10
! 94: #define MOSCOM_ISR_RTSCTS 0x20
! 95: #define MOSCOM_ISR_FIFOEN 0xc0
! 96:
! 97: #define MOSCOM_LCR_DBITS(x) (x - 5)
! 98: #define MOSCOM_LCR_STOP_BITS_1 0x00
! 99: #define MOSCOM_LCR_STOP_BITS_2 0x04 /* 2 if 6-8 bits/char or 1.5 if 5 */
! 100: #define MOSCOM_LCR_PARITY_NONE 0x00
! 101: #define MOSCOM_LCR_PARITY_ODD 0x08
! 102: #define MOSCOM_LCR_PARITY_EVEN 0x18
! 103: #define MOSCOM_LCR_BREAK 0x40
! 104: #define MOSCOM_LCR_DIVLATCH_EN 0x80
! 105:
! 106: #define MOSCOM_MCR_DTR 0x01
! 107: #define MOSCOM_MCR_RTS 0x02
! 108: #define MOSCOM_MCR_LOOP 0x04
! 109: #define MOSCOM_MCR_INTEN 0x08
! 110: #define MOSCOM_MCR_LOOPBACK 0x10
! 111: #define MOSCOM_MCR_XONANY 0x20
! 112: #define MOSCOM_MCR_IRDA_EN 0x40
! 113: #define MOSCOM_MCR_BAUD_DIV4 0x80
! 114:
! 115: #define MOSCOM_LSR_RXDATA 0x01
! 116: #define MOSCOM_LSR_RXOVER 0x02
! 117: #define MOSCOM_LSR_RXPAR_ERR 0x04
! 118: #define MOSCOM_LSR_RXFRM_ERR 0x08
! 119: #define MOSCOM_LSR_RXBREAK 0x10
! 120: #define MOSCOM_LSR_TXEMPTY 0x20
! 121: #define MOSCOM_LSR_TXALLEMPTY 0x40
! 122: #define MOSCOM_LSR_TXFIFO_ERR 0x80
! 123:
! 124: #define MOSCOM_MSR_CTS_CHG 0x01
! 125: #define MOSCOM_MSR_DSR_CHG 0x02
! 126: #define MOSCOM_MSR_RI_CHG 0x04
! 127: #define MOSCOM_MSR_CD_CHG 0x08
! 128: #define MOSCOM_MSR_CTS 0x10
! 129: #define MOSCOM_MSR_RTS 0x20
! 130: #define MOSCOM_MSR_RI 0x40
! 131: #define MOSCOM_MSR_CD 0x80
! 132:
! 133: #define MOSCOM_BAUD_REF 115200
! 134:
! 135: struct moscom_softc {
! 136: struct device sc_dev;
! 137: usbd_device_handle sc_udev;
! 138: usbd_interface_handle sc_iface;
! 139: struct device *sc_subdev;
! 140:
! 141: u_char sc_msr;
! 142: u_char sc_lsr;
! 143: u_char sc_lcr;
! 144:
! 145: u_char sc_dying;
! 146: };
! 147:
! 148: void moscom_get_status(void *, int, u_char *, u_char *);
! 149: void moscom_set(void *, int, int, int);
! 150: int moscom_param(void *, int, struct termios *);
! 151: int moscom_open(void *, int);
! 152: int moscom_cmd(struct moscom_softc *, int, int);
! 153:
! 154: struct ucom_methods moscom_methods = {
! 155: NULL,
! 156: moscom_set,
! 157: moscom_param,
! 158: NULL,
! 159: moscom_open,
! 160: NULL,
! 161: NULL,
! 162: NULL,
! 163: };
! 164:
! 165: static const struct usb_devno moscom_devs[] = {
! 166: { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7703 }
! 167: };
! 168:
! 169: int moscom_match(struct device *, void *, void *);
! 170: void moscom_attach(struct device *, struct device *, void *);
! 171: int moscom_detach(struct device *, int);
! 172: int moscom_activate(struct device *, enum devact);
! 173:
! 174: struct cfdriver moscom_cd = {
! 175: NULL, "moscom", DV_DULL
! 176: };
! 177:
! 178: const struct cfattach moscom_ca = {
! 179: sizeof(struct moscom_softc),
! 180: moscom_match,
! 181: moscom_attach,
! 182: moscom_detach,
! 183: moscom_activate,
! 184: };
! 185:
! 186: int
! 187: moscom_match(struct device *parent, void *match, void *aux)
! 188: {
! 189: struct usb_attach_arg *uaa = aux;
! 190:
! 191: if (uaa->iface != NULL)
! 192: return UMATCH_NONE;
! 193:
! 194: return (usb_lookup(moscom_devs, uaa->vendor, uaa->product) != NULL) ?
! 195: UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
! 196: }
! 197:
! 198: void
! 199: moscom_attach(struct device *parent, struct device *self, void *aux)
! 200: {
! 201: struct moscom_softc *sc = (struct moscom_softc *)self;
! 202: struct usb_attach_arg *uaa = aux;
! 203: struct ucom_attach_args uca;
! 204: usb_interface_descriptor_t *id;
! 205: usb_endpoint_descriptor_t *ed;
! 206: usbd_status error;
! 207: char *devinfop;
! 208: int i;
! 209:
! 210: bzero(&uca, sizeof(uca));
! 211: sc->sc_udev = uaa->device;
! 212: devinfop = usbd_devinfo_alloc(uaa->device, 0);
! 213: printf("\n%s: %s\n", sc->sc_dev.dv_xname, devinfop);
! 214: usbd_devinfo_free(devinfop);
! 215:
! 216: if (usbd_set_config_index(sc->sc_udev, MOSCOM_CONFIG_NO, 1) != 0) {
! 217: printf("%s: could not set configuration no\n",
! 218: sc->sc_dev.dv_xname);
! 219: sc->sc_dying = 1;
! 220: return;
! 221: }
! 222:
! 223: /* get the first interface handle */
! 224: error = usbd_device2interface_handle(sc->sc_udev, MOSCOM_IFACE_NO,
! 225: &sc->sc_iface);
! 226: if (error != 0) {
! 227: printf("%s: could not get interface handle\n",
! 228: sc->sc_dev.dv_xname);
! 229: sc->sc_dying = 1;
! 230: return;
! 231: }
! 232:
! 233: id = usbd_get_interface_descriptor(sc->sc_iface);
! 234:
! 235: uca.bulkin = uca.bulkout = -1;
! 236: for (i = 0; i < id->bNumEndpoints; i++) {
! 237: ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
! 238: if (ed == NULL) {
! 239: printf("%s: no endpoint descriptor found for %d\n",
! 240: sc->sc_dev.dv_xname, i);
! 241: sc->sc_dying = 1;
! 242: return;
! 243: }
! 244:
! 245: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 246: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
! 247: uca.bulkin = ed->bEndpointAddress;
! 248: else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
! 249: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
! 250: uca.bulkout = ed->bEndpointAddress;
! 251: }
! 252:
! 253: if (uca.bulkin == -1 || uca.bulkout == -1) {
! 254: printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
! 255: sc->sc_dying = 1;
! 256: return;
! 257: }
! 258:
! 259: uca.ibufsize = MOSCOMBUFSZ;
! 260: uca.obufsize = MOSCOMBUFSZ;
! 261: uca.ibufsizepad = MOSCOMBUFSZ;
! 262: uca.opkthdrlen = 0;
! 263: uca.device = sc->sc_udev;
! 264: uca.iface = sc->sc_iface;
! 265: uca.methods = &moscom_methods;
! 266: uca.arg = sc;
! 267: uca.info = NULL;
! 268:
! 269: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
! 270: &sc->sc_dev);
! 271:
! 272: sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
! 273: }
! 274:
! 275: int
! 276: moscom_detach(struct device *self, int flags)
! 277: {
! 278: struct moscom_softc *sc = (struct moscom_softc *)self;
! 279: int rv = 0;
! 280:
! 281: sc->sc_dying = 1;
! 282: if (sc->sc_subdev != NULL) {
! 283: rv = config_detach(sc->sc_subdev, flags);
! 284: sc->sc_subdev = NULL;
! 285: }
! 286:
! 287: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 288: &sc->sc_dev);
! 289:
! 290: return (rv);
! 291: }
! 292:
! 293: int
! 294: moscom_activate(struct device *self, enum devact act)
! 295: {
! 296: struct moscom_softc *sc = (struct moscom_softc *)self;
! 297: int rv = 0;
! 298:
! 299: switch (act) {
! 300: case DVACT_ACTIVATE:
! 301: break;
! 302:
! 303: case DVACT_DEACTIVATE:
! 304: if (sc->sc_subdev != NULL)
! 305: rv = config_deactivate(sc->sc_subdev);
! 306: sc->sc_dying = 1;
! 307: break;
! 308: }
! 309: return (rv);
! 310: }
! 311:
! 312: int
! 313: moscom_open(void *vsc, int portno)
! 314: {
! 315: struct moscom_softc *sc = vsc;
! 316: usb_device_request_t req;
! 317:
! 318: if (sc->sc_dying)
! 319: return (EIO);
! 320:
! 321: /* Purge FIFOs or odd things happen */
! 322: if (moscom_cmd(sc, MOSCOM_FIFO, 0x00) != 0)
! 323: return (EIO);
! 324:
! 325: if (moscom_cmd(sc, MOSCOM_FIFO, MOSCOM_FIFO_EN |
! 326: MOSCOM_FIFO_RXCLR | MOSCOM_FIFO_TXCLR |
! 327: MOSCOM_FIFO_DMA_BLK | MOSCOM_FIFO_RXLVL_MASK) != 0)
! 328: return (EIO);
! 329:
! 330: /* Magic tell device we're ready for data command */
! 331: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 332: req.bRequest = MOSCOM_WRITE;
! 333: USETW(req.wValue, 0x08);
! 334: USETW(req.wIndex, MOSCOM_INT);
! 335: USETW(req.wLength, 0);
! 336: if (usbd_do_request(sc->sc_udev, &req, NULL) != 0)
! 337: return (EIO);
! 338:
! 339: return (0);
! 340: }
! 341:
! 342: void
! 343: moscom_set(void *vsc, int portno, int reg, int onoff)
! 344: {
! 345: struct moscom_softc *sc = vsc;
! 346: int val;
! 347:
! 348: switch (reg) {
! 349: case UCOM_SET_DTR:
! 350: val = onoff ? MOSCOM_MCR_DTR : 0;
! 351: break;
! 352: case UCOM_SET_RTS:
! 353: val = onoff ? MOSCOM_MCR_RTS : 0;
! 354: break;
! 355: case UCOM_SET_BREAK:
! 356: val = sc->sc_lcr;
! 357: if (onoff)
! 358: val |= MOSCOM_LCR_BREAK;
! 359: moscom_cmd(sc, MOSCOM_LCR, val);
! 360: return;
! 361: default:
! 362: return;
! 363: }
! 364:
! 365: moscom_cmd(sc, MOSCOM_MCR, val);
! 366: }
! 367:
! 368: int
! 369: moscom_param(void *vsc, int portno, struct termios *t)
! 370: {
! 371: struct moscom_softc *sc = (struct moscom_softc *)vsc;
! 372: int data;
! 373:
! 374: if (t->c_ospeed <= 0 || t->c_ospeed > 115200)
! 375: return (EINVAL);
! 376:
! 377: data = MOSCOM_BAUD_REF / t->c_ospeed;
! 378:
! 379: if (data == 0 || data > 0xffff)
! 380: return (EINVAL);
! 381:
! 382: moscom_cmd(sc, MOSCOM_LCR, MOSCOM_LCR_DIVLATCH_EN);
! 383: moscom_cmd(sc, MOSCOM_BAUDLO, data & 0xFF);
! 384: moscom_cmd(sc, MOSCOM_BAUDHI, (data >> 8) & 0xFF);
! 385:
! 386: if (ISSET(t->c_cflag, CSTOPB))
! 387: data = MOSCOM_LCR_STOP_BITS_2;
! 388: else
! 389: data = MOSCOM_LCR_STOP_BITS_1;
! 390: if (ISSET(t->c_cflag, PARENB)) {
! 391: if (ISSET(t->c_cflag, PARODD))
! 392: data |= MOSCOM_LCR_PARITY_ODD;
! 393: else
! 394: data |= MOSCOM_LCR_PARITY_EVEN;
! 395: } else
! 396: data |= MOSCOM_LCR_PARITY_NONE;
! 397: switch (ISSET(t->c_cflag, CSIZE)) {
! 398: case CS5:
! 399: data |= MOSCOM_LCR_DBITS(5);
! 400: break;
! 401: case CS6:
! 402: data |= MOSCOM_LCR_DBITS(6);
! 403: break;
! 404: case CS7:
! 405: data |= MOSCOM_LCR_DBITS(7);
! 406: break;
! 407: case CS8:
! 408: data |= MOSCOM_LCR_DBITS(8);
! 409: break;
! 410: }
! 411:
! 412: sc->sc_lcr = data;
! 413: moscom_cmd(sc, MOSCOM_LCR, sc->sc_lcr);
! 414:
! 415: #if 0
! 416: /* XXX flow control */
! 417: if (ISSET(t->c_cflag, CRTSCTS))
! 418: /* rts/cts flow ctl */
! 419: } else if (ISSET(t->c_iflag, IXON|IXOFF)) {
! 420: /* xon/xoff flow ctl */
! 421: } else {
! 422: /* disable flow ctl */
! 423: }
! 424: #endif
! 425:
! 426: return (0);
! 427: }
! 428:
! 429: void
! 430: moscom_get_status(void *vsc, int portno, u_char *lsr, u_char *msr)
! 431: {
! 432: struct moscom_softc *sc = vsc;
! 433:
! 434: if (msr != NULL)
! 435: *msr = sc->sc_msr;
! 436: if (lsr != NULL)
! 437: *lsr = sc->sc_lsr;
! 438: }
! 439:
! 440: int
! 441: moscom_cmd(struct moscom_softc *sc, int reg, int val)
! 442: {
! 443: usb_device_request_t req;
! 444: usbd_status err;
! 445:
! 446: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 447: req.bRequest = MOSCOM_WRITE;
! 448: USETW(req.wValue, val + MOSCOM_UART_REG);
! 449: USETW(req.wIndex, reg);
! 450: USETW(req.wLength, 0);
! 451: err = usbd_do_request(sc->sc_udev, &req, NULL);
! 452: if (err)
! 453: return (EIO);
! 454: else
! 455: return (0);
! 456: }
CVSweb