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