uftdi.c revision 187970
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/usb2/serial/uftdi2.c 187970 2009-02-01 00:51:25Z thompsa $"); 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 <dev/usb2/include/usb2_devid.h> 52#include <dev/usb2/include/usb2_standard.h> 53#include <dev/usb2/include/usb2_mfunc.h> 54#include <dev/usb2/include/usb2_error.h> 55#include <dev/usb2/include/usb2_cdc.h> 56 57#define USB_DEBUG_VAR uftdi_debug 58 59#include <dev/usb2/core/usb2_core.h> 60#include <dev/usb2/core/usb2_debug.h> 61#include <dev/usb2/core/usb2_process.h> 62#include <dev/usb2/core/usb2_request.h> 63#include <dev/usb2/core/usb2_lookup.h> 64#include <dev/usb2/core/usb2_util.h> 65#include <dev/usb2/core/usb2_busdma.h> 66 67#include <dev/usb2/serial/usb2_serial.h> 68#include <dev/usb2/serial/uftdi2_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_BULK_CS_WR, 90 UFTDI_BULK_CS_RD, 91 UFTDI_N_TRANSFER = 4, 92}; 93 94struct uftdi_softc { 95 struct usb2_com_super_softc sc_super_ucom; 96 struct usb2_com_softc sc_ucom; 97 98 struct usb2_device *sc_udev; 99 struct usb2_xfer *sc_xfer[UFTDI_N_TRANSFER]; 100 device_t sc_dev; 101 102 uint32_t sc_unit; 103 enum uftdi_type sc_type; 104 105 uint16_t sc_last_lcr; 106 107 uint8_t sc_iface_index; 108 uint8_t sc_hdrlen; 109 110 uint8_t sc_msr; 111 uint8_t sc_lsr; 112 113 uint8_t sc_flag; 114#define UFTDI_FLAG_WRITE_STALL 0x01 115#define UFTDI_FLAG_READ_STALL 0x02 116 117 uint8_t sc_name[16]; 118}; 119 120struct uftdi_param_config { 121 uint16_t rate; 122 uint16_t lcr; 123 uint8_t v_start; 124 uint8_t v_stop; 125 uint8_t v_flow; 126}; 127 128/* prototypes */ 129 130static device_probe_t uftdi_probe; 131static device_attach_t uftdi_attach; 132static device_detach_t uftdi_detach; 133 134static usb2_callback_t uftdi_write_callback; 135static usb2_callback_t uftdi_write_clear_stall_callback; 136static usb2_callback_t uftdi_read_callback; 137static usb2_callback_t uftdi_read_clear_stall_callback; 138 139static void uftdi_cfg_do_request(struct uftdi_softc *, 140 struct usb2_device_request *, void *); 141static void uftdi_cfg_open(struct usb2_com_softc *); 142static void uftdi_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 143static void uftdi_cfg_set_rts(struct usb2_com_softc *, uint8_t); 144static void uftdi_cfg_set_break(struct usb2_com_softc *, uint8_t); 145static int uftdi_set_parm_soft(struct termios *, 146 struct uftdi_param_config *, uint8_t); 147static int uftdi_pre_param(struct usb2_com_softc *, struct termios *); 148static void uftdi_cfg_param(struct usb2_com_softc *, struct termios *); 149static void uftdi_cfg_get_status(struct usb2_com_softc *, uint8_t *, 150 uint8_t *); 151static void uftdi_start_read(struct usb2_com_softc *); 152static void uftdi_stop_read(struct usb2_com_softc *); 153static void uftdi_start_write(struct usb2_com_softc *); 154static void uftdi_stop_write(struct usb2_com_softc *); 155static uint8_t uftdi_8u232am_getrate(uint32_t, uint16_t *); 156 157static const struct usb2_config uftdi_config[UFTDI_N_TRANSFER] = { 158 159 [UFTDI_BULK_DT_WR] = { 160 .type = UE_BULK, 161 .endpoint = UE_ADDR_ANY, 162 .direction = UE_DIR_OUT, 163 .mh.bufsize = UFTDI_OBUFSIZE, 164 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 165 .mh.callback = &uftdi_write_callback, 166 }, 167 168 [UFTDI_BULK_DT_RD] = { 169 .type = UE_BULK, 170 .endpoint = UE_ADDR_ANY, 171 .direction = UE_DIR_IN, 172 .mh.bufsize = UFTDI_IBUFSIZE, 173 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 174 .mh.callback = &uftdi_read_callback, 175 }, 176 177 [UFTDI_BULK_CS_WR] = { 178 .type = UE_CONTROL, 179 .endpoint = 0x00, /* Control pipe */ 180 .direction = UE_DIR_ANY, 181 .mh.bufsize = sizeof(struct usb2_device_request), 182 .mh.flags = {}, 183 .mh.callback = &uftdi_write_clear_stall_callback, 184 .mh.timeout = 1000, /* 1 second */ 185 .mh.interval = 50, /* 50ms */ 186 }, 187 188 [UFTDI_BULK_CS_RD] = { 189 .type = UE_CONTROL, 190 .endpoint = 0x00, /* Control pipe */ 191 .direction = UE_DIR_ANY, 192 .mh.bufsize = sizeof(struct usb2_device_request), 193 .mh.flags = {}, 194 .mh.callback = &uftdi_read_clear_stall_callback, 195 .mh.timeout = 1000, /* 1 second */ 196 .mh.interval = 50, /* 50ms */ 197 }, 198}; 199 200static const struct usb2_com_callback uftdi_callback = { 201 .usb2_com_cfg_get_status = &uftdi_cfg_get_status, 202 .usb2_com_cfg_set_dtr = &uftdi_cfg_set_dtr, 203 .usb2_com_cfg_set_rts = &uftdi_cfg_set_rts, 204 .usb2_com_cfg_set_break = &uftdi_cfg_set_break, 205 .usb2_com_cfg_param = &uftdi_cfg_param, 206 .usb2_com_cfg_open = &uftdi_cfg_open, 207 .usb2_com_pre_param = &uftdi_pre_param, 208 .usb2_com_start_read = &uftdi_start_read, 209 .usb2_com_stop_read = &uftdi_stop_read, 210 .usb2_com_start_write = &uftdi_start_write, 211 .usb2_com_stop_write = &uftdi_stop_write, 212}; 213 214static device_method_t uftdi_methods[] = { 215 /* Device interface */ 216 DEVMETHOD(device_probe, uftdi_probe), 217 DEVMETHOD(device_attach, uftdi_attach), 218 DEVMETHOD(device_detach, uftdi_detach), 219 220 {0, 0} 221}; 222 223static devclass_t uftdi_devclass; 224 225static driver_t uftdi_driver = { 226 .name = "uftdi", 227 .methods = uftdi_methods, 228 .size = sizeof(struct uftdi_softc), 229}; 230 231DRIVER_MODULE(uftdi, ushub, uftdi_driver, uftdi_devclass, NULL, 0); 232MODULE_DEPEND(uftdi, usb2_serial, 1, 1, 1); 233MODULE_DEPEND(uftdi, usb2_core, 1, 1, 1); 234 235static struct usb2_device_id uftdi_devs[] = { 236 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_8U100AX, UFTDI_TYPE_SIO)}, 237 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_2232C, UFTDI_TYPE_8U232AM)}, 238 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_8U232AM, UFTDI_TYPE_8U232AM)}, 239 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SEMC_DSS20, UFTDI_TYPE_8U232AM)}, 240 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_631, UFTDI_TYPE_8U232AM)}, 241 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_632, UFTDI_TYPE_8U232AM)}, 242 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_633, UFTDI_TYPE_8U232AM)}, 243 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_634, UFTDI_TYPE_8U232AM)}, 244 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_635, UFTDI_TYPE_8U232AM)}, 245 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_USBSERIAL, UFTDI_TYPE_8U232AM)}, 246 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MX2_3, UFTDI_TYPE_8U232AM)}, 247 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MX4_5, UFTDI_TYPE_8U232AM)}, 248 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_LK202, UFTDI_TYPE_8U232AM)}, 249 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_LK204, UFTDI_TYPE_8U232AM)}, 250 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13M, UFTDI_TYPE_8U232AM)}, 251 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13S, UFTDI_TYPE_8U232AM)}, 252 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13U, UFTDI_TYPE_8U232AM)}, 253 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EISCOU, UFTDI_TYPE_8U232AM)}, 254 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_UOPTBR, UFTDI_TYPE_8U232AM)}, 255 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2D, UFTDI_TYPE_8U232AM)}, 256 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_PCMSFU, UFTDI_TYPE_8U232AM)}, 257 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2H, UFTDI_TYPE_8U232AM)}, 258 {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MAXSTREAM, UFTDI_TYPE_8U232AM)}, 259 {USB_VPI(USB_VENDOR_SIIG2, USB_PRODUCT_SIIG2_US2308, UFTDI_TYPE_8U232AM)}, 260 {USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_VALUECAN, UFTDI_TYPE_8U232AM)}, 261 {USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_NEOVI, UFTDI_TYPE_8U232AM)}, 262 {USB_VPI(USB_VENDOR_BBELECTRONICS, USB_PRODUCT_BBELECTRONICS_USOTL4, UFTDI_TYPE_8U232AM)}, 263 {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_PCOPRS1, UFTDI_TYPE_8U232AM)}, 264}; 265 266static int 267uftdi_probe(device_t dev) 268{ 269 struct usb2_attach_arg *uaa = device_get_ivars(dev); 270 271 if (uaa->usb2_mode != USB_MODE_HOST) { 272 return (ENXIO); 273 } 274 if (uaa->info.bConfigIndex != UFTDI_CONFIG_INDEX) { 275 return (ENXIO); 276 } 277 /* attach to all present interfaces */ 278 279 return (usb2_lookup_id_by_uaa(uftdi_devs, sizeof(uftdi_devs), uaa)); 280} 281 282static int 283uftdi_attach(device_t dev) 284{ 285 struct usb2_attach_arg *uaa = device_get_ivars(dev); 286 struct uftdi_softc *sc = device_get_softc(dev); 287 int error; 288 289 sc->sc_udev = uaa->device; 290 sc->sc_dev = dev; 291 sc->sc_unit = device_get_unit(dev); 292 293 device_set_usb2_desc(dev); 294 295 snprintf(sc->sc_name, sizeof(sc->sc_name), 296 "%s", device_get_nameunit(dev)); 297 298 DPRINTF("\n"); 299 300 sc->sc_iface_index = uaa->info.bIfaceIndex; 301 sc->sc_type = USB_GET_DRIVER_INFO(uaa); 302 303 switch (sc->sc_type) { 304 case UFTDI_TYPE_SIO: 305 sc->sc_hdrlen = 1; 306 break; 307 case UFTDI_TYPE_8U232AM: 308 default: 309 sc->sc_hdrlen = 0; 310 break; 311 } 312 313 error = usb2_transfer_setup(uaa->device, 314 &sc->sc_iface_index, sc->sc_xfer, uftdi_config, 315 UFTDI_N_TRANSFER, sc, &Giant); 316 317 if (error) { 318 device_printf(dev, "allocating USB " 319 "transfers failed!\n"); 320 goto detach; 321 } 322 sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum; 323 324 /* clear stall at first run */ 325 326 sc->sc_flag |= (UFTDI_FLAG_WRITE_STALL | 327 UFTDI_FLAG_READ_STALL); 328 329 /* set a valid "lcr" value */ 330 331 sc->sc_last_lcr = 332 (FTDI_SIO_SET_DATA_STOP_BITS_2 | 333 FTDI_SIO_SET_DATA_PARITY_NONE | 334 FTDI_SIO_SET_DATA_BITS(8)); 335 336 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 337 &uftdi_callback, &Giant); 338 if (error) { 339 goto detach; 340 } 341 return (0); /* success */ 342 343detach: 344 uftdi_detach(dev); 345 return (ENXIO); 346} 347 348static int 349uftdi_detach(device_t dev) 350{ 351 struct uftdi_softc *sc = device_get_softc(dev); 352 353 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 354 355 usb2_transfer_unsetup(sc->sc_xfer, UFTDI_N_TRANSFER); 356 357 return (0); 358} 359 360static void 361uftdi_cfg_do_request(struct uftdi_softc *sc, struct usb2_device_request *req, 362 void *data) 363{ 364 uint16_t length; 365 usb2_error_t err; 366 367 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 368 goto error; 369 } 370 err = usb2_do_request_flags 371 (sc->sc_udev, &Giant, req, data, 0, NULL, 1000); 372 373 if (err) { 374 375 DPRINTFN(0, "device request failed, err=%s " 376 "(ignored)\n", usb2_errstr(err)); 377 378error: 379 length = UGETW(req->wLength); 380 381 if ((req->bmRequestType & UT_READ) && length) { 382 bzero(data, length); 383 } 384 } 385} 386 387static void 388uftdi_cfg_open(struct usb2_com_softc *ucom) 389{ 390 struct uftdi_softc *sc = ucom->sc_parent; 391 uint16_t wIndex = ucom->sc_portno; 392 struct usb2_device_request req; 393 394 DPRINTF(""); 395 396 /* perform a full reset on the device */ 397 398 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 399 req.bRequest = FTDI_SIO_RESET; 400 USETW(req.wValue, FTDI_SIO_RESET_SIO); 401 USETW(req.wIndex, wIndex); 402 USETW(req.wLength, 0); 403 uftdi_cfg_do_request(sc, &req, NULL); 404 405 /* turn on RTS/CTS flow control */ 406 407 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 408 req.bRequest = FTDI_SIO_SET_FLOW_CTRL; 409 USETW(req.wValue, 0); 410 USETW2(req.wIndex, FTDI_SIO_RTS_CTS_HS, wIndex); 411 USETW(req.wLength, 0); 412 uftdi_cfg_do_request(sc, &req, NULL); 413 414 /* 415 * NOTE: with the new UCOM layer there will always be a 416 * "uftdi_cfg_param()" call after "open()", so there is no need for 417 * "open()" to configure anything 418 */ 419} 420 421static void 422uftdi_write_callback(struct usb2_xfer *xfer) 423{ 424 struct uftdi_softc *sc = xfer->priv_sc; 425 uint32_t actlen; 426 uint8_t buf[1]; 427 428 switch (USB_GET_STATE(xfer)) { 429 case USB_ST_SETUP: 430 case USB_ST_TRANSFERRED: 431 if (sc->sc_flag & UFTDI_FLAG_WRITE_STALL) { 432 usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_CS_WR]); 433 return; 434 } 435 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 436 sc->sc_hdrlen, UFTDI_OBUFSIZE - sc->sc_hdrlen, 437 &actlen)) { 438 439 if (sc->sc_hdrlen > 0) { 440 buf[0] = 441 FTDI_OUT_TAG(actlen, sc->sc_ucom.sc_portno); 442 usb2_copy_in(xfer->frbuffers, 0, buf, 1); 443 } 444 xfer->frlengths[0] = actlen + sc->sc_hdrlen; 445 usb2_start_hardware(xfer); 446 } 447 return; 448 449 default: /* Error */ 450 if (xfer->error != USB_ERR_CANCELLED) { 451 sc->sc_flag |= UFTDI_FLAG_WRITE_STALL; 452 usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_CS_WR]); 453 } 454 return; 455 456 } 457} 458 459static void 460uftdi_write_clear_stall_callback(struct usb2_xfer *xfer) 461{ 462 struct uftdi_softc *sc = xfer->priv_sc; 463 struct usb2_xfer *xfer_other = sc->sc_xfer[UFTDI_BULK_DT_WR]; 464 465 if (usb2_clear_stall_callback(xfer, xfer_other)) { 466 DPRINTF("stall cleared\n"); 467 sc->sc_flag &= ~UFTDI_FLAG_WRITE_STALL; 468 usb2_transfer_start(xfer_other); 469 } 470} 471 472static void 473uftdi_read_callback(struct usb2_xfer *xfer) 474{ 475 struct uftdi_softc *sc = xfer->priv_sc; 476 uint8_t buf[2]; 477 uint8_t ftdi_msr; 478 uint8_t msr; 479 uint8_t lsr; 480 481 switch (USB_GET_STATE(xfer)) { 482 case USB_ST_TRANSFERRED: 483 484 if (xfer->actlen < 2) { 485 goto tr_setup; 486 } 487 usb2_copy_out(xfer->frbuffers, 0, buf, 2); 488 489 ftdi_msr = FTDI_GET_MSR(buf); 490 lsr = FTDI_GET_LSR(buf); 491 492 msr = 0; 493 if (ftdi_msr & FTDI_SIO_CTS_MASK) 494 msr |= SER_CTS; 495 if (ftdi_msr & FTDI_SIO_DSR_MASK) 496 msr |= SER_DSR; 497 if (ftdi_msr & FTDI_SIO_RI_MASK) 498 msr |= SER_RI; 499 if (ftdi_msr & FTDI_SIO_RLSD_MASK) 500 msr |= SER_DCD; 501 502 if ((sc->sc_msr != msr) || 503 ((sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK))) { 504 DPRINTF("status change msr=0x%02x (0x%02x) " 505 "lsr=0x%02x (0x%02x)\n", msr, sc->sc_msr, 506 lsr, sc->sc_lsr); 507 508 sc->sc_msr = msr; 509 sc->sc_lsr = lsr; 510 511 usb2_com_status_change(&sc->sc_ucom); 512 } 513 xfer->actlen -= 2; 514 515 if (xfer->actlen > 0) { 516 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 2, 517 xfer->actlen); 518 } 519 case USB_ST_SETUP: 520tr_setup: 521 if (sc->sc_flag & UFTDI_FLAG_READ_STALL) { 522 usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_CS_RD]); 523 } else { 524 xfer->frlengths[0] = xfer->max_data_length; 525 usb2_start_hardware(xfer); 526 } 527 return; 528 529 default: /* Error */ 530 if (xfer->error != USB_ERR_CANCELLED) { 531 sc->sc_flag |= UFTDI_FLAG_READ_STALL; 532 usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_CS_RD]); 533 } 534 return; 535 536 } 537} 538 539static void 540uftdi_read_clear_stall_callback(struct usb2_xfer *xfer) 541{ 542 struct uftdi_softc *sc = xfer->priv_sc; 543 struct usb2_xfer *xfer_other = sc->sc_xfer[UFTDI_BULK_DT_RD]; 544 545 if (usb2_clear_stall_callback(xfer, xfer_other)) { 546 DPRINTF("stall cleared\n"); 547 sc->sc_flag &= ~UFTDI_FLAG_READ_STALL; 548 usb2_transfer_start(xfer_other); 549 } 550} 551 552static void 553uftdi_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 554{ 555 struct uftdi_softc *sc = ucom->sc_parent; 556 uint16_t wIndex = ucom->sc_portno; 557 uint16_t wValue; 558 struct usb2_device_request req; 559 560 wValue = onoff ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW; 561 562 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 563 req.bRequest = FTDI_SIO_MODEM_CTRL; 564 USETW(req.wValue, wValue); 565 USETW(req.wIndex, wIndex); 566 USETW(req.wLength, 0); 567 uftdi_cfg_do_request(sc, &req, NULL); 568} 569 570static void 571uftdi_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 572{ 573 struct uftdi_softc *sc = ucom->sc_parent; 574 uint16_t wIndex = ucom->sc_portno; 575 uint16_t wValue; 576 struct usb2_device_request req; 577 578 wValue = onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW; 579 580 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 581 req.bRequest = FTDI_SIO_MODEM_CTRL; 582 USETW(req.wValue, wValue); 583 USETW(req.wIndex, wIndex); 584 USETW(req.wLength, 0); 585 uftdi_cfg_do_request(sc, &req, NULL); 586} 587 588static void 589uftdi_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 590{ 591 struct uftdi_softc *sc = ucom->sc_parent; 592 uint16_t wIndex = ucom->sc_portno; 593 uint16_t wValue; 594 struct usb2_device_request req; 595 596 if (onoff) { 597 sc->sc_last_lcr |= FTDI_SIO_SET_BREAK; 598 } else { 599 sc->sc_last_lcr &= ~FTDI_SIO_SET_BREAK; 600 } 601 602 wValue = sc->sc_last_lcr; 603 604 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 605 req.bRequest = FTDI_SIO_SET_DATA; 606 USETW(req.wValue, wValue); 607 USETW(req.wIndex, wIndex); 608 USETW(req.wLength, 0); 609 uftdi_cfg_do_request(sc, &req, NULL); 610} 611 612static int 613uftdi_set_parm_soft(struct termios *t, 614 struct uftdi_param_config *cfg, uint8_t type) 615{ 616 bzero(cfg, sizeof(*cfg)); 617 618 switch (type) { 619 case UFTDI_TYPE_SIO: 620 switch (t->c_ospeed) { 621 case 300: 622 cfg->rate = ftdi_sio_b300; 623 break; 624 case 600: 625 cfg->rate = ftdi_sio_b600; 626 break; 627 case 1200: 628 cfg->rate = ftdi_sio_b1200; 629 break; 630 case 2400: 631 cfg->rate = ftdi_sio_b2400; 632 break; 633 case 4800: 634 cfg->rate = ftdi_sio_b4800; 635 break; 636 case 9600: 637 cfg->rate = ftdi_sio_b9600; 638 break; 639 case 19200: 640 cfg->rate = ftdi_sio_b19200; 641 break; 642 case 38400: 643 cfg->rate = ftdi_sio_b38400; 644 break; 645 case 57600: 646 cfg->rate = ftdi_sio_b57600; 647 break; 648 case 115200: 649 cfg->rate = ftdi_sio_b115200; 650 break; 651 default: 652 return (EINVAL); 653 } 654 break; 655 656 case UFTDI_TYPE_8U232AM: 657 if (uftdi_8u232am_getrate(t->c_ospeed, &cfg->rate)) { 658 return (EINVAL); 659 } 660 break; 661 } 662 663 if (t->c_cflag & CSTOPB) 664 cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_2; 665 else 666 cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_1; 667 668 if (t->c_cflag & PARENB) { 669 if (t->c_cflag & PARODD) { 670 cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_ODD; 671 } else { 672 cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_EVEN; 673 } 674 } else { 675 cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_NONE; 676 } 677 678 switch (t->c_cflag & CSIZE) { 679 case CS5: 680 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(5); 681 break; 682 683 case CS6: 684 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(6); 685 break; 686 687 case CS7: 688 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(7); 689 break; 690 691 case CS8: 692 cfg->lcr |= FTDI_SIO_SET_DATA_BITS(8); 693 break; 694 } 695 696 if (t->c_cflag & CRTSCTS) { 697 cfg->v_flow = FTDI_SIO_RTS_CTS_HS; 698 } else if (t->c_iflag & (IXON | IXOFF)) { 699 cfg->v_flow = FTDI_SIO_XON_XOFF_HS; 700 cfg->v_start = t->c_cc[VSTART]; 701 cfg->v_stop = t->c_cc[VSTOP]; 702 } else { 703 cfg->v_flow = FTDI_SIO_DISABLE_FLOW_CTRL; 704 } 705 706 return (0); 707} 708 709static int 710uftdi_pre_param(struct usb2_com_softc *ucom, struct termios *t) 711{ 712 struct uftdi_softc *sc = ucom->sc_parent; 713 struct uftdi_param_config cfg; 714 715 DPRINTF("\n"); 716 717 return (uftdi_set_parm_soft(t, &cfg, sc->sc_type)); 718} 719 720static void 721uftdi_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 722{ 723 struct uftdi_softc *sc = ucom->sc_parent; 724 uint16_t wIndex = ucom->sc_portno; 725 struct uftdi_param_config cfg; 726 struct usb2_device_request req; 727 728 if (uftdi_set_parm_soft(t, &cfg, sc->sc_type)) { 729 /* should not happen */ 730 return; 731 } 732 sc->sc_last_lcr = cfg.lcr; 733 734 DPRINTF("\n"); 735 736 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 737 req.bRequest = FTDI_SIO_SET_BAUD_RATE; 738 USETW(req.wValue, cfg.rate); 739 USETW(req.wIndex, wIndex); 740 USETW(req.wLength, 0); 741 uftdi_cfg_do_request(sc, &req, NULL); 742 743 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 744 req.bRequest = FTDI_SIO_SET_DATA; 745 USETW(req.wValue, cfg.lcr); 746 USETW(req.wIndex, wIndex); 747 USETW(req.wLength, 0); 748 uftdi_cfg_do_request(sc, &req, NULL); 749 750 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 751 req.bRequest = FTDI_SIO_SET_FLOW_CTRL; 752 USETW2(req.wValue, cfg.v_stop, cfg.v_start); 753 USETW2(req.wIndex, cfg.v_flow, wIndex); 754 USETW(req.wLength, 0); 755 uftdi_cfg_do_request(sc, &req, NULL); 756} 757 758static void 759uftdi_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 760{ 761 struct uftdi_softc *sc = ucom->sc_parent; 762 763 DPRINTF("msr=0x%02x lsr=0x%02x\n", 764 sc->sc_msr, sc->sc_lsr); 765 766 *msr = sc->sc_msr; 767 *lsr = sc->sc_lsr; 768} 769 770static void 771uftdi_start_read(struct usb2_com_softc *ucom) 772{ 773 struct uftdi_softc *sc = ucom->sc_parent; 774 775 usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_RD]); 776} 777 778static void 779uftdi_stop_read(struct usb2_com_softc *ucom) 780{ 781 struct uftdi_softc *sc = ucom->sc_parent; 782 783 usb2_transfer_stop(sc->sc_xfer[UFTDI_BULK_CS_RD]); 784 usb2_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_RD]); 785} 786 787static void 788uftdi_start_write(struct usb2_com_softc *ucom) 789{ 790 struct uftdi_softc *sc = ucom->sc_parent; 791 792 usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_WR]); 793} 794 795static void 796uftdi_stop_write(struct usb2_com_softc *ucom) 797{ 798 struct uftdi_softc *sc = ucom->sc_parent; 799 800 usb2_transfer_stop(sc->sc_xfer[UFTDI_BULK_CS_WR]); 801 usb2_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_WR]); 802} 803 804/*------------------------------------------------------------------------* 805 * uftdi_8u232am_getrate 806 * 807 * Return values: 808 * 0: Success 809 * Else: Failure 810 *------------------------------------------------------------------------*/ 811static uint8_t 812uftdi_8u232am_getrate(uint32_t speed, uint16_t *rate) 813{ 814 /* Table of the nearest even powers-of-2 for values 0..15. */ 815 static const uint8_t roundoff[16] = { 816 0, 2, 2, 4, 4, 4, 8, 8, 817 8, 8, 8, 8, 16, 16, 16, 16, 818 }; 819 uint32_t d; 820 uint32_t freq; 821 uint16_t result; 822 823 if ((speed < 178) || (speed > ((3000000 * 100) / 97))) 824 return (1); /* prevent numerical overflow */ 825 826 /* Special cases for 2M and 3M. */ 827 if ((speed >= ((3000000 * 100) / 103)) && 828 (speed <= ((3000000 * 100) / 97))) { 829 result = 0; 830 goto done; 831 } 832 if ((speed >= ((2000000 * 100) / 103)) && 833 (speed <= ((2000000 * 100) / 97))) { 834 result = 1; 835 goto done; 836 } 837 d = (FTDI_8U232AM_FREQ << 4) / speed; 838 d = (d & ~15) + roundoff[d & 15]; 839 840 if (d < FTDI_8U232AM_MIN_DIV) 841 d = FTDI_8U232AM_MIN_DIV; 842 else if (d > FTDI_8U232AM_MAX_DIV) 843 d = FTDI_8U232AM_MAX_DIV; 844 845 /* 846 * Calculate the frequency needed for "d" to exactly divide down to 847 * our target "speed", and check that the actual frequency is within 848 * 3% of this. 849 */ 850 freq = (speed * d); 851 if ((freq < ((FTDI_8U232AM_FREQ * 1600ULL) / 103)) || 852 (freq > ((FTDI_8U232AM_FREQ * 1600ULL) / 97))) 853 return (1); 854 855 /* 856 * Pack the divisor into the resultant value. The lower 14-bits 857 * hold the integral part, while the upper 2 bits encode the 858 * fractional component: either 0, 0.5, 0.25, or 0.125. 859 */ 860 result = (d >> 4); 861 if (d & 8) 862 result |= 0x4000; 863 else if (d & 4) 864 result |= 0x8000; 865 else if (d & 2) 866 result |= 0xc000; 867 868done: 869 *rate = result; 870 return (0); 871} 872