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