at91dci.c revision 199673
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/controller/at91dci.c 199673 2009-11-22 21:19:01Z thompsa $"); 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/linker_set.h> 56194677Sthompsa#include <sys/module.h> 57194677Sthompsa#include <sys/lock.h> 58194677Sthompsa#include <sys/mutex.h> 59194677Sthompsa#include <sys/condvar.h> 60194677Sthompsa#include <sys/sysctl.h> 61194677Sthompsa#include <sys/sx.h> 62194677Sthompsa#include <sys/unistd.h> 63194677Sthompsa#include <sys/callout.h> 64194677Sthompsa#include <sys/malloc.h> 65194677Sthompsa#include <sys/priv.h> 66194677Sthompsa 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> 83188942Sthompsa#include <dev/usb/controller/at91dci.h> 84184610Salfred 85184610Salfred#define AT9100_DCI_BUS2SC(bus) \ 86184610Salfred ((struct at91dci_softc *)(((uint8_t *)(bus)) - \ 87190181Sthompsa ((uint8_t *)&(((struct at91dci_softc *)0)->sc_bus)))) 88184610Salfred 89184610Salfred#define AT9100_DCI_PC2SC(pc) \ 90190180Sthompsa AT9100_DCI_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus) 91184610Salfred 92194677Sthompsa#ifdef USB_DEBUG 93184610Salfredstatic int at91dcidebug = 0; 94184610Salfred 95192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, at91dci, CTLFLAG_RW, 0, "USB at91dci"); 96192502SthompsaSYSCTL_INT(_hw_usb_at91dci, OID_AUTO, debug, CTLFLAG_RW, 97184610Salfred &at91dcidebug, 0, "at91dci debug level"); 98184610Salfred#endif 99184610Salfred 100184610Salfred#define AT9100_DCI_INTR_ENDPT 1 101184610Salfred 102184610Salfred/* prototypes */ 103184610Salfred 104192984Sthompsastruct usb_bus_methods at91dci_bus_methods; 105192984Sthompsastruct usb_pipe_methods at91dci_device_bulk_methods; 106192984Sthompsastruct usb_pipe_methods at91dci_device_ctrl_methods; 107192984Sthompsastruct usb_pipe_methods at91dci_device_intr_methods; 108192984Sthompsastruct usb_pipe_methods at91dci_device_isoc_fs_methods; 109184610Salfred 110184610Salfredstatic at91dci_cmd_t at91dci_setup_rx; 111184610Salfredstatic at91dci_cmd_t at91dci_data_rx; 112184610Salfredstatic at91dci_cmd_t at91dci_data_tx; 113184610Salfredstatic at91dci_cmd_t at91dci_data_tx_sync; 114193045Sthompsastatic void at91dci_device_done(struct usb_xfer *, usb_error_t); 115192984Sthompsastatic void at91dci_do_poll(struct usb_bus *); 116192984Sthompsastatic void at91dci_standard_done(struct usb_xfer *); 117190735Sthompsastatic void at91dci_root_intr(struct at91dci_softc *sc); 118184610Salfred 119184610Salfred/* 120184610Salfred * NOTE: Some of the bits in the CSR register have inverse meaning so 121184610Salfred * we need a helper macro when acknowledging events: 122184610Salfred */ 123184610Salfred#define AT91_CSR_ACK(csr, what) do { \ 124184610Salfred (csr) &= ~((AT91_UDP_CSR_FORCESTALL| \ 125184610Salfred AT91_UDP_CSR_TXPKTRDY| \ 126184610Salfred AT91_UDP_CSR_RXBYTECNT) ^ (what));\ 127184610Salfred (csr) |= ((AT91_UDP_CSR_RX_DATA_BK0| \ 128184610Salfred AT91_UDP_CSR_RX_DATA_BK1| \ 129184610Salfred AT91_UDP_CSR_TXCOMP| \ 130184610Salfred AT91_UDP_CSR_RXSETUP| \ 131184610Salfred AT91_UDP_CSR_STALLSENT) ^ (what)); \ 132184610Salfred} while (0) 133184610Salfred 134184610Salfred/* 135184610Salfred * Here is a list of what the chip supports. 136184610Salfred * Probably it supports more than listed here! 137184610Salfred */ 138192984Sthompsastatic const struct usb_hw_ep_profile 139184610Salfred at91dci_ep_profile[AT91_UDP_EP_MAX] = { 140184610Salfred 141184610Salfred [0] = { 142184610Salfred .max_in_frame_size = 8, 143184610Salfred .max_out_frame_size = 8, 144184610Salfred .is_simplex = 1, 145184610Salfred .support_control = 1, 146184610Salfred }, 147184610Salfred [1] = { 148184610Salfred .max_in_frame_size = 64, 149184610Salfred .max_out_frame_size = 64, 150184610Salfred .is_simplex = 1, 151184610Salfred .support_multi_buffer = 1, 152184610Salfred .support_bulk = 1, 153184610Salfred .support_interrupt = 1, 154184610Salfred .support_isochronous = 1, 155184610Salfred .support_in = 1, 156184610Salfred .support_out = 1, 157184610Salfred }, 158184610Salfred [2] = { 159184610Salfred .max_in_frame_size = 64, 160184610Salfred .max_out_frame_size = 64, 161184610Salfred .is_simplex = 1, 162184610Salfred .support_multi_buffer = 1, 163184610Salfred .support_bulk = 1, 164184610Salfred .support_interrupt = 1, 165184610Salfred .support_isochronous = 1, 166184610Salfred .support_in = 1, 167184610Salfred .support_out = 1, 168184610Salfred }, 169184610Salfred [3] = { 170184610Salfred /* can also do BULK */ 171184610Salfred .max_in_frame_size = 8, 172184610Salfred .max_out_frame_size = 8, 173184610Salfred .is_simplex = 1, 174184610Salfred .support_interrupt = 1, 175184610Salfred .support_in = 1, 176184610Salfred .support_out = 1, 177184610Salfred }, 178184610Salfred [4] = { 179184610Salfred .max_in_frame_size = 256, 180184610Salfred .max_out_frame_size = 256, 181184610Salfred .is_simplex = 1, 182184610Salfred .support_multi_buffer = 1, 183184610Salfred .support_bulk = 1, 184184610Salfred .support_interrupt = 1, 185184610Salfred .support_isochronous = 1, 186184610Salfred .support_in = 1, 187184610Salfred .support_out = 1, 188184610Salfred }, 189184610Salfred [5] = { 190184610Salfred .max_in_frame_size = 256, 191184610Salfred .max_out_frame_size = 256, 192184610Salfred .is_simplex = 1, 193184610Salfred .support_multi_buffer = 1, 194184610Salfred .support_bulk = 1, 195184610Salfred .support_interrupt = 1, 196184610Salfred .support_isochronous = 1, 197184610Salfred .support_in = 1, 198184610Salfred .support_out = 1, 199184610Salfred }, 200184610Salfred}; 201184610Salfred 202184610Salfredstatic void 203192984Sthompsaat91dci_get_hw_ep_profile(struct usb_device *udev, 204192984Sthompsa const struct usb_hw_ep_profile **ppf, uint8_t ep_addr) 205184610Salfred{ 206184610Salfred if (ep_addr < AT91_UDP_EP_MAX) { 207184610Salfred *ppf = (at91dci_ep_profile + ep_addr); 208184610Salfred } else { 209184610Salfred *ppf = NULL; 210184610Salfred } 211184610Salfred} 212184610Salfred 213184610Salfredstatic void 214184610Salfredat91dci_clocks_on(struct at91dci_softc *sc) 215184610Salfred{ 216184610Salfred if (sc->sc_flags.clocks_off && 217184610Salfred sc->sc_flags.port_powered) { 218184610Salfred 219184610Salfred DPRINTFN(5, "\n"); 220184610Salfred 221184610Salfred if (sc->sc_clocks_on) { 222184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 223184610Salfred } 224184610Salfred sc->sc_flags.clocks_off = 0; 225184610Salfred 226184610Salfred /* enable Transceiver */ 227184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, 0); 228184610Salfred } 229184610Salfred} 230184610Salfred 231184610Salfredstatic void 232184610Salfredat91dci_clocks_off(struct at91dci_softc *sc) 233184610Salfred{ 234184610Salfred if (!sc->sc_flags.clocks_off) { 235184610Salfred 236184610Salfred DPRINTFN(5, "\n"); 237184610Salfred 238184610Salfred /* disable Transceiver */ 239184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); 240184610Salfred 241184610Salfred if (sc->sc_clocks_off) { 242184610Salfred (sc->sc_clocks_off) (sc->sc_clocks_arg); 243184610Salfred } 244184610Salfred sc->sc_flags.clocks_off = 1; 245184610Salfred } 246184610Salfred} 247184610Salfred 248184610Salfredstatic void 249184610Salfredat91dci_pull_up(struct at91dci_softc *sc) 250184610Salfred{ 251184610Salfred /* pullup D+, if possible */ 252184610Salfred 253184610Salfred if (!sc->sc_flags.d_pulled_up && 254184610Salfred sc->sc_flags.port_powered) { 255184610Salfred sc->sc_flags.d_pulled_up = 1; 256184610Salfred (sc->sc_pull_up) (sc->sc_pull_arg); 257184610Salfred } 258184610Salfred} 259184610Salfred 260184610Salfredstatic void 261184610Salfredat91dci_pull_down(struct at91dci_softc *sc) 262184610Salfred{ 263184610Salfred /* pulldown D+, if possible */ 264184610Salfred 265184610Salfred if (sc->sc_flags.d_pulled_up) { 266184610Salfred sc->sc_flags.d_pulled_up = 0; 267184610Salfred (sc->sc_pull_down) (sc->sc_pull_arg); 268184610Salfred } 269184610Salfred} 270184610Salfred 271184610Salfredstatic void 272190735Sthompsaat91dci_wakeup_peer(struct at91dci_softc *sc) 273184610Salfred{ 274184610Salfred if (!(sc->sc_flags.status_suspend)) { 275184610Salfred return; 276184610Salfred } 277184610Salfred 278186730Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, AT91_UDP_GSTATE_ESR); 279184610Salfred 280186730Salfred /* wait 8 milliseconds */ 281188983Sthompsa /* Wait for reset to complete. */ 282194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); 283184610Salfred 284186730Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, 0); 285184610Salfred} 286184610Salfred 287184610Salfredstatic void 288184610Salfredat91dci_set_address(struct at91dci_softc *sc, uint8_t addr) 289184610Salfred{ 290184610Salfred DPRINTFN(5, "addr=%d\n", addr); 291184610Salfred 292184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, addr | 293184610Salfred AT91_UDP_FADDR_EN); 294184610Salfred} 295184610Salfred 296184610Salfredstatic uint8_t 297184610Salfredat91dci_setup_rx(struct at91dci_td *td) 298184610Salfred{ 299184610Salfred struct at91dci_softc *sc; 300192984Sthompsa struct usb_device_request req; 301184610Salfred uint32_t csr; 302184610Salfred uint32_t temp; 303184610Salfred uint16_t count; 304184610Salfred 305184610Salfred /* read out FIFO status */ 306184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 307184610Salfred td->status_reg); 308184610Salfred 309184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 310184610Salfred 311184610Salfred temp = csr; 312184610Salfred temp &= (AT91_UDP_CSR_RX_DATA_BK0 | 313184610Salfred AT91_UDP_CSR_RX_DATA_BK1 | 314184610Salfred AT91_UDP_CSR_STALLSENT | 315184610Salfred AT91_UDP_CSR_RXSETUP | 316184610Salfred AT91_UDP_CSR_TXCOMP); 317184610Salfred 318184610Salfred if (!(csr & AT91_UDP_CSR_RXSETUP)) { 319184610Salfred goto not_complete; 320184610Salfred } 321190721Sthompsa /* clear did stall */ 322190721Sthompsa td->did_stall = 0; 323190721Sthompsa 324184610Salfred /* get the packet byte count */ 325184610Salfred count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; 326184610Salfred 327184610Salfred /* verify data length */ 328184610Salfred if (count != td->remainder) { 329184610Salfred DPRINTFN(0, "Invalid SETUP packet " 330184610Salfred "length, %d bytes\n", count); 331184610Salfred goto not_complete; 332184610Salfred } 333184610Salfred if (count != sizeof(req)) { 334184610Salfred DPRINTFN(0, "Unsupported SETUP packet " 335184610Salfred "length, %d bytes\n", count); 336184610Salfred goto not_complete; 337184610Salfred } 338184610Salfred /* receive data */ 339184610Salfred bus_space_read_multi_1(td->io_tag, td->io_hdl, 340184610Salfred td->fifo_reg, (void *)&req, sizeof(req)); 341184610Salfred 342184610Salfred /* copy data into real buffer */ 343194228Sthompsa usbd_copy_in(td->pc, 0, &req, sizeof(req)); 344184610Salfred 345184610Salfred td->offset = sizeof(req); 346184610Salfred td->remainder = 0; 347184610Salfred 348184610Salfred /* get pointer to softc */ 349184610Salfred sc = AT9100_DCI_PC2SC(td->pc); 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); 368184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 369184610Salfred td->status_reg, csr); 370184610Salfred return (0); /* complete */ 371184610Salfred 372184610Salfrednot_complete: 373190721Sthompsa /* abort any ongoing transfer */ 374190721Sthompsa if (!td->did_stall) { 375190721Sthompsa DPRINTFN(5, "stalling\n"); 376190721Sthompsa temp |= AT91_UDP_CSR_FORCESTALL; 377190721Sthompsa td->did_stall = 1; 378190721Sthompsa } 379190721Sthompsa 380184610Salfred /* clear interrupts, if any */ 381184610Salfred if (temp) { 382184610Salfred DPRINTFN(5, "clearing 0x%08x\n", temp); 383184610Salfred AT91_CSR_ACK(csr, temp); 384184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 385184610Salfred td->status_reg, csr); 386184610Salfred } 387184610Salfred return (1); /* not complete */ 388184610Salfred 389184610Salfred} 390184610Salfred 391184610Salfredstatic uint8_t 392184610Salfredat91dci_data_rx(struct at91dci_td *td) 393184610Salfred{ 394192984Sthompsa struct usb_page_search buf_res; 395184610Salfred uint32_t csr; 396184610Salfred uint32_t temp; 397184610Salfred uint16_t count; 398184610Salfred uint8_t to; 399184610Salfred uint8_t got_short; 400184610Salfred 401184610Salfred to = 2; /* don't loop forever! */ 402184610Salfred got_short = 0; 403184610Salfred 404184610Salfred /* check if any of the FIFO banks have data */ 405184610Salfredrepeat: 406184610Salfred /* read out FIFO status */ 407184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 408184610Salfred td->status_reg); 409184610Salfred 410184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 411184610Salfred 412184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 413184610Salfred if (td->remainder == 0) { 414184610Salfred /* 415184610Salfred * We are actually complete and have 416184610Salfred * received the next SETUP 417184610Salfred */ 418184610Salfred DPRINTFN(5, "faking complete\n"); 419184610Salfred return (0); /* complete */ 420184610Salfred } 421184610Salfred /* 422184610Salfred * USB Host Aborted the transfer. 423184610Salfred */ 424184610Salfred td->error = 1; 425184610Salfred return (0); /* complete */ 426184610Salfred } 427184610Salfred /* Make sure that "STALLSENT" gets cleared */ 428184610Salfred temp = csr; 429184610Salfred temp &= AT91_UDP_CSR_STALLSENT; 430184610Salfred 431184610Salfred /* check status */ 432184610Salfred if (!(csr & (AT91_UDP_CSR_RX_DATA_BK0 | 433184610Salfred AT91_UDP_CSR_RX_DATA_BK1))) { 434184610Salfred if (temp) { 435184610Salfred /* write command */ 436184610Salfred AT91_CSR_ACK(csr, temp); 437184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 438184610Salfred td->status_reg, csr); 439184610Salfred } 440184610Salfred return (1); /* not complete */ 441184610Salfred } 442184610Salfred /* get the packet byte count */ 443184610Salfred count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; 444184610Salfred 445184610Salfred /* verify the packet byte count */ 446184610Salfred if (count != td->max_packet_size) { 447184610Salfred if (count < td->max_packet_size) { 448184610Salfred /* we have a short packet */ 449184610Salfred td->short_pkt = 1; 450184610Salfred got_short = 1; 451184610Salfred } else { 452184610Salfred /* invalid USB packet */ 453184610Salfred td->error = 1; 454184610Salfred return (0); /* we are complete */ 455184610Salfred } 456184610Salfred } 457184610Salfred /* verify the packet byte count */ 458184610Salfred if (count > td->remainder) { 459184610Salfred /* invalid USB packet */ 460184610Salfred td->error = 1; 461184610Salfred return (0); /* we are complete */ 462184610Salfred } 463184610Salfred while (count > 0) { 464194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 465184610Salfred 466184610Salfred /* get correct length */ 467184610Salfred if (buf_res.length > count) { 468184610Salfred buf_res.length = count; 469184610Salfred } 470184610Salfred /* receive data */ 471184610Salfred bus_space_read_multi_1(td->io_tag, td->io_hdl, 472184610Salfred td->fifo_reg, buf_res.buffer, buf_res.length); 473184610Salfred 474184610Salfred /* update counters */ 475184610Salfred count -= buf_res.length; 476184610Salfred td->offset += buf_res.length; 477184610Salfred td->remainder -= buf_res.length; 478184610Salfred } 479184610Salfred 480184610Salfred /* clear status bits */ 481184610Salfred if (td->support_multi_buffer) { 482184610Salfred if (td->fifo_bank) { 483184610Salfred td->fifo_bank = 0; 484184610Salfred temp |= AT91_UDP_CSR_RX_DATA_BK1; 485184610Salfred } else { 486184610Salfred td->fifo_bank = 1; 487184610Salfred temp |= AT91_UDP_CSR_RX_DATA_BK0; 488184610Salfred } 489184610Salfred } else { 490184610Salfred temp |= (AT91_UDP_CSR_RX_DATA_BK0 | 491184610Salfred AT91_UDP_CSR_RX_DATA_BK1); 492184610Salfred } 493184610Salfred 494184610Salfred /* write command */ 495184610Salfred AT91_CSR_ACK(csr, temp); 496184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 497184610Salfred td->status_reg, csr); 498184610Salfred 499184610Salfred /* 500184610Salfred * NOTE: We may have to delay a little bit before 501184610Salfred * proceeding after clearing the DATA_BK bits. 502184610Salfred */ 503184610Salfred 504184610Salfred /* check if we are complete */ 505184610Salfred if ((td->remainder == 0) || got_short) { 506184610Salfred if (td->short_pkt) { 507184610Salfred /* we are complete */ 508184610Salfred return (0); 509184610Salfred } 510184610Salfred /* else need to receive a zero length packet */ 511184610Salfred } 512184610Salfred if (--to) { 513184610Salfred goto repeat; 514184610Salfred } 515184610Salfred return (1); /* not complete */ 516184610Salfred} 517184610Salfred 518184610Salfredstatic uint8_t 519184610Salfredat91dci_data_tx(struct at91dci_td *td) 520184610Salfred{ 521192984Sthompsa struct usb_page_search buf_res; 522184610Salfred uint32_t csr; 523184610Salfred uint32_t temp; 524184610Salfred uint16_t count; 525184610Salfred uint8_t to; 526184610Salfred 527184610Salfred to = 2; /* don't loop forever! */ 528184610Salfred 529184610Salfredrepeat: 530184610Salfred 531184610Salfred /* read out FIFO status */ 532184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 533184610Salfred td->status_reg); 534184610Salfred 535184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 536184610Salfred 537184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 538184610Salfred /* 539184610Salfred * The current transfer was aborted 540184610Salfred * by the USB Host 541184610Salfred */ 542184610Salfred td->error = 1; 543184610Salfred return (0); /* complete */ 544184610Salfred } 545184610Salfred /* Make sure that "STALLSENT" gets cleared */ 546184610Salfred temp = csr; 547184610Salfred temp &= AT91_UDP_CSR_STALLSENT; 548184610Salfred 549184610Salfred if (csr & AT91_UDP_CSR_TXPKTRDY) { 550184610Salfred if (temp) { 551184610Salfred /* write command */ 552184610Salfred AT91_CSR_ACK(csr, temp); 553184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 554184610Salfred td->status_reg, csr); 555184610Salfred } 556184610Salfred return (1); /* not complete */ 557184610Salfred } else { 558184610Salfred /* clear TXCOMP and set TXPKTRDY */ 559184610Salfred temp |= (AT91_UDP_CSR_TXCOMP | 560184610Salfred AT91_UDP_CSR_TXPKTRDY); 561184610Salfred } 562184610Salfred 563184610Salfred count = td->max_packet_size; 564184610Salfred if (td->remainder < count) { 565184610Salfred /* we have a short packet */ 566184610Salfred td->short_pkt = 1; 567184610Salfred count = td->remainder; 568184610Salfred } 569184610Salfred while (count > 0) { 570184610Salfred 571194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 572184610Salfred 573184610Salfred /* get correct length */ 574184610Salfred if (buf_res.length > count) { 575184610Salfred buf_res.length = count; 576184610Salfred } 577184610Salfred /* transmit data */ 578184610Salfred bus_space_write_multi_1(td->io_tag, td->io_hdl, 579184610Salfred td->fifo_reg, buf_res.buffer, buf_res.length); 580184610Salfred 581184610Salfred /* update counters */ 582184610Salfred count -= buf_res.length; 583184610Salfred td->offset += buf_res.length; 584184610Salfred td->remainder -= buf_res.length; 585184610Salfred } 586184610Salfred 587184610Salfred /* write command */ 588184610Salfred AT91_CSR_ACK(csr, temp); 589184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 590184610Salfred td->status_reg, csr); 591184610Salfred 592184610Salfred /* check remainder */ 593184610Salfred if (td->remainder == 0) { 594184610Salfred if (td->short_pkt) { 595184610Salfred return (0); /* complete */ 596184610Salfred } 597184610Salfred /* else we need to transmit a short packet */ 598184610Salfred } 599184610Salfred if (--to) { 600184610Salfred goto repeat; 601184610Salfred } 602184610Salfred return (1); /* not complete */ 603184610Salfred} 604184610Salfred 605184610Salfredstatic uint8_t 606184610Salfredat91dci_data_tx_sync(struct at91dci_td *td) 607184610Salfred{ 608184610Salfred struct at91dci_softc *sc; 609184610Salfred uint32_t csr; 610184610Salfred uint32_t temp; 611184610Salfred 612184610Salfred#if 0 613184610Salfredrepeat: 614184610Salfred#endif 615184610Salfred 616184610Salfred /* read out FIFO status */ 617184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 618184610Salfred td->status_reg); 619184610Salfred 620184610Salfred DPRINTFN(5, "csr=0x%08x\n", csr); 621184610Salfred 622184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 623184610Salfred DPRINTFN(5, "faking complete\n"); 624184610Salfred /* Race condition */ 625184610Salfred return (0); /* complete */ 626184610Salfred } 627184610Salfred temp = csr; 628184610Salfred temp &= (AT91_UDP_CSR_STALLSENT | 629184610Salfred AT91_UDP_CSR_TXCOMP); 630184610Salfred 631184610Salfred /* check status */ 632184610Salfred if (csr & AT91_UDP_CSR_TXPKTRDY) { 633184610Salfred goto not_complete; 634184610Salfred } 635184610Salfred if (!(csr & AT91_UDP_CSR_TXCOMP)) { 636184610Salfred goto not_complete; 637184610Salfred } 638184610Salfred sc = AT9100_DCI_PC2SC(td->pc); 639184610Salfred if (sc->sc_dv_addr != 0xFF) { 640184610Salfred /* 641184610Salfred * The AT91 has a special requirement with regard to 642184610Salfred * setting the address and that is to write the new 643184610Salfred * address before clearing TXCOMP: 644184610Salfred */ 645184610Salfred at91dci_set_address(sc, sc->sc_dv_addr); 646184610Salfred } 647184610Salfred /* write command */ 648184610Salfred AT91_CSR_ACK(csr, temp); 649184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 650184610Salfred td->status_reg, csr); 651184610Salfred 652184610Salfred return (0); /* complete */ 653184610Salfred 654184610Salfrednot_complete: 655184610Salfred if (temp) { 656184610Salfred /* write command */ 657184610Salfred AT91_CSR_ACK(csr, temp); 658184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 659184610Salfred td->status_reg, csr); 660184610Salfred } 661184610Salfred return (1); /* not complete */ 662184610Salfred} 663184610Salfred 664184610Salfredstatic uint8_t 665192984Sthompsaat91dci_xfer_do_fifo(struct usb_xfer *xfer) 666184610Salfred{ 667184610Salfred struct at91dci_softc *sc; 668184610Salfred struct at91dci_td *td; 669184610Salfred uint8_t temp; 670184610Salfred 671184610Salfred DPRINTFN(9, "\n"); 672184610Salfred 673184610Salfred td = xfer->td_transfer_cache; 674184610Salfred while (1) { 675184610Salfred if ((td->func) (td)) { 676184610Salfred /* operation in progress */ 677184610Salfred break; 678184610Salfred } 679184610Salfred if (((void *)td) == xfer->td_transfer_last) { 680184610Salfred goto done; 681184610Salfred } 682184610Salfred if (td->error) { 683184610Salfred goto done; 684184610Salfred } else if (td->remainder > 0) { 685184610Salfred /* 686184610Salfred * We had a short transfer. If there is no alternate 687184610Salfred * next, stop processing ! 688184610Salfred */ 689184610Salfred if (!td->alt_next) { 690184610Salfred goto done; 691184610Salfred } 692184610Salfred } 693184610Salfred /* 694184610Salfred * Fetch the next transfer descriptor and transfer 695184610Salfred * some flags to the next transfer descriptor 696184610Salfred */ 697184610Salfred temp = 0; 698184610Salfred if (td->fifo_bank) 699184610Salfred temp |= 1; 700184610Salfred td = td->obj_next; 701184610Salfred xfer->td_transfer_cache = td; 702184610Salfred if (temp & 1) 703184610Salfred td->fifo_bank = 1; 704184610Salfred } 705184610Salfred return (1); /* not complete */ 706184610Salfred 707184610Salfreddone: 708187173Sthompsa sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 709193644Sthompsa temp = (xfer->endpointno & UE_ADDR); 710184610Salfred 711184610Salfred /* update FIFO bank flag and multi buffer */ 712184610Salfred if (td->fifo_bank) { 713184610Salfred sc->sc_ep_flags[temp].fifo_bank = 1; 714184610Salfred } else { 715184610Salfred sc->sc_ep_flags[temp].fifo_bank = 0; 716184610Salfred } 717184610Salfred 718184610Salfred /* compute all actual lengths */ 719184610Salfred 720184610Salfred at91dci_standard_done(xfer); 721184610Salfred 722184610Salfred return (0); /* complete */ 723184610Salfred} 724184610Salfred 725184610Salfredstatic void 726184610Salfredat91dci_interrupt_poll(struct at91dci_softc *sc) 727184610Salfred{ 728192984Sthompsa struct usb_xfer *xfer; 729184610Salfred 730184610Salfredrepeat: 731184610Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 732184610Salfred if (!at91dci_xfer_do_fifo(xfer)) { 733184610Salfred /* queue has been modified */ 734184610Salfred goto repeat; 735184610Salfred } 736184610Salfred } 737184610Salfred} 738184610Salfred 739187175Sthompsavoid 740187175Sthompsaat91dci_vbus_interrupt(struct at91dci_softc *sc, uint8_t is_on) 741184610Salfred{ 742184610Salfred DPRINTFN(5, "vbus = %u\n", is_on); 743184610Salfred 744184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 745184610Salfred if (is_on) { 746184610Salfred if (!sc->sc_flags.status_vbus) { 747184610Salfred sc->sc_flags.status_vbus = 1; 748184610Salfred 749184610Salfred /* complete root HUB interrupt endpoint */ 750190735Sthompsa at91dci_root_intr(sc); 751184610Salfred } 752184610Salfred } else { 753184610Salfred if (sc->sc_flags.status_vbus) { 754184610Salfred sc->sc_flags.status_vbus = 0; 755184610Salfred sc->sc_flags.status_bus_reset = 0; 756184610Salfred sc->sc_flags.status_suspend = 0; 757184610Salfred sc->sc_flags.change_suspend = 0; 758184610Salfred sc->sc_flags.change_connect = 1; 759184610Salfred 760184610Salfred /* complete root HUB interrupt endpoint */ 761190735Sthompsa at91dci_root_intr(sc); 762184610Salfred } 763184610Salfred } 764184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 765184610Salfred} 766184610Salfred 767184610Salfredvoid 768184610Salfredat91dci_interrupt(struct at91dci_softc *sc) 769184610Salfred{ 770184610Salfred uint32_t status; 771184610Salfred 772184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 773184610Salfred 774184610Salfred status = AT91_UDP_READ_4(sc, AT91_UDP_ISR); 775184610Salfred status &= AT91_UDP_INT_DEFAULT; 776184610Salfred 777184610Salfred if (!status) { 778184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 779184610Salfred return; 780184610Salfred } 781184610Salfred /* acknowledge interrupts */ 782184610Salfred 783184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status); 784184610Salfred 785184610Salfred /* check for any bus state change interrupts */ 786184610Salfred 787184610Salfred if (status & AT91_UDP_INT_BUS) { 788184610Salfred 789184610Salfred DPRINTFN(5, "real bus interrupt 0x%08x\n", status); 790184610Salfred 791184610Salfred if (status & AT91_UDP_INT_END_BR) { 792184610Salfred 793184610Salfred /* set correct state */ 794184610Salfred sc->sc_flags.status_bus_reset = 1; 795184610Salfred sc->sc_flags.status_suspend = 0; 796184610Salfred sc->sc_flags.change_suspend = 0; 797184610Salfred sc->sc_flags.change_connect = 1; 798184610Salfred 799184610Salfred /* disable resume interrupt */ 800184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 801184610Salfred AT91_UDP_INT_RXRSM); 802184610Salfred /* enable suspend interrupt */ 803184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 804184610Salfred AT91_UDP_INT_RXSUSP); 805184610Salfred } 806184610Salfred /* 807184610Salfred * If RXRSM and RXSUSP is set at the same time we interpret 808184610Salfred * that like RESUME. Resume is set when there is at least 3 809184610Salfred * milliseconds of inactivity on the USB BUS. 810184610Salfred */ 811184610Salfred if (status & AT91_UDP_INT_RXRSM) { 812184610Salfred if (sc->sc_flags.status_suspend) { 813184610Salfred sc->sc_flags.status_suspend = 0; 814184610Salfred sc->sc_flags.change_suspend = 1; 815184610Salfred 816184610Salfred /* disable resume interrupt */ 817184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 818184610Salfred AT91_UDP_INT_RXRSM); 819184610Salfred /* enable suspend interrupt */ 820184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 821184610Salfred AT91_UDP_INT_RXSUSP); 822184610Salfred } 823184610Salfred } else if (status & AT91_UDP_INT_RXSUSP) { 824184610Salfred if (!sc->sc_flags.status_suspend) { 825184610Salfred sc->sc_flags.status_suspend = 1; 826184610Salfred sc->sc_flags.change_suspend = 1; 827184610Salfred 828184610Salfred /* disable suspend interrupt */ 829184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 830184610Salfred AT91_UDP_INT_RXSUSP); 831184610Salfred 832184610Salfred /* enable resume interrupt */ 833184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 834184610Salfred AT91_UDP_INT_RXRSM); 835184610Salfred } 836184610Salfred } 837184610Salfred /* complete root HUB interrupt endpoint */ 838190735Sthompsa at91dci_root_intr(sc); 839184610Salfred } 840184610Salfred /* check for any endpoint interrupts */ 841184610Salfred 842184610Salfred if (status & AT91_UDP_INT_EPS) { 843184610Salfred 844184610Salfred DPRINTFN(5, "real endpoint interrupt 0x%08x\n", status); 845184610Salfred 846184610Salfred at91dci_interrupt_poll(sc); 847184610Salfred } 848184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 849184610Salfred} 850184610Salfred 851184610Salfredstatic void 852184610Salfredat91dci_setup_standard_chain_sub(struct at91dci_std_temp *temp) 853184610Salfred{ 854184610Salfred struct at91dci_td *td; 855184610Salfred 856184610Salfred /* get current Transfer Descriptor */ 857184610Salfred td = temp->td_next; 858184610Salfred temp->td = td; 859184610Salfred 860184610Salfred /* prepare for next TD */ 861184610Salfred temp->td_next = td->obj_next; 862184610Salfred 863184610Salfred /* fill out the Transfer Descriptor */ 864184610Salfred td->func = temp->func; 865184610Salfred td->pc = temp->pc; 866184610Salfred td->offset = temp->offset; 867184610Salfred td->remainder = temp->len; 868184610Salfred td->fifo_bank = 0; 869184610Salfred td->error = 0; 870192552Sthompsa td->did_stall = temp->did_stall; 871184610Salfred td->short_pkt = temp->short_pkt; 872184610Salfred td->alt_next = temp->setup_alt_next; 873184610Salfred} 874184610Salfred 875184610Salfredstatic void 876192984Sthompsaat91dci_setup_standard_chain(struct usb_xfer *xfer) 877184610Salfred{ 878184610Salfred struct at91dci_std_temp temp; 879184610Salfred struct at91dci_softc *sc; 880184610Salfred struct at91dci_td *td; 881184610Salfred uint32_t x; 882184610Salfred uint8_t ep_no; 883184610Salfred uint8_t need_sync; 884184610Salfred 885184610Salfred DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", 886193644Sthompsa xfer->address, UE_GET_ADDR(xfer->endpointno), 887194228Sthompsa xfer->sumlen, usbd_get_speed(xfer->xroot->udev)); 888184610Salfred 889184610Salfred temp.max_frame_size = xfer->max_frame_size; 890184610Salfred 891184610Salfred td = xfer->td_start[0]; 892184610Salfred xfer->td_transfer_first = td; 893184610Salfred xfer->td_transfer_cache = td; 894184610Salfred 895184610Salfred /* setup temp */ 896184610Salfred 897199673Sthompsa temp.pc = NULL; 898184610Salfred temp.td = NULL; 899184610Salfred temp.td_next = xfer->td_start[0]; 900190183Sthompsa temp.offset = 0; 901184610Salfred temp.setup_alt_next = xfer->flags_int.short_frames_ok; 902192552Sthompsa temp.did_stall = !xfer->flags_int.control_stall; 903184610Salfred 904187173Sthompsa sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 905193644Sthompsa ep_no = (xfer->endpointno & UE_ADDR); 906184610Salfred 907184610Salfred /* check if we should prepend a setup message */ 908184610Salfred 909184610Salfred if (xfer->flags_int.control_xfr) { 910184610Salfred if (xfer->flags_int.control_hdr) { 911184610Salfred 912184610Salfred temp.func = &at91dci_setup_rx; 913184610Salfred temp.len = xfer->frlengths[0]; 914184610Salfred temp.pc = xfer->frbuffers + 0; 915184610Salfred temp.short_pkt = temp.len ? 1 : 0; 916190183Sthompsa /* check for last frame */ 917190183Sthompsa if (xfer->nframes == 1) { 918190183Sthompsa /* no STATUS stage yet, SETUP is last */ 919190183Sthompsa if (xfer->flags_int.control_act) 920190183Sthompsa temp.setup_alt_next = 0; 921190183Sthompsa } 922184610Salfred 923184610Salfred at91dci_setup_standard_chain_sub(&temp); 924184610Salfred } 925184610Salfred x = 1; 926184610Salfred } else { 927184610Salfred x = 0; 928184610Salfred } 929184610Salfred 930184610Salfred if (x != xfer->nframes) { 931193644Sthompsa if (xfer->endpointno & UE_DIR_IN) { 932184610Salfred temp.func = &at91dci_data_tx; 933184610Salfred need_sync = 1; 934184610Salfred } else { 935184610Salfred temp.func = &at91dci_data_rx; 936184610Salfred need_sync = 0; 937184610Salfred } 938184610Salfred 939184610Salfred /* setup "pc" pointer */ 940184610Salfred temp.pc = xfer->frbuffers + x; 941184610Salfred } else { 942184610Salfred need_sync = 0; 943184610Salfred } 944184610Salfred while (x != xfer->nframes) { 945184610Salfred 946184610Salfred /* DATA0 / DATA1 message */ 947184610Salfred 948184610Salfred temp.len = xfer->frlengths[x]; 949184610Salfred 950184610Salfred x++; 951184610Salfred 952184610Salfred if (x == xfer->nframes) { 953190183Sthompsa if (xfer->flags_int.control_xfr) { 954190183Sthompsa if (xfer->flags_int.control_act) { 955190183Sthompsa temp.setup_alt_next = 0; 956190183Sthompsa } 957190183Sthompsa } else { 958190183Sthompsa temp.setup_alt_next = 0; 959190183Sthompsa } 960184610Salfred } 961184610Salfred if (temp.len == 0) { 962184610Salfred 963184610Salfred /* make sure that we send an USB packet */ 964184610Salfred 965184610Salfred temp.short_pkt = 0; 966184610Salfred 967184610Salfred } else { 968184610Salfred 969184610Salfred /* regular data transfer */ 970184610Salfred 971184610Salfred temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; 972184610Salfred } 973184610Salfred 974184610Salfred at91dci_setup_standard_chain_sub(&temp); 975184610Salfred 976184610Salfred if (xfer->flags_int.isochronous_xfr) { 977184610Salfred temp.offset += temp.len; 978184610Salfred } else { 979184610Salfred /* get next Page Cache pointer */ 980184610Salfred temp.pc = xfer->frbuffers + x; 981184610Salfred } 982184610Salfred } 983184610Salfred 984190183Sthompsa /* check for control transfer */ 985190183Sthompsa if (xfer->flags_int.control_xfr) { 986184610Salfred 987190183Sthompsa /* always setup a valid "pc" pointer for status and sync */ 988190183Sthompsa temp.pc = xfer->frbuffers + 0; 989184610Salfred temp.len = 0; 990184610Salfred temp.short_pkt = 0; 991190183Sthompsa temp.setup_alt_next = 0; 992184610Salfred 993190183Sthompsa /* check if we need to sync */ 994184610Salfred if (need_sync) { 995184610Salfred /* we need a SYNC point after TX */ 996184610Salfred temp.func = &at91dci_data_tx_sync; 997190183Sthompsa at91dci_setup_standard_chain_sub(&temp); 998190183Sthompsa } 999184610Salfred 1000190183Sthompsa /* check if we should append a status stage */ 1001190183Sthompsa if (!xfer->flags_int.control_act) { 1002190183Sthompsa 1003190183Sthompsa /* 1004190183Sthompsa * Send a DATA1 message and invert the current 1005190183Sthompsa * endpoint direction. 1006190183Sthompsa */ 1007193644Sthompsa if (xfer->endpointno & UE_DIR_IN) { 1008190183Sthompsa temp.func = &at91dci_data_rx; 1009190183Sthompsa need_sync = 0; 1010190183Sthompsa } else { 1011190183Sthompsa temp.func = &at91dci_data_tx; 1012190183Sthompsa need_sync = 1; 1013190183Sthompsa } 1014190183Sthompsa 1015184610Salfred at91dci_setup_standard_chain_sub(&temp); 1016190183Sthompsa if (need_sync) { 1017190183Sthompsa /* we need a SYNC point after TX */ 1018190183Sthompsa temp.func = &at91dci_data_tx_sync; 1019190183Sthompsa at91dci_setup_standard_chain_sub(&temp); 1020190183Sthompsa } 1021184610Salfred } 1022184610Salfred } 1023190183Sthompsa 1024184610Salfred /* must have at least one frame! */ 1025184610Salfred td = temp.td; 1026184610Salfred xfer->td_transfer_last = td; 1027184610Salfred 1028184610Salfred /* setup the correct fifo bank */ 1029184610Salfred if (sc->sc_ep_flags[ep_no].fifo_bank) { 1030184610Salfred td = xfer->td_transfer_first; 1031184610Salfred td->fifo_bank = 1; 1032184610Salfred } 1033184610Salfred} 1034184610Salfred 1035184610Salfredstatic void 1036184610Salfredat91dci_timeout(void *arg) 1037184610Salfred{ 1038192984Sthompsa struct usb_xfer *xfer = arg; 1039184610Salfred 1040184610Salfred DPRINTF("xfer=%p\n", xfer); 1041184610Salfred 1042187177Sthompsa USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 1043184610Salfred 1044184610Salfred /* transfer is transferred */ 1045184610Salfred at91dci_device_done(xfer, USB_ERR_TIMEOUT); 1046184610Salfred} 1047184610Salfred 1048184610Salfredstatic void 1049192984Sthompsaat91dci_start_standard_chain(struct usb_xfer *xfer) 1050184610Salfred{ 1051184610Salfred DPRINTFN(9, "\n"); 1052184610Salfred 1053184610Salfred /* poll one time */ 1054184610Salfred if (at91dci_xfer_do_fifo(xfer)) { 1055184610Salfred 1056187173Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1057193644Sthompsa uint8_t ep_no = xfer->endpointno & UE_ADDR; 1058184610Salfred 1059184610Salfred /* 1060184610Salfred * Only enable the endpoint interrupt when we are actually 1061184610Salfred * waiting for data, hence we are dealing with level 1062184610Salfred * triggered interrupts ! 1063184610Salfred */ 1064184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_EP(ep_no)); 1065184610Salfred 1066184610Salfred DPRINTFN(15, "enable interrupts on endpoint %d\n", ep_no); 1067184610Salfred 1068184610Salfred /* put transfer on interrupt queue */ 1069194228Sthompsa usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); 1070184610Salfred 1071184610Salfred /* start timeout, if any */ 1072184610Salfred if (xfer->timeout != 0) { 1073194228Sthompsa usbd_transfer_timeout_ms(xfer, 1074184610Salfred &at91dci_timeout, xfer->timeout); 1075184610Salfred } 1076184610Salfred } 1077184610Salfred} 1078184610Salfred 1079184610Salfredstatic void 1080190735Sthompsaat91dci_root_intr(struct at91dci_softc *sc) 1081184610Salfred{ 1082184610Salfred DPRINTFN(9, "\n"); 1083184610Salfred 1084184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1085184610Salfred 1086184610Salfred /* set port bit */ 1087184610Salfred sc->sc_hub_idata[0] = 0x02; /* we only have one port */ 1088184610Salfred 1089190735Sthompsa uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, 1090190735Sthompsa sizeof(sc->sc_hub_idata)); 1091184610Salfred} 1092184610Salfred 1093193045Sthompsastatic usb_error_t 1094192984Sthompsaat91dci_standard_done_sub(struct usb_xfer *xfer) 1095184610Salfred{ 1096184610Salfred struct at91dci_td *td; 1097184610Salfred uint32_t len; 1098184610Salfred uint8_t error; 1099184610Salfred 1100184610Salfred DPRINTFN(9, "\n"); 1101184610Salfred 1102184610Salfred td = xfer->td_transfer_cache; 1103184610Salfred 1104184610Salfred do { 1105184610Salfred len = td->remainder; 1106184610Salfred 1107184610Salfred if (xfer->aframes != xfer->nframes) { 1108184610Salfred /* 1109184610Salfred * Verify the length and subtract 1110184610Salfred * the remainder from "frlengths[]": 1111184610Salfred */ 1112184610Salfred if (len > xfer->frlengths[xfer->aframes]) { 1113184610Salfred td->error = 1; 1114184610Salfred } else { 1115184610Salfred xfer->frlengths[xfer->aframes] -= len; 1116184610Salfred } 1117184610Salfred } 1118184610Salfred /* Check for transfer error */ 1119184610Salfred if (td->error) { 1120184610Salfred /* the transfer is finished */ 1121184610Salfred error = 1; 1122184610Salfred td = NULL; 1123184610Salfred break; 1124184610Salfred } 1125184610Salfred /* Check for short transfer */ 1126184610Salfred if (len > 0) { 1127184610Salfred if (xfer->flags_int.short_frames_ok) { 1128184610Salfred /* follow alt next */ 1129184610Salfred if (td->alt_next) { 1130184610Salfred td = td->obj_next; 1131184610Salfred } else { 1132184610Salfred td = NULL; 1133184610Salfred } 1134184610Salfred } else { 1135184610Salfred /* the transfer is finished */ 1136184610Salfred td = NULL; 1137184610Salfred } 1138184610Salfred error = 0; 1139184610Salfred break; 1140184610Salfred } 1141184610Salfred td = td->obj_next; 1142184610Salfred 1143184610Salfred /* this USB frame is complete */ 1144184610Salfred error = 0; 1145184610Salfred break; 1146184610Salfred 1147184610Salfred } while (0); 1148184610Salfred 1149184610Salfred /* update transfer cache */ 1150184610Salfred 1151184610Salfred xfer->td_transfer_cache = td; 1152184610Salfred 1153184610Salfred return (error ? 1154184610Salfred USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); 1155184610Salfred} 1156184610Salfred 1157184610Salfredstatic void 1158192984Sthompsaat91dci_standard_done(struct usb_xfer *xfer) 1159184610Salfred{ 1160193045Sthompsa usb_error_t err = 0; 1161184610Salfred 1162193644Sthompsa DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", 1163193644Sthompsa xfer, xfer->endpoint); 1164184610Salfred 1165184610Salfred /* reset scanner */ 1166184610Salfred 1167184610Salfred xfer->td_transfer_cache = xfer->td_transfer_first; 1168184610Salfred 1169184610Salfred if (xfer->flags_int.control_xfr) { 1170184610Salfred 1171184610Salfred if (xfer->flags_int.control_hdr) { 1172184610Salfred 1173184610Salfred err = at91dci_standard_done_sub(xfer); 1174184610Salfred } 1175184610Salfred xfer->aframes = 1; 1176184610Salfred 1177184610Salfred if (xfer->td_transfer_cache == NULL) { 1178184610Salfred goto done; 1179184610Salfred } 1180184610Salfred } 1181184610Salfred while (xfer->aframes != xfer->nframes) { 1182184610Salfred 1183184610Salfred err = at91dci_standard_done_sub(xfer); 1184184610Salfred xfer->aframes++; 1185184610Salfred 1186184610Salfred if (xfer->td_transfer_cache == NULL) { 1187184610Salfred goto done; 1188184610Salfred } 1189184610Salfred } 1190184610Salfred 1191184610Salfred if (xfer->flags_int.control_xfr && 1192184610Salfred !xfer->flags_int.control_act) { 1193184610Salfred 1194184610Salfred err = at91dci_standard_done_sub(xfer); 1195184610Salfred } 1196184610Salfreddone: 1197184610Salfred at91dci_device_done(xfer, err); 1198184610Salfred} 1199184610Salfred 1200184610Salfred/*------------------------------------------------------------------------* 1201184610Salfred * at91dci_device_done 1202184610Salfred * 1203184610Salfred * NOTE: this function can be called more than one time on the 1204184610Salfred * same USB transfer! 1205184610Salfred *------------------------------------------------------------------------*/ 1206184610Salfredstatic void 1207193045Sthompsaat91dci_device_done(struct usb_xfer *xfer, usb_error_t error) 1208184610Salfred{ 1209187173Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1210184610Salfred uint8_t ep_no; 1211184610Salfred 1212184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1213184610Salfred 1214193644Sthompsa DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n", 1215193644Sthompsa xfer, xfer->endpoint, error); 1216184610Salfred 1217192499Sthompsa if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { 1218193644Sthompsa ep_no = (xfer->endpointno & UE_ADDR); 1219184610Salfred 1220184610Salfred /* disable endpoint interrupt */ 1221184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, AT91_UDP_INT_EP(ep_no)); 1222184610Salfred 1223184610Salfred DPRINTFN(15, "disable interrupts on endpoint %d\n", ep_no); 1224184610Salfred } 1225184610Salfred /* dequeue transfer and start next transfer */ 1226194228Sthompsa usbd_transfer_done(xfer, error); 1227184610Salfred} 1228184610Salfred 1229184610Salfredstatic void 1230192984Sthompsaat91dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer, 1231195121Sthompsa struct usb_endpoint *ep, uint8_t *did_stall) 1232184610Salfred{ 1233184610Salfred struct at91dci_softc *sc; 1234184610Salfred uint32_t csr_val; 1235184610Salfred uint8_t csr_reg; 1236184610Salfred 1237184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 1238184610Salfred 1239193644Sthompsa DPRINTFN(5, "endpoint=%p\n", ep); 1240184610Salfred 1241184610Salfred if (xfer) { 1242184610Salfred /* cancel any ongoing transfers */ 1243184610Salfred at91dci_device_done(xfer, USB_ERR_STALLED); 1244184610Salfred } 1245184610Salfred /* set FORCESTALL */ 1246184610Salfred sc = AT9100_DCI_BUS2SC(udev->bus); 1247193644Sthompsa csr_reg = (ep->edesc->bEndpointAddress & UE_ADDR); 1248184610Salfred csr_reg = AT91_UDP_CSR(csr_reg); 1249184610Salfred csr_val = AT91_UDP_READ_4(sc, csr_reg); 1250184610Salfred AT91_CSR_ACK(csr_val, AT91_UDP_CSR_FORCESTALL); 1251184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1252184610Salfred} 1253184610Salfred 1254184610Salfredstatic void 1255184610Salfredat91dci_clear_stall_sub(struct at91dci_softc *sc, uint8_t ep_no, 1256184610Salfred uint8_t ep_type, uint8_t ep_dir) 1257184610Salfred{ 1258192984Sthompsa const struct usb_hw_ep_profile *pf; 1259184610Salfred uint32_t csr_val; 1260184610Salfred uint32_t temp; 1261184610Salfred uint8_t csr_reg; 1262184610Salfred uint8_t to; 1263184610Salfred 1264184610Salfred if (ep_type == UE_CONTROL) { 1265184610Salfred /* clearing stall is not needed */ 1266184610Salfred return; 1267184610Salfred } 1268184610Salfred /* compute CSR register offset */ 1269184610Salfred csr_reg = AT91_UDP_CSR(ep_no); 1270184610Salfred 1271184610Salfred /* compute default CSR value */ 1272184610Salfred csr_val = 0; 1273184610Salfred AT91_CSR_ACK(csr_val, 0); 1274184610Salfred 1275184610Salfred /* disable endpoint */ 1276184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1277184610Salfred 1278184610Salfred /* get endpoint profile */ 1279184610Salfred at91dci_get_hw_ep_profile(NULL, &pf, ep_no); 1280184610Salfred 1281184610Salfred /* reset FIFO */ 1282184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(ep_no)); 1283184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0); 1284184610Salfred 1285184610Salfred /* 1286184610Salfred * NOTE: One would assume that a FIFO reset would release the 1287184610Salfred * FIFO banks aswell, but it doesn't! We have to do this 1288184610Salfred * manually! 1289184610Salfred */ 1290184610Salfred 1291184610Salfred /* release FIFO banks, if any */ 1292184610Salfred for (to = 0; to != 2; to++) { 1293184610Salfred 1294184610Salfred /* get csr value */ 1295184610Salfred csr_val = AT91_UDP_READ_4(sc, csr_reg); 1296184610Salfred 1297184610Salfred if (csr_val & (AT91_UDP_CSR_RX_DATA_BK0 | 1298184610Salfred AT91_UDP_CSR_RX_DATA_BK1)) { 1299184610Salfred /* clear status bits */ 1300184610Salfred if (pf->support_multi_buffer) { 1301184610Salfred if (sc->sc_ep_flags[ep_no].fifo_bank) { 1302184610Salfred sc->sc_ep_flags[ep_no].fifo_bank = 0; 1303184610Salfred temp = AT91_UDP_CSR_RX_DATA_BK1; 1304184610Salfred } else { 1305184610Salfred sc->sc_ep_flags[ep_no].fifo_bank = 1; 1306184610Salfred temp = AT91_UDP_CSR_RX_DATA_BK0; 1307184610Salfred } 1308184610Salfred } else { 1309184610Salfred temp = (AT91_UDP_CSR_RX_DATA_BK0 | 1310184610Salfred AT91_UDP_CSR_RX_DATA_BK1); 1311184610Salfred } 1312184610Salfred } else { 1313184610Salfred temp = 0; 1314184610Salfred } 1315184610Salfred 1316184610Salfred /* clear FORCESTALL */ 1317184610Salfred temp |= AT91_UDP_CSR_STALLSENT; 1318184610Salfred 1319184610Salfred AT91_CSR_ACK(csr_val, temp); 1320184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1321184610Salfred } 1322184610Salfred 1323184610Salfred /* compute default CSR value */ 1324184610Salfred csr_val = 0; 1325184610Salfred AT91_CSR_ACK(csr_val, 0); 1326184610Salfred 1327184610Salfred /* enable endpoint */ 1328184610Salfred csr_val &= ~AT91_UDP_CSR_ET_MASK; 1329184610Salfred csr_val |= AT91_UDP_CSR_EPEDS; 1330184610Salfred 1331184610Salfred if (ep_type == UE_CONTROL) { 1332184610Salfred csr_val |= AT91_UDP_CSR_ET_CTRL; 1333184610Salfred } else { 1334184610Salfred if (ep_type == UE_BULK) { 1335184610Salfred csr_val |= AT91_UDP_CSR_ET_BULK; 1336184610Salfred } else if (ep_type == UE_INTERRUPT) { 1337184610Salfred csr_val |= AT91_UDP_CSR_ET_INT; 1338184610Salfred } else { 1339184610Salfred csr_val |= AT91_UDP_CSR_ET_ISO; 1340184610Salfred } 1341184610Salfred if (ep_dir & UE_DIR_IN) { 1342184610Salfred csr_val |= AT91_UDP_CSR_ET_DIR_IN; 1343184610Salfred } 1344184610Salfred } 1345184610Salfred 1346184610Salfred /* enable endpoint */ 1347184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(ep_no), csr_val); 1348184610Salfred} 1349184610Salfred 1350184610Salfredstatic void 1351193644Sthompsaat91dci_clear_stall(struct usb_device *udev, struct usb_endpoint *ep) 1352184610Salfred{ 1353184610Salfred struct at91dci_softc *sc; 1354192984Sthompsa struct usb_endpoint_descriptor *ed; 1355184610Salfred 1356193644Sthompsa DPRINTFN(5, "endpoint=%p\n", ep); 1357184610Salfred 1358184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 1359184610Salfred 1360184610Salfred /* check mode */ 1361192499Sthompsa if (udev->flags.usb_mode != USB_MODE_DEVICE) { 1362184610Salfred /* not supported */ 1363184610Salfred return; 1364184610Salfred } 1365184610Salfred /* get softc */ 1366184610Salfred sc = AT9100_DCI_BUS2SC(udev->bus); 1367184610Salfred 1368184610Salfred /* get endpoint descriptor */ 1369193644Sthompsa ed = ep->edesc; 1370184610Salfred 1371184610Salfred /* reset endpoint */ 1372184610Salfred at91dci_clear_stall_sub(sc, 1373184610Salfred (ed->bEndpointAddress & UE_ADDR), 1374184610Salfred (ed->bmAttributes & UE_XFERTYPE), 1375184610Salfred (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); 1376184610Salfred} 1377184610Salfred 1378193045Sthompsausb_error_t 1379184610Salfredat91dci_init(struct at91dci_softc *sc) 1380184610Salfred{ 1381184610Salfred uint32_t csr_val; 1382184610Salfred uint8_t n; 1383184610Salfred 1384184610Salfred DPRINTF("start\n"); 1385184610Salfred 1386184610Salfred /* set up the bus structure */ 1387184610Salfred sc->sc_bus.usbrev = USB_REV_1_1; 1388184610Salfred sc->sc_bus.methods = &at91dci_bus_methods; 1389184610Salfred 1390184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1391184610Salfred 1392184610Salfred /* turn on clocks */ 1393184610Salfred 1394184610Salfred if (sc->sc_clocks_on) { 1395184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 1396184610Salfred } 1397184610Salfred /* wait a little for things to stabilise */ 1398194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); 1399184610Salfred 1400184610Salfred /* disable and clear all interrupts */ 1401184610Salfred 1402184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); 1403184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF); 1404184610Salfred 1405184610Salfred /* compute default CSR value */ 1406184610Salfred 1407184610Salfred csr_val = 0; 1408184610Salfred AT91_CSR_ACK(csr_val, 0); 1409184610Salfred 1410184610Salfred /* disable all endpoints */ 1411184610Salfred 1412184610Salfred for (n = 0; n != AT91_UDP_EP_MAX; n++) { 1413184610Salfred 1414184610Salfred /* disable endpoint */ 1415184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(n), csr_val); 1416184610Salfred } 1417184610Salfred 1418184610Salfred /* enable the control endpoint */ 1419184610Salfred 1420184610Salfred AT91_CSR_ACK(csr_val, AT91_UDP_CSR_ET_CTRL | 1421184610Salfred AT91_UDP_CSR_EPEDS); 1422184610Salfred 1423184610Salfred /* write to FIFO control register */ 1424184610Salfred 1425184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(0), csr_val); 1426184610Salfred 1427184610Salfred /* enable the interrupts we want */ 1428184610Salfred 1429184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_BUS); 1430184610Salfred 1431184610Salfred /* turn off clocks */ 1432184610Salfred 1433184610Salfred at91dci_clocks_off(sc); 1434184610Salfred 1435184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1436184610Salfred 1437184610Salfred /* catch any lost interrupts */ 1438184610Salfred 1439184610Salfred at91dci_do_poll(&sc->sc_bus); 1440184610Salfred 1441184610Salfred return (0); /* success */ 1442184610Salfred} 1443184610Salfred 1444184610Salfredvoid 1445184610Salfredat91dci_uninit(struct at91dci_softc *sc) 1446184610Salfred{ 1447184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1448184610Salfred 1449184610Salfred /* disable and clear all interrupts */ 1450184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); 1451184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF); 1452184610Salfred 1453184610Salfred sc->sc_flags.port_powered = 0; 1454184610Salfred sc->sc_flags.status_vbus = 0; 1455184610Salfred sc->sc_flags.status_bus_reset = 0; 1456184610Salfred sc->sc_flags.status_suspend = 0; 1457184610Salfred sc->sc_flags.change_suspend = 0; 1458184610Salfred sc->sc_flags.change_connect = 1; 1459184610Salfred 1460184610Salfred at91dci_pull_down(sc); 1461184610Salfred at91dci_clocks_off(sc); 1462184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1463184610Salfred} 1464184610Salfred 1465184610Salfredvoid 1466184610Salfredat91dci_suspend(struct at91dci_softc *sc) 1467184610Salfred{ 1468184610Salfred return; 1469184610Salfred} 1470184610Salfred 1471184610Salfredvoid 1472184610Salfredat91dci_resume(struct at91dci_softc *sc) 1473184610Salfred{ 1474184610Salfred return; 1475184610Salfred} 1476184610Salfred 1477184610Salfredstatic void 1478192984Sthompsaat91dci_do_poll(struct usb_bus *bus) 1479184610Salfred{ 1480184610Salfred struct at91dci_softc *sc = AT9100_DCI_BUS2SC(bus); 1481184610Salfred 1482184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1483184610Salfred at91dci_interrupt_poll(sc); 1484184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1485184610Salfred} 1486184610Salfred 1487184610Salfred/*------------------------------------------------------------------------* 1488184610Salfred * at91dci bulk support 1489184610Salfred *------------------------------------------------------------------------*/ 1490184610Salfredstatic void 1491192984Sthompsaat91dci_device_bulk_open(struct usb_xfer *xfer) 1492184610Salfred{ 1493184610Salfred return; 1494184610Salfred} 1495184610Salfred 1496184610Salfredstatic void 1497192984Sthompsaat91dci_device_bulk_close(struct usb_xfer *xfer) 1498184610Salfred{ 1499184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1500184610Salfred} 1501184610Salfred 1502184610Salfredstatic void 1503192984Sthompsaat91dci_device_bulk_enter(struct usb_xfer *xfer) 1504184610Salfred{ 1505184610Salfred return; 1506184610Salfred} 1507184610Salfred 1508184610Salfredstatic void 1509192984Sthompsaat91dci_device_bulk_start(struct usb_xfer *xfer) 1510184610Salfred{ 1511184610Salfred /* setup TDs */ 1512184610Salfred at91dci_setup_standard_chain(xfer); 1513184610Salfred at91dci_start_standard_chain(xfer); 1514184610Salfred} 1515184610Salfred 1516192984Sthompsastruct usb_pipe_methods at91dci_device_bulk_methods = 1517184610Salfred{ 1518184610Salfred .open = at91dci_device_bulk_open, 1519184610Salfred .close = at91dci_device_bulk_close, 1520184610Salfred .enter = at91dci_device_bulk_enter, 1521184610Salfred .start = at91dci_device_bulk_start, 1522184610Salfred}; 1523184610Salfred 1524184610Salfred/*------------------------------------------------------------------------* 1525184610Salfred * at91dci control support 1526184610Salfred *------------------------------------------------------------------------*/ 1527184610Salfredstatic void 1528192984Sthompsaat91dci_device_ctrl_open(struct usb_xfer *xfer) 1529184610Salfred{ 1530184610Salfred return; 1531184610Salfred} 1532184610Salfred 1533184610Salfredstatic void 1534192984Sthompsaat91dci_device_ctrl_close(struct usb_xfer *xfer) 1535184610Salfred{ 1536184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1537184610Salfred} 1538184610Salfred 1539184610Salfredstatic void 1540192984Sthompsaat91dci_device_ctrl_enter(struct usb_xfer *xfer) 1541184610Salfred{ 1542184610Salfred return; 1543184610Salfred} 1544184610Salfred 1545184610Salfredstatic void 1546192984Sthompsaat91dci_device_ctrl_start(struct usb_xfer *xfer) 1547184610Salfred{ 1548184610Salfred /* setup TDs */ 1549184610Salfred at91dci_setup_standard_chain(xfer); 1550184610Salfred at91dci_start_standard_chain(xfer); 1551184610Salfred} 1552184610Salfred 1553192984Sthompsastruct usb_pipe_methods at91dci_device_ctrl_methods = 1554184610Salfred{ 1555184610Salfred .open = at91dci_device_ctrl_open, 1556184610Salfred .close = at91dci_device_ctrl_close, 1557184610Salfred .enter = at91dci_device_ctrl_enter, 1558184610Salfred .start = at91dci_device_ctrl_start, 1559184610Salfred}; 1560184610Salfred 1561184610Salfred/*------------------------------------------------------------------------* 1562184610Salfred * at91dci interrupt support 1563184610Salfred *------------------------------------------------------------------------*/ 1564184610Salfredstatic void 1565192984Sthompsaat91dci_device_intr_open(struct usb_xfer *xfer) 1566184610Salfred{ 1567184610Salfred return; 1568184610Salfred} 1569184610Salfred 1570184610Salfredstatic void 1571192984Sthompsaat91dci_device_intr_close(struct usb_xfer *xfer) 1572184610Salfred{ 1573184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1574184610Salfred} 1575184610Salfred 1576184610Salfredstatic void 1577192984Sthompsaat91dci_device_intr_enter(struct usb_xfer *xfer) 1578184610Salfred{ 1579184610Salfred return; 1580184610Salfred} 1581184610Salfred 1582184610Salfredstatic void 1583192984Sthompsaat91dci_device_intr_start(struct usb_xfer *xfer) 1584184610Salfred{ 1585184610Salfred /* setup TDs */ 1586184610Salfred at91dci_setup_standard_chain(xfer); 1587184610Salfred at91dci_start_standard_chain(xfer); 1588184610Salfred} 1589184610Salfred 1590192984Sthompsastruct usb_pipe_methods at91dci_device_intr_methods = 1591184610Salfred{ 1592184610Salfred .open = at91dci_device_intr_open, 1593184610Salfred .close = at91dci_device_intr_close, 1594184610Salfred .enter = at91dci_device_intr_enter, 1595184610Salfred .start = at91dci_device_intr_start, 1596184610Salfred}; 1597184610Salfred 1598184610Salfred/*------------------------------------------------------------------------* 1599184610Salfred * at91dci full speed isochronous support 1600184610Salfred *------------------------------------------------------------------------*/ 1601184610Salfredstatic void 1602192984Sthompsaat91dci_device_isoc_fs_open(struct usb_xfer *xfer) 1603184610Salfred{ 1604184610Salfred return; 1605184610Salfred} 1606184610Salfred 1607184610Salfredstatic void 1608192984Sthompsaat91dci_device_isoc_fs_close(struct usb_xfer *xfer) 1609184610Salfred{ 1610184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1611184610Salfred} 1612184610Salfred 1613184610Salfredstatic void 1614192984Sthompsaat91dci_device_isoc_fs_enter(struct usb_xfer *xfer) 1615184610Salfred{ 1616187173Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1617184610Salfred uint32_t temp; 1618184610Salfred uint32_t nframes; 1619184610Salfred 1620184610Salfred DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", 1621193644Sthompsa xfer, xfer->endpoint->isoc_next, xfer->nframes); 1622184610Salfred 1623184610Salfred /* get the current frame index */ 1624184610Salfred 1625184610Salfred nframes = AT91_UDP_READ_4(sc, AT91_UDP_FRM); 1626184610Salfred 1627184610Salfred /* 1628184610Salfred * check if the frame index is within the window where the frames 1629184610Salfred * will be inserted 1630184610Salfred */ 1631193644Sthompsa temp = (nframes - xfer->endpoint->isoc_next) & AT91_UDP_FRM_MASK; 1632184610Salfred 1633193644Sthompsa if ((xfer->endpoint->is_synced == 0) || 1634184610Salfred (temp < xfer->nframes)) { 1635184610Salfred /* 1636193644Sthompsa * If there is data underflow or the endpoint queue is 1637184610Salfred * empty we schedule the transfer a few frames ahead 1638184610Salfred * of the current frame position. Else two isochronous 1639184610Salfred * transfers might overlap. 1640184610Salfred */ 1641193644Sthompsa xfer->endpoint->isoc_next = (nframes + 3) & AT91_UDP_FRM_MASK; 1642193644Sthompsa xfer->endpoint->is_synced = 1; 1643193644Sthompsa DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next); 1644184610Salfred } 1645184610Salfred /* 1646184610Salfred * compute how many milliseconds the insertion is ahead of the 1647184610Salfred * current frame position: 1648184610Salfred */ 1649193644Sthompsa temp = (xfer->endpoint->isoc_next - nframes) & AT91_UDP_FRM_MASK; 1650184610Salfred 1651184610Salfred /* 1652184610Salfred * pre-compute when the isochronous transfer will be finished: 1653184610Salfred */ 1654184610Salfred xfer->isoc_time_complete = 1655194228Sthompsa usb_isoc_time_expand(&sc->sc_bus, nframes) + temp + 1656184610Salfred xfer->nframes; 1657184610Salfred 1658184610Salfred /* compute frame number for next insertion */ 1659193644Sthompsa xfer->endpoint->isoc_next += xfer->nframes; 1660184610Salfred 1661184610Salfred /* setup TDs */ 1662184610Salfred at91dci_setup_standard_chain(xfer); 1663184610Salfred} 1664184610Salfred 1665184610Salfredstatic void 1666192984Sthompsaat91dci_device_isoc_fs_start(struct usb_xfer *xfer) 1667184610Salfred{ 1668184610Salfred /* start TD chain */ 1669184610Salfred at91dci_start_standard_chain(xfer); 1670184610Salfred} 1671184610Salfred 1672192984Sthompsastruct usb_pipe_methods at91dci_device_isoc_fs_methods = 1673184610Salfred{ 1674184610Salfred .open = at91dci_device_isoc_fs_open, 1675184610Salfred .close = at91dci_device_isoc_fs_close, 1676184610Salfred .enter = at91dci_device_isoc_fs_enter, 1677184610Salfred .start = at91dci_device_isoc_fs_start, 1678184610Salfred}; 1679184610Salfred 1680184610Salfred/*------------------------------------------------------------------------* 1681184610Salfred * at91dci root control support 1682184610Salfred *------------------------------------------------------------------------* 1683190735Sthompsa * Simulate a hardware HUB by handling all the necessary requests. 1684184610Salfred *------------------------------------------------------------------------*/ 1685184610Salfred 1686192984Sthompsastatic const struct usb_device_descriptor at91dci_devd = { 1687192984Sthompsa .bLength = sizeof(struct usb_device_descriptor), 1688184610Salfred .bDescriptorType = UDESC_DEVICE, 1689184610Salfred .bcdUSB = {0x00, 0x02}, 1690184610Salfred .bDeviceClass = UDCLASS_HUB, 1691184610Salfred .bDeviceSubClass = UDSUBCLASS_HUB, 1692184610Salfred .bDeviceProtocol = UDPROTO_HSHUBSTT, 1693184610Salfred .bMaxPacketSize = 64, 1694184610Salfred .bcdDevice = {0x00, 0x01}, 1695184610Salfred .iManufacturer = 1, 1696184610Salfred .iProduct = 2, 1697184610Salfred .bNumConfigurations = 1, 1698184610Salfred}; 1699184610Salfred 1700192984Sthompsastatic const struct usb_device_qualifier at91dci_odevd = { 1701192984Sthompsa .bLength = sizeof(struct usb_device_qualifier), 1702184610Salfred .bDescriptorType = UDESC_DEVICE_QUALIFIER, 1703184610Salfred .bcdUSB = {0x00, 0x02}, 1704184610Salfred .bDeviceClass = UDCLASS_HUB, 1705184610Salfred .bDeviceSubClass = UDSUBCLASS_HUB, 1706184610Salfred .bDeviceProtocol = UDPROTO_FSHUB, 1707184610Salfred .bMaxPacketSize0 = 0, 1708184610Salfred .bNumConfigurations = 0, 1709184610Salfred}; 1710184610Salfred 1711184610Salfredstatic const struct at91dci_config_desc at91dci_confd = { 1712184610Salfred .confd = { 1713192984Sthompsa .bLength = sizeof(struct usb_config_descriptor), 1714184610Salfred .bDescriptorType = UDESC_CONFIG, 1715184610Salfred .wTotalLength[0] = sizeof(at91dci_confd), 1716184610Salfred .bNumInterface = 1, 1717184610Salfred .bConfigurationValue = 1, 1718184610Salfred .iConfiguration = 0, 1719184610Salfred .bmAttributes = UC_SELF_POWERED, 1720184610Salfred .bMaxPower = 0, 1721184610Salfred }, 1722184610Salfred .ifcd = { 1723192984Sthompsa .bLength = sizeof(struct usb_interface_descriptor), 1724184610Salfred .bDescriptorType = UDESC_INTERFACE, 1725184610Salfred .bNumEndpoints = 1, 1726184610Salfred .bInterfaceClass = UICLASS_HUB, 1727184610Salfred .bInterfaceSubClass = UISUBCLASS_HUB, 1728184610Salfred .bInterfaceProtocol = UIPROTO_HSHUBSTT, 1729184610Salfred }, 1730184610Salfred .endpd = { 1731192984Sthompsa .bLength = sizeof(struct usb_endpoint_descriptor), 1732184610Salfred .bDescriptorType = UDESC_ENDPOINT, 1733184610Salfred .bEndpointAddress = (UE_DIR_IN | AT9100_DCI_INTR_ENDPT), 1734184610Salfred .bmAttributes = UE_INTERRUPT, 1735184610Salfred .wMaxPacketSize[0] = 8, 1736184610Salfred .bInterval = 255, 1737184610Salfred }, 1738184610Salfred}; 1739184610Salfred 1740192984Sthompsastatic const struct usb_hub_descriptor_min at91dci_hubd = { 1741184610Salfred .bDescLength = sizeof(at91dci_hubd), 1742184610Salfred .bDescriptorType = UDESC_HUB, 1743184610Salfred .bNbrPorts = 1, 1744184610Salfred .wHubCharacteristics[0] = 1745184610Salfred (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) & 0xFF, 1746184610Salfred .wHubCharacteristics[1] = 1747187183Sthompsa (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) >> 8, 1748184610Salfred .bPwrOn2PwrGood = 50, 1749184610Salfred .bHubContrCurrent = 0, 1750184610Salfred .DeviceRemovable = {0}, /* port is removable */ 1751184610Salfred}; 1752184610Salfred 1753184610Salfred#define STRING_LANG \ 1754184610Salfred 0x09, 0x04, /* American English */ 1755184610Salfred 1756184610Salfred#define STRING_VENDOR \ 1757184610Salfred 'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L', 0 1758184610Salfred 1759184610Salfred#define STRING_PRODUCT \ 1760184610Salfred 'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \ 1761184610Salfred 'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \ 1762184610Salfred 'U', 0, 'B', 0, 1763184610Salfred 1764184610SalfredUSB_MAKE_STRING_DESC(STRING_LANG, at91dci_langtab); 1765184610SalfredUSB_MAKE_STRING_DESC(STRING_VENDOR, at91dci_vendor); 1766184610SalfredUSB_MAKE_STRING_DESC(STRING_PRODUCT, at91dci_product); 1767184610Salfred 1768193045Sthompsastatic usb_error_t 1769192984Sthompsaat91dci_roothub_exec(struct usb_device *udev, 1770192984Sthompsa struct usb_device_request *req, const void **pptr, uint16_t *plength) 1771184610Salfred{ 1772191402Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus); 1773191402Sthompsa const void *ptr; 1774191402Sthompsa uint16_t len; 1775184610Salfred uint16_t value; 1776184610Salfred uint16_t index; 1777193045Sthompsa usb_error_t err; 1778184610Salfred 1779184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1780184610Salfred 1781184610Salfred /* buffer reset */ 1782191402Sthompsa ptr = (const void *)&sc->sc_hub_temp; 1783191402Sthompsa len = 0; 1784191402Sthompsa err = 0; 1785184610Salfred 1786191402Sthompsa value = UGETW(req->wValue); 1787191402Sthompsa index = UGETW(req->wIndex); 1788184610Salfred 1789184610Salfred /* demultiplex the control request */ 1790184610Salfred 1791191402Sthompsa switch (req->bmRequestType) { 1792184610Salfred case UT_READ_DEVICE: 1793191402Sthompsa switch (req->bRequest) { 1794184610Salfred case UR_GET_DESCRIPTOR: 1795184610Salfred goto tr_handle_get_descriptor; 1796184610Salfred case UR_GET_CONFIG: 1797184610Salfred goto tr_handle_get_config; 1798184610Salfred case UR_GET_STATUS: 1799184610Salfred goto tr_handle_get_status; 1800184610Salfred default: 1801184610Salfred goto tr_stalled; 1802184610Salfred } 1803184610Salfred break; 1804184610Salfred 1805184610Salfred case UT_WRITE_DEVICE: 1806191402Sthompsa switch (req->bRequest) { 1807184610Salfred case UR_SET_ADDRESS: 1808184610Salfred goto tr_handle_set_address; 1809184610Salfred case UR_SET_CONFIG: 1810184610Salfred goto tr_handle_set_config; 1811184610Salfred case UR_CLEAR_FEATURE: 1812184610Salfred goto tr_valid; /* nop */ 1813184610Salfred case UR_SET_DESCRIPTOR: 1814184610Salfred goto tr_valid; /* nop */ 1815184610Salfred case UR_SET_FEATURE: 1816184610Salfred default: 1817184610Salfred goto tr_stalled; 1818184610Salfred } 1819184610Salfred break; 1820184610Salfred 1821184610Salfred case UT_WRITE_ENDPOINT: 1822191402Sthompsa switch (req->bRequest) { 1823184610Salfred case UR_CLEAR_FEATURE: 1824191402Sthompsa switch (UGETW(req->wValue)) { 1825184610Salfred case UF_ENDPOINT_HALT: 1826184610Salfred goto tr_handle_clear_halt; 1827184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 1828184610Salfred goto tr_handle_clear_wakeup; 1829184610Salfred default: 1830184610Salfred goto tr_stalled; 1831184610Salfred } 1832184610Salfred break; 1833184610Salfred case UR_SET_FEATURE: 1834191402Sthompsa switch (UGETW(req->wValue)) { 1835184610Salfred case UF_ENDPOINT_HALT: 1836184610Salfred goto tr_handle_set_halt; 1837184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 1838184610Salfred goto tr_handle_set_wakeup; 1839184610Salfred default: 1840184610Salfred goto tr_stalled; 1841184610Salfred } 1842184610Salfred break; 1843184610Salfred case UR_SYNCH_FRAME: 1844184610Salfred goto tr_valid; /* nop */ 1845184610Salfred default: 1846184610Salfred goto tr_stalled; 1847184610Salfred } 1848184610Salfred break; 1849184610Salfred 1850184610Salfred case UT_READ_ENDPOINT: 1851191402Sthompsa switch (req->bRequest) { 1852184610Salfred case UR_GET_STATUS: 1853184610Salfred goto tr_handle_get_ep_status; 1854184610Salfred default: 1855184610Salfred goto tr_stalled; 1856184610Salfred } 1857184610Salfred break; 1858184610Salfred 1859184610Salfred case UT_WRITE_INTERFACE: 1860191402Sthompsa switch (req->bRequest) { 1861184610Salfred case UR_SET_INTERFACE: 1862184610Salfred goto tr_handle_set_interface; 1863184610Salfred case UR_CLEAR_FEATURE: 1864184610Salfred goto tr_valid; /* nop */ 1865184610Salfred case UR_SET_FEATURE: 1866184610Salfred default: 1867184610Salfred goto tr_stalled; 1868184610Salfred } 1869184610Salfred break; 1870184610Salfred 1871184610Salfred case UT_READ_INTERFACE: 1872191402Sthompsa switch (req->bRequest) { 1873184610Salfred case UR_GET_INTERFACE: 1874184610Salfred goto tr_handle_get_interface; 1875184610Salfred case UR_GET_STATUS: 1876184610Salfred goto tr_handle_get_iface_status; 1877184610Salfred default: 1878184610Salfred goto tr_stalled; 1879184610Salfred } 1880184610Salfred break; 1881184610Salfred 1882184610Salfred case UT_WRITE_CLASS_INTERFACE: 1883184610Salfred case UT_WRITE_VENDOR_INTERFACE: 1884184610Salfred /* XXX forward */ 1885184610Salfred break; 1886184610Salfred 1887184610Salfred case UT_READ_CLASS_INTERFACE: 1888184610Salfred case UT_READ_VENDOR_INTERFACE: 1889184610Salfred /* XXX forward */ 1890184610Salfred break; 1891184610Salfred 1892184610Salfred case UT_WRITE_CLASS_DEVICE: 1893191402Sthompsa switch (req->bRequest) { 1894184610Salfred case UR_CLEAR_FEATURE: 1895184610Salfred goto tr_valid; 1896184610Salfred case UR_SET_DESCRIPTOR: 1897184610Salfred case UR_SET_FEATURE: 1898184610Salfred break; 1899184610Salfred default: 1900184610Salfred goto tr_stalled; 1901184610Salfred } 1902184610Salfred break; 1903184610Salfred 1904184610Salfred case UT_WRITE_CLASS_OTHER: 1905191402Sthompsa switch (req->bRequest) { 1906184610Salfred case UR_CLEAR_FEATURE: 1907184610Salfred goto tr_handle_clear_port_feature; 1908184610Salfred case UR_SET_FEATURE: 1909184610Salfred goto tr_handle_set_port_feature; 1910184610Salfred case UR_CLEAR_TT_BUFFER: 1911184610Salfred case UR_RESET_TT: 1912184610Salfred case UR_STOP_TT: 1913184610Salfred goto tr_valid; 1914184610Salfred 1915184610Salfred default: 1916184610Salfred goto tr_stalled; 1917184610Salfred } 1918184610Salfred break; 1919184610Salfred 1920184610Salfred case UT_READ_CLASS_OTHER: 1921191402Sthompsa switch (req->bRequest) { 1922184610Salfred case UR_GET_TT_STATE: 1923184610Salfred goto tr_handle_get_tt_state; 1924184610Salfred case UR_GET_STATUS: 1925184610Salfred goto tr_handle_get_port_status; 1926184610Salfred default: 1927184610Salfred goto tr_stalled; 1928184610Salfred } 1929184610Salfred break; 1930184610Salfred 1931184610Salfred case UT_READ_CLASS_DEVICE: 1932191402Sthompsa switch (req->bRequest) { 1933184610Salfred case UR_GET_DESCRIPTOR: 1934184610Salfred goto tr_handle_get_class_descriptor; 1935184610Salfred case UR_GET_STATUS: 1936184610Salfred goto tr_handle_get_class_status; 1937184610Salfred 1938184610Salfred default: 1939184610Salfred goto tr_stalled; 1940184610Salfred } 1941184610Salfred break; 1942184610Salfred default: 1943184610Salfred goto tr_stalled; 1944184610Salfred } 1945184610Salfred goto tr_valid; 1946184610Salfred 1947184610Salfredtr_handle_get_descriptor: 1948184610Salfred switch (value >> 8) { 1949184610Salfred case UDESC_DEVICE: 1950184610Salfred if (value & 0xff) { 1951184610Salfred goto tr_stalled; 1952184610Salfred } 1953191402Sthompsa len = sizeof(at91dci_devd); 1954191402Sthompsa ptr = (const void *)&at91dci_devd; 1955184610Salfred goto tr_valid; 1956184610Salfred case UDESC_CONFIG: 1957184610Salfred if (value & 0xff) { 1958184610Salfred goto tr_stalled; 1959184610Salfred } 1960191402Sthompsa len = sizeof(at91dci_confd); 1961191402Sthompsa ptr = (const void *)&at91dci_confd; 1962184610Salfred goto tr_valid; 1963184610Salfred case UDESC_STRING: 1964184610Salfred switch (value & 0xff) { 1965184610Salfred case 0: /* Language table */ 1966191402Sthompsa len = sizeof(at91dci_langtab); 1967191402Sthompsa ptr = (const void *)&at91dci_langtab; 1968184610Salfred goto tr_valid; 1969184610Salfred 1970184610Salfred case 1: /* Vendor */ 1971191402Sthompsa len = sizeof(at91dci_vendor); 1972191402Sthompsa ptr = (const void *)&at91dci_vendor; 1973184610Salfred goto tr_valid; 1974184610Salfred 1975184610Salfred case 2: /* Product */ 1976191402Sthompsa len = sizeof(at91dci_product); 1977191402Sthompsa ptr = (const void *)&at91dci_product; 1978184610Salfred goto tr_valid; 1979184610Salfred default: 1980184610Salfred break; 1981184610Salfred } 1982184610Salfred break; 1983184610Salfred default: 1984184610Salfred goto tr_stalled; 1985184610Salfred } 1986184610Salfred goto tr_stalled; 1987184610Salfred 1988184610Salfredtr_handle_get_config: 1989191402Sthompsa len = 1; 1990184610Salfred sc->sc_hub_temp.wValue[0] = sc->sc_conf; 1991184610Salfred goto tr_valid; 1992184610Salfred 1993184610Salfredtr_handle_get_status: 1994191402Sthompsa len = 2; 1995184610Salfred USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); 1996184610Salfred goto tr_valid; 1997184610Salfred 1998184610Salfredtr_handle_set_address: 1999184610Salfred if (value & 0xFF00) { 2000184610Salfred goto tr_stalled; 2001184610Salfred } 2002184610Salfred sc->sc_rt_addr = value; 2003184610Salfred goto tr_valid; 2004184610Salfred 2005184610Salfredtr_handle_set_config: 2006184610Salfred if (value >= 2) { 2007184610Salfred goto tr_stalled; 2008184610Salfred } 2009184610Salfred sc->sc_conf = value; 2010184610Salfred goto tr_valid; 2011184610Salfred 2012184610Salfredtr_handle_get_interface: 2013191402Sthompsa len = 1; 2014184610Salfred sc->sc_hub_temp.wValue[0] = 0; 2015184610Salfred goto tr_valid; 2016184610Salfred 2017184610Salfredtr_handle_get_tt_state: 2018184610Salfredtr_handle_get_class_status: 2019184610Salfredtr_handle_get_iface_status: 2020184610Salfredtr_handle_get_ep_status: 2021191402Sthompsa len = 2; 2022184610Salfred USETW(sc->sc_hub_temp.wValue, 0); 2023184610Salfred goto tr_valid; 2024184610Salfred 2025184610Salfredtr_handle_set_halt: 2026184610Salfredtr_handle_set_interface: 2027184610Salfredtr_handle_set_wakeup: 2028184610Salfredtr_handle_clear_wakeup: 2029184610Salfredtr_handle_clear_halt: 2030184610Salfred goto tr_valid; 2031184610Salfred 2032184610Salfredtr_handle_clear_port_feature: 2033184610Salfred if (index != 1) { 2034184610Salfred goto tr_stalled; 2035184610Salfred } 2036184610Salfred DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index); 2037184610Salfred 2038184610Salfred switch (value) { 2039184610Salfred case UHF_PORT_SUSPEND: 2040190735Sthompsa at91dci_wakeup_peer(sc); 2041184610Salfred break; 2042184610Salfred 2043184610Salfred case UHF_PORT_ENABLE: 2044184610Salfred sc->sc_flags.port_enabled = 0; 2045184610Salfred break; 2046184610Salfred 2047184610Salfred case UHF_PORT_TEST: 2048184610Salfred case UHF_PORT_INDICATOR: 2049184610Salfred case UHF_C_PORT_ENABLE: 2050184610Salfred case UHF_C_PORT_OVER_CURRENT: 2051184610Salfred case UHF_C_PORT_RESET: 2052184610Salfred /* nops */ 2053184610Salfred break; 2054184610Salfred case UHF_PORT_POWER: 2055184610Salfred sc->sc_flags.port_powered = 0; 2056184610Salfred at91dci_pull_down(sc); 2057184610Salfred at91dci_clocks_off(sc); 2058184610Salfred break; 2059184610Salfred case UHF_C_PORT_CONNECTION: 2060184610Salfred sc->sc_flags.change_connect = 0; 2061184610Salfred break; 2062184610Salfred case UHF_C_PORT_SUSPEND: 2063184610Salfred sc->sc_flags.change_suspend = 0; 2064184610Salfred break; 2065184610Salfred default: 2066191402Sthompsa err = USB_ERR_IOERROR; 2067184610Salfred goto done; 2068184610Salfred } 2069184610Salfred goto tr_valid; 2070184610Salfred 2071184610Salfredtr_handle_set_port_feature: 2072184610Salfred if (index != 1) { 2073184610Salfred goto tr_stalled; 2074184610Salfred } 2075184610Salfred DPRINTFN(9, "UR_SET_PORT_FEATURE\n"); 2076184610Salfred 2077184610Salfred switch (value) { 2078184610Salfred case UHF_PORT_ENABLE: 2079184610Salfred sc->sc_flags.port_enabled = 1; 2080184610Salfred break; 2081184610Salfred case UHF_PORT_SUSPEND: 2082184610Salfred case UHF_PORT_RESET: 2083184610Salfred case UHF_PORT_TEST: 2084184610Salfred case UHF_PORT_INDICATOR: 2085184610Salfred /* nops */ 2086184610Salfred break; 2087184610Salfred case UHF_PORT_POWER: 2088184610Salfred sc->sc_flags.port_powered = 1; 2089184610Salfred break; 2090184610Salfred default: 2091191402Sthompsa err = USB_ERR_IOERROR; 2092184610Salfred goto done; 2093184610Salfred } 2094184610Salfred goto tr_valid; 2095184610Salfred 2096184610Salfredtr_handle_get_port_status: 2097184610Salfred 2098184610Salfred DPRINTFN(9, "UR_GET_PORT_STATUS\n"); 2099184610Salfred 2100184610Salfred if (index != 1) { 2101184610Salfred goto tr_stalled; 2102184610Salfred } 2103184610Salfred if (sc->sc_flags.status_vbus) { 2104184610Salfred at91dci_clocks_on(sc); 2105184610Salfred at91dci_pull_up(sc); 2106184610Salfred } else { 2107184610Salfred at91dci_pull_down(sc); 2108184610Salfred at91dci_clocks_off(sc); 2109184610Salfred } 2110184610Salfred 2111184610Salfred /* Select FULL-speed and Device Side Mode */ 2112184610Salfred 2113184610Salfred value = UPS_PORT_MODE_DEVICE; 2114184610Salfred 2115184610Salfred if (sc->sc_flags.port_powered) { 2116184610Salfred value |= UPS_PORT_POWER; 2117184610Salfred } 2118184610Salfred if (sc->sc_flags.port_enabled) { 2119184610Salfred value |= UPS_PORT_ENABLED; 2120184610Salfred } 2121184610Salfred if (sc->sc_flags.status_vbus && 2122184610Salfred sc->sc_flags.status_bus_reset) { 2123184610Salfred value |= UPS_CURRENT_CONNECT_STATUS; 2124184610Salfred } 2125184610Salfred if (sc->sc_flags.status_suspend) { 2126184610Salfred value |= UPS_SUSPEND; 2127184610Salfred } 2128184610Salfred USETW(sc->sc_hub_temp.ps.wPortStatus, value); 2129184610Salfred 2130184610Salfred value = 0; 2131184610Salfred 2132184610Salfred if (sc->sc_flags.change_connect) { 2133184610Salfred value |= UPS_C_CONNECT_STATUS; 2134184610Salfred 2135184610Salfred if (sc->sc_flags.status_vbus && 2136184610Salfred sc->sc_flags.status_bus_reset) { 2137184610Salfred /* reset endpoint flags */ 2138184610Salfred bzero(sc->sc_ep_flags, sizeof(sc->sc_ep_flags)); 2139184610Salfred } 2140184610Salfred } 2141184610Salfred if (sc->sc_flags.change_suspend) { 2142184610Salfred value |= UPS_C_SUSPEND; 2143184610Salfred } 2144184610Salfred USETW(sc->sc_hub_temp.ps.wPortChange, value); 2145191402Sthompsa len = sizeof(sc->sc_hub_temp.ps); 2146184610Salfred goto tr_valid; 2147184610Salfred 2148184610Salfredtr_handle_get_class_descriptor: 2149184610Salfred if (value & 0xFF) { 2150184610Salfred goto tr_stalled; 2151184610Salfred } 2152191402Sthompsa ptr = (const void *)&at91dci_hubd; 2153191402Sthompsa len = sizeof(at91dci_hubd); 2154184610Salfred goto tr_valid; 2155184610Salfred 2156184610Salfredtr_stalled: 2157191402Sthompsa err = USB_ERR_STALLED; 2158184610Salfredtr_valid: 2159184610Salfreddone: 2160191402Sthompsa *plength = len; 2161191402Sthompsa *pptr = ptr; 2162191402Sthompsa return (err); 2163184610Salfred} 2164184610Salfred 2165184610Salfredstatic void 2166192984Sthompsaat91dci_xfer_setup(struct usb_setup_params *parm) 2167184610Salfred{ 2168192984Sthompsa const struct usb_hw_ep_profile *pf; 2169184610Salfred struct at91dci_softc *sc; 2170192984Sthompsa struct usb_xfer *xfer; 2171184610Salfred void *last_obj; 2172184610Salfred uint32_t ntd; 2173184610Salfred uint32_t n; 2174184610Salfred uint8_t ep_no; 2175184610Salfred 2176184610Salfred sc = AT9100_DCI_BUS2SC(parm->udev->bus); 2177184610Salfred xfer = parm->curr_xfer; 2178184610Salfred 2179184610Salfred /* 2180184610Salfred * NOTE: This driver does not use any of the parameters that 2181184610Salfred * are computed from the following values. Just set some 2182184610Salfred * reasonable dummies: 2183184610Salfred */ 2184184610Salfred parm->hc_max_packet_size = 0x500; 2185184610Salfred parm->hc_max_packet_count = 1; 2186184610Salfred parm->hc_max_frame_size = 0x500; 2187184610Salfred 2188194228Sthompsa usbd_transfer_setup_sub(parm); 2189184610Salfred 2190184610Salfred /* 2191184610Salfred * compute maximum number of TDs 2192184610Salfred */ 2193184610Salfred if (parm->methods == &at91dci_device_ctrl_methods) { 2194184610Salfred 2195184610Salfred ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */ 2196184610Salfred + 1 /* SYNC 2 */ ; 2197184610Salfred 2198184610Salfred } else if (parm->methods == &at91dci_device_bulk_methods) { 2199184610Salfred 2200184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2201184610Salfred 2202184610Salfred } else if (parm->methods == &at91dci_device_intr_methods) { 2203184610Salfred 2204184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2205184610Salfred 2206184610Salfred } else if (parm->methods == &at91dci_device_isoc_fs_methods) { 2207184610Salfred 2208184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2209184610Salfred 2210184610Salfred } else { 2211184610Salfred 2212184610Salfred ntd = 0; 2213184610Salfred } 2214184610Salfred 2215184610Salfred /* 2216194228Sthompsa * check if "usbd_transfer_setup_sub" set an error 2217184610Salfred */ 2218184610Salfred if (parm->err) { 2219184610Salfred return; 2220184610Salfred } 2221184610Salfred /* 2222184610Salfred * allocate transfer descriptors 2223184610Salfred */ 2224184610Salfred last_obj = NULL; 2225184610Salfred 2226184610Salfred /* 2227184610Salfred * get profile stuff 2228184610Salfred */ 2229184610Salfred if (ntd) { 2230184610Salfred 2231193644Sthompsa ep_no = xfer->endpointno & UE_ADDR; 2232184610Salfred at91dci_get_hw_ep_profile(parm->udev, &pf, ep_no); 2233184610Salfred 2234184610Salfred if (pf == NULL) { 2235184610Salfred /* should not happen */ 2236184610Salfred parm->err = USB_ERR_INVAL; 2237184610Salfred return; 2238184610Salfred } 2239184610Salfred } else { 2240184610Salfred ep_no = 0; 2241184610Salfred pf = NULL; 2242184610Salfred } 2243184610Salfred 2244184610Salfred /* align data */ 2245184610Salfred parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); 2246184610Salfred 2247184610Salfred for (n = 0; n != ntd; n++) { 2248184610Salfred 2249184610Salfred struct at91dci_td *td; 2250184610Salfred 2251184610Salfred if (parm->buf) { 2252184610Salfred 2253184610Salfred td = USB_ADD_BYTES(parm->buf, parm->size[0]); 2254184610Salfred 2255184610Salfred /* init TD */ 2256184610Salfred td->io_tag = sc->sc_io_tag; 2257184610Salfred td->io_hdl = sc->sc_io_hdl; 2258184610Salfred td->max_packet_size = xfer->max_packet_size; 2259184610Salfred td->status_reg = AT91_UDP_CSR(ep_no); 2260184610Salfred td->fifo_reg = AT91_UDP_FDR(ep_no); 2261184610Salfred if (pf->support_multi_buffer) { 2262184610Salfred td->support_multi_buffer = 1; 2263184610Salfred } 2264184610Salfred td->obj_next = last_obj; 2265184610Salfred 2266184610Salfred last_obj = td; 2267184610Salfred } 2268184610Salfred parm->size[0] += sizeof(*td); 2269184610Salfred } 2270184610Salfred 2271184610Salfred xfer->td_start[0] = last_obj; 2272184610Salfred} 2273184610Salfred 2274184610Salfredstatic void 2275192984Sthompsaat91dci_xfer_unsetup(struct usb_xfer *xfer) 2276184610Salfred{ 2277184610Salfred return; 2278184610Salfred} 2279184610Salfred 2280184610Salfredstatic void 2281193644Sthompsaat91dci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, 2282193644Sthompsa struct usb_endpoint *ep) 2283184610Salfred{ 2284184610Salfred struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus); 2285184610Salfred 2286193644Sthompsa DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n", 2287193644Sthompsa ep, udev->address, 2288192499Sthompsa edesc->bEndpointAddress, udev->flags.usb_mode, 2289184610Salfred sc->sc_rt_addr); 2290184610Salfred 2291190735Sthompsa if (udev->device_index != sc->sc_rt_addr) { 2292184610Salfred 2293192499Sthompsa if (udev->flags.usb_mode != USB_MODE_DEVICE) { 2294184610Salfred /* not supported */ 2295184610Salfred return; 2296184610Salfred } 2297184610Salfred if (udev->speed != USB_SPEED_FULL) { 2298184610Salfred /* not supported */ 2299184610Salfred return; 2300184610Salfred } 2301184610Salfred switch (edesc->bmAttributes & UE_XFERTYPE) { 2302184610Salfred case UE_CONTROL: 2303193644Sthompsa ep->methods = &at91dci_device_ctrl_methods; 2304184610Salfred break; 2305184610Salfred case UE_INTERRUPT: 2306193644Sthompsa ep->methods = &at91dci_device_intr_methods; 2307184610Salfred break; 2308184610Salfred case UE_ISOCHRONOUS: 2309193644Sthompsa ep->methods = &at91dci_device_isoc_fs_methods; 2310184610Salfred break; 2311184610Salfred case UE_BULK: 2312193644Sthompsa ep->methods = &at91dci_device_bulk_methods; 2313184610Salfred break; 2314184610Salfred default: 2315184610Salfred /* do nothing */ 2316184610Salfred break; 2317184610Salfred } 2318184610Salfred } 2319184610Salfred} 2320184610Salfred 2321192984Sthompsastruct usb_bus_methods at91dci_bus_methods = 2322184610Salfred{ 2323193644Sthompsa .endpoint_init = &at91dci_ep_init, 2324184610Salfred .xfer_setup = &at91dci_xfer_setup, 2325184610Salfred .xfer_unsetup = &at91dci_xfer_unsetup, 2326184610Salfred .get_hw_ep_profile = &at91dci_get_hw_ep_profile, 2327184610Salfred .set_stall = &at91dci_set_stall, 2328184610Salfred .clear_stall = &at91dci_clear_stall, 2329190735Sthompsa .roothub_exec = &at91dci_roothub_exec, 2330195960Salfred .xfer_poll = &at91dci_do_poll, 2331184610Salfred}; 2332