Annotation of sys/dev/usb/uplcom.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: uplcom.c,v 1.43 2007/06/14 10:11:16 mbalmer Exp $ */
! 2: /* $NetBSD: uplcom.c,v 1.29 2002/09/23 05:51:23 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: * Simple datasheet
! 41: * http://www.prolific.com.tw/PDF/PL-2303%20Market%20Spec.pdf
! 42: * http://www.hitachi-hitec.com/jyouhou/prolific/2303.pdf
! 43: * (english)
! 44: *
! 45: */
! 46:
! 47: #include <sys/param.h>
! 48: #include <sys/systm.h>
! 49: #include <sys/kernel.h>
! 50: #include <sys/malloc.h>
! 51: #include <sys/ioctl.h>
! 52: #include <sys/conf.h>
! 53: #include <sys/tty.h>
! 54: #include <sys/file.h>
! 55: #include <sys/selinfo.h>
! 56: #include <sys/proc.h>
! 57: #include <sys/vnode.h>
! 58: #include <sys/device.h>
! 59: #include <sys/poll.h>
! 60:
! 61: #include <dev/usb/usb.h>
! 62: #include <dev/usb/usbcdc.h>
! 63:
! 64: #include <dev/usb/usbdi.h>
! 65: #include <dev/usb/usbdi_util.h>
! 66: #include <dev/usb/usbdevs.h>
! 67: #include <dev/usb/usb_quirks.h>
! 68:
! 69: #include <dev/usb/usbdevs.h>
! 70: #include <dev/usb/ucomvar.h>
! 71:
! 72: #ifdef UPLCOM_DEBUG
! 73: #define DPRINTFN(n, x) do { if (uplcomdebug > (n)) printf x; } while (0)
! 74: int uplcomdebug = 0;
! 75: #else
! 76: #define DPRINTFN(n, x)
! 77: #endif
! 78: #define DPRINTF(x) DPRINTFN(0, x)
! 79:
! 80: #define UPLCOM_CONFIG_INDEX 0
! 81: #define UPLCOM_IFACE_INDEX 0
! 82: #define UPLCOM_SECOND_IFACE_INDEX 1
! 83:
! 84: #define UPLCOM_SET_REQUEST 0x01
! 85: #define UPLCOM_SET_CRTSCTS 0x41
! 86: #define UPLCOM_HX_SET_CRTSCTS 0x61
! 87: #define RSAQ_STATUS_CTS 0x80
! 88: #define RSAQ_STATUS_DSR 0x02
! 89: #define RSAQ_STATUS_DCD 0x01
! 90:
! 91: struct uplcom_softc {
! 92: struct device sc_dev; /* base device */
! 93: usbd_device_handle sc_udev; /* USB device */
! 94: usbd_interface_handle sc_iface; /* interface */
! 95: int sc_iface_number; /* interface number */
! 96:
! 97: usbd_interface_handle sc_intr_iface; /* interrupt interface */
! 98: int sc_intr_number; /* interrupt number */
! 99: usbd_pipe_handle sc_intr_pipe; /* interrupt pipe */
! 100: u_char *sc_intr_buf; /* interrupt buffer */
! 101: int sc_isize;
! 102:
! 103: usb_cdc_line_state_t sc_line_state; /* current line state */
! 104: int sc_dtr; /* current DTR state */
! 105: int sc_rts; /* current RTS state */
! 106:
! 107: struct device *sc_subdev; /* ucom device */
! 108:
! 109: u_char sc_dying; /* disconnecting */
! 110:
! 111: u_char sc_lsr; /* Local status register */
! 112: u_char sc_msr; /* uplcom status register */
! 113: int sc_type_hx; /* HX variant */
! 114: };
! 115:
! 116: /*
! 117: * These are the maximum number of bytes transferred per frame.
! 118: * The output buffer size cannot be increased due to the size encoding.
! 119: */
! 120: #define UPLCOMIBUFSIZE 256
! 121: #define UPLCOMOBUFSIZE 256
! 122:
! 123: usbd_status uplcom_reset(struct uplcom_softc *);
! 124: usbd_status uplcom_set_line_coding(struct uplcom_softc *sc,
! 125: usb_cdc_line_state_t *state);
! 126: usbd_status uplcom_set_crtscts(struct uplcom_softc *);
! 127: void uplcom_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 128:
! 129: void uplcom_set(void *, int, int, int);
! 130: void uplcom_dtr(struct uplcom_softc *, int);
! 131: void uplcom_rts(struct uplcom_softc *, int);
! 132: void uplcom_break(struct uplcom_softc *, int);
! 133: void uplcom_set_line_state(struct uplcom_softc *);
! 134: void uplcom_get_status(void *, int portno, u_char *lsr, u_char *msr);
! 135: #if TODO
! 136: int uplcom_ioctl(void *, int, u_long, caddr_t, int, struct proc *);
! 137: #endif
! 138: int uplcom_param(void *, int, struct termios *);
! 139: int uplcom_open(void *, int);
! 140: void uplcom_close(void *, int);
! 141:
! 142: struct ucom_methods uplcom_methods = {
! 143: uplcom_get_status,
! 144: uplcom_set,
! 145: uplcom_param,
! 146: NULL, /* uplcom_ioctl, TODO */
! 147: uplcom_open,
! 148: uplcom_close,
! 149: NULL,
! 150: NULL,
! 151: };
! 152:
! 153: static const struct usb_devno uplcom_devs[] = {
! 154: { USB_VENDOR_ALCATEL, USB_PRODUCT_ALCATEL_OT535 },
! 155: { USB_VENDOR_ANCHOR, USB_PRODUCT_ANCHOR_SERIAL },
! 156: { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A },
! 157: { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U257 },
! 158: { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT },
! 159: { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0 },
! 160: { USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 },
! 161: { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ },
! 162: { USB_VENDOR_LEADTEK, USB_PRODUCT_LEADTEK_9531 },
! 163: { USB_VENDOR_MOBILEACTION, USB_PRODUCT_MOBILEACTION_MA620 },
! 164: { USB_VENDOR_NOKIA, USB_PRODUCT_NOKIA_CA42 },
! 165: { USB_VENDOR_OTI, USB_PRODUCT_OTI_DKU5 },
! 166: { USB_VENDOR_PLX, USB_PRODUCT_PLX_CA42 },
! 167: { USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_TYTP50P6S },
! 168: { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
! 169: { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X },
! 170: { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X2 },
! 171: { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 },
! 172: { USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_PL2303 },
! 173: { USB_VENDOR_RADIOSHACK, USB_PRODUCT_RADIOSHACK_PL2303 },
! 174: { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 },
! 175: { USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_SERIAL },
! 176: { USB_VENDOR_SAMSUNG2, USB_PRODUCT_SAMSUNG2_I330 },
! 177: { USB_VENDOR_SIEMENS3, USB_PRODUCT_SIEMENS3_SX1 },
! 178: { USB_VENDOR_SIEMENS3, USB_PRODUCT_SIEMENS3_X65 },
! 179: { USB_VENDOR_SIEMENS3, USB_PRODUCT_SIEMENS3_X75 },
! 180: { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_CN104 },
! 181: { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 },
! 182: { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG },
! 183: { USB_VENDOR_SPEEDDRAGON, USB_PRODUCT_SPEEDDRAGON_MS3303H },
! 184: { USB_VENDOR_SUSTEEN, USB_PRODUCT_SUSTEEN_DCU11 },
! 185: { USB_VENDOR_SYNTECH, USB_PRODUCT_SYNTECH_SERIAL },
! 186: { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 },
! 187: { USB_VENDOR_TDK, USB_PRODUCT_TDK_UPA9664 },
! 188: { USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209 }
! 189: };
! 190: #define uplcom_lookup(v, p) usb_lookup(uplcom_devs, v, p)
! 191:
! 192: int uplcom_match(struct device *, void *, void *);
! 193: void uplcom_attach(struct device *, struct device *, void *);
! 194: int uplcom_detach(struct device *, int);
! 195: int uplcom_activate(struct device *, enum devact);
! 196:
! 197: struct cfdriver uplcom_cd = {
! 198: NULL, "uplcom", DV_DULL
! 199: };
! 200:
! 201: const struct cfattach uplcom_ca = {
! 202: sizeof(struct uplcom_softc),
! 203: uplcom_match,
! 204: uplcom_attach,
! 205: uplcom_detach,
! 206: uplcom_activate,
! 207: };
! 208:
! 209: int
! 210: uplcom_match(struct device *parent, void *match, void *aux)
! 211: {
! 212: struct usb_attach_arg *uaa = aux;
! 213:
! 214: if (uaa->iface != NULL)
! 215: return (UMATCH_NONE);
! 216:
! 217: return (uplcom_lookup(uaa->vendor, uaa->product) != NULL ?
! 218: UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
! 219: }
! 220:
! 221: void
! 222: uplcom_attach(struct device *parent, struct device *self, void *aux)
! 223: {
! 224: struct uplcom_softc *sc = (struct uplcom_softc *)self;
! 225: struct usb_attach_arg *uaa = aux;
! 226: usbd_device_handle dev = uaa->device;
! 227: usb_config_descriptor_t *cdesc;
! 228: usb_device_descriptor_t *ddesc;
! 229: usb_interface_descriptor_t *id;
! 230: usb_endpoint_descriptor_t *ed;
! 231:
! 232: char *devinfop;
! 233: char *devname = sc->sc_dev.dv_xname;
! 234: usbd_status err;
! 235: int i;
! 236: struct ucom_attach_args uca;
! 237:
! 238: devinfop = usbd_devinfo_alloc(dev, 0);
! 239: printf("\n%s: %s\n", devname, devinfop);
! 240: usbd_devinfo_free(devinfop);
! 241:
! 242: sc->sc_udev = dev;
! 243:
! 244: DPRINTF(("\n\nuplcom attach: sc=%p\n", sc));
! 245:
! 246: /* initialize endpoints */
! 247: uca.bulkin = uca.bulkout = -1;
! 248: sc->sc_intr_number = -1;
! 249: sc->sc_intr_pipe = NULL;
! 250:
! 251: /* Move the device into the configured state. */
! 252: err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1);
! 253: if (err) {
! 254: printf("\n%s: failed to set configuration, err=%s\n",
! 255: devname, usbd_errstr(err));
! 256: sc->sc_dying = 1;
! 257: return;
! 258: }
! 259:
! 260: /* get the config descriptor */
! 261: cdesc = usbd_get_config_descriptor(sc->sc_udev);
! 262:
! 263: if (cdesc == NULL) {
! 264: printf("%s: failed to get configuration descriptor\n",
! 265: sc->sc_dev.dv_xname);
! 266: sc->sc_dying = 1;
! 267: return;
! 268: }
! 269:
! 270: /* get the device descriptor */
! 271: ddesc = usbd_get_device_descriptor(sc->sc_udev);
! 272: if (ddesc == NULL) {
! 273: printf("%s: failed to get device descriptor\n",
! 274: sc->sc_dev.dv_xname);
! 275: sc->sc_dying = 1;
! 276: return;
! 277: }
! 278:
! 279: /*
! 280: * The Linux driver suggest this will only be true for the HX
! 281: * variants. The datasheets disagree.
! 282: */
! 283: if (ddesc->bMaxPacketSize == 0x40) {
! 284: DPRINTF(("%s: Assuming HX variant\n", sc->sc_dev.dv_xname));
! 285: sc->sc_type_hx = 1;
! 286: } else
! 287: sc->sc_type_hx = 0;
! 288:
! 289: /* get the (first/common) interface */
! 290: err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX,
! 291: &sc->sc_iface);
! 292: if (err) {
! 293: printf("\n%s: failed to get interface, err=%s\n",
! 294: devname, usbd_errstr(err));
! 295: sc->sc_dying = 1;
! 296: return;
! 297: }
! 298:
! 299: /* Find the interrupt endpoints */
! 300:
! 301: id = usbd_get_interface_descriptor(sc->sc_iface);
! 302: sc->sc_iface_number = id->bInterfaceNumber;
! 303:
! 304: for (i = 0; i < id->bNumEndpoints; i++) {
! 305: ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
! 306: if (ed == NULL) {
! 307: printf("%s: no endpoint descriptor for %d\n",
! 308: sc->sc_dev.dv_xname, i);
! 309: sc->sc_dying = 1;
! 310: return;
! 311: }
! 312:
! 313: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 314: UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
! 315: sc->sc_intr_number = ed->bEndpointAddress;
! 316: sc->sc_isize = UGETW(ed->wMaxPacketSize);
! 317: }
! 318: }
! 319:
! 320: if (sc->sc_intr_number== -1) {
! 321: printf("%s: Could not find interrupt in\n",
! 322: sc->sc_dev.dv_xname);
! 323: sc->sc_dying = 1;
! 324: return;
! 325: }
! 326:
! 327: /* keep interface for interrupt */
! 328: sc->sc_intr_iface = sc->sc_iface;
! 329:
! 330: /*
! 331: * USB-RSAQ1 has two interface
! 332: *
! 333: * USB-RSAQ1 | USB-RSAQ2
! 334: * -----------------+-----------------
! 335: * Interface 0 |Interface 0
! 336: * Interrupt(0x81) | Interrupt(0x81)
! 337: * -----------------+ BulkIN(0x02)
! 338: * Interface 1 | BulkOUT(0x83)
! 339: * BulkIN(0x02) |
! 340: * BulkOUT(0x83) |
! 341: */
! 342: if (cdesc->bNumInterface == 2) {
! 343: err = usbd_device2interface_handle(dev,
! 344: UPLCOM_SECOND_IFACE_INDEX, &sc->sc_iface);
! 345: if (err) {
! 346: printf("\n%s: failed to get second interface, err=%s\n",
! 347: devname, usbd_errstr(err));
! 348: sc->sc_dying = 1;
! 349: return;
! 350: }
! 351: }
! 352:
! 353: /* Find the bulk{in,out} endpoints */
! 354:
! 355: id = usbd_get_interface_descriptor(sc->sc_iface);
! 356: sc->sc_iface_number = id->bInterfaceNumber;
! 357:
! 358: for (i = 0; i < id->bNumEndpoints; i++) {
! 359: ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
! 360: if (ed == NULL) {
! 361: printf("%s: no endpoint descriptor for %d\n",
! 362: sc->sc_dev.dv_xname, i);
! 363: sc->sc_dying = 1;
! 364: return;
! 365: }
! 366:
! 367: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 368: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 369: uca.bulkin = ed->bEndpointAddress;
! 370: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
! 371: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 372: uca.bulkout = ed->bEndpointAddress;
! 373: }
! 374: }
! 375:
! 376: if (uca.bulkin == -1) {
! 377: printf("%s: Could not find data bulk in\n",
! 378: sc->sc_dev.dv_xname);
! 379: sc->sc_dying = 1;
! 380: return;
! 381: }
! 382:
! 383: if (uca.bulkout == -1) {
! 384: printf("%s: Could not find data bulk out\n",
! 385: sc->sc_dev.dv_xname);
! 386: sc->sc_dying = 1;
! 387: return;
! 388: }
! 389:
! 390: sc->sc_dtr = sc->sc_rts = -1;
! 391: uca.portno = UCOM_UNK_PORTNO;
! 392: /* bulkin, bulkout set above */
! 393: uca.ibufsize = UPLCOMIBUFSIZE;
! 394: uca.obufsize = UPLCOMOBUFSIZE;
! 395: uca.ibufsizepad = UPLCOMIBUFSIZE;
! 396: uca.opkthdrlen = 0;
! 397: uca.device = dev;
! 398: uca.iface = sc->sc_iface;
! 399: uca.methods = &uplcom_methods;
! 400: uca.arg = sc;
! 401: uca.info = NULL;
! 402:
! 403: err = uplcom_reset(sc);
! 404:
! 405: if (err) {
! 406: printf("%s: reset failed, %s\n", sc->sc_dev.dv_xname,
! 407: usbd_errstr(err));
! 408: sc->sc_dying = 1;
! 409: return;
! 410: }
! 411:
! 412: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
! 413: &sc->sc_dev);
! 414:
! 415: DPRINTF(("uplcom: in=0x%x out=0x%x intr=0x%x\n",
! 416: uca.bulkin, uca.bulkout, sc->sc_intr_number ));
! 417: sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
! 418: }
! 419:
! 420: int
! 421: uplcom_detach(struct device *self, int flags)
! 422: {
! 423: struct uplcom_softc *sc = (struct uplcom_softc *)self;
! 424: int rv = 0;
! 425:
! 426: DPRINTF(("uplcom_detach: sc=%p flags=%d\n", sc, flags));
! 427:
! 428: if (sc->sc_intr_pipe != NULL) {
! 429: usbd_abort_pipe(sc->sc_intr_pipe);
! 430: usbd_close_pipe(sc->sc_intr_pipe);
! 431: free(sc->sc_intr_buf, M_USBDEV);
! 432: sc->sc_intr_pipe = NULL;
! 433: }
! 434:
! 435: sc->sc_dying = 1;
! 436: if (sc->sc_subdev != NULL) {
! 437: rv = config_detach(sc->sc_subdev, flags);
! 438: sc->sc_subdev = NULL;
! 439: }
! 440:
! 441: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 442: &sc->sc_dev);
! 443:
! 444: return (rv);
! 445: }
! 446:
! 447: int
! 448: uplcom_activate(struct device *self, enum devact act)
! 449: {
! 450: struct uplcom_softc *sc = (struct uplcom_softc *)self;
! 451: int rv = 0;
! 452:
! 453: switch (act) {
! 454: case DVACT_ACTIVATE:
! 455: break;
! 456:
! 457: case DVACT_DEACTIVATE:
! 458: if (sc->sc_subdev != NULL)
! 459: rv = config_deactivate(sc->sc_subdev);
! 460: sc->sc_dying = 1;
! 461: break;
! 462: }
! 463: return (rv);
! 464: }
! 465:
! 466: usbd_status
! 467: uplcom_reset(struct uplcom_softc *sc)
! 468: {
! 469: usb_device_request_t req;
! 470: usbd_status err;
! 471:
! 472: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 473: req.bRequest = UPLCOM_SET_REQUEST;
! 474: USETW(req.wValue, 0);
! 475: USETW(req.wIndex, sc->sc_iface_number);
! 476: USETW(req.wLength, 0);
! 477:
! 478: err = usbd_do_request(sc->sc_udev, &req, 0);
! 479: if (err)
! 480: return (EIO);
! 481:
! 482: return (0);
! 483: }
! 484:
! 485: void
! 486: uplcom_set_line_state(struct uplcom_softc *sc)
! 487: {
! 488: usb_device_request_t req;
! 489: int ls;
! 490:
! 491: /* Make sure we have initialized state for sc_dtr and sc_rts */
! 492: if (sc->sc_dtr == -1)
! 493: sc->sc_dtr = 0;
! 494: if (sc->sc_rts == -1)
! 495: sc->sc_rts = 0;
! 496:
! 497: ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) |
! 498: (sc->sc_rts ? UCDC_LINE_RTS : 0);
! 499:
! 500: req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
! 501: req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
! 502: USETW(req.wValue, ls);
! 503: USETW(req.wIndex, sc->sc_iface_number);
! 504: USETW(req.wLength, 0);
! 505:
! 506: (void)usbd_do_request(sc->sc_udev, &req, 0);
! 507:
! 508: }
! 509:
! 510: void
! 511: uplcom_set(void *addr, int portno, int reg, int onoff)
! 512: {
! 513: struct uplcom_softc *sc = addr;
! 514:
! 515: switch (reg) {
! 516: case UCOM_SET_DTR:
! 517: uplcom_dtr(sc, onoff);
! 518: break;
! 519: case UCOM_SET_RTS:
! 520: uplcom_rts(sc, onoff);
! 521: break;
! 522: case UCOM_SET_BREAK:
! 523: uplcom_break(sc, onoff);
! 524: break;
! 525: default:
! 526: break;
! 527: }
! 528: }
! 529:
! 530: void
! 531: uplcom_dtr(struct uplcom_softc *sc, int onoff)
! 532: {
! 533:
! 534: DPRINTF(("uplcom_dtr: onoff=%d\n", onoff));
! 535:
! 536: if (sc->sc_dtr != -1 && !sc->sc_dtr == !onoff)
! 537: return;
! 538:
! 539: sc->sc_dtr = !!onoff;
! 540:
! 541: uplcom_set_line_state(sc);
! 542: }
! 543:
! 544: void
! 545: uplcom_rts(struct uplcom_softc *sc, int onoff)
! 546: {
! 547: DPRINTF(("uplcom_rts: onoff=%d\n", onoff));
! 548:
! 549: if (sc->sc_rts == -1 && !sc->sc_rts == !onoff)
! 550: return;
! 551:
! 552: sc->sc_rts = !!onoff;
! 553:
! 554: uplcom_set_line_state(sc);
! 555: }
! 556:
! 557: void
! 558: uplcom_break(struct uplcom_softc *sc, int onoff)
! 559: {
! 560: usb_device_request_t req;
! 561:
! 562: DPRINTF(("uplcom_break: onoff=%d\n", onoff));
! 563:
! 564: req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
! 565: req.bRequest = UCDC_SEND_BREAK;
! 566: USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
! 567: USETW(req.wIndex, sc->sc_iface_number);
! 568: USETW(req.wLength, 0);
! 569:
! 570: (void)usbd_do_request(sc->sc_udev, &req, 0);
! 571: }
! 572:
! 573: usbd_status
! 574: uplcom_set_crtscts(struct uplcom_softc *sc)
! 575: {
! 576: usb_device_request_t req;
! 577: usbd_status err;
! 578:
! 579: DPRINTF(("uplcom_set_crtscts: on\n"));
! 580:
! 581: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 582: req.bRequest = UPLCOM_SET_REQUEST;
! 583: USETW(req.wValue, 0);
! 584: USETW(req.wIndex,
! 585: (sc->sc_type_hx ? UPLCOM_HX_SET_CRTSCTS : UPLCOM_SET_CRTSCTS));
! 586: USETW(req.wLength, 0);
! 587:
! 588: err = usbd_do_request(sc->sc_udev, &req, 0);
! 589: if (err) {
! 590: DPRINTF(("uplcom_set_crtscts: failed, err=%s\n",
! 591: usbd_errstr(err)));
! 592: return (err);
! 593: }
! 594:
! 595: return (USBD_NORMAL_COMPLETION);
! 596: }
! 597:
! 598: usbd_status
! 599: uplcom_set_line_coding(struct uplcom_softc *sc, usb_cdc_line_state_t *state)
! 600: {
! 601: usb_device_request_t req;
! 602: usbd_status err;
! 603:
! 604: DPRINTF(("uplcom_set_line_coding: rate=%d fmt=%d parity=%d bits=%d\n",
! 605: UGETDW(state->dwDTERate), state->bCharFormat,
! 606: state->bParityType, state->bDataBits));
! 607:
! 608: if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) {
! 609: DPRINTF(("uplcom_set_line_coding: already set\n"));
! 610: return (USBD_NORMAL_COMPLETION);
! 611: }
! 612:
! 613: req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
! 614: req.bRequest = UCDC_SET_LINE_CODING;
! 615: USETW(req.wValue, 0);
! 616: USETW(req.wIndex, sc->sc_iface_number);
! 617: USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
! 618:
! 619: err = usbd_do_request(sc->sc_udev, &req, state);
! 620: if (err) {
! 621: DPRINTF(("uplcom_set_line_coding: failed, err=%s\n",
! 622: usbd_errstr(err)));
! 623: return (err);
! 624: }
! 625:
! 626: sc->sc_line_state = *state;
! 627:
! 628: return (USBD_NORMAL_COMPLETION);
! 629: }
! 630:
! 631: int
! 632: uplcom_param(void *addr, int portno, struct termios *t)
! 633: {
! 634: struct uplcom_softc *sc = addr;
! 635: usbd_status err;
! 636: usb_cdc_line_state_t ls;
! 637:
! 638: DPRINTF(("uplcom_param: sc=%p\n", sc));
! 639:
! 640: USETDW(ls.dwDTERate, t->c_ospeed);
! 641: if (ISSET(t->c_cflag, CSTOPB))
! 642: ls.bCharFormat = UCDC_STOP_BIT_2;
! 643: else
! 644: ls.bCharFormat = UCDC_STOP_BIT_1;
! 645: if (ISSET(t->c_cflag, PARENB)) {
! 646: if (ISSET(t->c_cflag, PARODD))
! 647: ls.bParityType = UCDC_PARITY_ODD;
! 648: else
! 649: ls.bParityType = UCDC_PARITY_EVEN;
! 650: } else
! 651: ls.bParityType = UCDC_PARITY_NONE;
! 652: switch (ISSET(t->c_cflag, CSIZE)) {
! 653: case CS5:
! 654: ls.bDataBits = 5;
! 655: break;
! 656: case CS6:
! 657: ls.bDataBits = 6;
! 658: break;
! 659: case CS7:
! 660: ls.bDataBits = 7;
! 661: break;
! 662: case CS8:
! 663: ls.bDataBits = 8;
! 664: break;
! 665: }
! 666:
! 667: err = uplcom_set_line_coding(sc, &ls);
! 668: if (err) {
! 669: DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err)));
! 670: return (EIO);
! 671: }
! 672:
! 673: if (ISSET(t->c_cflag, CRTSCTS))
! 674: uplcom_set_crtscts(sc);
! 675:
! 676: if (sc->sc_rts == -1 || sc->sc_dtr == -1)
! 677: uplcom_set_line_state(sc);
! 678:
! 679: if (err) {
! 680: DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err)));
! 681: return (EIO);
! 682: }
! 683:
! 684: return (0);
! 685: }
! 686:
! 687: int
! 688: uplcom_open(void *addr, int portno)
! 689: {
! 690: struct uplcom_softc *sc = addr;
! 691: usb_device_request_t req;
! 692: usbd_status uerr;
! 693: int err;
! 694:
! 695: if (sc->sc_dying)
! 696: return (EIO);
! 697:
! 698: DPRINTF(("uplcom_open: sc=%p\n", sc));
! 699:
! 700: if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
! 701: sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
! 702: err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number,
! 703: USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc,
! 704: sc->sc_intr_buf, sc->sc_isize,
! 705: uplcom_intr, USBD_DEFAULT_INTERVAL);
! 706: if (err) {
! 707: DPRINTF(("%s: cannot open interrupt pipe (addr %d)\n",
! 708: sc->sc_dev.dv_xname, sc->sc_intr_number));
! 709: return (EIO);
! 710: }
! 711: }
! 712:
! 713: if (sc->sc_type_hx == 1) {
! 714: /*
! 715: * Undocumented (vendor unresponsive) - possibly changes
! 716: * flow control semantics. It is needed for HX variant devices.
! 717: */
! 718: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 719: req.bRequest = UPLCOM_SET_REQUEST;
! 720: USETW(req.wValue, 2);
! 721: USETW(req.wIndex, 0x44);
! 722: USETW(req.wLength, 0);
! 723:
! 724: uerr = usbd_do_request(sc->sc_udev, &req, 0);
! 725: if (uerr)
! 726: return (EIO);
! 727:
! 728: /* Reset upstream data pipes */
! 729: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 730: req.bRequest = UPLCOM_SET_REQUEST;
! 731: USETW(req.wValue, 8);
! 732: USETW(req.wIndex, 0);
! 733: USETW(req.wLength, 0);
! 734:
! 735: uerr = usbd_do_request(sc->sc_udev, &req, 0);
! 736: if (uerr)
! 737: return (EIO);
! 738:
! 739: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 740: req.bRequest = UPLCOM_SET_REQUEST;
! 741: USETW(req.wValue, 9);
! 742: USETW(req.wIndex, 0);
! 743: USETW(req.wLength, 0);
! 744:
! 745: uerr = usbd_do_request(sc->sc_udev, &req, 0);
! 746: if (uerr)
! 747: return (EIO);
! 748: }
! 749:
! 750: return (0);
! 751: }
! 752:
! 753: void
! 754: uplcom_close(void *addr, int portno)
! 755: {
! 756: struct uplcom_softc *sc = addr;
! 757: int err;
! 758:
! 759: if (sc->sc_dying)
! 760: return;
! 761:
! 762: DPRINTF(("uplcom_close: close\n"));
! 763:
! 764: if (sc->sc_intr_pipe != NULL) {
! 765: err = usbd_abort_pipe(sc->sc_intr_pipe);
! 766: if (err)
! 767: printf("%s: abort interrupt pipe failed: %s\n",
! 768: sc->sc_dev.dv_xname, usbd_errstr(err));
! 769: err = usbd_close_pipe(sc->sc_intr_pipe);
! 770: if (err)
! 771: printf("%s: close interrupt pipe failed: %s\n",
! 772: sc->sc_dev.dv_xname, usbd_errstr(err));
! 773: free(sc->sc_intr_buf, M_USBDEV);
! 774: sc->sc_intr_pipe = NULL;
! 775: }
! 776: }
! 777:
! 778: void
! 779: uplcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 780: {
! 781: struct uplcom_softc *sc = priv;
! 782: u_char *buf = sc->sc_intr_buf;
! 783: u_char pstatus;
! 784:
! 785: if (sc->sc_dying)
! 786: return;
! 787:
! 788: if (status != USBD_NORMAL_COMPLETION) {
! 789: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 790: return;
! 791:
! 792: DPRINTF(("%s: abnormal status: %s\n", sc->sc_dev.dv_xname,
! 793: usbd_errstr(status)));
! 794: usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
! 795: return;
! 796: }
! 797:
! 798: DPRINTF(("%s: uplcom status = %02x\n", sc->sc_dev.dv_xname, buf[8]));
! 799:
! 800: sc->sc_lsr = sc->sc_msr = 0;
! 801: pstatus = buf[8];
! 802: if (ISSET(pstatus, RSAQ_STATUS_CTS))
! 803: sc->sc_msr |= UMSR_CTS;
! 804: else
! 805: sc->sc_msr &= ~UMSR_CTS;
! 806: if (ISSET(pstatus, RSAQ_STATUS_DSR))
! 807: sc->sc_msr |= UMSR_DSR;
! 808: else
! 809: sc->sc_msr &= ~UMSR_DSR;
! 810: if (ISSET(pstatus, RSAQ_STATUS_DCD))
! 811: sc->sc_msr |= UMSR_DCD;
! 812: else
! 813: sc->sc_msr &= ~UMSR_DCD;
! 814: ucom_status_change((struct ucom_softc *) sc->sc_subdev);
! 815: }
! 816:
! 817: void
! 818: uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
! 819: {
! 820: struct uplcom_softc *sc = addr;
! 821:
! 822: DPRINTF(("uplcom_get_status:\n"));
! 823:
! 824: if (lsr != NULL)
! 825: *lsr = sc->sc_lsr;
! 826: if (msr != NULL)
! 827: *msr = sc->sc_msr;
! 828: }
! 829:
! 830: #if TODO
! 831: int
! 832: uplcom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
! 833: struct proc *p)
! 834: {
! 835: struct uplcom_softc *sc = addr;
! 836: int error = 0;
! 837:
! 838: if (sc->sc_dying)
! 839: return (EIO);
! 840:
! 841: DPRINTF(("uplcom_ioctl: cmd=0x%08lx\n", cmd));
! 842:
! 843: switch (cmd) {
! 844: case TIOCNOTTY:
! 845: case TIOCMGET:
! 846: case TIOCMSET:
! 847: case USB_GET_CM_OVER_DATA:
! 848: case USB_SET_CM_OVER_DATA:
! 849: break;
! 850:
! 851: default:
! 852: DPRINTF(("uplcom_ioctl: unknown\n"));
! 853: error = ENOTTY;
! 854: break;
! 855: }
! 856:
! 857: return (error);
! 858: }
! 859: #endif
CVSweb