1184610Salfred/* $FreeBSD: releng/11.0/sys/dev/usb/serial/umoscom.c 292080 2015-12-11 05:28:00Z imp $ */ 2184610Salfred/* $OpenBSD: umoscom.c,v 1.2 2006/10/26 06:02:43 jsg Exp $ */ 3184610Salfred 4184610Salfred/* 5184610Salfred * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org> 6184610Salfred * 7184610Salfred * Permission to use, copy, modify, and distribute this software for any 8184610Salfred * purpose with or without fee is hereby granted, provided that the above 9184610Salfred * copyright notice and this permission notice appear in all copies. 10184610Salfred * 11184610Salfred * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12184610Salfred * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13184610Salfred * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14184610Salfred * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15184610Salfred * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16184610Salfred * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17184610Salfred * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18184610Salfred */ 19184610Salfred 20194677Sthompsa#include <sys/stdint.h> 21194677Sthompsa#include <sys/stddef.h> 22194677Sthompsa#include <sys/param.h> 23194677Sthompsa#include <sys/queue.h> 24194677Sthompsa#include <sys/types.h> 25194677Sthompsa#include <sys/systm.h> 26194677Sthompsa#include <sys/kernel.h> 27194677Sthompsa#include <sys/bus.h> 28194677Sthompsa#include <sys/module.h> 29194677Sthompsa#include <sys/lock.h> 30194677Sthompsa#include <sys/mutex.h> 31194677Sthompsa#include <sys/condvar.h> 32194677Sthompsa#include <sys/sysctl.h> 33194677Sthompsa#include <sys/sx.h> 34194677Sthompsa#include <sys/unistd.h> 35194677Sthompsa#include <sys/callout.h> 36194677Sthompsa#include <sys/malloc.h> 37194677Sthompsa#include <sys/priv.h> 38194677Sthompsa 39194677Sthompsa#include <dev/usb/usb.h> 40194677Sthompsa#include <dev/usb/usbdi.h> 41194677Sthompsa#include <dev/usb/usbdi_util.h> 42188746Sthompsa#include "usbdevs.h" 43184610Salfred 44184610Salfred#define USB_DEBUG_VAR umoscom_debug 45188942Sthompsa#include <dev/usb/usb_debug.h> 46188942Sthompsa#include <dev/usb/usb_process.h> 47184610Salfred 48188942Sthompsa#include <dev/usb/serial/usb_serial.h> 49184610Salfred 50207077Sthompsa#ifdef USB_DEBUG 51184610Salfredstatic int umoscom_debug = 0; 52184610Salfred 53227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, umoscom, CTLFLAG_RW, 0, "USB umoscom"); 54276701ShselaskySYSCTL_INT(_hw_usb_umoscom, OID_AUTO, debug, CTLFLAG_RWTUN, 55184610Salfred &umoscom_debug, 0, "Debug level"); 56184610Salfred#endif 57184610Salfred 58184610Salfred#define UMOSCOM_BUFSIZE 1024 /* bytes */ 59184610Salfred 60184610Salfred#define UMOSCOM_CONFIG_INDEX 0 61184610Salfred#define UMOSCOM_IFACE_INDEX 0 62184610Salfred 63184610Salfred/* interrupt packet */ 64184610Salfred#define UMOSCOM_IIR_RLS 0x06 65184610Salfred#define UMOSCOM_IIR_RDA 0x04 66184610Salfred#define UMOSCOM_IIR_CTI 0x0c 67184610Salfred#define UMOSCOM_IIR_THR 0x02 68184610Salfred#define UMOSCOM_IIR_MS 0x00 69184610Salfred 70184610Salfred/* registers */ 71184610Salfred#define UMOSCOM_READ 0x0d 72184610Salfred#define UMOSCOM_WRITE 0x0e 73184610Salfred#define UMOSCOM_UART_REG 0x0300 74184610Salfred#define UMOSCOM_VEND_REG 0x0000 75184610Salfred 76184610Salfred#define UMOSCOM_TXBUF 0x00 /* Write */ 77184610Salfred#define UMOSCOM_RXBUF 0x00 /* Read */ 78184610Salfred#define UMOSCOM_INT 0x01 79184610Salfred#define UMOSCOM_FIFO 0x02 /* Write */ 80184610Salfred#define UMOSCOM_ISR 0x02 /* Read */ 81184610Salfred#define UMOSCOM_LCR 0x03 82184610Salfred#define UMOSCOM_MCR 0x04 83184610Salfred#define UMOSCOM_LSR 0x05 84184610Salfred#define UMOSCOM_MSR 0x06 85184610Salfred#define UMOSCOM_SCRATCH 0x07 86184610Salfred#define UMOSCOM_DIV_LO 0x08 87184610Salfred#define UMOSCOM_DIV_HI 0x09 88184610Salfred#define UMOSCOM_EFR 0x0a 89184610Salfred#define UMOSCOM_XON1 0x0b 90184610Salfred#define UMOSCOM_XON2 0x0c 91184610Salfred#define UMOSCOM_XOFF1 0x0d 92184610Salfred#define UMOSCOM_XOFF2 0x0e 93184610Salfred 94184610Salfred#define UMOSCOM_BAUDLO 0x00 95184610Salfred#define UMOSCOM_BAUDHI 0x01 96184610Salfred 97184610Salfred#define UMOSCOM_INT_RXEN 0x01 98184610Salfred#define UMOSCOM_INT_TXEN 0x02 99184610Salfred#define UMOSCOM_INT_RSEN 0x04 100184610Salfred#define UMOSCOM_INT_MDMEM 0x08 101184610Salfred#define UMOSCOM_INT_SLEEP 0x10 102184610Salfred#define UMOSCOM_INT_XOFF 0x20 103184610Salfred#define UMOSCOM_INT_RTS 0x40 104184610Salfred 105184610Salfred#define UMOSCOM_FIFO_EN 0x01 106184610Salfred#define UMOSCOM_FIFO_RXCLR 0x02 107184610Salfred#define UMOSCOM_FIFO_TXCLR 0x04 108184610Salfred#define UMOSCOM_FIFO_DMA_BLK 0x08 109184610Salfred#define UMOSCOM_FIFO_TXLVL_MASK 0x30 110184610Salfred#define UMOSCOM_FIFO_TXLVL_8 0x00 111184610Salfred#define UMOSCOM_FIFO_TXLVL_16 0x10 112184610Salfred#define UMOSCOM_FIFO_TXLVL_32 0x20 113184610Salfred#define UMOSCOM_FIFO_TXLVL_56 0x30 114184610Salfred#define UMOSCOM_FIFO_RXLVL_MASK 0xc0 115184610Salfred#define UMOSCOM_FIFO_RXLVL_8 0x00 116184610Salfred#define UMOSCOM_FIFO_RXLVL_16 0x40 117184610Salfred#define UMOSCOM_FIFO_RXLVL_56 0x80 118184610Salfred#define UMOSCOM_FIFO_RXLVL_80 0xc0 119184610Salfred 120184610Salfred#define UMOSCOM_ISR_MDM 0x00 121184610Salfred#define UMOSCOM_ISR_NONE 0x01 122184610Salfred#define UMOSCOM_ISR_TX 0x02 123184610Salfred#define UMOSCOM_ISR_RX 0x04 124184610Salfred#define UMOSCOM_ISR_LINE 0x06 125184610Salfred#define UMOSCOM_ISR_RXTIMEOUT 0x0c 126184610Salfred#define UMOSCOM_ISR_RX_XOFF 0x10 127184610Salfred#define UMOSCOM_ISR_RTSCTS 0x20 128184610Salfred#define UMOSCOM_ISR_FIFOEN 0xc0 129184610Salfred 130184610Salfred#define UMOSCOM_LCR_DBITS(x) ((x) - 5) 131184610Salfred#define UMOSCOM_LCR_STOP_BITS_1 0x00 132184610Salfred#define UMOSCOM_LCR_STOP_BITS_2 0x04 /* 2 if 6-8 bits/char or 1.5 if 5 */ 133184610Salfred#define UMOSCOM_LCR_PARITY_NONE 0x00 134184610Salfred#define UMOSCOM_LCR_PARITY_ODD 0x08 135184610Salfred#define UMOSCOM_LCR_PARITY_EVEN 0x18 136184610Salfred#define UMOSCOM_LCR_BREAK 0x40 137184610Salfred#define UMOSCOM_LCR_DIVLATCH_EN 0x80 138184610Salfred 139184610Salfred#define UMOSCOM_MCR_DTR 0x01 140184610Salfred#define UMOSCOM_MCR_RTS 0x02 141184610Salfred#define UMOSCOM_MCR_LOOP 0x04 142184610Salfred#define UMOSCOM_MCR_INTEN 0x08 143184610Salfred#define UMOSCOM_MCR_LOOPBACK 0x10 144184610Salfred#define UMOSCOM_MCR_XONANY 0x20 145184610Salfred#define UMOSCOM_MCR_IRDA_EN 0x40 146184610Salfred#define UMOSCOM_MCR_BAUD_DIV4 0x80 147184610Salfred 148184610Salfred#define UMOSCOM_LSR_RXDATA 0x01 149184610Salfred#define UMOSCOM_LSR_RXOVER 0x02 150184610Salfred#define UMOSCOM_LSR_RXPAR_ERR 0x04 151184610Salfred#define UMOSCOM_LSR_RXFRM_ERR 0x08 152184610Salfred#define UMOSCOM_LSR_RXBREAK 0x10 153184610Salfred#define UMOSCOM_LSR_TXEMPTY 0x20 154184610Salfred#define UMOSCOM_LSR_TXALLEMPTY 0x40 155184610Salfred#define UMOSCOM_LSR_TXFIFO_ERR 0x80 156184610Salfred 157184610Salfred#define UMOSCOM_MSR_CTS_CHG 0x01 158184610Salfred#define UMOSCOM_MSR_DSR_CHG 0x02 159184610Salfred#define UMOSCOM_MSR_RI_CHG 0x04 160184610Salfred#define UMOSCOM_MSR_CD_CHG 0x08 161184610Salfred#define UMOSCOM_MSR_CTS 0x10 162184610Salfred#define UMOSCOM_MSR_RTS 0x20 163184610Salfred#define UMOSCOM_MSR_RI 0x40 164184610Salfred#define UMOSCOM_MSR_CD 0x80 165184610Salfred 166184610Salfred#define UMOSCOM_BAUD_REF 115200 167184610Salfred 168187259Sthompsaenum { 169187259Sthompsa UMOSCOM_BULK_DT_WR, 170187259Sthompsa UMOSCOM_BULK_DT_RD, 171187259Sthompsa UMOSCOM_INTR_DT_RD, 172188413Sthompsa UMOSCOM_N_TRANSFER, 173187259Sthompsa}; 174187259Sthompsa 175184610Salfredstruct umoscom_softc { 176192984Sthompsa struct ucom_super_softc sc_super_ucom; 177192984Sthompsa struct ucom_softc sc_ucom; 178184610Salfred 179192984Sthompsa struct usb_xfer *sc_xfer[UMOSCOM_N_TRANSFER]; 180192984Sthompsa struct usb_device *sc_udev; 181189265Sthompsa struct mtx sc_mtx; 182184610Salfred 183184610Salfred uint8_t sc_mcr; 184184610Salfred uint8_t sc_lcr; 185184610Salfred}; 186184610Salfred 187184610Salfred/* prototypes */ 188184610Salfred 189184610Salfredstatic device_probe_t umoscom_probe; 190184610Salfredstatic device_attach_t umoscom_attach; 191184610Salfredstatic device_detach_t umoscom_detach; 192239299Shselaskystatic void umoscom_free_softc(struct umoscom_softc *); 193184610Salfred 194193045Sthompsastatic usb_callback_t umoscom_write_callback; 195193045Sthompsastatic usb_callback_t umoscom_read_callback; 196193045Sthompsastatic usb_callback_t umoscom_intr_callback; 197184610Salfred 198239180Shselaskystatic void umoscom_free(struct ucom_softc *); 199192984Sthompsastatic void umoscom_cfg_open(struct ucom_softc *); 200192984Sthompsastatic void umoscom_cfg_close(struct ucom_softc *); 201192984Sthompsastatic void umoscom_cfg_set_break(struct ucom_softc *, uint8_t); 202192984Sthompsastatic void umoscom_cfg_set_dtr(struct ucom_softc *, uint8_t); 203192984Sthompsastatic void umoscom_cfg_set_rts(struct ucom_softc *, uint8_t); 204192984Sthompsastatic int umoscom_pre_param(struct ucom_softc *, struct termios *); 205192984Sthompsastatic void umoscom_cfg_param(struct ucom_softc *, struct termios *); 206192984Sthompsastatic void umoscom_cfg_get_status(struct ucom_softc *, uint8_t *, 207185948Sthompsa uint8_t *); 208185948Sthompsastatic void umoscom_cfg_write(struct umoscom_softc *, uint16_t, uint16_t); 209185948Sthompsastatic uint8_t umoscom_cfg_read(struct umoscom_softc *, uint16_t); 210192984Sthompsastatic void umoscom_start_read(struct ucom_softc *); 211192984Sthompsastatic void umoscom_stop_read(struct ucom_softc *); 212192984Sthompsastatic void umoscom_start_write(struct ucom_softc *); 213192984Sthompsastatic void umoscom_stop_write(struct ucom_softc *); 214197570Sthompsastatic void umoscom_poll(struct ucom_softc *ucom); 215184610Salfred 216192984Sthompsastatic const struct usb_config umoscom_config_data[UMOSCOM_N_TRANSFER] = { 217184610Salfred 218187259Sthompsa [UMOSCOM_BULK_DT_WR] = { 219184610Salfred .type = UE_BULK, 220184610Salfred .endpoint = UE_ADDR_ANY, 221184610Salfred .direction = UE_DIR_OUT, 222190734Sthompsa .bufsize = UMOSCOM_BUFSIZE, 223190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 224190734Sthompsa .callback = &umoscom_write_callback, 225184610Salfred }, 226184610Salfred 227187259Sthompsa [UMOSCOM_BULK_DT_RD] = { 228184610Salfred .type = UE_BULK, 229184610Salfred .endpoint = UE_ADDR_ANY, 230184610Salfred .direction = UE_DIR_IN, 231190734Sthompsa .bufsize = UMOSCOM_BUFSIZE, 232190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 233190734Sthompsa .callback = &umoscom_read_callback, 234184610Salfred }, 235184610Salfred 236187259Sthompsa [UMOSCOM_INTR_DT_RD] = { 237184610Salfred .type = UE_INTERRUPT, 238184610Salfred .endpoint = UE_ADDR_ANY, 239184610Salfred .direction = UE_DIR_IN, 240190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 241190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 242190734Sthompsa .callback = &umoscom_intr_callback, 243184610Salfred }, 244184610Salfred}; 245184610Salfred 246192984Sthompsastatic const struct ucom_callback umoscom_callback = { 247184610Salfred /* configuration callbacks */ 248194228Sthompsa .ucom_cfg_get_status = &umoscom_cfg_get_status, 249194228Sthompsa .ucom_cfg_set_dtr = &umoscom_cfg_set_dtr, 250194228Sthompsa .ucom_cfg_set_rts = &umoscom_cfg_set_rts, 251194228Sthompsa .ucom_cfg_set_break = &umoscom_cfg_set_break, 252194228Sthompsa .ucom_cfg_param = &umoscom_cfg_param, 253194228Sthompsa .ucom_cfg_open = &umoscom_cfg_open, 254194228Sthompsa .ucom_cfg_close = &umoscom_cfg_close, 255184610Salfred 256184610Salfred /* other callbacks */ 257194228Sthompsa .ucom_pre_param = &umoscom_pre_param, 258194228Sthompsa .ucom_start_read = &umoscom_start_read, 259194228Sthompsa .ucom_stop_read = &umoscom_stop_read, 260194228Sthompsa .ucom_start_write = &umoscom_start_write, 261194228Sthompsa .ucom_stop_write = &umoscom_stop_write, 262197570Sthompsa .ucom_poll = &umoscom_poll, 263239180Shselasky .ucom_free = &umoscom_free, 264184610Salfred}; 265184610Salfred 266184610Salfredstatic device_method_t umoscom_methods[] = { 267184610Salfred DEVMETHOD(device_probe, umoscom_probe), 268184610Salfred DEVMETHOD(device_attach, umoscom_attach), 269184610Salfred DEVMETHOD(device_detach, umoscom_detach), 270239180Shselasky DEVMETHOD_END 271184610Salfred}; 272184610Salfred 273184610Salfredstatic devclass_t umoscom_devclass; 274184610Salfred 275184610Salfredstatic driver_t umoscom_driver = { 276184610Salfred .name = "umoscom", 277184610Salfred .methods = umoscom_methods, 278184610Salfred .size = sizeof(struct umoscom_softc), 279184610Salfred}; 280184610Salfred 281292080Simpstatic const STRUCT_USB_HOST_ID umoscom_devs[] = { 282292080Simp {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7703, 0)} 283292080Simp}; 284292080Simp 285189275SthompsaDRIVER_MODULE(umoscom, uhub, umoscom_driver, umoscom_devclass, NULL, 0); 286188942SthompsaMODULE_DEPEND(umoscom, ucom, 1, 1, 1); 287188942SthompsaMODULE_DEPEND(umoscom, usb, 1, 1, 1); 288212122SthompsaMODULE_VERSION(umoscom, 1); 289292080SimpUSB_PNP_HOST_INFO(umoscom_devs); 290184610Salfred 291184610Salfredstatic int 292184610Salfredumoscom_probe(device_t dev) 293184610Salfred{ 294192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 295184610Salfred 296192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 297184610Salfred return (ENXIO); 298184610Salfred } 299184610Salfred if (uaa->info.bConfigIndex != UMOSCOM_CONFIG_INDEX) { 300184610Salfred return (ENXIO); 301184610Salfred } 302184610Salfred if (uaa->info.bIfaceIndex != UMOSCOM_IFACE_INDEX) { 303184610Salfred return (ENXIO); 304184610Salfred } 305194228Sthompsa return (usbd_lookup_id_by_uaa(umoscom_devs, sizeof(umoscom_devs), uaa)); 306184610Salfred} 307184610Salfred 308184610Salfredstatic int 309184610Salfredumoscom_attach(device_t dev) 310184610Salfred{ 311192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 312184610Salfred struct umoscom_softc *sc = device_get_softc(dev); 313184610Salfred int error; 314184610Salfred uint8_t iface_index; 315184610Salfred 316184610Salfred sc->sc_udev = uaa->device; 317184610Salfred sc->sc_mcr = 0x08; /* enable interrupts */ 318184610Salfred 319184610Salfred /* XXX the device doesn't provide any ID string, so set a static one */ 320184610Salfred device_set_desc(dev, "MOSCHIP USB Serial Port Adapter"); 321184610Salfred device_printf(dev, "<MOSCHIP USB Serial Port Adapter>\n"); 322184610Salfred 323189265Sthompsa mtx_init(&sc->sc_mtx, "umoscom", NULL, MTX_DEF); 324239180Shselasky ucom_ref(&sc->sc_super_ucom); 325189265Sthompsa 326184610Salfred iface_index = UMOSCOM_IFACE_INDEX; 327194228Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 328187259Sthompsa sc->sc_xfer, umoscom_config_data, 329189265Sthompsa UMOSCOM_N_TRANSFER, sc, &sc->sc_mtx); 330184610Salfred 331184610Salfred if (error) { 332184610Salfred goto detach; 333184610Salfred } 334184610Salfred /* clear stall at first run */ 335189265Sthompsa mtx_lock(&sc->sc_mtx); 336194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[UMOSCOM_BULK_DT_WR]); 337194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[UMOSCOM_BULK_DT_RD]); 338189265Sthompsa mtx_unlock(&sc->sc_mtx); 339184610Salfred 340194228Sthompsa error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 341189265Sthompsa &umoscom_callback, &sc->sc_mtx); 342184610Salfred if (error) { 343184610Salfred goto detach; 344184610Salfred } 345214843Sn_hibma ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); 346214843Sn_hibma 347184610Salfred return (0); 348184610Salfred 349184610Salfreddetach: 350194228Sthompsa device_printf(dev, "attach error: %s\n", usbd_errstr(error)); 351184610Salfred umoscom_detach(dev); 352184610Salfred return (ENXIO); 353184610Salfred} 354184610Salfred 355184610Salfredstatic int 356184610Salfredumoscom_detach(device_t dev) 357184610Salfred{ 358184610Salfred struct umoscom_softc *sc = device_get_softc(dev); 359184610Salfred 360214761Sn_hibma ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); 361194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UMOSCOM_N_TRANSFER); 362184610Salfred 363239299Shselasky device_claim_softc(dev); 364239299Shselasky 365239299Shselasky umoscom_free_softc(sc); 366239299Shselasky 367184610Salfred return (0); 368184610Salfred} 369184610Salfred 370239180ShselaskyUCOM_UNLOAD_DRAIN(umoscom); 371239180Shselasky 372184610Salfredstatic void 373239299Shselaskyumoscom_free_softc(struct umoscom_softc *sc) 374239180Shselasky{ 375239180Shselasky if (ucom_unref(&sc->sc_super_ucom)) { 376239299Shselasky mtx_destroy(&sc->sc_mtx); 377239299Shselasky device_free_softc(sc); 378239180Shselasky } 379239180Shselasky} 380239180Shselasky 381239180Shselaskystatic void 382239180Shselaskyumoscom_free(struct ucom_softc *ucom) 383239180Shselasky{ 384239299Shselasky umoscom_free_softc(ucom->sc_parent); 385239180Shselasky} 386239180Shselasky 387239180Shselaskystatic void 388192984Sthompsaumoscom_cfg_open(struct ucom_softc *ucom) 389184610Salfred{ 390184610Salfred struct umoscom_softc *sc = ucom->sc_parent; 391184610Salfred 392184610Salfred DPRINTF("\n"); 393184610Salfred 394184610Salfred /* Purge FIFOs or odd things happen */ 395184610Salfred umoscom_cfg_write(sc, UMOSCOM_FIFO, 0x00 | UMOSCOM_UART_REG); 396184610Salfred 397184610Salfred /* Enable FIFO */ 398184610Salfred umoscom_cfg_write(sc, UMOSCOM_FIFO, UMOSCOM_FIFO_EN | 399184610Salfred UMOSCOM_FIFO_RXCLR | UMOSCOM_FIFO_TXCLR | 400184610Salfred UMOSCOM_FIFO_DMA_BLK | UMOSCOM_FIFO_RXLVL_MASK | 401184610Salfred UMOSCOM_UART_REG); 402184610Salfred 403184610Salfred /* Enable Interrupt Registers */ 404184610Salfred umoscom_cfg_write(sc, UMOSCOM_INT, 0x0C | UMOSCOM_UART_REG); 405184610Salfred 406184610Salfred /* Magic */ 407184610Salfred umoscom_cfg_write(sc, 0x01, 0x08); 408184610Salfred 409184610Salfred /* Magic */ 410184610Salfred umoscom_cfg_write(sc, 0x00, 0x02); 411184610Salfred} 412184610Salfred 413184610Salfredstatic void 414192984Sthompsaumoscom_cfg_close(struct ucom_softc *ucom) 415184610Salfred{ 416184610Salfred return; 417184610Salfred} 418184610Salfred 419184610Salfredstatic void 420192984Sthompsaumoscom_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) 421184610Salfred{ 422184610Salfred struct umoscom_softc *sc = ucom->sc_parent; 423184610Salfred uint16_t val; 424184610Salfred 425184610Salfred val = sc->sc_lcr; 426184610Salfred if (onoff) 427184610Salfred val |= UMOSCOM_LCR_BREAK; 428184610Salfred 429184610Salfred umoscom_cfg_write(sc, UMOSCOM_LCR, val | UMOSCOM_UART_REG); 430184610Salfred} 431184610Salfred 432184610Salfredstatic void 433192984Sthompsaumoscom_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 434184610Salfred{ 435184610Salfred struct umoscom_softc *sc = ucom->sc_parent; 436184610Salfred 437184610Salfred if (onoff) 438184610Salfred sc->sc_mcr |= UMOSCOM_MCR_DTR; 439184610Salfred else 440184610Salfred sc->sc_mcr &= ~UMOSCOM_MCR_DTR; 441184610Salfred 442184610Salfred umoscom_cfg_write(sc, UMOSCOM_MCR, sc->sc_mcr | UMOSCOM_UART_REG); 443184610Salfred} 444184610Salfred 445184610Salfredstatic void 446192984Sthompsaumoscom_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) 447184610Salfred{ 448184610Salfred struct umoscom_softc *sc = ucom->sc_parent; 449184610Salfred 450184610Salfred if (onoff) 451184610Salfred sc->sc_mcr |= UMOSCOM_MCR_RTS; 452184610Salfred else 453184610Salfred sc->sc_mcr &= ~UMOSCOM_MCR_RTS; 454184610Salfred 455184610Salfred umoscom_cfg_write(sc, UMOSCOM_MCR, sc->sc_mcr | UMOSCOM_UART_REG); 456184610Salfred} 457184610Salfred 458184610Salfredstatic int 459192984Sthompsaumoscom_pre_param(struct ucom_softc *ucom, struct termios *t) 460184610Salfred{ 461184610Salfred if ((t->c_ospeed <= 1) || (t->c_ospeed > 115200)) 462184610Salfred return (EINVAL); 463184610Salfred 464184610Salfred return (0); 465184610Salfred} 466184610Salfred 467184610Salfredstatic void 468192984Sthompsaumoscom_cfg_param(struct ucom_softc *ucom, struct termios *t) 469184610Salfred{ 470184610Salfred struct umoscom_softc *sc = ucom->sc_parent; 471184610Salfred uint16_t data; 472184610Salfred 473184610Salfred DPRINTF("speed=%d\n", t->c_ospeed); 474184610Salfred 475184610Salfred data = ((uint32_t)UMOSCOM_BAUD_REF) / ((uint32_t)t->c_ospeed); 476184610Salfred 477184610Salfred if (data == 0) { 478184610Salfred DPRINTF("invalid baud rate!\n"); 479184610Salfred return; 480184610Salfred } 481184610Salfred umoscom_cfg_write(sc, UMOSCOM_LCR, 482184610Salfred UMOSCOM_LCR_DIVLATCH_EN | UMOSCOM_UART_REG); 483184610Salfred 484184610Salfred umoscom_cfg_write(sc, UMOSCOM_BAUDLO, 485184610Salfred (data & 0xFF) | UMOSCOM_UART_REG); 486184610Salfred 487184610Salfred umoscom_cfg_write(sc, UMOSCOM_BAUDHI, 488184610Salfred ((data >> 8) & 0xFF) | UMOSCOM_UART_REG); 489184610Salfred 490184610Salfred if (t->c_cflag & CSTOPB) 491184610Salfred data = UMOSCOM_LCR_STOP_BITS_2; 492184610Salfred else 493184610Salfred data = UMOSCOM_LCR_STOP_BITS_1; 494184610Salfred 495184610Salfred if (t->c_cflag & PARENB) { 496184610Salfred if (t->c_cflag & PARODD) 497184610Salfred data |= UMOSCOM_LCR_PARITY_ODD; 498184610Salfred else 499184610Salfred data |= UMOSCOM_LCR_PARITY_EVEN; 500184610Salfred } else 501184610Salfred data |= UMOSCOM_LCR_PARITY_NONE; 502184610Salfred 503184610Salfred switch (t->c_cflag & CSIZE) { 504184610Salfred case CS5: 505184610Salfred data |= UMOSCOM_LCR_DBITS(5); 506184610Salfred break; 507184610Salfred case CS6: 508184610Salfred data |= UMOSCOM_LCR_DBITS(6); 509184610Salfred break; 510184610Salfred case CS7: 511184610Salfred data |= UMOSCOM_LCR_DBITS(7); 512184610Salfred break; 513184610Salfred case CS8: 514184610Salfred data |= UMOSCOM_LCR_DBITS(8); 515184610Salfred break; 516184610Salfred } 517184610Salfred 518184610Salfred sc->sc_lcr = data; 519184610Salfred umoscom_cfg_write(sc, UMOSCOM_LCR, data | UMOSCOM_UART_REG); 520184610Salfred} 521184610Salfred 522184610Salfredstatic void 523192984Sthompsaumoscom_cfg_get_status(struct ucom_softc *ucom, uint8_t *p_lsr, uint8_t *p_msr) 524184610Salfred{ 525184610Salfred struct umoscom_softc *sc = ucom->sc_parent; 526184610Salfred uint8_t lsr; 527184610Salfred uint8_t msr; 528184610Salfred 529184610Salfred DPRINTFN(5, "\n"); 530184610Salfred 531184610Salfred /* read status registers */ 532184610Salfred 533184610Salfred lsr = umoscom_cfg_read(sc, UMOSCOM_LSR); 534184610Salfred msr = umoscom_cfg_read(sc, UMOSCOM_MSR); 535184610Salfred 536184610Salfred /* translate bits */ 537184610Salfred 538184610Salfred if (msr & UMOSCOM_MSR_CTS) 539184610Salfred *p_msr |= SER_CTS; 540184610Salfred 541184610Salfred if (msr & UMOSCOM_MSR_CD) 542184610Salfred *p_msr |= SER_DCD; 543184610Salfred 544184610Salfred if (msr & UMOSCOM_MSR_RI) 545184610Salfred *p_msr |= SER_RI; 546184610Salfred 547184610Salfred if (msr & UMOSCOM_MSR_RTS) 548184610Salfred *p_msr |= SER_DSR; 549184610Salfred} 550184610Salfred 551184610Salfredstatic void 552184610Salfredumoscom_cfg_write(struct umoscom_softc *sc, uint16_t reg, uint16_t val) 553184610Salfred{ 554192984Sthompsa struct usb_device_request req; 555184610Salfred 556184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 557184610Salfred req.bRequest = UMOSCOM_WRITE; 558184610Salfred USETW(req.wValue, val); 559184610Salfred USETW(req.wIndex, reg); 560184610Salfred USETW(req.wLength, 0); 561184610Salfred 562194228Sthompsa ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 563188413Sthompsa &req, NULL, 0, 1000); 564184610Salfred} 565184610Salfred 566184610Salfredstatic uint8_t 567184610Salfredumoscom_cfg_read(struct umoscom_softc *sc, uint16_t reg) 568184610Salfred{ 569192984Sthompsa struct usb_device_request req; 570184610Salfred uint8_t val; 571184610Salfred 572184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 573184610Salfred req.bRequest = UMOSCOM_READ; 574184610Salfred USETW(req.wValue, 0); 575184610Salfred USETW(req.wIndex, reg); 576184610Salfred USETW(req.wLength, 1); 577184610Salfred 578194228Sthompsa ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 579188413Sthompsa &req, &val, 0, 1000); 580184610Salfred 581184610Salfred DPRINTF("reg=0x%04x, val=0x%02x\n", reg, val); 582184610Salfred 583184610Salfred return (val); 584184610Salfred} 585184610Salfred 586184610Salfredstatic void 587192984Sthompsaumoscom_start_read(struct ucom_softc *ucom) 588184610Salfred{ 589184610Salfred struct umoscom_softc *sc = ucom->sc_parent; 590184610Salfred 591184610Salfred#if 0 592184610Salfred /* start interrupt endpoint */ 593194228Sthompsa usbd_transfer_start(sc->sc_xfer[UMOSCOM_INTR_DT_RD]); 594184610Salfred#endif 595184610Salfred /* start read endpoint */ 596194228Sthompsa usbd_transfer_start(sc->sc_xfer[UMOSCOM_BULK_DT_RD]); 597184610Salfred} 598184610Salfred 599184610Salfredstatic void 600192984Sthompsaumoscom_stop_read(struct ucom_softc *ucom) 601184610Salfred{ 602184610Salfred struct umoscom_softc *sc = ucom->sc_parent; 603184610Salfred 604184610Salfred /* stop interrupt transfer */ 605194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UMOSCOM_INTR_DT_RD]); 606184610Salfred 607184610Salfred /* stop read endpoint */ 608194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UMOSCOM_BULK_DT_RD]); 609184610Salfred} 610184610Salfred 611184610Salfredstatic void 612192984Sthompsaumoscom_start_write(struct ucom_softc *ucom) 613184610Salfred{ 614184610Salfred struct umoscom_softc *sc = ucom->sc_parent; 615184610Salfred 616194228Sthompsa usbd_transfer_start(sc->sc_xfer[UMOSCOM_BULK_DT_WR]); 617184610Salfred} 618184610Salfred 619184610Salfredstatic void 620192984Sthompsaumoscom_stop_write(struct ucom_softc *ucom) 621184610Salfred{ 622184610Salfred struct umoscom_softc *sc = ucom->sc_parent; 623184610Salfred 624194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UMOSCOM_BULK_DT_WR]); 625184610Salfred} 626184610Salfred 627184610Salfredstatic void 628194677Sthompsaumoscom_write_callback(struct usb_xfer *xfer, usb_error_t error) 629184610Salfred{ 630194677Sthompsa struct umoscom_softc *sc = usbd_xfer_softc(xfer); 631194677Sthompsa struct usb_page_cache *pc; 632184610Salfred uint32_t actlen; 633184610Salfred 634184610Salfred switch (USB_GET_STATE(xfer)) { 635184610Salfred case USB_ST_SETUP: 636184610Salfred case USB_ST_TRANSFERRED: 637188413Sthompsatr_setup: 638184610Salfred DPRINTF("\n"); 639184610Salfred 640194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 641194677Sthompsa if (ucom_get_data(&sc->sc_ucom, pc, 0, 642184610Salfred UMOSCOM_BUFSIZE, &actlen)) { 643184610Salfred 644194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, actlen); 645194228Sthompsa usbd_transfer_submit(xfer); 646184610Salfred } 647184610Salfred return; 648184610Salfred 649184610Salfred default: /* Error */ 650194677Sthompsa if (error != USB_ERR_CANCELLED) { 651184610Salfred DPRINTFN(0, "transfer failed\n"); 652188413Sthompsa /* try to clear stall first */ 653194677Sthompsa usbd_xfer_set_stall(xfer); 654188413Sthompsa goto tr_setup; 655184610Salfred } 656184610Salfred return; 657184610Salfred } 658184610Salfred} 659184610Salfred 660184610Salfredstatic void 661194677Sthompsaumoscom_read_callback(struct usb_xfer *xfer, usb_error_t error) 662184610Salfred{ 663194677Sthompsa struct umoscom_softc *sc = usbd_xfer_softc(xfer); 664194677Sthompsa struct usb_page_cache *pc; 665194677Sthompsa int actlen; 666184610Salfred 667194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 668194677Sthompsa 669184610Salfred switch (USB_GET_STATE(xfer)) { 670184610Salfred case USB_ST_TRANSFERRED: 671194677Sthompsa DPRINTF("got %d bytes\n", actlen); 672194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 673194677Sthompsa ucom_put_data(&sc->sc_ucom, pc, 0, actlen); 674184610Salfred 675184610Salfred case USB_ST_SETUP: 676188413Sthompsatr_setup: 677184610Salfred DPRINTF("\n"); 678184610Salfred 679194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 680194228Sthompsa usbd_transfer_submit(xfer); 681184610Salfred return; 682184610Salfred 683184610Salfred default: /* Error */ 684194677Sthompsa if (error != USB_ERR_CANCELLED) { 685184610Salfred DPRINTFN(0, "transfer failed\n"); 686188413Sthompsa /* try to clear stall first */ 687194677Sthompsa usbd_xfer_set_stall(xfer); 688188413Sthompsa goto tr_setup; 689184610Salfred } 690184610Salfred return; 691184610Salfred } 692184610Salfred} 693184610Salfred 694184610Salfredstatic void 695194677Sthompsaumoscom_intr_callback(struct usb_xfer *xfer, usb_error_t error) 696184610Salfred{ 697194677Sthompsa struct umoscom_softc *sc = usbd_xfer_softc(xfer); 698194677Sthompsa int actlen; 699184610Salfred 700194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 701194677Sthompsa 702184610Salfred switch (USB_GET_STATE(xfer)) { 703184610Salfred case USB_ST_TRANSFERRED: 704194677Sthompsa if (actlen < 2) { 705184610Salfred DPRINTF("too short message\n"); 706184610Salfred goto tr_setup; 707184610Salfred } 708194228Sthompsa ucom_status_change(&sc->sc_ucom); 709184610Salfred 710184610Salfred case USB_ST_SETUP: 711184610Salfredtr_setup: 712194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 713194228Sthompsa usbd_transfer_submit(xfer); 714184610Salfred return; 715184610Salfred 716184610Salfred default: /* Error */ 717194677Sthompsa if (error != USB_ERR_CANCELLED) { 718184610Salfred DPRINTFN(0, "transfer failed\n"); 719188413Sthompsa /* try to clear stall first */ 720194677Sthompsa usbd_xfer_set_stall(xfer); 721188413Sthompsa goto tr_setup; 722184610Salfred } 723184610Salfred return; 724184610Salfred } 725184610Salfred} 726197570Sthompsa 727197570Sthompsastatic void 728197570Sthompsaumoscom_poll(struct ucom_softc *ucom) 729197570Sthompsa{ 730197570Sthompsa struct umoscom_softc *sc = ucom->sc_parent; 731197570Sthompsa usbd_transfer_poll(sc->sc_xfer, UMOSCOM_N_TRANSFER); 732197570Sthompsa} 733