1 /* $OpenBSD: uslcom.c,v 1.17 2007/11/24 10:52:12 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/stdint.h> 20 #include <sys/param.h> 21 #include <sys/queue.h> 22 #include <sys/types.h> 23 #include <sys/systm.h> 24 #include <sys/kernel.h> 25 #include <sys/bus.h> 26 #include <sys/module.h> 27 #include <sys/lock.h> 28 #include <sys/condvar.h> 29 #include <sys/sysctl.h> 30 #include <sys/unistd.h> 31 #include <sys/callout.h> 32 #include <sys/malloc.h> 33 #include <sys/priv.h> 34 #include <sys/serial.h> 35 36 #include <bus/u4b/usb.h> 37 #include <bus/u4b/usbdi.h> 38 #include <bus/u4b/usbdi_util.h> 39 #include <bus/u4b/usb_ioctl.h> 40 #include "usbdevs.h" 41 42 #define USB_DEBUG_VAR uslcom_debug 43 #include <bus/u4b/usb_debug.h> 44 #include <bus/u4b/usb_process.h> 45 46 #include <bus/u4b/serial/usb_serial.h> 47 48 #ifdef USB_DEBUG 49 static int uslcom_debug = 0; 50 51 static SYSCTL_NODE(_hw_usb, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom"); 52 SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RW, 53 &uslcom_debug, 0, "Debug level"); 54 #endif 55 56 #define USLCOM_BULK_BUF_SIZE 1024 57 #define USLCOM_CONFIG_INDEX 0 58 #define USLCOM_IFACE_INDEX 0 59 60 #define USLCOM_SET_DATA_BITS(x) ((x) << 8) 61 62 /* Request types */ 63 #define USLCOM_WRITE 0x41 64 #define USLCOM_READ 0xc1 65 66 /* Request codes */ 67 #define USLCOM_UART 0x00 68 #define USLCOM_BAUD_RATE 0x01 69 #define USLCOM_DATA 0x03 70 #define USLCOM_BREAK 0x05 71 #define USLCOM_CTRL 0x07 72 #define USLCOM_RCTRL 0x08 73 #define USLCOM_SET_FLOWCTRL 0x13 74 #define USLCOM_VENDOR_SPECIFIC 0xff 75 76 /* USLCOM_UART values */ 77 #define USLCOM_UART_DISABLE 0x00 78 #define USLCOM_UART_ENABLE 0x01 79 80 /* USLCOM_CTRL/USLCOM_RCTRL values */ 81 #define USLCOM_CTRL_DTR_ON 0x0001 82 #define USLCOM_CTRL_DTR_SET 0x0100 83 #define USLCOM_CTRL_RTS_ON 0x0002 84 #define USLCOM_CTRL_RTS_SET 0x0200 85 #define USLCOM_CTRL_CTS 0x0010 86 #define USLCOM_CTRL_DSR 0x0020 87 #define USLCOM_CTRL_RI 0x0040 88 #define USLCOM_CTRL_DCD 0x0080 89 90 /* USLCOM_BAUD_RATE values */ 91 #define USLCOM_BAUD_REF 0x384000 92 93 /* USLCOM_DATA values */ 94 #define USLCOM_STOP_BITS_1 0x00 95 #define USLCOM_STOP_BITS_2 0x02 96 #define USLCOM_PARITY_NONE 0x00 97 #define USLCOM_PARITY_ODD 0x10 98 #define USLCOM_PARITY_EVEN 0x20 99 100 #define USLCOM_PORT_NO 0x0000 101 102 /* USLCOM_BREAK values */ 103 #define USLCOM_BREAK_OFF 0x00 104 #define USLCOM_BREAK_ON 0x01 105 106 /* USLCOM_SET_FLOWCTRL values - 1st word */ 107 #define USLCOM_FLOW_DTR_ON 0x00000001 /* DTR static active */ 108 #define USLCOM_FLOW_CTS_HS 0x00000008 /* CTS handshake */ 109 /* USLCOM_SET_FLOWCTRL values - 2nd word */ 110 #define USLCOM_FLOW_RTS_ON 0x00000040 /* RTS static active */ 111 #define USLCOM_FLOW_RTS_HS 0x00000080 /* RTS handshake */ 112 113 /* USLCOM_VENDOR_SPECIFIC values */ 114 #define USLCOM_WRITE_LATCH 0x37E1 115 #define USLCOM_READ_LATCH 0x00C2 116 117 enum { 118 USLCOM_BULK_DT_WR, 119 USLCOM_BULK_DT_RD, 120 USLCOM_CTRL_DT_RD, 121 USLCOM_N_TRANSFER, 122 }; 123 124 struct uslcom_softc { 125 struct ucom_super_softc sc_super_ucom; 126 struct ucom_softc sc_ucom; 127 struct usb_callout sc_watchdog; 128 129 struct usb_xfer *sc_xfer[USLCOM_N_TRANSFER]; 130 struct usb_device *sc_udev; 131 struct lock sc_lock; 132 133 uint8_t sc_msr; 134 uint8_t sc_lsr; 135 }; 136 137 static device_probe_t uslcom_probe; 138 static device_attach_t uslcom_attach; 139 static device_detach_t uslcom_detach; 140 141 static usb_callback_t uslcom_write_callback; 142 static usb_callback_t uslcom_read_callback; 143 static usb_callback_t uslcom_control_callback; 144 145 static void uslcom_open(struct ucom_softc *); 146 static void uslcom_close(struct ucom_softc *); 147 static void uslcom_set_dtr(struct ucom_softc *, uint8_t); 148 static void uslcom_set_rts(struct ucom_softc *, uint8_t); 149 static void uslcom_set_break(struct ucom_softc *, uint8_t); 150 static int uslcom_ioctl(struct ucom_softc *, uint32_t, caddr_t, int, 151 struct thread *); 152 static int uslcom_pre_param(struct ucom_softc *, struct termios *); 153 static void uslcom_param(struct ucom_softc *, struct termios *); 154 static void uslcom_get_status(struct ucom_softc *, uint8_t *, uint8_t *); 155 static void uslcom_start_read(struct ucom_softc *); 156 static void uslcom_stop_read(struct ucom_softc *); 157 static void uslcom_start_write(struct ucom_softc *); 158 static void uslcom_stop_write(struct ucom_softc *); 159 static void uslcom_poll(struct ucom_softc *ucom); 160 161 static const struct usb_config uslcom_config[USLCOM_N_TRANSFER] = { 162 163 [USLCOM_BULK_DT_WR] = { 164 .type = UE_BULK, 165 .endpoint = UE_ADDR_ANY, 166 .direction = UE_DIR_OUT, 167 .bufsize = USLCOM_BULK_BUF_SIZE, 168 .flags = {.pipe_bof = 1,}, 169 .callback = &uslcom_write_callback, 170 }, 171 172 [USLCOM_BULK_DT_RD] = { 173 .type = UE_BULK, 174 .endpoint = UE_ADDR_ANY, 175 .direction = UE_DIR_IN, 176 .bufsize = USLCOM_BULK_BUF_SIZE, 177 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 178 .callback = &uslcom_read_callback, 179 }, 180 [USLCOM_CTRL_DT_RD] = { 181 .type = UE_CONTROL, 182 .endpoint = 0x00, 183 .direction = UE_DIR_ANY, 184 .bufsize = sizeof(struct usb_device_request) + 8, 185 .flags = {.pipe_bof = 1,}, 186 .callback = &uslcom_control_callback, 187 .timeout = 1000, /* 1 second timeout */ 188 }, 189 }; 190 191 static struct ucom_callback uslcom_callback = { 192 .ucom_cfg_open = &uslcom_open, 193 .ucom_cfg_close = &uslcom_close, 194 .ucom_cfg_get_status = &uslcom_get_status, 195 .ucom_cfg_set_dtr = &uslcom_set_dtr, 196 .ucom_cfg_set_rts = &uslcom_set_rts, 197 .ucom_cfg_set_break = &uslcom_set_break, 198 .ucom_ioctl = &uslcom_ioctl, 199 .ucom_cfg_param = &uslcom_param, 200 .ucom_pre_param = &uslcom_pre_param, 201 .ucom_start_read = &uslcom_start_read, 202 .ucom_stop_read = &uslcom_stop_read, 203 .ucom_start_write = &uslcom_start_write, 204 .ucom_stop_write = &uslcom_stop_write, 205 .ucom_poll = &uslcom_poll, 206 }; 207 208 static const STRUCT_USB_HOST_ID uslcom_devs[] = { 209 #define USLCOM_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 210 USLCOM_DEV(BALTECH, CARDREADER), 211 USLCOM_DEV(CLIPSAL, 5500PCU), 212 USLCOM_DEV(DATAAPEX, MULTICOM), 213 USLCOM_DEV(DELL, DW700), 214 USLCOM_DEV(DIGIANSWER, ZIGBEE802154), 215 USLCOM_DEV(DYNASTREAM, ANTDEVBOARD), 216 USLCOM_DEV(DYNASTREAM, ANTDEVBOARD2), 217 USLCOM_DEV(DYNASTREAM, ANT2USB), 218 USLCOM_DEV(ELV, USBI2C), 219 USLCOM_DEV(FOXCONN, PIRELLI_DP_L10), 220 USLCOM_DEV(FOXCONN, TCOM_TC_300), 221 USLCOM_DEV(GEMALTO, PROXPU), 222 USLCOM_DEV(JABLOTRON, PC60B), 223 USLCOM_DEV(MEI, CASHFLOW_SC), 224 USLCOM_DEV(MEI, S2000), 225 USLCOM_DEV(JABLOTRON, PC60B), 226 USLCOM_DEV(OWEN, AC4), 227 USLCOM_DEV(PHILIPS, ACE1001), 228 USLCOM_DEV(PLX, CA42), 229 USLCOM_DEV(RENESAS, RX610), 230 USLCOM_DEV(SILABS, AEROCOMM), 231 USLCOM_DEV(SILABS, AMBER_AMB2560), 232 USLCOM_DEV(SILABS, ARGUSISP), 233 USLCOM_DEV(SILABS, ARKHAM_DS101_A), 234 USLCOM_DEV(SILABS, ARKHAM_DS101_M), 235 USLCOM_DEV(SILABS, ARYGON_MIFARE), 236 USLCOM_DEV(SILABS, AVIT_USB_TTL), 237 USLCOM_DEV(SILABS, B_G_H3000), 238 USLCOM_DEV(SILABS, BALLUFF_RFID), 239 USLCOM_DEV(SILABS, BEI_VCP), 240 USLCOM_DEV(SILABS, BSM7DUSB), 241 USLCOM_DEV(SILABS, BURNSIDE), 242 USLCOM_DEV(SILABS, C2_EDGE_MODEM), 243 USLCOM_DEV(SILABS, CP2102), 244 USLCOM_DEV(SILABS, CP210X_2), 245 USLCOM_DEV(SILABS, CRUMB128), 246 USLCOM_DEV(SILABS, CYGNAL), 247 USLCOM_DEV(SILABS, CYGNAL_DEBUG), 248 USLCOM_DEV(SILABS, CYGNAL_GPS), 249 USLCOM_DEV(SILABS, DEGREE), 250 USLCOM_DEV(SILABS, EMS_C1007), 251 USLCOM_DEV(SILABS, HELICOM), 252 USLCOM_DEV(SILABS, IMS_USB_RS422), 253 USLCOM_DEV(SILABS, INFINITY_MIC), 254 USLCOM_DEV(SILABS, INSYS_MODEM), 255 USLCOM_DEV(SILABS, KYOCERA_GPS), 256 USLCOM_DEV(SILABS, LIPOWSKY_HARP), 257 USLCOM_DEV(SILABS, LIPOWSKY_JTAG), 258 USLCOM_DEV(SILABS, LIPOWSKY_LIN), 259 USLCOM_DEV(SILABS, MC35PU), 260 USLCOM_DEV(SILABS, MJS_TOSLINK), 261 USLCOM_DEV(SILABS, MSD_DASHHAWK), 262 USLCOM_DEV(SILABS, POLOLU), 263 USLCOM_DEV(SILABS, PROCYON_AVS), 264 USLCOM_DEV(SILABS, SB_PARAMOUNT_ME), 265 USLCOM_DEV(SILABS, SUUNTO), 266 USLCOM_DEV(SILABS, TAMSMASTER), 267 USLCOM_DEV(SILABS, TELEGESIS_ETRX2), 268 USLCOM_DEV(SILABS, TRACIENT), 269 USLCOM_DEV(SILABS, TRAQMATE), 270 USLCOM_DEV(SILABS, USBCOUNT50), 271 USLCOM_DEV(SILABS, USBPULSE100), 272 USLCOM_DEV(SILABS, USBSCOPE50), 273 USLCOM_DEV(SILABS, USBWAVE12), 274 USLCOM_DEV(SILABS, VSTABI), 275 USLCOM_DEV(SILABS, WAVIT), 276 USLCOM_DEV(SILABS, WMRBATT), 277 USLCOM_DEV(SILABS, WMRRIGBLASTER), 278 USLCOM_DEV(SILABS, WMRRIGTALK), 279 USLCOM_DEV(SILABS, ZEPHYR_BIO), 280 USLCOM_DEV(SILABS2, DCU11CLONE), 281 USLCOM_DEV(SILABS3, GPRS_MODEM), 282 USLCOM_DEV(SILABS4, 100EU_MODEM), 283 USLCOM_DEV(SYNTECH, CYPHERLAB100), 284 USLCOM_DEV(USI, MC60), 285 USLCOM_DEV(VAISALA, CABLE), 286 USLCOM_DEV(WAGO, SERVICECABLE), 287 USLCOM_DEV(WAVESENSE, JAZZ), 288 USLCOM_DEV(WIENERPLEINBAUS, PL512), 289 USLCOM_DEV(WIENERPLEINBAUS, RCM), 290 USLCOM_DEV(WIENERPLEINBAUS, MPOD), 291 USLCOM_DEV(WIENERPLEINBAUS, CML), 292 #undef USLCOM_DEV 293 }; 294 295 static device_method_t uslcom_methods[] = { 296 DEVMETHOD(device_probe, uslcom_probe), 297 DEVMETHOD(device_attach, uslcom_attach), 298 DEVMETHOD(device_detach, uslcom_detach), 299 DEVMETHOD_END 300 }; 301 302 static devclass_t uslcom_devclass; 303 304 static driver_t uslcom_driver = { 305 .name = "uslcom", 306 .methods = uslcom_methods, 307 .size = sizeof(struct uslcom_softc), 308 }; 309 310 DRIVER_MODULE(uslcom, uhub, uslcom_driver, uslcom_devclass, NULL, NULL); 311 MODULE_DEPEND(uslcom, ucom, 1, 1, 1); 312 MODULE_DEPEND(uslcom, usb, 1, 1, 1); 313 MODULE_VERSION(uslcom, 1); 314 315 static void 316 uslcom_watchdog(void *arg) 317 { 318 struct uslcom_softc *sc = arg; 319 320 KKASSERT(lockowned(&sc->sc_lock)); 321 322 usbd_transfer_start(sc->sc_xfer[USLCOM_CTRL_DT_RD]); 323 324 usb_callout_reset(&sc->sc_watchdog, 325 hz / 4, &uslcom_watchdog, sc); 326 } 327 328 static int 329 uslcom_probe(device_t dev) 330 { 331 struct usb_attach_arg *uaa = device_get_ivars(dev); 332 333 DPRINTFN(11, "\n"); 334 335 if (uaa->usb_mode != USB_MODE_HOST) { 336 return (ENXIO); 337 } 338 if (uaa->info.bConfigIndex != USLCOM_CONFIG_INDEX) { 339 return (ENXIO); 340 } 341 if (uaa->info.bIfaceIndex != USLCOM_IFACE_INDEX) { 342 return (ENXIO); 343 } 344 return (usbd_lookup_id_by_uaa(uslcom_devs, sizeof(uslcom_devs), uaa)); 345 } 346 347 static int 348 uslcom_attach(device_t dev) 349 { 350 struct usb_attach_arg *uaa = device_get_ivars(dev); 351 struct uslcom_softc *sc = device_get_softc(dev); 352 int error; 353 354 DPRINTFN(11, "\n"); 355 356 device_set_usb_desc(dev); 357 lockinit(&sc->sc_lock, "uslcom", 0, LK_CANRECURSE); 358 usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_lock, 0); 359 360 sc->sc_udev = uaa->device; 361 362 error = usbd_transfer_setup(uaa->device, 363 &uaa->info.bIfaceIndex, sc->sc_xfer, uslcom_config, 364 USLCOM_N_TRANSFER, sc, &sc->sc_lock); 365 if (error) { 366 DPRINTF("one or more missing USB endpoints, " 367 "error=%s\n", usbd_errstr(error)); 368 goto detach; 369 } 370 /* clear stall at first run */ 371 lockmgr(&sc->sc_lock, LK_EXCLUSIVE); 372 usbd_xfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_WR]); 373 usbd_xfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_RD]); 374 lockmgr(&sc->sc_lock, LK_RELEASE); 375 376 error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 377 &uslcom_callback, &sc->sc_lock); 378 if (error) { 379 goto detach; 380 } 381 ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); 382 383 return (0); 384 385 detach: 386 uslcom_detach(dev); 387 return (ENXIO); 388 } 389 390 static int 391 uslcom_detach(device_t dev) 392 { 393 struct uslcom_softc *sc = device_get_softc(dev); 394 395 DPRINTF("sc=%p\n", sc); 396 397 ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); 398 usbd_transfer_unsetup(sc->sc_xfer, USLCOM_N_TRANSFER); 399 400 usb_callout_drain(&sc->sc_watchdog); 401 lockuninit(&sc->sc_lock); 402 403 return (0); 404 } 405 406 static void 407 uslcom_open(struct ucom_softc *ucom) 408 { 409 struct uslcom_softc *sc = ucom->sc_parent; 410 struct usb_device_request req; 411 412 req.bmRequestType = USLCOM_WRITE; 413 req.bRequest = USLCOM_UART; 414 USETW(req.wValue, USLCOM_UART_ENABLE); 415 USETW(req.wIndex, USLCOM_PORT_NO); 416 USETW(req.wLength, 0); 417 418 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 419 &req, NULL, 0, 1000)) { 420 DPRINTF("UART enable failed (ignored)\n"); 421 } 422 423 /* start polling status */ 424 uslcom_watchdog(sc); 425 } 426 427 static void 428 uslcom_close(struct ucom_softc *ucom) 429 { 430 struct uslcom_softc *sc = ucom->sc_parent; 431 struct usb_device_request req; 432 433 /* stop polling status */ 434 usb_callout_stop(&sc->sc_watchdog); 435 436 req.bmRequestType = USLCOM_WRITE; 437 req.bRequest = USLCOM_UART; 438 USETW(req.wValue, USLCOM_UART_DISABLE); 439 USETW(req.wIndex, USLCOM_PORT_NO); 440 USETW(req.wLength, 0); 441 442 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 443 &req, NULL, 0, 1000)) { 444 DPRINTF("UART disable failed (ignored)\n"); 445 } 446 } 447 448 static void 449 uslcom_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 450 { 451 struct uslcom_softc *sc = ucom->sc_parent; 452 struct usb_device_request req; 453 uint16_t ctl; 454 455 DPRINTF("onoff = %d\n", onoff); 456 457 ctl = onoff ? USLCOM_CTRL_DTR_ON : 0; 458 ctl |= USLCOM_CTRL_DTR_SET; 459 460 req.bmRequestType = USLCOM_WRITE; 461 req.bRequest = USLCOM_CTRL; 462 USETW(req.wValue, ctl); 463 USETW(req.wIndex, USLCOM_PORT_NO); 464 USETW(req.wLength, 0); 465 466 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 467 &req, NULL, 0, 1000)) { 468 DPRINTF("Setting DTR failed (ignored)\n"); 469 } 470 } 471 472 static void 473 uslcom_set_rts(struct ucom_softc *ucom, uint8_t onoff) 474 { 475 struct uslcom_softc *sc = ucom->sc_parent; 476 struct usb_device_request req; 477 uint16_t ctl; 478 479 DPRINTF("onoff = %d\n", onoff); 480 481 ctl = onoff ? USLCOM_CTRL_RTS_ON : 0; 482 ctl |= USLCOM_CTRL_RTS_SET; 483 484 req.bmRequestType = USLCOM_WRITE; 485 req.bRequest = USLCOM_CTRL; 486 USETW(req.wValue, ctl); 487 USETW(req.wIndex, USLCOM_PORT_NO); 488 USETW(req.wLength, 0); 489 490 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 491 &req, NULL, 0, 1000)) { 492 DPRINTF("Setting DTR failed (ignored)\n"); 493 } 494 } 495 496 static int 497 uslcom_pre_param(struct ucom_softc *ucom, struct termios *t) 498 { 499 if (t->c_ospeed <= 0 || t->c_ospeed > 921600) 500 return (EINVAL); 501 return (0); 502 } 503 504 static void 505 uslcom_param(struct ucom_softc *ucom, struct termios *t) 506 { 507 struct uslcom_softc *sc = ucom->sc_parent; 508 struct usb_device_request req; 509 uint32_t flowctrl[4]; 510 uint16_t data; 511 512 DPRINTF("\n"); 513 514 req.bmRequestType = USLCOM_WRITE; 515 req.bRequest = USLCOM_BAUD_RATE; 516 USETW(req.wValue, USLCOM_BAUD_REF / t->c_ospeed); 517 USETW(req.wIndex, USLCOM_PORT_NO); 518 USETW(req.wLength, 0); 519 520 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 521 &req, NULL, 0, 1000)) { 522 DPRINTF("Set baudrate failed (ignored)\n"); 523 } 524 525 if (t->c_cflag & CSTOPB) 526 data = USLCOM_STOP_BITS_2; 527 else 528 data = USLCOM_STOP_BITS_1; 529 if (t->c_cflag & PARENB) { 530 if (t->c_cflag & PARODD) 531 data |= USLCOM_PARITY_ODD; 532 else 533 data |= USLCOM_PARITY_EVEN; 534 } else 535 data |= USLCOM_PARITY_NONE; 536 switch (t->c_cflag & CSIZE) { 537 case CS5: 538 data |= USLCOM_SET_DATA_BITS(5); 539 break; 540 case CS6: 541 data |= USLCOM_SET_DATA_BITS(6); 542 break; 543 case CS7: 544 data |= USLCOM_SET_DATA_BITS(7); 545 break; 546 case CS8: 547 data |= USLCOM_SET_DATA_BITS(8); 548 break; 549 } 550 551 req.bmRequestType = USLCOM_WRITE; 552 req.bRequest = USLCOM_DATA; 553 USETW(req.wValue, data); 554 USETW(req.wIndex, USLCOM_PORT_NO); 555 USETW(req.wLength, 0); 556 557 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 558 &req, NULL, 0, 1000)) { 559 DPRINTF("Set format failed (ignored)\n"); 560 } 561 562 if (t->c_cflag & CRTSCTS) { 563 flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON | USLCOM_FLOW_CTS_HS); 564 flowctrl[1] = htole32(USLCOM_FLOW_RTS_HS); 565 flowctrl[2] = 0; 566 flowctrl[3] = 0; 567 } else { 568 flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON); 569 flowctrl[1] = htole32(USLCOM_FLOW_RTS_ON); 570 flowctrl[2] = 0; 571 flowctrl[3] = 0; 572 } 573 req.bmRequestType = USLCOM_WRITE; 574 req.bRequest = USLCOM_SET_FLOWCTRL; 575 USETW(req.wValue, 0); 576 USETW(req.wIndex, USLCOM_PORT_NO); 577 USETW(req.wLength, sizeof(flowctrl)); 578 579 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 580 &req, flowctrl, 0, 1000)) { 581 DPRINTF("Set flowcontrol failed (ignored)\n"); 582 } 583 } 584 585 static void 586 uslcom_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) 587 { 588 struct uslcom_softc *sc = ucom->sc_parent; 589 590 DPRINTF("\n"); 591 592 *lsr = sc->sc_lsr; 593 *msr = sc->sc_msr; 594 } 595 596 static void 597 uslcom_set_break(struct ucom_softc *ucom, uint8_t onoff) 598 { 599 struct uslcom_softc *sc = ucom->sc_parent; 600 struct usb_device_request req; 601 uint16_t brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF; 602 603 req.bmRequestType = USLCOM_WRITE; 604 req.bRequest = USLCOM_BREAK; 605 USETW(req.wValue, brk); 606 USETW(req.wIndex, USLCOM_PORT_NO); 607 USETW(req.wLength, 0); 608 609 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 610 &req, NULL, 0, 1000)) { 611 DPRINTF("Set BREAK failed (ignored)\n"); 612 } 613 } 614 615 static int 616 uslcom_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data, 617 int flag, struct thread *td) 618 { 619 struct uslcom_softc *sc = ucom->sc_parent; 620 struct usb_device_request req; 621 int error = 0; 622 uint8_t latch; 623 624 DPRINTF("cmd=0x%08x\n", cmd); 625 626 switch (cmd) { 627 case USB_GET_GPIO: 628 req.bmRequestType = USLCOM_READ; 629 req.bRequest = USLCOM_VENDOR_SPECIFIC; 630 USETW(req.wValue, USLCOM_READ_LATCH); 631 USETW(req.wIndex, 0); 632 USETW(req.wLength, sizeof(latch)); 633 634 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 635 &req, &latch, 0, 1000)) { 636 DPRINTF("Get LATCH failed\n"); 637 error = EIO; 638 } 639 *(int *)data = latch; 640 break; 641 642 case USB_SET_GPIO: 643 req.bmRequestType = USLCOM_WRITE; 644 req.bRequest = USLCOM_VENDOR_SPECIFIC; 645 USETW(req.wValue, USLCOM_WRITE_LATCH); 646 USETW(req.wIndex, (*(int *)data)); 647 USETW(req.wLength, 0); 648 649 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 650 &req, NULL, 0, 1000)) { 651 DPRINTF("Set LATCH failed\n"); 652 error = EIO; 653 } 654 break; 655 656 default: 657 DPRINTF("Unknown IOCTL\n"); 658 error = ENOIOCTL; 659 break; 660 } 661 return (error); 662 } 663 664 static void 665 uslcom_write_callback(struct usb_xfer *xfer, usb_error_t error) 666 { 667 struct uslcom_softc *sc = usbd_xfer_softc(xfer); 668 struct usb_page_cache *pc; 669 uint32_t actlen; 670 671 switch (USB_GET_STATE(xfer)) { 672 case USB_ST_SETUP: 673 case USB_ST_TRANSFERRED: 674 tr_setup: 675 pc = usbd_xfer_get_frame(xfer, 0); 676 if (ucom_get_data(&sc->sc_ucom, pc, 0, 677 USLCOM_BULK_BUF_SIZE, &actlen)) { 678 679 DPRINTF("actlen = %d\n", actlen); 680 681 usbd_xfer_set_frame_len(xfer, 0, actlen); 682 usbd_transfer_submit(xfer); 683 } 684 return; 685 686 default: /* Error */ 687 if (error != USB_ERR_CANCELLED) { 688 /* try to clear stall first */ 689 usbd_xfer_set_stall(xfer); 690 goto tr_setup; 691 } 692 return; 693 } 694 } 695 696 static void 697 uslcom_read_callback(struct usb_xfer *xfer, usb_error_t error) 698 { 699 struct uslcom_softc *sc = usbd_xfer_softc(xfer); 700 struct usb_page_cache *pc; 701 int actlen; 702 703 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 704 705 switch (USB_GET_STATE(xfer)) { 706 case USB_ST_TRANSFERRED: 707 pc = usbd_xfer_get_frame(xfer, 0); 708 ucom_put_data(&sc->sc_ucom, pc, 0, actlen); 709 710 case USB_ST_SETUP: 711 tr_setup: 712 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 713 usbd_transfer_submit(xfer); 714 return; 715 716 default: /* Error */ 717 if (error != USB_ERR_CANCELLED) { 718 /* try to clear stall first */ 719 usbd_xfer_set_stall(xfer); 720 goto tr_setup; 721 } 722 return; 723 } 724 } 725 726 static void 727 uslcom_control_callback(struct usb_xfer *xfer, usb_error_t error) 728 { 729 struct uslcom_softc *sc = usbd_xfer_softc(xfer); 730 struct usb_page_cache *pc; 731 struct usb_device_request req; 732 uint8_t msr = 0; 733 uint8_t buf; 734 735 switch (USB_GET_STATE(xfer)) { 736 case USB_ST_TRANSFERRED: 737 pc = usbd_xfer_get_frame(xfer, 1); 738 usbd_copy_out(pc, 0, &buf, sizeof(buf)); 739 if (buf & USLCOM_CTRL_CTS) 740 msr |= SER_CTS; 741 if (buf & USLCOM_CTRL_DSR) 742 msr |= SER_DSR; 743 if (buf & USLCOM_CTRL_RI) 744 msr |= SER_RI; 745 if (buf & USLCOM_CTRL_DCD) 746 msr |= SER_DCD; 747 748 if (msr != sc->sc_msr) { 749 DPRINTF("status change msr=0x%02x " 750 "(was 0x%02x)\n", msr, sc->sc_msr); 751 sc->sc_msr = msr; 752 ucom_status_change(&sc->sc_ucom); 753 } 754 break; 755 756 case USB_ST_SETUP: 757 req.bmRequestType = USLCOM_READ; 758 req.bRequest = USLCOM_RCTRL; 759 USETW(req.wValue, 0); 760 USETW(req.wIndex, USLCOM_PORT_NO); 761 USETW(req.wLength, sizeof(buf)); 762 763 usbd_xfer_set_frames(xfer, 2); 764 usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 765 usbd_xfer_set_frame_len(xfer, 1, sizeof(buf)); 766 767 pc = usbd_xfer_get_frame(xfer, 0); 768 usbd_copy_in(pc, 0, &req, sizeof(req)); 769 usbd_transfer_submit(xfer); 770 break; 771 772 default: /* error */ 773 if (error != USB_ERR_CANCELLED) 774 DPRINTF("error=%s\n", usbd_errstr(error)); 775 break; 776 } 777 } 778 779 static void 780 uslcom_start_read(struct ucom_softc *ucom) 781 { 782 struct uslcom_softc *sc = ucom->sc_parent; 783 784 /* start read endpoint */ 785 usbd_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_RD]); 786 } 787 788 static void 789 uslcom_stop_read(struct ucom_softc *ucom) 790 { 791 struct uslcom_softc *sc = ucom->sc_parent; 792 793 /* stop read endpoint */ 794 usbd_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_RD]); 795 } 796 797 static void 798 uslcom_start_write(struct ucom_softc *ucom) 799 { 800 struct uslcom_softc *sc = ucom->sc_parent; 801 802 usbd_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_WR]); 803 } 804 805 static void 806 uslcom_stop_write(struct ucom_softc *ucom) 807 { 808 struct uslcom_softc *sc = ucom->sc_parent; 809 810 usbd_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_WR]); 811 } 812 813 static void 814 uslcom_poll(struct ucom_softc *ucom) 815 { 816 struct uslcom_softc *sc = ucom->sc_parent; 817 usbd_transfer_poll(sc->sc_xfer, USLCOM_N_TRANSFER); 818 } 819