1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2025 Diane Bruce 5 * All rights reserved 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Device driver for Fintek F81232 USB to UART bridge. 31 */ 32 33 #include <sys/stdint.h> 34 #include <sys/stddef.h> 35 #include <sys/param.h> 36 #include <sys/queue.h> 37 #include <sys/types.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/bus.h> 41 #include <sys/module.h> 42 #include <sys/lock.h> 43 #include <sys/mutex.h> 44 #include <sys/condvar.h> 45 #include <sys/sysctl.h> 46 #include <sys/sx.h> 47 #include <sys/unistd.h> 48 #include <sys/callout.h> 49 #include <sys/malloc.h> 50 #include <sys/priv.h> 51 52 #include <dev/usb/usb.h> 53 #include <dev/usb/usbdi.h> 54 #include <dev/usb/usbdi_util.h> 55 #include "usbdevs.h" 56 57 #define USB_DEBUG_VAR ufintek_debug 58 #include <dev/usb/usb_debug.h> 59 #include <dev/usb/usb_process.h> 60 61 #include <dev/usb/serial/usb_serial.h> 62 63 #ifdef USB_DEBUG 64 static int ufintek_debug = 0; 65 66 static SYSCTL_NODE(_hw_usb, OID_AUTO, ufintek, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 67 "USB ufintek"); 68 SYSCTL_INT(_hw_usb_ufintek, OID_AUTO, debug, CTLFLAG_RWTUN, 69 &ufintek_debug, 1, "Debug level"); 70 #endif 71 72 #define UFINTEK_BUFSIZE 256 73 #define UFINTEK_CONFIG_INDEX 0 74 75 #define UFINTEK_REGISTER_REQUEST 0xA0 /* uint8_t request */ 76 #define UFINTEK_READ 0xC0 /* uint8_t requesttype */ 77 #define UFINTEK_WRITE 0x40 /* uint8_t requesttype */ 78 79 #define UFINTEK_IFACE_INDEX 0 80 81 #define UFINTEK_UART_REG 0x120 82 83 /* 84 * It appears the FINTEK serial port looks much like a 16550 85 */ 86 87 #define UFINTEK_RXBUF 0x00 /* Receiver Buffer Read only */ 88 #define UFINTEK_TXBUF 0x00 /* Transmitter Holding Register Write only*/ 89 #define UFINTEK_IER 0x01 /* Interrupt Enable Read/Write */ 90 #define UFINTEK_IIR 0x02 /* Interrupt Identification Read only */ 91 #define UFINTEK_FCR 0x02 /* FIFO control Write only */ 92 #define UFINTEK_LCR 0x03 /* Line Control Register Read/Write */ 93 #define UFINTEK_MCR 0x04 /* Modem Control Write only */ 94 #define UFINTEK_LSR 0x05 /* Line Status Read only */ 95 #define UFINTEK_MSR 0x06 /* Modem Status Read only */ 96 97 #define UFINTEK_BAUDLO 0x00 /* Same as UFINTEK_TXBUF and UFINTEK_RXBUF */ 98 #define UFINTEK_BAUDHI 0x01 /* Same as UFINTEK_IER */ 99 100 /* From uart16550.readthedocs.io */ 101 #define UFINTEK_IER_RXEN 0x01 /* Received data available interrupt */ 102 #define UFINTEK_IER_TXEN 0x02 103 #define UFINTEK_IER_RSEN 0x04 /* Receiver line status interrupt */ 104 #define UFINTEK_IER_MSI 0x08 105 #define UFINTEK_IER_SLEEP 0x10 106 #define UFINTEK_IER_XOFF 0x20 107 #define UFINTEK_IER_RTS 0x40 108 109 #define UFINTEK_FCR_EN 0x01 110 #define UFINTEK_FCR_RXCLR 0x02 111 #define UFINTEK_FCR_TXCLR 0x04 112 #define UFINTEK_FCR_DMA_BLK 0x08 113 #define UFINTEK_FCR_TXLVL_MASK 0x30 114 #define UFINTEK_FCR_TRIGGER_8 0x80 115 116 #define UFINTEK_ISR_NONE 0x01 117 #define UFINTEK_ISR_TX 0x02 118 #define UFINTEK_ISR_RX 0x04 119 #define UFINTEK_ISR_LINE 0x06 120 #define UFINTEK_ISR_MDM 0x08 121 #define UFINTEK_ISR_RXTIMEOUT 0x0C 122 #define UFINTEK_ISR_RX_XOFF 0x10 123 #define UFINTEK_ISR_RTSCTS 0x20 124 #define UFINTEK_ISR_FIFOEN 0xC0 125 126 #define UFINTEK_LCR_WORDLEN_5 0x00 127 #define UFINTEK_LCR_WORDLEN_6 0x01 128 #define UFINTEK_LCR_WORDLEN_7 0x02 129 #define UFINTEK_LCR_WORDLEN_8 0x03 130 131 /* As with ns16550 if word length is 5 then 2 stops is 1.5 stop bits. 132 * This mimics the ancient TTY15/19 (Murray code/Baudot) printers that 133 * needed an extra half stop bit to stop the mechanical clutch! 134 */ 135 #define UFINTEK_LCR_STOP_BITS_1 0x00 136 #define UFINTEK_LCR_STOP_BITS_2 0x04 137 138 #define UFINTEK_LCR_PARITY_NONE 0x00 139 #define UFINTEK_LCR_PARITY_ODD 0x08 140 #define UFINTEK_LCR_PARITY_EVEN 0x18 141 #define UFINTEK_LCR_BREAK 0x40 142 #define UFINTEK_LCR_DLAB 0x80 143 144 #define UFINTEK_MCR_DTR 0x01 145 #define UFINTEK_MCR_RTS 0x02 146 #define UFINTEK_MCR_LOOP 0x04 147 #define UFINTEK_MCR_INTEN 0x08 148 #define UFINTEK_MCR_LOOPBACK 0x10 149 #define UFINTEK_MCR_XONANY 0x20 150 #define UFINTEK_MCR_IRDA_EN 0x40 151 #define UFINTEK_MCR_BAUD_DIV4 0x80 152 153 #define UFINTEK_LSR_RXDATA 0x01 154 #define UFINTEK_LSR_RXOVER 0x02 155 #define UFINTEK_LSR_RXPAR_ERR 0x04 156 #define UFINTEK_LSR_RXFRM_ERR 0x08 157 #define UFINTEK_LSR_RXBREAK 0x10 158 #define UFINTEK_LSR_TXEMPTY 0x20 159 #define UFINTEK_LSR_TXALLEMPTY 0x40 160 #define UFINTEK_LSR_TXFIFO_ERR 0x80 161 162 #define UFINTEK_MSR_CTS_CHG 0x01 163 #define UFINTEK_MSR_DSR_CHG 0x02 164 #define UFINTEK_MSR_RI_CHG 0x04 165 #define UFINTEK_MSR_CD_CHG 0x08 166 #define UFINTEK_MSR_CTS 0x10 167 #define UFINTEK_MSR_RTS 0x20 168 #define UFINTEK_MSR_RI 0x40 169 #define UFINTEK_MSR_CD 0x80 170 171 #define UFINTEK_BAUD_REF 115200 172 #define UFINTEK_DEF_SPEED 115200 173 174 /* 175 * XXX Future use 176 * Baud rate multiplier clock 177 * On other similar FINTEK chips the divider clock can be modified 178 * via another port. This will be easy to add later. 179 * 180 * 0x00 1.846MHz 181 * 0x01 18.46MHz 182 * 0x10 24.00MHz 183 * 0x11 14.77MHz 184 */ 185 #define UFINTEK_CLK_REG 0x106 186 #define UFINTEK_CLK_MSK 0x3 187 #define UFINTEK_CLK_1_846 0x00 188 #define UFINTEK_CLK_18_46 0x01 189 #define UFINTEK_CLK_24_00 0x10 190 #define UFINTEK_CLK_14_77 0x11 191 192 enum { 193 UFINTEK_BULK_DT_WR, 194 UFINTEK_BULK_DT_RD, 195 UFINTEK_N_TRANSFER, 196 }; 197 198 struct ufintek_softc { 199 struct ucom_super_softc sc_super_ucom; 200 struct ucom_softc sc_ucom; 201 202 struct usb_xfer *sc_xfer[UFINTEK_N_TRANSFER]; 203 struct usb_device *sc_udev; 204 struct mtx sc_mtx; 205 206 uint32_t sc_model; 207 uint8_t sc_lcr; 208 uint8_t sc_mcr; 209 }; 210 211 /* prototypes */ 212 static device_probe_t ufintek_probe; 213 static device_attach_t ufintek_attach; 214 static device_detach_t ufintek_detach; 215 static void ufintek_free_softc(struct ufintek_softc *); 216 217 static usb_callback_t ufintek_write_callback; 218 static usb_callback_t ufintek_read_callback; 219 static void ufintek_free(struct ucom_softc *); 220 static void ufintek_cfg_open(struct ucom_softc *); 221 static void ufintek_cfg_close(struct ucom_softc *); 222 static void ufintek_cfg_set_dtr(struct ucom_softc *, uint8_t); 223 static void ufintek_cfg_set_rts(struct ucom_softc *, uint8_t); 224 static void ufintek_cfg_set_break(struct ucom_softc *, uint8_t); 225 static void ufintek_cfg_param(struct ucom_softc *, struct termios *); 226 static void ufintek_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *); 227 static int ufintek_pre_param(struct ucom_softc *, struct termios *); 228 static void ufintek_cfg_write(struct ufintek_softc *, uint16_t, uint8_t); 229 static uint8_t ufintek_cfg_read(struct ufintek_softc *, uint16_t); 230 static void ufintek_start_read(struct ucom_softc *); 231 static void ufintek_stop_read(struct ucom_softc *); 232 static void ufintek_start_write(struct ucom_softc *); 233 static void ufintek_stop_write(struct ucom_softc *); 234 static void ufintek_poll(struct ucom_softc *ucom); 235 236 static const struct usb_config ufintek_config[UFINTEK_N_TRANSFER] = { 237 [UFINTEK_BULK_DT_WR] = { 238 .type = UE_BULK, 239 .endpoint = UE_ADDR_ANY, 240 .direction = UE_DIR_OUT, 241 .bufsize = UFINTEK_BUFSIZE, 242 .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 243 .callback = &ufintek_write_callback, 244 }, 245 [UFINTEK_BULK_DT_RD] = { 246 .type = UE_BULK, 247 .endpoint = UE_ADDR_ANY, 248 .direction = UE_DIR_IN, 249 .bufsize = UFINTEK_BUFSIZE, 250 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 251 .callback = &ufintek_read_callback, 252 }, 253 }; 254 255 static const struct ucom_callback ufintek_callback = { 256 /* configuration callbacks */ 257 .ucom_cfg_get_status = &ufintek_cfg_get_status, 258 .ucom_cfg_set_dtr = &ufintek_cfg_set_dtr, 259 .ucom_cfg_set_rts = &ufintek_cfg_set_rts, 260 .ucom_cfg_set_break = &ufintek_cfg_set_break, 261 .ucom_cfg_open = &ufintek_cfg_open, 262 .ucom_cfg_close = &ufintek_cfg_close, 263 .ucom_cfg_param = &ufintek_cfg_param, 264 .ucom_pre_param = &ufintek_pre_param, 265 .ucom_start_read = &ufintek_start_read, 266 .ucom_stop_read = &ufintek_stop_read, 267 .ucom_start_write = &ufintek_start_write, 268 .ucom_stop_write = &ufintek_stop_write, 269 .ucom_poll = &ufintek_poll, 270 .ucom_free = &ufintek_free, 271 }; 272 273 static device_method_t ufintek_methods[] = { 274 DEVMETHOD(device_probe, ufintek_probe), 275 DEVMETHOD(device_attach, ufintek_attach), 276 DEVMETHOD(device_detach, ufintek_detach), 277 DEVMETHOD_END 278 }; 279 280 static driver_t ufintek_driver = { 281 .name = "ufintek", 282 .methods = ufintek_methods, 283 .size = sizeof(struct ufintek_softc), 284 }; 285 286 287 /* 288 * The following VENDOR PRODUCT definitions should be moved to usbdevs 289 * 290 * vendor FINTEK 0x1934 291 * product FINTEK SERIAL 0x0706 292 * 293 */ 294 #ifndef USB_VENDOR_FINTEK 295 #define USB_VENDOR_FINTEK 0x1934 296 #endif 297 #ifndef USB_PRODUCT_FINTEK_SERIAL 298 #define USB_PRODUCT_FINTEK_SERIAL 0x0706 299 #endif 300 #ifndef FINTEK_MODEL_F81232 301 #define FINTEK_MODEL_F81232 0x02 302 #endif 303 304 static const STRUCT_USB_HOST_ID ufintek_devs[] = { 305 {USB_VPI(USB_VENDOR_FINTEK, USB_PRODUCT_FINTEK_SERIAL, FINTEK_MODEL_F81232)} 306 }; 307 308 DRIVER_MODULE(ufintek, uhub, ufintek_driver, NULL, NULL); 309 MODULE_DEPEND(ufintek, ucom, 1, 1, 1); 310 MODULE_DEPEND(ufintek, usb, 1, 1, 1); 311 MODULE_VERSION(ufintek, 1); 312 USB_PNP_HOST_INFO(ufintek_devs); 313 314 #define UFINTEK_DEFAULT_BAUD 115200 315 #define UFINTEK_DEFAULT_LCR UFINTEK_LCR_WORDLEN_8|UFINTEK_LCR_STOP_BITS_1| \ 316 UFINTEK_LCR_PARITY_NONE 317 318 static int 319 ufintek_probe(device_t dev) 320 { 321 struct usb_attach_arg *uaa = device_get_ivars(dev); 322 323 if (uaa->usb_mode != USB_MODE_HOST) { 324 return (ENXIO); 325 } 326 if (uaa->info.bConfigIndex != UFINTEK_CONFIG_INDEX) { 327 return (ENXIO); 328 } 329 if (uaa->info.bIfaceIndex != UFINTEK_IFACE_INDEX) { 330 return (ENXIO); 331 } 332 return (usbd_lookup_id_by_uaa(ufintek_devs, sizeof(ufintek_devs), uaa)); 333 } 334 335 static int 336 ufintek_attach(device_t dev) 337 { 338 struct usb_attach_arg *uaa = device_get_ivars(dev); 339 struct ufintek_softc *sc = device_get_softc(dev); 340 int error; 341 uint8_t iface_index; 342 343 sc->sc_udev = uaa->device; 344 345 device_set_usb_desc(dev); 346 347 device_printf(dev, "<FINTEK USB Serial Port Adapter>\n"); 348 349 mtx_init(&sc->sc_mtx, "ufintek", NULL, MTX_DEF); 350 ucom_ref(&sc->sc_super_ucom); 351 352 DPRINTF("\n"); 353 354 /* get chip model */ 355 sc->sc_model = USB_GET_DRIVER_INFO(uaa); 356 if (sc->sc_model == 0) { 357 device_printf(dev, "unsupported device\n"); 358 goto detach; 359 } 360 device_printf(dev, "FINTEK F8123%X USB to RS232 bridge\n", sc->sc_model); 361 iface_index = UFINTEK_IFACE_INDEX; 362 error = usbd_transfer_setup(uaa->device, &iface_index, 363 sc->sc_xfer, ufintek_config, 364 UFINTEK_N_TRANSFER, sc, &sc->sc_mtx); 365 366 if (error) { 367 device_printf(dev, "allocating USB transfers failed\n"); 368 goto detach; 369 } 370 371 /* clear stall at first run */ 372 mtx_lock(&sc->sc_mtx); 373 usbd_xfer_set_stall(sc->sc_xfer[UFINTEK_BULK_DT_WR]); 374 usbd_xfer_set_stall(sc->sc_xfer[UFINTEK_BULK_DT_RD]); 375 mtx_unlock(&sc->sc_mtx); 376 377 error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 378 &ufintek_callback, &sc->sc_mtx); 379 if (error) { 380 goto detach; 381 } 382 ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); 383 384 return (0); /* success */ 385 386 detach: 387 ufintek_detach(dev); 388 return (ENXIO); 389 } 390 391 static int 392 ufintek_detach(device_t dev) 393 { 394 struct ufintek_softc *sc = device_get_softc(dev); 395 396 ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); 397 usbd_transfer_unsetup(sc->sc_xfer, UFINTEK_N_TRANSFER); 398 399 device_claim_softc(dev); 400 401 ufintek_free_softc(sc); 402 403 return (0); 404 } 405 406 UCOM_UNLOAD_DRAIN(ufintek); 407 408 static void 409 ufintek_free_softc(struct ufintek_softc *sc) 410 { 411 if (ucom_unref(&sc->sc_super_ucom)) { 412 mtx_destroy(&sc->sc_mtx); 413 device_free_softc(sc); 414 } 415 } 416 417 static void 418 ufintek_free(struct ucom_softc *ucom) 419 { 420 ufintek_free_softc(ucom->sc_parent); 421 } 422 423 static void 424 ufintek_cfg_open(struct ucom_softc *ucom) 425 { 426 struct ufintek_softc *sc = ucom->sc_parent; 427 428 /* Enable FIFO, trigger8 */ 429 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_FCR, 430 UFINTEK_FCR_EN | UFINTEK_FCR_TRIGGER_8); 431 432 sc->sc_mcr = UFINTEK_MCR_DTR|UFINTEK_MCR_RTS; 433 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_MCR, sc->sc_mcr); 434 435 /* Enable interrupts */ 436 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_IER, 437 UFINTEK_IER_MSI ); 438 } 439 440 static void 441 ufintek_cfg_close(struct ucom_softc *ucom) 442 { 443 return; 444 } 445 446 static void 447 ufintek_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) 448 { 449 struct ufintek_softc *sc = ucom->sc_parent; 450 451 if (onoff) 452 sc->sc_lcr |= UFINTEK_LCR_BREAK; 453 else 454 sc->sc_lcr &= ~UFINTEK_LCR_BREAK; 455 456 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_LCR, sc->sc_lcr); 457 } 458 459 static void 460 ufintek_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 461 { 462 struct ufintek_softc *sc = ucom->sc_parent; 463 464 if (onoff) 465 sc->sc_mcr |= UFINTEK_MCR_DTR; 466 else 467 sc->sc_mcr &= ~UFINTEK_MCR_DTR; 468 469 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_MCR, sc->sc_mcr); 470 } 471 472 static void 473 ufintek_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) 474 { 475 struct ufintek_softc *sc = ucom->sc_parent; 476 477 if (onoff) 478 sc->sc_mcr |= UFINTEK_MCR_RTS; 479 else 480 sc->sc_mcr &= ~UFINTEK_MCR_RTS; 481 482 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_MCR, sc->sc_mcr); 483 } 484 485 static int 486 ufintek_pre_param(struct ucom_softc *ucom, struct termios *t) 487 { 488 struct ufintek_softc *sc = ucom->sc_parent; 489 uint16_t divisor; 490 491 if ((t->c_ospeed <= 1) || (t->c_ospeed > 115200)) 492 return (EINVAL); 493 494 sc->sc_mcr = UFINTEK_MCR_DTR|UFINTEK_MCR_RTS; 495 sc->sc_lcr = UFINTEK_DEFAULT_LCR; 496 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_LCR, sc->sc_lcr); 497 498 DPRINTF("baud=%d\n", t->c_ospeed); 499 500 divisor = ((uint32_t)UFINTEK_BAUD_REF) / ((uint32_t)t->c_ospeed); 501 502 if (divisor == 0) { 503 DPRINTF("invalid baud rate!\n"); 504 return (1); 505 } 506 507 /* Flip RXBUF and TXBUF to BAUDLO and BAUDHI */ 508 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_LCR, UFINTEK_LCR_DLAB); 509 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_BAUDLO, 510 (divisor & 0xFF)); 511 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_BAUDHI, 512 ((divisor >> 8) & 0xFF)); 513 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_LCR, sc->sc_lcr); 514 515 return (0); 516 } 517 518 static void 519 ufintek_cfg_param(struct ucom_softc *ucom, struct termios *t) 520 { 521 struct ufintek_softc *sc = ucom->sc_parent; 522 uint8_t lcr=0; 523 uint16_t divisor; 524 525 DPRINTF("baud=%d\n", t->c_ospeed); 526 527 divisor = ((uint32_t)UFINTEK_BAUD_REF) / ((uint32_t)t->c_ospeed); 528 529 if (divisor == 0) { 530 DPRINTF("invalid baud rate!\n"); 531 return; 532 } 533 534 /* Flip RXBUF and TXBUF to BAUDLO and BAUDHI */ 535 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_LCR, UFINTEK_LCR_DLAB); 536 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_BAUDLO, 537 (divisor & 0xFF)); 538 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_BAUDHI, 539 ((divisor >> 8) & 0xFF)); 540 541 if (!(t->c_cflag & CIGNORE)) { 542 lcr = 0; 543 switch (t->c_cflag & CSIZE) { 544 case CS8: 545 lcr |= UFINTEK_LCR_WORDLEN_8; 546 break; 547 case CS7: 548 lcr |= UFINTEK_LCR_WORDLEN_7; 549 break; 550 case CS6: 551 lcr |= UFINTEK_LCR_WORDLEN_6; 552 break; 553 case CS5: 554 break; 555 default: 556 break; 557 } 558 559 if (t->c_cflag & CSTOPB) 560 lcr |= UFINTEK_LCR_STOP_BITS_1; 561 if (t->c_cflag & PARODD) 562 lcr |= UFINTEK_LCR_PARITY_ODD; 563 else if (t->c_cflag & PARENB) 564 lcr |= UFINTEK_LCR_PARITY_EVEN; 565 } 566 sc->sc_lcr = lcr; 567 ufintek_cfg_write(sc, UFINTEK_UART_REG | UFINTEK_LCR, sc->sc_lcr); 568 } 569 570 static void 571 ufintek_cfg_get_status(struct ucom_softc *ucom, uint8_t *p_lsr, uint8_t *p_msr) 572 { 573 struct ufintek_softc *sc = ucom->sc_parent; 574 uint8_t lsr; 575 uint8_t ufintek_msr; 576 577 lsr = ufintek_cfg_read(sc, UFINTEK_UART_REG | UFINTEK_LSR); 578 lsr &= 7; /* Only need bottom bits */ 579 *p_lsr = lsr; 580 581 ufintek_msr = ufintek_cfg_read(sc, UFINTEK_UART_REG | UFINTEK_MSR); 582 583 /* translate bits */ 584 585 *p_msr = 0; 586 if (ufintek_msr & UFINTEK_MSR_CTS) 587 *p_msr |= SER_CTS; 588 589 if (ufintek_msr & UFINTEK_MSR_CD) 590 *p_msr |= SER_DCD; 591 592 if (ufintek_msr & UFINTEK_MSR_RI) 593 *p_msr |= SER_RI; 594 595 if (ufintek_msr & UFINTEK_MSR_RTS) 596 *p_msr |= SER_RTS; 597 } 598 599 static void 600 ufintek_start_read(struct ucom_softc *ucom) 601 { 602 struct ufintek_softc *sc = ucom->sc_parent; 603 604 usbd_transfer_start(sc->sc_xfer[UFINTEK_BULK_DT_RD]); 605 } 606 607 static void 608 ufintek_stop_read(struct ucom_softc *ucom) 609 { 610 struct ufintek_softc *sc = ucom->sc_parent; 611 612 usbd_transfer_stop(sc->sc_xfer[UFINTEK_BULK_DT_RD]); 613 } 614 615 static void 616 ufintek_start_write(struct ucom_softc *ucom) 617 { 618 struct ufintek_softc *sc = ucom->sc_parent; 619 620 usbd_transfer_start(sc->sc_xfer[UFINTEK_BULK_DT_WR]); 621 } 622 623 static void 624 ufintek_stop_write(struct ucom_softc *ucom) 625 { 626 struct ufintek_softc *sc = ucom->sc_parent; 627 628 usbd_transfer_stop(sc->sc_xfer[UFINTEK_BULK_DT_WR]); 629 } 630 631 static void 632 ufintek_cfg_write(struct ufintek_softc *sc, uint16_t reg, uint8_t val) 633 { 634 struct usb_device_request req; 635 usb_error_t uerr; 636 uint8_t data; 637 638 req.bmRequestType = UFINTEK_WRITE; 639 req.bRequest = UFINTEK_REGISTER_REQUEST; 640 USETW(req.wValue, reg); 641 USETW(req.wIndex, 0); 642 USETW(req.wLength, 1); 643 644 data = val; 645 646 uerr = ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 647 &req, &data, 0, 1000); 648 if (uerr != 0) 649 DPRINTF("failed to set ctrl %s\n", usbd_errstr(uerr)); 650 } 651 652 static uint8_t 653 ufintek_cfg_read(struct ufintek_softc *sc, uint16_t reg) 654 { 655 struct usb_device_request req; 656 uint8_t val; 657 658 req.bmRequestType = UFINTEK_READ; 659 req.bRequest = UFINTEK_REGISTER_REQUEST; 660 USETW(req.wValue, reg); 661 USETW(req.wIndex, 0); 662 USETW(req.wLength, 1); 663 664 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 665 &req, &val, 0, 1000); 666 667 DPRINTF("reg=0x%04x, val=0x%02x\n", reg, val); 668 return (val); 669 } 670 671 672 static void 673 ufintek_write_callback(struct usb_xfer *xfer, usb_error_t error) 674 { 675 struct ufintek_softc *sc = usbd_xfer_softc(xfer); 676 struct usb_page_cache *pc; 677 uint32_t actlen; 678 679 switch (USB_GET_STATE(xfer)) { 680 case USB_ST_SETUP: 681 case USB_ST_TRANSFERRED: 682 tr_setup: 683 684 pc = usbd_xfer_get_frame(xfer, 0); 685 if (ucom_get_data(&sc->sc_ucom, pc, 0, 686 UFINTEK_BUFSIZE, &actlen)) { 687 usbd_xfer_set_frame_len(xfer, 0, actlen); 688 usbd_transfer_submit(xfer); 689 } 690 return; 691 692 default: /* Error */ 693 if (error != USB_ERR_CANCELLED) { 694 /* try to clear stall first */ 695 usbd_xfer_set_stall(xfer); 696 goto tr_setup; 697 } 698 return; 699 } 700 } 701 702 static void 703 ufintek_read_callback(struct usb_xfer *xfer, usb_error_t error) 704 { 705 struct ufintek_softc *sc = usbd_xfer_softc(xfer); 706 struct usb_page_cache *pc; 707 int actlen; 708 uint8_t buf[UFINTEK_BUFSIZE]; 709 int i; 710 711 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 712 switch (USB_GET_STATE(xfer)) { 713 case USB_ST_TRANSFERRED: 714 DPRINTF("got %d bytes\n", actlen); 715 if ((actlen < 2) || (actlen % 2)) 716 goto tr_setup; 717 pc = usbd_xfer_get_frame(xfer, 0); 718 usbd_copy_out(pc, 0, &buf, sizeof(buf)); 719 /* XXX From Linux driver the very first byte after open 720 * is supposed to be a status which we should ignore. 721 * Why it is 0xFF I don't know TBH. 722 */ 723 if (buf[0] == 0xFF) 724 buf[0] = ufintek_cfg_read(sc, UFINTEK_UART_REG); 725 else { 726 /* 727 * Annoyingly this device presents data as 728 * <LSR><DATA><LSR><DATA> ... 729 */ 730 for (i = 0; i < actlen; i += 2) { 731 ucom_put_data(&sc->sc_ucom, pc, i+1, 1); 732 } 733 734 /* FALLTHROUGH */ 735 } 736 case USB_ST_SETUP: 737 tr_setup: 738 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 739 usbd_transfer_submit(xfer); 740 return; 741 742 default: /* Error */ 743 if (error != USB_ERR_CANCELLED) { 744 /* try to clear stall first */ 745 usbd_xfer_set_stall(xfer); 746 goto tr_setup; 747 } 748 return; 749 } 750 } 751 752 753 754 static void 755 ufintek_poll(struct ucom_softc *ucom) 756 { 757 struct ufintek_softc *sc = ucom->sc_parent; 758 usbd_transfer_poll(sc->sc_xfer, UFINTEK_N_TRANSFER); 759 } 760