at91dci.c revision 190754
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/controller/at91dci.c 190754 2009-04-06 00:22:49Z 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 47188942Sthompsa#include <dev/usb/usb.h> 48188942Sthompsa#include <dev/usb/usb_mfunc.h> 49188942Sthompsa#include <dev/usb/usb_error.h> 50184610Salfred 51184610Salfred#define USB_DEBUG_VAR at91dcidebug 52184610Salfred 53188942Sthompsa#include <dev/usb/usb_core.h> 54188942Sthompsa#include <dev/usb/usb_debug.h> 55188942Sthompsa#include <dev/usb/usb_busdma.h> 56188942Sthompsa#include <dev/usb/usb_process.h> 57188942Sthompsa#include <dev/usb/usb_sw_transfer.h> 58188942Sthompsa#include <dev/usb/usb_transfer.h> 59188942Sthompsa#include <dev/usb/usb_device.h> 60188942Sthompsa#include <dev/usb/usb_hub.h> 61188942Sthompsa#include <dev/usb/usb_util.h> 62184610Salfred 63188942Sthompsa#include <dev/usb/usb_controller.h> 64188942Sthompsa#include <dev/usb/usb_bus.h> 65188942Sthompsa#include <dev/usb/controller/at91dci.h> 66184610Salfred 67184610Salfred#define AT9100_DCI_BUS2SC(bus) \ 68184610Salfred ((struct at91dci_softc *)(((uint8_t *)(bus)) - \ 69190181Sthompsa ((uint8_t *)&(((struct at91dci_softc *)0)->sc_bus)))) 70184610Salfred 71184610Salfred#define AT9100_DCI_PC2SC(pc) \ 72190180Sthompsa AT9100_DCI_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus) 73184610Salfred 74184610Salfred#if USB_DEBUG 75184610Salfredstatic int at91dcidebug = 0; 76184610Salfred 77184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, at91dci, CTLFLAG_RW, 0, "USB at91dci"); 78184610SalfredSYSCTL_INT(_hw_usb2_at91dci, OID_AUTO, debug, CTLFLAG_RW, 79184610Salfred &at91dcidebug, 0, "at91dci debug level"); 80184610Salfred#endif 81184610Salfred 82184610Salfred#define AT9100_DCI_INTR_ENDPT 1 83184610Salfred 84184610Salfred/* prototypes */ 85184610Salfred 86184610Salfredstruct usb2_bus_methods at91dci_bus_methods; 87184610Salfredstruct usb2_pipe_methods at91dci_device_bulk_methods; 88184610Salfredstruct usb2_pipe_methods at91dci_device_ctrl_methods; 89184610Salfredstruct usb2_pipe_methods at91dci_device_intr_methods; 90184610Salfredstruct usb2_pipe_methods at91dci_device_isoc_fs_methods; 91184610Salfred 92184610Salfredstatic at91dci_cmd_t at91dci_setup_rx; 93184610Salfredstatic at91dci_cmd_t at91dci_data_rx; 94184610Salfredstatic at91dci_cmd_t at91dci_data_tx; 95184610Salfredstatic at91dci_cmd_t at91dci_data_tx_sync; 96185948Sthompsastatic void at91dci_device_done(struct usb2_xfer *, usb2_error_t); 97185948Sthompsastatic void at91dci_do_poll(struct usb2_bus *); 98185948Sthompsastatic void at91dci_standard_done(struct usb2_xfer *); 99190735Sthompsastatic void at91dci_root_intr(struct at91dci_softc *sc); 100184610Salfred 101184610Salfred/* 102184610Salfred * NOTE: Some of the bits in the CSR register have inverse meaning so 103184610Salfred * we need a helper macro when acknowledging events: 104184610Salfred */ 105184610Salfred#define AT91_CSR_ACK(csr, what) do { \ 106184610Salfred (csr) &= ~((AT91_UDP_CSR_FORCESTALL| \ 107184610Salfred AT91_UDP_CSR_TXPKTRDY| \ 108184610Salfred AT91_UDP_CSR_RXBYTECNT) ^ (what));\ 109184610Salfred (csr) |= ((AT91_UDP_CSR_RX_DATA_BK0| \ 110184610Salfred AT91_UDP_CSR_RX_DATA_BK1| \ 111184610Salfred AT91_UDP_CSR_TXCOMP| \ 112184610Salfred AT91_UDP_CSR_RXSETUP| \ 113184610Salfred AT91_UDP_CSR_STALLSENT) ^ (what)); \ 114184610Salfred} while (0) 115184610Salfred 116184610Salfred/* 117184610Salfred * Here is a list of what the chip supports. 118184610Salfred * Probably it supports more than listed here! 119184610Salfred */ 120184610Salfredstatic const struct usb2_hw_ep_profile 121184610Salfred at91dci_ep_profile[AT91_UDP_EP_MAX] = { 122184610Salfred 123184610Salfred [0] = { 124184610Salfred .max_in_frame_size = 8, 125184610Salfred .max_out_frame_size = 8, 126184610Salfred .is_simplex = 1, 127184610Salfred .support_control = 1, 128184610Salfred }, 129184610Salfred [1] = { 130184610Salfred .max_in_frame_size = 64, 131184610Salfred .max_out_frame_size = 64, 132184610Salfred .is_simplex = 1, 133184610Salfred .support_multi_buffer = 1, 134184610Salfred .support_bulk = 1, 135184610Salfred .support_interrupt = 1, 136184610Salfred .support_isochronous = 1, 137184610Salfred .support_in = 1, 138184610Salfred .support_out = 1, 139184610Salfred }, 140184610Salfred [2] = { 141184610Salfred .max_in_frame_size = 64, 142184610Salfred .max_out_frame_size = 64, 143184610Salfred .is_simplex = 1, 144184610Salfred .support_multi_buffer = 1, 145184610Salfred .support_bulk = 1, 146184610Salfred .support_interrupt = 1, 147184610Salfred .support_isochronous = 1, 148184610Salfred .support_in = 1, 149184610Salfred .support_out = 1, 150184610Salfred }, 151184610Salfred [3] = { 152184610Salfred /* can also do BULK */ 153184610Salfred .max_in_frame_size = 8, 154184610Salfred .max_out_frame_size = 8, 155184610Salfred .is_simplex = 1, 156184610Salfred .support_interrupt = 1, 157184610Salfred .support_in = 1, 158184610Salfred .support_out = 1, 159184610Salfred }, 160184610Salfred [4] = { 161184610Salfred .max_in_frame_size = 256, 162184610Salfred .max_out_frame_size = 256, 163184610Salfred .is_simplex = 1, 164184610Salfred .support_multi_buffer = 1, 165184610Salfred .support_bulk = 1, 166184610Salfred .support_interrupt = 1, 167184610Salfred .support_isochronous = 1, 168184610Salfred .support_in = 1, 169184610Salfred .support_out = 1, 170184610Salfred }, 171184610Salfred [5] = { 172184610Salfred .max_in_frame_size = 256, 173184610Salfred .max_out_frame_size = 256, 174184610Salfred .is_simplex = 1, 175184610Salfred .support_multi_buffer = 1, 176184610Salfred .support_bulk = 1, 177184610Salfred .support_interrupt = 1, 178184610Salfred .support_isochronous = 1, 179184610Salfred .support_in = 1, 180184610Salfred .support_out = 1, 181184610Salfred }, 182184610Salfred}; 183184610Salfred 184184610Salfredstatic void 185184610Salfredat91dci_get_hw_ep_profile(struct usb2_device *udev, 186184610Salfred const struct usb2_hw_ep_profile **ppf, uint8_t ep_addr) 187184610Salfred{ 188184610Salfred if (ep_addr < AT91_UDP_EP_MAX) { 189184610Salfred *ppf = (at91dci_ep_profile + ep_addr); 190184610Salfred } else { 191184610Salfred *ppf = NULL; 192184610Salfred } 193184610Salfred} 194184610Salfred 195184610Salfredstatic void 196184610Salfredat91dci_clocks_on(struct at91dci_softc *sc) 197184610Salfred{ 198184610Salfred if (sc->sc_flags.clocks_off && 199184610Salfred sc->sc_flags.port_powered) { 200184610Salfred 201184610Salfred DPRINTFN(5, "\n"); 202184610Salfred 203184610Salfred if (sc->sc_clocks_on) { 204184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 205184610Salfred } 206184610Salfred sc->sc_flags.clocks_off = 0; 207184610Salfred 208184610Salfred /* enable Transceiver */ 209184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, 0); 210184610Salfred } 211184610Salfred} 212184610Salfred 213184610Salfredstatic void 214184610Salfredat91dci_clocks_off(struct at91dci_softc *sc) 215184610Salfred{ 216184610Salfred if (!sc->sc_flags.clocks_off) { 217184610Salfred 218184610Salfred DPRINTFN(5, "\n"); 219184610Salfred 220184610Salfred /* disable Transceiver */ 221184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); 222184610Salfred 223184610Salfred if (sc->sc_clocks_off) { 224184610Salfred (sc->sc_clocks_off) (sc->sc_clocks_arg); 225184610Salfred } 226184610Salfred sc->sc_flags.clocks_off = 1; 227184610Salfred } 228184610Salfred} 229184610Salfred 230184610Salfredstatic void 231184610Salfredat91dci_pull_up(struct at91dci_softc *sc) 232184610Salfred{ 233184610Salfred /* pullup D+, if possible */ 234184610Salfred 235184610Salfred if (!sc->sc_flags.d_pulled_up && 236184610Salfred sc->sc_flags.port_powered) { 237184610Salfred sc->sc_flags.d_pulled_up = 1; 238184610Salfred (sc->sc_pull_up) (sc->sc_pull_arg); 239184610Salfred } 240184610Salfred} 241184610Salfred 242184610Salfredstatic void 243184610Salfredat91dci_pull_down(struct at91dci_softc *sc) 244184610Salfred{ 245184610Salfred /* pulldown D+, if possible */ 246184610Salfred 247184610Salfred if (sc->sc_flags.d_pulled_up) { 248184610Salfred sc->sc_flags.d_pulled_up = 0; 249184610Salfred (sc->sc_pull_down) (sc->sc_pull_arg); 250184610Salfred } 251184610Salfred} 252184610Salfred 253184610Salfredstatic void 254190735Sthompsaat91dci_wakeup_peer(struct at91dci_softc *sc) 255184610Salfred{ 256184610Salfred if (!(sc->sc_flags.status_suspend)) { 257184610Salfred return; 258184610Salfred } 259184610Salfred 260186730Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, AT91_UDP_GSTATE_ESR); 261184610Salfred 262186730Salfred /* wait 8 milliseconds */ 263188983Sthompsa /* Wait for reset to complete. */ 264188983Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); 265184610Salfred 266186730Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, 0); 267184610Salfred} 268184610Salfred 269184610Salfredstatic void 270184610Salfredat91dci_set_address(struct at91dci_softc *sc, uint8_t addr) 271184610Salfred{ 272184610Salfred DPRINTFN(5, "addr=%d\n", addr); 273184610Salfred 274184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, addr | 275184610Salfred AT91_UDP_FADDR_EN); 276184610Salfred} 277184610Salfred 278184610Salfredstatic uint8_t 279184610Salfredat91dci_setup_rx(struct at91dci_td *td) 280184610Salfred{ 281184610Salfred struct at91dci_softc *sc; 282184610Salfred struct usb2_device_request req; 283184610Salfred uint32_t csr; 284184610Salfred uint32_t temp; 285184610Salfred uint16_t count; 286184610Salfred 287184610Salfred /* read out FIFO status */ 288184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 289184610Salfred td->status_reg); 290184610Salfred 291184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 292184610Salfred 293184610Salfred temp = csr; 294184610Salfred temp &= (AT91_UDP_CSR_RX_DATA_BK0 | 295184610Salfred AT91_UDP_CSR_RX_DATA_BK1 | 296184610Salfred AT91_UDP_CSR_STALLSENT | 297184610Salfred AT91_UDP_CSR_RXSETUP | 298184610Salfred AT91_UDP_CSR_TXCOMP); 299184610Salfred 300184610Salfred if (!(csr & AT91_UDP_CSR_RXSETUP)) { 301184610Salfred goto not_complete; 302184610Salfred } 303190721Sthompsa /* clear did stall */ 304190721Sthompsa td->did_stall = 0; 305190721Sthompsa 306184610Salfred /* get the packet byte count */ 307184610Salfred count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; 308184610Salfred 309184610Salfred /* verify data length */ 310184610Salfred if (count != td->remainder) { 311184610Salfred DPRINTFN(0, "Invalid SETUP packet " 312184610Salfred "length, %d bytes\n", count); 313184610Salfred goto not_complete; 314184610Salfred } 315184610Salfred if (count != sizeof(req)) { 316184610Salfred DPRINTFN(0, "Unsupported SETUP packet " 317184610Salfred "length, %d bytes\n", count); 318184610Salfred goto not_complete; 319184610Salfred } 320184610Salfred /* receive data */ 321184610Salfred bus_space_read_multi_1(td->io_tag, td->io_hdl, 322184610Salfred td->fifo_reg, (void *)&req, sizeof(req)); 323184610Salfred 324184610Salfred /* copy data into real buffer */ 325184610Salfred usb2_copy_in(td->pc, 0, &req, sizeof(req)); 326184610Salfred 327184610Salfred td->offset = sizeof(req); 328184610Salfred td->remainder = 0; 329184610Salfred 330184610Salfred /* get pointer to softc */ 331184610Salfred sc = AT9100_DCI_PC2SC(td->pc); 332184610Salfred 333184610Salfred /* sneak peek the set address */ 334184610Salfred if ((req.bmRequestType == UT_WRITE_DEVICE) && 335184610Salfred (req.bRequest == UR_SET_ADDRESS)) { 336184610Salfred sc->sc_dv_addr = req.wValue[0] & 0x7F; 337184610Salfred } else { 338184610Salfred sc->sc_dv_addr = 0xFF; 339184610Salfred } 340184610Salfred 341184610Salfred /* sneak peek the endpoint direction */ 342184610Salfred if (req.bmRequestType & UE_DIR_IN) { 343184610Salfred csr |= AT91_UDP_CSR_DIR; 344184610Salfred } else { 345184610Salfred csr &= ~AT91_UDP_CSR_DIR; 346184610Salfred } 347184610Salfred 348184610Salfred /* write the direction of the control transfer */ 349184610Salfred AT91_CSR_ACK(csr, temp); 350184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 351184610Salfred td->status_reg, csr); 352184610Salfred return (0); /* complete */ 353184610Salfred 354184610Salfrednot_complete: 355190721Sthompsa /* abort any ongoing transfer */ 356190721Sthompsa if (!td->did_stall) { 357190721Sthompsa DPRINTFN(5, "stalling\n"); 358190721Sthompsa temp |= AT91_UDP_CSR_FORCESTALL; 359190721Sthompsa td->did_stall = 1; 360190721Sthompsa } 361190721Sthompsa 362184610Salfred /* clear interrupts, if any */ 363184610Salfred if (temp) { 364184610Salfred DPRINTFN(5, "clearing 0x%08x\n", temp); 365184610Salfred AT91_CSR_ACK(csr, temp); 366184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 367184610Salfred td->status_reg, csr); 368184610Salfred } 369184610Salfred return (1); /* not complete */ 370184610Salfred 371184610Salfred} 372184610Salfred 373184610Salfredstatic uint8_t 374184610Salfredat91dci_data_rx(struct at91dci_td *td) 375184610Salfred{ 376184610Salfred struct usb2_page_search buf_res; 377184610Salfred uint32_t csr; 378184610Salfred uint32_t temp; 379184610Salfred uint16_t count; 380184610Salfred uint8_t to; 381184610Salfred uint8_t got_short; 382184610Salfred 383184610Salfred to = 2; /* don't loop forever! */ 384184610Salfred got_short = 0; 385184610Salfred 386184610Salfred /* check if any of the FIFO banks have data */ 387184610Salfredrepeat: 388184610Salfred /* read out FIFO status */ 389184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 390184610Salfred td->status_reg); 391184610Salfred 392184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 393184610Salfred 394184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 395184610Salfred if (td->remainder == 0) { 396184610Salfred /* 397184610Salfred * We are actually complete and have 398184610Salfred * received the next SETUP 399184610Salfred */ 400184610Salfred DPRINTFN(5, "faking complete\n"); 401184610Salfred return (0); /* complete */ 402184610Salfred } 403184610Salfred /* 404184610Salfred * USB Host Aborted the transfer. 405184610Salfred */ 406184610Salfred td->error = 1; 407184610Salfred return (0); /* complete */ 408184610Salfred } 409184610Salfred /* Make sure that "STALLSENT" gets cleared */ 410184610Salfred temp = csr; 411184610Salfred temp &= AT91_UDP_CSR_STALLSENT; 412184610Salfred 413184610Salfred /* check status */ 414184610Salfred if (!(csr & (AT91_UDP_CSR_RX_DATA_BK0 | 415184610Salfred AT91_UDP_CSR_RX_DATA_BK1))) { 416184610Salfred if (temp) { 417184610Salfred /* write command */ 418184610Salfred AT91_CSR_ACK(csr, temp); 419184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 420184610Salfred td->status_reg, csr); 421184610Salfred } 422184610Salfred return (1); /* not complete */ 423184610Salfred } 424184610Salfred /* get the packet byte count */ 425184610Salfred count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; 426184610Salfred 427184610Salfred /* verify the packet byte count */ 428184610Salfred if (count != td->max_packet_size) { 429184610Salfred if (count < td->max_packet_size) { 430184610Salfred /* we have a short packet */ 431184610Salfred td->short_pkt = 1; 432184610Salfred got_short = 1; 433184610Salfred } else { 434184610Salfred /* invalid USB packet */ 435184610Salfred td->error = 1; 436184610Salfred return (0); /* we are complete */ 437184610Salfred } 438184610Salfred } 439184610Salfred /* verify the packet byte count */ 440184610Salfred if (count > td->remainder) { 441184610Salfred /* invalid USB packet */ 442184610Salfred td->error = 1; 443184610Salfred return (0); /* we are complete */ 444184610Salfred } 445184610Salfred while (count > 0) { 446184610Salfred usb2_get_page(td->pc, td->offset, &buf_res); 447184610Salfred 448184610Salfred /* get correct length */ 449184610Salfred if (buf_res.length > count) { 450184610Salfred buf_res.length = count; 451184610Salfred } 452184610Salfred /* receive data */ 453184610Salfred bus_space_read_multi_1(td->io_tag, td->io_hdl, 454184610Salfred td->fifo_reg, buf_res.buffer, buf_res.length); 455184610Salfred 456184610Salfred /* update counters */ 457184610Salfred count -= buf_res.length; 458184610Salfred td->offset += buf_res.length; 459184610Salfred td->remainder -= buf_res.length; 460184610Salfred } 461184610Salfred 462184610Salfred /* clear status bits */ 463184610Salfred if (td->support_multi_buffer) { 464184610Salfred if (td->fifo_bank) { 465184610Salfred td->fifo_bank = 0; 466184610Salfred temp |= AT91_UDP_CSR_RX_DATA_BK1; 467184610Salfred } else { 468184610Salfred td->fifo_bank = 1; 469184610Salfred temp |= AT91_UDP_CSR_RX_DATA_BK0; 470184610Salfred } 471184610Salfred } else { 472184610Salfred temp |= (AT91_UDP_CSR_RX_DATA_BK0 | 473184610Salfred AT91_UDP_CSR_RX_DATA_BK1); 474184610Salfred } 475184610Salfred 476184610Salfred /* write command */ 477184610Salfred AT91_CSR_ACK(csr, temp); 478184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 479184610Salfred td->status_reg, csr); 480184610Salfred 481184610Salfred /* 482184610Salfred * NOTE: We may have to delay a little bit before 483184610Salfred * proceeding after clearing the DATA_BK bits. 484184610Salfred */ 485184610Salfred 486184610Salfred /* check if we are complete */ 487184610Salfred if ((td->remainder == 0) || got_short) { 488184610Salfred if (td->short_pkt) { 489184610Salfred /* we are complete */ 490184610Salfred return (0); 491184610Salfred } 492184610Salfred /* else need to receive a zero length packet */ 493184610Salfred } 494184610Salfred if (--to) { 495184610Salfred goto repeat; 496184610Salfred } 497184610Salfred return (1); /* not complete */ 498184610Salfred} 499184610Salfred 500184610Salfredstatic uint8_t 501184610Salfredat91dci_data_tx(struct at91dci_td *td) 502184610Salfred{ 503184610Salfred struct usb2_page_search buf_res; 504184610Salfred uint32_t csr; 505184610Salfred uint32_t temp; 506184610Salfred uint16_t count; 507184610Salfred uint8_t to; 508184610Salfred 509184610Salfred to = 2; /* don't loop forever! */ 510184610Salfred 511184610Salfredrepeat: 512184610Salfred 513184610Salfred /* read out FIFO status */ 514184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 515184610Salfred td->status_reg); 516184610Salfred 517184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 518184610Salfred 519184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 520184610Salfred /* 521184610Salfred * The current transfer was aborted 522184610Salfred * by the USB Host 523184610Salfred */ 524184610Salfred td->error = 1; 525184610Salfred return (0); /* complete */ 526184610Salfred } 527184610Salfred /* Make sure that "STALLSENT" gets cleared */ 528184610Salfred temp = csr; 529184610Salfred temp &= AT91_UDP_CSR_STALLSENT; 530184610Salfred 531184610Salfred if (csr & AT91_UDP_CSR_TXPKTRDY) { 532184610Salfred if (temp) { 533184610Salfred /* write command */ 534184610Salfred AT91_CSR_ACK(csr, temp); 535184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 536184610Salfred td->status_reg, csr); 537184610Salfred } 538184610Salfred return (1); /* not complete */ 539184610Salfred } else { 540184610Salfred /* clear TXCOMP and set TXPKTRDY */ 541184610Salfred temp |= (AT91_UDP_CSR_TXCOMP | 542184610Salfred AT91_UDP_CSR_TXPKTRDY); 543184610Salfred } 544184610Salfred 545184610Salfred count = td->max_packet_size; 546184610Salfred if (td->remainder < count) { 547184610Salfred /* we have a short packet */ 548184610Salfred td->short_pkt = 1; 549184610Salfred count = td->remainder; 550184610Salfred } 551184610Salfred while (count > 0) { 552184610Salfred 553184610Salfred usb2_get_page(td->pc, td->offset, &buf_res); 554184610Salfred 555184610Salfred /* get correct length */ 556184610Salfred if (buf_res.length > count) { 557184610Salfred buf_res.length = count; 558184610Salfred } 559184610Salfred /* transmit data */ 560184610Salfred bus_space_write_multi_1(td->io_tag, td->io_hdl, 561184610Salfred td->fifo_reg, buf_res.buffer, buf_res.length); 562184610Salfred 563184610Salfred /* update counters */ 564184610Salfred count -= buf_res.length; 565184610Salfred td->offset += buf_res.length; 566184610Salfred td->remainder -= buf_res.length; 567184610Salfred } 568184610Salfred 569184610Salfred /* write command */ 570184610Salfred AT91_CSR_ACK(csr, temp); 571184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 572184610Salfred td->status_reg, csr); 573184610Salfred 574184610Salfred /* check remainder */ 575184610Salfred if (td->remainder == 0) { 576184610Salfred if (td->short_pkt) { 577184610Salfred return (0); /* complete */ 578184610Salfred } 579184610Salfred /* else we need to transmit a short packet */ 580184610Salfred } 581184610Salfred if (--to) { 582184610Salfred goto repeat; 583184610Salfred } 584184610Salfred return (1); /* not complete */ 585184610Salfred} 586184610Salfred 587184610Salfredstatic uint8_t 588184610Salfredat91dci_data_tx_sync(struct at91dci_td *td) 589184610Salfred{ 590184610Salfred struct at91dci_softc *sc; 591184610Salfred uint32_t csr; 592184610Salfred uint32_t temp; 593184610Salfred 594184610Salfred#if 0 595184610Salfredrepeat: 596184610Salfred#endif 597184610Salfred 598184610Salfred /* read out FIFO status */ 599184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 600184610Salfred td->status_reg); 601184610Salfred 602184610Salfred DPRINTFN(5, "csr=0x%08x\n", csr); 603184610Salfred 604184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 605184610Salfred DPRINTFN(5, "faking complete\n"); 606184610Salfred /* Race condition */ 607184610Salfred return (0); /* complete */ 608184610Salfred } 609184610Salfred temp = csr; 610184610Salfred temp &= (AT91_UDP_CSR_STALLSENT | 611184610Salfred AT91_UDP_CSR_TXCOMP); 612184610Salfred 613184610Salfred /* check status */ 614184610Salfred if (csr & AT91_UDP_CSR_TXPKTRDY) { 615184610Salfred goto not_complete; 616184610Salfred } 617184610Salfred if (!(csr & AT91_UDP_CSR_TXCOMP)) { 618184610Salfred goto not_complete; 619184610Salfred } 620184610Salfred sc = AT9100_DCI_PC2SC(td->pc); 621184610Salfred if (sc->sc_dv_addr != 0xFF) { 622184610Salfred /* 623184610Salfred * The AT91 has a special requirement with regard to 624184610Salfred * setting the address and that is to write the new 625184610Salfred * address before clearing TXCOMP: 626184610Salfred */ 627184610Salfred at91dci_set_address(sc, sc->sc_dv_addr); 628184610Salfred } 629184610Salfred /* write command */ 630184610Salfred AT91_CSR_ACK(csr, temp); 631184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 632184610Salfred td->status_reg, csr); 633184610Salfred 634184610Salfred return (0); /* complete */ 635184610Salfred 636184610Salfrednot_complete: 637184610Salfred if (temp) { 638184610Salfred /* write command */ 639184610Salfred AT91_CSR_ACK(csr, temp); 640184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 641184610Salfred td->status_reg, csr); 642184610Salfred } 643184610Salfred return (1); /* not complete */ 644184610Salfred} 645184610Salfred 646184610Salfredstatic uint8_t 647184610Salfredat91dci_xfer_do_fifo(struct usb2_xfer *xfer) 648184610Salfred{ 649184610Salfred struct at91dci_softc *sc; 650184610Salfred struct at91dci_td *td; 651184610Salfred uint8_t temp; 652184610Salfred 653184610Salfred DPRINTFN(9, "\n"); 654184610Salfred 655184610Salfred td = xfer->td_transfer_cache; 656184610Salfred while (1) { 657184610Salfred if ((td->func) (td)) { 658184610Salfred /* operation in progress */ 659184610Salfred break; 660184610Salfred } 661184610Salfred if (((void *)td) == xfer->td_transfer_last) { 662184610Salfred goto done; 663184610Salfred } 664184610Salfred if (td->error) { 665184610Salfred goto done; 666184610Salfred } else if (td->remainder > 0) { 667184610Salfred /* 668184610Salfred * We had a short transfer. If there is no alternate 669184610Salfred * next, stop processing ! 670184610Salfred */ 671184610Salfred if (!td->alt_next) { 672184610Salfred goto done; 673184610Salfred } 674184610Salfred } 675184610Salfred /* 676184610Salfred * Fetch the next transfer descriptor and transfer 677184610Salfred * some flags to the next transfer descriptor 678184610Salfred */ 679184610Salfred temp = 0; 680184610Salfred if (td->fifo_bank) 681184610Salfred temp |= 1; 682184610Salfred td = td->obj_next; 683184610Salfred xfer->td_transfer_cache = td; 684184610Salfred if (temp & 1) 685184610Salfred td->fifo_bank = 1; 686184610Salfred } 687184610Salfred return (1); /* not complete */ 688184610Salfred 689184610Salfreddone: 690187173Sthompsa sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 691184610Salfred temp = (xfer->endpoint & UE_ADDR); 692184610Salfred 693184610Salfred /* update FIFO bank flag and multi buffer */ 694184610Salfred if (td->fifo_bank) { 695184610Salfred sc->sc_ep_flags[temp].fifo_bank = 1; 696184610Salfred } else { 697184610Salfred sc->sc_ep_flags[temp].fifo_bank = 0; 698184610Salfred } 699184610Salfred 700184610Salfred /* compute all actual lengths */ 701184610Salfred 702184610Salfred at91dci_standard_done(xfer); 703184610Salfred 704184610Salfred return (0); /* complete */ 705184610Salfred} 706184610Salfred 707184610Salfredstatic void 708184610Salfredat91dci_interrupt_poll(struct at91dci_softc *sc) 709184610Salfred{ 710184610Salfred struct usb2_xfer *xfer; 711184610Salfred 712184610Salfredrepeat: 713184610Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 714184610Salfred if (!at91dci_xfer_do_fifo(xfer)) { 715184610Salfred /* queue has been modified */ 716184610Salfred goto repeat; 717184610Salfred } 718184610Salfred } 719184610Salfred} 720184610Salfred 721187175Sthompsavoid 722187175Sthompsaat91dci_vbus_interrupt(struct at91dci_softc *sc, uint8_t is_on) 723184610Salfred{ 724184610Salfred DPRINTFN(5, "vbus = %u\n", is_on); 725184610Salfred 726184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 727184610Salfred if (is_on) { 728184610Salfred if (!sc->sc_flags.status_vbus) { 729184610Salfred sc->sc_flags.status_vbus = 1; 730184610Salfred 731184610Salfred /* complete root HUB interrupt endpoint */ 732190735Sthompsa at91dci_root_intr(sc); 733184610Salfred } 734184610Salfred } else { 735184610Salfred if (sc->sc_flags.status_vbus) { 736184610Salfred sc->sc_flags.status_vbus = 0; 737184610Salfred sc->sc_flags.status_bus_reset = 0; 738184610Salfred sc->sc_flags.status_suspend = 0; 739184610Salfred sc->sc_flags.change_suspend = 0; 740184610Salfred sc->sc_flags.change_connect = 1; 741184610Salfred 742184610Salfred /* complete root HUB interrupt endpoint */ 743190735Sthompsa at91dci_root_intr(sc); 744184610Salfred } 745184610Salfred } 746184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 747184610Salfred} 748184610Salfred 749184610Salfredvoid 750184610Salfredat91dci_interrupt(struct at91dci_softc *sc) 751184610Salfred{ 752184610Salfred uint32_t status; 753184610Salfred 754184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 755184610Salfred 756184610Salfred status = AT91_UDP_READ_4(sc, AT91_UDP_ISR); 757184610Salfred status &= AT91_UDP_INT_DEFAULT; 758184610Salfred 759184610Salfred if (!status) { 760184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 761184610Salfred return; 762184610Salfred } 763184610Salfred /* acknowledge interrupts */ 764184610Salfred 765184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status); 766184610Salfred 767184610Salfred /* check for any bus state change interrupts */ 768184610Salfred 769184610Salfred if (status & AT91_UDP_INT_BUS) { 770184610Salfred 771184610Salfred DPRINTFN(5, "real bus interrupt 0x%08x\n", status); 772184610Salfred 773184610Salfred if (status & AT91_UDP_INT_END_BR) { 774184610Salfred 775184610Salfred /* set correct state */ 776184610Salfred sc->sc_flags.status_bus_reset = 1; 777184610Salfred sc->sc_flags.status_suspend = 0; 778184610Salfred sc->sc_flags.change_suspend = 0; 779184610Salfred sc->sc_flags.change_connect = 1; 780184610Salfred 781184610Salfred /* disable resume interrupt */ 782184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 783184610Salfred AT91_UDP_INT_RXRSM); 784184610Salfred /* enable suspend interrupt */ 785184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 786184610Salfred AT91_UDP_INT_RXSUSP); 787184610Salfred } 788184610Salfred /* 789184610Salfred * If RXRSM and RXSUSP is set at the same time we interpret 790184610Salfred * that like RESUME. Resume is set when there is at least 3 791184610Salfred * milliseconds of inactivity on the USB BUS. 792184610Salfred */ 793184610Salfred if (status & AT91_UDP_INT_RXRSM) { 794184610Salfred if (sc->sc_flags.status_suspend) { 795184610Salfred sc->sc_flags.status_suspend = 0; 796184610Salfred sc->sc_flags.change_suspend = 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 } else if (status & AT91_UDP_INT_RXSUSP) { 806184610Salfred if (!sc->sc_flags.status_suspend) { 807184610Salfred sc->sc_flags.status_suspend = 1; 808184610Salfred sc->sc_flags.change_suspend = 1; 809184610Salfred 810184610Salfred /* disable suspend interrupt */ 811184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 812184610Salfred AT91_UDP_INT_RXSUSP); 813184610Salfred 814184610Salfred /* enable resume interrupt */ 815184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 816184610Salfred AT91_UDP_INT_RXRSM); 817184610Salfred } 818184610Salfred } 819184610Salfred /* complete root HUB interrupt endpoint */ 820190735Sthompsa at91dci_root_intr(sc); 821184610Salfred } 822184610Salfred /* check for any endpoint interrupts */ 823184610Salfred 824184610Salfred if (status & AT91_UDP_INT_EPS) { 825184610Salfred 826184610Salfred DPRINTFN(5, "real endpoint interrupt 0x%08x\n", status); 827184610Salfred 828184610Salfred at91dci_interrupt_poll(sc); 829184610Salfred } 830184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 831184610Salfred} 832184610Salfred 833184610Salfredstatic void 834184610Salfredat91dci_setup_standard_chain_sub(struct at91dci_std_temp *temp) 835184610Salfred{ 836184610Salfred struct at91dci_td *td; 837184610Salfred 838184610Salfred /* get current Transfer Descriptor */ 839184610Salfred td = temp->td_next; 840184610Salfred temp->td = td; 841184610Salfred 842184610Salfred /* prepare for next TD */ 843184610Salfred temp->td_next = td->obj_next; 844184610Salfred 845184610Salfred /* fill out the Transfer Descriptor */ 846184610Salfred td->func = temp->func; 847184610Salfred td->pc = temp->pc; 848184610Salfred td->offset = temp->offset; 849184610Salfred td->remainder = temp->len; 850184610Salfred td->fifo_bank = 0; 851184610Salfred td->error = 0; 852184610Salfred td->did_stall = 0; 853184610Salfred td->short_pkt = temp->short_pkt; 854184610Salfred td->alt_next = temp->setup_alt_next; 855184610Salfred} 856184610Salfred 857184610Salfredstatic void 858184610Salfredat91dci_setup_standard_chain(struct usb2_xfer *xfer) 859184610Salfred{ 860184610Salfred struct at91dci_std_temp temp; 861184610Salfred struct at91dci_softc *sc; 862184610Salfred struct at91dci_td *td; 863184610Salfred uint32_t x; 864184610Salfred uint8_t ep_no; 865184610Salfred uint8_t need_sync; 866184610Salfred 867184610Salfred DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", 868184610Salfred xfer->address, UE_GET_ADDR(xfer->endpoint), 869187173Sthompsa xfer->sumlen, usb2_get_speed(xfer->xroot->udev)); 870184610Salfred 871184610Salfred temp.max_frame_size = xfer->max_frame_size; 872184610Salfred 873184610Salfred td = xfer->td_start[0]; 874184610Salfred xfer->td_transfer_first = td; 875184610Salfred xfer->td_transfer_cache = td; 876184610Salfred 877184610Salfred /* setup temp */ 878184610Salfred 879184610Salfred temp.td = NULL; 880184610Salfred temp.td_next = xfer->td_start[0]; 881190183Sthompsa temp.offset = 0; 882184610Salfred temp.setup_alt_next = xfer->flags_int.short_frames_ok; 883184610Salfred 884187173Sthompsa sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 885184610Salfred ep_no = (xfer->endpoint & UE_ADDR); 886184610Salfred 887184610Salfred /* check if we should prepend a setup message */ 888184610Salfred 889184610Salfred if (xfer->flags_int.control_xfr) { 890184610Salfred if (xfer->flags_int.control_hdr) { 891184610Salfred 892184610Salfred temp.func = &at91dci_setup_rx; 893184610Salfred temp.len = xfer->frlengths[0]; 894184610Salfred temp.pc = xfer->frbuffers + 0; 895184610Salfred temp.short_pkt = temp.len ? 1 : 0; 896190183Sthompsa /* check for last frame */ 897190183Sthompsa if (xfer->nframes == 1) { 898190183Sthompsa /* no STATUS stage yet, SETUP is last */ 899190183Sthompsa if (xfer->flags_int.control_act) 900190183Sthompsa temp.setup_alt_next = 0; 901190183Sthompsa } 902184610Salfred 903184610Salfred at91dci_setup_standard_chain_sub(&temp); 904184610Salfred } 905184610Salfred x = 1; 906184610Salfred } else { 907184610Salfred x = 0; 908184610Salfred } 909184610Salfred 910184610Salfred if (x != xfer->nframes) { 911184610Salfred if (xfer->endpoint & UE_DIR_IN) { 912184610Salfred temp.func = &at91dci_data_tx; 913184610Salfred need_sync = 1; 914184610Salfred } else { 915184610Salfred temp.func = &at91dci_data_rx; 916184610Salfred need_sync = 0; 917184610Salfred } 918184610Salfred 919184610Salfred /* setup "pc" pointer */ 920184610Salfred temp.pc = xfer->frbuffers + x; 921184610Salfred } else { 922184610Salfred need_sync = 0; 923184610Salfred } 924184610Salfred while (x != xfer->nframes) { 925184610Salfred 926184610Salfred /* DATA0 / DATA1 message */ 927184610Salfred 928184610Salfred temp.len = xfer->frlengths[x]; 929184610Salfred 930184610Salfred x++; 931184610Salfred 932184610Salfred if (x == xfer->nframes) { 933190183Sthompsa if (xfer->flags_int.control_xfr) { 934190183Sthompsa if (xfer->flags_int.control_act) { 935190183Sthompsa temp.setup_alt_next = 0; 936190183Sthompsa } 937190183Sthompsa } else { 938190183Sthompsa temp.setup_alt_next = 0; 939190183Sthompsa } 940184610Salfred } 941184610Salfred if (temp.len == 0) { 942184610Salfred 943184610Salfred /* make sure that we send an USB packet */ 944184610Salfred 945184610Salfred temp.short_pkt = 0; 946184610Salfred 947184610Salfred } else { 948184610Salfred 949184610Salfred /* regular data transfer */ 950184610Salfred 951184610Salfred temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; 952184610Salfred } 953184610Salfred 954184610Salfred at91dci_setup_standard_chain_sub(&temp); 955184610Salfred 956184610Salfred if (xfer->flags_int.isochronous_xfr) { 957184610Salfred temp.offset += temp.len; 958184610Salfred } else { 959184610Salfred /* get next Page Cache pointer */ 960184610Salfred temp.pc = xfer->frbuffers + x; 961184610Salfred } 962184610Salfred } 963184610Salfred 964190183Sthompsa /* check for control transfer */ 965190183Sthompsa if (xfer->flags_int.control_xfr) { 966184610Salfred 967190183Sthompsa /* always setup a valid "pc" pointer for status and sync */ 968190183Sthompsa temp.pc = xfer->frbuffers + 0; 969184610Salfred temp.len = 0; 970184610Salfred temp.short_pkt = 0; 971190183Sthompsa temp.setup_alt_next = 0; 972184610Salfred 973190183Sthompsa /* check if we need to sync */ 974184610Salfred if (need_sync) { 975184610Salfred /* we need a SYNC point after TX */ 976184610Salfred temp.func = &at91dci_data_tx_sync; 977190183Sthompsa at91dci_setup_standard_chain_sub(&temp); 978190183Sthompsa } 979184610Salfred 980190183Sthompsa /* check if we should append a status stage */ 981190183Sthompsa if (!xfer->flags_int.control_act) { 982190183Sthompsa 983190183Sthompsa /* 984190183Sthompsa * Send a DATA1 message and invert the current 985190183Sthompsa * endpoint direction. 986190183Sthompsa */ 987190183Sthompsa if (xfer->endpoint & UE_DIR_IN) { 988190183Sthompsa temp.func = &at91dci_data_rx; 989190183Sthompsa need_sync = 0; 990190183Sthompsa } else { 991190183Sthompsa temp.func = &at91dci_data_tx; 992190183Sthompsa need_sync = 1; 993190183Sthompsa } 994190183Sthompsa 995184610Salfred at91dci_setup_standard_chain_sub(&temp); 996190183Sthompsa if (need_sync) { 997190183Sthompsa /* we need a SYNC point after TX */ 998190183Sthompsa temp.func = &at91dci_data_tx_sync; 999190183Sthompsa at91dci_setup_standard_chain_sub(&temp); 1000190183Sthompsa } 1001184610Salfred } 1002184610Salfred } 1003190183Sthompsa 1004184610Salfred /* must have at least one frame! */ 1005184610Salfred td = temp.td; 1006184610Salfred xfer->td_transfer_last = td; 1007184610Salfred 1008184610Salfred /* setup the correct fifo bank */ 1009184610Salfred if (sc->sc_ep_flags[ep_no].fifo_bank) { 1010184610Salfred td = xfer->td_transfer_first; 1011184610Salfred td->fifo_bank = 1; 1012184610Salfred } 1013184610Salfred} 1014184610Salfred 1015184610Salfredstatic void 1016184610Salfredat91dci_timeout(void *arg) 1017184610Salfred{ 1018184610Salfred struct usb2_xfer *xfer = arg; 1019184610Salfred 1020184610Salfred DPRINTF("xfer=%p\n", xfer); 1021184610Salfred 1022187177Sthompsa USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 1023184610Salfred 1024184610Salfred /* transfer is transferred */ 1025184610Salfred at91dci_device_done(xfer, USB_ERR_TIMEOUT); 1026184610Salfred} 1027184610Salfred 1028184610Salfredstatic void 1029184610Salfredat91dci_start_standard_chain(struct usb2_xfer *xfer) 1030184610Salfred{ 1031184610Salfred DPRINTFN(9, "\n"); 1032184610Salfred 1033184610Salfred /* poll one time */ 1034184610Salfred if (at91dci_xfer_do_fifo(xfer)) { 1035184610Salfred 1036187173Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1037184610Salfred uint8_t ep_no = xfer->endpoint & UE_ADDR; 1038184610Salfred 1039184610Salfred /* 1040184610Salfred * Only enable the endpoint interrupt when we are actually 1041184610Salfred * waiting for data, hence we are dealing with level 1042184610Salfred * triggered interrupts ! 1043184610Salfred */ 1044184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_EP(ep_no)); 1045184610Salfred 1046184610Salfred DPRINTFN(15, "enable interrupts on endpoint %d\n", ep_no); 1047184610Salfred 1048184610Salfred /* put transfer on interrupt queue */ 1049187173Sthompsa usb2_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); 1050184610Salfred 1051184610Salfred /* start timeout, if any */ 1052184610Salfred if (xfer->timeout != 0) { 1053184610Salfred usb2_transfer_timeout_ms(xfer, 1054184610Salfred &at91dci_timeout, xfer->timeout); 1055184610Salfred } 1056184610Salfred } 1057184610Salfred} 1058184610Salfred 1059184610Salfredstatic void 1060190735Sthompsaat91dci_root_intr(struct at91dci_softc *sc) 1061184610Salfred{ 1062184610Salfred DPRINTFN(9, "\n"); 1063184610Salfred 1064184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1065184610Salfred 1066184610Salfred /* set port bit */ 1067184610Salfred sc->sc_hub_idata[0] = 0x02; /* we only have one port */ 1068184610Salfred 1069190735Sthompsa uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, 1070190735Sthompsa sizeof(sc->sc_hub_idata)); 1071184610Salfred} 1072184610Salfred 1073184610Salfredstatic usb2_error_t 1074184610Salfredat91dci_standard_done_sub(struct usb2_xfer *xfer) 1075184610Salfred{ 1076184610Salfred struct at91dci_td *td; 1077184610Salfred uint32_t len; 1078184610Salfred uint8_t error; 1079184610Salfred 1080184610Salfred DPRINTFN(9, "\n"); 1081184610Salfred 1082184610Salfred td = xfer->td_transfer_cache; 1083184610Salfred 1084184610Salfred do { 1085184610Salfred len = td->remainder; 1086184610Salfred 1087184610Salfred if (xfer->aframes != xfer->nframes) { 1088184610Salfred /* 1089184610Salfred * Verify the length and subtract 1090184610Salfred * the remainder from "frlengths[]": 1091184610Salfred */ 1092184610Salfred if (len > xfer->frlengths[xfer->aframes]) { 1093184610Salfred td->error = 1; 1094184610Salfred } else { 1095184610Salfred xfer->frlengths[xfer->aframes] -= len; 1096184610Salfred } 1097184610Salfred } 1098184610Salfred /* Check for transfer error */ 1099184610Salfred if (td->error) { 1100184610Salfred /* the transfer is finished */ 1101184610Salfred error = 1; 1102184610Salfred td = NULL; 1103184610Salfred break; 1104184610Salfred } 1105184610Salfred /* Check for short transfer */ 1106184610Salfred if (len > 0) { 1107184610Salfred if (xfer->flags_int.short_frames_ok) { 1108184610Salfred /* follow alt next */ 1109184610Salfred if (td->alt_next) { 1110184610Salfred td = td->obj_next; 1111184610Salfred } else { 1112184610Salfred td = NULL; 1113184610Salfred } 1114184610Salfred } else { 1115184610Salfred /* the transfer is finished */ 1116184610Salfred td = NULL; 1117184610Salfred } 1118184610Salfred error = 0; 1119184610Salfred break; 1120184610Salfred } 1121184610Salfred td = td->obj_next; 1122184610Salfred 1123184610Salfred /* this USB frame is complete */ 1124184610Salfred error = 0; 1125184610Salfred break; 1126184610Salfred 1127184610Salfred } while (0); 1128184610Salfred 1129184610Salfred /* update transfer cache */ 1130184610Salfred 1131184610Salfred xfer->td_transfer_cache = td; 1132184610Salfred 1133184610Salfred return (error ? 1134184610Salfred USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); 1135184610Salfred} 1136184610Salfred 1137184610Salfredstatic void 1138184610Salfredat91dci_standard_done(struct usb2_xfer *xfer) 1139184610Salfred{ 1140184610Salfred usb2_error_t err = 0; 1141184610Salfred 1142184610Salfred DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", 1143184610Salfred xfer, xfer->pipe); 1144184610Salfred 1145184610Salfred /* reset scanner */ 1146184610Salfred 1147184610Salfred xfer->td_transfer_cache = xfer->td_transfer_first; 1148184610Salfred 1149184610Salfred if (xfer->flags_int.control_xfr) { 1150184610Salfred 1151184610Salfred if (xfer->flags_int.control_hdr) { 1152184610Salfred 1153184610Salfred err = at91dci_standard_done_sub(xfer); 1154184610Salfred } 1155184610Salfred xfer->aframes = 1; 1156184610Salfred 1157184610Salfred if (xfer->td_transfer_cache == NULL) { 1158184610Salfred goto done; 1159184610Salfred } 1160184610Salfred } 1161184610Salfred while (xfer->aframes != xfer->nframes) { 1162184610Salfred 1163184610Salfred err = at91dci_standard_done_sub(xfer); 1164184610Salfred xfer->aframes++; 1165184610Salfred 1166184610Salfred if (xfer->td_transfer_cache == NULL) { 1167184610Salfred goto done; 1168184610Salfred } 1169184610Salfred } 1170184610Salfred 1171184610Salfred if (xfer->flags_int.control_xfr && 1172184610Salfred !xfer->flags_int.control_act) { 1173184610Salfred 1174184610Salfred err = at91dci_standard_done_sub(xfer); 1175184610Salfred } 1176184610Salfreddone: 1177184610Salfred at91dci_device_done(xfer, err); 1178184610Salfred} 1179184610Salfred 1180184610Salfred/*------------------------------------------------------------------------* 1181184610Salfred * at91dci_device_done 1182184610Salfred * 1183184610Salfred * NOTE: this function can be called more than one time on the 1184184610Salfred * same USB transfer! 1185184610Salfred *------------------------------------------------------------------------*/ 1186184610Salfredstatic void 1187184610Salfredat91dci_device_done(struct usb2_xfer *xfer, usb2_error_t error) 1188184610Salfred{ 1189187173Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1190184610Salfred uint8_t ep_no; 1191184610Salfred 1192184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1193184610Salfred 1194184610Salfred DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", 1195184610Salfred xfer, xfer->pipe, error); 1196184610Salfred 1197184610Salfred if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { 1198184610Salfred ep_no = (xfer->endpoint & UE_ADDR); 1199184610Salfred 1200184610Salfred /* disable endpoint interrupt */ 1201184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, AT91_UDP_INT_EP(ep_no)); 1202184610Salfred 1203184610Salfred DPRINTFN(15, "disable interrupts on endpoint %d\n", ep_no); 1204184610Salfred } 1205184610Salfred /* dequeue transfer and start next transfer */ 1206184610Salfred usb2_transfer_done(xfer, error); 1207184610Salfred} 1208184610Salfred 1209184610Salfredstatic void 1210184610Salfredat91dci_set_stall(struct usb2_device *udev, struct usb2_xfer *xfer, 1211184610Salfred struct usb2_pipe *pipe) 1212184610Salfred{ 1213184610Salfred struct at91dci_softc *sc; 1214184610Salfred uint32_t csr_val; 1215184610Salfred uint8_t csr_reg; 1216184610Salfred 1217184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 1218184610Salfred 1219184610Salfred DPRINTFN(5, "pipe=%p\n", pipe); 1220184610Salfred 1221184610Salfred if (xfer) { 1222184610Salfred /* cancel any ongoing transfers */ 1223184610Salfred at91dci_device_done(xfer, USB_ERR_STALLED); 1224184610Salfred } 1225184610Salfred /* set FORCESTALL */ 1226184610Salfred sc = AT9100_DCI_BUS2SC(udev->bus); 1227184610Salfred csr_reg = (pipe->edesc->bEndpointAddress & UE_ADDR); 1228184610Salfred csr_reg = AT91_UDP_CSR(csr_reg); 1229184610Salfred csr_val = AT91_UDP_READ_4(sc, csr_reg); 1230184610Salfred AT91_CSR_ACK(csr_val, AT91_UDP_CSR_FORCESTALL); 1231184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1232184610Salfred} 1233184610Salfred 1234184610Salfredstatic void 1235184610Salfredat91dci_clear_stall_sub(struct at91dci_softc *sc, uint8_t ep_no, 1236184610Salfred uint8_t ep_type, uint8_t ep_dir) 1237184610Salfred{ 1238184610Salfred const struct usb2_hw_ep_profile *pf; 1239184610Salfred uint32_t csr_val; 1240184610Salfred uint32_t temp; 1241184610Salfred uint8_t csr_reg; 1242184610Salfred uint8_t to; 1243184610Salfred 1244184610Salfred if (ep_type == UE_CONTROL) { 1245184610Salfred /* clearing stall is not needed */ 1246184610Salfred return; 1247184610Salfred } 1248184610Salfred /* compute CSR register offset */ 1249184610Salfred csr_reg = AT91_UDP_CSR(ep_no); 1250184610Salfred 1251184610Salfred /* compute default CSR value */ 1252184610Salfred csr_val = 0; 1253184610Salfred AT91_CSR_ACK(csr_val, 0); 1254184610Salfred 1255184610Salfred /* disable endpoint */ 1256184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1257184610Salfred 1258184610Salfred /* get endpoint profile */ 1259184610Salfred at91dci_get_hw_ep_profile(NULL, &pf, ep_no); 1260184610Salfred 1261184610Salfred /* reset FIFO */ 1262184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(ep_no)); 1263184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0); 1264184610Salfred 1265184610Salfred /* 1266184610Salfred * NOTE: One would assume that a FIFO reset would release the 1267184610Salfred * FIFO banks aswell, but it doesn't! We have to do this 1268184610Salfred * manually! 1269184610Salfred */ 1270184610Salfred 1271184610Salfred /* release FIFO banks, if any */ 1272184610Salfred for (to = 0; to != 2; to++) { 1273184610Salfred 1274184610Salfred /* get csr value */ 1275184610Salfred csr_val = AT91_UDP_READ_4(sc, csr_reg); 1276184610Salfred 1277184610Salfred if (csr_val & (AT91_UDP_CSR_RX_DATA_BK0 | 1278184610Salfred AT91_UDP_CSR_RX_DATA_BK1)) { 1279184610Salfred /* clear status bits */ 1280184610Salfred if (pf->support_multi_buffer) { 1281184610Salfred if (sc->sc_ep_flags[ep_no].fifo_bank) { 1282184610Salfred sc->sc_ep_flags[ep_no].fifo_bank = 0; 1283184610Salfred temp = AT91_UDP_CSR_RX_DATA_BK1; 1284184610Salfred } else { 1285184610Salfred sc->sc_ep_flags[ep_no].fifo_bank = 1; 1286184610Salfred temp = AT91_UDP_CSR_RX_DATA_BK0; 1287184610Salfred } 1288184610Salfred } else { 1289184610Salfred temp = (AT91_UDP_CSR_RX_DATA_BK0 | 1290184610Salfred AT91_UDP_CSR_RX_DATA_BK1); 1291184610Salfred } 1292184610Salfred } else { 1293184610Salfred temp = 0; 1294184610Salfred } 1295184610Salfred 1296184610Salfred /* clear FORCESTALL */ 1297184610Salfred temp |= AT91_UDP_CSR_STALLSENT; 1298184610Salfred 1299184610Salfred AT91_CSR_ACK(csr_val, temp); 1300184610Salfred AT91_UDP_WRITE_4(sc, csr_reg, csr_val); 1301184610Salfred } 1302184610Salfred 1303184610Salfred /* compute default CSR value */ 1304184610Salfred csr_val = 0; 1305184610Salfred AT91_CSR_ACK(csr_val, 0); 1306184610Salfred 1307184610Salfred /* enable endpoint */ 1308184610Salfred csr_val &= ~AT91_UDP_CSR_ET_MASK; 1309184610Salfred csr_val |= AT91_UDP_CSR_EPEDS; 1310184610Salfred 1311184610Salfred if (ep_type == UE_CONTROL) { 1312184610Salfred csr_val |= AT91_UDP_CSR_ET_CTRL; 1313184610Salfred } else { 1314184610Salfred if (ep_type == UE_BULK) { 1315184610Salfred csr_val |= AT91_UDP_CSR_ET_BULK; 1316184610Salfred } else if (ep_type == UE_INTERRUPT) { 1317184610Salfred csr_val |= AT91_UDP_CSR_ET_INT; 1318184610Salfred } else { 1319184610Salfred csr_val |= AT91_UDP_CSR_ET_ISO; 1320184610Salfred } 1321184610Salfred if (ep_dir & UE_DIR_IN) { 1322184610Salfred csr_val |= AT91_UDP_CSR_ET_DIR_IN; 1323184610Salfred } 1324184610Salfred } 1325184610Salfred 1326184610Salfred /* enable endpoint */ 1327184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(ep_no), csr_val); 1328184610Salfred} 1329184610Salfred 1330184610Salfredstatic void 1331184610Salfredat91dci_clear_stall(struct usb2_device *udev, struct usb2_pipe *pipe) 1332184610Salfred{ 1333184610Salfred struct at91dci_softc *sc; 1334184610Salfred struct usb2_endpoint_descriptor *ed; 1335184610Salfred 1336184610Salfred DPRINTFN(5, "pipe=%p\n", pipe); 1337184610Salfred 1338184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 1339184610Salfred 1340184610Salfred /* check mode */ 1341184610Salfred if (udev->flags.usb2_mode != USB_MODE_DEVICE) { 1342184610Salfred /* not supported */ 1343184610Salfred return; 1344184610Salfred } 1345184610Salfred /* get softc */ 1346184610Salfred sc = AT9100_DCI_BUS2SC(udev->bus); 1347184610Salfred 1348184610Salfred /* get endpoint descriptor */ 1349184610Salfred ed = pipe->edesc; 1350184610Salfred 1351184610Salfred /* reset endpoint */ 1352184610Salfred at91dci_clear_stall_sub(sc, 1353184610Salfred (ed->bEndpointAddress & UE_ADDR), 1354184610Salfred (ed->bmAttributes & UE_XFERTYPE), 1355184610Salfred (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); 1356184610Salfred} 1357184610Salfred 1358184610Salfredusb2_error_t 1359184610Salfredat91dci_init(struct at91dci_softc *sc) 1360184610Salfred{ 1361184610Salfred uint32_t csr_val; 1362184610Salfred uint8_t n; 1363184610Salfred 1364184610Salfred DPRINTF("start\n"); 1365184610Salfred 1366184610Salfred /* set up the bus structure */ 1367184610Salfred sc->sc_bus.usbrev = USB_REV_1_1; 1368184610Salfred sc->sc_bus.methods = &at91dci_bus_methods; 1369184610Salfred 1370184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1371184610Salfred 1372184610Salfred /* turn on clocks */ 1373184610Salfred 1374184610Salfred if (sc->sc_clocks_on) { 1375184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 1376184610Salfred } 1377184610Salfred /* wait a little for things to stabilise */ 1378188409Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); 1379184610Salfred 1380184610Salfred /* disable and clear all interrupts */ 1381184610Salfred 1382184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); 1383184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF); 1384184610Salfred 1385184610Salfred /* compute default CSR value */ 1386184610Salfred 1387184610Salfred csr_val = 0; 1388184610Salfred AT91_CSR_ACK(csr_val, 0); 1389184610Salfred 1390184610Salfred /* disable all endpoints */ 1391184610Salfred 1392184610Salfred for (n = 0; n != AT91_UDP_EP_MAX; n++) { 1393184610Salfred 1394184610Salfred /* disable endpoint */ 1395184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(n), csr_val); 1396184610Salfred } 1397184610Salfred 1398184610Salfred /* enable the control endpoint */ 1399184610Salfred 1400184610Salfred AT91_CSR_ACK(csr_val, AT91_UDP_CSR_ET_CTRL | 1401184610Salfred AT91_UDP_CSR_EPEDS); 1402184610Salfred 1403184610Salfred /* write to FIFO control register */ 1404184610Salfred 1405184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(0), csr_val); 1406184610Salfred 1407184610Salfred /* enable the interrupts we want */ 1408184610Salfred 1409184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_BUS); 1410184610Salfred 1411184610Salfred /* turn off clocks */ 1412184610Salfred 1413184610Salfred at91dci_clocks_off(sc); 1414184610Salfred 1415184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1416184610Salfred 1417184610Salfred /* catch any lost interrupts */ 1418184610Salfred 1419184610Salfred at91dci_do_poll(&sc->sc_bus); 1420184610Salfred 1421184610Salfred return (0); /* success */ 1422184610Salfred} 1423184610Salfred 1424184610Salfredvoid 1425184610Salfredat91dci_uninit(struct at91dci_softc *sc) 1426184610Salfred{ 1427184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1428184610Salfred 1429184610Salfred /* disable and clear all interrupts */ 1430184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); 1431184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF); 1432184610Salfred 1433184610Salfred sc->sc_flags.port_powered = 0; 1434184610Salfred sc->sc_flags.status_vbus = 0; 1435184610Salfred sc->sc_flags.status_bus_reset = 0; 1436184610Salfred sc->sc_flags.status_suspend = 0; 1437184610Salfred sc->sc_flags.change_suspend = 0; 1438184610Salfred sc->sc_flags.change_connect = 1; 1439184610Salfred 1440184610Salfred at91dci_pull_down(sc); 1441184610Salfred at91dci_clocks_off(sc); 1442184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1443184610Salfred} 1444184610Salfred 1445184610Salfredvoid 1446184610Salfredat91dci_suspend(struct at91dci_softc *sc) 1447184610Salfred{ 1448184610Salfred return; 1449184610Salfred} 1450184610Salfred 1451184610Salfredvoid 1452184610Salfredat91dci_resume(struct at91dci_softc *sc) 1453184610Salfred{ 1454184610Salfred return; 1455184610Salfred} 1456184610Salfred 1457184610Salfredstatic void 1458184610Salfredat91dci_do_poll(struct usb2_bus *bus) 1459184610Salfred{ 1460184610Salfred struct at91dci_softc *sc = AT9100_DCI_BUS2SC(bus); 1461184610Salfred 1462184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1463184610Salfred at91dci_interrupt_poll(sc); 1464184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1465184610Salfred} 1466184610Salfred 1467184610Salfred/*------------------------------------------------------------------------* 1468184610Salfred * at91dci bulk support 1469184610Salfred *------------------------------------------------------------------------*/ 1470184610Salfredstatic void 1471184610Salfredat91dci_device_bulk_open(struct usb2_xfer *xfer) 1472184610Salfred{ 1473184610Salfred return; 1474184610Salfred} 1475184610Salfred 1476184610Salfredstatic void 1477184610Salfredat91dci_device_bulk_close(struct usb2_xfer *xfer) 1478184610Salfred{ 1479184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1480184610Salfred} 1481184610Salfred 1482184610Salfredstatic void 1483184610Salfredat91dci_device_bulk_enter(struct usb2_xfer *xfer) 1484184610Salfred{ 1485184610Salfred return; 1486184610Salfred} 1487184610Salfred 1488184610Salfredstatic void 1489184610Salfredat91dci_device_bulk_start(struct usb2_xfer *xfer) 1490184610Salfred{ 1491184610Salfred /* setup TDs */ 1492184610Salfred at91dci_setup_standard_chain(xfer); 1493184610Salfred at91dci_start_standard_chain(xfer); 1494184610Salfred} 1495184610Salfred 1496184610Salfredstruct usb2_pipe_methods at91dci_device_bulk_methods = 1497184610Salfred{ 1498184610Salfred .open = at91dci_device_bulk_open, 1499184610Salfred .close = at91dci_device_bulk_close, 1500184610Salfred .enter = at91dci_device_bulk_enter, 1501184610Salfred .start = at91dci_device_bulk_start, 1502184610Salfred}; 1503184610Salfred 1504184610Salfred/*------------------------------------------------------------------------* 1505184610Salfred * at91dci control support 1506184610Salfred *------------------------------------------------------------------------*/ 1507184610Salfredstatic void 1508184610Salfredat91dci_device_ctrl_open(struct usb2_xfer *xfer) 1509184610Salfred{ 1510184610Salfred return; 1511184610Salfred} 1512184610Salfred 1513184610Salfredstatic void 1514184610Salfredat91dci_device_ctrl_close(struct usb2_xfer *xfer) 1515184610Salfred{ 1516184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1517184610Salfred} 1518184610Salfred 1519184610Salfredstatic void 1520184610Salfredat91dci_device_ctrl_enter(struct usb2_xfer *xfer) 1521184610Salfred{ 1522184610Salfred return; 1523184610Salfred} 1524184610Salfred 1525184610Salfredstatic void 1526184610Salfredat91dci_device_ctrl_start(struct usb2_xfer *xfer) 1527184610Salfred{ 1528184610Salfred /* setup TDs */ 1529184610Salfred at91dci_setup_standard_chain(xfer); 1530184610Salfred at91dci_start_standard_chain(xfer); 1531184610Salfred} 1532184610Salfred 1533184610Salfredstruct usb2_pipe_methods at91dci_device_ctrl_methods = 1534184610Salfred{ 1535184610Salfred .open = at91dci_device_ctrl_open, 1536184610Salfred .close = at91dci_device_ctrl_close, 1537184610Salfred .enter = at91dci_device_ctrl_enter, 1538184610Salfred .start = at91dci_device_ctrl_start, 1539184610Salfred}; 1540184610Salfred 1541184610Salfred/*------------------------------------------------------------------------* 1542184610Salfred * at91dci interrupt support 1543184610Salfred *------------------------------------------------------------------------*/ 1544184610Salfredstatic void 1545184610Salfredat91dci_device_intr_open(struct usb2_xfer *xfer) 1546184610Salfred{ 1547184610Salfred return; 1548184610Salfred} 1549184610Salfred 1550184610Salfredstatic void 1551184610Salfredat91dci_device_intr_close(struct usb2_xfer *xfer) 1552184610Salfred{ 1553184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1554184610Salfred} 1555184610Salfred 1556184610Salfredstatic void 1557184610Salfredat91dci_device_intr_enter(struct usb2_xfer *xfer) 1558184610Salfred{ 1559184610Salfred return; 1560184610Salfred} 1561184610Salfred 1562184610Salfredstatic void 1563184610Salfredat91dci_device_intr_start(struct usb2_xfer *xfer) 1564184610Salfred{ 1565184610Salfred /* setup TDs */ 1566184610Salfred at91dci_setup_standard_chain(xfer); 1567184610Salfred at91dci_start_standard_chain(xfer); 1568184610Salfred} 1569184610Salfred 1570184610Salfredstruct usb2_pipe_methods at91dci_device_intr_methods = 1571184610Salfred{ 1572184610Salfred .open = at91dci_device_intr_open, 1573184610Salfred .close = at91dci_device_intr_close, 1574184610Salfred .enter = at91dci_device_intr_enter, 1575184610Salfred .start = at91dci_device_intr_start, 1576184610Salfred}; 1577184610Salfred 1578184610Salfred/*------------------------------------------------------------------------* 1579184610Salfred * at91dci full speed isochronous support 1580184610Salfred *------------------------------------------------------------------------*/ 1581184610Salfredstatic void 1582184610Salfredat91dci_device_isoc_fs_open(struct usb2_xfer *xfer) 1583184610Salfred{ 1584184610Salfred return; 1585184610Salfred} 1586184610Salfred 1587184610Salfredstatic void 1588184610Salfredat91dci_device_isoc_fs_close(struct usb2_xfer *xfer) 1589184610Salfred{ 1590184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1591184610Salfred} 1592184610Salfred 1593184610Salfredstatic void 1594184610Salfredat91dci_device_isoc_fs_enter(struct usb2_xfer *xfer) 1595184610Salfred{ 1596187173Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 1597184610Salfred uint32_t temp; 1598184610Salfred uint32_t nframes; 1599184610Salfred 1600184610Salfred DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", 1601184610Salfred xfer, xfer->pipe->isoc_next, xfer->nframes); 1602184610Salfred 1603184610Salfred /* get the current frame index */ 1604184610Salfred 1605184610Salfred nframes = AT91_UDP_READ_4(sc, AT91_UDP_FRM); 1606184610Salfred 1607184610Salfred /* 1608184610Salfred * check if the frame index is within the window where the frames 1609184610Salfred * will be inserted 1610184610Salfred */ 1611184610Salfred temp = (nframes - xfer->pipe->isoc_next) & AT91_UDP_FRM_MASK; 1612184610Salfred 1613184610Salfred if ((xfer->pipe->is_synced == 0) || 1614184610Salfred (temp < xfer->nframes)) { 1615184610Salfred /* 1616184610Salfred * If there is data underflow or the pipe queue is 1617184610Salfred * empty we schedule the transfer a few frames ahead 1618184610Salfred * of the current frame position. Else two isochronous 1619184610Salfred * transfers might overlap. 1620184610Salfred */ 1621184610Salfred xfer->pipe->isoc_next = (nframes + 3) & AT91_UDP_FRM_MASK; 1622184610Salfred xfer->pipe->is_synced = 1; 1623184610Salfred DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next); 1624184610Salfred } 1625184610Salfred /* 1626184610Salfred * compute how many milliseconds the insertion is ahead of the 1627184610Salfred * current frame position: 1628184610Salfred */ 1629184610Salfred temp = (xfer->pipe->isoc_next - nframes) & AT91_UDP_FRM_MASK; 1630184610Salfred 1631184610Salfred /* 1632184610Salfred * pre-compute when the isochronous transfer will be finished: 1633184610Salfred */ 1634184610Salfred xfer->isoc_time_complete = 1635184610Salfred usb2_isoc_time_expand(&sc->sc_bus, nframes) + temp + 1636184610Salfred xfer->nframes; 1637184610Salfred 1638184610Salfred /* compute frame number for next insertion */ 1639184610Salfred xfer->pipe->isoc_next += xfer->nframes; 1640184610Salfred 1641184610Salfred /* setup TDs */ 1642184610Salfred at91dci_setup_standard_chain(xfer); 1643184610Salfred} 1644184610Salfred 1645184610Salfredstatic void 1646184610Salfredat91dci_device_isoc_fs_start(struct usb2_xfer *xfer) 1647184610Salfred{ 1648184610Salfred /* start TD chain */ 1649184610Salfred at91dci_start_standard_chain(xfer); 1650184610Salfred} 1651184610Salfred 1652184610Salfredstruct usb2_pipe_methods at91dci_device_isoc_fs_methods = 1653184610Salfred{ 1654184610Salfred .open = at91dci_device_isoc_fs_open, 1655184610Salfred .close = at91dci_device_isoc_fs_close, 1656184610Salfred .enter = at91dci_device_isoc_fs_enter, 1657184610Salfred .start = at91dci_device_isoc_fs_start, 1658184610Salfred}; 1659184610Salfred 1660184610Salfred/*------------------------------------------------------------------------* 1661184610Salfred * at91dci root control support 1662184610Salfred *------------------------------------------------------------------------* 1663190735Sthompsa * Simulate a hardware HUB by handling all the necessary requests. 1664184610Salfred *------------------------------------------------------------------------*/ 1665184610Salfred 1666184610Salfredstatic const struct usb2_device_descriptor at91dci_devd = { 1667184610Salfred .bLength = sizeof(struct usb2_device_descriptor), 1668184610Salfred .bDescriptorType = UDESC_DEVICE, 1669184610Salfred .bcdUSB = {0x00, 0x02}, 1670184610Salfred .bDeviceClass = UDCLASS_HUB, 1671184610Salfred .bDeviceSubClass = UDSUBCLASS_HUB, 1672184610Salfred .bDeviceProtocol = UDPROTO_HSHUBSTT, 1673184610Salfred .bMaxPacketSize = 64, 1674184610Salfred .bcdDevice = {0x00, 0x01}, 1675184610Salfred .iManufacturer = 1, 1676184610Salfred .iProduct = 2, 1677184610Salfred .bNumConfigurations = 1, 1678184610Salfred}; 1679184610Salfred 1680184610Salfredstatic const struct usb2_device_qualifier at91dci_odevd = { 1681184610Salfred .bLength = sizeof(struct usb2_device_qualifier), 1682184610Salfred .bDescriptorType = UDESC_DEVICE_QUALIFIER, 1683184610Salfred .bcdUSB = {0x00, 0x02}, 1684184610Salfred .bDeviceClass = UDCLASS_HUB, 1685184610Salfred .bDeviceSubClass = UDSUBCLASS_HUB, 1686184610Salfred .bDeviceProtocol = UDPROTO_FSHUB, 1687184610Salfred .bMaxPacketSize0 = 0, 1688184610Salfred .bNumConfigurations = 0, 1689184610Salfred}; 1690184610Salfred 1691184610Salfredstatic const struct at91dci_config_desc at91dci_confd = { 1692184610Salfred .confd = { 1693184610Salfred .bLength = sizeof(struct usb2_config_descriptor), 1694184610Salfred .bDescriptorType = UDESC_CONFIG, 1695184610Salfred .wTotalLength[0] = sizeof(at91dci_confd), 1696184610Salfred .bNumInterface = 1, 1697184610Salfred .bConfigurationValue = 1, 1698184610Salfred .iConfiguration = 0, 1699184610Salfred .bmAttributes = UC_SELF_POWERED, 1700184610Salfred .bMaxPower = 0, 1701184610Salfred }, 1702184610Salfred .ifcd = { 1703184610Salfred .bLength = sizeof(struct usb2_interface_descriptor), 1704184610Salfred .bDescriptorType = UDESC_INTERFACE, 1705184610Salfred .bNumEndpoints = 1, 1706184610Salfred .bInterfaceClass = UICLASS_HUB, 1707184610Salfred .bInterfaceSubClass = UISUBCLASS_HUB, 1708184610Salfred .bInterfaceProtocol = UIPROTO_HSHUBSTT, 1709184610Salfred }, 1710184610Salfred .endpd = { 1711184610Salfred .bLength = sizeof(struct usb2_endpoint_descriptor), 1712184610Salfred .bDescriptorType = UDESC_ENDPOINT, 1713184610Salfred .bEndpointAddress = (UE_DIR_IN | AT9100_DCI_INTR_ENDPT), 1714184610Salfred .bmAttributes = UE_INTERRUPT, 1715184610Salfred .wMaxPacketSize[0] = 8, 1716184610Salfred .bInterval = 255, 1717184610Salfred }, 1718184610Salfred}; 1719184610Salfred 1720184610Salfredstatic const struct usb2_hub_descriptor_min at91dci_hubd = { 1721184610Salfred .bDescLength = sizeof(at91dci_hubd), 1722184610Salfred .bDescriptorType = UDESC_HUB, 1723184610Salfred .bNbrPorts = 1, 1724184610Salfred .wHubCharacteristics[0] = 1725184610Salfred (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) & 0xFF, 1726184610Salfred .wHubCharacteristics[1] = 1727187183Sthompsa (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) >> 8, 1728184610Salfred .bPwrOn2PwrGood = 50, 1729184610Salfred .bHubContrCurrent = 0, 1730184610Salfred .DeviceRemovable = {0}, /* port is removable */ 1731184610Salfred}; 1732184610Salfred 1733184610Salfred#define STRING_LANG \ 1734184610Salfred 0x09, 0x04, /* American English */ 1735184610Salfred 1736184610Salfred#define STRING_VENDOR \ 1737184610Salfred 'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L', 0 1738184610Salfred 1739184610Salfred#define STRING_PRODUCT \ 1740184610Salfred 'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \ 1741184610Salfred 'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \ 1742184610Salfred 'U', 0, 'B', 0, 1743184610Salfred 1744184610SalfredUSB_MAKE_STRING_DESC(STRING_LANG, at91dci_langtab); 1745184610SalfredUSB_MAKE_STRING_DESC(STRING_VENDOR, at91dci_vendor); 1746184610SalfredUSB_MAKE_STRING_DESC(STRING_PRODUCT, at91dci_product); 1747184610Salfred 1748184610Salfredstatic void 1749190735Sthompsaat91dci_roothub_exec(struct usb2_bus *bus) 1750184610Salfred{ 1751190735Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(bus); 1752190735Sthompsa struct usb2_sw_transfer *std = &sc->sc_bus.roothub_req; 1753184610Salfred uint16_t value; 1754184610Salfred uint16_t index; 1755184610Salfred 1756184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1757184610Salfred 1758184610Salfred /* buffer reset */ 1759184610Salfred std->ptr = USB_ADD_BYTES(&sc->sc_hub_temp, 0); 1760184610Salfred std->len = 0; 1761184610Salfred 1762184610Salfred value = UGETW(std->req.wValue); 1763184610Salfred index = UGETW(std->req.wIndex); 1764184610Salfred 1765184610Salfred /* demultiplex the control request */ 1766184610Salfred 1767184610Salfred switch (std->req.bmRequestType) { 1768184610Salfred case UT_READ_DEVICE: 1769184610Salfred switch (std->req.bRequest) { 1770184610Salfred case UR_GET_DESCRIPTOR: 1771184610Salfred goto tr_handle_get_descriptor; 1772184610Salfred case UR_GET_CONFIG: 1773184610Salfred goto tr_handle_get_config; 1774184610Salfred case UR_GET_STATUS: 1775184610Salfred goto tr_handle_get_status; 1776184610Salfred default: 1777184610Salfred goto tr_stalled; 1778184610Salfred } 1779184610Salfred break; 1780184610Salfred 1781184610Salfred case UT_WRITE_DEVICE: 1782184610Salfred switch (std->req.bRequest) { 1783184610Salfred case UR_SET_ADDRESS: 1784184610Salfred goto tr_handle_set_address; 1785184610Salfred case UR_SET_CONFIG: 1786184610Salfred goto tr_handle_set_config; 1787184610Salfred case UR_CLEAR_FEATURE: 1788184610Salfred goto tr_valid; /* nop */ 1789184610Salfred case UR_SET_DESCRIPTOR: 1790184610Salfred goto tr_valid; /* nop */ 1791184610Salfred case UR_SET_FEATURE: 1792184610Salfred default: 1793184610Salfred goto tr_stalled; 1794184610Salfred } 1795184610Salfred break; 1796184610Salfred 1797184610Salfred case UT_WRITE_ENDPOINT: 1798184610Salfred switch (std->req.bRequest) { 1799184610Salfred case UR_CLEAR_FEATURE: 1800184610Salfred switch (UGETW(std->req.wValue)) { 1801184610Salfred case UF_ENDPOINT_HALT: 1802184610Salfred goto tr_handle_clear_halt; 1803184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 1804184610Salfred goto tr_handle_clear_wakeup; 1805184610Salfred default: 1806184610Salfred goto tr_stalled; 1807184610Salfred } 1808184610Salfred break; 1809184610Salfred case UR_SET_FEATURE: 1810184610Salfred switch (UGETW(std->req.wValue)) { 1811184610Salfred case UF_ENDPOINT_HALT: 1812184610Salfred goto tr_handle_set_halt; 1813184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 1814184610Salfred goto tr_handle_set_wakeup; 1815184610Salfred default: 1816184610Salfred goto tr_stalled; 1817184610Salfred } 1818184610Salfred break; 1819184610Salfred case UR_SYNCH_FRAME: 1820184610Salfred goto tr_valid; /* nop */ 1821184610Salfred default: 1822184610Salfred goto tr_stalled; 1823184610Salfred } 1824184610Salfred break; 1825184610Salfred 1826184610Salfred case UT_READ_ENDPOINT: 1827184610Salfred switch (std->req.bRequest) { 1828184610Salfred case UR_GET_STATUS: 1829184610Salfred goto tr_handle_get_ep_status; 1830184610Salfred default: 1831184610Salfred goto tr_stalled; 1832184610Salfred } 1833184610Salfred break; 1834184610Salfred 1835184610Salfred case UT_WRITE_INTERFACE: 1836184610Salfred switch (std->req.bRequest) { 1837184610Salfred case UR_SET_INTERFACE: 1838184610Salfred goto tr_handle_set_interface; 1839184610Salfred case UR_CLEAR_FEATURE: 1840184610Salfred goto tr_valid; /* nop */ 1841184610Salfred case UR_SET_FEATURE: 1842184610Salfred default: 1843184610Salfred goto tr_stalled; 1844184610Salfred } 1845184610Salfred break; 1846184610Salfred 1847184610Salfred case UT_READ_INTERFACE: 1848184610Salfred switch (std->req.bRequest) { 1849184610Salfred case UR_GET_INTERFACE: 1850184610Salfred goto tr_handle_get_interface; 1851184610Salfred case UR_GET_STATUS: 1852184610Salfred goto tr_handle_get_iface_status; 1853184610Salfred default: 1854184610Salfred goto tr_stalled; 1855184610Salfred } 1856184610Salfred break; 1857184610Salfred 1858184610Salfred case UT_WRITE_CLASS_INTERFACE: 1859184610Salfred case UT_WRITE_VENDOR_INTERFACE: 1860184610Salfred /* XXX forward */ 1861184610Salfred break; 1862184610Salfred 1863184610Salfred case UT_READ_CLASS_INTERFACE: 1864184610Salfred case UT_READ_VENDOR_INTERFACE: 1865184610Salfred /* XXX forward */ 1866184610Salfred break; 1867184610Salfred 1868184610Salfred case UT_WRITE_CLASS_DEVICE: 1869184610Salfred switch (std->req.bRequest) { 1870184610Salfred case UR_CLEAR_FEATURE: 1871184610Salfred goto tr_valid; 1872184610Salfred case UR_SET_DESCRIPTOR: 1873184610Salfred case UR_SET_FEATURE: 1874184610Salfred break; 1875184610Salfred default: 1876184610Salfred goto tr_stalled; 1877184610Salfred } 1878184610Salfred break; 1879184610Salfred 1880184610Salfred case UT_WRITE_CLASS_OTHER: 1881184610Salfred switch (std->req.bRequest) { 1882184610Salfred case UR_CLEAR_FEATURE: 1883184610Salfred goto tr_handle_clear_port_feature; 1884184610Salfred case UR_SET_FEATURE: 1885184610Salfred goto tr_handle_set_port_feature; 1886184610Salfred case UR_CLEAR_TT_BUFFER: 1887184610Salfred case UR_RESET_TT: 1888184610Salfred case UR_STOP_TT: 1889184610Salfred goto tr_valid; 1890184610Salfred 1891184610Salfred default: 1892184610Salfred goto tr_stalled; 1893184610Salfred } 1894184610Salfred break; 1895184610Salfred 1896184610Salfred case UT_READ_CLASS_OTHER: 1897184610Salfred switch (std->req.bRequest) { 1898184610Salfred case UR_GET_TT_STATE: 1899184610Salfred goto tr_handle_get_tt_state; 1900184610Salfred case UR_GET_STATUS: 1901184610Salfred goto tr_handle_get_port_status; 1902184610Salfred default: 1903184610Salfred goto tr_stalled; 1904184610Salfred } 1905184610Salfred break; 1906184610Salfred 1907184610Salfred case UT_READ_CLASS_DEVICE: 1908184610Salfred switch (std->req.bRequest) { 1909184610Salfred case UR_GET_DESCRIPTOR: 1910184610Salfred goto tr_handle_get_class_descriptor; 1911184610Salfred case UR_GET_STATUS: 1912184610Salfred goto tr_handle_get_class_status; 1913184610Salfred 1914184610Salfred default: 1915184610Salfred goto tr_stalled; 1916184610Salfred } 1917184610Salfred break; 1918184610Salfred default: 1919184610Salfred goto tr_stalled; 1920184610Salfred } 1921184610Salfred goto tr_valid; 1922184610Salfred 1923184610Salfredtr_handle_get_descriptor: 1924184610Salfred switch (value >> 8) { 1925184610Salfred case UDESC_DEVICE: 1926184610Salfred if (value & 0xff) { 1927184610Salfred goto tr_stalled; 1928184610Salfred } 1929184610Salfred std->len = sizeof(at91dci_devd); 1930184610Salfred std->ptr = USB_ADD_BYTES(&at91dci_devd, 0); 1931184610Salfred goto tr_valid; 1932184610Salfred case UDESC_CONFIG: 1933184610Salfred if (value & 0xff) { 1934184610Salfred goto tr_stalled; 1935184610Salfred } 1936184610Salfred std->len = sizeof(at91dci_confd); 1937184610Salfred std->ptr = USB_ADD_BYTES(&at91dci_confd, 0); 1938184610Salfred goto tr_valid; 1939184610Salfred case UDESC_STRING: 1940184610Salfred switch (value & 0xff) { 1941184610Salfred case 0: /* Language table */ 1942184610Salfred std->len = sizeof(at91dci_langtab); 1943184610Salfred std->ptr = USB_ADD_BYTES(&at91dci_langtab, 0); 1944184610Salfred goto tr_valid; 1945184610Salfred 1946184610Salfred case 1: /* Vendor */ 1947184610Salfred std->len = sizeof(at91dci_vendor); 1948184610Salfred std->ptr = USB_ADD_BYTES(&at91dci_vendor, 0); 1949184610Salfred goto tr_valid; 1950184610Salfred 1951184610Salfred case 2: /* Product */ 1952184610Salfred std->len = sizeof(at91dci_product); 1953184610Salfred std->ptr = USB_ADD_BYTES(&at91dci_product, 0); 1954184610Salfred goto tr_valid; 1955184610Salfred default: 1956184610Salfred break; 1957184610Salfred } 1958184610Salfred break; 1959184610Salfred default: 1960184610Salfred goto tr_stalled; 1961184610Salfred } 1962184610Salfred goto tr_stalled; 1963184610Salfred 1964184610Salfredtr_handle_get_config: 1965184610Salfred std->len = 1; 1966184610Salfred sc->sc_hub_temp.wValue[0] = sc->sc_conf; 1967184610Salfred goto tr_valid; 1968184610Salfred 1969184610Salfredtr_handle_get_status: 1970184610Salfred std->len = 2; 1971184610Salfred USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); 1972184610Salfred goto tr_valid; 1973184610Salfred 1974184610Salfredtr_handle_set_address: 1975184610Salfred if (value & 0xFF00) { 1976184610Salfred goto tr_stalled; 1977184610Salfred } 1978184610Salfred sc->sc_rt_addr = value; 1979184610Salfred goto tr_valid; 1980184610Salfred 1981184610Salfredtr_handle_set_config: 1982184610Salfred if (value >= 2) { 1983184610Salfred goto tr_stalled; 1984184610Salfred } 1985184610Salfred sc->sc_conf = value; 1986184610Salfred goto tr_valid; 1987184610Salfred 1988184610Salfredtr_handle_get_interface: 1989184610Salfred std->len = 1; 1990184610Salfred sc->sc_hub_temp.wValue[0] = 0; 1991184610Salfred goto tr_valid; 1992184610Salfred 1993184610Salfredtr_handle_get_tt_state: 1994184610Salfredtr_handle_get_class_status: 1995184610Salfredtr_handle_get_iface_status: 1996184610Salfredtr_handle_get_ep_status: 1997184610Salfred std->len = 2; 1998184610Salfred USETW(sc->sc_hub_temp.wValue, 0); 1999184610Salfred goto tr_valid; 2000184610Salfred 2001184610Salfredtr_handle_set_halt: 2002184610Salfredtr_handle_set_interface: 2003184610Salfredtr_handle_set_wakeup: 2004184610Salfredtr_handle_clear_wakeup: 2005184610Salfredtr_handle_clear_halt: 2006184610Salfred goto tr_valid; 2007184610Salfred 2008184610Salfredtr_handle_clear_port_feature: 2009184610Salfred if (index != 1) { 2010184610Salfred goto tr_stalled; 2011184610Salfred } 2012184610Salfred DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index); 2013184610Salfred 2014184610Salfred switch (value) { 2015184610Salfred case UHF_PORT_SUSPEND: 2016190735Sthompsa at91dci_wakeup_peer(sc); 2017184610Salfred break; 2018184610Salfred 2019184610Salfred case UHF_PORT_ENABLE: 2020184610Salfred sc->sc_flags.port_enabled = 0; 2021184610Salfred break; 2022184610Salfred 2023184610Salfred case UHF_PORT_TEST: 2024184610Salfred case UHF_PORT_INDICATOR: 2025184610Salfred case UHF_C_PORT_ENABLE: 2026184610Salfred case UHF_C_PORT_OVER_CURRENT: 2027184610Salfred case UHF_C_PORT_RESET: 2028184610Salfred /* nops */ 2029184610Salfred break; 2030184610Salfred case UHF_PORT_POWER: 2031184610Salfred sc->sc_flags.port_powered = 0; 2032184610Salfred at91dci_pull_down(sc); 2033184610Salfred at91dci_clocks_off(sc); 2034184610Salfred break; 2035184610Salfred case UHF_C_PORT_CONNECTION: 2036184610Salfred sc->sc_flags.change_connect = 0; 2037184610Salfred break; 2038184610Salfred case UHF_C_PORT_SUSPEND: 2039184610Salfred sc->sc_flags.change_suspend = 0; 2040184610Salfred break; 2041184610Salfred default: 2042184610Salfred std->err = USB_ERR_IOERROR; 2043184610Salfred goto done; 2044184610Salfred } 2045184610Salfred goto tr_valid; 2046184610Salfred 2047184610Salfredtr_handle_set_port_feature: 2048184610Salfred if (index != 1) { 2049184610Salfred goto tr_stalled; 2050184610Salfred } 2051184610Salfred DPRINTFN(9, "UR_SET_PORT_FEATURE\n"); 2052184610Salfred 2053184610Salfred switch (value) { 2054184610Salfred case UHF_PORT_ENABLE: 2055184610Salfred sc->sc_flags.port_enabled = 1; 2056184610Salfred break; 2057184610Salfred case UHF_PORT_SUSPEND: 2058184610Salfred case UHF_PORT_RESET: 2059184610Salfred case UHF_PORT_TEST: 2060184610Salfred case UHF_PORT_INDICATOR: 2061184610Salfred /* nops */ 2062184610Salfred break; 2063184610Salfred case UHF_PORT_POWER: 2064184610Salfred sc->sc_flags.port_powered = 1; 2065184610Salfred break; 2066184610Salfred default: 2067184610Salfred std->err = USB_ERR_IOERROR; 2068184610Salfred goto done; 2069184610Salfred } 2070184610Salfred goto tr_valid; 2071184610Salfred 2072184610Salfredtr_handle_get_port_status: 2073184610Salfred 2074184610Salfred DPRINTFN(9, "UR_GET_PORT_STATUS\n"); 2075184610Salfred 2076184610Salfred if (index != 1) { 2077184610Salfred goto tr_stalled; 2078184610Salfred } 2079184610Salfred if (sc->sc_flags.status_vbus) { 2080184610Salfred at91dci_clocks_on(sc); 2081184610Salfred at91dci_pull_up(sc); 2082184610Salfred } else { 2083184610Salfred at91dci_pull_down(sc); 2084184610Salfred at91dci_clocks_off(sc); 2085184610Salfred } 2086184610Salfred 2087184610Salfred /* Select FULL-speed and Device Side Mode */ 2088184610Salfred 2089184610Salfred value = UPS_PORT_MODE_DEVICE; 2090184610Salfred 2091184610Salfred if (sc->sc_flags.port_powered) { 2092184610Salfred value |= UPS_PORT_POWER; 2093184610Salfred } 2094184610Salfred if (sc->sc_flags.port_enabled) { 2095184610Salfred value |= UPS_PORT_ENABLED; 2096184610Salfred } 2097184610Salfred if (sc->sc_flags.status_vbus && 2098184610Salfred sc->sc_flags.status_bus_reset) { 2099184610Salfred value |= UPS_CURRENT_CONNECT_STATUS; 2100184610Salfred } 2101184610Salfred if (sc->sc_flags.status_suspend) { 2102184610Salfred value |= UPS_SUSPEND; 2103184610Salfred } 2104184610Salfred USETW(sc->sc_hub_temp.ps.wPortStatus, value); 2105184610Salfred 2106184610Salfred value = 0; 2107184610Salfred 2108184610Salfred if (sc->sc_flags.change_connect) { 2109184610Salfred value |= UPS_C_CONNECT_STATUS; 2110184610Salfred 2111184610Salfred if (sc->sc_flags.status_vbus && 2112184610Salfred sc->sc_flags.status_bus_reset) { 2113184610Salfred /* reset endpoint flags */ 2114184610Salfred bzero(sc->sc_ep_flags, sizeof(sc->sc_ep_flags)); 2115184610Salfred } 2116184610Salfred } 2117184610Salfred if (sc->sc_flags.change_suspend) { 2118184610Salfred value |= UPS_C_SUSPEND; 2119184610Salfred } 2120184610Salfred USETW(sc->sc_hub_temp.ps.wPortChange, value); 2121184610Salfred std->len = sizeof(sc->sc_hub_temp.ps); 2122184610Salfred goto tr_valid; 2123184610Salfred 2124184610Salfredtr_handle_get_class_descriptor: 2125184610Salfred if (value & 0xFF) { 2126184610Salfred goto tr_stalled; 2127184610Salfred } 2128184610Salfred std->ptr = USB_ADD_BYTES(&at91dci_hubd, 0); 2129184610Salfred std->len = sizeof(at91dci_hubd); 2130184610Salfred goto tr_valid; 2131184610Salfred 2132184610Salfredtr_stalled: 2133184610Salfred std->err = USB_ERR_STALLED; 2134184610Salfredtr_valid: 2135184610Salfreddone: 2136184610Salfred return; 2137184610Salfred} 2138184610Salfred 2139184610Salfredstatic void 2140184610Salfredat91dci_xfer_setup(struct usb2_setup_params *parm) 2141184610Salfred{ 2142184610Salfred const struct usb2_hw_ep_profile *pf; 2143184610Salfred struct at91dci_softc *sc; 2144184610Salfred struct usb2_xfer *xfer; 2145184610Salfred void *last_obj; 2146184610Salfred uint32_t ntd; 2147184610Salfred uint32_t n; 2148184610Salfred uint8_t ep_no; 2149184610Salfred 2150184610Salfred sc = AT9100_DCI_BUS2SC(parm->udev->bus); 2151184610Salfred xfer = parm->curr_xfer; 2152184610Salfred 2153184610Salfred /* 2154184610Salfred * NOTE: This driver does not use any of the parameters that 2155184610Salfred * are computed from the following values. Just set some 2156184610Salfred * reasonable dummies: 2157184610Salfred */ 2158184610Salfred parm->hc_max_packet_size = 0x500; 2159184610Salfred parm->hc_max_packet_count = 1; 2160184610Salfred parm->hc_max_frame_size = 0x500; 2161184610Salfred 2162184610Salfred usb2_transfer_setup_sub(parm); 2163184610Salfred 2164184610Salfred /* 2165184610Salfred * compute maximum number of TDs 2166184610Salfred */ 2167184610Salfred if (parm->methods == &at91dci_device_ctrl_methods) { 2168184610Salfred 2169184610Salfred ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */ 2170184610Salfred + 1 /* SYNC 2 */ ; 2171184610Salfred 2172184610Salfred } else if (parm->methods == &at91dci_device_bulk_methods) { 2173184610Salfred 2174184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2175184610Salfred 2176184610Salfred } else if (parm->methods == &at91dci_device_intr_methods) { 2177184610Salfred 2178184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2179184610Salfred 2180184610Salfred } else if (parm->methods == &at91dci_device_isoc_fs_methods) { 2181184610Salfred 2182184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2183184610Salfred 2184184610Salfred } else { 2185184610Salfred 2186184610Salfred ntd = 0; 2187184610Salfred } 2188184610Salfred 2189184610Salfred /* 2190184610Salfred * check if "usb2_transfer_setup_sub" set an error 2191184610Salfred */ 2192184610Salfred if (parm->err) { 2193184610Salfred return; 2194184610Salfred } 2195184610Salfred /* 2196184610Salfred * allocate transfer descriptors 2197184610Salfred */ 2198184610Salfred last_obj = NULL; 2199184610Salfred 2200184610Salfred /* 2201184610Salfred * get profile stuff 2202184610Salfred */ 2203184610Salfred if (ntd) { 2204184610Salfred 2205184610Salfred ep_no = xfer->endpoint & UE_ADDR; 2206184610Salfred at91dci_get_hw_ep_profile(parm->udev, &pf, ep_no); 2207184610Salfred 2208184610Salfred if (pf == NULL) { 2209184610Salfred /* should not happen */ 2210184610Salfred parm->err = USB_ERR_INVAL; 2211184610Salfred return; 2212184610Salfred } 2213184610Salfred } else { 2214184610Salfred ep_no = 0; 2215184610Salfred pf = NULL; 2216184610Salfred } 2217184610Salfred 2218184610Salfred /* align data */ 2219184610Salfred parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); 2220184610Salfred 2221184610Salfred for (n = 0; n != ntd; n++) { 2222184610Salfred 2223184610Salfred struct at91dci_td *td; 2224184610Salfred 2225184610Salfred if (parm->buf) { 2226184610Salfred 2227184610Salfred td = USB_ADD_BYTES(parm->buf, parm->size[0]); 2228184610Salfred 2229184610Salfred /* init TD */ 2230184610Salfred td->io_tag = sc->sc_io_tag; 2231184610Salfred td->io_hdl = sc->sc_io_hdl; 2232184610Salfred td->max_packet_size = xfer->max_packet_size; 2233184610Salfred td->status_reg = AT91_UDP_CSR(ep_no); 2234184610Salfred td->fifo_reg = AT91_UDP_FDR(ep_no); 2235184610Salfred if (pf->support_multi_buffer) { 2236184610Salfred td->support_multi_buffer = 1; 2237184610Salfred } 2238184610Salfred td->obj_next = last_obj; 2239184610Salfred 2240184610Salfred last_obj = td; 2241184610Salfred } 2242184610Salfred parm->size[0] += sizeof(*td); 2243184610Salfred } 2244184610Salfred 2245184610Salfred xfer->td_start[0] = last_obj; 2246184610Salfred} 2247184610Salfred 2248184610Salfredstatic void 2249184610Salfredat91dci_xfer_unsetup(struct usb2_xfer *xfer) 2250184610Salfred{ 2251184610Salfred return; 2252184610Salfred} 2253184610Salfred 2254184610Salfredstatic void 2255184610Salfredat91dci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, 2256184610Salfred struct usb2_pipe *pipe) 2257184610Salfred{ 2258184610Salfred struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus); 2259184610Salfred 2260184610Salfred DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", 2261184610Salfred pipe, udev->address, 2262184610Salfred edesc->bEndpointAddress, udev->flags.usb2_mode, 2263184610Salfred sc->sc_rt_addr); 2264184610Salfred 2265190735Sthompsa if (udev->device_index != sc->sc_rt_addr) { 2266184610Salfred 2267184610Salfred if (udev->flags.usb2_mode != USB_MODE_DEVICE) { 2268184610Salfred /* not supported */ 2269184610Salfred return; 2270184610Salfred } 2271184610Salfred if (udev->speed != USB_SPEED_FULL) { 2272184610Salfred /* not supported */ 2273184610Salfred return; 2274184610Salfred } 2275184610Salfred switch (edesc->bmAttributes & UE_XFERTYPE) { 2276184610Salfred case UE_CONTROL: 2277184610Salfred pipe->methods = &at91dci_device_ctrl_methods; 2278184610Salfred break; 2279184610Salfred case UE_INTERRUPT: 2280184610Salfred pipe->methods = &at91dci_device_intr_methods; 2281184610Salfred break; 2282184610Salfred case UE_ISOCHRONOUS: 2283184610Salfred pipe->methods = &at91dci_device_isoc_fs_methods; 2284184610Salfred break; 2285184610Salfred case UE_BULK: 2286184610Salfred pipe->methods = &at91dci_device_bulk_methods; 2287184610Salfred break; 2288184610Salfred default: 2289184610Salfred /* do nothing */ 2290184610Salfred break; 2291184610Salfred } 2292184610Salfred } 2293184610Salfred} 2294184610Salfred 2295184610Salfredstruct usb2_bus_methods at91dci_bus_methods = 2296184610Salfred{ 2297184610Salfred .pipe_init = &at91dci_pipe_init, 2298184610Salfred .xfer_setup = &at91dci_xfer_setup, 2299184610Salfred .xfer_unsetup = &at91dci_xfer_unsetup, 2300184610Salfred .get_hw_ep_profile = &at91dci_get_hw_ep_profile, 2301184610Salfred .set_stall = &at91dci_set_stall, 2302184610Salfred .clear_stall = &at91dci_clear_stall, 2303190735Sthompsa .roothub_exec = &at91dci_roothub_exec, 2304184610Salfred}; 2305