1246122Shselasky/* $FreeBSD: releng/11.0/sys/dev/usb/controller/at91dci.c 298932 2016-05-02 17:44:03Z pfg $ */ 2184610Salfred/*- 3184610Salfred * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24184610Salfred * SUCH DAMAGE. 25184610Salfred */ 26184610Salfred 27184610Salfred/* 28184610Salfred * This file contains the driver for the AT91 series USB Device 29184610Salfred * Controller 30184610Salfred */ 31184610Salfred 32184610Salfred/* 33184610Salfred * Thanks to "David Brownell" for helping out regarding the hardware 34184610Salfred * endpoint profiles. 35184610Salfred */ 36184610Salfred 37184610Salfred/* 38184610Salfred * NOTE: The "fifo_bank" is not reset in hardware when the endpoint is 39190754Sthompsa * reset. 40184610Salfred * 41184610Salfred * NOTE: When the chip detects BUS-reset it will also reset the 42184610Salfred * endpoints, Function-address and more. 43184610Salfred */ 44184610Salfred 45246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE 46246122Shselasky#include USB_GLOBAL_INCLUDE_FILE 47246122Shselasky#else 48194677Sthompsa#include <sys/stdint.h> 49194677Sthompsa#include <sys/stddef.h> 50194677Sthompsa#include <sys/param.h> 51194677Sthompsa#include <sys/queue.h> 52194677Sthompsa#include <sys/types.h> 53194677Sthompsa#include <sys/systm.h> 54194677Sthompsa#include <sys/kernel.h> 55194677Sthompsa#include <sys/bus.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 67188942Sthompsa#include <dev/usb/usb.h> 68194677Sthompsa#include <dev/usb/usbdi.h> 69184610Salfred 70184610Salfred#define USB_DEBUG_VAR at91dcidebug 71184610Salfred 72188942Sthompsa#include <dev/usb/usb_core.h> 73188942Sthompsa#include <dev/usb/usb_debug.h> 74188942Sthompsa#include <dev/usb/usb_busdma.h> 75188942Sthompsa#include <dev/usb/usb_process.h> 76188942Sthompsa#include <dev/usb/usb_transfer.h> 77188942Sthompsa#include <dev/usb/usb_device.h> 78188942Sthompsa#include <dev/usb/usb_hub.h> 79188942Sthompsa#include <dev/usb/usb_util.h> 80184610Salfred 81188942Sthompsa#include <dev/usb/usb_controller.h> 82188942Sthompsa#include <dev/usb/usb_bus.h> 83246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 84246122Shselasky 85188942Sthompsa#include <dev/usb/controller/at91dci.h> 86184610Salfred 87184610Salfred#define AT9100_DCI_BUS2SC(bus) \ 88184610Salfred ((struct at91dci_softc *)(((uint8_t *)(bus)) - \ 89190181Sthompsa ((uint8_t *)&(((struct at91dci_softc *)0)->sc_bus)))) 90184610Salfred 91184610Salfred#define AT9100_DCI_PC2SC(pc) \ 92190180Sthompsa AT9100_DCI_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus) 93184610Salfred 94269604Shselasky#define AT9100_DCI_THREAD_IRQ \ 95269604Shselasky (AT91_UDP_INT_BUS | AT91_UDP_INT_END_BR | AT91_UDP_INT_RXRSM | AT91_UDP_INT_RXSUSP) 96269604Shselasky 97194677Sthompsa#ifdef USB_DEBUG 98184610Salfredstatic int at91dcidebug = 0; 99184610Salfred 100227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, at91dci, CTLFLAG_RW, 0, "USB at91dci"); 101276701ShselaskySYSCTL_INT(_hw_usb_at91dci, OID_AUTO, debug, CTLFLAG_RWTUN, 102184610Salfred &at91dcidebug, 0, "at91dci debug level"); 103184610Salfred#endif 104184610Salfred 105184610Salfred#define AT9100_DCI_INTR_ENDPT 1 106184610Salfred 107184610Salfred/* prototypes */ 108184610Salfred 109259218Shselaskystatic const struct usb_bus_methods at91dci_bus_methods; 110259218Shselaskystatic const struct usb_pipe_methods at91dci_device_bulk_methods; 111259218Shselaskystatic const struct usb_pipe_methods at91dci_device_ctrl_methods; 112259218Shselaskystatic const struct usb_pipe_methods at91dci_device_intr_methods; 113259218Shselaskystatic const struct usb_pipe_methods at91dci_device_isoc_fs_methods; 114184610Salfred 115184610Salfredstatic at91dci_cmd_t at91dci_setup_rx; 116184610Salfredstatic at91dci_cmd_t at91dci_data_rx; 117184610Salfredstatic at91dci_cmd_t at91dci_data_tx; 118184610Salfredstatic at91dci_cmd_t at91dci_data_tx_sync; 119193045Sthompsastatic void at91dci_device_done(struct usb_xfer *, usb_error_t); 120192984Sthompsastatic void at91dci_do_poll(struct usb_bus *); 121192984Sthompsastatic void at91dci_standard_done(struct usb_xfer *); 122190735Sthompsastatic void at91dci_root_intr(struct at91dci_softc *sc); 123184610Salfred 124184610Salfred/* 125184610Salfred * NOTE: Some of the bits in the CSR register have inverse meaning so 126184610Salfred * we need a helper macro when acknowledging events: 127184610Salfred */ 128184610Salfred#define AT91_CSR_ACK(csr, what) do { \ 129184610Salfred (csr) &= ~((AT91_UDP_CSR_FORCESTALL| \ 130184610Salfred AT91_UDP_CSR_TXPKTRDY| \ 131184610Salfred AT91_UDP_CSR_RXBYTECNT) ^ (what));\ 132184610Salfred (csr) |= ((AT91_UDP_CSR_RX_DATA_BK0| \ 133184610Salfred AT91_UDP_CSR_RX_DATA_BK1| \ 134184610Salfred AT91_UDP_CSR_TXCOMP| \ 135184610Salfred AT91_UDP_CSR_RXSETUP| \ 136184610Salfred AT91_UDP_CSR_STALLSENT) ^ (what)); \ 137184610Salfred} while (0) 138184610Salfred 139184610Salfred/* 140184610Salfred * Here is a list of what the chip supports. 141184610Salfred * Probably it supports more than listed here! 142184610Salfred */ 143192984Sthompsastatic const struct usb_hw_ep_profile 144184610Salfred at91dci_ep_profile[AT91_UDP_EP_MAX] = { 145184610Salfred 146184610Salfred [0] = { 147184610Salfred .max_in_frame_size = 8, 148184610Salfred .max_out_frame_size = 8, 149184610Salfred .is_simplex = 1, 150184610Salfred .support_control = 1, 151184610Salfred }, 152184610Salfred [1] = { 153184610Salfred .max_in_frame_size = 64, 154184610Salfred .max_out_frame_size = 64, 155184610Salfred .is_simplex = 1, 156184610Salfred .support_multi_buffer = 1, 157184610Salfred .support_bulk = 1, 158184610Salfred .support_interrupt = 1, 159184610Salfred .support_isochronous = 1, 160184610Salfred .support_in = 1, 161184610Salfred .support_out = 1, 162184610Salfred }, 163184610Salfred [2] = { 164184610Salfred .max_in_frame_size = 64, 165184610Salfred .max_out_frame_size = 64, 166184610Salfred .is_simplex = 1, 167184610Salfred .support_multi_buffer = 1, 168184610Salfred .support_bulk = 1, 169184610Salfred .support_interrupt = 1, 170184610Salfred .support_isochronous = 1, 171184610Salfred .support_in = 1, 172184610Salfred .support_out = 1, 173184610Salfred }, 174184610Salfred [3] = { 175184610Salfred /* can also do BULK */ 176184610Salfred .max_in_frame_size = 8, 177184610Salfred .max_out_frame_size = 8, 178184610Salfred .is_simplex = 1, 179184610Salfred .support_interrupt = 1, 180184610Salfred .support_in = 1, 181184610Salfred .support_out = 1, 182184610Salfred }, 183184610Salfred [4] = { 184184610Salfred .max_in_frame_size = 256, 185184610Salfred .max_out_frame_size = 256, 186184610Salfred .is_simplex = 1, 187184610Salfred .support_multi_buffer = 1, 188184610Salfred .support_bulk = 1, 189184610Salfred .support_interrupt = 1, 190184610Salfred .support_isochronous = 1, 191184610Salfred .support_in = 1, 192184610Salfred .support_out = 1, 193184610Salfred }, 194184610Salfred [5] = { 195184610Salfred .max_in_frame_size = 256, 196184610Salfred .max_out_frame_size = 256, 197184610Salfred .is_simplex = 1, 198184610Salfred .support_multi_buffer = 1, 199184610Salfred .support_bulk = 1, 200184610Salfred .support_interrupt = 1, 201184610Salfred .support_isochronous = 1, 202184610Salfred .support_in = 1, 203184610Salfred .support_out = 1, 204184610Salfred }, 205184610Salfred}; 206184610Salfred 207184610Salfredstatic void 208192984Sthompsaat91dci_get_hw_ep_profile(struct usb_device *udev, 209192984Sthompsa const struct usb_hw_ep_profile **ppf, uint8_t ep_addr) 210184610Salfred{ 211184610Salfred if (ep_addr < AT91_UDP_EP_MAX) { 212184610Salfred *ppf = (at91dci_ep_profile + ep_addr); 213184610Salfred } else { 214184610Salfred *ppf = NULL; 215184610Salfred } 216184610Salfred} 217184610Salfred 218184610Salfredstatic void 219184610Salfredat91dci_clocks_on(struct at91dci_softc *sc) 220184610Salfred{ 221184610Salfred if (sc->sc_flags.clocks_off && 222184610Salfred sc->sc_flags.port_powered) { 223184610Salfred 224184610Salfred DPRINTFN(5, "\n"); 225184610Salfred 226184610Salfred if (sc->sc_clocks_on) { 227184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 228184610Salfred } 229184610Salfred sc->sc_flags.clocks_off = 0; 230184610Salfred 231184610Salfred /* enable Transceiver */ 232184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, 0); 233184610Salfred } 234184610Salfred} 235184610Salfred 236184610Salfredstatic void 237184610Salfredat91dci_clocks_off(struct at91dci_softc *sc) 238184610Salfred{ 239184610Salfred if (!sc->sc_flags.clocks_off) { 240184610Salfred 241184610Salfred DPRINTFN(5, "\n"); 242184610Salfred 243184610Salfred /* disable Transceiver */ 244184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); 245184610Salfred 246184610Salfred if (sc->sc_clocks_off) { 247184610Salfred (sc->sc_clocks_off) (sc->sc_clocks_arg); 248184610Salfred } 249184610Salfred sc->sc_flags.clocks_off = 1; 250184610Salfred } 251184610Salfred} 252184610Salfred 253184610Salfredstatic void 254184610Salfredat91dci_pull_up(struct at91dci_softc *sc) 255184610Salfred{ 256184610Salfred /* pullup D+, if possible */ 257184610Salfred 258184610Salfred if (!sc->sc_flags.d_pulled_up && 259184610Salfred sc->sc_flags.port_powered) { 260184610Salfred sc->sc_flags.d_pulled_up = 1; 261184610Salfred (sc->sc_pull_up) (sc->sc_pull_arg); 262184610Salfred } 263184610Salfred} 264184610Salfred 265184610Salfredstatic void 266184610Salfredat91dci_pull_down(struct at91dci_softc *sc) 267184610Salfred{ 268184610Salfred /* pulldown D+, if possible */ 269184610Salfred 270184610Salfred if (sc->sc_flags.d_pulled_up) { 271184610Salfred sc->sc_flags.d_pulled_up = 0; 272184610Salfred (sc->sc_pull_down) (sc->sc_pull_arg); 273184610Salfred } 274184610Salfred} 275184610Salfred 276184610Salfredstatic void 277190735Sthompsaat91dci_wakeup_peer(struct at91dci_softc *sc) 278184610Salfred{ 279184610Salfred if (!(sc->sc_flags.status_suspend)) { 280184610Salfred return; 281184610Salfred } 282184610Salfred 283186730Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, AT91_UDP_GSTATE_ESR); 284184610Salfred 285186730Salfred /* wait 8 milliseconds */ 286188983Sthompsa /* Wait for reset to complete. */ 287194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); 288184610Salfred 289186730Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, 0); 290184610Salfred} 291184610Salfred 292184610Salfredstatic void 293184610Salfredat91dci_set_address(struct at91dci_softc *sc, uint8_t addr) 294184610Salfred{ 295184610Salfred DPRINTFN(5, "addr=%d\n", addr); 296184610Salfred 297184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, addr | 298184610Salfred AT91_UDP_FADDR_EN); 299184610Salfred} 300184610Salfred 301184610Salfredstatic uint8_t 302269604Shselaskyat91dci_setup_rx(struct at91dci_softc *sc, struct at91dci_td *td) 303184610Salfred{ 304192984Sthompsa struct usb_device_request req; 305184610Salfred uint32_t csr; 306184610Salfred uint32_t temp; 307184610Salfred uint16_t count; 308184610Salfred 309184610Salfred /* read out FIFO status */ 310269604Shselasky csr = AT91_UDP_READ_4(sc, td->status_reg); 311184610Salfred 312184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 313184610Salfred 314184610Salfred temp = csr; 315184610Salfred temp &= (AT91_UDP_CSR_RX_DATA_BK0 | 316184610Salfred AT91_UDP_CSR_RX_DATA_BK1 | 317184610Salfred AT91_UDP_CSR_STALLSENT | 318184610Salfred AT91_UDP_CSR_RXSETUP | 319184610Salfred AT91_UDP_CSR_TXCOMP); 320184610Salfred 321184610Salfred if (!(csr & AT91_UDP_CSR_RXSETUP)) { 322184610Salfred goto not_complete; 323184610Salfred } 324190721Sthompsa /* clear did stall */ 325190721Sthompsa td->did_stall = 0; 326190721Sthompsa 327184610Salfred /* get the packet byte count */ 328184610Salfred count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; 329184610Salfred 330184610Salfred /* verify data length */ 331184610Salfred if (count != td->remainder) { 332184610Salfred DPRINTFN(0, "Invalid SETUP packet " 333184610Salfred "length, %d bytes\n", count); 334184610Salfred goto not_complete; 335184610Salfred } 336184610Salfred if (count != sizeof(req)) { 337184610Salfred DPRINTFN(0, "Unsupported SETUP packet " 338184610Salfred "length, %d bytes\n", count); 339184610Salfred goto not_complete; 340184610Salfred } 341184610Salfred /* receive data */ 342269604Shselasky bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 343184610Salfred td->fifo_reg, (void *)&req, sizeof(req)); 344184610Salfred 345184610Salfred /* copy data into real buffer */ 346194228Sthompsa usbd_copy_in(td->pc, 0, &req, sizeof(req)); 347184610Salfred 348184610Salfred td->offset = sizeof(req); 349184610Salfred td->remainder = 0; 350184610Salfred 351184610Salfred /* sneak peek the set address */ 352184610Salfred if ((req.bmRequestType == UT_WRITE_DEVICE) && 353184610Salfred (req.bRequest == UR_SET_ADDRESS)) { 354184610Salfred sc->sc_dv_addr = req.wValue[0] & 0x7F; 355184610Salfred } else { 356184610Salfred sc->sc_dv_addr = 0xFF; 357184610Salfred } 358184610Salfred 359184610Salfred /* sneak peek the endpoint direction */ 360184610Salfred if (req.bmRequestType & UE_DIR_IN) { 361184610Salfred csr |= AT91_UDP_CSR_DIR; 362184610Salfred } else { 363184610Salfred csr &= ~AT91_UDP_CSR_DIR; 364184610Salfred } 365184610Salfred 366184610Salfred /* write the direction of the control transfer */ 367184610Salfred AT91_CSR_ACK(csr, temp); 368269604Shselasky AT91_UDP_WRITE_4(sc, td->status_reg, csr); 369184610Salfred return (0); /* complete */ 370184610Salfred 371184610Salfrednot_complete: 372190721Sthompsa /* abort any ongoing transfer */ 373190721Sthompsa if (!td->did_stall) { 374190721Sthompsa DPRINTFN(5, "stalling\n"); 375190721Sthompsa temp |= AT91_UDP_CSR_FORCESTALL; 376190721Sthompsa td->did_stall = 1; 377190721Sthompsa } 378190721Sthompsa 379184610Salfred /* clear interrupts, if any */ 380184610Salfred if (temp) { 381184610Salfred DPRINTFN(5, "clearing 0x%08x\n", temp); 382184610Salfred AT91_CSR_ACK(csr, temp); 383269604Shselasky AT91_UDP_WRITE_4(sc, td->status_reg, csr); 384184610Salfred } 385184610Salfred return (1); /* not complete */ 386184610Salfred} 387184610Salfred 388184610Salfredstatic uint8_t 389269604Shselaskyat91dci_data_rx(struct at91dci_softc *sc, struct at91dci_td *td) 390184610Salfred{ 391192984Sthompsa struct usb_page_search buf_res; 392184610Salfred uint32_t csr; 393184610Salfred uint32_t temp; 394184610Salfred uint16_t count; 395184610Salfred uint8_t to; 396184610Salfred uint8_t got_short; 397184610Salfred 398184610Salfred to = 2; /* don't loop forever! */ 399184610Salfred got_short = 0; 400184610Salfred 401184610Salfred /* check if any of the FIFO banks have data */ 402184610Salfredrepeat: 403184610Salfred /* read out FIFO status */ 404269604Shselasky csr = AT91_UDP_READ_4(sc, td->status_reg); 405184610Salfred 406184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 407184610Salfred 408184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 409184610Salfred if (td->remainder == 0) { 410184610Salfred /* 411184610Salfred * We are actually complete and have 412184610Salfred * received the next SETUP 413184610Salfred */ 414184610Salfred DPRINTFN(5, "faking complete\n"); 415184610Salfred return (0); /* complete */ 416184610Salfred } 417184610Salfred /* 418184610Salfred * USB Host Aborted the transfer. 419184610Salfred */ 420184610Salfred td->error = 1; 421184610Salfred return (0); /* complete */ 422184610Salfred } 423184610Salfred /* Make sure that "STALLSENT" gets cleared */ 424184610Salfred temp = csr; 425184610Salfred temp &= AT91_UDP_CSR_STALLSENT; 426184610Salfred 427184610Salfred /* check status */ 428184610Salfred if (!(csr & (AT91_UDP_CSR_RX_DATA_BK0 | 429184610Salfred AT91_UDP_CSR_RX_DATA_BK1))) { 430184610Salfred if (temp) { 431184610Salfred /* write command */ 432184610Salfred AT91_CSR_ACK(csr, temp); 433269604Shselasky AT91_UDP_WRITE_4(sc, td->status_reg, csr); 434184610Salfred } 435184610Salfred return (1); /* not complete */ 436184610Salfred } 437184610Salfred /* get the packet byte count */ 438184610Salfred count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; 439184610Salfred 440184610Salfred /* verify the packet byte count */ 441184610Salfred if (count != td->max_packet_size) { 442184610Salfred if (count < td->max_packet_size) { 443184610Salfred /* we have a short packet */ 444184610Salfred td->short_pkt = 1; 445184610Salfred got_short = 1; 446184610Salfred } else { 447184610Salfred /* invalid USB packet */ 448184610Salfred td->error = 1; 449184610Salfred return (0); /* we are complete */ 450184610Salfred } 451184610Salfred } 452184610Salfred /* verify the packet byte count */ 453184610Salfred if (count > td->remainder) { 454184610Salfred /* invalid USB packet */ 455184610Salfred td->error = 1; 456184610Salfred return (0); /* we are complete */ 457184610Salfred } 458184610Salfred while (count > 0) { 459194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 460184610Salfred 461184610Salfred /* get correct length */ 462184610Salfred if (buf_res.length > count) { 463184610Salfred buf_res.length = count; 464184610Salfred } 465184610Salfred /* receive data */ 466269604Shselasky bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 467184610Salfred td->fifo_reg, buf_res.buffer, buf_res.length); 468184610Salfred 469184610Salfred /* update counters */ 470184610Salfred count -= buf_res.length; 471184610Salfred td->offset += buf_res.length; 472184610Salfred td->remainder -= buf_res.length; 473184610Salfred } 474184610Salfred 475184610Salfred /* clear status bits */ 476184610Salfred if (td->support_multi_buffer) { 477184610Salfred if (td->fifo_bank) { 478184610Salfred td->fifo_bank = 0; 479184610Salfred temp |= AT91_UDP_CSR_RX_DATA_BK1; 480184610Salfred } else { 481184610Salfred td->fifo_bank = 1; 482184610Salfred temp |= AT91_UDP_CSR_RX_DATA_BK0; 483184610Salfred } 484184610Salfred } else { 485184610Salfred temp |= (AT91_UDP_CSR_RX_DATA_BK0 | 486184610Salfred AT91_UDP_CSR_RX_DATA_BK1); 487184610Salfred } 488184610Salfred 489184610Salfred /* write command */ 490184610Salfred AT91_CSR_ACK(csr, temp); 491269604Shselasky AT91_UDP_WRITE_4(sc, td->status_reg, csr); 492184610Salfred 493184610Salfred /* 494184610Salfred * NOTE: We may have to delay a little bit before 495184610Salfred * proceeding after clearing the DATA_BK bits. 496184610Salfred */ 497184610Salfred 498184610Salfred /* check if we are complete */ 499184610Salfred if ((td->remainder == 0) || got_short) { 500184610Salfred if (td->short_pkt) { 501184610Salfred /* we are complete */ 502184610Salfred return (0); 503184610Salfred } 504184610Salfred /* else need to receive a zero length packet */ 505184610Salfred } 506184610Salfred if (--to) { 507184610Salfred goto repeat; 508184610Salfred } 509184610Salfred return (1); /* not complete */ 510184610Salfred} 511184610Salfred 512184610Salfredstatic uint8_t 513269604Shselaskyat91dci_data_tx(struct at91dci_softc *sc, struct at91dci_td *td) 514184610Salfred{ 515192984Sthompsa struct usb_page_search buf_res; 516184610Salfred uint32_t csr; 517184610Salfred uint32_t temp; 518184610Salfred uint16_t count; 519184610Salfred uint8_t to; 520184610Salfred 521184610Salfred to = 2; /* don't loop forever! */ 522184610Salfred 523184610Salfredrepeat: 524184610Salfred 525184610Salfred /* read out FIFO status */ 526269604Shselasky csr = AT91_UDP_READ_4(sc, td->status_reg); 527184610Salfred 528184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 529184610Salfred 530184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 531184610Salfred /* 532184610Salfred * The current transfer was aborted 533184610Salfred * by the USB Host 534184610Salfred */ 535184610Salfred td->error = 1; 536184610Salfred return (0); /* complete */ 537184610Salfred } 538184610Salfred /* Make sure that "STALLSENT" gets cleared */ 539184610Salfred temp = csr; 540184610Salfred temp &= AT91_UDP_CSR_STALLSENT; 541184610Salfred 542184610Salfred if (csr & AT91_UDP_CSR_TXPKTRDY) { 543184610Salfred if (temp) { 544184610Salfred /* write command */ 545184610Salfred AT91_CSR_ACK(csr, temp); 546269604Shselasky AT91_UDP_WRITE_4(sc, td->status_reg, csr); 547184610Salfred } 548184610Salfred return (1); /* not complete */ 549184610Salfred } else { 550184610Salfred /* clear TXCOMP and set TXPKTRDY */ 551184610Salfred temp |= (AT91_UDP_CSR_TXCOMP | 552184610Salfred AT91_UDP_CSR_TXPKTRDY); 553184610Salfred } 554184610Salfred 555184610Salfred count = td->max_packet_size; 556184610Salfred if (td->remainder < count) { 557184610Salfred /* we have a short packet */ 558184610Salfred td->short_pkt = 1; 559184610Salfred count = td->remainder; 560184610Salfred } 561184610Salfred while (count > 0) { 562194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 563184610Salfred 564184610Salfred /* get correct length */ 565184610Salfred if (buf_res.length > count) { 566184610Salfred buf_res.length = count; 567184610Salfred } 568184610Salfred /* transmit data */ 569269604Shselasky bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 570184610Salfred td->fifo_reg, buf_res.buffer, buf_res.length); 571184610Salfred 572184610Salfred /* update counters */ 573184610Salfred count -= buf_res.length; 574184610Salfred td->offset += buf_res.length; 575184610Salfred td->remainder -= buf_res.length; 576184610Salfred } 577184610Salfred 578184610Salfred /* write command */ 579184610Salfred AT91_CSR_ACK(csr, temp); 580269604Shselasky AT91_UDP_WRITE_4(sc, td->status_reg, csr); 581184610Salfred 582184610Salfred /* check remainder */ 583184610Salfred if (td->remainder == 0) { 584184610Salfred if (td->short_pkt) { 585184610Salfred return (0); /* complete */ 586184610Salfred } 587184610Salfred /* else we need to transmit a short packet */ 588184610Salfred } 589184610Salfred if (--to) { 590184610Salfred goto repeat; 591184610Salfred } 592184610Salfred return (1); /* not complete */ 593184610Salfred} 594184610Salfred 595184610Salfredstatic uint8_t 596269604Shselaskyat91dci_data_tx_sync(struct at91dci_softc *sc, struct at91dci_td *td) 597184610Salfred{ 598184610Salfred uint32_t csr; 599184610Salfred uint32_t temp; 600184610Salfred 601184610Salfred /* read out FIFO status */ 602269604Shselasky csr = AT91_UDP_READ_4(sc, td->status_reg); 603184610Salfred 604184610Salfred DPRINTFN(5, "csr=0x%08x\n", csr); 605184610Salfred 606184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 607184610Salfred DPRINTFN(5, "faking complete\n"); 608184610Salfred /* Race condition */ 609184610Salfred return (0); /* complete */ 610184610Salfred } 611184610Salfred temp = csr; 612184610Salfred temp &= (AT91_UDP_CSR_STALLSENT | 613184610Salfred AT91_UDP_CSR_TXCOMP); 614184610Salfred 615184610Salfred /* check status */ 616184610Salfred if (csr & AT91_UDP_CSR_TXPKTRDY) { 617184610Salfred goto not_complete; 618184610Salfred } 619184610Salfred if (!(csr & AT91_UDP_CSR_TXCOMP)) { 620184610Salfred goto not_complete; 621184610Salfred } 622269604Shselasky if (td->status_reg == AT91_UDP_CSR(0) && sc->sc_dv_addr != 0xFF) { 623184610Salfred /* 624184610Salfred * The AT91 has a special requirement with regard to 625184610Salfred * setting the address and that is to write the new 626184610Salfred * address before clearing TXCOMP: 627184610Salfred */ 628184610Salfred at91dci_set_address(sc, sc->sc_dv_addr); 629184610Salfred } 630184610Salfred /* write command */ 631184610Salfred AT91_CSR_ACK(csr, temp); 632269604Shselasky AT91_UDP_WRITE_4(sc, td->status_reg, csr); 633184610Salfred 634184610Salfred return (0); /* complete */ 635184610Salfred 636184610Salfrednot_complete: 637184610Salfred if (temp) { 638184610Salfred /* write command */ 639184610Salfred AT91_CSR_ACK(csr, temp); 640269604Shselasky AT91_UDP_WRITE_4(sc, td->status_reg, csr); 641184610Salfred } 642184610Salfred return (1); /* not complete */ 643184610Salfred} 644184610Salfred 645269604Shselaskystatic void 646192984Sthompsaat91dci_xfer_do_fifo(struct usb_xfer *xfer) 647184610Salfred{ 648269604Shselasky struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 649184610Salfred struct at91dci_td *td; 650184610Salfred uint8_t temp; 651184610Salfred 652184610Salfred DPRINTFN(9, "\n"); 653184610Salfred 654184610Salfred td = xfer->td_transfer_cache; 655269604Shselasky if (td == NULL) 656269604Shselasky return; 657269604Shselasky 658184610Salfred while (1) { 659269604Shselasky if ((td->func) (sc, td)) { 660184610Salfred /* operation in progress */ 661184610Salfred break; 662184610Salfred } 663184610Salfred if (((void *)td) == xfer->td_transfer_last) { 664184610Salfred goto done; 665184610Salfred } 666184610Salfred if (td->error) { 667184610Salfred goto done; 668184610Salfred } else if (td->remainder > 0) { 669184610Salfred /* 670184610Salfred * We had a short transfer. If there is no alternate 671184610Salfred * next, stop processing ! 672184610Salfred */ 673184610Salfred if (!td->alt_next) { 674184610Salfred goto done; 675184610Salfred } 676184610Salfred } 677184610Salfred /* 678184610Salfred * Fetch the next transfer descriptor and transfer 679184610Salfred * some flags to the next transfer descriptor 680184610Salfred */ 681184610Salfred temp = 0; 682184610Salfred if (td->fifo_bank) 683184610Salfred temp |= 1; 684184610Salfred td = td->obj_next; 685184610Salfred xfer->td_transfer_cache = td; 686184610Salfred if (temp & 1) 687184610Salfred td->fifo_bank = 1; 688184610Salfred } 689269604Shselasky return; 690184610Salfred 691184610Salfreddone: 692193644Sthompsa temp = (xfer->endpointno & UE_ADDR); 693184610Salfred 694184610Salfred /* update FIFO bank flag and multi buffer */ 695184610Salfred if (td->fifo_bank) { 696184610Salfred sc->sc_ep_flags[temp].fifo_bank = 1; 697184610Salfred } else { 698184610Salfred sc->sc_ep_flags[temp].fifo_bank = 0; 699184610Salfred } 700184610Salfred 701184610Salfred /* compute all actual lengths */ 702269604Shselasky xfer->td_transfer_cache = NULL; 703269604Shselasky sc->sc_xfer_complete = 1; 704269604Shselasky} 705184610Salfred 706269604Shselaskystatic uint8_t 707269604Shselaskyat91dci_xfer_do_complete(struct usb_xfer *xfer) 708269604Shselasky{ 709269604Shselasky struct at91dci_td *td; 710184610Salfred 711269604Shselasky DPRINTFN(9, "\n"); 712269604Shselasky td = xfer->td_transfer_cache; 713269604Shselasky if (td == NULL) { 714269604Shselasky /* compute all actual lengths */ 715269604Shselasky at91dci_standard_done(xfer); 716269604Shselasky return(1); 717269604Shselasky } 718269604Shselasky return (0); 719184610Salfred} 720184610Salfred 721184610Salfredstatic void 722269604Shselaskyat91dci_interrupt_poll_locked(struct at91dci_softc *sc) 723184610Salfred{ 724192984Sthompsa struct usb_xfer *xfer; 725184610Salfred 726269604Shselasky TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) 727269604Shselasky at91dci_xfer_do_fifo(xfer); 728269604Shselasky} 729269604Shselasky 730269604Shselaskystatic void 731269604Shselaskyat91dci_interrupt_complete_locked(struct at91dci_softc *sc) 732269604Shselasky{ 733269604Shselasky struct usb_xfer *xfer; 734184610Salfredrepeat: 735184610Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 736269604Shselasky if (at91dci_xfer_do_complete(xfer)) 737184610Salfred goto repeat; 738184610Salfred } 739184610Salfred} 740184610Salfred 741187175Sthompsavoid 742187175Sthompsaat91dci_vbus_interrupt(struct at91dci_softc *sc, uint8_t is_on) 743184610Salfred{ 744184610Salfred DPRINTFN(5, "vbus = %u\n", is_on); 745184610Salfred 746184610Salfred if (is_on) { 747184610Salfred if (!sc->sc_flags.status_vbus) { 748184610Salfred sc->sc_flags.status_vbus = 1; 749184610Salfred 750184610Salfred /* complete root HUB interrupt endpoint */ 751190735Sthompsa at91dci_root_intr(sc); 752184610Salfred } 753184610Salfred } else { 754184610Salfred if (sc->sc_flags.status_vbus) { 755184610Salfred sc->sc_flags.status_vbus = 0; 756184610Salfred sc->sc_flags.status_bus_reset = 0; 757184610Salfred sc->sc_flags.status_suspend = 0; 758184610Salfred sc->sc_flags.change_suspend = 0; 759184610Salfred sc->sc_flags.change_connect = 1; 760184610Salfred 761184610Salfred /* complete root HUB interrupt endpoint */ 762190735Sthompsa at91dci_root_intr(sc); 763184610Salfred } 764184610Salfred } 765184610Salfred} 766184610Salfred 767269604Shselaskyint 768269604Shselaskyat91dci_filter_interrupt(void *arg) 769269604Shselasky{ 770269604Shselasky struct at91dci_softc *sc = arg; 771269604Shselasky int retval = FILTER_HANDLED; 772269604Shselasky uint32_t status; 773269604Shselasky 774269604Shselasky USB_BUS_SPIN_LOCK(&sc->sc_bus); 775269604Shselasky 776269604Shselasky status = AT91_UDP_READ_4(sc, AT91_UDP_ISR); 777269604Shselasky status &= AT91_UDP_INT_DEFAULT; 778269604Shselasky 779269604Shselasky if (status & AT9100_DCI_THREAD_IRQ) 780269604Shselasky retval = FILTER_SCHEDULE_THREAD; 781269604Shselasky 782269604Shselasky /* acknowledge interrupts */ 783269604Shselasky AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status & ~AT9100_DCI_THREAD_IRQ); 784269604Shselasky 785269604Shselasky /* poll FIFOs, if any */ 786269604Shselasky at91dci_interrupt_poll_locked(sc); 787269604Shselasky 788269604Shselasky if (sc->sc_xfer_complete != 0) 789269604Shselasky retval = FILTER_SCHEDULE_THREAD; 790269604Shselasky 791269604Shselasky USB_BUS_SPIN_UNLOCK(&sc->sc_bus); 792269604Shselasky 793269604Shselasky return (retval); 794269604Shselasky} 795269604Shselasky 796184610Salfredvoid 797269604Shselaskyat91dci_interrupt(void *arg) 798184610Salfred{ 799269604Shselasky struct at91dci_softc *sc = arg; 800184610Salfred uint32_t status; 801184610Salfred 802184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 803269604Shselasky USB_BUS_SPIN_LOCK(&sc->sc_bus); 804184610Salfred 805184610Salfred status = AT91_UDP_READ_4(sc, AT91_UDP_ISR); 806269604Shselasky status &= AT9100_DCI_THREAD_IRQ; 807184610Salfred 808184610Salfred /* acknowledge interrupts */ 809184610Salfred 810184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status); 811184610Salfred 812184610Salfred /* check for any bus state change interrupts */ 813184610Salfred 814184610Salfred if (status & AT91_UDP_INT_BUS) { 815184610Salfred 816184610Salfred DPRINTFN(5, "real bus interrupt 0x%08x\n", status); 817184610Salfred 818184610Salfred if (status & AT91_UDP_INT_END_BR) { 819184610Salfred 820184610Salfred /* set correct state */ 821184610Salfred sc->sc_flags.status_bus_reset = 1; 822184610Salfred sc->sc_flags.status_suspend = 0; 823184610Salfred sc->sc_flags.change_suspend = 0; 824184610Salfred sc->sc_flags.change_connect = 1; 825184610Salfred 826184610Salfred /* disable resume interrupt */ 827184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 828184610Salfred AT91_UDP_INT_RXRSM); 829184610Salfred /* enable suspend interrupt */ 830184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 831184610Salfred AT91_UDP_INT_RXSUSP); 832184610Salfred } 833184610Salfred /* 834184610Salfred * If RXRSM and RXSUSP is set at the same time we interpret 835184610Salfred * that like RESUME. Resume is set when there is at least 3 836184610Salfred * milliseconds of inactivity on the USB BUS. 837184610Salfred */ 838184610Salfred if (status & AT91_UDP_INT_RXRSM) { 839184610Salfred if (sc->sc_flags.status_suspend) { 840184610Salfred sc->sc_flags.status_suspend = 0; 841184610Salfred sc->sc_flags.change_suspend = 1; 842184610Salfred 843184610Salfred /* disable resume interrupt */ 844184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 845184610Salfred AT91_UDP_INT_RXRSM); 846184610Salfred /* enable suspend interrupt */ 847184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 848184610Salfred AT91_UDP_INT_RXSUSP); 849184610Salfred } 850184610Salfred } else if (status & AT91_UDP_INT_RXSUSP) { 851184610Salfred if (!sc->sc_flags.status_suspend) { 852184610Salfred sc->sc_flags.status_suspend = 1; 853184610Salfred sc->sc_flags.change_suspend = 1; 854184610Salfred 855184610Salfred /* disable suspend interrupt */ 856184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 857184610Salfred AT91_UDP_INT_RXSUSP); 858184610Salfred 859184610Salfred /* enable resume interrupt */ 860184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 861184610Salfred AT91_UDP_INT_RXRSM); 862184610Salfred } 863184610Salfred } 864184610Salfred /* complete root HUB interrupt endpoint */ 865190735Sthompsa at91dci_root_intr(sc); 866184610Salfred } 867184610Salfred 868269604Shselasky if (sc->sc_xfer_complete != 0) { 869269604Shselasky sc->sc_xfer_complete = 0; 870269604Shselasky at91dci_interrupt_complete_locked(sc); 871184610Salfred } 872269604Shselasky USB_BUS_SPIN_UNLOCK(&sc->sc_bus); 873184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 874184610Salfred} 875184610Salfred 876184610Salfredstatic void 877184610Salfredat91dci_setup_standard_chain_sub(struct at91dci_std_temp *temp) 878184610Salfred{ 879184610Salfred struct at91dci_td *td; 880184610Salfred 881184610Salfred /* get current Transfer Descriptor */ 882184610Salfred td = temp->td_next; 883184610Salfred temp->td = td; 884184610Salfred 885184610Salfred /* prepare for next TD */ 886184610Salfred temp->td_next = td->obj_next; 887184610Salfred 888184610Salfred /* fill out the Transfer Descriptor */ 889184610Salfred td->func = temp->func; 890184610Salfred td->pc = temp->pc; 891184610Salfred td->offset = temp->offset; 892184610Salfred td->remainder = temp->len; 893184610Salfred td->fifo_bank = 0; 894184610Salfred td->error = 0; 895192552Sthompsa td->did_stall = temp->did_stall; 896184610Salfred td->short_pkt = temp->short_pkt; 897184610Salfred td->alt_next = temp->setup_alt_next; 898184610Salfred} 899184610Salfred 900184610Salfredstatic void 901192984Sthompsaat91dci_setup_standard_chain(struct usb_xfer *xfer) 902184610Salfred{ 903184610Salfred struct at91dci_std_temp temp; 904184610Salfred struct at91dci_softc *sc; 905184610Salfred struct at91dci_td *td; 906184610Salfred uint32_t x; 907184610Salfred uint8_t ep_no; 908184610Salfred uint8_t need_sync; 909184610Salfred 910184610Salfred DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", 911193644Sthompsa xfer->address, UE_GET_ADDR(xfer->endpointno), 912194228Sthompsa xfer->sumlen, usbd_get_speed(xfer->xroot->udev)); 913184610Salfred 914184610Salfred temp.max_frame_size = xfer->max_frame_size; 915184610Salfred 916184610Salfred td = xfer->td_start[0]; 917184610Salfred xfer->td_transfer_first = td; 918184610Salfred xfer->td_transfer_cache = td; 919184610Salfred 920184610Salfred /* setup temp */ 921184610Salfred 922199673Sthompsa temp.pc = NULL; 923184610Salfred temp.td = NULL; 924184610Salfred temp.td_next = xfer->td_start[0]; 925190183Sthompsa temp.offset = 0; 926265949Shselasky temp.setup_alt_next = xfer->flags_int.short_frames_ok || 927265949Shselasky xfer->flags_int.isochronous_xfr; 928192552Sthompsa temp.did_stall = !xfer->flags_int.control_stall; 929184610Salfred 930187173Sthompsa sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 931193644Sthompsa ep_no = (xfer->endpointno & UE_ADDR); 932184610Salfred 933184610Salfred /* check if we should prepend a setup message */ 934184610Salfred 935184610Salfred if (xfer->flags_int.control_xfr) { 936184610Salfred if (xfer->flags_int.control_hdr) { 937184610Salfred 938184610Salfred temp.func = &at91dci_setup_rx; 939184610Salfred temp.len = xfer->frlengths[0]; 940184610Salfred temp.pc = xfer->frbuffers + 0; 941184610Salfred temp.short_pkt = temp.len ? 1 : 0; 942190183Sthompsa /* check for last frame */ 943190183Sthompsa if (xfer->nframes == 1) { 944190183Sthompsa /* no STATUS stage yet, SETUP is last */ 945190183Sthompsa if (xfer->flags_int.control_act) 946190183Sthompsa temp.setup_alt_next = 0; 947190183Sthompsa } 948184610Salfred 949184610Salfred at91dci_setup_standard_chain_sub(&temp); 950184610Salfred } 951184610Salfred x = 1; 952184610Salfred } else { 953184610Salfred x = 0; 954184610Salfred } 955184610Salfred 956184610Salfred if (x != xfer->nframes) { 957193644Sthompsa if (xfer->endpointno & UE_DIR_IN) { 958184610Salfred temp.func = &at91dci_data_tx; 959184610Salfred need_sync = 1; 960184610Salfred } else { 961184610Salfred temp.func = &at91dci_data_rx; 962184610Salfred need_sync = 0; 963184610Salfred } 964184610Salfred 965184610Salfred /* setup "pc" pointer */ 966184610Salfred temp.pc = xfer->frbuffers + x; 967184610Salfred } else { 968184610Salfred need_sync = 0; 969184610Salfred } 970184610Salfred while (x != xfer->nframes) { 971184610Salfred 972184610Salfred /* DATA0 / DATA1 message */ 973184610Salfred 974184610Salfred temp.len = xfer->frlengths[x]; 975184610Salfred 976184610Salfred x++; 977184610Salfred 978184610Salfred if (x == xfer->nframes) { 979190183Sthompsa if (xfer->flags_int.control_xfr) { 980190183Sthompsa if (xfer->flags_int.control_act) { 981190183Sthompsa temp.setup_alt_next = 0; 982190183Sthompsa } 983190183Sthompsa } else { 984190183Sthompsa temp.setup_alt_next = 0; 985190183Sthompsa } 986184610Salfred } 987184610Salfred if (temp.len == 0) { 988184610Salfred 989184610Salfred /* make sure that we send an USB packet */ 990184610Salfred 991184610Salfred temp.short_pkt = 0; 992184610Salfred 993184610Salfred } else { 994184610Salfred 995184610Salfred /* regular data transfer */ 996184610Salfred 997184610Salfred temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; 998184610Salfred } 999184610Salfred 1000184610Salfred at91dci_setup_standard_chain_sub(&temp); 1001184610Salfred 1002184610Salfred if (xfer->flags_int.isochronous_xfr) { 1003184610Salfred temp.offset += temp.len; 1004184610Salfred } else { 1005184610Salfred /* get next Page Cache pointer */ 1006184610Salfred temp.pc = xfer->frbuffers + x; 1007184610Salfred } 1008184610Salfred } 1009184610Salfred 1010190183Sthompsa /* check for control transfer */ 1011190183Sthompsa if (xfer->flags_int.control_xfr) { 1012184610Salfred 1013190183Sthompsa /* always setup a valid "pc" pointer for status and sync */ 1014190183Sthompsa temp.pc = xfer->frbuffers + 0; 1015184610Salfred temp.len = 0; 1016184610Salfred temp.short_pkt = 0; 1017190183Sthompsa temp.setup_alt_next = 0; 1018184610Salfred 1019190183Sthompsa /* check if we need to sync */ 1020184610Salfred if (need_sync) { 1021184610Salfred /* we need a SYNC point after TX */ 1022184610Salfred temp.func = &at91dci_data_tx_sync; 1023190183Sthompsa at91dci_setup_standard_chain_sub(&temp); 1024190183Sthompsa } 1025184610Salfred 1026190183Sthompsa /* check if we should append a status stage */ 1027190183Sthompsa if (!xfer->flags_int.control_act) { 1028190183Sthompsa 1029190183Sthompsa /* 1030190183Sthompsa * Send a DATA1 message and invert the current 1031190183Sthompsa * endpoint direction. 1032190183Sthompsa */ 1033193644Sthompsa if (xfer->endpointno & UE_DIR_IN) { 1034190183Sthompsa temp.func = &at91dci_data_rx; 1035190183Sthompsa need_sync = 0; 1036190183Sthompsa } else { 1037190183Sthompsa temp.func = &at91dci_data_tx; 1038190183Sthompsa need_sync = 1; 1039190183Sthompsa } 1040190183Sthompsa 1041184610Salfred at91dci_setup_standard_chain_sub(&temp); 1042190183Sthompsa if (need_sync) { 1043190183Sthompsa /* we need a SYNC point after TX */ 1044190183Sthompsa temp.func = &at91dci_data_tx_sync; 1045190183Sthompsa at91dci_setup_standard_chain_sub(&temp); 1046190183Sthompsa } 1047184610Salfred } 1048184610Salfred } 1049190183Sthompsa 1050184610Salfred /* must have at least one frame! */ 1051184610Salfred td = temp.td; 1052184610Salfred xfer->td_transfer_last = td; 1053184610Salfred 1054184610Salfred /* setup the correct fifo bank */ 1055184610Salfred if (sc->sc_ep_flags[ep_no].fifo_bank) { 1056184610Salfred td = xfer->td_transfer_first; 1057184610Salfred td->fifo_bank = 1; 1058184610Salfred } 1059184610Salfred} 1060184610Salfred 1061184610Salfredstatic void 1062184610Salfredat91dci_timeout(void *arg) 1063184610Salfred{ 1064192984Sthompsa struct usb_xfer *xfer = arg; 1065184610Salfred 1066184610Salfred DPRINTF("xfer=%p\n", xfer); 1067184610Salfred 1068187177Sthompsa USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 1069184610Salfred 1070184610Salfred /* transfer is transferred */ 1071184610Salfred at91dci_device_done(xfer, USB_ERR_TIMEOUT); 1072184610Salfred} 1073184610Salfred 1074184610Salfredstatic void 1075192984Sthompsaat91dci_start_standard_chain(struct usb_xfer *xfer) 1076184610Salfred{ 1077269604Shselasky struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1078269604Shselasky 1079184610Salfred DPRINTFN(9, "\n"); 1080184610Salfred 1081269604Shselasky USB_BUS_SPIN_LOCK(&sc->sc_bus); 1082269604Shselasky 1083184610Salfred /* poll one time */ 1084269604Shselasky at91dci_xfer_do_fifo(xfer); 1085184610Salfred 1086269604Shselasky if (at91dci_xfer_do_complete(xfer) == 0) { 1087269604Shselasky 1088193644Sthompsa uint8_t ep_no = xfer->endpointno & UE_ADDR; 1089184610Salfred 1090184610Salfred /* 1091184610Salfred * Only enable the endpoint interrupt when we are actually 1092184610Salfred * waiting for data, hence we are dealing with level 1093184610Salfred * triggered interrupts ! 1094184610Salfred */ 1095184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_EP(ep_no)); 1096184610Salfred 1097184610Salfred DPRINTFN(15, "enable interrupts on endpoint %d\n", ep_no); 1098184610Salfred 1099184610Salfred /* put transfer on interrupt queue */ 1100194228Sthompsa usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); 1101184610Salfred 1102184610Salfred /* start timeout, if any */ 1103184610Salfred if (xfer->timeout != 0) { 1104194228Sthompsa usbd_transfer_timeout_ms(xfer, 1105184610Salfred &at91dci_timeout, xfer->timeout); 1106184610Salfred } 1107184610Salfred } 1108269604Shselasky USB_BUS_SPIN_UNLOCK(&sc->sc_bus); 1109184610Salfred} 1110184610Salfred 1111184610Salfredstatic void 1112190735Sthompsaat91dci_root_intr(struct at91dci_softc *sc) 1113184610Salfred{ 1114184610Salfred DPRINTFN(9, "\n"); 1115184610Salfred 1116184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1117184610Salfred 1118184610Salfred /* set port bit */ 1119184610Salfred sc->sc_hub_idata[0] = 0x02; /* we only have one port */ 1120184610Salfred 1121190735Sthompsa uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, 1122190735Sthompsa sizeof(sc->sc_hub_idata)); 1123184610Salfred} 1124184610Salfred 1125193045Sthompsastatic usb_error_t 1126192984Sthompsaat91dci_standard_done_sub(struct usb_xfer *xfer) 1127184610Salfred{ 1128184610Salfred struct at91dci_td *td; 1129184610Salfred uint32_t len; 1130184610Salfred uint8_t error; 1131184610Salfred 1132184610Salfred DPRINTFN(9, "\n"); 1133184610Salfred 1134184610Salfred td = xfer->td_transfer_cache; 1135184610Salfred 1136184610Salfred do { 1137184610Salfred len = td->remainder; 1138184610Salfred 1139184610Salfred if (xfer->aframes != xfer->nframes) { 1140184610Salfred /* 1141184610Salfred * Verify the length and subtract 1142184610Salfred * the remainder from "frlengths[]": 1143184610Salfred */ 1144184610Salfred if (len > xfer->frlengths[xfer->aframes]) { 1145184610Salfred td->error = 1; 1146184610Salfred } else { 1147184610Salfred xfer->frlengths[xfer->aframes] -= len; 1148184610Salfred } 1149184610Salfred } 1150184610Salfred /* Check for transfer error */ 1151184610Salfred if (td->error) { 1152184610Salfred /* the transfer is finished */ 1153184610Salfred error = 1; 1154184610Salfred td = NULL; 1155184610Salfred break; 1156184610Salfred } 1157184610Salfred /* Check for short transfer */ 1158184610Salfred if (len > 0) { 1159265949Shselasky if (xfer->flags_int.short_frames_ok || 1160265949Shselasky xfer->flags_int.isochronous_xfr) { 1161184610Salfred /* follow alt next */ 1162184610Salfred if (td->alt_next) { 1163184610Salfred td = td->obj_next; 1164184610Salfred } else { 1165184610Salfred td = NULL; 1166184610Salfred } 1167184610Salfred } else { 1168184610Salfred /* the transfer is finished */ 1169184610Salfred td = NULL; 1170184610Salfred } 1171184610Salfred error = 0; 1172184610Salfred break; 1173184610Salfred } 1174184610Salfred td = td->obj_next; 1175184610Salfred 1176184610Salfred /* this USB frame is complete */ 1177184610Salfred error = 0; 1178184610Salfred break; 1179184610Salfred 1180184610Salfred } while (0); 1181184610Salfred 1182184610Salfred /* update transfer cache */ 1183184610Salfred 1184184610Salfred xfer->td_transfer_cache = td; 1185184610Salfred 1186184610Salfred return (error ? 1187184610Salfred USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); 1188184610Salfred} 1189184610Salfred 1190184610Salfredstatic void 1191192984Sthompsaat91dci_standard_done(struct usb_xfer *xfer) 1192184610Salfred{ 1193193045Sthompsa usb_error_t err = 0; 1194184610Salfred 1195193644Sthompsa DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", 1196193644Sthompsa xfer, xfer->endpoint); 1197184610Salfred 1198184610Salfred /* reset scanner */ 1199184610Salfred 1200184610Salfred xfer->td_transfer_cache = xfer->td_transfer_first; 1201184610Salfred 1202184610Salfred if (xfer->flags_int.control_xfr) { 1203184610Salfred 1204184610Salfred if (xfer->flags_int.control_hdr) { 1205184610Salfred 1206184610Salfred err = at91dci_standard_done_sub(xfer); 1207184610Salfred } 1208184610Salfred xfer->aframes = 1; 1209184610Salfred 1210184610Salfred if (xfer->td_transfer_cache == NULL) { 1211184610Salfred goto done; 1212184610Salfred } 1213184610Salfred } 1214184610Salfred while (xfer->aframes != xfer->nframes) { 1215184610Salfred 1216184610Salfred err = at91dci_standard_done_sub(xfer); 1217184610Salfred xfer->aframes++; 1218184610Salfred 1219184610Salfred if (xfer->td_transfer_cache == NULL) { 1220184610Salfred goto done; 1221184610Salfred } 1222184610Salfred } 1223184610Salfred 1224184610Salfred if (xfer->flags_int.control_xfr && 1225184610Salfred !xfer->flags_int.control_act) { 1226184610Salfred 1227184610Salfred err = at91dci_standard_done_sub(xfer); 1228184610Salfred } 1229184610Salfreddone: 1230184610Salfred at91dci_device_done(xfer, err); 1231184610Salfred} 1232184610Salfred 1233184610Salfred/*------------------------------------------------------------------------* 1234184610Salfred * at91dci_device_done 1235184610Salfred * 1236184610Salfred * NOTE: this function can be called more than one time on the 1237184610Salfred * same USB transfer! 1238184610Salfred *------------------------------------------------------------------------*/ 1239184610Salfredstatic void 1240193045Sthompsaat91dci_device_done(struct usb_xfer *xfer, usb_error_t error) 1241184610Salfred{ 1242187173Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1243184610Salfred uint8_t ep_no; 1244184610Salfred 1245184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1246184610Salfred 1247193644Sthompsa DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n", 1248193644Sthompsa xfer, xfer->endpoint, error); 1249184610Salfred 1250269604Shselasky USB_BUS_SPIN_LOCK(&sc->sc_bus); 1251269604Shselasky 1252192499Sthompsa if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { 1253193644Sthompsa ep_no = (xfer->endpointno & UE_ADDR); 1254184610Salfred 1255184610Salfred /* disable endpoint interrupt */ 1256184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, AT91_UDP_INT_EP(ep_no)); 1257184610Salfred 1258184610Salfred DPRINTFN(15, "disable interrupts on endpoint %d\n", ep_no); 1259184610Salfred } 1260269604Shselasky 1261184610Salfred /* dequeue transfer and start next transfer */ 1262194228Sthompsa usbd_transfer_done(xfer, error); 1263269604Shselasky 1264269604Shselasky USB_BUS_SPIN_UNLOCK(&sc->sc_bus); 1265184610Salfred} 1266184610Salfred 1267184610Salfredstatic void 1268239214Shselaskyat91dci_xfer_stall(struct usb_xfer *xfer) 1269239214Shselasky{ 1270239214Shselasky at91dci_device_done(xfer, USB_ERR_STALLED); 1271239214Shselasky} 1272239214Shselasky 1273239214Shselaskystatic void 1274239214Shselaskyat91dci_set_stall(struct usb_device *udev, 1275195121Sthompsa struct usb_endpoint *ep, uint8_t *did_stall) 1276184610Salfred{ 1277184610Salfred struct at91dci_softc *sc; 1278184610Salfred uint32_t csr_val; 1279184610Salfred uint8_t csr_reg; 1280184610Salfred 1281184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 1282184610Salfred 1283193644Sthompsa DPRINTFN(5, "endpoint=%p\n", ep); 1284184610Salfred 1285184610Salfred /* set FORCESTALL */ 1286184610Salfred sc = AT9100_DCI_BUS2SC(udev->bus); 1287269604Shselasky 1288269604Shselasky USB_BUS_SPIN_LOCK(&sc->sc_bus); 1289193644Sthompsa csr_reg = (ep->edesc->bEndpointAddress & UE_ADDR); 1290184610Salfred csr_reg = AT91_UDP_CSR(csr_reg); 1291184610Salfred csr_val = AT91_UDP_READ_4(sc, csr_reg); 1292184610Salfred AT91_CSR_ACK(csr_val, AT91_UDP_CSR_FORCESTALL); 1293184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1294269604Shselasky USB_BUS_SPIN_UNLOCK(&sc->sc_bus); 1295184610Salfred} 1296184610Salfred 1297184610Salfredstatic void 1298184610Salfredat91dci_clear_stall_sub(struct at91dci_softc *sc, uint8_t ep_no, 1299184610Salfred uint8_t ep_type, uint8_t ep_dir) 1300184610Salfred{ 1301192984Sthompsa const struct usb_hw_ep_profile *pf; 1302184610Salfred uint32_t csr_val; 1303184610Salfred uint32_t temp; 1304184610Salfred uint8_t csr_reg; 1305184610Salfred uint8_t to; 1306184610Salfred 1307184610Salfred if (ep_type == UE_CONTROL) { 1308184610Salfred /* clearing stall is not needed */ 1309184610Salfred return; 1310184610Salfred } 1311269604Shselasky 1312269604Shselasky USB_BUS_SPIN_LOCK(&sc->sc_bus); 1313269604Shselasky 1314184610Salfred /* compute CSR register offset */ 1315184610Salfred csr_reg = AT91_UDP_CSR(ep_no); 1316184610Salfred 1317184610Salfred /* compute default CSR value */ 1318184610Salfred csr_val = 0; 1319184610Salfred AT91_CSR_ACK(csr_val, 0); 1320184610Salfred 1321184610Salfred /* disable endpoint */ 1322184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1323184610Salfred 1324184610Salfred /* get endpoint profile */ 1325184610Salfred at91dci_get_hw_ep_profile(NULL, &pf, ep_no); 1326184610Salfred 1327184610Salfred /* reset FIFO */ 1328184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(ep_no)); 1329184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0); 1330184610Salfred 1331184610Salfred /* 1332184610Salfred * NOTE: One would assume that a FIFO reset would release the 1333298932Spfg * FIFO banks as well, but it doesn't! We have to do this 1334184610Salfred * manually! 1335184610Salfred */ 1336184610Salfred 1337184610Salfred /* release FIFO banks, if any */ 1338184610Salfred for (to = 0; to != 2; to++) { 1339184610Salfred 1340184610Salfred /* get csr value */ 1341184610Salfred csr_val = AT91_UDP_READ_4(sc, csr_reg); 1342184610Salfred 1343184610Salfred if (csr_val & (AT91_UDP_CSR_RX_DATA_BK0 | 1344184610Salfred AT91_UDP_CSR_RX_DATA_BK1)) { 1345184610Salfred /* clear status bits */ 1346184610Salfred if (pf->support_multi_buffer) { 1347184610Salfred if (sc->sc_ep_flags[ep_no].fifo_bank) { 1348184610Salfred sc->sc_ep_flags[ep_no].fifo_bank = 0; 1349184610Salfred temp = AT91_UDP_CSR_RX_DATA_BK1; 1350184610Salfred } else { 1351184610Salfred sc->sc_ep_flags[ep_no].fifo_bank = 1; 1352184610Salfred temp = AT91_UDP_CSR_RX_DATA_BK0; 1353184610Salfred } 1354184610Salfred } else { 1355184610Salfred temp = (AT91_UDP_CSR_RX_DATA_BK0 | 1356184610Salfred AT91_UDP_CSR_RX_DATA_BK1); 1357184610Salfred } 1358184610Salfred } else { 1359184610Salfred temp = 0; 1360184610Salfred } 1361184610Salfred 1362184610Salfred /* clear FORCESTALL */ 1363184610Salfred temp |= AT91_UDP_CSR_STALLSENT; 1364184610Salfred 1365184610Salfred AT91_CSR_ACK(csr_val, temp); 1366184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1367184610Salfred } 1368184610Salfred 1369184610Salfred /* compute default CSR value */ 1370184610Salfred csr_val = 0; 1371184610Salfred AT91_CSR_ACK(csr_val, 0); 1372184610Salfred 1373184610Salfred /* enable endpoint */ 1374184610Salfred csr_val &= ~AT91_UDP_CSR_ET_MASK; 1375184610Salfred csr_val |= AT91_UDP_CSR_EPEDS; 1376184610Salfred 1377184610Salfred if (ep_type == UE_CONTROL) { 1378184610Salfred csr_val |= AT91_UDP_CSR_ET_CTRL; 1379184610Salfred } else { 1380184610Salfred if (ep_type == UE_BULK) { 1381184610Salfred csr_val |= AT91_UDP_CSR_ET_BULK; 1382184610Salfred } else if (ep_type == UE_INTERRUPT) { 1383184610Salfred csr_val |= AT91_UDP_CSR_ET_INT; 1384184610Salfred } else { 1385184610Salfred csr_val |= AT91_UDP_CSR_ET_ISO; 1386184610Salfred } 1387184610Salfred if (ep_dir & UE_DIR_IN) { 1388184610Salfred csr_val |= AT91_UDP_CSR_ET_DIR_IN; 1389184610Salfred } 1390184610Salfred } 1391184610Salfred 1392184610Salfred /* enable endpoint */ 1393184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(ep_no), csr_val); 1394269604Shselasky 1395269604Shselasky USB_BUS_SPIN_UNLOCK(&sc->sc_bus); 1396184610Salfred} 1397184610Salfred 1398184610Salfredstatic void 1399193644Sthompsaat91dci_clear_stall(struct usb_device *udev, struct usb_endpoint *ep) 1400184610Salfred{ 1401184610Salfred struct at91dci_softc *sc; 1402192984Sthompsa struct usb_endpoint_descriptor *ed; 1403184610Salfred 1404193644Sthompsa DPRINTFN(5, "endpoint=%p\n", ep); 1405184610Salfred 1406184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 1407184610Salfred 1408184610Salfred /* check mode */ 1409192499Sthompsa if (udev->flags.usb_mode != USB_MODE_DEVICE) { 1410184610Salfred /* not supported */ 1411184610Salfred return; 1412184610Salfred } 1413184610Salfred /* get softc */ 1414184610Salfred sc = AT9100_DCI_BUS2SC(udev->bus); 1415184610Salfred 1416184610Salfred /* get endpoint descriptor */ 1417193644Sthompsa ed = ep->edesc; 1418184610Salfred 1419184610Salfred /* reset endpoint */ 1420184610Salfred at91dci_clear_stall_sub(sc, 1421184610Salfred (ed->bEndpointAddress & UE_ADDR), 1422184610Salfred (ed->bmAttributes & UE_XFERTYPE), 1423184610Salfred (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); 1424184610Salfred} 1425184610Salfred 1426193045Sthompsausb_error_t 1427184610Salfredat91dci_init(struct at91dci_softc *sc) 1428184610Salfred{ 1429184610Salfred uint32_t csr_val; 1430184610Salfred uint8_t n; 1431184610Salfred 1432184610Salfred DPRINTF("start\n"); 1433184610Salfred 1434184610Salfred /* set up the bus structure */ 1435184610Salfred sc->sc_bus.usbrev = USB_REV_1_1; 1436184610Salfred sc->sc_bus.methods = &at91dci_bus_methods; 1437184610Salfred 1438184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1439184610Salfred 1440184610Salfred /* turn on clocks */ 1441184610Salfred 1442184610Salfred if (sc->sc_clocks_on) { 1443184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 1444184610Salfred } 1445184610Salfred /* wait a little for things to stabilise */ 1446194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); 1447184610Salfred 1448184610Salfred /* disable and clear all interrupts */ 1449184610Salfred 1450184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); 1451184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF); 1452184610Salfred 1453184610Salfred /* compute default CSR value */ 1454184610Salfred 1455184610Salfred csr_val = 0; 1456184610Salfred AT91_CSR_ACK(csr_val, 0); 1457184610Salfred 1458184610Salfred /* disable all endpoints */ 1459184610Salfred 1460184610Salfred for (n = 0; n != AT91_UDP_EP_MAX; n++) { 1461184610Salfred 1462184610Salfred /* disable endpoint */ 1463184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(n), csr_val); 1464184610Salfred } 1465184610Salfred 1466184610Salfred /* enable the control endpoint */ 1467184610Salfred 1468184610Salfred AT91_CSR_ACK(csr_val, AT91_UDP_CSR_ET_CTRL | 1469184610Salfred AT91_UDP_CSR_EPEDS); 1470184610Salfred 1471184610Salfred /* write to FIFO control register */ 1472184610Salfred 1473184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(0), csr_val); 1474184610Salfred 1475184610Salfred /* enable the interrupts we want */ 1476184610Salfred 1477184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_BUS); 1478184610Salfred 1479184610Salfred /* turn off clocks */ 1480184610Salfred 1481184610Salfred at91dci_clocks_off(sc); 1482184610Salfred 1483184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1484184610Salfred 1485184610Salfred /* catch any lost interrupts */ 1486184610Salfred 1487184610Salfred at91dci_do_poll(&sc->sc_bus); 1488184610Salfred 1489184610Salfred return (0); /* success */ 1490184610Salfred} 1491184610Salfred 1492184610Salfredvoid 1493184610Salfredat91dci_uninit(struct at91dci_softc *sc) 1494184610Salfred{ 1495184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1496184610Salfred 1497184610Salfred /* disable and clear all interrupts */ 1498184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); 1499184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF); 1500184610Salfred 1501184610Salfred sc->sc_flags.port_powered = 0; 1502184610Salfred sc->sc_flags.status_vbus = 0; 1503184610Salfred sc->sc_flags.status_bus_reset = 0; 1504184610Salfred sc->sc_flags.status_suspend = 0; 1505184610Salfred sc->sc_flags.change_suspend = 0; 1506184610Salfred sc->sc_flags.change_connect = 1; 1507184610Salfred 1508184610Salfred at91dci_pull_down(sc); 1509184610Salfred at91dci_clocks_off(sc); 1510184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1511184610Salfred} 1512184610Salfred 1513228483Shselaskystatic void 1514184610Salfredat91dci_suspend(struct at91dci_softc *sc) 1515184610Salfred{ 1516228483Shselasky /* TODO */ 1517184610Salfred} 1518184610Salfred 1519228483Shselaskystatic void 1520184610Salfredat91dci_resume(struct at91dci_softc *sc) 1521184610Salfred{ 1522228483Shselasky /* TODO */ 1523184610Salfred} 1524184610Salfred 1525184610Salfredstatic void 1526192984Sthompsaat91dci_do_poll(struct usb_bus *bus) 1527184610Salfred{ 1528184610Salfred struct at91dci_softc *sc = AT9100_DCI_BUS2SC(bus); 1529184610Salfred 1530184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1531269604Shselasky USB_BUS_SPIN_LOCK(&sc->sc_bus); 1532269604Shselasky at91dci_interrupt_poll_locked(sc); 1533269604Shselasky at91dci_interrupt_complete_locked(sc); 1534269604Shselasky USB_BUS_SPIN_UNLOCK(&sc->sc_bus); 1535184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1536184610Salfred} 1537184610Salfred 1538184610Salfred/*------------------------------------------------------------------------* 1539184610Salfred * at91dci bulk support 1540184610Salfred *------------------------------------------------------------------------*/ 1541184610Salfredstatic void 1542192984Sthompsaat91dci_device_bulk_open(struct usb_xfer *xfer) 1543184610Salfred{ 1544184610Salfred return; 1545184610Salfred} 1546184610Salfred 1547184610Salfredstatic void 1548192984Sthompsaat91dci_device_bulk_close(struct usb_xfer *xfer) 1549184610Salfred{ 1550184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1551184610Salfred} 1552184610Salfred 1553184610Salfredstatic void 1554192984Sthompsaat91dci_device_bulk_enter(struct usb_xfer *xfer) 1555184610Salfred{ 1556184610Salfred return; 1557184610Salfred} 1558184610Salfred 1559184610Salfredstatic void 1560192984Sthompsaat91dci_device_bulk_start(struct usb_xfer *xfer) 1561184610Salfred{ 1562184610Salfred /* setup TDs */ 1563184610Salfred at91dci_setup_standard_chain(xfer); 1564184610Salfred at91dci_start_standard_chain(xfer); 1565184610Salfred} 1566184610Salfred 1567259218Shselaskystatic const struct usb_pipe_methods at91dci_device_bulk_methods = 1568184610Salfred{ 1569184610Salfred .open = at91dci_device_bulk_open, 1570184610Salfred .close = at91dci_device_bulk_close, 1571184610Salfred .enter = at91dci_device_bulk_enter, 1572184610Salfred .start = at91dci_device_bulk_start, 1573184610Salfred}; 1574184610Salfred 1575184610Salfred/*------------------------------------------------------------------------* 1576184610Salfred * at91dci control support 1577184610Salfred *------------------------------------------------------------------------*/ 1578184610Salfredstatic void 1579192984Sthompsaat91dci_device_ctrl_open(struct usb_xfer *xfer) 1580184610Salfred{ 1581184610Salfred return; 1582184610Salfred} 1583184610Salfred 1584184610Salfredstatic void 1585192984Sthompsaat91dci_device_ctrl_close(struct usb_xfer *xfer) 1586184610Salfred{ 1587184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1588184610Salfred} 1589184610Salfred 1590184610Salfredstatic void 1591192984Sthompsaat91dci_device_ctrl_enter(struct usb_xfer *xfer) 1592184610Salfred{ 1593184610Salfred return; 1594184610Salfred} 1595184610Salfred 1596184610Salfredstatic void 1597192984Sthompsaat91dci_device_ctrl_start(struct usb_xfer *xfer) 1598184610Salfred{ 1599184610Salfred /* setup TDs */ 1600184610Salfred at91dci_setup_standard_chain(xfer); 1601184610Salfred at91dci_start_standard_chain(xfer); 1602184610Salfred} 1603184610Salfred 1604259218Shselaskystatic const struct usb_pipe_methods at91dci_device_ctrl_methods = 1605184610Salfred{ 1606184610Salfred .open = at91dci_device_ctrl_open, 1607184610Salfred .close = at91dci_device_ctrl_close, 1608184610Salfred .enter = at91dci_device_ctrl_enter, 1609184610Salfred .start = at91dci_device_ctrl_start, 1610184610Salfred}; 1611184610Salfred 1612184610Salfred/*------------------------------------------------------------------------* 1613184610Salfred * at91dci interrupt support 1614184610Salfred *------------------------------------------------------------------------*/ 1615184610Salfredstatic void 1616192984Sthompsaat91dci_device_intr_open(struct usb_xfer *xfer) 1617184610Salfred{ 1618184610Salfred return; 1619184610Salfred} 1620184610Salfred 1621184610Salfredstatic void 1622192984Sthompsaat91dci_device_intr_close(struct usb_xfer *xfer) 1623184610Salfred{ 1624184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1625184610Salfred} 1626184610Salfred 1627184610Salfredstatic void 1628192984Sthompsaat91dci_device_intr_enter(struct usb_xfer *xfer) 1629184610Salfred{ 1630184610Salfred return; 1631184610Salfred} 1632184610Salfred 1633184610Salfredstatic void 1634192984Sthompsaat91dci_device_intr_start(struct usb_xfer *xfer) 1635184610Salfred{ 1636184610Salfred /* setup TDs */ 1637184610Salfred at91dci_setup_standard_chain(xfer); 1638184610Salfred at91dci_start_standard_chain(xfer); 1639184610Salfred} 1640184610Salfred 1641259218Shselaskystatic const struct usb_pipe_methods at91dci_device_intr_methods = 1642184610Salfred{ 1643184610Salfred .open = at91dci_device_intr_open, 1644184610Salfred .close = at91dci_device_intr_close, 1645184610Salfred .enter = at91dci_device_intr_enter, 1646184610Salfred .start = at91dci_device_intr_start, 1647184610Salfred}; 1648184610Salfred 1649184610Salfred/*------------------------------------------------------------------------* 1650184610Salfred * at91dci full speed isochronous support 1651184610Salfred *------------------------------------------------------------------------*/ 1652184610Salfredstatic void 1653192984Sthompsaat91dci_device_isoc_fs_open(struct usb_xfer *xfer) 1654184610Salfred{ 1655184610Salfred return; 1656184610Salfred} 1657184610Salfred 1658184610Salfredstatic void 1659192984Sthompsaat91dci_device_isoc_fs_close(struct usb_xfer *xfer) 1660184610Salfred{ 1661184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1662184610Salfred} 1663184610Salfred 1664184610Salfredstatic void 1665192984Sthompsaat91dci_device_isoc_fs_enter(struct usb_xfer *xfer) 1666184610Salfred{ 1667187173Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1668184610Salfred uint32_t temp; 1669184610Salfred uint32_t nframes; 1670184610Salfred 1671184610Salfred DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", 1672193644Sthompsa xfer, xfer->endpoint->isoc_next, xfer->nframes); 1673184610Salfred 1674184610Salfred /* get the current frame index */ 1675184610Salfred 1676184610Salfred nframes = AT91_UDP_READ_4(sc, AT91_UDP_FRM); 1677184610Salfred 1678184610Salfred /* 1679184610Salfred * check if the frame index is within the window where the frames 1680184610Salfred * will be inserted 1681184610Salfred */ 1682193644Sthompsa temp = (nframes - xfer->endpoint->isoc_next) & AT91_UDP_FRM_MASK; 1683184610Salfred 1684193644Sthompsa if ((xfer->endpoint->is_synced == 0) || 1685184610Salfred (temp < xfer->nframes)) { 1686184610Salfred /* 1687193644Sthompsa * If there is data underflow or the endpoint queue is 1688184610Salfred * empty we schedule the transfer a few frames ahead 1689184610Salfred * of the current frame position. Else two isochronous 1690184610Salfred * transfers might overlap. 1691184610Salfred */ 1692193644Sthompsa xfer->endpoint->isoc_next = (nframes + 3) & AT91_UDP_FRM_MASK; 1693193644Sthompsa xfer->endpoint->is_synced = 1; 1694193644Sthompsa DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next); 1695184610Salfred } 1696184610Salfred /* 1697184610Salfred * compute how many milliseconds the insertion is ahead of the 1698184610Salfred * current frame position: 1699184610Salfred */ 1700193644Sthompsa temp = (xfer->endpoint->isoc_next - nframes) & AT91_UDP_FRM_MASK; 1701184610Salfred 1702184610Salfred /* 1703184610Salfred * pre-compute when the isochronous transfer will be finished: 1704184610Salfred */ 1705184610Salfred xfer->isoc_time_complete = 1706194228Sthompsa usb_isoc_time_expand(&sc->sc_bus, nframes) + temp + 1707184610Salfred xfer->nframes; 1708184610Salfred 1709184610Salfred /* compute frame number for next insertion */ 1710193644Sthompsa xfer->endpoint->isoc_next += xfer->nframes; 1711184610Salfred 1712184610Salfred /* setup TDs */ 1713184610Salfred at91dci_setup_standard_chain(xfer); 1714184610Salfred} 1715184610Salfred 1716184610Salfredstatic void 1717192984Sthompsaat91dci_device_isoc_fs_start(struct usb_xfer *xfer) 1718184610Salfred{ 1719184610Salfred /* start TD chain */ 1720184610Salfred at91dci_start_standard_chain(xfer); 1721184610Salfred} 1722184610Salfred 1723259218Shselaskystatic const struct usb_pipe_methods at91dci_device_isoc_fs_methods = 1724184610Salfred{ 1725184610Salfred .open = at91dci_device_isoc_fs_open, 1726184610Salfred .close = at91dci_device_isoc_fs_close, 1727184610Salfred .enter = at91dci_device_isoc_fs_enter, 1728184610Salfred .start = at91dci_device_isoc_fs_start, 1729184610Salfred}; 1730184610Salfred 1731184610Salfred/*------------------------------------------------------------------------* 1732184610Salfred * at91dci root control support 1733184610Salfred *------------------------------------------------------------------------* 1734190735Sthompsa * Simulate a hardware HUB by handling all the necessary requests. 1735184610Salfred *------------------------------------------------------------------------*/ 1736184610Salfred 1737192984Sthompsastatic const struct usb_device_descriptor at91dci_devd = { 1738192984Sthompsa .bLength = sizeof(struct usb_device_descriptor), 1739184610Salfred .bDescriptorType = UDESC_DEVICE, 1740184610Salfred .bcdUSB = {0x00, 0x02}, 1741184610Salfred .bDeviceClass = UDCLASS_HUB, 1742184610Salfred .bDeviceSubClass = UDSUBCLASS_HUB, 1743213802Shselasky .bDeviceProtocol = UDPROTO_FSHUB, 1744184610Salfred .bMaxPacketSize = 64, 1745184610Salfred .bcdDevice = {0x00, 0x01}, 1746184610Salfred .iManufacturer = 1, 1747184610Salfred .iProduct = 2, 1748184610Salfred .bNumConfigurations = 1, 1749184610Salfred}; 1750184610Salfred 1751184610Salfredstatic const struct at91dci_config_desc at91dci_confd = { 1752184610Salfred .confd = { 1753192984Sthompsa .bLength = sizeof(struct usb_config_descriptor), 1754184610Salfred .bDescriptorType = UDESC_CONFIG, 1755184610Salfred .wTotalLength[0] = sizeof(at91dci_confd), 1756184610Salfred .bNumInterface = 1, 1757184610Salfred .bConfigurationValue = 1, 1758184610Salfred .iConfiguration = 0, 1759184610Salfred .bmAttributes = UC_SELF_POWERED, 1760184610Salfred .bMaxPower = 0, 1761184610Salfred }, 1762184610Salfred .ifcd = { 1763192984Sthompsa .bLength = sizeof(struct usb_interface_descriptor), 1764184610Salfred .bDescriptorType = UDESC_INTERFACE, 1765184610Salfred .bNumEndpoints = 1, 1766184610Salfred .bInterfaceClass = UICLASS_HUB, 1767184610Salfred .bInterfaceSubClass = UISUBCLASS_HUB, 1768213802Shselasky .bInterfaceProtocol = 0, 1769184610Salfred }, 1770184610Salfred .endpd = { 1771192984Sthompsa .bLength = sizeof(struct usb_endpoint_descriptor), 1772184610Salfred .bDescriptorType = UDESC_ENDPOINT, 1773184610Salfred .bEndpointAddress = (UE_DIR_IN | AT9100_DCI_INTR_ENDPT), 1774184610Salfred .bmAttributes = UE_INTERRUPT, 1775184610Salfred .wMaxPacketSize[0] = 8, 1776184610Salfred .bInterval = 255, 1777184610Salfred }, 1778184610Salfred}; 1779184610Salfred 1780233774Shselasky#define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } 1781233774Shselasky 1782192984Sthompsastatic const struct usb_hub_descriptor_min at91dci_hubd = { 1783184610Salfred .bDescLength = sizeof(at91dci_hubd), 1784184610Salfred .bDescriptorType = UDESC_HUB, 1785184610Salfred .bNbrPorts = 1, 1786233774Shselasky HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)), 1787184610Salfred .bPwrOn2PwrGood = 50, 1788184610Salfred .bHubContrCurrent = 0, 1789184610Salfred .DeviceRemovable = {0}, /* port is removable */ 1790184610Salfred}; 1791184610Salfred 1792184610Salfred#define STRING_VENDOR \ 1793246125Shselasky "A\0T\0M\0E\0L" 1794184610Salfred 1795184610Salfred#define STRING_PRODUCT \ 1796246125Shselasky "D\0C\0I\0 \0R\0o\0o\0t\0 \0H\0U\0B" 1797184610Salfred 1798184610SalfredUSB_MAKE_STRING_DESC(STRING_VENDOR, at91dci_vendor); 1799184610SalfredUSB_MAKE_STRING_DESC(STRING_PRODUCT, at91dci_product); 1800184610Salfred 1801193045Sthompsastatic usb_error_t 1802192984Sthompsaat91dci_roothub_exec(struct usb_device *udev, 1803192984Sthompsa struct usb_device_request *req, const void **pptr, uint16_t *plength) 1804184610Salfred{ 1805191402Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus); 1806191402Sthompsa const void *ptr; 1807191402Sthompsa uint16_t len; 1808184610Salfred uint16_t value; 1809184610Salfred uint16_t index; 1810193045Sthompsa usb_error_t err; 1811184610Salfred 1812184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1813184610Salfred 1814184610Salfred /* buffer reset */ 1815191402Sthompsa ptr = (const void *)&sc->sc_hub_temp; 1816191402Sthompsa len = 0; 1817191402Sthompsa err = 0; 1818184610Salfred 1819191402Sthompsa value = UGETW(req->wValue); 1820191402Sthompsa index = UGETW(req->wIndex); 1821184610Salfred 1822184610Salfred /* demultiplex the control request */ 1823184610Salfred 1824191402Sthompsa switch (req->bmRequestType) { 1825184610Salfred case UT_READ_DEVICE: 1826191402Sthompsa switch (req->bRequest) { 1827184610Salfred case UR_GET_DESCRIPTOR: 1828184610Salfred goto tr_handle_get_descriptor; 1829184610Salfred case UR_GET_CONFIG: 1830184610Salfred goto tr_handle_get_config; 1831184610Salfred case UR_GET_STATUS: 1832184610Salfred goto tr_handle_get_status; 1833184610Salfred default: 1834184610Salfred goto tr_stalled; 1835184610Salfred } 1836184610Salfred break; 1837184610Salfred 1838184610Salfred case UT_WRITE_DEVICE: 1839191402Sthompsa switch (req->bRequest) { 1840184610Salfred case UR_SET_ADDRESS: 1841184610Salfred goto tr_handle_set_address; 1842184610Salfred case UR_SET_CONFIG: 1843184610Salfred goto tr_handle_set_config; 1844184610Salfred case UR_CLEAR_FEATURE: 1845184610Salfred goto tr_valid; /* nop */ 1846184610Salfred case UR_SET_DESCRIPTOR: 1847184610Salfred goto tr_valid; /* nop */ 1848184610Salfred case UR_SET_FEATURE: 1849184610Salfred default: 1850184610Salfred goto tr_stalled; 1851184610Salfred } 1852184610Salfred break; 1853184610Salfred 1854184610Salfred case UT_WRITE_ENDPOINT: 1855191402Sthompsa switch (req->bRequest) { 1856184610Salfred case UR_CLEAR_FEATURE: 1857191402Sthompsa switch (UGETW(req->wValue)) { 1858184610Salfred case UF_ENDPOINT_HALT: 1859184610Salfred goto tr_handle_clear_halt; 1860184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 1861184610Salfred goto tr_handle_clear_wakeup; 1862184610Salfred default: 1863184610Salfred goto tr_stalled; 1864184610Salfred } 1865184610Salfred break; 1866184610Salfred case UR_SET_FEATURE: 1867191402Sthompsa switch (UGETW(req->wValue)) { 1868184610Salfred case UF_ENDPOINT_HALT: 1869184610Salfred goto tr_handle_set_halt; 1870184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 1871184610Salfred goto tr_handle_set_wakeup; 1872184610Salfred default: 1873184610Salfred goto tr_stalled; 1874184610Salfred } 1875184610Salfred break; 1876184610Salfred case UR_SYNCH_FRAME: 1877184610Salfred goto tr_valid; /* nop */ 1878184610Salfred default: 1879184610Salfred goto tr_stalled; 1880184610Salfred } 1881184610Salfred break; 1882184610Salfred 1883184610Salfred case UT_READ_ENDPOINT: 1884191402Sthompsa switch (req->bRequest) { 1885184610Salfred case UR_GET_STATUS: 1886184610Salfred goto tr_handle_get_ep_status; 1887184610Salfred default: 1888184610Salfred goto tr_stalled; 1889184610Salfred } 1890184610Salfred break; 1891184610Salfred 1892184610Salfred case UT_WRITE_INTERFACE: 1893191402Sthompsa switch (req->bRequest) { 1894184610Salfred case UR_SET_INTERFACE: 1895184610Salfred goto tr_handle_set_interface; 1896184610Salfred case UR_CLEAR_FEATURE: 1897184610Salfred goto tr_valid; /* nop */ 1898184610Salfred case UR_SET_FEATURE: 1899184610Salfred default: 1900184610Salfred goto tr_stalled; 1901184610Salfred } 1902184610Salfred break; 1903184610Salfred 1904184610Salfred case UT_READ_INTERFACE: 1905191402Sthompsa switch (req->bRequest) { 1906184610Salfred case UR_GET_INTERFACE: 1907184610Salfred goto tr_handle_get_interface; 1908184610Salfred case UR_GET_STATUS: 1909184610Salfred goto tr_handle_get_iface_status; 1910184610Salfred default: 1911184610Salfred goto tr_stalled; 1912184610Salfred } 1913184610Salfred break; 1914184610Salfred 1915184610Salfred case UT_WRITE_CLASS_INTERFACE: 1916184610Salfred case UT_WRITE_VENDOR_INTERFACE: 1917184610Salfred /* XXX forward */ 1918184610Salfred break; 1919184610Salfred 1920184610Salfred case UT_READ_CLASS_INTERFACE: 1921184610Salfred case UT_READ_VENDOR_INTERFACE: 1922184610Salfred /* XXX forward */ 1923184610Salfred break; 1924184610Salfred 1925184610Salfred case UT_WRITE_CLASS_DEVICE: 1926191402Sthompsa switch (req->bRequest) { 1927184610Salfred case UR_CLEAR_FEATURE: 1928184610Salfred goto tr_valid; 1929184610Salfred case UR_SET_DESCRIPTOR: 1930184610Salfred case UR_SET_FEATURE: 1931184610Salfred break; 1932184610Salfred default: 1933184610Salfred goto tr_stalled; 1934184610Salfred } 1935184610Salfred break; 1936184610Salfred 1937184610Salfred case UT_WRITE_CLASS_OTHER: 1938191402Sthompsa switch (req->bRequest) { 1939184610Salfred case UR_CLEAR_FEATURE: 1940184610Salfred goto tr_handle_clear_port_feature; 1941184610Salfred case UR_SET_FEATURE: 1942184610Salfred goto tr_handle_set_port_feature; 1943184610Salfred case UR_CLEAR_TT_BUFFER: 1944184610Salfred case UR_RESET_TT: 1945184610Salfred case UR_STOP_TT: 1946184610Salfred goto tr_valid; 1947184610Salfred 1948184610Salfred default: 1949184610Salfred goto tr_stalled; 1950184610Salfred } 1951184610Salfred break; 1952184610Salfred 1953184610Salfred case UT_READ_CLASS_OTHER: 1954191402Sthompsa switch (req->bRequest) { 1955184610Salfred case UR_GET_TT_STATE: 1956184610Salfred goto tr_handle_get_tt_state; 1957184610Salfred case UR_GET_STATUS: 1958184610Salfred goto tr_handle_get_port_status; 1959184610Salfred default: 1960184610Salfred goto tr_stalled; 1961184610Salfred } 1962184610Salfred break; 1963184610Salfred 1964184610Salfred case UT_READ_CLASS_DEVICE: 1965191402Sthompsa switch (req->bRequest) { 1966184610Salfred case UR_GET_DESCRIPTOR: 1967184610Salfred goto tr_handle_get_class_descriptor; 1968184610Salfred case UR_GET_STATUS: 1969184610Salfred goto tr_handle_get_class_status; 1970184610Salfred 1971184610Salfred default: 1972184610Salfred goto tr_stalled; 1973184610Salfred } 1974184610Salfred break; 1975184610Salfred default: 1976184610Salfred goto tr_stalled; 1977184610Salfred } 1978184610Salfred goto tr_valid; 1979184610Salfred 1980184610Salfredtr_handle_get_descriptor: 1981184610Salfred switch (value >> 8) { 1982184610Salfred case UDESC_DEVICE: 1983184610Salfred if (value & 0xff) { 1984184610Salfred goto tr_stalled; 1985184610Salfred } 1986191402Sthompsa len = sizeof(at91dci_devd); 1987191402Sthompsa ptr = (const void *)&at91dci_devd; 1988184610Salfred goto tr_valid; 1989184610Salfred case UDESC_CONFIG: 1990184610Salfred if (value & 0xff) { 1991184610Salfred goto tr_stalled; 1992184610Salfred } 1993191402Sthompsa len = sizeof(at91dci_confd); 1994191402Sthompsa ptr = (const void *)&at91dci_confd; 1995184610Salfred goto tr_valid; 1996184610Salfred case UDESC_STRING: 1997184610Salfred switch (value & 0xff) { 1998184610Salfred case 0: /* Language table */ 1999246123Shselasky len = sizeof(usb_string_lang_en); 2000246123Shselasky ptr = (const void *)&usb_string_lang_en; 2001184610Salfred goto tr_valid; 2002184610Salfred 2003184610Salfred case 1: /* Vendor */ 2004191402Sthompsa len = sizeof(at91dci_vendor); 2005191402Sthompsa ptr = (const void *)&at91dci_vendor; 2006184610Salfred goto tr_valid; 2007184610Salfred 2008184610Salfred case 2: /* Product */ 2009191402Sthompsa len = sizeof(at91dci_product); 2010191402Sthompsa ptr = (const void *)&at91dci_product; 2011184610Salfred goto tr_valid; 2012184610Salfred default: 2013184610Salfred break; 2014184610Salfred } 2015184610Salfred break; 2016184610Salfred default: 2017184610Salfred goto tr_stalled; 2018184610Salfred } 2019184610Salfred goto tr_stalled; 2020184610Salfred 2021184610Salfredtr_handle_get_config: 2022191402Sthompsa len = 1; 2023184610Salfred sc->sc_hub_temp.wValue[0] = sc->sc_conf; 2024184610Salfred goto tr_valid; 2025184610Salfred 2026184610Salfredtr_handle_get_status: 2027191402Sthompsa len = 2; 2028184610Salfred USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); 2029184610Salfred goto tr_valid; 2030184610Salfred 2031184610Salfredtr_handle_set_address: 2032184610Salfred if (value & 0xFF00) { 2033184610Salfred goto tr_stalled; 2034184610Salfred } 2035184610Salfred sc->sc_rt_addr = value; 2036184610Salfred goto tr_valid; 2037184610Salfred 2038184610Salfredtr_handle_set_config: 2039184610Salfred if (value >= 2) { 2040184610Salfred goto tr_stalled; 2041184610Salfred } 2042184610Salfred sc->sc_conf = value; 2043184610Salfred goto tr_valid; 2044184610Salfred 2045184610Salfredtr_handle_get_interface: 2046191402Sthompsa len = 1; 2047184610Salfred sc->sc_hub_temp.wValue[0] = 0; 2048184610Salfred goto tr_valid; 2049184610Salfred 2050184610Salfredtr_handle_get_tt_state: 2051184610Salfredtr_handle_get_class_status: 2052184610Salfredtr_handle_get_iface_status: 2053184610Salfredtr_handle_get_ep_status: 2054191402Sthompsa len = 2; 2055184610Salfred USETW(sc->sc_hub_temp.wValue, 0); 2056184610Salfred goto tr_valid; 2057184610Salfred 2058184610Salfredtr_handle_set_halt: 2059184610Salfredtr_handle_set_interface: 2060184610Salfredtr_handle_set_wakeup: 2061184610Salfredtr_handle_clear_wakeup: 2062184610Salfredtr_handle_clear_halt: 2063184610Salfred goto tr_valid; 2064184610Salfred 2065184610Salfredtr_handle_clear_port_feature: 2066184610Salfred if (index != 1) { 2067184610Salfred goto tr_stalled; 2068184610Salfred } 2069184610Salfred DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index); 2070184610Salfred 2071184610Salfred switch (value) { 2072184610Salfred case UHF_PORT_SUSPEND: 2073190735Sthompsa at91dci_wakeup_peer(sc); 2074184610Salfred break; 2075184610Salfred 2076184610Salfred case UHF_PORT_ENABLE: 2077184610Salfred sc->sc_flags.port_enabled = 0; 2078184610Salfred break; 2079184610Salfred 2080184610Salfred case UHF_PORT_TEST: 2081184610Salfred case UHF_PORT_INDICATOR: 2082184610Salfred case UHF_C_PORT_ENABLE: 2083184610Salfred case UHF_C_PORT_OVER_CURRENT: 2084184610Salfred case UHF_C_PORT_RESET: 2085184610Salfred /* nops */ 2086184610Salfred break; 2087184610Salfred case UHF_PORT_POWER: 2088184610Salfred sc->sc_flags.port_powered = 0; 2089184610Salfred at91dci_pull_down(sc); 2090184610Salfred at91dci_clocks_off(sc); 2091184610Salfred break; 2092184610Salfred case UHF_C_PORT_CONNECTION: 2093184610Salfred sc->sc_flags.change_connect = 0; 2094184610Salfred break; 2095184610Salfred case UHF_C_PORT_SUSPEND: 2096184610Salfred sc->sc_flags.change_suspend = 0; 2097184610Salfred break; 2098184610Salfred default: 2099191402Sthompsa err = USB_ERR_IOERROR; 2100184610Salfred goto done; 2101184610Salfred } 2102184610Salfred goto tr_valid; 2103184610Salfred 2104184610Salfredtr_handle_set_port_feature: 2105184610Salfred if (index != 1) { 2106184610Salfred goto tr_stalled; 2107184610Salfred } 2108184610Salfred DPRINTFN(9, "UR_SET_PORT_FEATURE\n"); 2109184610Salfred 2110184610Salfred switch (value) { 2111184610Salfred case UHF_PORT_ENABLE: 2112184610Salfred sc->sc_flags.port_enabled = 1; 2113184610Salfred break; 2114184610Salfred case UHF_PORT_SUSPEND: 2115184610Salfred case UHF_PORT_RESET: 2116184610Salfred case UHF_PORT_TEST: 2117184610Salfred case UHF_PORT_INDICATOR: 2118184610Salfred /* nops */ 2119184610Salfred break; 2120184610Salfred case UHF_PORT_POWER: 2121184610Salfred sc->sc_flags.port_powered = 1; 2122184610Salfred break; 2123184610Salfred default: 2124191402Sthompsa err = USB_ERR_IOERROR; 2125184610Salfred goto done; 2126184610Salfred } 2127184610Salfred goto tr_valid; 2128184610Salfred 2129184610Salfredtr_handle_get_port_status: 2130184610Salfred 2131184610Salfred DPRINTFN(9, "UR_GET_PORT_STATUS\n"); 2132184610Salfred 2133184610Salfred if (index != 1) { 2134184610Salfred goto tr_stalled; 2135184610Salfred } 2136184610Salfred if (sc->sc_flags.status_vbus) { 2137184610Salfred at91dci_clocks_on(sc); 2138184610Salfred at91dci_pull_up(sc); 2139184610Salfred } else { 2140184610Salfred at91dci_pull_down(sc); 2141184610Salfred at91dci_clocks_off(sc); 2142184610Salfred } 2143184610Salfred 2144184610Salfred /* Select FULL-speed and Device Side Mode */ 2145184610Salfred 2146184610Salfred value = UPS_PORT_MODE_DEVICE; 2147184610Salfred 2148184610Salfred if (sc->sc_flags.port_powered) { 2149184610Salfred value |= UPS_PORT_POWER; 2150184610Salfred } 2151184610Salfred if (sc->sc_flags.port_enabled) { 2152184610Salfred value |= UPS_PORT_ENABLED; 2153184610Salfred } 2154184610Salfred if (sc->sc_flags.status_vbus && 2155184610Salfred sc->sc_flags.status_bus_reset) { 2156184610Salfred value |= UPS_CURRENT_CONNECT_STATUS; 2157184610Salfred } 2158184610Salfred if (sc->sc_flags.status_suspend) { 2159184610Salfred value |= UPS_SUSPEND; 2160184610Salfred } 2161184610Salfred USETW(sc->sc_hub_temp.ps.wPortStatus, value); 2162184610Salfred 2163184610Salfred value = 0; 2164184610Salfred 2165184610Salfred if (sc->sc_flags.change_connect) { 2166184610Salfred value |= UPS_C_CONNECT_STATUS; 2167184610Salfred 2168184610Salfred if (sc->sc_flags.status_vbus && 2169184610Salfred sc->sc_flags.status_bus_reset) { 2170184610Salfred /* reset endpoint flags */ 2171227461Shselasky memset(sc->sc_ep_flags, 0, sizeof(sc->sc_ep_flags)); 2172184610Salfred } 2173184610Salfred } 2174184610Salfred if (sc->sc_flags.change_suspend) { 2175184610Salfred value |= UPS_C_SUSPEND; 2176184610Salfred } 2177184610Salfred USETW(sc->sc_hub_temp.ps.wPortChange, value); 2178191402Sthompsa len = sizeof(sc->sc_hub_temp.ps); 2179184610Salfred goto tr_valid; 2180184610Salfred 2181184610Salfredtr_handle_get_class_descriptor: 2182184610Salfred if (value & 0xFF) { 2183184610Salfred goto tr_stalled; 2184184610Salfred } 2185191402Sthompsa ptr = (const void *)&at91dci_hubd; 2186191402Sthompsa len = sizeof(at91dci_hubd); 2187184610Salfred goto tr_valid; 2188184610Salfred 2189184610Salfredtr_stalled: 2190191402Sthompsa err = USB_ERR_STALLED; 2191184610Salfredtr_valid: 2192184610Salfreddone: 2193191402Sthompsa *plength = len; 2194191402Sthompsa *pptr = ptr; 2195191402Sthompsa return (err); 2196184610Salfred} 2197184610Salfred 2198184610Salfredstatic void 2199192984Sthompsaat91dci_xfer_setup(struct usb_setup_params *parm) 2200184610Salfred{ 2201192984Sthompsa const struct usb_hw_ep_profile *pf; 2202184610Salfred struct at91dci_softc *sc; 2203192984Sthompsa struct usb_xfer *xfer; 2204184610Salfred void *last_obj; 2205184610Salfred uint32_t ntd; 2206184610Salfred uint32_t n; 2207184610Salfred uint8_t ep_no; 2208184610Salfred 2209184610Salfred sc = AT9100_DCI_BUS2SC(parm->udev->bus); 2210184610Salfred xfer = parm->curr_xfer; 2211184610Salfred 2212184610Salfred /* 2213184610Salfred * NOTE: This driver does not use any of the parameters that 2214184610Salfred * are computed from the following values. Just set some 2215184610Salfred * reasonable dummies: 2216184610Salfred */ 2217184610Salfred parm->hc_max_packet_size = 0x500; 2218184610Salfred parm->hc_max_packet_count = 1; 2219184610Salfred parm->hc_max_frame_size = 0x500; 2220184610Salfred 2221194228Sthompsa usbd_transfer_setup_sub(parm); 2222184610Salfred 2223184610Salfred /* 2224184610Salfred * compute maximum number of TDs 2225184610Salfred */ 2226184610Salfred if (parm->methods == &at91dci_device_ctrl_methods) { 2227184610Salfred 2228184610Salfred ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */ 2229184610Salfred + 1 /* SYNC 2 */ ; 2230184610Salfred 2231184610Salfred } else if (parm->methods == &at91dci_device_bulk_methods) { 2232184610Salfred 2233184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2234184610Salfred 2235184610Salfred } else if (parm->methods == &at91dci_device_intr_methods) { 2236184610Salfred 2237184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2238184610Salfred 2239184610Salfred } else if (parm->methods == &at91dci_device_isoc_fs_methods) { 2240184610Salfred 2241184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2242184610Salfred 2243184610Salfred } else { 2244184610Salfred 2245184610Salfred ntd = 0; 2246184610Salfred } 2247184610Salfred 2248184610Salfred /* 2249194228Sthompsa * check if "usbd_transfer_setup_sub" set an error 2250184610Salfred */ 2251184610Salfred if (parm->err) { 2252184610Salfred return; 2253184610Salfred } 2254184610Salfred /* 2255184610Salfred * allocate transfer descriptors 2256184610Salfred */ 2257184610Salfred last_obj = NULL; 2258184610Salfred 2259184610Salfred /* 2260184610Salfred * get profile stuff 2261184610Salfred */ 2262184610Salfred if (ntd) { 2263184610Salfred 2264193644Sthompsa ep_no = xfer->endpointno & UE_ADDR; 2265184610Salfred at91dci_get_hw_ep_profile(parm->udev, &pf, ep_no); 2266184610Salfred 2267184610Salfred if (pf == NULL) { 2268184610Salfred /* should not happen */ 2269184610Salfred parm->err = USB_ERR_INVAL; 2270184610Salfred return; 2271184610Salfred } 2272184610Salfred } else { 2273184610Salfred ep_no = 0; 2274184610Salfred pf = NULL; 2275184610Salfred } 2276184610Salfred 2277184610Salfred /* align data */ 2278184610Salfred parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); 2279184610Salfred 2280184610Salfred for (n = 0; n != ntd; n++) { 2281184610Salfred 2282184610Salfred struct at91dci_td *td; 2283184610Salfred 2284184610Salfred if (parm->buf) { 2285184610Salfred 2286184610Salfred td = USB_ADD_BYTES(parm->buf, parm->size[0]); 2287184610Salfred 2288184610Salfred /* init TD */ 2289184610Salfred td->max_packet_size = xfer->max_packet_size; 2290184610Salfred td->status_reg = AT91_UDP_CSR(ep_no); 2291184610Salfred td->fifo_reg = AT91_UDP_FDR(ep_no); 2292184610Salfred if (pf->support_multi_buffer) { 2293184610Salfred td->support_multi_buffer = 1; 2294184610Salfred } 2295184610Salfred td->obj_next = last_obj; 2296184610Salfred 2297184610Salfred last_obj = td; 2298184610Salfred } 2299184610Salfred parm->size[0] += sizeof(*td); 2300184610Salfred } 2301184610Salfred 2302184610Salfred xfer->td_start[0] = last_obj; 2303184610Salfred} 2304184610Salfred 2305184610Salfredstatic void 2306192984Sthompsaat91dci_xfer_unsetup(struct usb_xfer *xfer) 2307184610Salfred{ 2308184610Salfred return; 2309184610Salfred} 2310184610Salfred 2311184610Salfredstatic void 2312193644Sthompsaat91dci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, 2313193644Sthompsa struct usb_endpoint *ep) 2314184610Salfred{ 2315184610Salfred struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus); 2316184610Salfred 2317193644Sthompsa DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n", 2318193644Sthompsa ep, udev->address, 2319192499Sthompsa edesc->bEndpointAddress, udev->flags.usb_mode, 2320184610Salfred sc->sc_rt_addr); 2321184610Salfred 2322190735Sthompsa if (udev->device_index != sc->sc_rt_addr) { 2323184610Salfred 2324184610Salfred if (udev->speed != USB_SPEED_FULL) { 2325184610Salfred /* not supported */ 2326184610Salfred return; 2327184610Salfred } 2328184610Salfred switch (edesc->bmAttributes & UE_XFERTYPE) { 2329184610Salfred case UE_CONTROL: 2330193644Sthompsa ep->methods = &at91dci_device_ctrl_methods; 2331184610Salfred break; 2332184610Salfred case UE_INTERRUPT: 2333193644Sthompsa ep->methods = &at91dci_device_intr_methods; 2334184610Salfred break; 2335184610Salfred case UE_ISOCHRONOUS: 2336193644Sthompsa ep->methods = &at91dci_device_isoc_fs_methods; 2337184610Salfred break; 2338184610Salfred case UE_BULK: 2339193644Sthompsa ep->methods = &at91dci_device_bulk_methods; 2340184610Salfred break; 2341184610Salfred default: 2342184610Salfred /* do nothing */ 2343184610Salfred break; 2344184610Salfred } 2345184610Salfred } 2346184610Salfred} 2347184610Salfred 2348228483Shselaskystatic void 2349228483Shselaskyat91dci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) 2350228483Shselasky{ 2351228483Shselasky struct at91dci_softc *sc = AT9100_DCI_BUS2SC(bus); 2352228483Shselasky 2353228483Shselasky switch (state) { 2354228483Shselasky case USB_HW_POWER_SUSPEND: 2355228483Shselasky at91dci_suspend(sc); 2356228483Shselasky break; 2357228483Shselasky case USB_HW_POWER_SHUTDOWN: 2358228483Shselasky at91dci_uninit(sc); 2359228483Shselasky break; 2360228483Shselasky case USB_HW_POWER_RESUME: 2361228483Shselasky at91dci_resume(sc); 2362228483Shselasky break; 2363228483Shselasky default: 2364228483Shselasky break; 2365228483Shselasky } 2366228483Shselasky} 2367228483Shselasky 2368259218Shselaskystatic const struct usb_bus_methods at91dci_bus_methods = 2369184610Salfred{ 2370193644Sthompsa .endpoint_init = &at91dci_ep_init, 2371184610Salfred .xfer_setup = &at91dci_xfer_setup, 2372184610Salfred .xfer_unsetup = &at91dci_xfer_unsetup, 2373184610Salfred .get_hw_ep_profile = &at91dci_get_hw_ep_profile, 2374184610Salfred .set_stall = &at91dci_set_stall, 2375239214Shselasky .xfer_stall = &at91dci_xfer_stall, 2376184610Salfred .clear_stall = &at91dci_clear_stall, 2377190735Sthompsa .roothub_exec = &at91dci_roothub_exec, 2378195960Salfred .xfer_poll = &at91dci_do_poll, 2379228483Shselasky .set_hw_power_sleep = &at91dci_set_hw_power_sleep, 2380184610Salfred}; 2381