at91dci.c revision 193644
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/controller/at91dci.c 193644 2009-06-07 19:41:11Z 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_transfer.h> 58188942Sthompsa#include <dev/usb/usb_device.h> 59188942Sthompsa#include <dev/usb/usb_hub.h> 60188942Sthompsa#include <dev/usb/usb_util.h> 61184610Salfred 62188942Sthompsa#include <dev/usb/usb_controller.h> 63188942Sthompsa#include <dev/usb/usb_bus.h> 64188942Sthompsa#include <dev/usb/controller/at91dci.h> 65184610Salfred 66184610Salfred#define AT9100_DCI_BUS2SC(bus) \ 67184610Salfred ((struct at91dci_softc *)(((uint8_t *)(bus)) - \ 68190181Sthompsa ((uint8_t *)&(((struct at91dci_softc *)0)->sc_bus)))) 69184610Salfred 70184610Salfred#define AT9100_DCI_PC2SC(pc) \ 71190180Sthompsa AT9100_DCI_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus) 72184610Salfred 73184610Salfred#if USB_DEBUG 74184610Salfredstatic int at91dcidebug = 0; 75184610Salfred 76192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, at91dci, CTLFLAG_RW, 0, "USB at91dci"); 77192502SthompsaSYSCTL_INT(_hw_usb_at91dci, OID_AUTO, debug, CTLFLAG_RW, 78184610Salfred &at91dcidebug, 0, "at91dci debug level"); 79184610Salfred#endif 80184610Salfred 81184610Salfred#define AT9100_DCI_INTR_ENDPT 1 82184610Salfred 83184610Salfred/* prototypes */ 84184610Salfred 85192984Sthompsastruct usb_bus_methods at91dci_bus_methods; 86192984Sthompsastruct usb_pipe_methods at91dci_device_bulk_methods; 87192984Sthompsastruct usb_pipe_methods at91dci_device_ctrl_methods; 88192984Sthompsastruct usb_pipe_methods at91dci_device_intr_methods; 89192984Sthompsastruct usb_pipe_methods at91dci_device_isoc_fs_methods; 90184610Salfred 91184610Salfredstatic at91dci_cmd_t at91dci_setup_rx; 92184610Salfredstatic at91dci_cmd_t at91dci_data_rx; 93184610Salfredstatic at91dci_cmd_t at91dci_data_tx; 94184610Salfredstatic at91dci_cmd_t at91dci_data_tx_sync; 95193045Sthompsastatic void at91dci_device_done(struct usb_xfer *, usb_error_t); 96192984Sthompsastatic void at91dci_do_poll(struct usb_bus *); 97192984Sthompsastatic void at91dci_standard_done(struct usb_xfer *); 98190735Sthompsastatic void at91dci_root_intr(struct at91dci_softc *sc); 99184610Salfred 100184610Salfred/* 101184610Salfred * NOTE: Some of the bits in the CSR register have inverse meaning so 102184610Salfred * we need a helper macro when acknowledging events: 103184610Salfred */ 104184610Salfred#define AT91_CSR_ACK(csr, what) do { \ 105184610Salfred (csr) &= ~((AT91_UDP_CSR_FORCESTALL| \ 106184610Salfred AT91_UDP_CSR_TXPKTRDY| \ 107184610Salfred AT91_UDP_CSR_RXBYTECNT) ^ (what));\ 108184610Salfred (csr) |= ((AT91_UDP_CSR_RX_DATA_BK0| \ 109184610Salfred AT91_UDP_CSR_RX_DATA_BK1| \ 110184610Salfred AT91_UDP_CSR_TXCOMP| \ 111184610Salfred AT91_UDP_CSR_RXSETUP| \ 112184610Salfred AT91_UDP_CSR_STALLSENT) ^ (what)); \ 113184610Salfred} while (0) 114184610Salfred 115184610Salfred/* 116184610Salfred * Here is a list of what the chip supports. 117184610Salfred * Probably it supports more than listed here! 118184610Salfred */ 119192984Sthompsastatic const struct usb_hw_ep_profile 120184610Salfred at91dci_ep_profile[AT91_UDP_EP_MAX] = { 121184610Salfred 122184610Salfred [0] = { 123184610Salfred .max_in_frame_size = 8, 124184610Salfred .max_out_frame_size = 8, 125184610Salfred .is_simplex = 1, 126184610Salfred .support_control = 1, 127184610Salfred }, 128184610Salfred [1] = { 129184610Salfred .max_in_frame_size = 64, 130184610Salfred .max_out_frame_size = 64, 131184610Salfred .is_simplex = 1, 132184610Salfred .support_multi_buffer = 1, 133184610Salfred .support_bulk = 1, 134184610Salfred .support_interrupt = 1, 135184610Salfred .support_isochronous = 1, 136184610Salfred .support_in = 1, 137184610Salfred .support_out = 1, 138184610Salfred }, 139184610Salfred [2] = { 140184610Salfred .max_in_frame_size = 64, 141184610Salfred .max_out_frame_size = 64, 142184610Salfred .is_simplex = 1, 143184610Salfred .support_multi_buffer = 1, 144184610Salfred .support_bulk = 1, 145184610Salfred .support_interrupt = 1, 146184610Salfred .support_isochronous = 1, 147184610Salfred .support_in = 1, 148184610Salfred .support_out = 1, 149184610Salfred }, 150184610Salfred [3] = { 151184610Salfred /* can also do BULK */ 152184610Salfred .max_in_frame_size = 8, 153184610Salfred .max_out_frame_size = 8, 154184610Salfred .is_simplex = 1, 155184610Salfred .support_interrupt = 1, 156184610Salfred .support_in = 1, 157184610Salfred .support_out = 1, 158184610Salfred }, 159184610Salfred [4] = { 160184610Salfred .max_in_frame_size = 256, 161184610Salfred .max_out_frame_size = 256, 162184610Salfred .is_simplex = 1, 163184610Salfred .support_multi_buffer = 1, 164184610Salfred .support_bulk = 1, 165184610Salfred .support_interrupt = 1, 166184610Salfred .support_isochronous = 1, 167184610Salfred .support_in = 1, 168184610Salfred .support_out = 1, 169184610Salfred }, 170184610Salfred [5] = { 171184610Salfred .max_in_frame_size = 256, 172184610Salfred .max_out_frame_size = 256, 173184610Salfred .is_simplex = 1, 174184610Salfred .support_multi_buffer = 1, 175184610Salfred .support_bulk = 1, 176184610Salfred .support_interrupt = 1, 177184610Salfred .support_isochronous = 1, 178184610Salfred .support_in = 1, 179184610Salfred .support_out = 1, 180184610Salfred }, 181184610Salfred}; 182184610Salfred 183184610Salfredstatic void 184192984Sthompsaat91dci_get_hw_ep_profile(struct usb_device *udev, 185192984Sthompsa const struct usb_hw_ep_profile **ppf, uint8_t ep_addr) 186184610Salfred{ 187184610Salfred if (ep_addr < AT91_UDP_EP_MAX) { 188184610Salfred *ppf = (at91dci_ep_profile + ep_addr); 189184610Salfred } else { 190184610Salfred *ppf = NULL; 191184610Salfred } 192184610Salfred} 193184610Salfred 194184610Salfredstatic void 195184610Salfredat91dci_clocks_on(struct at91dci_softc *sc) 196184610Salfred{ 197184610Salfred if (sc->sc_flags.clocks_off && 198184610Salfred sc->sc_flags.port_powered) { 199184610Salfred 200184610Salfred DPRINTFN(5, "\n"); 201184610Salfred 202184610Salfred if (sc->sc_clocks_on) { 203184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 204184610Salfred } 205184610Salfred sc->sc_flags.clocks_off = 0; 206184610Salfred 207184610Salfred /* enable Transceiver */ 208184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, 0); 209184610Salfred } 210184610Salfred} 211184610Salfred 212184610Salfredstatic void 213184610Salfredat91dci_clocks_off(struct at91dci_softc *sc) 214184610Salfred{ 215184610Salfred if (!sc->sc_flags.clocks_off) { 216184610Salfred 217184610Salfred DPRINTFN(5, "\n"); 218184610Salfred 219184610Salfred /* disable Transceiver */ 220184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); 221184610Salfred 222184610Salfred if (sc->sc_clocks_off) { 223184610Salfred (sc->sc_clocks_off) (sc->sc_clocks_arg); 224184610Salfred } 225184610Salfred sc->sc_flags.clocks_off = 1; 226184610Salfred } 227184610Salfred} 228184610Salfred 229184610Salfredstatic void 230184610Salfredat91dci_pull_up(struct at91dci_softc *sc) 231184610Salfred{ 232184610Salfred /* pullup D+, if possible */ 233184610Salfred 234184610Salfred if (!sc->sc_flags.d_pulled_up && 235184610Salfred sc->sc_flags.port_powered) { 236184610Salfred sc->sc_flags.d_pulled_up = 1; 237184610Salfred (sc->sc_pull_up) (sc->sc_pull_arg); 238184610Salfred } 239184610Salfred} 240184610Salfred 241184610Salfredstatic void 242184610Salfredat91dci_pull_down(struct at91dci_softc *sc) 243184610Salfred{ 244184610Salfred /* pulldown D+, if possible */ 245184610Salfred 246184610Salfred if (sc->sc_flags.d_pulled_up) { 247184610Salfred sc->sc_flags.d_pulled_up = 0; 248184610Salfred (sc->sc_pull_down) (sc->sc_pull_arg); 249184610Salfred } 250184610Salfred} 251184610Salfred 252184610Salfredstatic void 253190735Sthompsaat91dci_wakeup_peer(struct at91dci_softc *sc) 254184610Salfred{ 255184610Salfred if (!(sc->sc_flags.status_suspend)) { 256184610Salfred return; 257184610Salfred } 258184610Salfred 259186730Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, AT91_UDP_GSTATE_ESR); 260184610Salfred 261186730Salfred /* wait 8 milliseconds */ 262188983Sthompsa /* Wait for reset to complete. */ 263188983Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); 264184610Salfred 265186730Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, 0); 266184610Salfred} 267184610Salfred 268184610Salfredstatic void 269184610Salfredat91dci_set_address(struct at91dci_softc *sc, uint8_t addr) 270184610Salfred{ 271184610Salfred DPRINTFN(5, "addr=%d\n", addr); 272184610Salfred 273184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, addr | 274184610Salfred AT91_UDP_FADDR_EN); 275184610Salfred} 276184610Salfred 277184610Salfredstatic uint8_t 278184610Salfredat91dci_setup_rx(struct at91dci_td *td) 279184610Salfred{ 280184610Salfred struct at91dci_softc *sc; 281192984Sthompsa struct usb_device_request req; 282184610Salfred uint32_t csr; 283184610Salfred uint32_t temp; 284184610Salfred uint16_t count; 285184610Salfred 286184610Salfred /* read out FIFO status */ 287184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 288184610Salfred td->status_reg); 289184610Salfred 290184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 291184610Salfred 292184610Salfred temp = csr; 293184610Salfred temp &= (AT91_UDP_CSR_RX_DATA_BK0 | 294184610Salfred AT91_UDP_CSR_RX_DATA_BK1 | 295184610Salfred AT91_UDP_CSR_STALLSENT | 296184610Salfred AT91_UDP_CSR_RXSETUP | 297184610Salfred AT91_UDP_CSR_TXCOMP); 298184610Salfred 299184610Salfred if (!(csr & AT91_UDP_CSR_RXSETUP)) { 300184610Salfred goto not_complete; 301184610Salfred } 302190721Sthompsa /* clear did stall */ 303190721Sthompsa td->did_stall = 0; 304190721Sthompsa 305184610Salfred /* get the packet byte count */ 306184610Salfred count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; 307184610Salfred 308184610Salfred /* verify data length */ 309184610Salfred if (count != td->remainder) { 310184610Salfred DPRINTFN(0, "Invalid SETUP packet " 311184610Salfred "length, %d bytes\n", count); 312184610Salfred goto not_complete; 313184610Salfred } 314184610Salfred if (count != sizeof(req)) { 315184610Salfred DPRINTFN(0, "Unsupported SETUP packet " 316184610Salfred "length, %d bytes\n", count); 317184610Salfred goto not_complete; 318184610Salfred } 319184610Salfred /* receive data */ 320184610Salfred bus_space_read_multi_1(td->io_tag, td->io_hdl, 321184610Salfred td->fifo_reg, (void *)&req, sizeof(req)); 322184610Salfred 323184610Salfred /* copy data into real buffer */ 324184610Salfred usb2_copy_in(td->pc, 0, &req, sizeof(req)); 325184610Salfred 326184610Salfred td->offset = sizeof(req); 327184610Salfred td->remainder = 0; 328184610Salfred 329184610Salfred /* get pointer to softc */ 330184610Salfred sc = AT9100_DCI_PC2SC(td->pc); 331184610Salfred 332184610Salfred /* sneak peek the set address */ 333184610Salfred if ((req.bmRequestType == UT_WRITE_DEVICE) && 334184610Salfred (req.bRequest == UR_SET_ADDRESS)) { 335184610Salfred sc->sc_dv_addr = req.wValue[0] & 0x7F; 336184610Salfred } else { 337184610Salfred sc->sc_dv_addr = 0xFF; 338184610Salfred } 339184610Salfred 340184610Salfred /* sneak peek the endpoint direction */ 341184610Salfred if (req.bmRequestType & UE_DIR_IN) { 342184610Salfred csr |= AT91_UDP_CSR_DIR; 343184610Salfred } else { 344184610Salfred csr &= ~AT91_UDP_CSR_DIR; 345184610Salfred } 346184610Salfred 347184610Salfred /* write the direction of the control transfer */ 348184610Salfred AT91_CSR_ACK(csr, temp); 349184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 350184610Salfred td->status_reg, csr); 351184610Salfred return (0); /* complete */ 352184610Salfred 353184610Salfrednot_complete: 354190721Sthompsa /* abort any ongoing transfer */ 355190721Sthompsa if (!td->did_stall) { 356190721Sthompsa DPRINTFN(5, "stalling\n"); 357190721Sthompsa temp |= AT91_UDP_CSR_FORCESTALL; 358190721Sthompsa td->did_stall = 1; 359190721Sthompsa } 360190721Sthompsa 361184610Salfred /* clear interrupts, if any */ 362184610Salfred if (temp) { 363184610Salfred DPRINTFN(5, "clearing 0x%08x\n", temp); 364184610Salfred AT91_CSR_ACK(csr, temp); 365184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 366184610Salfred td->status_reg, csr); 367184610Salfred } 368184610Salfred return (1); /* not complete */ 369184610Salfred 370184610Salfred} 371184610Salfred 372184610Salfredstatic uint8_t 373184610Salfredat91dci_data_rx(struct at91dci_td *td) 374184610Salfred{ 375192984Sthompsa struct usb_page_search buf_res; 376184610Salfred uint32_t csr; 377184610Salfred uint32_t temp; 378184610Salfred uint16_t count; 379184610Salfred uint8_t to; 380184610Salfred uint8_t got_short; 381184610Salfred 382184610Salfred to = 2; /* don't loop forever! */ 383184610Salfred got_short = 0; 384184610Salfred 385184610Salfred /* check if any of the FIFO banks have data */ 386184610Salfredrepeat: 387184610Salfred /* read out FIFO status */ 388184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 389184610Salfred td->status_reg); 390184610Salfred 391184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 392184610Salfred 393184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 394184610Salfred if (td->remainder == 0) { 395184610Salfred /* 396184610Salfred * We are actually complete and have 397184610Salfred * received the next SETUP 398184610Salfred */ 399184610Salfred DPRINTFN(5, "faking complete\n"); 400184610Salfred return (0); /* complete */ 401184610Salfred } 402184610Salfred /* 403184610Salfred * USB Host Aborted the transfer. 404184610Salfred */ 405184610Salfred td->error = 1; 406184610Salfred return (0); /* complete */ 407184610Salfred } 408184610Salfred /* Make sure that "STALLSENT" gets cleared */ 409184610Salfred temp = csr; 410184610Salfred temp &= AT91_UDP_CSR_STALLSENT; 411184610Salfred 412184610Salfred /* check status */ 413184610Salfred if (!(csr & (AT91_UDP_CSR_RX_DATA_BK0 | 414184610Salfred AT91_UDP_CSR_RX_DATA_BK1))) { 415184610Salfred if (temp) { 416184610Salfred /* write command */ 417184610Salfred AT91_CSR_ACK(csr, temp); 418184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 419184610Salfred td->status_reg, csr); 420184610Salfred } 421184610Salfred return (1); /* not complete */ 422184610Salfred } 423184610Salfred /* get the packet byte count */ 424184610Salfred count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; 425184610Salfred 426184610Salfred /* verify the packet byte count */ 427184610Salfred if (count != td->max_packet_size) { 428184610Salfred if (count < td->max_packet_size) { 429184610Salfred /* we have a short packet */ 430184610Salfred td->short_pkt = 1; 431184610Salfred got_short = 1; 432184610Salfred } else { 433184610Salfred /* invalid USB packet */ 434184610Salfred td->error = 1; 435184610Salfred return (0); /* we are complete */ 436184610Salfred } 437184610Salfred } 438184610Salfred /* verify the packet byte count */ 439184610Salfred if (count > td->remainder) { 440184610Salfred /* invalid USB packet */ 441184610Salfred td->error = 1; 442184610Salfred return (0); /* we are complete */ 443184610Salfred } 444184610Salfred while (count > 0) { 445184610Salfred usb2_get_page(td->pc, td->offset, &buf_res); 446184610Salfred 447184610Salfred /* get correct length */ 448184610Salfred if (buf_res.length > count) { 449184610Salfred buf_res.length = count; 450184610Salfred } 451184610Salfred /* receive data */ 452184610Salfred bus_space_read_multi_1(td->io_tag, td->io_hdl, 453184610Salfred td->fifo_reg, buf_res.buffer, buf_res.length); 454184610Salfred 455184610Salfred /* update counters */ 456184610Salfred count -= buf_res.length; 457184610Salfred td->offset += buf_res.length; 458184610Salfred td->remainder -= buf_res.length; 459184610Salfred } 460184610Salfred 461184610Salfred /* clear status bits */ 462184610Salfred if (td->support_multi_buffer) { 463184610Salfred if (td->fifo_bank) { 464184610Salfred td->fifo_bank = 0; 465184610Salfred temp |= AT91_UDP_CSR_RX_DATA_BK1; 466184610Salfred } else { 467184610Salfred td->fifo_bank = 1; 468184610Salfred temp |= AT91_UDP_CSR_RX_DATA_BK0; 469184610Salfred } 470184610Salfred } else { 471184610Salfred temp |= (AT91_UDP_CSR_RX_DATA_BK0 | 472184610Salfred AT91_UDP_CSR_RX_DATA_BK1); 473184610Salfred } 474184610Salfred 475184610Salfred /* write command */ 476184610Salfred AT91_CSR_ACK(csr, temp); 477184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 478184610Salfred td->status_reg, csr); 479184610Salfred 480184610Salfred /* 481184610Salfred * NOTE: We may have to delay a little bit before 482184610Salfred * proceeding after clearing the DATA_BK bits. 483184610Salfred */ 484184610Salfred 485184610Salfred /* check if we are complete */ 486184610Salfred if ((td->remainder == 0) || got_short) { 487184610Salfred if (td->short_pkt) { 488184610Salfred /* we are complete */ 489184610Salfred return (0); 490184610Salfred } 491184610Salfred /* else need to receive a zero length packet */ 492184610Salfred } 493184610Salfred if (--to) { 494184610Salfred goto repeat; 495184610Salfred } 496184610Salfred return (1); /* not complete */ 497184610Salfred} 498184610Salfred 499184610Salfredstatic uint8_t 500184610Salfredat91dci_data_tx(struct at91dci_td *td) 501184610Salfred{ 502192984Sthompsa struct usb_page_search buf_res; 503184610Salfred uint32_t csr; 504184610Salfred uint32_t temp; 505184610Salfred uint16_t count; 506184610Salfred uint8_t to; 507184610Salfred 508184610Salfred to = 2; /* don't loop forever! */ 509184610Salfred 510184610Salfredrepeat: 511184610Salfred 512184610Salfred /* read out FIFO status */ 513184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 514184610Salfred td->status_reg); 515184610Salfred 516184610Salfred DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); 517184610Salfred 518184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 519184610Salfred /* 520184610Salfred * The current transfer was aborted 521184610Salfred * by the USB Host 522184610Salfred */ 523184610Salfred td->error = 1; 524184610Salfred return (0); /* complete */ 525184610Salfred } 526184610Salfred /* Make sure that "STALLSENT" gets cleared */ 527184610Salfred temp = csr; 528184610Salfred temp &= AT91_UDP_CSR_STALLSENT; 529184610Salfred 530184610Salfred if (csr & AT91_UDP_CSR_TXPKTRDY) { 531184610Salfred if (temp) { 532184610Salfred /* write command */ 533184610Salfred AT91_CSR_ACK(csr, temp); 534184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 535184610Salfred td->status_reg, csr); 536184610Salfred } 537184610Salfred return (1); /* not complete */ 538184610Salfred } else { 539184610Salfred /* clear TXCOMP and set TXPKTRDY */ 540184610Salfred temp |= (AT91_UDP_CSR_TXCOMP | 541184610Salfred AT91_UDP_CSR_TXPKTRDY); 542184610Salfred } 543184610Salfred 544184610Salfred count = td->max_packet_size; 545184610Salfred if (td->remainder < count) { 546184610Salfred /* we have a short packet */ 547184610Salfred td->short_pkt = 1; 548184610Salfred count = td->remainder; 549184610Salfred } 550184610Salfred while (count > 0) { 551184610Salfred 552184610Salfred usb2_get_page(td->pc, td->offset, &buf_res); 553184610Salfred 554184610Salfred /* get correct length */ 555184610Salfred if (buf_res.length > count) { 556184610Salfred buf_res.length = count; 557184610Salfred } 558184610Salfred /* transmit data */ 559184610Salfred bus_space_write_multi_1(td->io_tag, td->io_hdl, 560184610Salfred td->fifo_reg, buf_res.buffer, buf_res.length); 561184610Salfred 562184610Salfred /* update counters */ 563184610Salfred count -= buf_res.length; 564184610Salfred td->offset += buf_res.length; 565184610Salfred td->remainder -= buf_res.length; 566184610Salfred } 567184610Salfred 568184610Salfred /* write command */ 569184610Salfred AT91_CSR_ACK(csr, temp); 570184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 571184610Salfred td->status_reg, csr); 572184610Salfred 573184610Salfred /* check remainder */ 574184610Salfred if (td->remainder == 0) { 575184610Salfred if (td->short_pkt) { 576184610Salfred return (0); /* complete */ 577184610Salfred } 578184610Salfred /* else we need to transmit a short packet */ 579184610Salfred } 580184610Salfred if (--to) { 581184610Salfred goto repeat; 582184610Salfred } 583184610Salfred return (1); /* not complete */ 584184610Salfred} 585184610Salfred 586184610Salfredstatic uint8_t 587184610Salfredat91dci_data_tx_sync(struct at91dci_td *td) 588184610Salfred{ 589184610Salfred struct at91dci_softc *sc; 590184610Salfred uint32_t csr; 591184610Salfred uint32_t temp; 592184610Salfred 593184610Salfred#if 0 594184610Salfredrepeat: 595184610Salfred#endif 596184610Salfred 597184610Salfred /* read out FIFO status */ 598184610Salfred csr = bus_space_read_4(td->io_tag, td->io_hdl, 599184610Salfred td->status_reg); 600184610Salfred 601184610Salfred DPRINTFN(5, "csr=0x%08x\n", csr); 602184610Salfred 603184610Salfred if (csr & AT91_UDP_CSR_RXSETUP) { 604184610Salfred DPRINTFN(5, "faking complete\n"); 605184610Salfred /* Race condition */ 606184610Salfred return (0); /* complete */ 607184610Salfred } 608184610Salfred temp = csr; 609184610Salfred temp &= (AT91_UDP_CSR_STALLSENT | 610184610Salfred AT91_UDP_CSR_TXCOMP); 611184610Salfred 612184610Salfred /* check status */ 613184610Salfred if (csr & AT91_UDP_CSR_TXPKTRDY) { 614184610Salfred goto not_complete; 615184610Salfred } 616184610Salfred if (!(csr & AT91_UDP_CSR_TXCOMP)) { 617184610Salfred goto not_complete; 618184610Salfred } 619184610Salfred sc = AT9100_DCI_PC2SC(td->pc); 620184610Salfred if (sc->sc_dv_addr != 0xFF) { 621184610Salfred /* 622184610Salfred * The AT91 has a special requirement with regard to 623184610Salfred * setting the address and that is to write the new 624184610Salfred * address before clearing TXCOMP: 625184610Salfred */ 626184610Salfred at91dci_set_address(sc, sc->sc_dv_addr); 627184610Salfred } 628184610Salfred /* write command */ 629184610Salfred AT91_CSR_ACK(csr, temp); 630184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 631184610Salfred td->status_reg, csr); 632184610Salfred 633184610Salfred return (0); /* complete */ 634184610Salfred 635184610Salfrednot_complete: 636184610Salfred if (temp) { 637184610Salfred /* write command */ 638184610Salfred AT91_CSR_ACK(csr, temp); 639184610Salfred bus_space_write_4(td->io_tag, td->io_hdl, 640184610Salfred td->status_reg, csr); 641184610Salfred } 642184610Salfred return (1); /* not complete */ 643184610Salfred} 644184610Salfred 645184610Salfredstatic uint8_t 646192984Sthompsaat91dci_xfer_do_fifo(struct usb_xfer *xfer) 647184610Salfred{ 648184610Salfred struct at91dci_softc *sc; 649184610Salfred struct at91dci_td *td; 650184610Salfred uint8_t temp; 651184610Salfred 652184610Salfred DPRINTFN(9, "\n"); 653184610Salfred 654184610Salfred td = xfer->td_transfer_cache; 655184610Salfred while (1) { 656184610Salfred if ((td->func) (td)) { 657184610Salfred /* operation in progress */ 658184610Salfred break; 659184610Salfred } 660184610Salfred if (((void *)td) == xfer->td_transfer_last) { 661184610Salfred goto done; 662184610Salfred } 663184610Salfred if (td->error) { 664184610Salfred goto done; 665184610Salfred } else if (td->remainder > 0) { 666184610Salfred /* 667184610Salfred * We had a short transfer. If there is no alternate 668184610Salfred * next, stop processing ! 669184610Salfred */ 670184610Salfred if (!td->alt_next) { 671184610Salfred goto done; 672184610Salfred } 673184610Salfred } 674184610Salfred /* 675184610Salfred * Fetch the next transfer descriptor and transfer 676184610Salfred * some flags to the next transfer descriptor 677184610Salfred */ 678184610Salfred temp = 0; 679184610Salfred if (td->fifo_bank) 680184610Salfred temp |= 1; 681184610Salfred td = td->obj_next; 682184610Salfred xfer->td_transfer_cache = td; 683184610Salfred if (temp & 1) 684184610Salfred td->fifo_bank = 1; 685184610Salfred } 686184610Salfred return (1); /* not complete */ 687184610Salfred 688184610Salfreddone: 689187173Sthompsa sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 690193644Sthompsa temp = (xfer->endpointno & UE_ADDR); 691184610Salfred 692184610Salfred /* update FIFO bank flag and multi buffer */ 693184610Salfred if (td->fifo_bank) { 694184610Salfred sc->sc_ep_flags[temp].fifo_bank = 1; 695184610Salfred } else { 696184610Salfred sc->sc_ep_flags[temp].fifo_bank = 0; 697184610Salfred } 698184610Salfred 699184610Salfred /* compute all actual lengths */ 700184610Salfred 701184610Salfred at91dci_standard_done(xfer); 702184610Salfred 703184610Salfred return (0); /* complete */ 704184610Salfred} 705184610Salfred 706184610Salfredstatic void 707184610Salfredat91dci_interrupt_poll(struct at91dci_softc *sc) 708184610Salfred{ 709192984Sthompsa struct usb_xfer *xfer; 710184610Salfred 711184610Salfredrepeat: 712184610Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 713184610Salfred if (!at91dci_xfer_do_fifo(xfer)) { 714184610Salfred /* queue has been modified */ 715184610Salfred goto repeat; 716184610Salfred } 717184610Salfred } 718184610Salfred} 719184610Salfred 720187175Sthompsavoid 721187175Sthompsaat91dci_vbus_interrupt(struct at91dci_softc *sc, uint8_t is_on) 722184610Salfred{ 723184610Salfred DPRINTFN(5, "vbus = %u\n", is_on); 724184610Salfred 725184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 726184610Salfred if (is_on) { 727184610Salfred if (!sc->sc_flags.status_vbus) { 728184610Salfred sc->sc_flags.status_vbus = 1; 729184610Salfred 730184610Salfred /* complete root HUB interrupt endpoint */ 731190735Sthompsa at91dci_root_intr(sc); 732184610Salfred } 733184610Salfred } else { 734184610Salfred if (sc->sc_flags.status_vbus) { 735184610Salfred sc->sc_flags.status_vbus = 0; 736184610Salfred sc->sc_flags.status_bus_reset = 0; 737184610Salfred sc->sc_flags.status_suspend = 0; 738184610Salfred sc->sc_flags.change_suspend = 0; 739184610Salfred sc->sc_flags.change_connect = 1; 740184610Salfred 741184610Salfred /* complete root HUB interrupt endpoint */ 742190735Sthompsa at91dci_root_intr(sc); 743184610Salfred } 744184610Salfred } 745184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 746184610Salfred} 747184610Salfred 748184610Salfredvoid 749184610Salfredat91dci_interrupt(struct at91dci_softc *sc) 750184610Salfred{ 751184610Salfred uint32_t status; 752184610Salfred 753184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 754184610Salfred 755184610Salfred status = AT91_UDP_READ_4(sc, AT91_UDP_ISR); 756184610Salfred status &= AT91_UDP_INT_DEFAULT; 757184610Salfred 758184610Salfred if (!status) { 759184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 760184610Salfred return; 761184610Salfred } 762184610Salfred /* acknowledge interrupts */ 763184610Salfred 764184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status); 765184610Salfred 766184610Salfred /* check for any bus state change interrupts */ 767184610Salfred 768184610Salfred if (status & AT91_UDP_INT_BUS) { 769184610Salfred 770184610Salfred DPRINTFN(5, "real bus interrupt 0x%08x\n", status); 771184610Salfred 772184610Salfred if (status & AT91_UDP_INT_END_BR) { 773184610Salfred 774184610Salfred /* set correct state */ 775184610Salfred sc->sc_flags.status_bus_reset = 1; 776184610Salfred sc->sc_flags.status_suspend = 0; 777184610Salfred sc->sc_flags.change_suspend = 0; 778184610Salfred sc->sc_flags.change_connect = 1; 779184610Salfred 780184610Salfred /* disable resume interrupt */ 781184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 782184610Salfred AT91_UDP_INT_RXRSM); 783184610Salfred /* enable suspend interrupt */ 784184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 785184610Salfred AT91_UDP_INT_RXSUSP); 786184610Salfred } 787184610Salfred /* 788184610Salfred * If RXRSM and RXSUSP is set at the same time we interpret 789184610Salfred * that like RESUME. Resume is set when there is at least 3 790184610Salfred * milliseconds of inactivity on the USB BUS. 791184610Salfred */ 792184610Salfred if (status & AT91_UDP_INT_RXRSM) { 793184610Salfred if (sc->sc_flags.status_suspend) { 794184610Salfred sc->sc_flags.status_suspend = 0; 795184610Salfred sc->sc_flags.change_suspend = 1; 796184610Salfred 797184610Salfred /* disable resume interrupt */ 798184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 799184610Salfred AT91_UDP_INT_RXRSM); 800184610Salfred /* enable suspend interrupt */ 801184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 802184610Salfred AT91_UDP_INT_RXSUSP); 803184610Salfred } 804184610Salfred } else if (status & AT91_UDP_INT_RXSUSP) { 805184610Salfred if (!sc->sc_flags.status_suspend) { 806184610Salfred sc->sc_flags.status_suspend = 1; 807184610Salfred sc->sc_flags.change_suspend = 1; 808184610Salfred 809184610Salfred /* disable suspend interrupt */ 810184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 811184610Salfred AT91_UDP_INT_RXSUSP); 812184610Salfred 813184610Salfred /* enable resume interrupt */ 814184610Salfred AT91_UDP_WRITE_4(sc, AT91_UDP_IER, 815184610Salfred AT91_UDP_INT_RXRSM); 816184610Salfred } 817184610Salfred } 818184610Salfred /* complete root HUB interrupt endpoint */ 819190735Sthompsa at91dci_root_intr(sc); 820184610Salfred } 821184610Salfred /* check for any endpoint interrupts */ 822184610Salfred 823184610Salfred if (status & AT91_UDP_INT_EPS) { 824184610Salfred 825184610Salfred DPRINTFN(5, "real endpoint interrupt 0x%08x\n", status); 826184610Salfred 827184610Salfred at91dci_interrupt_poll(sc); 828184610Salfred } 829184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 830184610Salfred} 831184610Salfred 832184610Salfredstatic void 833184610Salfredat91dci_setup_standard_chain_sub(struct at91dci_std_temp *temp) 834184610Salfred{ 835184610Salfred struct at91dci_td *td; 836184610Salfred 837184610Salfred /* get current Transfer Descriptor */ 838184610Salfred td = temp->td_next; 839184610Salfred temp->td = td; 840184610Salfred 841184610Salfred /* prepare for next TD */ 842184610Salfred temp->td_next = td->obj_next; 843184610Salfred 844184610Salfred /* fill out the Transfer Descriptor */ 845184610Salfred td->func = temp->func; 846184610Salfred td->pc = temp->pc; 847184610Salfred td->offset = temp->offset; 848184610Salfred td->remainder = temp->len; 849184610Salfred td->fifo_bank = 0; 850184610Salfred td->error = 0; 851192552Sthompsa td->did_stall = temp->did_stall; 852184610Salfred td->short_pkt = temp->short_pkt; 853184610Salfred td->alt_next = temp->setup_alt_next; 854184610Salfred} 855184610Salfred 856184610Salfredstatic void 857192984Sthompsaat91dci_setup_standard_chain(struct usb_xfer *xfer) 858184610Salfred{ 859184610Salfred struct at91dci_std_temp temp; 860184610Salfred struct at91dci_softc *sc; 861184610Salfred struct at91dci_td *td; 862184610Salfred uint32_t x; 863184610Salfred uint8_t ep_no; 864184610Salfred uint8_t need_sync; 865184610Salfred 866184610Salfred DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", 867193644Sthompsa xfer->address, UE_GET_ADDR(xfer->endpointno), 868187173Sthompsa xfer->sumlen, usb2_get_speed(xfer->xroot->udev)); 869184610Salfred 870184610Salfred temp.max_frame_size = xfer->max_frame_size; 871184610Salfred 872184610Salfred td = xfer->td_start[0]; 873184610Salfred xfer->td_transfer_first = td; 874184610Salfred xfer->td_transfer_cache = td; 875184610Salfred 876184610Salfred /* setup temp */ 877184610Salfred 878184610Salfred temp.td = NULL; 879184610Salfred temp.td_next = xfer->td_start[0]; 880190183Sthompsa temp.offset = 0; 881184610Salfred temp.setup_alt_next = xfer->flags_int.short_frames_ok; 882192552Sthompsa temp.did_stall = !xfer->flags_int.control_stall; 883184610Salfred 884187173Sthompsa sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); 885193644Sthompsa ep_no = (xfer->endpointno & 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) { 911193644Sthompsa if (xfer->endpointno & 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 */ 987193644Sthompsa if (xfer->endpointno & 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{ 1018192984Sthompsa struct usb_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 1029192984Sthompsaat91dci_start_standard_chain(struct usb_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); 1037193644Sthompsa uint8_t ep_no = xfer->endpointno & 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 1073193045Sthompsastatic usb_error_t 1074192984Sthompsaat91dci_standard_done_sub(struct usb_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 1138192984Sthompsaat91dci_standard_done(struct usb_xfer *xfer) 1139184610Salfred{ 1140193045Sthompsa usb_error_t err = 0; 1141184610Salfred 1142193644Sthompsa DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", 1143193644Sthompsa xfer, xfer->endpoint); 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 1187193045Sthompsaat91dci_device_done(struct usb_xfer *xfer, usb_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 1194193644Sthompsa DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n", 1195193644Sthompsa xfer, xfer->endpoint, error); 1196184610Salfred 1197192499Sthompsa if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { 1198193644Sthompsa ep_no = (xfer->endpointno & 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 1210192984Sthompsaat91dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer, 1211193644Sthompsa struct usb_endpoint *ep) 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 1219193644Sthompsa DPRINTFN(5, "endpoint=%p\n", ep); 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); 1227193644Sthompsa csr_reg = (ep->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{ 1238192984Sthompsa const struct usb_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 1331193644Sthompsaat91dci_clear_stall(struct usb_device *udev, struct usb_endpoint *ep) 1332184610Salfred{ 1333184610Salfred struct at91dci_softc *sc; 1334192984Sthompsa struct usb_endpoint_descriptor *ed; 1335184610Salfred 1336193644Sthompsa DPRINTFN(5, "endpoint=%p\n", ep); 1337184610Salfred 1338184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 1339184610Salfred 1340184610Salfred /* check mode */ 1341192499Sthompsa if (udev->flags.usb_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 */ 1349193644Sthompsa ed = ep->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 1358193045Sthompsausb_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 1458192984Sthompsaat91dci_do_poll(struct usb_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 1471192984Sthompsaat91dci_device_bulk_open(struct usb_xfer *xfer) 1472184610Salfred{ 1473184610Salfred return; 1474184610Salfred} 1475184610Salfred 1476184610Salfredstatic void 1477192984Sthompsaat91dci_device_bulk_close(struct usb_xfer *xfer) 1478184610Salfred{ 1479184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1480184610Salfred} 1481184610Salfred 1482184610Salfredstatic void 1483192984Sthompsaat91dci_device_bulk_enter(struct usb_xfer *xfer) 1484184610Salfred{ 1485184610Salfred return; 1486184610Salfred} 1487184610Salfred 1488184610Salfredstatic void 1489192984Sthompsaat91dci_device_bulk_start(struct usb_xfer *xfer) 1490184610Salfred{ 1491184610Salfred /* setup TDs */ 1492184610Salfred at91dci_setup_standard_chain(xfer); 1493184610Salfred at91dci_start_standard_chain(xfer); 1494184610Salfred} 1495184610Salfred 1496192984Sthompsastruct usb_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 1508192984Sthompsaat91dci_device_ctrl_open(struct usb_xfer *xfer) 1509184610Salfred{ 1510184610Salfred return; 1511184610Salfred} 1512184610Salfred 1513184610Salfredstatic void 1514192984Sthompsaat91dci_device_ctrl_close(struct usb_xfer *xfer) 1515184610Salfred{ 1516184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1517184610Salfred} 1518184610Salfred 1519184610Salfredstatic void 1520192984Sthompsaat91dci_device_ctrl_enter(struct usb_xfer *xfer) 1521184610Salfred{ 1522184610Salfred return; 1523184610Salfred} 1524184610Salfred 1525184610Salfredstatic void 1526192984Sthompsaat91dci_device_ctrl_start(struct usb_xfer *xfer) 1527184610Salfred{ 1528184610Salfred /* setup TDs */ 1529184610Salfred at91dci_setup_standard_chain(xfer); 1530184610Salfred at91dci_start_standard_chain(xfer); 1531184610Salfred} 1532184610Salfred 1533192984Sthompsastruct usb_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 1545192984Sthompsaat91dci_device_intr_open(struct usb_xfer *xfer) 1546184610Salfred{ 1547184610Salfred return; 1548184610Salfred} 1549184610Salfred 1550184610Salfredstatic void 1551192984Sthompsaat91dci_device_intr_close(struct usb_xfer *xfer) 1552184610Salfred{ 1553184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1554184610Salfred} 1555184610Salfred 1556184610Salfredstatic void 1557192984Sthompsaat91dci_device_intr_enter(struct usb_xfer *xfer) 1558184610Salfred{ 1559184610Salfred return; 1560184610Salfred} 1561184610Salfred 1562184610Salfredstatic void 1563192984Sthompsaat91dci_device_intr_start(struct usb_xfer *xfer) 1564184610Salfred{ 1565184610Salfred /* setup TDs */ 1566184610Salfred at91dci_setup_standard_chain(xfer); 1567184610Salfred at91dci_start_standard_chain(xfer); 1568184610Salfred} 1569184610Salfred 1570192984Sthompsastruct usb_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 1582192984Sthompsaat91dci_device_isoc_fs_open(struct usb_xfer *xfer) 1583184610Salfred{ 1584184610Salfred return; 1585184610Salfred} 1586184610Salfred 1587184610Salfredstatic void 1588192984Sthompsaat91dci_device_isoc_fs_close(struct usb_xfer *xfer) 1589184610Salfred{ 1590184610Salfred at91dci_device_done(xfer, USB_ERR_CANCELLED); 1591184610Salfred} 1592184610Salfred 1593184610Salfredstatic void 1594192984Sthompsaat91dci_device_isoc_fs_enter(struct usb_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", 1601193644Sthompsa xfer, xfer->endpoint->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 */ 1611193644Sthompsa temp = (nframes - xfer->endpoint->isoc_next) & AT91_UDP_FRM_MASK; 1612184610Salfred 1613193644Sthompsa if ((xfer->endpoint->is_synced == 0) || 1614184610Salfred (temp < xfer->nframes)) { 1615184610Salfred /* 1616193644Sthompsa * If there is data underflow or the endpoint 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 */ 1621193644Sthompsa xfer->endpoint->isoc_next = (nframes + 3) & AT91_UDP_FRM_MASK; 1622193644Sthompsa xfer->endpoint->is_synced = 1; 1623193644Sthompsa DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next); 1624184610Salfred } 1625184610Salfred /* 1626184610Salfred * compute how many milliseconds the insertion is ahead of the 1627184610Salfred * current frame position: 1628184610Salfred */ 1629193644Sthompsa temp = (xfer->endpoint->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 */ 1639193644Sthompsa xfer->endpoint->isoc_next += xfer->nframes; 1640184610Salfred 1641184610Salfred /* setup TDs */ 1642184610Salfred at91dci_setup_standard_chain(xfer); 1643184610Salfred} 1644184610Salfred 1645184610Salfredstatic void 1646192984Sthompsaat91dci_device_isoc_fs_start(struct usb_xfer *xfer) 1647184610Salfred{ 1648184610Salfred /* start TD chain */ 1649184610Salfred at91dci_start_standard_chain(xfer); 1650184610Salfred} 1651184610Salfred 1652192984Sthompsastruct usb_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 1666192984Sthompsastatic const struct usb_device_descriptor at91dci_devd = { 1667192984Sthompsa .bLength = sizeof(struct usb_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 1680192984Sthompsastatic const struct usb_device_qualifier at91dci_odevd = { 1681192984Sthompsa .bLength = sizeof(struct usb_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 = { 1693192984Sthompsa .bLength = sizeof(struct usb_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 = { 1703192984Sthompsa .bLength = sizeof(struct usb_interface_descriptor), 1704184610Salfred .bDescriptorType = UDESC_INTERFACE, 1705184610Salfred .bNumEndpoints = 1, 1706184610Salfred .bInterfaceClass = UICLASS_HUB, 1707184610Salfred .bInterfaceSubClass = UISUBCLASS_HUB, 1708184610Salfred .bInterfaceProtocol = UIPROTO_HSHUBSTT, 1709184610Salfred }, 1710184610Salfred .endpd = { 1711192984Sthompsa .bLength = sizeof(struct usb_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 1720192984Sthompsastatic const struct usb_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 1748193045Sthompsastatic usb_error_t 1749192984Sthompsaat91dci_roothub_exec(struct usb_device *udev, 1750192984Sthompsa struct usb_device_request *req, const void **pptr, uint16_t *plength) 1751184610Salfred{ 1752191402Sthompsa struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus); 1753191402Sthompsa const void *ptr; 1754191402Sthompsa uint16_t len; 1755184610Salfred uint16_t value; 1756184610Salfred uint16_t index; 1757193045Sthompsa usb_error_t err; 1758184610Salfred 1759184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1760184610Salfred 1761184610Salfred /* buffer reset */ 1762191402Sthompsa ptr = (const void *)&sc->sc_hub_temp; 1763191402Sthompsa len = 0; 1764191402Sthompsa err = 0; 1765184610Salfred 1766191402Sthompsa value = UGETW(req->wValue); 1767191402Sthompsa index = UGETW(req->wIndex); 1768184610Salfred 1769184610Salfred /* demultiplex the control request */ 1770184610Salfred 1771191402Sthompsa switch (req->bmRequestType) { 1772184610Salfred case UT_READ_DEVICE: 1773191402Sthompsa switch (req->bRequest) { 1774184610Salfred case UR_GET_DESCRIPTOR: 1775184610Salfred goto tr_handle_get_descriptor; 1776184610Salfred case UR_GET_CONFIG: 1777184610Salfred goto tr_handle_get_config; 1778184610Salfred case UR_GET_STATUS: 1779184610Salfred goto tr_handle_get_status; 1780184610Salfred default: 1781184610Salfred goto tr_stalled; 1782184610Salfred } 1783184610Salfred break; 1784184610Salfred 1785184610Salfred case UT_WRITE_DEVICE: 1786191402Sthompsa switch (req->bRequest) { 1787184610Salfred case UR_SET_ADDRESS: 1788184610Salfred goto tr_handle_set_address; 1789184610Salfred case UR_SET_CONFIG: 1790184610Salfred goto tr_handle_set_config; 1791184610Salfred case UR_CLEAR_FEATURE: 1792184610Salfred goto tr_valid; /* nop */ 1793184610Salfred case UR_SET_DESCRIPTOR: 1794184610Salfred goto tr_valid; /* nop */ 1795184610Salfred case UR_SET_FEATURE: 1796184610Salfred default: 1797184610Salfred goto tr_stalled; 1798184610Salfred } 1799184610Salfred break; 1800184610Salfred 1801184610Salfred case UT_WRITE_ENDPOINT: 1802191402Sthompsa switch (req->bRequest) { 1803184610Salfred case UR_CLEAR_FEATURE: 1804191402Sthompsa switch (UGETW(req->wValue)) { 1805184610Salfred case UF_ENDPOINT_HALT: 1806184610Salfred goto tr_handle_clear_halt; 1807184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 1808184610Salfred goto tr_handle_clear_wakeup; 1809184610Salfred default: 1810184610Salfred goto tr_stalled; 1811184610Salfred } 1812184610Salfred break; 1813184610Salfred case UR_SET_FEATURE: 1814191402Sthompsa switch (UGETW(req->wValue)) { 1815184610Salfred case UF_ENDPOINT_HALT: 1816184610Salfred goto tr_handle_set_halt; 1817184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 1818184610Salfred goto tr_handle_set_wakeup; 1819184610Salfred default: 1820184610Salfred goto tr_stalled; 1821184610Salfred } 1822184610Salfred break; 1823184610Salfred case UR_SYNCH_FRAME: 1824184610Salfred goto tr_valid; /* nop */ 1825184610Salfred default: 1826184610Salfred goto tr_stalled; 1827184610Salfred } 1828184610Salfred break; 1829184610Salfred 1830184610Salfred case UT_READ_ENDPOINT: 1831191402Sthompsa switch (req->bRequest) { 1832184610Salfred case UR_GET_STATUS: 1833184610Salfred goto tr_handle_get_ep_status; 1834184610Salfred default: 1835184610Salfred goto tr_stalled; 1836184610Salfred } 1837184610Salfred break; 1838184610Salfred 1839184610Salfred case UT_WRITE_INTERFACE: 1840191402Sthompsa switch (req->bRequest) { 1841184610Salfred case UR_SET_INTERFACE: 1842184610Salfred goto tr_handle_set_interface; 1843184610Salfred case UR_CLEAR_FEATURE: 1844184610Salfred goto tr_valid; /* nop */ 1845184610Salfred case UR_SET_FEATURE: 1846184610Salfred default: 1847184610Salfred goto tr_stalled; 1848184610Salfred } 1849184610Salfred break; 1850184610Salfred 1851184610Salfred case UT_READ_INTERFACE: 1852191402Sthompsa switch (req->bRequest) { 1853184610Salfred case UR_GET_INTERFACE: 1854184610Salfred goto tr_handle_get_interface; 1855184610Salfred case UR_GET_STATUS: 1856184610Salfred goto tr_handle_get_iface_status; 1857184610Salfred default: 1858184610Salfred goto tr_stalled; 1859184610Salfred } 1860184610Salfred break; 1861184610Salfred 1862184610Salfred case UT_WRITE_CLASS_INTERFACE: 1863184610Salfred case UT_WRITE_VENDOR_INTERFACE: 1864184610Salfred /* XXX forward */ 1865184610Salfred break; 1866184610Salfred 1867184610Salfred case UT_READ_CLASS_INTERFACE: 1868184610Salfred case UT_READ_VENDOR_INTERFACE: 1869184610Salfred /* XXX forward */ 1870184610Salfred break; 1871184610Salfred 1872184610Salfred case UT_WRITE_CLASS_DEVICE: 1873191402Sthompsa switch (req->bRequest) { 1874184610Salfred case UR_CLEAR_FEATURE: 1875184610Salfred goto tr_valid; 1876184610Salfred case UR_SET_DESCRIPTOR: 1877184610Salfred case UR_SET_FEATURE: 1878184610Salfred break; 1879184610Salfred default: 1880184610Salfred goto tr_stalled; 1881184610Salfred } 1882184610Salfred break; 1883184610Salfred 1884184610Salfred case UT_WRITE_CLASS_OTHER: 1885191402Sthompsa switch (req->bRequest) { 1886184610Salfred case UR_CLEAR_FEATURE: 1887184610Salfred goto tr_handle_clear_port_feature; 1888184610Salfred case UR_SET_FEATURE: 1889184610Salfred goto tr_handle_set_port_feature; 1890184610Salfred case UR_CLEAR_TT_BUFFER: 1891184610Salfred case UR_RESET_TT: 1892184610Salfred case UR_STOP_TT: 1893184610Salfred goto tr_valid; 1894184610Salfred 1895184610Salfred default: 1896184610Salfred goto tr_stalled; 1897184610Salfred } 1898184610Salfred break; 1899184610Salfred 1900184610Salfred case UT_READ_CLASS_OTHER: 1901191402Sthompsa switch (req->bRequest) { 1902184610Salfred case UR_GET_TT_STATE: 1903184610Salfred goto tr_handle_get_tt_state; 1904184610Salfred case UR_GET_STATUS: 1905184610Salfred goto tr_handle_get_port_status; 1906184610Salfred default: 1907184610Salfred goto tr_stalled; 1908184610Salfred } 1909184610Salfred break; 1910184610Salfred 1911184610Salfred case UT_READ_CLASS_DEVICE: 1912191402Sthompsa switch (req->bRequest) { 1913184610Salfred case UR_GET_DESCRIPTOR: 1914184610Salfred goto tr_handle_get_class_descriptor; 1915184610Salfred case UR_GET_STATUS: 1916184610Salfred goto tr_handle_get_class_status; 1917184610Salfred 1918184610Salfred default: 1919184610Salfred goto tr_stalled; 1920184610Salfred } 1921184610Salfred break; 1922184610Salfred default: 1923184610Salfred goto tr_stalled; 1924184610Salfred } 1925184610Salfred goto tr_valid; 1926184610Salfred 1927184610Salfredtr_handle_get_descriptor: 1928184610Salfred switch (value >> 8) { 1929184610Salfred case UDESC_DEVICE: 1930184610Salfred if (value & 0xff) { 1931184610Salfred goto tr_stalled; 1932184610Salfred } 1933191402Sthompsa len = sizeof(at91dci_devd); 1934191402Sthompsa ptr = (const void *)&at91dci_devd; 1935184610Salfred goto tr_valid; 1936184610Salfred case UDESC_CONFIG: 1937184610Salfred if (value & 0xff) { 1938184610Salfred goto tr_stalled; 1939184610Salfred } 1940191402Sthompsa len = sizeof(at91dci_confd); 1941191402Sthompsa ptr = (const void *)&at91dci_confd; 1942184610Salfred goto tr_valid; 1943184610Salfred case UDESC_STRING: 1944184610Salfred switch (value & 0xff) { 1945184610Salfred case 0: /* Language table */ 1946191402Sthompsa len = sizeof(at91dci_langtab); 1947191402Sthompsa ptr = (const void *)&at91dci_langtab; 1948184610Salfred goto tr_valid; 1949184610Salfred 1950184610Salfred case 1: /* Vendor */ 1951191402Sthompsa len = sizeof(at91dci_vendor); 1952191402Sthompsa ptr = (const void *)&at91dci_vendor; 1953184610Salfred goto tr_valid; 1954184610Salfred 1955184610Salfred case 2: /* Product */ 1956191402Sthompsa len = sizeof(at91dci_product); 1957191402Sthompsa ptr = (const void *)&at91dci_product; 1958184610Salfred goto tr_valid; 1959184610Salfred default: 1960184610Salfred break; 1961184610Salfred } 1962184610Salfred break; 1963184610Salfred default: 1964184610Salfred goto tr_stalled; 1965184610Salfred } 1966184610Salfred goto tr_stalled; 1967184610Salfred 1968184610Salfredtr_handle_get_config: 1969191402Sthompsa len = 1; 1970184610Salfred sc->sc_hub_temp.wValue[0] = sc->sc_conf; 1971184610Salfred goto tr_valid; 1972184610Salfred 1973184610Salfredtr_handle_get_status: 1974191402Sthompsa len = 2; 1975184610Salfred USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); 1976184610Salfred goto tr_valid; 1977184610Salfred 1978184610Salfredtr_handle_set_address: 1979184610Salfred if (value & 0xFF00) { 1980184610Salfred goto tr_stalled; 1981184610Salfred } 1982184610Salfred sc->sc_rt_addr = value; 1983184610Salfred goto tr_valid; 1984184610Salfred 1985184610Salfredtr_handle_set_config: 1986184610Salfred if (value >= 2) { 1987184610Salfred goto tr_stalled; 1988184610Salfred } 1989184610Salfred sc->sc_conf = value; 1990184610Salfred goto tr_valid; 1991184610Salfred 1992184610Salfredtr_handle_get_interface: 1993191402Sthompsa len = 1; 1994184610Salfred sc->sc_hub_temp.wValue[0] = 0; 1995184610Salfred goto tr_valid; 1996184610Salfred 1997184610Salfredtr_handle_get_tt_state: 1998184610Salfredtr_handle_get_class_status: 1999184610Salfredtr_handle_get_iface_status: 2000184610Salfredtr_handle_get_ep_status: 2001191402Sthompsa len = 2; 2002184610Salfred USETW(sc->sc_hub_temp.wValue, 0); 2003184610Salfred goto tr_valid; 2004184610Salfred 2005184610Salfredtr_handle_set_halt: 2006184610Salfredtr_handle_set_interface: 2007184610Salfredtr_handle_set_wakeup: 2008184610Salfredtr_handle_clear_wakeup: 2009184610Salfredtr_handle_clear_halt: 2010184610Salfred goto tr_valid; 2011184610Salfred 2012184610Salfredtr_handle_clear_port_feature: 2013184610Salfred if (index != 1) { 2014184610Salfred goto tr_stalled; 2015184610Salfred } 2016184610Salfred DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index); 2017184610Salfred 2018184610Salfred switch (value) { 2019184610Salfred case UHF_PORT_SUSPEND: 2020190735Sthompsa at91dci_wakeup_peer(sc); 2021184610Salfred break; 2022184610Salfred 2023184610Salfred case UHF_PORT_ENABLE: 2024184610Salfred sc->sc_flags.port_enabled = 0; 2025184610Salfred break; 2026184610Salfred 2027184610Salfred case UHF_PORT_TEST: 2028184610Salfred case UHF_PORT_INDICATOR: 2029184610Salfred case UHF_C_PORT_ENABLE: 2030184610Salfred case UHF_C_PORT_OVER_CURRENT: 2031184610Salfred case UHF_C_PORT_RESET: 2032184610Salfred /* nops */ 2033184610Salfred break; 2034184610Salfred case UHF_PORT_POWER: 2035184610Salfred sc->sc_flags.port_powered = 0; 2036184610Salfred at91dci_pull_down(sc); 2037184610Salfred at91dci_clocks_off(sc); 2038184610Salfred break; 2039184610Salfred case UHF_C_PORT_CONNECTION: 2040184610Salfred sc->sc_flags.change_connect = 0; 2041184610Salfred break; 2042184610Salfred case UHF_C_PORT_SUSPEND: 2043184610Salfred sc->sc_flags.change_suspend = 0; 2044184610Salfred break; 2045184610Salfred default: 2046191402Sthompsa err = USB_ERR_IOERROR; 2047184610Salfred goto done; 2048184610Salfred } 2049184610Salfred goto tr_valid; 2050184610Salfred 2051184610Salfredtr_handle_set_port_feature: 2052184610Salfred if (index != 1) { 2053184610Salfred goto tr_stalled; 2054184610Salfred } 2055184610Salfred DPRINTFN(9, "UR_SET_PORT_FEATURE\n"); 2056184610Salfred 2057184610Salfred switch (value) { 2058184610Salfred case UHF_PORT_ENABLE: 2059184610Salfred sc->sc_flags.port_enabled = 1; 2060184610Salfred break; 2061184610Salfred case UHF_PORT_SUSPEND: 2062184610Salfred case UHF_PORT_RESET: 2063184610Salfred case UHF_PORT_TEST: 2064184610Salfred case UHF_PORT_INDICATOR: 2065184610Salfred /* nops */ 2066184610Salfred break; 2067184610Salfred case UHF_PORT_POWER: 2068184610Salfred sc->sc_flags.port_powered = 1; 2069184610Salfred break; 2070184610Salfred default: 2071191402Sthompsa err = USB_ERR_IOERROR; 2072184610Salfred goto done; 2073184610Salfred } 2074184610Salfred goto tr_valid; 2075184610Salfred 2076184610Salfredtr_handle_get_port_status: 2077184610Salfred 2078184610Salfred DPRINTFN(9, "UR_GET_PORT_STATUS\n"); 2079184610Salfred 2080184610Salfred if (index != 1) { 2081184610Salfred goto tr_stalled; 2082184610Salfred } 2083184610Salfred if (sc->sc_flags.status_vbus) { 2084184610Salfred at91dci_clocks_on(sc); 2085184610Salfred at91dci_pull_up(sc); 2086184610Salfred } else { 2087184610Salfred at91dci_pull_down(sc); 2088184610Salfred at91dci_clocks_off(sc); 2089184610Salfred } 2090184610Salfred 2091184610Salfred /* Select FULL-speed and Device Side Mode */ 2092184610Salfred 2093184610Salfred value = UPS_PORT_MODE_DEVICE; 2094184610Salfred 2095184610Salfred if (sc->sc_flags.port_powered) { 2096184610Salfred value |= UPS_PORT_POWER; 2097184610Salfred } 2098184610Salfred if (sc->sc_flags.port_enabled) { 2099184610Salfred value |= UPS_PORT_ENABLED; 2100184610Salfred } 2101184610Salfred if (sc->sc_flags.status_vbus && 2102184610Salfred sc->sc_flags.status_bus_reset) { 2103184610Salfred value |= UPS_CURRENT_CONNECT_STATUS; 2104184610Salfred } 2105184610Salfred if (sc->sc_flags.status_suspend) { 2106184610Salfred value |= UPS_SUSPEND; 2107184610Salfred } 2108184610Salfred USETW(sc->sc_hub_temp.ps.wPortStatus, value); 2109184610Salfred 2110184610Salfred value = 0; 2111184610Salfred 2112184610Salfred if (sc->sc_flags.change_connect) { 2113184610Salfred value |= UPS_C_CONNECT_STATUS; 2114184610Salfred 2115184610Salfred if (sc->sc_flags.status_vbus && 2116184610Salfred sc->sc_flags.status_bus_reset) { 2117184610Salfred /* reset endpoint flags */ 2118184610Salfred bzero(sc->sc_ep_flags, sizeof(sc->sc_ep_flags)); 2119184610Salfred } 2120184610Salfred } 2121184610Salfred if (sc->sc_flags.change_suspend) { 2122184610Salfred value |= UPS_C_SUSPEND; 2123184610Salfred } 2124184610Salfred USETW(sc->sc_hub_temp.ps.wPortChange, value); 2125191402Sthompsa len = sizeof(sc->sc_hub_temp.ps); 2126184610Salfred goto tr_valid; 2127184610Salfred 2128184610Salfredtr_handle_get_class_descriptor: 2129184610Salfred if (value & 0xFF) { 2130184610Salfred goto tr_stalled; 2131184610Salfred } 2132191402Sthompsa ptr = (const void *)&at91dci_hubd; 2133191402Sthompsa len = sizeof(at91dci_hubd); 2134184610Salfred goto tr_valid; 2135184610Salfred 2136184610Salfredtr_stalled: 2137191402Sthompsa err = USB_ERR_STALLED; 2138184610Salfredtr_valid: 2139184610Salfreddone: 2140191402Sthompsa *plength = len; 2141191402Sthompsa *pptr = ptr; 2142191402Sthompsa return (err); 2143184610Salfred} 2144184610Salfred 2145184610Salfredstatic void 2146192984Sthompsaat91dci_xfer_setup(struct usb_setup_params *parm) 2147184610Salfred{ 2148192984Sthompsa const struct usb_hw_ep_profile *pf; 2149184610Salfred struct at91dci_softc *sc; 2150192984Sthompsa struct usb_xfer *xfer; 2151184610Salfred void *last_obj; 2152184610Salfred uint32_t ntd; 2153184610Salfred uint32_t n; 2154184610Salfred uint8_t ep_no; 2155184610Salfred 2156184610Salfred sc = AT9100_DCI_BUS2SC(parm->udev->bus); 2157184610Salfred xfer = parm->curr_xfer; 2158184610Salfred 2159184610Salfred /* 2160184610Salfred * NOTE: This driver does not use any of the parameters that 2161184610Salfred * are computed from the following values. Just set some 2162184610Salfred * reasonable dummies: 2163184610Salfred */ 2164184610Salfred parm->hc_max_packet_size = 0x500; 2165184610Salfred parm->hc_max_packet_count = 1; 2166184610Salfred parm->hc_max_frame_size = 0x500; 2167184610Salfred 2168184610Salfred usb2_transfer_setup_sub(parm); 2169184610Salfred 2170184610Salfred /* 2171184610Salfred * compute maximum number of TDs 2172184610Salfred */ 2173184610Salfred if (parm->methods == &at91dci_device_ctrl_methods) { 2174184610Salfred 2175184610Salfred ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */ 2176184610Salfred + 1 /* SYNC 2 */ ; 2177184610Salfred 2178184610Salfred } else if (parm->methods == &at91dci_device_bulk_methods) { 2179184610Salfred 2180184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2181184610Salfred 2182184610Salfred } else if (parm->methods == &at91dci_device_intr_methods) { 2183184610Salfred 2184184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2185184610Salfred 2186184610Salfred } else if (parm->methods == &at91dci_device_isoc_fs_methods) { 2187184610Salfred 2188184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 2189184610Salfred 2190184610Salfred } else { 2191184610Salfred 2192184610Salfred ntd = 0; 2193184610Salfred } 2194184610Salfred 2195184610Salfred /* 2196184610Salfred * check if "usb2_transfer_setup_sub" set an error 2197184610Salfred */ 2198184610Salfred if (parm->err) { 2199184610Salfred return; 2200184610Salfred } 2201184610Salfred /* 2202184610Salfred * allocate transfer descriptors 2203184610Salfred */ 2204184610Salfred last_obj = NULL; 2205184610Salfred 2206184610Salfred /* 2207184610Salfred * get profile stuff 2208184610Salfred */ 2209184610Salfred if (ntd) { 2210184610Salfred 2211193644Sthompsa ep_no = xfer->endpointno & UE_ADDR; 2212184610Salfred at91dci_get_hw_ep_profile(parm->udev, &pf, ep_no); 2213184610Salfred 2214184610Salfred if (pf == NULL) { 2215184610Salfred /* should not happen */ 2216184610Salfred parm->err = USB_ERR_INVAL; 2217184610Salfred return; 2218184610Salfred } 2219184610Salfred } else { 2220184610Salfred ep_no = 0; 2221184610Salfred pf = NULL; 2222184610Salfred } 2223184610Salfred 2224184610Salfred /* align data */ 2225184610Salfred parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); 2226184610Salfred 2227184610Salfred for (n = 0; n != ntd; n++) { 2228184610Salfred 2229184610Salfred struct at91dci_td *td; 2230184610Salfred 2231184610Salfred if (parm->buf) { 2232184610Salfred 2233184610Salfred td = USB_ADD_BYTES(parm->buf, parm->size[0]); 2234184610Salfred 2235184610Salfred /* init TD */ 2236184610Salfred td->io_tag = sc->sc_io_tag; 2237184610Salfred td->io_hdl = sc->sc_io_hdl; 2238184610Salfred td->max_packet_size = xfer->max_packet_size; 2239184610Salfred td->status_reg = AT91_UDP_CSR(ep_no); 2240184610Salfred td->fifo_reg = AT91_UDP_FDR(ep_no); 2241184610Salfred if (pf->support_multi_buffer) { 2242184610Salfred td->support_multi_buffer = 1; 2243184610Salfred } 2244184610Salfred td->obj_next = last_obj; 2245184610Salfred 2246184610Salfred last_obj = td; 2247184610Salfred } 2248184610Salfred parm->size[0] += sizeof(*td); 2249184610Salfred } 2250184610Salfred 2251184610Salfred xfer->td_start[0] = last_obj; 2252184610Salfred} 2253184610Salfred 2254184610Salfredstatic void 2255192984Sthompsaat91dci_xfer_unsetup(struct usb_xfer *xfer) 2256184610Salfred{ 2257184610Salfred return; 2258184610Salfred} 2259184610Salfred 2260184610Salfredstatic void 2261193644Sthompsaat91dci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, 2262193644Sthompsa struct usb_endpoint *ep) 2263184610Salfred{ 2264184610Salfred struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus); 2265184610Salfred 2266193644Sthompsa DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n", 2267193644Sthompsa ep, udev->address, 2268192499Sthompsa edesc->bEndpointAddress, udev->flags.usb_mode, 2269184610Salfred sc->sc_rt_addr); 2270184610Salfred 2271190735Sthompsa if (udev->device_index != sc->sc_rt_addr) { 2272184610Salfred 2273192499Sthompsa if (udev->flags.usb_mode != USB_MODE_DEVICE) { 2274184610Salfred /* not supported */ 2275184610Salfred return; 2276184610Salfred } 2277184610Salfred if (udev->speed != USB_SPEED_FULL) { 2278184610Salfred /* not supported */ 2279184610Salfred return; 2280184610Salfred } 2281184610Salfred switch (edesc->bmAttributes & UE_XFERTYPE) { 2282184610Salfred case UE_CONTROL: 2283193644Sthompsa ep->methods = &at91dci_device_ctrl_methods; 2284184610Salfred break; 2285184610Salfred case UE_INTERRUPT: 2286193644Sthompsa ep->methods = &at91dci_device_intr_methods; 2287184610Salfred break; 2288184610Salfred case UE_ISOCHRONOUS: 2289193644Sthompsa ep->methods = &at91dci_device_isoc_fs_methods; 2290184610Salfred break; 2291184610Salfred case UE_BULK: 2292193644Sthompsa ep->methods = &at91dci_device_bulk_methods; 2293184610Salfred break; 2294184610Salfred default: 2295184610Salfred /* do nothing */ 2296184610Salfred break; 2297184610Salfred } 2298184610Salfred } 2299184610Salfred} 2300184610Salfred 2301192984Sthompsastruct usb_bus_methods at91dci_bus_methods = 2302184610Salfred{ 2303193644Sthompsa .endpoint_init = &at91dci_ep_init, 2304184610Salfred .xfer_setup = &at91dci_xfer_setup, 2305184610Salfred .xfer_unsetup = &at91dci_xfer_unsetup, 2306184610Salfred .get_hw_ep_profile = &at91dci_get_hw_ep_profile, 2307184610Salfred .set_stall = &at91dci_set_stall, 2308184610Salfred .clear_stall = &at91dci_clear_stall, 2309190735Sthompsa .roothub_exec = &at91dci_roothub_exec, 2310184610Salfred}; 2311