umct.c revision 212122
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/serial/umct.c 212122 2010-09-01 23:47:53Z thompsa $"); 3184610Salfred 4184610Salfred/*- 5184610Salfred * Copyright (c) 2003 Scott Long 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 * 2. Redistributions in binary form must reproduce the above copyright 14184610Salfred * notice, this list of conditions and the following disclaimer in the 15184610Salfred * documentation and/or other materials provided with the distribution. 16184610Salfred * 17184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27184610Salfred * SUCH DAMAGE. 28184610Salfred * 29184610Salfred */ 30184610Salfred 31184610Salfred/* 32184610Salfred * Driver for the MCT (Magic Control Technology) USB-RS232 Converter. 33184610Salfred * Based on the superb documentation from the linux mct_u232 driver by 34184610Salfred * Wolfgang Grandeggar <wolfgang@cec.ch>. 35184610Salfred * This device smells a lot like the Belkin F5U103, except that it has 36184610Salfred * suffered some mild brain-damage. This driver is based off of the ubsa.c 37189002Sed * driver from Alexander Kabaev <kan@FreeBSD.org>. Merging the two together 38184610Salfred * might be useful, though the subtle differences might lead to lots of 39184610Salfred * #ifdef's. 40184610Salfred */ 41184610Salfred 42184610Salfred/* 43184610Salfred * NOTE: all function names beginning like "umct_cfg_" can only 44184610Salfred * be called from within the config thread function ! 45184610Salfred */ 46184610Salfred 47194677Sthompsa#include <sys/stdint.h> 48194677Sthompsa#include <sys/stddef.h> 49194677Sthompsa#include <sys/param.h> 50194677Sthompsa#include <sys/queue.h> 51194677Sthompsa#include <sys/types.h> 52194677Sthompsa#include <sys/systm.h> 53194677Sthompsa#include <sys/kernel.h> 54194677Sthompsa#include <sys/bus.h> 55194677Sthompsa#include <sys/linker_set.h> 56194677Sthompsa#include <sys/module.h> 57194677Sthompsa#include <sys/lock.h> 58194677Sthompsa#include <sys/mutex.h> 59194677Sthompsa#include <sys/condvar.h> 60194677Sthompsa#include <sys/sysctl.h> 61194677Sthompsa#include <sys/sx.h> 62194677Sthompsa#include <sys/unistd.h> 63194677Sthompsa#include <sys/callout.h> 64194677Sthompsa#include <sys/malloc.h> 65194677Sthompsa#include <sys/priv.h> 66194677Sthompsa 67194677Sthompsa#include <dev/usb/usb.h> 68194677Sthompsa#include <dev/usb/usbdi.h> 69194677Sthompsa#include <dev/usb/usbdi_util.h> 70188746Sthompsa#include "usbdevs.h" 71184610Salfred 72194228Sthompsa#define USB_DEBUG_VAR usb_debug 73188942Sthompsa#include <dev/usb/usb_debug.h> 74188942Sthompsa#include <dev/usb/usb_process.h> 75184610Salfred 76188942Sthompsa#include <dev/usb/serial/usb_serial.h> 77184610Salfred 78184610Salfred/* The UMCT advertises the standard 8250 UART registers */ 79184610Salfred#define UMCT_GET_MSR 2 /* Get Modem Status Register */ 80184610Salfred#define UMCT_GET_MSR_SIZE 1 81184610Salfred#define UMCT_GET_LCR 6 /* Get Line Control Register */ 82184610Salfred#define UMCT_GET_LCR_SIZE 1 83184610Salfred#define UMCT_SET_BAUD 5 /* Set the Baud Rate Divisor */ 84184610Salfred#define UMCT_SET_BAUD_SIZE 4 85184610Salfred#define UMCT_SET_LCR 7 /* Set Line Control Register */ 86184610Salfred#define UMCT_SET_LCR_SIZE 1 87184610Salfred#define UMCT_SET_MCR 10 /* Set Modem Control Register */ 88184610Salfred#define UMCT_SET_MCR_SIZE 1 89184610Salfred 90184610Salfred#define UMCT_INTR_INTERVAL 100 91184610Salfred#define UMCT_IFACE_INDEX 0 92192556Sthompsa#define UMCT_CONFIG_INDEX 0 93184610Salfred 94187259Sthompsaenum { 95187259Sthompsa UMCT_BULK_DT_WR, 96187259Sthompsa UMCT_BULK_DT_RD, 97187259Sthompsa UMCT_INTR_DT_RD, 98188413Sthompsa UMCT_N_TRANSFER, 99187259Sthompsa}; 100184610Salfred 101184610Salfredstruct umct_softc { 102192984Sthompsa struct ucom_super_softc sc_super_ucom; 103192984Sthompsa struct ucom_softc sc_ucom; 104184610Salfred 105192984Sthompsa struct usb_device *sc_udev; 106192984Sthompsa struct usb_xfer *sc_xfer[UMCT_N_TRANSFER]; 107189265Sthompsa struct mtx sc_mtx; 108184610Salfred 109184610Salfred uint32_t sc_unit; 110184610Salfred 111184610Salfred uint16_t sc_obufsize; 112184610Salfred 113184610Salfred uint8_t sc_lsr; 114184610Salfred uint8_t sc_msr; 115184610Salfred uint8_t sc_lcr; 116184610Salfred uint8_t sc_mcr; 117188413Sthompsa uint8_t sc_iface_no; 118197573Sthompsa uint8_t sc_swap_cb; 119184610Salfred uint8_t sc_name[16]; 120184610Salfred}; 121184610Salfred 122184610Salfred/* prototypes */ 123184610Salfred 124184610Salfredstatic device_probe_t umct_probe; 125184610Salfredstatic device_attach_t umct_attach; 126184610Salfredstatic device_detach_t umct_detach; 127184610Salfred 128193045Sthompsastatic usb_callback_t umct_intr_callback; 129197573Sthompsastatic usb_callback_t umct_intr_callback_sub; 130197573Sthompsastatic usb_callback_t umct_read_callback; 131197573Sthompsastatic usb_callback_t umct_read_callback_sub; 132193045Sthompsastatic usb_callback_t umct_write_callback; 133184610Salfred 134188413Sthompsastatic void umct_cfg_do_request(struct umct_softc *sc, uint8_t request, 135188413Sthompsa uint16_t len, uint32_t value); 136192984Sthompsastatic void umct_cfg_get_status(struct ucom_softc *, uint8_t *, 137185948Sthompsa uint8_t *); 138192984Sthompsastatic void umct_cfg_set_break(struct ucom_softc *, uint8_t); 139192984Sthompsastatic void umct_cfg_set_dtr(struct ucom_softc *, uint8_t); 140192984Sthompsastatic void umct_cfg_set_rts(struct ucom_softc *, uint8_t); 141185948Sthompsastatic uint8_t umct_calc_baud(uint32_t); 142192984Sthompsastatic int umct_pre_param(struct ucom_softc *, struct termios *); 143192984Sthompsastatic void umct_cfg_param(struct ucom_softc *, struct termios *); 144192984Sthompsastatic void umct_start_read(struct ucom_softc *); 145192984Sthompsastatic void umct_stop_read(struct ucom_softc *); 146192984Sthompsastatic void umct_start_write(struct ucom_softc *); 147192984Sthompsastatic void umct_stop_write(struct ucom_softc *); 148197570Sthompsastatic void umct_poll(struct ucom_softc *ucom); 149184610Salfred 150192984Sthompsastatic const struct usb_config umct_config[UMCT_N_TRANSFER] = { 151184610Salfred 152187259Sthompsa [UMCT_BULK_DT_WR] = { 153184610Salfred .type = UE_BULK, 154184610Salfred .endpoint = UE_ADDR_ANY, 155184610Salfred .direction = UE_DIR_OUT, 156190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 157190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 158190734Sthompsa .callback = &umct_write_callback, 159184610Salfred }, 160184610Salfred 161187259Sthompsa [UMCT_BULK_DT_RD] = { 162184610Salfred .type = UE_INTERRUPT, 163184610Salfred .endpoint = UE_ADDR_ANY, 164184610Salfred .direction = UE_DIR_IN, 165190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 166190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 167190734Sthompsa .callback = &umct_read_callback, 168184610Salfred .ep_index = 0, /* first interrupt endpoint */ 169184610Salfred }, 170184610Salfred 171187259Sthompsa [UMCT_INTR_DT_RD] = { 172184610Salfred .type = UE_INTERRUPT, 173184610Salfred .endpoint = UE_ADDR_ANY, 174184610Salfred .direction = UE_DIR_IN, 175190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 176190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 177190734Sthompsa .callback = &umct_intr_callback, 178184610Salfred .ep_index = 1, /* second interrupt endpoint */ 179184610Salfred }, 180184610Salfred}; 181184610Salfred 182192984Sthompsastatic const struct ucom_callback umct_callback = { 183194228Sthompsa .ucom_cfg_get_status = &umct_cfg_get_status, 184194228Sthompsa .ucom_cfg_set_dtr = &umct_cfg_set_dtr, 185194228Sthompsa .ucom_cfg_set_rts = &umct_cfg_set_rts, 186194228Sthompsa .ucom_cfg_set_break = &umct_cfg_set_break, 187194228Sthompsa .ucom_cfg_param = &umct_cfg_param, 188194228Sthompsa .ucom_pre_param = &umct_pre_param, 189194228Sthompsa .ucom_start_read = &umct_start_read, 190194228Sthompsa .ucom_stop_read = &umct_stop_read, 191194228Sthompsa .ucom_start_write = &umct_start_write, 192194228Sthompsa .ucom_stop_write = &umct_stop_write, 193197570Sthompsa .ucom_poll = &umct_poll, 194184610Salfred}; 195184610Salfred 196192984Sthompsastatic const struct usb_device_id umct_devs[] = { 197184610Salfred {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0)}, 198184610Salfred {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232, 0)}, 199184610Salfred {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232, 0)}, 200184610Salfred {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U109, 0)}, 201184610Salfred {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U409, 0)}, 202184610Salfred}; 203184610Salfred 204184610Salfredstatic device_method_t umct_methods[] = { 205184610Salfred DEVMETHOD(device_probe, umct_probe), 206184610Salfred DEVMETHOD(device_attach, umct_attach), 207184610Salfred DEVMETHOD(device_detach, umct_detach), 208184610Salfred {0, 0} 209184610Salfred}; 210184610Salfred 211184610Salfredstatic devclass_t umct_devclass; 212184610Salfred 213184610Salfredstatic driver_t umct_driver = { 214184610Salfred .name = "umct", 215184610Salfred .methods = umct_methods, 216184610Salfred .size = sizeof(struct umct_softc), 217184610Salfred}; 218184610Salfred 219189275SthompsaDRIVER_MODULE(umct, uhub, umct_driver, umct_devclass, NULL, 0); 220188942SthompsaMODULE_DEPEND(umct, ucom, 1, 1, 1); 221188942SthompsaMODULE_DEPEND(umct, usb, 1, 1, 1); 222212122SthompsaMODULE_VERSION(umct, 1); 223184610Salfred 224184610Salfredstatic int 225184610Salfredumct_probe(device_t dev) 226184610Salfred{ 227192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 228184610Salfred 229192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 230184610Salfred return (ENXIO); 231184610Salfred } 232184610Salfred if (uaa->info.bConfigIndex != UMCT_CONFIG_INDEX) { 233184610Salfred return (ENXIO); 234184610Salfred } 235184610Salfred if (uaa->info.bIfaceIndex != UMCT_IFACE_INDEX) { 236184610Salfred return (ENXIO); 237184610Salfred } 238194228Sthompsa return (usbd_lookup_id_by_uaa(umct_devs, sizeof(umct_devs), uaa)); 239184610Salfred} 240184610Salfred 241184610Salfredstatic int 242184610Salfredumct_attach(device_t dev) 243184610Salfred{ 244192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 245184610Salfred struct umct_softc *sc = device_get_softc(dev); 246184610Salfred int32_t error; 247197573Sthompsa uint16_t maxp; 248184610Salfred uint8_t iface_index; 249184610Salfred 250184610Salfred sc->sc_udev = uaa->device; 251184610Salfred sc->sc_unit = device_get_unit(dev); 252184610Salfred 253194228Sthompsa device_set_usb_desc(dev); 254189265Sthompsa mtx_init(&sc->sc_mtx, "umct", NULL, MTX_DEF); 255184610Salfred 256184610Salfred snprintf(sc->sc_name, sizeof(sc->sc_name), 257184610Salfred "%s", device_get_nameunit(dev)); 258184610Salfred 259184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 260184610Salfred 261184610Salfred iface_index = UMCT_IFACE_INDEX; 262194228Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 263189265Sthompsa sc->sc_xfer, umct_config, UMCT_N_TRANSFER, sc, &sc->sc_mtx); 264184610Salfred 265184610Salfred if (error) { 266184610Salfred device_printf(dev, "allocating USB " 267199816Sthompsa "transfers failed\n"); 268184610Salfred goto detach; 269184610Salfred } 270197573Sthompsa 271184610Salfred /* 272184610Salfred * The real bulk-in endpoint is also marked as an interrupt. 273184610Salfred * The only way to differentiate it from the real interrupt 274184610Salfred * endpoint is to look at the wMaxPacketSize field. 275184610Salfred */ 276197573Sthompsa maxp = usbd_xfer_max_framelen(sc->sc_xfer[UMCT_BULK_DT_RD]); 277184610Salfred if (maxp == 0x2) { 278184610Salfred 279184610Salfred /* guessed wrong - switch around endpoints */ 280184610Salfred 281192984Sthompsa struct usb_xfer *temp = sc->sc_xfer[UMCT_INTR_DT_RD]; 282184610Salfred 283187259Sthompsa sc->sc_xfer[UMCT_INTR_DT_RD] = sc->sc_xfer[UMCT_BULK_DT_RD]; 284187259Sthompsa sc->sc_xfer[UMCT_BULK_DT_RD] = temp; 285197573Sthompsa sc->sc_swap_cb = 1; 286197573Sthompsa } 287184610Salfred 288194677Sthompsa sc->sc_obufsize = usbd_xfer_max_len(sc->sc_xfer[UMCT_BULK_DT_WR]); 289184610Salfred 290184610Salfred if (uaa->info.idProduct == USB_PRODUCT_MCT_SITECOM_USB232) { 291184610Salfred if (sc->sc_obufsize > 16) { 292184610Salfred sc->sc_obufsize = 16; 293184610Salfred } 294184610Salfred } 295194228Sthompsa error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 296189265Sthompsa &umct_callback, &sc->sc_mtx); 297184610Salfred if (error) { 298184610Salfred goto detach; 299184610Salfred } 300184610Salfred return (0); /* success */ 301184610Salfred 302184610Salfreddetach: 303184610Salfred umct_detach(dev); 304184610Salfred return (ENXIO); /* failure */ 305184610Salfred} 306184610Salfred 307184610Salfredstatic int 308184610Salfredumct_detach(device_t dev) 309184610Salfred{ 310184610Salfred struct umct_softc *sc = device_get_softc(dev); 311184610Salfred 312194228Sthompsa ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 313194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UMCT_N_TRANSFER); 314189265Sthompsa mtx_destroy(&sc->sc_mtx); 315184610Salfred 316184610Salfred return (0); 317184610Salfred} 318184610Salfred 319184610Salfredstatic void 320184610Salfredumct_cfg_do_request(struct umct_softc *sc, uint8_t request, 321184610Salfred uint16_t len, uint32_t value) 322184610Salfred{ 323192984Sthompsa struct usb_device_request req; 324193045Sthompsa usb_error_t err; 325184610Salfred uint8_t temp[4]; 326184610Salfred 327188413Sthompsa if (len > 4) 328184610Salfred len = 4; 329184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 330184610Salfred req.bRequest = request; 331184610Salfred USETW(req.wValue, 0); 332184610Salfred req.wIndex[0] = sc->sc_iface_no; 333184610Salfred req.wIndex[1] = 0; 334184610Salfred USETW(req.wLength, len); 335184610Salfred USETDW(temp, value); 336184610Salfred 337194228Sthompsa err = ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 338188413Sthompsa &req, temp, 0, 1000); 339184610Salfred if (err) { 340184610Salfred DPRINTFN(0, "device request failed, err=%s " 341194228Sthompsa "(ignored)\n", usbd_errstr(err)); 342184610Salfred } 343184610Salfred return; 344184610Salfred} 345184610Salfred 346184610Salfredstatic void 347197573Sthompsaumct_intr_callback_sub(struct usb_xfer *xfer, usb_error_t error) 348184610Salfred{ 349194677Sthompsa struct umct_softc *sc = usbd_xfer_softc(xfer); 350194677Sthompsa struct usb_page_cache *pc; 351184610Salfred uint8_t buf[2]; 352194677Sthompsa int actlen; 353184610Salfred 354194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 355194677Sthompsa 356184610Salfred switch (USB_GET_STATE(xfer)) { 357184610Salfred case USB_ST_TRANSFERRED: 358194677Sthompsa if (actlen < 2) { 359184610Salfred DPRINTF("too short message\n"); 360184610Salfred goto tr_setup; 361184610Salfred } 362194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 363194677Sthompsa usbd_copy_out(pc, 0, buf, sizeof(buf)); 364184610Salfred 365184610Salfred sc->sc_msr = buf[0]; 366184610Salfred sc->sc_lsr = buf[1]; 367184610Salfred 368194228Sthompsa ucom_status_change(&sc->sc_ucom); 369184610Salfred 370184610Salfred case USB_ST_SETUP: 371184610Salfredtr_setup: 372194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 373194228Sthompsa usbd_transfer_submit(xfer); 374184610Salfred return; 375184610Salfred 376184610Salfred default: /* Error */ 377194677Sthompsa if (error != USB_ERR_CANCELLED) { 378188413Sthompsa /* try to clear stall first */ 379194677Sthompsa usbd_xfer_set_stall(xfer); 380188413Sthompsa goto tr_setup; 381184610Salfred } 382184610Salfred return; 383184610Salfred } 384184610Salfred} 385184610Salfred 386184610Salfredstatic void 387192984Sthompsaumct_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) 388184610Salfred{ 389184610Salfred struct umct_softc *sc = ucom->sc_parent; 390184610Salfred 391184610Salfred *lsr = sc->sc_lsr; 392184610Salfred *msr = sc->sc_msr; 393184610Salfred} 394184610Salfred 395184610Salfredstatic void 396192984Sthompsaumct_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) 397184610Salfred{ 398184610Salfred struct umct_softc *sc = ucom->sc_parent; 399184610Salfred 400184610Salfred if (onoff) 401184610Salfred sc->sc_lcr |= 0x40; 402184610Salfred else 403184610Salfred sc->sc_lcr &= ~0x40; 404184610Salfred 405184610Salfred umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, sc->sc_lcr); 406184610Salfred} 407184610Salfred 408184610Salfredstatic void 409192984Sthompsaumct_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 410184610Salfred{ 411184610Salfred struct umct_softc *sc = ucom->sc_parent; 412184610Salfred 413184610Salfred if (onoff) 414184610Salfred sc->sc_mcr |= 0x01; 415184610Salfred else 416184610Salfred sc->sc_mcr &= ~0x01; 417184610Salfred 418184610Salfred umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr); 419184610Salfred} 420184610Salfred 421184610Salfredstatic void 422192984Sthompsaumct_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) 423184610Salfred{ 424184610Salfred struct umct_softc *sc = ucom->sc_parent; 425184610Salfred 426184610Salfred if (onoff) 427184610Salfred sc->sc_mcr |= 0x02; 428184610Salfred else 429184610Salfred sc->sc_mcr &= ~0x02; 430184610Salfred 431184610Salfred umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr); 432184610Salfred} 433184610Salfred 434184610Salfredstatic uint8_t 435184610Salfredumct_calc_baud(uint32_t baud) 436184610Salfred{ 437184610Salfred switch (baud) { 438184610Salfred case B300:return (0x1); 439184610Salfred case B600: 440184610Salfred return (0x2); 441184610Salfred case B1200: 442184610Salfred return (0x3); 443184610Salfred case B2400: 444184610Salfred return (0x4); 445184610Salfred case B4800: 446184610Salfred return (0x6); 447184610Salfred case B9600: 448184610Salfred return (0x8); 449184610Salfred case B19200: 450184610Salfred return (0x9); 451184610Salfred case B38400: 452184610Salfred return (0xa); 453184610Salfred case B57600: 454184610Salfred return (0xb); 455184610Salfred case 115200: 456184610Salfred return (0xc); 457184610Salfred case B0: 458184610Salfred default: 459184610Salfred break; 460184610Salfred } 461184610Salfred return (0x0); 462184610Salfred} 463184610Salfred 464184610Salfredstatic int 465192984Sthompsaumct_pre_param(struct ucom_softc *ucom, struct termios *t) 466184610Salfred{ 467184610Salfred return (0); /* we accept anything */ 468184610Salfred} 469184610Salfred 470184610Salfredstatic void 471192984Sthompsaumct_cfg_param(struct ucom_softc *ucom, struct termios *t) 472184610Salfred{ 473184610Salfred struct umct_softc *sc = ucom->sc_parent; 474184610Salfred uint32_t value; 475184610Salfred 476184610Salfred value = umct_calc_baud(t->c_ospeed); 477184610Salfred umct_cfg_do_request(sc, UMCT_SET_BAUD, UMCT_SET_BAUD_SIZE, value); 478184610Salfred 479184610Salfred value = (sc->sc_lcr & 0x40); 480184610Salfred 481184610Salfred switch (t->c_cflag & CSIZE) { 482184610Salfred case CS5: 483184610Salfred value |= 0x0; 484184610Salfred break; 485184610Salfred case CS6: 486184610Salfred value |= 0x1; 487184610Salfred break; 488184610Salfred case CS7: 489184610Salfred value |= 0x2; 490184610Salfred break; 491184610Salfred default: 492184610Salfred case CS8: 493184610Salfred value |= 0x3; 494184610Salfred break; 495184610Salfred } 496184610Salfred 497184610Salfred value |= (t->c_cflag & CSTOPB) ? 0x4 : 0; 498184610Salfred if (t->c_cflag & PARENB) { 499184610Salfred value |= 0x8; 500184610Salfred value |= (t->c_cflag & PARODD) ? 0x0 : 0x10; 501184610Salfred } 502184610Salfred /* 503184610Salfred * XXX There doesn't seem to be a way to tell the device 504184610Salfred * to use flow control. 505184610Salfred */ 506184610Salfred 507184610Salfred sc->sc_lcr = value; 508184610Salfred umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, value); 509184610Salfred} 510184610Salfred 511184610Salfredstatic void 512192984Sthompsaumct_start_read(struct ucom_softc *ucom) 513184610Salfred{ 514184610Salfred struct umct_softc *sc = ucom->sc_parent; 515184610Salfred 516184610Salfred /* start interrupt endpoint */ 517194228Sthompsa usbd_transfer_start(sc->sc_xfer[UMCT_INTR_DT_RD]); 518184610Salfred 519184610Salfred /* start read endpoint */ 520194228Sthompsa usbd_transfer_start(sc->sc_xfer[UMCT_BULK_DT_RD]); 521184610Salfred} 522184610Salfred 523184610Salfredstatic void 524192984Sthompsaumct_stop_read(struct ucom_softc *ucom) 525184610Salfred{ 526184610Salfred struct umct_softc *sc = ucom->sc_parent; 527184610Salfred 528184610Salfred /* stop interrupt endpoint */ 529194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UMCT_INTR_DT_RD]); 530184610Salfred 531184610Salfred /* stop read endpoint */ 532194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_RD]); 533184610Salfred} 534184610Salfred 535184610Salfredstatic void 536192984Sthompsaumct_start_write(struct ucom_softc *ucom) 537184610Salfred{ 538184610Salfred struct umct_softc *sc = ucom->sc_parent; 539184610Salfred 540194228Sthompsa usbd_transfer_start(sc->sc_xfer[UMCT_BULK_DT_WR]); 541184610Salfred} 542184610Salfred 543184610Salfredstatic void 544192984Sthompsaumct_stop_write(struct ucom_softc *ucom) 545184610Salfred{ 546184610Salfred struct umct_softc *sc = ucom->sc_parent; 547184610Salfred 548194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_WR]); 549184610Salfred} 550184610Salfred 551184610Salfredstatic void 552197573Sthompsaumct_read_callback(struct usb_xfer *xfer, usb_error_t error) 553197573Sthompsa{ 554197573Sthompsa struct umct_softc *sc = usbd_xfer_softc(xfer); 555197573Sthompsa 556197573Sthompsa if (sc->sc_swap_cb) 557197573Sthompsa umct_intr_callback_sub(xfer, error); 558197573Sthompsa else 559197573Sthompsa umct_read_callback_sub(xfer, error); 560197573Sthompsa} 561197573Sthompsa 562197573Sthompsastatic void 563197573Sthompsaumct_intr_callback(struct usb_xfer *xfer, usb_error_t error) 564197573Sthompsa{ 565197573Sthompsa struct umct_softc *sc = usbd_xfer_softc(xfer); 566197573Sthompsa 567197573Sthompsa if (sc->sc_swap_cb) 568197573Sthompsa umct_read_callback_sub(xfer, error); 569197573Sthompsa else 570197573Sthompsa umct_intr_callback_sub(xfer, error); 571197573Sthompsa} 572197573Sthompsa 573197573Sthompsastatic void 574194677Sthompsaumct_write_callback(struct usb_xfer *xfer, usb_error_t error) 575184610Salfred{ 576194677Sthompsa struct umct_softc *sc = usbd_xfer_softc(xfer); 577194677Sthompsa struct usb_page_cache *pc; 578184610Salfred uint32_t actlen; 579184610Salfred 580184610Salfred switch (USB_GET_STATE(xfer)) { 581184610Salfred case USB_ST_SETUP: 582184610Salfred case USB_ST_TRANSFERRED: 583188413Sthompsatr_setup: 584194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 585194677Sthompsa if (ucom_get_data(&sc->sc_ucom, pc, 0, 586184610Salfred sc->sc_obufsize, &actlen)) { 587184610Salfred 588194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, actlen); 589194228Sthompsa usbd_transfer_submit(xfer); 590184610Salfred } 591184610Salfred return; 592184610Salfred 593184610Salfred default: /* Error */ 594194677Sthompsa if (error != USB_ERR_CANCELLED) { 595188413Sthompsa /* try to clear stall first */ 596194677Sthompsa usbd_xfer_set_stall(xfer); 597188413Sthompsa goto tr_setup; 598184610Salfred } 599184610Salfred return; 600184610Salfred } 601184610Salfred} 602184610Salfred 603184610Salfredstatic void 604197573Sthompsaumct_read_callback_sub(struct usb_xfer *xfer, usb_error_t error) 605184610Salfred{ 606194677Sthompsa struct umct_softc *sc = usbd_xfer_softc(xfer); 607194677Sthompsa struct usb_page_cache *pc; 608194677Sthompsa int actlen; 609184610Salfred 610194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 611194677Sthompsa 612184610Salfred switch (USB_GET_STATE(xfer)) { 613184610Salfred case USB_ST_TRANSFERRED: 614194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 615194677Sthompsa ucom_put_data(&sc->sc_ucom, pc, 0, actlen); 616184610Salfred 617184610Salfred case USB_ST_SETUP: 618188413Sthompsatr_setup: 619194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 620194228Sthompsa usbd_transfer_submit(xfer); 621184610Salfred return; 622184610Salfred 623184610Salfred default: /* Error */ 624194677Sthompsa if (error != USB_ERR_CANCELLED) { 625188413Sthompsa /* try to clear stall first */ 626194677Sthompsa usbd_xfer_set_stall(xfer); 627188413Sthompsa goto tr_setup; 628184610Salfred } 629184610Salfred return; 630184610Salfred } 631184610Salfred} 632197570Sthompsa 633197570Sthompsastatic void 634197570Sthompsaumct_poll(struct ucom_softc *ucom) 635197570Sthompsa{ 636197570Sthompsa struct umct_softc *sc = ucom->sc_parent; 637197570Sthompsa usbd_transfer_poll(sc->sc_xfer, UMCT_N_TRANSFER); 638197570Sthompsa} 639