1184610Salfred/*- 2189002Sed * Copyright (c) 2004 Bernd Walter <ticso@FreeBSD.org> 3184610Salfred * 4184610Salfred * $URL: https://devel.bwct.de/svn/projects/ubser/ubser.c $ 5184610Salfred * $Date: 2004-02-29 01:53:10 +0100 (Sun, 29 Feb 2004) $ 6184610Salfred * $Author: ticso $ 7184610Salfred * $Rev: 1127 $ 8184610Salfred */ 9184610Salfred 10184610Salfred/*- 11184610Salfred * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>. 12184610Salfred * All rights reserved. 13184610Salfred * 14184610Salfred * Redistribution and use in source and binary forms, with or without 15184610Salfred * modification, are permitted provided that the following conditions 16184610Salfred * are met: 17184610Salfred * 1. Redistributions of source code must retain the above copyright 18184610Salfred * notice, this list of conditions and the following disclaimer. 19184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 20184610Salfred * notice, this list of conditions and the following disclaimer in the 21184610Salfred * documentation and/or other materials provided with the distribution. 22184610Salfred * 23184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33184610Salfred * SUCH DAMAGE. 34184610Salfred */ 35184610Salfred 36184610Salfred/*- 37184610Salfred * Copyright (c) 2000 The NetBSD Foundation, Inc. 38184610Salfred * All rights reserved. 39184610Salfred * 40184610Salfred * This code is derived from software contributed to The NetBSD Foundation 41184610Salfred * by Lennart Augustsson (lennart@augustsson.net). 42184610Salfred * 43184610Salfred * Redistribution and use in source and binary forms, with or without 44184610Salfred * modification, are permitted provided that the following conditions 45184610Salfred * are met: 46184610Salfred * 1. Redistributions of source code must retain the above copyright 47184610Salfred * notice, this list of conditions and the following disclaimer. 48184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 49184610Salfred * notice, this list of conditions and the following disclaimer in the 50184610Salfred * documentation and/or other materials provided with the distribution. 51184610Salfred * 52184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 53184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 54184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 55184610Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 56184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 57184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 58184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 59184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 60184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 61184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 62184610Salfred * POSSIBILITY OF SUCH DAMAGE. 63184610Salfred */ 64184610Salfred 65184610Salfred#include <sys/cdefs.h> 66184610Salfred__FBSDID("$FreeBSD$"); 67184610Salfred 68184610Salfred/* 69184610Salfred * BWCT serial adapter driver 70184610Salfred */ 71184610Salfred 72194677Sthompsa#include <sys/stdint.h> 73194677Sthompsa#include <sys/stddef.h> 74194677Sthompsa#include <sys/param.h> 75194677Sthompsa#include <sys/queue.h> 76194677Sthompsa#include <sys/types.h> 77194677Sthompsa#include <sys/systm.h> 78194677Sthompsa#include <sys/kernel.h> 79194677Sthompsa#include <sys/bus.h> 80194677Sthompsa#include <sys/module.h> 81194677Sthompsa#include <sys/lock.h> 82194677Sthompsa#include <sys/mutex.h> 83194677Sthompsa#include <sys/condvar.h> 84194677Sthompsa#include <sys/sysctl.h> 85194677Sthompsa#include <sys/sx.h> 86194677Sthompsa#include <sys/unistd.h> 87194677Sthompsa#include <sys/callout.h> 88194677Sthompsa#include <sys/malloc.h> 89194677Sthompsa#include <sys/priv.h> 90194677Sthompsa 91188942Sthompsa#include <dev/usb/usb.h> 92194677Sthompsa#include <dev/usb/usbdi.h> 93194677Sthompsa#include <dev/usb/usbdi_util.h> 94194677Sthompsa#include "usbdevs.h" 95184610Salfred 96184610Salfred#define USB_DEBUG_VAR ubser_debug 97188942Sthompsa#include <dev/usb/usb_debug.h> 98188942Sthompsa#include <dev/usb/usb_process.h> 99184610Salfred 100188942Sthompsa#include <dev/usb/serial/usb_serial.h> 101184610Salfred 102184610Salfred#define UBSER_UNIT_MAX 32 103184610Salfred 104184610Salfred/* Vendor Interface Requests */ 105184610Salfred#define VENDOR_GET_NUMSER 0x01 106184610Salfred#define VENDOR_SET_BREAK 0x02 107184610Salfred#define VENDOR_CLEAR_BREAK 0x03 108184610Salfred 109207077Sthompsa#ifdef USB_DEBUG 110184610Salfredstatic int ubser_debug = 0; 111184610Salfred 112227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, ubser, CTLFLAG_RW, 0, "USB ubser"); 113276701ShselaskySYSCTL_INT(_hw_usb_ubser, OID_AUTO, debug, CTLFLAG_RWTUN, 114184610Salfred &ubser_debug, 0, "ubser debug level"); 115184610Salfred#endif 116184610Salfred 117187259Sthompsaenum { 118187259Sthompsa UBSER_BULK_DT_WR, 119187259Sthompsa UBSER_BULK_DT_RD, 120188413Sthompsa UBSER_N_TRANSFER, 121187259Sthompsa}; 122184610Salfred 123184610Salfredstruct ubser_softc { 124192984Sthompsa struct ucom_super_softc sc_super_ucom; 125192984Sthompsa struct ucom_softc sc_ucom[UBSER_UNIT_MAX]; 126184610Salfred 127192984Sthompsa struct usb_xfer *sc_xfer[UBSER_N_TRANSFER]; 128192984Sthompsa struct usb_device *sc_udev; 129189265Sthompsa struct mtx sc_mtx; 130184610Salfred 131184610Salfred uint16_t sc_tx_size; 132184610Salfred 133184610Salfred uint8_t sc_numser; 134184610Salfred uint8_t sc_iface_no; 135184610Salfred uint8_t sc_iface_index; 136184610Salfred uint8_t sc_curr_tx_unit; 137184610Salfred}; 138184610Salfred 139184610Salfred/* prototypes */ 140184610Salfred 141184610Salfredstatic device_probe_t ubser_probe; 142184610Salfredstatic device_attach_t ubser_attach; 143184610Salfredstatic device_detach_t ubser_detach; 144239299Shselaskystatic void ubser_free_softc(struct ubser_softc *); 145184610Salfred 146193045Sthompsastatic usb_callback_t ubser_write_callback; 147193045Sthompsastatic usb_callback_t ubser_read_callback; 148184610Salfred 149239180Shselaskystatic void ubser_free(struct ucom_softc *); 150192984Sthompsastatic int ubser_pre_param(struct ucom_softc *, struct termios *); 151192984Sthompsastatic void ubser_cfg_set_break(struct ucom_softc *, uint8_t); 152192984Sthompsastatic void ubser_cfg_get_status(struct ucom_softc *, uint8_t *, 153185948Sthompsa uint8_t *); 154192984Sthompsastatic void ubser_start_read(struct ucom_softc *); 155192984Sthompsastatic void ubser_stop_read(struct ucom_softc *); 156192984Sthompsastatic void ubser_start_write(struct ucom_softc *); 157192984Sthompsastatic void ubser_stop_write(struct ucom_softc *); 158197570Sthompsastatic void ubser_poll(struct ucom_softc *ucom); 159184610Salfred 160192984Sthompsastatic const struct usb_config ubser_config[UBSER_N_TRANSFER] = { 161184610Salfred 162187259Sthompsa [UBSER_BULK_DT_WR] = { 163184610Salfred .type = UE_BULK, 164184610Salfred .endpoint = UE_ADDR_ANY, 165184610Salfred .direction = UE_DIR_OUT, 166190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 167190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 168190734Sthompsa .callback = &ubser_write_callback, 169184610Salfred }, 170184610Salfred 171187259Sthompsa [UBSER_BULK_DT_RD] = { 172184610Salfred .type = UE_BULK, 173184610Salfred .endpoint = UE_ADDR_ANY, 174184610Salfred .direction = UE_DIR_IN, 175190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 176190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 177190734Sthompsa .callback = &ubser_read_callback, 178184610Salfred }, 179184610Salfred}; 180184610Salfred 181192984Sthompsastatic const struct ucom_callback ubser_callback = { 182194228Sthompsa .ucom_cfg_set_break = &ubser_cfg_set_break, 183194228Sthompsa .ucom_cfg_get_status = &ubser_cfg_get_status, 184194228Sthompsa .ucom_pre_param = &ubser_pre_param, 185194228Sthompsa .ucom_start_read = &ubser_start_read, 186194228Sthompsa .ucom_stop_read = &ubser_stop_read, 187194228Sthompsa .ucom_start_write = &ubser_start_write, 188194228Sthompsa .ucom_stop_write = &ubser_stop_write, 189197570Sthompsa .ucom_poll = &ubser_poll, 190239180Shselasky .ucom_free = &ubser_free, 191184610Salfred}; 192184610Salfred 193184610Salfredstatic device_method_t ubser_methods[] = { 194184610Salfred DEVMETHOD(device_probe, ubser_probe), 195184610Salfred DEVMETHOD(device_attach, ubser_attach), 196184610Salfred DEVMETHOD(device_detach, ubser_detach), 197239180Shselasky DEVMETHOD_END 198184610Salfred}; 199184610Salfred 200184610Salfredstatic devclass_t ubser_devclass; 201184610Salfred 202184610Salfredstatic driver_t ubser_driver = { 203184610Salfred .name = "ubser", 204184610Salfred .methods = ubser_methods, 205184610Salfred .size = sizeof(struct ubser_softc), 206184610Salfred}; 207184610Salfred 208189275SthompsaDRIVER_MODULE(ubser, uhub, ubser_driver, ubser_devclass, NULL, 0); 209188942SthompsaMODULE_DEPEND(ubser, ucom, 1, 1, 1); 210188942SthompsaMODULE_DEPEND(ubser, usb, 1, 1, 1); 211212122SthompsaMODULE_VERSION(ubser, 1); 212184610Salfred 213184610Salfredstatic int 214184610Salfredubser_probe(device_t dev) 215184610Salfred{ 216192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 217184610Salfred 218192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 219184610Salfred return (ENXIO); 220184610Salfred } 221184610Salfred /* check if this is a BWCT vendor specific ubser interface */ 222212136Sthompsa if ((strcmp(usb_get_manufacturer(uaa->device), "BWCT") == 0) && 223184610Salfred (uaa->info.bInterfaceClass == 0xff) && 224184610Salfred (uaa->info.bInterfaceSubClass == 0x00)) 225184610Salfred return (0); 226184610Salfred 227184610Salfred return (ENXIO); 228184610Salfred} 229184610Salfred 230184610Salfredstatic int 231184610Salfredubser_attach(device_t dev) 232184610Salfred{ 233192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 234184610Salfred struct ubser_softc *sc = device_get_softc(dev); 235192984Sthompsa struct usb_device_request req; 236184610Salfred uint8_t n; 237184610Salfred int error; 238184610Salfred 239194228Sthompsa device_set_usb_desc(dev); 240189265Sthompsa mtx_init(&sc->sc_mtx, "ubser", NULL, MTX_DEF); 241239180Shselasky ucom_ref(&sc->sc_super_ucom); 242184610Salfred 243184610Salfred sc->sc_iface_no = uaa->info.bIfaceNum; 244184610Salfred sc->sc_iface_index = uaa->info.bIfaceIndex; 245184610Salfred sc->sc_udev = uaa->device; 246184610Salfred 247184610Salfred /* get number of serials */ 248184610Salfred req.bmRequestType = UT_READ_VENDOR_INTERFACE; 249184610Salfred req.bRequest = VENDOR_GET_NUMSER; 250184610Salfred USETW(req.wValue, 0); 251184610Salfred req.wIndex[0] = sc->sc_iface_no; 252184610Salfred req.wIndex[1] = 0; 253184610Salfred USETW(req.wLength, 1); 254194228Sthompsa error = usbd_do_request_flags(uaa->device, NULL, 255190172Sthompsa &req, &sc->sc_numser, 256184610Salfred 0, NULL, USB_DEFAULT_TIMEOUT); 257184610Salfred 258184610Salfred if (error || (sc->sc_numser == 0)) { 259184610Salfred device_printf(dev, "failed to get number " 260184610Salfred "of serial ports: %s\n", 261194228Sthompsa usbd_errstr(error)); 262184610Salfred goto detach; 263184610Salfred } 264184610Salfred if (sc->sc_numser > UBSER_UNIT_MAX) 265184610Salfred sc->sc_numser = UBSER_UNIT_MAX; 266184610Salfred 267184610Salfred device_printf(dev, "found %i serials\n", sc->sc_numser); 268184610Salfred 269194228Sthompsa error = usbd_transfer_setup(uaa->device, &sc->sc_iface_index, 270189265Sthompsa sc->sc_xfer, ubser_config, UBSER_N_TRANSFER, sc, &sc->sc_mtx); 271184610Salfred if (error) { 272184610Salfred goto detach; 273184610Salfred } 274194677Sthompsa sc->sc_tx_size = usbd_xfer_max_len(sc->sc_xfer[UBSER_BULK_DT_WR]); 275184610Salfred 276184610Salfred if (sc->sc_tx_size == 0) { 277199816Sthompsa DPRINTFN(0, "invalid tx_size\n"); 278184610Salfred goto detach; 279184610Salfred } 280184610Salfred /* initialize port numbers */ 281184610Salfred 282184610Salfred for (n = 0; n < sc->sc_numser; n++) { 283184610Salfred sc->sc_ucom[n].sc_portno = n; 284184610Salfred } 285184610Salfred 286194228Sthompsa error = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom, 287189265Sthompsa sc->sc_numser, sc, &ubser_callback, &sc->sc_mtx); 288184610Salfred if (error) { 289184610Salfred goto detach; 290184610Salfred } 291214843Sn_hibma ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); 292184610Salfred 293189265Sthompsa mtx_lock(&sc->sc_mtx); 294194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[UBSER_BULK_DT_WR]); 295194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[UBSER_BULK_DT_RD]); 296194228Sthompsa usbd_transfer_start(sc->sc_xfer[UBSER_BULK_DT_RD]); 297189265Sthompsa mtx_unlock(&sc->sc_mtx); 298184610Salfred 299184610Salfred return (0); /* success */ 300184610Salfred 301184610Salfreddetach: 302184610Salfred ubser_detach(dev); 303184610Salfred return (ENXIO); /* failure */ 304184610Salfred} 305184610Salfred 306184610Salfredstatic int 307184610Salfredubser_detach(device_t dev) 308184610Salfred{ 309184610Salfred struct ubser_softc *sc = device_get_softc(dev); 310184610Salfred 311184610Salfred DPRINTF("\n"); 312184610Salfred 313214761Sn_hibma ucom_detach(&sc->sc_super_ucom, sc->sc_ucom); 314194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UBSER_N_TRANSFER); 315184610Salfred 316239299Shselasky device_claim_softc(dev); 317239299Shselasky 318239299Shselasky ubser_free_softc(sc); 319239299Shselasky 320184610Salfred return (0); 321184610Salfred} 322184610Salfred 323239180ShselaskyUCOM_UNLOAD_DRAIN(ubser); 324239180Shselasky 325239180Shselaskystatic void 326239299Shselaskyubser_free_softc(struct ubser_softc *sc) 327239180Shselasky{ 328239180Shselasky if (ucom_unref(&sc->sc_super_ucom)) { 329239299Shselasky mtx_destroy(&sc->sc_mtx); 330239299Shselasky device_free_softc(sc); 331239180Shselasky } 332239180Shselasky} 333239180Shselasky 334239180Shselaskystatic void 335239180Shselaskyubser_free(struct ucom_softc *ucom) 336239180Shselasky{ 337239299Shselasky ubser_free_softc(ucom->sc_parent); 338239180Shselasky} 339239180Shselasky 340184610Salfredstatic int 341192984Sthompsaubser_pre_param(struct ucom_softc *ucom, struct termios *t) 342184610Salfred{ 343184610Salfred DPRINTF("\n"); 344184610Salfred 345184610Salfred /* 346184610Salfred * The firmware on our devices can only do 8n1@9600bps 347184610Salfred * without handshake. 348184610Salfred * We refuse to accept other configurations. 349184610Salfred */ 350184610Salfred 351184610Salfred /* ensure 9600bps */ 352184610Salfred switch (t->c_ospeed) { 353184610Salfred case 9600: 354184610Salfred break; 355184610Salfred default: 356184610Salfred return (EINVAL); 357184610Salfred } 358184610Salfred 359184610Salfred /* 2 stop bits not possible */ 360184610Salfred if (t->c_cflag & CSTOPB) 361184610Salfred return (EINVAL); 362184610Salfred 363184610Salfred /* XXX parity handling not possible with current firmware */ 364184610Salfred if (t->c_cflag & PARENB) 365184610Salfred return (EINVAL); 366184610Salfred 367184610Salfred /* we can only do 8 data bits */ 368184610Salfred switch (t->c_cflag & CSIZE) { 369184610Salfred case CS8: 370184610Salfred break; 371184610Salfred default: 372184610Salfred return (EINVAL); 373184610Salfred } 374184610Salfred 375184610Salfred /* we can't do any kind of hardware handshaking */ 376184610Salfred if ((t->c_cflag & 377184610Salfred (CRTS_IFLOW | CDTR_IFLOW | CDSR_OFLOW | CCAR_OFLOW)) != 0) 378184610Salfred return (EINVAL); 379184610Salfred 380184610Salfred /* 381184610Salfred * XXX xon/xoff not supported by the firmware! 382184610Salfred * This is handled within FreeBSD only and may overflow buffers 383184610Salfred * because of delayed reaction due to device buffering. 384184610Salfred */ 385184610Salfred 386184610Salfred return (0); 387184610Salfred} 388184610Salfred 389184610Salfredstatic __inline void 390184610Salfredubser_inc_tx_unit(struct ubser_softc *sc) 391184610Salfred{ 392184610Salfred sc->sc_curr_tx_unit++; 393184610Salfred if (sc->sc_curr_tx_unit >= sc->sc_numser) { 394184610Salfred sc->sc_curr_tx_unit = 0; 395184610Salfred } 396184610Salfred} 397184610Salfred 398184610Salfredstatic void 399194677Sthompsaubser_write_callback(struct usb_xfer *xfer, usb_error_t error) 400184610Salfred{ 401194677Sthompsa struct ubser_softc *sc = usbd_xfer_softc(xfer); 402194677Sthompsa struct usb_page_cache *pc; 403184610Salfred uint8_t buf[1]; 404184610Salfred uint8_t first_unit = sc->sc_curr_tx_unit; 405184610Salfred uint32_t actlen; 406184610Salfred 407184610Salfred switch (USB_GET_STATE(xfer)) { 408184610Salfred case USB_ST_SETUP: 409184610Salfred case USB_ST_TRANSFERRED: 410188413Sthompsatr_setup: 411194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 412184610Salfred do { 413194228Sthompsa if (ucom_get_data(sc->sc_ucom + sc->sc_curr_tx_unit, 414194677Sthompsa pc, 1, sc->sc_tx_size - 1, 415184610Salfred &actlen)) { 416184610Salfred 417184610Salfred buf[0] = sc->sc_curr_tx_unit; 418184610Salfred 419194677Sthompsa usbd_copy_in(pc, 0, buf, 1); 420184610Salfred 421194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, actlen + 1); 422194228Sthompsa usbd_transfer_submit(xfer); 423184610Salfred 424184610Salfred ubser_inc_tx_unit(sc); /* round robin */ 425184610Salfred 426184610Salfred break; 427184610Salfred } 428184610Salfred ubser_inc_tx_unit(sc); 429184610Salfred 430184610Salfred } while (sc->sc_curr_tx_unit != first_unit); 431184610Salfred 432184610Salfred return; 433184610Salfred 434184610Salfred default: /* Error */ 435194677Sthompsa if (error != USB_ERR_CANCELLED) { 436188413Sthompsa /* try to clear stall first */ 437194677Sthompsa usbd_xfer_set_stall(xfer); 438188413Sthompsa goto tr_setup; 439184610Salfred } 440184610Salfred return; 441184610Salfred 442184610Salfred } 443184610Salfred} 444184610Salfred 445184610Salfredstatic void 446194677Sthompsaubser_read_callback(struct usb_xfer *xfer, usb_error_t error) 447184610Salfred{ 448194677Sthompsa struct ubser_softc *sc = usbd_xfer_softc(xfer); 449194677Sthompsa struct usb_page_cache *pc; 450184610Salfred uint8_t buf[1]; 451194677Sthompsa int actlen; 452184610Salfred 453194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 454194677Sthompsa 455184610Salfred switch (USB_GET_STATE(xfer)) { 456184610Salfred case USB_ST_TRANSFERRED: 457194677Sthompsa if (actlen < 1) { 458184610Salfred DPRINTF("invalid actlen=0!\n"); 459184610Salfred goto tr_setup; 460184610Salfred } 461194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 462194677Sthompsa usbd_copy_out(pc, 0, buf, 1); 463184610Salfred 464184610Salfred if (buf[0] >= sc->sc_numser) { 465184610Salfred DPRINTF("invalid serial number!\n"); 466184610Salfred goto tr_setup; 467184610Salfred } 468194677Sthompsa ucom_put_data(sc->sc_ucom + buf[0], pc, 1, actlen - 1); 469184610Salfred 470184610Salfred case USB_ST_SETUP: 471184610Salfredtr_setup: 472194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 473194228Sthompsa usbd_transfer_submit(xfer); 474184610Salfred return; 475184610Salfred 476184610Salfred default: /* Error */ 477194677Sthompsa if (error != USB_ERR_CANCELLED) { 478188413Sthompsa /* try to clear stall first */ 479194677Sthompsa usbd_xfer_set_stall(xfer); 480188413Sthompsa goto tr_setup; 481184610Salfred } 482184610Salfred return; 483184610Salfred 484184610Salfred } 485184610Salfred} 486184610Salfred 487184610Salfredstatic void 488192984Sthompsaubser_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) 489184610Salfred{ 490184610Salfred struct ubser_softc *sc = ucom->sc_parent; 491184610Salfred uint8_t x = ucom->sc_portno; 492192984Sthompsa struct usb_device_request req; 493193045Sthompsa usb_error_t err; 494184610Salfred 495184610Salfred if (onoff) { 496184610Salfred 497184610Salfred req.bmRequestType = UT_READ_VENDOR_INTERFACE; 498184610Salfred req.bRequest = VENDOR_SET_BREAK; 499184610Salfred req.wValue[0] = x; 500184610Salfred req.wValue[1] = 0; 501184610Salfred req.wIndex[0] = sc->sc_iface_no; 502184610Salfred req.wIndex[1] = 0; 503184610Salfred USETW(req.wLength, 0); 504184610Salfred 505194228Sthompsa err = ucom_cfg_do_request(sc->sc_udev, ucom, 506188413Sthompsa &req, NULL, 0, 1000); 507184610Salfred if (err) { 508184610Salfred DPRINTFN(0, "send break failed, error=%s\n", 509194228Sthompsa usbd_errstr(err)); 510184610Salfred } 511184610Salfred } 512184610Salfred} 513184610Salfred 514184610Salfredstatic void 515192984Sthompsaubser_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) 516184610Salfred{ 517184610Salfred /* fake status bits */ 518184610Salfred *lsr = 0; 519184610Salfred *msr = SER_DCD; 520184610Salfred} 521184610Salfred 522184610Salfredstatic void 523192984Sthompsaubser_start_read(struct ucom_softc *ucom) 524184610Salfred{ 525184610Salfred struct ubser_softc *sc = ucom->sc_parent; 526184610Salfred 527194228Sthompsa usbd_transfer_start(sc->sc_xfer[UBSER_BULK_DT_RD]); 528184610Salfred} 529184610Salfred 530184610Salfredstatic void 531192984Sthompsaubser_stop_read(struct ucom_softc *ucom) 532184610Salfred{ 533184610Salfred struct ubser_softc *sc = ucom->sc_parent; 534184610Salfred 535194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UBSER_BULK_DT_RD]); 536184610Salfred} 537184610Salfred 538184610Salfredstatic void 539192984Sthompsaubser_start_write(struct ucom_softc *ucom) 540184610Salfred{ 541184610Salfred struct ubser_softc *sc = ucom->sc_parent; 542184610Salfred 543194228Sthompsa usbd_transfer_start(sc->sc_xfer[UBSER_BULK_DT_WR]); 544184610Salfred} 545184610Salfred 546184610Salfredstatic void 547192984Sthompsaubser_stop_write(struct ucom_softc *ucom) 548184610Salfred{ 549184610Salfred struct ubser_softc *sc = ucom->sc_parent; 550184610Salfred 551194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UBSER_BULK_DT_WR]); 552184610Salfred} 553197570Sthompsa 554197570Sthompsastatic void 555197570Sthompsaubser_poll(struct ucom_softc *ucom) 556197570Sthompsa{ 557197570Sthompsa struct ubser_softc *sc = ucom->sc_parent; 558197570Sthompsa usbd_transfer_poll(sc->sc_xfer, UBSER_N_TRANSFER); 559197570Sthompsa} 560