1 /* $NetBSD: uplcom.c,v 1.90 2021/04/24 23:36:59 thorpej Exp $ */ 2 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 * General information: http://www.prolific.com.tw/fr_pl2303.htm 34 * http://www.hitachi-hitec.com/jyouhou/prolific/2303.pdf 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: uplcom.c,v 1.90 2021/04/24 23:36:59 thorpej Exp $"); 39 40 #ifdef _KERNEL_OPT 41 #include "opt_usb.h" 42 #endif 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/kmem.h> 48 #include <sys/ioctl.h> 49 #include <sys/conf.h> 50 #include <sys/tty.h> 51 #include <sys/file.h> 52 #include <sys/select.h> 53 #include <sys/proc.h> 54 #include <sys/device.h> 55 #include <sys/poll.h> 56 #include <sys/sysctl.h> 57 58 #include <dev/usb/usb.h> 59 #include <dev/usb/usbcdc.h> 60 61 #include <dev/usb/usbdi.h> 62 #include <dev/usb/usbdi_util.h> 63 #include <dev/usb/usbdevs.h> 64 #include <dev/usb/usb_quirks.h> 65 #include <dev/usb/usbhist.h> 66 67 #include <dev/usb/ucomvar.h> 68 69 #ifdef USB_DEBUG 70 #ifndef UPLCOM_DEBUG 71 #define uplcomdebug 0 72 #else 73 int uplcomdebug = 0; 74 75 SYSCTL_SETUP(sysctl_hw_uplcom_setup, "sysctl hw.uplcom setup") 76 { 77 int err; 78 const struct sysctlnode *rnode; 79 const struct sysctlnode *cnode; 80 81 err = sysctl_createv(clog, 0, NULL, &rnode, 82 CTLFLAG_PERMANENT, CTLTYPE_NODE, "uplcom", 83 SYSCTL_DESCR("uplcom global controls"), 84 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); 85 86 if (err) 87 goto fail; 88 89 /* control debugging printfs */ 90 err = sysctl_createv(clog, 0, &rnode, &cnode, 91 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 92 "debug", SYSCTL_DESCR("Enable debugging output"), 93 NULL, 0, &uplcomdebug, sizeof(uplcomdebug), CTL_CREATE, CTL_EOL); 94 if (err) 95 goto fail; 96 97 return; 98 fail: 99 aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); 100 } 101 102 #endif /* UCOM_DEBUG */ 103 #endif /* USB_DEBUG */ 104 105 106 #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(uplcomdebug,1,FMT,A,B,C,D) 107 #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(uplcomdebug,N,FMT,A,B,C,D) 108 #define UPLCOMHIST_FUNC() USBHIST_FUNC() 109 #define UPLCOMHIST_CALLED(name) USBHIST_CALLED(uplcomdebug) 110 111 #define UPLCOM_CONFIG_INDEX 0 112 #define UPLCOM_IFACE_INDEX 0 113 #define UPLCOM_SECOND_IFACE_INDEX 1 114 115 #define UPLCOM_SET_REQUEST 0x01 116 #define UPLCOM_SET_CRTSCTS_0 0x41 117 #define UPLCOM_SET_CRTSCTS_HX 0x61 118 119 #define UPLCOM_N_SERIAL_CTS 0x80 120 121 enum pl2303_type { 122 UPLCOM_TYPE_0, /* we use this for all non-HX variants */ 123 UPLCOM_TYPE_HX, 124 }; 125 126 struct uplcom_softc { 127 device_t sc_dev; /* base device */ 128 struct usbd_device * sc_udev; /* USB device */ 129 struct usbd_interface * sc_iface; /* interface */ 130 int sc_iface_number; /* interface number */ 131 132 struct usbd_interface * sc_intr_iface; /* interrupt interface */ 133 int sc_intr_number; /* interrupt number */ 134 struct usbd_pipe * sc_intr_pipe; /* interrupt pipe */ 135 u_char *sc_intr_buf; /* interrupt buffer */ 136 int sc_isize; 137 138 usb_cdc_line_state_t sc_line_state; /* current line state */ 139 int sc_dtr; /* current DTR state */ 140 int sc_rts; /* current RTS state */ 141 142 device_t sc_subdev; /* ucom device */ 143 144 bool sc_dying; /* disconnecting */ 145 146 u_char sc_lsr; /* Local status register */ 147 u_char sc_msr; /* uplcom status register */ 148 149 enum pl2303_type sc_type; /* PL2303 chip type */ 150 }; 151 152 /* 153 * These are the maximum number of bytes transferred per frame. 154 * The output buffer size cannot be increased due to the size encoding. 155 */ 156 #define UPLCOMIBUFSIZE 256 157 #define UPLCOMOBUFSIZE 256 158 159 static usbd_status uplcom_reset(struct uplcom_softc *); 160 static usbd_status uplcom_set_line_coding(struct uplcom_softc *, 161 usb_cdc_line_state_t *); 162 static usbd_status uplcom_set_crtscts(struct uplcom_softc *); 163 static void uplcom_intr(struct usbd_xfer *, void *, usbd_status); 164 165 static void uplcom_set(void *, int, int, int); 166 static void uplcom_dtr(struct uplcom_softc *, int); 167 static void uplcom_rts(struct uplcom_softc *, int); 168 static void uplcom_break(struct uplcom_softc *, int); 169 static void uplcom_set_line_state(struct uplcom_softc *); 170 static void uplcom_get_status(void *, int, u_char *, u_char *); 171 #if TODO 172 static int uplcom_ioctl(void *, int, u_long, void *, int, proc_t *); 173 #endif 174 static int uplcom_param(void *, int, struct termios *); 175 static int uplcom_open(void *, int); 176 static void uplcom_close(void *, int); 177 static usbd_status uplcom_vendor_control_write(struct usbd_device *, uint16_t, uint16_t); 178 static void uplcom_close_pipe(struct uplcom_softc *); 179 180 static const struct ucom_methods uplcom_methods = { 181 .ucom_get_status = uplcom_get_status, 182 .ucom_set = uplcom_set, 183 .ucom_param = uplcom_param, 184 .ucom_ioctl = NULL, /* TODO */ 185 .ucom_open = uplcom_open, 186 .ucom_close = uplcom_close, 187 }; 188 189 static const struct usb_devno uplcom_devs[] = { 190 /* I/O DATA USB-RSAQ2 */ 191 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 }, 192 /* I/O DATA USB-RSAQ3 */ 193 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3 }, 194 /* I/O DATA USB-RSAQ */ 195 { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ }, 196 /* I/O DATA USB-RSAQ5 */ 197 { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ5 }, 198 /* PLANEX USB-RS232 URS-03 */ 199 { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A }, 200 /* various */ 201 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 }, 202 /* SMART Technologies USB to serial */ 203 { USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_PL2303 }, 204 /* IOGEAR/ATENTRIPPLITE */ 205 { USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209 }, 206 /* ELECOM UC-SGT */ 207 { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT }, 208 /* ELECOM UC-SGT0 */ 209 { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0 }, 210 /* Panasonic 50" Touch Panel */ 211 { USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_TYTP50P6S }, 212 /* RATOC REX-USB60 */ 213 { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 }, 214 /* TDK USB-PHS Adapter UHA6400 */ 215 { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 }, 216 /* TDK USB-PDC Adapter UPA9664 */ 217 { USB_VENDOR_TDK, USB_PRODUCT_TDK_UPA9664 }, 218 /* Sony Ericsson USB Cable */ 219 { USB_VENDOR_SUSTEEN, USB_PRODUCT_SUSTEEN_DCU10 }, 220 /* SOURCENEXT KeikaiDenwa 8 */ 221 { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 }, 222 /* SOURCENEXT KeikaiDenwa 8 with charger */ 223 { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG }, 224 /* HAL Corporation Crossam2+USB */ 225 { USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 }, 226 /* Sitecom USB to serial cable */ 227 { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_CN104 }, 228 /* Pharos USB GPS - Microsoft version */ 229 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X }, 230 /* Willcom WS002IN (DD) */ 231 { USB_VENDOR_NETINDEX, USB_PRODUCT_NETINDEX_WS002IN }, 232 /* COREGA CG-USBRS232R */ 233 { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_CGUSBRS232R }, 234 /* Sharp CE-175TU (USB to Zaurus option port 15 adapter) */ 235 { USB_VENDOR_SHARP, USB_PRODUCT_SHARP_CE175TU }, 236 }; 237 #define uplcom_lookup(v, p) usb_lookup(uplcom_devs, v, p) 238 239 static int uplcom_match(device_t, cfdata_t, void *); 240 static void uplcom_attach(device_t, device_t, void *); 241 static void uplcom_childdet(device_t, device_t); 242 static int uplcom_detach(device_t, int); 243 244 CFATTACH_DECL2_NEW(uplcom, sizeof(struct uplcom_softc), uplcom_match, 245 uplcom_attach, uplcom_detach, NULL, NULL, uplcom_childdet); 246 247 static int 248 uplcom_match(device_t parent, cfdata_t match, void *aux) 249 { 250 struct usb_attach_arg *uaa = aux; 251 252 return uplcom_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? 253 UMATCH_VENDOR_PRODUCT : UMATCH_NONE; 254 } 255 256 static void 257 uplcom_attach(device_t parent, device_t self, void *aux) 258 { 259 struct uplcom_softc *sc = device_private(self); 260 struct usb_attach_arg *uaa = aux; 261 struct usbd_device *dev = uaa->uaa_device; 262 usb_device_descriptor_t *ddesc; 263 usb_config_descriptor_t *cdesc; 264 usb_interface_descriptor_t *id; 265 usb_endpoint_descriptor_t *ed; 266 char *devinfop; 267 const char *devname = device_xname(self); 268 usbd_status err; 269 int i; 270 struct ucom_attach_args ucaa; 271 272 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 273 DPRINTF("sc=%#jx", (uintptr_t)sc, 0, 0, 0); 274 275 sc->sc_dev = self; 276 sc->sc_dying = false; 277 278 aprint_naive("\n"); 279 aprint_normal("\n"); 280 281 devinfop = usbd_devinfo_alloc(dev, 0); 282 aprint_normal_dev(self, "%s\n", devinfop); 283 usbd_devinfo_free(devinfop); 284 285 sc->sc_udev = dev; 286 287 /* initialize endpoints */ 288 ucaa.ucaa_bulkin = ucaa.ucaa_bulkout = -1; 289 sc->sc_intr_number = -1; 290 sc->sc_intr_pipe = NULL; 291 292 /* Move the device into the configured state. */ 293 err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1); 294 if (err) { 295 aprint_error("\n%s: failed to set configuration, err=%s\n", 296 devname, usbd_errstr(err)); 297 sc->sc_dying = true; 298 return; 299 } 300 301 /* determine chip type */ 302 ddesc = usbd_get_device_descriptor(dev); 303 if (ddesc->bDeviceClass != UDCLASS_COMM && 304 ddesc->bMaxPacketSize == 0x40) 305 sc->sc_type = UPLCOM_TYPE_HX; 306 307 #ifdef UPLCOM_DEBUG 308 /* print the chip type */ 309 if (sc->sc_type == UPLCOM_TYPE_HX) { 310 DPRINTF("chiptype HX", 0, 0, 0, 0); 311 } else { 312 DPRINTF("chiptype 0", 0, 0, 0, 0); 313 } 314 #endif 315 316 /* Move the device into the configured state. */ 317 err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1); 318 if (err) { 319 aprint_error_dev(self, "failed to set configuration: %s\n", 320 usbd_errstr(err)); 321 sc->sc_dying = true; 322 return; 323 } 324 325 /* get the config descriptor */ 326 cdesc = usbd_get_config_descriptor(sc->sc_udev); 327 328 if (cdesc == NULL) { 329 aprint_error_dev(self, 330 "failed to get configuration descriptor\n"); 331 sc->sc_dying = true; 332 return; 333 } 334 335 /* get the (first/common) interface */ 336 err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX, 337 &sc->sc_iface); 338 if (err) { 339 aprint_error("\n%s: failed to get interface, err=%s\n", 340 devname, usbd_errstr(err)); 341 sc->sc_dying = true; 342 return; 343 } 344 345 /* Find the interrupt endpoints */ 346 347 id = usbd_get_interface_descriptor(sc->sc_iface); 348 sc->sc_iface_number = id->bInterfaceNumber; 349 350 for (i = 0; i < id->bNumEndpoints; i++) { 351 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 352 if (ed == NULL) { 353 aprint_error_dev(self, 354 "no endpoint descriptor for %d\n", i); 355 sc->sc_dying = true; 356 return; 357 } 358 359 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 360 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 361 sc->sc_intr_number = ed->bEndpointAddress; 362 sc->sc_isize = UGETW(ed->wMaxPacketSize); 363 } 364 } 365 366 if (sc->sc_intr_number== -1) { 367 aprint_error_dev(self, "Could not find interrupt in\n"); 368 sc->sc_dying = true; 369 return; 370 } 371 372 /* keep interface for interrupt */ 373 sc->sc_intr_iface = sc->sc_iface; 374 375 /* 376 * USB-RSAQ1 has two interface 377 * 378 * USB-RSAQ1 | USB-RSAQ2 379 * -----------------+----------------- 380 * Interface 0 |Interface 0 381 * Interrupt(0x81) | Interrupt(0x81) 382 * -----------------+ BulkIN(0x02) 383 * Interface 1 | BulkOUT(0x83) 384 * BulkIN(0x02) | 385 * BulkOUT(0x83) | 386 */ 387 if (cdesc->bNumInterface == 2) { 388 err = usbd_device2interface_handle(dev, 389 UPLCOM_SECOND_IFACE_INDEX, &sc->sc_iface); 390 if (err) { 391 aprint_error("\n%s: failed to get second interface, " 392 "err=%s\n", devname, usbd_errstr(err)); 393 sc->sc_dying = true; 394 return; 395 } 396 } 397 398 /* Find the bulk{in,out} endpoints */ 399 400 id = usbd_get_interface_descriptor(sc->sc_iface); 401 sc->sc_iface_number = id->bInterfaceNumber; 402 403 for (i = 0; i < id->bNumEndpoints; i++) { 404 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 405 if (ed == NULL) { 406 aprint_error_dev(self, 407 "no endpoint descriptor for %d\n", i); 408 sc->sc_dying = true; 409 return; 410 } 411 412 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 413 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 414 ucaa.ucaa_bulkin = ed->bEndpointAddress; 415 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 416 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 417 ucaa.ucaa_bulkout = ed->bEndpointAddress; 418 } 419 } 420 421 if (ucaa.ucaa_bulkin == -1) { 422 aprint_error_dev(self, "Could not find data bulk in\n"); 423 sc->sc_dying = true; 424 return; 425 } 426 427 if (ucaa.ucaa_bulkout == -1) { 428 aprint_error_dev(self, "Could not find data bulk out\n"); 429 sc->sc_dying = true; 430 return; 431 } 432 433 sc->sc_dtr = sc->sc_rts = -1; 434 ucaa.ucaa_portno = UCOM_UNK_PORTNO; 435 /* ucaa_bulkin, ucaa_bulkout set above */ 436 ucaa.ucaa_ibufsize = UPLCOMIBUFSIZE; 437 ucaa.ucaa_obufsize = UPLCOMOBUFSIZE; 438 ucaa.ucaa_ibufsizepad = UPLCOMIBUFSIZE; 439 ucaa.ucaa_opkthdrlen = 0; 440 ucaa.ucaa_device = dev; 441 ucaa.ucaa_iface = sc->sc_iface; 442 ucaa.ucaa_methods = &uplcom_methods; 443 ucaa.ucaa_arg = sc; 444 ucaa.ucaa_info = NULL; 445 446 err = uplcom_reset(sc); 447 448 if (err) { 449 aprint_error_dev(self, "reset failed, %s\n", usbd_errstr(err)); 450 sc->sc_dying = true; 451 return; 452 } 453 454 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); 455 456 DPRINTF("in=%#jx out=%#jx intr=%#jx", 457 ucaa.ucaa_bulkin, ucaa.ucaa_bulkout, sc->sc_intr_number, 0); 458 sc->sc_subdev = config_found(self, &ucaa, ucomprint, 459 CFARG_SUBMATCH, ucomsubmatch, 460 CFARG_EOL); 461 462 if (!pmf_device_register(self, NULL, NULL)) 463 aprint_error_dev(self, "couldn't establish power handler\n"); 464 465 return; 466 } 467 468 static void 469 uplcom_childdet(device_t self, device_t child) 470 { 471 struct uplcom_softc *sc = device_private(self); 472 473 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 474 475 KASSERT(sc->sc_subdev == child); 476 sc->sc_subdev = NULL; 477 } 478 479 static void 480 uplcom_close_pipe(struct uplcom_softc *sc) 481 { 482 483 if (sc->sc_intr_pipe != NULL) { 484 usbd_abort_pipe(sc->sc_intr_pipe); 485 usbd_close_pipe(sc->sc_intr_pipe); 486 sc->sc_intr_pipe = NULL; 487 } 488 if (sc->sc_intr_buf != NULL) { 489 kmem_free(sc->sc_intr_buf, sc->sc_isize); 490 sc->sc_intr_buf = NULL; 491 } 492 } 493 494 static int 495 uplcom_detach(device_t self, int flags) 496 { 497 struct uplcom_softc *sc = device_private(self); 498 int rv = 0; 499 500 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 501 DPRINTF("sc=%#jx flags=%jd", (uintptr_t)sc, flags, 0, 0); 502 503 sc->sc_dying = true; 504 505 uplcom_close_pipe(sc); 506 507 if (sc->sc_subdev != NULL) { 508 rv = config_detach(sc->sc_subdev, flags); 509 sc->sc_subdev = NULL; 510 } 511 512 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); 513 514 pmf_device_deregister(self); 515 516 return rv; 517 } 518 519 usbd_status 520 uplcom_reset(struct uplcom_softc *sc) 521 { 522 usb_device_request_t req; 523 usbd_status err; 524 525 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 526 req.bRequest = UPLCOM_SET_REQUEST; 527 USETW(req.wValue, 0); 528 USETW(req.wIndex, sc->sc_iface_number); 529 USETW(req.wLength, 0); 530 531 err = usbd_do_request(sc->sc_udev, &req, 0); 532 if (err) 533 return EIO; 534 535 return 0; 536 } 537 538 struct pl2303x_init { 539 uint8_t req_type; 540 uint8_t request; 541 uint16_t value; 542 uint16_t index; 543 }; 544 545 static const struct pl2303x_init pl2303x[] = { 546 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0 }, 547 { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 0 }, 548 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0 }, 549 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0 }, 550 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0 }, 551 { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 1 }, 552 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0 }, 553 { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0 }, 554 { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0, 1 }, 555 { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0 }, 556 { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44 } 557 }; 558 #define N_PL2302X_INIT (sizeof(pl2303x)/sizeof(pl2303x[0])) 559 560 static usbd_status 561 uplcom_pl2303x_init(struct uplcom_softc *sc) 562 { 563 usb_device_request_t req; 564 usbd_status err; 565 int i; 566 567 for (i = 0; i < N_PL2302X_INIT; i++) { 568 char buf[1]; 569 void *b; 570 571 req.bmRequestType = pl2303x[i].req_type; 572 req.bRequest = pl2303x[i].request; 573 USETW(req.wValue, pl2303x[i].value); 574 USETW(req.wIndex, pl2303x[i].index); 575 if (UT_GET_DIR(req.bmRequestType) == UT_READ) { 576 b = buf; 577 USETW(req.wLength, sizeof(buf)); 578 } else { 579 b = NULL; 580 USETW(req.wLength, 0); 581 } 582 583 err = usbd_do_request(sc->sc_udev, &req, b); 584 if (err) { 585 aprint_error_dev(sc->sc_dev, 586 "uplcom_pl2303x_init failed: %s\n", 587 usbd_errstr(err)); 588 return EIO; 589 } 590 } 591 592 return 0; 593 } 594 595 static void 596 uplcom_set_line_state(struct uplcom_softc *sc) 597 { 598 usb_device_request_t req; 599 int ls; 600 601 /* make sure we have initialized state for sc_dtr and sc_rts */ 602 if (sc->sc_dtr == -1) 603 sc->sc_dtr = 0; 604 if (sc->sc_rts == -1) 605 sc->sc_rts = 0; 606 607 ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) | 608 (sc->sc_rts ? UCDC_LINE_RTS : 0); 609 610 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 611 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 612 USETW(req.wValue, ls); 613 USETW(req.wIndex, sc->sc_iface_number); 614 USETW(req.wLength, 0); 615 616 (void)usbd_do_request(sc->sc_udev, &req, 0); 617 } 618 619 static void 620 uplcom_set(void *addr, int portno, int reg, int onoff) 621 { 622 struct uplcom_softc *sc = addr; 623 624 if (sc->sc_dying) 625 return; 626 627 switch (reg) { 628 case UCOM_SET_DTR: 629 uplcom_dtr(sc, onoff); 630 break; 631 case UCOM_SET_RTS: 632 uplcom_rts(sc, onoff); 633 break; 634 case UCOM_SET_BREAK: 635 uplcom_break(sc, onoff); 636 break; 637 default: 638 break; 639 } 640 } 641 642 static void 643 uplcom_dtr(struct uplcom_softc *sc, int onoff) 644 { 645 646 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 647 DPRINTF("onoff=%jd", onoff, 0, 0, 0); 648 649 if (sc->sc_dtr != -1 && !sc->sc_dtr == !onoff) 650 return; 651 652 sc->sc_dtr = !!onoff; 653 654 uplcom_set_line_state(sc); 655 } 656 657 static void 658 uplcom_rts(struct uplcom_softc *sc, int onoff) 659 { 660 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 661 DPRINTF("onoff=%jd", onoff, 0, 0, 0); 662 663 if (sc->sc_rts != -1 && !sc->sc_rts == !onoff) 664 return; 665 666 sc->sc_rts = !!onoff; 667 668 uplcom_set_line_state(sc); 669 } 670 671 static void 672 uplcom_break(struct uplcom_softc *sc, int onoff) 673 { 674 usb_device_request_t req; 675 676 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 677 DPRINTF("onoff=%jd", onoff, 0, 0, 0); 678 679 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 680 req.bRequest = UCDC_SEND_BREAK; 681 USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF); 682 USETW(req.wIndex, sc->sc_iface_number); 683 USETW(req.wLength, 0); 684 685 (void)usbd_do_request(sc->sc_udev, &req, 0); 686 } 687 688 static usbd_status 689 uplcom_set_crtscts(struct uplcom_softc *sc) 690 { 691 usb_device_request_t req; 692 usbd_status err; 693 694 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 695 696 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 697 req.bRequest = UPLCOM_SET_REQUEST; 698 USETW(req.wValue, 0); 699 if (sc->sc_type == UPLCOM_TYPE_HX) 700 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_HX); 701 else 702 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_0); 703 USETW(req.wLength, 0); 704 705 err = usbd_do_request(sc->sc_udev, &req, 0); 706 if (err) { 707 DPRINTF("failed, err=%jd", err, 0, 0, 0); 708 return err; 709 } 710 711 return USBD_NORMAL_COMPLETION; 712 } 713 714 static usbd_status 715 uplcom_set_line_coding(struct uplcom_softc *sc, usb_cdc_line_state_t *state) 716 { 717 usb_device_request_t req; 718 usbd_status err; 719 720 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 721 722 DPRINTF("rate=%jd fmt=%jd parity=%jd bits=%jd", 723 UGETDW(state->dwDTERate), state->bCharFormat, 724 state->bParityType, state->bDataBits); 725 726 if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) { 727 DPRINTF("already set", 0, 0, 0, 0); 728 return USBD_NORMAL_COMPLETION; 729 } 730 731 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 732 req.bRequest = UCDC_SET_LINE_CODING; 733 USETW(req.wValue, 0); 734 USETW(req.wIndex, sc->sc_iface_number); 735 USETW(req.wLength, UCDC_LINE_STATE_LENGTH); 736 737 err = usbd_do_request(sc->sc_udev, &req, state); 738 if (err) { 739 DPRINTF("failed, err=%ju", err, 0, 0, 0); 740 return err; 741 } 742 743 sc->sc_line_state = *state; 744 745 return USBD_NORMAL_COMPLETION; 746 } 747 748 static int 749 uplcom_param(void *addr, int portno, struct termios *t) 750 { 751 struct uplcom_softc *sc = addr; 752 usbd_status err; 753 usb_cdc_line_state_t ls; 754 755 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 756 DPRINTF("sc=%#jx", (uintptr_t)sc, 0, 0, 0); 757 758 if (sc->sc_dying) 759 return EIO; 760 761 USETDW(ls.dwDTERate, t->c_ospeed); 762 if (ISSET(t->c_cflag, CSTOPB)) 763 ls.bCharFormat = UCDC_STOP_BIT_2; 764 else 765 ls.bCharFormat = UCDC_STOP_BIT_1; 766 if (ISSET(t->c_cflag, PARENB)) { 767 if (ISSET(t->c_cflag, PARODD)) 768 ls.bParityType = UCDC_PARITY_ODD; 769 else 770 ls.bParityType = UCDC_PARITY_EVEN; 771 } else 772 ls.bParityType = UCDC_PARITY_NONE; 773 switch (ISSET(t->c_cflag, CSIZE)) { 774 case CS5: 775 ls.bDataBits = 5; 776 break; 777 case CS6: 778 ls.bDataBits = 6; 779 break; 780 case CS7: 781 ls.bDataBits = 7; 782 break; 783 case CS8: 784 ls.bDataBits = 8; 785 break; 786 } 787 788 err = uplcom_set_line_coding(sc, &ls); 789 if (err) { 790 DPRINTF("err=%jd", err, 0, 0, 0); 791 return EIO; 792 } 793 794 if (ISSET(t->c_cflag, CRTSCTS)) 795 uplcom_set_crtscts(sc); 796 797 if (sc->sc_rts == -1 || sc->sc_dtr == -1) 798 uplcom_set_line_state(sc); 799 800 if (err) { 801 DPRINTF("err=%jd", err, 0, 0, 0); 802 return EIO; 803 } 804 805 return 0; 806 } 807 808 static usbd_status 809 uplcom_vendor_control_write(struct usbd_device *dev, uint16_t value, 810 uint16_t index) 811 { 812 usb_device_request_t req; 813 usbd_status err; 814 815 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 816 817 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 818 req.bRequest = UPLCOM_SET_REQUEST; 819 USETW(req.wValue, value); 820 USETW(req.wIndex, index); 821 USETW(req.wLength, 0); 822 823 err = usbd_do_request(dev, &req, NULL); 824 825 if (err) { 826 DPRINTF("vendor write failed, err=%jd", err, 0, 0, 0); 827 } 828 829 return err; 830 } 831 832 static int 833 uplcom_open(void *addr, int portno) 834 { 835 struct uplcom_softc *sc = addr; 836 usbd_status err = 0; 837 838 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 839 DPRINTF("sc=%#jx", (uintptr_t)sc, 0, 0, 0); 840 841 if (sc->sc_dying) 842 return EIO; 843 844 /* Some unknown device frobbing. */ 845 if (sc->sc_type == UPLCOM_TYPE_HX) 846 uplcom_vendor_control_write(sc->sc_udev, 2, 0x44); 847 else 848 uplcom_vendor_control_write(sc->sc_udev, 2, 0x24); 849 850 if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { 851 sc->sc_intr_buf = kmem_alloc(sc->sc_isize, KM_SLEEP); 852 err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number, 853 USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, 854 sc->sc_intr_buf, sc->sc_isize, 855 uplcom_intr, USBD_DEFAULT_INTERVAL); 856 if (err) { 857 DPRINTF("cannot open interrupt pipe (addr %jd)", 858 sc->sc_intr_number, 0, 0, 0); 859 } 860 } 861 862 if (err == 0 && sc->sc_type == UPLCOM_TYPE_HX) 863 err = uplcom_pl2303x_init(sc); 864 865 return err; 866 } 867 868 static void 869 uplcom_close(void *addr, int portno) 870 { 871 struct uplcom_softc *sc = addr; 872 873 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 874 DPRINTF("sc=%#jx", (uintptr_t)sc, 0, 0, 0); 875 876 if (sc->sc_dying) 877 return; 878 879 uplcom_close_pipe(sc); 880 } 881 882 static void 883 uplcom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 884 { 885 struct uplcom_softc *sc = priv; 886 u_char *buf = sc->sc_intr_buf; 887 u_char pstatus; 888 889 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 890 891 if (sc->sc_dying) 892 return; 893 894 if (status != USBD_NORMAL_COMPLETION) { 895 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 896 return; 897 898 DPRINTF("abnormal status: %ju", status, 0, 0, 0); 899 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 900 return; 901 } 902 903 DPRINTF("uplcom status = %02jx", buf[8], 0, 0, 0); 904 905 sc->sc_lsr = sc->sc_msr = 0; 906 pstatus = buf[8]; 907 if (ISSET(pstatus, UPLCOM_N_SERIAL_CTS)) 908 sc->sc_msr |= UMSR_CTS; 909 if (ISSET(pstatus, UCDC_N_SERIAL_RI)) 910 sc->sc_msr |= UMSR_RI; 911 if (ISSET(pstatus, UCDC_N_SERIAL_DSR)) 912 sc->sc_msr |= UMSR_DSR; 913 if (ISSET(pstatus, UCDC_N_SERIAL_DCD)) 914 sc->sc_msr |= UMSR_DCD; 915 ucom_status_change(device_private(sc->sc_subdev)); 916 } 917 918 static void 919 uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr) 920 { 921 struct uplcom_softc *sc = addr; 922 923 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 924 925 if (sc->sc_dying) 926 return; 927 928 *lsr = sc->sc_lsr; 929 *msr = sc->sc_msr; 930 } 931 932 #if TODO 933 static int 934 uplcom_ioctl(void *addr, int portno, u_long cmd, void *data, int flag, 935 proc_t *p) 936 { 937 struct uplcom_softc *sc = addr; 938 int error = 0; 939 940 UPLCOMHIST_FUNC(); UPLCOMHIST_CALLED(); 941 942 if (sc->sc_dying) 943 return EIO; 944 945 DPRINTF("cmd=0x%08lx", cmd, 0, 0, 0); 946 947 switch (cmd) { 948 case TIOCNOTTY: 949 case TIOCMGET: 950 case TIOCMSET: 951 case USB_GET_CM_OVER_DATA: 952 case USB_SET_CM_OVER_DATA: 953 break; 954 955 default: 956 DPRINTF("unknown", 0, 0, 0, 0); 957 error = ENOTTY; 958 break; 959 } 960 961 return error; 962 } 963 #endif 964