uftdi.c revision 190633
1117610Sdes/* $NetBSD: uftdi.c,v 1.13 2002/09/23 05:51:23 simonb Exp $ */ 2271947Sdes 3117610Sdes/*- 4271947Sdes * Copyright (c) 2000 The NetBSD Foundation, Inc. 5117610Sdes * All rights reserved. 6174832Sdes * 7117610Sdes * This code is derived from software contributed to The NetBSD Foundation 8228692Sdes * by Lennart Augustsson (lennart@augustsson.net). 9255376Sdes * 10228692Sdes * Redistribution and use in source and binary forms, with or without 11228692Sdes * modification, are permitted provided that the following conditions 12117610Sdes * are met: 13117610Sdes * 1. Redistributions of source code must retain the above copyright 14228692Sdes * notice, this list of conditions and the following disclaimer. 15228692Sdes * 2. Redistributions in binary form must reproduce the above copyright 16228692Sdes * notice, this list of conditions and the following disclaimer in the 17117610Sdes * documentation and/or other materials provided with the distribution. 18174832Sdes * 3. All advertising materials mentioning features or use of this software 19174832Sdes * must display the following acknowledgement: 20228692Sdes * This product includes software developed by the NetBSD 21117610Sdes * Foundation, Inc. and its contributors. 22117610Sdes * 4. Neither the name of The NetBSD Foundation nor the names of its 23228692Sdes * contributors may be used to endorse or promote products derived 24141098Sdes * from this software without specific prior written permission. 25141098Sdes * 26174832Sdes * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27174832Sdes * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28228692Sdes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29228692Sdes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30228692Sdes * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31228692Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32228692Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33174832Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34117610Sdes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35117610Sdes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36174832Sdes * POSSIBILITY OF SUCH DAMAGE. 37228692Sdes */ 38228692Sdes 39228692Sdes#include <sys/cdefs.h> 40228692Sdes__FBSDID("$FreeBSD: head/sys/dev/usb/serial/uftdi.c 190633 2009-04-01 20:23:47Z piso $"); 41228692Sdes 42228692Sdes/* 43228692Sdes * NOTE: all function names beginning like "uftdi_cfg_" can only 44228692Sdes * be called from within the config thread function ! 45228692Sdes */ 46228692Sdes 47228692Sdes/* 48228692Sdes * FTDI FT8U100AX serial adapter driver 49228692Sdes */ 50228692Sdes 51228692Sdes#include "usbdevs.h" 52228692Sdes#include <dev/usb/usb.h> 53228692Sdes#include <dev/usb/usb_mfunc.h> 54228692Sdes#include <dev/usb/usb_error.h> 55228692Sdes#include <dev/usb/usb_cdc.h> 56228692Sdes 57174832Sdes#define USB_DEBUG_VAR uftdi_debug 58228692Sdes 59228692Sdes#include <dev/usb/usb_core.h> 60228692Sdes#include <dev/usb/usb_debug.h> 61228692Sdes#include <dev/usb/usb_process.h> 62228692Sdes#include <dev/usb/usb_request.h> 63228692Sdes#include <dev/usb/usb_lookup.h> 64228692Sdes#include <dev/usb/usb_util.h> 65228692Sdes#include <dev/usb/usb_busdma.h> 66228692Sdes 67228692Sdes#include <dev/usb/serial/usb_serial.h> 68228692Sdes#include <dev/usb/serial/uftdi_reg.h> 69228692Sdes 70174832Sdes#if USB_DEBUG 71228692Sdesstatic int uftdi_debug = 0; 72228692Sdes 73174832SdesSYSCTL_NODE(_hw_usb2, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi"); 74174832SdesSYSCTL_INT(_hw_usb2_uftdi, OID_AUTO, debug, CTLFLAG_RW, 75228692Sdes &uftdi_debug, 0, "Debug level"); 76228692Sdes#endif 77228692Sdes 78228692Sdes#define UFTDI_CONFIG_INDEX 0 79228692Sdes#define UFTDI_IFACE_INDEX 0 80228692Sdes 81228692Sdes#define UFTDI_IBUFSIZE 64 /* bytes, maximum number of bytes per 82117610Sdes * frame */ 83117610Sdes#define UFTDI_OBUFSIZE 64 /* bytes, cannot be increased due to 84117610Sdes * do size encoding */ 85174832Sdes 86174832Sdesenum { 87174832Sdes UFTDI_BULK_DT_WR, 88174832Sdes UFTDI_BULK_DT_RD, 89174832Sdes UFTDI_N_TRANSFER, 90174832Sdes}; 91174832Sdes 92174832Sdesstruct uftdi_softc { 93228692Sdes struct usb2_com_super_softc sc_super_ucom; 94228692Sdes struct usb2_com_softc sc_ucom; 95174832Sdes 96174832Sdes struct usb2_device *sc_udev; 97174832Sdes struct usb2_xfer *sc_xfer[UFTDI_N_TRANSFER]; 98174832Sdes device_t sc_dev; 99174832Sdes struct mtx sc_mtx; 100174832Sdes 101228692Sdes uint32_t sc_unit; 102228692Sdes enum uftdi_type sc_type; 103174832Sdes 104174832Sdes uint16_t sc_last_lcr; 105174832Sdes 106174832Sdes uint8_t sc_iface_index; 107174832Sdes uint8_t sc_hdrlen; 108174832Sdes uint8_t sc_msr; 109174832Sdes uint8_t sc_lsr; 110174832Sdes 111174832Sdes uint8_t sc_name[16]; 112174832Sdes}; 113228692Sdes 114228692Sdesstruct uftdi_param_config { 115174832Sdes uint16_t rate; 116174832Sdes uint16_t lcr; 117228692Sdes uint8_t v_start; 118228692Sdes uint8_t v_stop; 119228692Sdes uint8_t v_flow; 120228692Sdes}; 121228692Sdes 122228692Sdes/* prototypes */ 123228692Sdes 124174832Sdesstatic device_probe_t uftdi_probe; 125141098Sdesstatic device_attach_t uftdi_attach; 126141098Sdesstatic device_detach_t uftdi_detach; 127141098Sdes 128117610Sdesstatic usb2_callback_t uftdi_write_callback; 129141098Sdesstatic usb2_callback_t uftdi_read_callback; 130228692Sdes 131228692Sdesstatic void uftdi_cfg_open(struct usb2_com_softc *); 132228692Sdesstatic void uftdi_cfg_set_dtr(struct usb2_com_softc *, uint8_t); 133228692Sdesstatic void uftdi_cfg_set_rts(struct usb2_com_softc *, uint8_t); 134141098Sdesstatic void uftdi_cfg_set_break(struct usb2_com_softc *, uint8_t); 135174832Sdesstatic int uftdi_set_parm_soft(struct termios *, 136228692Sdes struct uftdi_param_config *, uint8_t); 137141098Sdesstatic int uftdi_pre_param(struct usb2_com_softc *, struct termios *); 138255376Sdesstatic void uftdi_cfg_param(struct usb2_com_softc *, struct termios *); 139255376Sdesstatic void uftdi_cfg_get_status(struct usb2_com_softc *, uint8_t *, 140255376Sdes uint8_t *); 141255376Sdesstatic void uftdi_start_read(struct usb2_com_softc *); 142255376Sdesstatic void uftdi_stop_read(struct usb2_com_softc *); 143255376Sdesstatic void uftdi_start_write(struct usb2_com_softc *); 144255376Sdesstatic void uftdi_stop_write(struct usb2_com_softc *); 145255376Sdesstatic uint8_t uftdi_8u232am_getrate(uint32_t, uint16_t *); 146255376Sdes 147255376Sdesstatic const struct usb2_config uftdi_config[UFTDI_N_TRANSFER] = { 148255376Sdes 149255376Sdes [UFTDI_BULK_DT_WR] = { 150255376Sdes .type = UE_BULK, 151255376Sdes .endpoint = UE_ADDR_ANY, 152255376Sdes .direction = UE_DIR_OUT, 153255376Sdes .mh.bufsize = UFTDI_OBUFSIZE, 154255376Sdes .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 155255376Sdes .mh.callback = &uftdi_write_callback, 156255376Sdes }, 157255376Sdes 158255376Sdes [UFTDI_BULK_DT_RD] = { 159255376Sdes .type = UE_BULK, 160255376Sdes .endpoint = UE_ADDR_ANY, 161255376Sdes .direction = UE_DIR_IN, 162255376Sdes .mh.bufsize = UFTDI_IBUFSIZE, 163174832Sdes .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 164228692Sdes .mh.callback = &uftdi_read_callback, 165228692Sdes }, 166228692Sdes}; 167228692Sdes 168228692Sdesstatic const struct usb2_com_callback uftdi_callback = { 169228692Sdes .usb2_com_cfg_get_status = &uftdi_cfg_get_status, 170228692Sdes .usb2_com_cfg_set_dtr = &uftdi_cfg_set_dtr, 171174832Sdes .usb2_com_cfg_set_rts = &uftdi_cfg_set_rts, 172228692Sdes .usb2_com_cfg_set_break = &uftdi_cfg_set_break, 173228692Sdes .usb2_com_cfg_param = &uftdi_cfg_param, 174228692Sdes .usb2_com_cfg_open = &uftdi_cfg_open, 175228692Sdes .usb2_com_pre_param = &uftdi_pre_param, 176228692Sdes .usb2_com_start_read = &uftdi_start_read, 177228692Sdes .usb2_com_stop_read = &uftdi_stop_read, 178117610Sdes .usb2_com_start_write = &uftdi_start_write, 179228692Sdes .usb2_com_stop_write = &uftdi_stop_write, 180228692Sdes}; 181228692Sdes 182228692Sdesstatic device_method_t uftdi_methods[] = { 183228692Sdes /* Device interface */ 184228692Sdes DEVMETHOD(device_probe, uftdi_probe), 185117610Sdes DEVMETHOD(device_attach, uftdi_attach), 186174832Sdes DEVMETHOD(device_detach, uftdi_detach), 187228692Sdes 188228692Sdes {0, 0} 189228692Sdes}; 190228692Sdes 191228692Sdesstatic devclass_t uftdi_devclass; 192117610Sdes 193174832Sdesstatic driver_t uftdi_driver = { 194228692Sdes .name = "uftdi", 195174832Sdes .methods = uftdi_methods, 196255376Sdes .size = sizeof(struct uftdi_softc), 197255376Sdes}; 198228692Sdes 199228692SdesDRIVER_MODULE(uftdi, uhub, uftdi_driver, uftdi_devclass, NULL, 0); 200228692SdesMODULE_DEPEND(uftdi, ucom, 1, 1, 1); 201228692SdesMODULE_DEPEND(uftdi, usb, 1, 1, 1); 202228692Sdes 203174832Sdesstatic struct usb2_device_id uftdi_devs[] = { 204228692Sdes {USB_VPI(USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_STK541, UFTDI_TYPE_8U232AM)}, 205228692Sdes {USB_VPI(USB_VENDOR_DRESDENELEKTRONIK, USB_PRODUCT_DRESDENELEKTRONIK_SENSORTERMINALBOARD, UFTDI_TYPE_8U232AM)}, 206228692Sdes {USB_VPI(USB_VENDOR_DRESDENELEKTRONIK, USB_PRODUCT_DRESDENELEKTRONIK_WIRELESSHANDHELDTERMINAL, UFTDI_TYPE_8U232AM)}, 207228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_8U100AX, UFTDI_TYPE_SIO)}, 208228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_2232C, UFTDI_TYPE_8U232AM)}, 209228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_8U232AM, UFTDI_TYPE_8U232AM)}, 210228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SEMC_DSS20, UFTDI_TYPE_8U232AM)}, 211228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_631, UFTDI_TYPE_8U232AM)}, 212228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_632, UFTDI_TYPE_8U232AM)}, 213174832Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_633, UFTDI_TYPE_8U232AM)}, 214228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_634, UFTDI_TYPE_8U232AM)}, 215174832Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_635, UFTDI_TYPE_8U232AM)}, 216228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_USBSERIAL, UFTDI_TYPE_8U232AM)}, 217174832Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MX2_3, UFTDI_TYPE_8U232AM)}, 218174832Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MX4_5, UFTDI_TYPE_8U232AM)}, 219228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_LK202, UFTDI_TYPE_8U232AM)}, 220228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_LK204, UFTDI_TYPE_8U232AM)}, 221117610Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13M, UFTDI_TYPE_8U232AM)}, 222117610Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13S, UFTDI_TYPE_8U232AM)}, 223117610Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13U, UFTDI_TYPE_8U232AM)}, 224117610Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EISCOU, UFTDI_TYPE_8U232AM)}, 225228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_UOPTBR, UFTDI_TYPE_8U232AM)}, 226228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2D, UFTDI_TYPE_8U232AM)}, 227117610Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_PCMSFU, UFTDI_TYPE_8U232AM)}, 228174832Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2H, UFTDI_TYPE_8U232AM)}, 229228692Sdes {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MAXSTREAM, UFTDI_TYPE_8U232AM)}, 230228692Sdes {USB_VPI(USB_VENDOR_SIIG2, USB_PRODUCT_SIIG2_US2308, UFTDI_TYPE_8U232AM)}, 231228692Sdes {USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_VALUECAN, UFTDI_TYPE_8U232AM)}, 232228692Sdes {USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_NEOVI, UFTDI_TYPE_8U232AM)}, 233228692Sdes {USB_VPI(USB_VENDOR_BBELECTRONICS, USB_PRODUCT_BBELECTRONICS_USOTL4, UFTDI_TYPE_8U232AM)}, 234228692Sdes {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_PCOPRS1, UFTDI_TYPE_8U232AM)}, 235228692Sdes}; 236228692Sdes 237228692Sdesstatic int 238174832Sdesuftdi_probe(device_t dev) 239174832Sdes{ 240228692Sdes struct usb2_attach_arg *uaa = device_get_ivars(dev); 241174832Sdes 242228692Sdes if (uaa->usb2_mode != USB_MODE_HOST) { 243228692Sdes return (ENXIO); 244228692Sdes } 245228692Sdes if (uaa->info.bConfigIndex != UFTDI_CONFIG_INDEX) { 246174832Sdes return (ENXIO); 247174832Sdes } 248174832Sdes /* attach to all present interfaces */ 249228692Sdes 250255376Sdes return (usb2_lookup_id_by_uaa(uftdi_devs, sizeof(uftdi_devs), uaa)); 251255376Sdes} 252255376Sdes 253255376Sdesstatic int 254255376Sdesuftdi_attach(device_t dev) 255255376Sdes{ 256255376Sdes struct usb2_attach_arg *uaa = device_get_ivars(dev); 257255376Sdes struct uftdi_softc *sc = device_get_softc(dev); 258255376Sdes int error; 259255376Sdes 260255376Sdes sc->sc_udev = uaa->device; 261255376Sdes sc->sc_dev = dev; 262255376Sdes sc->sc_unit = device_get_unit(dev); 263255376Sdes 264255376Sdes device_set_usb2_desc(dev); 265255376Sdes mtx_init(&sc->sc_mtx, "uftdi", NULL, MTX_DEF); 266255376Sdes 267255376Sdes snprintf(sc->sc_name, sizeof(sc->sc_name), 268255376Sdes "%s", device_get_nameunit(dev)); 269174832Sdes 270174832Sdes DPRINTF("\n"); 271228692Sdes 272228692Sdes sc->sc_iface_index = uaa->info.bIfaceIndex; 273228692Sdes sc->sc_type = USB_GET_DRIVER_INFO(uaa); 274228692Sdes 275228692Sdes switch (sc->sc_type) { 276228692Sdes case UFTDI_TYPE_SIO: 277228692Sdes sc->sc_hdrlen = 1; 278228692Sdes break; 279228692Sdes case UFTDI_TYPE_8U232AM: 280228692Sdes default: 281228692Sdes sc->sc_hdrlen = 0; 282228692Sdes break; 283228692Sdes } 284174832Sdes 285174832Sdes error = usb2_transfer_setup(uaa->device, 286174832Sdes &sc->sc_iface_index, sc->sc_xfer, uftdi_config, 287228692Sdes UFTDI_N_TRANSFER, sc, &sc->sc_mtx); 288228692Sdes 289228692Sdes if (error) { 290228692Sdes device_printf(dev, "allocating USB " 291228692Sdes "transfers failed!\n"); 292174832Sdes goto detach; 293228692Sdes } 294228692Sdes sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum; 295228692Sdes 296228692Sdes /* clear stall at first run */ 297228692Sdes mtx_lock(&sc->sc_mtx); 298228692Sdes usb2_transfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_WR]); 299228692Sdes usb2_transfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_RD]); 300228692Sdes mtx_unlock(&sc->sc_mtx); 301228692Sdes 302228692Sdes /* set a valid "lcr" value */ 303228692Sdes 304174832Sdes sc->sc_last_lcr = 305228692Sdes (FTDI_SIO_SET_DATA_STOP_BITS_2 | 306228692Sdes FTDI_SIO_SET_DATA_PARITY_NONE | 307228692Sdes FTDI_SIO_SET_DATA_BITS(8)); 308228692Sdes 309228692Sdes error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 310228692Sdes &uftdi_callback, &sc->sc_mtx); 311228692Sdes if (error) { 312174832Sdes goto detach; 313228692Sdes } 314228692Sdes return (0); /* success */ 315228692Sdes 316228692Sdesdetach: 317228692Sdes uftdi_detach(dev); 318228692Sdes return (ENXIO); 319228692Sdes} 320228692Sdes 321228692Sdesstatic int 322174832Sdesuftdi_detach(device_t dev) 323228692Sdes{ 324228692Sdes struct uftdi_softc *sc = device_get_softc(dev); 325228692Sdes 326228692Sdes usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 327228692Sdes usb2_transfer_unsetup(sc->sc_xfer, UFTDI_N_TRANSFER); 328174832Sdes mtx_destroy(&sc->sc_mtx); 329228692Sdes 330228692Sdes return (0); 331228692Sdes} 332228692Sdes 333228692Sdesstatic void 334228692Sdesuftdi_cfg_open(struct usb2_com_softc *ucom) 335228692Sdes{ 336228692Sdes struct uftdi_softc *sc = ucom->sc_parent; 337228692Sdes uint16_t wIndex = ucom->sc_portno; 338228692Sdes struct usb2_device_request req; 339228692Sdes 340228692Sdes DPRINTF(""); 341228692Sdes 342228692Sdes /* perform a full reset on the device */ 343228692Sdes 344228692Sdes req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 345228692Sdes req.bRequest = FTDI_SIO_RESET; 346228692Sdes USETW(req.wValue, FTDI_SIO_RESET_SIO); 347228692Sdes USETW(req.wIndex, wIndex); 348228692Sdes USETW(req.wLength, 0); 349228692Sdes usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 350228692Sdes &req, NULL, 0, 1000); 351228692Sdes 352228692Sdes /* turn on RTS/CTS flow control */ 353228692Sdes 354228692Sdes req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 355228692Sdes req.bRequest = FTDI_SIO_SET_FLOW_CTRL; 356228692Sdes USETW(req.wValue, 0); 357228692Sdes USETW2(req.wIndex, FTDI_SIO_RTS_CTS_HS, wIndex); 358228692Sdes USETW(req.wLength, 0); 359228692Sdes usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 360228692Sdes &req, NULL, 0, 1000); 361228692Sdes 362228692Sdes /* 363228692Sdes * NOTE: with the new UCOM layer there will always be a 364228692Sdes * "uftdi_cfg_param()" call after "open()", so there is no need for 365228692Sdes * "open()" to configure anything 366228692Sdes */ 367117610Sdes} 368174832Sdes 369228692Sdesstatic void 370255376Sdesuftdi_write_callback(struct usb2_xfer *xfer) 371255376Sdes{ 372255376Sdes struct uftdi_softc *sc = xfer->priv_sc; 373255376Sdes uint32_t actlen; 374255376Sdes uint8_t buf[1]; 375255376Sdes 376255376Sdes switch (USB_GET_STATE(xfer)) { 377255376Sdes case USB_ST_SETUP: 378228692Sdes case USB_ST_TRANSFERRED: 379228692Sdestr_setup: 380228692Sdes if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 381228692Sdes sc->sc_hdrlen, UFTDI_OBUFSIZE - sc->sc_hdrlen, 382228692Sdes &actlen)) { 383228692Sdes 384228692Sdes if (sc->sc_hdrlen > 0) { 385228692Sdes buf[0] = 386228692Sdes FTDI_OUT_TAG(actlen, sc->sc_ucom.sc_portno); 387228692Sdes usb2_copy_in(xfer->frbuffers, 0, buf, 1); 388228692Sdes } 389228692Sdes xfer->frlengths[0] = actlen + sc->sc_hdrlen; 390228692Sdes usb2_start_hardware(xfer); 391228692Sdes } 392228692Sdes return; 393228692Sdes 394228692Sdes default: /* Error */ 395174832Sdes if (xfer->error != USB_ERR_CANCELLED) { 396228692Sdes /* try to clear stall first */ 397228692Sdes xfer->flags.stall_pipe = 1; 398228692Sdes goto tr_setup; 399228692Sdes } 400228692Sdes return; 401228692Sdes } 402228692Sdes} 403228692Sdes 404228692Sdesstatic void 405228692Sdesuftdi_read_callback(struct usb2_xfer *xfer) 406228692Sdes{ 407228692Sdes struct uftdi_softc *sc = xfer->priv_sc; 408228692Sdes uint8_t buf[2]; 409228692Sdes uint8_t ftdi_msr; 410228692Sdes uint8_t msr; 411228692Sdes uint8_t lsr; 412174832Sdes 413174832Sdes switch (USB_GET_STATE(xfer)) { 414228692Sdes case USB_ST_TRANSFERRED: 415228692Sdes 416228692Sdes if (xfer->actlen < 2) { 417228692Sdes goto tr_setup; 418228692Sdes } 419228692Sdes usb2_copy_out(xfer->frbuffers, 0, buf, 2); 420228692Sdes 421228692Sdes ftdi_msr = FTDI_GET_MSR(buf); 422228692Sdes lsr = FTDI_GET_LSR(buf); 423228692Sdes 424228692Sdes msr = 0; 425228692Sdes if (ftdi_msr & FTDI_SIO_CTS_MASK) 426228692Sdes msr |= SER_CTS; 427228692Sdes if (ftdi_msr & FTDI_SIO_DSR_MASK) 428228692Sdes msr |= SER_DSR; 429174832Sdes if (ftdi_msr & FTDI_SIO_RI_MASK) 430228692Sdes msr |= SER_RI; 431228692Sdes if (ftdi_msr & FTDI_SIO_RLSD_MASK) 432228692Sdes msr |= SER_DCD; 433174832Sdes 434228692Sdes if ((sc->sc_msr != msr) || 435174832Sdes ((sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK))) { 436174832Sdes DPRINTF("status change msr=0x%02x (0x%02x) " 437228692Sdes "lsr=0x%02x (0x%02x)\n", msr, sc->sc_msr, 438228692Sdes lsr, sc->sc_lsr); 439174832Sdes 440228692Sdes sc->sc_msr = msr; 441174832Sdes sc->sc_lsr = lsr; 442174832Sdes 443228692Sdes usb2_com_status_change(&sc->sc_ucom); 444228692Sdes } 445174832Sdes xfer->actlen -= 2; 446228692Sdes 447174832Sdes if (xfer->actlen > 0) { 448174832Sdes usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 2, 449228692Sdes xfer->actlen); 450228692Sdes } 451228692Sdes case USB_ST_SETUP: 452228692Sdestr_setup: 453228692Sdes xfer->frlengths[0] = xfer->max_data_length; 454228692Sdes usb2_start_hardware(xfer); 455228692Sdes return; 456228692Sdes 457228692Sdes default: /* Error */ 458228692Sdes if (xfer->error != USB_ERR_CANCELLED) { 459228692Sdes /* try to clear stall first */ 460228692Sdes xfer->flags.stall_pipe = 1; 461228692Sdes goto tr_setup; 462228692Sdes } 463228692Sdes return; 464228692Sdes } 465228692Sdes} 466228692Sdes 467174832Sdesstatic void 468228692Sdesuftdi_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff) 469228692Sdes{ 470228692Sdes struct uftdi_softc *sc = ucom->sc_parent; 471228692Sdes uint16_t wIndex = ucom->sc_portno; 472228692Sdes uint16_t wValue; 473228692Sdes struct usb2_device_request req; 474174832Sdes 475174832Sdes wValue = onoff ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW; 476228692Sdes 477228692Sdes req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 478228692Sdes req.bRequest = FTDI_SIO_MODEM_CTRL; 479228692Sdes USETW(req.wValue, wValue); 480228692Sdes USETW(req.wIndex, wIndex); 481174832Sdes USETW(req.wLength, 0); 482174832Sdes usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 483174832Sdes &req, NULL, 0, 1000); 484174832Sdes} 485117610Sdes 486174832Sdesstatic void 487174832Sdesuftdi_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff) 488174832Sdes{ 489174832Sdes struct uftdi_softc *sc = ucom->sc_parent; 490117610Sdes uint16_t wIndex = ucom->sc_portno; 491174832Sdes uint16_t wValue; 492174832Sdes struct usb2_device_request req; 493117610Sdes 494174832Sdes wValue = onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW; 495117610Sdes 496174832Sdes req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 497228692Sdes req.bRequest = FTDI_SIO_MODEM_CTRL; 498117610Sdes USETW(req.wValue, wValue); 499255376Sdes USETW(req.wIndex, wIndex); 500255376Sdes USETW(req.wLength, 0); 501255376Sdes usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 502255376Sdes &req, NULL, 0, 1000); 503117610Sdes} 504117610Sdes 505174832Sdesstatic void 506174832Sdesuftdi_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff) 507117610Sdes{ 508117610Sdes struct uftdi_softc *sc = ucom->sc_parent; 509117610Sdes uint16_t wIndex = ucom->sc_portno; 510117610Sdes uint16_t wValue; 511174832Sdes struct usb2_device_request req; 512228692Sdes 513174832Sdes if (onoff) { 514228692Sdes sc->sc_last_lcr |= FTDI_SIO_SET_BREAK; 515174832Sdes } else { 516228692Sdes sc->sc_last_lcr &= ~FTDI_SIO_SET_BREAK; 517228692Sdes } 518228692Sdes 519174832Sdes wValue = sc->sc_last_lcr; 520174832Sdes 521174832Sdes req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 522117610Sdes req.bRequest = FTDI_SIO_SET_DATA; 523117610Sdes USETW(req.wValue, wValue); 524117610Sdes USETW(req.wIndex, wIndex); 525174832Sdes USETW(req.wLength, 0); 526174832Sdes usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 527174832Sdes &req, NULL, 0, 1000); 528174832Sdes} 529228692Sdes 530174832Sdesstatic int 531228692Sdesuftdi_set_parm_soft(struct termios *t, 532228692Sdes struct uftdi_param_config *cfg, uint8_t type) 533228692Sdes{ 534228692Sdes bzero(cfg, sizeof(*cfg)); 535228692Sdes 536228692Sdes switch (type) { 537255376Sdes case UFTDI_TYPE_SIO: 538228692Sdes switch (t->c_ospeed) { 539255376Sdes case 300: 540228692Sdes cfg->rate = ftdi_sio_b300; 541228692Sdes break; 542228692Sdes case 600: 543255376Sdes cfg->rate = ftdi_sio_b600; 544228692Sdes break; 545117610Sdes case 1200: 546255376Sdes cfg->rate = ftdi_sio_b1200; 547117610Sdes break; 548174832Sdes case 2400: 549174832Sdes cfg->rate = ftdi_sio_b2400; 550117610Sdes break; 551141098Sdes case 4800: 552228692Sdes cfg->rate = ftdi_sio_b4800; 553141098Sdes break; 554141098Sdes case 9600: 555141098Sdes cfg->rate = ftdi_sio_b9600; 556141098Sdes break; 557141098Sdes case 19200: 558255376Sdes cfg->rate = ftdi_sio_b19200; 559255376Sdes break; 560117610Sdes case 38400: 561117610Sdes cfg->rate = ftdi_sio_b38400; 562141098Sdes break; 563117610Sdes case 57600: 564117610Sdes cfg->rate = ftdi_sio_b57600; 565141098Sdes break; 566117610Sdes case 115200: 567141098Sdes cfg->rate = ftdi_sio_b115200; 568141098Sdes break; 569141098Sdes default: 570228692Sdes return (EINVAL); 571228692Sdes } 572141098Sdes break; 573117610Sdes 574228692Sdes case UFTDI_TYPE_8U232AM: 575117610Sdes if (uftdi_8u232am_getrate(t->c_ospeed, &cfg->rate)) { 576117610Sdes return (EINVAL); 577117610Sdes } 578117610Sdes break; 579117610Sdes } 580117610Sdes 581117610Sdes if (t->c_cflag & CSTOPB) 582174832Sdes cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_2; 583141098Sdes else 584174832Sdes cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_1; 585117610Sdes 586117610Sdes if (t->c_cflag & PARENB) { 587117610Sdes if (t->c_cflag & PARODD) { 588117610Sdes cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_ODD; 589117610Sdes } else { 590117610Sdes cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_EVEN; 591117610Sdes } 592117610Sdes } else { 593271947Sdes cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_NONE; 594271947Sdes } 595174832Sdes 596255376Sdes switch (t->c_cflag & CSIZE) { 597117610Sdes case CS5: 598255376Sdes cfg->lcr |= FTDI_SIO_SET_DATA_BITS(5); 599117610Sdes break; 600117610Sdes 601117610Sdes case CS6: 602174832Sdes cfg->lcr |= FTDI_SIO_SET_DATA_BITS(6); 603117610Sdes break; 604117610Sdes 605174832Sdes case CS7: 606117610Sdes cfg->lcr |= FTDI_SIO_SET_DATA_BITS(7); 607117610Sdes break; 608174832Sdes 609117610Sdes case CS8: 610117610Sdes cfg->lcr |= FTDI_SIO_SET_DATA_BITS(8); 611117610Sdes break; 612174832Sdes } 613117610Sdes 614117610Sdes if (t->c_cflag & CRTSCTS) { 615117610Sdes cfg->v_flow = FTDI_SIO_RTS_CTS_HS; 616174832Sdes } else if (t->c_iflag & (IXON | IXOFF)) { 617174832Sdes cfg->v_flow = FTDI_SIO_XON_XOFF_HS; 618117610Sdes cfg->v_start = t->c_cc[VSTART]; 619117610Sdes cfg->v_stop = t->c_cc[VSTOP]; 620117610Sdes } else { 621117610Sdes cfg->v_flow = FTDI_SIO_DISABLE_FLOW_CTRL; 622174832Sdes } 623117610Sdes 624117610Sdes return (0); 625174832Sdes} 626117610Sdes 627117610Sdesstatic int 628174832Sdesuftdi_pre_param(struct usb2_com_softc *ucom, struct termios *t) 629174832Sdes{ 630174832Sdes struct uftdi_softc *sc = ucom->sc_parent; 631174832Sdes struct uftdi_param_config cfg; 632117610Sdes 633117610Sdes DPRINTF("\n"); 634117610Sdes 635228692Sdes return (uftdi_set_parm_soft(t, &cfg, sc->sc_type)); 636228692Sdes} 637228692Sdes 638228692Sdesstatic void 639255376Sdesuftdi_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 640228692Sdes{ 641228692Sdes struct uftdi_softc *sc = ucom->sc_parent; 642228692Sdes uint16_t wIndex = ucom->sc_portno; 643228692Sdes struct uftdi_param_config cfg; 644228692Sdes struct usb2_device_request req; 645228692Sdes 646228692Sdes if (uftdi_set_parm_soft(t, &cfg, sc->sc_type)) { 647228692Sdes /* should not happen */ 648228692Sdes return; 649228692Sdes } 650255376Sdes sc->sc_last_lcr = cfg.lcr; 651255376Sdes 652228692Sdes DPRINTF("\n"); 653228692Sdes 654228692Sdes req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 655228692Sdes req.bRequest = FTDI_SIO_SET_BAUD_RATE; 656228692Sdes USETW(req.wValue, cfg.rate); 657228692Sdes USETW(req.wIndex, wIndex); 658228692Sdes USETW(req.wLength, 0); 659228692Sdes usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 660228692Sdes &req, NULL, 0, 1000); 661228692Sdes 662228692Sdes req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 663228692Sdes req.bRequest = FTDI_SIO_SET_DATA; 664228692Sdes USETW(req.wValue, cfg.lcr); 665228692Sdes USETW(req.wIndex, wIndex); 666228692Sdes USETW(req.wLength, 0); 667228692Sdes usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 668228692Sdes &req, NULL, 0, 1000); 669228692Sdes 670228692Sdes req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 671228692Sdes req.bRequest = FTDI_SIO_SET_FLOW_CTRL; 672228692Sdes USETW2(req.wValue, cfg.v_stop, cfg.v_start); 673228692Sdes USETW2(req.wIndex, cfg.v_flow, wIndex); 674228692Sdes USETW(req.wLength, 0); 675228692Sdes usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 676228692Sdes &req, NULL, 0, 1000); 677228692Sdes} 678228692Sdes 679174832Sdesstatic void 680228692Sdesuftdi_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr) 681228692Sdes{ 682228692Sdes struct uftdi_softc *sc = ucom->sc_parent; 683228692Sdes 684228692Sdes DPRINTF("msr=0x%02x lsr=0x%02x\n", 685228692Sdes sc->sc_msr, sc->sc_lsr); 686228692Sdes 687255376Sdes *msr = sc->sc_msr; 688228692Sdes *lsr = sc->sc_lsr; 689228692Sdes} 690228692Sdes 691228692Sdesstatic void 692228692Sdesuftdi_start_read(struct usb2_com_softc *ucom) 693228692Sdes{ 694228692Sdes struct uftdi_softc *sc = ucom->sc_parent; 695228692Sdes 696228692Sdes usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_RD]); 697228692Sdes} 698228692Sdes 699228692Sdesstatic void 700174832Sdesuftdi_stop_read(struct usb2_com_softc *ucom) 701255376Sdes{ 702255376Sdes struct uftdi_softc *sc = ucom->sc_parent; 703255376Sdes 704255376Sdes usb2_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_RD]); 705228692Sdes} 706228692Sdes 707228692Sdesstatic void 708228692Sdesuftdi_start_write(struct usb2_com_softc *ucom) 709228692Sdes{ 710228692Sdes struct uftdi_softc *sc = ucom->sc_parent; 711228692Sdes 712228692Sdes usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_WR]); 713228692Sdes} 714174832Sdes 715228692Sdesstatic void 716228692Sdesuftdi_stop_write(struct usb2_com_softc *ucom) 717228692Sdes{ 718228692Sdes struct uftdi_softc *sc = ucom->sc_parent; 719228692Sdes 720228692Sdes usb2_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_WR]); 721228692Sdes} 722228692Sdes 723228692Sdes/*------------------------------------------------------------------------* 724228692Sdes * uftdi_8u232am_getrate 725228692Sdes * 726228692Sdes * Return values: 727174832Sdes * 0: Success 728228692Sdes * Else: Failure 729228692Sdes *------------------------------------------------------------------------*/ 730228692Sdesstatic uint8_t 731228692Sdesuftdi_8u232am_getrate(uint32_t speed, uint16_t *rate) 732228692Sdes{ 733228692Sdes /* Table of the nearest even powers-of-2 for values 0..15. */ 734228692Sdes static const uint8_t roundoff[16] = { 735228692Sdes 0, 2, 2, 4, 4, 4, 8, 8, 736228692Sdes 8, 8, 8, 8, 16, 16, 16, 16, 737228692Sdes }; 738228692Sdes uint32_t d; 739228692Sdes uint32_t freq; 740228692Sdes uint16_t result; 741228692Sdes 742228692Sdes if ((speed < 178) || (speed > ((3000000 * 100) / 97))) 743228692Sdes return (1); /* prevent numerical overflow */ 744228692Sdes 745228692Sdes /* Special cases for 2M and 3M. */ 746228692Sdes if ((speed >= ((3000000 * 100) / 103)) && 747228692Sdes (speed <= ((3000000 * 100) / 97))) { 748228692Sdes result = 0; 749228692Sdes goto done; 750228692Sdes } 751228692Sdes if ((speed >= ((2000000 * 100) / 103)) && 752228692Sdes (speed <= ((2000000 * 100) / 97))) { 753228692Sdes result = 1; 754228692Sdes goto done; 755228692Sdes } 756228692Sdes d = (FTDI_8U232AM_FREQ << 4) / speed; 757228692Sdes d = (d & ~15) + roundoff[d & 15]; 758228692Sdes 759228692Sdes if (d < FTDI_8U232AM_MIN_DIV) 760228692Sdes d = FTDI_8U232AM_MIN_DIV; 761228692Sdes else if (d > FTDI_8U232AM_MAX_DIV) 762228692Sdes d = FTDI_8U232AM_MAX_DIV; 763228692Sdes 764228692Sdes /* 765228692Sdes * Calculate the frequency needed for "d" to exactly divide down to 766141098Sdes * our target "speed", and check that the actual frequency is within 767228692Sdes * 3% of this. 768228692Sdes */ 769255376Sdes freq = (speed * d); 770228692Sdes if ((freq < ((FTDI_8U232AM_FREQ * 1600ULL) / 103)) || 771228692Sdes (freq > ((FTDI_8U232AM_FREQ * 1600ULL) / 97))) 772228692Sdes return (1); 773228692Sdes 774228692Sdes /* 775228692Sdes * Pack the divisor into the resultant value. The lower 14-bits 776228692Sdes * hold the integral part, while the upper 2 bits encode the 777228692Sdes * fractional component: either 0, 0.5, 0.25, or 0.125. 778228692Sdes */ 779228692Sdes result = (d >> 4); 780228692Sdes if (d & 8) 781228692Sdes result |= 0x4000; 782228692Sdes else if (d & 4) 783228692Sdes result |= 0x8000; 784228692Sdes else if (d & 2) 785228692Sdes result |= 0xc000; 786228692Sdes 787228692Sdesdone: 788228692Sdes *rate = result; 789174832Sdes return (0); 790174832Sdes} 791174832Sdes