1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD$"); 3184610Salfred 4184610Salfred/*- 5184610Salfred * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved. 6184610Salfred * 7184610Salfred * Redistribution and use in source and binary forms, with or without 8184610Salfred * modification, are permitted provided that the following conditions 9184610Salfred * are met: 10184610Salfred * 1. Redistributions of source code must retain the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer. 12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer in the 14184610Salfred * documentation and/or other materials provided with the distribution. 15184610Salfred * 16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26184610Salfred * SUCH DAMAGE. 27184610Salfred */ 28184610Salfred 29184610Salfred/* 30184610Salfred * This file contains the driver for the AT91 series USB Device 31184610Salfred * Controller 32184610Salfred */ 33184610Salfred 34184610Salfred/* 35184610Salfred * Thanks to "David Brownell" for helping out regarding the hardware 36184610Salfred * endpoint profiles. 37184610Salfred */ 38184610Salfred 39184610Salfred/* 40184610Salfred * NOTE: The "fifo_bank" is not reset in hardware when the endpoint is 41190754Sthompsa * reset. 42184610Salfred * 43184610Salfred * NOTE: When the chip detects BUS-reset it will also reset the 44184610Salfred * endpoints, Function-address and more. 45184610Salfred */ 46184610Salfred 47194677Sthompsa#include <sys/stdint.h> 48194677Sthompsa#include <sys/stddef.h> 49194677Sthompsa#include <sys/param.h> 50194677Sthompsa#include <sys/queue.h> 51194677Sthompsa#include <sys/types.h> 52194677Sthompsa#include <sys/systm.h> 53194677Sthompsa#include <sys/kernel.h> 54194677Sthompsa#include <sys/bus.h> 55194677Sthompsa#include <sys/module.h> 56194677Sthompsa#include <sys/lock.h> 57194677Sthompsa#include <sys/mutex.h> 58194677Sthompsa#include <sys/condvar.h> 59194677Sthompsa#include <sys/sysctl.h> 60194677Sthompsa#include <sys/sx.h> 61194677Sthompsa#include <sys/unistd.h> 62194677Sthompsa#include <sys/callout.h> 63194677Sthompsa#include <sys/malloc.h> 64194677Sthompsa#include <sys/priv.h> 65194677Sthompsa 66188942Sthompsa#include <dev/usb/usb.h> 67194677Sthompsa#include <dev/usb/usbdi.h> 68184610Salfred 69184610Salfred#define USB_DEBUG_VAR at91dcidebug 70184610Salfred 71188942Sthompsa#include <dev/usb/usb_core.h> 72188942Sthompsa#include <dev/usb/usb_debug.h> 73188942Sthompsa#include <dev/usb/usb_busdma.h> 74188942Sthompsa#include <dev/usb/usb_process.h> 75188942Sthompsa#include <dev/usb/usb_transfer.h> 76188942Sthompsa#include <dev/usb/usb_device.h> 77188942Sthompsa#include <dev/usb/usb_hub.h> 78188942Sthompsa#include <dev/usb/usb_util.h> 79184610Salfred 80188942Sthompsa#include <dev/usb/usb_controller.h> 81188942Sthompsa#include <dev/usb/usb_bus.h> 82188942Sthompsa#include <dev/usb/controller/at91dci.h> 83184610Salfred 84184610Salfred#define AT9100_DCI_BUS2SC(bus) \ 85184610Salfred ((struct at91dci_softc *)(((uint8_t *)(bus)) - \ 86190181Sthompsa ((uint8_t *)&(((struct at91dci_softc *)0)->sc_bus)))) 87184610Salfred 88184610Salfred#define AT9100_DCI_PC2SC(pc) \ 89190180Sthompsa AT9100_DCI_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus) 90184610Salfred 91194677Sthompsa#ifdef USB_DEBUG 92184610Salfredstatic int at91dcidebug = 0; 93184610Salfred 94248085Smariusstatic SYSCTL_NODE(_hw_usb, OID_AUTO, at91dci, CTLFLAG_RW, 0, "USB at91dci"); 95192502SthompsaSYSCTL_INT(_hw_usb_at91dci, OID_AUTO, debug, CTLFLAG_RW, 96184610Salfred &at91dcidebug, 0, "at91dci debug level"); 97184610Salfred#endif 98184610Salfred 99184610Salfred#define AT9100_DCI_INTR_ENDPT 1 100184610Salfred 101184610Salfred/* prototypes */ 102184610Salfred 103192984Sthompsastruct usb_bus_methods at91dci_bus_methods; 104192984Sthompsastruct usb_pipe_methods at91dci_device_bulk_methods; 105192984Sthompsastruct usb_pipe_methods at91dci_device_ctrl_methods; 106192984Sthompsastruct usb_pipe_methods at91dci_device_intr_methods; 107192984Sthompsastruct usb_pipe_methods at91dci_device_isoc_fs_methods; 108184610Salfred 109184610Salfredstatic at91dci_cmd_t at91dci_setup_rx; 110184610Salfredstatic at91dci_cmd_t at91dci_data_rx; 111184610Salfredstatic at91dci_cmd_t at91dci_data_tx; 112184610Salfredstatic at91dci_cmd_t at91dci_data_tx_sync; 113193045Sthompsastatic void at91dci_device_done(struct usb_xfer *, usb_error_t); 114192984Sthompsastatic void at91dci_do_poll(struct usb_bus *); 115192984Sthompsastatic void at91dci_standard_done(struct usb_xfer *); 116190735Sthompsastatic void at91dci_root_intr(struct at91dci_softc *sc); 117184610Salfred 118184610Salfred/* 119184610Salfred * NOTE: Some of the bits in the CSR register have inverse meaning so 120184610Salfred * we need a helper macro when acknowledging events: 121184610Salfred */ 122184610Salfred#define AT91_CSR_ACK(csr, what) do { \ 123184610Salfred (csr) &= ~((AT91_UDP_CSR_FORCESTALL| \ 124184610Salfred AT91_UDP_CSR_TXPKTRDY| \ 125184610Salfred AT91_UDP_CSR_RXBYTECNT) ^ (what));\ 126184610Salfred (csr) |= ((AT91_UDP_CSR_RX_DATA_BK0| \ 127184610Salfred AT91_UDP_CSR_RX_DATA_BK1| \ 128184610Salfred AT91_UDP_CSR_TXCOMP| \ 129184610Salfred AT91_UDP_CSR_RXSETUP| \ 130184610Salfred AT91_UDP_CSR_STALLSENT) ^ (what)); \ 131184610Salfred} while (0) 132184610Salfred 133184610Salfred/* 134184610Salfred * Here is a list of what the chip supports. 135184610Salfred * Probably it supports more than listed here! 136184610Salfred */ 137192984Sthompsastatic const struct usb_hw_ep_profile 138184610Salfred at91dci_ep_profile[AT91_UDP_EP_MAX] = { 139184610Salfred 140184610Salfred [0] = { 141184610Salfred .max_in_frame_size = 8, 142184610Salfred .max_out_frame_size = 8, 143184610Salfred .is_simplex = 1, 144184610Salfred .support_control = 1, 145184610Salfred }, 146184610Salfred [1] = { 147184610Salfred .max_in_frame_size = 64, 148184610Salfred .max_out_frame_size = 64, 149184610Salfred .is_simplex = 1, 150184610Salfred .support_multi_buffer = 1, 151184610Salfred .support_bulk = 1, 152184610Salfred .support_interrupt = 1, 153184610Salfred .support_isochronous = 1, 154184610Salfred .support_in = 1, 155184610Salfred .support_out = 1, 156184610Salfred }, 157184610Salfred [2] = { 158184610Salfred .max_in_frame_size = 64, 159184610Salfred .max_out_frame_size = 64, 160184610Salfred .is_simplex = 1, 161184610Salfred .support_multi_buffer = 1, 162184610Salfred .support_bulk = 1, 163184610Salfred .support_interrupt = 1, 164184610Salfred .support_isochronous = 1, 165184610Salfred .support_in = 1, 166184610Salfred .support_out = 1, 167184610Salfred }, 168184610Salfred [3] = { 169184610Salfred /* can also do BULK */ 170184610Salfred .max_in_frame_size = 8, 171184610Salfred .max_out_frame_size = 8, 172184610Salfred .is_simplex = 1, 173184610Salfred .support_interrupt = 1, 174184610Salfred .support_in = 1, 175184610Salfred .support_out = 1, 176184610Salfred }, 177184610Salfred [4] = { 178184610Salfred .max_in_frame_size = 256, 179184610Salfred .max_out_frame_size = 256, 180184610Salfred .is_simplex = 1, 181184610Salfred .support_multi_buffer = 1, 182184610Salfred .support_bulk = 1, 183184610Salfred .support_interrupt = 1, 184184610Salfred .support_isochronous = 1, 185184610Salfred .support_in = 1, 186184610Salfred .support_out = 1, 187184610Salfred }, 188184610Salfred [5] = { 189184610Salfred .max_in_frame_size = 256, 190184610Salfred .max_out_frame_size = 256, 191184610Salfred .is_simplex = 1, 192184610Salfred .support_multi_buffer = 1, 193184610Salfred .support_bulk = 1, 194184610Salfred .support_interrupt = 1, 195184610Salfred .support_isochronous = 1, 196184610Salfred .support_in = 1, 197184610Salfred .support_out = 1, 198184610Salfred }, 199184610Salfred}; 200184610Salfred 201184610Salfredstatic void 202192984Sthompsaat91dci_get_hw_ep_profile(struct usb_device *udev, 203192984Sthompsa const struct usb_hw_ep_profile **ppf, uint8_t ep_addr) 204184610Salfred{ 205184610Salfred if (ep_addr < AT91_UDP_EP_MAX) { 206184610Salfred *ppf = (at91dci_ep_profile + ep_addr); 207184610Salfred } else { 208184610Salfred *ppf = NULL; 209184610Salfred } 210184610Salfred} 211184610Salfred 212184610Salfredstatic void 213184610Salfredat91dci_clocks_on(struct at91dci_softc *sc) 214184610Salfred{ 215184610Salfred if (sc->sc_flags.clocks_off && 216184610Salfred sc->sc_flags.port_powered) { 217184610Salfred 218184610Salfred DPRINTFN(5, "\n"); 219184610Salfred 220184610Salfred if (sc->sc_clocks_on) { 221184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 222184610Salfred } 223184610Salfred sc->sc_flags.clocks_off = 0; 224184610Salfred 225184610Salfred /* enable Transceiver */ 226184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, 0); 227184610Salfred } 228184610Salfred} 229184610Salfred 230184610Salfredstatic void 231184610Salfredat91dci_clocks_off(struct at91dci_softc *sc) 232184610Salfred{ 233184610Salfred if (!sc->sc_flags.clocks_off) { 234184610Salfred 235184610Salfred DPRINTFN(5, "\n"); 236184610Salfred 237184610Salfred /* disable Transceiver */ 238184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); 239184610Salfred 240184610Salfred if (sc->sc_clocks_off) { 241184610Salfred (sc->sc_clocks_off) (sc->sc_clocks_arg); 242184610Salfred } 243184610Salfred sc->sc_flags.clocks_off = 1; 244184610Salfred } 245184610Salfred} 246184610Salfred 247184610Salfredstatic void 248184610Salfredat91dci_pull_up(struct at91dci_softc *sc) 249184610Salfred{ 250184610Salfred /* pullup D+, if possible */ 251184610Salfred 252184610Salfred if (!sc->sc_flags.d_pulled_up && 253184610Salfred sc->sc_flags.port_powered) { 254184610Salfred sc->sc_flags.d_pulled_up = 1; 255184610Salfred (sc->sc_pull_up) (sc->sc_pull_arg); 256184610Salfred } 257184610Salfred} 258184610Salfred 259184610Salfredstatic void 260184610Salfredat91dci_pull_down(struct at91dci_softc *sc) 261184610Salfred{ 262184610Salfred /* pulldown D+, if possible */ 263184610Salfred 264184610Salfred if (sc->sc_flags.d_pulled_up) { 265184610Salfred sc->sc_flags.d_pulled_up = 0; 266184610Salfred (sc->sc_pull_down) (sc->sc_pull_arg); 267184610Salfred } 268184610Salfred} 269184610Salfred 270184610Salfredstatic void 271190735Sthompsaat91dci_wakeup_peer(struct at91dci_softc *sc) 272184610Salfred{ 273184610Salfred if (!(sc->sc_flags.status_suspend)) { 274184610Salfred return; 275184610Salfred } 276184610Salfred 277186730Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, AT91_UDP_GSTATE_ESR); 278184610Salfred 279186730Salfred /* wait 8 milliseconds */ 280188983Sthompsa /* Wait for reset to complete. */ 281194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); 282184610Salfred 283186730Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, 0); 284184610Salfred} 285184610Salfred 286184610Salfredstatic void 287184610Salfredat91dci_set_address(struct at91dci_softc *sc, uint8_t addr) 288184610Salfred{ 289184610Salfred DPRINTFN(5, "addr=%d\n", addr); 290184610Salfred 291184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, addr | 292184610Salfred AT91_UDP_FADDR_EN); 293184610Salfred} 294184610Salfred 295184610Salfredstatic uint8_t 296184610Salfredat91dci_setup_rx(struct at91dci_td *td) 297184610Salfred{ 298184610Salfred struct at91dci_softc *sc; 299192984Sthompsa struct usb_device_request req; 300184610Salfred uint32_t csr; 301184610Salfred uint32_t temp; 302184610Salfred uint16_t count; 303184610Salfred 304184610Salfred /* read out FIFO status */ 305184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 306184610Salfred td->status_reg); 307184610Salfred 308184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 309184610Salfred 310184610Salfred temp = csr; 311184610Salfred temp &= (AT91_UDP_CSR_RX_DATA_BK0 | 312184610Salfred AT91_UDP_CSR_RX_DATA_BK1 | 313184610Salfred AT91_UDP_CSR_STALLSENT | 314184610Salfred AT91_UDP_CSR_RXSETUP | 315184610Salfred AT91_UDP_CSR_TXCOMP); 316184610Salfred 317184610Salfred if (!(csr & AT91_UDP_CSR_RXSETUP)) { 318184610Salfred goto not_complete; 319184610Salfred } 320190721Sthompsa /* clear did stall */ 321190721Sthompsa td->did_stall = 0; 322190721Sthompsa 323184610Salfred /* get the packet byte count */ 324184610Salfred count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; 325184610Salfred 326184610Salfred /* verify data length */ 327184610Salfred if (count != td->remainder) { 328184610Salfred DPRINTFN(0, "Invalid SETUP packet " 329184610Salfred "length, %d bytes\n", count); 330184610Salfred goto not_complete; 331184610Salfred } 332184610Salfred if (count != sizeof(req)) { 333184610Salfred DPRINTFN(0, "Unsupported SETUP packet " 334184610Salfred "length, %d bytes\n", count); 335184610Salfred goto not_complete; 336184610Salfred } 337184610Salfred /* receive data */ 338184610Salfred bus_space_read_multi_1(td->io_tag, td->io_hdl, 339184610Salfred td->fifo_reg, (void *)&req, sizeof(req)); 340184610Salfred 341184610Salfred /* copy data into real buffer */ 342194228Sthompsa usbd_copy_in(td->pc, 0, &req, sizeof(req)); 343184610Salfred 344184610Salfred td->offset = sizeof(req); 345184610Salfred td->remainder = 0; 346184610Salfred 347184610Salfred /* get pointer to softc */ 348184610Salfred sc = AT9100_DCI_PC2SC(td->pc); 349184610Salfred 350184610Salfred /* sneak peek the set address */ 351184610Salfred if ((req.bmRequestType == UT_WRITE_DEVICE) && 352184610Salfred (req.bRequest == UR_SET_ADDRESS)) { 353184610Salfred sc->sc_dv_addr = req.wValue[0] & 0x7F; 354184610Salfred } else { 355184610Salfred sc->sc_dv_addr = 0xFF; 356184610Salfred } 357184610Salfred 358184610Salfred /* sneak peek the endpoint direction */ 359184610Salfred if (req.bmRequestType & UE_DIR_IN) { 360184610Salfred csr |= AT91_UDP_CSR_DIR; 361184610Salfred } else { 362184610Salfred csr &= ~AT91_UDP_CSR_DIR; 363184610Salfred } 364184610Salfred 365184610Salfred /* write the direction of the control transfer */ 366184610Salfred AT91_CSR_ACK(csr, temp); 367184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 368184610Salfred 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); 383184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 384184610Salfred td->status_reg, csr); 385184610Salfred } 386184610Salfred return (1); /* not complete */ 387184610Salfred 388184610Salfred} 389184610Salfred 390184610Salfredstatic uint8_t 391184610Salfredat91dci_data_rx(struct at91dci_td *td) 392184610Salfred{ 393192984Sthompsa struct usb_page_search buf_res; 394184610Salfred uint32_t csr; 395184610Salfred uint32_t temp; 396184610Salfred uint16_t count; 397184610Salfred uint8_t to; 398184610Salfred uint8_t got_short; 399184610Salfred 400184610Salfred to = 2; /* don't loop forever! */ 401184610Salfred got_short = 0; 402184610Salfred 403184610Salfred /* check if any of the FIFO banks have data */ 404184610Salfredrepeat: 405184610Salfred /* read out FIFO status */ 406184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 407184610Salfred td->status_reg); 408184610Salfred 409184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 410184610Salfred 411184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 412184610Salfred if (td->remainder == 0) { 413184610Salfred /* 414184610Salfred * We are actually complete and have 415184610Salfred * received the next SETUP 416184610Salfred */ 417184610Salfred DPRINTFN(5, "faking complete\n"); 418184610Salfred return (0); /* complete */ 419184610Salfred } 420184610Salfred /* 421184610Salfred * USB Host Aborted the transfer. 422184610Salfred */ 423184610Salfred td->error = 1; 424184610Salfred return (0); /* complete */ 425184610Salfred } 426184610Salfred /* Make sure that "STALLSENT" gets cleared */ 427184610Salfred temp = csr; 428184610Salfred temp &= AT91_UDP_CSR_STALLSENT; 429184610Salfred 430184610Salfred /* check status */ 431184610Salfred if (!(csr & (AT91_UDP_CSR_RX_DATA_BK0 | 432184610Salfred AT91_UDP_CSR_RX_DATA_BK1))) { 433184610Salfred if (temp) { 434184610Salfred /* write command */ 435184610Salfred AT91_CSR_ACK(csr, temp); 436184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 437184610Salfred td->status_reg, csr); 438184610Salfred } 439184610Salfred return (1); /* not complete */ 440184610Salfred } 441184610Salfred /* get the packet byte count */ 442184610Salfred count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; 443184610Salfred 444184610Salfred /* verify the packet byte count */ 445184610Salfred if (count != td->max_packet_size) { 446184610Salfred if (count < td->max_packet_size) { 447184610Salfred /* we have a short packet */ 448184610Salfred td->short_pkt = 1; 449184610Salfred got_short = 1; 450184610Salfred } else { 451184610Salfred /* invalid USB packet */ 452184610Salfred td->error = 1; 453184610Salfred return (0); /* we are complete */ 454184610Salfred } 455184610Salfred } 456184610Salfred /* verify the packet byte count */ 457184610Salfred if (count > td->remainder) { 458184610Salfred /* invalid USB packet */ 459184610Salfred td->error = 1; 460184610Salfred return (0); /* we are complete */ 461184610Salfred } 462184610Salfred while (count > 0) { 463194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 464184610Salfred 465184610Salfred /* get correct length */ 466184610Salfred if (buf_res.length > count) { 467184610Salfred buf_res.length = count; 468184610Salfred } 469184610Salfred /* receive data */ 470184610Salfred bus_space_read_multi_1(td->io_tag, td->io_hdl, 471184610Salfred td->fifo_reg, buf_res.buffer, buf_res.length); 472184610Salfred 473184610Salfred /* update counters */ 474184610Salfred count -= buf_res.length; 475184610Salfred td->offset += buf_res.length; 476184610Salfred td->remainder -= buf_res.length; 477184610Salfred } 478184610Salfred 479184610Salfred /* clear status bits */ 480184610Salfred if (td->support_multi_buffer) { 481184610Salfred if (td->fifo_bank) { 482184610Salfred td->fifo_bank = 0; 483184610Salfred temp |= AT91_UDP_CSR_RX_DATA_BK1; 484184610Salfred } else { 485184610Salfred td->fifo_bank = 1; 486184610Salfred temp |= AT91_UDP_CSR_RX_DATA_BK0; 487184610Salfred } 488184610Salfred } else { 489184610Salfred temp |= (AT91_UDP_CSR_RX_DATA_BK0 | 490184610Salfred AT91_UDP_CSR_RX_DATA_BK1); 491184610Salfred } 492184610Salfred 493184610Salfred /* write command */ 494184610Salfred AT91_CSR_ACK(csr, temp); 495184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 496184610Salfred td->status_reg, csr); 497184610Salfred 498184610Salfred /* 499184610Salfred * NOTE: We may have to delay a little bit before 500184610Salfred * proceeding after clearing the DATA_BK bits. 501184610Salfred */ 502184610Salfred 503184610Salfred /* check if we are complete */ 504184610Salfred if ((td->remainder == 0) || got_short) { 505184610Salfred if (td->short_pkt) { 506184610Salfred /* we are complete */ 507184610Salfred return (0); 508184610Salfred } 509184610Salfred /* else need to receive a zero length packet */ 510184610Salfred } 511184610Salfred if (--to) { 512184610Salfred goto repeat; 513184610Salfred } 514184610Salfred return (1); /* not complete */ 515184610Salfred} 516184610Salfred 517184610Salfredstatic uint8_t 518184610Salfredat91dci_data_tx(struct at91dci_td *td) 519184610Salfred{ 520192984Sthompsa struct usb_page_search buf_res; 521184610Salfred uint32_t csr; 522184610Salfred uint32_t temp; 523184610Salfred uint16_t count; 524184610Salfred uint8_t to; 525184610Salfred 526184610Salfred to = 2; /* don't loop forever! */ 527184610Salfred 528184610Salfredrepeat: 529184610Salfred 530184610Salfred /* read out FIFO status */ 531184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 532184610Salfred td->status_reg); 533184610Salfred 534184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 535184610Salfred 536184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 537184610Salfred /* 538184610Salfred * The current transfer was aborted 539184610Salfred * by the USB Host 540184610Salfred */ 541184610Salfred td->error = 1; 542184610Salfred return (0); /* complete */ 543184610Salfred } 544184610Salfred /* Make sure that "STALLSENT" gets cleared */ 545184610Salfred temp = csr; 546184610Salfred temp &= AT91_UDP_CSR_STALLSENT; 547184610Salfred 548184610Salfred if (csr & AT91_UDP_CSR_TXPKTRDY) { 549184610Salfred if (temp) { 550184610Salfred /* write command */ 551184610Salfred AT91_CSR_ACK(csr, temp); 552184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 553184610Salfred td->status_reg, csr); 554184610Salfred } 555184610Salfred return (1); /* not complete */ 556184610Salfred } else { 557184610Salfred /* clear TXCOMP and set TXPKTRDY */ 558184610Salfred temp |= (AT91_UDP_CSR_TXCOMP | 559184610Salfred AT91_UDP_CSR_TXPKTRDY); 560184610Salfred } 561184610Salfred 562184610Salfred count = td->max_packet_size; 563184610Salfred if (td->remainder < count) { 564184610Salfred /* we have a short packet */ 565184610Salfred td->short_pkt = 1; 566184610Salfred count = td->remainder; 567184610Salfred } 568184610Salfred while (count > 0) { 569184610Salfred 570194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 571184610Salfred 572184610Salfred /* get correct length */ 573184610Salfred if (buf_res.length > count) { 574184610Salfred buf_res.length = count; 575184610Salfred } 576184610Salfred /* transmit data */ 577184610Salfred bus_space_write_multi_1(td->io_tag, td->io_hdl, 578184610Salfred td->fifo_reg, buf_res.buffer, buf_res.length); 579184610Salfred 580184610Salfred /* update counters */ 581184610Salfred count -= buf_res.length; 582184610Salfred td->offset += buf_res.length; 583184610Salfred td->remainder -= buf_res.length; 584184610Salfred } 585184610Salfred 586184610Salfred /* write command */ 587184610Salfred AT91_CSR_ACK(csr, temp); 588184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 589184610Salfred td->status_reg, csr); 590184610Salfred 591184610Salfred /* check remainder */ 592184610Salfred if (td->remainder == 0) { 593184610Salfred if (td->short_pkt) { 594184610Salfred return (0); /* complete */ 595184610Salfred } 596184610Salfred /* else we need to transmit a short packet */ 597184610Salfred } 598184610Salfred if (--to) { 599184610Salfred goto repeat; 600184610Salfred } 601184610Salfred return (1); /* not complete */ 602184610Salfred} 603184610Salfred 604184610Salfredstatic uint8_t 605184610Salfredat91dci_data_tx_sync(struct at91dci_td *td) 606184610Salfred{ 607184610Salfred struct at91dci_softc *sc; 608184610Salfred uint32_t csr; 609184610Salfred uint32_t temp; 610184610Salfred 611184610Salfred#if 0 612184610Salfredrepeat: 613184610Salfred#endif 614184610Salfred 615184610Salfred /* read out FIFO status */ 616184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 617184610Salfred td->status_reg); 618184610Salfred 619184610Salfred DPRINTFN(5, "csr=0x%08x\n", csr); 620184610Salfred 621184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 622184610Salfred DPRINTFN(5, "faking complete\n"); 623184610Salfred /* Race condition */ 624184610Salfred return (0); /* complete */ 625184610Salfred } 626184610Salfred temp = csr; 627184610Salfred temp &= (AT91_UDP_CSR_STALLSENT | 628184610Salfred AT91_UDP_CSR_TXCOMP); 629184610Salfred 630184610Salfred /* check status */ 631184610Salfred if (csr & AT91_UDP_CSR_TXPKTRDY) { 632184610Salfred goto not_complete; 633184610Salfred } 634184610Salfred if (!(csr & AT91_UDP_CSR_TXCOMP)) { 635184610Salfred goto not_complete; 636184610Salfred } 637184610Salfred sc = AT9100_DCI_PC2SC(td->pc); 638184610Salfred if (sc->sc_dv_addr != 0xFF) { 639184610Salfred /* 640184610Salfred * The AT91 has a special requirement with regard to 641184610Salfred * setting the address and that is to write the new 642184610Salfred * address before clearing TXCOMP: 643184610Salfred */ 644184610Salfred at91dci_set_address(sc, sc->sc_dv_addr); 645184610Salfred } 646184610Salfred /* write command */ 647184610Salfred AT91_CSR_ACK(csr, temp); 648184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 649184610Salfred td->status_reg, csr); 650184610Salfred 651184610Salfred return (0); /* complete */ 652184610Salfred 653184610Salfrednot_complete: 654184610Salfred if (temp) { 655184610Salfred /* write command */ 656184610Salfred AT91_CSR_ACK(csr, temp); 657184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 658184610Salfred td->status_reg, csr); 659184610Salfred } 660184610Salfred return (1); /* not complete */ 661184610Salfred} 662184610Salfred 663184610Salfredstatic uint8_t 664192984Sthompsaat91dci_xfer_do_fifo(struct usb_xfer *xfer) 665184610Salfred{ 666184610Salfred struct at91dci_softc *sc; 667184610Salfred struct at91dci_td *td; 668184610Salfred uint8_t temp; 669184610Salfred 670184610Salfred DPRINTFN(9, "\n"); 671184610Salfred 672184610Salfred td = xfer->td_transfer_cache; 673184610Salfred while (1) { 674184610Salfred if ((td->func) (td)) { 675184610Salfred /* operation in progress */ 676184610Salfred break; 677184610Salfred } 678184610Salfred if (((void *)td) == xfer->td_transfer_last) { 679184610Salfred goto done; 680184610Salfred } 681184610Salfred if (td->error) { 682184610Salfred goto done; 683184610Salfred } else if (td->remainder > 0) { 684184610Salfred /* 685184610Salfred * We had a short transfer. If there is no alternate 686184610Salfred * next, stop processing ! 687184610Salfred */ 688184610Salfred if (!td->alt_next) { 689184610Salfred goto done; 690184610Salfred } 691184610Salfred } 692184610Salfred /* 693184610Salfred * Fetch the next transfer descriptor and transfer 694184610Salfred * some flags to the next transfer descriptor 695184610Salfred */ 696184610Salfred temp = 0; 697184610Salfred if (td->fifo_bank) 698184610Salfred temp |= 1; 699184610Salfred td = td->obj_next; 700184610Salfred xfer->td_transfer_cache = td; 701184610Salfred if (temp & 1) 702184610Salfred td->fifo_bank = 1; 703184610Salfred } 704184610Salfred return (1); /* not complete */ 705184610Salfred 706184610Salfreddone: 707187173Sthompsa sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 708193644Sthompsa temp = (xfer->endpointno & UE_ADDR); 709184610Salfred 710184610Salfred /* update FIFO bank flag and multi buffer */ 711184610Salfred if (td->fifo_bank) { 712184610Salfred sc->sc_ep_flags[temp].fifo_bank = 1; 713184610Salfred } else { 714184610Salfred sc->sc_ep_flags[temp].fifo_bank = 0; 715184610Salfred } 716184610Salfred 717184610Salfred /* compute all actual lengths */ 718184610Salfred 719184610Salfred at91dci_standard_done(xfer); 720184610Salfred 721184610Salfred return (0); /* complete */ 722184610Salfred} 723184610Salfred 724184610Salfredstatic void 725184610Salfredat91dci_interrupt_poll(struct at91dci_softc *sc) 726184610Salfred{ 727192984Sthompsa struct usb_xfer *xfer; 728184610Salfred 729184610Salfredrepeat: 730184610Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 731184610Salfred if (!at91dci_xfer_do_fifo(xfer)) { 732184610Salfred /* queue has been modified */ 733184610Salfred goto repeat; 734184610Salfred } 735184610Salfred } 736184610Salfred} 737184610Salfred 738187175Sthompsavoid 739187175Sthompsaat91dci_vbus_interrupt(struct at91dci_softc *sc, uint8_t is_on) 740184610Salfred{ 741184610Salfred DPRINTFN(5, "vbus = %u\n", is_on); 742184610Salfred 743184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 744184610Salfred if (is_on) { 745184610Salfred if (!sc->sc_flags.status_vbus) { 746184610Salfred sc->sc_flags.status_vbus = 1; 747184610Salfred 748184610Salfred /* complete root HUB interrupt endpoint */ 749190735Sthompsa at91dci_root_intr(sc); 750184610Salfred } 751184610Salfred } else { 752184610Salfred if (sc->sc_flags.status_vbus) { 753184610Salfred sc->sc_flags.status_vbus = 0; 754184610Salfred sc->sc_flags.status_bus_reset = 0; 755184610Salfred sc->sc_flags.status_suspend = 0; 756184610Salfred sc->sc_flags.change_suspend = 0; 757184610Salfred sc->sc_flags.change_connect = 1; 758184610Salfred 759184610Salfred /* complete root HUB interrupt endpoint */ 760190735Sthompsa at91dci_root_intr(sc); 761184610Salfred } 762184610Salfred } 763184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 764184610Salfred} 765184610Salfred 766184610Salfredvoid 767184610Salfredat91dci_interrupt(struct at91dci_softc *sc) 768184610Salfred{ 769184610Salfred uint32_t status; 770184610Salfred 771184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 772184610Salfred 773184610Salfred status = AT91_UDP_READ_4(sc, AT91_UDP_ISR); 774184610Salfred status &= AT91_UDP_INT_DEFAULT; 775184610Salfred 776184610Salfred if (!status) { 777184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 778184610Salfred return; 779184610Salfred } 780184610Salfred /* acknowledge interrupts */ 781184610Salfred 782184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status); 783184610Salfred 784184610Salfred /* check for any bus state change interrupts */ 785184610Salfred 786184610Salfred if (status & AT91_UDP_INT_BUS) { 787184610Salfred 788184610Salfred DPRINTFN(5, "real bus interrupt 0x%08x\n", status); 789184610Salfred 790184610Salfred if (status & AT91_UDP_INT_END_BR) { 791184610Salfred 792184610Salfred /* set correct state */ 793184610Salfred sc->sc_flags.status_bus_reset = 1; 794184610Salfred sc->sc_flags.status_suspend = 0; 795184610Salfred sc->sc_flags.change_suspend = 0; 796184610Salfred sc->sc_flags.change_connect = 1; 797184610Salfred 798184610Salfred /* disable resume interrupt */ 799184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 800184610Salfred AT91_UDP_INT_RXRSM); 801184610Salfred /* enable suspend interrupt */ 802184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 803184610Salfred AT91_UDP_INT_RXSUSP); 804184610Salfred } 805184610Salfred /* 806184610Salfred * If RXRSM and RXSUSP is set at the same time we interpret 807184610Salfred * that like RESUME. Resume is set when there is at least 3 808184610Salfred * milliseconds of inactivity on the USB BUS. 809184610Salfred */ 810184610Salfred if (status & AT91_UDP_INT_RXRSM) { 811184610Salfred if (sc->sc_flags.status_suspend) { 812184610Salfred sc->sc_flags.status_suspend = 0; 813184610Salfred sc->sc_flags.change_suspend = 1; 814184610Salfred 815184610Salfred /* disable resume interrupt */ 816184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 817184610Salfred AT91_UDP_INT_RXRSM); 818184610Salfred /* enable suspend interrupt */ 819184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 820184610Salfred AT91_UDP_INT_RXSUSP); 821184610Salfred } 822184610Salfred } else if (status & AT91_UDP_INT_RXSUSP) { 823184610Salfred if (!sc->sc_flags.status_suspend) { 824184610Salfred sc->sc_flags.status_suspend = 1; 825184610Salfred sc->sc_flags.change_suspend = 1; 826184610Salfred 827184610Salfred /* disable suspend interrupt */ 828184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 829184610Salfred AT91_UDP_INT_RXSUSP); 830184610Salfred 831184610Salfred /* enable resume interrupt */ 832184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 833184610Salfred AT91_UDP_INT_RXRSM); 834184610Salfred } 835184610Salfred } 836184610Salfred /* complete root HUB interrupt endpoint */ 837190735Sthompsa at91dci_root_intr(sc); 838184610Salfred } 839184610Salfred /* check for any endpoint interrupts */ 840184610Salfred 841184610Salfred if (status & AT91_UDP_INT_EPS) { 842184610Salfred 843184610Salfred DPRINTFN(5, "real endpoint interrupt 0x%08x\n", status); 844184610Salfred 845184610Salfred at91dci_interrupt_poll(sc); 846184610Salfred } 847184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 848184610Salfred} 849184610Salfred 850184610Salfredstatic void 851184610Salfredat91dci_setup_standard_chain_sub(struct at91dci_std_temp *temp) 852184610Salfred{ 853184610Salfred struct at91dci_td *td; 854184610Salfred 855184610Salfred /* get current Transfer Descriptor */ 856184610Salfred td = temp->td_next; 857184610Salfred temp->td = td; 858184610Salfred 859184610Salfred /* prepare for next TD */ 860184610Salfred temp->td_next = td->obj_next; 861184610Salfred 862184610Salfred /* fill out the Transfer Descriptor */ 863184610Salfred td->func = temp->func; 864184610Salfred td->pc = temp->pc; 865184610Salfred td->offset = temp->offset; 866184610Salfred td->remainder = temp->len; 867184610Salfred td->fifo_bank = 0; 868184610Salfred td->error = 0; 869192552Sthompsa td->did_stall = temp->did_stall; 870184610Salfred td->short_pkt = temp->short_pkt; 871184610Salfred td->alt_next = temp->setup_alt_next; 872184610Salfred} 873184610Salfred 874184610Salfredstatic void 875192984Sthompsaat91dci_setup_standard_chain(struct usb_xfer *xfer) 876184610Salfred{ 877184610Salfred struct at91dci_std_temp temp; 878184610Salfred struct at91dci_softc *sc; 879184610Salfred struct at91dci_td *td; 880184610Salfred uint32_t x; 881184610Salfred uint8_t ep_no; 882184610Salfred uint8_t need_sync; 883184610Salfred 884184610Salfred DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", 885193644Sthompsa xfer->address, UE_GET_ADDR(xfer->endpointno), 886194228Sthompsa xfer->sumlen, usbd_get_speed(xfer->xroot->udev)); 887184610Salfred 888184610Salfred temp.max_frame_size = xfer->max_frame_size; 889184610Salfred 890184610Salfred td = xfer->td_start[0]; 891184610Salfred xfer->td_transfer_first = td; 892184610Salfred xfer->td_transfer_cache = td; 893184610Salfred 894184610Salfred /* setup temp */ 895184610Salfred 896199673Sthompsa temp.pc = NULL; 897184610Salfred temp.td = NULL; 898184610Salfred temp.td_next = xfer->td_start[0]; 899190183Sthompsa temp.offset = 0; 900184610Salfred temp.setup_alt_next = xfer->flags_int.short_frames_ok; 901192552Sthompsa temp.did_stall = !xfer->flags_int.control_stall; 902184610Salfred 903187173Sthompsa sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 904193644Sthompsa ep_no = (xfer->endpointno & UE_ADDR); 905184610Salfred 906184610Salfred /* check if we should prepend a setup message */ 907184610Salfred 908184610Salfred if (xfer->flags_int.control_xfr) { 909184610Salfred if (xfer->flags_int.control_hdr) { 910184610Salfred 911184610Salfred temp.func = &at91dci_setup_rx; 912184610Salfred temp.len = xfer->frlengths[0]; 913184610Salfred temp.pc = xfer->frbuffers + 0; 914184610Salfred temp.short_pkt = temp.len ? 1 : 0; 915190183Sthompsa /* check for last frame */ 916190183Sthompsa if (xfer->nframes == 1) { 917190183Sthompsa /* no STATUS stage yet, SETUP is last */ 918190183Sthompsa if (xfer->flags_int.control_act) 919190183Sthompsa temp.setup_alt_next = 0; 920190183Sthompsa } 921184610Salfred 922184610Salfred at91dci_setup_standard_chain_sub(&temp); 923184610Salfred } 924184610Salfred x = 1; 925184610Salfred } else { 926184610Salfred x = 0; 927184610Salfred } 928184610Salfred 929184610Salfred if (x != xfer->nframes) { 930193644Sthompsa if (xfer->endpointno & UE_DIR_IN) { 931184610Salfred temp.func = &at91dci_data_tx; 932184610Salfred need_sync = 1; 933184610Salfred } else { 934184610Salfred temp.func = &at91dci_data_rx; 935184610Salfred need_sync = 0; 936184610Salfred } 937184610Salfred 938184610Salfred /* setup "pc" pointer */ 939184610Salfred temp.pc = xfer->frbuffers + x; 940184610Salfred } else { 941184610Salfred need_sync = 0; 942184610Salfred } 943184610Salfred while (x != xfer->nframes) { 944184610Salfred 945184610Salfred /* DATA0 / DATA1 message */ 946184610Salfred 947184610Salfred temp.len = xfer->frlengths[x]; 948184610Salfred 949184610Salfred x++; 950184610Salfred 951184610Salfred if (x == xfer->nframes) { 952190183Sthompsa if (xfer->flags_int.control_xfr) { 953190183Sthompsa if (xfer->flags_int.control_act) { 954190183Sthompsa temp.setup_alt_next = 0; 955190183Sthompsa } 956190183Sthompsa } else { 957190183Sthompsa temp.setup_alt_next = 0; 958190183Sthompsa } 959184610Salfred } 960184610Salfred if (temp.len == 0) { 961184610Salfred 962184610Salfred /* make sure that we send an USB packet */ 963184610Salfred 964184610Salfred temp.short_pkt = 0; 965184610Salfred 966184610Salfred } else { 967184610Salfred 968184610Salfred /* regular data transfer */ 969184610Salfred 970184610Salfred temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; 971184610Salfred } 972184610Salfred 973184610Salfred at91dci_setup_standard_chain_sub(&temp); 974184610Salfred 975184610Salfred if (xfer->flags_int.isochronous_xfr) { 976184610Salfred temp.offset += temp.len; 977184610Salfred } else { 978184610Salfred /* get next Page Cache pointer */ 979184610Salfred temp.pc = xfer->frbuffers + x; 980184610Salfred } 981184610Salfred } 982184610Salfred 983190183Sthompsa /* check for control transfer */ 984190183Sthompsa if (xfer->flags_int.control_xfr) { 985184610Salfred 986190183Sthompsa /* always setup a valid "pc" pointer for status and sync */ 987190183Sthompsa temp.pc = xfer->frbuffers + 0; 988184610Salfred temp.len = 0; 989184610Salfred temp.short_pkt = 0; 990190183Sthompsa temp.setup_alt_next = 0; 991184610Salfred 992190183Sthompsa /* check if we need to sync */ 993184610Salfred if (need_sync) { 994184610Salfred /* we need a SYNC point after TX */ 995184610Salfred temp.func = &at91dci_data_tx_sync; 996190183Sthompsa at91dci_setup_standard_chain_sub(&temp); 997190183Sthompsa } 998184610Salfred 999190183Sthompsa /* check if we should append a status stage */ 1000190183Sthompsa if (!xfer->flags_int.control_act) { 1001190183Sthompsa 1002190183Sthompsa /* 1003190183Sthompsa * Send a DATA1 message and invert the current 1004190183Sthompsa * endpoint direction. 1005190183Sthompsa */ 1006193644Sthompsa if (xfer->endpointno & UE_DIR_IN) { 1007190183Sthompsa temp.func = &at91dci_data_rx; 1008190183Sthompsa need_sync = 0; 1009190183Sthompsa } else { 1010190183Sthompsa temp.func = &at91dci_data_tx; 1011190183Sthompsa need_sync = 1; 1012190183Sthompsa } 1013190183Sthompsa 1014184610Salfred at91dci_setup_standard_chain_sub(&temp); 1015190183Sthompsa if (need_sync) { 1016190183Sthompsa /* we need a SYNC point after TX */ 1017190183Sthompsa temp.func = &at91dci_data_tx_sync; 1018190183Sthompsa at91dci_setup_standard_chain_sub(&temp); 1019190183Sthompsa } 1020184610Salfred } 1021184610Salfred } 1022190183Sthompsa 1023184610Salfred /* must have at least one frame! */ 1024184610Salfred td = temp.td; 1025184610Salfred xfer->td_transfer_last = td; 1026184610Salfred 1027184610Salfred /* setup the correct fifo bank */ 1028184610Salfred if (sc->sc_ep_flags[ep_no].fifo_bank) { 1029184610Salfred td = xfer->td_transfer_first; 1030184610Salfred td->fifo_bank = 1; 1031184610Salfred } 1032184610Salfred} 1033184610Salfred 1034184610Salfredstatic void 1035184610Salfredat91dci_timeout(void *arg) 1036184610Salfred{ 1037192984Sthompsa struct usb_xfer *xfer = arg; 1038184610Salfred 1039184610Salfred DPRINTF("xfer=%p\n", xfer); 1040184610Salfred 1041187177Sthompsa USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 1042184610Salfred 1043184610Salfred /* transfer is transferred */ 1044184610Salfred at91dci_device_done(xfer, USB_ERR_TIMEOUT); 1045184610Salfred} 1046184610Salfred 1047184610Salfredstatic void 1048192984Sthompsaat91dci_start_standard_chain(struct usb_xfer *xfer) 1049184610Salfred{ 1050184610Salfred DPRINTFN(9, "\n"); 1051184610Salfred 1052184610Salfred /* poll one time */ 1053184610Salfred if (at91dci_xfer_do_fifo(xfer)) { 1054184610Salfred 1055187173Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1056193644Sthompsa uint8_t ep_no = xfer->endpointno & UE_ADDR; 1057184610Salfred 1058184610Salfred /* 1059184610Salfred * Only enable the endpoint interrupt when we are actually 1060184610Salfred * waiting for data, hence we are dealing with level 1061184610Salfred * triggered interrupts ! 1062184610Salfred */ 1063184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_EP(ep_no)); 1064184610Salfred 1065184610Salfred DPRINTFN(15, "enable interrupts on endpoint %d\n", ep_no); 1066184610Salfred 1067184610Salfred /* put transfer on interrupt queue */ 1068194228Sthompsa usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); 1069184610Salfred 1070184610Salfred /* start timeout, if any */ 1071184610Salfred if (xfer->timeout != 0) { 1072194228Sthompsa usbd_transfer_timeout_ms(xfer, 1073184610Salfred &at91dci_timeout, xfer->timeout); 1074184610Salfred } 1075184610Salfred } 1076184610Salfred} 1077184610Salfred 1078184610Salfredstatic void 1079190735Sthompsaat91dci_root_intr(struct at91dci_softc *sc) 1080184610Salfred{ 1081184610Salfred DPRINTFN(9, "\n"); 1082184610Salfred 1083184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1084184610Salfred 1085184610Salfred /* set port bit */ 1086184610Salfred sc->sc_hub_idata[0] = 0x02; /* we only have one port */ 1087184610Salfred 1088190735Sthompsa uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, 1089190735Sthompsa sizeof(sc->sc_hub_idata)); 1090184610Salfred} 1091184610Salfred 1092193045Sthompsastatic usb_error_t 1093192984Sthompsaat91dci_standard_done_sub(struct usb_xfer *xfer) 1094184610Salfred{ 1095184610Salfred struct at91dci_td *td; 1096184610Salfred uint32_t len; 1097184610Salfred uint8_t error; 1098184610Salfred 1099184610Salfred DPRINTFN(9, "\n"); 1100184610Salfred 1101184610Salfred td = xfer->td_transfer_cache; 1102184610Salfred 1103184610Salfred do { 1104184610Salfred len = td->remainder; 1105184610Salfred 1106184610Salfred if (xfer->aframes != xfer->nframes) { 1107184610Salfred /* 1108184610Salfred * Verify the length and subtract 1109184610Salfred * the remainder from "frlengths[]": 1110184610Salfred */ 1111184610Salfred if (len > xfer->frlengths[xfer->aframes]) { 1112184610Salfred td->error = 1; 1113184610Salfred } else { 1114184610Salfred xfer->frlengths[xfer->aframes] -= len; 1115184610Salfred } 1116184610Salfred } 1117184610Salfred /* Check for transfer error */ 1118184610Salfred if (td->error) { 1119184610Salfred /* the transfer is finished */ 1120184610Salfred error = 1; 1121184610Salfred td = NULL; 1122184610Salfred break; 1123184610Salfred } 1124184610Salfred /* Check for short transfer */ 1125184610Salfred if (len > 0) { 1126184610Salfred if (xfer->flags_int.short_frames_ok) { 1127184610Salfred /* follow alt next */ 1128184610Salfred if (td->alt_next) { 1129184610Salfred td = td->obj_next; 1130184610Salfred } else { 1131184610Salfred td = NULL; 1132184610Salfred } 1133184610Salfred } else { 1134184610Salfred /* the transfer is finished */ 1135184610Salfred td = NULL; 1136184610Salfred } 1137184610Salfred error = 0; 1138184610Salfred break; 1139184610Salfred } 1140184610Salfred td = td->obj_next; 1141184610Salfred 1142184610Salfred /* this USB frame is complete */ 1143184610Salfred error = 0; 1144184610Salfred break; 1145184610Salfred 1146184610Salfred } while (0); 1147184610Salfred 1148184610Salfred /* update transfer cache */ 1149184610Salfred 1150184610Salfred xfer->td_transfer_cache = td; 1151184610Salfred 1152184610Salfred return (error ? 1153184610Salfred USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); 1154184610Salfred} 1155184610Salfred 1156184610Salfredstatic void 1157192984Sthompsaat91dci_standard_done(struct usb_xfer *xfer) 1158184610Salfred{ 1159193045Sthompsa usb_error_t err = 0; 1160184610Salfred 1161193644Sthompsa DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", 1162193644Sthompsa xfer, xfer->endpoint); 1163184610Salfred 1164184610Salfred /* reset scanner */ 1165184610Salfred 1166184610Salfred xfer->td_transfer_cache = xfer->td_transfer_first; 1167184610Salfred 1168184610Salfred if (xfer->flags_int.control_xfr) { 1169184610Salfred 1170184610Salfred if (xfer->flags_int.control_hdr) { 1171184610Salfred 1172184610Salfred err = at91dci_standard_done_sub(xfer); 1173184610Salfred } 1174184610Salfred xfer->aframes = 1; 1175184610Salfred 1176184610Salfred if (xfer->td_transfer_cache == NULL) { 1177184610Salfred goto done; 1178184610Salfred } 1179184610Salfred } 1180184610Salfred while (xfer->aframes != xfer->nframes) { 1181184610Salfred 1182184610Salfred err = at91dci_standard_done_sub(xfer); 1183184610Salfred xfer->aframes++; 1184184610Salfred 1185184610Salfred if (xfer->td_transfer_cache == NULL) { 1186184610Salfred goto done; 1187184610Salfred } 1188184610Salfred } 1189184610Salfred 1190184610Salfred if (xfer->flags_int.control_xfr && 1191184610Salfred !xfer->flags_int.control_act) { 1192184610Salfred 1193184610Salfred err = at91dci_standard_done_sub(xfer); 1194184610Salfred } 1195184610Salfreddone: 1196184610Salfred at91dci_device_done(xfer, err); 1197184610Salfred} 1198184610Salfred 1199184610Salfred/*------------------------------------------------------------------------* 1200184610Salfred * at91dci_device_done 1201184610Salfred * 1202184610Salfred * NOTE: this function can be called more than one time on the 1203184610Salfred * same USB transfer! 1204184610Salfred *------------------------------------------------------------------------*/ 1205184610Salfredstatic void 1206193045Sthompsaat91dci_device_done(struct usb_xfer *xfer, usb_error_t error) 1207184610Salfred{ 1208187173Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1209184610Salfred uint8_t ep_no; 1210184610Salfred 1211184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1212184610Salfred 1213193644Sthompsa DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n", 1214193644Sthompsa xfer, xfer->endpoint, error); 1215184610Salfred 1216192499Sthompsa if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { 1217193644Sthompsa ep_no = (xfer->endpointno & UE_ADDR); 1218184610Salfred 1219184610Salfred /* disable endpoint interrupt */ 1220184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, AT91_UDP_INT_EP(ep_no)); 1221184610Salfred 1222184610Salfred DPRINTFN(15, "disable interrupts on endpoint %d\n", ep_no); 1223184610Salfred } 1224184610Salfred /* dequeue transfer and start next transfer */ 1225194228Sthompsa usbd_transfer_done(xfer, error); 1226184610Salfred} 1227184610Salfred 1228184610Salfredstatic void 1229192984Sthompsaat91dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer, 1230195121Sthompsa struct usb_endpoint *ep, uint8_t *did_stall) 1231184610Salfred{ 1232184610Salfred struct at91dci_softc *sc; 1233184610Salfred uint32_t csr_val; 1234184610Salfred uint8_t csr_reg; 1235184610Salfred 1236184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 1237184610Salfred 1238193644Sthompsa DPRINTFN(5, "endpoint=%p\n", ep); 1239184610Salfred 1240184610Salfred if (xfer) { 1241184610Salfred /* cancel any ongoing transfers */ 1242184610Salfred at91dci_device_done(xfer, USB_ERR_STALLED); 1243184610Salfred } 1244184610Salfred /* set FORCESTALL */ 1245184610Salfred sc = AT9100_DCI_BUS2SC(udev->bus); 1246193644Sthompsa csr_reg = (ep->edesc->bEndpointAddress & UE_ADDR); 1247184610Salfred csr_reg = AT91_UDP_CSR(csr_reg); 1248184610Salfred csr_val = AT91_UDP_READ_4(sc, csr_reg); 1249184610Salfred AT91_CSR_ACK(csr_val, AT91_UDP_CSR_FORCESTALL); 1250184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1251184610Salfred} 1252184610Salfred 1253184610Salfredstatic void 1254184610Salfredat91dci_clear_stall_sub(struct at91dci_softc *sc, uint8_t ep_no, 1255184610Salfred uint8_t ep_type, uint8_t ep_dir) 1256184610Salfred{ 1257192984Sthompsa const struct usb_hw_ep_profile *pf; 1258184610Salfred uint32_t csr_val; 1259184610Salfred uint32_t temp; 1260184610Salfred uint8_t csr_reg; 1261184610Salfred uint8_t to; 1262184610Salfred 1263184610Salfred if (ep_type == UE_CONTROL) { 1264184610Salfred /* clearing stall is not needed */ 1265184610Salfred return; 1266184610Salfred } 1267184610Salfred /* compute CSR register offset */ 1268184610Salfred csr_reg = AT91_UDP_CSR(ep_no); 1269184610Salfred 1270184610Salfred /* compute default CSR value */ 1271184610Salfred csr_val = 0; 1272184610Salfred AT91_CSR_ACK(csr_val, 0); 1273184610Salfred 1274184610Salfred /* disable endpoint */ 1275184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1276184610Salfred 1277184610Salfred /* get endpoint profile */ 1278184610Salfred at91dci_get_hw_ep_profile(NULL, &pf, ep_no); 1279184610Salfred 1280184610Salfred /* reset FIFO */ 1281184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(ep_no)); 1282184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0); 1283184610Salfred 1284184610Salfred /* 1285184610Salfred * NOTE: One would assume that a FIFO reset would release the 1286184610Salfred * FIFO banks aswell, but it doesn't! We have to do this 1287184610Salfred * manually! 1288184610Salfred */ 1289184610Salfred 1290184610Salfred /* release FIFO banks, if any */ 1291184610Salfred for (to = 0; to != 2; to++) { 1292184610Salfred 1293184610Salfred /* get csr value */ 1294184610Salfred csr_val = AT91_UDP_READ_4(sc, csr_reg); 1295184610Salfred 1296184610Salfred if (csr_val & (AT91_UDP_CSR_RX_DATA_BK0 | 1297184610Salfred AT91_UDP_CSR_RX_DATA_BK1)) { 1298184610Salfred /* clear status bits */ 1299184610Salfred if (pf->support_multi_buffer) { 1300184610Salfred if (sc->sc_ep_flags[ep_no].fifo_bank) { 1301184610Salfred sc->sc_ep_flags[ep_no].fifo_bank = 0; 1302184610Salfred temp = AT91_UDP_CSR_RX_DATA_BK1; 1303184610Salfred } else { 1304184610Salfred sc->sc_ep_flags[ep_no].fifo_bank = 1; 1305184610Salfred temp = AT91_UDP_CSR_RX_DATA_BK0; 1306184610Salfred } 1307184610Salfred } else { 1308184610Salfred temp = (AT91_UDP_CSR_RX_DATA_BK0 | 1309184610Salfred AT91_UDP_CSR_RX_DATA_BK1); 1310184610Salfred } 1311184610Salfred } else { 1312184610Salfred temp = 0; 1313184610Salfred } 1314184610Salfred 1315184610Salfred /* clear FORCESTALL */ 1316184610Salfred temp |= AT91_UDP_CSR_STALLSENT; 1317184610Salfred 1318184610Salfred AT91_CSR_ACK(csr_val, temp); 1319184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1320184610Salfred } 1321184610Salfred 1322184610Salfred /* compute default CSR value */ 1323184610Salfred csr_val = 0; 1324184610Salfred AT91_CSR_ACK(csr_val, 0); 1325184610Salfred 1326184610Salfred /* enable endpoint */ 1327184610Salfred csr_val &= ~AT91_UDP_CSR_ET_MASK; 1328184610Salfred csr_val |= AT91_UDP_CSR_EPEDS; 1329184610Salfred 1330184610Salfred if (ep_type == UE_CONTROL) { 1331184610Salfred csr_val |= AT91_UDP_CSR_ET_CTRL; 1332184610Salfred } else { 1333184610Salfred if (ep_type == UE_BULK) { 1334184610Salfred csr_val |= AT91_UDP_CSR_ET_BULK; 1335184610Salfred } else if (ep_type == UE_INTERRUPT) { 1336184610Salfred csr_val |= AT91_UDP_CSR_ET_INT; 1337184610Salfred } else { 1338184610Salfred csr_val |= AT91_UDP_CSR_ET_ISO; 1339184610Salfred } 1340184610Salfred if (ep_dir & UE_DIR_IN) { 1341184610Salfred csr_val |= AT91_UDP_CSR_ET_DIR_IN; 1342184610Salfred } 1343184610Salfred } 1344184610Salfred 1345184610Salfred /* enable endpoint */ 1346184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(ep_no), csr_val); 1347184610Salfred} 1348184610Salfred 1349184610Salfredstatic void 1350193644Sthompsaat91dci_clear_stall(struct usb_device *udev, struct usb_endpoint *ep) 1351184610Salfred{ 1352184610Salfred struct at91dci_softc *sc; 1353192984Sthompsa struct usb_endpoint_descriptor *ed; 1354184610Salfred 1355193644Sthompsa DPRINTFN(5, "endpoint=%p\n", ep); 1356184610Salfred 1357184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 1358184610Salfred 1359184610Salfred /* check mode */ 1360192499Sthompsa if (udev->flags.usb_mode != USB_MODE_DEVICE) { 1361184610Salfred /* not supported */ 1362184610Salfred return; 1363184610Salfred } 1364184610Salfred /* get softc */ 1365184610Salfred sc = AT9100_DCI_BUS2SC(udev->bus); 1366184610Salfred 1367184610Salfred /* get endpoint descriptor */ 1368193644Sthompsa ed = ep->edesc; 1369184610Salfred 1370184610Salfred /* reset endpoint */ 1371184610Salfred at91dci_clear_stall_sub(sc, 1372184610Salfred (ed->bEndpointAddress & UE_ADDR), 1373184610Salfred (ed->bmAttributes & UE_XFERTYPE), 1374184610Salfred (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); 1375184610Salfred} 1376184610Salfred 1377193045Sthompsausb_error_t 1378184610Salfredat91dci_init(struct at91dci_softc *sc) 1379184610Salfred{ 1380184610Salfred uint32_t csr_val; 1381184610Salfred uint8_t n; 1382184610Salfred 1383184610Salfred DPRINTF("start\n"); 1384184610Salfred 1385184610Salfred /* set up the bus structure */ 1386184610Salfred sc->sc_bus.usbrev = USB_REV_1_1; 1387184610Salfred sc->sc_bus.methods = &at91dci_bus_methods; 1388184610Salfred 1389184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1390184610Salfred 1391184610Salfred /* turn on clocks */ 1392184610Salfred 1393184610Salfred if (sc->sc_clocks_on) { 1394184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 1395184610Salfred } 1396184610Salfred /* wait a little for things to stabilise */ 1397194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); 1398184610Salfred 1399184610Salfred /* disable and clear all interrupts */ 1400184610Salfred 1401184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); 1402184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF); 1403184610Salfred 1404184610Salfred /* compute default CSR value */ 1405184610Salfred 1406184610Salfred csr_val = 0; 1407184610Salfred AT91_CSR_ACK(csr_val, 0); 1408184610Salfred 1409184610Salfred /* disable all endpoints */ 1410184610Salfred 1411184610Salfred for (n = 0; n != AT91_UDP_EP_MAX; n++) { 1412184610Salfred 1413184610Salfred /* disable endpoint */ 1414184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(n), csr_val); 1415184610Salfred } 1416184610Salfred 1417184610Salfred /* enable the control endpoint */ 1418184610Salfred 1419184610Salfred AT91_CSR_ACK(csr_val, AT91_UDP_CSR_ET_CTRL | 1420184610Salfred AT91_UDP_CSR_EPEDS); 1421184610Salfred 1422184610Salfred /* write to FIFO control register */ 1423184610Salfred 1424184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(0), csr_val); 1425184610Salfred 1426184610Salfred /* enable the interrupts we want */ 1427184610Salfred 1428184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_BUS); 1429184610Salfred 1430184610Salfred /* turn off clocks */ 1431184610Salfred 1432184610Salfred at91dci_clocks_off(sc); 1433184610Salfred 1434184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1435184610Salfred 1436184610Salfred /* catch any lost interrupts */ 1437184610Salfred 1438184610Salfred at91dci_do_poll(&sc->sc_bus); 1439184610Salfred 1440184610Salfred return (0); /* success */ 1441184610Salfred} 1442184610Salfred 1443184610Salfredvoid 1444184610Salfredat91dci_uninit(struct at91dci_softc *sc) 1445184610Salfred{ 1446184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1447184610Salfred 1448184610Salfred /* disable and clear all interrupts */ 1449184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); 1450184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF); 1451184610Salfred 1452184610Salfred sc->sc_flags.port_powered = 0; 1453184610Salfred sc->sc_flags.status_vbus = 0; 1454184610Salfred sc->sc_flags.status_bus_reset = 0; 1455184610Salfred sc->sc_flags.status_suspend = 0; 1456184610Salfred sc->sc_flags.change_suspend = 0; 1457184610Salfred sc->sc_flags.change_connect = 1; 1458184610Salfred 1459184610Salfred at91dci_pull_down(sc); 1460184610Salfred at91dci_clocks_off(sc); 1461184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1462184610Salfred} 1463184610Salfred 1464229096Shselaskystatic void 1465184610Salfredat91dci_suspend(struct at91dci_softc *sc) 1466184610Salfred{ 1467229096Shselasky /* TODO */ 1468184610Salfred} 1469184610Salfred 1470229096Shselaskystatic void 1471184610Salfredat91dci_resume(struct at91dci_softc *sc) 1472184610Salfred{ 1473229096Shselasky /* TODO */ 1474184610Salfred} 1475184610Salfred 1476184610Salfredstatic void 1477192984Sthompsaat91dci_do_poll(struct usb_bus *bus) 1478184610Salfred{ 1479184610Salfred struct at91dci_softc *sc = AT9100_DCI_BUS2SC(bus); 1480184610Salfred 1481184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1482184610Salfred at91dci_interrupt_poll(sc); 1483184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1484184610Salfred} 1485184610Salfred 1486184610Salfred/*------------------------------------------------------------------------* 1487184610Salfred * at91dci bulk support 1488184610Salfred *------------------------------------------------------------------------*/ 1489184610Salfredstatic void 1490192984Sthompsaat91dci_device_bulk_open(struct usb_xfer *xfer) 1491184610Salfred{ 1492184610Salfred return; 1493184610Salfred} 1494184610Salfred 1495184610Salfredstatic void 1496192984Sthompsaat91dci_device_bulk_close(struct usb_xfer *xfer) 1497184610Salfred{ 1498184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1499184610Salfred} 1500184610Salfred 1501184610Salfredstatic void 1502192984Sthompsaat91dci_device_bulk_enter(struct usb_xfer *xfer) 1503184610Salfred{ 1504184610Salfred return; 1505184610Salfred} 1506184610Salfred 1507184610Salfredstatic void 1508192984Sthompsaat91dci_device_bulk_start(struct usb_xfer *xfer) 1509184610Salfred{ 1510184610Salfred /* setup TDs */ 1511184610Salfred at91dci_setup_standard_chain(xfer); 1512184610Salfred at91dci_start_standard_chain(xfer); 1513184610Salfred} 1514184610Salfred 1515192984Sthompsastruct usb_pipe_methods at91dci_device_bulk_methods = 1516184610Salfred{ 1517184610Salfred .open = at91dci_device_bulk_open, 1518184610Salfred .close = at91dci_device_bulk_close, 1519184610Salfred .enter = at91dci_device_bulk_enter, 1520184610Salfred .start = at91dci_device_bulk_start, 1521184610Salfred}; 1522184610Salfred 1523184610Salfred/*------------------------------------------------------------------------* 1524184610Salfred * at91dci control support 1525184610Salfred *------------------------------------------------------------------------*/ 1526184610Salfredstatic void 1527192984Sthompsaat91dci_device_ctrl_open(struct usb_xfer *xfer) 1528184610Salfred{ 1529184610Salfred return; 1530184610Salfred} 1531184610Salfred 1532184610Salfredstatic void 1533192984Sthompsaat91dci_device_ctrl_close(struct usb_xfer *xfer) 1534184610Salfred{ 1535184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1536184610Salfred} 1537184610Salfred 1538184610Salfredstatic void 1539192984Sthompsaat91dci_device_ctrl_enter(struct usb_xfer *xfer) 1540184610Salfred{ 1541184610Salfred return; 1542184610Salfred} 1543184610Salfred 1544184610Salfredstatic void 1545192984Sthompsaat91dci_device_ctrl_start(struct usb_xfer *xfer) 1546184610Salfred{ 1547184610Salfred /* setup TDs */ 1548184610Salfred at91dci_setup_standard_chain(xfer); 1549184610Salfred at91dci_start_standard_chain(xfer); 1550184610Salfred} 1551184610Salfred 1552192984Sthompsastruct usb_pipe_methods at91dci_device_ctrl_methods = 1553184610Salfred{ 1554184610Salfred .open = at91dci_device_ctrl_open, 1555184610Salfred .close = at91dci_device_ctrl_close, 1556184610Salfred .enter = at91dci_device_ctrl_enter, 1557184610Salfred .start = at91dci_device_ctrl_start, 1558184610Salfred}; 1559184610Salfred 1560184610Salfred/*------------------------------------------------------------------------* 1561184610Salfred * at91dci interrupt support 1562184610Salfred *------------------------------------------------------------------------*/ 1563184610Salfredstatic void 1564192984Sthompsaat91dci_device_intr_open(struct usb_xfer *xfer) 1565184610Salfred{ 1566184610Salfred return; 1567184610Salfred} 1568184610Salfred 1569184610Salfredstatic void 1570192984Sthompsaat91dci_device_intr_close(struct usb_xfer *xfer) 1571184610Salfred{ 1572184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1573184610Salfred} 1574184610Salfred 1575184610Salfredstatic void 1576192984Sthompsaat91dci_device_intr_enter(struct usb_xfer *xfer) 1577184610Salfred{ 1578184610Salfred return; 1579184610Salfred} 1580184610Salfred 1581184610Salfredstatic void 1582192984Sthompsaat91dci_device_intr_start(struct usb_xfer *xfer) 1583184610Salfred{ 1584184610Salfred /* setup TDs */ 1585184610Salfred at91dci_setup_standard_chain(xfer); 1586184610Salfred at91dci_start_standard_chain(xfer); 1587184610Salfred} 1588184610Salfred 1589192984Sthompsastruct usb_pipe_methods at91dci_device_intr_methods = 1590184610Salfred{ 1591184610Salfred .open = at91dci_device_intr_open, 1592184610Salfred .close = at91dci_device_intr_close, 1593184610Salfred .enter = at91dci_device_intr_enter, 1594184610Salfred .start = at91dci_device_intr_start, 1595184610Salfred}; 1596184610Salfred 1597184610Salfred/*------------------------------------------------------------------------* 1598184610Salfred * at91dci full speed isochronous support 1599184610Salfred *------------------------------------------------------------------------*/ 1600184610Salfredstatic void 1601192984Sthompsaat91dci_device_isoc_fs_open(struct usb_xfer *xfer) 1602184610Salfred{ 1603184610Salfred return; 1604184610Salfred} 1605184610Salfred 1606184610Salfredstatic void 1607192984Sthompsaat91dci_device_isoc_fs_close(struct usb_xfer *xfer) 1608184610Salfred{ 1609184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1610184610Salfred} 1611184610Salfred 1612184610Salfredstatic void 1613192984Sthompsaat91dci_device_isoc_fs_enter(struct usb_xfer *xfer) 1614184610Salfred{ 1615187173Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1616184610Salfred uint32_t temp; 1617184610Salfred uint32_t nframes; 1618184610Salfred 1619184610Salfred DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", 1620193644Sthompsa xfer, xfer->endpoint->isoc_next, xfer->nframes); 1621184610Salfred 1622184610Salfred /* get the current frame index */ 1623184610Salfred 1624184610Salfred nframes = AT91_UDP_READ_4(sc, AT91_UDP_FRM); 1625184610Salfred 1626184610Salfred /* 1627184610Salfred * check if the frame index is within the window where the frames 1628184610Salfred * will be inserted 1629184610Salfred */ 1630193644Sthompsa temp = (nframes - xfer->endpoint->isoc_next) & AT91_UDP_FRM_MASK; 1631184610Salfred 1632193644Sthompsa if ((xfer->endpoint->is_synced == 0) || 1633184610Salfred (temp < xfer->nframes)) { 1634184610Salfred /* 1635193644Sthompsa * If there is data underflow or the endpoint queue is 1636184610Salfred * empty we schedule the transfer a few frames ahead 1637184610Salfred * of the current frame position. Else two isochronous 1638184610Salfred * transfers might overlap. 1639184610Salfred */ 1640193644Sthompsa xfer->endpoint->isoc_next = (nframes + 3) & AT91_UDP_FRM_MASK; 1641193644Sthompsa xfer->endpoint->is_synced = 1; 1642193644Sthompsa DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next); 1643184610Salfred } 1644184610Salfred /* 1645184610Salfred * compute how many milliseconds the insertion is ahead of the 1646184610Salfred * current frame position: 1647184610Salfred */ 1648193644Sthompsa temp = (xfer->endpoint->isoc_next - nframes) & AT91_UDP_FRM_MASK; 1649184610Salfred 1650184610Salfred /* 1651184610Salfred * pre-compute when the isochronous transfer will be finished: 1652184610Salfred */ 1653184610Salfred xfer->isoc_time_complete = 1654194228Sthompsa usb_isoc_time_expand(&sc->sc_bus, nframes) + temp + 1655184610Salfred xfer->nframes; 1656184610Salfred 1657184610Salfred /* compute frame number for next insertion */ 1658193644Sthompsa xfer->endpoint->isoc_next += xfer->nframes; 1659184610Salfred 1660184610Salfred /* setup TDs */ 1661184610Salfred at91dci_setup_standard_chain(xfer); 1662184610Salfred} 1663184610Salfred 1664184610Salfredstatic void 1665192984Sthompsaat91dci_device_isoc_fs_start(struct usb_xfer *xfer) 1666184610Salfred{ 1667184610Salfred /* start TD chain */ 1668184610Salfred at91dci_start_standard_chain(xfer); 1669184610Salfred} 1670184610Salfred 1671192984Sthompsastruct usb_pipe_methods at91dci_device_isoc_fs_methods = 1672184610Salfred{ 1673184610Salfred .open = at91dci_device_isoc_fs_open, 1674184610Salfred .close = at91dci_device_isoc_fs_close, 1675184610Salfred .enter = at91dci_device_isoc_fs_enter, 1676184610Salfred .start = at91dci_device_isoc_fs_start, 1677184610Salfred}; 1678184610Salfred 1679184610Salfred/*------------------------------------------------------------------------* 1680184610Salfred * at91dci root control support 1681184610Salfred *------------------------------------------------------------------------* 1682190735Sthompsa * Simulate a hardware HUB by handling all the necessary requests. 1683184610Salfred *------------------------------------------------------------------------*/ 1684184610Salfred 1685192984Sthompsastatic const struct usb_device_descriptor at91dci_devd = { 1686192984Sthompsa .bLength = sizeof(struct usb_device_descriptor), 1687184610Salfred .bDescriptorType = UDESC_DEVICE, 1688184610Salfred .bcdUSB = {0x00, 0x02}, 1689184610Salfred .bDeviceClass = UDCLASS_HUB, 1690184610Salfred .bDeviceSubClass = UDSUBCLASS_HUB, 1691213802Shselasky .bDeviceProtocol = UDPROTO_FSHUB, 1692184610Salfred .bMaxPacketSize = 64, 1693184610Salfred .bcdDevice = {0x00, 0x01}, 1694184610Salfred .iManufacturer = 1, 1695184610Salfred .iProduct = 2, 1696184610Salfred .bNumConfigurations = 1, 1697184610Salfred}; 1698184610Salfred 1699184610Salfredstatic const struct at91dci_config_desc at91dci_confd = { 1700184610Salfred .confd = { 1701192984Sthompsa .bLength = sizeof(struct usb_config_descriptor), 1702184610Salfred .bDescriptorType = UDESC_CONFIG, 1703184610Salfred .wTotalLength[0] = sizeof(at91dci_confd), 1704184610Salfred .bNumInterface = 1, 1705184610Salfred .bConfigurationValue = 1, 1706184610Salfred .iConfiguration = 0, 1707184610Salfred .bmAttributes = UC_SELF_POWERED, 1708184610Salfred .bMaxPower = 0, 1709184610Salfred }, 1710184610Salfred .ifcd = { 1711192984Sthompsa .bLength = sizeof(struct usb_interface_descriptor), 1712184610Salfred .bDescriptorType = UDESC_INTERFACE, 1713184610Salfred .bNumEndpoints = 1, 1714184610Salfred .bInterfaceClass = UICLASS_HUB, 1715184610Salfred .bInterfaceSubClass = UISUBCLASS_HUB, 1716213802Shselasky .bInterfaceProtocol = 0, 1717184610Salfred }, 1718184610Salfred .endpd = { 1719192984Sthompsa .bLength = sizeof(struct usb_endpoint_descriptor), 1720184610Salfred .bDescriptorType = UDESC_ENDPOINT, 1721184610Salfred .bEndpointAddress = (UE_DIR_IN | AT9100_DCI_INTR_ENDPT), 1722184610Salfred .bmAttributes = UE_INTERRUPT, 1723184610Salfred .wMaxPacketSize[0] = 8, 1724184610Salfred .bInterval = 255, 1725184610Salfred }, 1726184610Salfred}; 1727184610Salfred 1728235000Shselasky#define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } 1729235000Shselasky 1730192984Sthompsastatic const struct usb_hub_descriptor_min at91dci_hubd = { 1731184610Salfred .bDescLength = sizeof(at91dci_hubd), 1732184610Salfred .bDescriptorType = UDESC_HUB, 1733184610Salfred .bNbrPorts = 1, 1734235000Shselasky HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)), 1735184610Salfred .bPwrOn2PwrGood = 50, 1736184610Salfred .bHubContrCurrent = 0, 1737184610Salfred .DeviceRemovable = {0}, /* port is removable */ 1738184610Salfred}; 1739184610Salfred 1740184610Salfred#define STRING_LANG \ 1741184610Salfred 0x09, 0x04, /* American English */ 1742184610Salfred 1743184610Salfred#define STRING_VENDOR \ 1744184610Salfred 'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L', 0 1745184610Salfred 1746184610Salfred#define STRING_PRODUCT \ 1747184610Salfred 'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \ 1748184610Salfred 'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \ 1749184610Salfred 'U', 0, 'B', 0, 1750184610Salfred 1751184610SalfredUSB_MAKE_STRING_DESC(STRING_LANG, at91dci_langtab); 1752184610SalfredUSB_MAKE_STRING_DESC(STRING_VENDOR, at91dci_vendor); 1753184610SalfredUSB_MAKE_STRING_DESC(STRING_PRODUCT, at91dci_product); 1754184610Salfred 1755193045Sthompsastatic usb_error_t 1756192984Sthompsaat91dci_roothub_exec(struct usb_device *udev, 1757192984Sthompsa struct usb_device_request *req, const void **pptr, uint16_t *plength) 1758184610Salfred{ 1759191402Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus); 1760191402Sthompsa const void *ptr; 1761191402Sthompsa uint16_t len; 1762184610Salfred uint16_t value; 1763184610Salfred uint16_t index; 1764193045Sthompsa usb_error_t err; 1765184610Salfred 1766184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1767184610Salfred 1768184610Salfred /* buffer reset */ 1769191402Sthompsa ptr = (const void *)&sc->sc_hub_temp; 1770191402Sthompsa len = 0; 1771191402Sthompsa err = 0; 1772184610Salfred 1773191402Sthompsa value = UGETW(req->wValue); 1774191402Sthompsa index = UGETW(req->wIndex); 1775184610Salfred 1776184610Salfred /* demultiplex the control request */ 1777184610Salfred 1778191402Sthompsa switch (req->bmRequestType) { 1779184610Salfred case UT_READ_DEVICE: 1780191402Sthompsa switch (req->bRequest) { 1781184610Salfred case UR_GET_DESCRIPTOR: 1782184610Salfred goto tr_handle_get_descriptor; 1783184610Salfred case UR_GET_CONFIG: 1784184610Salfred goto tr_handle_get_config; 1785184610Salfred case UR_GET_STATUS: 1786184610Salfred goto tr_handle_get_status; 1787184610Salfred default: 1788184610Salfred goto tr_stalled; 1789184610Salfred } 1790184610Salfred break; 1791184610Salfred 1792184610Salfred case UT_WRITE_DEVICE: 1793191402Sthompsa switch (req->bRequest) { 1794184610Salfred case UR_SET_ADDRESS: 1795184610Salfred goto tr_handle_set_address; 1796184610Salfred case UR_SET_CONFIG: 1797184610Salfred goto tr_handle_set_config; 1798184610Salfred case UR_CLEAR_FEATURE: 1799184610Salfred goto tr_valid; /* nop */ 1800184610Salfred case UR_SET_DESCRIPTOR: 1801184610Salfred goto tr_valid; /* nop */ 1802184610Salfred case UR_SET_FEATURE: 1803184610Salfred default: 1804184610Salfred goto tr_stalled; 1805184610Salfred } 1806184610Salfred break; 1807184610Salfred 1808184610Salfred case UT_WRITE_ENDPOINT: 1809191402Sthompsa switch (req->bRequest) { 1810184610Salfred case UR_CLEAR_FEATURE: 1811191402Sthompsa switch (UGETW(req->wValue)) { 1812184610Salfred case UF_ENDPOINT_HALT: 1813184610Salfred goto tr_handle_clear_halt; 1814184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 1815184610Salfred goto tr_handle_clear_wakeup; 1816184610Salfred default: 1817184610Salfred goto tr_stalled; 1818184610Salfred } 1819184610Salfred break; 1820184610Salfred case UR_SET_FEATURE: 1821191402Sthompsa switch (UGETW(req->wValue)) { 1822184610Salfred case UF_ENDPOINT_HALT: 1823184610Salfred goto tr_handle_set_halt; 1824184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 1825184610Salfred goto tr_handle_set_wakeup; 1826184610Salfred default: 1827184610Salfred goto tr_stalled; 1828184610Salfred } 1829184610Salfred break; 1830184610Salfred case UR_SYNCH_FRAME: 1831184610Salfred goto tr_valid; /* nop */ 1832184610Salfred default: 1833184610Salfred goto tr_stalled; 1834184610Salfred } 1835184610Salfred break; 1836184610Salfred 1837184610Salfred case UT_READ_ENDPOINT: 1838191402Sthompsa switch (req->bRequest) { 1839184610Salfred case UR_GET_STATUS: 1840184610Salfred goto tr_handle_get_ep_status; 1841184610Salfred default: 1842184610Salfred goto tr_stalled; 1843184610Salfred } 1844184610Salfred break; 1845184610Salfred 1846184610Salfred case UT_WRITE_INTERFACE: 1847191402Sthompsa switch (req->bRequest) { 1848184610Salfred case UR_SET_INTERFACE: 1849184610Salfred goto tr_handle_set_interface; 1850184610Salfred case UR_CLEAR_FEATURE: 1851184610Salfred goto tr_valid; /* nop */ 1852184610Salfred case UR_SET_FEATURE: 1853184610Salfred default: 1854184610Salfred goto tr_stalled; 1855184610Salfred } 1856184610Salfred break; 1857184610Salfred 1858184610Salfred case UT_READ_INTERFACE: 1859191402Sthompsa switch (req->bRequest) { 1860184610Salfred case UR_GET_INTERFACE: 1861184610Salfred goto tr_handle_get_interface; 1862184610Salfred case UR_GET_STATUS: 1863184610Salfred goto tr_handle_get_iface_status; 1864184610Salfred default: 1865184610Salfred goto tr_stalled; 1866184610Salfred } 1867184610Salfred break; 1868184610Salfred 1869184610Salfred case UT_WRITE_CLASS_INTERFACE: 1870184610Salfred case UT_WRITE_VENDOR_INTERFACE: 1871184610Salfred /* XXX forward */ 1872184610Salfred break; 1873184610Salfred 1874184610Salfred case UT_READ_CLASS_INTERFACE: 1875184610Salfred case UT_READ_VENDOR_INTERFACE: 1876184610Salfred /* XXX forward */ 1877184610Salfred break; 1878184610Salfred 1879184610Salfred case UT_WRITE_CLASS_DEVICE: 1880191402Sthompsa switch (req->bRequest) { 1881184610Salfred case UR_CLEAR_FEATURE: 1882184610Salfred goto tr_valid; 1883184610Salfred case UR_SET_DESCRIPTOR: 1884184610Salfred case UR_SET_FEATURE: 1885184610Salfred break; 1886184610Salfred default: 1887184610Salfred goto tr_stalled; 1888184610Salfred } 1889184610Salfred break; 1890184610Salfred 1891184610Salfred case UT_WRITE_CLASS_OTHER: 1892191402Sthompsa switch (req->bRequest) { 1893184610Salfred case UR_CLEAR_FEATURE: 1894184610Salfred goto tr_handle_clear_port_feature; 1895184610Salfred case UR_SET_FEATURE: 1896184610Salfred goto tr_handle_set_port_feature; 1897184610Salfred case UR_CLEAR_TT_BUFFER: 1898184610Salfred case UR_RESET_TT: 1899184610Salfred case UR_STOP_TT: 1900184610Salfred goto tr_valid; 1901184610Salfred 1902184610Salfred default: 1903184610Salfred goto tr_stalled; 1904184610Salfred } 1905184610Salfred break; 1906184610Salfred 1907184610Salfred case UT_READ_CLASS_OTHER: 1908191402Sthompsa switch (req->bRequest) { 1909184610Salfred case UR_GET_TT_STATE: 1910184610Salfred goto tr_handle_get_tt_state; 1911184610Salfred case UR_GET_STATUS: 1912184610Salfred goto tr_handle_get_port_status; 1913184610Salfred default: 1914184610Salfred goto tr_stalled; 1915184610Salfred } 1916184610Salfred break; 1917184610Salfred 1918184610Salfred case UT_READ_CLASS_DEVICE: 1919191402Sthompsa switch (req->bRequest) { 1920184610Salfred case UR_GET_DESCRIPTOR: 1921184610Salfred goto tr_handle_get_class_descriptor; 1922184610Salfred case UR_GET_STATUS: 1923184610Salfred goto tr_handle_get_class_status; 1924184610Salfred 1925184610Salfred default: 1926184610Salfred goto tr_stalled; 1927184610Salfred } 1928184610Salfred break; 1929184610Salfred default: 1930184610Salfred goto tr_stalled; 1931184610Salfred } 1932184610Salfred goto tr_valid; 1933184610Salfred 1934184610Salfredtr_handle_get_descriptor: 1935184610Salfred switch (value >> 8) { 1936184610Salfred case UDESC_DEVICE: 1937184610Salfred if (value & 0xff) { 1938184610Salfred goto tr_stalled; 1939184610Salfred } 1940191402Sthompsa len = sizeof(at91dci_devd); 1941191402Sthompsa ptr = (const void *)&at91dci_devd; 1942184610Salfred goto tr_valid; 1943184610Salfred case UDESC_CONFIG: 1944184610Salfred if (value & 0xff) { 1945184610Salfred goto tr_stalled; 1946184610Salfred } 1947191402Sthompsa len = sizeof(at91dci_confd); 1948191402Sthompsa ptr = (const void *)&at91dci_confd; 1949184610Salfred goto tr_valid; 1950184610Salfred case UDESC_STRING: 1951184610Salfred switch (value & 0xff) { 1952184610Salfred case 0: /* Language table */ 1953191402Sthompsa len = sizeof(at91dci_langtab); 1954191402Sthompsa ptr = (const void *)&at91dci_langtab; 1955184610Salfred goto tr_valid; 1956184610Salfred 1957184610Salfred case 1: /* Vendor */ 1958191402Sthompsa len = sizeof(at91dci_vendor); 1959191402Sthompsa ptr = (const void *)&at91dci_vendor; 1960184610Salfred goto tr_valid; 1961184610Salfred 1962184610Salfred case 2: /* Product */ 1963191402Sthompsa len = sizeof(at91dci_product); 1964191402Sthompsa ptr = (const void *)&at91dci_product; 1965184610Salfred goto tr_valid; 1966184610Salfred default: 1967184610Salfred break; 1968184610Salfred } 1969184610Salfred break; 1970184610Salfred default: 1971184610Salfred goto tr_stalled; 1972184610Salfred } 1973184610Salfred goto tr_stalled; 1974184610Salfred 1975184610Salfredtr_handle_get_config: 1976191402Sthompsa len = 1; 1977184610Salfred sc->sc_hub_temp.wValue[0] = sc->sc_conf; 1978184610Salfred goto tr_valid; 1979184610Salfred 1980184610Salfredtr_handle_get_status: 1981191402Sthompsa len = 2; 1982184610Salfred USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); 1983184610Salfred goto tr_valid; 1984184610Salfred 1985184610Salfredtr_handle_set_address: 1986184610Salfred if (value & 0xFF00) { 1987184610Salfred goto tr_stalled; 1988184610Salfred } 1989184610Salfred sc->sc_rt_addr = value; 1990184610Salfred goto tr_valid; 1991184610Salfred 1992184610Salfredtr_handle_set_config: 1993184610Salfred if (value >= 2) { 1994184610Salfred goto tr_stalled; 1995184610Salfred } 1996184610Salfred sc->sc_conf = value; 1997184610Salfred goto tr_valid; 1998184610Salfred 1999184610Salfredtr_handle_get_interface: 2000191402Sthompsa len = 1; 2001184610Salfred sc->sc_hub_temp.wValue[0] = 0; 2002184610Salfred goto tr_valid; 2003184610Salfred 2004184610Salfredtr_handle_get_tt_state: 2005184610Salfredtr_handle_get_class_status: 2006184610Salfredtr_handle_get_iface_status: 2007184610Salfredtr_handle_get_ep_status: 2008191402Sthompsa len = 2; 2009184610Salfred USETW(sc->sc_hub_temp.wValue, 0); 2010184610Salfred goto tr_valid; 2011184610Salfred 2012184610Salfredtr_handle_set_halt: 2013184610Salfredtr_handle_set_interface: 2014184610Salfredtr_handle_set_wakeup: 2015184610Salfredtr_handle_clear_wakeup: 2016184610Salfredtr_handle_clear_halt: 2017184610Salfred goto tr_valid; 2018184610Salfred 2019184610Salfredtr_handle_clear_port_feature: 2020184610Salfred if (index != 1) { 2021184610Salfred goto tr_stalled; 2022184610Salfred } 2023184610Salfred DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index); 2024184610Salfred 2025184610Salfred switch (value) { 2026184610Salfred case UHF_PORT_SUSPEND: 2027190735Sthompsa at91dci_wakeup_peer(sc); 2028184610Salfred break; 2029184610Salfred 2030184610Salfred case UHF_PORT_ENABLE: 2031184610Salfred sc->sc_flags.port_enabled = 0; 2032184610Salfred break; 2033184610Salfred 2034184610Salfred case UHF_PORT_TEST: 2035184610Salfred case UHF_PORT_INDICATOR: 2036184610Salfred case UHF_C_PORT_ENABLE: 2037184610Salfred case UHF_C_PORT_OVER_CURRENT: 2038184610Salfred case UHF_C_PORT_RESET: 2039184610Salfred /* nops */ 2040184610Salfred break; 2041184610Salfred case UHF_PORT_POWER: 2042184610Salfred sc->sc_flags.port_powered = 0; 2043184610Salfred at91dci_pull_down(sc); 2044184610Salfred at91dci_clocks_off(sc); 2045184610Salfred break; 2046184610Salfred case UHF_C_PORT_CONNECTION: 2047184610Salfred sc->sc_flags.change_connect = 0; 2048184610Salfred break; 2049184610Salfred case UHF_C_PORT_SUSPEND: 2050184610Salfred sc->sc_flags.change_suspend = 0; 2051184610Salfred break; 2052184610Salfred default: 2053191402Sthompsa err = USB_ERR_IOERROR; 2054184610Salfred goto done; 2055184610Salfred } 2056184610Salfred goto tr_valid; 2057184610Salfred 2058184610Salfredtr_handle_set_port_feature: 2059184610Salfred if (index != 1) { 2060184610Salfred goto tr_stalled; 2061184610Salfred } 2062184610Salfred DPRINTFN(9, "UR_SET_PORT_FEATURE\n"); 2063184610Salfred 2064184610Salfred switch (value) { 2065184610Salfred case UHF_PORT_ENABLE: 2066184610Salfred sc->sc_flags.port_enabled = 1; 2067184610Salfred break; 2068184610Salfred case UHF_PORT_SUSPEND: 2069184610Salfred case UHF_PORT_RESET: 2070184610Salfred case UHF_PORT_TEST: 2071184610Salfred case UHF_PORT_INDICATOR: 2072184610Salfred /* nops */ 2073184610Salfred break; 2074184610Salfred case UHF_PORT_POWER: 2075184610Salfred sc->sc_flags.port_powered = 1; 2076184610Salfred break; 2077184610Salfred default: 2078191402Sthompsa err = USB_ERR_IOERROR; 2079184610Salfred goto done; 2080184610Salfred } 2081184610Salfred goto tr_valid; 2082184610Salfred 2083184610Salfredtr_handle_get_port_status: 2084184610Salfred 2085184610Salfred DPRINTFN(9, "UR_GET_PORT_STATUS\n"); 2086184610Salfred 2087184610Salfred if (index != 1) { 2088184610Salfred goto tr_stalled; 2089184610Salfred } 2090184610Salfred if (sc->sc_flags.status_vbus) { 2091184610Salfred at91dci_clocks_on(sc); 2092184610Salfred at91dci_pull_up(sc); 2093184610Salfred } else { 2094184610Salfred at91dci_pull_down(sc); 2095184610Salfred at91dci_clocks_off(sc); 2096184610Salfred } 2097184610Salfred 2098184610Salfred /* Select FULL-speed and Device Side Mode */ 2099184610Salfred 2100184610Salfred value = UPS_PORT_MODE_DEVICE; 2101184610Salfred 2102184610Salfred if (sc->sc_flags.port_powered) { 2103184610Salfred value |= UPS_PORT_POWER; 2104184610Salfred } 2105184610Salfred if (sc->sc_flags.port_enabled) { 2106184610Salfred value |= UPS_PORT_ENABLED; 2107184610Salfred } 2108184610Salfred if (sc->sc_flags.status_vbus && 2109184610Salfred sc->sc_flags.status_bus_reset) { 2110184610Salfred value |= UPS_CURRENT_CONNECT_STATUS; 2111184610Salfred } 2112184610Salfred if (sc->sc_flags.status_suspend) { 2113184610Salfred value |= UPS_SUSPEND; 2114184610Salfred } 2115184610Salfred USETW(sc->sc_hub_temp.ps.wPortStatus, value); 2116184610Salfred 2117184610Salfred value = 0; 2118184610Salfred 2119184610Salfred if (sc->sc_flags.change_connect) { 2120184610Salfred value |= UPS_C_CONNECT_STATUS; 2121184610Salfred 2122184610Salfred if (sc->sc_flags.status_vbus && 2123184610Salfred sc->sc_flags.status_bus_reset) { 2124184610Salfred /* reset endpoint flags */ 2125229080Shselasky memset(sc->sc_ep_flags, 0, sizeof(sc->sc_ep_flags)); 2126184610Salfred } 2127184610Salfred } 2128184610Salfred if (sc->sc_flags.change_suspend) { 2129184610Salfred value |= UPS_C_SUSPEND; 2130184610Salfred } 2131184610Salfred USETW(sc->sc_hub_temp.ps.wPortChange, value); 2132191402Sthompsa len = sizeof(sc->sc_hub_temp.ps); 2133184610Salfred goto tr_valid; 2134184610Salfred 2135184610Salfredtr_handle_get_class_descriptor: 2136184610Salfred if (value & 0xFF) { 2137184610Salfred goto tr_stalled; 2138184610Salfred } 2139191402Sthompsa ptr = (const void *)&at91dci_hubd; 2140191402Sthompsa len = sizeof(at91dci_hubd); 2141184610Salfred goto tr_valid; 2142184610Salfred 2143184610Salfredtr_stalled: 2144191402Sthompsa err = USB_ERR_STALLED; 2145184610Salfredtr_valid: 2146184610Salfreddone: 2147191402Sthompsa *plength = len; 2148191402Sthompsa *pptr = ptr; 2149191402Sthompsa return (err); 2150184610Salfred} 2151184610Salfred 2152184610Salfredstatic void 2153192984Sthompsaat91dci_xfer_setup(struct usb_setup_params *parm) 2154184610Salfred{ 2155192984Sthompsa const struct usb_hw_ep_profile *pf; 2156184610Salfred struct at91dci_softc *sc; 2157192984Sthompsa struct usb_xfer *xfer; 2158184610Salfred void *last_obj; 2159184610Salfred uint32_t ntd; 2160184610Salfred uint32_t n; 2161184610Salfred uint8_t ep_no; 2162184610Salfred 2163184610Salfred sc = AT9100_DCI_BUS2SC(parm->udev->bus); 2164184610Salfred xfer = parm->curr_xfer; 2165184610Salfred 2166184610Salfred /* 2167184610Salfred * NOTE: This driver does not use any of the parameters that 2168184610Salfred * are computed from the following values. Just set some 2169184610Salfred * reasonable dummies: 2170184610Salfred */ 2171184610Salfred parm->hc_max_packet_size = 0x500; 2172184610Salfred parm->hc_max_packet_count = 1; 2173184610Salfred parm->hc_max_frame_size = 0x500; 2174184610Salfred 2175194228Sthompsa usbd_transfer_setup_sub(parm); 2176184610Salfred 2177184610Salfred /* 2178184610Salfred * compute maximum number of TDs 2179184610Salfred */ 2180184610Salfred if (parm->methods == &at91dci_device_ctrl_methods) { 2181184610Salfred 2182184610Salfred ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */ 2183184610Salfred + 1 /* SYNC 2 */ ; 2184184610Salfred 2185184610Salfred } else if (parm->methods == &at91dci_device_bulk_methods) { 2186184610Salfred 2187184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2188184610Salfred 2189184610Salfred } else if (parm->methods == &at91dci_device_intr_methods) { 2190184610Salfred 2191184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2192184610Salfred 2193184610Salfred } else if (parm->methods == &at91dci_device_isoc_fs_methods) { 2194184610Salfred 2195184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2196184610Salfred 2197184610Salfred } else { 2198184610Salfred 2199184610Salfred ntd = 0; 2200184610Salfred } 2201184610Salfred 2202184610Salfred /* 2203194228Sthompsa * check if "usbd_transfer_setup_sub" set an error 2204184610Salfred */ 2205184610Salfred if (parm->err) { 2206184610Salfred return; 2207184610Salfred } 2208184610Salfred /* 2209184610Salfred * allocate transfer descriptors 2210184610Salfred */ 2211184610Salfred last_obj = NULL; 2212184610Salfred 2213184610Salfred /* 2214184610Salfred * get profile stuff 2215184610Salfred */ 2216184610Salfred if (ntd) { 2217184610Salfred 2218193644Sthompsa ep_no = xfer->endpointno & UE_ADDR; 2219184610Salfred at91dci_get_hw_ep_profile(parm->udev, &pf, ep_no); 2220184610Salfred 2221184610Salfred if (pf == NULL) { 2222184610Salfred /* should not happen */ 2223184610Salfred parm->err = USB_ERR_INVAL; 2224184610Salfred return; 2225184610Salfred } 2226184610Salfred } else { 2227184610Salfred ep_no = 0; 2228184610Salfred pf = NULL; 2229184610Salfred } 2230184610Salfred 2231184610Salfred /* align data */ 2232184610Salfred parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); 2233184610Salfred 2234184610Salfred for (n = 0; n != ntd; n++) { 2235184610Salfred 2236184610Salfred struct at91dci_td *td; 2237184610Salfred 2238184610Salfred if (parm->buf) { 2239184610Salfred 2240184610Salfred td = USB_ADD_BYTES(parm->buf, parm->size[0]); 2241184610Salfred 2242184610Salfred /* init TD */ 2243184610Salfred td->io_tag = sc->sc_io_tag; 2244184610Salfred td->io_hdl = sc->sc_io_hdl; 2245184610Salfred td->max_packet_size = xfer->max_packet_size; 2246184610Salfred td->status_reg = AT91_UDP_CSR(ep_no); 2247184610Salfred td->fifo_reg = AT91_UDP_FDR(ep_no); 2248184610Salfred if (pf->support_multi_buffer) { 2249184610Salfred td->support_multi_buffer = 1; 2250184610Salfred } 2251184610Salfred td->obj_next = last_obj; 2252184610Salfred 2253184610Salfred last_obj = td; 2254184610Salfred } 2255184610Salfred parm->size[0] += sizeof(*td); 2256184610Salfred } 2257184610Salfred 2258184610Salfred xfer->td_start[0] = last_obj; 2259184610Salfred} 2260184610Salfred 2261184610Salfredstatic void 2262192984Sthompsaat91dci_xfer_unsetup(struct usb_xfer *xfer) 2263184610Salfred{ 2264184610Salfred return; 2265184610Salfred} 2266184610Salfred 2267184610Salfredstatic void 2268193644Sthompsaat91dci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, 2269193644Sthompsa struct usb_endpoint *ep) 2270184610Salfred{ 2271184610Salfred struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus); 2272184610Salfred 2273193644Sthompsa DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n", 2274193644Sthompsa ep, udev->address, 2275192499Sthompsa edesc->bEndpointAddress, udev->flags.usb_mode, 2276184610Salfred sc->sc_rt_addr); 2277184610Salfred 2278190735Sthompsa if (udev->device_index != sc->sc_rt_addr) { 2279184610Salfred 2280184610Salfred if (udev->speed != USB_SPEED_FULL) { 2281184610Salfred /* not supported */ 2282184610Salfred return; 2283184610Salfred } 2284184610Salfred switch (edesc->bmAttributes & UE_XFERTYPE) { 2285184610Salfred case UE_CONTROL: 2286193644Sthompsa ep->methods = &at91dci_device_ctrl_methods; 2287184610Salfred break; 2288184610Salfred case UE_INTERRUPT: 2289193644Sthompsa ep->methods = &at91dci_device_intr_methods; 2290184610Salfred break; 2291184610Salfred case UE_ISOCHRONOUS: 2292193644Sthompsa ep->methods = &at91dci_device_isoc_fs_methods; 2293184610Salfred break; 2294184610Salfred case UE_BULK: 2295193644Sthompsa ep->methods = &at91dci_device_bulk_methods; 2296184610Salfred break; 2297184610Salfred default: 2298184610Salfred /* do nothing */ 2299184610Salfred break; 2300184610Salfred } 2301184610Salfred } 2302184610Salfred} 2303184610Salfred 2304229096Shselaskystatic void 2305229096Shselaskyat91dci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) 2306229096Shselasky{ 2307229096Shselasky struct at91dci_softc *sc = AT9100_DCI_BUS2SC(bus); 2308229096Shselasky 2309229096Shselasky switch (state) { 2310229096Shselasky case USB_HW_POWER_SUSPEND: 2311229096Shselasky at91dci_suspend(sc); 2312229096Shselasky break; 2313229096Shselasky case USB_HW_POWER_SHUTDOWN: 2314229096Shselasky at91dci_uninit(sc); 2315229096Shselasky break; 2316229096Shselasky case USB_HW_POWER_RESUME: 2317229096Shselasky at91dci_resume(sc); 2318229096Shselasky break; 2319229096Shselasky default: 2320229096Shselasky break; 2321229096Shselasky } 2322229096Shselasky} 2323229096Shselasky 2324192984Sthompsastruct usb_bus_methods at91dci_bus_methods = 2325184610Salfred{ 2326193644Sthompsa .endpoint_init = &at91dci_ep_init, 2327184610Salfred .xfer_setup = &at91dci_xfer_setup, 2328184610Salfred .xfer_unsetup = &at91dci_xfer_unsetup, 2329184610Salfred .get_hw_ep_profile = &at91dci_get_hw_ep_profile, 2330184610Salfred .set_stall = &at91dci_set_stall, 2331184610Salfred .clear_stall = &at91dci_clear_stall, 2332190735Sthompsa .roothub_exec = &at91dci_roothub_exec, 2333195960Salfred .xfer_poll = &at91dci_do_poll, 2334229096Shselasky .set_hw_power_sleep = &at91dci_set_hw_power_sleep, 2335184610Salfred}; 2336