ucycom.c revision 187259
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/ucycom2.c 187259 2009-01-15 02:35:40Z 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 37184610Salfred#include <dev/usb2/include/usb2_devid.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, 65187259Sthompsa UCYCOM_INTR_CS, 66187259Sthompsa UCYCOM_N_TRANSFER = 3, 67187259Sthompsa}; 68187259Sthompsa 69184610Salfredstruct ucycom_softc { 70184610Salfred struct usb2_com_super_softc sc_super_ucom; 71184610Salfred struct usb2_com_softc sc_ucom; 72184610Salfred 73184610Salfred struct usb2_device *sc_udev; 74187259Sthompsa struct usb2_xfer *sc_xfer[UCYCOM_N_TRANSFER]; 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_flags; 95184610Salfred#define UCYCOM_FLAG_INTR_STALL 0x01 96184610Salfred uint8_t sc_name[16]; 97184610Salfred uint8_t sc_iface_no; 98184610Salfred uint8_t sc_temp_cfg[32]; 99184610Salfred}; 100184610Salfred 101184610Salfred/* prototypes */ 102184610Salfred 103184610Salfredstatic device_probe_t ucycom_probe; 104184610Salfredstatic device_attach_t ucycom_attach; 105184610Salfredstatic device_detach_t ucycom_detach; 106184610Salfred 107184610Salfredstatic usb2_callback_t ucycom_ctrl_write_callback; 108184610Salfredstatic usb2_callback_t ucycom_intr_read_clear_stall_callback; 109184610Salfredstatic usb2_callback_t ucycom_intr_read_callback; 110184610Salfred 111185948Sthompsastatic void ucycom_cfg_open(struct usb2_com_softc *); 112185948Sthompsastatic void ucycom_start_read(struct usb2_com_softc *); 113185948Sthompsastatic void ucycom_stop_read(struct usb2_com_softc *); 114185948Sthompsastatic void ucycom_start_write(struct usb2_com_softc *); 115185948Sthompsastatic void ucycom_stop_write(struct usb2_com_softc *); 116185948Sthompsastatic void ucycom_cfg_write(struct ucycom_softc *, uint32_t, uint8_t); 117185948Sthompsastatic int ucycom_pre_param(struct usb2_com_softc *, struct termios *); 118185948Sthompsastatic void ucycom_cfg_param(struct usb2_com_softc *, struct termios *); 119184610Salfred 120187259Sthompsastatic const struct usb2_config ucycom_config[UCYCOM_N_TRANSFER] = { 121184610Salfred 122187259Sthompsa [UCYCOM_CTRL_RD] = { 123184610Salfred .type = UE_CONTROL, 124184610Salfred .endpoint = 0x00, /* Control pipe */ 125184610Salfred .direction = UE_DIR_ANY, 126184610Salfred .mh.bufsize = (sizeof(struct usb2_device_request) + UCYCOM_MAX_IOLEN), 127184610Salfred .mh.flags = {}, 128184610Salfred .mh.callback = &ucycom_ctrl_write_callback, 129184610Salfred .mh.timeout = 1000, /* 1 second */ 130184610Salfred }, 131184610Salfred 132187259Sthompsa [UCYCOM_INTR_RD] = { 133184610Salfred .type = UE_INTERRUPT, 134184610Salfred .endpoint = UE_ADDR_ANY, 135184610Salfred .direction = UE_DIR_IN, 136184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 137184610Salfred .mh.bufsize = UCYCOM_MAX_IOLEN, 138184610Salfred .mh.callback = &ucycom_intr_read_callback, 139184610Salfred }, 140184610Salfred 141187259Sthompsa [UCYCOM_INTR_CS] = { 142184610Salfred .type = UE_CONTROL, 143184610Salfred .endpoint = 0x00, /* Control pipe */ 144184610Salfred .direction = UE_DIR_ANY, 145184610Salfred .mh.bufsize = sizeof(struct usb2_device_request), 146184610Salfred .mh.flags = {}, 147184610Salfred .mh.callback = &ucycom_intr_read_clear_stall_callback, 148184610Salfred .mh.timeout = 1000, /* 1 second */ 149184610Salfred .mh.interval = 50, /* 50ms */ 150184610Salfred }, 151184610Salfred}; 152184610Salfred 153184610Salfredstatic const struct usb2_com_callback ucycom_callback = { 154184610Salfred .usb2_com_cfg_param = &ucycom_cfg_param, 155184610Salfred .usb2_com_cfg_open = &ucycom_cfg_open, 156184610Salfred .usb2_com_pre_param = &ucycom_pre_param, 157184610Salfred .usb2_com_start_read = &ucycom_start_read, 158184610Salfred .usb2_com_stop_read = &ucycom_stop_read, 159184610Salfred .usb2_com_start_write = &ucycom_start_write, 160184610Salfred .usb2_com_stop_write = &ucycom_stop_write, 161184610Salfred}; 162184610Salfred 163184610Salfredstatic device_method_t ucycom_methods[] = { 164184610Salfred DEVMETHOD(device_probe, ucycom_probe), 165184610Salfred DEVMETHOD(device_attach, ucycom_attach), 166184610Salfred DEVMETHOD(device_detach, ucycom_detach), 167184610Salfred {0, 0} 168184610Salfred}; 169184610Salfred 170184610Salfredstatic devclass_t ucycom_devclass; 171184610Salfred 172184610Salfredstatic driver_t ucycom_driver = { 173184610Salfred .name = "ucycom", 174184610Salfred .methods = ucycom_methods, 175184610Salfred .size = sizeof(struct ucycom_softc), 176184610Salfred}; 177184610Salfred 178184610SalfredDRIVER_MODULE(ucycom, ushub, ucycom_driver, ucycom_devclass, NULL, 0); 179184610SalfredMODULE_DEPEND(ucycom, usb2_serial, 1, 1, 1); 180184610SalfredMODULE_DEPEND(ucycom, usb2_core, 1, 1, 1); 181184610Salfred 182184610Salfred/* 183184610Salfred * Supported devices 184184610Salfred */ 185184610Salfredstatic const struct usb2_device_id ucycom_devs[] = { 186184610Salfred {USB_VPI(USB_VENDOR_DELORME, USB_PRODUCT_DELORME_EARTHMATE, MODEL_CY7C64013)}, 187184610Salfred}; 188184610Salfred 189184610Salfred#define UCYCOM_DEFAULT_RATE 4800 190184610Salfred#define UCYCOM_DEFAULT_CFG 0x03 /* N-8-1 */ 191184610Salfred 192184610Salfredstatic int 193184610Salfreducycom_probe(device_t dev) 194184610Salfred{ 195184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 196184610Salfred 197184610Salfred if (uaa->usb2_mode != USB_MODE_HOST) { 198184610Salfred return (ENXIO); 199184610Salfred } 200184610Salfred if (uaa->info.bConfigIndex != 0) { 201184610Salfred return (ENXIO); 202184610Salfred } 203184610Salfred if (uaa->info.bIfaceIndex != UCYCOM_IFACE_INDEX) { 204184610Salfred return (ENXIO); 205184610Salfred } 206184610Salfred return (usb2_lookup_id_by_uaa(ucycom_devs, sizeof(ucycom_devs), uaa)); 207184610Salfred} 208184610Salfred 209184610Salfredstatic int 210184610Salfreducycom_attach(device_t dev) 211184610Salfred{ 212184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 213184610Salfred struct ucycom_softc *sc = device_get_softc(dev); 214184610Salfred void *urd_ptr = NULL; 215184610Salfred int32_t error; 216184610Salfred uint16_t urd_len; 217184610Salfred uint8_t iface_index; 218184610Salfred 219184610Salfred if (sc == NULL) { 220184610Salfred return (ENOMEM); 221184610Salfred } 222184610Salfred sc->sc_udev = uaa->device; 223184610Salfred 224184610Salfred device_set_usb2_desc(dev); 225184610Salfred 226184610Salfred snprintf(sc->sc_name, sizeof(sc->sc_name), 227184610Salfred "%s", device_get_nameunit(dev)); 228184610Salfred 229184610Salfred DPRINTF("\n"); 230184610Salfred 231184610Salfred /* get chip model */ 232184610Salfred sc->sc_model = USB_GET_DRIVER_INFO(uaa); 233184610Salfred if (sc->sc_model == 0) { 234184610Salfred device_printf(dev, "unsupported device\n"); 235184610Salfred goto detach; 236184610Salfred } 237184610Salfred device_printf(dev, "Cypress CY7C%X USB to RS232 bridge\n", sc->sc_model); 238184610Salfred 239184610Salfred /* get report descriptor */ 240184610Salfred 241184610Salfred error = usb2_req_get_hid_desc 242184610Salfred (uaa->device, &Giant, 243184610Salfred &urd_ptr, &urd_len, M_USBDEV, 244184610Salfred UCYCOM_IFACE_INDEX); 245184610Salfred 246184610Salfred if (error) { 247184610Salfred device_printf(dev, "failed to get report " 248184610Salfred "descriptor: %s\n", 249184610Salfred usb2_errstr(error)); 250184610Salfred goto detach; 251184610Salfred } 252184610Salfred /* get report sizes */ 253184610Salfred 254184610Salfred sc->sc_flen = hid_report_size(urd_ptr, urd_len, hid_feature, &sc->sc_fid); 255184610Salfred sc->sc_ilen = hid_report_size(urd_ptr, urd_len, hid_input, &sc->sc_iid); 256184610Salfred sc->sc_olen = hid_report_size(urd_ptr, urd_len, hid_output, &sc->sc_oid); 257184610Salfred 258184610Salfred if ((sc->sc_ilen > UCYCOM_MAX_IOLEN) || (sc->sc_ilen < 1) || 259184610Salfred (sc->sc_olen > UCYCOM_MAX_IOLEN) || (sc->sc_olen < 2) || 260184610Salfred (sc->sc_flen > UCYCOM_MAX_IOLEN) || (sc->sc_flen < 5)) { 261184610Salfred device_printf(dev, "invalid report size i=%d, o=%d, f=%d, max=%d\n", 262184610Salfred sc->sc_ilen, sc->sc_olen, sc->sc_flen, 263184610Salfred UCYCOM_MAX_IOLEN); 264184610Salfred goto detach; 265184610Salfred } 266184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 267184610Salfred 268184610Salfred iface_index = UCYCOM_IFACE_INDEX; 269184610Salfred error = usb2_transfer_setup(uaa->device, &iface_index, 270187259Sthompsa sc->sc_xfer, ucycom_config, UCYCOM_N_TRANSFER, 271184610Salfred sc, &Giant); 272184610Salfred if (error) { 273184610Salfred device_printf(dev, "allocating USB " 274184610Salfred "transfers failed!\n"); 275184610Salfred goto detach; 276184610Salfred } 277184610Salfred error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 278184610Salfred &ucycom_callback, &Giant); 279184610Salfred 280184610Salfred if (error) { 281184610Salfred goto detach; 282184610Salfred } 283184610Salfred if (urd_ptr) { 284184610Salfred free(urd_ptr, M_USBDEV); 285184610Salfred } 286184610Salfred return (0); /* success */ 287184610Salfred 288184610Salfreddetach: 289184610Salfred if (urd_ptr) { 290184610Salfred free(urd_ptr, M_USBDEV); 291184610Salfred } 292184610Salfred ucycom_detach(dev); 293184610Salfred return (ENXIO); 294184610Salfred} 295184610Salfred 296184610Salfredstatic int 297184610Salfreducycom_detach(device_t dev) 298184610Salfred{ 299184610Salfred struct ucycom_softc *sc = device_get_softc(dev); 300184610Salfred 301184610Salfred usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 302184610Salfred 303187259Sthompsa usb2_transfer_unsetup(sc->sc_xfer, UCYCOM_N_TRANSFER); 304184610Salfred 305184610Salfred return (0); 306184610Salfred} 307184610Salfred 308184610Salfredstatic void 309184610Salfreducycom_cfg_open(struct usb2_com_softc *ucom) 310184610Salfred{ 311184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 312184610Salfred 313184610Salfred /* set default configuration */ 314184610Salfred ucycom_cfg_write(sc, UCYCOM_DEFAULT_RATE, UCYCOM_DEFAULT_CFG); 315184610Salfred} 316184610Salfred 317184610Salfredstatic void 318184610Salfreducycom_start_read(struct usb2_com_softc *ucom) 319184610Salfred{ 320184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 321184610Salfred 322187259Sthompsa usb2_transfer_start(sc->sc_xfer[UCYCOM_INTR_RD]); 323184610Salfred} 324184610Salfred 325184610Salfredstatic void 326184610Salfreducycom_stop_read(struct usb2_com_softc *ucom) 327184610Salfred{ 328184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 329184610Salfred 330187259Sthompsa usb2_transfer_stop(sc->sc_xfer[UCYCOM_INTR_CS]); 331187259Sthompsa usb2_transfer_stop(sc->sc_xfer[UCYCOM_INTR_RD]); 332184610Salfred} 333184610Salfred 334184610Salfredstatic void 335184610Salfreducycom_start_write(struct usb2_com_softc *ucom) 336184610Salfred{ 337184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 338184610Salfred 339187259Sthompsa usb2_transfer_start(sc->sc_xfer[UCYCOM_CTRL_RD]); 340184610Salfred} 341184610Salfred 342184610Salfredstatic void 343184610Salfreducycom_stop_write(struct usb2_com_softc *ucom) 344184610Salfred{ 345184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 346184610Salfred 347187259Sthompsa usb2_transfer_stop(sc->sc_xfer[UCYCOM_CTRL_RD]); 348184610Salfred} 349184610Salfred 350184610Salfredstatic void 351184610Salfreducycom_ctrl_write_callback(struct usb2_xfer *xfer) 352184610Salfred{ 353184610Salfred struct ucycom_softc *sc = xfer->priv_sc; 354184610Salfred struct usb2_device_request req; 355184610Salfred uint8_t data[2]; 356184610Salfred uint8_t offset; 357184610Salfred uint32_t actlen; 358184610Salfred 359184610Salfred switch (USB_GET_STATE(xfer)) { 360184610Salfred case USB_ST_TRANSFERRED: 361184610Salfredtr_transferred: 362184610Salfred case USB_ST_SETUP: 363184610Salfred 364184610Salfred switch (sc->sc_model) { 365184610Salfred case MODEL_CY7C63743: 366184610Salfred offset = 1; 367184610Salfred break; 368184610Salfred case MODEL_CY7C64013: 369184610Salfred offset = 2; 370184610Salfred break; 371184610Salfred default: 372184610Salfred offset = 0; 373184610Salfred break; 374184610Salfred } 375184610Salfred 376184610Salfred if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers + 1, offset, 377184610Salfred sc->sc_olen - offset, &actlen)) { 378184610Salfred 379184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 380184610Salfred req.bRequest = UR_SET_REPORT; 381184610Salfred USETW2(req.wValue, UHID_OUTPUT_REPORT, sc->sc_oid); 382184610Salfred req.wIndex[0] = sc->sc_iface_no; 383184610Salfred req.wIndex[1] = 0; 384184610Salfred USETW(req.wLength, sc->sc_olen); 385184610Salfred 386184610Salfred switch (sc->sc_model) { 387184610Salfred case MODEL_CY7C63743: 388184610Salfred data[0] = actlen; 389184610Salfred break; 390184610Salfred case MODEL_CY7C64013: 391184610Salfred data[0] = 0; 392184610Salfred data[1] = actlen; 393184610Salfred break; 394184610Salfred default: 395184610Salfred break; 396184610Salfred } 397184610Salfred 398184610Salfred usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 399184610Salfred usb2_copy_in(xfer->frbuffers + 1, 0, data, offset); 400184610Salfred 401184610Salfred xfer->frlengths[0] = sizeof(req); 402184610Salfred xfer->frlengths[1] = sc->sc_olen; 403184610Salfred xfer->nframes = xfer->frlengths[1] ? 2 : 1; 404184610Salfred usb2_start_hardware(xfer); 405184610Salfred } 406184610Salfred return; 407184610Salfred 408184610Salfred default: /* Error */ 409184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 410184610Salfred return; 411184610Salfred } 412184610Salfred DPRINTF("error=%s\n", 413184610Salfred usb2_errstr(xfer->error)); 414184610Salfred goto tr_transferred; 415184610Salfred } 416184610Salfred} 417184610Salfred 418184610Salfredstatic void 419184610Salfreducycom_cfg_write(struct ucycom_softc *sc, uint32_t baud, uint8_t cfg) 420184610Salfred{ 421184610Salfred struct usb2_device_request req; 422184610Salfred uint16_t len; 423184610Salfred usb2_error_t err; 424184610Salfred 425184610Salfred len = sc->sc_flen; 426184610Salfred if (len > sizeof(sc->sc_temp_cfg)) { 427184610Salfred len = sizeof(sc->sc_temp_cfg); 428184610Salfred } 429184610Salfred sc->sc_cfg = cfg; 430184610Salfred 431184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 432184610Salfred req.bRequest = UR_SET_REPORT; 433184610Salfred USETW2(req.wValue, UHID_FEATURE_REPORT, sc->sc_fid); 434184610Salfred req.wIndex[0] = sc->sc_iface_no; 435184610Salfred req.wIndex[1] = 0; 436184610Salfred USETW(req.wLength, len); 437184610Salfred 438184610Salfred sc->sc_temp_cfg[0] = (baud & 0xff); 439184610Salfred sc->sc_temp_cfg[1] = (baud >> 8) & 0xff; 440184610Salfred sc->sc_temp_cfg[2] = (baud >> 16) & 0xff; 441184610Salfred sc->sc_temp_cfg[3] = (baud >> 24) & 0xff; 442184610Salfred sc->sc_temp_cfg[4] = cfg; 443184610Salfred 444184610Salfred if (usb2_com_cfg_is_gone(&sc->sc_ucom)) { 445184610Salfred return; 446184610Salfred } 447184610Salfred err = usb2_do_request_flags 448184610Salfred (sc->sc_udev, &Giant, &req, sc->sc_temp_cfg, 0, NULL, 1000); 449184610Salfred 450184610Salfred if (err) { 451184610Salfred DPRINTFN(0, "device request failed, err=%s " 452184610Salfred "(ignored)\n", usb2_errstr(err)); 453184610Salfred } 454184610Salfred} 455184610Salfred 456184610Salfredstatic int 457184610Salfreducycom_pre_param(struct usb2_com_softc *ucom, struct termios *t) 458184610Salfred{ 459184610Salfred switch (t->c_ospeed) { 460184610Salfred case 600: 461184610Salfred case 1200: 462184610Salfred case 2400: 463184610Salfred case 4800: 464184610Salfred case 9600: 465184610Salfred case 19200: 466184610Salfred case 38400: 467184610Salfred case 57600: 468184610Salfred#if 0 469184610Salfred /* 470184610Salfred * Stock chips only support standard baud rates in the 600 - 57600 471184610Salfred * range, but higher rates can be achieved using custom firmware. 472184610Salfred */ 473184610Salfred case 115200: 474184610Salfred case 153600: 475184610Salfred case 192000: 476184610Salfred#endif 477184610Salfred break; 478184610Salfred default: 479184610Salfred return (EINVAL); 480184610Salfred } 481184610Salfred return (0); 482184610Salfred} 483184610Salfred 484184610Salfredstatic void 485184610Salfreducycom_cfg_param(struct usb2_com_softc *ucom, struct termios *t) 486184610Salfred{ 487184610Salfred struct ucycom_softc *sc = ucom->sc_parent; 488184610Salfred uint8_t cfg; 489184610Salfred 490184610Salfred DPRINTF("\n"); 491184610Salfred 492184610Salfred if (t->c_cflag & CIGNORE) { 493184610Salfred cfg = sc->sc_cfg; 494184610Salfred } else { 495184610Salfred cfg = 0; 496184610Salfred switch (t->c_cflag & CSIZE) { 497184610Salfred default: 498184610Salfred case CS8: 499184610Salfred ++cfg; 500184610Salfred case CS7: 501184610Salfred ++cfg; 502184610Salfred case CS6: 503184610Salfred ++cfg; 504184610Salfred case CS5: 505184610Salfred break; 506184610Salfred } 507184610Salfred 508184610Salfred if (t->c_cflag & CSTOPB) 509184610Salfred cfg |= UCYCOM_CFG_STOPB; 510184610Salfred if (t->c_cflag & PARENB) 511184610Salfred cfg |= UCYCOM_CFG_PAREN; 512184610Salfred if (t->c_cflag & PARODD) 513184610Salfred cfg |= UCYCOM_CFG_PARODD; 514184610Salfred } 515184610Salfred 516184610Salfred ucycom_cfg_write(sc, t->c_ospeed, cfg); 517184610Salfred} 518184610Salfred 519184610Salfredstatic void 520184610Salfreducycom_intr_read_clear_stall_callback(struct usb2_xfer *xfer) 521184610Salfred{ 522184610Salfred struct ucycom_softc *sc = xfer->priv_sc; 523187259Sthompsa struct usb2_xfer *xfer_other = sc->sc_xfer[UCYCOM_INTR_RD]; 524184610Salfred 525184610Salfred if (usb2_clear_stall_callback(xfer, xfer_other)) { 526184610Salfred DPRINTF("stall cleared\n"); 527184610Salfred sc->sc_flags &= ~UCYCOM_FLAG_INTR_STALL; 528184610Salfred usb2_transfer_start(xfer_other); 529184610Salfred } 530184610Salfred} 531184610Salfred 532184610Salfredstatic void 533184610Salfreducycom_intr_read_callback(struct usb2_xfer *xfer) 534184610Salfred{ 535184610Salfred struct ucycom_softc *sc = xfer->priv_sc; 536184610Salfred uint8_t buf[2]; 537184610Salfred uint32_t offset; 538184610Salfred uint32_t len; 539184610Salfred 540184610Salfred switch (USB_GET_STATE(xfer)) { 541184610Salfred case USB_ST_TRANSFERRED: 542184610Salfred switch (sc->sc_model) { 543184610Salfred case MODEL_CY7C63743: 544184610Salfred if (xfer->actlen < 1) { 545184610Salfred goto tr_setup; 546184610Salfred } 547184610Salfred usb2_copy_out(xfer->frbuffers, 0, buf, 1); 548184610Salfred 549184610Salfred sc->sc_ist = buf[0] & ~0x07; 550184610Salfred len = buf[0] & 0x07; 551184610Salfred 552184610Salfred (xfer->actlen)--; 553184610Salfred 554184610Salfred offset = 1; 555184610Salfred 556184610Salfred break; 557184610Salfred 558184610Salfred case MODEL_CY7C64013: 559184610Salfred if (xfer->actlen < 2) { 560184610Salfred goto tr_setup; 561184610Salfred } 562184610Salfred usb2_copy_out(xfer->frbuffers, 0, buf, 2); 563184610Salfred 564184610Salfred sc->sc_ist = buf[0] & ~0x07; 565184610Salfred len = buf[1]; 566184610Salfred 567184610Salfred (xfer->actlen) -= 2; 568184610Salfred 569184610Salfred offset = 2; 570184610Salfred 571184610Salfred break; 572184610Salfred 573184610Salfred default: 574184610Salfred DPRINTFN(0, "unsupported model number!\n"); 575184610Salfred goto tr_setup; 576184610Salfred } 577184610Salfred 578184610Salfred if (len > xfer->actlen) { 579184610Salfred len = xfer->actlen; 580184610Salfred } 581184610Salfred if (len) { 582184610Salfred usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 583184610Salfred offset, len); 584184610Salfred } 585184610Salfred case USB_ST_SETUP: 586184610Salfredtr_setup: 587184610Salfred if (sc->sc_flags & UCYCOM_FLAG_INTR_STALL) { 588187259Sthompsa usb2_transfer_start(sc->sc_xfer[UCYCOM_INTR_CS]); 589184610Salfred } else { 590184610Salfred xfer->frlengths[0] = sc->sc_ilen; 591184610Salfred usb2_start_hardware(xfer); 592184610Salfred } 593184610Salfred return; 594184610Salfred 595184610Salfred default: /* Error */ 596184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 597184610Salfred sc->sc_flags |= UCYCOM_FLAG_INTR_STALL; 598187259Sthompsa usb2_transfer_start(sc->sc_xfer[UCYCOM_INTR_CS]); 599184610Salfred } 600184610Salfred return; 601184610Salfred 602184610Salfred } 603184610Salfred} 604