Annotation of sys/dev/usb/umct.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: umct.c,v 1.26 2007/06/14 10:11:16 mbalmer Exp $ */
! 2: /* $NetBSD: umct.c,v 1.10 2003/02/23 04:20:07 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: * MCT USB-RS232 Interface Controller
! 41: * http://www.mct.com.tw/prod/rs232.html
! 42: * http://www.dlink.com/products/usb/dsbs25
! 43: */
! 44:
! 45: #include <sys/param.h>
! 46: #include <sys/systm.h>
! 47: #include <sys/kernel.h>
! 48: #include <sys/malloc.h>
! 49: #include <sys/ioctl.h>
! 50: #include <sys/conf.h>
! 51: #include <sys/tty.h>
! 52: #include <sys/file.h>
! 53: #include <sys/selinfo.h>
! 54: #include <sys/proc.h>
! 55: #include <sys/vnode.h>
! 56: #include <sys/device.h>
! 57: #include <sys/poll.h>
! 58:
! 59: #include <dev/usb/usb.h>
! 60: #include <dev/usb/usbcdc.h>
! 61:
! 62: #include <dev/usb/usbdi.h>
! 63: #include <dev/usb/usbdi_util.h>
! 64: #include <dev/usb/usbdevs.h>
! 65: #include <dev/usb/usb_quirks.h>
! 66:
! 67: #include <dev/usb/usbdevs.h>
! 68: #include <dev/usb/ucomvar.h>
! 69:
! 70: #include <dev/usb/umct.h>
! 71:
! 72: #ifdef UMCT_DEBUG
! 73: #define DPRINTFN(n, x) do { if (umctdebug > (n)) printf x; } while (0)
! 74: int umctdebug = 0;
! 75: #else
! 76: #define DPRINTFN(n, x)
! 77: #endif
! 78: #define DPRINTF(x) DPRINTFN(0, x)
! 79:
! 80: #define UMCT_CONFIG_INDEX 0
! 81: #define UMCT_IFACE_INDEX 0
! 82:
! 83: struct umct_softc {
! 84: struct device sc_dev; /* base device */
! 85: usbd_device_handle sc_udev; /* USB device */
! 86: usbd_interface_handle sc_iface; /* interface */
! 87: int sc_iface_number; /* interface number */
! 88: u_int16_t sc_product;
! 89:
! 90: int sc_intr_number; /* interrupt number */
! 91: usbd_pipe_handle sc_intr_pipe; /* interrupt pipe */
! 92: u_char *sc_intr_buf; /* interrupt buffer */
! 93: int sc_isize;
! 94:
! 95: usb_cdc_line_state_t sc_line_state; /* current line state */
! 96: u_char sc_dtr; /* current DTR state */
! 97: u_char sc_rts; /* current RTS state */
! 98: u_char sc_break; /* set break */
! 99:
! 100: u_char sc_status;
! 101:
! 102: struct device *sc_subdev; /* ucom device */
! 103:
! 104: u_char sc_dying; /* disconnecting */
! 105:
! 106: u_char sc_lsr; /* Local status register */
! 107: u_char sc_msr; /* umct status register */
! 108:
! 109: u_int last_lcr; /* keep lcr register */
! 110: };
! 111:
! 112: /*
! 113: * These are the maximum number of bytes transferred per frame.
! 114: * The output buffer size cannot be increased due to the size encoding.
! 115: */
! 116: #define UMCTIBUFSIZE 256
! 117: #define UMCTOBUFSIZE 256
! 118:
! 119: void umct_init(struct umct_softc *);
! 120: void umct_set_baudrate(struct umct_softc *, u_int);
! 121: void umct_set_lcr(struct umct_softc *, u_int);
! 122: void umct_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 123:
! 124: void umct_set(void *, int, int, int);
! 125: void umct_dtr(struct umct_softc *, int);
! 126: void umct_rts(struct umct_softc *, int);
! 127: void umct_break(struct umct_softc *, int);
! 128: void umct_set_line_state(struct umct_softc *);
! 129: void umct_get_status(void *, int portno, u_char *lsr, u_char *msr);
! 130: int umct_param(void *, int, struct termios *);
! 131: int umct_open(void *, int);
! 132: void umct_close(void *, int);
! 133:
! 134: struct ucom_methods umct_methods = {
! 135: umct_get_status,
! 136: umct_set,
! 137: umct_param,
! 138: NULL,
! 139: umct_open,
! 140: umct_close,
! 141: NULL,
! 142: NULL,
! 143: };
! 144:
! 145: static const struct usb_devno umct_devs[] = {
! 146: /* MCT USB-232 Interface Products */
! 147: { USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232 },
! 148: /* Sitecom USB-232 Products */
! 149: { USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232 },
! 150: /* D-Link DU-H3SP USB BAY Hub Products */
! 151: { USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232 },
! 152: /* BELKIN F5U109 */
! 153: { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U109 },
! 154: /* BELKIN F5U409 */
! 155: { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U409 },
! 156: };
! 157: #define umct_lookup(v, p) usb_lookup(umct_devs, v, p)
! 158:
! 159: int umct_match(struct device *, void *, void *);
! 160: void umct_attach(struct device *, struct device *, void *);
! 161: int umct_detach(struct device *, int);
! 162: int umct_activate(struct device *, enum devact);
! 163:
! 164: struct cfdriver umct_cd = {
! 165: NULL, "umct", DV_DULL
! 166: };
! 167:
! 168: const struct cfattach umct_ca = {
! 169: sizeof(struct umct_softc),
! 170: umct_match,
! 171: umct_attach,
! 172: umct_detach,
! 173: umct_activate,
! 174: };
! 175:
! 176: int
! 177: umct_match(struct device *parent, void *match, void *aux)
! 178: {
! 179: struct usb_attach_arg *uaa = aux;
! 180:
! 181: if (uaa->iface != NULL)
! 182: return (UMATCH_NONE);
! 183:
! 184: return (umct_lookup(uaa->vendor, uaa->product) != NULL ?
! 185: UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
! 186: }
! 187:
! 188: void
! 189: umct_attach(struct device *parent, struct device *self, void *aux)
! 190: {
! 191: struct umct_softc *sc = (struct umct_softc *)self;
! 192: struct usb_attach_arg *uaa = aux;
! 193: usbd_device_handle dev = uaa->device;
! 194: usb_config_descriptor_t *cdesc;
! 195: usb_interface_descriptor_t *id;
! 196: usb_endpoint_descriptor_t *ed;
! 197:
! 198: char *devinfop;
! 199: char *devname = sc->sc_dev.dv_xname;
! 200: usbd_status err;
! 201: int i;
! 202: struct ucom_attach_args uca;
! 203:
! 204: devinfop = usbd_devinfo_alloc(dev, 0);
! 205: printf("\n%s: %s\n", devname, devinfop);
! 206: usbd_devinfo_free(devinfop);
! 207:
! 208: sc->sc_udev = dev;
! 209: sc->sc_product = uaa->product;
! 210:
! 211: DPRINTF(("\n\numct attach: sc=%p\n", sc));
! 212:
! 213: /* initialize endpoints */
! 214: uca.bulkin = uca.bulkout = -1;
! 215: sc->sc_intr_number = -1;
! 216: sc->sc_intr_pipe = NULL;
! 217:
! 218: /* Move the device into the configured state. */
! 219: err = usbd_set_config_index(dev, UMCT_CONFIG_INDEX, 1);
! 220: if (err) {
! 221: printf("\n%s: failed to set configuration, err=%s\n",
! 222: devname, usbd_errstr(err));
! 223: sc->sc_dying = 1;
! 224: return;
! 225: }
! 226:
! 227: /* get the config descriptor */
! 228: cdesc = usbd_get_config_descriptor(sc->sc_udev);
! 229:
! 230: if (cdesc == NULL) {
! 231: printf("%s: failed to get configuration descriptor\n",
! 232: sc->sc_dev.dv_xname);
! 233: sc->sc_dying = 1;
! 234: return;
! 235: }
! 236:
! 237: /* get the interface */
! 238: err = usbd_device2interface_handle(dev, UMCT_IFACE_INDEX,
! 239: &sc->sc_iface);
! 240: if (err) {
! 241: printf("\n%s: failed to get interface, err=%s\n",
! 242: devname, usbd_errstr(err));
! 243: sc->sc_dying = 1;
! 244: return;
! 245: }
! 246:
! 247: /* Find the bulk{in,out} and interrupt endpoints */
! 248:
! 249: id = usbd_get_interface_descriptor(sc->sc_iface);
! 250: sc->sc_iface_number = id->bInterfaceNumber;
! 251:
! 252: for (i = 0; i < id->bNumEndpoints; i++) {
! 253: ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
! 254: if (ed == NULL) {
! 255: printf("%s: no endpoint descriptor for %d\n",
! 256: sc->sc_dev.dv_xname, i);
! 257: sc->sc_dying = 1;
! 258: return;
! 259: }
! 260:
! 261: /*
! 262: * The Bulkin endpoint is marked as an interrupt. Since
! 263: * we can't rely on the endpoint descriptor order, we'll
! 264: * check the wMaxPacketSize field to differentiate.
! 265: */
! 266: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 267: UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT &&
! 268: UGETW(ed->wMaxPacketSize) != 0x2) {
! 269: uca.bulkin = ed->bEndpointAddress;
! 270: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
! 271: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 272: uca.bulkout = ed->bEndpointAddress;
! 273: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 274: UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
! 275: sc->sc_intr_number = ed->bEndpointAddress;
! 276: sc->sc_isize = UGETW(ed->wMaxPacketSize);
! 277: }
! 278: }
! 279:
! 280: if (uca.bulkin == -1) {
! 281: printf("%s: Could not find data bulk in\n",
! 282: sc->sc_dev.dv_xname);
! 283: sc->sc_dying = 1;
! 284: return;
! 285: }
! 286:
! 287: if (uca.bulkout == -1) {
! 288: printf("%s: Could not find data bulk out\n",
! 289: sc->sc_dev.dv_xname);
! 290: sc->sc_dying = 1;
! 291: return;
! 292: }
! 293:
! 294: if (sc->sc_intr_number== -1) {
! 295: printf("%s: Could not find interrupt in\n",
! 296: sc->sc_dev.dv_xname);
! 297: sc->sc_dying = 1;
! 298: return;
! 299: }
! 300:
! 301: sc->sc_dtr = sc->sc_rts = 0;
! 302: uca.portno = UCOM_UNK_PORTNO;
! 303: /* bulkin, bulkout set above */
! 304: uca.ibufsize = UMCTIBUFSIZE;
! 305: if (sc->sc_product == USB_PRODUCT_MCT_SITECOM_USB232)
! 306: uca.obufsize = 16; /* device is broken */
! 307: else
! 308: uca.obufsize = UMCTOBUFSIZE;
! 309: uca.ibufsizepad = UMCTIBUFSIZE;
! 310: uca.opkthdrlen = 0;
! 311: uca.device = dev;
! 312: uca.iface = sc->sc_iface;
! 313: uca.methods = &umct_methods;
! 314: uca.arg = sc;
! 315: uca.info = NULL;
! 316:
! 317: umct_init(sc);
! 318:
! 319: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
! 320: &sc->sc_dev);
! 321:
! 322: DPRINTF(("umct: in=0x%x out=0x%x intr=0x%x\n",
! 323: uca.bulkin, uca.bulkout, sc->sc_intr_number ));
! 324: sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
! 325: }
! 326:
! 327: int
! 328: umct_detach(struct device *self, int flags)
! 329: {
! 330: struct umct_softc *sc = (struct umct_softc *)self;
! 331: int rv = 0;
! 332:
! 333: DPRINTF(("umct_detach: sc=%p flags=%d\n", sc, flags));
! 334:
! 335: if (sc->sc_intr_pipe != NULL) {
! 336: usbd_abort_pipe(sc->sc_intr_pipe);
! 337: usbd_close_pipe(sc->sc_intr_pipe);
! 338: free(sc->sc_intr_buf, M_USBDEV);
! 339: sc->sc_intr_pipe = NULL;
! 340: }
! 341:
! 342: sc->sc_dying = 1;
! 343: if (sc->sc_subdev != NULL) {
! 344: rv = config_detach(sc->sc_subdev, flags);
! 345: sc->sc_subdev = NULL;
! 346: }
! 347:
! 348: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 349: &sc->sc_dev);
! 350:
! 351: return (rv);
! 352: }
! 353:
! 354: int
! 355: umct_activate(struct device *self, enum devact act)
! 356: {
! 357: struct umct_softc *sc = (struct umct_softc *)self;
! 358: int rv = 0;
! 359:
! 360: switch (act) {
! 361: case DVACT_ACTIVATE:
! 362: break;
! 363:
! 364: case DVACT_DEACTIVATE:
! 365: if (sc->sc_subdev != NULL)
! 366: rv = config_deactivate(sc->sc_subdev);
! 367: sc->sc_dying = 1;
! 368: break;
! 369: }
! 370: return (rv);
! 371: }
! 372:
! 373: void
! 374: umct_set_line_state(struct umct_softc *sc)
! 375: {
! 376: usb_device_request_t req;
! 377: uByte ls;
! 378:
! 379: ls = (sc->sc_dtr ? MCR_DTR : 0) |
! 380: (sc->sc_rts ? MCR_RTS : 0);
! 381:
! 382: DPRINTF(("umct_set_line_state: DTR=%d,RTS=%d,ls=%02x\n",
! 383: sc->sc_dtr, sc->sc_rts, ls));
! 384:
! 385: req.bmRequestType = UMCT_SET_REQUEST;
! 386: req.bRequest = REQ_SET_MCR;
! 387: USETW(req.wValue, 0);
! 388: USETW(req.wIndex, sc->sc_iface_number);
! 389: USETW(req.wLength, LENGTH_SET_MCR);
! 390:
! 391: (void)usbd_do_request(sc->sc_udev, &req, &ls);
! 392: }
! 393:
! 394: void
! 395: umct_set(void *addr, int portno, int reg, int onoff)
! 396: {
! 397: struct umct_softc *sc = addr;
! 398:
! 399: switch (reg) {
! 400: case UCOM_SET_DTR:
! 401: umct_dtr(sc, onoff);
! 402: break;
! 403: case UCOM_SET_RTS:
! 404: umct_rts(sc, onoff);
! 405: break;
! 406: case UCOM_SET_BREAK:
! 407: umct_break(sc, onoff);
! 408: break;
! 409: default:
! 410: break;
! 411: }
! 412: }
! 413:
! 414: void
! 415: umct_dtr(struct umct_softc *sc, int onoff)
! 416: {
! 417:
! 418: DPRINTF(("umct_dtr: onoff=%d\n", onoff));
! 419:
! 420: if (sc->sc_dtr == onoff)
! 421: return;
! 422: sc->sc_dtr = onoff;
! 423:
! 424: umct_set_line_state(sc);
! 425: }
! 426:
! 427: void
! 428: umct_rts(struct umct_softc *sc, int onoff)
! 429: {
! 430: DPRINTF(("umct_rts: onoff=%d\n", onoff));
! 431:
! 432: if (sc->sc_rts == onoff)
! 433: return;
! 434: sc->sc_rts = onoff;
! 435:
! 436: umct_set_line_state(sc);
! 437: }
! 438:
! 439: void
! 440: umct_break(struct umct_softc *sc, int onoff)
! 441: {
! 442: DPRINTF(("umct_break: onoff=%d\n", onoff));
! 443:
! 444: umct_set_lcr(sc, onoff ? sc->last_lcr | LCR_SET_BREAK :
! 445: sc->last_lcr);
! 446: }
! 447:
! 448: void
! 449: umct_set_lcr(struct umct_softc *sc, u_int data)
! 450: {
! 451: usb_device_request_t req;
! 452: uByte adata;
! 453:
! 454: adata = data;
! 455: req.bmRequestType = UMCT_SET_REQUEST;
! 456: req.bRequest = REQ_SET_LCR;
! 457: USETW(req.wValue, 0);
! 458: USETW(req.wIndex, sc->sc_iface_number);
! 459: USETW(req.wLength, LENGTH_SET_LCR);
! 460:
! 461: /* XXX should check */
! 462: (void)usbd_do_request(sc->sc_udev, &req, &adata);
! 463: }
! 464:
! 465: void
! 466: umct_set_baudrate(struct umct_softc *sc, u_int rate)
! 467: {
! 468: usb_device_request_t req;
! 469: uDWord arate;
! 470: u_int val;
! 471:
! 472: if (sc->sc_product == USB_PRODUCT_MCT_SITECOM_USB232 ||
! 473: sc->sc_product == USB_PRODUCT_BELKIN_F5U109) {
! 474: switch (rate) {
! 475: case 300: val = 0x01; break;
! 476: case 600: val = 0x02; break;
! 477: case 1200: val = 0x03; break;
! 478: case 2400: val = 0x04; break;
! 479: case 4800: val = 0x06; break;
! 480: case 9600: val = 0x08; break;
! 481: case 19200: val = 0x09; break;
! 482: case 38400: val = 0x0a; break;
! 483: case 57600: val = 0x0b; break;
! 484: case 115200: val = 0x0c; break;
! 485: default: val = -1; break;
! 486: }
! 487: } else {
! 488: val = UMCT_BAUD_RATE(rate);
! 489: }
! 490: USETDW(arate, val);
! 491:
! 492: req.bmRequestType = UMCT_SET_REQUEST;
! 493: req.bRequest = REQ_SET_BAUD_RATE;
! 494: USETW(req.wValue, 0);
! 495: USETW(req.wIndex, sc->sc_iface_number);
! 496: USETW(req.wLength, LENGTH_BAUD_RATE);
! 497:
! 498: /* XXX should check */
! 499: (void)usbd_do_request(sc->sc_udev, &req, arate);
! 500: }
! 501:
! 502: void
! 503: umct_init(struct umct_softc *sc)
! 504: {
! 505: umct_set_baudrate(sc, 9600);
! 506: umct_set_lcr(sc, LCR_DATA_BITS_8 | LCR_PARITY_NONE | LCR_STOP_BITS_1);
! 507: }
! 508:
! 509: int
! 510: umct_param(void *addr, int portno, struct termios *t)
! 511: {
! 512: struct umct_softc *sc = addr;
! 513: u_int data = 0;
! 514:
! 515: DPRINTF(("umct_param: sc=%p\n", sc));
! 516:
! 517: DPRINTF(("umct_param: BAUDRATE=%d\n", t->c_ospeed));
! 518:
! 519: if (ISSET(t->c_cflag, CSTOPB))
! 520: data |= LCR_STOP_BITS_2;
! 521: else
! 522: data |= LCR_STOP_BITS_1;
! 523: if (ISSET(t->c_cflag, PARENB)) {
! 524: if (ISSET(t->c_cflag, PARODD))
! 525: data |= LCR_PARITY_ODD;
! 526: else
! 527: data |= LCR_PARITY_EVEN;
! 528: } else
! 529: data |= LCR_PARITY_NONE;
! 530: switch (ISSET(t->c_cflag, CSIZE)) {
! 531: case CS5:
! 532: data |= LCR_DATA_BITS_5;
! 533: break;
! 534: case CS6:
! 535: data |= LCR_DATA_BITS_6;
! 536: break;
! 537: case CS7:
! 538: data |= LCR_DATA_BITS_7;
! 539: break;
! 540: case CS8:
! 541: data |= LCR_DATA_BITS_8;
! 542: break;
! 543: }
! 544:
! 545: umct_set_baudrate(sc, t->c_ospeed);
! 546:
! 547: sc->last_lcr = data;
! 548: umct_set_lcr(sc, data);
! 549:
! 550: return (0);
! 551: }
! 552:
! 553: int
! 554: umct_open(void *addr, int portno)
! 555: {
! 556: struct umct_softc *sc = addr;
! 557: int err, lcr_data;
! 558:
! 559: if (sc->sc_dying)
! 560: return (EIO);
! 561:
! 562: DPRINTF(("umct_open: sc=%p\n", sc));
! 563:
! 564: /* initialize LCR */
! 565: lcr_data = LCR_DATA_BITS_8 | LCR_PARITY_NONE |
! 566: LCR_STOP_BITS_1;
! 567: umct_set_lcr(sc, lcr_data);
! 568:
! 569: if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
! 570: sc->sc_status = 0; /* clear status bit */
! 571: sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
! 572: err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_intr_number,
! 573: USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc,
! 574: sc->sc_intr_buf, sc->sc_isize,
! 575: umct_intr, USBD_DEFAULT_INTERVAL);
! 576: if (err) {
! 577: DPRINTF(("%s: cannot open interrupt pipe (addr %d)\n",
! 578: sc->sc_dev.dv_xname, sc->sc_intr_number));
! 579: return (EIO);
! 580: }
! 581: }
! 582:
! 583: return (0);
! 584: }
! 585:
! 586: void
! 587: umct_close(void *addr, int portno)
! 588: {
! 589: struct umct_softc *sc = addr;
! 590: int err;
! 591:
! 592: if (sc->sc_dying)
! 593: return;
! 594:
! 595: DPRINTF(("umct_close: close\n"));
! 596:
! 597: if (sc->sc_intr_pipe != NULL) {
! 598: err = usbd_abort_pipe(sc->sc_intr_pipe);
! 599: if (err)
! 600: printf("%s: abort interrupt pipe failed: %s\n",
! 601: sc->sc_dev.dv_xname, usbd_errstr(err));
! 602: err = usbd_close_pipe(sc->sc_intr_pipe);
! 603: if (err)
! 604: printf("%s: close interrupt pipe failed: %s\n",
! 605: sc->sc_dev.dv_xname, usbd_errstr(err));
! 606: free(sc->sc_intr_buf, M_USBDEV);
! 607: sc->sc_intr_pipe = NULL;
! 608: }
! 609: }
! 610:
! 611: void
! 612: umct_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 613: {
! 614: struct umct_softc *sc = priv;
! 615: u_char *buf = sc->sc_intr_buf;
! 616: u_char mstatus;
! 617:
! 618: if (sc->sc_dying)
! 619: return;
! 620:
! 621: if (status != USBD_NORMAL_COMPLETION) {
! 622: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 623: return;
! 624:
! 625: DPRINTF(("%s: abnormal status: %s\n", sc->sc_dev.dv_xname,
! 626: usbd_errstr(status)));
! 627: usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
! 628: return;
! 629: }
! 630:
! 631: DPRINTF(("%s: umct status = MSR:%02x, LSR:%02x\n",
! 632: sc->sc_dev.dv_xname, buf[0],buf[1]));
! 633:
! 634: sc->sc_lsr = sc->sc_msr = 0;
! 635: mstatus = buf[0];
! 636: if (ISSET(mstatus, MSR_DSR))
! 637: sc->sc_msr |= UMSR_DSR;
! 638: if (ISSET(mstatus, MSR_DCD))
! 639: sc->sc_msr |= UMSR_DCD;
! 640: ucom_status_change((struct ucom_softc *)sc->sc_subdev);
! 641: }
! 642:
! 643: void
! 644: umct_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
! 645: {
! 646: struct umct_softc *sc = addr;
! 647:
! 648: DPRINTF(("umct_get_status:\n"));
! 649:
! 650: if (lsr != NULL)
! 651: *lsr = sc->sc_lsr;
! 652: if (msr != NULL)
! 653: *msr = sc->sc_msr;
! 654: }
CVSweb