ucycom.c revision 189275
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/serial/ucycom.c 189275 2009-03-02 05:37:05Z 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" 38188942Sthompsa#include <dev/usb/usb.h> 39188942Sthompsa#include <dev/usb/usb_mfunc.h> 40188942Sthompsa#include <dev/usb/usb_error.h> 41188942Sthompsa#include <dev/usb/usb_cdc.h> 42188942Sthompsa#include <dev/usb/usb_ioctl.h> 43188942Sthompsa#include <dev/usb/usbhid.h> 44184610Salfred 45184610Salfred#define USB_DEBUG_VAR usb2_debug 46184610Salfred 47188942Sthompsa#include <dev/usb/usb_core.h> 48188942Sthompsa#include <dev/usb/usb_debug.h> 49188942Sthompsa#include <dev/usb/usb_process.h> 50188942Sthompsa#include <dev/usb/usb_request.h> 51188942Sthompsa#include <dev/usb/usb_lookup.h> 52188942Sthompsa#include <dev/usb/usb_util.h> 53188942Sthompsa#include <dev/usb/usb_busdma.h> 54188942Sthompsa#include <dev/usb/usb_hid.h> 55184610Salfred 56188942Sthompsa#include <dev/usb/serial/usb_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]; 74189265Sthompsa struct mtx sc_mtx; 75184610Salfred 76184610Salfred uint32_t sc_model; 77184610Salfred#define MODEL_CY7C63743 0x63743 78184610Salfred#define MODEL_CY7C64013 0x64013 79184610Salfred 80184610Salfred uint16_t sc_flen; /* feature report length */ 81184610Salfred uint16_t sc_ilen; /* input report length */ 82184610Salfred uint16_t sc_olen; /* output report length */ 83184610Salfred 84184610Salfred uint8_t sc_fid; /* feature report id */ 85184610Salfred uint8_t sc_iid; /* input report id */ 86184610Salfred uint8_t sc_oid; /* output report id */ 87184610Salfred uint8_t sc_cfg; 88184610Salfred#define UCYCOM_CFG_RESET 0x80 89184610Salfred#define UCYCOM_CFG_PARODD 0x20 90184610Salfred#define UCYCOM_CFG_PAREN 0x10 91184610Salfred#define UCYCOM_CFG_STOPB 0x08 92184610Salfred#define UCYCOM_CFG_DATAB 0x03 93184610Salfred uint8_t sc_ist; /* status flags from last input */ 94184610Salfred uint8_t sc_name[16]; 95184610Salfred uint8_t sc_iface_no; 96184610Salfred uint8_t sc_temp_cfg[32]; 97184610Salfred}; 98184610Salfred 99184610Salfred/* prototypes */ 100184610Salfred 101184610Salfredstatic device_probe_t ucycom_probe; 102184610Salfredstatic device_attach_t ucycom_attach; 103184610Salfredstatic device_detach_t ucycom_detach; 104184610Salfred 105184610Salfredstatic usb2_callback_t ucycom_ctrl_write_callback; 106184610Salfredstatic usb2_callback_t ucycom_intr_read_callback; 107184610Salfred 108185948Sthompsastatic void ucycom_cfg_open(struct usb2_com_softc *); 109185948Sthompsastatic void ucycom_start_read(struct usb2_com_softc *); 110185948Sthompsastatic void ucycom_stop_read(struct usb2_com_softc *); 111185948Sthompsastatic void ucycom_start_write(struct usb2_com_softc *); 112185948Sthompsastatic void ucycom_stop_write(struct usb2_com_softc *); 113185948Sthompsastatic void ucycom_cfg_write(struct ucycom_softc *, uint32_t, uint8_t); 114185948Sthompsastatic int ucycom_pre_param(struct usb2_com_softc *, struct termios *); 115185948Sthompsastatic void ucycom_cfg_param(struct usb2_com_softc *, struct termios *); 116184610Salfred 117187259Sthompsastatic const struct usb2_config ucycom_config[UCYCOM_N_TRANSFER] = { 118184610Salfred 119187259Sthompsa [UCYCOM_CTRL_RD] = { 120184610Salfred .type = UE_CONTROL, 121184610Salfred .endpoint = 0x00, /* Control pipe */ 122184610Salfred .direction = UE_DIR_ANY, 123184610Salfred .mh.bufsize = (sizeof(struct usb2_device_request) + UCYCOM_MAX_IOLEN), 124184610Salfred .mh.flags = {}, 125184610Salfred .mh.callback = &ucycom_ctrl_write_callback, 126184610Salfred .mh.timeout = 1000, /* 1 second */ 127184610Salfred }, 128184610Salfred 129187259Sthompsa [UCYCOM_INTR_RD] = { 130184610Salfred .type = UE_INTERRUPT, 131184610Salfred .endpoint = UE_ADDR_ANY, 132184610Salfred .direction = UE_DIR_IN, 133184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 134184610Salfred .mh.bufsize = UCYCOM_MAX_IOLEN, 135184610Salfred .mh.callback = &ucycom_intr_read_callback, 136184610Salfred }, 137184610Salfred}; 138184610Salfred 139184610Salfredstatic const struct usb2_com_callback ucycom_callback = { 140184610Salfred .usb2_com_cfg_param = &ucycom_cfg_param, 141184610Salfred .usb2_com_cfg_open = &ucycom_cfg_open, 142184610Salfred .usb2_com_pre_param = &ucycom_pre_param, 143184610Salfred .usb2_com_start_read = &ucycom_start_read, 144184610Salfred .usb2_com_stop_read = &ucycom_stop_read, 145184610Salfred .usb2_com_start_write = &ucycom_start_write, 146184610Salfred .usb2_com_stop_write = &ucycom_stop_write, 147184610Salfred}; 148184610Salfred 149184610Salfredstatic device_method_t ucycom_methods[] = { 150184610Salfred DEVMETHOD(device_probe, ucycom_probe), 151184610Salfred DEVMETHOD(device_attach, ucycom_attach), 152184610Salfred DEVMETHOD(device_detach, ucycom_detach), 153184610Salfred {0, 0} 154184610Salfred}; 155184610Salfred 156184610Salfredstatic devclass_t ucycom_devclass; 157184610Salfred 158184610Salfredstatic driver_t ucycom_driver = { 159184610Salfred .name = "ucycom", 160184610Salfred .methods = ucycom_methods, 161184610Salfred .size = sizeof(struct ucycom_softc), 162184610Salfred}; 163184610Salfred 164189275SthompsaDRIVER_MODULE(ucycom, uhub, ucycom_driver, ucycom_devclass, NULL, 0); 165188942SthompsaMODULE_DEPEND(ucycom, ucom, 1, 1, 1); 166188942SthompsaMODULE_DEPEND(ucycom, usb, 1, 1, 1); 167184610Salfred 168184610Salfred/* 169184610Salfred * Supported devices 170184610Salfred */ 171184610Salfredstatic const struct usb2_device_id ucycom_devs[] = { 172184610Salfred {USB_VPI(USB_VENDOR_DELORME, USB_PRODUCT_DELORME_EARTHMATE, MODEL_CY7C64013)}, 173184610Salfred}; 174184610Salfred 175184610Salfred#define UCYCOM_DEFAULT_RATE 4800 176184610Salfred#define UCYCOM_DEFAULT_CFG 0x03 /* N-8-1 */ 177184610Salfred 178184610Salfredstatic int 179184610Salfreducycom_probe(device_t dev) 180184610Salfred{ 181184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 182184610Salfred 183184610Salfred if (uaa->usb2_mode != USB_MODE_HOST) { 184184610Salfred return (ENXIO); 185184610Salfred } 186184610Salfred if (uaa->info.bConfigIndex != 0) { 187184610Salfred return (ENXIO); 188184610Salfred } 189184610Salfred if (uaa->info.bIfaceIndex != UCYCOM_IFACE_INDEX) { 190184610Salfred return (ENXIO); 191184610Salfred } 192184610Salfred return (usb2_lookup_id_by_uaa(ucycom_devs, sizeof(ucycom_devs), uaa)); 193184610Salfred} 194184610Salfred 195184610Salfredstatic int 196184610Salfreducycom_attach(device_t dev) 197184610Salfred{ 198184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 199184610Salfred struct ucycom_softc *sc = device_get_softc(dev); 200184610Salfred void *urd_ptr = NULL; 201184610Salfred int32_t error; 202184610Salfred uint16_t urd_len; 203184610Salfred uint8_t iface_index; 204184610Salfred 205184610Salfred sc->sc_udev = uaa->device; 206184610Salfred 207184610Salfred device_set_usb2_desc(dev); 208189265Sthompsa mtx_init(&sc->sc_mtx, "ucycom", NULL, MTX_DEF); 209184610Salfred 210184610Salfred snprintf(sc->sc_name, sizeof(sc->sc_name), 211184610Salfred "%s", device_get_nameunit(dev)); 212184610Salfred 213184610Salfred DPRINTF("\n"); 214184610Salfred 215184610Salfred /* get chip model */ 216184610Salfred sc->sc_model = USB_GET_DRIVER_INFO(uaa); 217184610Salfred if (sc->sc_model == 0) { 218184610Salfred device_printf(dev, "unsupported device\n"); 219184610Salfred goto detach; 220184610Salfred } 221184610Salfred device_printf(dev, "Cypress CY7C%X USB to RS232 bridge\n", sc->sc_model); 222184610Salfred 223184610Salfred /* get report descriptor */ 224184610Salfred 225184610Salfred error = usb2_req_get_hid_desc 226184610Salfred (uaa->device, &Giant, 227184610Salfred &urd_ptr, &urd_len, M_USBDEV, 228184610Salfred UCYCOM_IFACE_INDEX); 229184610Salfred 230184610Salfred if (error) { 231184610Salfred device_printf(dev, "failed to get report " 232184610Salfred "descriptor: %s\n", 233184610Salfred usb2_errstr(error)); 234184610Salfred goto detach; 235184610Salfred } 236184610Salfred /* get report sizes */ 237184610Salfred 238184610Salfred sc->sc_flen = hid_report_size(urd_ptr, urd_len, hid_feature, &sc->sc_fid); 239184610Salfred sc->sc_ilen = hid_report_size(urd_ptr, urd_len, hid_input, &sc->sc_iid); 240184610Salfred sc->sc_olen = hid_report_size(urd_ptr, urd_len, hid_output, &sc->sc_oid); 241184610Salfred 242184610Salfred if ((sc->sc_ilen > UCYCOM_MAX_IOLEN) || (sc->sc_ilen < 1) || 243184610Salfred (sc->sc_olen > UCYCOM_MAX_IOLEN) || (sc->sc_olen < 2) || 244184610Salfred (sc->sc_flen > UCYCOM_MAX_IOLEN) || (sc->sc_flen < 5)) { 245184610Salfred device_printf(dev, "invalid report size i=%d, o=%d, f=%d, max=%d\n", 246184610Salfred sc->sc_ilen, sc->sc_olen, sc->sc_flen, 247184610Salfred UCYCOM_MAX_IOLEN); 248184610Salfred goto detach; 249184610Salfred } 250184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 251184610Salfred 252184610Salfred iface_index = UCYCOM_IFACE_INDEX; 253184610Salfred error = usb2_transfer_setup(uaa->device, &iface_index, 254187259Sthompsa sc->sc_xfer, ucycom_config, UCYCOM_N_TRANSFER, 255189265Sthompsa sc, &sc->sc_mtx); 256184610Salfred if (error) { 257184610Salfred device_printf(dev, "allocating USB " 258184610Salfred "transfers failed!\n"); 259184610Salfred goto detach; 260184610Salfred } 261184610Salfred error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 262189265Sthompsa &ucycom_callback, &sc->sc_mtx); 263184610Salfred 264184610Salfred if (error) { 265184610Salfred goto detach; 266184610Salfred } 267184610Salfred if (urd_ptr) { 268184610Salfred free(urd_ptr, M_USBDEV); 269184610Salfred } 270184610Salfred return (0); /* success */ 271184610Salfred 272184610Salfreddetach: 273184610Salfred if (urd_ptr) { 274184610Salfred free(urd_ptr, M_USBDEV); 275184610Salfred } 276184610Salfred ucycom_detach(dev); 277184610Salfred return (ENXIO); 278184610Salfred} 279184610Salfred 280184610Salfredstatic int 281184610Salfreducycom_detach(device_t dev) 282184610Salfred{ 283184610Salfred struct ucycom_softc *sc = device_get_softc(dev); 284184610Salfred 285184610Salfred usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 286187259Sthompsa usb2_transfer_unsetup(sc->sc_xfer, UCYCOM_N_TRANSFER); 287189265Sthompsa mtx_destroy(&sc->sc_mtx); 288184610Salfred 289184610Salfred return (0); 290184610Salfred} 291184610Salfred 292184610Salfredstatic void 293184610Salfreducycom_cfg_open(struct usb2_com_softc *ucom) 294184610Salfred{ 295184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 296184610Salfred 297184610Salfred /* set default configuration */ 298184610Salfred ucycom_cfg_write(sc, UCYCOM_DEFAULT_RATE, UCYCOM_DEFAULT_CFG); 299184610Salfred} 300184610Salfred 301184610Salfredstatic void 302184610Salfreducycom_start_read(struct usb2_com_softc *ucom) 303184610Salfred{ 304184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 305184610Salfred 306187259Sthompsa usb2_transfer_start(sc->sc_xfer[UCYCOM_INTR_RD]); 307184610Salfred} 308184610Salfred 309184610Salfredstatic void 310184610Salfreducycom_stop_read(struct usb2_com_softc *ucom) 311184610Salfred{ 312184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 313184610Salfred 314187259Sthompsa usb2_transfer_stop(sc->sc_xfer[UCYCOM_INTR_RD]); 315184610Salfred} 316184610Salfred 317184610Salfredstatic void 318184610Salfreducycom_start_write(struct usb2_com_softc *ucom) 319184610Salfred{ 320184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 321184610Salfred 322187259Sthompsa usb2_transfer_start(sc->sc_xfer[UCYCOM_CTRL_RD]); 323184610Salfred} 324184610Salfred 325184610Salfredstatic void 326184610Salfreducycom_stop_write(struct usb2_com_softc *ucom) 327184610Salfred{ 328184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 329184610Salfred 330187259Sthompsa usb2_transfer_stop(sc->sc_xfer[UCYCOM_CTRL_RD]); 331184610Salfred} 332184610Salfred 333184610Salfredstatic void 334184610Salfreducycom_ctrl_write_callback(struct usb2_xfer *xfer) 335184610Salfred{ 336184610Salfred struct ucycom_softc *sc = xfer->priv_sc; 337184610Salfred struct usb2_device_request req; 338184610Salfred uint8_t data[2]; 339184610Salfred uint8_t offset; 340184610Salfred uint32_t actlen; 341184610Salfred 342184610Salfred switch (USB_GET_STATE(xfer)) { 343184610Salfred case USB_ST_TRANSFERRED: 344184610Salfredtr_transferred: 345184610Salfred case USB_ST_SETUP: 346184610Salfred 347184610Salfred switch (sc->sc_model) { 348184610Salfred case MODEL_CY7C63743: 349184610Salfred offset = 1; 350184610Salfred break; 351184610Salfred case MODEL_CY7C64013: 352184610Salfred offset = 2; 353184610Salfred break; 354184610Salfred default: 355184610Salfred offset = 0; 356184610Salfred break; 357184610Salfred } 358184610Salfred 359184610Salfred if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers + 1, offset, 360184610Salfred sc->sc_olen - offset, &actlen)) { 361184610Salfred 362184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 363184610Salfred req.bRequest = UR_SET_REPORT; 364184610Salfred USETW2(req.wValue, UHID_OUTPUT_REPORT, sc->sc_oid); 365184610Salfred req.wIndex[0] = sc->sc_iface_no; 366184610Salfred req.wIndex[1] = 0; 367184610Salfred USETW(req.wLength, sc->sc_olen); 368184610Salfred 369184610Salfred switch (sc->sc_model) { 370184610Salfred case MODEL_CY7C63743: 371184610Salfred data[0] = actlen; 372184610Salfred break; 373184610Salfred case MODEL_CY7C64013: 374184610Salfred data[0] = 0; 375184610Salfred data[1] = actlen; 376184610Salfred break; 377184610Salfred default: 378184610Salfred break; 379184610Salfred } 380184610Salfred 381184610Salfred usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 382184610Salfred usb2_copy_in(xfer->frbuffers + 1, 0, data, offset); 383184610Salfred 384184610Salfred xfer->frlengths[0] = sizeof(req); 385184610Salfred xfer->frlengths[1] = sc->sc_olen; 386184610Salfred xfer->nframes = xfer->frlengths[1] ? 2 : 1; 387184610Salfred usb2_start_hardware(xfer); 388184610Salfred } 389184610Salfred return; 390184610Salfred 391184610Salfred default: /* Error */ 392184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 393184610Salfred return; 394184610Salfred } 395184610Salfred DPRINTF("error=%s\n", 396184610Salfred usb2_errstr(xfer->error)); 397184610Salfred goto tr_transferred; 398184610Salfred } 399184610Salfred} 400184610Salfred 401184610Salfredstatic void 402184610Salfreducycom_cfg_write(struct ucycom_softc *sc, uint32_t baud, uint8_t cfg) 403184610Salfred{ 404184610Salfred struct usb2_device_request req; 405184610Salfred uint16_t len; 406184610Salfred usb2_error_t err; 407184610Salfred 408184610Salfred len = sc->sc_flen; 409184610Salfred if (len > sizeof(sc->sc_temp_cfg)) { 410184610Salfred len = sizeof(sc->sc_temp_cfg); 411184610Salfred } 412184610Salfred sc->sc_cfg = cfg; 413184610Salfred 414184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 415184610Salfred req.bRequest = UR_SET_REPORT; 416184610Salfred USETW2(req.wValue, UHID_FEATURE_REPORT, sc->sc_fid); 417184610Salfred req.wIndex[0] = sc->sc_iface_no; 418184610Salfred req.wIndex[1] = 0; 419184610Salfred USETW(req.wLength, len); 420184610Salfred 421184610Salfred sc->sc_temp_cfg[0] = (baud & 0xff); 422184610Salfred sc->sc_temp_cfg[1] = (baud >> 8) & 0xff; 423184610Salfred sc->sc_temp_cfg[2] = (baud >> 16) & 0xff; 424184610Salfred sc->sc_temp_cfg[3] = (baud >> 24) & 0xff; 425184610Salfred sc->sc_temp_cfg[4] = cfg; 426184610Salfred 427188413Sthompsa err = usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 428188413Sthompsa &req, sc->sc_temp_cfg, 0, 1000); 429184610Salfred if (err) { 430184610Salfred DPRINTFN(0, "device request failed, err=%s " 431184610Salfred "(ignored)\n", usb2_errstr(err)); 432184610Salfred } 433184610Salfred} 434184610Salfred 435184610Salfredstatic int 436184610Salfreducycom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 437184610Salfred{ 438184610Salfred switch (t->c_ospeed) { 439184610Salfred case 600: 440184610Salfred case 1200: 441184610Salfred case 2400: 442184610Salfred case 4800: 443184610Salfred case 9600: 444184610Salfred case 19200: 445184610Salfred case 38400: 446184610Salfred case 57600: 447184610Salfred#if 0 448184610Salfred /* 449184610Salfred * Stock chips only support standard baud rates in the 600 - 57600 450184610Salfred * range, but higher rates can be achieved using custom firmware. 451184610Salfred */ 452184610Salfred case 115200: 453184610Salfred case 153600: 454184610Salfred case 192000: 455184610Salfred#endif 456184610Salfred break; 457184610Salfred default: 458184610Salfred return (EINVAL); 459184610Salfred } 460184610Salfred return (0); 461184610Salfred} 462184610Salfred 463184610Salfredstatic void 464184610Salfreducycom_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 465184610Salfred{ 466184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 467184610Salfred uint8_t cfg; 468184610Salfred 469184610Salfred DPRINTF("\n"); 470184610Salfred 471184610Salfred if (t->c_cflag & CIGNORE) { 472184610Salfred cfg = sc->sc_cfg; 473184610Salfred } else { 474184610Salfred cfg = 0; 475184610Salfred switch (t->c_cflag & CSIZE) { 476184610Salfred default: 477184610Salfred case CS8: 478184610Salfred ++cfg; 479184610Salfred case CS7: 480184610Salfred ++cfg; 481184610Salfred case CS6: 482184610Salfred ++cfg; 483184610Salfred case CS5: 484184610Salfred break; 485184610Salfred } 486184610Salfred 487184610Salfred if (t->c_cflag & CSTOPB) 488184610Salfred cfg |= UCYCOM_CFG_STOPB; 489184610Salfred if (t->c_cflag & PARENB) 490184610Salfred cfg |= UCYCOM_CFG_PAREN; 491184610Salfred if (t->c_cflag & PARODD) 492184610Salfred cfg |= UCYCOM_CFG_PARODD; 493184610Salfred } 494184610Salfred 495184610Salfred ucycom_cfg_write(sc, t->c_ospeed, cfg); 496184610Salfred} 497184610Salfred 498184610Salfredstatic void 499184610Salfreducycom_intr_read_callback(struct usb2_xfer *xfer) 500184610Salfred{ 501184610Salfred struct ucycom_softc *sc = xfer->priv_sc; 502184610Salfred uint8_t buf[2]; 503184610Salfred uint32_t offset; 504184610Salfred uint32_t len; 505184610Salfred 506184610Salfred switch (USB_GET_STATE(xfer)) { 507184610Salfred case USB_ST_TRANSFERRED: 508184610Salfred switch (sc->sc_model) { 509184610Salfred case MODEL_CY7C63743: 510184610Salfred if (xfer->actlen < 1) { 511184610Salfred goto tr_setup; 512184610Salfred } 513184610Salfred usb2_copy_out(xfer->frbuffers, 0, buf, 1); 514184610Salfred 515184610Salfred sc->sc_ist = buf[0] & ~0x07; 516184610Salfred len = buf[0] & 0x07; 517184610Salfred 518184610Salfred (xfer->actlen)--; 519184610Salfred 520184610Salfred offset = 1; 521184610Salfred 522184610Salfred break; 523184610Salfred 524184610Salfred case MODEL_CY7C64013: 525184610Salfred if (xfer->actlen < 2) { 526184610Salfred goto tr_setup; 527184610Salfred } 528184610Salfred usb2_copy_out(xfer->frbuffers, 0, buf, 2); 529184610Salfred 530184610Salfred sc->sc_ist = buf[0] & ~0x07; 531184610Salfred len = buf[1]; 532184610Salfred 533184610Salfred (xfer->actlen) -= 2; 534184610Salfred 535184610Salfred offset = 2; 536184610Salfred 537184610Salfred break; 538184610Salfred 539184610Salfred default: 540184610Salfred DPRINTFN(0, "unsupported model number!\n"); 541184610Salfred goto tr_setup; 542184610Salfred } 543184610Salfred 544184610Salfred if (len > xfer->actlen) { 545184610Salfred len = xfer->actlen; 546184610Salfred } 547184610Salfred if (len) { 548184610Salfred usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 549184610Salfred offset, len); 550184610Salfred } 551184610Salfred case USB_ST_SETUP: 552184610Salfredtr_setup: 553188413Sthompsa xfer->frlengths[0] = sc->sc_ilen; 554188413Sthompsa usb2_start_hardware(xfer); 555184610Salfred return; 556184610Salfred 557184610Salfred default: /* Error */ 558184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 559188413Sthompsa /* try to clear stall first */ 560188413Sthompsa xfer->flags.stall_pipe = 1; 561188413Sthompsa goto tr_setup; 562184610Salfred } 563184610Salfred return; 564184610Salfred 565184610Salfred } 566184610Salfred} 567