ucycom.c revision 188746
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/ucycom2.c 188746 2009-02-18 06:33:10Z thompsa $"); 3184610Salfred 4184610Salfred/*- 5184610Salfred * Copyright (c) 2004 Dag-Erling Co�dan Sm�rgrav 6184610Salfred * All rights reserved. 7184610Salfred * 8184610Salfred * Redistribution and use in source and binary forms, with or without 9184610Salfred * modification, are permitted provided that the following conditions 10184610Salfred * are met: 11184610Salfred * 1. Redistributions of source code must retain the above copyright 12184610Salfred * notice, this list of conditions and the following disclaimer 13184610Salfred * in this position and unchanged. 14184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 15184610Salfred * notice, this list of conditions and the following disclaimer in the 16184610Salfred * documentation and/or other materials provided with the distribution. 17184610Salfred * 3. The name of the author may not be used to endorse or promote products 18184610Salfred * derived from this software without specific prior written permission. 19184610Salfred * 20184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21184610Salfred * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22184610Salfred * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23184610Salfred * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24184610Salfred * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25184610Salfred * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26184610Salfred * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27184610Salfred * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28184610Salfred * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29184610Salfred * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30184610Salfred */ 31184610Salfred 32184610Salfred/* 33184610Salfred * Device driver for Cypress CY7C637xx and CY7C640/1xx series USB to 34184610Salfred * RS232 bridges. 35184610Salfred */ 36184610Salfred 37188746Sthompsa#include "usbdevs.h" 38184610Salfred#include <dev/usb2/include/usb2_standard.h> 39184610Salfred#include <dev/usb2/include/usb2_mfunc.h> 40184610Salfred#include <dev/usb2/include/usb2_error.h> 41184610Salfred#include <dev/usb2/include/usb2_cdc.h> 42184610Salfred#include <dev/usb2/include/usb2_ioctl.h> 43184610Salfred#include <dev/usb2/include/usb2_hid.h> 44184610Salfred 45184610Salfred#define USB_DEBUG_VAR usb2_debug 46184610Salfred 47184610Salfred#include <dev/usb2/core/usb2_core.h> 48184610Salfred#include <dev/usb2/core/usb2_debug.h> 49184610Salfred#include <dev/usb2/core/usb2_process.h> 50184610Salfred#include <dev/usb2/core/usb2_request.h> 51184610Salfred#include <dev/usb2/core/usb2_lookup.h> 52184610Salfred#include <dev/usb2/core/usb2_util.h> 53184610Salfred#include <dev/usb2/core/usb2_busdma.h> 54184610Salfred#include <dev/usb2/core/usb2_hid.h> 55184610Salfred 56184610Salfred#include <dev/usb2/serial/usb2_serial.h> 57184610Salfred 58184610Salfred#define UCYCOM_MAX_IOLEN (1024 + 2) /* bytes */ 59184610Salfred 60184610Salfred#define UCYCOM_IFACE_INDEX 0 61184610Salfred 62187259Sthompsaenum { 63187259Sthompsa UCYCOM_CTRL_RD, 64187259Sthompsa UCYCOM_INTR_RD, 65188413Sthompsa UCYCOM_N_TRANSFER, 66187259Sthompsa}; 67187259Sthompsa 68184610Salfredstruct ucycom_softc { 69184610Salfred struct usb2_com_super_softc sc_super_ucom; 70184610Salfred struct usb2_com_softc sc_ucom; 71184610Salfred 72184610Salfred struct usb2_device *sc_udev; 73187259Sthompsa struct usb2_xfer *sc_xfer[UCYCOM_N_TRANSFER]; 74184610Salfred 75184610Salfred uint32_t sc_model; 76184610Salfred#define MODEL_CY7C63743 0x63743 77184610Salfred#define MODEL_CY7C64013 0x64013 78184610Salfred 79184610Salfred uint16_t sc_flen; /* feature report length */ 80184610Salfred uint16_t sc_ilen; /* input report length */ 81184610Salfred uint16_t sc_olen; /* output report length */ 82184610Salfred 83184610Salfred uint8_t sc_fid; /* feature report id */ 84184610Salfred uint8_t sc_iid; /* input report id */ 85184610Salfred uint8_t sc_oid; /* output report id */ 86184610Salfred uint8_t sc_cfg; 87184610Salfred#define UCYCOM_CFG_RESET 0x80 88184610Salfred#define UCYCOM_CFG_PARODD 0x20 89184610Salfred#define UCYCOM_CFG_PAREN 0x10 90184610Salfred#define UCYCOM_CFG_STOPB 0x08 91184610Salfred#define UCYCOM_CFG_DATAB 0x03 92184610Salfred uint8_t sc_ist; /* status flags from last input */ 93184610Salfred uint8_t sc_name[16]; 94184610Salfred uint8_t sc_iface_no; 95184610Salfred uint8_t sc_temp_cfg[32]; 96184610Salfred}; 97184610Salfred 98184610Salfred/* prototypes */ 99184610Salfred 100184610Salfredstatic device_probe_t ucycom_probe; 101184610Salfredstatic device_attach_t ucycom_attach; 102184610Salfredstatic device_detach_t ucycom_detach; 103184610Salfred 104184610Salfredstatic usb2_callback_t ucycom_ctrl_write_callback; 105184610Salfredstatic usb2_callback_t ucycom_intr_read_callback; 106184610Salfred 107185948Sthompsastatic void ucycom_cfg_open(struct usb2_com_softc *); 108185948Sthompsastatic void ucycom_start_read(struct usb2_com_softc *); 109185948Sthompsastatic void ucycom_stop_read(struct usb2_com_softc *); 110185948Sthompsastatic void ucycom_start_write(struct usb2_com_softc *); 111185948Sthompsastatic void ucycom_stop_write(struct usb2_com_softc *); 112185948Sthompsastatic void ucycom_cfg_write(struct ucycom_softc *, uint32_t, uint8_t); 113185948Sthompsastatic int ucycom_pre_param(struct usb2_com_softc *, struct termios *); 114185948Sthompsastatic void ucycom_cfg_param(struct usb2_com_softc *, struct termios *); 115184610Salfred 116187259Sthompsastatic const struct usb2_config ucycom_config[UCYCOM_N_TRANSFER] = { 117184610Salfred 118187259Sthompsa [UCYCOM_CTRL_RD] = { 119184610Salfred .type = UE_CONTROL, 120184610Salfred .endpoint = 0x00, /* Control pipe */ 121184610Salfred .direction = UE_DIR_ANY, 122184610Salfred .mh.bufsize = (sizeof(struct usb2_device_request) + UCYCOM_MAX_IOLEN), 123184610Salfred .mh.flags = {}, 124184610Salfred .mh.callback = &ucycom_ctrl_write_callback, 125184610Salfred .mh.timeout = 1000, /* 1 second */ 126184610Salfred }, 127184610Salfred 128187259Sthompsa [UCYCOM_INTR_RD] = { 129184610Salfred .type = UE_INTERRUPT, 130184610Salfred .endpoint = UE_ADDR_ANY, 131184610Salfred .direction = UE_DIR_IN, 132184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 133184610Salfred .mh.bufsize = UCYCOM_MAX_IOLEN, 134184610Salfred .mh.callback = &ucycom_intr_read_callback, 135184610Salfred }, 136184610Salfred}; 137184610Salfred 138184610Salfredstatic const struct usb2_com_callback ucycom_callback = { 139184610Salfred .usb2_com_cfg_param = &ucycom_cfg_param, 140184610Salfred .usb2_com_cfg_open = &ucycom_cfg_open, 141184610Salfred .usb2_com_pre_param = &ucycom_pre_param, 142184610Salfred .usb2_com_start_read = &ucycom_start_read, 143184610Salfred .usb2_com_stop_read = &ucycom_stop_read, 144184610Salfred .usb2_com_start_write = &ucycom_start_write, 145184610Salfred .usb2_com_stop_write = &ucycom_stop_write, 146184610Salfred}; 147184610Salfred 148184610Salfredstatic device_method_t ucycom_methods[] = { 149184610Salfred DEVMETHOD(device_probe, ucycom_probe), 150184610Salfred DEVMETHOD(device_attach, ucycom_attach), 151184610Salfred DEVMETHOD(device_detach, ucycom_detach), 152184610Salfred {0, 0} 153184610Salfred}; 154184610Salfred 155184610Salfredstatic devclass_t ucycom_devclass; 156184610Salfred 157184610Salfredstatic driver_t ucycom_driver = { 158184610Salfred .name = "ucycom", 159184610Salfred .methods = ucycom_methods, 160184610Salfred .size = sizeof(struct ucycom_softc), 161184610Salfred}; 162184610Salfred 163184610SalfredDRIVER_MODULE(ucycom, ushub, ucycom_driver, ucycom_devclass, NULL, 0); 164184610SalfredMODULE_DEPEND(ucycom, usb2_serial, 1, 1, 1); 165184610SalfredMODULE_DEPEND(ucycom, usb2_core, 1, 1, 1); 166184610Salfred 167184610Salfred/* 168184610Salfred * Supported devices 169184610Salfred */ 170184610Salfredstatic const struct usb2_device_id ucycom_devs[] = { 171184610Salfred {USB_VPI(USB_VENDOR_DELORME, USB_PRODUCT_DELORME_EARTHMATE, MODEL_CY7C64013)}, 172184610Salfred}; 173184610Salfred 174184610Salfred#define UCYCOM_DEFAULT_RATE 4800 175184610Salfred#define UCYCOM_DEFAULT_CFG 0x03 /* N-8-1 */ 176184610Salfred 177184610Salfredstatic int 178184610Salfreducycom_probe(device_t dev) 179184610Salfred{ 180184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 181184610Salfred 182184610Salfred if (uaa->usb2_mode != USB_MODE_HOST) { 183184610Salfred return (ENXIO); 184184610Salfred } 185184610Salfred if (uaa->info.bConfigIndex != 0) { 186184610Salfred return (ENXIO); 187184610Salfred } 188184610Salfred if (uaa->info.bIfaceIndex != UCYCOM_IFACE_INDEX) { 189184610Salfred return (ENXIO); 190184610Salfred } 191184610Salfred return (usb2_lookup_id_by_uaa(ucycom_devs, sizeof(ucycom_devs), uaa)); 192184610Salfred} 193184610Salfred 194184610Salfredstatic int 195184610Salfreducycom_attach(device_t dev) 196184610Salfred{ 197184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 198184610Salfred struct ucycom_softc *sc = device_get_softc(dev); 199184610Salfred void *urd_ptr = NULL; 200184610Salfred int32_t error; 201184610Salfred uint16_t urd_len; 202184610Salfred uint8_t iface_index; 203184610Salfred 204184610Salfred sc->sc_udev = uaa->device; 205184610Salfred 206184610Salfred device_set_usb2_desc(dev); 207184610Salfred 208184610Salfred snprintf(sc->sc_name, sizeof(sc->sc_name), 209184610Salfred "%s", device_get_nameunit(dev)); 210184610Salfred 211184610Salfred DPRINTF("\n"); 212184610Salfred 213184610Salfred /* get chip model */ 214184610Salfred sc->sc_model = USB_GET_DRIVER_INFO(uaa); 215184610Salfred if (sc->sc_model == 0) { 216184610Salfred device_printf(dev, "unsupported device\n"); 217184610Salfred goto detach; 218184610Salfred } 219184610Salfred device_printf(dev, "Cypress CY7C%X USB to RS232 bridge\n", sc->sc_model); 220184610Salfred 221184610Salfred /* get report descriptor */ 222184610Salfred 223184610Salfred error = usb2_req_get_hid_desc 224184610Salfred (uaa->device, &Giant, 225184610Salfred &urd_ptr, &urd_len, M_USBDEV, 226184610Salfred UCYCOM_IFACE_INDEX); 227184610Salfred 228184610Salfred if (error) { 229184610Salfred device_printf(dev, "failed to get report " 230184610Salfred "descriptor: %s\n", 231184610Salfred usb2_errstr(error)); 232184610Salfred goto detach; 233184610Salfred } 234184610Salfred /* get report sizes */ 235184610Salfred 236184610Salfred sc->sc_flen = hid_report_size(urd_ptr, urd_len, hid_feature, &sc->sc_fid); 237184610Salfred sc->sc_ilen = hid_report_size(urd_ptr, urd_len, hid_input, &sc->sc_iid); 238184610Salfred sc->sc_olen = hid_report_size(urd_ptr, urd_len, hid_output, &sc->sc_oid); 239184610Salfred 240184610Salfred if ((sc->sc_ilen > UCYCOM_MAX_IOLEN) || (sc->sc_ilen < 1) || 241184610Salfred (sc->sc_olen > UCYCOM_MAX_IOLEN) || (sc->sc_olen < 2) || 242184610Salfred (sc->sc_flen > UCYCOM_MAX_IOLEN) || (sc->sc_flen < 5)) { 243184610Salfred device_printf(dev, "invalid report size i=%d, o=%d, f=%d, max=%d\n", 244184610Salfred sc->sc_ilen, sc->sc_olen, sc->sc_flen, 245184610Salfred UCYCOM_MAX_IOLEN); 246184610Salfred goto detach; 247184610Salfred } 248184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 249184610Salfred 250184610Salfred iface_index = UCYCOM_IFACE_INDEX; 251184610Salfred error = usb2_transfer_setup(uaa->device, &iface_index, 252187259Sthompsa sc->sc_xfer, ucycom_config, UCYCOM_N_TRANSFER, 253184610Salfred sc, &Giant); 254184610Salfred if (error) { 255184610Salfred device_printf(dev, "allocating USB " 256184610Salfred "transfers failed!\n"); 257184610Salfred goto detach; 258184610Salfred } 259184610Salfred error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 260184610Salfred &ucycom_callback, &Giant); 261184610Salfred 262184610Salfred if (error) { 263184610Salfred goto detach; 264184610Salfred } 265184610Salfred if (urd_ptr) { 266184610Salfred free(urd_ptr, M_USBDEV); 267184610Salfred } 268184610Salfred return (0); /* success */ 269184610Salfred 270184610Salfreddetach: 271184610Salfred if (urd_ptr) { 272184610Salfred free(urd_ptr, M_USBDEV); 273184610Salfred } 274184610Salfred ucycom_detach(dev); 275184610Salfred return (ENXIO); 276184610Salfred} 277184610Salfred 278184610Salfredstatic int 279184610Salfreducycom_detach(device_t dev) 280184610Salfred{ 281184610Salfred struct ucycom_softc *sc = device_get_softc(dev); 282184610Salfred 283184610Salfred usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 284184610Salfred 285187259Sthompsa usb2_transfer_unsetup(sc->sc_xfer, UCYCOM_N_TRANSFER); 286184610Salfred 287184610Salfred return (0); 288184610Salfred} 289184610Salfred 290184610Salfredstatic void 291184610Salfreducycom_cfg_open(struct usb2_com_softc *ucom) 292184610Salfred{ 293184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 294184610Salfred 295184610Salfred /* set default configuration */ 296184610Salfred ucycom_cfg_write(sc, UCYCOM_DEFAULT_RATE, UCYCOM_DEFAULT_CFG); 297184610Salfred} 298184610Salfred 299184610Salfredstatic void 300184610Salfreducycom_start_read(struct usb2_com_softc *ucom) 301184610Salfred{ 302184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 303184610Salfred 304187259Sthompsa usb2_transfer_start(sc->sc_xfer[UCYCOM_INTR_RD]); 305184610Salfred} 306184610Salfred 307184610Salfredstatic void 308184610Salfreducycom_stop_read(struct usb2_com_softc *ucom) 309184610Salfred{ 310184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 311184610Salfred 312187259Sthompsa usb2_transfer_stop(sc->sc_xfer[UCYCOM_INTR_RD]); 313184610Salfred} 314184610Salfred 315184610Salfredstatic void 316184610Salfreducycom_start_write(struct usb2_com_softc *ucom) 317184610Salfred{ 318184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 319184610Salfred 320187259Sthompsa usb2_transfer_start(sc->sc_xfer[UCYCOM_CTRL_RD]); 321184610Salfred} 322184610Salfred 323184610Salfredstatic void 324184610Salfreducycom_stop_write(struct usb2_com_softc *ucom) 325184610Salfred{ 326184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 327184610Salfred 328187259Sthompsa usb2_transfer_stop(sc->sc_xfer[UCYCOM_CTRL_RD]); 329184610Salfred} 330184610Salfred 331184610Salfredstatic void 332184610Salfreducycom_ctrl_write_callback(struct usb2_xfer *xfer) 333184610Salfred{ 334184610Salfred struct ucycom_softc *sc = xfer->priv_sc; 335184610Salfred struct usb2_device_request req; 336184610Salfred uint8_t data[2]; 337184610Salfred uint8_t offset; 338184610Salfred uint32_t actlen; 339184610Salfred 340184610Salfred switch (USB_GET_STATE(xfer)) { 341184610Salfred case USB_ST_TRANSFERRED: 342184610Salfredtr_transferred: 343184610Salfred case USB_ST_SETUP: 344184610Salfred 345184610Salfred switch (sc->sc_model) { 346184610Salfred case MODEL_CY7C63743: 347184610Salfred offset = 1; 348184610Salfred break; 349184610Salfred case MODEL_CY7C64013: 350184610Salfred offset = 2; 351184610Salfred break; 352184610Salfred default: 353184610Salfred offset = 0; 354184610Salfred break; 355184610Salfred } 356184610Salfred 357184610Salfred if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers + 1, offset, 358184610Salfred sc->sc_olen - offset, &actlen)) { 359184610Salfred 360184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 361184610Salfred req.bRequest = UR_SET_REPORT; 362184610Salfred USETW2(req.wValue, UHID_OUTPUT_REPORT, sc->sc_oid); 363184610Salfred req.wIndex[0] = sc->sc_iface_no; 364184610Salfred req.wIndex[1] = 0; 365184610Salfred USETW(req.wLength, sc->sc_olen); 366184610Salfred 367184610Salfred switch (sc->sc_model) { 368184610Salfred case MODEL_CY7C63743: 369184610Salfred data[0] = actlen; 370184610Salfred break; 371184610Salfred case MODEL_CY7C64013: 372184610Salfred data[0] = 0; 373184610Salfred data[1] = actlen; 374184610Salfred break; 375184610Salfred default: 376184610Salfred break; 377184610Salfred } 378184610Salfred 379184610Salfred usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 380184610Salfred usb2_copy_in(xfer->frbuffers + 1, 0, data, offset); 381184610Salfred 382184610Salfred xfer->frlengths[0] = sizeof(req); 383184610Salfred xfer->frlengths[1] = sc->sc_olen; 384184610Salfred xfer->nframes = xfer->frlengths[1] ? 2 : 1; 385184610Salfred usb2_start_hardware(xfer); 386184610Salfred } 387184610Salfred return; 388184610Salfred 389184610Salfred default: /* Error */ 390184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 391184610Salfred return; 392184610Salfred } 393184610Salfred DPRINTF("error=%s\n", 394184610Salfred usb2_errstr(xfer->error)); 395184610Salfred goto tr_transferred; 396184610Salfred } 397184610Salfred} 398184610Salfred 399184610Salfredstatic void 400184610Salfreducycom_cfg_write(struct ucycom_softc *sc, uint32_t baud, uint8_t cfg) 401184610Salfred{ 402184610Salfred struct usb2_device_request req; 403184610Salfred uint16_t len; 404184610Salfred usb2_error_t err; 405184610Salfred 406184610Salfred len = sc->sc_flen; 407184610Salfred if (len > sizeof(sc->sc_temp_cfg)) { 408184610Salfred len = sizeof(sc->sc_temp_cfg); 409184610Salfred } 410184610Salfred sc->sc_cfg = cfg; 411184610Salfred 412184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 413184610Salfred req.bRequest = UR_SET_REPORT; 414184610Salfred USETW2(req.wValue, UHID_FEATURE_REPORT, sc->sc_fid); 415184610Salfred req.wIndex[0] = sc->sc_iface_no; 416184610Salfred req.wIndex[1] = 0; 417184610Salfred USETW(req.wLength, len); 418184610Salfred 419184610Salfred sc->sc_temp_cfg[0] = (baud & 0xff); 420184610Salfred sc->sc_temp_cfg[1] = (baud >> 8) & 0xff; 421184610Salfred sc->sc_temp_cfg[2] = (baud >> 16) & 0xff; 422184610Salfred sc->sc_temp_cfg[3] = (baud >> 24) & 0xff; 423184610Salfred sc->sc_temp_cfg[4] = cfg; 424184610Salfred 425188413Sthompsa err = usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 426188413Sthompsa &req, sc->sc_temp_cfg, 0, 1000); 427184610Salfred if (err) { 428184610Salfred DPRINTFN(0, "device request failed, err=%s " 429184610Salfred "(ignored)\n", usb2_errstr(err)); 430184610Salfred } 431184610Salfred} 432184610Salfred 433184610Salfredstatic int 434184610Salfreducycom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 435184610Salfred{ 436184610Salfred switch (t->c_ospeed) { 437184610Salfred case 600: 438184610Salfred case 1200: 439184610Salfred case 2400: 440184610Salfred case 4800: 441184610Salfred case 9600: 442184610Salfred case 19200: 443184610Salfred case 38400: 444184610Salfred case 57600: 445184610Salfred#if 0 446184610Salfred /* 447184610Salfred * Stock chips only support standard baud rates in the 600 - 57600 448184610Salfred * range, but higher rates can be achieved using custom firmware. 449184610Salfred */ 450184610Salfred case 115200: 451184610Salfred case 153600: 452184610Salfred case 192000: 453184610Salfred#endif 454184610Salfred break; 455184610Salfred default: 456184610Salfred return (EINVAL); 457184610Salfred } 458184610Salfred return (0); 459184610Salfred} 460184610Salfred 461184610Salfredstatic void 462184610Salfreducycom_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 463184610Salfred{ 464184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 465184610Salfred uint8_t cfg; 466184610Salfred 467184610Salfred DPRINTF("\n"); 468184610Salfred 469184610Salfred if (t->c_cflag & CIGNORE) { 470184610Salfred cfg = sc->sc_cfg; 471184610Salfred } else { 472184610Salfred cfg = 0; 473184610Salfred switch (t->c_cflag & CSIZE) { 474184610Salfred default: 475184610Salfred case CS8: 476184610Salfred ++cfg; 477184610Salfred case CS7: 478184610Salfred ++cfg; 479184610Salfred case CS6: 480184610Salfred ++cfg; 481184610Salfred case CS5: 482184610Salfred break; 483184610Salfred } 484184610Salfred 485184610Salfred if (t->c_cflag & CSTOPB) 486184610Salfred cfg |= UCYCOM_CFG_STOPB; 487184610Salfred if (t->c_cflag & PARENB) 488184610Salfred cfg |= UCYCOM_CFG_PAREN; 489184610Salfred if (t->c_cflag & PARODD) 490184610Salfred cfg |= UCYCOM_CFG_PARODD; 491184610Salfred } 492184610Salfred 493184610Salfred ucycom_cfg_write(sc, t->c_ospeed, cfg); 494184610Salfred} 495184610Salfred 496184610Salfredstatic void 497184610Salfreducycom_intr_read_callback(struct usb2_xfer *xfer) 498184610Salfred{ 499184610Salfred struct ucycom_softc *sc = xfer->priv_sc; 500184610Salfred uint8_t buf[2]; 501184610Salfred uint32_t offset; 502184610Salfred uint32_t len; 503184610Salfred 504184610Salfred switch (USB_GET_STATE(xfer)) { 505184610Salfred case USB_ST_TRANSFERRED: 506184610Salfred switch (sc->sc_model) { 507184610Salfred case MODEL_CY7C63743: 508184610Salfred if (xfer->actlen < 1) { 509184610Salfred goto tr_setup; 510184610Salfred } 511184610Salfred usb2_copy_out(xfer->frbuffers, 0, buf, 1); 512184610Salfred 513184610Salfred sc->sc_ist = buf[0] & ~0x07; 514184610Salfred len = buf[0] & 0x07; 515184610Salfred 516184610Salfred (xfer->actlen)--; 517184610Salfred 518184610Salfred offset = 1; 519184610Salfred 520184610Salfred break; 521184610Salfred 522184610Salfred case MODEL_CY7C64013: 523184610Salfred if (xfer->actlen < 2) { 524184610Salfred goto tr_setup; 525184610Salfred } 526184610Salfred usb2_copy_out(xfer->frbuffers, 0, buf, 2); 527184610Salfred 528184610Salfred sc->sc_ist = buf[0] & ~0x07; 529184610Salfred len = buf[1]; 530184610Salfred 531184610Salfred (xfer->actlen) -= 2; 532184610Salfred 533184610Salfred offset = 2; 534184610Salfred 535184610Salfred break; 536184610Salfred 537184610Salfred default: 538184610Salfred DPRINTFN(0, "unsupported model number!\n"); 539184610Salfred goto tr_setup; 540184610Salfred } 541184610Salfred 542184610Salfred if (len > xfer->actlen) { 543184610Salfred len = xfer->actlen; 544184610Salfred } 545184610Salfred if (len) { 546184610Salfred usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 547184610Salfred offset, len); 548184610Salfred } 549184610Salfred case USB_ST_SETUP: 550184610Salfredtr_setup: 551188413Sthompsa xfer->frlengths[0] = sc->sc_ilen; 552188413Sthompsa usb2_start_hardware(xfer); 553184610Salfred return; 554184610Salfred 555184610Salfred default: /* Error */ 556184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 557188413Sthompsa /* try to clear stall first */ 558188413Sthompsa xfer->flags.stall_pipe = 1; 559188413Sthompsa goto tr_setup; 560184610Salfred } 561184610Salfred return; 562184610Salfred 563184610Salfred } 564184610Salfred} 565