1 /* $NetBSD: uftdi.c,v 1.13 2002/09/23 05:51:23 simonb Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (lennart@augustsson.net). 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 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 /* 36 * NOTE: all function names beginning like "uftdi_cfg_" can only 37 * be called from within the config thread function ! 38 */ 39 40 /* 41 * FTDI FT2232x, FT8U100AX and FT8U232AM serial adapter driver 42 */ 43 44 #include <sys/stdint.h> 45 #include <sys/stddef.h> 46 #include <sys/param.h> 47 #include <sys/queue.h> 48 #include <sys/types.h> 49 #include <sys/systm.h> 50 #include <sys/kernel.h> 51 #include <sys/bus.h> 52 #include <sys/module.h> 53 #include <sys/lock.h> 54 #include <sys/mutex.h> 55 #include <sys/condvar.h> 56 #include <sys/sysctl.h> 57 #include <sys/sx.h> 58 #include <sys/unistd.h> 59 #include <sys/callout.h> 60 #include <sys/malloc.h> 61 #include <sys/priv.h> 62 63 #include <dev/usb/usb.h> 64 #include <dev/usb/usbdi.h> 65 #include <dev/usb/usbdi_util.h> 66 #include "usbdevs.h" 67 68 #define USB_DEBUG_VAR uftdi_debug 69 #include <dev/usb/usb_debug.h> 70 #include <dev/usb/usb_process.h> 71 72 #include <dev/usb/serial/usb_serial.h> 73 #include <dev/usb/serial/uftdi_reg.h> 74 75 #ifdef USB_DEBUG 76 static int uftdi_debug = 0; 77 78 static SYSCTL_NODE(_hw_usb, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi"); 79 SYSCTL_INT(_hw_usb_uftdi, OID_AUTO, debug, CTLFLAG_RW, 80 &uftdi_debug, 0, "Debug level"); 81 #endif 82 83 #define UFTDI_CONFIG_INDEX 0 84 #define UFTDI_IFACE_INDEX_JTAG 0 85 86 #define UFTDI_OBUFSIZE 64 /* bytes, cannot be increased due to 87 * do size encoding */ 88 89 enum { 90 UFTDI_BULK_DT_WR, 91 UFTDI_BULK_DT_RD, 92 UFTDI_N_TRANSFER, 93 }; 94 95 struct uftdi_softc { 96 struct ucom_super_softc sc_super_ucom; 97 struct ucom_softc sc_ucom; 98 99 struct usb_device *sc_udev; 100 struct usb_xfer *sc_xfer[UFTDI_N_TRANSFER]; 101 device_t sc_dev; 102 struct mtx sc_mtx; 103 104 uint32_t sc_unit; 105 106 uint16_t sc_last_lcr; 107 108 uint8_t sc_type; 109 uint8_t sc_iface_index; 110 uint8_t sc_hdrlen; 111 uint8_t sc_msr; 112 uint8_t sc_lsr; 113 114 uint8_t sc_name[16]; 115 }; 116 117 struct uftdi_param_config { 118 uint16_t rate; 119 uint16_t lcr; 120 uint8_t v_start; 121 uint8_t v_stop; 122 uint8_t v_flow; 123 }; 124 125 /* prototypes */ 126 127 static device_probe_t uftdi_probe; 128 static device_attach_t uftdi_attach; 129 static device_detach_t uftdi_detach; 130 131 static usb_callback_t uftdi_write_callback; 132 static usb_callback_t uftdi_read_callback; 133 134 static void uftdi_cfg_open(struct ucom_softc *); 135 static void uftdi_cfg_set_dtr(struct ucom_softc *, uint8_t); 136 static void uftdi_cfg_set_rts(struct ucom_softc *, uint8_t); 137 static void uftdi_cfg_set_break(struct ucom_softc *, uint8_t); 138 static int uftdi_set_parm_soft(struct termios *, 139 struct uftdi_param_config *, uint8_t); 140 static int uftdi_pre_param(struct ucom_softc *, struct termios *); 141 static void uftdi_cfg_param(struct ucom_softc *, struct termios *); 142 static void uftdi_cfg_get_status(struct ucom_softc *, uint8_t *, 143 uint8_t *); 144 static void uftdi_start_read(struct ucom_softc *); 145 static void uftdi_stop_read(struct ucom_softc *); 146 static void uftdi_start_write(struct ucom_softc *); 147 static void uftdi_stop_write(struct ucom_softc *); 148 static uint8_t uftdi_8u232am_getrate(uint32_t, uint16_t *); 149 static void uftdi_poll(struct ucom_softc *ucom); 150 151 static const struct usb_config uftdi_config[UFTDI_N_TRANSFER] = { 152 153 [UFTDI_BULK_DT_WR] = { 154 .type = UE_BULK, 155 .endpoint = UE_ADDR_ANY, 156 .direction = UE_DIR_OUT, 157 .bufsize = UFTDI_OBUFSIZE, 158 .flags = {.pipe_bof = 1,}, 159 .callback = &uftdi_write_callback, 160 }, 161 162 [UFTDI_BULK_DT_RD] = { 163 .type = UE_BULK, 164 .endpoint = UE_ADDR_ANY, 165 .direction = UE_DIR_IN, 166 .bufsize = 0, /* use wMaxPacketSize */ 167 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 168 .callback = &uftdi_read_callback, 169 }, 170 }; 171 172 static const struct ucom_callback uftdi_callback = { 173 .ucom_cfg_get_status = &uftdi_cfg_get_status, 174 .ucom_cfg_set_dtr = &uftdi_cfg_set_dtr, 175 .ucom_cfg_set_rts = &uftdi_cfg_set_rts, 176 .ucom_cfg_set_break = &uftdi_cfg_set_break, 177 .ucom_cfg_param = &uftdi_cfg_param, 178 .ucom_cfg_open = &uftdi_cfg_open, 179 .ucom_pre_param = &uftdi_pre_param, 180 .ucom_start_read = &uftdi_start_read, 181 .ucom_stop_read = &uftdi_stop_read, 182 .ucom_start_write = &uftdi_start_write, 183 .ucom_stop_write = &uftdi_stop_write, 184 .ucom_poll = &uftdi_poll, 185 }; 186 187 static device_method_t uftdi_methods[] = { 188 /* Device interface */ 189 DEVMETHOD(device_probe, uftdi_probe), 190 DEVMETHOD(device_attach, uftdi_attach), 191 DEVMETHOD(device_detach, uftdi_detach), 192 193 DEVMETHOD_END 194 }; 195 196 static devclass_t uftdi_devclass; 197 198 static driver_t uftdi_driver = { 199 .name = "uftdi", 200 .methods = uftdi_methods, 201 .size = sizeof(struct uftdi_softc), 202 }; 203 204 DRIVER_MODULE(uftdi, uhub, uftdi_driver, uftdi_devclass, NULL, NULL); 205 MODULE_DEPEND(uftdi, ucom, 1, 1, 1); 206 MODULE_DEPEND(uftdi, usb, 1, 1, 1); 207 MODULE_VERSION(uftdi, 1); 208 209 static const STRUCT_USB_HOST_ID uftdi_devs[] = { 210 #define UFTDI_DEV(v, p, i) \ 211 { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } 212 UFTDI_DEV(ATMEL, STK541, UFTDI_TYPE_8U232AM), 213 UFTDI_DEV(BBELECTRONICS, USOTL4, UFTDI_TYPE_8U232AM), 214 UFTDI_DEV(DRESDENELEKTRONIK, SENSORTERMINALBOARD, 215 UFTDI_TYPE_8U232AM), 216 UFTDI_DEV(DRESDENELEKTRONIK, WIRELESSHANDHELDTERMINAL, 217 UFTDI_TYPE_8U232AM), 218 UFTDI_DEV(FALCOM, TWIST, UFTDI_TYPE_8U232AM), 219 UFTDI_DEV(FTDI, BEAGLEBONE, UFTDI_TYPE_8U232AM), 220 UFTDI_DEV(FTDI, CFA_631, UFTDI_TYPE_8U232AM), 221 UFTDI_DEV(FTDI, CFA_632, UFTDI_TYPE_8U232AM), 222 UFTDI_DEV(FTDI, CFA_633, UFTDI_TYPE_8U232AM), 223 UFTDI_DEV(FTDI, CFA_634, UFTDI_TYPE_8U232AM), 224 UFTDI_DEV(FTDI, CFA_635, UFTDI_TYPE_8U232AM), 225 UFTDI_DEV(FTDI, CTI_USB_MINI_485, UFTDI_TYPE_8U232AM), 226 UFTDI_DEV(FTDI, CTI_USB_NANO_485, UFTDI_TYPE_8U232AM), 227 UFTDI_DEV(FTDI, EISCOU, UFTDI_TYPE_8U232AM), 228 UFTDI_DEV(FTDI, EMCU2D, UFTDI_TYPE_8U232AM), 229 UFTDI_DEV(FTDI, EMCU2H, UFTDI_TYPE_8U232AM), 230 UFTDI_DEV(FTDI, GAMMASCOUT, UFTDI_TYPE_8U232AM), 231 UFTDI_DEV(FTDI, KBS, UFTDI_TYPE_8U232AM), 232 UFTDI_DEV(FTDI, LK202, UFTDI_TYPE_8U232AM), 233 UFTDI_DEV(FTDI, LK204, UFTDI_TYPE_8U232AM), 234 UFTDI_DEV(FTDI, MAXSTREAM, UFTDI_TYPE_8U232AM), 235 UFTDI_DEV(FTDI, MX2_3, UFTDI_TYPE_8U232AM), 236 UFTDI_DEV(FTDI, MX4_5, UFTDI_TYPE_8U232AM), 237 UFTDI_DEV(FTDI, PCMSFU, UFTDI_TYPE_8U232AM), 238 UFTDI_DEV(FTDI, SEMC_DSS20, UFTDI_TYPE_8U232AM), 239 UFTDI_DEV(FTDI, SERIAL_2232C, UFTDI_TYPE_8U232AM), 240 UFTDI_DEV(FTDI, SERIAL_2232D, UFTDI_TYPE_8U232AM), 241 UFTDI_DEV(FTDI, SERIAL_4232H, UFTDI_TYPE_8U232AM), 242 UFTDI_DEV(FTDI, SERIAL_8U100AX, UFTDI_TYPE_SIO), 243 UFTDI_DEV(FTDI, SERIAL_8U232AM, UFTDI_TYPE_8U232AM), 244 UFTDI_DEV(FTDI, SERIAL_8U232AM4, UFTDI_TYPE_8U232AM), 245 UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13M, UFTDI_TYPE_8U232AM), 246 UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13S, UFTDI_TYPE_8U232AM), 247 UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13U, UFTDI_TYPE_8U232AM), 248 UFTDI_DEV(FTDI, TURTELIZER2, UFTDI_TYPE_8U232AM | UFTDI_FLAG_JTAG), 249 UFTDI_DEV(FTDI, UOPTBR, UFTDI_TYPE_8U232AM), 250 UFTDI_DEV(FTDI, USBSERIAL, UFTDI_TYPE_8U232AM), 251 UFTDI_DEV(FTDI, USB_UIRT, UFTDI_TYPE_8U232AM), 252 UFTDI_DEV(INTREPIDCS, NEOVI, UFTDI_TYPE_8U232AM), 253 UFTDI_DEV(INTREPIDCS, VALUECAN, UFTDI_TYPE_8U232AM), 254 UFTDI_DEV(MARVELL, SHEEVAPLUG, UFTDI_TYPE_8U232AM), 255 UFTDI_DEV(MATRIXORBITAL, MOUA, UFTDI_TYPE_8U232AM), 256 UFTDI_DEV(MELCO, PCOPRS1, UFTDI_TYPE_8U232AM), 257 UFTDI_DEV(RATOC, REXUSB60F, UFTDI_TYPE_8U232AM), 258 UFTDI_DEV(SIIG2, US2308, UFTDI_TYPE_8U232AM) 259 #undef UFTDI_DEV 260 }; 261 262 static int 263 uftdi_probe(device_t dev) 264 { 265 struct usb_attach_arg *uaa = device_get_ivars(dev); 266 const struct usb_device_id *id; 267 268 if (uaa->usb_mode != USB_MODE_HOST) { 269 return (ENXIO); 270 } 271 if (uaa->info.bConfigIndex != UFTDI_CONFIG_INDEX) { 272 return (ENXIO); 273 } 274 275 /* 276 * Attach to all present interfaces unless this is a JTAG one, which 277 * we leave for userland. 278 */ 279 id = usbd_lookup_id_by_info(uftdi_devs, sizeof(uftdi_devs), 280 &uaa->info); 281 if (id == NULL) 282 return (ENXIO); 283 if ((id->driver_info & UFTDI_FLAG_JTAG) != 0 && 284 uaa->info.bIfaceIndex == UFTDI_IFACE_INDEX_JTAG) { 285 printf("%s: skipping JTAG interface at %u.%u\n", 286 device_get_name(dev), usbd_get_bus_index(uaa->device), 287 usbd_get_device_index(uaa->device)); 288 return (ENXIO); 289 } 290 uaa->driver_info = id->driver_info; 291 return (BUS_PROBE_SPECIFIC); 292 } 293 294 static int 295 uftdi_attach(device_t dev) 296 { 297 struct usb_attach_arg *uaa = device_get_ivars(dev); 298 struct uftdi_softc *sc = device_get_softc(dev); 299 int error; 300 301 sc->sc_udev = uaa->device; 302 sc->sc_dev = dev; 303 sc->sc_unit = device_get_unit(dev); 304 305 device_set_usb_desc(dev); 306 mtx_init(&sc->sc_mtx, "uftdi", NULL, MTX_DEF); 307 308 snprintf(sc->sc_name, sizeof(sc->sc_name), 309 "%s", device_get_nameunit(dev)); 310 311 DPRINTF("\n"); 312 313 sc->sc_iface_index = uaa->info.bIfaceIndex; 314 sc->sc_type = USB_GET_DRIVER_INFO(uaa) & UFTDI_TYPE_MASK; 315 316 switch (sc->sc_type) { 317 case UFTDI_TYPE_SIO: 318 sc->sc_hdrlen = 1; 319 break; 320 case UFTDI_TYPE_8U232AM: 321 default: 322 sc->sc_hdrlen = 0; 323 break; 324 } 325 326 error = usbd_transfer_setup(uaa->device, 327 &sc->sc_iface_index, sc->sc_xfer, uftdi_config, 328 UFTDI_N_TRANSFER, sc, &sc->sc_mtx); 329 330 if (error) { 331 device_printf(dev, "allocating USB " 332 "transfers failed\n"); 333 goto detach; 334 } 335 sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum; 336 337 /* clear stall at first run */ 338 mtx_lock(&sc->sc_mtx); 339 usbd_xfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_WR]); 340 usbd_xfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_RD]); 341 mtx_unlock(&sc->sc_mtx); 342 343 /* set a valid "lcr" value */ 344 345 sc->sc_last_lcr = 346 (FTDI_SIO_SET_DATA_STOP_BITS_2 | 347 FTDI_SIO_SET_DATA_PARITY_NONE | 348 FTDI_SIO_SET_DATA_BITS(8)); 349 350 error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 351 &uftdi_callback, &sc->sc_mtx); 352 if (error) { 353 goto detach; 354 } 355 ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); 356 357 return (0); /* success */ 358 359 detach: 360 uftdi_detach(dev); 361 return (ENXIO); 362 } 363 364 static int 365 uftdi_detach(device_t dev) 366 { 367 struct uftdi_softc *sc = device_get_softc(dev); 368 369 ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); 370 usbd_transfer_unsetup(sc->sc_xfer, UFTDI_N_TRANSFER); 371 mtx_destroy(&sc->sc_mtx); 372 373 return (0); 374 } 375 376 static void 377 uftdi_cfg_open(struct ucom_softc *ucom) 378 { 379 struct uftdi_softc *sc = ucom->sc_parent; 380 uint16_t wIndex = ucom->sc_portno; 381 struct usb_device_request req; 382 383 DPRINTF(""); 384 385 /* perform a full reset on the device */ 386 387 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 388 req.bRequest = FTDI_SIO_RESET; 389 USETW(req.wValue, FTDI_SIO_RESET_SIO); 390 USETW(req.wIndex, wIndex); 391 USETW(req.wLength, 0); 392 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 393 &req, NULL, 0, 1000); 394 395 /* turn on RTS/CTS flow control */ 396 397 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 398 req.bRequest = FTDI_SIO_SET_FLOW_CTRL; 399 USETW(req.wValue, 0); 400 USETW2(req.wIndex, FTDI_SIO_RTS_CTS_HS, wIndex); 401 USETW(req.wLength, 0); 402 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 403 &req, NULL, 0, 1000); 404 405 /* 406 * NOTE: with the new UCOM layer there will always be a 407 * "uftdi_cfg_param()" call after "open()", so there is no need for 408 * "open()" to configure anything 409 */ 410 } 411 412 static void 413 uftdi_write_callback(struct usb_xfer *xfer, usb_error_t error) 414 { 415 struct uftdi_softc *sc = usbd_xfer_softc(xfer); 416 struct usb_page_cache *pc; 417 uint32_t actlen; 418 uint8_t buf[1]; 419 420 switch (USB_GET_STATE(xfer)) { 421 case USB_ST_SETUP: 422 case USB_ST_TRANSFERRED: 423 tr_setup: 424 pc = usbd_xfer_get_frame(xfer, 0); 425 if (ucom_get_data(&sc->sc_ucom, pc, 426 sc->sc_hdrlen, UFTDI_OBUFSIZE - sc->sc_hdrlen, 427 &actlen)) { 428 429 if (sc->sc_hdrlen > 0) { 430 buf[0] = 431 FTDI_OUT_TAG(actlen, sc->sc_ucom.sc_portno); 432 usbd_copy_in(pc, 0, buf, 1); 433 } 434 usbd_xfer_set_frame_len(xfer, 0, actlen + sc->sc_hdrlen); 435 usbd_transfer_submit(xfer); 436 } 437 return; 438 439 default: /* Error */ 440 if (error != USB_ERR_CANCELLED) { 441 /* try to clear stall first */ 442 usbd_xfer_set_stall(xfer); 443 goto tr_setup; 444 } 445 return; 446 } 447 } 448 449 static void 450 uftdi_read_callback(struct usb_xfer *xfer, usb_error_t error) 451 { 452 struct uftdi_softc *sc = usbd_xfer_softc(xfer); 453 struct usb_page_cache *pc; 454 uint8_t buf[2]; 455 uint8_t ftdi_msr; 456 uint8_t msr; 457 uint8_t lsr; 458 int actlen; 459 460 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 461 462 switch (USB_GET_STATE(xfer)) { 463 case USB_ST_TRANSFERRED: 464 465 if (actlen < 2) { 466 goto tr_setup; 467 } 468 pc = usbd_xfer_get_frame(xfer, 0); 469 usbd_copy_out(pc, 0, buf, 2); 470 471 ftdi_msr = FTDI_GET_MSR(buf); 472 lsr = FTDI_GET_LSR(buf); 473 474 msr = 0; 475 if (ftdi_msr & FTDI_SIO_CTS_MASK) 476 msr |= SER_CTS; 477 if (ftdi_msr & FTDI_SIO_DSR_MASK) 478 msr |= SER_DSR; 479 if (ftdi_msr & FTDI_SIO_RI_MASK) 480 msr |= SER_RI; 481 if (ftdi_msr & FTDI_SIO_RLSD_MASK) 482 msr |= SER_DCD; 483 484 if ((sc->sc_msr != msr) || 485 ((sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK))) { 486 DPRINTF("status change msr=0x%02x (0x%02x) " 487 "lsr=0x%02x (0x%02x)\n", msr, sc->sc_msr, 488 lsr, sc->sc_lsr); 489 490 sc->sc_msr = msr; 491 sc->sc_lsr = lsr; 492 493 ucom_status_change(&sc->sc_ucom); 494 } 495 actlen -= 2; 496 497 if (actlen > 0) { 498 ucom_put_data(&sc->sc_ucom, pc, 2, actlen); 499 } 500 case USB_ST_SETUP: 501 tr_setup: 502 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 503 usbd_transfer_submit(xfer); 504 return; 505 506 default: /* Error */ 507 if (error != USB_ERR_CANCELLED) { 508 /* try to clear stall first */ 509 usbd_xfer_set_stall(xfer); 510 goto tr_setup; 511 } 512 return; 513 } 514 } 515 516 static void 517 uftdi_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 518 { 519 struct uftdi_softc *sc = ucom->sc_parent; 520 uint16_t wIndex = ucom->sc_portno; 521 uint16_t wValue; 522 struct usb_device_request req; 523 524 wValue = onoff ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW; 525 526 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 527 req.bRequest = FTDI_SIO_MODEM_CTRL; 528 USETW(req.wValue, wValue); 529 USETW(req.wIndex, wIndex); 530 USETW(req.wLength, 0); 531 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 532 &req, NULL, 0, 1000); 533 } 534 535 static void 536 uftdi_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) 537 { 538 struct uftdi_softc *sc = ucom->sc_parent; 539 uint16_t wIndex = ucom->sc_portno; 540 uint16_t wValue; 541 struct usb_device_request req; 542 543 wValue = onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW; 544 545 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 546 req.bRequest = FTDI_SIO_MODEM_CTRL; 547 USETW(req.wValue, wValue); 548 USETW(req.wIndex, wIndex); 549 USETW(req.wLength, 0); 550 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 551 &req, NULL, 0, 1000); 552 } 553 554 static void 555 uftdi_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) 556 { 557 struct uftdi_softc *sc = ucom->sc_parent; 558 uint16_t wIndex = ucom->sc_portno; 559 uint16_t wValue; 560 struct usb_device_request req; 561 562 if (onoff) { 563 sc->sc_last_lcr |= FTDI_SIO_SET_BREAK; 564 } else { 565 sc->sc_last_lcr &= ~FTDI_SIO_SET_BREAK; 566 } 567 568 wValue = sc->sc_last_lcr; 569 570 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 571 req.bRequest = FTDI_SIO_SET_DATA; 572 USETW(req.wValue, wValue); 573 USETW(req.wIndex, wIndex); 574 USETW(req.wLength, 0); 575 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 576 &req, NULL, 0, 1000); 577 } 578 579 static int 580 uftdi_set_parm_soft(struct termios *t, 581 struct uftdi_param_config *cfg, uint8_t type) 582 { 583 584 memset(cfg, 0, sizeof(*cfg)); 585 586 switch (type) { 587 case UFTDI_TYPE_SIO: 588 switch (t->c_ospeed) { 589 case 300: 590 cfg->rate = ftdi_sio_b300; 591 break; 592 case 600: 593 cfg->rate = ftdi_sio_b600; 594 break; 595 case 1200: 596 cfg->rate = ftdi_sio_b1200; 597 break; 598 case 2400: 599 cfg->rate = ftdi_sio_b2400; 600 break; 601 case 4800: 602 cfg->rate = ftdi_sio_b4800; 603 break; 604 case 9600: 605 cfg->rate = ftdi_sio_b9600; 606 break; 607 case 19200: 608 cfg->rate = ftdi_sio_b19200; 609 break; 610 case 38400: 611 cfg->rate = ftdi_sio_b38400; 612 break; 613 case 57600: 614 cfg->rate = ftdi_sio_b57600; 615 break; 616 case 115200: 617 cfg->rate = ftdi_sio_b115200; 618 break; 619 default: 620 return (EINVAL); 621 } 622 break; 623 624 case UFTDI_TYPE_8U232AM: 625 if (uftdi_8u232am_getrate(t->c_ospeed, &cfg->rate)) { 626 return (EINVAL); 627 } 628 break; 629 } 630 631 if (t->c_cflag & CSTOPB) 632 cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_2; 633 else 634 cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_1; 635 636 if (t->c_cflag & PARENB) { 637 if (t->c_cflag & PARODD) { 638 cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_ODD; 639 } else { 640 cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_EVEN; 641 } 642 } else { 643 cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_NONE; 644 } 645 646 switch (t->c_cflag & CSIZE) { 647 case CS5: 648 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(5); 649 break; 650 651 case CS6: 652 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(6); 653 break; 654 655 case CS7: 656 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(7); 657 break; 658 659 case CS8: 660 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(8); 661 break; 662 } 663 664 if (t->c_cflag & CRTSCTS) { 665 cfg->v_flow = FTDI_SIO_RTS_CTS_HS; 666 } else if (t->c_iflag & (IXON | IXOFF)) { 667 cfg->v_flow = FTDI_SIO_XON_XOFF_HS; 668 cfg->v_start = t->c_cc[VSTART]; 669 cfg->v_stop = t->c_cc[VSTOP]; 670 } else { 671 cfg->v_flow = FTDI_SIO_DISABLE_FLOW_CTRL; 672 } 673 674 return (0); 675 } 676 677 static int 678 uftdi_pre_param(struct ucom_softc *ucom, struct termios *t) 679 { 680 struct uftdi_softc *sc = ucom->sc_parent; 681 struct uftdi_param_config cfg; 682 683 DPRINTF("\n"); 684 685 return (uftdi_set_parm_soft(t, &cfg, sc->sc_type)); 686 } 687 688 static void 689 uftdi_cfg_param(struct ucom_softc *ucom, struct termios *t) 690 { 691 struct uftdi_softc *sc = ucom->sc_parent; 692 uint16_t wIndex = ucom->sc_portno; 693 struct uftdi_param_config cfg; 694 struct usb_device_request req; 695 696 if (uftdi_set_parm_soft(t, &cfg, sc->sc_type)) { 697 /* should not happen */ 698 return; 699 } 700 sc->sc_last_lcr = cfg.lcr; 701 702 DPRINTF("\n"); 703 704 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 705 req.bRequest = FTDI_SIO_SET_BAUD_RATE; 706 USETW(req.wValue, cfg.rate); 707 USETW(req.wIndex, wIndex); 708 USETW(req.wLength, 0); 709 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 710 &req, NULL, 0, 1000); 711 712 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 713 req.bRequest = FTDI_SIO_SET_DATA; 714 USETW(req.wValue, cfg.lcr); 715 USETW(req.wIndex, wIndex); 716 USETW(req.wLength, 0); 717 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 718 &req, NULL, 0, 1000); 719 720 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 721 req.bRequest = FTDI_SIO_SET_FLOW_CTRL; 722 USETW2(req.wValue, cfg.v_stop, cfg.v_start); 723 USETW2(req.wIndex, cfg.v_flow, wIndex); 724 USETW(req.wLength, 0); 725 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 726 &req, NULL, 0, 1000); 727 } 728 729 static void 730 uftdi_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) 731 { 732 struct uftdi_softc *sc = ucom->sc_parent; 733 734 DPRINTF("msr=0x%02x lsr=0x%02x\n", 735 sc->sc_msr, sc->sc_lsr); 736 737 *msr = sc->sc_msr; 738 *lsr = sc->sc_lsr; 739 } 740 741 static void 742 uftdi_start_read(struct ucom_softc *ucom) 743 { 744 struct uftdi_softc *sc = ucom->sc_parent; 745 746 usbd_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_RD]); 747 } 748 749 static void 750 uftdi_stop_read(struct ucom_softc *ucom) 751 { 752 struct uftdi_softc *sc = ucom->sc_parent; 753 754 usbd_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_RD]); 755 } 756 757 static void 758 uftdi_start_write(struct ucom_softc *ucom) 759 { 760 struct uftdi_softc *sc = ucom->sc_parent; 761 762 usbd_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_WR]); 763 } 764 765 static void 766 uftdi_stop_write(struct ucom_softc *ucom) 767 { 768 struct uftdi_softc *sc = ucom->sc_parent; 769 770 usbd_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_WR]); 771 } 772 773 /*------------------------------------------------------------------------* 774 * uftdi_8u232am_getrate 775 * 776 * Return values: 777 * 0: Success 778 * Else: Failure 779 *------------------------------------------------------------------------*/ 780 static uint8_t 781 uftdi_8u232am_getrate(uint32_t speed, uint16_t *rate) 782 { 783 /* Table of the nearest even powers-of-2 for values 0..15. */ 784 static const uint8_t roundoff[16] = { 785 0, 2, 2, 4, 4, 4, 8, 8, 786 8, 8, 8, 8, 16, 16, 16, 16, 787 }; 788 uint32_t d; 789 uint32_t freq; 790 uint16_t result; 791 792 if ((speed < 178) || (speed > ((3000000 * 100) / 97))) 793 return (1); /* prevent numerical overflow */ 794 795 /* Special cases for 2M and 3M. */ 796 if ((speed >= ((3000000 * 100) / 103)) && 797 (speed <= ((3000000 * 100) / 97))) { 798 result = 0; 799 goto done; 800 } 801 if ((speed >= ((2000000 * 100) / 103)) && 802 (speed <= ((2000000 * 100) / 97))) { 803 result = 1; 804 goto done; 805 } 806 d = (FTDI_8U232AM_FREQ << 4) / speed; 807 d = (d & ~15) + roundoff[d & 15]; 808 809 if (d < FTDI_8U232AM_MIN_DIV) 810 d = FTDI_8U232AM_MIN_DIV; 811 else if (d > FTDI_8U232AM_MAX_DIV) 812 d = FTDI_8U232AM_MAX_DIV; 813 814 /* 815 * Calculate the frequency needed for "d" to exactly divide down to 816 * our target "speed", and check that the actual frequency is within 817 * 3% of this. 818 */ 819 freq = (speed * d); 820 if ((freq < ((FTDI_8U232AM_FREQ * 1600ULL) / 103)) || 821 (freq > ((FTDI_8U232AM_FREQ * 1600ULL) / 97))) 822 return (1); 823 824 /* 825 * Pack the divisor into the resultant value. The lower 14-bits 826 * hold the integral part, while the upper 2 bits encode the 827 * fractional component: either 0, 0.5, 0.25, or 0.125. 828 */ 829 result = (d >> 4); 830 if (d & 8) 831 result |= 0x4000; 832 else if (d & 4) 833 result |= 0x8000; 834 else if (d & 2) 835 result |= 0xc000; 836 837 done: 838 *rate = result; 839 return (0); 840 } 841 842 static void 843 uftdi_poll(struct ucom_softc *ucom) 844 { 845 struct uftdi_softc *sc = ucom->sc_parent; 846 847 usbd_transfer_poll(sc->sc_xfer, UFTDI_N_TRANSFER); 848 } 849