uftdi.c revision 190581
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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD: head/sys/dev/usb/serial/uftdi.c 190581 2009-03-30 22:18:38Z mav $"); 41 42/* 43 * NOTE: all function names beginning like "uftdi_cfg_" can only 44 * be called from within the config thread function ! 45 */ 46 47/* 48 * FTDI FT8U100AX serial adapter driver 49 */ 50 51#include "usbdevs.h" 52#include <dev/usb/usb.h> 53#include <dev/usb/usb_mfunc.h> 54#include <dev/usb/usb_error.h> 55#include <dev/usb/usb_cdc.h> 56 57#define USB_DEBUG_VAR uftdi_debug 58 59#include <dev/usb/usb_core.h> 60#include <dev/usb/usb_debug.h> 61#include <dev/usb/usb_process.h> 62#include <dev/usb/usb_request.h> 63#include <dev/usb/usb_lookup.h> 64#include <dev/usb/usb_util.h> 65#include <dev/usb/usb_busdma.h> 66 67#include <dev/usb/serial/usb_serial.h> 68#include <dev/usb/serial/uftdi_reg.h> 69 70#if USB_DEBUG 71static int uftdi_debug = 0; 72 73SYSCTL_NODE(_hw_usb2, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi"); 74SYSCTL_INT(_hw_usb2_uftdi, OID_AUTO, debug, CTLFLAG_RW, 75 &uftdi_debug, 0, "Debug level"); 76#endif 77 78#define UFTDI_CONFIG_INDEX 0 79#define UFTDI_IFACE_INDEX 0 80 81#define UFTDI_IBUFSIZE 64 /* bytes, maximum number of bytes per 82 * frame */ 83#define UFTDI_OBUFSIZE 64 /* bytes, cannot be increased due to 84 * do size encoding */ 85 86enum { 87 UFTDI_BULK_DT_WR, 88 UFTDI_BULK_DT_RD, 89 UFTDI_N_TRANSFER, 90}; 91 92struct uftdi_softc { 93 struct usb2_com_super_softc sc_super_ucom; 94 struct usb2_com_softc sc_ucom; 95 96 struct usb2_device *sc_udev; 97 struct usb2_xfer *sc_xfer[UFTDI_N_TRANSFER]; 98 device_t sc_dev; 99 struct mtx sc_mtx; 100 101 uint32_t sc_unit; 102 enum uftdi_type sc_type; 103 104 uint16_t sc_last_lcr; 105 106 uint8_t sc_iface_index; 107 uint8_t sc_hdrlen; 108 uint8_t sc_msr; 109 uint8_t sc_lsr; 110 111 uint8_t sc_name[16]; 112}; 113 114struct uftdi_param_config { 115 uint16_t rate; 116 uint16_t lcr; 117 uint8_t v_start; 118 uint8_t v_stop; 119 uint8_t v_flow; 120}; 121 122/* prototypes */ 123 124static device_probe_t uftdi_probe; 125static device_attach_t uftdi_attach; 126static device_detach_t uftdi_detach; 127 128static usb2_callback_t uftdi_write_callback; 129static usb2_callback_t uftdi_read_callback; 130 131static void uftdi_cfg_open(struct usb2_com_softc *); 132static void uftdi_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 133static void uftdi_cfg_set_rts(struct usb2_com_softc *, uint8_t); 134static void uftdi_cfg_set_break(struct usb2_com_softc *, uint8_t); 135static int uftdi_set_parm_soft(struct termios *, 136 struct uftdi_param_config *, uint8_t); 137static int uftdi_pre_param(struct usb2_com_softc *, struct termios *); 138static void uftdi_cfg_param(struct usb2_com_softc *, struct termios *); 139static void uftdi_cfg_get_status(struct usb2_com_softc *, uint8_t *, 140 uint8_t *); 141static void uftdi_start_read(struct usb2_com_softc *); 142static void uftdi_stop_read(struct usb2_com_softc *); 143static void uftdi_start_write(struct usb2_com_softc *); 144static void uftdi_stop_write(struct usb2_com_softc *); 145static uint8_t uftdi_8u232am_getrate(uint32_t, uint16_t *); 146 147static const struct usb2_config uftdi_config[UFTDI_N_TRANSFER] = { 148 149 [UFTDI_BULK_DT_WR] = { 150 .type = UE_BULK, 151 .endpoint = UE_ADDR_ANY, 152 .direction = UE_DIR_OUT, 153 .mh.bufsize = UFTDI_OBUFSIZE, 154 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 155 .mh.callback = &uftdi_write_callback, 156 }, 157 158 [UFTDI_BULK_DT_RD] = { 159 .type = UE_BULK, 160 .endpoint = UE_ADDR_ANY, 161 .direction = UE_DIR_IN, 162 .mh.bufsize = UFTDI_IBUFSIZE, 163 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 164 .mh.callback = &uftdi_read_callback, 165 }, 166}; 167 168static const struct usb2_com_callback uftdi_callback = { 169 .usb2_com_cfg_get_status = &uftdi_cfg_get_status, 170 .usb2_com_cfg_set_dtr = &uftdi_cfg_set_dtr, 171 .usb2_com_cfg_set_rts = &uftdi_cfg_set_rts, 172 .usb2_com_cfg_set_break = &uftdi_cfg_set_break, 173 .usb2_com_cfg_param = &uftdi_cfg_param, 174 .usb2_com_cfg_open = &uftdi_cfg_open, 175 .usb2_com_pre_param = &uftdi_pre_param, 176 .usb2_com_start_read = &uftdi_start_read, 177 .usb2_com_stop_read = &uftdi_stop_read, 178 .usb2_com_start_write = &uftdi_start_write, 179 .usb2_com_stop_write = &uftdi_stop_write, 180}; 181 182static device_method_t uftdi_methods[] = { 183 /* Device interface */ 184 DEVMETHOD(device_probe, uftdi_probe), 185 DEVMETHOD(device_attach, uftdi_attach), 186 DEVMETHOD(device_detach, uftdi_detach), 187 188 {0, 0} 189}; 190 191static devclass_t uftdi_devclass; 192 193static driver_t uftdi_driver = { 194 .name = "uftdi", 195 .methods = uftdi_methods, 196 .size = sizeof(struct uftdi_softc), 197}; 198 199DRIVER_MODULE(uftdi, uhub, uftdi_driver, uftdi_devclass, NULL, 0); 200MODULE_DEPEND(uftdi, ucom, 1, 1, 1); 201MODULE_DEPEND(uftdi, usb, 1, 1, 1); 202 203static struct usb2_device_id uftdi_devs[] = { 204 {USB_VPI(USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_STK541, UFTDI_TYPE_8U232AM)}, 205 {USB_VPI(USB_VENDOR_DRESDENELEKTRONIK, USB_PRODUCT_DRESDENELEKTRONIK_SENSORTERMINALBOARD, UFTDI_TYPE_8U232AM)}, 206 {USB_VPI(USB_VENDOR_DRESDENELEKTRONIK, USB_PRODUCT_DRESDENELEKTRONIK_WIRELESSHANDHELDTERMINAL, UFTDI_TYPE_8U232AM)}, 207 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_8U100AX, UFTDI_TYPE_SIO)}, 208 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_2232C, UFTDI_TYPE_8U232AM)}, 209 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_8U232AM, UFTDI_TYPE_8U232AM)}, 210 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SEMC_DSS20, UFTDI_TYPE_8U232AM)}, 211 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_631, UFTDI_TYPE_8U232AM)}, 212 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_632, UFTDI_TYPE_8U232AM)}, 213 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_633, UFTDI_TYPE_8U232AM)}, 214 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_634, UFTDI_TYPE_8U232AM)}, 215 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_635, UFTDI_TYPE_8U232AM)}, 216 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_USBSERIAL, UFTDI_TYPE_8U232AM)}, 217 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MX2_3, UFTDI_TYPE_8U232AM)}, 218 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MX4_5, UFTDI_TYPE_8U232AM)}, 219 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_LK202, UFTDI_TYPE_8U232AM)}, 220 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_LK204, UFTDI_TYPE_8U232AM)}, 221 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13M, UFTDI_TYPE_8U232AM)}, 222 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13S, UFTDI_TYPE_8U232AM)}, 223 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13U, UFTDI_TYPE_8U232AM)}, 224 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EISCOU, UFTDI_TYPE_8U232AM)}, 225 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_UOPTBR, UFTDI_TYPE_8U232AM)}, 226 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2D, UFTDI_TYPE_8U232AM)}, 227 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_PCMSFU, UFTDI_TYPE_8U232AM)}, 228 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2H, UFTDI_TYPE_8U232AM)}, 229 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MAXSTREAM, UFTDI_TYPE_8U232AM)}, 230 {USB_VPI(USB_VENDOR_SIIG2, USB_PRODUCT_SIIG2_US2308, UFTDI_TYPE_8U232AM)}, 231 {USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_VALUECAN, UFTDI_TYPE_8U232AM)}, 232 {USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_NEOVI, UFTDI_TYPE_8U232AM)}, 233 {USB_VPI(USB_VENDOR_BBELECTRONICS, USB_PRODUCT_BBELECTRONICS_USOTL4, UFTDI_TYPE_8U232AM)}, 234 {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_PCOPRS1, UFTDI_TYPE_8U232AM)}, 235}; 236 237static int 238uftdi_probe(device_t dev) 239{ 240 struct usb2_attach_arg *uaa = device_get_ivars(dev); 241 242 if (uaa->usb2_mode != USB_MODE_HOST) { 243 return (ENXIO); 244 } 245 if (uaa->info.bConfigIndex != UFTDI_CONFIG_INDEX) { 246 return (ENXIO); 247 } 248 /* attach to all present interfaces */ 249 250 return (usb2_lookup_id_by_uaa(uftdi_devs, sizeof(uftdi_devs), uaa)); 251} 252 253static int 254uftdi_attach(device_t dev) 255{ 256 struct usb2_attach_arg *uaa = device_get_ivars(dev); 257 struct uftdi_softc *sc = device_get_softc(dev); 258 int error; 259 260 sc->sc_udev = uaa->device; 261 sc->sc_dev = dev; 262 sc->sc_unit = device_get_unit(dev); 263 264 device_set_usb2_desc(dev); 265 mtx_init(&sc->sc_mtx, "uftdi", NULL, MTX_DEF); 266 267 snprintf(sc->sc_name, sizeof(sc->sc_name), 268 "%s", device_get_nameunit(dev)); 269 270 DPRINTF("\n"); 271 272 sc->sc_iface_index = uaa->info.bIfaceIndex; 273 sc->sc_type = USB_GET_DRIVER_INFO(uaa); 274 275 switch (sc->sc_type) { 276 case UFTDI_TYPE_SIO: 277 sc->sc_hdrlen = 1; 278 break; 279 case UFTDI_TYPE_8U232AM: 280 default: 281 sc->sc_hdrlen = 0; 282 break; 283 } 284 285 error = usb2_transfer_setup(uaa->device, 286 &sc->sc_iface_index, sc->sc_xfer, uftdi_config, 287 UFTDI_N_TRANSFER, sc, &sc->sc_mtx); 288 289 if (error) { 290 device_printf(dev, "allocating USB " 291 "transfers failed!\n"); 292 goto detach; 293 } 294 sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum; 295 296 /* clear stall at first run */ 297 mtx_lock(&sc->sc_mtx); 298 usb2_transfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_WR]); 299 usb2_transfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_RD]); 300 mtx_unlock(&sc->sc_mtx); 301 302 /* set a valid "lcr" value */ 303 304 sc->sc_last_lcr = 305 (FTDI_SIO_SET_DATA_STOP_BITS_2 | 306 FTDI_SIO_SET_DATA_PARITY_NONE | 307 FTDI_SIO_SET_DATA_BITS(8)); 308 309 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 310 &uftdi_callback, &sc->sc_mtx); 311 if (error) { 312 goto detach; 313 } 314 return (0); /* success */ 315 316detach: 317 uftdi_detach(dev); 318 return (ENXIO); 319} 320 321static int 322uftdi_detach(device_t dev) 323{ 324 struct uftdi_softc *sc = device_get_softc(dev); 325 326 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 327 usb2_transfer_unsetup(sc->sc_xfer, UFTDI_N_TRANSFER); 328 mtx_destroy(&sc->sc_mtx); 329 330 return (0); 331} 332 333static void 334uftdi_cfg_open(struct usb2_com_softc *ucom) 335{ 336 struct uftdi_softc *sc = ucom->sc_parent; 337 uint16_t wIndex = ucom->sc_portno; 338 struct usb2_device_request req; 339 340 DPRINTF(""); 341 342 /* perform a full reset on the device */ 343 344 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 345 req.bRequest = FTDI_SIO_RESET; 346 USETW(req.wValue, FTDI_SIO_RESET_SIO); 347 USETW(req.wIndex, wIndex); 348 USETW(req.wLength, 0); 349 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 350 &req, NULL, 0, 1000); 351 352 /* turn on RTS/CTS flow control */ 353 354 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 355 req.bRequest = FTDI_SIO_SET_FLOW_CTRL; 356 USETW(req.wValue, 0); 357 USETW2(req.wIndex, FTDI_SIO_RTS_CTS_HS, wIndex); 358 USETW(req.wLength, 0); 359 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 360 &req, NULL, 0, 1000); 361 362 /* 363 * NOTE: with the new UCOM layer there will always be a 364 * "uftdi_cfg_param()" call after "open()", so there is no need for 365 * "open()" to configure anything 366 */ 367} 368 369static void 370uftdi_write_callback(struct usb2_xfer *xfer) 371{ 372 struct uftdi_softc *sc = xfer->priv_sc; 373 uint32_t actlen; 374 uint8_t buf[1]; 375 376 switch (USB_GET_STATE(xfer)) { 377 case USB_ST_SETUP: 378 case USB_ST_TRANSFERRED: 379tr_setup: 380 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 381 sc->sc_hdrlen, UFTDI_OBUFSIZE - sc->sc_hdrlen, 382 &actlen)) { 383 384 if (sc->sc_hdrlen > 0) { 385 buf[0] = 386 FTDI_OUT_TAG(actlen, sc->sc_ucom.sc_portno); 387 usb2_copy_in(xfer->frbuffers, 0, buf, 1); 388 } 389 xfer->frlengths[0] = actlen + sc->sc_hdrlen; 390 usb2_start_hardware(xfer); 391 } 392 return; 393 394 default: /* Error */ 395 if (xfer->error != USB_ERR_CANCELLED) { 396 /* try to clear stall first */ 397 xfer->flags.stall_pipe = 1; 398 goto tr_setup; 399 } 400 return; 401 } 402} 403 404static void 405uftdi_read_callback(struct usb2_xfer *xfer) 406{ 407 struct uftdi_softc *sc = xfer->priv_sc; 408 uint8_t buf[2]; 409 uint8_t ftdi_msr; 410 uint8_t msr; 411 uint8_t lsr; 412 413 switch (USB_GET_STATE(xfer)) { 414 case USB_ST_TRANSFERRED: 415 416 if (xfer->actlen < 2) { 417 goto tr_setup; 418 } 419 usb2_copy_out(xfer->frbuffers, 0, buf, 2); 420 421 ftdi_msr = FTDI_GET_MSR(buf); 422 lsr = FTDI_GET_LSR(buf); 423 424 msr = 0; 425 if (ftdi_msr & FTDI_SIO_CTS_MASK) 426 msr |= SER_CTS; 427 if (ftdi_msr & FTDI_SIO_DSR_MASK) 428 msr |= SER_DSR; 429 if (ftdi_msr & FTDI_SIO_RI_MASK) 430 msr |= SER_RI; 431 if (ftdi_msr & FTDI_SIO_RLSD_MASK) 432 msr |= SER_DCD; 433 434 if ((sc->sc_msr != msr) || 435 ((sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK))) { 436 DPRINTF("status change msr=0x%02x (0x%02x) " 437 "lsr=0x%02x (0x%02x)\n", msr, sc->sc_msr, 438 lsr, sc->sc_lsr); 439 440 sc->sc_msr = msr; 441 sc->sc_lsr = lsr; 442 443 usb2_com_status_change(&sc->sc_ucom); 444 } 445 xfer->actlen -= 2; 446 447 if (xfer->actlen > 0) { 448 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 2, 449 xfer->actlen); 450 } 451 case USB_ST_SETUP: 452tr_setup: 453 xfer->frlengths[0] = xfer->max_data_length; 454 usb2_start_hardware(xfer); 455 return; 456 457 default: /* Error */ 458 if (xfer->error != USB_ERR_CANCELLED) { 459 /* try to clear stall first */ 460 xfer->flags.stall_pipe = 1; 461 goto tr_setup; 462 } 463 return; 464 } 465} 466 467static void 468uftdi_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 469{ 470 struct uftdi_softc *sc = ucom->sc_parent; 471 uint16_t wIndex = ucom->sc_portno; 472 uint16_t wValue; 473 struct usb2_device_request req; 474 475 wValue = onoff ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW; 476 477 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 478 req.bRequest = FTDI_SIO_MODEM_CTRL; 479 USETW(req.wValue, wValue); 480 USETW(req.wIndex, wIndex); 481 USETW(req.wLength, 0); 482 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 483 &req, NULL, 0, 1000); 484} 485 486static void 487uftdi_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 488{ 489 struct uftdi_softc *sc = ucom->sc_parent; 490 uint16_t wIndex = ucom->sc_portno; 491 uint16_t wValue; 492 struct usb2_device_request req; 493 494 wValue = onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW; 495 496 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 497 req.bRequest = FTDI_SIO_MODEM_CTRL; 498 USETW(req.wValue, wValue); 499 USETW(req.wIndex, wIndex); 500 USETW(req.wLength, 0); 501 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 502 &req, NULL, 0, 1000); 503} 504 505static void 506uftdi_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 507{ 508 struct uftdi_softc *sc = ucom->sc_parent; 509 uint16_t wIndex = ucom->sc_portno; 510 uint16_t wValue; 511 struct usb2_device_request req; 512 513 if (onoff) { 514 sc->sc_last_lcr |= FTDI_SIO_SET_BREAK; 515 } else { 516 sc->sc_last_lcr &= ~FTDI_SIO_SET_BREAK; 517 } 518 519 wValue = sc->sc_last_lcr; 520 521 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 522 req.bRequest = FTDI_SIO_SET_DATA; 523 USETW(req.wValue, wValue); 524 USETW(req.wIndex, wIndex); 525 USETW(req.wLength, 0); 526 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 527 &req, NULL, 0, 1000); 528} 529 530static int 531uftdi_set_parm_soft(struct termios *t, 532 struct uftdi_param_config *cfg, uint8_t type) 533{ 534 bzero(cfg, sizeof(*cfg)); 535 536 switch (type) { 537 case UFTDI_TYPE_SIO: 538 switch (t->c_ospeed) { 539 case 300: 540 cfg->rate = ftdi_sio_b300; 541 break; 542 case 600: 543 cfg->rate = ftdi_sio_b600; 544 break; 545 case 1200: 546 cfg->rate = ftdi_sio_b1200; 547 break; 548 case 2400: 549 cfg->rate = ftdi_sio_b2400; 550 break; 551 case 4800: 552 cfg->rate = ftdi_sio_b4800; 553 break; 554 case 9600: 555 cfg->rate = ftdi_sio_b9600; 556 break; 557 case 19200: 558 cfg->rate = ftdi_sio_b19200; 559 break; 560 case 38400: 561 cfg->rate = ftdi_sio_b38400; 562 break; 563 case 57600: 564 cfg->rate = ftdi_sio_b57600; 565 break; 566 case 115200: 567 cfg->rate = ftdi_sio_b115200; 568 break; 569 default: 570 return (EINVAL); 571 } 572 break; 573 574 case UFTDI_TYPE_8U232AM: 575 if (uftdi_8u232am_getrate(t->c_ospeed, &cfg->rate)) { 576 return (EINVAL); 577 } 578 break; 579 } 580 581 if (t->c_cflag & CSTOPB) 582 cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_2; 583 else 584 cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_1; 585 586 if (t->c_cflag & PARENB) { 587 if (t->c_cflag & PARODD) { 588 cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_ODD; 589 } else { 590 cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_EVEN; 591 } 592 } else { 593 cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_NONE; 594 } 595 596 switch (t->c_cflag & CSIZE) { 597 case CS5: 598 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(5); 599 break; 600 601 case CS6: 602 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(6); 603 break; 604 605 case CS7: 606 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(7); 607 break; 608 609 case CS8: 610 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(8); 611 break; 612 } 613 614 if (t->c_cflag & CRTSCTS) { 615 cfg->v_flow = FTDI_SIO_RTS_CTS_HS; 616 } else if (t->c_iflag & (IXON | IXOFF)) { 617 cfg->v_flow = FTDI_SIO_XON_XOFF_HS; 618 cfg->v_start = t->c_cc[VSTART]; 619 cfg->v_stop = t->c_cc[VSTOP]; 620 } else { 621 cfg->v_flow = FTDI_SIO_DISABLE_FLOW_CTRL; 622 } 623 624 return (0); 625} 626 627static int 628uftdi_pre_param(struct usb2_com_softc *ucom, struct termios *t) 629{ 630 struct uftdi_softc *sc = ucom->sc_parent; 631 struct uftdi_param_config cfg; 632 633 DPRINTF("\n"); 634 635 return (uftdi_set_parm_soft(t, &cfg, sc->sc_type)); 636} 637 638static void 639uftdi_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 640{ 641 struct uftdi_softc *sc = ucom->sc_parent; 642 uint16_t wIndex = ucom->sc_portno; 643 struct uftdi_param_config cfg; 644 struct usb2_device_request req; 645 646 if (uftdi_set_parm_soft(t, &cfg, sc->sc_type)) { 647 /* should not happen */ 648 return; 649 } 650 sc->sc_last_lcr = cfg.lcr; 651 652 DPRINTF("\n"); 653 654 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 655 req.bRequest = FTDI_SIO_SET_BAUD_RATE; 656 USETW(req.wValue, cfg.rate); 657 USETW(req.wIndex, wIndex); 658 USETW(req.wLength, 0); 659 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 660 &req, NULL, 0, 1000); 661 662 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 663 req.bRequest = FTDI_SIO_SET_DATA; 664 USETW(req.wValue, cfg.lcr); 665 USETW(req.wIndex, wIndex); 666 USETW(req.wLength, 0); 667 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 668 &req, NULL, 0, 1000); 669 670 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 671 req.bRequest = FTDI_SIO_SET_FLOW_CTRL; 672 USETW2(req.wValue, cfg.v_stop, cfg.v_start); 673 USETW2(req.wIndex, cfg.v_flow, wIndex); 674 USETW(req.wLength, 0); 675 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 676 &req, NULL, 0, 1000); 677} 678 679static void 680uftdi_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 681{ 682 struct uftdi_softc *sc = ucom->sc_parent; 683 684 DPRINTF("msr=0x%02x lsr=0x%02x\n", 685 sc->sc_msr, sc->sc_lsr); 686 687 *msr = sc->sc_msr; 688 *lsr = sc->sc_lsr; 689} 690 691static void 692uftdi_start_read(struct usb2_com_softc *ucom) 693{ 694 struct uftdi_softc *sc = ucom->sc_parent; 695 696 usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_RD]); 697} 698 699static void 700uftdi_stop_read(struct usb2_com_softc *ucom) 701{ 702 struct uftdi_softc *sc = ucom->sc_parent; 703 704 usb2_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_RD]); 705} 706 707static void 708uftdi_start_write(struct usb2_com_softc *ucom) 709{ 710 struct uftdi_softc *sc = ucom->sc_parent; 711 712 usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_WR]); 713} 714 715static void 716uftdi_stop_write(struct usb2_com_softc *ucom) 717{ 718 struct uftdi_softc *sc = ucom->sc_parent; 719 720 usb2_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_WR]); 721} 722 723/*------------------------------------------------------------------------* 724 * uftdi_8u232am_getrate 725 * 726 * Return values: 727 * 0: Success 728 * Else: Failure 729 *------------------------------------------------------------------------*/ 730static uint8_t 731uftdi_8u232am_getrate(uint32_t speed, uint16_t *rate) 732{ 733 /* Table of the nearest even powers-of-2 for values 0..15. */ 734 static const uint8_t roundoff[16] = { 735 0, 2, 2, 4, 4, 4, 8, 8, 736 8, 8, 8, 8, 16, 16, 16, 16, 737 }; 738 uint32_t d; 739 uint32_t freq; 740 uint16_t result; 741 742 if ((speed < 178) || (speed > ((3000000 * 100) / 97))) 743 return (1); /* prevent numerical overflow */ 744 745 /* Special cases for 2M and 3M. */ 746 if ((speed >= ((3000000 * 100) / 103)) && 747 (speed <= ((3000000 * 100) / 97))) { 748 result = 0; 749 goto done; 750 } 751 if ((speed >= ((2000000 * 100) / 103)) && 752 (speed <= ((2000000 * 100) / 97))) { 753 result = 1; 754 goto done; 755 } 756 d = (FTDI_8U232AM_FREQ << 4) / speed; 757 d = (d & ~15) + roundoff[d & 15]; 758 759 if (d < FTDI_8U232AM_MIN_DIV) 760 d = FTDI_8U232AM_MIN_DIV; 761 else if (d > FTDI_8U232AM_MAX_DIV) 762 d = FTDI_8U232AM_MAX_DIV; 763 764 /* 765 * Calculate the frequency needed for "d" to exactly divide down to 766 * our target "speed", and check that the actual frequency is within 767 * 3% of this. 768 */ 769 freq = (speed * d); 770 if ((freq < ((FTDI_8U232AM_FREQ * 1600ULL) / 103)) || 771 (freq > ((FTDI_8U232AM_FREQ * 1600ULL) / 97))) 772 return (1); 773 774 /* 775 * Pack the divisor into the resultant value. The lower 14-bits 776 * hold the integral part, while the upper 2 bits encode the 777 * fractional component: either 0, 0.5, 0.25, or 0.125. 778 */ 779 result = (d >> 4); 780 if (d & 8) 781 result |= 0x4000; 782 else if (d & 4) 783 result |= 0x8000; 784 else if (d & 2) 785 result |= 0xc000; 786 787done: 788 *rate = result; 789 return (0); 790} 791