diff options
Diffstat (limited to 'sys/dev/usb2/controller')
29 files changed, 0 insertions, 27228 deletions
diff --git a/sys/dev/usb2/controller/at91dci.c b/sys/dev/usb2/controller/at91dci.c deleted file mode 100644 index 501d0c0..0000000 --- a/sys/dev/usb2/controller/at91dci.c +++ /dev/null @@ -1,2467 +0,0 @@ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/*- - * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * This file contains the driver for the AT91 series USB Device - * Controller - */ - -/* - * Thanks to "David Brownell" for helping out regarding the hardware - * endpoint profiles. - */ - -/* - * NOTE: The "fifo_bank" is not reset in hardware when the endpoint is - * reset ! - * - * NOTE: When the chip detects BUS-reset it will also reset the - * endpoints, Function-address and more. - */ - -#include <dev/usb2/include/usb2_standard.h> -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_error.h> -#include <dev/usb2/include/usb2_defs.h> - -#define USB_DEBUG_VAR at91dcidebug - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_debug.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_transfer.h> -#include <dev/usb2/core/usb2_device.h> -#include <dev/usb2/core/usb2_hub.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/at91dci.h> - -#define AT9100_DCI_BUS2SC(bus) \ - ((struct at91dci_softc *)(((uint8_t *)(bus)) - \ - USB_P2U(&(((struct at91dci_softc *)0)->sc_bus)))) - -#define AT9100_DCI_PC2SC(pc) \ - AT9100_DCI_BUS2SC((pc)->tag_parent->info->bus) - -#if USB_DEBUG -static int at91dcidebug = 0; - -SYSCTL_NODE(_hw_usb2, OID_AUTO, at91dci, CTLFLAG_RW, 0, "USB at91dci"); -SYSCTL_INT(_hw_usb2_at91dci, OID_AUTO, debug, CTLFLAG_RW, - &at91dcidebug, 0, "at91dci debug level"); -#endif - -#define AT9100_DCI_INTR_ENDPT 1 - -/* prototypes */ - -struct usb2_bus_methods at91dci_bus_methods; -struct usb2_pipe_methods at91dci_device_bulk_methods; -struct usb2_pipe_methods at91dci_device_ctrl_methods; -struct usb2_pipe_methods at91dci_device_intr_methods; -struct usb2_pipe_methods at91dci_device_isoc_fs_methods; -struct usb2_pipe_methods at91dci_root_ctrl_methods; -struct usb2_pipe_methods at91dci_root_intr_methods; - -static at91dci_cmd_t at91dci_setup_rx; -static at91dci_cmd_t at91dci_data_rx; -static at91dci_cmd_t at91dci_data_tx; -static at91dci_cmd_t at91dci_data_tx_sync; -static void at91dci_device_done(struct usb2_xfer *, usb2_error_t); -static void at91dci_do_poll(struct usb2_bus *); -static void at91dci_root_ctrl_poll(struct at91dci_softc *); -static void at91dci_standard_done(struct usb2_xfer *); - -static usb2_sw_transfer_func_t at91dci_root_intr_done; -static usb2_sw_transfer_func_t at91dci_root_ctrl_done; - -/* - * NOTE: Some of the bits in the CSR register have inverse meaning so - * we need a helper macro when acknowledging events: - */ -#define AT91_CSR_ACK(csr, what) do { \ - (csr) &= ~((AT91_UDP_CSR_FORCESTALL| \ - AT91_UDP_CSR_TXPKTRDY| \ - AT91_UDP_CSR_RXBYTECNT) ^ (what));\ - (csr) |= ((AT91_UDP_CSR_RX_DATA_BK0| \ - AT91_UDP_CSR_RX_DATA_BK1| \ - AT91_UDP_CSR_TXCOMP| \ - AT91_UDP_CSR_RXSETUP| \ - AT91_UDP_CSR_STALLSENT) ^ (what)); \ -} while (0) - -/* - * Here is a list of what the chip supports. - * Probably it supports more than listed here! - */ -static const struct usb2_hw_ep_profile - at91dci_ep_profile[AT91_UDP_EP_MAX] = { - - [0] = { - .max_in_frame_size = 8, - .max_out_frame_size = 8, - .is_simplex = 1, - .support_control = 1, - }, - [1] = { - .max_in_frame_size = 64, - .max_out_frame_size = 64, - .is_simplex = 1, - .support_multi_buffer = 1, - .support_bulk = 1, - .support_interrupt = 1, - .support_isochronous = 1, - .support_in = 1, - .support_out = 1, - }, - [2] = { - .max_in_frame_size = 64, - .max_out_frame_size = 64, - .is_simplex = 1, - .support_multi_buffer = 1, - .support_bulk = 1, - .support_interrupt = 1, - .support_isochronous = 1, - .support_in = 1, - .support_out = 1, - }, - [3] = { - /* can also do BULK */ - .max_in_frame_size = 8, - .max_out_frame_size = 8, - .is_simplex = 1, - .support_interrupt = 1, - .support_in = 1, - .support_out = 1, - }, - [4] = { - .max_in_frame_size = 256, - .max_out_frame_size = 256, - .is_simplex = 1, - .support_multi_buffer = 1, - .support_bulk = 1, - .support_interrupt = 1, - .support_isochronous = 1, - .support_in = 1, - .support_out = 1, - }, - [5] = { - .max_in_frame_size = 256, - .max_out_frame_size = 256, - .is_simplex = 1, - .support_multi_buffer = 1, - .support_bulk = 1, - .support_interrupt = 1, - .support_isochronous = 1, - .support_in = 1, - .support_out = 1, - }, -}; - -static void -at91dci_get_hw_ep_profile(struct usb2_device *udev, - const struct usb2_hw_ep_profile **ppf, uint8_t ep_addr) -{ - if (ep_addr < AT91_UDP_EP_MAX) { - *ppf = (at91dci_ep_profile + ep_addr); - } else { - *ppf = NULL; - } -} - -static void -at91dci_clocks_on(struct at91dci_softc *sc) -{ - if (sc->sc_flags.clocks_off && - sc->sc_flags.port_powered) { - - DPRINTFN(5, "\n"); - - if (sc->sc_clocks_on) { - (sc->sc_clocks_on) (sc->sc_clocks_arg); - } - sc->sc_flags.clocks_off = 0; - - /* enable Transceiver */ - AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, 0); - } -} - -static void -at91dci_clocks_off(struct at91dci_softc *sc) -{ - if (!sc->sc_flags.clocks_off) { - - DPRINTFN(5, "\n"); - - /* disable Transceiver */ - AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); - - if (sc->sc_clocks_off) { - (sc->sc_clocks_off) (sc->sc_clocks_arg); - } - sc->sc_flags.clocks_off = 1; - } -} - -static void -at91dci_pull_up(struct at91dci_softc *sc) -{ - /* pullup D+, if possible */ - - if (!sc->sc_flags.d_pulled_up && - sc->sc_flags.port_powered) { - sc->sc_flags.d_pulled_up = 1; - (sc->sc_pull_up) (sc->sc_pull_arg); - } -} - -static void -at91dci_pull_down(struct at91dci_softc *sc) -{ - /* pulldown D+, if possible */ - - if (sc->sc_flags.d_pulled_up) { - sc->sc_flags.d_pulled_up = 0; - (sc->sc_pull_down) (sc->sc_pull_arg); - } -} - -static void -at91dci_wakeup_peer(struct usb2_xfer *xfer) -{ - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - uint8_t use_polling; - - if (!(sc->sc_flags.status_suspend)) { - return; - } - use_polling = mtx_owned(xfer->xroot->xfer_mtx) ? 1 : 0; - - AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, AT91_UDP_GSTATE_ESR); - - /* wait 8 milliseconds */ - if (use_polling) { - /* polling */ - DELAY(8000); - } else { - /* Wait for reset to complete. */ - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); - } - - AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, 0); -} - -static void -at91dci_set_address(struct at91dci_softc *sc, uint8_t addr) -{ - DPRINTFN(5, "addr=%d\n", addr); - - AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, addr | - AT91_UDP_FADDR_EN); -} - -static uint8_t -at91dci_setup_rx(struct at91dci_td *td) -{ - struct at91dci_softc *sc; - struct usb2_device_request req; - uint32_t csr; - uint32_t temp; - uint16_t count; - - /* read out FIFO status */ - csr = bus_space_read_4(td->io_tag, td->io_hdl, - td->status_reg); - - DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); - - temp = csr; - temp &= (AT91_UDP_CSR_RX_DATA_BK0 | - AT91_UDP_CSR_RX_DATA_BK1 | - AT91_UDP_CSR_STALLSENT | - AT91_UDP_CSR_RXSETUP | - AT91_UDP_CSR_TXCOMP); - - if (!(csr & AT91_UDP_CSR_RXSETUP)) { - /* abort any ongoing transfer */ - if (!td->did_stall) { - DPRINTFN(5, "stalling\n"); - temp |= AT91_UDP_CSR_FORCESTALL; - td->did_stall = 1; - } - goto not_complete; - } - /* get the packet byte count */ - count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; - - /* verify data length */ - if (count != td->remainder) { - DPRINTFN(0, "Invalid SETUP packet " - "length, %d bytes\n", count); - goto not_complete; - } - if (count != sizeof(req)) { - DPRINTFN(0, "Unsupported SETUP packet " - "length, %d bytes\n", count); - goto not_complete; - } - /* receive data */ - bus_space_read_multi_1(td->io_tag, td->io_hdl, - td->fifo_reg, (void *)&req, sizeof(req)); - - /* copy data into real buffer */ - usb2_copy_in(td->pc, 0, &req, sizeof(req)); - - td->offset = sizeof(req); - td->remainder = 0; - - /* get pointer to softc */ - sc = AT9100_DCI_PC2SC(td->pc); - - /* sneak peek the set address */ - if ((req.bmRequestType == UT_WRITE_DEVICE) && - (req.bRequest == UR_SET_ADDRESS)) { - sc->sc_dv_addr = req.wValue[0] & 0x7F; - } else { - sc->sc_dv_addr = 0xFF; - } - - /* sneak peek the endpoint direction */ - if (req.bmRequestType & UE_DIR_IN) { - csr |= AT91_UDP_CSR_DIR; - } else { - csr &= ~AT91_UDP_CSR_DIR; - } - - /* write the direction of the control transfer */ - AT91_CSR_ACK(csr, temp); - bus_space_write_4(td->io_tag, td->io_hdl, - td->status_reg, csr); - return (0); /* complete */ - -not_complete: - /* clear interrupts, if any */ - if (temp) { - DPRINTFN(5, "clearing 0x%08x\n", temp); - AT91_CSR_ACK(csr, temp); - bus_space_write_4(td->io_tag, td->io_hdl, - td->status_reg, csr); - } - return (1); /* not complete */ - -} - -static uint8_t -at91dci_data_rx(struct at91dci_td *td) -{ - struct usb2_page_search buf_res; - uint32_t csr; - uint32_t temp; - uint16_t count; - uint8_t to; - uint8_t got_short; - - to = 2; /* don't loop forever! */ - got_short = 0; - - /* check if any of the FIFO banks have data */ -repeat: - /* read out FIFO status */ - csr = bus_space_read_4(td->io_tag, td->io_hdl, - td->status_reg); - - DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); - - if (csr & AT91_UDP_CSR_RXSETUP) { - if (td->remainder == 0) { - /* - * We are actually complete and have - * received the next SETUP - */ - DPRINTFN(5, "faking complete\n"); - return (0); /* complete */ - } - /* - * USB Host Aborted the transfer. - */ - td->error = 1; - return (0); /* complete */ - } - /* Make sure that "STALLSENT" gets cleared */ - temp = csr; - temp &= AT91_UDP_CSR_STALLSENT; - - /* check status */ - if (!(csr & (AT91_UDP_CSR_RX_DATA_BK0 | - AT91_UDP_CSR_RX_DATA_BK1))) { - if (temp) { - /* write command */ - AT91_CSR_ACK(csr, temp); - bus_space_write_4(td->io_tag, td->io_hdl, - td->status_reg, csr); - } - return (1); /* not complete */ - } - /* get the packet byte count */ - count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16; - - /* verify the packet byte count */ - if (count != td->max_packet_size) { - if (count < td->max_packet_size) { - /* we have a short packet */ - td->short_pkt = 1; - got_short = 1; - } else { - /* invalid USB packet */ - td->error = 1; - return (0); /* we are complete */ - } - } - /* verify the packet byte count */ - if (count > td->remainder) { - /* invalid USB packet */ - td->error = 1; - return (0); /* we are complete */ - } - while (count > 0) { - usb2_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* receive data */ - bus_space_read_multi_1(td->io_tag, td->io_hdl, - td->fifo_reg, buf_res.buffer, buf_res.length); - - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } - - /* clear status bits */ - if (td->support_multi_buffer) { - if (td->fifo_bank) { - td->fifo_bank = 0; - temp |= AT91_UDP_CSR_RX_DATA_BK1; - } else { - td->fifo_bank = 1; - temp |= AT91_UDP_CSR_RX_DATA_BK0; - } - } else { - temp |= (AT91_UDP_CSR_RX_DATA_BK0 | - AT91_UDP_CSR_RX_DATA_BK1); - } - - /* write command */ - AT91_CSR_ACK(csr, temp); - bus_space_write_4(td->io_tag, td->io_hdl, - td->status_reg, csr); - - /* - * NOTE: We may have to delay a little bit before - * proceeding after clearing the DATA_BK bits. - */ - - /* check if we are complete */ - if ((td->remainder == 0) || got_short) { - if (td->short_pkt) { - /* we are complete */ - return (0); - } - /* else need to receive a zero length packet */ - } - if (--to) { - goto repeat; - } - return (1); /* not complete */ -} - -static uint8_t -at91dci_data_tx(struct at91dci_td *td) -{ - struct usb2_page_search buf_res; - uint32_t csr; - uint32_t temp; - uint16_t count; - uint8_t to; - - to = 2; /* don't loop forever! */ - -repeat: - - /* read out FIFO status */ - csr = bus_space_read_4(td->io_tag, td->io_hdl, - td->status_reg); - - DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder); - - if (csr & AT91_UDP_CSR_RXSETUP) { - /* - * The current transfer was aborted - * by the USB Host - */ - td->error = 1; - return (0); /* complete */ - } - /* Make sure that "STALLSENT" gets cleared */ - temp = csr; - temp &= AT91_UDP_CSR_STALLSENT; - - if (csr & AT91_UDP_CSR_TXPKTRDY) { - if (temp) { - /* write command */ - AT91_CSR_ACK(csr, temp); - bus_space_write_4(td->io_tag, td->io_hdl, - td->status_reg, csr); - } - return (1); /* not complete */ - } else { - /* clear TXCOMP and set TXPKTRDY */ - temp |= (AT91_UDP_CSR_TXCOMP | - AT91_UDP_CSR_TXPKTRDY); - } - - count = td->max_packet_size; - if (td->remainder < count) { - /* we have a short packet */ - td->short_pkt = 1; - count = td->remainder; - } - while (count > 0) { - - usb2_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* transmit data */ - bus_space_write_multi_1(td->io_tag, td->io_hdl, - td->fifo_reg, buf_res.buffer, buf_res.length); - - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } - - /* write command */ - AT91_CSR_ACK(csr, temp); - bus_space_write_4(td->io_tag, td->io_hdl, - td->status_reg, csr); - - /* check remainder */ - if (td->remainder == 0) { - if (td->short_pkt) { - return (0); /* complete */ - } - /* else we need to transmit a short packet */ - } - if (--to) { - goto repeat; - } - return (1); /* not complete */ -} - -static uint8_t -at91dci_data_tx_sync(struct at91dci_td *td) -{ - struct at91dci_softc *sc; - uint32_t csr; - uint32_t temp; - -#if 0 -repeat: -#endif - - /* read out FIFO status */ - csr = bus_space_read_4(td->io_tag, td->io_hdl, - td->status_reg); - - DPRINTFN(5, "csr=0x%08x\n", csr); - - if (csr & AT91_UDP_CSR_RXSETUP) { - DPRINTFN(5, "faking complete\n"); - /* Race condition */ - return (0); /* complete */ - } - temp = csr; - temp &= (AT91_UDP_CSR_STALLSENT | - AT91_UDP_CSR_TXCOMP); - - /* check status */ - if (csr & AT91_UDP_CSR_TXPKTRDY) { - goto not_complete; - } - if (!(csr & AT91_UDP_CSR_TXCOMP)) { - goto not_complete; - } - sc = AT9100_DCI_PC2SC(td->pc); - if (sc->sc_dv_addr != 0xFF) { - /* - * The AT91 has a special requirement with regard to - * setting the address and that is to write the new - * address before clearing TXCOMP: - */ - at91dci_set_address(sc, sc->sc_dv_addr); - } - /* write command */ - AT91_CSR_ACK(csr, temp); - bus_space_write_4(td->io_tag, td->io_hdl, - td->status_reg, csr); - - return (0); /* complete */ - -not_complete: - if (temp) { - /* write command */ - AT91_CSR_ACK(csr, temp); - bus_space_write_4(td->io_tag, td->io_hdl, - td->status_reg, csr); - } - return (1); /* not complete */ -} - -static uint8_t -at91dci_xfer_do_fifo(struct usb2_xfer *xfer) -{ - struct at91dci_softc *sc; - struct at91dci_td *td; - uint8_t temp; - - DPRINTFN(9, "\n"); - - td = xfer->td_transfer_cache; - while (1) { - if ((td->func) (td)) { - /* operation in progress */ - break; - } - if (((void *)td) == xfer->td_transfer_last) { - goto done; - } - if (td->error) { - goto done; - } else if (td->remainder > 0) { - /* - * We had a short transfer. If there is no alternate - * next, stop processing ! - */ - if (!td->alt_next) { - goto done; - } - } - /* - * Fetch the next transfer descriptor and transfer - * some flags to the next transfer descriptor - */ - temp = 0; - if (td->fifo_bank) - temp |= 1; - td = td->obj_next; - xfer->td_transfer_cache = td; - if (temp & 1) - td->fifo_bank = 1; - } - return (1); /* not complete */ - -done: - sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - temp = (xfer->endpoint & UE_ADDR); - - /* update FIFO bank flag and multi buffer */ - if (td->fifo_bank) { - sc->sc_ep_flags[temp].fifo_bank = 1; - } else { - sc->sc_ep_flags[temp].fifo_bank = 0; - } - - /* compute all actual lengths */ - - at91dci_standard_done(xfer); - - return (0); /* complete */ -} - -static void -at91dci_interrupt_poll(struct at91dci_softc *sc) -{ - struct usb2_xfer *xfer; - -repeat: - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - if (!at91dci_xfer_do_fifo(xfer)) { - /* queue has been modified */ - goto repeat; - } - } -} - -void -at91dci_vbus_interrupt(struct at91dci_softc *sc, uint8_t is_on) -{ - DPRINTFN(5, "vbus = %u\n", is_on); - - USB_BUS_LOCK(&sc->sc_bus); - if (is_on) { - if (!sc->sc_flags.status_vbus) { - sc->sc_flags.status_vbus = 1; - - /* complete root HUB interrupt endpoint */ - - usb2_sw_transfer(&sc->sc_root_intr, - &at91dci_root_intr_done); - } - } else { - if (sc->sc_flags.status_vbus) { - sc->sc_flags.status_vbus = 0; - sc->sc_flags.status_bus_reset = 0; - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 0; - sc->sc_flags.change_connect = 1; - - /* complete root HUB interrupt endpoint */ - - usb2_sw_transfer(&sc->sc_root_intr, - &at91dci_root_intr_done); - } - } - USB_BUS_UNLOCK(&sc->sc_bus); -} - -void -at91dci_interrupt(struct at91dci_softc *sc) -{ - uint32_t status; - - USB_BUS_LOCK(&sc->sc_bus); - - status = AT91_UDP_READ_4(sc, AT91_UDP_ISR); - status &= AT91_UDP_INT_DEFAULT; - - if (!status) { - USB_BUS_UNLOCK(&sc->sc_bus); - return; - } - /* acknowledge interrupts */ - - AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status); - - /* check for any bus state change interrupts */ - - if (status & AT91_UDP_INT_BUS) { - - DPRINTFN(5, "real bus interrupt 0x%08x\n", status); - - if (status & AT91_UDP_INT_END_BR) { - - /* set correct state */ - sc->sc_flags.status_bus_reset = 1; - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 0; - sc->sc_flags.change_connect = 1; - - /* disable resume interrupt */ - AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, - AT91_UDP_INT_RXRSM); - /* enable suspend interrupt */ - AT91_UDP_WRITE_4(sc, AT91_UDP_IER, - AT91_UDP_INT_RXSUSP); - } - /* - * If RXRSM and RXSUSP is set at the same time we interpret - * that like RESUME. Resume is set when there is at least 3 - * milliseconds of inactivity on the USB BUS. - */ - if (status & AT91_UDP_INT_RXRSM) { - if (sc->sc_flags.status_suspend) { - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 1; - - /* disable resume interrupt */ - AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, - AT91_UDP_INT_RXRSM); - /* enable suspend interrupt */ - AT91_UDP_WRITE_4(sc, AT91_UDP_IER, - AT91_UDP_INT_RXSUSP); - } - } else if (status & AT91_UDP_INT_RXSUSP) { - if (!sc->sc_flags.status_suspend) { - sc->sc_flags.status_suspend = 1; - sc->sc_flags.change_suspend = 1; - - /* disable suspend interrupt */ - AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, - AT91_UDP_INT_RXSUSP); - - /* enable resume interrupt */ - AT91_UDP_WRITE_4(sc, AT91_UDP_IER, - AT91_UDP_INT_RXRSM); - } - } - /* complete root HUB interrupt endpoint */ - - usb2_sw_transfer(&sc->sc_root_intr, - &at91dci_root_intr_done); - } - /* check for any endpoint interrupts */ - - if (status & AT91_UDP_INT_EPS) { - - DPRINTFN(5, "real endpoint interrupt 0x%08x\n", status); - - at91dci_interrupt_poll(sc); - } - USB_BUS_UNLOCK(&sc->sc_bus); -} - -static void -at91dci_setup_standard_chain_sub(struct at91dci_std_temp *temp) -{ - struct at91dci_td *td; - - /* get current Transfer Descriptor */ - td = temp->td_next; - temp->td = td; - - /* prepare for next TD */ - temp->td_next = td->obj_next; - - /* fill out the Transfer Descriptor */ - td->func = temp->func; - td->pc = temp->pc; - td->offset = temp->offset; - td->remainder = temp->len; - td->fifo_bank = 0; - td->error = 0; - td->did_stall = 0; - td->short_pkt = temp->short_pkt; - td->alt_next = temp->setup_alt_next; -} - -static void -at91dci_setup_standard_chain(struct usb2_xfer *xfer) -{ - struct at91dci_std_temp temp; - struct at91dci_softc *sc; - struct at91dci_td *td; - uint32_t x; - uint8_t ep_no; - uint8_t need_sync; - - DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", - xfer->address, UE_GET_ADDR(xfer->endpoint), - xfer->sumlen, usb2_get_speed(xfer->xroot->udev)); - - temp.max_frame_size = xfer->max_frame_size; - - td = xfer->td_start[0]; - xfer->td_transfer_first = td; - xfer->td_transfer_cache = td; - - /* setup temp */ - - temp.td = NULL; - temp.td_next = xfer->td_start[0]; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; - temp.offset = 0; - - sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - ep_no = (xfer->endpoint & UE_ADDR); - - /* check if we should prepend a setup message */ - - if (xfer->flags_int.control_xfr) { - if (xfer->flags_int.control_hdr) { - - temp.func = &at91dci_setup_rx; - temp.len = xfer->frlengths[0]; - temp.pc = xfer->frbuffers + 0; - temp.short_pkt = temp.len ? 1 : 0; - - at91dci_setup_standard_chain_sub(&temp); - } - x = 1; - } else { - x = 0; - } - - if (x != xfer->nframes) { - if (xfer->endpoint & UE_DIR_IN) { - temp.func = &at91dci_data_tx; - need_sync = 1; - } else { - temp.func = &at91dci_data_rx; - need_sync = 0; - } - - /* setup "pc" pointer */ - temp.pc = xfer->frbuffers + x; - } else { - need_sync = 0; - } - while (x != xfer->nframes) { - - /* DATA0 / DATA1 message */ - - temp.len = xfer->frlengths[x]; - - x++; - - if (x == xfer->nframes) { - temp.setup_alt_next = 0; - } - if (temp.len == 0) { - - /* make sure that we send an USB packet */ - - temp.short_pkt = 0; - - } else { - - /* regular data transfer */ - - temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; - } - - at91dci_setup_standard_chain_sub(&temp); - - if (xfer->flags_int.isochronous_xfr) { - temp.offset += temp.len; - } else { - /* get next Page Cache pointer */ - temp.pc = xfer->frbuffers + x; - } - } - - /* always setup a valid "pc" pointer for status and sync */ - temp.pc = xfer->frbuffers + 0; - - /* check if we need to sync */ - if (need_sync && xfer->flags_int.control_xfr) { - - /* we need a SYNC point after TX */ - temp.func = &at91dci_data_tx_sync; - temp.len = 0; - temp.short_pkt = 0; - - at91dci_setup_standard_chain_sub(&temp); - } - /* check if we should append a status stage */ - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - /* - * Send a DATA1 message and invert the current - * endpoint direction. - */ - if (xfer->endpoint & UE_DIR_IN) { - temp.func = &at91dci_data_rx; - need_sync = 0; - } else { - temp.func = &at91dci_data_tx; - need_sync = 1; - } - temp.len = 0; - temp.short_pkt = 0; - - at91dci_setup_standard_chain_sub(&temp); - if (need_sync) { - /* we need a SYNC point after TX */ - temp.func = &at91dci_data_tx_sync; - temp.len = 0; - temp.short_pkt = 0; - - at91dci_setup_standard_chain_sub(&temp); - } - } - /* must have at least one frame! */ - td = temp.td; - xfer->td_transfer_last = td; - - /* setup the correct fifo bank */ - if (sc->sc_ep_flags[ep_no].fifo_bank) { - td = xfer->td_transfer_first; - td->fifo_bank = 1; - } -} - -static void -at91dci_timeout(void *arg) -{ - struct usb2_xfer *xfer = arg; - - DPRINTF("xfer=%p\n", xfer); - - USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); - - /* transfer is transferred */ - at91dci_device_done(xfer, USB_ERR_TIMEOUT); -} - -static void -at91dci_start_standard_chain(struct usb2_xfer *xfer) -{ - DPRINTFN(9, "\n"); - - /* poll one time */ - if (at91dci_xfer_do_fifo(xfer)) { - - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - uint8_t ep_no = xfer->endpoint & UE_ADDR; - - /* - * Only enable the endpoint interrupt when we are actually - * waiting for data, hence we are dealing with level - * triggered interrupts ! - */ - AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_EP(ep_no)); - - DPRINTFN(15, "enable interrupts on endpoint %d\n", ep_no); - - /* put transfer on interrupt queue */ - usb2_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); - - /* start timeout, if any */ - if (xfer->timeout != 0) { - usb2_transfer_timeout_ms(xfer, - &at91dci_timeout, xfer->timeout); - } - } -} - -static void -at91dci_root_intr_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - - DPRINTFN(9, "\n"); - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_PRE_DATA) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - at91dci_device_done(xfer, std->err); - } - goto done; - } - /* setup buffer */ - std->ptr = sc->sc_hub_idata; - std->len = sizeof(sc->sc_hub_idata); - - /* set port bit */ - sc->sc_hub_idata[0] = 0x02; /* we only have one port */ - -done: - return; -} - -static usb2_error_t -at91dci_standard_done_sub(struct usb2_xfer *xfer) -{ - struct at91dci_td *td; - uint32_t len; - uint8_t error; - - DPRINTFN(9, "\n"); - - td = xfer->td_transfer_cache; - - do { - len = td->remainder; - - if (xfer->aframes != xfer->nframes) { - /* - * Verify the length and subtract - * the remainder from "frlengths[]": - */ - if (len > xfer->frlengths[xfer->aframes]) { - td->error = 1; - } else { - xfer->frlengths[xfer->aframes] -= len; - } - } - /* Check for transfer error */ - if (td->error) { - /* the transfer is finished */ - error = 1; - td = NULL; - break; - } - /* Check for short transfer */ - if (len > 0) { - if (xfer->flags_int.short_frames_ok) { - /* follow alt next */ - if (td->alt_next) { - td = td->obj_next; - } else { - td = NULL; - } - } else { - /* the transfer is finished */ - td = NULL; - } - error = 0; - break; - } - td = td->obj_next; - - /* this USB frame is complete */ - error = 0; - break; - - } while (0); - - /* update transfer cache */ - - xfer->td_transfer_cache = td; - - return (error ? - USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); -} - -static void -at91dci_standard_done(struct usb2_xfer *xfer) -{ - usb2_error_t err = 0; - - DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", - xfer, xfer->pipe); - - /* reset scanner */ - - xfer->td_transfer_cache = xfer->td_transfer_first; - - if (xfer->flags_int.control_xfr) { - - if (xfer->flags_int.control_hdr) { - - err = at91dci_standard_done_sub(xfer); - } - xfer->aframes = 1; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - while (xfer->aframes != xfer->nframes) { - - err = at91dci_standard_done_sub(xfer); - xfer->aframes++; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - err = at91dci_standard_done_sub(xfer); - } -done: - at91dci_device_done(xfer, err); -} - -/*------------------------------------------------------------------------* - * at91dci_device_done - * - * NOTE: this function can be called more than one time on the - * same USB transfer! - *------------------------------------------------------------------------*/ -static void -at91dci_device_done(struct usb2_xfer *xfer, usb2_error_t error) -{ - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - uint8_t ep_no; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", - xfer, xfer->pipe, error); - - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { - ep_no = (xfer->endpoint & UE_ADDR); - - /* disable endpoint interrupt */ - AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, AT91_UDP_INT_EP(ep_no)); - - DPRINTFN(15, "disable interrupts on endpoint %d\n", ep_no); - } - /* dequeue transfer and start next transfer */ - usb2_transfer_done(xfer, error); -} - -static void -at91dci_set_stall(struct usb2_device *udev, struct usb2_xfer *xfer, - struct usb2_pipe *pipe) -{ - struct at91dci_softc *sc; - uint32_t csr_val; - uint8_t csr_reg; - - USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); - - DPRINTFN(5, "pipe=%p\n", pipe); - - if (xfer) { - /* cancel any ongoing transfers */ - at91dci_device_done(xfer, USB_ERR_STALLED); - } - /* set FORCESTALL */ - sc = AT9100_DCI_BUS2SC(udev->bus); - csr_reg = (pipe->edesc->bEndpointAddress & UE_ADDR); - csr_reg = AT91_UDP_CSR(csr_reg); - csr_val = AT91_UDP_READ_4(sc, csr_reg); - AT91_CSR_ACK(csr_val, AT91_UDP_CSR_FORCESTALL); - AT91_UDP_WRITE_4(sc, csr_reg, csr_val); -} - -static void -at91dci_clear_stall_sub(struct at91dci_softc *sc, uint8_t ep_no, - uint8_t ep_type, uint8_t ep_dir) -{ - const struct usb2_hw_ep_profile *pf; - uint32_t csr_val; - uint32_t temp; - uint8_t csr_reg; - uint8_t to; - - if (ep_type == UE_CONTROL) { - /* clearing stall is not needed */ - return; - } - /* compute CSR register offset */ - csr_reg = AT91_UDP_CSR(ep_no); - - /* compute default CSR value */ - csr_val = 0; - AT91_CSR_ACK(csr_val, 0); - - /* disable endpoint */ - AT91_UDP_WRITE_4(sc, csr_reg, csr_val); - - /* get endpoint profile */ - at91dci_get_hw_ep_profile(NULL, &pf, ep_no); - - /* reset FIFO */ - AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(ep_no)); - AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0); - - /* - * NOTE: One would assume that a FIFO reset would release the - * FIFO banks aswell, but it doesn't! We have to do this - * manually! - */ - - /* release FIFO banks, if any */ - for (to = 0; to != 2; to++) { - - /* get csr value */ - csr_val = AT91_UDP_READ_4(sc, csr_reg); - - if (csr_val & (AT91_UDP_CSR_RX_DATA_BK0 | - AT91_UDP_CSR_RX_DATA_BK1)) { - /* clear status bits */ - if (pf->support_multi_buffer) { - if (sc->sc_ep_flags[ep_no].fifo_bank) { - sc->sc_ep_flags[ep_no].fifo_bank = 0; - temp = AT91_UDP_CSR_RX_DATA_BK1; - } else { - sc->sc_ep_flags[ep_no].fifo_bank = 1; - temp = AT91_UDP_CSR_RX_DATA_BK0; - } - } else { - temp = (AT91_UDP_CSR_RX_DATA_BK0 | - AT91_UDP_CSR_RX_DATA_BK1); - } - } else { - temp = 0; - } - - /* clear FORCESTALL */ - temp |= AT91_UDP_CSR_STALLSENT; - - AT91_CSR_ACK(csr_val, temp); - AT91_UDP_WRITE_4(sc, csr_reg, csr_val); - } - - /* compute default CSR value */ - csr_val = 0; - AT91_CSR_ACK(csr_val, 0); - - /* enable endpoint */ - csr_val &= ~AT91_UDP_CSR_ET_MASK; - csr_val |= AT91_UDP_CSR_EPEDS; - - if (ep_type == UE_CONTROL) { - csr_val |= AT91_UDP_CSR_ET_CTRL; - } else { - if (ep_type == UE_BULK) { - csr_val |= AT91_UDP_CSR_ET_BULK; - } else if (ep_type == UE_INTERRUPT) { - csr_val |= AT91_UDP_CSR_ET_INT; - } else { - csr_val |= AT91_UDP_CSR_ET_ISO; - } - if (ep_dir & UE_DIR_IN) { - csr_val |= AT91_UDP_CSR_ET_DIR_IN; - } - } - - /* enable endpoint */ - AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(ep_no), csr_val); -} - -static void -at91dci_clear_stall(struct usb2_device *udev, struct usb2_pipe *pipe) -{ - struct at91dci_softc *sc; - struct usb2_endpoint_descriptor *ed; - - DPRINTFN(5, "pipe=%p\n", pipe); - - USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); - - /* check mode */ - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { - /* not supported */ - return; - } - /* get softc */ - sc = AT9100_DCI_BUS2SC(udev->bus); - - /* get endpoint descriptor */ - ed = pipe->edesc; - - /* reset endpoint */ - at91dci_clear_stall_sub(sc, - (ed->bEndpointAddress & UE_ADDR), - (ed->bmAttributes & UE_XFERTYPE), - (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); -} - -usb2_error_t -at91dci_init(struct at91dci_softc *sc) -{ - uint32_t csr_val; - uint8_t n; - - DPRINTF("start\n"); - - /* set up the bus structure */ - sc->sc_bus.usbrev = USB_REV_1_1; - sc->sc_bus.methods = &at91dci_bus_methods; - - USB_BUS_LOCK(&sc->sc_bus); - - /* turn on clocks */ - - if (sc->sc_clocks_on) { - (sc->sc_clocks_on) (sc->sc_clocks_arg); - } - /* wait a little for things to stabilise */ - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); - - /* disable and clear all interrupts */ - - AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); - AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF); - - /* compute default CSR value */ - - csr_val = 0; - AT91_CSR_ACK(csr_val, 0); - - /* disable all endpoints */ - - for (n = 0; n != AT91_UDP_EP_MAX; n++) { - - /* disable endpoint */ - AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(n), csr_val); - } - - /* enable the control endpoint */ - - AT91_CSR_ACK(csr_val, AT91_UDP_CSR_ET_CTRL | - AT91_UDP_CSR_EPEDS); - - /* write to FIFO control register */ - - AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(0), csr_val); - - /* enable the interrupts we want */ - - AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_BUS); - - /* turn off clocks */ - - at91dci_clocks_off(sc); - - USB_BUS_UNLOCK(&sc->sc_bus); - - /* catch any lost interrupts */ - - at91dci_do_poll(&sc->sc_bus); - - return (0); /* success */ -} - -void -at91dci_uninit(struct at91dci_softc *sc) -{ - USB_BUS_LOCK(&sc->sc_bus); - - /* disable and clear all interrupts */ - AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF); - AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF); - - sc->sc_flags.port_powered = 0; - sc->sc_flags.status_vbus = 0; - sc->sc_flags.status_bus_reset = 0; - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 0; - sc->sc_flags.change_connect = 1; - - at91dci_pull_down(sc); - at91dci_clocks_off(sc); - USB_BUS_UNLOCK(&sc->sc_bus); -} - -void -at91dci_suspend(struct at91dci_softc *sc) -{ - return; -} - -void -at91dci_resume(struct at91dci_softc *sc) -{ - return; -} - -static void -at91dci_do_poll(struct usb2_bus *bus) -{ - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(bus); - - USB_BUS_LOCK(&sc->sc_bus); - at91dci_interrupt_poll(sc); - at91dci_root_ctrl_poll(sc); - USB_BUS_UNLOCK(&sc->sc_bus); -} - -/*------------------------------------------------------------------------* - * at91dci bulk support - *------------------------------------------------------------------------*/ -static void -at91dci_device_bulk_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_device_bulk_close(struct usb2_xfer *xfer) -{ - at91dci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -at91dci_device_bulk_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_device_bulk_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - at91dci_setup_standard_chain(xfer); - at91dci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods at91dci_device_bulk_methods = -{ - .open = at91dci_device_bulk_open, - .close = at91dci_device_bulk_close, - .enter = at91dci_device_bulk_enter, - .start = at91dci_device_bulk_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci control support - *------------------------------------------------------------------------*/ -static void -at91dci_device_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_device_ctrl_close(struct usb2_xfer *xfer) -{ - at91dci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -at91dci_device_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_device_ctrl_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - at91dci_setup_standard_chain(xfer); - at91dci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods at91dci_device_ctrl_methods = -{ - .open = at91dci_device_ctrl_open, - .close = at91dci_device_ctrl_close, - .enter = at91dci_device_ctrl_enter, - .start = at91dci_device_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci interrupt support - *------------------------------------------------------------------------*/ -static void -at91dci_device_intr_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_device_intr_close(struct usb2_xfer *xfer) -{ - at91dci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -at91dci_device_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_device_intr_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - at91dci_setup_standard_chain(xfer); - at91dci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods at91dci_device_intr_methods = -{ - .open = at91dci_device_intr_open, - .close = at91dci_device_intr_close, - .enter = at91dci_device_intr_enter, - .start = at91dci_device_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci full speed isochronous support - *------------------------------------------------------------------------*/ -static void -at91dci_device_isoc_fs_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_device_isoc_fs_close(struct usb2_xfer *xfer) -{ - at91dci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -at91dci_device_isoc_fs_enter(struct usb2_xfer *xfer) -{ - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - uint32_t temp; - uint32_t nframes; - - DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", - xfer, xfer->pipe->isoc_next, xfer->nframes); - - /* get the current frame index */ - - nframes = AT91_UDP_READ_4(sc, AT91_UDP_FRM); - - /* - * check if the frame index is within the window where the frames - * will be inserted - */ - temp = (nframes - xfer->pipe->isoc_next) & AT91_UDP_FRM_MASK; - - if ((xfer->pipe->is_synced == 0) || - (temp < xfer->nframes)) { - /* - * If there is data underflow or the pipe queue is - * empty we schedule the transfer a few frames ahead - * of the current frame position. Else two isochronous - * transfers might overlap. - */ - xfer->pipe->isoc_next = (nframes + 3) & AT91_UDP_FRM_MASK; - xfer->pipe->is_synced = 1; - DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next); - } - /* - * compute how many milliseconds the insertion is ahead of the - * current frame position: - */ - temp = (xfer->pipe->isoc_next - nframes) & AT91_UDP_FRM_MASK; - - /* - * pre-compute when the isochronous transfer will be finished: - */ - xfer->isoc_time_complete = - usb2_isoc_time_expand(&sc->sc_bus, nframes) + temp + - xfer->nframes; - - /* compute frame number for next insertion */ - xfer->pipe->isoc_next += xfer->nframes; - - /* setup TDs */ - at91dci_setup_standard_chain(xfer); -} - -static void -at91dci_device_isoc_fs_start(struct usb2_xfer *xfer) -{ - /* start TD chain */ - at91dci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods at91dci_device_isoc_fs_methods = -{ - .open = at91dci_device_isoc_fs_open, - .close = at91dci_device_isoc_fs_close, - .enter = at91dci_device_isoc_fs_enter, - .start = at91dci_device_isoc_fs_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci root control support - *------------------------------------------------------------------------* - * simulate a hardware HUB by handling - * all the necessary requests - *------------------------------------------------------------------------*/ - -static void -at91dci_root_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_root_ctrl_close(struct usb2_xfer *xfer) -{ - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_ctrl.xfer == xfer) { - sc->sc_root_ctrl.xfer = NULL; - } - at91dci_device_done(xfer, USB_ERR_CANCELLED); -} - -/* - * USB descriptors for the virtual Root HUB: - */ - -static const struct usb2_device_descriptor at91dci_devd = { - .bLength = sizeof(struct usb2_device_descriptor), - .bDescriptorType = UDESC_DEVICE, - .bcdUSB = {0x00, 0x02}, - .bDeviceClass = UDCLASS_HUB, - .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_HSHUBSTT, - .bMaxPacketSize = 64, - .bcdDevice = {0x00, 0x01}, - .iManufacturer = 1, - .iProduct = 2, - .bNumConfigurations = 1, -}; - -static const struct usb2_device_qualifier at91dci_odevd = { - .bLength = sizeof(struct usb2_device_qualifier), - .bDescriptorType = UDESC_DEVICE_QUALIFIER, - .bcdUSB = {0x00, 0x02}, - .bDeviceClass = UDCLASS_HUB, - .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_FSHUB, - .bMaxPacketSize0 = 0, - .bNumConfigurations = 0, -}; - -static const struct at91dci_config_desc at91dci_confd = { - .confd = { - .bLength = sizeof(struct usb2_config_descriptor), - .bDescriptorType = UDESC_CONFIG, - .wTotalLength[0] = sizeof(at91dci_confd), - .bNumInterface = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = UC_SELF_POWERED, - .bMaxPower = 0, - }, - .ifcd = { - .bLength = sizeof(struct usb2_interface_descriptor), - .bDescriptorType = UDESC_INTERFACE, - .bNumEndpoints = 1, - .bInterfaceClass = UICLASS_HUB, - .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_HSHUBSTT, - }, - - .endpd = { - .bLength = sizeof(struct usb2_endpoint_descriptor), - .bDescriptorType = UDESC_ENDPOINT, - .bEndpointAddress = (UE_DIR_IN | AT9100_DCI_INTR_ENDPT), - .bmAttributes = UE_INTERRUPT, - .wMaxPacketSize[0] = 8, - .bInterval = 255, - }, -}; - -static const struct usb2_hub_descriptor_min at91dci_hubd = { - .bDescLength = sizeof(at91dci_hubd), - .bDescriptorType = UDESC_HUB, - .bNbrPorts = 1, - .wHubCharacteristics[0] = - (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) & 0xFF, - .wHubCharacteristics[1] = - (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) >> 8, - .bPwrOn2PwrGood = 50, - .bHubContrCurrent = 0, - .DeviceRemovable = {0}, /* port is removable */ -}; - -#define STRING_LANG \ - 0x09, 0x04, /* American English */ - -#define STRING_VENDOR \ - 'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L', 0 - -#define STRING_PRODUCT \ - 'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \ - 'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \ - 'U', 0, 'B', 0, - -USB_MAKE_STRING_DESC(STRING_LANG, at91dci_langtab); -USB_MAKE_STRING_DESC(STRING_VENDOR, at91dci_vendor); -USB_MAKE_STRING_DESC(STRING_PRODUCT, at91dci_product); - -static void -at91dci_root_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_root_ctrl_start(struct usb2_xfer *xfer) -{ - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - - sc->sc_root_ctrl.xfer = xfer; - - usb2_bus_roothub_exec(xfer->xroot->bus); -} - -static void -at91dci_root_ctrl_task(struct usb2_bus *bus) -{ - at91dci_root_ctrl_poll(AT9100_DCI_BUS2SC(bus)); -} - -static void -at91dci_root_ctrl_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - uint16_t value; - uint16_t index; - uint8_t use_polling; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_SETUP) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - at91dci_device_done(xfer, std->err); - } - goto done; - } - /* buffer reset */ - std->ptr = USB_ADD_BYTES(&sc->sc_hub_temp, 0); - std->len = 0; - - value = UGETW(std->req.wValue); - index = UGETW(std->req.wIndex); - - use_polling = mtx_owned(xfer->xroot->xfer_mtx) ? 1 : 0; - - /* demultiplex the control request */ - - switch (std->req.bmRequestType) { - case UT_READ_DEVICE: - switch (std->req.bRequest) { - case UR_GET_DESCRIPTOR: - goto tr_handle_get_descriptor; - case UR_GET_CONFIG: - goto tr_handle_get_config; - case UR_GET_STATUS: - goto tr_handle_get_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_DEVICE: - switch (std->req.bRequest) { - case UR_SET_ADDRESS: - goto tr_handle_set_address; - case UR_SET_CONFIG: - goto tr_handle_set_config; - case UR_CLEAR_FEATURE: - goto tr_valid; /* nop */ - case UR_SET_DESCRIPTOR: - goto tr_valid; /* nop */ - case UR_SET_FEATURE: - default: - goto tr_stalled; - } - break; - - case UT_WRITE_ENDPOINT: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - switch (UGETW(std->req.wValue)) { - case UF_ENDPOINT_HALT: - goto tr_handle_clear_halt; - case UF_DEVICE_REMOTE_WAKEUP: - goto tr_handle_clear_wakeup; - default: - goto tr_stalled; - } - break; - case UR_SET_FEATURE: - switch (UGETW(std->req.wValue)) { - case UF_ENDPOINT_HALT: - goto tr_handle_set_halt; - case UF_DEVICE_REMOTE_WAKEUP: - goto tr_handle_set_wakeup; - default: - goto tr_stalled; - } - break; - case UR_SYNCH_FRAME: - goto tr_valid; /* nop */ - default: - goto tr_stalled; - } - break; - - case UT_READ_ENDPOINT: - switch (std->req.bRequest) { - case UR_GET_STATUS: - goto tr_handle_get_ep_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_INTERFACE: - switch (std->req.bRequest) { - case UR_SET_INTERFACE: - goto tr_handle_set_interface; - case UR_CLEAR_FEATURE: - goto tr_valid; /* nop */ - case UR_SET_FEATURE: - default: - goto tr_stalled; - } - break; - - case UT_READ_INTERFACE: - switch (std->req.bRequest) { - case UR_GET_INTERFACE: - goto tr_handle_get_interface; - case UR_GET_STATUS: - goto tr_handle_get_iface_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_CLASS_INTERFACE: - case UT_WRITE_VENDOR_INTERFACE: - /* XXX forward */ - break; - - case UT_READ_CLASS_INTERFACE: - case UT_READ_VENDOR_INTERFACE: - /* XXX forward */ - break; - - case UT_WRITE_CLASS_DEVICE: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - goto tr_valid; - case UR_SET_DESCRIPTOR: - case UR_SET_FEATURE: - break; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_CLASS_OTHER: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - goto tr_handle_clear_port_feature; - case UR_SET_FEATURE: - goto tr_handle_set_port_feature; - case UR_CLEAR_TT_BUFFER: - case UR_RESET_TT: - case UR_STOP_TT: - goto tr_valid; - - default: - goto tr_stalled; - } - break; - - case UT_READ_CLASS_OTHER: - switch (std->req.bRequest) { - case UR_GET_TT_STATE: - goto tr_handle_get_tt_state; - case UR_GET_STATUS: - goto tr_handle_get_port_status; - default: - goto tr_stalled; - } - break; - - case UT_READ_CLASS_DEVICE: - switch (std->req.bRequest) { - case UR_GET_DESCRIPTOR: - goto tr_handle_get_class_descriptor; - case UR_GET_STATUS: - goto tr_handle_get_class_status; - - default: - goto tr_stalled; - } - break; - default: - goto tr_stalled; - } - goto tr_valid; - -tr_handle_get_descriptor: - switch (value >> 8) { - case UDESC_DEVICE: - if (value & 0xff) { - goto tr_stalled; - } - std->len = sizeof(at91dci_devd); - std->ptr = USB_ADD_BYTES(&at91dci_devd, 0); - goto tr_valid; - case UDESC_CONFIG: - if (value & 0xff) { - goto tr_stalled; - } - std->len = sizeof(at91dci_confd); - std->ptr = USB_ADD_BYTES(&at91dci_confd, 0); - goto tr_valid; - case UDESC_STRING: - switch (value & 0xff) { - case 0: /* Language table */ - std->len = sizeof(at91dci_langtab); - std->ptr = USB_ADD_BYTES(&at91dci_langtab, 0); - goto tr_valid; - - case 1: /* Vendor */ - std->len = sizeof(at91dci_vendor); - std->ptr = USB_ADD_BYTES(&at91dci_vendor, 0); - goto tr_valid; - - case 2: /* Product */ - std->len = sizeof(at91dci_product); - std->ptr = USB_ADD_BYTES(&at91dci_product, 0); - goto tr_valid; - default: - break; - } - break; - default: - goto tr_stalled; - } - goto tr_stalled; - -tr_handle_get_config: - std->len = 1; - sc->sc_hub_temp.wValue[0] = sc->sc_conf; - goto tr_valid; - -tr_handle_get_status: - std->len = 2; - USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); - goto tr_valid; - -tr_handle_set_address: - if (value & 0xFF00) { - goto tr_stalled; - } - sc->sc_rt_addr = value; - goto tr_valid; - -tr_handle_set_config: - if (value >= 2) { - goto tr_stalled; - } - sc->sc_conf = value; - goto tr_valid; - -tr_handle_get_interface: - std->len = 1; - sc->sc_hub_temp.wValue[0] = 0; - goto tr_valid; - -tr_handle_get_tt_state: -tr_handle_get_class_status: -tr_handle_get_iface_status: -tr_handle_get_ep_status: - std->len = 2; - USETW(sc->sc_hub_temp.wValue, 0); - goto tr_valid; - -tr_handle_set_halt: -tr_handle_set_interface: -tr_handle_set_wakeup: -tr_handle_clear_wakeup: -tr_handle_clear_halt: - goto tr_valid; - -tr_handle_clear_port_feature: - if (index != 1) { - goto tr_stalled; - } - DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index); - - switch (value) { - case UHF_PORT_SUSPEND: - at91dci_wakeup_peer(xfer); - break; - - case UHF_PORT_ENABLE: - sc->sc_flags.port_enabled = 0; - break; - - case UHF_PORT_TEST: - case UHF_PORT_INDICATOR: - case UHF_C_PORT_ENABLE: - case UHF_C_PORT_OVER_CURRENT: - case UHF_C_PORT_RESET: - /* nops */ - break; - case UHF_PORT_POWER: - sc->sc_flags.port_powered = 0; - at91dci_pull_down(sc); - at91dci_clocks_off(sc); - break; - case UHF_C_PORT_CONNECTION: - sc->sc_flags.change_connect = 0; - break; - case UHF_C_PORT_SUSPEND: - sc->sc_flags.change_suspend = 0; - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - goto tr_valid; - -tr_handle_set_port_feature: - if (index != 1) { - goto tr_stalled; - } - DPRINTFN(9, "UR_SET_PORT_FEATURE\n"); - - switch (value) { - case UHF_PORT_ENABLE: - sc->sc_flags.port_enabled = 1; - break; - case UHF_PORT_SUSPEND: - case UHF_PORT_RESET: - case UHF_PORT_TEST: - case UHF_PORT_INDICATOR: - /* nops */ - break; - case UHF_PORT_POWER: - sc->sc_flags.port_powered = 1; - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - goto tr_valid; - -tr_handle_get_port_status: - - DPRINTFN(9, "UR_GET_PORT_STATUS\n"); - - if (index != 1) { - goto tr_stalled; - } - if (sc->sc_flags.status_vbus) { - at91dci_clocks_on(sc); - at91dci_pull_up(sc); - } else { - at91dci_pull_down(sc); - at91dci_clocks_off(sc); - } - - /* Select FULL-speed and Device Side Mode */ - - value = UPS_PORT_MODE_DEVICE; - - if (sc->sc_flags.port_powered) { - value |= UPS_PORT_POWER; - } - if (sc->sc_flags.port_enabled) { - value |= UPS_PORT_ENABLED; - } - if (sc->sc_flags.status_vbus && - sc->sc_flags.status_bus_reset) { - value |= UPS_CURRENT_CONNECT_STATUS; - } - if (sc->sc_flags.status_suspend) { - value |= UPS_SUSPEND; - } - USETW(sc->sc_hub_temp.ps.wPortStatus, value); - - value = 0; - - if (sc->sc_flags.change_connect) { - value |= UPS_C_CONNECT_STATUS; - - if (sc->sc_flags.status_vbus && - sc->sc_flags.status_bus_reset) { - /* reset endpoint flags */ - bzero(sc->sc_ep_flags, sizeof(sc->sc_ep_flags)); - } - } - if (sc->sc_flags.change_suspend) { - value |= UPS_C_SUSPEND; - } - USETW(sc->sc_hub_temp.ps.wPortChange, value); - std->len = sizeof(sc->sc_hub_temp.ps); - goto tr_valid; - -tr_handle_get_class_descriptor: - if (value & 0xFF) { - goto tr_stalled; - } - std->ptr = USB_ADD_BYTES(&at91dci_hubd, 0); - std->len = sizeof(at91dci_hubd); - goto tr_valid; - -tr_stalled: - std->err = USB_ERR_STALLED; -tr_valid: -done: - return; -} - -static void -at91dci_root_ctrl_poll(struct at91dci_softc *sc) -{ - usb2_sw_transfer(&sc->sc_root_ctrl, - &at91dci_root_ctrl_done); -} - -struct usb2_pipe_methods at91dci_root_ctrl_methods = -{ - .open = at91dci_root_ctrl_open, - .close = at91dci_root_ctrl_close, - .enter = at91dci_root_ctrl_enter, - .start = at91dci_root_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 0, -}; - -/*------------------------------------------------------------------------* - * at91dci root interrupt support - *------------------------------------------------------------------------*/ -static void -at91dci_root_intr_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_root_intr_close(struct usb2_xfer *xfer) -{ - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_intr.xfer == xfer) { - sc->sc_root_intr.xfer = NULL; - } - at91dci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -at91dci_root_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_root_intr_start(struct usb2_xfer *xfer) -{ - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); - - sc->sc_root_intr.xfer = xfer; -} - -struct usb2_pipe_methods at91dci_root_intr_methods = -{ - .open = at91dci_root_intr_open, - .close = at91dci_root_intr_close, - .enter = at91dci_root_intr_enter, - .start = at91dci_root_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -static void -at91dci_xfer_setup(struct usb2_setup_params *parm) -{ - const struct usb2_hw_ep_profile *pf; - struct at91dci_softc *sc; - struct usb2_xfer *xfer; - void *last_obj; - uint32_t ntd; - uint32_t n; - uint8_t ep_no; - - sc = AT9100_DCI_BUS2SC(parm->udev->bus); - xfer = parm->curr_xfer; - - /* - * NOTE: This driver does not use any of the parameters that - * are computed from the following values. Just set some - * reasonable dummies: - */ - parm->hc_max_packet_size = 0x500; - parm->hc_max_packet_count = 1; - parm->hc_max_frame_size = 0x500; - - usb2_transfer_setup_sub(parm); - - /* - * compute maximum number of TDs - */ - if (parm->methods == &at91dci_device_ctrl_methods) { - - ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */ - + 1 /* SYNC 2 */ ; - - } else if (parm->methods == &at91dci_device_bulk_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else if (parm->methods == &at91dci_device_intr_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else if (parm->methods == &at91dci_device_isoc_fs_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else { - - ntd = 0; - } - - /* - * check if "usb2_transfer_setup_sub" set an error - */ - if (parm->err) { - return; - } - /* - * allocate transfer descriptors - */ - last_obj = NULL; - - /* - * get profile stuff - */ - if (ntd) { - - ep_no = xfer->endpoint & UE_ADDR; - at91dci_get_hw_ep_profile(parm->udev, &pf, ep_no); - - if (pf == NULL) { - /* should not happen */ - parm->err = USB_ERR_INVAL; - return; - } - } else { - ep_no = 0; - pf = NULL; - } - - /* align data */ - parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); - - for (n = 0; n != ntd; n++) { - - struct at91dci_td *td; - - if (parm->buf) { - - td = USB_ADD_BYTES(parm->buf, parm->size[0]); - - /* init TD */ - td->io_tag = sc->sc_io_tag; - td->io_hdl = sc->sc_io_hdl; - td->max_packet_size = xfer->max_packet_size; - td->status_reg = AT91_UDP_CSR(ep_no); - td->fifo_reg = AT91_UDP_FDR(ep_no); - if (pf->support_multi_buffer) { - td->support_multi_buffer = 1; - } - td->obj_next = last_obj; - - last_obj = td; - } - parm->size[0] += sizeof(*td); - } - - xfer->td_start[0] = last_obj; -} - -static void -at91dci_xfer_unsetup(struct usb2_xfer *xfer) -{ - return; -} - -static void -at91dci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, - struct usb2_pipe *pipe) -{ - struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus); - - DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", - pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, - sc->sc_rt_addr); - - if (udev->device_index == sc->sc_rt_addr) { - - if (udev->flags.usb2_mode != USB_MODE_HOST) { - /* not supported */ - return; - } - switch (edesc->bEndpointAddress) { - case USB_CONTROL_ENDPOINT: - pipe->methods = &at91dci_root_ctrl_methods; - break; - case UE_DIR_IN | AT9100_DCI_INTR_ENDPT: - pipe->methods = &at91dci_root_intr_methods; - break; - default: - /* do nothing */ - break; - } - } else { - - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { - /* not supported */ - return; - } - if (udev->speed != USB_SPEED_FULL) { - /* not supported */ - return; - } - switch (edesc->bmAttributes & UE_XFERTYPE) { - case UE_CONTROL: - pipe->methods = &at91dci_device_ctrl_methods; - break; - case UE_INTERRUPT: - pipe->methods = &at91dci_device_intr_methods; - break; - case UE_ISOCHRONOUS: - pipe->methods = &at91dci_device_isoc_fs_methods; - break; - case UE_BULK: - pipe->methods = &at91dci_device_bulk_methods; - break; - default: - /* do nothing */ - break; - } - } -} - -struct usb2_bus_methods at91dci_bus_methods = -{ - .pipe_init = &at91dci_pipe_init, - .xfer_setup = &at91dci_xfer_setup, - .xfer_unsetup = &at91dci_xfer_unsetup, - .do_poll = &at91dci_do_poll, - .get_hw_ep_profile = &at91dci_get_hw_ep_profile, - .set_stall = &at91dci_set_stall, - .clear_stall = &at91dci_clear_stall, - .roothub_exec = &at91dci_root_ctrl_task, -}; diff --git a/sys/dev/usb2/controller/at91dci.h b/sys/dev/usb2/controller/at91dci.h deleted file mode 100644 index d386307..0000000 --- a/sys/dev/usb2/controller/at91dci.h +++ /dev/null @@ -1,245 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2006 ATMEL - * Copyright (c) 2007 Hans Petter Selasky <hselasky@freebsd.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * USB Device Port (UDP) register definition, based on - * "AT91RM9200.h" provided by ATMEL. - */ - -#ifndef _AT9100_DCI_H_ -#define _AT9100_DCI_H_ - -#define AT91_MAX_DEVICES (USB_MIN_DEVICES + 1) - -#define AT91_UDP_FRM 0x00 /* Frame number register */ -#define AT91_UDP_FRM_MASK (0x7FF << 0) /* Frame Number as Defined in - * the Packet Field Formats */ -#define AT91_UDP_FRM_ERR (0x1 << 16) /* Frame Error */ -#define AT91_UDP_FRM_OK (0x1 << 17) /* Frame OK */ - -#define AT91_UDP_GSTATE 0x04 /* Global state register */ -#define AT91_UDP_GSTATE_ADDR (0x1 << 0) /* Addressed state */ -#define AT91_UDP_GSTATE_CONFG (0x1 << 1) /* Configured */ -#define AT91_UDP_GSTATE_ESR (0x1 << 2) /* Enable Send Resume */ -#define AT91_UDP_GSTATE_RSM (0x1 << 3) /* A Resume Has Been Sent to - * the Host */ -#define AT91_UDP_GSTATE_RMW (0x1 << 4) /* Remote Wake Up Enable */ - -#define AT91_UDP_FADDR 0x08 /* Function Address Register */ -#define AT91_UDP_FADDR_MASK (0x7F << 0)/* Function Address Mask */ -#define AT91_UDP_FADDR_EN (0x1 << 8)/* Function Enable */ - -#define AT91_UDP_RES0 0x0C /* Reserved 0 */ - -#define AT91_UDP_IER 0x10 /* Interrupt Enable Register */ -#define AT91_UDP_IDR 0x14 /* Interrupt Disable Register */ -#define AT91_UDP_IMR 0x18 /* Interrupt Mask Register */ -#define AT91_UDP_ISR 0x1C /* Interrupt Status Register */ -#define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */ -#define AT91_UDP_INT_EP(n) (0x1 <<(n))/* Endpoint "n" Interrupt */ -#define AT91_UDP_INT_RXSUSP (0x1 << 8)/* USB Suspend Interrupt */ -#define AT91_UDP_INT_RXRSM (0x1 << 9)/* USB Resume Interrupt */ -#define AT91_UDP_INT_EXTRSM (0x1 << 10)/* USB External Resume Interrupt */ -#define AT91_UDP_INT_SOFINT (0x1 << 11)/* USB Start Of frame Interrupt */ -#define AT91_UDP_INT_END_BR (0x1 << 12)/* USB End Of Bus Reset Interrupt */ -#define AT91_UDP_INT_WAKEUP (0x1 << 13)/* USB Resume Interrupt */ - -#define AT91_UDP_INT_BUS \ - (AT91_UDP_INT_RXSUSP|AT91_UDP_INT_RXRSM| \ - AT91_UDP_INT_END_BR) - -#define AT91_UDP_INT_EPS \ - (AT91_UDP_INT_EP(0)|AT91_UDP_INT_EP(1)| \ - AT91_UDP_INT_EP(2)|AT91_UDP_INT_EP(3)| \ - AT91_UDP_INT_EP(4)|AT91_UDP_INT_EP(5)) - -#define AT91_UDP_INT_DEFAULT \ - (AT91_UDP_INT_EPS|AT91_UDP_INT_BUS) - -#define AT91_UDP_RES1 0x24 /* Reserved 1 */ -#define AT91_UDP_RST 0x28 /* Reset Endpoint Register */ -#define AT91_UDP_RST_EP(n) (0x1 << (n))/* Reset Endpoint "n" */ - -#define AT91_UDP_RES2 0x2C /* Reserved 2 */ - -#define AT91_UDP_CSR(n) (0x30 + (4*(n)))/* Endpoint Control and Status - * Register */ -#define AT91_UDP_CSR_TXCOMP (0x1 << 0) /* Generates an IN packet with data - * previously written in the DPR */ -#define AT91_UDP_CSR_RX_DATA_BK0 (0x1 << 1) /* Receive Data Bank 0 */ -#define AT91_UDP_CSR_RXSETUP (0x1 << 2) /* Sends STALL to the Host - * (Control endpoints) */ -#define AT91_UDP_CSR_ISOERROR (0x1 << 3) /* Isochronous error - * (Isochronous endpoints) */ -#define AT91_UDP_CSR_STALLSENT (0x1 << 3) /* Stall sent (Control, bulk, - * interrupt endpoints) */ -#define AT91_UDP_CSR_TXPKTRDY (0x1 << 4) /* Transmit Packet Ready */ -#define AT91_UDP_CSR_FORCESTALL (0x1 << 5) /* Force Stall (used by - * Control, Bulk and - * Isochronous endpoints). */ -#define AT91_UDP_CSR_RX_DATA_BK1 (0x1 << 6) /* Receive Data Bank 1 (only - * used by endpoints with - * ping-pong attributes). */ -#define AT91_UDP_CSR_DIR (0x1 << 7) /* Transfer Direction */ -#define AT91_UDP_CSR_ET_MASK (0x7 << 8) /* Endpoint transfer type mask */ -#define AT91_UDP_CSR_ET_CTRL (0x0 << 8) /* Control IN+OUT */ -#define AT91_UDP_CSR_ET_ISO (0x1 << 8) /* Isochronous */ -#define AT91_UDP_CSR_ET_BULK (0x2 << 8) /* Bulk */ -#define AT91_UDP_CSR_ET_INT (0x3 << 8) /* Interrupt */ -#define AT91_UDP_CSR_ET_DIR_OUT (0x0 << 8) /* OUT tokens */ -#define AT91_UDP_CSR_ET_DIR_IN (0x4 << 8) /* IN tokens */ -#define AT91_UDP_CSR_DTGLE (0x1 << 11) /* Data Toggle */ -#define AT91_UDP_CSR_EPEDS (0x1 << 15) /* Endpoint Enable Disable */ -#define AT91_UDP_CSR_RXBYTECNT (0x7FF << 16) /* Number Of Bytes Available - * in the FIFO */ - -#define AT91_UDP_FDR(n) (0x50 + (4*(n)))/* Endpoint FIFO Data Register */ -#define AT91_UDP_RES3 0x70 /* Reserved 3 */ -#define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */ -#define AT91_UDP_TXVC_DIS (0x1 << 8) - -#define AT91_UDP_EP_MAX 6 /* maximum number of endpoints - * supported */ - -#define AT91_UDP_READ_4(sc, reg) \ - bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg) - -#define AT91_UDP_WRITE_4(sc, reg, data) \ - bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data) - -struct at91dci_td; - -typedef uint8_t (at91dci_cmd_t)(struct at91dci_td *td); - -struct at91dci_td { - bus_space_tag_t io_tag; - bus_space_handle_t io_hdl; - struct at91dci_td *obj_next; - at91dci_cmd_t *func; - struct usb2_page_cache *pc; - uint32_t offset; - uint32_t remainder; - uint16_t max_packet_size; - uint8_t status_reg; - uint8_t fifo_reg; - uint8_t fifo_bank:1; - uint8_t error:1; - uint8_t alt_next:1; - uint8_t short_pkt:1; - uint8_t support_multi_buffer:1; - uint8_t did_stall:1; -}; - -struct at91dci_std_temp { - at91dci_cmd_t *func; - struct usb2_page_cache *pc; - struct at91dci_td *td; - struct at91dci_td *td_next; - uint32_t len; - uint32_t offset; - uint16_t max_frame_size; - uint8_t short_pkt; - /* - * short_pkt = 0: transfer should be short terminated - * short_pkt = 1: transfer should not be short terminated - */ - uint8_t setup_alt_next; -}; - -struct at91dci_config_desc { - struct usb2_config_descriptor confd; - struct usb2_interface_descriptor ifcd; - struct usb2_endpoint_descriptor endpd; -} __packed; - -union at91dci_hub_temp { - uWord wValue; - struct usb2_port_status ps; -}; - -struct at91dci_ep_flags { - uint8_t fifo_bank:1; /* hardware specific */ -}; - -struct at91dci_flags { - uint8_t change_connect:1; - uint8_t change_suspend:1; - uint8_t status_suspend:1; /* set if suspended */ - uint8_t status_vbus:1; /* set if present */ - uint8_t status_bus_reset:1; /* set if reset complete */ - uint8_t remote_wakeup:1; - uint8_t self_powered:1; - uint8_t clocks_off:1; - uint8_t port_powered:1; - uint8_t port_enabled:1; - uint8_t d_pulled_up:1; -}; - -struct at91dci_softc { - struct usb2_bus sc_bus; - union at91dci_hub_temp sc_hub_temp; - LIST_HEAD(, usb2_xfer) sc_interrupt_list_head; - struct usb2_sw_transfer sc_root_ctrl; - struct usb2_sw_transfer sc_root_intr; - - struct usb2_device *sc_devices[AT91_MAX_DEVICES]; - struct resource *sc_io_res; - struct resource *sc_irq_res; - void *sc_intr_hdl; - bus_size_t sc_io_size; - bus_space_tag_t sc_io_tag; - bus_space_handle_t sc_io_hdl; - - void (*sc_clocks_on) (void *arg); - void (*sc_clocks_off) (void *arg); - void *sc_clocks_arg; - - void (*sc_pull_up) (void *arg); - void (*sc_pull_down) (void *arg); - void *sc_pull_arg; - - uint8_t sc_rt_addr; /* root HUB address */ - uint8_t sc_dv_addr; /* device address */ - uint8_t sc_conf; /* root HUB config */ - - uint8_t sc_hub_idata[1]; - - struct at91dci_flags sc_flags; - struct at91dci_ep_flags sc_ep_flags[AT91_UDP_EP_MAX]; -}; - -/* prototypes */ - -usb2_error_t at91dci_init(struct at91dci_softc *sc); -void at91dci_uninit(struct at91dci_softc *sc); -void at91dci_suspend(struct at91dci_softc *sc); -void at91dci_resume(struct at91dci_softc *sc); -void at91dci_interrupt(struct at91dci_softc *sc); -void at91dci_vbus_interrupt(struct at91dci_softc *sc, uint8_t is_on); - -#endif /* _AT9100_DCI_H_ */ diff --git a/sys/dev/usb2/controller/at91dci_atmelarm.c b/sys/dev/usb2/controller/at91dci_atmelarm.c deleted file mode 100644 index 39d3782..0000000 --- a/sys/dev/usb2/controller/at91dci_atmelarm.c +++ /dev/null @@ -1,347 +0,0 @@ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/*- - * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - - -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_defs.h> -#include <dev/usb2/include/usb2_standard.h> - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/at91dci.h> - -#include <sys/rman.h> - -#include <arm/at91/at91_pmcvar.h> -#include <arm/at91/at91rm92reg.h> -#include <arm/at91/at91_pio_rm9200.h> -#include <arm/at91/at91_piovar.h> - -#define MEM_RID 0 - -/* Pin Definitions - do they belong here or somewhere else ? */ - -#define VBUS_MASK AT91C_PIO_PB24 -#define VBUS_BASE AT91RM92_PIOB_BASE - -#define PULLUP_MASK AT91C_PIO_PB22 -#define PULLUP_BASE AT91RM92_PIOB_BASE - -static device_probe_t at91_udp_probe; -static device_attach_t at91_udp_attach; -static device_detach_t at91_udp_detach; -static device_shutdown_t at91_udp_shutdown; - -struct at91_udp_softc { - struct at91dci_softc sc_dci; /* must be first */ - struct at91_pmc_clock *sc_iclk; - struct at91_pmc_clock *sc_fclk; - struct resource *sc_vbus_irq_res; - void *sc_vbus_intr_hdl; -}; - -static void -at91_vbus_poll(struct at91_udp_softc *sc) -{ - uint32_t temp; - uint8_t vbus_val; - - /* XXX temporary clear interrupts here */ - - temp = at91_pio_gpio_clear_interrupt(VBUS_BASE); - - /* just forward it */ - - vbus_val = at91_pio_gpio_get(VBUS_BASE, VBUS_MASK); - at91dci_vbus_interrupt(&sc->sc_dci, vbus_val); -} - -static void -at91_udp_clocks_on(void *arg) -{ - struct at91_udp_softc *sc = arg; - - at91_pmc_clock_enable(sc->sc_iclk); - at91_pmc_clock_enable(sc->sc_fclk); -} - -static void -at91_udp_clocks_off(void *arg) -{ - struct at91_udp_softc *sc = arg; - - at91_pmc_clock_disable(sc->sc_fclk); - at91_pmc_clock_disable(sc->sc_iclk); -} - -static void -at91_udp_pull_up(void *arg) -{ - at91_pio_gpio_set(PULLUP_BASE, PULLUP_MASK); -} - -static void -at91_udp_pull_down(void *arg) -{ - at91_pio_gpio_clear(PULLUP_BASE, PULLUP_MASK); -} - -static int -at91_udp_probe(device_t dev) -{ - device_set_desc(dev, "AT91 integrated AT91_UDP controller"); - return (0); -} - -static int -at91_udp_attach(device_t dev) -{ - struct at91_udp_softc *sc = device_get_softc(dev); - int err; - int rid; - - /* setup AT9100 USB device controller interface softc */ - - sc->sc_dci.sc_clocks_on = &at91_udp_clocks_on; - sc->sc_dci.sc_clocks_off = &at91_udp_clocks_off; - sc->sc_dci.sc_clocks_arg = sc; - sc->sc_dci.sc_pull_up = &at91_udp_pull_up; - sc->sc_dci.sc_pull_down = &at91_udp_pull_down; - sc->sc_dci.sc_pull_arg = sc; - - /* initialise some bus fields */ - sc->sc_dci.sc_bus.parent = dev; - sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; - sc->sc_dci.sc_bus.devices_max = AT91_MAX_DEVICES; - - /* get all DMA memory */ - if (usb2_bus_mem_alloc_all(&sc->sc_dci.sc_bus, - USB_GET_DMA_TAG(dev), NULL)) { - return (ENOMEM); - } - /* - * configure VBUS input pin, enable deglitch and enable - * interrupt : - */ - at91_pio_use_gpio(VBUS_BASE, VBUS_MASK); - at91_pio_gpio_input(VBUS_BASE, VBUS_MASK); - at91_pio_gpio_set_deglitch(VBUS_BASE, VBUS_MASK, 1); - at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 1); - - /* - * configure PULLUP output pin : - */ - at91_pio_use_gpio(PULLUP_BASE, PULLUP_MASK); - at91_pio_gpio_output(PULLUP_BASE, PULLUP_MASK, 0); - - at91_udp_pull_down(sc); - - /* wait 10ms for pulldown to stabilise */ - usb2_pause_mtx(NULL, hz / 100); - - sc->sc_iclk = at91_pmc_clock_ref("udc_clk"); - sc->sc_fclk = at91_pmc_clock_ref("udpck"); - - rid = MEM_RID; - sc->sc_dci.sc_io_res = - bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); - - if (!(sc->sc_dci.sc_io_res)) { - err = ENOMEM; - goto error; - } - sc->sc_dci.sc_io_tag = rman_get_bustag(sc->sc_dci.sc_io_res); - sc->sc_dci.sc_io_hdl = rman_get_bushandle(sc->sc_dci.sc_io_res); - sc->sc_dci.sc_io_size = rman_get_size(sc->sc_dci.sc_io_res); - - rid = 0; - sc->sc_dci.sc_irq_res = - bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); - if (!(sc->sc_dci.sc_irq_res)) { - goto error; - } - rid = 1; - sc->sc_vbus_irq_res = - bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); - if (!(sc->sc_vbus_irq_res)) { - goto error; - } - sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); - if (!(sc->sc_dci.sc_bus.bdev)) { - goto error; - } - device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); - -#if (__FreeBSD_version >= 700031) - err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl); -#else - err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl); -#endif - if (err) { - sc->sc_dci.sc_intr_hdl = NULL; - goto error; - } -#if (__FreeBSD_version >= 700031) - err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl); -#else - err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl); -#endif - if (err) { - sc->sc_vbus_intr_hdl = NULL; - goto error; - } - err = at91dci_init(&sc->sc_dci); - if (!err) { - err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); - } - if (err) { - goto error; - } else { - /* poll VBUS one time */ - at91_vbus_poll(sc); - } - return (0); - -error: - at91_udp_detach(dev); - return (ENXIO); -} - -static int -at91_udp_detach(device_t dev) -{ - struct at91_udp_softc *sc = device_get_softc(dev); - device_t bdev; - int err; - - if (sc->sc_dci.sc_bus.bdev) { - bdev = sc->sc_dci.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } - /* during module unload there are lots of children leftover */ - device_delete_all_children(dev); - - /* disable Transceiver */ - AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); - - /* disable and clear all interrupts */ - AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_IDR, 0xFFFFFFFF); - AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_ICR, 0xFFFFFFFF); - - /* disable VBUS interrupt */ - at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 0); - - if (sc->sc_vbus_irq_res && sc->sc_vbus_intr_hdl) { - err = bus_teardown_intr(dev, sc->sc_vbus_irq_res, - sc->sc_vbus_intr_hdl); - sc->sc_vbus_intr_hdl = NULL; - } - if (sc->sc_vbus_irq_res) { - bus_release_resource(dev, SYS_RES_IRQ, 1, - sc->sc_vbus_irq_res); - sc->sc_vbus_irq_res = NULL; - } - if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { - /* - * only call at91_udp_uninit() after at91_udp_init() - */ - at91dci_uninit(&sc->sc_dci); - - err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, - sc->sc_dci.sc_intr_hdl); - sc->sc_dci.sc_intr_hdl = NULL; - } - if (sc->sc_dci.sc_irq_res) { - bus_release_resource(dev, SYS_RES_IRQ, 0, - sc->sc_dci.sc_irq_res); - sc->sc_dci.sc_irq_res = NULL; - } - if (sc->sc_dci.sc_io_res) { - bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, - sc->sc_dci.sc_io_res); - sc->sc_dci.sc_io_res = NULL; - } - usb2_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); - - /* disable clocks */ - at91_pmc_clock_disable(sc->sc_iclk); - at91_pmc_clock_disable(sc->sc_fclk); - at91_pmc_clock_deref(sc->sc_fclk); - at91_pmc_clock_deref(sc->sc_iclk); - - return (0); -} - -static int -at91_udp_shutdown(device_t dev) -{ - struct at91_udp_softc *sc = device_get_softc(dev); - int err; - - err = bus_generic_shutdown(dev); - if (err) - return (err); - - at91dci_uninit(&sc->sc_dci); - - return (0); -} - -static device_method_t at91_udp_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, at91_udp_probe), - DEVMETHOD(device_attach, at91_udp_attach), - DEVMETHOD(device_detach, at91_udp_detach), - DEVMETHOD(device_shutdown, at91_udp_shutdown), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - {0, 0} -}; - -static driver_t at91_udp_driver = { - "at91_udp", - at91_udp_methods, - sizeof(struct at91_udp_softc), -}; - -static devclass_t at91_udp_devclass; - -DRIVER_MODULE(at91_udp, atmelarm, at91_udp_driver, at91_udp_devclass, 0, 0); diff --git a/sys/dev/usb2/controller/atmegadci.c b/sys/dev/usb2/controller/atmegadci.c deleted file mode 100644 index bea8835d..0000000 --- a/sys/dev/usb2/controller/atmegadci.c +++ /dev/null @@ -1,2327 +0,0 @@ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/*- - * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * This file contains the driver for the ATMEGA series USB Device - * Controller - */ - -/* - * NOTE: When the chip detects BUS-reset it will also reset the - * endpoints, Function-address and more. - */ - -#include <dev/usb2/include/usb2_standard.h> -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_error.h> -#include <dev/usb2/include/usb2_defs.h> - -#define USB_DEBUG_VAR atmegadci_debug - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_debug.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_transfer.h> -#include <dev/usb2/core/usb2_device.h> -#include <dev/usb2/core/usb2_hub.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/atmegadci.h> - -#define ATMEGA_BUS2SC(bus) \ - ((struct atmegadci_softc *)(((uint8_t *)(bus)) - \ - USB_P2U(&(((struct atmegadci_softc *)0)->sc_bus)))) - -#define ATMEGA_PC2SC(pc) \ - ATMEGA_BUS2SC((pc)->tag_parent->info->bus) - -#if USB_DEBUG -static int atmegadci_debug = 0; - -SYSCTL_NODE(_hw_usb2, OID_AUTO, atmegadci, CTLFLAG_RW, 0, "USB ATMEGA DCI"); -SYSCTL_INT(_hw_usb2_atmegadci, OID_AUTO, debug, CTLFLAG_RW, - &atmegadci_debug, 0, "ATMEGA DCI debug level"); -#endif - -#define ATMEGA_INTR_ENDPT 1 - -/* prototypes */ - -struct usb2_bus_methods atmegadci_bus_methods; -struct usb2_pipe_methods atmegadci_device_bulk_methods; -struct usb2_pipe_methods atmegadci_device_ctrl_methods; -struct usb2_pipe_methods atmegadci_device_intr_methods; -struct usb2_pipe_methods atmegadci_device_isoc_fs_methods; -struct usb2_pipe_methods atmegadci_root_ctrl_methods; -struct usb2_pipe_methods atmegadci_root_intr_methods; - -static atmegadci_cmd_t atmegadci_setup_rx; -static atmegadci_cmd_t atmegadci_data_rx; -static atmegadci_cmd_t atmegadci_data_tx; -static atmegadci_cmd_t atmegadci_data_tx_sync; -static void atmegadci_device_done(struct usb2_xfer *, usb2_error_t); -static void atmegadci_do_poll(struct usb2_bus *); -static void atmegadci_root_ctrl_poll(struct atmegadci_softc *); -static void atmegadci_standard_done(struct usb2_xfer *); - -static usb2_sw_transfer_func_t atmegadci_root_intr_done; -static usb2_sw_transfer_func_t atmegadci_root_ctrl_done; - -/* - * Here is a list of what the chip supports: - */ -static const struct usb2_hw_ep_profile - atmegadci_ep_profile[2] = { - - [0] = { - .max_in_frame_size = 64, - .max_out_frame_size = 64, - .is_simplex = 1, - .support_control = 1, - }, - [1] = { - .max_in_frame_size = 64, - .max_out_frame_size = 64, - .is_simplex = 1, - .support_multi_buffer = 1, - .support_bulk = 1, - .support_interrupt = 1, - .support_isochronous = 1, - .support_in = 1, - .support_out = 1, - }, -}; - -static void -atmegadci_get_hw_ep_profile(struct usb2_device *udev, - const struct usb2_hw_ep_profile **ppf, uint8_t ep_addr) -{ - if (ep_addr == 0) - *ppf = atmegadci_ep_profile; - else if (ep_addr < ATMEGA_EP_MAX) - *ppf = atmegadci_ep_profile + 1; - else - *ppf = NULL; -} - -static void -atmegadci_clocks_on(struct atmegadci_softc *sc) -{ - if (sc->sc_flags.clocks_off && - sc->sc_flags.port_powered) { - - DPRINTFN(5, "\n"); - - /* turn on clocks */ - (sc->sc_clocks_on) (&sc->sc_bus); - - ATMEGA_WRITE_1(sc, ATMEGA_USBCON, - ATMEGA_USBCON_USBE | - ATMEGA_USBCON_OTGPADE | - ATMEGA_USBCON_VBUSTE); - - sc->sc_flags.clocks_off = 0; - - /* enable transceiver ? */ - } -} - -static void -atmegadci_clocks_off(struct atmegadci_softc *sc) -{ - if (!sc->sc_flags.clocks_off) { - - DPRINTFN(5, "\n"); - - /* disable Transceiver ? */ - - ATMEGA_WRITE_1(sc, ATMEGA_USBCON, - ATMEGA_USBCON_USBE | - ATMEGA_USBCON_OTGPADE | - ATMEGA_USBCON_FRZCLK | - ATMEGA_USBCON_VBUSTE); - - /* turn clocks off */ - (sc->sc_clocks_off) (&sc->sc_bus); - - sc->sc_flags.clocks_off = 1; - } -} - -static void -atmegadci_pull_up(struct atmegadci_softc *sc) -{ - /* pullup D+, if possible */ - - if (!sc->sc_flags.d_pulled_up && - sc->sc_flags.port_powered) { - sc->sc_flags.d_pulled_up = 1; - ATMEGA_WRITE_1(sc, ATMEGA_UDCON, 0); - } -} - -static void -atmegadci_pull_down(struct atmegadci_softc *sc) -{ - /* pulldown D+, if possible */ - - if (sc->sc_flags.d_pulled_up) { - sc->sc_flags.d_pulled_up = 0; - ATMEGA_WRITE_1(sc, ATMEGA_UDCON, ATMEGA_UDCON_DETACH); - } -} - -static void -atmegadci_wakeup_peer(struct usb2_xfer *xfer) -{ - struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus); - uint8_t use_polling; - uint8_t temp; - - if (!sc->sc_flags.status_suspend) { - return; - } - use_polling = mtx_owned(xfer->xroot->xfer_mtx) ? 1 : 0; - - temp = ATMEGA_READ_1(sc, ATMEGA_UDCON); - ATMEGA_WRITE_1(sc, ATMEGA_UDCON, temp | ATMEGA_UDCON_RMWKUP); - - /* wait 8 milliseconds */ - if (use_polling) { - /* polling */ - DELAY(8000); - } else { - /* Wait for reset to complete. */ - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); - } - - /* hardware should have cleared RMWKUP bit */ -} - -static void -atmegadci_set_address(struct atmegadci_softc *sc, uint8_t addr) -{ - DPRINTFN(5, "addr=%d\n", addr); - - ATMEGA_WRITE_1(sc, ATMEGA_UDADDR, addr); - - addr |= ATMEGA_UDADDR_ADDEN; - - ATMEGA_WRITE_1(sc, ATMEGA_UDADDR, addr); -} - -static uint8_t -atmegadci_setup_rx(struct atmegadci_td *td) -{ - struct atmegadci_softc *sc; - struct usb2_device_request req; - uint16_t count; - uint8_t temp; - - /* get pointer to softc */ - sc = ATMEGA_PC2SC(td->pc); - - /* select endpoint number */ - ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no); - - /* check endpoint status */ - temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX); - - DPRINTFN(5, "UEINTX=0x%02x\n", temp); - - if (!(temp & ATMEGA_UEINTX_RXSTPI)) { - /* abort any ongoing transfer */ - if (!td->did_stall) { - DPRINTFN(5, "stalling\n"); - ATMEGA_WRITE_1(sc, ATMEGA_UECONX, - ATMEGA_UECONX_EPEN | - ATMEGA_UECONX_STALLRQ); - td->did_stall = 1; - } - goto not_complete; - } - /* get the packet byte count */ - count = - (ATMEGA_READ_1(sc, ATMEGA_UEBCHX) << 8) | - (ATMEGA_READ_1(sc, ATMEGA_UEBCLX)); - - /* mask away undefined bits */ - count &= 0x7FF; - - /* verify data length */ - if (count != td->remainder) { - DPRINTFN(0, "Invalid SETUP packet " - "length, %d bytes\n", count); - goto not_complete; - } - if (count != sizeof(req)) { - DPRINTFN(0, "Unsupported SETUP packet " - "length, %d bytes\n", count); - goto not_complete; - } - /* receive data */ - ATMEGA_READ_MULTI_1(sc, ATMEGA_UEDATX, - (void *)&req, sizeof(req)); - - /* copy data into real buffer */ - usb2_copy_in(td->pc, 0, &req, sizeof(req)); - - td->offset = sizeof(req); - td->remainder = 0; - - /* sneak peek the set address */ - if ((req.bmRequestType == UT_WRITE_DEVICE) && - (req.bRequest == UR_SET_ADDRESS)) { - sc->sc_dv_addr = req.wValue[0] & 0x7F; - } else { - sc->sc_dv_addr = 0xFF; - } - - /* clear SETUP packet interrupt */ - ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, ~ATMEGA_UEINTX_RXSTPI); - return (0); /* complete */ - -not_complete: - /* we only want to know if there is a SETUP packet */ - ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, ATMEGA_UEIENX_RXSTPE); - return (1); /* not complete */ -} - -static uint8_t -atmegadci_data_rx(struct atmegadci_td *td) -{ - struct atmegadci_softc *sc; - struct usb2_page_search buf_res; - uint16_t count; - uint8_t temp; - uint8_t to; - uint8_t got_short; - - to = 3; /* don't loop forever! */ - got_short = 0; - - /* get pointer to softc */ - sc = ATMEGA_PC2SC(td->pc); - - /* select endpoint number */ - ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no); - -repeat: - /* check if any of the FIFO banks have data */ - /* check endpoint status */ - temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX); - - DPRINTFN(5, "temp=0x%02x rem=%u\n", temp, td->remainder); - - if (temp & ATMEGA_UEINTX_RXSTPI) { - if (td->remainder == 0) { - /* - * We are actually complete and have - * received the next SETUP - */ - DPRINTFN(5, "faking complete\n"); - return (0); /* complete */ - } - /* - * USB Host Aborted the transfer. - */ - td->error = 1; - return (0); /* complete */ - } - /* check status */ - if (!(temp & (ATMEGA_UEINTX_FIFOCON | - ATMEGA_UEINTX_RXOUTI))) { - /* no data */ - goto not_complete; - } - /* get the packet byte count */ - count = - (ATMEGA_READ_1(sc, ATMEGA_UEBCHX) << 8) | - (ATMEGA_READ_1(sc, ATMEGA_UEBCLX)); - - /* mask away undefined bits */ - count &= 0x7FF; - - /* verify the packet byte count */ - if (count != td->max_packet_size) { - if (count < td->max_packet_size) { - /* we have a short packet */ - td->short_pkt = 1; - got_short = 1; - } else { - /* invalid USB packet */ - td->error = 1; - return (0); /* we are complete */ - } - } - /* verify the packet byte count */ - if (count > td->remainder) { - /* invalid USB packet */ - td->error = 1; - return (0); /* we are complete */ - } - while (count > 0) { - usb2_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* receive data */ - ATMEGA_READ_MULTI_1(sc, ATMEGA_UEDATX, - buf_res.buffer, buf_res.length); - - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } - - /* clear OUT packet interrupt */ - ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, ATMEGA_UEINTX_RXOUTI ^ 0xFF); - - /* release FIFO bank */ - ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, ATMEGA_UEINTX_FIFOCON ^ 0xFF); - - /* check if we are complete */ - if ((td->remainder == 0) || got_short) { - if (td->short_pkt) { - /* we are complete */ - return (0); - } - /* else need to receive a zero length packet */ - } - if (--to) { - goto repeat; - } -not_complete: - /* we only want to know if there is a SETUP packet or OUT packet */ - ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, - ATMEGA_UEIENX_RXSTPE | ATMEGA_UEIENX_RXOUTE); - return (1); /* not complete */ -} - -static uint8_t -atmegadci_data_tx(struct atmegadci_td *td) -{ - struct atmegadci_softc *sc; - struct usb2_page_search buf_res; - uint16_t count; - uint8_t to; - uint8_t temp; - - to = 3; /* don't loop forever! */ - - /* get pointer to softc */ - sc = ATMEGA_PC2SC(td->pc); - - /* select endpoint number */ - ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no); - -repeat: - - /* check endpoint status */ - temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX); - - DPRINTFN(5, "temp=0x%02x rem=%u\n", temp, td->remainder); - - if (temp & ATMEGA_UEINTX_RXSTPI) { - /* - * The current transfer was aborted - * by the USB Host - */ - td->error = 1; - return (0); /* complete */ - } - if (!(temp & (ATMEGA_UEINTX_FIFOCON | - ATMEGA_UEINTX_TXINI))) { - /* cannot write any data */ - goto not_complete; - } - count = td->max_packet_size; - if (td->remainder < count) { - /* we have a short packet */ - td->short_pkt = 1; - count = td->remainder; - } - while (count > 0) { - - usb2_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* transmit data */ - ATMEGA_WRITE_MULTI_1(sc, ATMEGA_UEDATX, - buf_res.buffer, buf_res.length); - - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } - - /* clear IN packet interrupt */ - ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, 0xFF ^ ATMEGA_UEINTX_TXINI); - - /* allocate FIFO bank */ - ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, 0xFF ^ ATMEGA_UEINTX_FIFOCON); - - /* check remainder */ - if (td->remainder == 0) { - if (td->short_pkt) { - return (0); /* complete */ - } - /* else we need to transmit a short packet */ - } - if (--to) { - goto repeat; - } -not_complete: - /* we only want to know if there is a SETUP packet or free IN packet */ - ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, - ATMEGA_UEIENX_RXSTPE | ATMEGA_UEIENX_TXINE); - return (1); /* not complete */ -} - -static uint8_t -atmegadci_data_tx_sync(struct atmegadci_td *td) -{ - struct atmegadci_softc *sc; - uint8_t temp; - - /* get pointer to softc */ - sc = ATMEGA_PC2SC(td->pc); - - /* select endpoint number */ - ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no); - - /* check endpoint status */ - temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX); - - DPRINTFN(5, "temp=0x%02x\n", temp); - - if (temp & ATMEGA_UEINTX_RXSTPI) { - DPRINTFN(5, "faking complete\n"); - /* Race condition */ - return (0); /* complete */ - } - /* - * The control endpoint has only got one bank, so if that bank - * is free the packet has been transferred! - */ - if (!(temp & (ATMEGA_UEINTX_FIFOCON | - ATMEGA_UEINTX_TXINI))) { - /* cannot write any data */ - goto not_complete; - } - if (sc->sc_dv_addr != 0xFF) { - /* set new address */ - atmegadci_set_address(sc, sc->sc_dv_addr); - } - return (0); /* complete */ - -not_complete: - /* we only want to know if there is a SETUP packet or free IN packet */ - ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, - ATMEGA_UEIENX_RXSTPE | ATMEGA_UEIENX_TXINE); - return (1); /* not complete */ -} - -static uint8_t -atmegadci_xfer_do_fifo(struct usb2_xfer *xfer) -{ - struct atmegadci_td *td; - - DPRINTFN(9, "\n"); - - td = xfer->td_transfer_cache; - while (1) { - if ((td->func) (td)) { - /* operation in progress */ - break; - } - if (((void *)td) == xfer->td_transfer_last) { - goto done; - } - if (td->error) { - goto done; - } else if (td->remainder > 0) { - /* - * We had a short transfer. If there is no alternate - * next, stop processing ! - */ - if (!td->alt_next) { - goto done; - } - } - /* - * Fetch the next transfer descriptor and transfer - * some flags to the next transfer descriptor - */ - td = td->obj_next; - xfer->td_transfer_cache = td; - } - return (1); /* not complete */ - -done: - /* compute all actual lengths */ - - atmegadci_standard_done(xfer); - return (0); /* complete */ -} - -static void -atmegadci_interrupt_poll(struct atmegadci_softc *sc) -{ - struct usb2_xfer *xfer; - -repeat: - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - if (!atmegadci_xfer_do_fifo(xfer)) { - /* queue has been modified */ - goto repeat; - } - } -} - -static void -atmegadci_vbus_interrupt(struct atmegadci_softc *sc, uint8_t is_on) -{ - DPRINTFN(5, "vbus = %u\n", is_on); - - if (is_on) { - if (!sc->sc_flags.status_vbus) { - sc->sc_flags.status_vbus = 1; - - /* complete root HUB interrupt endpoint */ - - usb2_sw_transfer(&sc->sc_root_intr, - &atmegadci_root_intr_done); - } - } else { - if (sc->sc_flags.status_vbus) { - sc->sc_flags.status_vbus = 0; - sc->sc_flags.status_bus_reset = 0; - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 0; - sc->sc_flags.change_connect = 1; - - /* complete root HUB interrupt endpoint */ - - usb2_sw_transfer(&sc->sc_root_intr, - &atmegadci_root_intr_done); - } - } -} - -void -atmegadci_interrupt(struct atmegadci_softc *sc) -{ - uint8_t status; - - USB_BUS_LOCK(&sc->sc_bus); - - /* read interrupt status */ - status = ATMEGA_READ_1(sc, ATMEGA_UDINT); - - /* clear all set interrupts */ - ATMEGA_WRITE_1(sc, ATMEGA_UDINT, ~status); - - /* check for any bus state change interrupts */ - if (status & ATMEGA_UDINT_EORSTI) { - - DPRINTFN(5, "end of reset\n"); - - /* set correct state */ - sc->sc_flags.status_bus_reset = 1; - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 0; - sc->sc_flags.change_connect = 1; - - /* disable resume interrupt */ - ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, - ATMEGA_UDINT_SUSPE | - ATMEGA_UDINT_EORSTE); - - /* complete root HUB interrupt endpoint */ - usb2_sw_transfer(&sc->sc_root_intr, - &atmegadci_root_intr_done); - } - /* - * If resume and suspend is set at the same time we interpret - * that like RESUME. Resume is set when there is at least 3 - * milliseconds of inactivity on the USB BUS. - */ - if (status & ATMEGA_UDINT_EORSMI) { - - DPRINTFN(5, "resume interrupt\n"); - - if (sc->sc_flags.status_suspend) { - /* update status bits */ - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 1; - - /* disable resume interrupt */ - ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, - ATMEGA_UDINT_SUSPE | - ATMEGA_UDINT_EORSTE); - - /* complete root HUB interrupt endpoint */ - usb2_sw_transfer(&sc->sc_root_intr, - &atmegadci_root_intr_done); - } - } else if (status & ATMEGA_UDINT_SUSPI) { - - DPRINTFN(5, "suspend interrupt\n"); - - if (!sc->sc_flags.status_suspend) { - /* update status bits */ - sc->sc_flags.status_suspend = 1; - sc->sc_flags.change_suspend = 1; - - /* disable suspend interrupt */ - ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, - ATMEGA_UDINT_EORSMI | - ATMEGA_UDINT_EORSTE); - - /* complete root HUB interrupt endpoint */ - usb2_sw_transfer(&sc->sc_root_intr, - &atmegadci_root_intr_done); - } - } - /* check VBUS */ - status = ATMEGA_READ_1(sc, ATMEGA_USBINT); - - /* clear all set interrupts */ - ATMEGA_WRITE_1(sc, ATMEGA_USBINT, ~status); - - if (status & ATMEGA_USBINT_VBUSTI) { - uint8_t temp; - - temp = ATMEGA_READ_1(sc, ATMEGA_USBSTA); - atmegadci_vbus_interrupt(sc, temp & ATMEGA_USBSTA_VBUS); - } - /* check for any endpoint interrupts */ - status = ATMEGA_READ_1(sc, ATMEGA_UEINT); - - /* clear all set interrupts */ - ATMEGA_WRITE_1(sc, ATMEGA_UEINT, ~status); - - if (status) { - - DPRINTFN(5, "real endpoint interrupt 0x%02x\n", status); - - atmegadci_interrupt_poll(sc); - } - USB_BUS_UNLOCK(&sc->sc_bus); -} - -static void -atmegadci_setup_standard_chain_sub(struct atmegadci_std_temp *temp) -{ - struct atmegadci_td *td; - - /* get current Transfer Descriptor */ - td = temp->td_next; - temp->td = td; - - /* prepare for next TD */ - temp->td_next = td->obj_next; - - /* fill out the Transfer Descriptor */ - td->func = temp->func; - td->pc = temp->pc; - td->offset = temp->offset; - td->remainder = temp->len; - td->error = 0; - td->did_stall = 0; - td->short_pkt = temp->short_pkt; - td->alt_next = temp->setup_alt_next; -} - -static void -atmegadci_setup_standard_chain(struct usb2_xfer *xfer) -{ - struct atmegadci_std_temp temp; - struct atmegadci_softc *sc; - struct atmegadci_td *td; - uint32_t x; - uint8_t ep_no; - uint8_t need_sync; - - DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", - xfer->address, UE_GET_ADDR(xfer->endpoint), - xfer->sumlen, usb2_get_speed(xfer->xroot->udev)); - - temp.max_frame_size = xfer->max_frame_size; - - td = xfer->td_start[0]; - xfer->td_transfer_first = td; - xfer->td_transfer_cache = td; - - /* setup temp */ - - temp.td = NULL; - temp.td_next = xfer->td_start[0]; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; - temp.offset = 0; - - sc = ATMEGA_BUS2SC(xfer->xroot->bus); - ep_no = (xfer->endpoint & UE_ADDR); - - /* check if we should prepend a setup message */ - - if (xfer->flags_int.control_xfr) { - if (xfer->flags_int.control_hdr) { - - temp.func = &atmegadci_setup_rx; - temp.len = xfer->frlengths[0]; - temp.pc = xfer->frbuffers + 0; - temp.short_pkt = temp.len ? 1 : 0; - - atmegadci_setup_standard_chain_sub(&temp); - } - x = 1; - } else { - x = 0; - } - - if (x != xfer->nframes) { - if (xfer->endpoint & UE_DIR_IN) { - temp.func = &atmegadci_data_tx; - need_sync = 1; - } else { - temp.func = &atmegadci_data_rx; - need_sync = 0; - } - - /* setup "pc" pointer */ - temp.pc = xfer->frbuffers + x; - } else { - need_sync = 0; - } - while (x != xfer->nframes) { - - /* DATA0 / DATA1 message */ - - temp.len = xfer->frlengths[x]; - - x++; - - if (x == xfer->nframes) { - temp.setup_alt_next = 0; - } - if (temp.len == 0) { - - /* make sure that we send an USB packet */ - - temp.short_pkt = 0; - - } else { - - /* regular data transfer */ - - temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; - } - - atmegadci_setup_standard_chain_sub(&temp); - - if (xfer->flags_int.isochronous_xfr) { - temp.offset += temp.len; - } else { - /* get next Page Cache pointer */ - temp.pc = xfer->frbuffers + x; - } - } - - /* always setup a valid "pc" pointer for status and sync */ - temp.pc = xfer->frbuffers + 0; - - /* check if we need to sync */ - if (need_sync && xfer->flags_int.control_xfr) { - - /* we need a SYNC point after TX */ - temp.func = &atmegadci_data_tx_sync; - temp.len = 0; - temp.short_pkt = 0; - - atmegadci_setup_standard_chain_sub(&temp); - } - /* check if we should append a status stage */ - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - /* - * Send a DATA1 message and invert the current - * endpoint direction. - */ - if (xfer->endpoint & UE_DIR_IN) { - temp.func = &atmegadci_data_rx; - need_sync = 0; - } else { - temp.func = &atmegadci_data_tx; - need_sync = 1; - } - temp.len = 0; - temp.short_pkt = 0; - - atmegadci_setup_standard_chain_sub(&temp); - if (need_sync) { - /* we need a SYNC point after TX */ - temp.func = &atmegadci_data_tx_sync; - temp.len = 0; - temp.short_pkt = 0; - - atmegadci_setup_standard_chain_sub(&temp); - } - } - /* must have at least one frame! */ - td = temp.td; - xfer->td_transfer_last = td; -} - -static void -atmegadci_timeout(void *arg) -{ - struct usb2_xfer *xfer = arg; - - DPRINTF("xfer=%p\n", xfer); - - USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); - - /* transfer is transferred */ - atmegadci_device_done(xfer, USB_ERR_TIMEOUT); -} - -static void -atmegadci_start_standard_chain(struct usb2_xfer *xfer) -{ - DPRINTFN(9, "\n"); - - /* poll one time - will turn on interrupts */ - if (atmegadci_xfer_do_fifo(xfer)) { - - /* put transfer on interrupt queue */ - usb2_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); - - /* start timeout, if any */ - if (xfer->timeout != 0) { - usb2_transfer_timeout_ms(xfer, - &atmegadci_timeout, xfer->timeout); - } - } -} - -static void -atmegadci_root_intr_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus); - - DPRINTFN(9, "\n"); - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_PRE_DATA) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - atmegadci_device_done(xfer, std->err); - } - goto done; - } - /* setup buffer */ - std->ptr = sc->sc_hub_idata; - std->len = sizeof(sc->sc_hub_idata); - - /* set port bit */ - sc->sc_hub_idata[0] = 0x02; /* we only have one port */ - -done: - return; -} - -static usb2_error_t -atmegadci_standard_done_sub(struct usb2_xfer *xfer) -{ - struct atmegadci_td *td; - uint32_t len; - uint8_t error; - - DPRINTFN(9, "\n"); - - td = xfer->td_transfer_cache; - - do { - len = td->remainder; - - if (xfer->aframes != xfer->nframes) { - /* - * Verify the length and subtract - * the remainder from "frlengths[]": - */ - if (len > xfer->frlengths[xfer->aframes]) { - td->error = 1; - } else { - xfer->frlengths[xfer->aframes] -= len; - } - } - /* Check for transfer error */ - if (td->error) { - /* the transfer is finished */ - error = 1; - td = NULL; - break; - } - /* Check for short transfer */ - if (len > 0) { - if (xfer->flags_int.short_frames_ok) { - /* follow alt next */ - if (td->alt_next) { - td = td->obj_next; - } else { - td = NULL; - } - } else { - /* the transfer is finished */ - td = NULL; - } - error = 0; - break; - } - td = td->obj_next; - - /* this USB frame is complete */ - error = 0; - break; - - } while (0); - - /* update transfer cache */ - - xfer->td_transfer_cache = td; - - return (error ? - USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); -} - -static void -atmegadci_standard_done(struct usb2_xfer *xfer) -{ - usb2_error_t err = 0; - - DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", - xfer, xfer->pipe); - - /* reset scanner */ - - xfer->td_transfer_cache = xfer->td_transfer_first; - - if (xfer->flags_int.control_xfr) { - - if (xfer->flags_int.control_hdr) { - - err = atmegadci_standard_done_sub(xfer); - } - xfer->aframes = 1; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - while (xfer->aframes != xfer->nframes) { - - err = atmegadci_standard_done_sub(xfer); - xfer->aframes++; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - err = atmegadci_standard_done_sub(xfer); - } -done: - atmegadci_device_done(xfer, err); -} - -/*------------------------------------------------------------------------* - * atmegadci_device_done - * - * NOTE: this function can be called more than one time on the - * same USB transfer! - *------------------------------------------------------------------------*/ -static void -atmegadci_device_done(struct usb2_xfer *xfer, usb2_error_t error) -{ - struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus); - uint8_t ep_no; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", - xfer, xfer->pipe, error); - - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { - ep_no = (xfer->endpoint & UE_ADDR); - - /* select endpoint number */ - ATMEGA_WRITE_1(sc, ATMEGA_UENUM, ep_no); - - /* disable endpoint interrupt */ - ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, 0); - - DPRINTFN(15, "disabled interrupts!\n"); - } - /* dequeue transfer and start next transfer */ - usb2_transfer_done(xfer, error); -} - -static void -atmegadci_set_stall(struct usb2_device *udev, struct usb2_xfer *xfer, - struct usb2_pipe *pipe) -{ - struct atmegadci_softc *sc; - uint8_t ep_no; - - USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); - - DPRINTFN(5, "pipe=%p\n", pipe); - - if (xfer) { - /* cancel any ongoing transfers */ - atmegadci_device_done(xfer, USB_ERR_STALLED); - } - sc = ATMEGA_BUS2SC(udev->bus); - /* get endpoint number */ - ep_no = (pipe->edesc->bEndpointAddress & UE_ADDR); - /* select endpoint number */ - ATMEGA_WRITE_1(sc, ATMEGA_UENUM, ep_no); - /* set stall */ - ATMEGA_WRITE_1(sc, ATMEGA_UECONX, - ATMEGA_UECONX_EPEN | - ATMEGA_UECONX_STALLRQ); -} - -static void -atmegadci_clear_stall_sub(struct atmegadci_softc *sc, uint8_t ep_no, - uint8_t ep_type, uint8_t ep_dir) -{ - uint8_t temp; - - if (ep_type == UE_CONTROL) { - /* clearing stall is not needed */ - return; - } - /* select endpoint number */ - ATMEGA_WRITE_1(sc, ATMEGA_UENUM, ep_no); - - /* set endpoint reset */ - ATMEGA_WRITE_1(sc, ATMEGA_UERST, ATMEGA_UERST_MASK(ep_no)); - - /* clear endpoint reset */ - ATMEGA_WRITE_1(sc, ATMEGA_UERST, 0); - - /* set stall */ - ATMEGA_WRITE_1(sc, ATMEGA_UECONX, - ATMEGA_UECONX_EPEN | - ATMEGA_UECONX_STALLRQ); - - /* reset data toggle */ - ATMEGA_WRITE_1(sc, ATMEGA_UECONX, - ATMEGA_UECONX_EPEN | - ATMEGA_UECONX_RSTDT); - - /* clear stall */ - ATMEGA_WRITE_1(sc, ATMEGA_UECONX, - ATMEGA_UECONX_EPEN | - ATMEGA_UECONX_STALLRQC); - - if (ep_type == UE_CONTROL) { - /* one bank, 64-bytes wMaxPacket */ - ATMEGA_WRITE_1(sc, ATMEGA_UECFG0X, - ATMEGA_UECFG0X_EPTYPE0); - ATMEGA_WRITE_1(sc, ATMEGA_UECFG1X, - ATMEGA_UECFG1X_ALLOC | - ATMEGA_UECFG1X_EPBK0 | - ATMEGA_UECFG1X_EPSIZE(7)); - } else { - temp = 0; - if (ep_type == UE_BULK) { - temp |= ATMEGA_UECFG0X_EPTYPE2; - } else if (ep_type == UE_INTERRUPT) { - temp |= ATMEGA_UECFG0X_EPTYPE3; - } else { - temp |= ATMEGA_UECFG0X_EPTYPE1; - } - if (ep_dir & UE_DIR_IN) { - temp |= ATMEGA_UECFG0X_EPDIR; - } - /* two banks, 64-bytes wMaxPacket */ - ATMEGA_WRITE_1(sc, ATMEGA_UECFG0X, temp); - ATMEGA_WRITE_1(sc, ATMEGA_UECFG1X, - ATMEGA_UECFG1X_ALLOC | - ATMEGA_UECFG1X_EPBK1 | - ATMEGA_UECFG1X_EPSIZE(7)); - - temp = ATMEGA_READ_1(sc, ATMEGA_UESTA0X); - if (!(temp & ATMEGA_UESTA0X_CFGOK)) { - DPRINTFN(0, "Chip rejected configuration\n"); - } - } -} - -static void -atmegadci_clear_stall(struct usb2_device *udev, struct usb2_pipe *pipe) -{ - struct atmegadci_softc *sc; - struct usb2_endpoint_descriptor *ed; - - DPRINTFN(5, "pipe=%p\n", pipe); - - USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); - - /* check mode */ - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { - /* not supported */ - return; - } - /* get softc */ - sc = ATMEGA_BUS2SC(udev->bus); - - /* get endpoint descriptor */ - ed = pipe->edesc; - - /* reset endpoint */ - atmegadci_clear_stall_sub(sc, - (ed->bEndpointAddress & UE_ADDR), - (ed->bmAttributes & UE_XFERTYPE), - (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); -} - -usb2_error_t -atmegadci_init(struct atmegadci_softc *sc) -{ - uint8_t n; - - DPRINTF("start\n"); - - /* set up the bus structure */ - sc->sc_bus.usbrev = USB_REV_1_1; - sc->sc_bus.methods = &atmegadci_bus_methods; - - USB_BUS_LOCK(&sc->sc_bus); - - /* enable USB PAD regulator */ - ATMEGA_WRITE_1(sc, ATMEGA_UHWCON, - ATMEGA_UHWCON_UVREGE); - - /* turn on clocks */ - (sc->sc_clocks_on) (&sc->sc_bus); - - /* wait a little for things to stabilise */ - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); - - /* enable interrupts */ - ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, - ATMEGA_UDINT_SUSPE | - ATMEGA_UDINT_EORSTE); - - /* reset all endpoints */ - ATMEGA_WRITE_1(sc, ATMEGA_UERST, - (1 << ATMEGA_EP_MAX) - 1); - - /* disable reset */ - ATMEGA_WRITE_1(sc, ATMEGA_UERST, 0); - - /* disable all endpoints */ - for (n = 1; n != ATMEGA_EP_MAX; n++) { - - /* select endpoint */ - ATMEGA_WRITE_1(sc, ATMEGA_UENUM, n); - - /* disable endpoint interrupt */ - ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, 0); - - /* disable endpoint */ - ATMEGA_WRITE_1(sc, ATMEGA_UECONX, 0); - } - - /* turn off clocks */ - - atmegadci_clocks_off(sc); - - USB_BUS_UNLOCK(&sc->sc_bus); - - /* catch any lost interrupts */ - - atmegadci_do_poll(&sc->sc_bus); - - return (0); /* success */ -} - -void -atmegadci_uninit(struct atmegadci_softc *sc) -{ - USB_BUS_LOCK(&sc->sc_bus); - - /* turn on clocks */ - (sc->sc_clocks_on) (&sc->sc_bus); - - /* disable interrupts */ - ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, 0); - - /* reset all endpoints */ - ATMEGA_WRITE_1(sc, ATMEGA_UERST, - (1 << ATMEGA_EP_MAX) - 1); - - /* disable reset */ - ATMEGA_WRITE_1(sc, ATMEGA_UERST, 0); - - sc->sc_flags.port_powered = 0; - sc->sc_flags.status_vbus = 0; - sc->sc_flags.status_bus_reset = 0; - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 0; - sc->sc_flags.change_connect = 1; - - atmegadci_pull_down(sc); - atmegadci_clocks_off(sc); - - /* disable USB PAD regulator */ - ATMEGA_WRITE_1(sc, ATMEGA_UHWCON, 0); - - USB_BUS_UNLOCK(&sc->sc_bus); -} - -void -atmegadci_suspend(struct atmegadci_softc *sc) -{ - return; -} - -void -atmegadci_resume(struct atmegadci_softc *sc) -{ - return; -} - -static void -atmegadci_do_poll(struct usb2_bus *bus) -{ - struct atmegadci_softc *sc = ATMEGA_BUS2SC(bus); - - USB_BUS_LOCK(&sc->sc_bus); - atmegadci_interrupt_poll(sc); - atmegadci_root_ctrl_poll(sc); - USB_BUS_UNLOCK(&sc->sc_bus); -} - -/*------------------------------------------------------------------------* - * at91dci bulk support - *------------------------------------------------------------------------*/ -static void -atmegadci_device_bulk_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_device_bulk_close(struct usb2_xfer *xfer) -{ - atmegadci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -atmegadci_device_bulk_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_device_bulk_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - atmegadci_setup_standard_chain(xfer); - atmegadci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods atmegadci_device_bulk_methods = -{ - .open = atmegadci_device_bulk_open, - .close = atmegadci_device_bulk_close, - .enter = atmegadci_device_bulk_enter, - .start = atmegadci_device_bulk_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci control support - *------------------------------------------------------------------------*/ -static void -atmegadci_device_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_device_ctrl_close(struct usb2_xfer *xfer) -{ - atmegadci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -atmegadci_device_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_device_ctrl_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - atmegadci_setup_standard_chain(xfer); - atmegadci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods atmegadci_device_ctrl_methods = -{ - .open = atmegadci_device_ctrl_open, - .close = atmegadci_device_ctrl_close, - .enter = atmegadci_device_ctrl_enter, - .start = atmegadci_device_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci interrupt support - *------------------------------------------------------------------------*/ -static void -atmegadci_device_intr_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_device_intr_close(struct usb2_xfer *xfer) -{ - atmegadci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -atmegadci_device_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_device_intr_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - atmegadci_setup_standard_chain(xfer); - atmegadci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods atmegadci_device_intr_methods = -{ - .open = atmegadci_device_intr_open, - .close = atmegadci_device_intr_close, - .enter = atmegadci_device_intr_enter, - .start = atmegadci_device_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci full speed isochronous support - *------------------------------------------------------------------------*/ -static void -atmegadci_device_isoc_fs_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_device_isoc_fs_close(struct usb2_xfer *xfer) -{ - atmegadci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -atmegadci_device_isoc_fs_enter(struct usb2_xfer *xfer) -{ - struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus); - uint32_t temp; - uint32_t nframes; - - DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", - xfer, xfer->pipe->isoc_next, xfer->nframes); - - /* get the current frame index */ - - nframes = - (ATMEGA_READ_1(sc, ATMEGA_UDFNUMH) << 8) | - (ATMEGA_READ_1(sc, ATMEGA_UDFNUML)); - - nframes &= ATMEGA_FRAME_MASK; - - /* - * check if the frame index is within the window where the frames - * will be inserted - */ - temp = (nframes - xfer->pipe->isoc_next) & ATMEGA_FRAME_MASK; - - if ((xfer->pipe->is_synced == 0) || - (temp < xfer->nframes)) { - /* - * If there is data underflow or the pipe queue is - * empty we schedule the transfer a few frames ahead - * of the current frame position. Else two isochronous - * transfers might overlap. - */ - xfer->pipe->isoc_next = (nframes + 3) & ATMEGA_FRAME_MASK; - xfer->pipe->is_synced = 1; - DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next); - } - /* - * compute how many milliseconds the insertion is ahead of the - * current frame position: - */ - temp = (xfer->pipe->isoc_next - nframes) & ATMEGA_FRAME_MASK; - - /* - * pre-compute when the isochronous transfer will be finished: - */ - xfer->isoc_time_complete = - usb2_isoc_time_expand(&sc->sc_bus, nframes) + temp + - xfer->nframes; - - /* compute frame number for next insertion */ - xfer->pipe->isoc_next += xfer->nframes; - - /* setup TDs */ - atmegadci_setup_standard_chain(xfer); -} - -static void -atmegadci_device_isoc_fs_start(struct usb2_xfer *xfer) -{ - /* start TD chain */ - atmegadci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods atmegadci_device_isoc_fs_methods = -{ - .open = atmegadci_device_isoc_fs_open, - .close = atmegadci_device_isoc_fs_close, - .enter = atmegadci_device_isoc_fs_enter, - .start = atmegadci_device_isoc_fs_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci root control support - *------------------------------------------------------------------------* - * simulate a hardware HUB by handling - * all the necessary requests - *------------------------------------------------------------------------*/ - -static void -atmegadci_root_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_root_ctrl_close(struct usb2_xfer *xfer) -{ - struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_ctrl.xfer == xfer) { - sc->sc_root_ctrl.xfer = NULL; - } - atmegadci_device_done(xfer, USB_ERR_CANCELLED); -} - -/* - * USB descriptors for the virtual Root HUB: - */ - -static const struct usb2_device_descriptor atmegadci_devd = { - .bLength = sizeof(struct usb2_device_descriptor), - .bDescriptorType = UDESC_DEVICE, - .bcdUSB = {0x00, 0x02}, - .bDeviceClass = UDCLASS_HUB, - .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_HSHUBSTT, - .bMaxPacketSize = 64, - .bcdDevice = {0x00, 0x01}, - .iManufacturer = 1, - .iProduct = 2, - .bNumConfigurations = 1, -}; - -static const struct usb2_device_qualifier atmegadci_odevd = { - .bLength = sizeof(struct usb2_device_qualifier), - .bDescriptorType = UDESC_DEVICE_QUALIFIER, - .bcdUSB = {0x00, 0x02}, - .bDeviceClass = UDCLASS_HUB, - .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_FSHUB, - .bMaxPacketSize0 = 0, - .bNumConfigurations = 0, -}; - -static const struct atmegadci_config_desc atmegadci_confd = { - .confd = { - .bLength = sizeof(struct usb2_config_descriptor), - .bDescriptorType = UDESC_CONFIG, - .wTotalLength[0] = sizeof(atmegadci_confd), - .bNumInterface = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = UC_SELF_POWERED, - .bMaxPower = 0, - }, - .ifcd = { - .bLength = sizeof(struct usb2_interface_descriptor), - .bDescriptorType = UDESC_INTERFACE, - .bNumEndpoints = 1, - .bInterfaceClass = UICLASS_HUB, - .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_HSHUBSTT, - }, - - .endpd = { - .bLength = sizeof(struct usb2_endpoint_descriptor), - .bDescriptorType = UDESC_ENDPOINT, - .bEndpointAddress = (UE_DIR_IN | ATMEGA_INTR_ENDPT), - .bmAttributes = UE_INTERRUPT, - .wMaxPacketSize[0] = 8, - .bInterval = 255, - }, -}; - -static const struct usb2_hub_descriptor_min atmegadci_hubd = { - .bDescLength = sizeof(atmegadci_hubd), - .bDescriptorType = UDESC_HUB, - .bNbrPorts = 1, - .wHubCharacteristics[0] = - (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) & 0xFF, - .wHubCharacteristics[1] = - (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) >> 8, - .bPwrOn2PwrGood = 50, - .bHubContrCurrent = 0, - .DeviceRemovable = {0}, /* port is removable */ -}; - -#define STRING_LANG \ - 0x09, 0x04, /* American English */ - -#define STRING_VENDOR \ - 'A', 0, 'T', 0, 'M', 0, 'E', 0, 'G', 0, 'A', 0 - -#define STRING_PRODUCT \ - 'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \ - 'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \ - 'U', 0, 'B', 0, - -USB_MAKE_STRING_DESC(STRING_LANG, atmegadci_langtab); -USB_MAKE_STRING_DESC(STRING_VENDOR, atmegadci_vendor); -USB_MAKE_STRING_DESC(STRING_PRODUCT, atmegadci_product); - -static void -atmegadci_root_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_root_ctrl_start(struct usb2_xfer *xfer) -{ - struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus); - - sc->sc_root_ctrl.xfer = xfer; - - usb2_bus_roothub_exec(xfer->xroot->bus); -} - -static void -atmegadci_root_ctrl_task(struct usb2_bus *bus) -{ - atmegadci_root_ctrl_poll(ATMEGA_BUS2SC(bus)); -} - -static void -atmegadci_root_ctrl_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus); - uint16_t value; - uint16_t index; - uint8_t use_polling; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_SETUP) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - atmegadci_device_done(xfer, std->err); - } - goto done; - } - /* buffer reset */ - std->ptr = USB_ADD_BYTES(&sc->sc_hub_temp, 0); - std->len = 0; - - value = UGETW(std->req.wValue); - index = UGETW(std->req.wIndex); - - use_polling = mtx_owned(xfer->xroot->xfer_mtx) ? 1 : 0; - - /* demultiplex the control request */ - - switch (std->req.bmRequestType) { - case UT_READ_DEVICE: - switch (std->req.bRequest) { - case UR_GET_DESCRIPTOR: - goto tr_handle_get_descriptor; - case UR_GET_CONFIG: - goto tr_handle_get_config; - case UR_GET_STATUS: - goto tr_handle_get_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_DEVICE: - switch (std->req.bRequest) { - case UR_SET_ADDRESS: - goto tr_handle_set_address; - case UR_SET_CONFIG: - goto tr_handle_set_config; - case UR_CLEAR_FEATURE: - goto tr_valid; /* nop */ - case UR_SET_DESCRIPTOR: - goto tr_valid; /* nop */ - case UR_SET_FEATURE: - default: - goto tr_stalled; - } - break; - - case UT_WRITE_ENDPOINT: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - switch (UGETW(std->req.wValue)) { - case UF_ENDPOINT_HALT: - goto tr_handle_clear_halt; - case UF_DEVICE_REMOTE_WAKEUP: - goto tr_handle_clear_wakeup; - default: - goto tr_stalled; - } - break; - case UR_SET_FEATURE: - switch (UGETW(std->req.wValue)) { - case UF_ENDPOINT_HALT: - goto tr_handle_set_halt; - case UF_DEVICE_REMOTE_WAKEUP: - goto tr_handle_set_wakeup; - default: - goto tr_stalled; - } - break; - case UR_SYNCH_FRAME: - goto tr_valid; /* nop */ - default: - goto tr_stalled; - } - break; - - case UT_READ_ENDPOINT: - switch (std->req.bRequest) { - case UR_GET_STATUS: - goto tr_handle_get_ep_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_INTERFACE: - switch (std->req.bRequest) { - case UR_SET_INTERFACE: - goto tr_handle_set_interface; - case UR_CLEAR_FEATURE: - goto tr_valid; /* nop */ - case UR_SET_FEATURE: - default: - goto tr_stalled; - } - break; - - case UT_READ_INTERFACE: - switch (std->req.bRequest) { - case UR_GET_INTERFACE: - goto tr_handle_get_interface; - case UR_GET_STATUS: - goto tr_handle_get_iface_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_CLASS_INTERFACE: - case UT_WRITE_VENDOR_INTERFACE: - /* XXX forward */ - break; - - case UT_READ_CLASS_INTERFACE: - case UT_READ_VENDOR_INTERFACE: - /* XXX forward */ - break; - - case UT_WRITE_CLASS_DEVICE: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - goto tr_valid; - case UR_SET_DESCRIPTOR: - case UR_SET_FEATURE: - break; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_CLASS_OTHER: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - goto tr_handle_clear_port_feature; - case UR_SET_FEATURE: - goto tr_handle_set_port_feature; - case UR_CLEAR_TT_BUFFER: - case UR_RESET_TT: - case UR_STOP_TT: - goto tr_valid; - - default: - goto tr_stalled; - } - break; - - case UT_READ_CLASS_OTHER: - switch (std->req.bRequest) { - case UR_GET_TT_STATE: - goto tr_handle_get_tt_state; - case UR_GET_STATUS: - goto tr_handle_get_port_status; - default: - goto tr_stalled; - } - break; - - case UT_READ_CLASS_DEVICE: - switch (std->req.bRequest) { - case UR_GET_DESCRIPTOR: - goto tr_handle_get_class_descriptor; - case UR_GET_STATUS: - goto tr_handle_get_class_status; - - default: - goto tr_stalled; - } - break; - default: - goto tr_stalled; - } - goto tr_valid; - -tr_handle_get_descriptor: - switch (value >> 8) { - case UDESC_DEVICE: - if (value & 0xff) { - goto tr_stalled; - } - std->len = sizeof(atmegadci_devd); - std->ptr = USB_ADD_BYTES(&atmegadci_devd, 0); - goto tr_valid; - case UDESC_CONFIG: - if (value & 0xff) { - goto tr_stalled; - } - std->len = sizeof(atmegadci_confd); - std->ptr = USB_ADD_BYTES(&atmegadci_confd, 0); - goto tr_valid; - case UDESC_STRING: - switch (value & 0xff) { - case 0: /* Language table */ - std->len = sizeof(atmegadci_langtab); - std->ptr = USB_ADD_BYTES(&atmegadci_langtab, 0); - goto tr_valid; - - case 1: /* Vendor */ - std->len = sizeof(atmegadci_vendor); - std->ptr = USB_ADD_BYTES(&atmegadci_vendor, 0); - goto tr_valid; - - case 2: /* Product */ - std->len = sizeof(atmegadci_product); - std->ptr = USB_ADD_BYTES(&atmegadci_product, 0); - goto tr_valid; - default: - break; - } - break; - default: - goto tr_stalled; - } - goto tr_stalled; - -tr_handle_get_config: - std->len = 1; - sc->sc_hub_temp.wValue[0] = sc->sc_conf; - goto tr_valid; - -tr_handle_get_status: - std->len = 2; - USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); - goto tr_valid; - -tr_handle_set_address: - if (value & 0xFF00) { - goto tr_stalled; - } - sc->sc_rt_addr = value; - goto tr_valid; - -tr_handle_set_config: - if (value >= 2) { - goto tr_stalled; - } - sc->sc_conf = value; - goto tr_valid; - -tr_handle_get_interface: - std->len = 1; - sc->sc_hub_temp.wValue[0] = 0; - goto tr_valid; - -tr_handle_get_tt_state: -tr_handle_get_class_status: -tr_handle_get_iface_status: -tr_handle_get_ep_status: - std->len = 2; - USETW(sc->sc_hub_temp.wValue, 0); - goto tr_valid; - -tr_handle_set_halt: -tr_handle_set_interface: -tr_handle_set_wakeup: -tr_handle_clear_wakeup: -tr_handle_clear_halt: - goto tr_valid; - -tr_handle_clear_port_feature: - if (index != 1) { - goto tr_stalled; - } - DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index); - - switch (value) { - case UHF_PORT_SUSPEND: - atmegadci_wakeup_peer(xfer); - break; - - case UHF_PORT_ENABLE: - sc->sc_flags.port_enabled = 0; - break; - - case UHF_PORT_TEST: - case UHF_PORT_INDICATOR: - case UHF_C_PORT_ENABLE: - case UHF_C_PORT_OVER_CURRENT: - case UHF_C_PORT_RESET: - /* nops */ - break; - case UHF_PORT_POWER: - sc->sc_flags.port_powered = 0; - atmegadci_pull_down(sc); - atmegadci_clocks_off(sc); - break; - case UHF_C_PORT_CONNECTION: - sc->sc_flags.change_connect = 0; - break; - case UHF_C_PORT_SUSPEND: - sc->sc_flags.change_suspend = 0; - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - goto tr_valid; - -tr_handle_set_port_feature: - if (index != 1) { - goto tr_stalled; - } - DPRINTFN(9, "UR_SET_PORT_FEATURE\n"); - - switch (value) { - case UHF_PORT_ENABLE: - sc->sc_flags.port_enabled = 1; - break; - case UHF_PORT_SUSPEND: - case UHF_PORT_RESET: - case UHF_PORT_TEST: - case UHF_PORT_INDICATOR: - /* nops */ - break; - case UHF_PORT_POWER: - sc->sc_flags.port_powered = 1; - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - goto tr_valid; - -tr_handle_get_port_status: - - DPRINTFN(9, "UR_GET_PORT_STATUS\n"); - - if (index != 1) { - goto tr_stalled; - } - if (sc->sc_flags.status_vbus) { - atmegadci_clocks_on(sc); - atmegadci_pull_up(sc); - } else { - atmegadci_pull_down(sc); - atmegadci_clocks_off(sc); - } - - /* Select FULL-speed and Device Side Mode */ - - value = UPS_PORT_MODE_DEVICE; - - if (sc->sc_flags.port_powered) { - value |= UPS_PORT_POWER; - } - if (sc->sc_flags.port_enabled) { - value |= UPS_PORT_ENABLED; - } - if (sc->sc_flags.status_vbus && - sc->sc_flags.status_bus_reset) { - value |= UPS_CURRENT_CONNECT_STATUS; - } - if (sc->sc_flags.status_suspend) { - value |= UPS_SUSPEND; - } - USETW(sc->sc_hub_temp.ps.wPortStatus, value); - - value = 0; - - if (sc->sc_flags.change_connect) { - value |= UPS_C_CONNECT_STATUS; - } - if (sc->sc_flags.change_suspend) { - value |= UPS_C_SUSPEND; - } - USETW(sc->sc_hub_temp.ps.wPortChange, value); - std->len = sizeof(sc->sc_hub_temp.ps); - goto tr_valid; - -tr_handle_get_class_descriptor: - if (value & 0xFF) { - goto tr_stalled; - } - std->ptr = USB_ADD_BYTES(&atmegadci_hubd, 0); - std->len = sizeof(atmegadci_hubd); - goto tr_valid; - -tr_stalled: - std->err = USB_ERR_STALLED; -tr_valid: -done: - return; -} - -static void -atmegadci_root_ctrl_poll(struct atmegadci_softc *sc) -{ - usb2_sw_transfer(&sc->sc_root_ctrl, - &atmegadci_root_ctrl_done); -} - -struct usb2_pipe_methods atmegadci_root_ctrl_methods = -{ - .open = atmegadci_root_ctrl_open, - .close = atmegadci_root_ctrl_close, - .enter = atmegadci_root_ctrl_enter, - .start = atmegadci_root_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 0, -}; - -/*------------------------------------------------------------------------* - * at91dci root interrupt support - *------------------------------------------------------------------------*/ -static void -atmegadci_root_intr_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_root_intr_close(struct usb2_xfer *xfer) -{ - struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_intr.xfer == xfer) { - sc->sc_root_intr.xfer = NULL; - } - atmegadci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -atmegadci_root_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_root_intr_start(struct usb2_xfer *xfer) -{ - struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus); - - sc->sc_root_intr.xfer = xfer; -} - -struct usb2_pipe_methods atmegadci_root_intr_methods = -{ - .open = atmegadci_root_intr_open, - .close = atmegadci_root_intr_close, - .enter = atmegadci_root_intr_enter, - .start = atmegadci_root_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -static void -atmegadci_xfer_setup(struct usb2_setup_params *parm) -{ - const struct usb2_hw_ep_profile *pf; - struct atmegadci_softc *sc; - struct usb2_xfer *xfer; - void *last_obj; - uint32_t ntd; - uint32_t n; - uint8_t ep_no; - - sc = ATMEGA_BUS2SC(parm->udev->bus); - xfer = parm->curr_xfer; - - /* - * NOTE: This driver does not use any of the parameters that - * are computed from the following values. Just set some - * reasonable dummies: - */ - parm->hc_max_packet_size = 0x500; - parm->hc_max_packet_count = 1; - parm->hc_max_frame_size = 0x500; - - usb2_transfer_setup_sub(parm); - - /* - * compute maximum number of TDs - */ - if (parm->methods == &atmegadci_device_ctrl_methods) { - - ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */ - + 1 /* SYNC 2 */ ; - - } else if (parm->methods == &atmegadci_device_bulk_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else if (parm->methods == &atmegadci_device_intr_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else if (parm->methods == &atmegadci_device_isoc_fs_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else { - - ntd = 0; - } - - /* - * check if "usb2_transfer_setup_sub" set an error - */ - if (parm->err) { - return; - } - /* - * allocate transfer descriptors - */ - last_obj = NULL; - - /* - * get profile stuff - */ - if (ntd) { - - ep_no = xfer->endpoint & UE_ADDR; - atmegadci_get_hw_ep_profile(parm->udev, &pf, ep_no); - - if (pf == NULL) { - /* should not happen */ - parm->err = USB_ERR_INVAL; - return; - } - } else { - ep_no = 0; - pf = NULL; - } - - /* align data */ - parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); - - for (n = 0; n != ntd; n++) { - - struct atmegadci_td *td; - - if (parm->buf) { - - td = USB_ADD_BYTES(parm->buf, parm->size[0]); - - /* init TD */ - td->max_packet_size = xfer->max_packet_size; - td->ep_no = ep_no; - if (pf->support_multi_buffer) { - td->support_multi_buffer = 1; - } - td->obj_next = last_obj; - - last_obj = td; - } - parm->size[0] += sizeof(*td); - } - - xfer->td_start[0] = last_obj; -} - -static void -atmegadci_xfer_unsetup(struct usb2_xfer *xfer) -{ - return; -} - -static void -atmegadci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, - struct usb2_pipe *pipe) -{ - struct atmegadci_softc *sc = ATMEGA_BUS2SC(udev->bus); - - DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", - pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, - sc->sc_rt_addr); - - if (udev->device_index == sc->sc_rt_addr) { - - if (udev->flags.usb2_mode != USB_MODE_HOST) { - /* not supported */ - return; - } - switch (edesc->bEndpointAddress) { - case USB_CONTROL_ENDPOINT: - pipe->methods = &atmegadci_root_ctrl_methods; - break; - case UE_DIR_IN | ATMEGA_INTR_ENDPT: - pipe->methods = &atmegadci_root_intr_methods; - break; - default: - /* do nothing */ - break; - } - } else { - - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { - /* not supported */ - return; - } - if (udev->speed != USB_SPEED_FULL) { - /* not supported */ - return; - } - switch (edesc->bmAttributes & UE_XFERTYPE) { - case UE_CONTROL: - pipe->methods = &atmegadci_device_ctrl_methods; - break; - case UE_INTERRUPT: - pipe->methods = &atmegadci_device_intr_methods; - break; - case UE_ISOCHRONOUS: - pipe->methods = &atmegadci_device_isoc_fs_methods; - break; - case UE_BULK: - pipe->methods = &atmegadci_device_bulk_methods; - break; - default: - /* do nothing */ - break; - } - } -} - -struct usb2_bus_methods atmegadci_bus_methods = -{ - .pipe_init = &atmegadci_pipe_init, - .xfer_setup = &atmegadci_xfer_setup, - .xfer_unsetup = &atmegadci_xfer_unsetup, - .do_poll = &atmegadci_do_poll, - .get_hw_ep_profile = &atmegadci_get_hw_ep_profile, - .set_stall = &atmegadci_set_stall, - .clear_stall = &atmegadci_clear_stall, - .roothub_exec = &atmegadci_root_ctrl_task, -}; diff --git a/sys/dev/usb2/controller/atmegadci.h b/sys/dev/usb2/controller/atmegadci.h deleted file mode 100644 index 90b3334..0000000 --- a/sys/dev/usb2/controller/atmegadci.h +++ /dev/null @@ -1,273 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * USB Device Port register definitions, copied from ATMEGA - * documentation provided by ATMEL. - */ - -#ifndef _ATMEGADCI_H_ -#define _ATMEGADCI_H_ - -#define ATMEGA_MAX_DEVICES (USB_MIN_DEVICES + 1) - -#ifndef ATMEGA_HAVE_BUS_SPACE -#define ATMEGA_HAVE_BUS_SPACE 1 -#endif - -#define ATMEGA_UEINT 0xF4 -#define ATMEGA_UEINT_MASK(n) (1 << (n)) /* endpoint interrupt mask */ - -#define ATMEGA_UEBCHX 0xF3 /* FIFO byte count high */ -#define ATMEGA_UEBCLX 0xF2 /* FIFO byte count low */ -#define ATMEGA_UEDATX 0xF1 /* FIFO data */ - -#define ATMEGA_UEIENX 0xF0 /* interrupt enable register */ -#define ATMEGA_UEIENX_TXINE (1 << 0) -#define ATMEGA_UEIENX_STALLEDE (1 << 1) -#define ATMEGA_UEIENX_RXOUTE (1 << 2) -#define ATMEGA_UEIENX_RXSTPE (1 << 3) /* received SETUP packet */ -#define ATMEGA_UEIENX_NAKOUTE (1 << 4) -#define ATMEGA_UEIENX_NAKINE (1 << 6) -#define ATMEGA_UEIENX_FLERRE (1 << 7) - -#define ATMEGA_UESTA1X 0xEF -#define ATMEGA_UESTA1X_CURRBK (3 << 0) /* current bank */ -#define ATMEGA_UESTA1X_CTRLDIR (1 << 2) /* control endpoint direction */ - -#define ATMEGA_UESTA0X 0xEE -#define ATMEGA_UESTA0X_NBUSYBK (3 << 0) -#define ATMEGA_UESTA0X_DTSEQ (3 << 2) -#define ATMEGA_UESTA0X_UNDERFI (1 << 5) /* underflow */ -#define ATMEGA_UESTA0X_OVERFI (1 << 6) /* overflow */ -#define ATMEGA_UESTA0X_CFGOK (1 << 7) - -#define ATMEGA_UECFG1X 0xED /* endpoint config register */ -#define ATMEGA_UECFG1X_ALLOC (1 << 1) -#define ATMEGA_UECFG1X_EPBK0 (0 << 2) -#define ATMEGA_UECFG1X_EPBK1 (1 << 2) -#define ATMEGA_UECFG1X_EPBK2 (2 << 2) -#define ATMEGA_UECFG1X_EPBK3 (3 << 2) -#define ATMEGA_UECFG1X_EPSIZE(n) ((n) << 4) - -#define ATMEGA_UECFG0X 0xEC -#define ATMEGA_UECFG0X_EPDIR (1 << 0) /* endpoint direction */ -#define ATMEGA_UECFG0X_EPTYPE0 (0 << 6) -#define ATMEGA_UECFG0X_EPTYPE1 (1 << 6) -#define ATMEGA_UECFG0X_EPTYPE2 (2 << 6) -#define ATMEGA_UECFG0X_EPTYPE3 (3 << 6) - -#define ATMEGA_UECONX 0xEB -#define ATMEGA_UECONX_EPEN (1 << 0) -#define ATMEGA_UECONX_RSTDT (1 << 3) -#define ATMEGA_UECONX_STALLRQC (1 << 4) /* stall request clear */ -#define ATMEGA_UECONX_STALLRQ (1 << 5) /* stall request set */ - -#define ATMEGA_UERST 0xEA /* endpoint reset register */ -#define ATMEGA_UERST_MASK(n) (1 << (n)) - -#define ATMEGA_UENUM 0xE9 /* endpoint number */ - -#define ATMEGA_UEINTX 0xE8 /* interrupt register */ -#define ATMEGA_UEINTX_TXINI (1 << 0) -#define ATMEGA_UEINTX_STALLEDI (1 << 1) -#define ATMEGA_UEINTX_RXOUTI (1 << 2) -#define ATMEGA_UEINTX_RXSTPI (1 << 3) /* received setup packet */ -#define ATMEGA_UEINTX_NAKOUTI (1 << 4) -#define ATMEGA_UEINTX_RWAL (1 << 5) -#define ATMEGA_UEINTX_NAKINI (1 << 6) -#define ATMEGA_UEINTX_FIFOCON (1 << 7) - -#define ATMEGA_UDMFN 0xE6 -#define ATMEGA_UDMFN_FNCERR (1 << 4) - -#define ATMEGA_UDFNUMH 0xE5 /* frame number high */ -#define ATMEGA_UDFNUMH_MASK 7 - -#define ATMEGA_UDFNUML 0xE4 /* frame number low */ -#define ATMEGA_UDFNUML_MASK 0xFF - -#define ATMEGA_FRAME_MASK 0x7FF - -#define ATMEGA_UDADDR 0xE3 /* USB address */ -#define ATMEGA_UDADDR_MASK 0x7F -#define ATMEGA_UDADDR_ADDEN (1 << 7) - -#define ATMEGA_UDIEN 0xE2 /* USB device interrupt enable */ -#define ATMEGA_UDINT_SUSPE (1 << 0) -#define ATMEGA_UDINT_MSOFE (1 << 1) -#define ATMEGA_UDINT_SOFE (1 << 2) -#define ATMEGA_UDINT_EORSTE (1 << 3) -#define ATMEGA_UDINT_WAKEUPE (1 << 4) -#define ATMEGA_UDINT_EORSME (1 << 5) -#define ATMEGA_UDINT_UPRSME (1 << 6) - -#define ATMEGA_UDINT 0xE1 /* USB device interrupt status */ -#define ATMEGA_UDINT_SUSPI (1 << 0) -#define ATMEGA_UDINT_MSOFI (1 << 1) -#define ATMEGA_UDINT_SOFI (1 << 2) -#define ATMEGA_UDINT_EORSTI (1 << 3) -#define ATMEGA_UDINT_WAKEUPI (1 << 4) -#define ATMEGA_UDINT_EORSMI (1 << 5) -#define ATMEGA_UDINT_UPRSMI (1 << 6) - -#define ATMEGA_UDCON 0xE0 /* USB device connection register */ -#define ATMEGA_UDCON_DETACH (1 << 0) -#define ATMEGA_UDCON_RMWKUP (1 << 1) -#define ATMEGA_UDCON_LSM (1 << 2) -#define ATMEGA_UDCON_RSTCPU (1 << 3) - -#define ATMEGA_USBINT 0xDA -#define ATMEGA_USBINT_VBUSTI (1 << 0) /* USB VBUS interrupt */ - -#define ATMEGA_USBSTA 0xD9 -#define ATMEGA_USBSTA_VBUS (1 << 0) -#define ATMEGA_USBSTA_ID (1 << 1) - -#define ATMEGA_USBCON 0xD8 -#define ATMEGA_USBCON_VBUSTE (1 << 0) -#define ATMEGA_USBCON_OTGPADE (1 << 4) -#define ATMEGA_USBCON_FRZCLK (1 << 5) -#define ATMEGA_USBCON_USBE (1 << 7) - -#define ATMEGA_UHWCON 0xD7 -#define ATMEGA_UHWCON_UVREGE (1 << 0) - -#define ATMEGA_READ_1(sc, reg) \ - bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg) - -#define ATMEGA_WRITE_1(sc, reg, data) \ - bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data) - -#define ATMEGA_WRITE_MULTI_1(sc, reg, ptr, len) \ - bus_space_write_multi_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, ptr, len) - -#define ATMEGA_READ_MULTI_1(sc, reg, ptr, len) \ - bus_space_read_multi_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, ptr, len) - -/* - * Maximum number of endpoints supported: - */ -#define ATMEGA_EP_MAX 7 - -struct atmegadci_td; - -typedef uint8_t (atmegadci_cmd_t)(struct atmegadci_td *td); -typedef void (atmegadci_clocks_t)(struct usb2_bus *); - -struct atmegadci_td { - struct atmegadci_td *obj_next; - atmegadci_cmd_t *func; - struct usb2_page_cache *pc; - uint32_t offset; - uint32_t remainder; - uint16_t max_packet_size; - uint8_t error:1; - uint8_t alt_next:1; - uint8_t short_pkt:1; - uint8_t support_multi_buffer:1; - uint8_t did_stall:1; - uint8_t ep_no:3; -}; - -struct atmegadci_std_temp { - atmegadci_cmd_t *func; - struct usb2_page_cache *pc; - struct atmegadci_td *td; - struct atmegadci_td *td_next; - uint32_t len; - uint32_t offset; - uint16_t max_frame_size; - uint8_t short_pkt; - /* - * short_pkt = 0: transfer should be short terminated - * short_pkt = 1: transfer should not be short terminated - */ - uint8_t setup_alt_next; -}; - -struct atmegadci_config_desc { - struct usb2_config_descriptor confd; - struct usb2_interface_descriptor ifcd; - struct usb2_endpoint_descriptor endpd; -} __packed; - -union atmegadci_hub_temp { - uWord wValue; - struct usb2_port_status ps; -}; - -struct atmegadci_flags { - uint8_t change_connect:1; - uint8_t change_suspend:1; - uint8_t status_suspend:1; /* set if suspended */ - uint8_t status_vbus:1; /* set if present */ - uint8_t status_bus_reset:1; /* set if reset complete */ - uint8_t remote_wakeup:1; - uint8_t self_powered:1; - uint8_t clocks_off:1; - uint8_t port_powered:1; - uint8_t port_enabled:1; - uint8_t d_pulled_up:1; -}; - -struct atmegadci_softc { - struct usb2_bus sc_bus; - union atmegadci_hub_temp sc_hub_temp; - LIST_HEAD(, usb2_xfer) sc_interrupt_list_head; - struct usb2_sw_transfer sc_root_ctrl; - struct usb2_sw_transfer sc_root_intr; - - /* must be set by by the bus interface layer */ - atmegadci_clocks_t *sc_clocks_on; - atmegadci_clocks_t *sc_clocks_off; - - struct usb2_device *sc_devices[ATMEGA_MAX_DEVICES]; - struct resource *sc_irq_res; - void *sc_intr_hdl; -#if (ATMEGA_HAVE_BUS_SPACE != 0) - struct resource *sc_io_res; - bus_space_tag_t sc_io_tag; - bus_space_handle_t sc_io_hdl; -#endif - uint8_t sc_rt_addr; /* root hub address */ - uint8_t sc_dv_addr; /* device address */ - uint8_t sc_conf; /* root hub config */ - - uint8_t sc_hub_idata[1]; - - struct atmegadci_flags sc_flags; -}; - -/* prototypes */ - -usb2_error_t atmegadci_init(struct atmegadci_softc *sc); -void atmegadci_uninit(struct atmegadci_softc *sc); -void atmegadci_suspend(struct atmegadci_softc *sc); -void atmegadci_resume(struct atmegadci_softc *sc); -void atmegadci_interrupt(struct atmegadci_softc *sc); - -#endif /* _ATMEGADCI_H_ */ diff --git a/sys/dev/usb2/controller/atmegadci_atmelarm.c b/sys/dev/usb2/controller/atmegadci_atmelarm.c deleted file mode 100644 index e63f5cc..0000000 --- a/sys/dev/usb2/controller/atmegadci_atmelarm.c +++ /dev/null @@ -1,27 +0,0 @@ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/*- - * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ diff --git a/sys/dev/usb2/controller/ehci2.c b/sys/dev/usb2/controller/ehci2.c deleted file mode 100644 index 87a6d03..0000000 --- a/sys/dev/usb2/controller/ehci2.c +++ /dev/null @@ -1,3965 +0,0 @@ -/*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. - * Copyright (c) 2004 The NetBSD Foundation, Inc. All rights reserved. - * Copyright (c) 2004 Lennart Augustsson. All rights reserved. - * Copyright (c) 2004 Charles M. Hannum. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller. - * - * The EHCI 0.96 spec can be found at - * http://developer.intel.com/technology/usb/download/ehci-r096.pdf - * The EHCI 1.0 spec can be found at - * http://developer.intel.com/technology/usb/download/ehci-r10.pdf - * and the USB 2.0 spec at - * http://www.usb.org/developers/docs/usb_20.zip - * - */ - -/* - * TODO: - * 1) command failures are not recovered correctly - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <dev/usb2/include/usb2_standard.h> -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_error.h> -#include <dev/usb2/include/usb2_defs.h> - -#define USB_DEBUG_VAR ehcidebug - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_debug.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_transfer.h> -#include <dev/usb2/core/usb2_device.h> -#include <dev/usb2/core/usb2_hub.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/ehci2.h> - -#define EHCI_BUS2SC(bus) ((ehci_softc_t *)(((uint8_t *)(bus)) - \ - USB_P2U(&(((ehci_softc_t *)0)->sc_bus)))) - -#if USB_DEBUG -static int ehcidebug = 0; -static int ehcinohighspeed = 0; - -SYSCTL_NODE(_hw_usb2, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci"); -SYSCTL_INT(_hw_usb2_ehci, OID_AUTO, debug, CTLFLAG_RW, - &ehcidebug, 0, "Debug level"); -SYSCTL_INT(_hw_usb2_ehci, OID_AUTO, no_hs, CTLFLAG_RW, - &ehcinohighspeed, 0, "Disable High Speed USB"); - -static void ehci_dump_regs(ehci_softc_t *sc); -static void ehci_dump_sqh(ehci_softc_t *sc, ehci_qh_t *sqh); - -#endif - -#define EHCI_INTR_ENDPT 1 - -extern struct usb2_bus_methods ehci_bus_methods; -extern struct usb2_pipe_methods ehci_device_bulk_methods; -extern struct usb2_pipe_methods ehci_device_ctrl_methods; -extern struct usb2_pipe_methods ehci_device_intr_methods; -extern struct usb2_pipe_methods ehci_device_isoc_fs_methods; -extern struct usb2_pipe_methods ehci_device_isoc_hs_methods; -extern struct usb2_pipe_methods ehci_root_ctrl_methods; -extern struct usb2_pipe_methods ehci_root_intr_methods; - -static void ehci_do_poll(struct usb2_bus *bus); -static void ehci_root_ctrl_poll(ehci_softc_t *sc); -static void ehci_device_done(struct usb2_xfer *xfer, usb2_error_t error); -static uint8_t ehci_check_transfer(struct usb2_xfer *xfer); -static void ehci_timeout(void *arg); - -static usb2_sw_transfer_func_t ehci_root_intr_done; -static usb2_sw_transfer_func_t ehci_root_ctrl_done; - -struct ehci_std_temp { - ehci_softc_t *sc; - struct usb2_page_cache *pc; - ehci_qtd_t *td; - ehci_qtd_t *td_next; - uint32_t average; - uint32_t qtd_status; - uint32_t len; - uint16_t max_frame_size; - uint8_t shortpkt; - uint8_t auto_data_toggle; - uint8_t setup_alt_next; - uint8_t short_frames_ok; -}; - -/* - * Byte-order conversion functions. - */ -static uint32_t -htoehci32(ehci_softc_t *sc, const uint32_t v) -{ - return ((sc->sc_flags & EHCI_SCFLG_BIGEDESC) ? - htobe32(v) : htole32(v)); -} - -static uint32_t -ehci32toh(ehci_softc_t *sc, const uint32_t v) -{ - return ((sc->sc_flags & EHCI_SCFLG_BIGEDESC) ? - be32toh(v) : le32toh(v)); -} - -void -ehci_iterate_hw_softc(struct usb2_bus *bus, usb2_bus_mem_sub_cb_t *cb) -{ - ehci_softc_t *sc = EHCI_BUS2SC(bus); - uint32_t i; - - cb(bus, &sc->sc_hw.pframes_pc, &sc->sc_hw.pframes_pg, - sizeof(uint32_t) * EHCI_FRAMELIST_COUNT, EHCI_FRAMELIST_ALIGN); - - cb(bus, &sc->sc_hw.async_start_pc, &sc->sc_hw.async_start_pg, - sizeof(ehci_qh_t), EHCI_QH_ALIGN); - - for (i = 0; i != EHCI_VIRTUAL_FRAMELIST_COUNT; i++) { - cb(bus, sc->sc_hw.intr_start_pc + i, - sc->sc_hw.intr_start_pg + i, - sizeof(ehci_qh_t), EHCI_QH_ALIGN); - } - - for (i = 0; i != EHCI_VIRTUAL_FRAMELIST_COUNT; i++) { - cb(bus, sc->sc_hw.isoc_hs_start_pc + i, - sc->sc_hw.isoc_hs_start_pg + i, - sizeof(ehci_itd_t), EHCI_ITD_ALIGN); - } - - for (i = 0; i != EHCI_VIRTUAL_FRAMELIST_COUNT; i++) { - cb(bus, sc->sc_hw.isoc_fs_start_pc + i, - sc->sc_hw.isoc_fs_start_pg + i, - sizeof(ehci_sitd_t), EHCI_SITD_ALIGN); - } -} - -static usb2_error_t -ehci_hc_reset(ehci_softc_t *sc) -{ - uint32_t hcr; - uint32_t n; - - EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ - - for (n = 0; n != 100; n++) { - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); - hcr = EOREAD4(sc, EHCI_USBSTS); - if (hcr & EHCI_STS_HCH) { - hcr = 0; - break; - } - } - - /* - * Fall through and try reset anyway even though - * Table 2-9 in the EHCI spec says this will result - * in undefined behavior. - */ - - EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); - for (n = 0; n != 100; n++) { - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); - hcr = EOREAD4(sc, EHCI_USBCMD); - if (!(hcr & EHCI_CMD_HCRESET)) { - if (sc->sc_flags & EHCI_SCFLG_SETMODE) - EOWRITE4(sc, 0x68, 0x3); - hcr = 0; - break; - } - } - - if (hcr) { - return (USB_ERR_IOERROR); - } - return (0); -} - -usb2_error_t -ehci_init(ehci_softc_t *sc) -{ - struct usb2_page_search buf_res; - uint32_t version; - uint32_t sparams; - uint32_t cparams; - uint32_t hcr; - uint16_t i; - uint16_t x; - uint16_t y; - uint16_t bit; - usb2_error_t err = 0; - - DPRINTF("start\n"); - - usb2_callout_init_mtx(&sc->sc_tmo_pcd, &sc->sc_bus.bus_mtx, 0); - -#if USB_DEBUG - if (ehcidebug > 2) { - ehci_dump_regs(sc); - } -#endif - - sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); - - version = EREAD2(sc, EHCI_HCIVERSION); - device_printf(sc->sc_bus.bdev, "EHCI version %x.%x\n", - version >> 8, version & 0xff); - - sparams = EREAD4(sc, EHCI_HCSPARAMS); - DPRINTF("sparams=0x%x\n", sparams); - - sc->sc_noport = EHCI_HCS_N_PORTS(sparams); - cparams = EREAD4(sc, EHCI_HCCPARAMS); - DPRINTF("cparams=0x%x\n", cparams); - - if (EHCI_HCC_64BIT(cparams)) { - DPRINTF("HCC uses 64-bit structures\n"); - - /* MUST clear segment register if 64 bit capable */ - EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0); - } - sc->sc_bus.usbrev = USB_REV_2_0; - - /* Reset the controller */ - DPRINTF("%s: resetting\n", device_get_nameunit(sc->sc_bus.bdev)); - - USB_BUS_LOCK(&sc->sc_bus); - err = ehci_hc_reset(sc); - USB_BUS_UNLOCK(&sc->sc_bus); - if (err) { - device_printf(sc->sc_bus.bdev, "reset timeout\n"); - return (err); - } - /* - * use current frame-list-size selection 0: 1024*4 bytes 1: 512*4 - * bytes 2: 256*4 bytes 3: unknown - */ - if (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD)) == 3) { - device_printf(sc->sc_bus.bdev, "invalid frame-list-size\n"); - return (USB_ERR_IOERROR); - } - /* set up the bus struct */ - sc->sc_bus.methods = &ehci_bus_methods; - - sc->sc_eintrs = EHCI_NORMAL_INTRS; - - for (i = 0; i < EHCI_VIRTUAL_FRAMELIST_COUNT; i++) { - ehci_qh_t *qh; - - usb2_get_page(sc->sc_hw.intr_start_pc + i, 0, &buf_res); - - qh = buf_res.buffer; - - /* initialize page cache pointer */ - - qh->page_cache = sc->sc_hw.intr_start_pc + i; - - /* store a pointer to queue head */ - - sc->sc_intr_p_last[i] = qh; - - qh->qh_self = - htoehci32(sc, buf_res.physaddr) | - htoehci32(sc, EHCI_LINK_QH); - - qh->qh_endp = - htoehci32(sc, EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH)); - qh->qh_endphub = - htoehci32(sc, EHCI_QH_SET_MULT(1)); - qh->qh_curqtd = 0; - - qh->qh_qtd.qtd_next = - htoehci32(sc, EHCI_LINK_TERMINATE); - qh->qh_qtd.qtd_altnext = - htoehci32(sc, EHCI_LINK_TERMINATE); - qh->qh_qtd.qtd_status = - htoehci32(sc, EHCI_QTD_HALTED); - } - - /* - * the QHs are arranged to give poll intervals that are - * powers of 2 times 1ms - */ - bit = EHCI_VIRTUAL_FRAMELIST_COUNT / 2; - while (bit) { - x = bit; - while (x & bit) { - ehci_qh_t *qh_x; - ehci_qh_t *qh_y; - - y = (x ^ bit) | (bit / 2); - - qh_x = sc->sc_intr_p_last[x]; - qh_y = sc->sc_intr_p_last[y]; - - /* - * the next QH has half the poll interval - */ - qh_x->qh_link = qh_y->qh_self; - - x++; - } - bit >>= 1; - } - - if (1) { - ehci_qh_t *qh; - - qh = sc->sc_intr_p_last[0]; - - /* the last (1ms) QH terminates */ - qh->qh_link = htoehci32(sc, EHCI_LINK_TERMINATE); - } - for (i = 0; i < EHCI_VIRTUAL_FRAMELIST_COUNT; i++) { - ehci_sitd_t *sitd; - ehci_itd_t *itd; - - usb2_get_page(sc->sc_hw.isoc_fs_start_pc + i, 0, &buf_res); - - sitd = buf_res.buffer; - - /* initialize page cache pointer */ - - sitd->page_cache = sc->sc_hw.isoc_fs_start_pc + i; - - /* store a pointer to the transfer descriptor */ - - sc->sc_isoc_fs_p_last[i] = sitd; - - /* initialize full speed isochronous */ - - sitd->sitd_self = - htoehci32(sc, buf_res.physaddr) | - htoehci32(sc, EHCI_LINK_SITD); - - sitd->sitd_back = - htoehci32(sc, EHCI_LINK_TERMINATE); - - sitd->sitd_next = - sc->sc_intr_p_last[i | (EHCI_VIRTUAL_FRAMELIST_COUNT / 2)]->qh_self; - - - usb2_get_page(sc->sc_hw.isoc_hs_start_pc + i, 0, &buf_res); - - itd = buf_res.buffer; - - /* initialize page cache pointer */ - - itd->page_cache = sc->sc_hw.isoc_hs_start_pc + i; - - /* store a pointer to the transfer descriptor */ - - sc->sc_isoc_hs_p_last[i] = itd; - - /* initialize high speed isochronous */ - - itd->itd_self = - htoehci32(sc, buf_res.physaddr) | - htoehci32(sc, EHCI_LINK_ITD); - - itd->itd_next = - sitd->sitd_self; - } - - usb2_get_page(&sc->sc_hw.pframes_pc, 0, &buf_res); - - if (1) { - uint32_t *pframes; - - pframes = buf_res.buffer; - - /* - * execution order: - * pframes -> high speed isochronous -> - * full speed isochronous -> interrupt QH's - */ - for (i = 0; i < EHCI_FRAMELIST_COUNT; i++) { - pframes[i] = sc->sc_isoc_hs_p_last - [i & (EHCI_VIRTUAL_FRAMELIST_COUNT - 1)]->itd_self; - } - } - /* setup sync list pointer */ - EOWRITE4(sc, EHCI_PERIODICLISTBASE, buf_res.physaddr); - - usb2_get_page(&sc->sc_hw.async_start_pc, 0, &buf_res); - - if (1) { - - ehci_qh_t *qh; - - qh = buf_res.buffer; - - /* initialize page cache pointer */ - - qh->page_cache = &sc->sc_hw.async_start_pc; - - /* store a pointer to the queue head */ - - sc->sc_async_p_last = qh; - - /* init dummy QH that starts the async list */ - - qh->qh_self = - htoehci32(sc, buf_res.physaddr) | - htoehci32(sc, EHCI_LINK_QH); - - /* fill the QH */ - qh->qh_endp = - htoehci32(sc, EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL); - qh->qh_endphub = htoehci32(sc, EHCI_QH_SET_MULT(1)); - qh->qh_link = qh->qh_self; - qh->qh_curqtd = 0; - - /* fill the overlay qTD */ - qh->qh_qtd.qtd_next = htoehci32(sc, EHCI_LINK_TERMINATE); - qh->qh_qtd.qtd_altnext = htoehci32(sc, EHCI_LINK_TERMINATE); - qh->qh_qtd.qtd_status = htoehci32(sc, EHCI_QTD_HALTED); - } - /* flush all cache into memory */ - - usb2_bus_mem_flush_all(&sc->sc_bus, &ehci_iterate_hw_softc); - -#if USB_DEBUG - if (ehcidebug) { - ehci_dump_sqh(sc, sc->sc_async_p_last); - } -#endif - - /* setup async list pointer */ - EOWRITE4(sc, EHCI_ASYNCLISTADDR, buf_res.physaddr | EHCI_LINK_QH); - - - /* enable interrupts */ - EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); - - /* turn on controller */ - EOWRITE4(sc, EHCI_USBCMD, - EHCI_CMD_ITC_1 | /* 1 microframes interrupt delay */ - (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) | - EHCI_CMD_ASE | - EHCI_CMD_PSE | - EHCI_CMD_RS); - - /* Take over port ownership */ - EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF); - - for (i = 0; i < 100; i++) { - usb2_pause_mtx(NULL, hz / 1000); - hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; - if (!hcr) { - break; - } - } - if (hcr) { - device_printf(sc->sc_bus.bdev, "run timeout\n"); - return (USB_ERR_IOERROR); - } - - if (!err) { - /* catch any lost interrupts */ - ehci_do_poll(&sc->sc_bus); - } - return (err); -} - -/* - * shut down the controller when the system is going down - */ -void -ehci_detach(ehci_softc_t *sc) -{ - USB_BUS_LOCK(&sc->sc_bus); - - usb2_callout_stop(&sc->sc_tmo_pcd); - - EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); - - if (ehci_hc_reset(sc)) { - DPRINTF("reset failed!\n"); - } - - USB_BUS_UNLOCK(&sc->sc_bus); - - /* XXX let stray task complete */ - usb2_pause_mtx(NULL, hz / 20); - - usb2_callout_drain(&sc->sc_tmo_pcd); -} - -void -ehci_suspend(ehci_softc_t *sc) -{ - uint32_t cmd; - uint32_t hcr; - uint8_t i; - - USB_BUS_LOCK(&sc->sc_bus); - - for (i = 1; i <= sc->sc_noport; i++) { - cmd = EOREAD4(sc, EHCI_PORTSC(i)); - if (((cmd & EHCI_PS_PO) == 0) && - ((cmd & EHCI_PS_PE) == EHCI_PS_PE)) { - EOWRITE4(sc, EHCI_PORTSC(i), - cmd | EHCI_PS_SUSP); - } - } - - sc->sc_cmd = EOREAD4(sc, EHCI_USBCMD); - - cmd = sc->sc_cmd & ~(EHCI_CMD_ASE | EHCI_CMD_PSE); - EOWRITE4(sc, EHCI_USBCMD, cmd); - - for (i = 0; i < 100; i++) { - hcr = EOREAD4(sc, EHCI_USBSTS) & - (EHCI_STS_ASS | EHCI_STS_PSS); - - if (hcr == 0) { - break; - } - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); - } - - if (hcr != 0) { - device_printf(sc->sc_bus.bdev, "reset timeout\n"); - } - cmd &= ~EHCI_CMD_RS; - EOWRITE4(sc, EHCI_USBCMD, cmd); - - for (i = 0; i < 100; i++) { - hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; - if (hcr == EHCI_STS_HCH) { - break; - } - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); - } - - if (hcr != EHCI_STS_HCH) { - device_printf(sc->sc_bus.bdev, - "config timeout\n"); - } - USB_BUS_UNLOCK(&sc->sc_bus); -} - -void -ehci_resume(ehci_softc_t *sc) -{ - struct usb2_page_search buf_res; - uint32_t cmd; - uint32_t hcr; - uint8_t i; - - USB_BUS_LOCK(&sc->sc_bus); - - /* restore things in case the bios doesn't */ - EOWRITE4(sc, EHCI_CTRLDSSEGMENT, 0); - - usb2_get_page(&sc->sc_hw.pframes_pc, 0, &buf_res); - EOWRITE4(sc, EHCI_PERIODICLISTBASE, buf_res.physaddr); - - usb2_get_page(&sc->sc_hw.async_start_pc, 0, &buf_res); - EOWRITE4(sc, EHCI_ASYNCLISTADDR, buf_res.physaddr | EHCI_LINK_QH); - - EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); - - hcr = 0; - for (i = 1; i <= sc->sc_noport; i++) { - cmd = EOREAD4(sc, EHCI_PORTSC(i)); - if (((cmd & EHCI_PS_PO) == 0) && - ((cmd & EHCI_PS_SUSP) == EHCI_PS_SUSP)) { - EOWRITE4(sc, EHCI_PORTSC(i), - cmd | EHCI_PS_FPR); - hcr = 1; - } - } - - if (hcr) { - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_RESUME_WAIT)); - - for (i = 1; i <= sc->sc_noport; i++) { - cmd = EOREAD4(sc, EHCI_PORTSC(i)); - if (((cmd & EHCI_PS_PO) == 0) && - ((cmd & EHCI_PS_SUSP) == EHCI_PS_SUSP)) { - EOWRITE4(sc, EHCI_PORTSC(i), - cmd & ~EHCI_PS_FPR); - } - } - } - EOWRITE4(sc, EHCI_USBCMD, sc->sc_cmd); - - for (i = 0; i < 100; i++) { - hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; - if (hcr != EHCI_STS_HCH) { - break; - } - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); - } - if (hcr == EHCI_STS_HCH) { - device_printf(sc->sc_bus.bdev, "config timeout\n"); - } - - USB_BUS_UNLOCK(&sc->sc_bus); - - usb2_pause_mtx(NULL, - USB_MS_TO_TICKS(USB_RESUME_WAIT)); - - /* catch any lost interrupts */ - ehci_do_poll(&sc->sc_bus); -} - -void -ehci_shutdown(ehci_softc_t *sc) -{ - DPRINTF("stopping the HC\n"); - - USB_BUS_LOCK(&sc->sc_bus); - - if (ehci_hc_reset(sc)) { - DPRINTF("reset failed!\n"); - } - USB_BUS_UNLOCK(&sc->sc_bus); -} - -#if USB_DEBUG -static void -ehci_dump_regs(ehci_softc_t *sc) -{ - uint32_t i; - - i = EOREAD4(sc, EHCI_USBCMD); - printf("cmd=0x%08x\n", i); - - if (i & EHCI_CMD_ITC_1) - printf(" EHCI_CMD_ITC_1\n"); - if (i & EHCI_CMD_ITC_2) - printf(" EHCI_CMD_ITC_2\n"); - if (i & EHCI_CMD_ITC_4) - printf(" EHCI_CMD_ITC_4\n"); - if (i & EHCI_CMD_ITC_8) - printf(" EHCI_CMD_ITC_8\n"); - if (i & EHCI_CMD_ITC_16) - printf(" EHCI_CMD_ITC_16\n"); - if (i & EHCI_CMD_ITC_32) - printf(" EHCI_CMD_ITC_32\n"); - if (i & EHCI_CMD_ITC_64) - printf(" EHCI_CMD_ITC_64\n"); - if (i & EHCI_CMD_ASPME) - printf(" EHCI_CMD_ASPME\n"); - if (i & EHCI_CMD_ASPMC) - printf(" EHCI_CMD_ASPMC\n"); - if (i & EHCI_CMD_LHCR) - printf(" EHCI_CMD_LHCR\n"); - if (i & EHCI_CMD_IAAD) - printf(" EHCI_CMD_IAAD\n"); - if (i & EHCI_CMD_ASE) - printf(" EHCI_CMD_ASE\n"); - if (i & EHCI_CMD_PSE) - printf(" EHCI_CMD_PSE\n"); - if (i & EHCI_CMD_FLS_M) - printf(" EHCI_CMD_FLS_M\n"); - if (i & EHCI_CMD_HCRESET) - printf(" EHCI_CMD_HCRESET\n"); - if (i & EHCI_CMD_RS) - printf(" EHCI_CMD_RS\n"); - - i = EOREAD4(sc, EHCI_USBSTS); - - printf("sts=0x%08x\n", i); - - if (i & EHCI_STS_ASS) - printf(" EHCI_STS_ASS\n"); - if (i & EHCI_STS_PSS) - printf(" EHCI_STS_PSS\n"); - if (i & EHCI_STS_REC) - printf(" EHCI_STS_REC\n"); - if (i & EHCI_STS_HCH) - printf(" EHCI_STS_HCH\n"); - if (i & EHCI_STS_IAA) - printf(" EHCI_STS_IAA\n"); - if (i & EHCI_STS_HSE) - printf(" EHCI_STS_HSE\n"); - if (i & EHCI_STS_FLR) - printf(" EHCI_STS_FLR\n"); - if (i & EHCI_STS_PCD) - printf(" EHCI_STS_PCD\n"); - if (i & EHCI_STS_ERRINT) - printf(" EHCI_STS_ERRINT\n"); - if (i & EHCI_STS_INT) - printf(" EHCI_STS_INT\n"); - - printf("ien=0x%08x\n", - EOREAD4(sc, EHCI_USBINTR)); - printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n", - EOREAD4(sc, EHCI_FRINDEX), - EOREAD4(sc, EHCI_CTRLDSSEGMENT), - EOREAD4(sc, EHCI_PERIODICLISTBASE), - EOREAD4(sc, EHCI_ASYNCLISTADDR)); - for (i = 1; i <= sc->sc_noport; i++) { - printf("port %d status=0x%08x\n", i, - EOREAD4(sc, EHCI_PORTSC(i))); - } -} - -static void -ehci_dump_link(ehci_softc_t *sc, uint32_t link, int type) -{ - link = ehci32toh(sc, link); - printf("0x%08x", link); - if (link & EHCI_LINK_TERMINATE) - printf("<T>"); - else { - printf("<"); - if (type) { - switch (EHCI_LINK_TYPE(link)) { - case EHCI_LINK_ITD: - printf("ITD"); - break; - case EHCI_LINK_QH: - printf("QH"); - break; - case EHCI_LINK_SITD: - printf("SITD"); - break; - case EHCI_LINK_FSTN: - printf("FSTN"); - break; - } - } - printf(">"); - } -} - -static void -ehci_dump_qtd(ehci_softc_t *sc, ehci_qtd_t *qtd) -{ - uint32_t s; - - printf(" next="); - ehci_dump_link(sc, qtd->qtd_next, 0); - printf(" altnext="); - ehci_dump_link(sc, qtd->qtd_altnext, 0); - printf("\n"); - s = ehci32toh(sc, qtd->qtd_status); - printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n", - s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s), - EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s)); - printf(" cerr=%d pid=%d stat=%s%s%s%s%s%s%s%s\n", - EHCI_QTD_GET_CERR(s), EHCI_QTD_GET_PID(s), - (s & EHCI_QTD_ACTIVE) ? "ACTIVE" : "NOT_ACTIVE", - (s & EHCI_QTD_HALTED) ? "-HALTED" : "", - (s & EHCI_QTD_BUFERR) ? "-BUFERR" : "", - (s & EHCI_QTD_BABBLE) ? "-BABBLE" : "", - (s & EHCI_QTD_XACTERR) ? "-XACTERR" : "", - (s & EHCI_QTD_MISSEDMICRO) ? "-MISSED" : "", - (s & EHCI_QTD_SPLITXSTATE) ? "-SPLIT" : "", - (s & EHCI_QTD_PINGSTATE) ? "-PING" : ""); - - for (s = 0; s < 5; s++) { - printf(" buffer[%d]=0x%08x\n", s, - ehci32toh(sc, qtd->qtd_buffer[s])); - } - for (s = 0; s < 5; s++) { - printf(" buffer_hi[%d]=0x%08x\n", s, - ehci32toh(sc, qtd->qtd_buffer_hi[s])); - } -} - -static uint8_t -ehci_dump_sqtd(ehci_softc_t *sc, ehci_qtd_t *sqtd) -{ - uint8_t temp; - - usb2_pc_cpu_invalidate(sqtd->page_cache); - printf("QTD(%p) at 0x%08x:\n", sqtd, ehci32toh(sc, sqtd->qtd_self)); - ehci_dump_qtd(sc, sqtd); - temp = (sqtd->qtd_next & htoehci32(sc, EHCI_LINK_TERMINATE)) ? 1 : 0; - return (temp); -} - -static void -ehci_dump_sqtds(ehci_softc_t *sc, ehci_qtd_t *sqtd) -{ - uint16_t i; - uint8_t stop; - - stop = 0; - for (i = 0; sqtd && (i < 20) && !stop; sqtd = sqtd->obj_next, i++) { - stop = ehci_dump_sqtd(sc, sqtd); - } - if (sqtd) { - printf("dump aborted, too many TDs\n"); - } -} - -static void -ehci_dump_sqh(ehci_softc_t *sc, ehci_qh_t *qh) -{ - uint32_t endp; - uint32_t endphub; - - usb2_pc_cpu_invalidate(qh->page_cache); - printf("QH(%p) at 0x%08x:\n", qh, ehci32toh(sc, qh->qh_self) & ~0x1F); - printf(" link="); - ehci_dump_link(sc, qh->qh_link, 1); - printf("\n"); - endp = ehci32toh(sc, qh->qh_endp); - printf(" endp=0x%08x\n", endp); - printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n", - EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp), - EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp), - EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp)); - printf(" mpl=0x%x ctl=%d nrl=%d\n", - EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp), - EHCI_QH_GET_NRL(endp)); - endphub = ehci32toh(sc, qh->qh_endphub); - printf(" endphub=0x%08x\n", endphub); - printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n", - EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub), - EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub), - EHCI_QH_GET_MULT(endphub)); - printf(" curqtd="); - ehci_dump_link(sc, qh->qh_curqtd, 0); - printf("\n"); - printf("Overlay qTD:\n"); - ehci_dump_qtd(sc, (void *)&qh->qh_qtd); -} - -static void -ehci_dump_sitd(ehci_softc_t *sc, ehci_sitd_t *sitd) -{ - usb2_pc_cpu_invalidate(sitd->page_cache); - printf("SITD(%p) at 0x%08x\n", sitd, ehci32toh(sc, sitd->sitd_self) & ~0x1F); - printf(" next=0x%08x\n", ehci32toh(sc, sitd->sitd_next)); - printf(" portaddr=0x%08x dir=%s addr=%d endpt=0x%x port=0x%x huba=0x%x\n", - ehci32toh(sc, sitd->sitd_portaddr), - (sitd->sitd_portaddr & htoehci32(sc, EHCI_SITD_SET_DIR_IN)) - ? "in" : "out", - EHCI_SITD_GET_ADDR(ehci32toh(sc, sitd->sitd_portaddr)), - EHCI_SITD_GET_ENDPT(ehci32toh(sc, sitd->sitd_portaddr)), - EHCI_SITD_GET_PORT(ehci32toh(sc, sitd->sitd_portaddr)), - EHCI_SITD_GET_HUBA(ehci32toh(sc, sitd->sitd_portaddr))); - printf(" mask=0x%08x\n", ehci32toh(sc, sitd->sitd_mask)); - printf(" status=0x%08x <%s> len=0x%x\n", ehci32toh(sc, sitd->sitd_status), - (sitd->sitd_status & htoehci32(sc, EHCI_SITD_ACTIVE)) ? "ACTIVE" : "", - EHCI_SITD_GET_LEN(ehci32toh(sc, sitd->sitd_status))); - printf(" back=0x%08x, bp=0x%08x,0x%08x,0x%08x,0x%08x\n", - ehci32toh(sc, sitd->sitd_back), - ehci32toh(sc, sitd->sitd_bp[0]), - ehci32toh(sc, sitd->sitd_bp[1]), - ehci32toh(sc, sitd->sitd_bp_hi[0]), - ehci32toh(sc, sitd->sitd_bp_hi[1])); -} - -static void -ehci_dump_itd(ehci_softc_t *sc, ehci_itd_t *itd) -{ - usb2_pc_cpu_invalidate(itd->page_cache); - printf("ITD(%p) at 0x%08x\n", itd, ehci32toh(sc, itd->itd_self) & ~0x1F); - printf(" next=0x%08x\n", ehci32toh(sc, itd->itd_next)); - printf(" status[0]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[0]), - (itd->itd_status[0] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : ""); - printf(" status[1]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[1]), - (itd->itd_status[1] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : ""); - printf(" status[2]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[2]), - (itd->itd_status[2] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : ""); - printf(" status[3]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[3]), - (itd->itd_status[3] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : ""); - printf(" status[4]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[4]), - (itd->itd_status[4] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : ""); - printf(" status[5]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[5]), - (itd->itd_status[5] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : ""); - printf(" status[6]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[6]), - (itd->itd_status[6] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : ""); - printf(" status[7]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[7]), - (itd->itd_status[7] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : ""); - printf(" bp[0]=0x%08x\n", ehci32toh(sc, itd->itd_bp[0])); - printf(" addr=0x%02x; endpt=0x%01x\n", - EHCI_ITD_GET_ADDR(ehci32toh(sc, itd->itd_bp[0])), - EHCI_ITD_GET_ENDPT(ehci32toh(sc, itd->itd_bp[0]))); - printf(" bp[1]=0x%08x\n", ehci32toh(sc, itd->itd_bp[1])); - printf(" dir=%s; mpl=0x%02x\n", - (ehci32toh(sc, itd->itd_bp[1]) & EHCI_ITD_SET_DIR_IN) ? "in" : "out", - EHCI_ITD_GET_MPL(ehci32toh(sc, itd->itd_bp[1]))); - printf(" bp[2..6]=0x%08x,0x%08x,0x%08x,0x%08x,0x%08x\n", - ehci32toh(sc, itd->itd_bp[2]), - ehci32toh(sc, itd->itd_bp[3]), - ehci32toh(sc, itd->itd_bp[4]), - ehci32toh(sc, itd->itd_bp[5]), - ehci32toh(sc, itd->itd_bp[6])); - printf(" bp_hi=0x%08x,0x%08x,0x%08x,0x%08x,\n" - " 0x%08x,0x%08x,0x%08x\n", - ehci32toh(sc, itd->itd_bp_hi[0]), - ehci32toh(sc, itd->itd_bp_hi[1]), - ehci32toh(sc, itd->itd_bp_hi[2]), - ehci32toh(sc, itd->itd_bp_hi[3]), - ehci32toh(sc, itd->itd_bp_hi[4]), - ehci32toh(sc, itd->itd_bp_hi[5]), - ehci32toh(sc, itd->itd_bp_hi[6])); -} - -static void -ehci_dump_isoc(ehci_softc_t *sc) -{ - ehci_itd_t *itd; - ehci_sitd_t *sitd; - uint16_t max = 1000; - uint16_t pos; - - pos = (EOREAD4(sc, EHCI_FRINDEX) / 8) & - (EHCI_VIRTUAL_FRAMELIST_COUNT - 1); - - printf("%s: isochronous dump from frame 0x%03x:\n", - __FUNCTION__, pos); - - itd = sc->sc_isoc_hs_p_last[pos]; - sitd = sc->sc_isoc_fs_p_last[pos]; - - while (itd && max && max--) { - ehci_dump_itd(sc, itd); - itd = itd->prev; - } - - while (sitd && max && max--) { - ehci_dump_sitd(sc, sitd); - sitd = sitd->prev; - } -} - -#endif - -static void -ehci_transfer_intr_enqueue(struct usb2_xfer *xfer) -{ - /* check for early completion */ - if (ehci_check_transfer(xfer)) { - return; - } - /* put transfer on interrupt queue */ - usb2_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); - - /* start timeout, if any */ - if (xfer->timeout != 0) { - usb2_transfer_timeout_ms(xfer, &ehci_timeout, xfer->timeout); - } -} - -#define EHCI_APPEND_FS_TD(std,last) (last) = _ehci_append_fs_td(std,last) -static ehci_sitd_t * -_ehci_append_fs_td(ehci_sitd_t *std, ehci_sitd_t *last) -{ - DPRINTFN(11, "%p to %p\n", std, last); - - /* (sc->sc_bus.mtx) must be locked */ - - std->next = last->next; - std->sitd_next = last->sitd_next; - - std->prev = last; - - usb2_pc_cpu_flush(std->page_cache); - - /* - * the last->next->prev is never followed: std->next->prev = std; - */ - last->next = std; - last->sitd_next = std->sitd_self; - - usb2_pc_cpu_flush(last->page_cache); - - return (std); -} - -#define EHCI_APPEND_HS_TD(std,last) (last) = _ehci_append_hs_td(std,last) -static ehci_itd_t * -_ehci_append_hs_td(ehci_itd_t *std, ehci_itd_t *last) -{ - DPRINTFN(11, "%p to %p\n", std, last); - - /* (sc->sc_bus.mtx) must be locked */ - - std->next = last->next; - std->itd_next = last->itd_next; - - std->prev = last; - - usb2_pc_cpu_flush(std->page_cache); - - /* - * the last->next->prev is never followed: std->next->prev = std; - */ - last->next = std; - last->itd_next = std->itd_self; - - usb2_pc_cpu_flush(last->page_cache); - - return (std); -} - -#define EHCI_APPEND_QH(sqh,last) (last) = _ehci_append_qh(sqh,last) -static ehci_qh_t * -_ehci_append_qh(ehci_qh_t *sqh, ehci_qh_t *last) -{ - DPRINTFN(11, "%p to %p\n", sqh, last); - - if (sqh->prev != NULL) { - /* should not happen */ - DPRINTFN(0, "QH already linked!\n"); - return (last); - } - /* (sc->sc_bus.mtx) must be locked */ - - sqh->next = last->next; - sqh->qh_link = last->qh_link; - - sqh->prev = last; - - usb2_pc_cpu_flush(sqh->page_cache); - - /* - * the last->next->prev is never followed: sqh->next->prev = sqh; - */ - - last->next = sqh; - last->qh_link = sqh->qh_self; - - usb2_pc_cpu_flush(last->page_cache); - - return (sqh); -} - -#define EHCI_REMOVE_FS_TD(std,last) (last) = _ehci_remove_fs_td(std,last) -static ehci_sitd_t * -_ehci_remove_fs_td(ehci_sitd_t *std, ehci_sitd_t *last) -{ - DPRINTFN(11, "%p from %p\n", std, last); - - /* (sc->sc_bus.mtx) must be locked */ - - std->prev->next = std->next; - std->prev->sitd_next = std->sitd_next; - - usb2_pc_cpu_flush(std->prev->page_cache); - - if (std->next) { - std->next->prev = std->prev; - usb2_pc_cpu_flush(std->next->page_cache); - } - return ((last == std) ? std->prev : last); -} - -#define EHCI_REMOVE_HS_TD(std,last) (last) = _ehci_remove_hs_td(std,last) -static ehci_itd_t * -_ehci_remove_hs_td(ehci_itd_t *std, ehci_itd_t *last) -{ - DPRINTFN(11, "%p from %p\n", std, last); - - /* (sc->sc_bus.mtx) must be locked */ - - std->prev->next = std->next; - std->prev->itd_next = std->itd_next; - - usb2_pc_cpu_flush(std->prev->page_cache); - - if (std->next) { - std->next->prev = std->prev; - usb2_pc_cpu_flush(std->next->page_cache); - } - return ((last == std) ? std->prev : last); -} - -#define EHCI_REMOVE_QH(sqh,last) (last) = _ehci_remove_qh(sqh,last) -static ehci_qh_t * -_ehci_remove_qh(ehci_qh_t *sqh, ehci_qh_t *last) -{ - DPRINTFN(11, "%p from %p\n", sqh, last); - - /* (sc->sc_bus.mtx) must be locked */ - - /* only remove if not removed from a queue */ - if (sqh->prev) { - - sqh->prev->next = sqh->next; - sqh->prev->qh_link = sqh->qh_link; - - usb2_pc_cpu_flush(sqh->prev->page_cache); - - if (sqh->next) { - sqh->next->prev = sqh->prev; - usb2_pc_cpu_flush(sqh->next->page_cache); - } - last = ((last == sqh) ? sqh->prev : last); - - sqh->prev = 0; - - usb2_pc_cpu_flush(sqh->page_cache); - } - return (last); -} - -static usb2_error_t -ehci_non_isoc_done_sub(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - ehci_qtd_t *td; - ehci_qtd_t *td_alt_next; - uint32_t status; - uint16_t len; - - td = xfer->td_transfer_cache; - td_alt_next = td->alt_next; - - if (xfer->aframes != xfer->nframes) { - xfer->frlengths[xfer->aframes] = 0; - } - while (1) { - - usb2_pc_cpu_invalidate(td->page_cache); - status = ehci32toh(sc, td->qtd_status); - - len = EHCI_QTD_GET_BYTES(status); - - /* - * Verify the status length and - * add the length to "frlengths[]": - */ - if (len > td->len) { - /* should not happen */ - DPRINTF("Invalid status length, " - "0x%04x/0x%04x bytes\n", len, td->len); - status |= EHCI_QTD_HALTED; - } else if (xfer->aframes != xfer->nframes) { - xfer->frlengths[xfer->aframes] += td->len - len; - } - /* Check for last transfer */ - if (((void *)td) == xfer->td_transfer_last) { - if (len == 0) { - /* - * Halt is ok if descriptor is last, - * and complete: - */ - status &= ~EHCI_QTD_HALTED; - } - td = NULL; - break; - } - /* Check for transfer error */ - if (status & EHCI_QTD_HALTED) { - /* the transfer is finished */ - td = NULL; - break; - } - /* Check for short transfer */ - if (len > 0) { - if (xfer->flags_int.short_frames_ok) { - /* follow alt next */ - td = td->alt_next; - } else { - /* the transfer is finished */ - td = NULL; - } - break; - } - td = td->obj_next; - - if (td->alt_next != td_alt_next) { - /* this USB frame is complete */ - break; - } - } - - /* update transfer cache */ - - xfer->td_transfer_cache = td; - - /* update data toggle */ - - xfer->pipe->toggle_next = - (status & EHCI_QTD_TOGGLE_MASK) ? 1 : 0; - -#if USB_DEBUG - if (status & EHCI_QTD_STATERRS) { - DPRINTFN(11, "error, addr=%d, endpt=0x%02x, frame=0x%02x" - "status=%s%s%s%s%s%s%s%s\n", - xfer->address, xfer->endpoint, xfer->aframes, - (status & EHCI_QTD_ACTIVE) ? "[ACTIVE]" : "[NOT_ACTIVE]", - (status & EHCI_QTD_HALTED) ? "[HALTED]" : "", - (status & EHCI_QTD_BUFERR) ? "[BUFERR]" : "", - (status & EHCI_QTD_BABBLE) ? "[BABBLE]" : "", - (status & EHCI_QTD_XACTERR) ? "[XACTERR]" : "", - (status & EHCI_QTD_MISSEDMICRO) ? "[MISSED]" : "", - (status & EHCI_QTD_SPLITXSTATE) ? "[SPLIT]" : "", - (status & EHCI_QTD_PINGSTATE) ? "[PING]" : ""); - } -#endif - - return ((status & EHCI_QTD_HALTED) ? - USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); -} - -static void -ehci_non_isoc_done(struct usb2_xfer *xfer) -{ - usb2_error_t err = 0; - - DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", - xfer, xfer->pipe); - -#if USB_DEBUG - if (ehcidebug > 10) { - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - - ehci_dump_sqtds(sc, xfer->td_transfer_first); - } -#endif - - /* reset scanner */ - - xfer->td_transfer_cache = xfer->td_transfer_first; - - if (xfer->flags_int.control_xfr) { - - if (xfer->flags_int.control_hdr) { - - err = ehci_non_isoc_done_sub(xfer); - } - xfer->aframes = 1; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - while (xfer->aframes != xfer->nframes) { - - err = ehci_non_isoc_done_sub(xfer); - xfer->aframes++; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - err = ehci_non_isoc_done_sub(xfer); - } -done: - ehci_device_done(xfer, err); -} - -/*------------------------------------------------------------------------* - * ehci_check_transfer - * - * Return values: - * 0: USB transfer is not finished - * Else: USB transfer is finished - *------------------------------------------------------------------------*/ -static uint8_t -ehci_check_transfer(struct usb2_xfer *xfer) -{ - struct usb2_pipe_methods *methods = xfer->pipe->methods; - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - - uint32_t status; - - DPRINTFN(13, "xfer=%p checking transfer\n", xfer); - - if (methods == &ehci_device_isoc_fs_methods) { - ehci_sitd_t *td; - - /* isochronous full speed transfer */ - - td = xfer->td_transfer_last; - usb2_pc_cpu_invalidate(td->page_cache); - status = ehci32toh(sc, td->sitd_status); - - /* also check if first is complete */ - - td = xfer->td_transfer_first; - usb2_pc_cpu_invalidate(td->page_cache); - status |= ehci32toh(sc, td->sitd_status); - - if (!(status & EHCI_SITD_ACTIVE)) { - ehci_device_done(xfer, USB_ERR_NORMAL_COMPLETION); - goto transferred; - } - } else if (methods == &ehci_device_isoc_hs_methods) { - ehci_itd_t *td; - - /* isochronous high speed transfer */ - - td = xfer->td_transfer_last; - usb2_pc_cpu_invalidate(td->page_cache); - status = - td->itd_status[0] | td->itd_status[1] | - td->itd_status[2] | td->itd_status[3] | - td->itd_status[4] | td->itd_status[5] | - td->itd_status[6] | td->itd_status[7]; - - /* also check first transfer */ - td = xfer->td_transfer_first; - usb2_pc_cpu_invalidate(td->page_cache); - status |= - td->itd_status[0] | td->itd_status[1] | - td->itd_status[2] | td->itd_status[3] | - td->itd_status[4] | td->itd_status[5] | - td->itd_status[6] | td->itd_status[7]; - - /* if no transactions are active we continue */ - if (!(status & htoehci32(sc, EHCI_ITD_ACTIVE))) { - ehci_device_done(xfer, USB_ERR_NORMAL_COMPLETION); - goto transferred; - } - } else { - ehci_qtd_t *td; - - /* non-isochronous transfer */ - - /* - * check whether there is an error somewhere in the middle, - * or whether there was a short packet (SPD and not ACTIVE) - */ - td = xfer->td_transfer_cache; - - while (1) { - usb2_pc_cpu_invalidate(td->page_cache); - status = ehci32toh(sc, td->qtd_status); - - /* - * if there is an active TD the transfer isn't done - */ - if (status & EHCI_QTD_ACTIVE) { - /* update cache */ - xfer->td_transfer_cache = td; - goto done; - } - /* - * last transfer descriptor makes the transfer done - */ - if (((void *)td) == xfer->td_transfer_last) { - break; - } - /* - * any kind of error makes the transfer done - */ - if (status & EHCI_QTD_HALTED) { - break; - } - /* - * if there is no alternate next transfer, a short - * packet also makes the transfer done - */ - if (EHCI_QTD_GET_BYTES(status)) { - if (xfer->flags_int.short_frames_ok) { - /* follow alt next */ - if (td->alt_next) { - td = td->alt_next; - continue; - } - } - /* transfer is done */ - break; - } - td = td->obj_next; - } - ehci_non_isoc_done(xfer); - goto transferred; - } - -done: - DPRINTFN(13, "xfer=%p is still active\n", xfer); - return (0); - -transferred: - return (1); -} - -static void -ehci_pcd_enable(ehci_softc_t *sc) -{ - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - sc->sc_eintrs |= EHCI_STS_PCD; - EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); - - /* acknowledge any PCD interrupt */ - EOWRITE4(sc, EHCI_USBSTS, EHCI_STS_PCD); - - usb2_sw_transfer(&sc->sc_root_intr, - &ehci_root_intr_done); -} - -static void -ehci_interrupt_poll(ehci_softc_t *sc) -{ - struct usb2_xfer *xfer; - -repeat: - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - /* - * check if transfer is transferred - */ - if (ehci_check_transfer(xfer)) { - /* queue has been modified */ - goto repeat; - } - } -} - -/*------------------------------------------------------------------------* - * ehci_interrupt - EHCI interrupt handler - * - * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler, - * hence the interrupt handler will be setup before "sc->sc_bus.bdev" - * is present ! - *------------------------------------------------------------------------*/ -void -ehci_interrupt(ehci_softc_t *sc) -{ - uint32_t status; - - USB_BUS_LOCK(&sc->sc_bus); - - DPRINTFN(16, "real interrupt\n"); - -#if USB_DEBUG - if (ehcidebug > 15) { - ehci_dump_regs(sc); - } -#endif - - status = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); - if (status == 0) { - /* the interrupt was not for us */ - goto done; - } - if (!(status & sc->sc_eintrs)) { - goto done; - } - EOWRITE4(sc, EHCI_USBSTS, status); /* acknowledge */ - - status &= sc->sc_eintrs; - - if (status & EHCI_STS_HSE) { - printf("%s: unrecoverable error, " - "controller halted\n", __FUNCTION__); -#if USB_DEBUG - ehci_dump_regs(sc); - ehci_dump_isoc(sc); -#endif - } - if (status & EHCI_STS_PCD) { - /* - * Disable PCD interrupt for now, because it will be - * on until the port has been reset. - */ - sc->sc_eintrs &= ~EHCI_STS_PCD; - EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); - - usb2_sw_transfer(&sc->sc_root_intr, - &ehci_root_intr_done); - - /* do not allow RHSC interrupts > 1 per second */ - usb2_callout_reset(&sc->sc_tmo_pcd, hz, - (void *)&ehci_pcd_enable, sc); - } - status &= ~(EHCI_STS_INT | EHCI_STS_ERRINT | EHCI_STS_PCD | EHCI_STS_IAA); - - if (status != 0) { - /* block unprocessed interrupts */ - sc->sc_eintrs &= ~status; - EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); - printf("%s: blocking interrupts 0x%x\n", __FUNCTION__, status); - } - /* poll all the USB transfers */ - ehci_interrupt_poll(sc); - -done: - USB_BUS_UNLOCK(&sc->sc_bus); -} - -/* - * called when a request does not complete - */ -static void -ehci_timeout(void *arg) -{ - struct usb2_xfer *xfer = arg; - - DPRINTF("xfer=%p\n", xfer); - - USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); - - /* transfer is transferred */ - ehci_device_done(xfer, USB_ERR_TIMEOUT); -} - -static void -ehci_do_poll(struct usb2_bus *bus) -{ - ehci_softc_t *sc = EHCI_BUS2SC(bus); - - USB_BUS_LOCK(&sc->sc_bus); - ehci_interrupt_poll(sc); - ehci_root_ctrl_poll(sc); - USB_BUS_UNLOCK(&sc->sc_bus); -} - -static void -ehci_setup_standard_chain_sub(struct ehci_std_temp *temp) -{ - struct usb2_page_search buf_res; - ehci_qtd_t *td; - ehci_qtd_t *td_next; - ehci_qtd_t *td_alt_next; - uint32_t qtd_altnext; - uint32_t buf_offset; - uint32_t average; - uint32_t len_old; - uint8_t shortpkt_old; - uint8_t precompute; - - qtd_altnext = htoehci32(temp->sc, EHCI_LINK_TERMINATE); - td_alt_next = NULL; - buf_offset = 0; - shortpkt_old = temp->shortpkt; - len_old = temp->len; - precompute = 1; - -restart: - - td = temp->td; - td_next = temp->td_next; - - while (1) { - - if (temp->len == 0) { - - if (temp->shortpkt) { - break; - } - /* send a Zero Length Packet, ZLP, last */ - - temp->shortpkt = 1; - average = 0; - - } else { - - average = temp->average; - - if (temp->len < average) { - if (temp->len % temp->max_frame_size) { - temp->shortpkt = 1; - } - average = temp->len; - } - } - - if (td_next == NULL) { - panic("%s: out of EHCI transfer descriptors!", __FUNCTION__); - } - /* get next TD */ - - td = td_next; - td_next = td->obj_next; - - /* check if we are pre-computing */ - - if (precompute) { - - /* update remaining length */ - - temp->len -= average; - - continue; - } - /* fill out current TD */ - - td->qtd_status = - temp->qtd_status | - htoehci32(temp->sc, EHCI_QTD_SET_BYTES(average)); - - if (average == 0) { - - if (temp->auto_data_toggle == 0) { - - /* update data toggle, ZLP case */ - - temp->qtd_status ^= - htoehci32(temp->sc, EHCI_QTD_TOGGLE_MASK); - } - td->len = 0; - - td->qtd_buffer[0] = 0; - td->qtd_buffer_hi[0] = 0; - - td->qtd_buffer[1] = 0; - td->qtd_buffer_hi[1] = 0; - - } else { - - uint8_t x; - - if (temp->auto_data_toggle == 0) { - - /* update data toggle */ - - if (((average + temp->max_frame_size - 1) / - temp->max_frame_size) & 1) { - temp->qtd_status ^= - htoehci32(temp->sc, EHCI_QTD_TOGGLE_MASK); - } - } - td->len = average; - - /* update remaining length */ - - temp->len -= average; - - /* fill out buffer pointers */ - - usb2_get_page(temp->pc, buf_offset, &buf_res); - td->qtd_buffer[0] = - htoehci32(temp->sc, buf_res.physaddr); - td->qtd_buffer_hi[0] = 0; - - x = 1; - - while (average > EHCI_PAGE_SIZE) { - average -= EHCI_PAGE_SIZE; - buf_offset += EHCI_PAGE_SIZE; - usb2_get_page(temp->pc, buf_offset, &buf_res); - td->qtd_buffer[x] = - htoehci32(temp->sc, - buf_res.physaddr & (~0xFFF)); - td->qtd_buffer_hi[x] = 0; - x++; - } - - /* - * NOTE: The "average" variable is never zero after - * exiting the loop above ! - * - * NOTE: We have to subtract one from the offset to - * ensure that we are computing the physical address - * of a valid page ! - */ - buf_offset += average; - usb2_get_page(temp->pc, buf_offset - 1, &buf_res); - td->qtd_buffer[x] = - htoehci32(temp->sc, - buf_res.physaddr & (~0xFFF)); - td->qtd_buffer_hi[x] = 0; - } - - if (td_next) { - /* link the current TD with the next one */ - td->qtd_next = td_next->qtd_self; - } - td->qtd_altnext = qtd_altnext; - td->alt_next = td_alt_next; - - usb2_pc_cpu_flush(td->page_cache); - } - - if (precompute) { - precompute = 0; - - /* setup alt next pointer, if any */ - if (temp->short_frames_ok) { - if (temp->setup_alt_next) { - td_alt_next = td_next; - qtd_altnext = td_next->qtd_self; - } - } else { - /* we use this field internally */ - td_alt_next = td_next; - } - - /* restore */ - temp->shortpkt = shortpkt_old; - temp->len = len_old; - goto restart; - } - temp->td = td; - temp->td_next = td_next; -} - -static void -ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last) -{ - struct ehci_std_temp temp; - struct usb2_pipe_methods *methods; - ehci_qh_t *qh; - ehci_qtd_t *td; - uint32_t qh_endp; - uint32_t qh_endphub; - uint32_t x; - - DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", - xfer->address, UE_GET_ADDR(xfer->endpoint), - xfer->sumlen, usb2_get_speed(xfer->xroot->udev)); - - temp.average = xfer->max_usb2_frame_size; - temp.max_frame_size = xfer->max_frame_size; - temp.sc = EHCI_BUS2SC(xfer->xroot->bus); - - /* toggle the DMA set we are using */ - xfer->flags_int.curr_dma_set ^= 1; - - /* get next DMA set */ - td = xfer->td_start[xfer->flags_int.curr_dma_set]; - - xfer->td_transfer_first = td; - xfer->td_transfer_cache = td; - - temp.td = NULL; - temp.td_next = td; - temp.qtd_status = 0; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; - temp.short_frames_ok = xfer->flags_int.short_frames_ok; - - if (xfer->flags_int.control_xfr) { - if (xfer->pipe->toggle_next) { - /* DATA1 is next */ - temp.qtd_status |= - htoehci32(temp.sc, EHCI_QTD_SET_TOGGLE(1)); - } - temp.auto_data_toggle = 0; - } else { - temp.auto_data_toggle = 1; - } - - if (usb2_get_speed(xfer->xroot->udev) != USB_SPEED_HIGH) { - /* max 3 retries */ - temp.qtd_status |= - htoehci32(temp.sc, EHCI_QTD_SET_CERR(3)); - } - /* check if we should prepend a setup message */ - - if (xfer->flags_int.control_xfr) { - if (xfer->flags_int.control_hdr) { - - temp.qtd_status &= - htoehci32(temp.sc, EHCI_QTD_SET_CERR(3)); - temp.qtd_status |= htole32 - (EHCI_QTD_ACTIVE | - EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) | - EHCI_QTD_SET_TOGGLE(0)); - - temp.len = xfer->frlengths[0]; - temp.pc = xfer->frbuffers + 0; - temp.shortpkt = temp.len ? 1 : 0; - - ehci_setup_standard_chain_sub(&temp); - } - x = 1; - } else { - x = 0; - } - - while (x != xfer->nframes) { - - /* DATA0 / DATA1 message */ - - temp.len = xfer->frlengths[x]; - temp.pc = xfer->frbuffers + x; - - x++; - - if (x == xfer->nframes) { - temp.setup_alt_next = 0; - } - /* keep previous data toggle and error count */ - - temp.qtd_status &= - htoehci32(temp.sc, EHCI_QTD_SET_CERR(3) | - EHCI_QTD_SET_TOGGLE(1)); - - if (temp.len == 0) { - - /* make sure that we send an USB packet */ - - temp.shortpkt = 0; - - } else { - - /* regular data transfer */ - - temp.shortpkt = (xfer->flags.force_short_xfer) ? 0 : 1; - } - - /* set endpoint direction */ - - temp.qtd_status |= - (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) ? - htoehci32(temp.sc, EHCI_QTD_ACTIVE | - EHCI_QTD_SET_PID(EHCI_QTD_PID_IN)) : - htoehci32(temp.sc, EHCI_QTD_ACTIVE | - EHCI_QTD_SET_PID(EHCI_QTD_PID_OUT)); - - ehci_setup_standard_chain_sub(&temp); - } - - /* check if we should append a status stage */ - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - /* - * Send a DATA1 message and invert the current endpoint - * direction. - */ - - temp.qtd_status &= htoehci32(temp.sc, EHCI_QTD_SET_CERR(3) | - EHCI_QTD_SET_TOGGLE(1)); - temp.qtd_status |= - (UE_GET_DIR(xfer->endpoint) == UE_DIR_OUT) ? - htoehci32(temp.sc, EHCI_QTD_ACTIVE | - EHCI_QTD_SET_PID(EHCI_QTD_PID_IN) | - EHCI_QTD_SET_TOGGLE(1)) : - htoehci32(temp.sc, EHCI_QTD_ACTIVE | - EHCI_QTD_SET_PID(EHCI_QTD_PID_OUT) | - EHCI_QTD_SET_TOGGLE(1)); - - temp.len = 0; - temp.pc = NULL; - temp.shortpkt = 0; - - ehci_setup_standard_chain_sub(&temp); - } - td = temp.td; - - /* the last TD terminates the transfer: */ - td->qtd_next = htoehci32(temp.sc, EHCI_LINK_TERMINATE); - td->qtd_altnext = htoehci32(temp.sc, EHCI_LINK_TERMINATE); - td->qtd_status |= htoehci32(temp.sc, EHCI_QTD_IOC); - - usb2_pc_cpu_flush(td->page_cache); - - /* must have at least one frame! */ - - xfer->td_transfer_last = td; - -#if USB_DEBUG - if (ehcidebug > 8) { - DPRINTF("nexttog=%d; data before transfer:\n", - xfer->pipe->toggle_next); - ehci_dump_sqtds(temp.sc, - xfer->td_transfer_first); - } -#endif - - methods = xfer->pipe->methods; - - qh = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - /* the "qh_link" field is filled when the QH is added */ - - qh_endp = - (EHCI_QH_SET_ADDR(xfer->address) | - EHCI_QH_SET_ENDPT(UE_GET_ADDR(xfer->endpoint)) | - EHCI_QH_SET_MPL(xfer->max_packet_size)); - - if (usb2_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) { - qh_endp |= (EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | - EHCI_QH_DTC); - if (methods != &ehci_device_intr_methods) - qh_endp |= EHCI_QH_SET_NRL(8); - } else { - - if (usb2_get_speed(xfer->xroot->udev) == USB_SPEED_FULL) { - qh_endp |= (EHCI_QH_SET_EPS(EHCI_QH_SPEED_FULL) | - EHCI_QH_DTC); - } else { - qh_endp |= (EHCI_QH_SET_EPS(EHCI_QH_SPEED_LOW) | - EHCI_QH_DTC); - } - - if (methods == &ehci_device_ctrl_methods) { - qh_endp |= EHCI_QH_CTL; - } - if (methods != &ehci_device_intr_methods) { - /* Only try one time per microframe! */ - qh_endp |= EHCI_QH_SET_NRL(1); - } - } - - qh->qh_endp = htoehci32(temp.sc, qh_endp); - - qh_endphub = - (EHCI_QH_SET_MULT(xfer->max_packet_count & 3) | - EHCI_QH_SET_CMASK(xfer->usb2_cmask) | - EHCI_QH_SET_SMASK(xfer->usb2_smask) | - EHCI_QH_SET_HUBA(xfer->xroot->udev->hs_hub_addr) | - EHCI_QH_SET_PORT(xfer->xroot->udev->hs_port_no)); - - qh->qh_endphub = htoehci32(temp.sc, qh_endphub); - qh->qh_curqtd = htoehci32(temp.sc, 0); - - /* fill the overlay qTD */ - qh->qh_qtd.qtd_status = htoehci32(temp.sc, 0); - - if (temp.auto_data_toggle) { - - /* let the hardware compute the data toggle */ - - qh->qh_endp &= htoehci32(temp.sc, ~EHCI_QH_DTC); - - if (xfer->pipe->toggle_next) { - /* DATA1 is next */ - qh->qh_qtd.qtd_status |= - htoehci32(temp.sc, EHCI_QTD_SET_TOGGLE(1)); - } - } - td = xfer->td_transfer_first; - - qh->qh_qtd.qtd_next = td->qtd_self; - qh->qh_qtd.qtd_altnext = - htoehci32(temp.sc, EHCI_LINK_TERMINATE); - - usb2_pc_cpu_flush(qh->page_cache); - - if (xfer->xroot->udev->pwr_save.suspended == 0) { - EHCI_APPEND_QH(qh, *qh_last); - } -} - -static void -ehci_root_intr_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - uint16_t i; - uint16_t m; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_PRE_DATA) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - ehci_device_done(xfer, std->err); - } - goto done; - } - /* setup buffer */ - std->ptr = sc->sc_hub_idata; - std->len = sizeof(sc->sc_hub_idata); - - /* clear any old interrupt data */ - bzero(sc->sc_hub_idata, sizeof(sc->sc_hub_idata)); - - /* set bits */ - m = (sc->sc_noport + 1); - if (m > (8 * sizeof(sc->sc_hub_idata))) { - m = (8 * sizeof(sc->sc_hub_idata)); - } - for (i = 1; i < m; i++) { - /* pick out CHANGE bits from the status register */ - if (EOREAD4(sc, EHCI_PORTSC(i)) & EHCI_PS_CLEAR) { - sc->sc_hub_idata[i / 8] |= 1 << (i % 8); - DPRINTF("port %d changed\n", i); - } - } -done: - return; -} - -static void -ehci_isoc_fs_done(ehci_softc_t *sc, struct usb2_xfer *xfer) -{ - uint32_t nframes = xfer->nframes; - uint32_t status; - uint32_t *plen = xfer->frlengths; - uint16_t len = 0; - ehci_sitd_t *td = xfer->td_transfer_first; - ehci_sitd_t **pp_last = &sc->sc_isoc_fs_p_last[xfer->qh_pos]; - - DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", - xfer, xfer->pipe); - - while (nframes--) { - if (td == NULL) { - panic("%s:%d: out of TD's\n", - __FUNCTION__, __LINE__); - } - if (pp_last >= &sc->sc_isoc_fs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]) { - pp_last = &sc->sc_isoc_fs_p_last[0]; - } -#if USB_DEBUG - if (ehcidebug > 15) { - DPRINTF("isoc FS-TD\n"); - ehci_dump_sitd(sc, td); - } -#endif - usb2_pc_cpu_invalidate(td->page_cache); - status = ehci32toh(sc, td->sitd_status); - - len = EHCI_SITD_GET_LEN(status); - - if (*plen >= len) { - len = *plen - len; - } else { - len = 0; - } - - *plen = len; - - /* remove FS-TD from schedule */ - EHCI_REMOVE_FS_TD(td, *pp_last); - - pp_last++; - plen++; - td = td->obj_next; - } - - xfer->aframes = xfer->nframes; -} - -static void -ehci_isoc_hs_done(ehci_softc_t *sc, struct usb2_xfer *xfer) -{ - uint32_t nframes = xfer->nframes; - uint32_t status; - uint32_t *plen = xfer->frlengths; - uint16_t len = 0; - uint8_t td_no = 0; - ehci_itd_t *td = xfer->td_transfer_first; - ehci_itd_t **pp_last = &sc->sc_isoc_hs_p_last[xfer->qh_pos]; - - DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", - xfer, xfer->pipe); - - while (nframes--) { - if (td == NULL) { - panic("%s:%d: out of TD's\n", - __FUNCTION__, __LINE__); - } - if (pp_last >= &sc->sc_isoc_hs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]) { - pp_last = &sc->sc_isoc_hs_p_last[0]; - } -#if USB_DEBUG - if (ehcidebug > 15) { - DPRINTF("isoc HS-TD\n"); - ehci_dump_itd(sc, td); - } -#endif - - usb2_pc_cpu_invalidate(td->page_cache); - status = ehci32toh(sc, td->itd_status[td_no]); - - len = EHCI_ITD_GET_LEN(status); - - if (*plen >= len) { - /* - * The length is valid. NOTE: The complete - * length is written back into the status - * field, and not the remainder like with - * other transfer descriptor types. - */ - } else { - /* Invalid length - truncate */ - len = 0; - } - - *plen = len; - - plen++; - td_no++; - - if ((td_no == 8) || (nframes == 0)) { - /* remove HS-TD from schedule */ - EHCI_REMOVE_HS_TD(td, *pp_last); - pp_last++; - - td_no = 0; - td = td->obj_next; - } - } - xfer->aframes = xfer->nframes; -} - -/* NOTE: "done" can be run two times in a row, - * from close and from interrupt - */ -static void -ehci_device_done(struct usb2_xfer *xfer, usb2_error_t error) -{ - struct usb2_pipe_methods *methods = xfer->pipe->methods; - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", - xfer, xfer->pipe, error); - - if ((methods == &ehci_device_bulk_methods) || - (methods == &ehci_device_ctrl_methods)) { -#if USB_DEBUG - if (ehcidebug > 8) { - DPRINTF("nexttog=%d; data after transfer:\n", - xfer->pipe->toggle_next); - ehci_dump_sqtds(sc, - xfer->td_transfer_first); - } -#endif - - EHCI_REMOVE_QH(xfer->qh_start[xfer->flags_int.curr_dma_set], - sc->sc_async_p_last); - } - if (methods == &ehci_device_intr_methods) { - EHCI_REMOVE_QH(xfer->qh_start[xfer->flags_int.curr_dma_set], - sc->sc_intr_p_last[xfer->qh_pos]); - } - /* - * Only finish isochronous transfers once which will update - * "xfer->frlengths". - */ - if (xfer->td_transfer_first && - xfer->td_transfer_last) { - if (methods == &ehci_device_isoc_fs_methods) { - ehci_isoc_fs_done(sc, xfer); - } - if (methods == &ehci_device_isoc_hs_methods) { - ehci_isoc_hs_done(sc, xfer); - } - xfer->td_transfer_first = NULL; - xfer->td_transfer_last = NULL; - } - /* dequeue transfer and start next transfer */ - usb2_transfer_done(xfer, error); -} - -/*------------------------------------------------------------------------* - * ehci bulk support - *------------------------------------------------------------------------*/ -static void -ehci_device_bulk_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -ehci_device_bulk_close(struct usb2_xfer *xfer) -{ - ehci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -ehci_device_bulk_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -ehci_device_bulk_start(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - - /* setup TD's and QH */ - ehci_setup_standard_chain(xfer, &sc->sc_async_p_last); - - /* put transfer on interrupt queue */ - ehci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods ehci_device_bulk_methods = -{ - .open = ehci_device_bulk_open, - .close = ehci_device_bulk_close, - .enter = ehci_device_bulk_enter, - .start = ehci_device_bulk_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * ehci control support - *------------------------------------------------------------------------*/ -static void -ehci_device_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -ehci_device_ctrl_close(struct usb2_xfer *xfer) -{ - ehci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -ehci_device_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -ehci_device_ctrl_start(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - - /* setup TD's and QH */ - ehci_setup_standard_chain(xfer, &sc->sc_async_p_last); - - /* put transfer on interrupt queue */ - ehci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods ehci_device_ctrl_methods = -{ - .open = ehci_device_ctrl_open, - .close = ehci_device_ctrl_close, - .enter = ehci_device_ctrl_enter, - .start = ehci_device_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * ehci interrupt support - *------------------------------------------------------------------------*/ -static void -ehci_device_intr_open(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - uint16_t best; - uint16_t bit; - uint16_t x; - uint8_t slot; - - /* Allocate a microframe slot first: */ - - slot = usb2_intr_schedule_adjust - (xfer->xroot->udev, xfer->max_frame_size, USB_HS_MICRO_FRAMES_MAX); - - if (usb2_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) { - xfer->usb2_uframe = slot; - xfer->usb2_smask = (1 << slot) & 0xFF; - xfer->usb2_cmask = 0; - } else { - xfer->usb2_uframe = slot; - xfer->usb2_smask = (1 << slot) & 0x3F; - xfer->usb2_cmask = (-(4 << slot)) & 0xFE; - } - - /* - * Find the best QH position corresponding to the given interval: - */ - - best = 0; - bit = EHCI_VIRTUAL_FRAMELIST_COUNT / 2; - while (bit) { - if (xfer->interval >= bit) { - x = bit; - best = bit; - while (x & bit) { - if (sc->sc_intr_stat[x] < - sc->sc_intr_stat[best]) { - best = x; - } - x++; - } - break; - } - bit >>= 1; - } - - sc->sc_intr_stat[best]++; - xfer->qh_pos = best; - - DPRINTFN(3, "best=%d interval=%d\n", - best, xfer->interval); -} - -static void -ehci_device_intr_close(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - uint8_t slot; - - slot = usb2_intr_schedule_adjust - (xfer->xroot->udev, -(xfer->max_frame_size), xfer->usb2_uframe); - - sc->sc_intr_stat[xfer->qh_pos]--; - - ehci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -ehci_device_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -ehci_device_intr_start(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - - /* setup TD's and QH */ - ehci_setup_standard_chain(xfer, &sc->sc_intr_p_last[xfer->qh_pos]); - - /* put transfer on interrupt queue */ - ehci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods ehci_device_intr_methods = -{ - .open = ehci_device_intr_open, - .close = ehci_device_intr_close, - .enter = ehci_device_intr_enter, - .start = ehci_device_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * ehci full speed isochronous support - *------------------------------------------------------------------------*/ -static void -ehci_device_isoc_fs_open(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - ehci_sitd_t *td; - uint32_t sitd_portaddr; - uint8_t ds; - - sitd_portaddr = - EHCI_SITD_SET_ADDR(xfer->address) | - EHCI_SITD_SET_ENDPT(UE_GET_ADDR(xfer->endpoint)) | - EHCI_SITD_SET_HUBA(xfer->xroot->udev->hs_hub_addr) | - EHCI_SITD_SET_PORT(xfer->xroot->udev->hs_port_no); - - if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) { - sitd_portaddr |= EHCI_SITD_SET_DIR_IN; - } - sitd_portaddr = htoehci32(sc, sitd_portaddr); - - /* initialize all TD's */ - - for (ds = 0; ds != 2; ds++) { - - for (td = xfer->td_start[ds]; td; td = td->obj_next) { - - td->sitd_portaddr = sitd_portaddr; - - /* - * TODO: make some kind of automatic - * SMASK/CMASK selection based on micro-frame - * usage - * - * micro-frame usage (8 microframes per 1ms) - */ - td->sitd_back = htoehci32(sc, EHCI_LINK_TERMINATE); - - usb2_pc_cpu_flush(td->page_cache); - } - } -} - -static void -ehci_device_isoc_fs_close(struct usb2_xfer *xfer) -{ - ehci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -ehci_device_isoc_fs_enter(struct usb2_xfer *xfer) -{ - struct usb2_page_search buf_res; - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - struct usb2_fs_isoc_schedule *fss_start; - struct usb2_fs_isoc_schedule *fss_end; - struct usb2_fs_isoc_schedule *fss; - ehci_sitd_t *td; - ehci_sitd_t *td_last = NULL; - ehci_sitd_t **pp_last; - uint32_t *plen; - uint32_t buf_offset; - uint32_t nframes; - uint32_t temp; - uint32_t sitd_mask; - uint16_t tlen; - uint8_t sa; - uint8_t sb; - uint8_t error; - -#if USB_DEBUG - uint8_t once = 1; - -#endif - - DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", - xfer, xfer->pipe->isoc_next, xfer->nframes); - - /* get the current frame index */ - - nframes = EOREAD4(sc, EHCI_FRINDEX) / 8; - - /* - * check if the frame index is within the window where the frames - * will be inserted - */ - buf_offset = (nframes - xfer->pipe->isoc_next) & - (EHCI_VIRTUAL_FRAMELIST_COUNT - 1); - - if ((xfer->pipe->is_synced == 0) || - (buf_offset < xfer->nframes)) { - /* - * If there is data underflow or the pipe queue is empty we - * schedule the transfer a few frames ahead of the current - * frame position. Else two isochronous transfers might - * overlap. - */ - xfer->pipe->isoc_next = (nframes + 3) & - (EHCI_VIRTUAL_FRAMELIST_COUNT - 1); - xfer->pipe->is_synced = 1; - DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next); - } - /* - * compute how many milliseconds the insertion is ahead of the - * current frame position: - */ - buf_offset = (xfer->pipe->isoc_next - nframes) & - (EHCI_VIRTUAL_FRAMELIST_COUNT - 1); - - /* - * pre-compute when the isochronous transfer will be finished: - */ - xfer->isoc_time_complete = - usb2_fs_isoc_schedule_isoc_time_expand - (xfer->xroot->udev, &fss_start, &fss_end, nframes) + buf_offset + - xfer->nframes; - - /* get the real number of frames */ - - nframes = xfer->nframes; - - buf_offset = 0; - - plen = xfer->frlengths; - - /* toggle the DMA set we are using */ - xfer->flags_int.curr_dma_set ^= 1; - - /* get next DMA set */ - td = xfer->td_start[xfer->flags_int.curr_dma_set]; - xfer->td_transfer_first = td; - - pp_last = &sc->sc_isoc_fs_p_last[xfer->pipe->isoc_next]; - - /* store starting position */ - - xfer->qh_pos = xfer->pipe->isoc_next; - - fss = fss_start + (xfer->qh_pos % USB_ISOC_TIME_MAX); - - while (nframes--) { - if (td == NULL) { - panic("%s:%d: out of TD's\n", - __FUNCTION__, __LINE__); - } - if (pp_last >= &sc->sc_isoc_fs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]) { - pp_last = &sc->sc_isoc_fs_p_last[0]; - } - if (fss >= fss_end) { - fss = fss_start; - } - /* reuse sitd_portaddr and sitd_back from last transfer */ - - if (*plen > xfer->max_frame_size) { -#if USB_DEBUG - if (once) { - once = 0; - printf("%s: frame length(%d) exceeds %d " - "bytes (frame truncated)\n", - __FUNCTION__, *plen, - xfer->max_frame_size); - } -#endif - *plen = xfer->max_frame_size; - } - /* - * We currently don't care if the ISOCHRONOUS schedule is - * full! - */ - error = usb2_fs_isoc_schedule_alloc(fss, &sa, *plen); - if (error) { - /* - * The FULL speed schedule is FULL! Set length - * to zero. - */ - *plen = 0; - } - if (*plen) { - /* - * only call "usb2_get_page()" when we have a - * non-zero length - */ - usb2_get_page(xfer->frbuffers, buf_offset, &buf_res); - td->sitd_bp[0] = htoehci32(sc, buf_res.physaddr); - buf_offset += *plen; - /* - * NOTE: We need to subtract one from the offset so - * that we are on a valid page! - */ - usb2_get_page(xfer->frbuffers, buf_offset - 1, - &buf_res); - temp = buf_res.physaddr & ~0xFFF; - } else { - td->sitd_bp[0] = 0; - temp = 0; - } - - if (UE_GET_DIR(xfer->endpoint) == UE_DIR_OUT) { - tlen = *plen; - if (tlen <= 188) { - temp |= 1; /* T-count = 1, TP = ALL */ - tlen = 1; - } else { - tlen += 187; - tlen /= 188; - temp |= tlen; /* T-count = [1..6] */ - temp |= 8; /* TP = Begin */ - } - - tlen += sa; - - if (tlen >= 8) { - sb = 0; - } else { - sb = (1 << tlen); - } - - sa = (1 << sa); - sa = (sb - sa) & 0x3F; - sb = 0; - } else { - sb = (-(4 << sa)) & 0xFE; - sa = (1 << sa) & 0x3F; - } - - sitd_mask = (EHCI_SITD_SET_SMASK(sa) | - EHCI_SITD_SET_CMASK(sb)); - - td->sitd_bp[1] = htoehci32(sc, temp); - - td->sitd_mask = htoehci32(sc, sitd_mask); - - if (nframes == 0) { - td->sitd_status = htole32 - (EHCI_SITD_IOC | - EHCI_SITD_ACTIVE | - EHCI_SITD_SET_LEN(*plen)); - } else { - td->sitd_status = htole32 - (EHCI_SITD_ACTIVE | - EHCI_SITD_SET_LEN(*plen)); - } - usb2_pc_cpu_flush(td->page_cache); - -#if USB_DEBUG - if (ehcidebug > 15) { - DPRINTF("FS-TD %d\n", nframes); - ehci_dump_sitd(sc, td); - } -#endif - /* insert TD into schedule */ - EHCI_APPEND_FS_TD(td, *pp_last); - pp_last++; - - plen++; - fss++; - td_last = td; - td = td->obj_next; - } - - xfer->td_transfer_last = td_last; - - /* update isoc_next */ - xfer->pipe->isoc_next = (pp_last - &sc->sc_isoc_fs_p_last[0]) & - (EHCI_VIRTUAL_FRAMELIST_COUNT - 1); -} - -static void -ehci_device_isoc_fs_start(struct usb2_xfer *xfer) -{ - /* put transfer on interrupt queue */ - ehci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods ehci_device_isoc_fs_methods = -{ - .open = ehci_device_isoc_fs_open, - .close = ehci_device_isoc_fs_close, - .enter = ehci_device_isoc_fs_enter, - .start = ehci_device_isoc_fs_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * ehci high speed isochronous support - *------------------------------------------------------------------------*/ -static void -ehci_device_isoc_hs_open(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - ehci_itd_t *td; - uint32_t temp; - uint8_t ds; - - /* initialize all TD's */ - - for (ds = 0; ds != 2; ds++) { - - for (td = xfer->td_start[ds]; td; td = td->obj_next) { - - /* set TD inactive */ - td->itd_status[0] = 0; - td->itd_status[1] = 0; - td->itd_status[2] = 0; - td->itd_status[3] = 0; - td->itd_status[4] = 0; - td->itd_status[5] = 0; - td->itd_status[6] = 0; - td->itd_status[7] = 0; - - /* set endpoint and address */ - td->itd_bp[0] = htole32 - (EHCI_ITD_SET_ADDR(xfer->address) | - EHCI_ITD_SET_ENDPT(UE_GET_ADDR(xfer->endpoint))); - - temp = - EHCI_ITD_SET_MPL(xfer->max_packet_size & 0x7FF); - - /* set direction */ - if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) { - temp |= EHCI_ITD_SET_DIR_IN; - } - /* set maximum packet size */ - td->itd_bp[1] = htoehci32(sc, temp); - - /* set transfer multiplier */ - td->itd_bp[2] = htoehci32(sc, xfer->max_packet_count & 3); - - usb2_pc_cpu_flush(td->page_cache); - } - } -} - -static void -ehci_device_isoc_hs_close(struct usb2_xfer *xfer) -{ - ehci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -ehci_device_isoc_hs_enter(struct usb2_xfer *xfer) -{ - struct usb2_page_search buf_res; - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - ehci_itd_t *td; - ehci_itd_t *td_last = NULL; - ehci_itd_t **pp_last; - bus_size_t page_addr; - uint32_t *plen; - uint32_t status; - uint32_t buf_offset; - uint32_t nframes; - uint32_t itd_offset[8 + 1]; - uint8_t x; - uint8_t td_no; - uint8_t page_no; - -#if USB_DEBUG - uint8_t once = 1; - -#endif - - DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", - xfer, xfer->pipe->isoc_next, xfer->nframes); - - /* get the current frame index */ - - nframes = EOREAD4(sc, EHCI_FRINDEX) / 8; - - /* - * check if the frame index is within the window where the frames - * will be inserted - */ - buf_offset = (nframes - xfer->pipe->isoc_next) & - (EHCI_VIRTUAL_FRAMELIST_COUNT - 1); - - if ((xfer->pipe->is_synced == 0) || - (buf_offset < ((xfer->nframes + 7) / 8))) { - /* - * If there is data underflow or the pipe queue is empty we - * schedule the transfer a few frames ahead of the current - * frame position. Else two isochronous transfers might - * overlap. - */ - xfer->pipe->isoc_next = (nframes + 3) & - (EHCI_VIRTUAL_FRAMELIST_COUNT - 1); - xfer->pipe->is_synced = 1; - DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next); - } - /* - * compute how many milliseconds the insertion is ahead of the - * current frame position: - */ - buf_offset = (xfer->pipe->isoc_next - nframes) & - (EHCI_VIRTUAL_FRAMELIST_COUNT - 1); - - /* - * pre-compute when the isochronous transfer will be finished: - */ - xfer->isoc_time_complete = - usb2_isoc_time_expand(&sc->sc_bus, nframes) + buf_offset + - ((xfer->nframes + 7) / 8); - - /* get the real number of frames */ - - nframes = xfer->nframes; - - buf_offset = 0; - td_no = 0; - - plen = xfer->frlengths; - - /* toggle the DMA set we are using */ - xfer->flags_int.curr_dma_set ^= 1; - - /* get next DMA set */ - td = xfer->td_start[xfer->flags_int.curr_dma_set]; - xfer->td_transfer_first = td; - - pp_last = &sc->sc_isoc_hs_p_last[xfer->pipe->isoc_next]; - - /* store starting position */ - - xfer->qh_pos = xfer->pipe->isoc_next; - - while (nframes--) { - if (td == NULL) { - panic("%s:%d: out of TD's\n", - __FUNCTION__, __LINE__); - } - if (pp_last >= &sc->sc_isoc_hs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]) { - pp_last = &sc->sc_isoc_hs_p_last[0]; - } - /* range check */ - if (*plen > xfer->max_frame_size) { -#if USB_DEBUG - if (once) { - once = 0; - printf("%s: frame length(%d) exceeds %d bytes " - "(frame truncated)\n", - __FUNCTION__, *plen, xfer->max_frame_size); - } -#endif - *plen = xfer->max_frame_size; - } - status = (EHCI_ITD_SET_LEN(*plen) | - EHCI_ITD_ACTIVE | - EHCI_ITD_SET_PG(0)); - td->itd_status[td_no] = htoehci32(sc, status); - itd_offset[td_no] = buf_offset; - buf_offset += *plen; - plen++; - td_no++; - - if ((td_no == 8) || (nframes == 0)) { - - /* the rest of the transfers are not active, if any */ - for (x = td_no; x != 8; x++) { - td->itd_status[x] = 0; /* not active */ - } - - /* check if there is any data to be transferred */ - if (itd_offset[0] != buf_offset) { - page_no = 0; - itd_offset[td_no] = buf_offset; - - /* get first page offset */ - usb2_get_page(xfer->frbuffers, itd_offset[0], &buf_res); - /* get page address */ - page_addr = buf_res.physaddr & ~0xFFF; - /* update page address */ - td->itd_bp[0] &= htoehci32(sc, 0xFFF); - td->itd_bp[0] |= htoehci32(sc, page_addr); - - for (x = 0; x != td_no; x++) { - /* set page number and page offset */ - status = (EHCI_ITD_SET_PG(page_no) | - (buf_res.physaddr & 0xFFF)); - td->itd_status[x] |= htoehci32(sc, status); - - /* get next page offset */ - if (itd_offset[x + 1] == buf_offset) { - /* - * We subtract one so that - * we don't go off the last - * page! - */ - usb2_get_page(xfer->frbuffers, buf_offset - 1, &buf_res); - } else { - usb2_get_page(xfer->frbuffers, itd_offset[x + 1], &buf_res); - } - - /* check if we need a new page */ - if ((buf_res.physaddr ^ page_addr) & ~0xFFF) { - /* new page needed */ - page_addr = buf_res.physaddr & ~0xFFF; - if (page_no == 6) { - panic("%s: too many pages\n", __FUNCTION__); - } - page_no++; - /* update page address */ - td->itd_bp[page_no] &= htoehci32(sc, 0xFFF); - td->itd_bp[page_no] |= htoehci32(sc, page_addr); - } - } - } - /* set IOC bit if we are complete */ - if (nframes == 0) { - td->itd_status[7] |= htoehci32(sc, EHCI_ITD_IOC); - } - usb2_pc_cpu_flush(td->page_cache); -#if USB_DEBUG - if (ehcidebug > 15) { - DPRINTF("HS-TD %d\n", nframes); - ehci_dump_itd(sc, td); - } -#endif - /* insert TD into schedule */ - EHCI_APPEND_HS_TD(td, *pp_last); - pp_last++; - - td_no = 0; - td_last = td; - td = td->obj_next; - } - } - - xfer->td_transfer_last = td_last; - - /* update isoc_next */ - xfer->pipe->isoc_next = (pp_last - &sc->sc_isoc_hs_p_last[0]) & - (EHCI_VIRTUAL_FRAMELIST_COUNT - 1); -} - -static void -ehci_device_isoc_hs_start(struct usb2_xfer *xfer) -{ - /* put transfer on interrupt queue */ - ehci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods ehci_device_isoc_hs_methods = -{ - .open = ehci_device_isoc_hs_open, - .close = ehci_device_isoc_hs_close, - .enter = ehci_device_isoc_hs_enter, - .start = ehci_device_isoc_hs_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * ehci root control support - *------------------------------------------------------------------------* - * simulate a hardware hub by handling - * all the necessary requests - *------------------------------------------------------------------------*/ - -static void -ehci_root_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -ehci_root_ctrl_close(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_ctrl.xfer == xfer) { - sc->sc_root_ctrl.xfer = NULL; - } - ehci_device_done(xfer, USB_ERR_CANCELLED); -} - -/* data structures and routines - * to emulate the root hub: - */ - -static const -struct usb2_device_descriptor ehci_devd = -{ - sizeof(struct usb2_device_descriptor), - UDESC_DEVICE, /* type */ - {0x00, 0x02}, /* USB version */ - UDCLASS_HUB, /* class */ - UDSUBCLASS_HUB, /* subclass */ - UDPROTO_HSHUBSTT, /* protocol */ - 64, /* max packet */ - {0}, {0}, {0x00, 0x01}, /* device id */ - 1, 2, 0, /* string indicies */ - 1 /* # of configurations */ -}; - -static const -struct usb2_device_qualifier ehci_odevd = -{ - sizeof(struct usb2_device_qualifier), - UDESC_DEVICE_QUALIFIER, /* type */ - {0x00, 0x02}, /* USB version */ - UDCLASS_HUB, /* class */ - UDSUBCLASS_HUB, /* subclass */ - UDPROTO_FSHUB, /* protocol */ - 0, /* max packet */ - 0, /* # of configurations */ - 0 -}; - -static const struct ehci_config_desc ehci_confd = { - .confd = { - .bLength = sizeof(struct usb2_config_descriptor), - .bDescriptorType = UDESC_CONFIG, - .wTotalLength[0] = sizeof(ehci_confd), - .bNumInterface = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = UC_SELF_POWERED, - .bMaxPower = 0 /* max power */ - }, - - .ifcd = { - .bLength = sizeof(struct usb2_interface_descriptor), - .bDescriptorType = UDESC_INTERFACE, - .bNumEndpoints = 1, - .bInterfaceClass = UICLASS_HUB, - .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_HSHUBSTT, - 0 - }, - - .endpd = { - .bLength = sizeof(struct usb2_endpoint_descriptor), - .bDescriptorType = UDESC_ENDPOINT, - .bEndpointAddress = UE_DIR_IN | EHCI_INTR_ENDPT, - .bmAttributes = UE_INTERRUPT, - .wMaxPacketSize[0] = 8, /* max packet (63 ports) */ - .bInterval = 255, - }, -}; - -static const -struct usb2_hub_descriptor ehci_hubd = -{ - 0, /* dynamic length */ - UDESC_HUB, - 0, - {0, 0}, - 0, - 0, - {0}, -}; - -static void -ehci_disown(ehci_softc_t *sc, uint16_t index, uint8_t lowspeed) -{ - uint32_t port; - uint32_t v; - - DPRINTF("index=%d lowspeed=%d\n", index, lowspeed); - - port = EHCI_PORTSC(index); - v = EOREAD4(sc, port) & ~EHCI_PS_CLEAR; - EOWRITE4(sc, port, v | EHCI_PS_PO); -} - -static void -ehci_root_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -ehci_root_ctrl_start(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - - DPRINTF("\n"); - - sc->sc_root_ctrl.xfer = xfer; - - usb2_bus_roothub_exec(xfer->xroot->bus); -} - -static void -ehci_root_ctrl_task(struct usb2_bus *bus) -{ - ehci_root_ctrl_poll(EHCI_BUS2SC(bus)); -} - -static void -ehci_root_ctrl_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - char *ptr; - uint32_t port; - uint32_t v; - uint16_t i; - uint16_t value; - uint16_t index; - uint8_t l; - uint8_t use_polling; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_SETUP) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - ehci_device_done(xfer, std->err); - } - goto done; - } - /* buffer reset */ - std->ptr = sc->sc_hub_desc.temp; - std->len = 0; - - value = UGETW(std->req.wValue); - index = UGETW(std->req.wIndex); - - use_polling = mtx_owned(xfer->xroot->xfer_mtx) ? 1 : 0; - - DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x " - "wValue=0x%04x wIndex=0x%04x\n", - std->req.bmRequestType, std->req.bRequest, - UGETW(std->req.wLength), value, index); - -#define C(x,y) ((x) | ((y) << 8)) - switch (C(std->req.bRequest, std->req.bmRequestType)) { - case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): - case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): - case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): - /* - * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops - * for the integrated root hub. - */ - break; - case C(UR_GET_CONFIG, UT_READ_DEVICE): - std->len = 1; - sc->sc_hub_desc.temp[0] = sc->sc_conf; - break; - case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): - switch (value >> 8) { - case UDESC_DEVICE: - if ((value & 0xff) != 0) { - std->err = USB_ERR_IOERROR; - goto done; - } - std->len = sizeof(ehci_devd); - sc->sc_hub_desc.devd = ehci_devd; - break; - /* - * We can't really operate at another speed, - * but the specification says we need this - * descriptor: - */ - case UDESC_DEVICE_QUALIFIER: - if ((value & 0xff) != 0) { - std->err = USB_ERR_IOERROR; - goto done; - } - std->len = sizeof(ehci_odevd); - sc->sc_hub_desc.odevd = ehci_odevd; - break; - - case UDESC_CONFIG: - if ((value & 0xff) != 0) { - std->err = USB_ERR_IOERROR; - goto done; - } - std->len = sizeof(ehci_confd); - std->ptr = USB_ADD_BYTES(&ehci_confd, 0); - break; - - case UDESC_STRING: - switch (value & 0xff) { - case 0: /* Language table */ - ptr = "\001"; - break; - - case 1: /* Vendor */ - ptr = sc->sc_vendor; - break; - - case 2: /* Product */ - ptr = "EHCI root HUB"; - break; - - default: - ptr = ""; - break; - } - - std->len = usb2_make_str_desc - (sc->sc_hub_desc.temp, - sizeof(sc->sc_hub_desc.temp), - ptr); - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - break; - case C(UR_GET_INTERFACE, UT_READ_INTERFACE): - std->len = 1; - sc->sc_hub_desc.temp[0] = 0; - break; - case C(UR_GET_STATUS, UT_READ_DEVICE): - std->len = 2; - USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED); - break; - case C(UR_GET_STATUS, UT_READ_INTERFACE): - case C(UR_GET_STATUS, UT_READ_ENDPOINT): - std->len = 2; - USETW(sc->sc_hub_desc.stat.wStatus, 0); - break; - case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): - if (value >= USB_MAX_DEVICES) { - std->err = USB_ERR_IOERROR; - goto done; - } - sc->sc_addr = value; - break; - case C(UR_SET_CONFIG, UT_WRITE_DEVICE): - if ((value != 0) && (value != 1)) { - std->err = USB_ERR_IOERROR; - goto done; - } - sc->sc_conf = value; - break; - case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): - break; - case C(UR_SET_FEATURE, UT_WRITE_DEVICE): - case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): - case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): - std->err = USB_ERR_IOERROR; - goto done; - case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): - break; - case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): - break; - /* Hub requests */ - case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): - break; - case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): - DPRINTFN(9, "UR_CLEAR_PORT_FEATURE\n"); - - if ((index < 1) || - (index > sc->sc_noport)) { - std->err = USB_ERR_IOERROR; - goto done; - } - port = EHCI_PORTSC(index); - v = EOREAD4(sc, port) & ~EHCI_PS_CLEAR; - switch (value) { - case UHF_PORT_ENABLE: - EOWRITE4(sc, port, v & ~EHCI_PS_PE); - break; - case UHF_PORT_SUSPEND: - if ((v & EHCI_PS_SUSP) && (!(v & EHCI_PS_FPR))) { - - /* - * waking up a High Speed device is rather - * complicated if - */ - EOWRITE4(sc, port, v | EHCI_PS_FPR); - } - /* wait 20ms for resume sequence to complete */ - if (use_polling) { - /* polling */ - DELAY(20000); - } else { - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 50); - } - - EOWRITE4(sc, port, v & ~(EHCI_PS_SUSP | - EHCI_PS_FPR | (3 << 10) /* High Speed */ )); - - /* settle time */ - if (use_polling) { - /* polling */ - DELAY(4000); - } else { - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 250); - } - break; - case UHF_PORT_POWER: - EOWRITE4(sc, port, v & ~EHCI_PS_PP); - break; - case UHF_PORT_TEST: - DPRINTFN(3, "clear port test " - "%d\n", index); - break; - case UHF_PORT_INDICATOR: - DPRINTFN(3, "clear port ind " - "%d\n", index); - EOWRITE4(sc, port, v & ~EHCI_PS_PIC); - break; - case UHF_C_PORT_CONNECTION: - EOWRITE4(sc, port, v | EHCI_PS_CSC); - break; - case UHF_C_PORT_ENABLE: - EOWRITE4(sc, port, v | EHCI_PS_PEC); - break; - case UHF_C_PORT_SUSPEND: - EOWRITE4(sc, port, v | EHCI_PS_SUSP); - break; - case UHF_C_PORT_OVER_CURRENT: - EOWRITE4(sc, port, v | EHCI_PS_OCC); - break; - case UHF_C_PORT_RESET: - sc->sc_isreset = 0; - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - break; - case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): - if ((value & 0xff) != 0) { - std->err = USB_ERR_IOERROR; - goto done; - } - v = EOREAD4(sc, EHCI_HCSPARAMS); - - sc->sc_hub_desc.hubd = ehci_hubd; - sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport; - USETW(sc->sc_hub_desc.hubd.wHubCharacteristics, - (EHCI_HCS_PPC(v) ? UHD_PWR_INDIVIDUAL : UHD_PWR_NO_SWITCH) | - (EHCI_HCS_P_INDICATOR(EREAD4(sc, EHCI_HCSPARAMS)) ? - UHD_PORT_IND : 0)); - /* XXX can't find out? */ - sc->sc_hub_desc.hubd.bPwrOn2PwrGood = 200; - for (l = 0; l < sc->sc_noport; l++) { - /* XXX can't find out? */ - sc->sc_hub_desc.hubd.DeviceRemovable[l / 8] &= ~(1 << (l % 8)); - } - sc->sc_hub_desc.hubd.bDescLength = - 8 + ((sc->sc_noport + 7) / 8); - std->len = sc->sc_hub_desc.hubd.bDescLength; - break; - case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): - std->len = 16; - bzero(sc->sc_hub_desc.temp, 16); - break; - case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): - DPRINTFN(9, "get port status i=%d\n", - index); - if ((index < 1) || - (index > sc->sc_noport)) { - std->err = USB_ERR_IOERROR; - goto done; - } - v = EOREAD4(sc, EHCI_PORTSC(index)); - DPRINTFN(9, "port status=0x%04x\n", v); - if (sc->sc_flags & EHCI_SCFLG_FORCESPEED) { - if ((v & 0xc000000) == 0x8000000) - i = UPS_HIGH_SPEED; - else if ((v & 0xc000000) == 0x4000000) - i = UPS_LOW_SPEED; - else - i = 0; - } else { - i = UPS_HIGH_SPEED; - } - if (v & EHCI_PS_CS) - i |= UPS_CURRENT_CONNECT_STATUS; - if (v & EHCI_PS_PE) - i |= UPS_PORT_ENABLED; - if ((v & EHCI_PS_SUSP) && !(v & EHCI_PS_FPR)) - i |= UPS_SUSPEND; - if (v & EHCI_PS_OCA) - i |= UPS_OVERCURRENT_INDICATOR; - if (v & EHCI_PS_PR) - i |= UPS_RESET; - if (v & EHCI_PS_PP) - i |= UPS_PORT_POWER; - USETW(sc->sc_hub_desc.ps.wPortStatus, i); - i = 0; - if (v & EHCI_PS_CSC) - i |= UPS_C_CONNECT_STATUS; - if (v & EHCI_PS_PEC) - i |= UPS_C_PORT_ENABLED; - if (v & EHCI_PS_OCC) - i |= UPS_C_OVERCURRENT_INDICATOR; - if (v & EHCI_PS_FPR) - i |= UPS_C_SUSPEND; - if (sc->sc_isreset) - i |= UPS_C_PORT_RESET; - USETW(sc->sc_hub_desc.ps.wPortChange, i); - std->len = sizeof(sc->sc_hub_desc.ps); - break; - case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): - std->err = USB_ERR_IOERROR; - goto done; - case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): - break; - case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): - if ((index < 1) || - (index > sc->sc_noport)) { - std->err = USB_ERR_IOERROR; - goto done; - } - port = EHCI_PORTSC(index); - v = EOREAD4(sc, port) & ~EHCI_PS_CLEAR; - switch (value) { - case UHF_PORT_ENABLE: - EOWRITE4(sc, port, v | EHCI_PS_PE); - break; - case UHF_PORT_SUSPEND: - EOWRITE4(sc, port, v | EHCI_PS_SUSP); - break; - case UHF_PORT_RESET: - DPRINTFN(6, "reset port %d\n", index); -#if USB_DEBUG - if (ehcinohighspeed) { - /* - * Connect USB device to companion - * controller. - */ - ehci_disown(sc, index, 1); - break; - } -#endif - if (EHCI_PS_IS_LOWSPEED(v)) { - /* Low speed device, give up ownership. */ - ehci_disown(sc, index, 1); - break; - } - /* Start reset sequence. */ - v &= ~(EHCI_PS_PE | EHCI_PS_PR); - EOWRITE4(sc, port, v | EHCI_PS_PR); - - if (use_polling) { - /* polling */ - DELAY(USB_PORT_ROOT_RESET_DELAY * 1000); - } else { - /* Wait for reset to complete. */ - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_PORT_ROOT_RESET_DELAY)); - } - - /* Terminate reset sequence. */ - if (!(sc->sc_flags & EHCI_SCFLG_NORESTERM)) - EOWRITE4(sc, port, v); - - if (use_polling) { - /* polling */ - DELAY(EHCI_PORT_RESET_COMPLETE * 1000); - } else { - /* Wait for HC to complete reset. */ - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(EHCI_PORT_RESET_COMPLETE)); - } - - v = EOREAD4(sc, port); - DPRINTF("ehci after reset, status=0x%08x\n", v); - if (v & EHCI_PS_PR) { - device_printf(sc->sc_bus.bdev, - "port reset timeout\n"); - std->err = USB_ERR_TIMEOUT; - goto done; - } - if (!(v & EHCI_PS_PE)) { - /* - * Not a high speed device, give up - * ownership. - */ - ehci_disown(sc, index, 0); - break; - } - sc->sc_isreset = 1; - DPRINTF("ehci port %d reset, status = 0x%08x\n", - index, v); - break; - - case UHF_PORT_POWER: - DPRINTFN(3, "set port power %d\n", index); - EOWRITE4(sc, port, v | EHCI_PS_PP); - break; - - case UHF_PORT_TEST: - DPRINTFN(3, "set port test %d\n", index); - break; - - case UHF_PORT_INDICATOR: - DPRINTFN(3, "set port ind %d\n", index); - EOWRITE4(sc, port, v | EHCI_PS_PIC); - break; - - default: - std->err = USB_ERR_IOERROR; - goto done; - } - break; - case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER): - case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER): - case C(UR_GET_TT_STATE, UT_READ_CLASS_OTHER): - case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER): - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } -done: - return; -} - -static void -ehci_root_ctrl_poll(ehci_softc_t *sc) -{ - usb2_sw_transfer(&sc->sc_root_ctrl, - &ehci_root_ctrl_done); -} - -struct usb2_pipe_methods ehci_root_ctrl_methods = -{ - .open = ehci_root_ctrl_open, - .close = ehci_root_ctrl_close, - .enter = ehci_root_ctrl_enter, - .start = ehci_root_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 0, -}; - -/*------------------------------------------------------------------------* - * ehci root interrupt support - *------------------------------------------------------------------------*/ -static void -ehci_root_intr_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -ehci_root_intr_close(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_intr.xfer == xfer) { - sc->sc_root_intr.xfer = NULL; - } - ehci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -ehci_root_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -ehci_root_intr_start(struct usb2_xfer *xfer) -{ - ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - - sc->sc_root_intr.xfer = xfer; -} - -struct usb2_pipe_methods ehci_root_intr_methods = -{ - .open = ehci_root_intr_open, - .close = ehci_root_intr_close, - .enter = ehci_root_intr_enter, - .start = ehci_root_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -static void -ehci_xfer_setup(struct usb2_setup_params *parm) -{ - struct usb2_page_search page_info; - struct usb2_page_cache *pc; - ehci_softc_t *sc; - struct usb2_xfer *xfer; - void *last_obj; - uint32_t nqtd; - uint32_t nqh; - uint32_t nsitd; - uint32_t nitd; - uint32_t n; - - sc = EHCI_BUS2SC(parm->udev->bus); - xfer = parm->curr_xfer; - - nqtd = 0; - nqh = 0; - nsitd = 0; - nitd = 0; - - /* - * compute maximum number of some structures - */ - if (parm->methods == &ehci_device_ctrl_methods) { - - /* - * The proof for the "nqtd" formula is illustrated like - * this: - * - * +------------------------------------+ - * | | - * | |remainder -> | - * | +-----+---+ | - * | | xxx | x | frm 0 | - * | +-----+---++ | - * | | xxx | xx | frm 1 | - * | +-----+----+ | - * | ... | - * +------------------------------------+ - * - * "xxx" means a completely full USB transfer descriptor - * - * "x" and "xx" means a short USB packet - * - * For the remainder of an USB transfer modulo - * "max_data_length" we need two USB transfer descriptors. - * One to transfer the remaining data and one to finalise - * with a zero length packet in case the "force_short_xfer" - * flag is set. We only need two USB transfer descriptors in - * the case where the transfer length of the first one is a - * factor of "max_frame_size". The rest of the needed USB - * transfer descriptors is given by the buffer size divided - * by the maximum data payload. - */ - parm->hc_max_packet_size = 0x400; - parm->hc_max_packet_count = 1; - parm->hc_max_frame_size = EHCI_QTD_PAYLOAD_MAX; - xfer->flags_int.bdma_enable = 1; - - usb2_transfer_setup_sub(parm); - - nqh = 1; - nqtd = ((2 * xfer->nframes) + 1 /* STATUS */ - + (xfer->max_data_length / xfer->max_usb2_frame_size)); - - } else if (parm->methods == &ehci_device_bulk_methods) { - - parm->hc_max_packet_size = 0x400; - parm->hc_max_packet_count = 1; - parm->hc_max_frame_size = EHCI_QTD_PAYLOAD_MAX; - xfer->flags_int.bdma_enable = 1; - - usb2_transfer_setup_sub(parm); - - nqh = 1; - nqtd = ((2 * xfer->nframes) - + (xfer->max_data_length / xfer->max_usb2_frame_size)); - - } else if (parm->methods == &ehci_device_intr_methods) { - - if (parm->speed == USB_SPEED_HIGH) { - parm->hc_max_packet_size = 0x400; - parm->hc_max_packet_count = 3; - } else if (parm->speed == USB_SPEED_FULL) { - parm->hc_max_packet_size = USB_FS_BYTES_PER_HS_UFRAME; - parm->hc_max_packet_count = 1; - } else { - parm->hc_max_packet_size = USB_FS_BYTES_PER_HS_UFRAME / 8; - parm->hc_max_packet_count = 1; - } - - parm->hc_max_frame_size = EHCI_QTD_PAYLOAD_MAX; - xfer->flags_int.bdma_enable = 1; - - usb2_transfer_setup_sub(parm); - - nqh = 1; - nqtd = ((2 * xfer->nframes) - + (xfer->max_data_length / xfer->max_usb2_frame_size)); - - } else if (parm->methods == &ehci_device_isoc_fs_methods) { - - parm->hc_max_packet_size = 0x3FF; - parm->hc_max_packet_count = 1; - parm->hc_max_frame_size = 0x3FF; - xfer->flags_int.bdma_enable = 1; - - usb2_transfer_setup_sub(parm); - - nsitd = xfer->nframes; - - } else if (parm->methods == &ehci_device_isoc_hs_methods) { - - parm->hc_max_packet_size = 0x400; - parm->hc_max_packet_count = 3; - parm->hc_max_frame_size = 0xC00; - xfer->flags_int.bdma_enable = 1; - - usb2_transfer_setup_sub(parm); - - nitd = (xfer->nframes + 7) / 8; - - } else { - - parm->hc_max_packet_size = 0x400; - parm->hc_max_packet_count = 1; - parm->hc_max_frame_size = 0x400; - - usb2_transfer_setup_sub(parm); - } - -alloc_dma_set: - - if (parm->err) { - return; - } - /* - * Allocate queue heads and transfer descriptors - */ - last_obj = NULL; - - if (usb2_transfer_setup_sub_malloc( - parm, &pc, sizeof(ehci_itd_t), - EHCI_ITD_ALIGN, nitd)) { - parm->err = USB_ERR_NOMEM; - return; - } - if (parm->buf) { - for (n = 0; n != nitd; n++) { - ehci_itd_t *td; - - usb2_get_page(pc + n, 0, &page_info); - - td = page_info.buffer; - - /* init TD */ - td->itd_self = htoehci32(sc, page_info.physaddr | EHCI_LINK_ITD); - td->obj_next = last_obj; - td->page_cache = pc + n; - - last_obj = td; - - usb2_pc_cpu_flush(pc + n); - } - } - if (usb2_transfer_setup_sub_malloc( - parm, &pc, sizeof(ehci_sitd_t), - EHCI_SITD_ALIGN, nsitd)) { - parm->err = USB_ERR_NOMEM; - return; - } - if (parm->buf) { - for (n = 0; n != nsitd; n++) { - ehci_sitd_t *td; - - usb2_get_page(pc + n, 0, &page_info); - - td = page_info.buffer; - - /* init TD */ - td->sitd_self = htoehci32(sc, page_info.physaddr | EHCI_LINK_SITD); - td->obj_next = last_obj; - td->page_cache = pc + n; - - last_obj = td; - - usb2_pc_cpu_flush(pc + n); - } - } - if (usb2_transfer_setup_sub_malloc( - parm, &pc, sizeof(ehci_qtd_t), - EHCI_QTD_ALIGN, nqtd)) { - parm->err = USB_ERR_NOMEM; - return; - } - if (parm->buf) { - for (n = 0; n != nqtd; n++) { - ehci_qtd_t *qtd; - - usb2_get_page(pc + n, 0, &page_info); - - qtd = page_info.buffer; - - /* init TD */ - qtd->qtd_self = htoehci32(sc, page_info.physaddr); - qtd->obj_next = last_obj; - qtd->page_cache = pc + n; - - last_obj = qtd; - - usb2_pc_cpu_flush(pc + n); - } - } - xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; - - last_obj = NULL; - - if (usb2_transfer_setup_sub_malloc( - parm, &pc, sizeof(ehci_qh_t), - EHCI_QH_ALIGN, nqh)) { - parm->err = USB_ERR_NOMEM; - return; - } - if (parm->buf) { - for (n = 0; n != nqh; n++) { - ehci_qh_t *qh; - - usb2_get_page(pc + n, 0, &page_info); - - qh = page_info.buffer; - - /* init QH */ - qh->qh_self = htoehci32(sc, page_info.physaddr | EHCI_LINK_QH); - qh->obj_next = last_obj; - qh->page_cache = pc + n; - - last_obj = qh; - - usb2_pc_cpu_flush(pc + n); - } - } - xfer->qh_start[xfer->flags_int.curr_dma_set] = last_obj; - - if (!xfer->flags_int.curr_dma_set) { - xfer->flags_int.curr_dma_set = 1; - goto alloc_dma_set; - } -} - -static void -ehci_xfer_unsetup(struct usb2_xfer *xfer) -{ - return; -} - -static void -ehci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, - struct usb2_pipe *pipe) -{ - ehci_softc_t *sc = EHCI_BUS2SC(udev->bus); - - DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", - pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, - sc->sc_addr); - - if (udev->flags.usb2_mode != USB_MODE_HOST) { - /* not supported */ - return; - } - if (udev->device_index == sc->sc_addr) { - switch (edesc->bEndpointAddress) { - case USB_CONTROL_ENDPOINT: - pipe->methods = &ehci_root_ctrl_methods; - break; - case UE_DIR_IN | EHCI_INTR_ENDPT: - pipe->methods = &ehci_root_intr_methods; - break; - default: - /* do nothing */ - break; - } - } else { - if ((udev->speed != USB_SPEED_HIGH) && - ((udev->hs_hub_addr == 0) || - (udev->hs_port_no == 0) || - (udev->bus->devices[udev->hs_hub_addr] == NULL) || - (udev->bus->devices[udev->hs_hub_addr]->hub == NULL))) { - /* We need a transaction translator */ - goto done; - } - switch (edesc->bmAttributes & UE_XFERTYPE) { - case UE_CONTROL: - pipe->methods = &ehci_device_ctrl_methods; - break; - case UE_INTERRUPT: - pipe->methods = &ehci_device_intr_methods; - break; - case UE_ISOCHRONOUS: - if (udev->speed == USB_SPEED_HIGH) { - pipe->methods = &ehci_device_isoc_hs_methods; - } else if (udev->speed == USB_SPEED_FULL) { - pipe->methods = &ehci_device_isoc_fs_methods; - } - break; - case UE_BULK: - if (udev->speed != USB_SPEED_LOW) { - pipe->methods = &ehci_device_bulk_methods; - } - break; - default: - /* do nothing */ - break; - } - } -done: - return; -} - -static void -ehci_get_dma_delay(struct usb2_bus *bus, uint32_t *pus) -{ - /* - * Wait until the hardware has finished any possible use of - * the transfer descriptor(s) and QH - */ - *pus = (188); /* microseconds */ -} - -static void -ehci_device_resume(struct usb2_device *udev) -{ - ehci_softc_t *sc = EHCI_BUS2SC(udev->bus); - struct usb2_xfer *xfer; - struct usb2_pipe_methods *methods; - - DPRINTF("\n"); - - USB_BUS_LOCK(udev->bus); - - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - - if (xfer->xroot->udev == udev) { - - methods = xfer->pipe->methods; - - if ((methods == &ehci_device_bulk_methods) || - (methods == &ehci_device_ctrl_methods)) { - EHCI_APPEND_QH(xfer->qh_start[xfer->flags_int.curr_dma_set], - sc->sc_async_p_last); - } - if (methods == &ehci_device_intr_methods) { - EHCI_APPEND_QH(xfer->qh_start[xfer->flags_int.curr_dma_set], - sc->sc_intr_p_last[xfer->qh_pos]); - } - } - } - - USB_BUS_UNLOCK(udev->bus); - - return; -} - -static void -ehci_device_suspend(struct usb2_device *udev) -{ - ehci_softc_t *sc = EHCI_BUS2SC(udev->bus); - struct usb2_xfer *xfer; - struct usb2_pipe_methods *methods; - - DPRINTF("\n"); - - USB_BUS_LOCK(udev->bus); - - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - - if (xfer->xroot->udev == udev) { - - methods = xfer->pipe->methods; - - if ((methods == &ehci_device_bulk_methods) || - (methods == &ehci_device_ctrl_methods)) { - EHCI_REMOVE_QH(xfer->qh_start[xfer->flags_int.curr_dma_set], - sc->sc_async_p_last); - } - if (methods == &ehci_device_intr_methods) { - EHCI_REMOVE_QH(xfer->qh_start[xfer->flags_int.curr_dma_set], - sc->sc_intr_p_last[xfer->qh_pos]); - } - } - } - - USB_BUS_UNLOCK(udev->bus); - - return; -} - -static void -ehci_set_hw_power(struct usb2_bus *bus) -{ - ehci_softc_t *sc = EHCI_BUS2SC(bus); - uint32_t temp; - uint32_t flags; - - DPRINTF("\n"); - - USB_BUS_LOCK(bus); - - flags = bus->hw_power_state; - - temp = EOREAD4(sc, EHCI_USBCMD); - - temp &= ~(EHCI_CMD_ASE | EHCI_CMD_PSE); - - if (flags & (USB_HW_POWER_CONTROL | - USB_HW_POWER_BULK)) { - DPRINTF("Async is active\n"); - temp |= EHCI_CMD_ASE; - } - if (flags & (USB_HW_POWER_INTERRUPT | - USB_HW_POWER_ISOC)) { - DPRINTF("Periodic is active\n"); - temp |= EHCI_CMD_PSE; - } - EOWRITE4(sc, EHCI_USBCMD, temp); - - USB_BUS_UNLOCK(bus); - - return; -} - -struct usb2_bus_methods ehci_bus_methods = -{ - .pipe_init = ehci_pipe_init, - .xfer_setup = ehci_xfer_setup, - .xfer_unsetup = ehci_xfer_unsetup, - .do_poll = ehci_do_poll, - .get_dma_delay = ehci_get_dma_delay, - .device_resume = ehci_device_resume, - .device_suspend = ehci_device_suspend, - .set_hw_power = ehci_set_hw_power, - .roothub_exec = ehci_root_ctrl_task, -}; diff --git a/sys/dev/usb2/controller/ehci2.h b/sys/dev/usb2/controller/ehci2.h deleted file mode 100644 index 9d7baa1..0000000 --- a/sys/dev/usb2/controller/ehci2.h +++ /dev/null @@ -1,532 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Lennart Augustsson (lennart@augustsson.net). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _EHCI_H_ -#define _EHCI_H_ - -#define EHCI_MAX_DEVICES USB_MAX_DEVICES - -/* PCI config registers */ -#define PCI_CBMEM 0x10 /* configuration base MEM */ -#define PCI_INTERFACE_EHCI 0x20 -#define PCI_USBREV 0x60 /* RO USB protocol revision */ -#define PCI_USB_REV_MASK 0xff -#define PCI_USB_REV_PRE_1_0 0x00 -#define PCI_USB_REV_1_0 0x10 -#define PCI_USB_REV_1_1 0x11 -#define PCI_USB_REV_2_0 0x20 -#define PCI_EHCI_FLADJ 0x61 /* RW Frame len adj, SOF=59488+6*fladj */ -#define PCI_EHCI_PORTWAKECAP 0x62 /* RW Port wake caps (opt) */ - -/* EHCI Extended Capabilities */ -#define EHCI_EC_LEGSUP 0x01 -#define EHCI_EECP_NEXT(x) (((x) >> 8) & 0xff) -#define EHCI_EECP_ID(x) ((x) & 0xff) - -/* Legacy support extended capability */ -#define EHCI_LEGSUP_BIOS_SEM 0x02 -#define EHCI_LEGSUP_OS_SEM 0x03 -#define EHCI_LEGSUP_USBLEGCTLSTS 0x04 - -/* EHCI capability registers */ -#define EHCI_CAPLENGTH 0x00 /* RO Capability register length field */ -/* reserved 0x01 */ -#define EHCI_HCIVERSION 0x02 /* RO Interface version number */ -#define EHCI_HCSPARAMS 0x04 /* RO Structural parameters */ -#define EHCI_HCS_DEBUGPORT(x) (((x) >> 20) & 0xf) -#define EHCI_HCS_P_INDICATOR(x) ((x) & 0x10000) -#define EHCI_HCS_N_CC(x) (((x) >> 12) & 0xf) /* # of companion ctlrs */ -#define EHCI_HCS_N_PCC(x) (((x) >> 8) & 0xf) /* # of ports per comp. */ -#define EHCI_HCS_PPC(x) ((x) & 0x10) /* port power control */ -#define EHCI_HCS_N_PORTS(x) ((x) & 0xf) /* # of ports */ -#define EHCI_HCCPARAMS 0x08 /* RO Capability parameters */ -#define EHCI_HCC_EECP(x) (((x) >> 8) & 0xff) /* extended ports caps */ -#define EHCI_HCC_IST(x) (((x) >> 4) & 0xf) /* isoc sched threshold */ -#define EHCI_HCC_ASPC(x) ((x) & 0x4) /* async sched park cap */ -#define EHCI_HCC_PFLF(x) ((x) & 0x2) /* prog frame list flag */ -#define EHCI_HCC_64BIT(x) ((x) & 0x1) /* 64 bit address cap */ -#define EHCI_HCSP_PORTROUTE 0x0c /* RO Companion port route description */ - -/* EHCI operational registers. Offset given by EHCI_CAPLENGTH register */ -#define EHCI_USBCMD 0x00 /* RO, RW, WO Command register */ -#define EHCI_CMD_ITC_M 0x00ff0000 /* RW interrupt threshold ctrl */ -#define EHCI_CMD_ITC_1 0x00010000 -#define EHCI_CMD_ITC_2 0x00020000 -#define EHCI_CMD_ITC_4 0x00040000 -#define EHCI_CMD_ITC_8 0x00080000 -#define EHCI_CMD_ITC_16 0x00100000 -#define EHCI_CMD_ITC_32 0x00200000 -#define EHCI_CMD_ITC_64 0x00400000 -#define EHCI_CMD_ASPME 0x00000800 /* RW/RO async park enable */ -#define EHCI_CMD_ASPMC 0x00000300 /* RW/RO async park count */ -#define EHCI_CMD_LHCR 0x00000080 /* RW light host ctrl reset */ -#define EHCI_CMD_IAAD 0x00000040 /* RW intr on async adv door - * bell */ -#define EHCI_CMD_ASE 0x00000020 /* RW async sched enable */ -#define EHCI_CMD_PSE 0x00000010 /* RW periodic sched enable */ -#define EHCI_CMD_FLS_M 0x0000000c /* RW/RO frame list size */ -#define EHCI_CMD_FLS(x) (((x) >> 2) & 3) /* RW/RO frame list size */ -#define EHCI_CMD_HCRESET 0x00000002 /* RW reset */ -#define EHCI_CMD_RS 0x00000001 /* RW run/stop */ -#define EHCI_USBSTS 0x04 /* RO, RW, RWC Status register */ -#define EHCI_STS_ASS 0x00008000 /* RO async sched status */ -#define EHCI_STS_PSS 0x00004000 /* RO periodic sched status */ -#define EHCI_STS_REC 0x00002000 /* RO reclamation */ -#define EHCI_STS_HCH 0x00001000 /* RO host controller halted */ -#define EHCI_STS_IAA 0x00000020 /* RWC interrupt on async adv */ -#define EHCI_STS_HSE 0x00000010 /* RWC host system error */ -#define EHCI_STS_FLR 0x00000008 /* RWC frame list rollover */ -#define EHCI_STS_PCD 0x00000004 /* RWC port change detect */ -#define EHCI_STS_ERRINT 0x00000002 /* RWC error interrupt */ -#define EHCI_STS_INT 0x00000001 /* RWC interrupt */ -#define EHCI_STS_INTRS(x) ((x) & 0x3f) - -/* - * NOTE: the doorbell interrupt is enabled, but the doorbell is never - * used! SiS chipsets require this. - */ -#define EHCI_NORMAL_INTRS (EHCI_STS_IAA | EHCI_STS_HSE | \ - EHCI_STS_PCD | EHCI_STS_ERRINT | EHCI_STS_INT) - -#define EHCI_USBINTR 0x08 /* RW Interrupt register */ -#define EHCI_INTR_IAAE 0x00000020 /* interrupt on async advance - * ena */ -#define EHCI_INTR_HSEE 0x00000010 /* host system error ena */ -#define EHCI_INTR_FLRE 0x00000008 /* frame list rollover ena */ -#define EHCI_INTR_PCIE 0x00000004 /* port change ena */ -#define EHCI_INTR_UEIE 0x00000002 /* USB error intr ena */ -#define EHCI_INTR_UIE 0x00000001 /* USB intr ena */ - -#define EHCI_FRINDEX 0x0c /* RW Frame Index register */ - -#define EHCI_CTRLDSSEGMENT 0x10 /* RW Control Data Structure Segment */ - -#define EHCI_PERIODICLISTBASE 0x14 /* RW Periodic List Base */ -#define EHCI_ASYNCLISTADDR 0x18 /* RW Async List Base */ - -#define EHCI_CONFIGFLAG 0x40 /* RW Configure Flag register */ -#define EHCI_CONF_CF 0x00000001 /* RW configure flag */ - -#define EHCI_PORTSC(n) (0x40+(4*(n))) /* RO, RW, RWC Port Status reg */ -#define EHCI_PS_WKOC_E 0x00400000 /* RW wake on over current ena */ -#define EHCI_PS_WKDSCNNT_E 0x00200000 /* RW wake on disconnect ena */ -#define EHCI_PS_WKCNNT_E 0x00100000 /* RW wake on connect ena */ -#define EHCI_PS_PTC 0x000f0000 /* RW port test control */ -#define EHCI_PS_PIC 0x0000c000 /* RW port indicator control */ -#define EHCI_PS_PO 0x00002000 /* RW port owner */ -#define EHCI_PS_PP 0x00001000 /* RW,RO port power */ -#define EHCI_PS_LS 0x00000c00 /* RO line status */ -#define EHCI_PS_IS_LOWSPEED(x) (((x) & EHCI_PS_LS) == 0x00000400) -#define EHCI_PS_PR 0x00000100 /* RW port reset */ -#define EHCI_PS_SUSP 0x00000080 /* RW suspend */ -#define EHCI_PS_FPR 0x00000040 /* RW force port resume */ -#define EHCI_PS_OCC 0x00000020 /* RWC over current change */ -#define EHCI_PS_OCA 0x00000010 /* RO over current active */ -#define EHCI_PS_PEC 0x00000008 /* RWC port enable change */ -#define EHCI_PS_PE 0x00000004 /* RW port enable */ -#define EHCI_PS_CSC 0x00000002 /* RWC connect status change */ -#define EHCI_PS_CS 0x00000001 /* RO connect status */ -#define EHCI_PS_CLEAR (EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC) - -#define EHCI_USBMODE 0x68 /* RW USB Device mode register */ -#define EHCI_UM_CM 0x00000003 /* R/WO Controller Mode */ -#define EHCI_UM_CM_IDLE 0x0 /* Idle */ -#define EHCI_UM_CM_HOST 0x3 /* Host Controller */ -#define EHCI_UM_ES 0x00000004 /* R/WO Endian Select */ -#define EHCI_UM_ES_LE 0x0 /* Little-endian byte alignment */ -#define EHCI_UM_ES_BE 0x4 /* Big-endian byte alignment */ -#define EHCI_UM_SDIS 0x00000010 /* R/WO Stream Disable Mode */ - -#define EHCI_PORT_RESET_COMPLETE 2 /* ms */ - -/* - * Alignment NOTE: structures must be aligned so that the hardware can index - * without performing addition. - */ -#define EHCI_FRAMELIST_ALIGN 0x1000 /* bytes */ -#define EHCI_FRAMELIST_COUNT 1024 /* units */ -#define EHCI_VIRTUAL_FRAMELIST_COUNT 128 /* units */ - -#if ((8*EHCI_VIRTUAL_FRAMELIST_COUNT) < USB_MAX_HS_ISOC_FRAMES_PER_XFER) -#error "maximum number of high-speed isochronous frames is higher than supported!" -#endif - -#if (EHCI_VIRTUAL_FRAMELIST_COUNT < USB_MAX_FS_ISOC_FRAMES_PER_XFER) -#error "maximum number of full-speed isochronous frames is higher than supported!" -#endif - -/* Link types */ -#define EHCI_LINK_TERMINATE 0x00000001 -#define EHCI_LINK_TYPE(x) ((x) & 0x00000006) -#define EHCI_LINK_ITD 0x0 -#define EHCI_LINK_QH 0x2 -#define EHCI_LINK_SITD 0x4 -#define EHCI_LINK_FSTN 0x6 -#define EHCI_LINK_ADDR(x) ((x) &~ 0x1f) - -/* Structures alignment (bytes) */ -#define EHCI_ITD_ALIGN 128 -#define EHCI_SITD_ALIGN 64 -#define EHCI_QTD_ALIGN 64 -#define EHCI_QH_ALIGN 128 -#define EHCI_FSTN_ALIGN 32 -/* Data buffers are divided into one or more pages */ -#define EHCI_PAGE_SIZE 0x1000 -#if ((USB_PAGE_SIZE < EHCI_PAGE_SIZE) || (EHCI_PAGE_SIZE == 0) || \ - (USB_PAGE_SIZE < EHCI_ITD_ALIGN) || (EHCI_ITD_ALIGN == 0) || \ - (USB_PAGE_SIZE < EHCI_SITD_ALIGN) || (EHCI_SITD_ALIGN == 0) || \ - (USB_PAGE_SIZE < EHCI_QTD_ALIGN) || (EHCI_QTD_ALIGN == 0) || \ - (USB_PAGE_SIZE < EHCI_QH_ALIGN) || (EHCI_QH_ALIGN == 0) || \ - (USB_PAGE_SIZE < EHCI_FSTN_ALIGN) || (EHCI_FSTN_ALIGN == 0)) -#error "Invalid USB page size!" -#endif - - -/* - * Isochronous Transfer Descriptor. This descriptor is used for high speed - * transfers only. - */ -struct ehci_itd { - volatile uint32_t itd_next; - volatile uint32_t itd_status[8]; -#define EHCI_ITD_SET_LEN(x) ((x) << 16) -#define EHCI_ITD_GET_LEN(x) (((x) >> 16) & 0xFFF) -#define EHCI_ITD_IOC (1 << 15) -#define EHCI_ITD_SET_PG(x) ((x) << 12) -#define EHCI_ITD_GET_PG(x) (((x) >> 12) & 0x7) -#define EHCI_ITD_SET_OFFS(x) (x) -#define EHCI_ITD_GET_OFFS(x) (((x) >> 0) & 0xFFF) -#define EHCI_ITD_ACTIVE (1 << 31) -#define EHCI_ITD_DATABUFERR (1 << 30) -#define EHCI_ITD_BABBLE (1 << 29) -#define EHCI_ITD_XACTERR (1 << 28) - volatile uint32_t itd_bp[7]; - /* itd_bp[0] */ -#define EHCI_ITD_SET_ADDR(x) (x) -#define EHCI_ITD_GET_ADDR(x) (((x) >> 0) & 0x7F) -#define EHCI_ITD_SET_ENDPT(x) ((x) << 8) -#define EHCI_ITD_GET_ENDPT(x) (((x) >> 8) & 0xF) - /* itd_bp[1] */ -#define EHCI_ITD_SET_DIR_IN (1 << 11) -#define EHCI_ITD_SET_DIR_OUT (0 << 11) -#define EHCI_ITD_SET_MPL(x) (x) -#define EHCI_ITD_GET_MPL(x) (((x) >> 0) & 0x7FF) - volatile uint32_t itd_bp_hi[7]; -/* - * Extra information needed: - */ - uint32_t itd_self; - struct ehci_itd *next; - struct ehci_itd *prev; - struct ehci_itd *obj_next; - struct usb2_page_cache *page_cache; -} __aligned(EHCI_ITD_ALIGN); - -typedef struct ehci_itd ehci_itd_t; - -/* - * Split Transaction Isochronous Transfer Descriptor. This descriptor is used - * for full speed transfers only. - */ -struct ehci_sitd { - volatile uint32_t sitd_next; - volatile uint32_t sitd_portaddr; -#define EHCI_SITD_SET_DIR_OUT (0 << 31) -#define EHCI_SITD_SET_DIR_IN (1 << 31) -#define EHCI_SITD_SET_ADDR(x) (x) -#define EHCI_SITD_GET_ADDR(x) ((x) & 0x7F) -#define EHCI_SITD_SET_ENDPT(x) ((x) << 8) -#define EHCI_SITD_GET_ENDPT(x) (((x) >> 8) & 0xF) -#define EHCI_SITD_GET_DIR(x) ((x) >> 31) -#define EHCI_SITD_SET_PORT(x) ((x) << 24) -#define EHCI_SITD_GET_PORT(x) (((x) >> 24) & 0x7F) -#define EHCI_SITD_SET_HUBA(x) ((x) << 16) -#define EHCI_SITD_GET_HUBA(x) (((x) >> 16) & 0x7F) - volatile uint32_t sitd_mask; -#define EHCI_SITD_SET_SMASK(x) (x) -#define EHCI_SITD_SET_CMASK(x) ((x) << 8) - volatile uint32_t sitd_status; -#define EHCI_SITD_COMPLETE_SPLIT (1<<1) -#define EHCI_SITD_START_SPLIT (0<<1) -#define EHCI_SITD_MISSED_MICRO_FRAME (1<<2) -#define EHCI_SITD_XACTERR (1<<3) -#define EHCI_SITD_BABBLE (1<<4) -#define EHCI_SITD_DATABUFERR (1<<5) -#define EHCI_SITD_ERROR (1<<6) -#define EHCI_SITD_ACTIVE (1<<7) -#define EHCI_SITD_IOC (1<<31) -#define EHCI_SITD_SET_LEN(len) ((len)<<16) -#define EHCI_SITD_GET_LEN(x) (((x)>>16) & 0x3FF) - volatile uint32_t sitd_bp[2]; - volatile uint32_t sitd_back; - volatile uint32_t sitd_bp_hi[2]; -/* - * Extra information needed: - */ - uint32_t sitd_self; - struct ehci_sitd *next; - struct ehci_sitd *prev; - struct ehci_sitd *obj_next; - struct usb2_page_cache *page_cache; -} __aligned(EHCI_SITD_ALIGN); - -typedef struct ehci_sitd ehci_sitd_t; - -/* Queue Element Transfer Descriptor */ -struct ehci_qtd { - volatile uint32_t qtd_next; - volatile uint32_t qtd_altnext; - volatile uint32_t qtd_status; -#define EHCI_QTD_GET_STATUS(x) (((x) >> 0) & 0xff) -#define EHCI_QTD_SET_STATUS(x) ((x) << 0) -#define EHCI_QTD_ACTIVE 0x80 -#define EHCI_QTD_HALTED 0x40 -#define EHCI_QTD_BUFERR 0x20 -#define EHCI_QTD_BABBLE 0x10 -#define EHCI_QTD_XACTERR 0x08 -#define EHCI_QTD_MISSEDMICRO 0x04 -#define EHCI_QTD_SPLITXSTATE 0x02 -#define EHCI_QTD_PINGSTATE 0x01 -#define EHCI_QTD_STATERRS 0x74 -#define EHCI_QTD_GET_PID(x) (((x) >> 8) & 0x3) -#define EHCI_QTD_SET_PID(x) ((x) << 8) -#define EHCI_QTD_PID_OUT 0x0 -#define EHCI_QTD_PID_IN 0x1 -#define EHCI_QTD_PID_SETUP 0x2 -#define EHCI_QTD_GET_CERR(x) (((x) >> 10) & 0x3) -#define EHCI_QTD_SET_CERR(x) ((x) << 10) -#define EHCI_QTD_GET_C_PAGE(x) (((x) >> 12) & 0x7) -#define EHCI_QTD_SET_C_PAGE(x) ((x) << 12) -#define EHCI_QTD_GET_IOC(x) (((x) >> 15) & 0x1) -#define EHCI_QTD_IOC 0x00008000 -#define EHCI_QTD_GET_BYTES(x) (((x) >> 16) & 0x7fff) -#define EHCI_QTD_SET_BYTES(x) ((x) << 16) -#define EHCI_QTD_GET_TOGGLE(x) (((x) >> 31) & 0x1) -#define EHCI_QTD_SET_TOGGLE(x) ((x) << 31) -#define EHCI_QTD_TOGGLE_MASK 0x80000000 -#define EHCI_QTD_NBUFFERS 5 -#define EHCI_QTD_PAYLOAD_MAX ((EHCI_QTD_NBUFFERS-1)*EHCI_PAGE_SIZE) - volatile uint32_t qtd_buffer[EHCI_QTD_NBUFFERS]; - volatile uint32_t qtd_buffer_hi[EHCI_QTD_NBUFFERS]; -/* - * Extra information needed: - */ - struct ehci_qtd *alt_next; - struct ehci_qtd *obj_next; - struct usb2_page_cache *page_cache; - uint32_t qtd_self; - uint16_t len; -} __aligned(EHCI_QTD_ALIGN); - -typedef struct ehci_qtd ehci_qtd_t; - -/* Queue Head Sub Structure */ -struct ehci_qh_sub { - volatile uint32_t qtd_next; - volatile uint32_t qtd_altnext; - volatile uint32_t qtd_status; - volatile uint32_t qtd_buffer[EHCI_QTD_NBUFFERS]; - volatile uint32_t qtd_buffer_hi[EHCI_QTD_NBUFFERS]; -} __aligned(4); - -/* Queue Head */ -struct ehci_qh { - volatile uint32_t qh_link; - volatile uint32_t qh_endp; -#define EHCI_QH_GET_ADDR(x) (((x) >> 0) & 0x7f) /* endpoint addr */ -#define EHCI_QH_SET_ADDR(x) (x) -#define EHCI_QH_ADDRMASK 0x0000007f -#define EHCI_QH_GET_INACT(x) (((x) >> 7) & 0x01) /* inactivate on next */ -#define EHCI_QH_INACT 0x00000080 -#define EHCI_QH_GET_ENDPT(x) (((x) >> 8) & 0x0f) /* endpoint no */ -#define EHCI_QH_SET_ENDPT(x) ((x) << 8) -#define EHCI_QH_GET_EPS(x) (((x) >> 12) & 0x03) /* endpoint speed */ -#define EHCI_QH_SET_EPS(x) ((x) << 12) -#define EHCI_QH_SPEED_FULL 0x0 -#define EHCI_QH_SPEED_LOW 0x1 -#define EHCI_QH_SPEED_HIGH 0x2 -#define EHCI_QH_GET_DTC(x) (((x) >> 14) & 0x01) /* data toggle control */ -#define EHCI_QH_DTC 0x00004000 -#define EHCI_QH_GET_HRECL(x) (((x) >> 15) & 0x01) /* head of reclamation */ -#define EHCI_QH_HRECL 0x00008000 -#define EHCI_QH_GET_MPL(x) (((x) >> 16) & 0x7ff) /* max packet len */ -#define EHCI_QH_SET_MPL(x) ((x) << 16) -#define EHCI_QH_MPLMASK 0x07ff0000 -#define EHCI_QH_GET_CTL(x) (((x) >> 27) & 0x01) /* control endpoint */ -#define EHCI_QH_CTL 0x08000000 -#define EHCI_QH_GET_NRL(x) (((x) >> 28) & 0x0f) /* NAK reload */ -#define EHCI_QH_SET_NRL(x) ((x) << 28) - volatile uint32_t qh_endphub; -#define EHCI_QH_GET_SMASK(x) (((x) >> 0) & 0xff) /* intr sched mask */ -#define EHCI_QH_SET_SMASK(x) ((x) << 0) -#define EHCI_QH_GET_CMASK(x) (((x) >> 8) & 0xff) /* split completion mask */ -#define EHCI_QH_SET_CMASK(x) ((x) << 8) -#define EHCI_QH_GET_HUBA(x) (((x) >> 16) & 0x7f) /* hub address */ -#define EHCI_QH_SET_HUBA(x) ((x) << 16) -#define EHCI_QH_GET_PORT(x) (((x) >> 23) & 0x7f) /* hub port */ -#define EHCI_QH_SET_PORT(x) ((x) << 23) -#define EHCI_QH_GET_MULT(x) (((x) >> 30) & 0x03) /* pipe multiplier */ -#define EHCI_QH_SET_MULT(x) ((x) << 30) - volatile uint32_t qh_curqtd; - struct ehci_qh_sub qh_qtd; -/* - * Extra information needed: - */ - struct ehci_qh *next; - struct ehci_qh *prev; - struct ehci_qh *obj_next; - struct usb2_page_cache *page_cache; - uint32_t qh_self; -} __aligned(EHCI_QH_ALIGN); - -typedef struct ehci_qh ehci_qh_t; - -/* Periodic Frame Span Traversal Node */ -struct ehci_fstn { - volatile uint32_t fstn_link; - volatile uint32_t fstn_back; -} __aligned(EHCI_FSTN_ALIGN); - -typedef struct ehci_fstn ehci_fstn_t; - -struct ehci_hw_softc { - struct usb2_page_cache pframes_pc; - struct usb2_page_cache async_start_pc; - struct usb2_page_cache intr_start_pc[EHCI_VIRTUAL_FRAMELIST_COUNT]; - struct usb2_page_cache isoc_hs_start_pc[EHCI_VIRTUAL_FRAMELIST_COUNT]; - struct usb2_page_cache isoc_fs_start_pc[EHCI_VIRTUAL_FRAMELIST_COUNT]; - - struct usb2_page pframes_pg; - struct usb2_page async_start_pg; - struct usb2_page intr_start_pg[EHCI_VIRTUAL_FRAMELIST_COUNT]; - struct usb2_page isoc_hs_start_pg[EHCI_VIRTUAL_FRAMELIST_COUNT]; - struct usb2_page isoc_fs_start_pg[EHCI_VIRTUAL_FRAMELIST_COUNT]; -}; - -struct ehci_config_desc { - struct usb2_config_descriptor confd; - struct usb2_interface_descriptor ifcd; - struct usb2_endpoint_descriptor endpd; -} __packed; - -union ehci_hub_desc { - struct usb2_status stat; - struct usb2_port_status ps; - struct usb2_device_descriptor devd; - struct usb2_device_qualifier odevd; - struct usb2_hub_descriptor hubd; - uint8_t temp[128]; -}; - -typedef struct ehci_softc { - struct ehci_hw_softc sc_hw; - struct usb2_bus sc_bus; /* base device */ - struct usb2_callout sc_tmo_pcd; - union ehci_hub_desc sc_hub_desc; - struct usb2_sw_transfer sc_root_ctrl; - struct usb2_sw_transfer sc_root_intr; - - struct usb2_device *sc_devices[EHCI_MAX_DEVICES]; - struct resource *sc_io_res; - struct resource *sc_irq_res; - struct ehci_qh *sc_async_p_last; - struct ehci_qh *sc_intr_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]; - struct ehci_sitd *sc_isoc_fs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]; - struct ehci_itd *sc_isoc_hs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]; - void *sc_intr_hdl; - bus_size_t sc_io_size; - bus_space_tag_t sc_io_tag; - bus_space_handle_t sc_io_hdl; - - uint32_t sc_eintrs; - uint32_t sc_cmd; /* shadow of cmd register during - * suspend */ - - uint16_t sc_intr_stat[EHCI_VIRTUAL_FRAMELIST_COUNT]; - uint16_t sc_id_vendor; /* vendor ID for root hub */ - uint16_t sc_flags; /* chip specific flags */ -#define EHCI_SCFLG_SETMODE 0x0001 /* set bridge mode again after init */ -#define EHCI_SCFLG_FORCESPEED 0x0002 /* force speed */ -#define EHCI_SCFLG_NORESTERM 0x0004 /* don't terminate reset sequence */ -#define EHCI_SCFLG_BIGEDESC 0x0008 /* big-endian byte order descriptors */ -#define EHCI_SCFLG_BIGEMMIO 0x0010 /* big-endian byte order MMIO */ -#define EHCI_SCFLG_TT 0x0020 /* transaction translator present */ - - uint8_t sc_offs; /* offset to operational registers */ - uint8_t sc_doorbell_disable; /* set on doorbell failure */ - uint8_t sc_noport; - uint8_t sc_addr; /* device address */ - uint8_t sc_conf; /* device configuration */ - uint8_t sc_isreset; - uint8_t sc_hub_idata[8]; - - char sc_vendor[16]; /* vendor string for root hub */ - -} ehci_softc_t; - -#define EREAD1(sc, a) bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (a)) -#define EREAD2(sc, a) bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (a)) -#define EREAD4(sc, a) bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (a)) -#define EWRITE1(sc, a, x) \ - bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (a), (x)) -#define EWRITE2(sc, a, x) \ - bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (a), (x)) -#define EWRITE4(sc, a, x) \ - bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (a), (x)) -#define EOREAD1(sc, a) \ - bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a)) -#define EOREAD2(sc, a) \ - bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a)) -#define EOREAD4(sc, a) \ - bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a)) -#define EOWRITE1(sc, a, x) \ - bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a), (x)) -#define EOWRITE2(sc, a, x) \ - bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a), (x)) -#define EOWRITE4(sc, a, x) \ - bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a), (x)) - -usb2_bus_mem_cb_t ehci_iterate_hw_softc; - -usb2_error_t ehci_init(ehci_softc_t *sc); -void ehci_detach(struct ehci_softc *sc); -void ehci_suspend(struct ehci_softc *sc); -void ehci_resume(struct ehci_softc *sc); -void ehci_shutdown(ehci_softc_t *sc); -void ehci_interrupt(ehci_softc_t *sc); - -#endif /* _EHCI_H_ */ diff --git a/sys/dev/usb2/controller/ehci2_ixp4xx.c b/sys/dev/usb2/controller/ehci2_ixp4xx.c deleted file mode 100644 index 91ce863..0000000 --- a/sys/dev/usb2/controller/ehci2_ixp4xx.c +++ /dev/null @@ -1,349 +0,0 @@ -/*- - * Copyright (c) 2008 Sam Leffler. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * IXP435 attachment driver for the USB Enhanced Host Controller. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include "opt_bus.h" - -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_defs.h> -#include <dev/usb2/include/usb2_standard.h> - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/ehci2.h> - -#include <arm/xscale/ixp425/ixp425reg.h> -#include <arm/xscale/ixp425/ixp425var.h> - -#define EHCI_VENDORID_IXP4XX 0x42fa05 -#define EHCI_HC_DEVSTR "IXP4XX Integrated USB 2.0 controller" - -struct ixp_ehci_softc { - ehci_softc_t base; /* storage for EHCI code */ - bus_space_tag_t iot; - bus_space_handle_t ioh; - struct bus_space tag; /* tag for private bus space ops */ -}; - -static device_attach_t ehci_ixp_attach; -static device_detach_t ehci_ixp_detach; -static device_shutdown_t ehci_ixp_shutdown; -static device_suspend_t ehci_ixp_suspend; -static device_resume_t ehci_ixp_resume; - -static uint8_t ehci_bs_r_1(void *, bus_space_handle_t, bus_size_t); -static void ehci_bs_w_1(void *, bus_space_handle_t, bus_size_t, u_int8_t); -static uint16_t ehci_bs_r_2(void *, bus_space_handle_t, bus_size_t); -static void ehci_bs_w_2(void *, bus_space_handle_t, bus_size_t, uint16_t); -static uint32_t ehci_bs_r_4(void *, bus_space_handle_t, bus_size_t); -static void ehci_bs_w_4(void *, bus_space_handle_t, bus_size_t, uint32_t); - -static int -ehci_ixp_suspend(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - int err; - - err = bus_generic_suspend(self); - if (err) - return (err); - ehci_suspend(sc); - return (0); -} - -static int -ehci_ixp_resume(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - - ehci_resume(sc); - - bus_generic_resume(self); - - return (0); -} - -static int -ehci_ixp_shutdown(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - int err; - - err = bus_generic_shutdown(self); - if (err) - return (err); - ehci_shutdown(sc); - - return (0); -} - -static int -ehci_ixp_probe(device_t self) -{ - - device_set_desc(self, EHCI_HC_DEVSTR); - - return (BUS_PROBE_DEFAULT); -} - -static int -ehci_ixp_attach(device_t self) -{ - struct ixp_ehci_softc *isc = device_get_softc(self); - ehci_softc_t *sc = &isc->base; - int err; - int rid; - - /* initialise some bus fields */ - sc->sc_bus.parent = self; - sc->sc_bus.devices = sc->sc_devices; - sc->sc_bus.devices_max = EHCI_MAX_DEVICES; - - /* get all DMA memory */ - if (usb2_bus_mem_alloc_all(&sc->sc_bus, - USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { - return (ENOMEM); - } - - sc->sc_bus.usbrev = USB_REV_2_0; - - /* NB: hints fix the memory location and irq */ - - rid = 0; - sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (!sc->sc_io_res) { - device_printf(self, "Could not map memory\n"); - goto error; - } - - /* - * Craft special resource for bus space ops that handle - * byte-alignment of non-word addresses. Also, since - * we're already intercepting bus space ops we handle - * the register window offset that could otherwise be - * done with bus_space_subregion. - */ - isc->iot = rman_get_bustag(sc->sc_io_res); - isc->tag.bs_cookie = isc->iot; - /* read single */ - isc->tag.bs_r_1 = ehci_bs_r_1, - isc->tag.bs_r_2 = ehci_bs_r_2, - isc->tag.bs_r_4 = ehci_bs_r_4, - /* write (single) */ - isc->tag.bs_w_1 = ehci_bs_w_1, - isc->tag.bs_w_2 = ehci_bs_w_2, - isc->tag.bs_w_4 = ehci_bs_w_4, - - sc->sc_io_tag = &isc->tag; - sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); - sc->sc_io_size = IXP435_USB1_SIZE - 0x100; - - rid = 0; - sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, - RF_ACTIVE); - if (sc->sc_irq_res == NULL) { - device_printf(self, "Could not allocate irq\n"); - goto error; - } - sc->sc_bus.bdev = device_add_child(self, "usbus", -1); - if (!sc->sc_bus.bdev) { - device_printf(self, "Could not add USB device\n"); - goto error; - } - device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); - device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR); - - sprintf(sc->sc_vendor, "Intel"); - - - err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl); - if (err) { - device_printf(self, "Could not setup irq, %d\n", err); - sc->sc_intr_hdl = NULL; - goto error; - } - - /* - * Arrange to force Host mode, select big-endian byte alignment, - * and arrange to not terminate reset operations (the adapter - * will ignore it if we do but might as well save a reg write). - * Also, the controller has an embedded Transaction Translator - * which means port speed must be read from the Port Status - * register following a port enable. - */ - sc->sc_flags |= EHCI_SCFLG_TT - | EHCI_SCFLG_SETMODE - | EHCI_SCFLG_BIGEDESC - | EHCI_SCFLG_BIGEMMIO - | EHCI_SCFLG_NORESTERM - ; - - err = ehci_init(sc); - if (!err) { - err = device_probe_and_attach(sc->sc_bus.bdev); - } - if (err) { - device_printf(self, "USB init failed err=%d\n", err); - goto error; - } - return (0); - -error: - ehci_ixp_detach(self); - return (ENXIO); -} - -static int -ehci_ixp_detach(device_t self) -{ - struct ixp_ehci_softc *isc = device_get_softc(self); - ehci_softc_t *sc = &isc->base; - device_t bdev; - int err; - - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } - /* during module unload there are lots of children leftover */ - device_delete_all_children(self); - - /* - * disable interrupts that might have been switched on in ehci_init - */ - if (sc->sc_io_res) { - EWRITE4(sc, EHCI_USBINTR, 0); - } - - if (sc->sc_irq_res && sc->sc_intr_hdl) { - /* - * only call ehci_detach() after ehci_init() - */ - ehci_detach(sc); - - err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); - - if (err) - /* XXX or should we panic? */ - device_printf(self, "Could not tear down irq, %d\n", - err); - sc->sc_intr_hdl = NULL; - } - - if (sc->sc_irq_res) { - bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); - sc->sc_irq_res = NULL; - } - if (sc->sc_io_res) { - bus_release_resource(self, SYS_RES_MEMORY, 0, - sc->sc_io_res); - sc->sc_io_res = NULL; - } - usb2_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); - - return (0); -} - -/* - * Bus space accessors for PIO operations. - */ - -static uint8_t -ehci_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o) -{ - return bus_space_read_1((bus_space_tag_t) t, h, - 0x100 + (o &~ 3) + (3 - (o & 3))); -} - -static void -ehci_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v) -{ - panic("%s", __func__); -} - -static uint16_t -ehci_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o) -{ - return bus_space_read_2((bus_space_tag_t) t, h, - 0x100 + (o &~ 3) + (2 - (o & 3))); -} - -static void -ehci_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v) -{ - panic("%s", __func__); -} - -static uint32_t -ehci_bs_r_4(void *t, bus_space_handle_t h, bus_size_t o) -{ - return bus_space_read_4((bus_space_tag_t) t, h, 0x100 + o); -} - -static void -ehci_bs_w_4(void *t, bus_space_handle_t h, bus_size_t o, uint32_t v) -{ - bus_space_write_4((bus_space_tag_t) t, h, 0x100 + o, v); -} - -static device_method_t ehci_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, ehci_ixp_probe), - DEVMETHOD(device_attach, ehci_ixp_attach), - DEVMETHOD(device_detach, ehci_ixp_detach), - DEVMETHOD(device_suspend, ehci_ixp_suspend), - DEVMETHOD(device_resume, ehci_ixp_resume), - DEVMETHOD(device_shutdown, ehci_ixp_shutdown), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - {0, 0} -}; - -static driver_t ehci_driver = { - "ehci", - ehci_methods, - sizeof(struct ixp_ehci_softc), -}; - -static devclass_t ehci_devclass; - -DRIVER_MODULE(ehci, ixp, ehci_driver, ehci_devclass, 0, 0); -MODULE_DEPEND(ehci, usb2_controller, 1, 1, 1); -MODULE_DEPEND(ehci, usb2_core, 1, 1, 1); diff --git a/sys/dev/usb2/controller/ehci2_mbus.c b/sys/dev/usb2/controller/ehci2_mbus.c deleted file mode 100644 index 404617b..0000000 --- a/sys/dev/usb2/controller/ehci2_mbus.c +++ /dev/null @@ -1,365 +0,0 @@ -/*- - * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. - * All rights reserved. - * - * Developed by Semihalf. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of MARVELL nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * MBus attachment driver for the USB Enhanced Host Controller. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include "opt_bus.h" - -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_defs.h> -#include <dev/usb2/include/usb2_standard.h> - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/ehci2.h> - -#include <arm/mv/mvreg.h> -#include <arm/mv/mvvar.h> - -#define EHCI_VENDORID_MRVL 0x1286 -#define EHCI_HC_DEVSTR "Marvell Integrated USB 2.0 controller" - -static device_attach_t ehci_mbus_attach; -static device_detach_t ehci_mbus_detach; -static device_shutdown_t ehci_mbus_shutdown; -static device_suspend_t ehci_mbus_suspend; -static device_resume_t ehci_mbus_resume; - -static int err_intr(void *arg); - -static struct resource *irq_err; -static void *ih_err; - -#define USB_BRIDGE_INTR_CAUSE 0x210 -#define USB_BRIDGE_INTR_MASK 0x214 - -#define MV_USB_ADDR_DECODE_ERR (1 << 0) -#define MV_USB_HOST_UNDERFLOW (1 << 1) -#define MV_USB_HOST_OVERFLOW (1 << 2) -#define MV_USB_DEVICE_UNDERFLOW (1 << 3) - -static int -ehci_mbus_suspend(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - int err; - - err = bus_generic_suspend(self); - if (err) - return (err); - ehci_suspend(sc); - return (0); -} - -static int -ehci_mbus_resume(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - - ehci_resume(sc); - - bus_generic_resume(self); - - return (0); -} - -static int -ehci_mbus_shutdown(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - int err; - - err = bus_generic_shutdown(self); - if (err) - return (err); - ehci_shutdown(sc); - - return (0); -} - -static int -ehci_mbus_probe(device_t self) -{ - - device_set_desc(self, EHCI_HC_DEVSTR); - - return (BUS_PROBE_DEFAULT); -} - -static int -ehci_mbus_attach(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - bus_space_handle_t bsh; - int err; - int rid; - - /* initialise some bus fields */ - sc->sc_bus.parent = self; - sc->sc_bus.devices = sc->sc_devices; - sc->sc_bus.devices_max = EHCI_MAX_DEVICES; - - /* get all DMA memory */ - if (usb2_bus_mem_alloc_all(&sc->sc_bus, - USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { - return (ENOMEM); - } - - sc->sc_bus.usbrev = USB_REV_2_0; - - rid = 0; - sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (!sc->sc_io_res) { - device_printf(self, "Could not map memory\n"); - goto error; - } - sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); - bsh = rman_get_bushandle(sc->sc_io_res); - sc->sc_io_size = MV_USB_SIZE - MV_USB_HOST_OFST; - - /* - * Marvell EHCI host controller registers start at certain offset within - * the whole USB registers range, so create a subregion for the host - * mode configuration purposes. - */ - if (bus_space_subregion(sc->sc_io_tag, bsh, MV_USB_HOST_OFST, - sc->sc_io_size, &sc->sc_io_hdl) != 0) - panic("%s: unable to subregion USB host registers", - device_get_name(self)); - - rid = 0; - irq_err = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (irq_err == NULL) { - device_printf(self, "Could not allocate error irq\n"); - ehci_mbus_detach(self); - return (ENXIO); - } - - /* - * Notice: Marvell EHCI controller has TWO interrupt lines, so make sure to - * use the correct rid for the main one (controller interrupt) -- - * refer to obio_devices[] for the right resource number to use here. - */ - rid = 1; - sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (sc->sc_irq_res == NULL) { - device_printf(self, "Could not allocate irq\n"); - goto error; - } - - sc->sc_bus.bdev = device_add_child(self, "usbus", -1); - if (!sc->sc_bus.bdev) { - device_printf(self, "Could not add USB device\n"); - goto error; - } - device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); - device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR); - - sprintf(sc->sc_vendor, "Marvell"); - - err = bus_setup_intr(self, irq_err, INTR_FAST | INTR_TYPE_BIO, - err_intr, NULL, sc, &ih_err); - if (err) { - device_printf(self, "Could not setup error irq, %d\n", err); - ih_err = NULL; - goto error; - } - - EWRITE4(sc, USB_BRIDGE_INTR_MASK, MV_USB_ADDR_DECODE_ERR | - MV_USB_HOST_UNDERFLOW | MV_USB_HOST_OVERFLOW | - MV_USB_DEVICE_UNDERFLOW); - - err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl); - if (err) { - device_printf(self, "Could not setup irq, %d\n", err); - sc->sc_intr_hdl = NULL; - goto error; - } - - /* - * Workaround for Marvell integrated EHCI controller: reset of - * the EHCI core clears the USBMODE register, which sets the core in - * an undefined state (neither host nor agent), so it needs to be set - * again for proper operation. - * - * Refer to errata document MV-S500832-00D.pdf (p. 5.24 GL USB-2) for - * details. - */ - sc->sc_flags |= EHCI_SCFLG_SETMODE; - if (bootverbose) - device_printf(self, "5.24 GL USB-2 workaround enabled\n"); - - /* XXX all MV chips need it? */ - sc->sc_flags |= EHCI_SCFLG_FORCESPEED | EHCI_SCFLG_NORESTERM; - - err = ehci_init(sc); - if (!err) { - err = device_probe_and_attach(sc->sc_bus.bdev); - } - if (err) { - device_printf(self, "USB init failed err=%d\n", err); - goto error; - } - return (0); - -error: - ehci_mbus_detach(self); - return (ENXIO); -} - -static int -ehci_mbus_detach(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - device_t bdev; - int err; - - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } - /* during module unload there are lots of children leftover */ - device_delete_all_children(self); - - /* - * disable interrupts that might have been switched on in ehci_init - */ - if (sc->sc_io_res) { - EWRITE4(sc, EHCI_USBINTR, 0); - EWRITE4(sc, USB_BRIDGE_INTR_MASK, 0); - } - if (sc->sc_irq_res && sc->sc_intr_hdl) { - /* - * only call ehci_detach() after ehci_init() - */ - ehci_detach(sc); - - err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); - - if (err) - /* XXX or should we panic? */ - device_printf(self, "Could not tear down irq, %d\n", - err); - sc->sc_intr_hdl = NULL; - } - if (irq_err && ih_err) { - err = bus_teardown_intr(self, irq_err, ih_err); - - if (err) - device_printf(self, "Could not tear down irq, %d\n", - err); - ih_err = NULL; - } - if (irq_err) { - bus_release_resource(self, SYS_RES_IRQ, 0, irq_err); - irq_err = NULL; - } - if (sc->sc_irq_res) { - bus_release_resource(self, SYS_RES_IRQ, 1, sc->sc_irq_res); - sc->sc_irq_res = NULL; - } - if (sc->sc_io_res) { - bus_release_resource(self, SYS_RES_MEMORY, 0, - sc->sc_io_res); - sc->sc_io_res = NULL; - } - usb2_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); - - return (0); -} - -static int -err_intr(void *arg) -{ - ehci_softc_t *sc = arg; - unsigned int cause; - - cause = EREAD4(sc, USB_BRIDGE_INTR_CAUSE); - if (cause) { - printf("IRQ ERR: cause: 0x%08x\n", cause); - if (cause & MV_USB_ADDR_DECODE_ERR) - printf("IRQ ERR: Address decoding error\n"); - if (cause & MV_USB_HOST_UNDERFLOW) - printf("IRQ ERR: USB Host Underflow\n"); - if (cause & MV_USB_HOST_OVERFLOW) - printf("IRQ ERR: USB Host Overflow\n"); - if (cause & MV_USB_DEVICE_UNDERFLOW) - printf("IRQ ERR: USB Device Underflow\n"); - if (cause & ~(MV_USB_ADDR_DECODE_ERR | MV_USB_HOST_UNDERFLOW | - MV_USB_HOST_OVERFLOW | MV_USB_DEVICE_UNDERFLOW)) - printf("IRQ ERR: Unknown error\n"); - - EWRITE4(sc, USB_BRIDGE_INTR_CAUSE, 0); - } - return (FILTER_HANDLED); -} - -static device_method_t ehci_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, ehci_mbus_probe), - DEVMETHOD(device_attach, ehci_mbus_attach), - DEVMETHOD(device_detach, ehci_mbus_detach), - DEVMETHOD(device_suspend, ehci_mbus_suspend), - DEVMETHOD(device_resume, ehci_mbus_resume), - DEVMETHOD(device_shutdown, ehci_mbus_shutdown), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - {0, 0} -}; - -static driver_t ehci_driver = { - "ehci", - ehci_methods, - sizeof(ehci_softc_t), -}; - -static devclass_t ehci_devclass; - -DRIVER_MODULE(ehci, mbus, ehci_driver, ehci_devclass, 0, 0); -MODULE_DEPEND(ehci, usb2_controller, 1, 1, 1); -MODULE_DEPEND(ehci, usb2_core, 1, 1, 1); diff --git a/sys/dev/usb2/controller/ehci2_pci.c b/sys/dev/usb2/controller/ehci2_pci.c deleted file mode 100644 index 5e39c8f..0000000 --- a/sys/dev/usb2/controller/ehci2_pci.c +++ /dev/null @@ -1,487 +0,0 @@ -/*- - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Lennart Augustsson (augustss@carlstedt.se) at - * Carlstedt Research & Technology. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* - * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller. - * - * The EHCI 1.0 spec can be found at - * http://developer.intel.com/technology/usb/download/ehci-r10.pdf - * and the USB 2.0 spec at - * http://www.usb.org/developers/docs/usb_20.zip - */ - -/* The low level controller code for EHCI has been split into - * PCI probes and EHCI specific code. This was done to facilitate the - * sharing of code between *BSD's - */ - -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_defs.h> -#include <dev/usb2/include/usb2_standard.h> - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/usb2_pci.h> -#include <dev/usb2/controller/ehci2.h> - -#define PCI_EHCI_VENDORID_ACERLABS 0x10b9 -#define PCI_EHCI_VENDORID_AMD 0x1022 -#define PCI_EHCI_VENDORID_APPLE 0x106b -#define PCI_EHCI_VENDORID_ATI 0x1002 -#define PCI_EHCI_VENDORID_CMDTECH 0x1095 -#define PCI_EHCI_VENDORID_INTEL 0x8086 -#define PCI_EHCI_VENDORID_NEC 0x1033 -#define PCI_EHCI_VENDORID_OPTI 0x1045 -#define PCI_EHCI_VENDORID_PHILIPS 0x1131 -#define PCI_EHCI_VENDORID_SIS 0x1039 -#define PCI_EHCI_VENDORID_NVIDIA 0x12D2 -#define PCI_EHCI_VENDORID_NVIDIA2 0x10DE -#define PCI_EHCI_VENDORID_VIA 0x1106 - -#define PCI_EHCI_BASE_REG 0x10 - -static void ehci_pci_takecontroller(device_t self); - -static device_probe_t ehci_pci_probe; -static device_attach_t ehci_pci_attach; -static device_detach_t ehci_pci_detach; -static device_suspend_t ehci_pci_suspend; -static device_resume_t ehci_pci_resume; -static device_shutdown_t ehci_pci_shutdown; - -static int -ehci_pci_suspend(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - int err; - - err = bus_generic_suspend(self); - if (err) - return (err); - ehci_suspend(sc); - return (0); -} - -static int -ehci_pci_resume(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - - ehci_pci_takecontroller(self); - ehci_resume(sc); - - bus_generic_resume(self); - - return (0); -} - -static int -ehci_pci_shutdown(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - int err; - - err = bus_generic_shutdown(self); - if (err) - return (err); - ehci_shutdown(sc); - - return (0); -} - -static const char * -ehci_pci_match(device_t self) -{ - uint32_t device_id = pci_get_devid(self); - - switch (device_id) { - case 0x268c8086: - return ("Intel 63XXESB USB 2.0 controller"); - - case 0x523910b9: - return "ALi M5239 USB 2.0 controller"; - - case 0x10227463: - return "AMD 8111 USB 2.0 controller"; - - case 0x20951022: - return ("AMD CS5536 (Geode) USB 2.0 controller"); - - case 0x43451002: - return "ATI SB200 USB 2.0 controller"; - case 0x43731002: - return "ATI SB400 USB 2.0 controller"; - - case 0x25ad8086: - return "Intel 6300ESB USB 2.0 controller"; - case 0x24cd8086: - return "Intel 82801DB/L/M (ICH4) USB 2.0 controller"; - case 0x24dd8086: - return "Intel 82801EB/R (ICH5) USB 2.0 controller"; - case 0x265c8086: - return "Intel 82801FB (ICH6) USB 2.0 controller"; - case 0x27cc8086: - return "Intel 82801GB/R (ICH7) USB 2.0 controller"; - - case 0x28368086: - return "Intel 82801H (ICH8) USB 2.0 controller USB2-A"; - case 0x283a8086: - return "Intel 82801H (ICH8) USB 2.0 controller USB2-B"; - case 0x293a8086: - return "Intel 82801I (ICH9) USB 2.0 controller"; - case 0x293c8086: - return "Intel 82801I (ICH9) USB 2.0 controller"; - - case 0x00e01033: - return ("NEC uPD 720100 USB 2.0 controller"); - - case 0x006810de: - return "NVIDIA nForce2 USB 2.0 controller"; - case 0x008810de: - return "NVIDIA nForce2 Ultra 400 USB 2.0 controller"; - case 0x00d810de: - return "NVIDIA nForce3 USB 2.0 controller"; - case 0x00e810de: - return "NVIDIA nForce3 250 USB 2.0 controller"; - case 0x005b10de: - return "NVIDIA nForce4 USB 2.0 controller"; - - case 0x15621131: - return "Philips ISP156x USB 2.0 controller"; - - case 0x31041106: - return ("VIA VT6202 USB 2.0 controller"); - - default: - break; - } - - if ((pci_get_class(self) == PCIC_SERIALBUS) - && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) - && (pci_get_progif(self) == PCI_INTERFACE_EHCI)) { - return ("EHCI (generic) USB 2.0 controller"); - } - return (NULL); /* dunno */ -} - -static int -ehci_pci_probe(device_t self) -{ - const char *desc = ehci_pci_match(self); - - if (desc) { - device_set_desc(self, desc); - return (0); - } else { - return (ENXIO); - } -} - -static int -ehci_pci_attach(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - int err; - int rid; - - /* initialise some bus fields */ - sc->sc_bus.parent = self; - sc->sc_bus.devices = sc->sc_devices; - sc->sc_bus.devices_max = EHCI_MAX_DEVICES; - - /* get all DMA memory */ - if (usb2_bus_mem_alloc_all(&sc->sc_bus, - USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { - return (ENOMEM); - } - - pci_enable_busmaster(self); - - switch (pci_read_config(self, PCI_USBREV, 1) & PCI_USB_REV_MASK) { - case PCI_USB_REV_PRE_1_0: - case PCI_USB_REV_1_0: - case PCI_USB_REV_1_1: - /* - * NOTE: some EHCI USB controllers have the wrong USB - * revision number. It appears those controllers are - * fully compliant so we just ignore this value in - * some common cases. - */ - device_printf(self, "pre-2.0 USB revision (ignored)\n"); - /* fallthrough */ - case PCI_USB_REV_2_0: - sc->sc_bus.usbrev = USB_REV_2_0; - break; - default: - /* Quirk for Parallels Desktop 4.0 */ - device_printf(self, "USB revision is unknown. Assuming v2.0.\n"); - sc->sc_bus.usbrev = USB_REV_2_0; - break; - } - - rid = PCI_CBMEM; - sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, - RF_ACTIVE); - if (!sc->sc_io_res) { - device_printf(self, "Could not map memory\n"); - goto error; - } - sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); - sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); - sc->sc_io_size = rman_get_size(sc->sc_io_res); - - rid = 0; - sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (sc->sc_irq_res == NULL) { - device_printf(self, "Could not allocate irq\n"); - goto error; - } - sc->sc_bus.bdev = device_add_child(self, "usbus", -1); - if (!sc->sc_bus.bdev) { - device_printf(self, "Could not add USB device\n"); - goto error; - } - device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); - - /* - * ehci_pci_match will never return NULL if ehci_pci_probe - * succeeded - */ - device_set_desc(sc->sc_bus.bdev, ehci_pci_match(self)); - switch (pci_get_vendor(self)) { - case PCI_EHCI_VENDORID_ACERLABS: - sprintf(sc->sc_vendor, "AcerLabs"); - break; - case PCI_EHCI_VENDORID_AMD: - sprintf(sc->sc_vendor, "AMD"); - break; - case PCI_EHCI_VENDORID_APPLE: - sprintf(sc->sc_vendor, "Apple"); - break; - case PCI_EHCI_VENDORID_ATI: - sprintf(sc->sc_vendor, "ATI"); - break; - case PCI_EHCI_VENDORID_CMDTECH: - sprintf(sc->sc_vendor, "CMDTECH"); - break; - case PCI_EHCI_VENDORID_INTEL: - sprintf(sc->sc_vendor, "Intel"); - break; - case PCI_EHCI_VENDORID_NEC: - sprintf(sc->sc_vendor, "NEC"); - break; - case PCI_EHCI_VENDORID_OPTI: - sprintf(sc->sc_vendor, "OPTi"); - break; - case PCI_EHCI_VENDORID_PHILIPS: - sprintf(sc->sc_vendor, "Philips"); - break; - case PCI_EHCI_VENDORID_SIS: - sprintf(sc->sc_vendor, "SiS"); - break; - case PCI_EHCI_VENDORID_NVIDIA: - case PCI_EHCI_VENDORID_NVIDIA2: - sprintf(sc->sc_vendor, "nVidia"); - break; - case PCI_EHCI_VENDORID_VIA: - sprintf(sc->sc_vendor, "VIA"); - break; - default: - if (bootverbose) - device_printf(self, "(New EHCI DeviceId=0x%08x)\n", - pci_get_devid(self)); - sprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self)); - } - -#if (__FreeBSD_version >= 700031) - err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl); -#else - err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl); -#endif - if (err) { - device_printf(self, "Could not setup irq, %d\n", err); - sc->sc_intr_hdl = NULL; - goto error; - } - ehci_pci_takecontroller(self); - err = ehci_init(sc); - if (!err) { - err = device_probe_and_attach(sc->sc_bus.bdev); - } - if (err) { - device_printf(self, "USB init failed err=%d\n", err); - goto error; - } - return (0); - -error: - ehci_pci_detach(self); - return (ENXIO); -} - -static int -ehci_pci_detach(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - device_t bdev; - - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } - /* during module unload there are lots of children leftover */ - device_delete_all_children(self); - - pci_disable_busmaster(self); - - /* - * disable interrupts that might have been switched on in ehci_init - */ - if (sc->sc_io_res) { - EWRITE4(sc, EHCI_USBINTR, 0); - } - if (sc->sc_irq_res && sc->sc_intr_hdl) { - /* - * only call ehci_detach() after ehci_init() - */ - ehci_detach(sc); - - int err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); - - if (err) - /* XXX or should we panic? */ - device_printf(self, "Could not tear down irq, %d\n", - err); - sc->sc_intr_hdl = NULL; - } - if (sc->sc_irq_res) { - bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); - sc->sc_irq_res = NULL; - } - if (sc->sc_io_res) { - bus_release_resource(self, SYS_RES_MEMORY, PCI_CBMEM, - sc->sc_io_res); - sc->sc_io_res = NULL; - } - usb2_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); - - return (0); -} - -static void -ehci_pci_takecontroller(device_t self) -{ - ehci_softc_t *sc = device_get_softc(self); - uint32_t cparams; - uint32_t eec; - uint16_t to; - uint8_t eecp; - uint8_t bios_sem; - - cparams = EREAD4(sc, EHCI_HCCPARAMS); - - /* Synchronise with the BIOS if it owns the controller. */ - for (eecp = EHCI_HCC_EECP(cparams); eecp != 0; - eecp = EHCI_EECP_NEXT(eec)) { - eec = pci_read_config(self, eecp, 4); - if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) { - continue; - } - bios_sem = pci_read_config(self, eecp + - EHCI_LEGSUP_BIOS_SEM, 1); - if (bios_sem == 0) { - continue; - } - device_printf(sc->sc_bus.bdev, "waiting for BIOS " - "to give up control\n"); - pci_write_config(self, eecp + - EHCI_LEGSUP_OS_SEM, 1, 1); - to = 500; - while (1) { - bios_sem = pci_read_config(self, eecp + - EHCI_LEGSUP_BIOS_SEM, 1); - if (bios_sem == 0) - break; - - if (--to == 0) { - device_printf(sc->sc_bus.bdev, - "timed out waiting for BIOS\n"); - break; - } - usb2_pause_mtx(NULL, hz / 100); /* wait 10ms */ - } - } -} - -static driver_t ehci_driver = -{ - .name = "ehci", - .methods = (device_method_t[]){ - /* device interface */ - DEVMETHOD(device_probe, ehci_pci_probe), - DEVMETHOD(device_attach, ehci_pci_attach), - DEVMETHOD(device_detach, ehci_pci_detach), - DEVMETHOD(device_suspend, ehci_pci_suspend), - DEVMETHOD(device_resume, ehci_pci_resume), - DEVMETHOD(device_shutdown, ehci_pci_shutdown), - /* bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - {0, 0} - }, - .size = sizeof(struct ehci_softc), -}; - -static devclass_t ehci_devclass; - -DRIVER_MODULE(ehci, pci, ehci_driver, ehci_devclass, 0, 0); -DRIVER_MODULE(ehci, cardbus, ehci_driver, ehci_devclass, 0, 0); -MODULE_DEPEND(ehci, usb2_controller, 1, 1, 1); -MODULE_DEPEND(ehci, usb2_core, 1, 1, 1); diff --git a/sys/dev/usb2/controller/musb2_otg.c b/sys/dev/usb2/controller/musb2_otg.c deleted file mode 100644 index fd6b6d3..0000000 --- a/sys/dev/usb2/controller/musb2_otg.c +++ /dev/null @@ -1,2875 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Thanks to Mentor Graphics for providing a reference driver for this - * USB chip at their homepage. - */ - -/* - * This file contains the driver for the Mentor Graphics Inventra USB - * 2.0 High Speed Dual-Role controller. - * - * NOTE: The current implementation only supports Device Side Mode! - */ - -#include <dev/usb2/include/usb2_standard.h> -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_error.h> -#include <dev/usb2/include/usb2_defs.h> - -#define USB_DEBUG_VAR musbotgdebug - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_debug.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_transfer.h> -#include <dev/usb2/core/usb2_device.h> -#include <dev/usb2/core/usb2_hub.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/musb2_otg.h> - -#define MUSBOTG_INTR_ENDPT 1 - -#define MUSBOTG_BUS2SC(bus) \ - ((struct musbotg_softc *)(((uint8_t *)(bus)) - \ - USB_P2U(&(((struct musbotg_softc *)0)->sc_bus)))) - -#define MUSBOTG_PC2SC(pc) \ - MUSBOTG_BUS2SC((pc)->tag_parent->info->bus) - -#if USB_DEBUG -static int musbotgdebug = 0; - -SYSCTL_NODE(_hw_usb2, OID_AUTO, musbotg, CTLFLAG_RW, 0, "USB musbotg"); -SYSCTL_INT(_hw_usb2_musbotg, OID_AUTO, debug, CTLFLAG_RW, - &musbotgdebug, 0, "Debug level"); -#endif - -/* prototypes */ - -struct usb2_bus_methods musbotg_bus_methods; -struct usb2_pipe_methods musbotg_device_bulk_methods; -struct usb2_pipe_methods musbotg_device_ctrl_methods; -struct usb2_pipe_methods musbotg_device_intr_methods; -struct usb2_pipe_methods musbotg_device_isoc_methods; -struct usb2_pipe_methods musbotg_root_ctrl_methods; -struct usb2_pipe_methods musbotg_root_intr_methods; - -static musbotg_cmd_t musbotg_setup_rx; -static musbotg_cmd_t musbotg_setup_data_rx; -static musbotg_cmd_t musbotg_setup_data_tx; -static musbotg_cmd_t musbotg_setup_status; -static musbotg_cmd_t musbotg_data_rx; -static musbotg_cmd_t musbotg_data_tx; -static void musbotg_device_done(struct usb2_xfer *, usb2_error_t); -static void musbotg_do_poll(struct usb2_bus *); -static void musbotg_root_ctrl_poll(struct musbotg_softc *); -static void musbotg_standard_done(struct usb2_xfer *); -static void musbotg_interrupt_poll(struct musbotg_softc *); - -static usb2_sw_transfer_func_t musbotg_root_intr_done; -static usb2_sw_transfer_func_t musbotg_root_ctrl_done; - -/* - * Here is a configuration that the chip supports. - */ -static const struct usb2_hw_ep_profile musbotg_ep_profile[1] = { - - [0] = { - .max_in_frame_size = 64,/* fixed */ - .max_out_frame_size = 64, /* fixed */ - .is_simplex = 1, - .support_control = 1, - } -}; - -static void -musbotg_get_hw_ep_profile(struct usb2_device *udev, - const struct usb2_hw_ep_profile **ppf, uint8_t ep_addr) -{ - struct musbotg_softc *sc; - - sc = MUSBOTG_BUS2SC(udev->bus); - - if (ep_addr == 0) { - /* control endpoint */ - *ppf = musbotg_ep_profile; - } else if (ep_addr <= sc->sc_ep_max) { - /* other endpoints */ - *ppf = sc->sc_hw_ep_profile + ep_addr; - } else { - *ppf = NULL; - } -} - -static void -musbotg_clocks_on(struct musbotg_softc *sc) -{ - if (sc->sc_flags.clocks_off && - sc->sc_flags.port_powered) { - - DPRINTFN(4, "\n"); - - if (sc->sc_clocks_on) { - (sc->sc_clocks_on) (sc->sc_clocks_arg); - } - sc->sc_flags.clocks_off = 0; - - /* XXX enable Transceiver */ - } -} - -static void -musbotg_clocks_off(struct musbotg_softc *sc) -{ - if (!sc->sc_flags.clocks_off) { - - DPRINTFN(4, "\n"); - - /* XXX disable Transceiver */ - - if (sc->sc_clocks_off) { - (sc->sc_clocks_off) (sc->sc_clocks_arg); - } - sc->sc_flags.clocks_off = 1; - } -} - -static void -musbotg_pull_common(struct musbotg_softc *sc, uint8_t on) -{ - uint8_t temp; - - temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); - if (on) - temp |= MUSB2_MASK_SOFTC; - else - temp &= ~MUSB2_MASK_SOFTC; - - MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); -} - -static void -musbotg_pull_up(struct musbotg_softc *sc) -{ - /* pullup D+, if possible */ - - if (!sc->sc_flags.d_pulled_up && - sc->sc_flags.port_powered) { - sc->sc_flags.d_pulled_up = 1; - musbotg_pull_common(sc, 1); - } -} - -static void -musbotg_pull_down(struct musbotg_softc *sc) -{ - /* pulldown D+, if possible */ - - if (sc->sc_flags.d_pulled_up) { - sc->sc_flags.d_pulled_up = 0; - musbotg_pull_common(sc, 0); - } -} - -static void -musbotg_wakeup_peer(struct usb2_xfer *xfer) -{ - struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus); - uint8_t temp; - uint8_t use_polling; - - if (!(sc->sc_flags.status_suspend)) { - return; - } - use_polling = mtx_owned(xfer->xroot->xfer_mtx) ? 1 : 0; - - temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); - temp |= MUSB2_MASK_RESUME; - MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); - - /* wait 8 milliseconds */ - if (use_polling) { - /* polling */ - DELAY(8000); - } else { - /* Wait for reset to complete. */ - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); - } - - temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); - temp &= ~MUSB2_MASK_RESUME; - MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); -} - -static void -musbotg_set_address(struct musbotg_softc *sc, uint8_t addr) -{ - DPRINTFN(4, "addr=%d\n", addr); - addr &= 0x7F; - MUSB2_WRITE_1(sc, MUSB2_REG_FADDR, addr); -} - -static uint8_t -musbotg_setup_rx(struct musbotg_td *td) -{ - struct musbotg_softc *sc; - struct usb2_device_request req; - uint16_t count; - uint8_t csr; - - /* get pointer to softc */ - sc = MUSBOTG_PC2SC(td->pc); - - /* select endpoint 0 */ - MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); - - /* read out FIFO status */ - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - - DPRINTFN(4, "csr=0x%02x\n", csr); - - /* - * NOTE: If DATAEND is set we should not call the - * callback, hence the status stage is not complete. - */ - if (csr & MUSB2_MASK_CSR0L_DATAEND) { - /* wait for interrupt */ - goto not_complete; - } - if (csr & MUSB2_MASK_CSR0L_SENTSTALL) { - /* clear SENTSTALL */ - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); - /* get latest status */ - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - /* update EP0 state */ - sc->sc_ep0_busy = 0; - } - if (csr & MUSB2_MASK_CSR0L_SETUPEND) { - /* clear SETUPEND */ - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, - MUSB2_MASK_CSR0L_SETUPEND_CLR); - /* get latest status */ - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - /* update EP0 state */ - sc->sc_ep0_busy = 0; - } - if (sc->sc_ep0_busy) { - /* abort any ongoing transfer */ - if (!td->did_stall) { - DPRINTFN(4, "stalling\n"); - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, - MUSB2_MASK_CSR0L_SENDSTALL); - td->did_stall = 1; - } - goto not_complete; - } - if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY)) { - goto not_complete; - } - /* get the packet byte count */ - count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); - - /* verify data length */ - if (count != td->remainder) { - DPRINTFN(0, "Invalid SETUP packet " - "length, %d bytes\n", count); - goto not_complete; - } - if (count != sizeof(req)) { - DPRINTFN(0, "Unsupported SETUP packet " - "length, %d bytes\n", count); - goto not_complete; - } - /* receive data */ - bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(0), (void *)&req, sizeof(req)); - - /* copy data into real buffer */ - usb2_copy_in(td->pc, 0, &req, sizeof(req)); - - td->offset = sizeof(req); - td->remainder = 0; - - /* set pending command */ - sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_RXPKTRDY_CLR; - - /* we need set stall or dataend after this */ - sc->sc_ep0_busy = 1; - - /* sneak peek the set address */ - if ((req.bmRequestType == UT_WRITE_DEVICE) && - (req.bRequest == UR_SET_ADDRESS)) { - sc->sc_dv_addr = req.wValue[0] & 0x7F; - } else { - sc->sc_dv_addr = 0xFF; - } - return (0); /* complete */ - -not_complete: - return (1); /* not complete */ -} - -/* Control endpoint only data handling functions (RX/TX/SYNC) */ - -static uint8_t -musbotg_setup_data_rx(struct musbotg_td *td) -{ - struct usb2_page_search buf_res; - struct musbotg_softc *sc; - uint16_t count; - uint8_t csr; - uint8_t got_short; - - /* get pointer to softc */ - sc = MUSBOTG_PC2SC(td->pc); - - /* select endpoint 0 */ - MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); - - /* check if a command is pending */ - if (sc->sc_ep0_cmd) { - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd); - sc->sc_ep0_cmd = 0; - } - /* read out FIFO status */ - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - - DPRINTFN(4, "csr=0x%02x\n", csr); - - got_short = 0; - - if (csr & (MUSB2_MASK_CSR0L_SETUPEND | - MUSB2_MASK_CSR0L_SENTSTALL)) { - if (td->remainder == 0) { - /* - * We are actually complete and have - * received the next SETUP - */ - DPRINTFN(4, "faking complete\n"); - return (0); /* complete */ - } - /* - * USB Host Aborted the transfer. - */ - td->error = 1; - return (0); /* complete */ - } - if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY)) { - return (1); /* not complete */ - } - /* get the packet byte count */ - count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); - - /* verify the packet byte count */ - if (count != td->max_frame_size) { - if (count < td->max_frame_size) { - /* we have a short packet */ - td->short_pkt = 1; - got_short = 1; - } else { - /* invalid USB packet */ - td->error = 1; - return (0); /* we are complete */ - } - } - /* verify the packet byte count */ - if (count > td->remainder) { - /* invalid USB packet */ - td->error = 1; - return (0); /* we are complete */ - } - while (count > 0) { - uint32_t temp; - - usb2_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* check for unaligned memory address */ - if (USB_P2U(buf_res.buffer) & 3) { - - temp = count & ~3; - - if (temp) { - /* receive data 4 bytes at a time */ - bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf, - temp / 4); - } - temp = count & 3; - if (temp) { - /* receive data 1 byte at a time */ - bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(0), - (void *)(&sc->sc_bounce_buf[count / 4]), temp); - } - usb2_copy_in(td->pc, td->offset, - sc->sc_bounce_buf, count); - - /* update offset and remainder */ - td->offset += count; - td->remainder -= count; - break; - } - /* check if we can optimise */ - if (buf_res.length >= 4) { - - /* receive data 4 bytes at a time */ - bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(0), buf_res.buffer, - buf_res.length / 4); - - temp = buf_res.length & ~3; - - /* update counters */ - count -= temp; - td->offset += temp; - td->remainder -= temp; - continue; - } - /* receive data */ - bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length); - - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } - - /* check if we are complete */ - if ((td->remainder == 0) || got_short) { - if (td->short_pkt) { - /* we are complete */ - sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_RXPKTRDY_CLR; - return (0); - } - /* else need to receive a zero length packet */ - } - /* write command - need more data */ - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, - MUSB2_MASK_CSR0L_RXPKTRDY_CLR); - return (1); /* not complete */ -} - -static uint8_t -musbotg_setup_data_tx(struct musbotg_td *td) -{ - struct usb2_page_search buf_res; - struct musbotg_softc *sc; - uint16_t count; - uint8_t csr; - - /* get pointer to softc */ - sc = MUSBOTG_PC2SC(td->pc); - - /* select endpoint 0 */ - MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); - - /* check if a command is pending */ - if (sc->sc_ep0_cmd) { - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd); - sc->sc_ep0_cmd = 0; - } - /* read out FIFO status */ - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - - DPRINTFN(4, "csr=0x%02x\n", csr); - - if (csr & (MUSB2_MASK_CSR0L_SETUPEND | - MUSB2_MASK_CSR0L_SENTSTALL)) { - /* - * The current transfer was aborted - * by the USB Host - */ - td->error = 1; - return (0); /* complete */ - } - if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) { - return (1); /* not complete */ - } - count = td->max_frame_size; - if (td->remainder < count) { - /* we have a short packet */ - td->short_pkt = 1; - count = td->remainder; - } - while (count > 0) { - uint32_t temp; - - usb2_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* check for unaligned memory address */ - if (USB_P2U(buf_res.buffer) & 3) { - - usb2_copy_out(td->pc, td->offset, - sc->sc_bounce_buf, count); - - temp = count & ~3; - - if (temp) { - /* transmit data 4 bytes at a time */ - bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf, - temp / 4); - } - temp = count & 3; - if (temp) { - /* receive data 1 byte at a time */ - bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(0), - ((void *)&sc->sc_bounce_buf[count / 4]), temp); - } - /* update offset and remainder */ - td->offset += count; - td->remainder -= count; - break; - } - /* check if we can optimise */ - if (buf_res.length >= 4) { - - /* transmit data 4 bytes at a time */ - bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(0), buf_res.buffer, - buf_res.length / 4); - - temp = buf_res.length & ~3; - - /* update counters */ - count -= temp; - td->offset += temp; - td->remainder -= temp; - continue; - } - /* transmit data */ - bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length); - - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } - - /* check remainder */ - if (td->remainder == 0) { - if (td->short_pkt) { - sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_TXPKTRDY; - return (0); /* complete */ - } - /* else we need to transmit a short packet */ - } - /* write command */ - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, - MUSB2_MASK_CSR0L_TXPKTRDY); - - return (1); /* not complete */ -} - -static uint8_t -musbotg_setup_status(struct musbotg_td *td) -{ - struct musbotg_softc *sc; - uint8_t csr; - - /* get pointer to softc */ - sc = MUSBOTG_PC2SC(td->pc); - - /* select endpoint 0 */ - MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); - - if (sc->sc_ep0_busy) { - sc->sc_ep0_busy = 0; - sc->sc_ep0_cmd |= MUSB2_MASK_CSR0L_DATAEND; - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd); - sc->sc_ep0_cmd = 0; - } - /* read out FIFO status */ - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - - DPRINTFN(4, "csr=0x%02x\n", csr); - - if (csr & MUSB2_MASK_CSR0L_DATAEND) { - /* wait for interrupt */ - return (1); /* not complete */ - } - if (sc->sc_dv_addr != 0xFF) { - /* write function address */ - musbotg_set_address(sc, sc->sc_dv_addr); - } - return (0); /* complete */ -} - -static uint8_t -musbotg_data_rx(struct musbotg_td *td) -{ - struct usb2_page_search buf_res; - struct musbotg_softc *sc; - uint16_t count; - uint8_t csr; - uint8_t to; - uint8_t got_short; - - to = 8; /* don't loop forever! */ - got_short = 0; - - /* get pointer to softc */ - sc = MUSBOTG_PC2SC(td->pc); - - /* select endpoint */ - MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->ep_no); - -repeat: - /* read out FIFO status */ - csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); - - DPRINTFN(4, "csr=0x%02x\n", csr); - - /* clear overrun */ - if (csr & MUSB2_MASK_CSRL_RXOVERRUN) { - /* make sure we don't clear "RXPKTRDY" */ - MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, - MUSB2_MASK_CSRL_RXPKTRDY); - } - /* check status */ - if (!(csr & MUSB2_MASK_CSRL_RXPKTRDY)) { - return (1); /* not complete */ - } - /* get the packet byte count */ - count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); - - DPRINTFN(4, "count=0x%04x\n", count); - - /* - * Check for short or invalid packet: - */ - if (count != td->max_frame_size) { - if (count < td->max_frame_size) { - /* we have a short packet */ - td->short_pkt = 1; - got_short = 1; - } else { - /* invalid USB packet */ - td->error = 1; - return (0); /* we are complete */ - } - } - /* verify the packet byte count */ - if (count > td->remainder) { - /* invalid USB packet */ - td->error = 1; - return (0); /* we are complete */ - } - while (count > 0) { - uint32_t temp; - - usb2_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* check for unaligned memory address */ - if (USB_P2U(buf_res.buffer) & 3) { - - temp = count & ~3; - - if (temp) { - /* receive data 4 bytes at a time */ - bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(td->ep_no), sc->sc_bounce_buf, - temp / 4); - } - temp = count & 3; - if (temp) { - /* receive data 1 byte at a time */ - bus_space_read_multi_1(sc->sc_io_tag, - sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->ep_no), - ((void *)&sc->sc_bounce_buf[count / 4]), temp); - } - usb2_copy_in(td->pc, td->offset, - sc->sc_bounce_buf, count); - - /* update offset and remainder */ - td->offset += count; - td->remainder -= count; - break; - } - /* check if we can optimise */ - if (buf_res.length >= 4) { - - /* receive data 4 bytes at a time */ - bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(td->ep_no), buf_res.buffer, - buf_res.length / 4); - - temp = buf_res.length & ~3; - - /* update counters */ - count -= temp; - td->offset += temp; - td->remainder -= temp; - continue; - } - /* receive data */ - bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(td->ep_no), buf_res.buffer, - buf_res.length); - - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } - - /* clear status bits */ - MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0); - - /* check if we are complete */ - if ((td->remainder == 0) || got_short) { - if (td->short_pkt) { - /* we are complete */ - return (0); - } - /* else need to receive a zero length packet */ - } - if (--to) { - goto repeat; - } - return (1); /* not complete */ -} - -static uint8_t -musbotg_data_tx(struct musbotg_td *td) -{ - struct usb2_page_search buf_res; - struct musbotg_softc *sc; - uint16_t count; - uint8_t csr; - uint8_t to; - - to = 8; /* don't loop forever! */ - - /* get pointer to softc */ - sc = MUSBOTG_PC2SC(td->pc); - - /* select endpoint */ - MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->ep_no); - -repeat: - - /* read out FIFO status */ - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - - DPRINTFN(4, "csr=0x%02x\n", csr); - - if (csr & (MUSB2_MASK_CSRL_TXINCOMP | - MUSB2_MASK_CSRL_TXUNDERRUN)) { - /* clear status bits */ - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); - } - if (csr & MUSB2_MASK_CSRL_TXPKTRDY) { - return (1); /* not complete */ - } - /* check for short packet */ - count = td->max_frame_size; - if (td->remainder < count) { - /* we have a short packet */ - td->short_pkt = 1; - count = td->remainder; - } - while (count > 0) { - uint32_t temp; - - usb2_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* check for unaligned memory address */ - if (USB_P2U(buf_res.buffer) & 3) { - - usb2_copy_out(td->pc, td->offset, - sc->sc_bounce_buf, count); - - temp = count & ~3; - - if (temp) { - /* transmit data 4 bytes at a time */ - bus_space_write_multi_4(sc->sc_io_tag, - sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->ep_no), - sc->sc_bounce_buf, temp / 4); - } - temp = count & 3; - if (temp) { - /* receive data 1 byte at a time */ - bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(td->ep_no), - ((void *)&sc->sc_bounce_buf[count / 4]), temp); - } - /* update offset and remainder */ - td->offset += count; - td->remainder -= count; - break; - } - /* check if we can optimise */ - if (buf_res.length >= 4) { - - /* transmit data 4 bytes at a time */ - bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(td->ep_no), buf_res.buffer, - buf_res.length / 4); - - temp = buf_res.length & ~3; - - /* update counters */ - count -= temp; - td->offset += temp; - td->remainder -= temp; - continue; - } - /* transmit data */ - bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, - MUSB2_REG_EPFIFO(td->ep_no), buf_res.buffer, - buf_res.length); - - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } - - /* write command */ - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, - MUSB2_MASK_CSRL_TXPKTRDY); - - /* check remainder */ - if (td->remainder == 0) { - if (td->short_pkt) { - return (0); /* complete */ - } - /* else we need to transmit a short packet */ - } - if (--to) { - goto repeat; - } - return (1); /* not complete */ -} - -static uint8_t -musbotg_xfer_do_fifo(struct usb2_xfer *xfer) -{ - struct musbotg_softc *sc; - struct musbotg_td *td; - - DPRINTFN(8, "\n"); - - td = xfer->td_transfer_cache; - while (1) { - if ((td->func) (td)) { - /* operation in progress */ - break; - } - if (((void *)td) == xfer->td_transfer_last) { - goto done; - } - if (td->error) { - goto done; - } else if (td->remainder > 0) { - /* - * We had a short transfer. If there is no alternate - * next, stop processing ! - */ - if (!td->alt_next) { - goto done; - } - } - /* - * Fetch the next transfer descriptor and transfer - * some flags to the next transfer descriptor - */ - td = td->obj_next; - xfer->td_transfer_cache = td; - } - return (1); /* not complete */ - -done: - sc = MUSBOTG_BUS2SC(xfer->xroot->bus); - - /* compute all actual lengths */ - - musbotg_standard_done(xfer); - - return (0); /* complete */ -} - -static void -musbotg_interrupt_poll(struct musbotg_softc *sc) -{ - struct usb2_xfer *xfer; - -repeat: - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - if (!musbotg_xfer_do_fifo(xfer)) { - /* queue has been modified */ - goto repeat; - } - } -} - -void -musbotg_vbus_interrupt(struct musbotg_softc *sc, uint8_t is_on) -{ - DPRINTFN(4, "vbus = %u\n", is_on); - - USB_BUS_LOCK(&sc->sc_bus); - if (is_on) { - if (!sc->sc_flags.status_vbus) { - sc->sc_flags.status_vbus = 1; - - /* complete root HUB interrupt endpoint */ - - usb2_sw_transfer(&sc->sc_root_intr, - &musbotg_root_intr_done); - } - } else { - if (sc->sc_flags.status_vbus) { - sc->sc_flags.status_vbus = 0; - sc->sc_flags.status_bus_reset = 0; - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 0; - sc->sc_flags.change_connect = 1; - - /* complete root HUB interrupt endpoint */ - - usb2_sw_transfer(&sc->sc_root_intr, - &musbotg_root_intr_done); - } - } - - USB_BUS_UNLOCK(&sc->sc_bus); -} - -void -musbotg_interrupt(struct musbotg_softc *sc) -{ - uint16_t rx_status; - uint16_t tx_status; - uint8_t usb_status; - uint8_t temp; - uint8_t to = 2; - - USB_BUS_LOCK(&sc->sc_bus); - -repeat: - - /* read all interrupt registers */ - usb_status = MUSB2_READ_1(sc, MUSB2_REG_INTUSB); - - /* read all FIFO interrupts */ - rx_status = MUSB2_READ_2(sc, MUSB2_REG_INTRX); - tx_status = MUSB2_READ_2(sc, MUSB2_REG_INTTX); - - /* check for any bus state change interrupts */ - - if (usb_status & (MUSB2_MASK_IRESET | - MUSB2_MASK_IRESUME | MUSB2_MASK_ISUSP)) { - - DPRINTFN(4, "real bus interrupt 0x%08x\n", usb_status); - - if (usb_status & MUSB2_MASK_IRESET) { - - /* set correct state */ - sc->sc_flags.status_bus_reset = 1; - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 0; - sc->sc_flags.change_connect = 1; - - /* determine line speed */ - temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); - if (temp & MUSB2_MASK_HSMODE) - sc->sc_flags.status_high_speed = 1; - else - sc->sc_flags.status_high_speed = 0; - - /* - * After reset all interrupts are on and we need to - * turn them off! - */ - temp = MUSB2_MASK_IRESET; - /* disable resume interrupt */ - temp &= ~MUSB2_MASK_IRESUME; - /* enable suspend interrupt */ - temp |= MUSB2_MASK_ISUSP; - MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp); - /* disable TX and RX interrupts */ - MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0); - MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0); - } - /* - * If RXRSM and RXSUSP is set at the same time we interpret - * that like RESUME. Resume is set when there is at least 3 - * milliseconds of inactivity on the USB BUS. - */ - if (usb_status & MUSB2_MASK_IRESUME) { - if (sc->sc_flags.status_suspend) { - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 1; - - temp = MUSB2_READ_1(sc, MUSB2_REG_INTUSBE); - /* disable resume interrupt */ - temp &= ~MUSB2_MASK_IRESUME; - /* enable suspend interrupt */ - temp |= MUSB2_MASK_ISUSP; - MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp); - } - } else if (usb_status & MUSB2_MASK_ISUSP) { - if (!sc->sc_flags.status_suspend) { - sc->sc_flags.status_suspend = 1; - sc->sc_flags.change_suspend = 1; - - temp = MUSB2_READ_1(sc, MUSB2_REG_INTUSBE); - /* disable suspend interrupt */ - temp &= ~MUSB2_MASK_ISUSP; - /* enable resume interrupt */ - temp |= MUSB2_MASK_IRESUME; - MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp); - } - } - /* complete root HUB interrupt endpoint */ - - usb2_sw_transfer(&sc->sc_root_intr, - &musbotg_root_intr_done); - } - /* check for any endpoint interrupts */ - - if (rx_status || tx_status) { - DPRINTFN(4, "real endpoint interrupt " - "rx=0x%04x, tx=0x%04x\n", rx_status, tx_status); - } - /* poll one time regardless of FIFO status */ - - musbotg_interrupt_poll(sc); - - if (--to) - goto repeat; - - USB_BUS_UNLOCK(&sc->sc_bus); -} - -static void -musbotg_setup_standard_chain_sub(struct musbotg_std_temp *temp) -{ - struct musbotg_td *td; - - /* get current Transfer Descriptor */ - td = temp->td_next; - temp->td = td; - - /* prepare for next TD */ - temp->td_next = td->obj_next; - - /* fill out the Transfer Descriptor */ - td->func = temp->func; - td->pc = temp->pc; - td->offset = temp->offset; - td->remainder = temp->len; - td->error = 0; - td->did_stall = 0; - td->short_pkt = temp->short_pkt; - td->alt_next = temp->setup_alt_next; -} - -static void -musbotg_setup_standard_chain(struct usb2_xfer *xfer) -{ - struct musbotg_std_temp temp; - struct musbotg_softc *sc; - struct musbotg_td *td; - uint32_t x; - uint8_t ep_no; - - DPRINTFN(8, "addr=%d endpt=%d sumlen=%d speed=%d\n", - xfer->address, UE_GET_ADDR(xfer->endpoint), - xfer->sumlen, usb2_get_speed(xfer->xroot->udev)); - - temp.max_frame_size = xfer->max_frame_size; - - td = xfer->td_start[0]; - xfer->td_transfer_first = td; - xfer->td_transfer_cache = td; - - /* setup temp */ - - temp.td = NULL; - temp.td_next = xfer->td_start[0]; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; - temp.offset = 0; - - sc = MUSBOTG_BUS2SC(xfer->xroot->bus); - ep_no = (xfer->endpoint & UE_ADDR); - - /* check if we should prepend a setup message */ - - if (xfer->flags_int.control_xfr) { - if (xfer->flags_int.control_hdr) { - - temp.func = &musbotg_setup_rx; - temp.len = xfer->frlengths[0]; - temp.pc = xfer->frbuffers + 0; - temp.short_pkt = temp.len ? 1 : 0; - - musbotg_setup_standard_chain_sub(&temp); - } - x = 1; - } else { - x = 0; - } - - if (x != xfer->nframes) { - if (xfer->endpoint & UE_DIR_IN) { - if (xfer->flags_int.control_xfr) - temp.func = &musbotg_setup_data_tx; - else - temp.func = &musbotg_data_tx; - } else { - if (xfer->flags_int.control_xfr) - temp.func = &musbotg_setup_data_rx; - else - temp.func = &musbotg_data_rx; - } - - /* setup "pc" pointer */ - temp.pc = xfer->frbuffers + x; - } - while (x != xfer->nframes) { - - /* DATA0 / DATA1 message */ - - temp.len = xfer->frlengths[x]; - - x++; - - if (x == xfer->nframes) { - temp.setup_alt_next = 0; - } - if (temp.len == 0) { - - /* make sure that we send an USB packet */ - - temp.short_pkt = 0; - - } else { - - /* regular data transfer */ - - temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; - } - - musbotg_setup_standard_chain_sub(&temp); - - if (xfer->flags_int.isochronous_xfr) { - temp.offset += temp.len; - } else { - /* get next Page Cache pointer */ - temp.pc = xfer->frbuffers + x; - } - } - - /* always setup a valid "pc" pointer for status and sync */ - temp.pc = xfer->frbuffers + 0; - - /* check if we should append a status stage */ - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - /* - * Send a DATA1 message and invert the current - * endpoint direction. - */ - temp.func = &musbotg_setup_status; - temp.len = 0; - temp.short_pkt = 0; - - musbotg_setup_standard_chain_sub(&temp); - } - /* must have at least one frame! */ - td = temp.td; - xfer->td_transfer_last = td; -} - -static void -musbotg_timeout(void *arg) -{ - struct usb2_xfer *xfer = arg; - - DPRINTFN(1, "xfer=%p\n", xfer); - - USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); - - /* transfer is transferred */ - musbotg_device_done(xfer, USB_ERR_TIMEOUT); -} - -static void -musbotg_ep_int_set(struct usb2_xfer *xfer, uint8_t on) -{ - struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus); - uint16_t temp; - uint8_t ep_no = xfer->endpoint & UE_ADDR; - - /* - * Only enable the endpoint interrupt when we are - * actually waiting for data, hence we are dealing - * with level triggered interrupts ! - */ - if (ep_no == 0) { - temp = MUSB2_READ_2(sc, MUSB2_REG_INTTXE); - if (on) - temp |= MUSB2_MASK_EPINT(0); - else - temp &= ~MUSB2_MASK_EPINT(0); - - MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, temp); - } else { - if (USB_GET_DATA_ISREAD(xfer)) { - temp = MUSB2_READ_2(sc, MUSB2_REG_INTRXE); - if (on) - temp |= MUSB2_MASK_EPINT(ep_no); - else - temp &= ~MUSB2_MASK_EPINT(ep_no); - MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, temp); - - } else { - temp = MUSB2_READ_2(sc, MUSB2_REG_INTTXE); - if (on) - temp |= MUSB2_MASK_EPINT(ep_no); - else - temp &= ~MUSB2_MASK_EPINT(ep_no); - MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, temp); - } - } -} - -static void -musbotg_start_standard_chain(struct usb2_xfer *xfer) -{ - DPRINTFN(8, "\n"); - - /* poll one time */ - if (musbotg_xfer_do_fifo(xfer)) { - - musbotg_ep_int_set(xfer, 1); - - DPRINTFN(14, "enabled interrupts on endpoint\n"); - - /* put transfer on interrupt queue */ - usb2_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); - - /* start timeout, if any */ - if (xfer->timeout != 0) { - usb2_transfer_timeout_ms(xfer, - &musbotg_timeout, xfer->timeout); - } - } -} - -static void -musbotg_root_intr_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus); - - DPRINTFN(8, "\n"); - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_PRE_DATA) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - musbotg_device_done(xfer, std->err); - } - goto done; - } - /* setup buffer */ - std->ptr = sc->sc_hub_idata; - std->len = sizeof(sc->sc_hub_idata); - - /* set port bit */ - sc->sc_hub_idata[0] = 0x02; /* we only have one port */ - -done: - return; -} - -static usb2_error_t -musbotg_standard_done_sub(struct usb2_xfer *xfer) -{ - struct musbotg_td *td; - uint32_t len; - uint8_t error; - - DPRINTFN(8, "\n"); - - td = xfer->td_transfer_cache; - - do { - len = td->remainder; - - if (xfer->aframes != xfer->nframes) { - /* - * Verify the length and subtract - * the remainder from "frlengths[]": - */ - if (len > xfer->frlengths[xfer->aframes]) { - td->error = 1; - } else { - xfer->frlengths[xfer->aframes] -= len; - } - } - /* Check for transfer error */ - if (td->error) { - /* the transfer is finished */ - error = 1; - td = NULL; - break; - } - /* Check for short transfer */ - if (len > 0) { - if (xfer->flags_int.short_frames_ok) { - /* follow alt next */ - if (td->alt_next) { - td = td->obj_next; - } else { - td = NULL; - } - } else { - /* the transfer is finished */ - td = NULL; - } - error = 0; - break; - } - td = td->obj_next; - - /* this USB frame is complete */ - error = 0; - break; - - } while (0); - - /* update transfer cache */ - - xfer->td_transfer_cache = td; - - return (error ? - USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); -} - -static void -musbotg_standard_done(struct usb2_xfer *xfer) -{ - usb2_error_t err = 0; - - DPRINTFN(12, "xfer=%p pipe=%p transfer done\n", - xfer, xfer->pipe); - - /* reset scanner */ - - xfer->td_transfer_cache = xfer->td_transfer_first; - - if (xfer->flags_int.control_xfr) { - - if (xfer->flags_int.control_hdr) { - - err = musbotg_standard_done_sub(xfer); - } - xfer->aframes = 1; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - while (xfer->aframes != xfer->nframes) { - - err = musbotg_standard_done_sub(xfer); - xfer->aframes++; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - err = musbotg_standard_done_sub(xfer); - } -done: - musbotg_device_done(xfer, err); -} - -/*------------------------------------------------------------------------* - * musbotg_device_done - * - * NOTE: this function can be called more than one time on the - * same USB transfer! - *------------------------------------------------------------------------*/ -static void -musbotg_device_done(struct usb2_xfer *xfer, usb2_error_t error) -{ - USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); - - DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", - xfer, xfer->pipe, error); - - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { - - musbotg_ep_int_set(xfer, 0); - - DPRINTFN(14, "disabled interrupts on endpoint\n"); - } - /* dequeue transfer and start next transfer */ - usb2_transfer_done(xfer, error); -} - -static void -musbotg_set_stall(struct usb2_device *udev, struct usb2_xfer *xfer, - struct usb2_pipe *pipe) -{ - struct musbotg_softc *sc; - uint8_t ep_no; - - USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); - - DPRINTFN(4, "pipe=%p\n", pipe); - - if (xfer) { - /* cancel any ongoing transfers */ - musbotg_device_done(xfer, USB_ERR_STALLED); - } - /* set FORCESTALL */ - sc = MUSBOTG_BUS2SC(udev->bus); - - ep_no = (pipe->edesc->bEndpointAddress & UE_ADDR); - - /* select endpoint */ - MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, ep_no); - - if (pipe->edesc->bEndpointAddress & UE_DIR_IN) { - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, - MUSB2_MASK_CSRL_TXSENDSTALL); - } else { - MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, - MUSB2_MASK_CSRL_RXSENDSTALL); - } -} - -static void -musbotg_clear_stall_sub(struct musbotg_softc *sc, uint16_t wMaxPacket, - uint8_t ep_no, uint8_t ep_type, uint8_t ep_dir) -{ - uint16_t mps; - uint16_t temp; - uint8_t csr; - - if (ep_type == UE_CONTROL) { - /* clearing stall is not needed */ - return; - } - /* select endpoint */ - MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, ep_no); - - /* compute max frame size */ - mps = wMaxPacket & 0x7FF; - switch ((wMaxPacket >> 11) & 3) { - case 1: - mps *= 2; - break; - case 2: - mps *= 3; - break; - default: - break; - } - - if (ep_dir == UE_DIR_IN) { - - temp = 0; - - /* Configure endpoint */ - switch (ep_type) { - case UE_INTERRUPT: - MUSB2_WRITE_1(sc, MUSB2_REG_TXMAXP, wMaxPacket); - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, - MUSB2_MASK_CSRH_TXMODE | temp); - break; - case UE_ISOCHRONOUS: - MUSB2_WRITE_1(sc, MUSB2_REG_TXMAXP, wMaxPacket); - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, - MUSB2_MASK_CSRH_TXMODE | - MUSB2_MASK_CSRH_TXISO | temp); - break; - case UE_BULK: - MUSB2_WRITE_1(sc, MUSB2_REG_TXMAXP, wMaxPacket); - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, - MUSB2_MASK_CSRH_TXMODE | temp); - break; - default: - break; - } - - /* Need to flush twice in case of double bufring */ - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, - MUSB2_MASK_CSRL_TXFFLUSH); - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, - MUSB2_MASK_CSRL_TXFFLUSH); - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - } - } - /* reset data toggle */ - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, - MUSB2_MASK_CSRL_TXDT_CLR); - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - - /* set double/single buffering */ - temp = MUSB2_READ_2(sc, MUSB2_REG_TXDBDIS); - if (mps <= (sc->sc_hw_ep_profile[ep_no]. - max_in_frame_size / 2)) { - /* double buffer */ - temp &= ~(1 << ep_no); - } else { - /* single buffer */ - temp |= (1 << ep_no); - } - MUSB2_WRITE_2(sc, MUSB2_REG_TXDBDIS, temp); - - /* clear sent stall */ - if (csr & MUSB2_MASK_CSRL_TXSENTSTALL) { - MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); - csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); - } - } else { - - temp = 0; - - /* Configure endpoint */ - switch (ep_type) { - case UE_INTERRUPT: - MUSB2_WRITE_1(sc, MUSB2_REG_RXMAXP, wMaxPacket); - MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, - MUSB2_MASK_CSRH_RXNYET | temp); - break; - case UE_ISOCHRONOUS: - MUSB2_WRITE_1(sc, MUSB2_REG_RXMAXP, wMaxPacket); - MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, - MUSB2_MASK_CSRH_RXNYET | - MUSB2_MASK_CSRH_RXISO | temp); - break; - case UE_BULK: - MUSB2_WRITE_1(sc, MUSB2_REG_RXMAXP, wMaxPacket); - MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, temp); - break; - default: - break; - } - - /* Need to flush twice in case of double bufring */ - csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); - if (csr & MUSB2_MASK_CSRL_RXPKTRDY) { - MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, - MUSB2_MASK_CSRL_RXFFLUSH); - csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); - if (csr & MUSB2_MASK_CSRL_RXPKTRDY) { - MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, - MUSB2_MASK_CSRL_RXFFLUSH); - csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); - } - } - /* reset data toggle */ - MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, - MUSB2_MASK_CSRL_RXDT_CLR); - MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0); - csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); - - /* set double/single buffering */ - temp = MUSB2_READ_2(sc, MUSB2_REG_RXDBDIS); - if (mps <= (sc->sc_hw_ep_profile[ep_no]. - max_out_frame_size / 2)) { - /* double buffer */ - temp &= ~(1 << ep_no); - } else { - /* single buffer */ - temp |= (1 << ep_no); - } - MUSB2_WRITE_2(sc, MUSB2_REG_RXDBDIS, temp); - - /* clear sent stall */ - if (csr & MUSB2_MASK_CSRL_RXSENTSTALL) { - MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0); - } - } -} - -static void -musbotg_clear_stall(struct usb2_device *udev, struct usb2_pipe *pipe) -{ - struct musbotg_softc *sc; - struct usb2_endpoint_descriptor *ed; - - DPRINTFN(4, "pipe=%p\n", pipe); - - USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); - - /* check mode */ - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { - /* not supported */ - return; - } - /* get softc */ - sc = MUSBOTG_BUS2SC(udev->bus); - - /* get endpoint descriptor */ - ed = pipe->edesc; - - /* reset endpoint */ - musbotg_clear_stall_sub(sc, - UGETW(ed->wMaxPacketSize), - (ed->bEndpointAddress & UE_ADDR), - (ed->bmAttributes & UE_XFERTYPE), - (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); -} - -usb2_error_t -musbotg_init(struct musbotg_softc *sc) -{ - struct usb2_hw_ep_profile *pf; - uint8_t nrx; - uint8_t ntx; - uint8_t temp; - uint8_t fsize; - uint8_t frx; - uint8_t ftx; - - DPRINTFN(1, "start\n"); - - /* set up the bus structure */ - sc->sc_bus.usbrev = USB_REV_2_0; - sc->sc_bus.methods = &musbotg_bus_methods; - - USB_BUS_LOCK(&sc->sc_bus); - - /* turn on clocks */ - - if (sc->sc_clocks_on) { - (sc->sc_clocks_on) (sc->sc_clocks_arg); - } - /* wait a little for things to stabilise */ - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); - - /* disable all interrupts */ - - MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 0); - MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0); - MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0); - - /* disable pullup */ - - musbotg_pull_common(sc, 0); - - /* wait a little bit (10ms) */ - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100); - - /* disable double packet buffering */ - MUSB2_WRITE_2(sc, MUSB2_REG_RXDBDIS, 0xFFFF); - MUSB2_WRITE_2(sc, MUSB2_REG_TXDBDIS, 0xFFFF); - - /* enable HighSpeed and ISO Update flags */ - - MUSB2_WRITE_1(sc, MUSB2_REG_POWER, - MUSB2_MASK_HSENAB | MUSB2_MASK_ISOUPD); - - /* clear Session bit, if set */ - - temp = MUSB2_READ_1(sc, MUSB2_REG_DEVCTL); - temp &= ~MUSB2_MASK_SESS; - MUSB2_WRITE_1(sc, MUSB2_REG_DEVCTL, temp); - - DPRINTF("DEVCTL=0x%02x\n", temp); - - /* disable testmode */ - - MUSB2_WRITE_1(sc, MUSB2_REG_TESTMODE, 0); - - /* set default value */ - - MUSB2_WRITE_1(sc, MUSB2_REG_MISC, 0); - - /* select endpoint index 0 */ - - MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); - - /* read out number of endpoints */ - - nrx = - (MUSB2_READ_1(sc, MUSB2_REG_EPINFO) / 16); - - ntx = - (MUSB2_READ_1(sc, MUSB2_REG_EPINFO) % 16); - - /* these numbers exclude the control endpoint */ - - DPRINTFN(2, "RX/TX endpoints: %u/%u\n", nrx, ntx); - - sc->sc_ep_max = (nrx > ntx) ? nrx : ntx; - if (sc->sc_ep_max == 0) { - DPRINTFN(2, "ERROR: Looks like the clocks are off!\n"); - } - /* read out configuration data */ - - sc->sc_conf_data = MUSB2_READ_1(sc, MUSB2_REG_CONFDATA); - - DPRINTFN(2, "Config Data: 0x%02x\n", - sc->sc_conf_data); - - DPRINTFN(2, "HW version: 0x%04x\n", - MUSB2_READ_1(sc, MUSB2_REG_HWVERS)); - - /* initialise endpoint profiles */ - - for (temp = 1; temp <= sc->sc_ep_max; temp++) { - pf = sc->sc_hw_ep_profile + temp; - - /* select endpoint */ - MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, temp); - - fsize = MUSB2_READ_1(sc, MUSB2_REG_FSIZE); - frx = (fsize & MUSB2_MASK_RX_FSIZE) / 16;; - ftx = (fsize & MUSB2_MASK_TX_FSIZE); - - DPRINTF("Endpoint %u FIFO size: IN=%u, OUT=%u\n", - temp, pf->max_in_frame_size, - pf->max_out_frame_size); - - if (frx && ftx && (temp <= nrx) && (temp <= ntx)) { - pf->max_in_frame_size = 1 << ftx; - pf->max_out_frame_size = 1 << frx; - pf->is_simplex = 0; /* duplex */ - pf->support_multi_buffer = 1; - pf->support_bulk = 1; - pf->support_interrupt = 1; - pf->support_isochronous = 1; - pf->support_in = 1; - pf->support_out = 1; - } else if (frx && (temp <= nrx)) { - pf->max_out_frame_size = 1 << frx; - pf->is_simplex = 1; /* simplex */ - pf->support_multi_buffer = 1; - pf->support_bulk = 1; - pf->support_interrupt = 1; - pf->support_isochronous = 1; - pf->support_out = 1; - } else if (ftx && (temp <= ntx)) { - pf->max_in_frame_size = 1 << ftx; - pf->is_simplex = 1; /* simplex */ - pf->support_multi_buffer = 1; - pf->support_bulk = 1; - pf->support_interrupt = 1; - pf->support_isochronous = 1; - pf->support_in = 1; - } - } - - /* turn on default interrupts */ - - MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, - MUSB2_MASK_IRESET); - - musbotg_clocks_off(sc); - - USB_BUS_UNLOCK(&sc->sc_bus); - - /* catch any lost interrupts */ - - musbotg_do_poll(&sc->sc_bus); - - return (0); /* success */ -} - -void -musbotg_uninit(struct musbotg_softc *sc) -{ - USB_BUS_LOCK(&sc->sc_bus); - - /* disable all interrupts */ - MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 0); - MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0); - MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0); - - sc->sc_flags.port_powered = 0; - sc->sc_flags.status_vbus = 0; - sc->sc_flags.status_bus_reset = 0; - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 0; - sc->sc_flags.change_connect = 1; - - musbotg_pull_down(sc); - musbotg_clocks_off(sc); - USB_BUS_UNLOCK(&sc->sc_bus); -} - -void -musbotg_suspend(struct musbotg_softc *sc) -{ - return; -} - -void -musbotg_resume(struct musbotg_softc *sc) -{ - return; -} - -static void -musbotg_do_poll(struct usb2_bus *bus) -{ - struct musbotg_softc *sc = MUSBOTG_BUS2SC(bus); - - USB_BUS_LOCK(&sc->sc_bus); - musbotg_interrupt_poll(sc); - musbotg_root_ctrl_poll(sc); - USB_BUS_UNLOCK(&sc->sc_bus); -} - -/*------------------------------------------------------------------------* - * musbotg bulk support - *------------------------------------------------------------------------*/ -static void -musbotg_device_bulk_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_device_bulk_close(struct usb2_xfer *xfer) -{ - musbotg_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -musbotg_device_bulk_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_device_bulk_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - musbotg_setup_standard_chain(xfer); - musbotg_start_standard_chain(xfer); -} - -struct usb2_pipe_methods musbotg_device_bulk_methods = -{ - .open = musbotg_device_bulk_open, - .close = musbotg_device_bulk_close, - .enter = musbotg_device_bulk_enter, - .start = musbotg_device_bulk_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * musbotg control support - *------------------------------------------------------------------------*/ -static void -musbotg_device_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_device_ctrl_close(struct usb2_xfer *xfer) -{ - musbotg_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -musbotg_device_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_device_ctrl_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - musbotg_setup_standard_chain(xfer); - musbotg_start_standard_chain(xfer); -} - -struct usb2_pipe_methods musbotg_device_ctrl_methods = -{ - .open = musbotg_device_ctrl_open, - .close = musbotg_device_ctrl_close, - .enter = musbotg_device_ctrl_enter, - .start = musbotg_device_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * musbotg interrupt support - *------------------------------------------------------------------------*/ -static void -musbotg_device_intr_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_device_intr_close(struct usb2_xfer *xfer) -{ - musbotg_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -musbotg_device_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_device_intr_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - musbotg_setup_standard_chain(xfer); - musbotg_start_standard_chain(xfer); -} - -struct usb2_pipe_methods musbotg_device_intr_methods = -{ - .open = musbotg_device_intr_open, - .close = musbotg_device_intr_close, - .enter = musbotg_device_intr_enter, - .start = musbotg_device_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * musbotg full speed isochronous support - *------------------------------------------------------------------------*/ -static void -musbotg_device_isoc_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_device_isoc_close(struct usb2_xfer *xfer) -{ - musbotg_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -musbotg_device_isoc_enter(struct usb2_xfer *xfer) -{ - struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus); - uint32_t temp; - uint32_t nframes; - uint32_t fs_frames; - - DPRINTFN(5, "xfer=%p next=%d nframes=%d\n", - xfer, xfer->pipe->isoc_next, xfer->nframes); - - /* get the current frame index */ - - nframes = MUSB2_READ_2(sc, MUSB2_REG_FRAME); - - /* - * check if the frame index is within the window where the frames - * will be inserted - */ - temp = (nframes - xfer->pipe->isoc_next) & MUSB2_MASK_FRAME; - - if (usb2_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) { - fs_frames = (xfer->nframes + 7) / 8; - } else { - fs_frames = xfer->nframes; - } - - if ((xfer->pipe->is_synced == 0) || - (temp < fs_frames)) { - /* - * If there is data underflow or the pipe queue is - * empty we schedule the transfer a few frames ahead - * of the current frame position. Else two isochronous - * transfers might overlap. - */ - xfer->pipe->isoc_next = (nframes + 3) & MUSB2_MASK_FRAME; - xfer->pipe->is_synced = 1; - DPRINTFN(2, "start next=%d\n", xfer->pipe->isoc_next); - } - /* - * compute how many milliseconds the insertion is ahead of the - * current frame position: - */ - temp = (xfer->pipe->isoc_next - nframes) & MUSB2_MASK_FRAME; - - /* - * pre-compute when the isochronous transfer will be finished: - */ - xfer->isoc_time_complete = - usb2_isoc_time_expand(&sc->sc_bus, nframes) + temp + - fs_frames; - - /* compute frame number for next insertion */ - xfer->pipe->isoc_next += fs_frames; - - /* setup TDs */ - musbotg_setup_standard_chain(xfer); -} - -static void -musbotg_device_isoc_start(struct usb2_xfer *xfer) -{ - /* start TD chain */ - musbotg_start_standard_chain(xfer); -} - -struct usb2_pipe_methods musbotg_device_isoc_methods = -{ - .open = musbotg_device_isoc_open, - .close = musbotg_device_isoc_close, - .enter = musbotg_device_isoc_enter, - .start = musbotg_device_isoc_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * musbotg root control support - *------------------------------------------------------------------------* - * simulate a hardware HUB by handling - * all the necessary requests - *------------------------------------------------------------------------*/ -static void -musbotg_root_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_root_ctrl_close(struct usb2_xfer *xfer) -{ - struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_ctrl.xfer == xfer) { - sc->sc_root_ctrl.xfer = NULL; - } - musbotg_device_done(xfer, USB_ERR_CANCELLED); -} - -/* - * USB descriptors for the virtual Root HUB: - */ - -static const struct usb2_device_descriptor musbotg_devd = { - .bLength = sizeof(struct usb2_device_descriptor), - .bDescriptorType = UDESC_DEVICE, - .bcdUSB = {0x00, 0x02}, - .bDeviceClass = UDCLASS_HUB, - .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_HSHUBSTT, - .bMaxPacketSize = 64, - .bcdDevice = {0x00, 0x01}, - .iManufacturer = 1, - .iProduct = 2, - .bNumConfigurations = 1, -}; - -static const struct usb2_device_qualifier musbotg_odevd = { - .bLength = sizeof(struct usb2_device_qualifier), - .bDescriptorType = UDESC_DEVICE_QUALIFIER, - .bcdUSB = {0x00, 0x02}, - .bDeviceClass = UDCLASS_HUB, - .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_FSHUB, - .bMaxPacketSize0 = 0, - .bNumConfigurations = 0, -}; - -static const struct musbotg_config_desc musbotg_confd = { - .confd = { - .bLength = sizeof(struct usb2_config_descriptor), - .bDescriptorType = UDESC_CONFIG, - .wTotalLength[0] = sizeof(musbotg_confd), - .bNumInterface = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = UC_SELF_POWERED, - .bMaxPower = 0, - }, - .ifcd = { - .bLength = sizeof(struct usb2_interface_descriptor), - .bDescriptorType = UDESC_INTERFACE, - .bNumEndpoints = 1, - .bInterfaceClass = UICLASS_HUB, - .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_HSHUBSTT, - }, - - .endpd = { - .bLength = sizeof(struct usb2_endpoint_descriptor), - .bDescriptorType = UDESC_ENDPOINT, - .bEndpointAddress = (UE_DIR_IN | MUSBOTG_INTR_ENDPT), - .bmAttributes = UE_INTERRUPT, - .wMaxPacketSize[0] = 8, - .bInterval = 255, - }, -}; - -static const struct usb2_hub_descriptor_min musbotg_hubd = { - .bDescLength = sizeof(musbotg_hubd), - .bDescriptorType = UDESC_HUB, - .bNbrPorts = 1, - .wHubCharacteristics[0] = - (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) & 0xFF, - .wHubCharacteristics[1] = - (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) >> 16, - .bPwrOn2PwrGood = 50, - .bHubContrCurrent = 0, - .DeviceRemovable = {0}, /* port is removable */ -}; - -#define STRING_LANG \ - 0x09, 0x04, /* American English */ - -#define STRING_VENDOR \ - 'M', 0, 'e', 0, 'n', 0, 't', 0, 'o', 0, 'r', 0, ' ', 0, \ - 'G', 0, 'r', 0, 'a', 0, 'p', 0, 'h', 0, 'i', 0, 'c', 0, 's', 0 - -#define STRING_PRODUCT \ - 'O', 0, 'T', 0, 'G', 0, ' ', 0, 'R', 0, \ - 'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \ - 'U', 0, 'B', 0, - -USB_MAKE_STRING_DESC(STRING_LANG, musbotg_langtab); -USB_MAKE_STRING_DESC(STRING_VENDOR, musbotg_vendor); -USB_MAKE_STRING_DESC(STRING_PRODUCT, musbotg_product); - -static void -musbotg_root_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_root_ctrl_start(struct usb2_xfer *xfer) -{ - struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus); - - sc->sc_root_ctrl.xfer = xfer; - - usb2_bus_roothub_exec(xfer->xroot->bus); -} - -static void -musbotg_root_ctrl_task(struct usb2_bus *bus) -{ - musbotg_root_ctrl_poll(MUSBOTG_BUS2SC(bus)); -} - -static void -musbotg_root_ctrl_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus); - uint16_t value; - uint16_t index; - uint8_t use_polling; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_SETUP) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - musbotg_device_done(xfer, std->err); - } - goto done; - } - /* buffer reset */ - std->ptr = USB_ADD_BYTES(&sc->sc_hub_temp, 0); - std->len = 0; - - value = UGETW(std->req.wValue); - index = UGETW(std->req.wIndex); - - use_polling = mtx_owned(xfer->xroot->xfer_mtx) ? 1 : 0; - - /* demultiplex the control request */ - - switch (std->req.bmRequestType) { - case UT_READ_DEVICE: - switch (std->req.bRequest) { - case UR_GET_DESCRIPTOR: - goto tr_handle_get_descriptor; - case UR_GET_CONFIG: - goto tr_handle_get_config; - case UR_GET_STATUS: - goto tr_handle_get_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_DEVICE: - switch (std->req.bRequest) { - case UR_SET_ADDRESS: - goto tr_handle_set_address; - case UR_SET_CONFIG: - goto tr_handle_set_config; - case UR_CLEAR_FEATURE: - goto tr_valid; /* nop */ - case UR_SET_DESCRIPTOR: - goto tr_valid; /* nop */ - case UR_SET_FEATURE: - default: - goto tr_stalled; - } - break; - - case UT_WRITE_ENDPOINT: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - switch (UGETW(std->req.wValue)) { - case UF_ENDPOINT_HALT: - goto tr_handle_clear_halt; - case UF_DEVICE_REMOTE_WAKEUP: - goto tr_handle_clear_wakeup; - default: - goto tr_stalled; - } - break; - case UR_SET_FEATURE: - switch (UGETW(std->req.wValue)) { - case UF_ENDPOINT_HALT: - goto tr_handle_set_halt; - case UF_DEVICE_REMOTE_WAKEUP: - goto tr_handle_set_wakeup; - default: - goto tr_stalled; - } - break; - case UR_SYNCH_FRAME: - goto tr_valid; /* nop */ - default: - goto tr_stalled; - } - break; - - case UT_READ_ENDPOINT: - switch (std->req.bRequest) { - case UR_GET_STATUS: - goto tr_handle_get_ep_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_INTERFACE: - switch (std->req.bRequest) { - case UR_SET_INTERFACE: - goto tr_handle_set_interface; - case UR_CLEAR_FEATURE: - goto tr_valid; /* nop */ - case UR_SET_FEATURE: - default: - goto tr_stalled; - } - break; - - case UT_READ_INTERFACE: - switch (std->req.bRequest) { - case UR_GET_INTERFACE: - goto tr_handle_get_interface; - case UR_GET_STATUS: - goto tr_handle_get_iface_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_CLASS_INTERFACE: - case UT_WRITE_VENDOR_INTERFACE: - /* XXX forward */ - break; - - case UT_READ_CLASS_INTERFACE: - case UT_READ_VENDOR_INTERFACE: - /* XXX forward */ - break; - - case UT_WRITE_CLASS_DEVICE: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - goto tr_valid; - case UR_SET_DESCRIPTOR: - case UR_SET_FEATURE: - break; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_CLASS_OTHER: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - goto tr_handle_clear_port_feature; - case UR_SET_FEATURE: - goto tr_handle_set_port_feature; - case UR_CLEAR_TT_BUFFER: - case UR_RESET_TT: - case UR_STOP_TT: - goto tr_valid; - - default: - goto tr_stalled; - } - break; - - case UT_READ_CLASS_OTHER: - switch (std->req.bRequest) { - case UR_GET_TT_STATE: - goto tr_handle_get_tt_state; - case UR_GET_STATUS: - goto tr_handle_get_port_status; - default: - goto tr_stalled; - } - break; - - case UT_READ_CLASS_DEVICE: - switch (std->req.bRequest) { - case UR_GET_DESCRIPTOR: - goto tr_handle_get_class_descriptor; - case UR_GET_STATUS: - goto tr_handle_get_class_status; - - default: - goto tr_stalled; - } - break; - default: - goto tr_stalled; - } - goto tr_valid; - -tr_handle_get_descriptor: - switch (value >> 8) { - case UDESC_DEVICE: - if (value & 0xff) { - goto tr_stalled; - } - std->len = sizeof(musbotg_devd); - std->ptr = USB_ADD_BYTES(&musbotg_devd, 0); - goto tr_valid; - case UDESC_CONFIG: - if (value & 0xff) { - goto tr_stalled; - } - std->len = sizeof(musbotg_confd); - std->ptr = USB_ADD_BYTES(&musbotg_confd, 0); - goto tr_valid; - case UDESC_STRING: - switch (value & 0xff) { - case 0: /* Language table */ - std->len = sizeof(musbotg_langtab); - std->ptr = USB_ADD_BYTES(&musbotg_langtab, 0); - goto tr_valid; - - case 1: /* Vendor */ - std->len = sizeof(musbotg_vendor); - std->ptr = USB_ADD_BYTES(&musbotg_vendor, 0); - goto tr_valid; - - case 2: /* Product */ - std->len = sizeof(musbotg_product); - std->ptr = USB_ADD_BYTES(&musbotg_product, 0); - goto tr_valid; - default: - break; - } - break; - default: - goto tr_stalled; - } - goto tr_stalled; - -tr_handle_get_config: - std->len = 1; - sc->sc_hub_temp.wValue[0] = sc->sc_conf; - goto tr_valid; - -tr_handle_get_status: - std->len = 2; - USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); - goto tr_valid; - -tr_handle_set_address: - if (value & 0xFF00) { - goto tr_stalled; - } - sc->sc_rt_addr = value; - goto tr_valid; - -tr_handle_set_config: - if (value >= 2) { - goto tr_stalled; - } - sc->sc_conf = value; - goto tr_valid; - -tr_handle_get_interface: - std->len = 1; - sc->sc_hub_temp.wValue[0] = 0; - goto tr_valid; - -tr_handle_get_tt_state: -tr_handle_get_class_status: -tr_handle_get_iface_status: -tr_handle_get_ep_status: - std->len = 2; - USETW(sc->sc_hub_temp.wValue, 0); - goto tr_valid; - -tr_handle_set_halt: -tr_handle_set_interface: -tr_handle_set_wakeup: -tr_handle_clear_wakeup: -tr_handle_clear_halt: - goto tr_valid; - -tr_handle_clear_port_feature: - if (index != 1) { - goto tr_stalled; - } - DPRINTFN(8, "UR_CLEAR_PORT_FEATURE on port %d\n", index); - - switch (value) { - case UHF_PORT_SUSPEND: - musbotg_wakeup_peer(xfer); - break; - - case UHF_PORT_ENABLE: - sc->sc_flags.port_enabled = 0; - break; - - case UHF_PORT_TEST: - case UHF_PORT_INDICATOR: - case UHF_C_PORT_ENABLE: - case UHF_C_PORT_OVER_CURRENT: - case UHF_C_PORT_RESET: - /* nops */ - break; - case UHF_PORT_POWER: - sc->sc_flags.port_powered = 0; - musbotg_pull_down(sc); - musbotg_clocks_off(sc); - break; - case UHF_C_PORT_CONNECTION: - sc->sc_flags.change_connect = 0; - break; - case UHF_C_PORT_SUSPEND: - sc->sc_flags.change_suspend = 0; - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - goto tr_valid; - -tr_handle_set_port_feature: - if (index != 1) { - goto tr_stalled; - } - DPRINTFN(8, "UR_SET_PORT_FEATURE\n"); - - switch (value) { - case UHF_PORT_ENABLE: - sc->sc_flags.port_enabled = 1; - break; - case UHF_PORT_SUSPEND: - case UHF_PORT_RESET: - case UHF_PORT_TEST: - case UHF_PORT_INDICATOR: - /* nops */ - break; - case UHF_PORT_POWER: - sc->sc_flags.port_powered = 1; - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - goto tr_valid; - -tr_handle_get_port_status: - - DPRINTFN(8, "UR_GET_PORT_STATUS\n"); - - if (index != 1) { - goto tr_stalled; - } - if (sc->sc_flags.status_vbus) { - musbotg_clocks_on(sc); - musbotg_pull_up(sc); - } else { - musbotg_pull_down(sc); - musbotg_clocks_off(sc); - } - - /* Select Device Side Mode */ - value = UPS_PORT_MODE_DEVICE; - - if (sc->sc_flags.status_high_speed) { - value |= UPS_HIGH_SPEED; - } - if (sc->sc_flags.port_powered) { - value |= UPS_PORT_POWER; - } - if (sc->sc_flags.port_enabled) { - value |= UPS_PORT_ENABLED; - } - if (sc->sc_flags.status_vbus && - sc->sc_flags.status_bus_reset) { - value |= UPS_CURRENT_CONNECT_STATUS; - } - if (sc->sc_flags.status_suspend) { - value |= UPS_SUSPEND; - } - USETW(sc->sc_hub_temp.ps.wPortStatus, value); - - value = 0; - - if (sc->sc_flags.change_connect) { - value |= UPS_C_CONNECT_STATUS; - - if (sc->sc_flags.status_vbus && - sc->sc_flags.status_bus_reset) { - /* reset EP0 state */ - sc->sc_ep0_busy = 0; - sc->sc_ep0_cmd = 0; - } - } - if (sc->sc_flags.change_suspend) { - value |= UPS_C_SUSPEND; - } - USETW(sc->sc_hub_temp.ps.wPortChange, value); - std->len = sizeof(sc->sc_hub_temp.ps); - goto tr_valid; - -tr_handle_get_class_descriptor: - if (value & 0xFF) { - goto tr_stalled; - } - std->ptr = USB_ADD_BYTES(&musbotg_hubd, 0); - std->len = sizeof(musbotg_hubd); - goto tr_valid; - -tr_stalled: - std->err = USB_ERR_STALLED; -tr_valid: -done: - return; -} - -static void -musbotg_root_ctrl_poll(struct musbotg_softc *sc) -{ - usb2_sw_transfer(&sc->sc_root_ctrl, - &musbotg_root_ctrl_done); -} - -struct usb2_pipe_methods musbotg_root_ctrl_methods = -{ - .open = musbotg_root_ctrl_open, - .close = musbotg_root_ctrl_close, - .enter = musbotg_root_ctrl_enter, - .start = musbotg_root_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 0, -}; - -/*------------------------------------------------------------------------* - * musbotg root interrupt support - *------------------------------------------------------------------------*/ -static void -musbotg_root_intr_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_root_intr_close(struct usb2_xfer *xfer) -{ - struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_intr.xfer == xfer) { - sc->sc_root_intr.xfer = NULL; - } - musbotg_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -musbotg_root_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_root_intr_start(struct usb2_xfer *xfer) -{ - struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus); - - sc->sc_root_intr.xfer = xfer; -} - -struct usb2_pipe_methods musbotg_root_intr_methods = -{ - .open = musbotg_root_intr_open, - .close = musbotg_root_intr_close, - .enter = musbotg_root_intr_enter, - .start = musbotg_root_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -static void -musbotg_xfer_setup(struct usb2_setup_params *parm) -{ - const struct usb2_hw_ep_profile *pf; - struct musbotg_softc *sc; - struct usb2_xfer *xfer; - void *last_obj; - uint32_t ntd; - uint32_t n; - uint8_t ep_no; - - sc = MUSBOTG_BUS2SC(parm->udev->bus); - xfer = parm->curr_xfer; - - /* - * NOTE: This driver does not use any of the parameters that - * are computed from the following values. Just set some - * reasonable dummies: - */ - parm->hc_max_packet_size = 0x400; - parm->hc_max_frame_size = 0x400; - - if ((parm->methods == &musbotg_device_isoc_methods) || - (parm->methods == &musbotg_device_intr_methods)) - parm->hc_max_packet_count = 3; - else - parm->hc_max_packet_count = 1; - - usb2_transfer_setup_sub(parm); - - /* - * compute maximum number of TDs - */ - if (parm->methods == &musbotg_device_ctrl_methods) { - - ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC */ ; - - } else if (parm->methods == &musbotg_device_bulk_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else if (parm->methods == &musbotg_device_intr_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else if (parm->methods == &musbotg_device_isoc_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else { - - ntd = 0; - } - - /* - * check if "usb2_transfer_setup_sub" set an error - */ - if (parm->err) { - return; - } - /* - * allocate transfer descriptors - */ - last_obj = NULL; - - /* - * get profile stuff - */ - if (ntd) { - - ep_no = xfer->endpoint & UE_ADDR; - musbotg_get_hw_ep_profile(parm->udev, &pf, ep_no); - - if (pf == NULL) { - /* should not happen */ - parm->err = USB_ERR_INVAL; - return; - } - } else { - ep_no = 0; - pf = NULL; - } - - /* align data */ - parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); - - for (n = 0; n != ntd; n++) { - - struct musbotg_td *td; - - if (parm->buf) { - - td = USB_ADD_BYTES(parm->buf, parm->size[0]); - - /* init TD */ - td->max_frame_size = xfer->max_frame_size; - td->ep_no = ep_no; - td->obj_next = last_obj; - - last_obj = td; - } - parm->size[0] += sizeof(*td); - } - - xfer->td_start[0] = last_obj; -} - -static void -musbotg_xfer_unsetup(struct usb2_xfer *xfer) -{ - return; -} - -static void -musbotg_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, - struct usb2_pipe *pipe) -{ - struct musbotg_softc *sc = MUSBOTG_BUS2SC(udev->bus); - - DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", - pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, - sc->sc_rt_addr); - - if (udev->device_index == sc->sc_rt_addr) { - - if (udev->flags.usb2_mode != USB_MODE_HOST) { - /* not supported */ - return; - } - switch (edesc->bEndpointAddress) { - case USB_CONTROL_ENDPOINT: - pipe->methods = &musbotg_root_ctrl_methods; - break; - case UE_DIR_IN | MUSBOTG_INTR_ENDPT: - pipe->methods = &musbotg_root_intr_methods; - break; - default: - /* do nothing */ - break; - } - } else { - - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { - /* not supported */ - return; - } - if ((udev->speed != USB_SPEED_FULL) && - (udev->speed != USB_SPEED_HIGH)) { - /* not supported */ - return; - } - switch (edesc->bmAttributes & UE_XFERTYPE) { - case UE_CONTROL: - pipe->methods = &musbotg_device_ctrl_methods; - break; - case UE_INTERRUPT: - pipe->methods = &musbotg_device_intr_methods; - break; - case UE_ISOCHRONOUS: - pipe->methods = &musbotg_device_isoc_methods; - break; - case UE_BULK: - pipe->methods = &musbotg_device_bulk_methods; - break; - default: - /* do nothing */ - break; - } - } -} - -struct usb2_bus_methods musbotg_bus_methods = -{ - .pipe_init = &musbotg_pipe_init, - .xfer_setup = &musbotg_xfer_setup, - .xfer_unsetup = &musbotg_xfer_unsetup, - .do_poll = &musbotg_do_poll, - .get_hw_ep_profile = &musbotg_get_hw_ep_profile, - .set_stall = &musbotg_set_stall, - .clear_stall = &musbotg_clear_stall, - .roothub_exec = &musbotg_root_ctrl_task, -}; diff --git a/sys/dev/usb2/controller/musb2_otg.h b/sys/dev/usb2/controller/musb2_otg.h deleted file mode 100644 index 0d880e1..0000000 --- a/sys/dev/usb2/controller/musb2_otg.h +++ /dev/null @@ -1,407 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * This header file defines the registers of the Mentor Graphics - * USB OnTheGo Inventra chip. - */ - -#ifndef _MUSB2_OTG_H_ -#define _MUSB2_OTG_H_ - -#define MUSB2_MAX_DEVICES (USB_MIN_DEVICES + 1) - -/* Common registers */ - -#define MUSB2_REG_FADDR 0x0000 /* function address register */ -#define MUSB2_MASK_FADDR 0x7F - -#define MUSB2_REG_POWER 0x0001 /* power register */ -#define MUSB2_MASK_SUSPM_ENA 0x01 -#define MUSB2_MASK_SUSPMODE 0x02 -#define MUSB2_MASK_RESUME 0x04 -#define MUSB2_MASK_RESET 0x08 -#define MUSB2_MASK_HSMODE 0x10 -#define MUSB2_MASK_HSENAB 0x20 -#define MUSB2_MASK_SOFTC 0x40 -#define MUSB2_MASK_ISOUPD 0x80 - -/* Endpoint interrupt handling */ - -#define MUSB2_REG_INTTX 0x0002 /* transmit interrupt register */ -#define MUSB2_REG_INTRX 0x0004 /* receive interrupt register */ -#define MUSB2_REG_INTTXE 0x0006 /* transmit interrupt enable register */ -#define MUSB2_REG_INTRXE 0x0008 /* receive interrupt enable register */ -#define MUSB2_MASK_EPINT(epn) (1 << (epn)) /* epn = [0..15] */ - -/* Common interrupt handling */ - -#define MUSB2_REG_INTUSB 0x000A /* USB interrupt register */ -#define MUSB2_MASK_ISUSP 0x01 -#define MUSB2_MASK_IRESUME 0x02 -#define MUSB2_MASK_IRESET 0x04 -#define MUSB2_MASK_IBABBLE 0x04 -#define MUSB2_MASK_ISOF 0x08 -#define MUSB2_MASK_ICONN 0x10 -#define MUSB2_MASK_IDISC 0x20 -#define MUSB2_MASK_ISESSRQ 0x40 -#define MUSB2_MASK_IVBUSERR 0x80 - -#define MUSB2_REG_INTUSBE 0x000B /* USB interrupt enable register */ -#define MUSB2_REG_FRAME 0x000C /* USB frame register */ -#define MUSB2_MASK_FRAME 0x3FF /* 0..1023 */ - -#define MUSB2_REG_EPINDEX 0x000E /* endpoint index register */ -#define MUSB2_MASK_EPINDEX 0x0F - -#define MUSB2_REG_TESTMODE 0x000F /* test mode register */ -#define MUSB2_MASK_TSE0_NAK 0x01 -#define MUSB2_MASK_TJ 0x02 -#define MUSB2_MASK_TK 0x04 -#define MUSB2_MASK_TPACKET 0x08 -#define MUSB2_MASK_TFORCE_HS 0x10 -#define MUSB2_MASK_TFORCE_LS 0x20 -#define MUSB2_MASK_TFIFO_ACC 0x40 -#define MUSB2_MASK_TFORCE_HC 0x80 - -#define MUSB2_REG_INDEXED_CSR 0x0010 /* EP control status register offset */ - -#define MUSB2_REG_TXMAXP (0x0000 + MUSB2_REG_INDEXED_CSR) -#define MUSB2_REG_RXMAXP (0x0004 + MUSB2_REG_INDEXED_CSR) -#define MUSB2_MASK_PKTSIZE 0x03FF /* in bytes, should be even */ -#define MUSB2_MASK_PKTMULT 0xFC00 /* HS packet multiplier: 0..2 */ - -#define MUSB2_REG_TXCSRL (0x0002 + MUSB2_REG_INDEXED_CSR) -#define MUSB2_MASK_CSRL_TXPKTRDY 0x01 -#define MUSB2_MASK_CSRL_TXFIFONEMPTY 0x02 -#define MUSB2_MASK_CSRL_TXUNDERRUN 0x04 /* Device Mode */ -#define MUSB2_MASK_CSRL_TXERROR 0x04 /* Host Mode */ -#define MUSB2_MASK_CSRL_TXFFLUSH 0x08 -#define MUSB2_MASK_CSRL_TXSENDSTALL 0x10/* Device Mode */ -#define MUSB2_MASK_CSRL_TXSETUPPKT 0x10 /* Host Mode */ -#define MUSB2_MASK_CSRL_TXSENTSTALL 0x20/* Device Mode */ -#define MUSB2_MASK_CSRL_TXSTALLED 0x20 /* Host Mode */ -#define MUSB2_MASK_CSRL_TXDT_CLR 0x40 -#define MUSB2_MASK_CSRL_TXINCOMP 0x80 - -/* Device Side Mode */ -#define MUSB2_MASK_CSR0L_RXPKTRDY 0x01 -#define MUSB2_MASK_CSR0L_TXPKTRDY 0x02 -#define MUSB2_MASK_CSR0L_SENTSTALL 0x04 -#define MUSB2_MASK_CSR0L_DATAEND 0x08 -#define MUSB2_MASK_CSR0L_SETUPEND 0x10 -#define MUSB2_MASK_CSR0L_SENDSTALL 0x20 -#define MUSB2_MASK_CSR0L_RXPKTRDY_CLR 0x40 -#define MUSB2_MASK_CSR0L_SETUPEND_CLR 0x80 - -/* Host Side Mode */ -#define MUSB2_MASK_CSR0L_RXSTALL 0x04 -#define MUSB2_MASK_CSR0L_SETUPPKT 0x08 -#define MUSB2_MASK_CSR0L_ERROR 0x10 -#define MUSB2_MASK_CSR0L_REQPKT 0x20 -#define MUSB2_MASK_CSR0L_STATUSPKT 0x40 -#define MUSB2_MASK_CSR0L_NAKTIMO 0x80 - -#define MUSB2_REG_TXCSRH (0x0003 + MUSB2_REG_INDEXED_CSR) -#define MUSB2_MASK_CSRH_TXDT_VAL 0x01 /* Host Mode */ -#define MUSB2_MASK_CSRH_TXDT_WR 0x02 /* Host Mode */ -#define MUSB2_MASK_CSRH_TXDMAREQMODE 0x04 -#define MUSB2_MASK_CSRH_TXDT_SWITCH 0x08 -#define MUSB2_MASK_CSRH_TXDMAREQENA 0x10 -#define MUSB2_MASK_CSRH_RXMODE 0x00 -#define MUSB2_MASK_CSRH_TXMODE 0x20 -#define MUSB2_MASK_CSRH_TXISO 0x40 /* Device Mode */ -#define MUSB2_MASK_CSRH_TXAUTOSET 0x80 - -#define MUSB2_MASK_CSR0H_FFLUSH 0x01 /* Device Side flush FIFO */ -#define MUSB2_MASK_CSR0H_DT 0x02 /* Host Side data toggle */ -#define MUSB2_MASK_CSR0H_DT_SET 0x04 /* Host Side */ -#define MUSB2_MASK_CSR0H_PING_DIS 0x08 /* Host Side */ - -#define MUSB2_REG_RXCSRL (0x0006 + MUSB2_REG_INDEXED_CSR) -#define MUSB2_MASK_CSRL_RXPKTRDY 0x01 -#define MUSB2_MASK_CSRL_RXFIFOFULL 0x02 -#define MUSB2_MASK_CSRL_RXOVERRUN 0x04 -#define MUSB2_MASK_CSRL_RXDATAERR 0x08 -#define MUSB2_MASK_CSRL_RXFFLUSH 0x10 -#define MUSB2_MASK_CSRL_RXSENDSTALL 0x20/* Device Mode */ -#define MUSB2_MASK_CSRL_RXREQPKT 0x20 /* Host Mode */ -#define MUSB2_MASK_CSRL_RXSENTSTALL 0x40/* Device Mode */ -#define MUSB2_MASK_CSRL_RXSTALL 0x40 /* Host Mode */ -#define MUSB2_MASK_CSRL_RXDT_CLR 0x80 - -#define MUSB2_REG_RXCSRH (0x0007 + MUSB2_REG_INDEXED_CSR) -#define MUSB2_MASK_CSRH_RXINCOMP 0x01 -#define MUSB2_MASK_CSRH_RXDT_VAL 0x02 /* Host Mode */ -#define MUSB2_MASK_CSRH_RXDT_SET 0x04 /* Host Mode */ -#define MUSB2_MASK_CSRH_RXDMAREQMODE 0x08 -#define MUSB2_MASK_CSRH_RXNYET 0x10 -#define MUSB2_MASK_CSRH_RXDMAREQENA 0x20 -#define MUSB2_MASK_CSRH_RXISO 0x40 /* Device Mode */ -#define MUSB2_MASK_CSRH_RXAUTOREQ 0x40 /* Host Mode */ -#define MUSB2_MASK_CSRH_RXAUTOCLEAR 0x80 - -#define MUSB2_REG_RXCOUNT (0x0008 + MUSB2_REG_INDEXED_CSR) -#define MUSB2_MASK_RXCOUNT 0xFFFF - -#define MUSB2_REG_TXTI (0x000A + MUSB2_REG_INDEXED_CSR) -#define MUSB2_REG_RXTI (0x000C + MUSB2_REG_INDEXED_CSR) - -/* Host Mode */ -#define MUSB2_MASK_TI_SPEED 0xC0 -#define MUSB2_MASK_TI_SPEED_LO 0xC0 -#define MUSB2_MASK_TI_SPEED_FS 0x80 -#define MUSB2_MASK_TI_SPEED_HS 0x40 -#define MUSB2_MASK_TI_PROTO_CTRL 0x00 -#define MUSB2_MASK_TI_PROTO_ISOC 0x10 -#define MUSB2_MASK_TI_PROTO_BULK 0x20 -#define MUSB2_MASK_TI_PROTO_INTR 0x30 -#define MUSB2_MASK_TI_EP_NUM 0x0F - -#define MUSB2_REG_TXNAKLIMIT (0x000B /* EPN=0 */ + MUSB2_REG_INDEXED_CSR) -#define MUSB2_REG_RXNAKLIMIT (0x000D /* EPN=0 */ + MUSB2_REG_INDEXED_CSR) -#define MUSB2_MASK_NAKLIMIT 0xFF - -#define MUSB2_REG_FSIZE (0x000F + MUSB2_REG_INDEXED_CSR) -#define MUSB2_MASK_RX_FSIZE 0xF0 /* 3..13, 2**n bytes */ -#define MUSB2_MASK_TX_FSIZE 0x0F /* 3..13, 2**n bytes */ - -#define MUSB2_REG_EPFIFO(n) (0x0020 + (4*(n))) - -#define MUSB2_REG_CONFDATA 0x000F /* EPN=0 */ -#define MUSB2_MASK_CD_UTMI_DW 0x01 -#define MUSB2_MASK_CD_SOFTCONE 0x02 -#define MUSB2_MASK_CD_DYNFIFOSZ 0x04 -#define MUSB2_MASK_CD_HBTXE 0x08 -#define MUSB2_MASK_CD_HBRXE 0x10 -#define MUSB2_MASK_CD_BIGEND 0x20 -#define MUSB2_MASK_CD_MPTXE 0x40 -#define MUSB2_MASK_CD_MPRXE 0x80 - -/* Various registers */ - -#define MUSB2_REG_DEVCTL 0x0060 -#define MUSB2_MASK_SESS 0x01 -#define MUSB2_MASK_HOSTREQ 0x02 -#define MUSB2_MASK_HOSTMD 0x04 -#define MUSB2_MASK_VBUS0 0x08 -#define MUSB2_MASK_VBUS1 0x10 -#define MUSB2_MASK_LSDEV 0x20 -#define MUSB2_MASK_FSDEV 0x40 -#define MUSB2_MASK_BDEV 0x80 - -#define MUSB2_REG_MISC 0x0061 -#define MUSB2_MASK_RXEDMA 0x01 -#define MUSB2_MASK_TXEDMA 0x02 - -#define MUSB2_REG_TXFIFOSZ 0x0062 -#define MUSB2_REG_RXFIFOSZ 0x0063 -#define MUSB2_MASK_FIFODB 0x10 /* set if double buffering, r/w */ -#define MUSB2_MASK_FIFOSZ 0x0F -#define MUSB2_VAL_FIFOSZ_8 0 -#define MUSB2_VAL_FIFOSZ_16 1 -#define MUSB2_VAL_FIFOSZ_32 2 -#define MUSB2_VAL_FIFOSZ_64 3 -#define MUSB2_VAL_FIFOSZ_128 4 -#define MUSB2_VAL_FIFOSZ_256 5 -#define MUSB2_VAL_FIFOSZ_512 6 -#define MUSB2_VAL_FIFOSZ_1024 7 -#define MUSB2_VAL_FIFOSZ_2048 8 -#define MUSB2_VAL_FIFOSZ_4096 9 - -#define MUSB2_REG_TXFIFOADD 0x0064 -#define MUSB2_REG_RXFIFOADD 0x0066 -#define MUSB2_MASK_FIFOADD 0xFFF /* unit is 8-bytes */ - -#define MUSB2_REG_VSTATUS 0x0068 -#define MUSB2_REG_VCONTROL 0x0068 -#define MUSB2_REG_HWVERS 0x006C -#define MUSB2_REG_ULPI_BASE 0x0070 - -#define MUSB2_REG_EPINFO 0x0078 -#define MUSB2_MASK_NRXEP 0xF0 -#define MUSB2_MASK_NTXEP 0x0F - -#define MUSB2_REG_RAMINFO 0x0079 -#define MUSB2_REG_LINKINFO 0x007A - -#define MUSB2_REG_VPLEN 0x007B -#define MUSB2_MASK_VPLEN 0xFF - -#define MUSB2_REG_HS_EOF1 0x007C -#define MUSB2_REG_FS_EOF1 0x007D -#define MUSB2_REG_LS_EOF1 0x007E -#define MUSB2_REG_SOFT_RST 0x007F -#define MUSB2_MASK_SRST 0x01 -#define MUSB2_MASK_SRSTX 0x02 - -#define MUSB2_REG_RQPKTCOUNT(n) (0x0300 + (4*(n)) -#define MUSB2_REG_RXDBDIS 0x0340 -#define MUSB2_REG_TXDBDIS 0x0342 -#define MUSB2_MASK_DB(n) (1 << (n)) /* disable double buffer, n = [0..15] */ - -#define MUSB2_REG_CHIRPTO 0x0344 -#define MUSB2_REG_HSRESUM 0x0346 - -/* Host Mode only registers */ - -#define MUSB2_REG_TXFADDR(n) (0x0080 + (8*(n))) -#define MUSB2_REG_TXHADDR(n) (0x0082 + (8*(n))) -#define MUSB2_REG_TXHUBPORT(n) (0x0083 + (8*(n))) -#define MUSB2_REG_RXFADDR(n) (0x0084 + (8*(n))) -#define MUSB2_REG_RXHADDR(n) (0x0086 + (8*(n))) -#define MUSB2_REG_RXHPORT(n) (0x0087 + (8*(n))) - -#define MUSB2_EP_MAX 16 /* maximum number of endpoints */ - -#define MUSB2_READ_2(sc, reg) \ - bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, reg) - -#define MUSB2_WRITE_2(sc, reg, data) \ - bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data) - -#define MUSB2_READ_1(sc, reg) \ - bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg) - -#define MUSB2_WRITE_1(sc, reg, data) \ - bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data) - -struct musbotg_td; -struct musbotg_softc; - -typedef uint8_t (musbotg_cmd_t)(struct musbotg_td *td); - -struct musbotg_dma { - struct musbotg_softc *sc; - uint32_t dma_chan; - uint8_t busy:1; - uint8_t complete:1; - uint8_t error:1; -}; - -struct musbotg_td { - struct musbotg_td *obj_next; - musbotg_cmd_t *func; - struct usb2_page_cache *pc; - uint32_t offset; - uint32_t remainder; - uint16_t max_frame_size; /* packet_size * mult */ - uint8_t ep_no; - uint8_t error:1; - uint8_t alt_next:1; - uint8_t short_pkt:1; - uint8_t support_multi_buffer:1; - uint8_t did_stall:1; - uint8_t dma_enabled:1; -}; - -struct musbotg_std_temp { - musbotg_cmd_t *func; - struct usb2_page_cache *pc; - struct musbotg_td *td; - struct musbotg_td *td_next; - uint32_t len; - uint32_t offset; - uint16_t max_frame_size; - uint8_t short_pkt; - /* - * short_pkt = 0: transfer should be short terminated - * short_pkt = 1: transfer should not be short terminated - */ - uint8_t setup_alt_next; -}; - -struct musbotg_config_desc { - struct usb2_config_descriptor confd; - struct usb2_interface_descriptor ifcd; - struct usb2_endpoint_descriptor endpd; -} __packed; - -union musbotg_hub_temp { - uWord wValue; - struct usb2_port_status ps; -}; - -struct musbotg_flags { - uint8_t change_connect:1; - uint8_t change_suspend:1; - uint8_t status_suspend:1; /* set if suspended */ - uint8_t status_vbus:1; /* set if present */ - uint8_t status_bus_reset:1; /* set if reset complete */ - uint8_t status_high_speed:1; /* set if High Speed is selected */ - uint8_t remote_wakeup:1; - uint8_t self_powered:1; - uint8_t clocks_off:1; - uint8_t port_powered:1; - uint8_t port_enabled:1; - uint8_t d_pulled_up:1; -}; - -struct musbotg_softc { - struct usb2_bus sc_bus; - union musbotg_hub_temp sc_hub_temp; - struct usb2_sw_transfer sc_root_ctrl; - struct usb2_sw_transfer sc_root_intr; - struct usb2_hw_ep_profile sc_hw_ep_profile[16]; - - struct usb2_device *sc_devices[MUSB2_MAX_DEVICES]; - struct resource *sc_io_res; - struct resource *sc_irq_res; - void *sc_intr_hdl; - bus_size_t sc_io_size; - bus_space_tag_t sc_io_tag; - bus_space_handle_t sc_io_hdl; - - void (*sc_clocks_on) (void *arg); - void (*sc_clocks_off) (void *arg); - void *sc_clocks_arg; - - uint32_t sc_bounce_buf[(1024 * 3) / 4]; /* bounce buffer */ - - uint8_t sc_ep_max; /* maximum number of RX and TX - * endpoints supported */ - uint8_t sc_rt_addr; /* root HUB address */ - uint8_t sc_dv_addr; /* device address */ - uint8_t sc_conf; /* root HUB config */ - uint8_t sc_ep0_busy; /* set if ep0 is busy */ - uint8_t sc_ep0_cmd; /* pending commands */ - uint8_t sc_conf_data; /* copy of hardware register */ - - uint8_t sc_hub_idata[1]; - - struct musbotg_flags sc_flags; -}; - -/* prototypes */ - -usb2_error_t musbotg_init(struct musbotg_softc *sc); -void musbotg_uninit(struct musbotg_softc *sc); -void musbotg_suspend(struct musbotg_softc *sc); -void musbotg_resume(struct musbotg_softc *sc); -void musbotg_interrupt(struct musbotg_softc *sc); -void musbotg_vbus_interrupt(struct musbotg_softc *sc, uint8_t is_on); - -#endif /* _MUSB2_OTG_H_ */ diff --git a/sys/dev/usb2/controller/musb2_otg_atmelarm.c b/sys/dev/usb2/controller/musb2_otg_atmelarm.c deleted file mode 100644 index 6477c97..0000000 --- a/sys/dev/usb2/controller/musb2_otg_atmelarm.c +++ /dev/null @@ -1,240 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_defs.h> -#include <dev/usb2/include/usb2_standard.h> - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/musb2_otg.h> - -#include <sys/rman.h> - -static device_probe_t musbotg_probe; -static device_attach_t musbotg_attach; -static device_detach_t musbotg_detach; -static device_shutdown_t musbotg_shutdown; - -struct musbotg_super_softc { - struct musbotg_softc sc_otg; /* must be first */ -}; - -static void -musbotg_vbus_poll(struct musbotg_super_softc *sc) -{ - uint8_t vbus_val = 1; /* fake VBUS on - TODO */ - - /* just forward it */ - musbotg_vbus_interrupt(&sc->sc_otg, vbus_val); -} - -static void -musbotg_clocks_on(void *arg) -{ -#if 0 - struct musbotg_super_softc *sc = arg; - -#endif -} - -static void -musbotg_clocks_off(void *arg) -{ -#if 0 - struct musbotg_super_softc *sc = arg; - -#endif -} - -static int -musbotg_probe(device_t dev) -{ - device_set_desc(dev, "MUSB OTG integrated USB controller"); - return (0); -} - -static int -musbotg_attach(device_t dev) -{ - struct musbotg_super_softc *sc = device_get_softc(dev); - int err; - int rid; - - /* setup MUSB OTG USB controller interface softc */ - sc->sc_otg.sc_clocks_on = &musbotg_clocks_on; - sc->sc_otg.sc_clocks_off = &musbotg_clocks_off; - sc->sc_otg.sc_clocks_arg = sc; - - /* initialise some bus fields */ - sc->sc_otg.sc_bus.parent = dev; - sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices; - sc->sc_otg.sc_bus.devices_max = MUSB2_MAX_DEVICES; - - /* get all DMA memory */ - if (usb2_bus_mem_alloc_all(&sc->sc_otg.sc_bus, - USB_GET_DMA_TAG(dev), NULL)) { - return (ENOMEM); - } - rid = 0; - sc->sc_otg.sc_io_res = - bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); - - if (!(sc->sc_otg.sc_io_res)) { - err = ENOMEM; - goto error; - } - sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res); - sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res); - sc->sc_otg.sc_io_size = rman_get_size(sc->sc_otg.sc_io_res); - - rid = 0; - sc->sc_otg.sc_irq_res = - bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); - if (!(sc->sc_otg.sc_irq_res)) { - goto error; - } - sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1); - if (!(sc->sc_otg.sc_bus.bdev)) { - goto error; - } - device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus); - -#if (__FreeBSD_version >= 700031) - err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); -#else - err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); -#endif - if (err) { - sc->sc_otg.sc_intr_hdl = NULL; - goto error; - } - err = musbotg_init(&sc->sc_otg); - if (!err) { - err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev); - } - if (err) { - goto error; - } else { - /* poll VBUS one time */ - musbotg_vbus_poll(sc); - } - return (0); - -error: - musbotg_detach(dev); - return (ENXIO); -} - -static int -musbotg_detach(device_t dev) -{ - struct musbotg_super_softc *sc = device_get_softc(dev); - device_t bdev; - int err; - - if (sc->sc_otg.sc_bus.bdev) { - bdev = sc->sc_otg.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } - /* during module unload there are lots of children leftover */ - device_delete_all_children(dev); - - if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) { - /* - * only call musbotg_uninit() after musbotg_init() - */ - musbotg_uninit(&sc->sc_otg); - - err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res, - sc->sc_otg.sc_intr_hdl); - sc->sc_otg.sc_intr_hdl = NULL; - } - /* free IRQ channel, if any */ - if (sc->sc_otg.sc_irq_res) { - bus_release_resource(dev, SYS_RES_IRQ, 0, - sc->sc_otg.sc_irq_res); - sc->sc_otg.sc_irq_res = NULL; - } - /* free memory resource, if any */ - if (sc->sc_otg.sc_io_res) { - bus_release_resource(dev, SYS_RES_MEMORY, 0, - sc->sc_otg.sc_io_res); - sc->sc_otg.sc_io_res = NULL; - } - usb2_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL); - - return (0); -} - -static int -musbotg_shutdown(device_t dev) -{ - struct musbotg_super_softc *sc = device_get_softc(dev); - int err; - - err = bus_generic_shutdown(dev); - if (err) - return (err); - - musbotg_uninit(&sc->sc_otg); - - return (0); -} - -static device_method_t musbotg_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, musbotg_probe), - DEVMETHOD(device_attach, musbotg_attach), - DEVMETHOD(device_detach, musbotg_detach), - DEVMETHOD(device_shutdown, musbotg_shutdown), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - {0, 0} -}; - -static driver_t musbotg_driver = { - "musbotg", - musbotg_methods, - sizeof(struct musbotg_super_softc), -}; - -static devclass_t musbotg_devclass; - -DRIVER_MODULE(musbotg, atmelarm, musbotg_driver, musbotg_devclass, 0, 0); -MODULE_DEPEND(musbotg, usb2_controller, 1, 1, 1); -MODULE_DEPEND(musbotg, usb2_core, 1, 1, 1); diff --git a/sys/dev/usb2/controller/ohci2.c b/sys/dev/usb2/controller/ohci2.c deleted file mode 100644 index 4c65ea7..0000000 --- a/sys/dev/usb2/controller/ohci2.c +++ /dev/null @@ -1,2862 +0,0 @@ -/*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. - * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. - * Copyright (c) 1998 Lennart Augustsson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* - * USB Open Host Controller driver. - * - * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html - * USB spec: http://www.usb.org/developers/docs/usbspec.zip - */ - -#include <dev/usb2/include/usb2_standard.h> -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_error.h> -#include <dev/usb2/include/usb2_defs.h> - -#define USB_DEBUG_VAR ohcidebug - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_debug.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_transfer.h> -#include <dev/usb2/core/usb2_device.h> -#include <dev/usb2/core/usb2_hub.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/ohci2.h> - -#define OHCI_BUS2SC(bus) ((ohci_softc_t *)(((uint8_t *)(bus)) - \ - USB_P2U(&(((ohci_softc_t *)0)->sc_bus)))) - -#if USB_DEBUG -static int ohcidebug = 0; - -SYSCTL_NODE(_hw_usb2, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci"); -SYSCTL_INT(_hw_usb2_ohci, OID_AUTO, debug, CTLFLAG_RW, - &ohcidebug, 0, "ohci debug level"); -static void ohci_dumpregs(ohci_softc_t *); -static void ohci_dump_tds(ohci_td_t *); -static uint8_t ohci_dump_td(ohci_td_t *); -static void ohci_dump_ed(ohci_ed_t *); -static uint8_t ohci_dump_itd(ohci_itd_t *); -static void ohci_dump_itds(ohci_itd_t *); - -#endif - -#define OBARR(sc) bus_space_barrier((sc)->sc_io_tag, (sc)->sc_io_hdl, 0, (sc)->sc_io_size, \ - BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) -#define OWRITE1(sc, r, x) \ - do { OBARR(sc); bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) -#define OWRITE2(sc, r, x) \ - do { OBARR(sc); bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) -#define OWRITE4(sc, r, x) \ - do { OBARR(sc); bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) -#define OREAD1(sc, r) (OBARR(sc), bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) -#define OREAD2(sc, r) (OBARR(sc), bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) -#define OREAD4(sc, r) (OBARR(sc), bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) - -#define OHCI_INTR_ENDPT 1 - -extern struct usb2_bus_methods ohci_bus_methods; -extern struct usb2_pipe_methods ohci_device_bulk_methods; -extern struct usb2_pipe_methods ohci_device_ctrl_methods; -extern struct usb2_pipe_methods ohci_device_intr_methods; -extern struct usb2_pipe_methods ohci_device_isoc_methods; -extern struct usb2_pipe_methods ohci_root_ctrl_methods; -extern struct usb2_pipe_methods ohci_root_intr_methods; - -static void ohci_root_ctrl_poll(struct ohci_softc *sc); -static void ohci_do_poll(struct usb2_bus *bus); -static void ohci_device_done(struct usb2_xfer *xfer, usb2_error_t error); - -static usb2_sw_transfer_func_t ohci_root_intr_done; -static usb2_sw_transfer_func_t ohci_root_ctrl_done; -static void ohci_timeout(void *arg); -static uint8_t ohci_check_transfer(struct usb2_xfer *xfer); - -struct ohci_std_temp { - struct usb2_page_cache *pc; - ohci_td_t *td; - ohci_td_t *td_next; - uint32_t average; - uint32_t td_flags; - uint32_t len; - uint16_t max_frame_size; - uint8_t shortpkt; - uint8_t setup_alt_next; - uint8_t short_frames_ok; -}; - -static struct ohci_hcca * -ohci_get_hcca(ohci_softc_t *sc) -{ - usb2_pc_cpu_invalidate(&sc->sc_hw.hcca_pc); - return (sc->sc_hcca_p); -} - -void -ohci_iterate_hw_softc(struct usb2_bus *bus, usb2_bus_mem_sub_cb_t *cb) -{ - struct ohci_softc *sc = OHCI_BUS2SC(bus); - uint32_t i; - - cb(bus, &sc->sc_hw.hcca_pc, &sc->sc_hw.hcca_pg, - sizeof(ohci_hcca_t), OHCI_HCCA_ALIGN); - - cb(bus, &sc->sc_hw.ctrl_start_pc, &sc->sc_hw.ctrl_start_pg, - sizeof(ohci_ed_t), OHCI_ED_ALIGN); - - cb(bus, &sc->sc_hw.bulk_start_pc, &sc->sc_hw.bulk_start_pg, - sizeof(ohci_ed_t), OHCI_ED_ALIGN); - - cb(bus, &sc->sc_hw.isoc_start_pc, &sc->sc_hw.isoc_start_pg, - sizeof(ohci_ed_t), OHCI_ED_ALIGN); - - for (i = 0; i != OHCI_NO_EDS; i++) { - cb(bus, sc->sc_hw.intr_start_pc + i, sc->sc_hw.intr_start_pg + i, - sizeof(ohci_ed_t), OHCI_ED_ALIGN); - } -} - -static usb2_error_t -ohci_controller_init(ohci_softc_t *sc) -{ - struct usb2_page_search buf_res; - uint32_t i; - uint32_t ctl; - uint32_t ival; - uint32_t hcr; - uint32_t fm; - uint32_t per; - uint32_t desca; - - /* Determine in what context we are running. */ - ctl = OREAD4(sc, OHCI_CONTROL); - if (ctl & OHCI_IR) { - /* SMM active, request change */ - DPRINTF("SMM active, request owner change\n"); - OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_OCR); - for (i = 0; (i < 100) && (ctl & OHCI_IR); i++) { - usb2_pause_mtx(NULL, hz / 1000); - ctl = OREAD4(sc, OHCI_CONTROL); - } - if (ctl & OHCI_IR) { - device_printf(sc->sc_bus.bdev, - "SMM does not respond, resetting\n"); - OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); - goto reset; - } - } else { - DPRINTF("cold started\n"); -reset: - /* controller was cold started */ - usb2_pause_mtx(NULL, - USB_MS_TO_TICKS(USB_BUS_RESET_DELAY)); - } - - /* - * This reset should not be necessary according to the OHCI spec, but - * without it some controllers do not start. - */ - DPRINTF("%s: resetting\n", device_get_nameunit(sc->sc_bus.bdev)); - OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); - - usb2_pause_mtx(NULL, - USB_MS_TO_TICKS(USB_BUS_RESET_DELAY)); - - /* we now own the host controller and the bus has been reset */ - ival = OHCI_GET_IVAL(OREAD4(sc, OHCI_FM_INTERVAL)); - - OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ - /* nominal time for a reset is 10 us */ - for (i = 0; i < 10; i++) { - DELAY(10); - hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; - if (!hcr) { - break; - } - } - if (hcr) { - device_printf(sc->sc_bus.bdev, "reset timeout\n"); - return (USB_ERR_IOERROR); - } -#if USB_DEBUG - if (ohcidebug > 15) { - ohci_dumpregs(sc); - } -#endif - - /* The controller is now in SUSPEND state, we have 2ms to finish. */ - - /* set up HC registers */ - usb2_get_page(&sc->sc_hw.hcca_pc, 0, &buf_res); - OWRITE4(sc, OHCI_HCCA, buf_res.physaddr); - - usb2_get_page(&sc->sc_hw.ctrl_start_pc, 0, &buf_res); - OWRITE4(sc, OHCI_CONTROL_HEAD_ED, buf_res.physaddr); - - usb2_get_page(&sc->sc_hw.bulk_start_pc, 0, &buf_res); - OWRITE4(sc, OHCI_BULK_HEAD_ED, buf_res.physaddr); - - /* disable all interrupts and then switch on all desired interrupts */ - OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); - OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); - /* switch on desired functional features */ - ctl = OREAD4(sc, OHCI_CONTROL); - ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); - ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | - OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL; - /* And finally start it! */ - OWRITE4(sc, OHCI_CONTROL, ctl); - - /* - * The controller is now OPERATIONAL. Set a some final - * registers that should be set earlier, but that the - * controller ignores when in the SUSPEND state. - */ - fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; - fm |= OHCI_FSMPS(ival) | ival; - OWRITE4(sc, OHCI_FM_INTERVAL, fm); - per = OHCI_PERIODIC(ival); /* 90% periodic */ - OWRITE4(sc, OHCI_PERIODIC_START, per); - - /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ - desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); - OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); - OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ - usb2_pause_mtx(NULL, - USB_MS_TO_TICKS(OHCI_ENABLE_POWER_DELAY)); - OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); - - /* - * The AMD756 requires a delay before re-reading the register, - * otherwise it will occasionally report 0 ports. - */ - sc->sc_noport = 0; - for (i = 0; (i < 10) && (sc->sc_noport == 0); i++) { - usb2_pause_mtx(NULL, - USB_MS_TO_TICKS(OHCI_READ_DESC_DELAY)); - sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); - } - -#if USB_DEBUG - if (ohcidebug > 5) { - ohci_dumpregs(sc); - } -#endif - return (USB_ERR_NORMAL_COMPLETION); -} - -static struct ohci_ed * -ohci_init_ed(struct usb2_page_cache *pc) -{ - struct usb2_page_search buf_res; - struct ohci_ed *ed; - - usb2_get_page(pc, 0, &buf_res); - - ed = buf_res.buffer; - - ed->ed_self = htole32(buf_res.physaddr); - ed->ed_flags = htole32(OHCI_ED_SKIP); - ed->page_cache = pc; - - return (ed); -} - -usb2_error_t -ohci_init(ohci_softc_t *sc) -{ - struct usb2_page_search buf_res; - uint16_t i; - uint16_t bit; - uint16_t x; - uint16_t y; - - DPRINTF("start\n"); - - sc->sc_eintrs = OHCI_NORMAL_INTRS; - - /* - * Setup all ED's - */ - - sc->sc_ctrl_p_last = - ohci_init_ed(&sc->sc_hw.ctrl_start_pc); - - sc->sc_bulk_p_last = - ohci_init_ed(&sc->sc_hw.bulk_start_pc); - - sc->sc_isoc_p_last = - ohci_init_ed(&sc->sc_hw.isoc_start_pc); - - for (i = 0; i != OHCI_NO_EDS; i++) { - sc->sc_intr_p_last[i] = - ohci_init_ed(sc->sc_hw.intr_start_pc + i); - } - - /* - * the QHs are arranged to give poll intervals that are - * powers of 2 times 1ms - */ - bit = OHCI_NO_EDS / 2; - while (bit) { - x = bit; - while (x & bit) { - ohci_ed_t *ed_x; - ohci_ed_t *ed_y; - - y = (x ^ bit) | (bit / 2); - - /* - * the next QH has half the poll interval - */ - ed_x = sc->sc_intr_p_last[x]; - ed_y = sc->sc_intr_p_last[y]; - - ed_x->next = NULL; - ed_x->ed_next = ed_y->ed_self; - - x++; - } - bit >>= 1; - } - - if (1) { - - ohci_ed_t *ed_int; - ohci_ed_t *ed_isc; - - ed_int = sc->sc_intr_p_last[0]; - ed_isc = sc->sc_isoc_p_last; - - /* the last (1ms) QH */ - ed_int->next = ed_isc; - ed_int->ed_next = ed_isc->ed_self; - } - usb2_get_page(&sc->sc_hw.hcca_pc, 0, &buf_res); - - sc->sc_hcca_p = buf_res.buffer; - - /* - * Fill HCCA interrupt table. The bit reversal is to get - * the tree set up properly to spread the interrupts. - */ - for (i = 0; i != OHCI_NO_INTRS; i++) { - sc->sc_hcca_p->hcca_interrupt_table[i] = - sc->sc_intr_p_last[i | (OHCI_NO_EDS / 2)]->ed_self; - } - /* flush all cache into memory */ - - usb2_bus_mem_flush_all(&sc->sc_bus, &ohci_iterate_hw_softc); - - /* set up the bus struct */ - sc->sc_bus.methods = &ohci_bus_methods; - - usb2_callout_init_mtx(&sc->sc_tmo_rhsc, &sc->sc_bus.bus_mtx, 0); - -#if USB_DEBUG - if (ohcidebug > 15) { - for (i = 0; i != OHCI_NO_EDS; i++) { - printf("ed#%d ", i); - ohci_dump_ed(sc->sc_intr_p_last[i]); - } - printf("iso "); - ohci_dump_ed(sc->sc_isoc_p_last); - } -#endif - - sc->sc_bus.usbrev = USB_REV_1_0; - - if (ohci_controller_init(sc)) { - return (USB_ERR_INVAL); - } else { - /* catch any lost interrupts */ - ohci_do_poll(&sc->sc_bus); - return (USB_ERR_NORMAL_COMPLETION); - } -} - -/* - * shut down the controller when the system is going down - */ -void -ohci_detach(struct ohci_softc *sc) -{ - USB_BUS_LOCK(&sc->sc_bus); - - usb2_callout_stop(&sc->sc_tmo_rhsc); - - OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); - OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); - - USB_BUS_UNLOCK(&sc->sc_bus); - - /* XXX let stray task complete */ - usb2_pause_mtx(NULL, hz / 20); - - usb2_callout_drain(&sc->sc_tmo_rhsc); -} - -/* NOTE: suspend/resume is called from - * interrupt context and cannot sleep! - */ -void -ohci_suspend(ohci_softc_t *sc) -{ - uint32_t ctl; - - USB_BUS_LOCK(&sc->sc_bus); - -#if USB_DEBUG - DPRINTF("\n"); - if (ohcidebug > 2) { - ohci_dumpregs(sc); - } -#endif - - ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK; - if (sc->sc_control == 0) { - /* - * Preserve register values, in case that APM BIOS - * does not recover them. - */ - sc->sc_control = ctl; - sc->sc_intre = OREAD4(sc, OHCI_INTERRUPT_ENABLE); - } - ctl |= OHCI_HCFS_SUSPEND; - OWRITE4(sc, OHCI_CONTROL, ctl); - - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_RESUME_WAIT)); - - USB_BUS_UNLOCK(&sc->sc_bus); -} - -void -ohci_resume(ohci_softc_t *sc) -{ - uint32_t ctl; - -#if USB_DEBUG - DPRINTF("\n"); - if (ohcidebug > 2) { - ohci_dumpregs(sc); - } -#endif - /* some broken BIOSes never initialize the Controller chip */ - ohci_controller_init(sc); - - USB_BUS_LOCK(&sc->sc_bus); - if (sc->sc_intre) { - OWRITE4(sc, OHCI_INTERRUPT_ENABLE, - sc->sc_intre & (OHCI_ALL_INTRS | OHCI_MIE)); - } - if (sc->sc_control) - ctl = sc->sc_control; - else - ctl = OREAD4(sc, OHCI_CONTROL); - ctl |= OHCI_HCFS_RESUME; - OWRITE4(sc, OHCI_CONTROL, ctl); - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_RESUME_DELAY)); - ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL; - OWRITE4(sc, OHCI_CONTROL, ctl); - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_RESUME_RECOVERY)); - sc->sc_control = sc->sc_intre = 0; - - USB_BUS_UNLOCK(&sc->sc_bus); - - /* catch any lost interrupts */ - ohci_do_poll(&sc->sc_bus); -} - -#if USB_DEBUG -static void -ohci_dumpregs(ohci_softc_t *sc) -{ - struct ohci_hcca *hcca; - - DPRINTF("ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n", - OREAD4(sc, OHCI_REVISION), - OREAD4(sc, OHCI_CONTROL), - OREAD4(sc, OHCI_COMMAND_STATUS)); - DPRINTF(" intrstat=0x%08x intre=0x%08x intrd=0x%08x\n", - OREAD4(sc, OHCI_INTERRUPT_STATUS), - OREAD4(sc, OHCI_INTERRUPT_ENABLE), - OREAD4(sc, OHCI_INTERRUPT_DISABLE)); - DPRINTF(" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n", - OREAD4(sc, OHCI_HCCA), - OREAD4(sc, OHCI_PERIOD_CURRENT_ED), - OREAD4(sc, OHCI_CONTROL_HEAD_ED)); - DPRINTF(" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n", - OREAD4(sc, OHCI_CONTROL_CURRENT_ED), - OREAD4(sc, OHCI_BULK_HEAD_ED), - OREAD4(sc, OHCI_BULK_CURRENT_ED)); - DPRINTF(" done=0x%08x fmival=0x%08x fmrem=0x%08x\n", - OREAD4(sc, OHCI_DONE_HEAD), - OREAD4(sc, OHCI_FM_INTERVAL), - OREAD4(sc, OHCI_FM_REMAINING)); - DPRINTF(" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n", - OREAD4(sc, OHCI_FM_NUMBER), - OREAD4(sc, OHCI_PERIODIC_START), - OREAD4(sc, OHCI_LS_THRESHOLD)); - DPRINTF(" desca=0x%08x descb=0x%08x stat=0x%08x\n", - OREAD4(sc, OHCI_RH_DESCRIPTOR_A), - OREAD4(sc, OHCI_RH_DESCRIPTOR_B), - OREAD4(sc, OHCI_RH_STATUS)); - DPRINTF(" port1=0x%08x port2=0x%08x\n", - OREAD4(sc, OHCI_RH_PORT_STATUS(1)), - OREAD4(sc, OHCI_RH_PORT_STATUS(2))); - - hcca = ohci_get_hcca(sc); - - DPRINTF(" HCCA: frame_number=0x%04x done_head=0x%08x\n", - le32toh(hcca->hcca_frame_number), - le32toh(hcca->hcca_done_head)); -} -static void -ohci_dump_tds(ohci_td_t *std) -{ - for (; std; std = std->obj_next) { - if (ohci_dump_td(std)) { - break; - } - } -} - -static uint8_t -ohci_dump_td(ohci_td_t *std) -{ - uint32_t td_flags; - uint8_t temp; - - usb2_pc_cpu_invalidate(std->page_cache); - - td_flags = le32toh(std->td_flags); - temp = (std->td_next == 0); - - printf("TD(%p) at 0x%08x: %s%s%s%s%s delay=%d ec=%d " - "cc=%d\ncbp=0x%08x next=0x%08x be=0x%08x\n", - std, le32toh(std->td_self), - (td_flags & OHCI_TD_R) ? "-R" : "", - (td_flags & OHCI_TD_OUT) ? "-OUT" : "", - (td_flags & OHCI_TD_IN) ? "-IN" : "", - ((td_flags & OHCI_TD_TOGGLE_MASK) == OHCI_TD_TOGGLE_1) ? "-TOG1" : "", - ((td_flags & OHCI_TD_TOGGLE_MASK) == OHCI_TD_TOGGLE_0) ? "-TOG0" : "", - OHCI_TD_GET_DI(td_flags), - OHCI_TD_GET_EC(td_flags), - OHCI_TD_GET_CC(td_flags), - le32toh(std->td_cbp), - le32toh(std->td_next), - le32toh(std->td_be)); - - return (temp); -} - -static uint8_t -ohci_dump_itd(ohci_itd_t *sitd) -{ - uint32_t itd_flags; - uint16_t i; - uint8_t temp; - - usb2_pc_cpu_invalidate(sitd->page_cache); - - itd_flags = le32toh(sitd->itd_flags); - temp = (sitd->itd_next == 0); - - printf("ITD(%p) at 0x%08x: sf=%d di=%d fc=%d cc=%d\n" - "bp0=0x%08x next=0x%08x be=0x%08x\n", - sitd, le32toh(sitd->itd_self), - OHCI_ITD_GET_SF(itd_flags), - OHCI_ITD_GET_DI(itd_flags), - OHCI_ITD_GET_FC(itd_flags), - OHCI_ITD_GET_CC(itd_flags), - le32toh(sitd->itd_bp0), - le32toh(sitd->itd_next), - le32toh(sitd->itd_be)); - for (i = 0; i < OHCI_ITD_NOFFSET; i++) { - printf("offs[%d]=0x%04x ", i, - (uint32_t)le16toh(sitd->itd_offset[i])); - } - printf("\n"); - - return (temp); -} - -static void -ohci_dump_itds(ohci_itd_t *sitd) -{ - for (; sitd; sitd = sitd->obj_next) { - if (ohci_dump_itd(sitd)) { - break; - } - } -} - -static void -ohci_dump_ed(ohci_ed_t *sed) -{ - uint32_t ed_flags; - uint32_t ed_headp; - - usb2_pc_cpu_invalidate(sed->page_cache); - - ed_flags = le32toh(sed->ed_flags); - ed_headp = le32toh(sed->ed_headp); - - printf("ED(%p) at 0x%08x: addr=%d endpt=%d maxp=%d flags=%s%s%s%s%s\n" - "tailp=0x%08x headflags=%s%s headp=0x%08x nexted=0x%08x\n", - sed, le32toh(sed->ed_self), - OHCI_ED_GET_FA(ed_flags), - OHCI_ED_GET_EN(ed_flags), - OHCI_ED_GET_MAXP(ed_flags), - (ed_flags & OHCI_ED_DIR_OUT) ? "-OUT" : "", - (ed_flags & OHCI_ED_DIR_IN) ? "-IN" : "", - (ed_flags & OHCI_ED_SPEED) ? "-LOWSPEED" : "", - (ed_flags & OHCI_ED_SKIP) ? "-SKIP" : "", - (ed_flags & OHCI_ED_FORMAT_ISO) ? "-ISO" : "", - le32toh(sed->ed_tailp), - (ed_headp & OHCI_HALTED) ? "-HALTED" : "", - (ed_headp & OHCI_TOGGLECARRY) ? "-CARRY" : "", - le32toh(sed->ed_headp), - le32toh(sed->ed_next)); -} - -#endif - -static void -ohci_transfer_intr_enqueue(struct usb2_xfer *xfer) -{ - /* check for early completion */ - if (ohci_check_transfer(xfer)) { - return; - } - /* put transfer on interrupt queue */ - usb2_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); - - /* start timeout, if any */ - if (xfer->timeout != 0) { - usb2_transfer_timeout_ms(xfer, &ohci_timeout, xfer->timeout); - } -} - -#define OHCI_APPEND_QH(sed,last) (last) = _ohci_append_qh(sed,last) -static ohci_ed_t * -_ohci_append_qh(ohci_ed_t *sed, ohci_ed_t *last) -{ - DPRINTFN(11, "%p to %p\n", sed, last); - - if (sed->prev != NULL) { - /* should not happen */ - DPRINTFN(0, "ED already linked!\n"); - return (last); - } - /* (sc->sc_bus.bus_mtx) must be locked */ - - sed->next = last->next; - sed->ed_next = last->ed_next; - sed->ed_tailp = 0; - - sed->prev = last; - - usb2_pc_cpu_flush(sed->page_cache); - - /* - * the last->next->prev is never followed: sed->next->prev = sed; - */ - - last->next = sed; - last->ed_next = sed->ed_self; - - usb2_pc_cpu_flush(last->page_cache); - - return (sed); -} - -#define OHCI_REMOVE_QH(sed,last) (last) = _ohci_remove_qh(sed,last) -static ohci_ed_t * -_ohci_remove_qh(ohci_ed_t *sed, ohci_ed_t *last) -{ - DPRINTFN(11, "%p from %p\n", sed, last); - - /* (sc->sc_bus.bus_mtx) must be locked */ - - /* only remove if not removed from a queue */ - if (sed->prev) { - - sed->prev->next = sed->next; - sed->prev->ed_next = sed->ed_next; - - usb2_pc_cpu_flush(sed->prev->page_cache); - - if (sed->next) { - sed->next->prev = sed->prev; - usb2_pc_cpu_flush(sed->next->page_cache); - } - last = ((last == sed) ? sed->prev : last); - - sed->prev = 0; - - usb2_pc_cpu_flush(sed->page_cache); - } - return (last); -} - -static void -ohci_isoc_done(struct usb2_xfer *xfer) -{ - uint8_t nframes; - uint32_t *plen = xfer->frlengths; - volatile uint16_t *olen; - uint16_t len = 0; - ohci_itd_t *td = xfer->td_transfer_first; - - while (1) { - if (td == NULL) { - panic("%s:%d: out of TD's\n", - __FUNCTION__, __LINE__); - } -#if USB_DEBUG - if (ohcidebug > 5) { - DPRINTF("isoc TD\n"); - ohci_dump_itd(td); - } -#endif - usb2_pc_cpu_invalidate(td->page_cache); - - nframes = td->frames; - olen = &td->itd_offset[0]; - - if (nframes > 8) { - nframes = 8; - } - while (nframes--) { - len = le16toh(*olen); - - if ((len >> 12) == OHCI_CC_NOT_ACCESSED) { - len = 0; - } else { - len &= ((1 << 12) - 1); - } - - if (len > *plen) { - len = 0;/* invalid length */ - } - *plen = len; - plen++; - olen++; - } - - if (((void *)td) == xfer->td_transfer_last) { - break; - } - td = td->obj_next; - } - - xfer->aframes = xfer->nframes; - ohci_device_done(xfer, USB_ERR_NORMAL_COMPLETION); -} - -#if USB_DEBUG -static const char *const - ohci_cc_strs[] = -{ - "NO_ERROR", - "CRC", - "BIT_STUFFING", - "DATA_TOGGLE_MISMATCH", - - "STALL", - "DEVICE_NOT_RESPONDING", - "PID_CHECK_FAILURE", - "UNEXPECTED_PID", - - "DATA_OVERRUN", - "DATA_UNDERRUN", - "BUFFER_OVERRUN", - "BUFFER_UNDERRUN", - - "reserved", - "reserved", - "NOT_ACCESSED", - "NOT_ACCESSED" -}; - -#endif - -static usb2_error_t -ohci_non_isoc_done_sub(struct usb2_xfer *xfer) -{ - ohci_td_t *td; - ohci_td_t *td_alt_next; - uint32_t temp; - uint32_t phy_start; - uint32_t phy_end; - uint32_t td_flags; - uint16_t cc; - - td = xfer->td_transfer_cache; - td_alt_next = td->alt_next; - td_flags = 0; - - if (xfer->aframes != xfer->nframes) { - xfer->frlengths[xfer->aframes] = 0; - } - while (1) { - - usb2_pc_cpu_invalidate(td->page_cache); - phy_start = le32toh(td->td_cbp); - td_flags = le32toh(td->td_flags); - cc = OHCI_TD_GET_CC(td_flags); - - if (phy_start) { - /* - * short transfer - compute the number of remaining - * bytes in the hardware buffer: - */ - phy_end = le32toh(td->td_be); - temp = (OHCI_PAGE(phy_start ^ phy_end) ? - (OHCI_PAGE_SIZE + 1) : 0x0001); - temp += OHCI_PAGE_OFFSET(phy_end); - temp -= OHCI_PAGE_OFFSET(phy_start); - - if (temp > td->len) { - /* guard against corruption */ - cc = OHCI_CC_STALL; - } else if (xfer->aframes != xfer->nframes) { - /* - * Sum up total transfer length - * in "frlengths[]": - */ - xfer->frlengths[xfer->aframes] += td->len - temp; - } - } else { - if (xfer->aframes != xfer->nframes) { - /* transfer was complete */ - xfer->frlengths[xfer->aframes] += td->len; - } - } - /* Check for last transfer */ - if (((void *)td) == xfer->td_transfer_last) { - td = NULL; - break; - } - /* Check transfer status */ - if (cc) { - /* the transfer is finished */ - td = NULL; - break; - } - /* Check for short transfer */ - if (phy_start) { - if (xfer->flags_int.short_frames_ok) { - /* follow alt next */ - td = td->alt_next; - } else { - /* the transfer is finished */ - td = NULL; - } - break; - } - td = td->obj_next; - - if (td->alt_next != td_alt_next) { - /* this USB frame is complete */ - break; - } - } - - /* update transfer cache */ - - xfer->td_transfer_cache = td; - - DPRINTFN(16, "error cc=%d (%s)\n", - cc, ohci_cc_strs[cc]); - - return ((cc == 0) ? USB_ERR_NORMAL_COMPLETION : - (cc == OHCI_CC_STALL) ? USB_ERR_STALLED : USB_ERR_IOERROR); -} - -static void -ohci_non_isoc_done(struct usb2_xfer *xfer) -{ - usb2_error_t err = 0; - - DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", - xfer, xfer->pipe); - -#if USB_DEBUG - if (ohcidebug > 10) { - ohci_dump_tds(xfer->td_transfer_first); - } -#endif - - /* reset scanner */ - - xfer->td_transfer_cache = xfer->td_transfer_first; - - if (xfer->flags_int.control_xfr) { - - if (xfer->flags_int.control_hdr) { - - err = ohci_non_isoc_done_sub(xfer); - } - xfer->aframes = 1; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - while (xfer->aframes != xfer->nframes) { - - err = ohci_non_isoc_done_sub(xfer); - xfer->aframes++; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - err = ohci_non_isoc_done_sub(xfer); - } -done: - ohci_device_done(xfer, err); -} - -/*------------------------------------------------------------------------* - * ohci_check_transfer_sub - *------------------------------------------------------------------------*/ -static void -ohci_check_transfer_sub(struct usb2_xfer *xfer) -{ - ohci_td_t *td; - ohci_ed_t *ed; - uint32_t phy_start; - uint32_t td_flags; - uint32_t td_next; - uint16_t cc; - - td = xfer->td_transfer_cache; - - while (1) { - - usb2_pc_cpu_invalidate(td->page_cache); - phy_start = le32toh(td->td_cbp); - td_flags = le32toh(td->td_flags); - td_next = le32toh(td->td_next); - - /* Check for last transfer */ - if (((void *)td) == xfer->td_transfer_last) { - /* the transfer is finished */ - td = NULL; - break; - } - /* Check transfer status */ - cc = OHCI_TD_GET_CC(td_flags); - if (cc) { - /* the transfer is finished */ - td = NULL; - break; - } - /* - * Check if we reached the last packet - * or if there is a short packet: - */ - - if (((td_next & (~0xF)) == OHCI_TD_NEXT_END) || phy_start) { - /* follow alt next */ - td = td->alt_next; - break; - } - td = td->obj_next; - } - - /* update transfer cache */ - - xfer->td_transfer_cache = td; - - if (td) { - - ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - ed->ed_headp = td->td_self; - usb2_pc_cpu_flush(ed->page_cache); - - DPRINTFN(13, "xfer=%p following alt next\n", xfer); - } -} - -/*------------------------------------------------------------------------* - * ohci_check_transfer - * - * Return values: - * 0: USB transfer is not finished - * Else: USB transfer is finished - *------------------------------------------------------------------------*/ -static uint8_t -ohci_check_transfer(struct usb2_xfer *xfer) -{ - ohci_ed_t *ed; - uint32_t ed_flags; - uint32_t ed_headp; - uint32_t ed_tailp; - - DPRINTFN(13, "xfer=%p checking transfer\n", xfer); - - ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - usb2_pc_cpu_invalidate(ed->page_cache); - ed_flags = le32toh(ed->ed_flags); - ed_headp = le32toh(ed->ed_headp); - ed_tailp = le32toh(ed->ed_tailp); - - if ((ed_flags & OHCI_ED_SKIP) || - (ed_headp & OHCI_HALTED) || - (((ed_headp ^ ed_tailp) & (~0xF)) == 0)) { - if (xfer->pipe->methods == &ohci_device_isoc_methods) { - /* isochronous transfer */ - ohci_isoc_done(xfer); - } else { - if (xfer->flags_int.short_frames_ok) { - ohci_check_transfer_sub(xfer); - if (xfer->td_transfer_cache) { - /* not finished yet */ - return (0); - } - } - /* store data-toggle */ - if (ed_headp & OHCI_TOGGLECARRY) { - xfer->pipe->toggle_next = 1; - } else { - xfer->pipe->toggle_next = 0; - } - - /* non-isochronous transfer */ - ohci_non_isoc_done(xfer); - } - return (1); - } - DPRINTFN(13, "xfer=%p is still active\n", xfer); - return (0); -} - -static void -ohci_rhsc_enable(ohci_softc_t *sc) -{ - DPRINTFN(5, "\n"); - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - sc->sc_eintrs |= OHCI_RHSC; - OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); - - /* acknowledge any RHSC interrupt */ - OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_RHSC); - - usb2_sw_transfer(&sc->sc_root_intr, - &ohci_root_intr_done); -} - -static void -ohci_interrupt_poll(ohci_softc_t *sc) -{ - struct usb2_xfer *xfer; - -repeat: - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - /* - * check if transfer is transferred - */ - if (ohci_check_transfer(xfer)) { - /* queue has been modified */ - goto repeat; - } - } -} - -/*------------------------------------------------------------------------* - * ohci_interrupt - OHCI interrupt handler - * - * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler, - * hence the interrupt handler will be setup before "sc->sc_bus.bdev" - * is present ! - *------------------------------------------------------------------------*/ -void -ohci_interrupt(ohci_softc_t *sc) -{ - struct ohci_hcca *hcca; - uint32_t status; - uint32_t done; - - USB_BUS_LOCK(&sc->sc_bus); - - hcca = ohci_get_hcca(sc); - - DPRINTFN(16, "real interrupt\n"); - -#if USB_DEBUG - if (ohcidebug > 15) { - ohci_dumpregs(sc); - } -#endif - - done = le32toh(hcca->hcca_done_head); - - /* - * The LSb of done is used to inform the HC Driver that an interrupt - * condition exists for both the Done list and for another event - * recorded in HcInterruptStatus. On an interrupt from the HC, the - * HC Driver checks the HccaDoneHead Value. If this value is 0, then - * the interrupt was caused by other than the HccaDoneHead update - * and the HcInterruptStatus register needs to be accessed to - * determine that exact interrupt cause. If HccaDoneHead is nonzero, - * then a Done list update interrupt is indicated and if the LSb of - * done is nonzero, then an additional interrupt event is indicated - * and HcInterruptStatus should be checked to determine its cause. - */ - if (done != 0) { - status = 0; - - if (done & ~OHCI_DONE_INTRS) { - status |= OHCI_WDH; - } - if (done & OHCI_DONE_INTRS) { - status |= OREAD4(sc, OHCI_INTERRUPT_STATUS); - } - hcca->hcca_done_head = 0; - - usb2_pc_cpu_flush(&sc->sc_hw.hcca_pc); - } else { - status = OREAD4(sc, OHCI_INTERRUPT_STATUS) & ~OHCI_WDH; - } - - status &= ~OHCI_MIE; - if (status == 0) { - /* - * nothing to be done (PCI shared - * interrupt) - */ - goto done; - } - OWRITE4(sc, OHCI_INTERRUPT_STATUS, status); /* Acknowledge */ - - status &= sc->sc_eintrs; - if (status == 0) { - goto done; - } - if (status & (OHCI_SO | OHCI_RD | OHCI_UE | OHCI_RHSC)) { -#if 0 - if (status & OHCI_SO) { - /* XXX do what */ - } -#endif - if (status & OHCI_RD) { - printf("%s: resume detect\n", __FUNCTION__); - /* XXX process resume detect */ - } - if (status & OHCI_UE) { - printf("%s: unrecoverable error, " - "controller halted\n", __FUNCTION__); - OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); - /* XXX what else */ - } - if (status & OHCI_RHSC) { - /* - * Disable RHSC interrupt for now, because it will be - * on until the port has been reset. - */ - sc->sc_eintrs &= ~OHCI_RHSC; - OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC); - - usb2_sw_transfer(&sc->sc_root_intr, - &ohci_root_intr_done); - - /* do not allow RHSC interrupts > 1 per second */ - usb2_callout_reset(&sc->sc_tmo_rhsc, hz, - (void *)&ohci_rhsc_enable, sc); - } - } - status &= ~(OHCI_RHSC | OHCI_WDH | OHCI_SO); - if (status != 0) { - /* Block unprocessed interrupts. XXX */ - OWRITE4(sc, OHCI_INTERRUPT_DISABLE, status); - sc->sc_eintrs &= ~status; - printf("%s: blocking intrs 0x%x\n", - __FUNCTION__, status); - } - /* poll all the USB transfers */ - ohci_interrupt_poll(sc); - -done: - USB_BUS_UNLOCK(&sc->sc_bus); -} - -/* - * called when a request does not complete - */ -static void -ohci_timeout(void *arg) -{ - struct usb2_xfer *xfer = arg; - - DPRINTF("xfer=%p\n", xfer); - - USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); - - /* transfer is transferred */ - ohci_device_done(xfer, USB_ERR_TIMEOUT); -} - -static void -ohci_do_poll(struct usb2_bus *bus) -{ - struct ohci_softc *sc = OHCI_BUS2SC(bus); - - USB_BUS_LOCK(&sc->sc_bus); - ohci_interrupt_poll(sc); - ohci_root_ctrl_poll(sc); - USB_BUS_UNLOCK(&sc->sc_bus); -} - -static void -ohci_setup_standard_chain_sub(struct ohci_std_temp *temp) -{ - struct usb2_page_search buf_res; - ohci_td_t *td; - ohci_td_t *td_next; - ohci_td_t *td_alt_next; - uint32_t buf_offset; - uint32_t average; - uint32_t len_old; - uint8_t shortpkt_old; - uint8_t precompute; - - td_alt_next = NULL; - buf_offset = 0; - shortpkt_old = temp->shortpkt; - len_old = temp->len; - precompute = 1; - - /* software is used to detect short incoming transfers */ - - if ((temp->td_flags & htole32(OHCI_TD_DP_MASK)) == htole32(OHCI_TD_IN)) { - temp->td_flags |= htole32(OHCI_TD_R); - } else { - temp->td_flags &= ~htole32(OHCI_TD_R); - } - -restart: - - td = temp->td; - td_next = temp->td_next; - - while (1) { - - if (temp->len == 0) { - - if (temp->shortpkt) { - break; - } - /* send a Zero Length Packet, ZLP, last */ - - temp->shortpkt = 1; - average = 0; - - } else { - - average = temp->average; - - if (temp->len < average) { - if (temp->len % temp->max_frame_size) { - temp->shortpkt = 1; - } - average = temp->len; - } - } - - if (td_next == NULL) { - panic("%s: out of OHCI transfer descriptors!", __FUNCTION__); - } - /* get next TD */ - - td = td_next; - td_next = td->obj_next; - - /* check if we are pre-computing */ - - if (precompute) { - - /* update remaining length */ - - temp->len -= average; - - continue; - } - /* fill out current TD */ - td->td_flags = temp->td_flags; - - /* the next TD uses TOGGLE_CARRY */ - temp->td_flags &= ~htole32(OHCI_TD_TOGGLE_MASK); - - if (average == 0) { - - td->td_cbp = 0; - td->td_be = ~0; - td->len = 0; - - } else { - - usb2_get_page(temp->pc, buf_offset, &buf_res); - td->td_cbp = htole32(buf_res.physaddr); - buf_offset += (average - 1); - - usb2_get_page(temp->pc, buf_offset, &buf_res); - td->td_be = htole32(buf_res.physaddr); - buf_offset++; - - td->len = average; - - /* update remaining length */ - - temp->len -= average; - } - - if ((td_next == td_alt_next) && temp->setup_alt_next) { - /* we need to receive these frames one by one ! */ - td->td_flags &= htole32(~OHCI_TD_INTR_MASK); - td->td_flags |= htole32(OHCI_TD_SET_DI(1)); - td->td_next = htole32(OHCI_TD_NEXT_END); - } else { - if (td_next) { - /* link the current TD with the next one */ - td->td_next = td_next->td_self; - } - } - - td->alt_next = td_alt_next; - - usb2_pc_cpu_flush(td->page_cache); - } - - if (precompute) { - precompute = 0; - - /* setup alt next pointer, if any */ - if (temp->short_frames_ok) { - if (temp->setup_alt_next) { - td_alt_next = td_next; - } - } else { - /* we use this field internally */ - td_alt_next = td_next; - } - - /* restore */ - temp->shortpkt = shortpkt_old; - temp->len = len_old; - goto restart; - } - temp->td = td; - temp->td_next = td_next; -} - -static void -ohci_setup_standard_chain(struct usb2_xfer *xfer, ohci_ed_t **ed_last) -{ - struct ohci_std_temp temp; - struct usb2_pipe_methods *methods; - ohci_ed_t *ed; - ohci_td_t *td; - uint32_t ed_flags; - uint32_t x; - - DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", - xfer->address, UE_GET_ADDR(xfer->endpoint), - xfer->sumlen, usb2_get_speed(xfer->xroot->udev)); - - temp.average = xfer->max_usb2_frame_size; - temp.max_frame_size = xfer->max_frame_size; - - /* toggle the DMA set we are using */ - xfer->flags_int.curr_dma_set ^= 1; - - /* get next DMA set */ - td = xfer->td_start[xfer->flags_int.curr_dma_set]; - - xfer->td_transfer_first = td; - xfer->td_transfer_cache = td; - - temp.td = NULL; - temp.td_next = td; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; - temp.short_frames_ok = xfer->flags_int.short_frames_ok; - - methods = xfer->pipe->methods; - - /* check if we should prepend a setup message */ - - if (xfer->flags_int.control_xfr) { - if (xfer->flags_int.control_hdr) { - - temp.td_flags = htole32(OHCI_TD_SETUP | OHCI_TD_NOCC | - OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); - - temp.len = xfer->frlengths[0]; - temp.pc = xfer->frbuffers + 0; - temp.shortpkt = temp.len ? 1 : 0; - - ohci_setup_standard_chain_sub(&temp); - - /* - * XXX assume that the setup message is - * contained within one USB packet: - */ - xfer->pipe->toggle_next = 1; - } - x = 1; - } else { - x = 0; - } - temp.td_flags = htole32(OHCI_TD_NOCC | OHCI_TD_NOINTR); - - /* set data toggle */ - - if (xfer->pipe->toggle_next) { - temp.td_flags |= htole32(OHCI_TD_TOGGLE_1); - } else { - temp.td_flags |= htole32(OHCI_TD_TOGGLE_0); - } - - /* set endpoint direction */ - - if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) { - temp.td_flags |= htole32(OHCI_TD_IN); - } else { - temp.td_flags |= htole32(OHCI_TD_OUT); - } - - while (x != xfer->nframes) { - - /* DATA0 / DATA1 message */ - - temp.len = xfer->frlengths[x]; - temp.pc = xfer->frbuffers + x; - - x++; - - if (x == xfer->nframes) { - temp.setup_alt_next = 0; - } - if (temp.len == 0) { - - /* make sure that we send an USB packet */ - - temp.shortpkt = 0; - - } else { - - /* regular data transfer */ - - temp.shortpkt = (xfer->flags.force_short_xfer) ? 0 : 1; - } - - ohci_setup_standard_chain_sub(&temp); - } - - /* check if we should append a status stage */ - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - /* - * Send a DATA1 message and invert the current endpoint - * direction. - */ - - /* set endpoint direction and data toggle */ - - if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) { - temp.td_flags = htole32(OHCI_TD_OUT | - OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); - } else { - temp.td_flags = htole32(OHCI_TD_IN | - OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); - } - - temp.len = 0; - temp.pc = NULL; - temp.shortpkt = 0; - - ohci_setup_standard_chain_sub(&temp); - } - td = temp.td; - - td->td_next = htole32(OHCI_TD_NEXT_END); - td->td_flags &= ~htole32(OHCI_TD_INTR_MASK); - td->td_flags |= htole32(OHCI_TD_SET_DI(1)); - - usb2_pc_cpu_flush(td->page_cache); - - /* must have at least one frame! */ - - xfer->td_transfer_last = td; - -#if USB_DEBUG - if (ohcidebug > 8) { - DPRINTF("nexttog=%d; data before transfer:\n", - xfer->pipe->toggle_next); - ohci_dump_tds(xfer->td_transfer_first); - } -#endif - - ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - ed_flags = (OHCI_ED_SET_FA(xfer->address) | - OHCI_ED_SET_EN(UE_GET_ADDR(xfer->endpoint)) | - OHCI_ED_SET_MAXP(xfer->max_frame_size)); - - ed_flags |= (OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD); - - if (xfer->xroot->udev->speed == USB_SPEED_LOW) { - ed_flags |= OHCI_ED_SPEED; - } - ed->ed_flags = htole32(ed_flags); - - td = xfer->td_transfer_first; - - ed->ed_headp = td->td_self; - - if (xfer->xroot->udev->pwr_save.suspended == 0) { - /* the append function will flush the endpoint descriptor */ - OHCI_APPEND_QH(ed, *ed_last); - - if (methods == &ohci_device_bulk_methods) { - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - - OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); - } - if (methods == &ohci_device_ctrl_methods) { - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - - OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); - } - } else { - usb2_pc_cpu_flush(ed->page_cache); - } -} - -static void -ohci_root_intr_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - uint32_t hstatus; - uint16_t i; - uint16_t m; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_PRE_DATA) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - ohci_device_done(xfer, std->err); - } - goto done; - } - /* setup buffer */ - std->ptr = sc->sc_hub_idata; - std->len = sizeof(sc->sc_hub_idata); - - /* clear any old interrupt data */ - bzero(sc->sc_hub_idata, sizeof(sc->sc_hub_idata)); - - hstatus = OREAD4(sc, OHCI_RH_STATUS); - DPRINTF("sc=%p xfer=%p hstatus=0x%08x\n", - sc, xfer, hstatus); - - /* set bits */ - m = (sc->sc_noport + 1); - if (m > (8 * sizeof(sc->sc_hub_idata))) { - m = (8 * sizeof(sc->sc_hub_idata)); - } - for (i = 1; i < m; i++) { - /* pick out CHANGE bits from the status register */ - if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16) { - sc->sc_hub_idata[i / 8] |= 1 << (i % 8); - DPRINTF("port %d changed\n", i); - } - } -done: - return; -} - -/* NOTE: "done" can be run two times in a row, - * from close and from interrupt - */ -static void -ohci_device_done(struct usb2_xfer *xfer, usb2_error_t error) -{ - struct usb2_pipe_methods *methods = xfer->pipe->methods; - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - ohci_ed_t *ed; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - - DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", - xfer, xfer->pipe, error); - - ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; - if (ed) { - usb2_pc_cpu_invalidate(ed->page_cache); - } - if (methods == &ohci_device_bulk_methods) { - OHCI_REMOVE_QH(ed, sc->sc_bulk_p_last); - } - if (methods == &ohci_device_ctrl_methods) { - OHCI_REMOVE_QH(ed, sc->sc_ctrl_p_last); - } - if (methods == &ohci_device_intr_methods) { - OHCI_REMOVE_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); - } - if (methods == &ohci_device_isoc_methods) { - OHCI_REMOVE_QH(ed, sc->sc_isoc_p_last); - } - xfer->td_transfer_first = NULL; - xfer->td_transfer_last = NULL; - - /* dequeue transfer and start next transfer */ - usb2_transfer_done(xfer, error); -} - -/*------------------------------------------------------------------------* - * ohci bulk support - *------------------------------------------------------------------------*/ -static void -ohci_device_bulk_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -ohci_device_bulk_close(struct usb2_xfer *xfer) -{ - ohci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -ohci_device_bulk_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -ohci_device_bulk_start(struct usb2_xfer *xfer) -{ - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - - /* setup TD's and QH */ - ohci_setup_standard_chain(xfer, &sc->sc_bulk_p_last); - - /* put transfer on interrupt queue */ - ohci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods ohci_device_bulk_methods = -{ - .open = ohci_device_bulk_open, - .close = ohci_device_bulk_close, - .enter = ohci_device_bulk_enter, - .start = ohci_device_bulk_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * ohci control support - *------------------------------------------------------------------------*/ -static void -ohci_device_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -ohci_device_ctrl_close(struct usb2_xfer *xfer) -{ - ohci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -ohci_device_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -ohci_device_ctrl_start(struct usb2_xfer *xfer) -{ - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - - /* setup TD's and QH */ - ohci_setup_standard_chain(xfer, &sc->sc_ctrl_p_last); - - /* put transfer on interrupt queue */ - ohci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods ohci_device_ctrl_methods = -{ - .open = ohci_device_ctrl_open, - .close = ohci_device_ctrl_close, - .enter = ohci_device_ctrl_enter, - .start = ohci_device_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * ohci interrupt support - *------------------------------------------------------------------------*/ -static void -ohci_device_intr_open(struct usb2_xfer *xfer) -{ - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - uint16_t best; - uint16_t bit; - uint16_t x; - - best = 0; - bit = OHCI_NO_EDS / 2; - while (bit) { - if (xfer->interval >= bit) { - x = bit; - best = bit; - while (x & bit) { - if (sc->sc_intr_stat[x] < - sc->sc_intr_stat[best]) { - best = x; - } - x++; - } - break; - } - bit >>= 1; - } - - sc->sc_intr_stat[best]++; - xfer->qh_pos = best; - - DPRINTFN(3, "best=%d interval=%d\n", - best, xfer->interval); -} - -static void -ohci_device_intr_close(struct usb2_xfer *xfer) -{ - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - - sc->sc_intr_stat[xfer->qh_pos]--; - - ohci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -ohci_device_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -ohci_device_intr_start(struct usb2_xfer *xfer) -{ - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - - /* setup TD's and QH */ - ohci_setup_standard_chain(xfer, &sc->sc_intr_p_last[xfer->qh_pos]); - - /* put transfer on interrupt queue */ - ohci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods ohci_device_intr_methods = -{ - .open = ohci_device_intr_open, - .close = ohci_device_intr_close, - .enter = ohci_device_intr_enter, - .start = ohci_device_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * ohci isochronous support - *------------------------------------------------------------------------*/ -static void -ohci_device_isoc_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -ohci_device_isoc_close(struct usb2_xfer *xfer) -{ - /**/ - ohci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -ohci_device_isoc_enter(struct usb2_xfer *xfer) -{ - struct usb2_page_search buf_res; - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - struct ohci_hcca *hcca; - uint32_t buf_offset; - uint32_t nframes; - uint32_t ed_flags; - uint32_t *plen; - uint16_t itd_offset[OHCI_ITD_NOFFSET]; - uint16_t length; - uint8_t ncur; - ohci_itd_t *td; - ohci_itd_t *td_last = NULL; - ohci_ed_t *ed; - - hcca = ohci_get_hcca(sc); - - nframes = le32toh(hcca->hcca_frame_number); - - DPRINTFN(6, "xfer=%p isoc_next=%u nframes=%u hcca_fn=%u\n", - xfer, xfer->pipe->isoc_next, xfer->nframes, nframes); - - if ((xfer->pipe->is_synced == 0) || - (((nframes - xfer->pipe->isoc_next) & 0xFFFF) < xfer->nframes) || - (((xfer->pipe->isoc_next - nframes) & 0xFFFF) >= 128)) { - /* - * If there is data underflow or the pipe queue is empty we - * schedule the transfer a few frames ahead of the current - * frame position. Else two isochronous transfers might - * overlap. - */ - xfer->pipe->isoc_next = (nframes + 3) & 0xFFFF; - xfer->pipe->is_synced = 1; - DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next); - } - /* - * compute how many milliseconds the insertion is ahead of the - * current frame position: - */ - buf_offset = ((xfer->pipe->isoc_next - nframes) & 0xFFFF); - - /* - * pre-compute when the isochronous transfer will be finished: - */ - xfer->isoc_time_complete = - (usb2_isoc_time_expand(&sc->sc_bus, nframes) + buf_offset + - xfer->nframes); - - /* get the real number of frames */ - - nframes = xfer->nframes; - - buf_offset = 0; - - plen = xfer->frlengths; - - /* toggle the DMA set we are using */ - xfer->flags_int.curr_dma_set ^= 1; - - /* get next DMA set */ - td = xfer->td_start[xfer->flags_int.curr_dma_set]; - - xfer->td_transfer_first = td; - - ncur = 0; - length = 0; - - while (nframes--) { - if (td == NULL) { - panic("%s:%d: out of TD's\n", - __FUNCTION__, __LINE__); - } - itd_offset[ncur] = length; - buf_offset += *plen; - length += *plen; - plen++; - ncur++; - - if ( /* check if the ITD is full */ - (ncur == OHCI_ITD_NOFFSET) || - /* check if we have put more than 4K into the ITD */ - (length & 0xF000) || - /* check if it is the last frame */ - (nframes == 0)) { - - /* fill current ITD */ - td->itd_flags = htole32( - OHCI_ITD_NOCC | - OHCI_ITD_SET_SF(xfer->pipe->isoc_next) | - OHCI_ITD_NOINTR | - OHCI_ITD_SET_FC(ncur)); - - td->frames = ncur; - xfer->pipe->isoc_next += ncur; - - if (length == 0) { - /* all zero */ - td->itd_bp0 = 0; - td->itd_be = ~0; - - while (ncur--) { - td->itd_offset[ncur] = - htole16(OHCI_ITD_MK_OFFS(0)); - } - } else { - usb2_get_page(xfer->frbuffers, buf_offset - length, &buf_res); - length = OHCI_PAGE_MASK(buf_res.physaddr); - buf_res.physaddr = - OHCI_PAGE(buf_res.physaddr); - td->itd_bp0 = htole32(buf_res.physaddr); - usb2_get_page(xfer->frbuffers, buf_offset - 1, &buf_res); - td->itd_be = htole32(buf_res.physaddr); - - while (ncur--) { - itd_offset[ncur] += length; - itd_offset[ncur] = - OHCI_ITD_MK_OFFS(itd_offset[ncur]); - td->itd_offset[ncur] = - htole16(itd_offset[ncur]); - } - } - ncur = 0; - length = 0; - td_last = td; - td = td->obj_next; - - if (td) { - /* link the last TD with the next one */ - td_last->itd_next = td->itd_self; - } - usb2_pc_cpu_flush(td_last->page_cache); - } - } - - /* update the last TD */ - td_last->itd_flags &= ~htole32(OHCI_ITD_NOINTR); - td_last->itd_flags |= htole32(OHCI_ITD_SET_DI(0)); - td_last->itd_next = 0; - - usb2_pc_cpu_flush(td_last->page_cache); - - xfer->td_transfer_last = td_last; - -#if USB_DEBUG - if (ohcidebug > 8) { - DPRINTF("data before transfer:\n"); - ohci_dump_itds(xfer->td_transfer_first); - } -#endif - ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) - ed_flags = (OHCI_ED_DIR_IN | OHCI_ED_FORMAT_ISO); - else - ed_flags = (OHCI_ED_DIR_OUT | OHCI_ED_FORMAT_ISO); - - ed_flags |= (OHCI_ED_SET_FA(xfer->address) | - OHCI_ED_SET_EN(UE_GET_ADDR(xfer->endpoint)) | - OHCI_ED_SET_MAXP(xfer->max_frame_size)); - - if (xfer->xroot->udev->speed == USB_SPEED_LOW) { - ed_flags |= OHCI_ED_SPEED; - } - ed->ed_flags = htole32(ed_flags); - - td = xfer->td_transfer_first; - - ed->ed_headp = td->itd_self; - - /* isochronous transfers are not affected by suspend / resume */ - /* the append function will flush the endpoint descriptor */ - - OHCI_APPEND_QH(ed, sc->sc_isoc_p_last); -} - -static void -ohci_device_isoc_start(struct usb2_xfer *xfer) -{ - /* put transfer on interrupt queue */ - ohci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods ohci_device_isoc_methods = -{ - .open = ohci_device_isoc_open, - .close = ohci_device_isoc_close, - .enter = ohci_device_isoc_enter, - .start = ohci_device_isoc_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * ohci root control support - *------------------------------------------------------------------------* - * simulate a hardware hub by handling - * all the necessary requests - *------------------------------------------------------------------------*/ - -static void -ohci_root_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -ohci_root_ctrl_close(struct usb2_xfer *xfer) -{ - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_ctrl.xfer == xfer) { - sc->sc_root_ctrl.xfer = NULL; - } - ohci_device_done(xfer, USB_ERR_CANCELLED); -} - -/* data structures and routines - * to emulate the root hub: - */ -static const -struct usb2_device_descriptor ohci_devd = -{ - sizeof(struct usb2_device_descriptor), - UDESC_DEVICE, /* type */ - {0x00, 0x01}, /* USB version */ - UDCLASS_HUB, /* class */ - UDSUBCLASS_HUB, /* subclass */ - UDPROTO_FSHUB, /* protocol */ - 64, /* max packet */ - {0}, {0}, {0x00, 0x01}, /* device id */ - 1, 2, 0, /* string indicies */ - 1 /* # of configurations */ -}; - -static const -struct ohci_config_desc ohci_confd = -{ - .confd = { - .bLength = sizeof(struct usb2_config_descriptor), - .bDescriptorType = UDESC_CONFIG, - .wTotalLength[0] = sizeof(ohci_confd), - .bNumInterface = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = UC_SELF_POWERED, - .bMaxPower = 0, /* max power */ - }, - - .ifcd = { - .bLength = sizeof(struct usb2_interface_descriptor), - .bDescriptorType = UDESC_INTERFACE, - .bNumEndpoints = 1, - .bInterfaceClass = UICLASS_HUB, - .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_FSHUB, - }, - - .endpd = { - .bLength = sizeof(struct usb2_endpoint_descriptor), - .bDescriptorType = UDESC_ENDPOINT, - .bEndpointAddress = UE_DIR_IN | OHCI_INTR_ENDPT, - .bmAttributes = UE_INTERRUPT, - .wMaxPacketSize[0] = 32,/* max packet (255 ports) */ - .bInterval = 255, - }, -}; - -static const -struct usb2_hub_descriptor ohci_hubd = -{ - 0, /* dynamic length */ - UDESC_HUB, - 0, - {0, 0}, - 0, - 0, - {0}, -}; - -static void -ohci_root_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -ohci_root_ctrl_start(struct usb2_xfer *xfer) -{ - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - - sc->sc_root_ctrl.xfer = xfer; - - usb2_bus_roothub_exec(xfer->xroot->bus); -} - -static void -ohci_root_ctrl_task(struct usb2_bus *bus) -{ - ohci_root_ctrl_poll(OHCI_BUS2SC(bus)); -} - -static void -ohci_root_ctrl_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - char *ptr; - uint32_t port; - uint32_t v; - uint16_t value; - uint16_t index; - uint8_t l; - uint8_t use_polling; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_SETUP) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - ohci_device_done(xfer, std->err); - } - goto done; - } - /* buffer reset */ - std->ptr = sc->sc_hub_desc.temp; - std->len = 0; - - value = UGETW(std->req.wValue); - index = UGETW(std->req.wIndex); - - use_polling = mtx_owned(xfer->xroot->xfer_mtx) ? 1 : 0; - - DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x " - "wValue=0x%04x wIndex=0x%04x\n", - std->req.bmRequestType, std->req.bRequest, - UGETW(std->req.wLength), value, index); - -#define C(x,y) ((x) | ((y) << 8)) - switch (C(std->req.bRequest, std->req.bmRequestType)) { - case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): - case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): - case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): - /* - * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops - * for the integrated root hub. - */ - break; - case C(UR_GET_CONFIG, UT_READ_DEVICE): - std->len = 1; - sc->sc_hub_desc.temp[0] = sc->sc_conf; - break; - case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): - switch (value >> 8) { - case UDESC_DEVICE: - if ((value & 0xff) != 0) { - std->err = USB_ERR_IOERROR; - goto done; - } - std->len = sizeof(ohci_devd); - sc->sc_hub_desc.devd = ohci_devd; - break; - - case UDESC_CONFIG: - if ((value & 0xff) != 0) { - std->err = USB_ERR_IOERROR; - goto done; - } - std->len = sizeof(ohci_confd); - std->ptr = USB_ADD_BYTES(&ohci_confd, 0); - break; - - case UDESC_STRING: - switch (value & 0xff) { - case 0: /* Language table */ - ptr = "\001"; - break; - - case 1: /* Vendor */ - ptr = sc->sc_vendor; - break; - - case 2: /* Product */ - ptr = "OHCI root HUB"; - break; - - default: - ptr = ""; - break; - } - - std->len = usb2_make_str_desc - (sc->sc_hub_desc.temp, - sizeof(sc->sc_hub_desc.temp), - ptr); - break; - - default: - std->err = USB_ERR_IOERROR; - goto done; - } - break; - case C(UR_GET_INTERFACE, UT_READ_INTERFACE): - std->len = 1; - sc->sc_hub_desc.temp[0] = 0; - break; - case C(UR_GET_STATUS, UT_READ_DEVICE): - std->len = 2; - USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED); - break; - case C(UR_GET_STATUS, UT_READ_INTERFACE): - case C(UR_GET_STATUS, UT_READ_ENDPOINT): - std->len = 2; - USETW(sc->sc_hub_desc.stat.wStatus, 0); - break; - case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): - if (value >= USB_MAX_DEVICES) { - std->err = USB_ERR_IOERROR; - goto done; - } - sc->sc_addr = value; - break; - case C(UR_SET_CONFIG, UT_WRITE_DEVICE): - if ((value != 0) && (value != 1)) { - std->err = USB_ERR_IOERROR; - goto done; - } - sc->sc_conf = value; - break; - case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): - break; - case C(UR_SET_FEATURE, UT_WRITE_DEVICE): - case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): - case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): - std->err = USB_ERR_IOERROR; - goto done; - case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): - break; - case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): - break; - /* Hub requests */ - case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): - break; - case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): - DPRINTFN(9, "UR_CLEAR_PORT_FEATURE " - "port=%d feature=%d\n", - index, value); - if ((index < 1) || - (index > sc->sc_noport)) { - std->err = USB_ERR_IOERROR; - goto done; - } - port = OHCI_RH_PORT_STATUS(index); - switch (value) { - case UHF_PORT_ENABLE: - OWRITE4(sc, port, UPS_CURRENT_CONNECT_STATUS); - break; - case UHF_PORT_SUSPEND: - OWRITE4(sc, port, UPS_OVERCURRENT_INDICATOR); - break; - case UHF_PORT_POWER: - /* Yes, writing to the LOW_SPEED bit clears power. */ - OWRITE4(sc, port, UPS_LOW_SPEED); - break; - case UHF_C_PORT_CONNECTION: - OWRITE4(sc, port, UPS_C_CONNECT_STATUS << 16); - break; - case UHF_C_PORT_ENABLE: - OWRITE4(sc, port, UPS_C_PORT_ENABLED << 16); - break; - case UHF_C_PORT_SUSPEND: - OWRITE4(sc, port, UPS_C_SUSPEND << 16); - break; - case UHF_C_PORT_OVER_CURRENT: - OWRITE4(sc, port, UPS_C_OVERCURRENT_INDICATOR << 16); - break; - case UHF_C_PORT_RESET: - OWRITE4(sc, port, UPS_C_PORT_RESET << 16); - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - switch (value) { - case UHF_C_PORT_CONNECTION: - case UHF_C_PORT_ENABLE: - case UHF_C_PORT_SUSPEND: - case UHF_C_PORT_OVER_CURRENT: - case UHF_C_PORT_RESET: - /* enable RHSC interrupt if condition is cleared. */ - if ((OREAD4(sc, port) >> 16) == 0) - ohci_rhsc_enable(sc); - break; - default: - break; - } - break; - case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): - if ((value & 0xff) != 0) { - std->err = USB_ERR_IOERROR; - goto done; - } - v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); - - sc->sc_hub_desc.hubd = ohci_hubd; - sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport; - USETW(sc->sc_hub_desc.hubd.wHubCharacteristics, - (v & OHCI_NPS ? UHD_PWR_NO_SWITCH : - v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL) - /* XXX overcurrent */ - ); - sc->sc_hub_desc.hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v); - v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); - - for (l = 0; l < sc->sc_noport; l++) { - if (v & 1) { - sc->sc_hub_desc.hubd.DeviceRemovable[l / 8] |= (1 << (l % 8)); - } - v >>= 1; - } - sc->sc_hub_desc.hubd.bDescLength = - 8 + ((sc->sc_noport + 7) / 8); - std->len = sc->sc_hub_desc.hubd.bDescLength; - break; - - case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): - std->len = 16; - bzero(sc->sc_hub_desc.temp, 16); - break; - case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): - DPRINTFN(9, "get port status i=%d\n", - index); - if ((index < 1) || - (index > sc->sc_noport)) { - std->err = USB_ERR_IOERROR; - goto done; - } - v = OREAD4(sc, OHCI_RH_PORT_STATUS(index)); - DPRINTFN(9, "port status=0x%04x\n", v); - USETW(sc->sc_hub_desc.ps.wPortStatus, v); - USETW(sc->sc_hub_desc.ps.wPortChange, v >> 16); - std->len = sizeof(sc->sc_hub_desc.ps); - break; - case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): - std->err = USB_ERR_IOERROR; - goto done; - case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): - break; - case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): - if ((index < 1) || - (index > sc->sc_noport)) { - std->err = USB_ERR_IOERROR; - goto done; - } - port = OHCI_RH_PORT_STATUS(index); - switch (value) { - case UHF_PORT_ENABLE: - OWRITE4(sc, port, UPS_PORT_ENABLED); - break; - case UHF_PORT_SUSPEND: - OWRITE4(sc, port, UPS_SUSPEND); - break; - case UHF_PORT_RESET: - DPRINTFN(6, "reset port %d\n", index); - OWRITE4(sc, port, UPS_RESET); - for (v = 0;; v++) { - if (v < 12) { - if (use_polling) { - /* polling */ - DELAY(USB_PORT_ROOT_RESET_DELAY * 1000); - } else { - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_PORT_ROOT_RESET_DELAY)); - } - - if ((OREAD4(sc, port) & UPS_RESET) == 0) { - break; - } - } else { - std->err = USB_ERR_TIMEOUT; - goto done; - } - } - DPRINTFN(9, "ohci port %d reset, status = 0x%04x\n", - index, OREAD4(sc, port)); - break; - case UHF_PORT_POWER: - DPRINTFN(3, "set port power %d\n", index); - OWRITE4(sc, port, UPS_PORT_POWER); - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } -done: - return; -} - -static void -ohci_root_ctrl_poll(struct ohci_softc *sc) -{ - usb2_sw_transfer(&sc->sc_root_ctrl, - &ohci_root_ctrl_done); -} - -struct usb2_pipe_methods ohci_root_ctrl_methods = -{ - .open = ohci_root_ctrl_open, - .close = ohci_root_ctrl_close, - .enter = ohci_root_ctrl_enter, - .start = ohci_root_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 0, -}; - -/*------------------------------------------------------------------------* - * ohci root interrupt support - *------------------------------------------------------------------------*/ -static void -ohci_root_intr_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -ohci_root_intr_close(struct usb2_xfer *xfer) -{ - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_intr.xfer == xfer) { - sc->sc_root_intr.xfer = NULL; - } - ohci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -ohci_root_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -ohci_root_intr_start(struct usb2_xfer *xfer) -{ - ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); - - sc->sc_root_intr.xfer = xfer; -} - -struct usb2_pipe_methods ohci_root_intr_methods = -{ - .open = ohci_root_intr_open, - .close = ohci_root_intr_close, - .enter = ohci_root_intr_enter, - .start = ohci_root_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -static void -ohci_xfer_setup(struct usb2_setup_params *parm) -{ - struct usb2_page_search page_info; - struct usb2_page_cache *pc; - ohci_softc_t *sc; - struct usb2_xfer *xfer; - void *last_obj; - uint32_t ntd; - uint32_t nitd; - uint32_t nqh; - uint32_t n; - - sc = OHCI_BUS2SC(parm->udev->bus); - xfer = parm->curr_xfer; - - parm->hc_max_packet_size = 0x500; - parm->hc_max_packet_count = 1; - parm->hc_max_frame_size = OHCI_PAGE_SIZE; - - /* - * calculate ntd and nqh - */ - if (parm->methods == &ohci_device_ctrl_methods) { - xfer->flags_int.bdma_enable = 1; - - usb2_transfer_setup_sub(parm); - - nitd = 0; - ntd = ((2 * xfer->nframes) + 1 /* STATUS */ - + (xfer->max_data_length / xfer->max_usb2_frame_size)); - nqh = 1; - - } else if (parm->methods == &ohci_device_bulk_methods) { - xfer->flags_int.bdma_enable = 1; - - usb2_transfer_setup_sub(parm); - - nitd = 0; - ntd = ((2 * xfer->nframes) - + (xfer->max_data_length / xfer->max_usb2_frame_size)); - nqh = 1; - - } else if (parm->methods == &ohci_device_intr_methods) { - xfer->flags_int.bdma_enable = 1; - - usb2_transfer_setup_sub(parm); - - nitd = 0; - ntd = ((2 * xfer->nframes) - + (xfer->max_data_length / xfer->max_usb2_frame_size)); - nqh = 1; - - } else if (parm->methods == &ohci_device_isoc_methods) { - xfer->flags_int.bdma_enable = 1; - - usb2_transfer_setup_sub(parm); - - nitd = ((xfer->max_data_length / OHCI_PAGE_SIZE) + - ((xfer->nframes + OHCI_ITD_NOFFSET - 1) / OHCI_ITD_NOFFSET) + - 1 /* EXTRA */ ); - ntd = 0; - nqh = 1; - - } else { - - usb2_transfer_setup_sub(parm); - - nitd = 0; - ntd = 0; - nqh = 0; - } - -alloc_dma_set: - - if (parm->err) { - return; - } - last_obj = NULL; - - if (usb2_transfer_setup_sub_malloc( - parm, &pc, sizeof(ohci_td_t), - OHCI_TD_ALIGN, ntd)) { - parm->err = USB_ERR_NOMEM; - return; - } - if (parm->buf) { - for (n = 0; n != ntd; n++) { - ohci_td_t *td; - - usb2_get_page(pc + n, 0, &page_info); - - td = page_info.buffer; - - /* init TD */ - td->td_self = htole32(page_info.physaddr); - td->obj_next = last_obj; - td->page_cache = pc + n; - - last_obj = td; - - usb2_pc_cpu_flush(pc + n); - } - } - if (usb2_transfer_setup_sub_malloc( - parm, &pc, sizeof(ohci_itd_t), - OHCI_ITD_ALIGN, nitd)) { - parm->err = USB_ERR_NOMEM; - return; - } - if (parm->buf) { - for (n = 0; n != nitd; n++) { - ohci_itd_t *itd; - - usb2_get_page(pc + n, 0, &page_info); - - itd = page_info.buffer; - - /* init TD */ - itd->itd_self = htole32(page_info.physaddr); - itd->obj_next = last_obj; - itd->page_cache = pc + n; - - last_obj = itd; - - usb2_pc_cpu_flush(pc + n); - } - } - xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; - - last_obj = NULL; - - if (usb2_transfer_setup_sub_malloc( - parm, &pc, sizeof(ohci_ed_t), - OHCI_ED_ALIGN, nqh)) { - parm->err = USB_ERR_NOMEM; - return; - } - if (parm->buf) { - for (n = 0; n != nqh; n++) { - ohci_ed_t *ed; - - usb2_get_page(pc + n, 0, &page_info); - - ed = page_info.buffer; - - /* init QH */ - ed->ed_self = htole32(page_info.physaddr); - ed->obj_next = last_obj; - ed->page_cache = pc + n; - - last_obj = ed; - - usb2_pc_cpu_flush(pc + n); - } - } - xfer->qh_start[xfer->flags_int.curr_dma_set] = last_obj; - - if (!xfer->flags_int.curr_dma_set) { - xfer->flags_int.curr_dma_set = 1; - goto alloc_dma_set; - } -} - -static void -ohci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, - struct usb2_pipe *pipe) -{ - ohci_softc_t *sc = OHCI_BUS2SC(udev->bus); - - DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", - pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, - sc->sc_addr); - - if (udev->flags.usb2_mode != USB_MODE_HOST) { - /* not supported */ - return; - } - if (udev->device_index == sc->sc_addr) { - switch (edesc->bEndpointAddress) { - case USB_CONTROL_ENDPOINT: - pipe->methods = &ohci_root_ctrl_methods; - break; - case UE_DIR_IN | OHCI_INTR_ENDPT: - pipe->methods = &ohci_root_intr_methods; - break; - default: - /* do nothing */ - break; - } - } else { - switch (edesc->bmAttributes & UE_XFERTYPE) { - case UE_CONTROL: - pipe->methods = &ohci_device_ctrl_methods; - break; - case UE_INTERRUPT: - pipe->methods = &ohci_device_intr_methods; - break; - case UE_ISOCHRONOUS: - if (udev->speed == USB_SPEED_FULL) { - pipe->methods = &ohci_device_isoc_methods; - } - break; - case UE_BULK: - if (udev->speed != USB_SPEED_LOW) { - pipe->methods = &ohci_device_bulk_methods; - } - break; - default: - /* do nothing */ - break; - } - } -} - -static void -ohci_xfer_unsetup(struct usb2_xfer *xfer) -{ - return; -} - -static void -ohci_get_dma_delay(struct usb2_bus *bus, uint32_t *pus) -{ - /* - * Wait until hardware has finished any possible use of the - * transfer descriptor(s) and QH - */ - *pus = (1125); /* microseconds */ -} - -static void -ohci_device_resume(struct usb2_device *udev) -{ - struct ohci_softc *sc = OHCI_BUS2SC(udev->bus); - struct usb2_xfer *xfer; - struct usb2_pipe_methods *methods; - ohci_ed_t *ed; - - DPRINTF("\n"); - - USB_BUS_LOCK(udev->bus); - - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - - if (xfer->xroot->udev == udev) { - - methods = xfer->pipe->methods; - ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - if (methods == &ohci_device_bulk_methods) { - OHCI_APPEND_QH(ed, sc->sc_bulk_p_last); - OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); - } - if (methods == &ohci_device_ctrl_methods) { - OHCI_APPEND_QH(ed, sc->sc_ctrl_p_last); - OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); - } - if (methods == &ohci_device_intr_methods) { - OHCI_APPEND_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); - } - } - } - - USB_BUS_UNLOCK(udev->bus); - - return; -} - -static void -ohci_device_suspend(struct usb2_device *udev) -{ - struct ohci_softc *sc = OHCI_BUS2SC(udev->bus); - struct usb2_xfer *xfer; - struct usb2_pipe_methods *methods; - ohci_ed_t *ed; - - DPRINTF("\n"); - - USB_BUS_LOCK(udev->bus); - - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - - if (xfer->xroot->udev == udev) { - - methods = xfer->pipe->methods; - ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - if (methods == &ohci_device_bulk_methods) { - OHCI_REMOVE_QH(ed, sc->sc_bulk_p_last); - } - if (methods == &ohci_device_ctrl_methods) { - OHCI_REMOVE_QH(ed, sc->sc_ctrl_p_last); - } - if (methods == &ohci_device_intr_methods) { - OHCI_REMOVE_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); - } - } - } - - USB_BUS_UNLOCK(udev->bus); - - return; -} - -static void -ohci_set_hw_power(struct usb2_bus *bus) -{ - struct ohci_softc *sc = OHCI_BUS2SC(bus); - uint32_t temp; - uint32_t flags; - - DPRINTF("\n"); - - USB_BUS_LOCK(bus); - - flags = bus->hw_power_state; - - temp = OREAD4(sc, OHCI_CONTROL); - temp &= ~(OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE); - - if (flags & USB_HW_POWER_CONTROL) - temp |= OHCI_CLE; - - if (flags & USB_HW_POWER_BULK) - temp |= OHCI_BLE; - - if (flags & USB_HW_POWER_INTERRUPT) - temp |= OHCI_PLE; - - if (flags & USB_HW_POWER_ISOC) - temp |= OHCI_IE | OHCI_PLE; - - OWRITE4(sc, OHCI_CONTROL, temp); - - USB_BUS_UNLOCK(bus); - - return; -} - -struct usb2_bus_methods ohci_bus_methods = -{ - .pipe_init = ohci_pipe_init, - .xfer_setup = ohci_xfer_setup, - .xfer_unsetup = ohci_xfer_unsetup, - .do_poll = ohci_do_poll, - .get_dma_delay = ohci_get_dma_delay, - .device_resume = ohci_device_resume, - .device_suspend = ohci_device_suspend, - .set_hw_power = ohci_set_hw_power, - .roothub_exec = ohci_root_ctrl_task, -}; diff --git a/sys/dev/usb2/controller/ohci2.h b/sys/dev/usb2/controller/ohci2.h deleted file mode 100644 index 84a6afd..0000000 --- a/sys/dev/usb2/controller/ohci2.h +++ /dev/null @@ -1,366 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Lennart Augustsson (lennart@augustsson.net) at - * Carlstedt Research & Technology. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _OHCI_H_ -#define _OHCI_H_ - -#define OHCI_MAX_DEVICES USB_MAX_DEVICES - -/* PCI config registers */ -#define PCI_CBMEM 0x10 /* configuration base memory */ -#define PCI_INTERFACE_OHCI 0x10 - -/* OHCI registers */ -#define OHCI_REVISION 0x00 /* OHCI revision */ -#define OHCI_REV_LO(rev) ((rev) & 0xf) -#define OHCI_REV_HI(rev) (((rev)>>4) & 0xf) -#define OHCI_REV_LEGACY(rev) ((rev) & 0x100) -#define OHCI_CONTROL 0x04 -#define OHCI_CBSR_MASK 0x00000003 /* Control/Bulk Service Ratio */ -#define OHCI_RATIO_1_1 0x00000000 -#define OHCI_RATIO_1_2 0x00000001 -#define OHCI_RATIO_1_3 0x00000002 -#define OHCI_RATIO_1_4 0x00000003 -#define OHCI_PLE 0x00000004 /* Periodic List Enable */ -#define OHCI_IE 0x00000008 /* Isochronous Enable */ -#define OHCI_CLE 0x00000010 /* Control List Enable */ -#define OHCI_BLE 0x00000020 /* Bulk List Enable */ -#define OHCI_HCFS_MASK 0x000000c0 /* HostControllerFunctionalStat - * e */ -#define OHCI_HCFS_RESET 0x00000000 -#define OHCI_HCFS_RESUME 0x00000040 -#define OHCI_HCFS_OPERATIONAL 0x00000080 -#define OHCI_HCFS_SUSPEND 0x000000c0 -#define OHCI_IR 0x00000100 /* Interrupt Routing */ -#define OHCI_RWC 0x00000200 /* Remote Wakeup Connected */ -#define OHCI_RWE 0x00000400 /* Remote Wakeup Enabled */ -#define OHCI_COMMAND_STATUS 0x08 -#define OHCI_HCR 0x00000001 /* Host Controller Reset */ -#define OHCI_CLF 0x00000002 /* Control List Filled */ -#define OHCI_BLF 0x00000004 /* Bulk List Filled */ -#define OHCI_OCR 0x00000008 /* Ownership Change Request */ -#define OHCI_SOC_MASK 0x00030000 /* Scheduling Overrun Count */ -#define OHCI_INTERRUPT_STATUS 0x0c -#define OHCI_SO 0x00000001 /* Scheduling Overrun */ -#define OHCI_WDH 0x00000002 /* Writeback Done Head */ -#define OHCI_SF 0x00000004 /* Start of Frame */ -#define OHCI_RD 0x00000008 /* Resume Detected */ -#define OHCI_UE 0x00000010 /* Unrecoverable Error */ -#define OHCI_FNO 0x00000020 /* Frame Number Overflow */ -#define OHCI_RHSC 0x00000040 /* Root Hub Status Change */ -#define OHCI_OC 0x40000000 /* Ownership Change */ -#define OHCI_MIE 0x80000000 /* Master Interrupt Enable */ -#define OHCI_INTERRUPT_ENABLE 0x10 -#define OHCI_INTERRUPT_DISABLE 0x14 -#define OHCI_HCCA 0x18 -#define OHCI_PERIOD_CURRENT_ED 0x1c -#define OHCI_CONTROL_HEAD_ED 0x20 -#define OHCI_CONTROL_CURRENT_ED 0x24 -#define OHCI_BULK_HEAD_ED 0x28 -#define OHCI_BULK_CURRENT_ED 0x2c -#define OHCI_DONE_HEAD 0x30 -#define OHCI_FM_INTERVAL 0x34 -#define OHCI_GET_IVAL(s) ((s) & 0x3fff) -#define OHCI_GET_FSMPS(s) (((s) >> 16) & 0x7fff) -#define OHCI_FIT 0x80000000 -#define OHCI_FM_REMAINING 0x38 -#define OHCI_FM_NUMBER 0x3c -#define OHCI_PERIODIC_START 0x40 -#define OHCI_LS_THRESHOLD 0x44 -#define OHCI_RH_DESCRIPTOR_A 0x48 -#define OHCI_GET_NDP(s) ((s) & 0xff) -#define OHCI_PSM 0x0100 /* Power Switching Mode */ -#define OHCI_NPS 0x0200 /* No Power Switching */ -#define OHCI_DT 0x0400 /* Device Type */ -#define OHCI_OCPM 0x0800 /* Overcurrent Protection Mode */ -#define OHCI_NOCP 0x1000 /* No Overcurrent Protection */ -#define OHCI_GET_POTPGT(s) ((s) >> 24) -#define OHCI_RH_DESCRIPTOR_B 0x4c -#define OHCI_RH_STATUS 0x50 -#define OHCI_LPS 0x00000001 /* Local Power Status */ -#define OHCI_OCI 0x00000002 /* OverCurrent Indicator */ -#define OHCI_DRWE 0x00008000 /* Device Remote Wakeup Enable */ -#define OHCI_LPSC 0x00010000 /* Local Power Status Change */ -#define OHCI_CCIC 0x00020000 /* OverCurrent Indicator - * Change */ -#define OHCI_CRWE 0x80000000 /* Clear Remote Wakeup Enable */ -#define OHCI_RH_PORT_STATUS(n) (0x50 + ((n)*4)) /* 1 based indexing */ - -#define OHCI_LES (OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE) -#define OHCI_ALL_INTRS (OHCI_SO | OHCI_WDH | OHCI_SF | \ - OHCI_RD | OHCI_UE | OHCI_FNO | \ - OHCI_RHSC | OHCI_OC) -#define OHCI_NORMAL_INTRS (OHCI_WDH | OHCI_RD | OHCI_UE | OHCI_RHSC) - -#define OHCI_FSMPS(i) (((i-210)*6/7) << 16) -#define OHCI_PERIODIC(i) ((i)*9/10) - -#define OHCI_NO_INTRS 32 -#define OHCI_HCCA_SIZE 256 - -/* Structures alignment (bytes) */ -#define OHCI_HCCA_ALIGN 256 -#define OHCI_ED_ALIGN 16 -#define OHCI_TD_ALIGN 16 -#define OHCI_ITD_ALIGN 32 - -#define OHCI_PAGE_SIZE 0x1000 -#define OHCI_PAGE(x) ((x) &~ 0xfff) -#define OHCI_PAGE_OFFSET(x) ((x) & 0xfff) -#define OHCI_PAGE_MASK(x) ((x) & 0xfff) - -#if ((USB_PAGE_SIZE < OHCI_ED_ALIGN) || (OHCI_ED_ALIGN == 0) || \ - (USB_PAGE_SIZE < OHCI_TD_ALIGN) || (OHCI_TD_ALIGN == 0) || \ - (USB_PAGE_SIZE < OHCI_ITD_ALIGN) || (OHCI_ITD_ALIGN == 0) || \ - (USB_PAGE_SIZE < OHCI_PAGE_SIZE) || (OHCI_PAGE_SIZE == 0)) -#error "Invalid USB page size!" -#endif - -#define OHCI_VIRTUAL_FRAMELIST_COUNT 128/* dummy */ - -#if (OHCI_VIRTUAL_FRAMELIST_COUNT < USB_MAX_FS_ISOC_FRAMES_PER_XFER) -#error "maximum number of full-speed isochronous frames is higher than supported!" -#endif - -struct ohci_hcca { - volatile uint32_t hcca_interrupt_table[OHCI_NO_INTRS]; - volatile uint32_t hcca_frame_number; - volatile uint32_t hcca_done_head; -#define OHCI_DONE_INTRS 1 -} __aligned(OHCI_HCCA_ALIGN); - -typedef struct ohci_hcca ohci_hcca_t; - -struct ohci_ed { - volatile uint32_t ed_flags; -#define OHCI_ED_GET_FA(s) ((s) & 0x7f) -#define OHCI_ED_ADDRMASK 0x0000007f -#define OHCI_ED_SET_FA(s) (s) -#define OHCI_ED_GET_EN(s) (((s) >> 7) & 0xf) -#define OHCI_ED_SET_EN(s) ((s) << 7) -#define OHCI_ED_DIR_MASK 0x00001800 -#define OHCI_ED_DIR_TD 0x00000000 -#define OHCI_ED_DIR_OUT 0x00000800 -#define OHCI_ED_DIR_IN 0x00001000 -#define OHCI_ED_SPEED 0x00002000 -#define OHCI_ED_SKIP 0x00004000 -#define OHCI_ED_FORMAT_GEN 0x00000000 -#define OHCI_ED_FORMAT_ISO 0x00008000 -#define OHCI_ED_GET_MAXP(s) (((s) >> 16) & 0x07ff) -#define OHCI_ED_SET_MAXP(s) ((s) << 16) -#define OHCI_ED_MAXPMASK (0x7ff << 16) - volatile uint32_t ed_tailp; - volatile uint32_t ed_headp; -#define OHCI_HALTED 0x00000001 -#define OHCI_TOGGLECARRY 0x00000002 -#define OHCI_HEADMASK 0xfffffffc - volatile uint32_t ed_next; -/* - * Extra information needed: - */ - struct ohci_ed *next; - struct ohci_ed *prev; - struct ohci_ed *obj_next; - struct usb2_page_cache *page_cache; - uint32_t ed_self; -} __aligned(OHCI_ED_ALIGN); - -typedef struct ohci_ed ohci_ed_t; - -struct ohci_td { - volatile uint32_t td_flags; -#define OHCI_TD_R 0x00040000 /* Buffer Rounding */ -#define OHCI_TD_DP_MASK 0x00180000 /* Direction / PID */ -#define OHCI_TD_SETUP 0x00000000 -#define OHCI_TD_OUT 0x00080000 -#define OHCI_TD_IN 0x00100000 -#define OHCI_TD_GET_DI(x) (((x) >> 21) & 7) /* Delay Interrupt */ -#define OHCI_TD_SET_DI(x) ((x) << 21) -#define OHCI_TD_NOINTR 0x00e00000 -#define OHCI_TD_INTR_MASK 0x00e00000 -#define OHCI_TD_TOGGLE_CARRY 0x00000000 -#define OHCI_TD_TOGGLE_0 0x02000000 -#define OHCI_TD_TOGGLE_1 0x03000000 -#define OHCI_TD_TOGGLE_MASK 0x03000000 -#define OHCI_TD_GET_EC(x) (((x) >> 26) & 3) /* Error Count */ -#define OHCI_TD_GET_CC(x) ((x) >> 28) /* Condition Code */ -#define OHCI_TD_SET_CC(x) ((x) << 28) -#define OHCI_TD_NOCC 0xf0000000 - volatile uint32_t td_cbp; /* Current Buffer Pointer */ - volatile uint32_t td_next; /* Next TD */ -#define OHCI_TD_NEXT_END 0 - volatile uint32_t td_be; /* Buffer End */ -/* - * Extra information needed: - */ - struct ohci_td *obj_next; - struct ohci_td *alt_next; - struct usb2_page_cache *page_cache; - uint32_t td_self; - uint16_t len; -} __aligned(OHCI_TD_ALIGN); - -typedef struct ohci_td ohci_td_t; - -struct ohci_itd { - volatile uint32_t itd_flags; -#define OHCI_ITD_GET_SF(x) ((x) & 0x0000ffff) -#define OHCI_ITD_SET_SF(x) ((x) & 0xffff) -#define OHCI_ITD_GET_DI(x) (((x) >> 21) & 7) /* Delay Interrupt */ -#define OHCI_ITD_SET_DI(x) ((x) << 21) -#define OHCI_ITD_NOINTR 0x00e00000 -#define OHCI_ITD_GET_FC(x) ((((x) >> 24) & 7)+1) /* Frame Count */ -#define OHCI_ITD_SET_FC(x) (((x)-1) << 24) -#define OHCI_ITD_GET_CC(x) ((x) >> 28) /* Condition Code */ -#define OHCI_ITD_NOCC 0xf0000000 -#define OHCI_ITD_NOFFSET 8 - volatile uint32_t itd_bp0; /* Buffer Page 0 */ - volatile uint32_t itd_next; /* Next ITD */ - volatile uint32_t itd_be; /* Buffer End */ - volatile uint16_t itd_offset[OHCI_ITD_NOFFSET]; /* Buffer offsets and - * Status */ -#define OHCI_ITD_PAGE_SELECT 0x00001000 -#define OHCI_ITD_MK_OFFS(len) (0xe000 | ((len) & 0x1fff)) -#define OHCI_ITD_PSW_LENGTH(x) ((x) & 0xfff) /* Transfer length */ -#define OHCI_ITD_PSW_GET_CC(x) ((x) >> 12) /* Condition Code */ -/* - * Extra information needed: - */ - struct ohci_itd *obj_next; - struct usb2_page_cache *page_cache; - uint32_t itd_self; - uint8_t frames; -} __aligned(OHCI_ITD_ALIGN); - -typedef struct ohci_itd ohci_itd_t; - -#define OHCI_CC_NO_ERROR 0 -#define OHCI_CC_CRC 1 -#define OHCI_CC_BIT_STUFFING 2 -#define OHCI_CC_DATA_TOGGLE_MISMATCH 3 -#define OHCI_CC_STALL 4 -#define OHCI_CC_DEVICE_NOT_RESPONDING 5 -#define OHCI_CC_PID_CHECK_FAILURE 6 -#define OHCI_CC_UNEXPECTED_PID 7 -#define OHCI_CC_DATA_OVERRUN 8 -#define OHCI_CC_DATA_UNDERRUN 9 -#define OHCI_CC_BUFFER_OVERRUN 12 -#define OHCI_CC_BUFFER_UNDERRUN 13 -#define OHCI_CC_NOT_ACCESSED 15 - -/* Some delay needed when changing certain registers. */ -#define OHCI_ENABLE_POWER_DELAY 5 -#define OHCI_READ_DESC_DELAY 5 - -#define OHCI_NO_EDS (2*OHCI_NO_INTRS) - -struct ohci_hw_softc { - struct usb2_page_cache hcca_pc; - struct usb2_page_cache ctrl_start_pc; - struct usb2_page_cache bulk_start_pc; - struct usb2_page_cache isoc_start_pc; - struct usb2_page_cache intr_start_pc[OHCI_NO_EDS]; - - struct usb2_page hcca_pg; - struct usb2_page ctrl_start_pg; - struct usb2_page bulk_start_pg; - struct usb2_page isoc_start_pg; - struct usb2_page intr_start_pg[OHCI_NO_EDS]; -}; - -struct ohci_config_desc { - struct usb2_config_descriptor confd; - struct usb2_interface_descriptor ifcd; - struct usb2_endpoint_descriptor endpd; -} __packed; - -union ohci_hub_desc { - struct usb2_status stat; - struct usb2_port_status ps; - struct usb2_device_descriptor devd; - struct usb2_hub_descriptor hubd; - uint8_t temp[128]; -}; - -typedef struct ohci_softc { - struct ohci_hw_softc sc_hw; - struct usb2_bus sc_bus; /* base device */ - struct usb2_callout sc_tmo_rhsc; - union ohci_hub_desc sc_hub_desc; - struct usb2_sw_transfer sc_root_ctrl; - struct usb2_sw_transfer sc_root_intr; - - struct usb2_device *sc_devices[OHCI_MAX_DEVICES]; - struct resource *sc_io_res; - struct resource *sc_irq_res; - struct ohci_hcca *sc_hcca_p; - struct ohci_ed *sc_ctrl_p_last; - struct ohci_ed *sc_bulk_p_last; - struct ohci_ed *sc_isoc_p_last; - struct ohci_ed *sc_intr_p_last[OHCI_NO_EDS]; - void *sc_intr_hdl; - device_t sc_dev; - bus_size_t sc_io_size; - bus_space_tag_t sc_io_tag; - bus_space_handle_t sc_io_hdl; - - uint32_t sc_eintrs; /* enabled interrupts */ - uint32_t sc_control; /* Preserved during suspend/standby */ - uint32_t sc_intre; - - uint16_t sc_intr_stat[OHCI_NO_EDS]; - uint16_t sc_id_vendor; - - uint8_t sc_noport; - uint8_t sc_addr; /* device address */ - uint8_t sc_conf; /* device configuration */ - uint8_t sc_hub_idata[32]; - - char sc_vendor[16]; - -} ohci_softc_t; - -usb2_bus_mem_cb_t ohci_iterate_hw_softc; - -usb2_error_t ohci_init(ohci_softc_t *sc); -void ohci_detach(struct ohci_softc *sc); -void ohci_suspend(ohci_softc_t *sc); -void ohci_resume(ohci_softc_t *sc); -void ohci_interrupt(ohci_softc_t *sc); - -#endif /* _OHCI_H_ */ diff --git a/sys/dev/usb2/controller/ohci2_atmelarm.c b/sys/dev/usb2/controller/ohci2_atmelarm.c deleted file mode 100644 index a7f086c..0000000 --- a/sys/dev/usb2/controller/ohci2_atmelarm.c +++ /dev/null @@ -1,224 +0,0 @@ -/*- - * Copyright (c) 2006 M. Warner Losh. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_defs.h> -#include <dev/usb2/include/usb2_standard.h> - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/ohci2.h> - -#include <sys/rman.h> - -#include <arm/at91/at91_pmcvar.h> - -#define MEM_RID 0 - -static device_probe_t ohci_atmelarm_probe; -static device_attach_t ohci_atmelarm_attach; -static device_detach_t ohci_atmelarm_detach; - -struct at91_ohci_softc { - struct ohci_softc sc_ohci; /* must be first */ - struct at91_pmc_clock *iclk; - struct at91_pmc_clock *fclk; -}; - -static int -ohci_atmelarm_probe(device_t dev) -{ - device_set_desc(dev, "AT91 integrated OHCI controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -ohci_atmelarm_attach(device_t dev) -{ - struct at91_ohci_softc *sc = device_get_softc(dev); - int err; - int rid; - - /* initialise some bus fields */ - sc->sc_ohci.sc_bus.parent = dev; - sc->sc_ohci.sc_bus.devices = sc->sc_ohci.sc_devices; - sc->sc_ohci.sc_bus.devices_max = OHCI_MAX_DEVICES; - - /* get all DMA memory */ - if (usb2_bus_mem_alloc_all(&sc->sc_ohci.sc_bus, - USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { - return (ENOMEM); - } - sc->iclk = at91_pmc_clock_ref("ohci_clk"); - sc->fclk = at91_pmc_clock_ref("uhpck"); - - sc->sc_ohci.sc_dev = dev; - - rid = MEM_RID; - sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &rid, RF_ACTIVE); - - if (!(sc->sc_ohci.sc_io_res)) { - err = ENOMEM; - goto error; - } - sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res); - sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res); - sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res); - - rid = 0; - sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE); - if (!(sc->sc_ohci.sc_irq_res)) { - goto error; - } - sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1); - if (!(sc->sc_ohci.sc_bus.bdev)) { - goto error; - } - device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus); - - strlcpy(sc->sc_ohci.sc_vendor, "Atmel", sizeof(sc->sc_ohci.sc_vendor)); - -#if (__FreeBSD_version >= 700031) - err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); -#else - err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); -#endif - if (err) { - sc->sc_ohci.sc_intr_hdl = NULL; - goto error; - } - /* - * turn on the clocks from the AT91's point of view. Keep the unit in reset. - */ - at91_pmc_clock_enable(sc->iclk); - at91_pmc_clock_enable(sc->fclk); - bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, - OHCI_CONTROL, 0); - - err = ohci_init(&sc->sc_ohci); - if (!err) { - err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev); - } - if (err) { - goto error; - } - return (0); - -error: - ohci_atmelarm_detach(dev); - return (ENXIO); -} - -static int -ohci_atmelarm_detach(device_t dev) -{ - struct at91_ohci_softc *sc = device_get_softc(dev); - device_t bdev; - int err; - - if (sc->sc_ohci.sc_bus.bdev) { - bdev = sc->sc_ohci.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } - /* during module unload there are lots of children leftover */ - device_delete_all_children(dev); - - /* - * Put the controller into reset, then disable clocks and do - * the MI tear down. We have to disable the clocks/hardware - * after we do the rest of the teardown. We also disable the - * clocks in the opposite order we acquire them, but that - * doesn't seem to be absolutely necessary. We free up the - * clocks after we disable them, so the system could, in - * theory, reuse them. - */ - bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, - OHCI_CONTROL, 0); - - at91_pmc_clock_disable(sc->fclk); - at91_pmc_clock_disable(sc->iclk); - at91_pmc_clock_deref(sc->fclk); - at91_pmc_clock_deref(sc->iclk); - - if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) { - /* - * only call ohci_detach() after ohci_init() - */ - ohci_detach(&sc->sc_ohci); - - err = bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl); - sc->sc_ohci.sc_intr_hdl = NULL; - } - if (sc->sc_ohci.sc_irq_res) { - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res); - sc->sc_ohci.sc_irq_res = NULL; - } - if (sc->sc_ohci.sc_io_res) { - bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, - sc->sc_ohci.sc_io_res); - sc->sc_ohci.sc_io_res = NULL; - } - usb2_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc); - - return (0); -} - -static device_method_t ohci_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, ohci_atmelarm_probe), - DEVMETHOD(device_attach, ohci_atmelarm_attach), - DEVMETHOD(device_detach, ohci_atmelarm_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - {0, 0} -}; - -static driver_t ohci_driver = { - "ohci", - ohci_methods, - sizeof(struct at91_ohci_softc), -}; - -static devclass_t ohci_devclass; - -DRIVER_MODULE(ohci, atmelarm, ohci_driver, ohci_devclass, 0, 0); -MODULE_DEPEND(ohci, usb2_controller, 1, 1, 1); -MODULE_DEPEND(ohci, usb2_core, 1, 1, 1); diff --git a/sys/dev/usb2/controller/ohci2_pci.c b/sys/dev/usb2/controller/ohci2_pci.c deleted file mode 100644 index 7d3506e..0000000 --- a/sys/dev/usb2/controller/ohci2_pci.c +++ /dev/null @@ -1,388 +0,0 @@ -/*- - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Lennart Augustsson (augustss@carlstedt.se) at - * Carlstedt Research & Technology. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* - * USB Open Host Controller driver. - * - * OHCI spec: http://www.intel.com/design/usb/ohci11d.pdf - */ - -/* The low level controller code for OHCI has been split into - * PCI probes and OHCI specific code. This was done to facilitate the - * sharing of code between *BSD's - */ - -#include <dev/usb2/include/usb2_standard.h> -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_error.h> -#include <dev/usb2/include/usb2_defs.h> - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/usb2_pci.h> -#include <dev/usb2/controller/ohci2.h> - -#define PCI_OHCI_VENDORID_ACERLABS 0x10b9 -#define PCI_OHCI_VENDORID_AMD 0x1022 -#define PCI_OHCI_VENDORID_APPLE 0x106b -#define PCI_OHCI_VENDORID_ATI 0x1002 -#define PCI_OHCI_VENDORID_CMDTECH 0x1095 -#define PCI_OHCI_VENDORID_NEC 0x1033 -#define PCI_OHCI_VENDORID_NVIDIA 0x12D2 -#define PCI_OHCI_VENDORID_NVIDIA2 0x10DE -#define PCI_OHCI_VENDORID_OPTI 0x1045 -#define PCI_OHCI_VENDORID_SIS 0x1039 -#define PCI_OHCI_VENDORID_SUN 0x108e - -#define PCI_OHCI_BASE_REG 0x10 - -static device_probe_t ohci_pci_probe; -static device_attach_t ohci_pci_attach; -static device_detach_t ohci_pci_detach; -static device_suspend_t ohci_pci_suspend; -static device_resume_t ohci_pci_resume; - -static int -ohci_pci_suspend(device_t self) -{ - ohci_softc_t *sc = device_get_softc(self); - int err; - - err = bus_generic_suspend(self); - if (err) { - return (err); - } - ohci_suspend(sc); - return (0); -} - -static int -ohci_pci_resume(device_t self) -{ - ohci_softc_t *sc = device_get_softc(self); - uint32_t reg, int_line; - - if (pci_get_powerstate(self) != PCI_POWERSTATE_D0) { - device_printf(self, "chip is in D%d mode " - "-- setting to D0\n", pci_get_powerstate(self)); - reg = pci_read_config(self, PCI_CBMEM, 4); - int_line = pci_read_config(self, PCIR_INTLINE, 4); - pci_set_powerstate(self, PCI_POWERSTATE_D0); - pci_write_config(self, PCI_CBMEM, reg, 4); - pci_write_config(self, PCIR_INTLINE, int_line, 4); - } - ohci_resume(sc); - - bus_generic_resume(self); - return (0); -} - -static const char * -ohci_pci_match(device_t self) -{ - uint32_t device_id = pci_get_devid(self); - - switch (device_id) { - case 0x523710b9: - return ("AcerLabs M5237 (Aladdin-V) USB controller"); - - case 0x740c1022: - return ("AMD-756 USB Controller"); - - case 0x74141022: - return ("AMD-766 USB Controller"); - - case 0x43741002: - return "ATI SB400 USB Controller"; - case 0x43751002: - return "ATI SB400 USB Controller"; - - case 0x06701095: - return ("CMD Tech 670 (USB0670) USB controller"); - - case 0x06731095: - return ("CMD Tech 673 (USB0673) USB controller"); - - case 0xc8611045: - return ("OPTi 82C861 (FireLink) USB controller"); - - case 0x00351033: - return ("NEC uPD 9210 USB controller"); - - case 0x00d710de: - return ("nVidia nForce3 USB Controller"); - - case 0x70011039: - return ("SiS 5571 USB controller"); - - case 0x1103108e: - return "Sun PCIO-2 USB controller"; - - case 0x0019106b: - return ("Apple KeyLargo USB controller"); - - default: - break; - } - if ((pci_get_class(self) == PCIC_SERIALBUS) && - (pci_get_subclass(self) == PCIS_SERIALBUS_USB) && - (pci_get_progif(self) == PCI_INTERFACE_OHCI)) { - return ("OHCI (generic) USB controller"); - } - return (NULL); -} - -static int -ohci_pci_probe(device_t self) -{ - const char *desc = ohci_pci_match(self); - - if (desc) { - device_set_desc(self, desc); - return (0); - } else { - return (ENXIO); - } -} - -static int -ohci_pci_attach(device_t self) -{ - ohci_softc_t *sc = device_get_softc(self); - int rid; - int err; - - /* initialise some bus fields */ - sc->sc_bus.parent = self; - sc->sc_bus.devices = sc->sc_devices; - sc->sc_bus.devices_max = OHCI_MAX_DEVICES; - - /* get all DMA memory */ - if (usb2_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(self), - &ohci_iterate_hw_softc)) { - return (ENOMEM); - } - sc->sc_dev = self; - - pci_enable_busmaster(self); - - /* - * Some Sun PCIO-2 USB controllers have their intpin register - * bogusly set to 0, although it should be 4. Correct that. - */ - if (pci_get_devid(self) == 0x1103108e && pci_get_intpin(self) == 0) - pci_set_intpin(self, 4); - - rid = PCI_CBMEM; - sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, - RF_ACTIVE); - if (!sc->sc_io_res) { - device_printf(self, "Could not map memory\n"); - goto error; - } - sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); - sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); - sc->sc_io_size = rman_get_size(sc->sc_io_res); - - rid = 0; - sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (sc->sc_irq_res == NULL) { - device_printf(self, "Could not allocate irq\n"); - goto error; - } - sc->sc_bus.bdev = device_add_child(self, "usbus", -1); - if (!sc->sc_bus.bdev) { - device_printf(self, "Could not add USB device\n"); - goto error; - } - device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); - - /* - * ohci_pci_match will never return NULL if ohci_pci_probe - * succeeded - */ - device_set_desc(sc->sc_bus.bdev, ohci_pci_match(self)); - switch (pci_get_vendor(self)) { - case PCI_OHCI_VENDORID_ACERLABS: - sprintf(sc->sc_vendor, "AcerLabs"); - break; - case PCI_OHCI_VENDORID_AMD: - sprintf(sc->sc_vendor, "AMD"); - break; - case PCI_OHCI_VENDORID_APPLE: - sprintf(sc->sc_vendor, "Apple"); - break; - case PCI_OHCI_VENDORID_ATI: - sprintf(sc->sc_vendor, "ATI"); - break; - case PCI_OHCI_VENDORID_CMDTECH: - sprintf(sc->sc_vendor, "CMDTECH"); - break; - case PCI_OHCI_VENDORID_NEC: - sprintf(sc->sc_vendor, "NEC"); - break; - case PCI_OHCI_VENDORID_NVIDIA: - case PCI_OHCI_VENDORID_NVIDIA2: - sprintf(sc->sc_vendor, "nVidia"); - break; - case PCI_OHCI_VENDORID_OPTI: - sprintf(sc->sc_vendor, "OPTi"); - break; - case PCI_OHCI_VENDORID_SIS: - sprintf(sc->sc_vendor, "SiS"); - break; - case PCI_OHCI_VENDORID_SUN: - sprintf(sc->sc_vendor, "SUN"); - break; - default: - if (bootverbose) { - device_printf(self, "(New OHCI DeviceId=0x%08x)\n", - pci_get_devid(self)); - } - sprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self)); - } - - /* sc->sc_bus.usbrev; set by ohci_init() */ - -#if (__FreeBSD_version >= 700031) - err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)(void *)ohci_interrupt, sc, &sc->sc_intr_hdl); -#else - err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)(void *)ohci_interrupt, sc, &sc->sc_intr_hdl); -#endif - if (err) { - device_printf(self, "Could not setup irq, %d\n", err); - sc->sc_intr_hdl = NULL; - goto error; - } - err = ohci_init(sc); - if (!err) { - err = device_probe_and_attach(sc->sc_bus.bdev); - } - if (err) { - device_printf(self, "USB init failed\n"); - goto error; - } - return (0); - -error: - ohci_pci_detach(self); - return (ENXIO); -} - -static int -ohci_pci_detach(device_t self) -{ - ohci_softc_t *sc = device_get_softc(self); - device_t bdev; - - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } - /* during module unload there are lots of children leftover */ - device_delete_all_children(self); - - pci_disable_busmaster(self); - - if (sc->sc_irq_res && sc->sc_intr_hdl) { - /* - * only call ohci_detach() after ohci_init() - */ - ohci_detach(sc); - - int err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); - - if (err) { - /* XXX or should we panic? */ - device_printf(self, "Could not tear down irq, %d\n", - err); - } - sc->sc_intr_hdl = NULL; - } - if (sc->sc_irq_res) { - bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); - sc->sc_irq_res = NULL; - } - if (sc->sc_io_res) { - bus_release_resource(self, SYS_RES_MEMORY, PCI_CBMEM, - sc->sc_io_res); - sc->sc_io_res = NULL; - } - usb2_bus_mem_free_all(&sc->sc_bus, &ohci_iterate_hw_softc); - - return (0); -} - -static driver_t ohci_driver = -{ - .name = "ohci", - .methods = (device_method_t[]){ - /* device interface */ - DEVMETHOD(device_probe, ohci_pci_probe), - DEVMETHOD(device_attach, ohci_pci_attach), - DEVMETHOD(device_detach, ohci_pci_detach), - DEVMETHOD(device_suspend, ohci_pci_suspend), - DEVMETHOD(device_resume, ohci_pci_resume), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - - /* bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - {0, 0} - }, - .size = sizeof(struct ohci_softc), -}; - -static devclass_t ohci_devclass; - -DRIVER_MODULE(ohci, pci, ohci_driver, ohci_devclass, 0, 0); -DRIVER_MODULE(ohci, cardbus, ohci_driver, ohci_devclass, 0, 0); -MODULE_DEPEND(ohci, usb2_controller, 1, 1, 1); -MODULE_DEPEND(ohci, usb2_core, 1, 1, 1); diff --git a/sys/dev/usb2/controller/uhci2.c b/sys/dev/usb2/controller/uhci2.c deleted file mode 100644 index a5af720..0000000 --- a/sys/dev/usb2/controller/uhci2.c +++ /dev/null @@ -1,3381 +0,0 @@ -/*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. - * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. - * Copyright (c) 1998 Lennart Augustsson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* - * USB Universal Host Controller driver. - * Handles e.g. PIIX3 and PIIX4. - * - * UHCI spec: http://developer.intel.com/design/USB/UHCI11D.htm - * USB spec: http://www.usb.org/developers/docs/usbspec.zip - * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf - * ftp://download.intel.com/design/intarch/datashts/29056201.pdf - */ - -#include <dev/usb2/include/usb2_standard.h> -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_error.h> -#include <dev/usb2/include/usb2_defs.h> - -#define USB_DEBUG_VAR uhcidebug - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_debug.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_transfer.h> -#include <dev/usb2/core/usb2_device.h> -#include <dev/usb2/core/usb2_hub.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/uhci2.h> - -#define alt_next next -#define UHCI_BUS2SC(bus) ((uhci_softc_t *)(((uint8_t *)(bus)) - \ - USB_P2U(&(((uhci_softc_t *)0)->sc_bus)))) - -#if USB_DEBUG -static int uhcidebug = 0; -static int uhcinoloop = 0; - -SYSCTL_NODE(_hw_usb2, OID_AUTO, uhci, CTLFLAG_RW, 0, "USB uhci"); -SYSCTL_INT(_hw_usb2_uhci, OID_AUTO, debug, CTLFLAG_RW, - &uhcidebug, 0, "uhci debug level"); -SYSCTL_INT(_hw_usb2_uhci, OID_AUTO, loop, CTLFLAG_RW, - &uhcinoloop, 0, "uhci noloop"); -static void uhci_dumpregs(uhci_softc_t *sc); -static void uhci_dump_tds(uhci_td_t *td); - -#endif - -#define UBARR(sc) bus_space_barrier((sc)->sc_io_tag, (sc)->sc_io_hdl, 0, (sc)->sc_io_size, \ - BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) -#define UWRITE1(sc, r, x) \ - do { UBARR(sc); bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); \ - } while (/*CONSTCOND*/0) -#define UWRITE2(sc, r, x) \ - do { UBARR(sc); bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); \ - } while (/*CONSTCOND*/0) -#define UWRITE4(sc, r, x) \ - do { UBARR(sc); bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); \ - } while (/*CONSTCOND*/0) -#define UREAD1(sc, r) (UBARR(sc), bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) -#define UREAD2(sc, r) (UBARR(sc), bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) -#define UREAD4(sc, r) (UBARR(sc), bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) - -#define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd) -#define UHCISTS(sc) UREAD2(sc, UHCI_STS) - -#define UHCI_RESET_TIMEOUT 100 /* ms, reset timeout */ - -#define UHCI_INTR_ENDPT 1 - -struct uhci_mem_layout { - - struct usb2_page_search buf_res; - struct usb2_page_search fix_res; - - struct usb2_page_cache *buf_pc; - struct usb2_page_cache *fix_pc; - - uint32_t buf_offset; - - uint16_t max_frame_size; -}; - -struct uhci_std_temp { - - struct uhci_mem_layout ml; - uhci_td_t *td; - uhci_td_t *td_next; - uint32_t average; - uint32_t td_status; - uint32_t td_token; - uint32_t len; - uint16_t max_frame_size; - uint8_t shortpkt; - uint8_t setup_alt_next; - uint8_t short_frames_ok; -}; - -extern struct usb2_bus_methods uhci_bus_methods; -extern struct usb2_pipe_methods uhci_device_bulk_methods; -extern struct usb2_pipe_methods uhci_device_ctrl_methods; -extern struct usb2_pipe_methods uhci_device_intr_methods; -extern struct usb2_pipe_methods uhci_device_isoc_methods; -extern struct usb2_pipe_methods uhci_root_ctrl_methods; -extern struct usb2_pipe_methods uhci_root_intr_methods; - -static void uhci_root_ctrl_poll(struct uhci_softc *); -static void uhci_do_poll(struct usb2_bus *); -static void uhci_device_done(struct usb2_xfer *, usb2_error_t); -static void uhci_transfer_intr_enqueue(struct usb2_xfer *); -static void uhci_root_intr_check(void *); -static void uhci_timeout(void *); -static uint8_t uhci_check_transfer(struct usb2_xfer *); - -void -uhci_iterate_hw_softc(struct usb2_bus *bus, usb2_bus_mem_sub_cb_t *cb) -{ - struct uhci_softc *sc = UHCI_BUS2SC(bus); - uint32_t i; - - cb(bus, &sc->sc_hw.pframes_pc, &sc->sc_hw.pframes_pg, - sizeof(uint32_t) * UHCI_FRAMELIST_COUNT, UHCI_FRAMELIST_ALIGN); - - cb(bus, &sc->sc_hw.ls_ctl_start_pc, &sc->sc_hw.ls_ctl_start_pg, - sizeof(uhci_qh_t), UHCI_QH_ALIGN); - - cb(bus, &sc->sc_hw.fs_ctl_start_pc, &sc->sc_hw.fs_ctl_start_pg, - sizeof(uhci_qh_t), UHCI_QH_ALIGN); - - cb(bus, &sc->sc_hw.bulk_start_pc, &sc->sc_hw.bulk_start_pg, - sizeof(uhci_qh_t), UHCI_QH_ALIGN); - - cb(bus, &sc->sc_hw.last_qh_pc, &sc->sc_hw.last_qh_pg, - sizeof(uhci_qh_t), UHCI_QH_ALIGN); - - cb(bus, &sc->sc_hw.last_td_pc, &sc->sc_hw.last_td_pg, - sizeof(uhci_td_t), UHCI_TD_ALIGN); - - for (i = 0; i != UHCI_VFRAMELIST_COUNT; i++) { - cb(bus, sc->sc_hw.isoc_start_pc + i, - sc->sc_hw.isoc_start_pg + i, - sizeof(uhci_td_t), UHCI_TD_ALIGN); - } - - for (i = 0; i != UHCI_IFRAMELIST_COUNT; i++) { - cb(bus, sc->sc_hw.intr_start_pc + i, - sc->sc_hw.intr_start_pg + i, - sizeof(uhci_qh_t), UHCI_QH_ALIGN); - } -} - -static void -uhci_mem_layout_init(struct uhci_mem_layout *ml, struct usb2_xfer *xfer) -{ - ml->buf_pc = xfer->frbuffers + 0; - ml->fix_pc = xfer->buf_fixup; - - ml->buf_offset = 0; - - ml->max_frame_size = xfer->max_frame_size; -} - -static void -uhci_mem_layout_fixup(struct uhci_mem_layout *ml, struct uhci_td *td) -{ - usb2_get_page(ml->buf_pc, ml->buf_offset, &ml->buf_res); - - if (ml->buf_res.length < td->len) { - - /* need to do a fixup */ - - usb2_get_page(ml->fix_pc, 0, &ml->fix_res); - - td->td_buffer = htole32(ml->fix_res.physaddr); - - /* - * The UHCI driver cannot handle - * page crossings, so a fixup is - * needed: - * - * +----+----+ - - - - * | YYY|Y | - * +----+----+ - - - - * \ \ - * \ \ - * +----+ - * |YYYY| (fixup) - * +----+ - */ - - if ((td->td_token & htole32(UHCI_TD_PID)) == - htole32(UHCI_TD_PID_IN)) { - td->fix_pc = ml->fix_pc; - usb2_pc_cpu_invalidate(ml->fix_pc); - - } else { - td->fix_pc = NULL; - - /* copy data to fixup location */ - - usb2_copy_out(ml->buf_pc, ml->buf_offset, - ml->fix_res.buffer, td->len); - - usb2_pc_cpu_flush(ml->fix_pc); - } - - /* prepare next fixup */ - - ml->fix_pc++; - - } else { - - td->td_buffer = htole32(ml->buf_res.physaddr); - td->fix_pc = NULL; - } - - /* prepare next data location */ - - ml->buf_offset += td->len; -} - -void -uhci_reset(uhci_softc_t *sc) -{ - struct usb2_page_search buf_res; - uint16_t n; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - DPRINTF("resetting the HC\n"); - - /* disable interrupts */ - - UWRITE2(sc, UHCI_INTR, 0); - - /* global reset */ - - UHCICMD(sc, UHCI_CMD_GRESET); - - /* wait */ - - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_BUS_RESET_DELAY)); - - /* terminate all transfers */ - - UHCICMD(sc, UHCI_CMD_HCRESET); - - /* the reset bit goes low when the controller is done */ - - n = UHCI_RESET_TIMEOUT; - while (n--) { - /* wait one millisecond */ - - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); - - if (!(UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET)) { - goto done_1; - } - } - - device_printf(sc->sc_bus.bdev, - "controller did not reset\n"); - -done_1: - - n = 10; - while (n--) { - /* wait one millisecond */ - - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); - - /* check if HC is stopped */ - if (UREAD2(sc, UHCI_STS) & UHCI_STS_HCH) { - goto done_2; - } - } - - device_printf(sc->sc_bus.bdev, - "controller did not stop\n"); - -done_2: - - /* reload the configuration */ - usb2_get_page(&sc->sc_hw.pframes_pc, 0, &buf_res); - UWRITE4(sc, UHCI_FLBASEADDR, buf_res.physaddr); - UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum); - UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof); -} - -static void -uhci_start(uhci_softc_t *sc) -{ - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - DPRINTFN(2, "enabling\n"); - - /* enable interrupts */ - - UWRITE2(sc, UHCI_INTR, - (UHCI_INTR_TOCRCIE | - UHCI_INTR_RIE | - UHCI_INTR_IOCE | - UHCI_INTR_SPIE)); - - /* - * assume 64 byte packets at frame end and start HC controller - */ - - UHCICMD(sc, (UHCI_CMD_MAXP | UHCI_CMD_RS)); - - uint8_t n = 10; - - while (n--) { - /* wait one millisecond */ - - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); - - /* check that controller has started */ - - if (!(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH)) { - goto done; - } - } - - device_printf(sc->sc_bus.bdev, - "cannot start HC controller\n"); - -done: - return; -} - -static struct uhci_qh * -uhci_init_qh(struct usb2_page_cache *pc) -{ - struct usb2_page_search buf_res; - struct uhci_qh *qh; - - usb2_get_page(pc, 0, &buf_res); - - qh = buf_res.buffer; - - qh->qh_self = - htole32(buf_res.physaddr) | - htole32(UHCI_PTR_QH); - - qh->page_cache = pc; - - return (qh); -} - -static struct uhci_td * -uhci_init_td(struct usb2_page_cache *pc) -{ - struct usb2_page_search buf_res; - struct uhci_td *td; - - usb2_get_page(pc, 0, &buf_res); - - td = buf_res.buffer; - - td->td_self = - htole32(buf_res.physaddr) | - htole32(UHCI_PTR_TD); - - td->page_cache = pc; - - return (td); -} - -usb2_error_t -uhci_init(uhci_softc_t *sc) -{ - uint16_t bit; - uint16_t x; - uint16_t y; - - DPRINTF("start\n"); - -#if USB_DEBUG - if (uhcidebug > 2) { - uhci_dumpregs(sc); - } -#endif - - sc->sc_saved_sof = 0x40; /* default value */ - sc->sc_saved_frnum = 0; /* default frame number */ - - /* - * Setup QH's - */ - sc->sc_ls_ctl_p_last = - uhci_init_qh(&sc->sc_hw.ls_ctl_start_pc); - - sc->sc_fs_ctl_p_last = - uhci_init_qh(&sc->sc_hw.fs_ctl_start_pc); - - sc->sc_bulk_p_last = - uhci_init_qh(&sc->sc_hw.bulk_start_pc); -#if 0 - sc->sc_reclaim_qh_p = - sc->sc_fs_ctl_p_last; -#else - /* setup reclaim looping point */ - sc->sc_reclaim_qh_p = - sc->sc_bulk_p_last; -#endif - - sc->sc_last_qh_p = - uhci_init_qh(&sc->sc_hw.last_qh_pc); - - sc->sc_last_td_p = - uhci_init_td(&sc->sc_hw.last_td_pc); - - for (x = 0; x != UHCI_VFRAMELIST_COUNT; x++) { - sc->sc_isoc_p_last[x] = - uhci_init_td(sc->sc_hw.isoc_start_pc + x); - } - - for (x = 0; x != UHCI_IFRAMELIST_COUNT; x++) { - sc->sc_intr_p_last[x] = - uhci_init_qh(sc->sc_hw.intr_start_pc + x); - } - - /* - * the QHs are arranged to give poll intervals that are - * powers of 2 times 1ms - */ - bit = UHCI_IFRAMELIST_COUNT / 2; - while (bit) { - x = bit; - while (x & bit) { - uhci_qh_t *qh_x; - uhci_qh_t *qh_y; - - y = (x ^ bit) | (bit / 2); - - /* - * the next QH has half the poll interval - */ - qh_x = sc->sc_intr_p_last[x]; - qh_y = sc->sc_intr_p_last[y]; - - qh_x->h_next = NULL; - qh_x->qh_h_next = qh_y->qh_self; - qh_x->e_next = NULL; - qh_x->qh_e_next = htole32(UHCI_PTR_T); - x++; - } - bit >>= 1; - } - - if (1) { - uhci_qh_t *qh_ls; - uhci_qh_t *qh_intr; - - qh_ls = sc->sc_ls_ctl_p_last; - qh_intr = sc->sc_intr_p_last[0]; - - /* start QH for interrupt traffic */ - qh_intr->h_next = qh_ls; - qh_intr->qh_h_next = qh_ls->qh_self; - qh_intr->e_next = 0; - qh_intr->qh_e_next = htole32(UHCI_PTR_T); - } - for (x = 0; x != UHCI_VFRAMELIST_COUNT; x++) { - - uhci_td_t *td_x; - uhci_qh_t *qh_intr; - - td_x = sc->sc_isoc_p_last[x]; - qh_intr = sc->sc_intr_p_last[x | (UHCI_IFRAMELIST_COUNT / 2)]; - - /* start TD for isochronous traffic */ - td_x->next = NULL; - td_x->td_next = qh_intr->qh_self; - td_x->td_status = htole32(UHCI_TD_IOS); - td_x->td_token = htole32(0); - td_x->td_buffer = htole32(0); - } - - if (1) { - uhci_qh_t *qh_ls; - uhci_qh_t *qh_fs; - - qh_ls = sc->sc_ls_ctl_p_last; - qh_fs = sc->sc_fs_ctl_p_last; - - /* start QH where low speed control traffic will be queued */ - qh_ls->h_next = qh_fs; - qh_ls->qh_h_next = qh_fs->qh_self; - qh_ls->e_next = 0; - qh_ls->qh_e_next = htole32(UHCI_PTR_T); - } - if (1) { - uhci_qh_t *qh_ctl; - uhci_qh_t *qh_blk; - uhci_qh_t *qh_lst; - uhci_td_t *td_lst; - - qh_ctl = sc->sc_fs_ctl_p_last; - qh_blk = sc->sc_bulk_p_last; - - /* start QH where full speed control traffic will be queued */ - qh_ctl->h_next = qh_blk; - qh_ctl->qh_h_next = qh_blk->qh_self; - qh_ctl->e_next = 0; - qh_ctl->qh_e_next = htole32(UHCI_PTR_T); - - qh_lst = sc->sc_last_qh_p; - - /* start QH where bulk traffic will be queued */ - qh_blk->h_next = qh_lst; - qh_blk->qh_h_next = qh_lst->qh_self; - qh_blk->e_next = 0; - qh_blk->qh_e_next = htole32(UHCI_PTR_T); - - td_lst = sc->sc_last_td_p; - - /* end QH which is used for looping the QHs */ - qh_lst->h_next = 0; - qh_lst->qh_h_next = htole32(UHCI_PTR_T); /* end of QH chain */ - qh_lst->e_next = td_lst; - qh_lst->qh_e_next = td_lst->td_self; - - /* - * end TD which hangs from the last QH, to avoid a bug in the PIIX - * that makes it run berserk otherwise - */ - td_lst->next = 0; - td_lst->td_next = htole32(UHCI_PTR_T); - td_lst->td_status = htole32(0); /* inactive */ - td_lst->td_token = htole32(0); - td_lst->td_buffer = htole32(0); - } - if (1) { - struct usb2_page_search buf_res; - uint32_t *pframes; - - usb2_get_page(&sc->sc_hw.pframes_pc, 0, &buf_res); - - pframes = buf_res.buffer; - - - /* - * Setup UHCI framelist - * - * Execution order: - * - * pframes -> full speed isochronous -> interrupt QH's -> low - * speed control -> full speed control -> bulk transfers - * - */ - - for (x = 0; x != UHCI_FRAMELIST_COUNT; x++) { - pframes[x] = - sc->sc_isoc_p_last[x % UHCI_VFRAMELIST_COUNT]->td_self; - } - } - /* flush all cache into memory */ - - usb2_bus_mem_flush_all(&sc->sc_bus, &uhci_iterate_hw_softc); - - /* set up the bus struct */ - sc->sc_bus.methods = &uhci_bus_methods; - - USB_BUS_LOCK(&sc->sc_bus); - /* reset the controller */ - uhci_reset(sc); - - /* start the controller */ - uhci_start(sc); - USB_BUS_UNLOCK(&sc->sc_bus); - - /* catch lost interrupts */ - uhci_do_poll(&sc->sc_bus); - - return (0); -} - -/* NOTE: suspend/resume is called from - * interrupt context and cannot sleep! - */ - -void -uhci_suspend(uhci_softc_t *sc) -{ - USB_BUS_LOCK(&sc->sc_bus); - -#if USB_DEBUG - if (uhcidebug > 2) { - uhci_dumpregs(sc); - } -#endif - /* save some state if BIOS doesn't */ - - sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM); - sc->sc_saved_sof = UREAD1(sc, UHCI_SOF); - - /* stop the controller */ - - uhci_reset(sc); - - /* enter global suspend */ - - UHCICMD(sc, UHCI_CMD_EGSM); - - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_RESUME_WAIT)); - - USB_BUS_UNLOCK(&sc->sc_bus); -} - -void -uhci_resume(uhci_softc_t *sc) -{ - USB_BUS_LOCK(&sc->sc_bus); - - /* reset the controller */ - - uhci_reset(sc); - - /* force global resume */ - - UHCICMD(sc, UHCI_CMD_FGR); - - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_RESUME_DELAY)); - - /* and start traffic again */ - - uhci_start(sc); - -#if USB_DEBUG - if (uhcidebug > 2) { - uhci_dumpregs(sc); - } -#endif - - USB_BUS_UNLOCK(&sc->sc_bus); - - /* catch lost interrupts */ - uhci_do_poll(&sc->sc_bus); -} - -#if USB_DEBUG -static void -uhci_dumpregs(uhci_softc_t *sc) -{ - DPRINTFN(0, "%s regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, " - "flbase=%08x, sof=%04x, portsc1=%04x, portsc2=%04x\n", - device_get_nameunit(sc->sc_bus.bdev), - UREAD2(sc, UHCI_CMD), - UREAD2(sc, UHCI_STS), - UREAD2(sc, UHCI_INTR), - UREAD2(sc, UHCI_FRNUM), - UREAD4(sc, UHCI_FLBASEADDR), - UREAD1(sc, UHCI_SOF), - UREAD2(sc, UHCI_PORTSC1), - UREAD2(sc, UHCI_PORTSC2)); -} - -static uint8_t -uhci_dump_td(uhci_td_t *p) -{ - uint32_t td_next; - uint32_t td_status; - uint32_t td_token; - uint8_t temp; - - usb2_pc_cpu_invalidate(p->page_cache); - - td_next = le32toh(p->td_next); - td_status = le32toh(p->td_status); - td_token = le32toh(p->td_token); - - /* - * Check whether the link pointer in this TD marks the link pointer - * as end of queue: - */ - temp = ((td_next & UHCI_PTR_T) || (td_next == 0)); - - printf("TD(%p) at 0x%08x = link=0x%08x status=0x%08x " - "token=0x%08x buffer=0x%08x\n", - p, - le32toh(p->td_self), - td_next, - td_status, - td_token, - le32toh(p->td_buffer)); - - printf("TD(%p) td_next=%s%s%s td_status=%s%s%s%s%s%s%s%s%s%s%s, errcnt=%d, actlen=%d pid=%02x," - "addr=%d,endpt=%d,D=%d,maxlen=%d\n", - p, - (td_next & 1) ? "-T" : "", - (td_next & 2) ? "-Q" : "", - (td_next & 4) ? "-VF" : "", - (td_status & UHCI_TD_BITSTUFF) ? "-BITSTUFF" : "", - (td_status & UHCI_TD_CRCTO) ? "-CRCTO" : "", - (td_status & UHCI_TD_NAK) ? "-NAK" : "", - (td_status & UHCI_TD_BABBLE) ? "-BABBLE" : "", - (td_status & UHCI_TD_DBUFFER) ? "-DBUFFER" : "", - (td_status & UHCI_TD_STALLED) ? "-STALLED" : "", - (td_status & UHCI_TD_ACTIVE) ? "-ACTIVE" : "", - (td_status & UHCI_TD_IOC) ? "-IOC" : "", - (td_status & UHCI_TD_IOS) ? "-IOS" : "", - (td_status & UHCI_TD_LS) ? "-LS" : "", - (td_status & UHCI_TD_SPD) ? "-SPD" : "", - UHCI_TD_GET_ERRCNT(td_status), - UHCI_TD_GET_ACTLEN(td_status), - UHCI_TD_GET_PID(td_token), - UHCI_TD_GET_DEVADDR(td_token), - UHCI_TD_GET_ENDPT(td_token), - UHCI_TD_GET_DT(td_token), - UHCI_TD_GET_MAXLEN(td_token)); - - return (temp); -} - -static uint8_t -uhci_dump_qh(uhci_qh_t *sqh) -{ - uint8_t temp; - uint32_t qh_h_next; - uint32_t qh_e_next; - - usb2_pc_cpu_invalidate(sqh->page_cache); - - qh_h_next = le32toh(sqh->qh_h_next); - qh_e_next = le32toh(sqh->qh_e_next); - - DPRINTFN(0, "QH(%p) at 0x%08x: h_next=0x%08x e_next=0x%08x\n", sqh, - le32toh(sqh->qh_self), qh_h_next, qh_e_next); - - temp = ((((sqh->h_next != NULL) && !(qh_h_next & UHCI_PTR_T)) ? 1 : 0) | - (((sqh->e_next != NULL) && !(qh_e_next & UHCI_PTR_T)) ? 2 : 0)); - - return (temp); -} - -static void -uhci_dump_all(uhci_softc_t *sc) -{ - uhci_dumpregs(sc); - uhci_dump_qh(sc->sc_ls_ctl_p_last); - uhci_dump_qh(sc->sc_fs_ctl_p_last); - uhci_dump_qh(sc->sc_bulk_p_last); - uhci_dump_qh(sc->sc_last_qh_p); -} - -static void -uhci_dump_qhs(uhci_qh_t *sqh) -{ - uint8_t temp; - - temp = uhci_dump_qh(sqh); - - /* - * uhci_dump_qhs displays all the QHs and TDs from the given QH - * onwards Traverses sideways first, then down. - * - * QH1 QH2 No QH TD2.1 TD2.2 TD1.1 etc. - * - * TD2.x being the TDs queued at QH2 and QH1 being referenced from QH1. - */ - - if (temp & 1) - uhci_dump_qhs(sqh->h_next); - else - DPRINTF("No QH\n"); - - if (temp & 2) - uhci_dump_tds(sqh->e_next); - else - DPRINTF("No TD\n"); -} - -static void -uhci_dump_tds(uhci_td_t *td) -{ - for (; - td != NULL; - td = td->obj_next) { - if (uhci_dump_td(td)) { - break; - } - } -} - -#endif - -/* - * Let the last QH loop back to the full speed control transfer QH. - * This is what intel calls "bandwidth reclamation" and improves - * USB performance a lot for some devices. - * If we are already looping, just count it. - */ -static void -uhci_add_loop(uhci_softc_t *sc) -{ - struct uhci_qh *qh_lst; - struct uhci_qh *qh_rec; - -#if USB_DEBUG - if (uhcinoloop) { - return; - } -#endif - if (++(sc->sc_loops) == 1) { - DPRINTFN(6, "add\n"); - - qh_lst = sc->sc_last_qh_p; - qh_rec = sc->sc_reclaim_qh_p; - - /* NOTE: we don't loop back the soft pointer */ - - qh_lst->qh_h_next = qh_rec->qh_self; - usb2_pc_cpu_flush(qh_lst->page_cache); - } -} - -static void -uhci_rem_loop(uhci_softc_t *sc) -{ - struct uhci_qh *qh_lst; - -#if USB_DEBUG - if (uhcinoloop) { - return; - } -#endif - if (--(sc->sc_loops) == 0) { - DPRINTFN(6, "remove\n"); - - qh_lst = sc->sc_last_qh_p; - qh_lst->qh_h_next = htole32(UHCI_PTR_T); - usb2_pc_cpu_flush(qh_lst->page_cache); - } -} - -static void -uhci_transfer_intr_enqueue(struct usb2_xfer *xfer) -{ - /* check for early completion */ - if (uhci_check_transfer(xfer)) { - return; - } - /* put transfer on interrupt queue */ - usb2_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); - - /* start timeout, if any */ - if (xfer->timeout != 0) { - usb2_transfer_timeout_ms(xfer, &uhci_timeout, xfer->timeout); - } -} - -#define UHCI_APPEND_TD(std,last) (last) = _uhci_append_td(std,last) -static uhci_td_t * -_uhci_append_td(uhci_td_t *std, uhci_td_t *last) -{ - DPRINTFN(11, "%p to %p\n", std, last); - - /* (sc->sc_bus.mtx) must be locked */ - - std->next = last->next; - std->td_next = last->td_next; - - std->prev = last; - - usb2_pc_cpu_flush(std->page_cache); - - /* - * the last->next->prev is never followed: std->next->prev = std; - */ - last->next = std; - last->td_next = std->td_self; - - usb2_pc_cpu_flush(last->page_cache); - - return (std); -} - -#define UHCI_APPEND_QH(sqh,last) (last) = _uhci_append_qh(sqh,last) -static uhci_qh_t * -_uhci_append_qh(uhci_qh_t *sqh, uhci_qh_t *last) -{ - DPRINTFN(11, "%p to %p\n", sqh, last); - - if (sqh->h_prev != NULL) { - /* should not happen */ - DPRINTFN(0, "QH already linked!\n"); - return (last); - } - /* (sc->sc_bus.mtx) must be locked */ - - sqh->h_next = last->h_next; - sqh->qh_h_next = last->qh_h_next; - - sqh->h_prev = last; - - usb2_pc_cpu_flush(sqh->page_cache); - - /* - * The "last->h_next->h_prev" is never followed: - * - * "sqh->h_next->h_prev" = sqh; - */ - - last->h_next = sqh; - last->qh_h_next = sqh->qh_self; - - usb2_pc_cpu_flush(last->page_cache); - - return (sqh); -} - -/**/ - -#define UHCI_REMOVE_TD(std,last) (last) = _uhci_remove_td(std,last) -static uhci_td_t * -_uhci_remove_td(uhci_td_t *std, uhci_td_t *last) -{ - DPRINTFN(11, "%p from %p\n", std, last); - - /* (sc->sc_bus.mtx) must be locked */ - - std->prev->next = std->next; - std->prev->td_next = std->td_next; - - usb2_pc_cpu_flush(std->prev->page_cache); - - if (std->next) { - std->next->prev = std->prev; - usb2_pc_cpu_flush(std->next->page_cache); - } - return ((last == std) ? std->prev : last); -} - -#define UHCI_REMOVE_QH(sqh,last) (last) = _uhci_remove_qh(sqh,last) -static uhci_qh_t * -_uhci_remove_qh(uhci_qh_t *sqh, uhci_qh_t *last) -{ - DPRINTFN(11, "%p from %p\n", sqh, last); - - /* (sc->sc_bus.mtx) must be locked */ - - /* only remove if not removed from a queue */ - if (sqh->h_prev) { - - sqh->h_prev->h_next = sqh->h_next; - sqh->h_prev->qh_h_next = sqh->qh_h_next; - - usb2_pc_cpu_flush(sqh->h_prev->page_cache); - - if (sqh->h_next) { - sqh->h_next->h_prev = sqh->h_prev; - usb2_pc_cpu_flush(sqh->h_next->page_cache); - } - last = ((last == sqh) ? sqh->h_prev : last); - - sqh->h_prev = 0; - - usb2_pc_cpu_flush(sqh->page_cache); - } - return (last); -} - -static void -uhci_isoc_done(uhci_softc_t *sc, struct usb2_xfer *xfer) -{ - struct usb2_page_search res; - uint32_t nframes = xfer->nframes; - uint32_t status; - uint32_t offset = 0; - uint32_t *plen = xfer->frlengths; - uint16_t len = 0; - uhci_td_t *td = xfer->td_transfer_first; - uhci_td_t **pp_last = &sc->sc_isoc_p_last[xfer->qh_pos]; - - DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", - xfer, xfer->pipe); - - /* sync any DMA memory before doing fixups */ - - usb2_bdma_post_sync(xfer); - - while (nframes--) { - if (td == NULL) { - panic("%s:%d: out of TD's\n", - __FUNCTION__, __LINE__); - } - if (pp_last >= &sc->sc_isoc_p_last[UHCI_VFRAMELIST_COUNT]) { - pp_last = &sc->sc_isoc_p_last[0]; - } -#if USB_DEBUG - if (uhcidebug > 5) { - DPRINTF("isoc TD\n"); - uhci_dump_td(td); - } -#endif - usb2_pc_cpu_invalidate(td->page_cache); - status = le32toh(td->td_status); - - len = UHCI_TD_GET_ACTLEN(status); - - if (len > *plen) { - len = *plen; - } - if (td->fix_pc) { - - usb2_get_page(td->fix_pc, 0, &res); - - /* copy data from fixup location to real location */ - - usb2_pc_cpu_invalidate(td->fix_pc); - - usb2_copy_in(xfer->frbuffers, offset, - res.buffer, len); - } - offset += *plen; - - *plen = len; - - /* remove TD from schedule */ - UHCI_REMOVE_TD(td, *pp_last); - - pp_last++; - plen++; - td = td->obj_next; - } - - xfer->aframes = xfer->nframes; -} - -static usb2_error_t -uhci_non_isoc_done_sub(struct usb2_xfer *xfer) -{ - struct usb2_page_search res; - uhci_td_t *td; - uhci_td_t *td_alt_next; - uint32_t status; - uint32_t token; - uint16_t len; - - td = xfer->td_transfer_cache; - td_alt_next = td->alt_next; - - if (xfer->aframes != xfer->nframes) { - xfer->frlengths[xfer->aframes] = 0; - } - while (1) { - - usb2_pc_cpu_invalidate(td->page_cache); - status = le32toh(td->td_status); - token = le32toh(td->td_token); - - /* - * Verify the status and add - * up the actual length: - */ - - len = UHCI_TD_GET_ACTLEN(status); - if (len > td->len) { - /* should not happen */ - DPRINTF("Invalid status length, " - "0x%04x/0x%04x bytes\n", len, td->len); - status |= UHCI_TD_STALLED; - - } else if ((xfer->aframes != xfer->nframes) && (len > 0)) { - - if (td->fix_pc) { - - usb2_get_page(td->fix_pc, 0, &res); - - /* - * copy data from fixup location to real - * location - */ - - usb2_pc_cpu_invalidate(td->fix_pc); - - usb2_copy_in(xfer->frbuffers + xfer->aframes, - xfer->frlengths[xfer->aframes], res.buffer, len); - } - /* update actual length */ - - xfer->frlengths[xfer->aframes] += len; - } - /* Check for last transfer */ - if (((void *)td) == xfer->td_transfer_last) { - td = NULL; - break; - } - if (status & UHCI_TD_STALLED) { - /* the transfer is finished */ - td = NULL; - break; - } - /* Check for short transfer */ - if (len != td->len) { - if (xfer->flags_int.short_frames_ok) { - /* follow alt next */ - td = td->alt_next; - } else { - /* the transfer is finished */ - td = NULL; - } - break; - } - td = td->obj_next; - - if (td->alt_next != td_alt_next) { - /* this USB frame is complete */ - break; - } - } - - /* update transfer cache */ - - xfer->td_transfer_cache = td; - - /* update data toggle */ - - xfer->pipe->toggle_next = (token & UHCI_TD_SET_DT(1)) ? 0 : 1; - -#if USB_DEBUG - if (status & UHCI_TD_ERROR) { - DPRINTFN(11, "error, addr=%d, endpt=0x%02x, frame=0x%02x " - "status=%s%s%s%s%s%s%s%s%s%s%s\n", - xfer->address, xfer->endpoint, xfer->aframes, - (status & UHCI_TD_BITSTUFF) ? "[BITSTUFF]" : "", - (status & UHCI_TD_CRCTO) ? "[CRCTO]" : "", - (status & UHCI_TD_NAK) ? "[NAK]" : "", - (status & UHCI_TD_BABBLE) ? "[BABBLE]" : "", - (status & UHCI_TD_DBUFFER) ? "[DBUFFER]" : "", - (status & UHCI_TD_STALLED) ? "[STALLED]" : "", - (status & UHCI_TD_ACTIVE) ? "[ACTIVE]" : "[NOT_ACTIVE]", - (status & UHCI_TD_IOC) ? "[IOC]" : "", - (status & UHCI_TD_IOS) ? "[IOS]" : "", - (status & UHCI_TD_LS) ? "[LS]" : "", - (status & UHCI_TD_SPD) ? "[SPD]" : ""); - } -#endif - return (status & UHCI_TD_STALLED) ? - USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION; -} - -static void -uhci_non_isoc_done(struct usb2_xfer *xfer) -{ - usb2_error_t err = 0; - - DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", - xfer, xfer->pipe); - -#if USB_DEBUG - if (uhcidebug > 10) { - uhci_dump_tds(xfer->td_transfer_first); - } -#endif - - /* sync any DMA memory before doing fixups */ - - usb2_bdma_post_sync(xfer); - - /* reset scanner */ - - xfer->td_transfer_cache = xfer->td_transfer_first; - - if (xfer->flags_int.control_xfr) { - if (xfer->flags_int.control_hdr) { - - err = uhci_non_isoc_done_sub(xfer); - } - xfer->aframes = 1; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - while (xfer->aframes != xfer->nframes) { - - err = uhci_non_isoc_done_sub(xfer); - xfer->aframes++; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - err = uhci_non_isoc_done_sub(xfer); - } -done: - uhci_device_done(xfer, err); -} - -/*------------------------------------------------------------------------* - * uhci_check_transfer_sub - * - * The main purpose of this function is to update the data-toggle - * in case it is wrong. - *------------------------------------------------------------------------*/ -static void -uhci_check_transfer_sub(struct usb2_xfer *xfer) -{ - uhci_qh_t *qh; - uhci_td_t *td; - uhci_td_t *td_alt_next; - - uint32_t td_token; - uint32_t td_self; - - td = xfer->td_transfer_cache; - qh = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - td_token = td->obj_next->td_token; - td = td->alt_next; - xfer->td_transfer_cache = td; - td_self = td->td_self; - td_alt_next = td->alt_next; - - if ((td->td_token ^ td_token) & htole32(UHCI_TD_SET_DT(1))) { - - /* - * The data toggle is wrong and - * we need to switch it ! - */ - - while (1) { - - td->td_token ^= htole32(UHCI_TD_SET_DT(1)); - usb2_pc_cpu_flush(td->page_cache); - - if (td == xfer->td_transfer_last) { - /* last transfer */ - break; - } - td = td->obj_next; - - if (td->alt_next != td_alt_next) { - /* next frame */ - break; - } - } - } - /* update the QH */ - qh->qh_e_next = td_self; - usb2_pc_cpu_flush(qh->page_cache); - - DPRINTFN(13, "xfer=%p following alt next\n", xfer); -} - -/*------------------------------------------------------------------------* - * uhci_check_transfer - * - * Return values: - * 0: USB transfer is not finished - * Else: USB transfer is finished - *------------------------------------------------------------------------*/ -static uint8_t -uhci_check_transfer(struct usb2_xfer *xfer) -{ - uint32_t status; - uint32_t token; - uhci_td_t *td; - - DPRINTFN(16, "xfer=%p checking transfer\n", xfer); - - if (xfer->pipe->methods == &uhci_device_isoc_methods) { - /* isochronous transfer */ - - td = xfer->td_transfer_last; - - usb2_pc_cpu_invalidate(td->page_cache); - status = le32toh(td->td_status); - - /* check also if the first is complete */ - - td = xfer->td_transfer_first; - - usb2_pc_cpu_invalidate(td->page_cache); - status |= le32toh(td->td_status); - - if (!(status & UHCI_TD_ACTIVE)) { - uhci_device_done(xfer, USB_ERR_NORMAL_COMPLETION); - goto transferred; - } - } else { - /* non-isochronous transfer */ - - /* - * check whether there is an error somewhere - * in the middle, or whether there was a short - * packet (SPD and not ACTIVE) - */ - td = xfer->td_transfer_cache; - - while (1) { - usb2_pc_cpu_invalidate(td->page_cache); - status = le32toh(td->td_status); - token = le32toh(td->td_token); - - /* - * if there is an active TD the transfer isn't done - */ - if (status & UHCI_TD_ACTIVE) { - /* update cache */ - xfer->td_transfer_cache = td; - goto done; - } - /* - * last transfer descriptor makes the transfer done - */ - if (((void *)td) == xfer->td_transfer_last) { - break; - } - /* - * any kind of error makes the transfer done - */ - if (status & UHCI_TD_STALLED) { - break; - } - /* - * check if we reached the last packet - * or if there is a short packet: - */ - if ((td->td_next == htole32(UHCI_PTR_T)) || - (UHCI_TD_GET_ACTLEN(status) < td->len)) { - - if (xfer->flags_int.short_frames_ok) { - /* follow alt next */ - if (td->alt_next) { - /* update cache */ - xfer->td_transfer_cache = td; - uhci_check_transfer_sub(xfer); - goto done; - } - } - /* transfer is done */ - break; - } - td = td->obj_next; - } - uhci_non_isoc_done(xfer); - goto transferred; - } - -done: - DPRINTFN(13, "xfer=%p is still active\n", xfer); - return (0); - -transferred: - return (1); -} - -static void -uhci_interrupt_poll(uhci_softc_t *sc) -{ - struct usb2_xfer *xfer; - -repeat: - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - /* - * check if transfer is transferred - */ - if (uhci_check_transfer(xfer)) { - /* queue has been modified */ - goto repeat; - } - } -} - -/*------------------------------------------------------------------------* - * uhci_interrupt - UHCI interrupt handler - * - * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler, - * hence the interrupt handler will be setup before "sc->sc_bus.bdev" - * is present ! - *------------------------------------------------------------------------*/ -void -uhci_interrupt(uhci_softc_t *sc) -{ - uint32_t status; - - USB_BUS_LOCK(&sc->sc_bus); - - DPRINTFN(16, "real interrupt\n"); - -#if USB_DEBUG - if (uhcidebug > 15) { - uhci_dumpregs(sc); - } -#endif - status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS; - if (status == 0) { - /* the interrupt was not for us */ - goto done; - } - if (status & (UHCI_STS_RD | UHCI_STS_HSE | - UHCI_STS_HCPE | UHCI_STS_HCH)) { - - if (status & UHCI_STS_RD) { -#if USB_DEBUG - printf("%s: resume detect\n", - __FUNCTION__); -#endif - } - if (status & UHCI_STS_HSE) { - printf("%s: host system error\n", - __FUNCTION__); - } - if (status & UHCI_STS_HCPE) { - printf("%s: host controller process error\n", - __FUNCTION__); - } - if (status & UHCI_STS_HCH) { - /* no acknowledge needed */ - DPRINTF("%s: host controller halted\n", - __FUNCTION__); -#if USB_DEBUG - if (uhcidebug > 0) { - uhci_dump_all(sc); - } -#endif - } - } - /* get acknowledge bits */ - status &= (UHCI_STS_USBINT | - UHCI_STS_USBEI | - UHCI_STS_RD | - UHCI_STS_HSE | - UHCI_STS_HCPE); - - if (status == 0) { - /* nothing to acknowledge */ - goto done; - } - /* acknowledge interrupts */ - UWRITE2(sc, UHCI_STS, status); - - /* poll all the USB transfers */ - uhci_interrupt_poll(sc); - -done: - USB_BUS_UNLOCK(&sc->sc_bus); -} - -/* - * called when a request does not complete - */ -static void -uhci_timeout(void *arg) -{ - struct usb2_xfer *xfer = arg; - - DPRINTF("xfer=%p\n", xfer); - - USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); - - /* transfer is transferred */ - uhci_device_done(xfer, USB_ERR_TIMEOUT); -} - -static void -uhci_do_poll(struct usb2_bus *bus) -{ - struct uhci_softc *sc = UHCI_BUS2SC(bus); - - USB_BUS_LOCK(&sc->sc_bus); - uhci_interrupt_poll(sc); - uhci_root_ctrl_poll(sc); - USB_BUS_UNLOCK(&sc->sc_bus); -} - -static void -uhci_setup_standard_chain_sub(struct uhci_std_temp *temp) -{ - uhci_td_t *td; - uhci_td_t *td_next; - uhci_td_t *td_alt_next; - uint32_t average; - uint32_t len_old; - uint8_t shortpkt_old; - uint8_t precompute; - - td_alt_next = NULL; - shortpkt_old = temp->shortpkt; - len_old = temp->len; - precompute = 1; - - /* software is used to detect short incoming transfers */ - - if ((temp->td_token & htole32(UHCI_TD_PID)) == htole32(UHCI_TD_PID_IN)) { - temp->td_status |= htole32(UHCI_TD_SPD); - } else { - temp->td_status &= ~htole32(UHCI_TD_SPD); - } - - temp->ml.buf_offset = 0; - -restart: - - temp->td_token &= ~htole32(UHCI_TD_SET_MAXLEN(0)); - temp->td_token |= htole32(UHCI_TD_SET_MAXLEN(temp->average)); - - td = temp->td; - td_next = temp->td_next; - - while (1) { - - if (temp->len == 0) { - - if (temp->shortpkt) { - break; - } - /* send a Zero Length Packet, ZLP, last */ - - temp->shortpkt = 1; - temp->td_token |= htole32(UHCI_TD_SET_MAXLEN(0)); - average = 0; - - } else { - - average = temp->average; - - if (temp->len < average) { - temp->shortpkt = 1; - temp->td_token &= ~htole32(UHCI_TD_SET_MAXLEN(0)); - temp->td_token |= htole32(UHCI_TD_SET_MAXLEN(temp->len)); - average = temp->len; - } - } - - if (td_next == NULL) { - panic("%s: out of UHCI transfer descriptors!", __FUNCTION__); - } - /* get next TD */ - - td = td_next; - td_next = td->obj_next; - - /* check if we are pre-computing */ - - if (precompute) { - - /* update remaining length */ - - temp->len -= average; - - continue; - } - /* fill out current TD */ - - td->td_status = temp->td_status; - td->td_token = temp->td_token; - - /* update data toggle */ - - temp->td_token ^= htole32(UHCI_TD_SET_DT(1)); - - if (average == 0) { - - td->len = 0; - td->td_buffer = 0; - td->fix_pc = NULL; - - } else { - - /* update remaining length */ - - temp->len -= average; - - td->len = average; - - /* fill out buffer pointer and do fixup, if any */ - - uhci_mem_layout_fixup(&temp->ml, td); - } - - td->alt_next = td_alt_next; - - if ((td_next == td_alt_next) && temp->setup_alt_next) { - /* we need to receive these frames one by one ! */ - td->td_status |= htole32(UHCI_TD_IOC); - td->td_next = htole32(UHCI_PTR_T); - } else { - if (td_next) { - /* link the current TD with the next one */ - td->td_next = td_next->td_self; - } - } - - usb2_pc_cpu_flush(td->page_cache); - } - - if (precompute) { - precompute = 0; - - /* setup alt next pointer, if any */ - if (temp->short_frames_ok) { - if (temp->setup_alt_next) { - td_alt_next = td_next; - } - } else { - /* we use this field internally */ - td_alt_next = td_next; - } - - /* restore */ - temp->shortpkt = shortpkt_old; - temp->len = len_old; - goto restart; - } - temp->td = td; - temp->td_next = td_next; -} - -static uhci_td_t * -uhci_setup_standard_chain(struct usb2_xfer *xfer) -{ - struct uhci_std_temp temp; - uhci_td_t *td; - uint32_t x; - - DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", - xfer->address, UE_GET_ADDR(xfer->endpoint), - xfer->sumlen, usb2_get_speed(xfer->xroot->udev)); - - temp.average = xfer->max_frame_size; - temp.max_frame_size = xfer->max_frame_size; - - /* toggle the DMA set we are using */ - xfer->flags_int.curr_dma_set ^= 1; - - /* get next DMA set */ - td = xfer->td_start[xfer->flags_int.curr_dma_set]; - xfer->td_transfer_first = td; - xfer->td_transfer_cache = td; - - temp.td = NULL; - temp.td_next = td; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; - temp.short_frames_ok = xfer->flags_int.short_frames_ok; - - uhci_mem_layout_init(&temp.ml, xfer); - - temp.td_status = - htole32(UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | - UHCI_TD_ACTIVE)); - - if (xfer->xroot->udev->speed == USB_SPEED_LOW) { - temp.td_status |= htole32(UHCI_TD_LS); - } - temp.td_token = - htole32(UHCI_TD_SET_ENDPT(xfer->endpoint) | - UHCI_TD_SET_DEVADDR(xfer->address)); - - if (xfer->pipe->toggle_next) { - /* DATA1 is next */ - temp.td_token |= htole32(UHCI_TD_SET_DT(1)); - } - /* check if we should prepend a setup message */ - - if (xfer->flags_int.control_xfr) { - - if (xfer->flags_int.control_hdr) { - - temp.td_token &= htole32(UHCI_TD_SET_DEVADDR(0x7F) | - UHCI_TD_SET_ENDPT(0xF)); - temp.td_token |= htole32(UHCI_TD_PID_SETUP | - UHCI_TD_SET_DT(0)); - - temp.len = xfer->frlengths[0]; - temp.ml.buf_pc = xfer->frbuffers + 0; - temp.shortpkt = temp.len ? 1 : 0; - - uhci_setup_standard_chain_sub(&temp); - } - x = 1; - } else { - x = 0; - } - - while (x != xfer->nframes) { - - /* DATA0 / DATA1 message */ - - temp.len = xfer->frlengths[x]; - temp.ml.buf_pc = xfer->frbuffers + x; - - x++; - - if (x == xfer->nframes) { - temp.setup_alt_next = 0; - } - /* - * Keep previous data toggle, - * device address and endpoint number: - */ - - temp.td_token &= htole32(UHCI_TD_SET_DEVADDR(0x7F) | - UHCI_TD_SET_ENDPT(0xF) | - UHCI_TD_SET_DT(1)); - - if (temp.len == 0) { - - /* make sure that we send an USB packet */ - - temp.shortpkt = 0; - - } else { - - /* regular data transfer */ - - temp.shortpkt = (xfer->flags.force_short_xfer) ? 0 : 1; - } - - /* set endpoint direction */ - - temp.td_token |= - (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) ? - htole32(UHCI_TD_PID_IN) : - htole32(UHCI_TD_PID_OUT); - - uhci_setup_standard_chain_sub(&temp); - } - - /* check if we should append a status stage */ - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - /* - * send a DATA1 message and reverse the current endpoint - * direction - */ - - temp.td_token &= htole32(UHCI_TD_SET_DEVADDR(0x7F) | - UHCI_TD_SET_ENDPT(0xF) | - UHCI_TD_SET_DT(1)); - temp.td_token |= - (UE_GET_DIR(xfer->endpoint) == UE_DIR_OUT) ? - htole32(UHCI_TD_PID_IN | UHCI_TD_SET_DT(1)) : - htole32(UHCI_TD_PID_OUT | UHCI_TD_SET_DT(1)); - - temp.len = 0; - temp.ml.buf_pc = NULL; - temp.shortpkt = 0; - - uhci_setup_standard_chain_sub(&temp); - } - td = temp.td; - - td->td_next = htole32(UHCI_PTR_T); - - /* set interrupt bit */ - - td->td_status |= htole32(UHCI_TD_IOC); - - usb2_pc_cpu_flush(td->page_cache); - - /* must have at least one frame! */ - - xfer->td_transfer_last = td; - -#if USB_DEBUG - if (uhcidebug > 8) { - DPRINTF("nexttog=%d; data before transfer:\n", - xfer->pipe->toggle_next); - uhci_dump_tds(xfer->td_transfer_first); - } -#endif - return (xfer->td_transfer_first); -} - -/* NOTE: "done" can be run two times in a row, - * from close and from interrupt - */ - -static void -uhci_device_done(struct usb2_xfer *xfer, usb2_error_t error) -{ - struct usb2_pipe_methods *methods = xfer->pipe->methods; - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - uhci_qh_t *qh; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", - xfer, xfer->pipe, error); - - qh = xfer->qh_start[xfer->flags_int.curr_dma_set]; - if (qh) { - usb2_pc_cpu_invalidate(qh->page_cache); - } - if (xfer->flags_int.bandwidth_reclaimed) { - xfer->flags_int.bandwidth_reclaimed = 0; - uhci_rem_loop(sc); - } - if (methods == &uhci_device_bulk_methods) { - UHCI_REMOVE_QH(qh, sc->sc_bulk_p_last); - } - if (methods == &uhci_device_ctrl_methods) { - if (xfer->xroot->udev->speed == USB_SPEED_LOW) { - UHCI_REMOVE_QH(qh, sc->sc_ls_ctl_p_last); - } else { - UHCI_REMOVE_QH(qh, sc->sc_fs_ctl_p_last); - } - } - if (methods == &uhci_device_intr_methods) { - UHCI_REMOVE_QH(qh, sc->sc_intr_p_last[xfer->qh_pos]); - } - /* - * Only finish isochronous transfers once - * which will update "xfer->frlengths". - */ - if (xfer->td_transfer_first && - xfer->td_transfer_last) { - if (methods == &uhci_device_isoc_methods) { - uhci_isoc_done(sc, xfer); - } - xfer->td_transfer_first = NULL; - xfer->td_transfer_last = NULL; - } - /* dequeue transfer and start next transfer */ - usb2_transfer_done(xfer, error); -} - -/*------------------------------------------------------------------------* - * uhci bulk support - *------------------------------------------------------------------------*/ -static void -uhci_device_bulk_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -uhci_device_bulk_close(struct usb2_xfer *xfer) -{ - uhci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -uhci_device_bulk_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -uhci_device_bulk_start(struct usb2_xfer *xfer) -{ - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - uhci_td_t *td; - uhci_qh_t *qh; - - /* setup TD's */ - td = uhci_setup_standard_chain(xfer); - - /* setup QH */ - qh = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - qh->e_next = td; - qh->qh_e_next = td->td_self; - - if (xfer->xroot->udev->pwr_save.suspended == 0) { - UHCI_APPEND_QH(qh, sc->sc_bulk_p_last); - uhci_add_loop(sc); - xfer->flags_int.bandwidth_reclaimed = 1; - } else { - usb2_pc_cpu_flush(qh->page_cache); - } - - /* put transfer on interrupt queue */ - uhci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods uhci_device_bulk_methods = -{ - .open = uhci_device_bulk_open, - .close = uhci_device_bulk_close, - .enter = uhci_device_bulk_enter, - .start = uhci_device_bulk_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * uhci control support - *------------------------------------------------------------------------*/ -static void -uhci_device_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -uhci_device_ctrl_close(struct usb2_xfer *xfer) -{ - uhci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -uhci_device_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -uhci_device_ctrl_start(struct usb2_xfer *xfer) -{ - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - uhci_qh_t *qh; - uhci_td_t *td; - - /* setup TD's */ - td = uhci_setup_standard_chain(xfer); - - /* setup QH */ - qh = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - qh->e_next = td; - qh->qh_e_next = td->td_self; - - /* - * NOTE: some devices choke on bandwidth- reclamation for control - * transfers - */ - if (xfer->xroot->udev->pwr_save.suspended == 0) { - if (xfer->xroot->udev->speed == USB_SPEED_LOW) { - UHCI_APPEND_QH(qh, sc->sc_ls_ctl_p_last); - } else { - UHCI_APPEND_QH(qh, sc->sc_fs_ctl_p_last); - } - } else { - usb2_pc_cpu_flush(qh->page_cache); - } - /* put transfer on interrupt queue */ - uhci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods uhci_device_ctrl_methods = -{ - .open = uhci_device_ctrl_open, - .close = uhci_device_ctrl_close, - .enter = uhci_device_ctrl_enter, - .start = uhci_device_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * uhci interrupt support - *------------------------------------------------------------------------*/ -static void -uhci_device_intr_open(struct usb2_xfer *xfer) -{ - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - uint16_t best; - uint16_t bit; - uint16_t x; - - best = 0; - bit = UHCI_IFRAMELIST_COUNT / 2; - while (bit) { - if (xfer->interval >= bit) { - x = bit; - best = bit; - while (x & bit) { - if (sc->sc_intr_stat[x] < - sc->sc_intr_stat[best]) { - best = x; - } - x++; - } - break; - } - bit >>= 1; - } - - sc->sc_intr_stat[best]++; - xfer->qh_pos = best; - - DPRINTFN(3, "best=%d interval=%d\n", - best, xfer->interval); -} - -static void -uhci_device_intr_close(struct usb2_xfer *xfer) -{ - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - - sc->sc_intr_stat[xfer->qh_pos]--; - - uhci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -uhci_device_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -uhci_device_intr_start(struct usb2_xfer *xfer) -{ - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - uhci_qh_t *qh; - uhci_td_t *td; - - /* setup TD's */ - td = uhci_setup_standard_chain(xfer); - - /* setup QH */ - qh = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - qh->e_next = td; - qh->qh_e_next = td->td_self; - - if (xfer->xroot->udev->pwr_save.suspended == 0) { - - /* enter QHs into the controller data structures */ - UHCI_APPEND_QH(qh, sc->sc_intr_p_last[xfer->qh_pos]); - - } else { - usb2_pc_cpu_flush(qh->page_cache); - } - - /* put transfer on interrupt queue */ - uhci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods uhci_device_intr_methods = -{ - .open = uhci_device_intr_open, - .close = uhci_device_intr_close, - .enter = uhci_device_intr_enter, - .start = uhci_device_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * uhci isochronous support - *------------------------------------------------------------------------*/ -static void -uhci_device_isoc_open(struct usb2_xfer *xfer) -{ - uhci_td_t *td; - uint32_t td_token; - uint8_t ds; - - td_token = - (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) ? - UHCI_TD_IN(0, xfer->endpoint, xfer->address, 0) : - UHCI_TD_OUT(0, xfer->endpoint, xfer->address, 0); - - td_token = htole32(td_token); - - /* initialize all TD's */ - - for (ds = 0; ds != 2; ds++) { - - for (td = xfer->td_start[ds]; td; td = td->obj_next) { - - /* mark TD as inactive */ - td->td_status = htole32(UHCI_TD_IOS); - td->td_token = td_token; - - usb2_pc_cpu_flush(td->page_cache); - } - } -} - -static void -uhci_device_isoc_close(struct usb2_xfer *xfer) -{ - uhci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -uhci_device_isoc_enter(struct usb2_xfer *xfer) -{ - struct uhci_mem_layout ml; - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - uint32_t nframes; - uint32_t temp; - uint32_t *plen; - -#if USB_DEBUG - uint8_t once = 1; - -#endif - uhci_td_t *td; - uhci_td_t *td_last = NULL; - uhci_td_t **pp_last; - - DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", - xfer, xfer->pipe->isoc_next, xfer->nframes); - - nframes = UREAD2(sc, UHCI_FRNUM); - - temp = (nframes - xfer->pipe->isoc_next) & - (UHCI_VFRAMELIST_COUNT - 1); - - if ((xfer->pipe->is_synced == 0) || - (temp < xfer->nframes)) { - /* - * If there is data underflow or the pipe queue is empty we - * schedule the transfer a few frames ahead of the current - * frame position. Else two isochronous transfers might - * overlap. - */ - xfer->pipe->isoc_next = (nframes + 3) & (UHCI_VFRAMELIST_COUNT - 1); - xfer->pipe->is_synced = 1; - DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next); - } - /* - * compute how many milliseconds the insertion is ahead of the - * current frame position: - */ - temp = (xfer->pipe->isoc_next - nframes) & - (UHCI_VFRAMELIST_COUNT - 1); - - /* - * pre-compute when the isochronous transfer will be finished: - */ - xfer->isoc_time_complete = - usb2_isoc_time_expand(&sc->sc_bus, nframes) + temp + - xfer->nframes; - - /* get the real number of frames */ - - nframes = xfer->nframes; - - uhci_mem_layout_init(&ml, xfer); - - plen = xfer->frlengths; - - /* toggle the DMA set we are using */ - xfer->flags_int.curr_dma_set ^= 1; - - /* get next DMA set */ - td = xfer->td_start[xfer->flags_int.curr_dma_set]; - xfer->td_transfer_first = td; - - pp_last = &sc->sc_isoc_p_last[xfer->pipe->isoc_next]; - - /* store starting position */ - - xfer->qh_pos = xfer->pipe->isoc_next; - - while (nframes--) { - if (td == NULL) { - panic("%s:%d: out of TD's\n", - __FUNCTION__, __LINE__); - } - if (pp_last >= &sc->sc_isoc_p_last[UHCI_VFRAMELIST_COUNT]) { - pp_last = &sc->sc_isoc_p_last[0]; - } - if (*plen > xfer->max_frame_size) { -#if USB_DEBUG - if (once) { - once = 0; - printf("%s: frame length(%d) exceeds %d " - "bytes (frame truncated)\n", - __FUNCTION__, *plen, - xfer->max_frame_size); - } -#endif - *plen = xfer->max_frame_size; - } - /* reuse td_token from last transfer */ - - td->td_token &= htole32(~UHCI_TD_MAXLEN_MASK); - td->td_token |= htole32(UHCI_TD_SET_MAXLEN(*plen)); - - td->len = *plen; - - if (td->len == 0) { - /* - * Do not call "uhci_mem_layout_fixup()" when the - * length is zero! - */ - td->td_buffer = 0; - td->fix_pc = NULL; - - } else { - - /* fill out buffer pointer and do fixup, if any */ - - uhci_mem_layout_fixup(&ml, td); - - } - - /* update status */ - if (nframes == 0) { - td->td_status = htole32 - (UHCI_TD_ZERO_ACTLEN - (UHCI_TD_SET_ERRCNT(0) | - UHCI_TD_ACTIVE | - UHCI_TD_IOS | - UHCI_TD_IOC)); - } else { - td->td_status = htole32 - (UHCI_TD_ZERO_ACTLEN - (UHCI_TD_SET_ERRCNT(0) | - UHCI_TD_ACTIVE | - UHCI_TD_IOS)); - } - - usb2_pc_cpu_flush(td->page_cache); - -#if USB_DEBUG - if (uhcidebug > 5) { - DPRINTF("TD %d\n", nframes); - uhci_dump_td(td); - } -#endif - /* insert TD into schedule */ - UHCI_APPEND_TD(td, *pp_last); - pp_last++; - - plen++; - td_last = td; - td = td->obj_next; - } - - xfer->td_transfer_last = td_last; - - /* update isoc_next */ - xfer->pipe->isoc_next = (pp_last - &sc->sc_isoc_p_last[0]) & - (UHCI_VFRAMELIST_COUNT - 1); -} - -static void -uhci_device_isoc_start(struct usb2_xfer *xfer) -{ - /* put transfer on interrupt queue */ - uhci_transfer_intr_enqueue(xfer); -} - -struct usb2_pipe_methods uhci_device_isoc_methods = -{ - .open = uhci_device_isoc_open, - .close = uhci_device_isoc_close, - .enter = uhci_device_isoc_enter, - .start = uhci_device_isoc_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * uhci root control support - *------------------------------------------------------------------------* - * simulate a hardware hub by handling - * all the necessary requests - *------------------------------------------------------------------------*/ - -static void -uhci_root_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -uhci_root_ctrl_close(struct usb2_xfer *xfer) -{ - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_ctrl.xfer == xfer) { - sc->sc_root_ctrl.xfer = NULL; - } - uhci_device_done(xfer, USB_ERR_CANCELLED); -} - -/* data structures and routines - * to emulate the root hub: - */ - -static const -struct usb2_device_descriptor uhci_devd = -{ - sizeof(struct usb2_device_descriptor), - UDESC_DEVICE, /* type */ - {0x00, 0x01}, /* USB version */ - UDCLASS_HUB, /* class */ - UDSUBCLASS_HUB, /* subclass */ - UDPROTO_FSHUB, /* protocol */ - 64, /* max packet */ - {0}, {0}, {0x00, 0x01}, /* device id */ - 1, 2, 0, /* string indicies */ - 1 /* # of configurations */ -}; - -static const struct uhci_config_desc uhci_confd = { - .confd = { - .bLength = sizeof(struct usb2_config_descriptor), - .bDescriptorType = UDESC_CONFIG, - .wTotalLength[0] = sizeof(uhci_confd), - .bNumInterface = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = UC_SELF_POWERED, - .bMaxPower = 0 /* max power */ - }, - - .ifcd = { - .bLength = sizeof(struct usb2_interface_descriptor), - .bDescriptorType = UDESC_INTERFACE, - .bNumEndpoints = 1, - .bInterfaceClass = UICLASS_HUB, - .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_FSHUB, - }, - - .endpd = { - .bLength = sizeof(struct usb2_endpoint_descriptor), - .bDescriptorType = UDESC_ENDPOINT, - .bEndpointAddress = UE_DIR_IN | UHCI_INTR_ENDPT, - .bmAttributes = UE_INTERRUPT, - .wMaxPacketSize[0] = 8, /* max packet (63 ports) */ - .bInterval = 255, - }, -}; - -static const -struct usb2_hub_descriptor_min uhci_hubd_piix = -{ - sizeof(uhci_hubd_piix), - UDESC_HUB, - 2, - {UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL, 0}, - 50, /* power on to power good */ - 0, - {0x00}, /* both ports are removable */ -}; - -/* - * The USB hub protocol requires that SET_FEATURE(PORT_RESET) also - * enables the port, and also states that SET_FEATURE(PORT_ENABLE) - * should not be used by the USB subsystem. As we cannot issue a - * SET_FEATURE(PORT_ENABLE) externally, we must ensure that the port - * will be enabled as part of the reset. - * - * On the VT83C572, the port cannot be successfully enabled until the - * outstanding "port enable change" and "connection status change" - * events have been reset. - */ -static usb2_error_t -uhci_portreset(uhci_softc_t *sc, uint16_t index, uint8_t use_polling) -{ - uint16_t port; - uint16_t x; - uint8_t lim; - - if (index == 1) - port = UHCI_PORTSC1; - else if (index == 2) - port = UHCI_PORTSC2; - else - return (USB_ERR_IOERROR); - - /* - * Before we do anything, turn on SOF messages on the USB - * BUS. Some USB devices do not cope without them! - */ - if (!(UREAD2(sc, UHCI_CMD) & UHCI_CMD_RS)) { - - DPRINTF("Activating SOFs!\n"); - - UHCICMD(sc, (UHCI_CMD_MAXP | UHCI_CMD_RS)); - - /* wait a little bit */ - if (use_polling) { - DELAY(10000); - } else { - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100); - } - } - - x = URWMASK(UREAD2(sc, port)); - UWRITE2(sc, port, x | UHCI_PORTSC_PR); - - if (use_polling) { - /* polling */ - DELAY(USB_PORT_ROOT_RESET_DELAY * 1000); - } else { - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_PORT_ROOT_RESET_DELAY)); - } - - DPRINTFN(4, "uhci port %d reset, status0 = 0x%04x\n", - index, UREAD2(sc, port)); - - x = URWMASK(UREAD2(sc, port)); - UWRITE2(sc, port, x & ~UHCI_PORTSC_PR); - - - mtx_unlock(&sc->sc_bus.bus_mtx); - - /* - * This delay needs to be exactly 100us, else some USB devices - * fail to attach! - */ - DELAY(100); - - mtx_lock(&sc->sc_bus.bus_mtx); - - DPRINTFN(4, "uhci port %d reset, status1 = 0x%04x\n", - index, UREAD2(sc, port)); - - x = URWMASK(UREAD2(sc, port)); - UWRITE2(sc, port, x | UHCI_PORTSC_PE); - - for (lim = 0; lim < 12; lim++) { - - if (use_polling) { - /* polling */ - DELAY(USB_PORT_RESET_DELAY * 1000); - } else { - usb2_pause_mtx(&sc->sc_bus.bus_mtx, - USB_MS_TO_TICKS(USB_PORT_RESET_DELAY)); - } - - x = UREAD2(sc, port); - - DPRINTFN(4, "uhci port %d iteration %u, status = 0x%04x\n", - index, lim, x); - - if (!(x & UHCI_PORTSC_CCS)) { - /* - * No device is connected (or was disconnected - * during reset). Consider the port reset. - * The delay must be long enough to ensure on - * the initial iteration that the device - * connection will have been registered. 50ms - * appears to be sufficient, but 20ms is not. - */ - DPRINTFN(4, "uhci port %d loop %u, device detached\n", - index, lim); - goto done; - } - if (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)) { - /* - * Port enabled changed and/or connection - * status changed were set. Reset either or - * both raised flags (by writing a 1 to that - * bit), and wait again for state to settle. - */ - UWRITE2(sc, port, URWMASK(x) | - (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC))); - continue; - } - if (x & UHCI_PORTSC_PE) { - /* port is enabled */ - goto done; - } - UWRITE2(sc, port, URWMASK(x) | UHCI_PORTSC_PE); - } - - DPRINTFN(2, "uhci port %d reset timed out\n", index); - return (USB_ERR_TIMEOUT); - -done: - DPRINTFN(4, "uhci port %d reset, status2 = 0x%04x\n", - index, UREAD2(sc, port)); - - sc->sc_isreset = 1; - return (USB_ERR_NORMAL_COMPLETION); -} - -static void -uhci_root_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -uhci_root_ctrl_start(struct usb2_xfer *xfer) -{ - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - - DPRINTF("\n"); - - sc->sc_root_ctrl.xfer = xfer; - - usb2_bus_roothub_exec(xfer->xroot->bus); -} - -static void -uhci_root_ctrl_task(struct usb2_bus *bus) -{ - uhci_root_ctrl_poll(UHCI_BUS2SC(bus)); -} - -static void -uhci_root_ctrl_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - char *ptr; - uint16_t x; - uint16_t port; - uint16_t value; - uint16_t index; - uint16_t status; - uint16_t change; - uint8_t use_polling; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_SETUP) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - uhci_device_done(xfer, std->err); - } - goto done; - } - /* buffer reset */ - std->ptr = sc->sc_hub_desc.temp; - std->len = 0; - - value = UGETW(std->req.wValue); - index = UGETW(std->req.wIndex); - - use_polling = mtx_owned(xfer->xroot->xfer_mtx) ? 1 : 0; - - DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x " - "wValue=0x%04x wIndex=0x%04x\n", - std->req.bmRequestType, std->req.bRequest, - UGETW(std->req.wLength), value, index); - -#define C(x,y) ((x) | ((y) << 8)) - switch (C(std->req.bRequest, std->req.bmRequestType)) { - case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): - case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): - case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): - /* - * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops - * for the integrated root hub. - */ - break; - case C(UR_GET_CONFIG, UT_READ_DEVICE): - std->len = 1; - sc->sc_hub_desc.temp[0] = sc->sc_conf; - break; - case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): - switch (value >> 8) { - case UDESC_DEVICE: - if ((value & 0xff) != 0) { - std->err = USB_ERR_IOERROR; - goto done; - } - std->len = sizeof(uhci_devd); - sc->sc_hub_desc.devd = uhci_devd; - break; - - case UDESC_CONFIG: - if ((value & 0xff) != 0) { - std->err = USB_ERR_IOERROR; - goto done; - } - std->len = sizeof(uhci_confd); - std->ptr = USB_ADD_BYTES(&uhci_confd, 0); - break; - - case UDESC_STRING: - switch (value & 0xff) { - case 0: /* Language table */ - ptr = "\001"; - break; - - case 1: /* Vendor */ - ptr = sc->sc_vendor; - break; - - case 2: /* Product */ - ptr = "UHCI root HUB"; - break; - - default: - ptr = ""; - break; - } - - std->len = usb2_make_str_desc - (sc->sc_hub_desc.temp, - sizeof(sc->sc_hub_desc.temp), - ptr); - break; - - default: - std->err = USB_ERR_IOERROR; - goto done; - } - break; - case C(UR_GET_INTERFACE, UT_READ_INTERFACE): - std->len = 1; - sc->sc_hub_desc.temp[0] = 0; - break; - case C(UR_GET_STATUS, UT_READ_DEVICE): - std->len = 2; - USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED); - break; - case C(UR_GET_STATUS, UT_READ_INTERFACE): - case C(UR_GET_STATUS, UT_READ_ENDPOINT): - std->len = 2; - USETW(sc->sc_hub_desc.stat.wStatus, 0); - break; - case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): - if (value >= USB_MAX_DEVICES) { - std->err = USB_ERR_IOERROR; - goto done; - } - sc->sc_addr = value; - break; - case C(UR_SET_CONFIG, UT_WRITE_DEVICE): - if ((value != 0) && (value != 1)) { - std->err = USB_ERR_IOERROR; - goto done; - } - sc->sc_conf = value; - break; - case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): - break; - case C(UR_SET_FEATURE, UT_WRITE_DEVICE): - case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): - case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): - std->err = USB_ERR_IOERROR; - goto done; - case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): - break; - case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): - break; - /* Hub requests */ - case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): - break; - case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): - DPRINTFN(4, "UR_CLEAR_PORT_FEATURE " - "port=%d feature=%d\n", - index, value); - if (index == 1) - port = UHCI_PORTSC1; - else if (index == 2) - port = UHCI_PORTSC2; - else { - std->err = USB_ERR_IOERROR; - goto done; - } - switch (value) { - case UHF_PORT_ENABLE: - x = URWMASK(UREAD2(sc, port)); - UWRITE2(sc, port, x & ~UHCI_PORTSC_PE); - break; - case UHF_PORT_SUSPEND: - x = URWMASK(UREAD2(sc, port)); - UWRITE2(sc, port, x & ~(UHCI_PORTSC_SUSP)); - break; - case UHF_PORT_RESET: - x = URWMASK(UREAD2(sc, port)); - UWRITE2(sc, port, x & ~UHCI_PORTSC_PR); - break; - case UHF_C_PORT_CONNECTION: - x = URWMASK(UREAD2(sc, port)); - UWRITE2(sc, port, x | UHCI_PORTSC_CSC); - break; - case UHF_C_PORT_ENABLE: - x = URWMASK(UREAD2(sc, port)); - UWRITE2(sc, port, x | UHCI_PORTSC_POEDC); - break; - case UHF_C_PORT_OVER_CURRENT: - x = URWMASK(UREAD2(sc, port)); - UWRITE2(sc, port, x | UHCI_PORTSC_OCIC); - break; - case UHF_C_PORT_RESET: - sc->sc_isreset = 0; - std->err = USB_ERR_NORMAL_COMPLETION; - goto done; - case UHF_C_PORT_SUSPEND: - sc->sc_isresumed &= ~(1 << index); - break; - case UHF_PORT_CONNECTION: - case UHF_PORT_OVER_CURRENT: - case UHF_PORT_POWER: - case UHF_PORT_LOW_SPEED: - default: - std->err = USB_ERR_IOERROR; - goto done; - } - break; - case C(UR_GET_BUS_STATE, UT_READ_CLASS_OTHER): - if (index == 1) - port = UHCI_PORTSC1; - else if (index == 2) - port = UHCI_PORTSC2; - else { - std->err = USB_ERR_IOERROR; - goto done; - } - std->len = 1; - sc->sc_hub_desc.temp[0] = - ((UREAD2(sc, port) & UHCI_PORTSC_LS) >> - UHCI_PORTSC_LS_SHIFT); - break; - case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): - if ((value & 0xff) != 0) { - std->err = USB_ERR_IOERROR; - goto done; - } - std->len = sizeof(uhci_hubd_piix); - std->ptr = USB_ADD_BYTES(&uhci_hubd_piix, 0); - break; - case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): - std->len = 16; - bzero(sc->sc_hub_desc.temp, 16); - break; - case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): - if (index == 1) - port = UHCI_PORTSC1; - else if (index == 2) - port = UHCI_PORTSC2; - else { - std->err = USB_ERR_IOERROR; - goto done; - } - x = UREAD2(sc, port); - status = change = 0; - if (x & UHCI_PORTSC_CCS) - status |= UPS_CURRENT_CONNECT_STATUS; - if (x & UHCI_PORTSC_CSC) - change |= UPS_C_CONNECT_STATUS; - if (x & UHCI_PORTSC_PE) - status |= UPS_PORT_ENABLED; - if (x & UHCI_PORTSC_POEDC) - change |= UPS_C_PORT_ENABLED; - if (x & UHCI_PORTSC_OCI) - status |= UPS_OVERCURRENT_INDICATOR; - if (x & UHCI_PORTSC_OCIC) - change |= UPS_C_OVERCURRENT_INDICATOR; - if (x & UHCI_PORTSC_LSDA) - status |= UPS_LOW_SPEED; - if ((x & UHCI_PORTSC_PE) && (x & UHCI_PORTSC_RD)) { - /* need to do a write back */ - UWRITE2(sc, port, URWMASK(x)); - - /* wait 20ms for resume sequence to complete */ - if (use_polling) { - /* polling */ - DELAY(20000); - } else { - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 50); - } - - /* clear suspend and resume detect */ - UWRITE2(sc, port, URWMASK(x) & ~(UHCI_PORTSC_RD | - UHCI_PORTSC_SUSP)); - - /* wait a little bit */ - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 500); - - sc->sc_isresumed |= (1 << index); - - } else if (x & UHCI_PORTSC_SUSP) { - status |= UPS_SUSPEND; - } - status |= UPS_PORT_POWER; - if (sc->sc_isresumed & (1 << index)) - change |= UPS_C_SUSPEND; - if (sc->sc_isreset) - change |= UPS_C_PORT_RESET; - USETW(sc->sc_hub_desc.ps.wPortStatus, status); - USETW(sc->sc_hub_desc.ps.wPortChange, change); - std->len = sizeof(sc->sc_hub_desc.ps); - break; - case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): - std->err = USB_ERR_IOERROR; - goto done; - case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): - break; - case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): - if (index == 1) - port = UHCI_PORTSC1; - else if (index == 2) - port = UHCI_PORTSC2; - else { - std->err = USB_ERR_IOERROR; - goto done; - } - switch (value) { - case UHF_PORT_ENABLE: - x = URWMASK(UREAD2(sc, port)); - UWRITE2(sc, port, x | UHCI_PORTSC_PE); - break; - case UHF_PORT_SUSPEND: - x = URWMASK(UREAD2(sc, port)); - UWRITE2(sc, port, x | UHCI_PORTSC_SUSP); - break; - case UHF_PORT_RESET: - std->err = uhci_portreset(sc, index, use_polling); - goto done; - case UHF_PORT_POWER: - /* pretend we turned on power */ - std->err = USB_ERR_NORMAL_COMPLETION; - goto done; - case UHF_C_PORT_CONNECTION: - case UHF_C_PORT_ENABLE: - case UHF_C_PORT_OVER_CURRENT: - case UHF_PORT_CONNECTION: - case UHF_PORT_OVER_CURRENT: - case UHF_PORT_LOW_SPEED: - case UHF_C_PORT_SUSPEND: - case UHF_C_PORT_RESET: - default: - std->err = USB_ERR_IOERROR; - goto done; - } - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } -done: - return; -} - -static void -uhci_root_ctrl_poll(struct uhci_softc *sc) -{ - usb2_sw_transfer(&sc->sc_root_ctrl, - &uhci_root_ctrl_done); -} - -struct usb2_pipe_methods uhci_root_ctrl_methods = -{ - .open = uhci_root_ctrl_open, - .close = uhci_root_ctrl_close, - .enter = uhci_root_ctrl_enter, - .start = uhci_root_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 0, -}; - -/*------------------------------------------------------------------------* - * uhci root interrupt support - *------------------------------------------------------------------------*/ -static void -uhci_root_intr_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -uhci_root_intr_close(struct usb2_xfer *xfer) -{ - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_intr.xfer == xfer) { - sc->sc_root_intr.xfer = NULL; - } - uhci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -uhci_root_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -uhci_root_intr_start(struct usb2_xfer *xfer) -{ - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - - sc->sc_root_intr.xfer = xfer; - - usb2_transfer_timeout_ms(xfer, - &uhci_root_intr_check, xfer->interval); -} - -static void -uhci_root_intr_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_PRE_DATA) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer is transferred */ - uhci_device_done(xfer, std->err); - } - goto done; - } - /* setup buffer */ - std->ptr = sc->sc_hub_idata; - std->len = sizeof(sc->sc_hub_idata); -done: - return; -} - -/* - * this routine is executed periodically and simulates interrupts - * from the root controller interrupt pipe for port status change - */ -static void -uhci_root_intr_check(void *arg) -{ - struct usb2_xfer *xfer = arg; - uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus); - - DPRINTFN(21, "\n"); - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - sc->sc_hub_idata[0] = 0; - - if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC | - UHCI_PORTSC_OCIC | UHCI_PORTSC_RD)) { - sc->sc_hub_idata[0] |= 1 << 1; - } - if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC | - UHCI_PORTSC_OCIC | UHCI_PORTSC_RD)) { - sc->sc_hub_idata[0] |= 1 << 2; - } - if (sc->sc_hub_idata[0] == 0) { - /* - * no change or controller not running, try again in a while - */ - uhci_root_intr_start(xfer); - } else { - usb2_sw_transfer(&sc->sc_root_intr, - &uhci_root_intr_done); - } -} - -struct usb2_pipe_methods uhci_root_intr_methods = -{ - .open = uhci_root_intr_open, - .close = uhci_root_intr_close, - .enter = uhci_root_intr_enter, - .start = uhci_root_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -static void -uhci_xfer_setup(struct usb2_setup_params *parm) -{ - struct usb2_page_search page_info; - struct usb2_page_cache *pc; - uhci_softc_t *sc; - struct usb2_xfer *xfer; - void *last_obj; - uint32_t ntd; - uint32_t nqh; - uint32_t nfixup; - uint32_t n; - uint16_t align; - - sc = UHCI_BUS2SC(parm->udev->bus); - xfer = parm->curr_xfer; - - parm->hc_max_packet_size = 0x500; - parm->hc_max_packet_count = 1; - parm->hc_max_frame_size = 0x500; - - /* - * compute ntd and nqh - */ - if (parm->methods == &uhci_device_ctrl_methods) { - xfer->flags_int.bdma_enable = 1; - xfer->flags_int.bdma_no_post_sync = 1; - - usb2_transfer_setup_sub(parm); - - /* see EHCI HC driver for proof of "ntd" formula */ - - nqh = 1; - ntd = ((2 * xfer->nframes) + 1 /* STATUS */ - + (xfer->max_data_length / xfer->max_frame_size)); - - } else if (parm->methods == &uhci_device_bulk_methods) { - xfer->flags_int.bdma_enable = 1; - xfer->flags_int.bdma_no_post_sync = 1; - - usb2_transfer_setup_sub(parm); - - nqh = 1; - ntd = ((2 * xfer->nframes) - + (xfer->max_data_length / xfer->max_frame_size)); - - } else if (parm->methods == &uhci_device_intr_methods) { - xfer->flags_int.bdma_enable = 1; - xfer->flags_int.bdma_no_post_sync = 1; - - usb2_transfer_setup_sub(parm); - - nqh = 1; - ntd = ((2 * xfer->nframes) - + (xfer->max_data_length / xfer->max_frame_size)); - - } else if (parm->methods == &uhci_device_isoc_methods) { - xfer->flags_int.bdma_enable = 1; - xfer->flags_int.bdma_no_post_sync = 1; - - usb2_transfer_setup_sub(parm); - - nqh = 0; - ntd = xfer->nframes; - - } else { - - usb2_transfer_setup_sub(parm); - - nqh = 0; - ntd = 0; - } - - if (parm->err) { - return; - } - /* - * NOTE: the UHCI controller requires that - * every packet must be contiguous on - * the same USB memory page ! - */ - nfixup = (parm->bufsize / USB_PAGE_SIZE) + 1; - - /* - * Compute a suitable power of two alignment - * for our "max_frame_size" fixup buffer(s): - */ - align = xfer->max_frame_size; - n = 0; - while (align) { - align >>= 1; - n++; - } - - /* check for power of two */ - if (!(xfer->max_frame_size & - (xfer->max_frame_size - 1))) { - n--; - } - /* - * We don't allow alignments of - * less than 8 bytes: - * - * NOTE: Allocating using an aligment - * of 1 byte has special meaning! - */ - if (n < 3) { - n = 3; - } - align = (1 << n); - - if (usb2_transfer_setup_sub_malloc( - parm, &pc, xfer->max_frame_size, - align, nfixup)) { - parm->err = USB_ERR_NOMEM; - return; - } - xfer->buf_fixup = pc; - -alloc_dma_set: - - if (parm->err) { - return; - } - last_obj = NULL; - - if (usb2_transfer_setup_sub_malloc( - parm, &pc, sizeof(uhci_td_t), - UHCI_TD_ALIGN, ntd)) { - parm->err = USB_ERR_NOMEM; - return; - } - if (parm->buf) { - for (n = 0; n != ntd; n++) { - uhci_td_t *td; - - usb2_get_page(pc + n, 0, &page_info); - - td = page_info.buffer; - - /* init TD */ - if ((parm->methods == &uhci_device_bulk_methods) || - (parm->methods == &uhci_device_ctrl_methods) || - (parm->methods == &uhci_device_intr_methods)) { - /* set depth first bit */ - td->td_self = htole32(page_info.physaddr | - UHCI_PTR_TD | UHCI_PTR_VF); - } else { - td->td_self = htole32(page_info.physaddr | - UHCI_PTR_TD); - } - - td->obj_next = last_obj; - td->page_cache = pc + n; - - last_obj = td; - - usb2_pc_cpu_flush(pc + n); - } - } - xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; - - last_obj = NULL; - - if (usb2_transfer_setup_sub_malloc( - parm, &pc, sizeof(uhci_qh_t), - UHCI_QH_ALIGN, nqh)) { - parm->err = USB_ERR_NOMEM; - return; - } - if (parm->buf) { - for (n = 0; n != nqh; n++) { - uhci_qh_t *qh; - - usb2_get_page(pc + n, 0, &page_info); - - qh = page_info.buffer; - - /* init QH */ - qh->qh_self = htole32(page_info.physaddr | UHCI_PTR_QH); - qh->obj_next = last_obj; - qh->page_cache = pc + n; - - last_obj = qh; - - usb2_pc_cpu_flush(pc + n); - } - } - xfer->qh_start[xfer->flags_int.curr_dma_set] = last_obj; - - if (!xfer->flags_int.curr_dma_set) { - xfer->flags_int.curr_dma_set = 1; - goto alloc_dma_set; - } -} - -static void -uhci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, - struct usb2_pipe *pipe) -{ - uhci_softc_t *sc = UHCI_BUS2SC(udev->bus); - - DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", - pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, - sc->sc_addr); - - if (udev->flags.usb2_mode != USB_MODE_HOST) { - /* not supported */ - return; - } - if (udev->device_index == sc->sc_addr) { - switch (edesc->bEndpointAddress) { - case USB_CONTROL_ENDPOINT: - pipe->methods = &uhci_root_ctrl_methods; - break; - case UE_DIR_IN | UHCI_INTR_ENDPT: - pipe->methods = &uhci_root_intr_methods; - break; - default: - /* do nothing */ - break; - } - } else { - switch (edesc->bmAttributes & UE_XFERTYPE) { - case UE_CONTROL: - pipe->methods = &uhci_device_ctrl_methods; - break; - case UE_INTERRUPT: - pipe->methods = &uhci_device_intr_methods; - break; - case UE_ISOCHRONOUS: - if (udev->speed == USB_SPEED_FULL) { - pipe->methods = &uhci_device_isoc_methods; - } - break; - case UE_BULK: - if (udev->speed != USB_SPEED_LOW) { - pipe->methods = &uhci_device_bulk_methods; - } - break; - default: - /* do nothing */ - break; - } - } -} - -static void -uhci_xfer_unsetup(struct usb2_xfer *xfer) -{ - return; -} - -static void -uhci_get_dma_delay(struct usb2_bus *bus, uint32_t *pus) -{ - /* - * Wait until hardware has finished any possible use of the - * transfer descriptor(s) and QH - */ - *pus = (1125); /* microseconds */ -} - -static void -uhci_device_resume(struct usb2_device *udev) -{ - struct uhci_softc *sc = UHCI_BUS2SC(udev->bus); - struct usb2_xfer *xfer; - struct usb2_pipe_methods *methods; - uhci_qh_t *qh; - - DPRINTF("\n"); - - USB_BUS_LOCK(udev->bus); - - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - - if (xfer->xroot->udev == udev) { - - methods = xfer->pipe->methods; - qh = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - if (methods == &uhci_device_bulk_methods) { - UHCI_APPEND_QH(qh, sc->sc_bulk_p_last); - uhci_add_loop(sc); - xfer->flags_int.bandwidth_reclaimed = 1; - } - if (methods == &uhci_device_ctrl_methods) { - if (xfer->xroot->udev->speed == USB_SPEED_LOW) { - UHCI_APPEND_QH(qh, sc->sc_ls_ctl_p_last); - } else { - UHCI_APPEND_QH(qh, sc->sc_fs_ctl_p_last); - } - } - if (methods == &uhci_device_intr_methods) { - UHCI_APPEND_QH(qh, sc->sc_intr_p_last[xfer->qh_pos]); - } - } - } - - USB_BUS_UNLOCK(udev->bus); - - return; -} - -static void -uhci_device_suspend(struct usb2_device *udev) -{ - struct uhci_softc *sc = UHCI_BUS2SC(udev->bus); - struct usb2_xfer *xfer; - struct usb2_pipe_methods *methods; - uhci_qh_t *qh; - - DPRINTF("\n"); - - USB_BUS_LOCK(udev->bus); - - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - - if (xfer->xroot->udev == udev) { - - methods = xfer->pipe->methods; - qh = xfer->qh_start[xfer->flags_int.curr_dma_set]; - - if (xfer->flags_int.bandwidth_reclaimed) { - xfer->flags_int.bandwidth_reclaimed = 0; - uhci_rem_loop(sc); - } - if (methods == &uhci_device_bulk_methods) { - UHCI_REMOVE_QH(qh, sc->sc_bulk_p_last); - } - if (methods == &uhci_device_ctrl_methods) { - if (xfer->xroot->udev->speed == USB_SPEED_LOW) { - UHCI_REMOVE_QH(qh, sc->sc_ls_ctl_p_last); - } else { - UHCI_REMOVE_QH(qh, sc->sc_fs_ctl_p_last); - } - } - if (methods == &uhci_device_intr_methods) { - UHCI_REMOVE_QH(qh, sc->sc_intr_p_last[xfer->qh_pos]); - } - } - } - - USB_BUS_UNLOCK(udev->bus); - - return; -} - -static void -uhci_set_hw_power(struct usb2_bus *bus) -{ - struct uhci_softc *sc = UHCI_BUS2SC(bus); - uint32_t flags; - - DPRINTF("\n"); - - USB_BUS_LOCK(bus); - - flags = bus->hw_power_state; - - /* - * WARNING: Some FULL speed USB devices require periodic SOF - * messages! If any USB devices are connected through the - * UHCI, power save will be disabled! - */ - if (flags & (USB_HW_POWER_CONTROL | - USB_HW_POWER_NON_ROOT_HUB | - USB_HW_POWER_BULK | - USB_HW_POWER_INTERRUPT | - USB_HW_POWER_ISOC)) { - DPRINTF("Some USB transfer is " - "active on %u.\n", - device_get_unit(sc->sc_bus.bdev)); - UHCICMD(sc, (UHCI_CMD_MAXP | UHCI_CMD_RS)); - } else { - DPRINTF("Power save on %u.\n", - device_get_unit(sc->sc_bus.bdev)); - UHCICMD(sc, UHCI_CMD_MAXP); - } - - USB_BUS_UNLOCK(bus); - - return; -} - - -struct usb2_bus_methods uhci_bus_methods = -{ - .pipe_init = uhci_pipe_init, - .xfer_setup = uhci_xfer_setup, - .xfer_unsetup = uhci_xfer_unsetup, - .do_poll = uhci_do_poll, - .get_dma_delay = uhci_get_dma_delay, - .device_resume = uhci_device_resume, - .device_suspend = uhci_device_suspend, - .set_hw_power = uhci_set_hw_power, - .roothub_exec = uhci_root_ctrl_task, -}; diff --git a/sys/dev/usb2/controller/uhci2.h b/sys/dev/usb2/controller/uhci2.h deleted file mode 100644 index 9365a4c..0000000 --- a/sys/dev/usb2/controller/uhci2.h +++ /dev/null @@ -1,321 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Lennart Augustsson (lennart@augustsson.net) at - * Carlstedt Research & Technology. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _UHCI_H_ -#define _UHCI_H_ - -#define UHCI_MAX_DEVICES USB_MAX_DEVICES - -/* PCI config registers */ -#define PCI_USBREV 0x60 /* USB protocol revision */ -#define PCI_USB_REV_MASK 0xff -#define PCI_USB_REV_PRE_1_0 0x00 -#define PCI_USB_REV_1_0 0x10 -#define PCI_USB_REV_1_1 0x11 -#define PCI_LEGSUP 0xc0 /* Legacy Support register */ -#define PCI_LEGSUP_USBPIRQDEN 0x2000 /* USB PIRQ D Enable */ -#define PCI_CBIO 0x20 /* configuration base IO */ -#define PCI_INTERFACE_UHCI 0x00 - -/* UHCI registers */ -#define UHCI_CMD 0x00 -#define UHCI_CMD_RS 0x0001 -#define UHCI_CMD_HCRESET 0x0002 -#define UHCI_CMD_GRESET 0x0004 -#define UHCI_CMD_EGSM 0x0008 -#define UHCI_CMD_FGR 0x0010 -#define UHCI_CMD_SWDBG 0x0020 -#define UHCI_CMD_CF 0x0040 -#define UHCI_CMD_MAXP 0x0080 -#define UHCI_STS 0x02 -#define UHCI_STS_USBINT 0x0001 -#define UHCI_STS_USBEI 0x0002 -#define UHCI_STS_RD 0x0004 -#define UHCI_STS_HSE 0x0008 -#define UHCI_STS_HCPE 0x0010 -#define UHCI_STS_HCH 0x0020 -#define UHCI_STS_ALLINTRS 0x003f -#define UHCI_INTR 0x04 -#define UHCI_INTR_TOCRCIE 0x0001 -#define UHCI_INTR_RIE 0x0002 -#define UHCI_INTR_IOCE 0x0004 -#define UHCI_INTR_SPIE 0x0008 -#define UHCI_FRNUM 0x06 -#define UHCI_FRNUM_MASK 0x03ff -#define UHCI_FLBASEADDR 0x08 -#define UHCI_SOF 0x0c -#define UHCI_SOF_MASK 0x7f -#define UHCI_PORTSC1 0x010 -#define UHCI_PORTSC2 0x012 -#define UHCI_PORTSC_CCS 0x0001 -#define UHCI_PORTSC_CSC 0x0002 -#define UHCI_PORTSC_PE 0x0004 -#define UHCI_PORTSC_POEDC 0x0008 -#define UHCI_PORTSC_LS 0x0030 -#define UHCI_PORTSC_LS_SHIFT 4 -#define UHCI_PORTSC_RD 0x0040 -#define UHCI_PORTSC_LSDA 0x0100 -#define UHCI_PORTSC_PR 0x0200 -#define UHCI_PORTSC_OCI 0x0400 -#define UHCI_PORTSC_OCIC 0x0800 -#define UHCI_PORTSC_SUSP 0x1000 - -#define URWMASK(x) ((x) & (UHCI_PORTSC_SUSP | \ - UHCI_PORTSC_PR | UHCI_PORTSC_RD | \ - UHCI_PORTSC_PE)) - -#define UHCI_FRAMELIST_COUNT 1024 /* units */ -#define UHCI_FRAMELIST_ALIGN 4096 /* bytes */ - -/* Structures alignment (bytes) */ -#define UHCI_TD_ALIGN 16 -#define UHCI_QH_ALIGN 16 - -#if ((USB_PAGE_SIZE < UHCI_TD_ALIGN) || (UHCI_TD_ALIGN == 0) || \ - (USB_PAGE_SIZE < UHCI_QH_ALIGN) || (UHCI_QH_ALIGN == 0)) -#error "Invalid USB page size!" -#endif - -typedef uint32_t uhci_physaddr_t; - -#define UHCI_PTR_T 0x00000001 -#define UHCI_PTR_TD 0x00000000 -#define UHCI_PTR_QH 0x00000002 -#define UHCI_PTR_VF 0x00000004 - -#define UHCI_QH_REMOVE_DELAY 5 /* us - QH remove delay */ - -/* - * The Queue Heads (QH) and Transfer Descriptors (TD) are accessed by - * both the CPU and the USB-controller which run concurrently. Great - * care must be taken. When the data-structures are linked into the - * USB controller's frame list, the USB-controller "owns" the - * td_status and qh_elink fields, which will not be written by the - * CPU. - * - */ - -struct uhci_td { -/* - * Data used by the UHCI controller. - * volatile is used in order to mantain struct members ordering. - */ - volatile uint32_t td_next; - volatile uint32_t td_status; -#define UHCI_TD_GET_ACTLEN(s) (((s) + 1) & 0x3ff) -#define UHCI_TD_ZERO_ACTLEN(t) ((t) | 0x3ff) -#define UHCI_TD_BITSTUFF 0x00020000 -#define UHCI_TD_CRCTO 0x00040000 -#define UHCI_TD_NAK 0x00080000 -#define UHCI_TD_BABBLE 0x00100000 -#define UHCI_TD_DBUFFER 0x00200000 -#define UHCI_TD_STALLED 0x00400000 -#define UHCI_TD_ACTIVE 0x00800000 -#define UHCI_TD_IOC 0x01000000 -#define UHCI_TD_IOS 0x02000000 -#define UHCI_TD_LS 0x04000000 -#define UHCI_TD_GET_ERRCNT(s) (((s) >> 27) & 3) -#define UHCI_TD_SET_ERRCNT(n) ((n) << 27) -#define UHCI_TD_SPD 0x20000000 - volatile uint32_t td_token; -#define UHCI_TD_PID 0x000000ff -#define UHCI_TD_PID_IN 0x00000069 -#define UHCI_TD_PID_OUT 0x000000e1 -#define UHCI_TD_PID_SETUP 0x0000002d -#define UHCI_TD_GET_PID(s) ((s) & 0xff) -#define UHCI_TD_SET_DEVADDR(a) ((a) << 8) -#define UHCI_TD_GET_DEVADDR(s) (((s) >> 8) & 0x7f) -#define UHCI_TD_SET_ENDPT(e) (((e) & 0xf) << 15) -#define UHCI_TD_GET_ENDPT(s) (((s) >> 15) & 0xf) -#define UHCI_TD_SET_DT(t) ((t) << 19) -#define UHCI_TD_GET_DT(s) (((s) >> 19) & 1) -#define UHCI_TD_SET_MAXLEN(l) (((l)-1) << 21) -#define UHCI_TD_GET_MAXLEN(s) ((((s) >> 21) + 1) & 0x7ff) -#define UHCI_TD_MAXLEN_MASK 0xffe00000 - volatile uint32_t td_buffer; -/* - * Extra information needed: - */ - struct uhci_td *next; - struct uhci_td *prev; - struct uhci_td *obj_next; - struct usb2_page_cache *page_cache; - struct usb2_page_cache *fix_pc; - uint32_t td_self; - uint16_t len; -} __aligned(UHCI_TD_ALIGN); - -typedef struct uhci_td uhci_td_t; - -#define UHCI_TD_ERROR (UHCI_TD_BITSTUFF | UHCI_TD_CRCTO | \ - UHCI_TD_BABBLE | UHCI_TD_DBUFFER | UHCI_TD_STALLED) - -#define UHCI_TD_SETUP(len, endp, dev) (UHCI_TD_SET_MAXLEN(len) | \ - UHCI_TD_SET_ENDPT(endp) | \ - UHCI_TD_SET_DEVADDR(dev) | \ - UHCI_TD_PID_SETUP) - -#define UHCI_TD_OUT(len, endp, dev, dt) (UHCI_TD_SET_MAXLEN(len) | \ - UHCI_TD_SET_ENDPT(endp) | \ - UHCI_TD_SET_DEVADDR(dev) | \ - UHCI_TD_PID_OUT | UHCI_TD_SET_DT(dt)) - -#define UHCI_TD_IN(len, endp, dev, dt) (UHCI_TD_SET_MAXLEN(len) | \ - UHCI_TD_SET_ENDPT(endp) | \ - UHCI_TD_SET_DEVADDR(dev) | \ - UHCI_TD_PID_IN | UHCI_TD_SET_DT(dt)) - -struct uhci_qh { -/* - * Data used by the UHCI controller. - */ - volatile uint32_t qh_h_next; - volatile uint32_t qh_e_next; -/* - * Extra information needed: - */ - struct uhci_qh *h_next; - struct uhci_qh *h_prev; - struct uhci_qh *obj_next; - struct uhci_td *e_next; - struct usb2_page_cache *page_cache; - uint32_t qh_self; - uint16_t intr_pos; -} __aligned(UHCI_QH_ALIGN); - -typedef struct uhci_qh uhci_qh_t; - -/* Maximum number of isochronous TD's and QH's interrupt */ -#define UHCI_VFRAMELIST_COUNT 128 -#define UHCI_IFRAMELIST_COUNT (2 * UHCI_VFRAMELIST_COUNT) - -#if (((UHCI_VFRAMELIST_COUNT & (UHCI_VFRAMELIST_COUNT-1)) != 0) || \ - (UHCI_VFRAMELIST_COUNT > UHCI_FRAMELIST_COUNT)) -#error "UHCI_VFRAMELIST_COUNT is not power of two" -#error "or UHCI_VFRAMELIST_COUNT > UHCI_FRAMELIST_COUNT" -#endif - -#if (UHCI_VFRAMELIST_COUNT < USB_MAX_FS_ISOC_FRAMES_PER_XFER) -#error "maximum number of full-speed isochronous frames is higher than supported!" -#endif - -struct uhci_config_desc { - struct usb2_config_descriptor confd; - struct usb2_interface_descriptor ifcd; - struct usb2_endpoint_descriptor endpd; -} __packed; - -union uhci_hub_desc { - struct usb2_status stat; - struct usb2_port_status ps; - struct usb2_device_descriptor devd; - uint8_t temp[128]; -}; - -struct uhci_hw_softc { - struct usb2_page_cache pframes_pc; - struct usb2_page_cache isoc_start_pc[UHCI_VFRAMELIST_COUNT]; - struct usb2_page_cache intr_start_pc[UHCI_IFRAMELIST_COUNT]; - struct usb2_page_cache ls_ctl_start_pc; - struct usb2_page_cache fs_ctl_start_pc; - struct usb2_page_cache bulk_start_pc; - struct usb2_page_cache last_qh_pc; - struct usb2_page_cache last_td_pc; - - struct usb2_page pframes_pg; - struct usb2_page isoc_start_pg[UHCI_VFRAMELIST_COUNT]; - struct usb2_page intr_start_pg[UHCI_IFRAMELIST_COUNT]; - struct usb2_page ls_ctl_start_pg; - struct usb2_page fs_ctl_start_pg; - struct usb2_page bulk_start_pg; - struct usb2_page last_qh_pg; - struct usb2_page last_td_pg; -}; - -typedef struct uhci_softc { - struct uhci_hw_softc sc_hw; - struct usb2_bus sc_bus; /* base device */ - union uhci_hub_desc sc_hub_desc; - struct usb2_sw_transfer sc_root_ctrl; - struct usb2_sw_transfer sc_root_intr; - - struct usb2_device *sc_devices[UHCI_MAX_DEVICES]; - struct uhci_td *sc_isoc_p_last[UHCI_VFRAMELIST_COUNT]; /* pointer to last TD - * for isochronous */ - struct uhci_qh *sc_intr_p_last[UHCI_IFRAMELIST_COUNT]; /* pointer to last QH - * for interrupt */ - struct uhci_qh *sc_ls_ctl_p_last; /* pointer to last QH for low - * speed control */ - struct uhci_qh *sc_fs_ctl_p_last; /* pointer to last QH for full - * speed control */ - struct uhci_qh *sc_bulk_p_last; /* pointer to last QH for bulk */ - struct uhci_qh *sc_reclaim_qh_p; - struct uhci_qh *sc_last_qh_p; - struct uhci_td *sc_last_td_p; - struct resource *sc_io_res; - struct resource *sc_irq_res; - void *sc_intr_hdl; - device_t sc_dev; - bus_size_t sc_io_size; - bus_space_tag_t sc_io_tag; - bus_space_handle_t sc_io_hdl; - - uint32_t sc_loops; /* number of QHs that wants looping */ - - uint16_t sc_intr_stat[UHCI_IFRAMELIST_COUNT]; - uint16_t sc_saved_frnum; - - uint8_t sc_addr; /* device address */ - uint8_t sc_conf; /* device configuration */ - uint8_t sc_isreset; /* bits set if a root hub is reset */ - uint8_t sc_isresumed; /* bits set if a port was resumed */ - uint8_t sc_saved_sof; - uint8_t sc_hub_idata[1]; - - char sc_vendor[16]; /* vendor string for root hub */ -} uhci_softc_t; - -usb2_bus_mem_cb_t uhci_iterate_hw_softc; - -usb2_error_t uhci_init(uhci_softc_t *sc); -void uhci_suspend(uhci_softc_t *sc); -void uhci_resume(uhci_softc_t *sc); -void uhci_reset(uhci_softc_t *sc); -void uhci_interrupt(uhci_softc_t *sc); - -#endif /* _UHCI_H_ */ diff --git a/sys/dev/usb2/controller/uhci2_pci.c b/sys/dev/usb2/controller/uhci2_pci.c deleted file mode 100644 index 725cd84..0000000 --- a/sys/dev/usb2/controller/uhci2_pci.c +++ /dev/null @@ -1,444 +0,0 @@ -/*- - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Lennart Augustsson (augustss@carlstedt.se) at - * Carlstedt Research & Technology. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* Universal Host Controller Interface - * - * UHCI spec: http://www.intel.com/ - */ - -/* The low level controller code for UHCI has been split into - * PCI probes and UHCI specific code. This was done to facilitate the - * sharing of code between *BSD's - */ - -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_defs.h> -#include <dev/usb2/include/usb2_standard.h> - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_util.h> -#include <dev/usb2/core/usb2_debug.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/usb2_pci.h> -#include <dev/usb2/controller/uhci2.h> - -#define PCI_UHCI_VENDORID_INTEL 0x8086 -#define PCI_UHCI_VENDORID_VIA 0x1106 - -/* PIIX4E has no separate stepping */ - -#define PCI_UHCI_BASE_REG 0x20 - -static device_probe_t uhci_pci_probe; -static device_attach_t uhci_pci_attach; -static device_detach_t uhci_pci_detach; -static device_suspend_t uhci_pci_suspend; -static device_resume_t uhci_pci_resume; - -static int -uhci_pci_suspend(device_t self) -{ - uhci_softc_t *sc = device_get_softc(self); - int err; - - err = bus_generic_suspend(self); - if (err) { - return (err); - } - uhci_suspend(sc); - return (0); -} - -static int -uhci_pci_resume(device_t self) -{ - uhci_softc_t *sc = device_get_softc(self); - - pci_write_config(self, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN, 2); - - uhci_resume(sc); - - bus_generic_resume(self); - return (0); -} - -static const char * -uhci_pci_match(device_t self) -{ - uint32_t device_id = pci_get_devid(self); - - switch (device_id) { - case 0x26888086: - return ("Intel 631XESB/632XESB/3100 USB controller USB-1"); - - case 0x26898086: - return ("Intel 631XESB/632XESB/3100 USB controller USB-2"); - - case 0x268a8086: - return ("Intel 631XESB/632XESB/3100 USB controller USB-3"); - - case 0x268b8086: - return ("Intel 631XESB/632XESB/3100 USB controller USB-4"); - - case 0x70208086: - return ("Intel 82371SB (PIIX3) USB controller"); - - case 0x71128086: - return ("Intel 82371AB/EB (PIIX4) USB controller"); - - case 0x24128086: - return ("Intel 82801AA (ICH) USB controller"); - - case 0x24228086: - return ("Intel 82801AB (ICH0) USB controller"); - - case 0x24428086: - return ("Intel 82801BA/BAM (ICH2) USB controller USB-A"); - - case 0x24448086: - return ("Intel 82801BA/BAM (ICH2) USB controller USB-B"); - - case 0x24828086: - return ("Intel 82801CA/CAM (ICH3) USB controller USB-A"); - - case 0x24848086: - return ("Intel 82801CA/CAM (ICH3) USB controller USB-B"); - - case 0x24878086: - return ("Intel 82801CA/CAM (ICH3) USB controller USB-C"); - - case 0x24c28086: - return ("Intel 82801DB (ICH4) USB controller USB-A"); - - case 0x24c48086: - return ("Intel 82801DB (ICH4) USB controller USB-B"); - - case 0x24c78086: - return ("Intel 82801DB (ICH4) USB controller USB-C"); - - case 0x24d28086: - return ("Intel 82801EB (ICH5) USB controller USB-A"); - - case 0x24d48086: - return ("Intel 82801EB (ICH5) USB controller USB-B"); - - case 0x24d78086: - return ("Intel 82801EB (ICH5) USB controller USB-C"); - - case 0x24de8086: - return ("Intel 82801EB (ICH5) USB controller USB-D"); - - case 0x26588086: - return ("Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-A"); - - case 0x26598086: - return ("Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-B"); - - case 0x265a8086: - return ("Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-C"); - - case 0x265b8086: - return ("Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-D"); - - case 0x28308086: - return ("Intel 82801H (ICH8) USB controller USB-A"); - case 0x28318086: - return ("Intel 82801H (ICH8) USB controller USB-B"); - case 0x28328086: - return ("Intel 82801H (ICH8) USB controller USB-C"); - case 0x28348086: - return ("Intel 82801H (ICH8) USB controller USB-D"); - case 0x28358086: - return ("Intel 82801H (ICH8) USB controller USB-E"); - case 0x29348086: - return ("Intel 82801I (ICH9) USB controller"); - case 0x29358086: - return ("Intel 82801I (ICH9) USB controller"); - case 0x29368086: - return ("Intel 82801I (ICH9) USB controller"); - case 0x29378086: - return ("Intel 82801I (ICH9) USB controller"); - case 0x29388086: - return ("Intel 82801I (ICH9) USB controller"); - case 0x29398086: - return ("Intel 82801I (ICH9) USB controller"); - - case 0x719a8086: - return ("Intel 82443MX USB controller"); - - case 0x76028086: - return ("Intel 82372FB/82468GX USB controller"); - - case 0x30381106: - return ("VIA 83C572 USB controller"); - - default: - break; - } - - if ((pci_get_class(self) == PCIC_SERIALBUS) && - (pci_get_subclass(self) == PCIS_SERIALBUS_USB) && - (pci_get_progif(self) == PCI_INTERFACE_UHCI)) { - return ("UHCI (generic) USB controller"); - } - return (NULL); -} - -static int -uhci_pci_probe(device_t self) -{ - const char *desc = uhci_pci_match(self); - - if (desc) { - device_set_desc(self, desc); - return (0); - } else { - return (ENXIO); - } -} - -static int -uhci_pci_attach(device_t self) -{ - uhci_softc_t *sc = device_get_softc(self); - int rid; - int err; - - /* initialise some bus fields */ - sc->sc_bus.parent = self; - sc->sc_bus.devices = sc->sc_devices; - sc->sc_bus.devices_max = UHCI_MAX_DEVICES; - - /* get all DMA memory */ - if (usb2_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(self), - &uhci_iterate_hw_softc)) { - return ENOMEM; - } - sc->sc_dev = self; - - pci_enable_busmaster(self); - - rid = PCI_UHCI_BASE_REG; - sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_IOPORT, &rid, - RF_ACTIVE); - if (!sc->sc_io_res) { - device_printf(self, "Could not map ports\n"); - goto error; - } - sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); - sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); - sc->sc_io_size = rman_get_size(sc->sc_io_res); - - /* disable interrupts */ - bus_space_write_2(sc->sc_io_tag, sc->sc_io_hdl, UHCI_INTR, 0); - - rid = 0; - sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (sc->sc_irq_res == NULL) { - device_printf(self, "Could not allocate irq\n"); - goto error; - } - sc->sc_bus.bdev = device_add_child(self, "usbus", -1); - if (!sc->sc_bus.bdev) { - device_printf(self, "Could not add USB device\n"); - goto error; - } - device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); - - /* - * uhci_pci_match must never return NULL if uhci_pci_probe - * succeeded - */ - device_set_desc(sc->sc_bus.bdev, uhci_pci_match(self)); - switch (pci_get_vendor(self)) { - case PCI_UHCI_VENDORID_INTEL: - sprintf(sc->sc_vendor, "Intel"); - break; - case PCI_UHCI_VENDORID_VIA: - sprintf(sc->sc_vendor, "VIA"); - break; - default: - if (bootverbose) { - device_printf(self, "(New UHCI DeviceId=0x%08x)\n", - pci_get_devid(self)); - } - sprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self)); - } - - switch (pci_read_config(self, PCI_USBREV, 1) & PCI_USB_REV_MASK) { - case PCI_USB_REV_PRE_1_0: - sc->sc_bus.usbrev = USB_REV_PRE_1_0; - break; - case PCI_USB_REV_1_0: - sc->sc_bus.usbrev = USB_REV_1_0; - break; - default: - /* Quirk for Parallels Desktop 4.0 */ - device_printf(self, "USB revision is unknown. Assuming v1.1.\n"); - sc->sc_bus.usbrev = USB_REV_1_1; - break; - } - -#if (__FreeBSD_version >= 700031) - err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)(void *)uhci_interrupt, sc, &sc->sc_intr_hdl); -#else - err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)(void *)uhci_interrupt, sc, &sc->sc_intr_hdl); -#endif - - if (err) { - device_printf(self, "Could not setup irq, %d\n", err); - sc->sc_intr_hdl = NULL; - goto error; - } - /* - * Set the PIRQD enable bit and switch off all the others. We don't - * want legacy support to interfere with us XXX Does this also mean - * that the BIOS won't touch the keyboard anymore if it is connected - * to the ports of the root hub? - */ -#if USB_DEBUG - if (pci_read_config(self, PCI_LEGSUP, 2) != PCI_LEGSUP_USBPIRQDEN) { - device_printf(self, "LegSup = 0x%04x\n", - pci_read_config(self, PCI_LEGSUP, 2)); - } -#endif - pci_write_config(self, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN, 2); - - err = uhci_init(sc); - if (!err) { - err = device_probe_and_attach(sc->sc_bus.bdev); - } - if (err) { - device_printf(self, "USB init failed\n"); - goto error; - } - return (0); - -error: - uhci_pci_detach(self); - return (ENXIO); -} - -int -uhci_pci_detach(device_t self) -{ - uhci_softc_t *sc = device_get_softc(self); - device_t bdev; - - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } - /* during module unload there are lots of children leftover */ - device_delete_all_children(self); - - /* - * disable interrupts that might have been switched on in - * uhci_init. - */ - if (sc->sc_io_res) { - USB_BUS_LOCK(&sc->sc_bus); - - /* stop the controller */ - uhci_reset(sc); - - USB_BUS_UNLOCK(&sc->sc_bus); - } - pci_disable_busmaster(self); - - if (sc->sc_irq_res && sc->sc_intr_hdl) { - int err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); - - if (err) { - /* XXX or should we panic? */ - device_printf(self, "Could not tear down irq, %d\n", - err); - } - sc->sc_intr_hdl = NULL; - } - if (sc->sc_irq_res) { - bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); - sc->sc_irq_res = NULL; - } - if (sc->sc_io_res) { - bus_release_resource(self, SYS_RES_IOPORT, PCI_UHCI_BASE_REG, - sc->sc_io_res); - sc->sc_io_res = NULL; - } - usb2_bus_mem_free_all(&sc->sc_bus, &uhci_iterate_hw_softc); - - return (0); -} - -static driver_t uhci_driver = -{ - .name = "uhci", - .methods = (device_method_t[]){ - /* device interface */ - DEVMETHOD(device_probe, uhci_pci_probe), - DEVMETHOD(device_attach, uhci_pci_attach), - DEVMETHOD(device_detach, uhci_pci_detach), - - DEVMETHOD(device_suspend, uhci_pci_suspend), - DEVMETHOD(device_resume, uhci_pci_resume), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - {0, 0} - }, - .size = sizeof(struct uhci_softc), -}; - -static devclass_t uhci_devclass; - -DRIVER_MODULE(uhci, pci, uhci_driver, uhci_devclass, 0, 0); -DRIVER_MODULE(uhci, cardbus, uhci_driver, uhci_devclass, 0, 0); -MODULE_DEPEND(uhci, usb2_controller, 1, 1, 1); -MODULE_DEPEND(uhci, usb2_core, 1, 1, 1); diff --git a/sys/dev/usb2/controller/usb2_bus.h b/sys/dev/usb2/controller/usb2_bus.h deleted file mode 100644 index 59287c4..0000000 --- a/sys/dev/usb2/controller/usb2_bus.h +++ /dev/null @@ -1,104 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _USB2_BUS_H_ -#define _USB2_BUS_H_ - -/* - * The following structure defines the USB explore message sent to the - * USB explore process. - */ - -struct usb2_bus_msg { - struct usb2_proc_msg hdr; - struct usb2_bus *bus; -}; - -/* - * The following structure defines the USB statistics structure. - */ -struct usb2_bus_stat { - uint32_t uds_requests[4]; -}; - -/* - * The following structure defines an USB BUS. There is one USB BUS - * for every Host or Device controller. - */ -struct usb2_bus { - struct usb2_bus_stat stats_err; - struct usb2_bus_stat stats_ok; - struct usb2_process explore_proc; - struct usb2_process roothub_proc; - struct root_hold_token *bus_roothold; - /* - * There are two callback processes. One for Giant locked - * callbacks. One for non-Giant locked callbacks. This should - * avoid congestion and reduce response time in most cases. - */ - struct usb2_process giant_callback_proc; - struct usb2_process non_giant_callback_proc; - struct usb2_bus_msg explore_msg[2]; - struct usb2_bus_msg detach_msg[2]; - struct usb2_bus_msg attach_msg[2]; - struct usb2_bus_msg roothub_msg[2]; - /* - * This mutex protects the USB hardware: - */ - struct mtx bus_mtx; - struct usb2_perm perm; - struct usb2_xfer_queue intr_q; - struct usb2_callout power_wdog; /* power management */ - - device_t parent; - device_t bdev; /* filled by HC driver */ - - struct usb2_dma_parent_tag dma_parent_tag[1]; - struct usb2_dma_tag dma_tags[USB_BUS_DMA_TAG_MAX]; - - struct usb2_bus_methods *methods; /* filled by HC driver */ - struct usb2_device **devices; - - uint32_t hw_power_state; /* see USB_HW_POWER_XXX */ - uint32_t uframe_usage[USB_HS_MICRO_FRAMES_MAX]; - uint32_t transfer_count[4]; - uint16_t isoc_time_last; /* in milliseconds */ - - uint8_t alloc_failed; /* Set if memory allocation failed. */ - uint8_t driver_added_refcount; /* Current driver generation count */ - uint8_t usbrev; /* USB revision. See "USB_REV_XXX". */ - - uint8_t devices_max; /* maximum number of USB devices */ - uint8_t do_probe; /* set if USB BUS should be re-probed */ - - union { - struct usb2_hw_ep_scratch hw_ep_scratch[1]; - struct usb2_temp_setup temp_setup[1]; - uint8_t data[128]; - } scratch[1]; -}; - -#endif /* _USB2_BUS_H_ */ diff --git a/sys/dev/usb2/controller/usb2_controller.c b/sys/dev/usb2/controller/usb2_controller.c deleted file mode 100644 index cd334ab..0000000 --- a/sys/dev/usb2/controller/usb2_controller.c +++ /dev/null @@ -1,623 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_defs.h> -#include <dev/usb2/include/usb2_error.h> -#include <dev/usb2/include/usb2_standard.h> - -#define USB_DEBUG_VAR usb2_ctrl_debug - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_debug.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_dynamic.h> -#include <dev/usb2/core/usb2_device.h> -#include <dev/usb2/core/usb2_hub.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> - -/* function prototypes */ - -static device_probe_t usb2_probe; -static device_attach_t usb2_attach; -static device_detach_t usb2_detach; - -static void usb2_attach_sub(device_t, struct usb2_bus *); -static void usb2_post_init(void *); -static void usb2_bus_mem_flush_all_cb(struct usb2_bus *, - struct usb2_page_cache *, struct usb2_page *, uint32_t, - uint32_t); -static void usb2_bus_mem_alloc_all_cb(struct usb2_bus *, - struct usb2_page_cache *, struct usb2_page *, uint32_t, - uint32_t); -static void usb2_bus_mem_free_all_cb(struct usb2_bus *, - struct usb2_page_cache *, struct usb2_page *, uint32_t, - uint32_t); -static void usb2_bus_roothub(struct usb2_proc_msg *pm); - -/* static variables */ - -#if USB_DEBUG -static int usb2_ctrl_debug = 0; - -SYSCTL_NODE(_hw_usb2, OID_AUTO, ctrl, CTLFLAG_RW, 0, "USB controller"); -SYSCTL_INT(_hw_usb2_ctrl, OID_AUTO, debug, CTLFLAG_RW, &usb2_ctrl_debug, 0, - "Debug level"); -#endif - -static uint8_t usb2_post_init_called = 0; - -static devclass_t usb2_devclass; - -static device_method_t usb2_methods[] = { - DEVMETHOD(device_probe, usb2_probe), - DEVMETHOD(device_attach, usb2_attach), - DEVMETHOD(device_detach, usb2_detach), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - {0, 0} -}; - -static driver_t usb2_driver = { - .name = "usbus", - .methods = usb2_methods, - .size = 0, -}; - -DRIVER_MODULE(usbus, ohci, usb2_driver, usb2_devclass, 0, 0); -DRIVER_MODULE(usbus, uhci, usb2_driver, usb2_devclass, 0, 0); -DRIVER_MODULE(usbus, ehci, usb2_driver, usb2_devclass, 0, 0); -DRIVER_MODULE(usbus, at91_udp, usb2_driver, usb2_devclass, 0, 0); -DRIVER_MODULE(usbus, uss820, usb2_driver, usb2_devclass, 0, 0); - -MODULE_DEPEND(usb2_controller, usb2_core, 1, 1, 1); -MODULE_VERSION(usb2_controller, 1); - -/*------------------------------------------------------------------------* - * usb2_probe - * - * This function is called from "{ehci,ohci,uhci}_pci_attach()". - *------------------------------------------------------------------------*/ -static int -usb2_probe(device_t dev) -{ - DPRINTF("\n"); - return (0); -} - -/*------------------------------------------------------------------------* - * usb2_attach - *------------------------------------------------------------------------*/ -static int -usb2_attach(device_t dev) -{ - struct usb2_bus *bus = device_get_ivars(dev); - - DPRINTF("\n"); - - if (bus == NULL) { - DPRINTFN(0, "USB device has no ivars\n"); - return (ENXIO); - } - - /* delay vfs_mountroot until the bus is explored */ - bus->bus_roothold = root_mount_hold(device_get_nameunit(dev)); - - if (usb2_post_init_called) { - mtx_lock(&Giant); - usb2_attach_sub(dev, bus); - mtx_unlock(&Giant); - usb2_needs_explore(bus, 1); - } - return (0); /* return success */ -} - -/*------------------------------------------------------------------------* - * usb2_detach - *------------------------------------------------------------------------*/ -static int -usb2_detach(device_t dev) -{ - struct usb2_bus *bus = device_get_softc(dev); - - DPRINTF("\n"); - - if (bus == NULL) { - /* was never setup properly */ - return (0); - } - /* Stop power watchdog */ - usb2_callout_drain(&bus->power_wdog); - - /* Let the USB explore process detach all devices. */ - if (bus->bus_roothold != NULL) { - root_mount_rel(bus->bus_roothold); - bus->bus_roothold = NULL; - } - - USB_BUS_LOCK(bus); - if (usb2_proc_msignal(&bus->explore_proc, - &bus->detach_msg[0], &bus->detach_msg[1])) { - /* ignore */ - } - /* Wait for detach to complete */ - - usb2_proc_mwait(&bus->explore_proc, - &bus->detach_msg[0], &bus->detach_msg[1]); - - USB_BUS_UNLOCK(bus); - - /* Get rid of USB callback processes */ - - usb2_proc_free(&bus->giant_callback_proc); - usb2_proc_free(&bus->non_giant_callback_proc); - - /* Get rid of USB roothub process */ - - usb2_proc_free(&bus->roothub_proc); - - /* Get rid of USB explore process */ - - usb2_proc_free(&bus->explore_proc); - - return (0); -} - -/*------------------------------------------------------------------------* - * usb2_bus_explore - * - * This function is used to explore the device tree from the root. - *------------------------------------------------------------------------*/ -static void -usb2_bus_explore(struct usb2_proc_msg *pm) -{ - struct usb2_bus *bus; - struct usb2_device *udev; - - bus = ((struct usb2_bus_msg *)pm)->bus; - udev = bus->devices[USB_ROOT_HUB_ADDR]; - - if (udev && udev->hub) { - - if (bus->do_probe) { - bus->do_probe = 0; - bus->driver_added_refcount++; - } - if (bus->driver_added_refcount == 0) { - /* avoid zero, hence that is memory default */ - bus->driver_added_refcount = 1; - } - USB_BUS_UNLOCK(bus); - - mtx_lock(&Giant); - - /* - * First update the USB power state! - */ - usb2_bus_powerd(bus); - - /* - * Explore the Root USB HUB. This call can sleep, - * exiting Giant, which is actually Giant. - */ - (udev->hub->explore) (udev); - - mtx_unlock(&Giant); - - USB_BUS_LOCK(bus); - } - if (bus->bus_roothold != NULL) { - root_mount_rel(bus->bus_roothold); - bus->bus_roothold = NULL; - } -} - -/*------------------------------------------------------------------------* - * usb2_bus_detach - * - * This function is used to detach the device tree from the root. - *------------------------------------------------------------------------*/ -static void -usb2_bus_detach(struct usb2_proc_msg *pm) -{ - struct usb2_bus *bus; - struct usb2_device *udev; - device_t dev; - - bus = ((struct usb2_bus_msg *)pm)->bus; - udev = bus->devices[USB_ROOT_HUB_ADDR]; - dev = bus->bdev; - /* clear the softc */ - device_set_softc(dev, NULL); - USB_BUS_UNLOCK(bus); - - mtx_lock(&Giant); - - /* detach children first */ - bus_generic_detach(dev); - - /* - * Free USB Root device, but not any sub-devices, hence they - * are freed by the caller of this function: - */ - usb2_detach_device(udev, USB_IFACE_INDEX_ANY, 0); - usb2_free_device(udev); - - mtx_unlock(&Giant); - USB_BUS_LOCK(bus); - /* clear bdev variable last */ - bus->bdev = NULL; -} - -static void -usb2_power_wdog(void *arg) -{ - struct usb2_bus *bus = arg; - - USB_BUS_LOCK_ASSERT(bus, MA_OWNED); - - usb2_callout_reset(&bus->power_wdog, - 4 * hz, usb2_power_wdog, arg); - - USB_BUS_UNLOCK(bus); - - usb2_bus_power_update(bus); - - return; -} - -/*------------------------------------------------------------------------* - * usb2_bus_attach - * - * This function attaches USB in context of the explore thread. - *------------------------------------------------------------------------*/ -static void -usb2_bus_attach(struct usb2_proc_msg *pm) -{ - struct usb2_bus *bus; - struct usb2_device *child; - device_t dev; - usb2_error_t err; - uint8_t speed; - - bus = ((struct usb2_bus_msg *)pm)->bus; - dev = bus->bdev; - - DPRINTF("\n"); - - switch (bus->usbrev) { - case USB_REV_1_0: - speed = USB_SPEED_FULL; - device_printf(bus->bdev, "12Mbps Full Speed USB v1.0\n"); - break; - - case USB_REV_1_1: - speed = USB_SPEED_FULL; - device_printf(bus->bdev, "12Mbps Full Speed USB v1.1\n"); - break; - - case USB_REV_2_0: - speed = USB_SPEED_HIGH; - device_printf(bus->bdev, "480Mbps High Speed USB v2.0\n"); - break; - - case USB_REV_2_5: - speed = USB_SPEED_VARIABLE; - device_printf(bus->bdev, "480Mbps Wireless USB v2.5\n"); - break; - - default: - device_printf(bus->bdev, "Unsupported USB revision!\n"); - return; - } - - USB_BUS_UNLOCK(bus); - mtx_lock(&Giant); /* XXX not required by USB */ - - /* Allocate the Root USB device */ - - child = usb2_alloc_device(bus->bdev, bus, NULL, 0, 0, 1, - speed, USB_MODE_HOST); - if (child) { - err = usb2_probe_and_attach(child, - USB_IFACE_INDEX_ANY); - if (!err) { - if (!bus->devices[USB_ROOT_HUB_ADDR]->hub) { - err = USB_ERR_NO_ROOT_HUB; - } - } - } else { - err = USB_ERR_NOMEM; - } - - mtx_unlock(&Giant); - USB_BUS_LOCK(bus); - - if (err) { - device_printf(bus->bdev, "Root HUB problem, error=%s\n", - usb2_errstr(err)); - } - - /* set softc - we are ready */ - device_set_softc(dev, bus); - - /* start watchdog - this function will unlock the BUS lock ! */ - usb2_power_wdog(bus); - - /* need to return locked */ - USB_BUS_LOCK(bus); -} - -/*------------------------------------------------------------------------* - * usb2_attach_sub - * - * This function creates a thread which runs the USB attach code. It - * is factored out, hence it can be called at two different places in - * time. During bootup this function is called from - * "usb2_post_init". During hot-plug it is called directly from the - * "usb2_attach()" method. - *------------------------------------------------------------------------*/ -static void -usb2_attach_sub(device_t dev, struct usb2_bus *bus) -{ - const char *pname = device_get_nameunit(dev); - - /* Initialise USB process messages */ - bus->explore_msg[0].hdr.pm_callback = &usb2_bus_explore; - bus->explore_msg[0].bus = bus; - bus->explore_msg[1].hdr.pm_callback = &usb2_bus_explore; - bus->explore_msg[1].bus = bus; - - bus->detach_msg[0].hdr.pm_callback = &usb2_bus_detach; - bus->detach_msg[0].bus = bus; - bus->detach_msg[1].hdr.pm_callback = &usb2_bus_detach; - bus->detach_msg[1].bus = bus; - - bus->attach_msg[0].hdr.pm_callback = &usb2_bus_attach; - bus->attach_msg[0].bus = bus; - bus->attach_msg[1].hdr.pm_callback = &usb2_bus_attach; - bus->attach_msg[1].bus = bus; - - bus->roothub_msg[0].hdr.pm_callback = &usb2_bus_roothub; - bus->roothub_msg[0].bus = bus; - bus->roothub_msg[1].hdr.pm_callback = &usb2_bus_roothub; - bus->roothub_msg[1].bus = bus; - - /* Create USB explore, roothub and callback processes */ - - if (usb2_proc_create(&bus->giant_callback_proc, - &bus->bus_mtx, pname, USB_PRI_MED)) { - printf("WARNING: Creation of USB Giant " - "callback process failed.\n"); - } else if (usb2_proc_create(&bus->non_giant_callback_proc, - &bus->bus_mtx, pname, USB_PRI_HIGH)) { - printf("WARNING: Creation of USB non-Giant " - "callback process failed.\n"); - } else if (usb2_proc_create(&bus->roothub_proc, - &bus->bus_mtx, pname, USB_PRI_HIGH)) { - printf("WARNING: Creation of USB roothub " - "process failed.\n"); - } else if (usb2_proc_create(&bus->explore_proc, - &bus->bus_mtx, pname, USB_PRI_MED)) { - printf("WARNING: Creation of USB explore " - "process failed.\n"); - } else { - /* Get final attach going */ - USB_BUS_LOCK(bus); - if (usb2_proc_msignal(&bus->explore_proc, - &bus->attach_msg[0], &bus->attach_msg[1])) { - /* ignore */ - } - USB_BUS_UNLOCK(bus); - } -} - -/*------------------------------------------------------------------------* - * usb2_post_init - * - * This function is called to attach all USB busses that were found - * during bootup. - *------------------------------------------------------------------------*/ -static void -usb2_post_init(void *arg) -{ - struct usb2_bus *bus; - devclass_t dc; - device_t dev; - int max; - int n; - - mtx_lock(&Giant); - - usb2_devclass_ptr = devclass_find("usbus"); - - dc = usb2_devclass_ptr; - if (dc) { - max = devclass_get_maxunit(dc) + 1; - for (n = 0; n != max; n++) { - dev = devclass_get_device(dc, n); - if (dev && device_is_attached(dev)) { - bus = device_get_ivars(dev); - if (bus) { - mtx_lock(&Giant); - usb2_attach_sub(dev, bus); - mtx_unlock(&Giant); - } - } - } - } else { - DPRINTFN(0, "no devclass\n"); - } - usb2_post_init_called = 1; - - /* explore all USB busses in parallell */ - - usb2_needs_explore_all(); - - mtx_unlock(&Giant); -} - -SYSINIT(usb2_post_init, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, usb2_post_init, NULL); -SYSUNINIT(usb2_bus_unload, SI_SUB_KLD, SI_ORDER_ANY, usb2_bus_unload, NULL); - -/*------------------------------------------------------------------------* - * usb2_bus_mem_flush_all_cb - *------------------------------------------------------------------------*/ -static void -usb2_bus_mem_flush_all_cb(struct usb2_bus *bus, struct usb2_page_cache *pc, - struct usb2_page *pg, uint32_t size, uint32_t align) -{ - usb2_pc_cpu_flush(pc); -} - -/*------------------------------------------------------------------------* - * usb2_bus_mem_flush_all - factored out code - *------------------------------------------------------------------------*/ -void -usb2_bus_mem_flush_all(struct usb2_bus *bus, usb2_bus_mem_cb_t *cb) -{ - if (cb) { - cb(bus, &usb2_bus_mem_flush_all_cb); - } -} - -/*------------------------------------------------------------------------* - * usb2_bus_mem_alloc_all_cb - *------------------------------------------------------------------------*/ -static void -usb2_bus_mem_alloc_all_cb(struct usb2_bus *bus, struct usb2_page_cache *pc, - struct usb2_page *pg, uint32_t size, uint32_t align) -{ - /* need to initialize the page cache */ - pc->tag_parent = bus->dma_parent_tag; - - if (usb2_pc_alloc_mem(pc, pg, size, align)) { - bus->alloc_failed = 1; - } -} - -/*------------------------------------------------------------------------* - * usb2_bus_mem_alloc_all - factored out code - * - * Returns: - * 0: Success - * Else: Failure - *------------------------------------------------------------------------*/ -uint8_t -usb2_bus_mem_alloc_all(struct usb2_bus *bus, bus_dma_tag_t dmat, - usb2_bus_mem_cb_t *cb) -{ - bus->alloc_failed = 0; - - mtx_init(&bus->bus_mtx, device_get_nameunit(bus->parent), - NULL, MTX_DEF | MTX_RECURSE); - - usb2_callout_init_mtx(&bus->power_wdog, - &bus->bus_mtx, CALLOUT_RETURNUNLOCKED); - - TAILQ_INIT(&bus->intr_q.head); - - usb2_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags, - dmat, &bus->bus_mtx, NULL, NULL, 32, USB_BUS_DMA_TAG_MAX); - - if ((bus->devices_max > USB_MAX_DEVICES) || - (bus->devices_max < USB_MIN_DEVICES) || - (bus->devices == NULL)) { - DPRINTFN(0, "Devices field has not been " - "initialised properly!\n"); - bus->alloc_failed = 1; /* failure */ - } - if (cb) { - cb(bus, &usb2_bus_mem_alloc_all_cb); - } - if (bus->alloc_failed) { - usb2_bus_mem_free_all(bus, cb); - } - return (bus->alloc_failed); -} - -/*------------------------------------------------------------------------* - * usb2_bus_mem_free_all_cb - *------------------------------------------------------------------------*/ -static void -usb2_bus_mem_free_all_cb(struct usb2_bus *bus, struct usb2_page_cache *pc, - struct usb2_page *pg, uint32_t size, uint32_t align) -{ - usb2_pc_free_mem(pc); -} - -/*------------------------------------------------------------------------* - * usb2_bus_mem_free_all - factored out code - *------------------------------------------------------------------------*/ -void -usb2_bus_mem_free_all(struct usb2_bus *bus, usb2_bus_mem_cb_t *cb) -{ - if (cb) { - cb(bus, &usb2_bus_mem_free_all_cb); - } - usb2_dma_tag_unsetup(bus->dma_parent_tag); - - mtx_destroy(&bus->bus_mtx); -} - -/*------------------------------------------------------------------------* - * usb2_bus_roothub - * - * This function is used to execute roothub control requests on the - * roothub and is called from the roothub process. - *------------------------------------------------------------------------*/ -static void -usb2_bus_roothub(struct usb2_proc_msg *pm) -{ - struct usb2_bus *bus; - - bus = ((struct usb2_bus_msg *)pm)->bus; - - USB_BUS_LOCK_ASSERT(bus, MA_OWNED); - - (bus->methods->roothub_exec) (bus); -} - -/*------------------------------------------------------------------------* - * usb2_bus_roothub_exec - * - * This function is used to schedule the "roothub_done" bus callback - * method. The bus lock must be locked when calling this function. - *------------------------------------------------------------------------*/ -void -usb2_bus_roothub_exec(struct usb2_bus *bus) -{ - USB_BUS_LOCK_ASSERT(bus, MA_OWNED); - - if (usb2_proc_msignal(&bus->roothub_proc, - &bus->roothub_msg[0], &bus->roothub_msg[1])) { - /* ignore */ - } -} diff --git a/sys/dev/usb2/controller/usb2_controller.h b/sys/dev/usb2/controller/usb2_controller.h deleted file mode 100644 index 80633d9..0000000 --- a/sys/dev/usb2/controller/usb2_controller.h +++ /dev/null @@ -1,199 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _USB2_CONTROLLER_H_ -#define _USB2_CONTROLLER_H_ - -/* defines */ - -#define USB_BUS_DMA_TAG_MAX 8 - -/* structure prototypes */ - -struct usb2_bus; -struct usb2_page; -struct usb2_pipe; -struct usb2_page_cache; -struct usb2_setup_params; -struct usb2_hw_ep_profile; -struct usb2_fs_isoc_schedule; -struct usb2_config_descriptor; -struct usb2_endpoint_descriptor; - -/* typedefs */ - -typedef void (usb2_bus_mem_sub_cb_t)(struct usb2_bus *bus, struct usb2_page_cache *pc, struct usb2_page *pg, uint32_t size, uint32_t align); -typedef void (usb2_bus_mem_cb_t)(struct usb2_bus *bus, usb2_bus_mem_sub_cb_t *scb); - -/* - * The following structure is used to define all the USB BUS - * callbacks. - */ -struct usb2_bus_methods { - - /* USB Device and Host mode - Mandatory */ - - void (*pipe_init) (struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, struct usb2_pipe *pipe); - void (*do_poll) (struct usb2_bus *); - void (*xfer_setup) (struct usb2_setup_params *parm); - void (*xfer_unsetup) (struct usb2_xfer *xfer); - void (*get_dma_delay) (struct usb2_bus *, uint32_t *pdelay); - void (*device_suspend) (struct usb2_device *udev); - void (*device_resume) (struct usb2_device *udev); - void (*set_hw_power) (struct usb2_bus *bus); - /* - * The following flag is set if one or more control transfers are - * active: - */ -#define USB_HW_POWER_CONTROL 0x01 - /* - * The following flag is set if one or more bulk transfers are - * active: - */ -#define USB_HW_POWER_BULK 0x02 - /* - * The following flag is set if one or more interrupt transfers are - * active: - */ -#define USB_HW_POWER_INTERRUPT 0x04 - /* - * The following flag is set if one or more isochronous transfers - * are active: - */ -#define USB_HW_POWER_ISOC 0x08 - /* - * The following flag is set if one or more non-root-HUB devices - * are present on the given USB bus: - */ -#define USB_HW_POWER_NON_ROOT_HUB 0x10 - - /* USB Device mode only - Mandatory */ - - void (*get_hw_ep_profile) (struct usb2_device *udev, const struct usb2_hw_ep_profile **ppf, uint8_t ep_addr); - void (*set_stall) (struct usb2_device *udev, struct usb2_xfer *xfer, struct usb2_pipe *pipe); - void (*clear_stall) (struct usb2_device *udev, struct usb2_pipe *pipe); - - /* USB Device and Host mode - Optional */ - - void (*roothub_exec) (struct usb2_bus *); -}; - -/* - * The following structure is used to define all the USB pipe - * callbacks. - */ -struct usb2_pipe_methods { - - /* Mandatory USB Device and Host mode callbacks: */ - - void (*open) (struct usb2_xfer *xfer); - void (*close) (struct usb2_xfer *xfer); - - void (*enter) (struct usb2_xfer *xfer); - void (*start) (struct usb2_xfer *xfer); - - /* Optional */ - - void *info; - - /* Flags */ - - uint8_t enter_is_cancelable:1; - uint8_t start_is_cancelable:1; -}; - -/* - * The following structure keeps information about what a hardware USB - * endpoint supports. - */ -struct usb2_hw_ep_profile { - uint16_t max_in_frame_size; /* IN-token direction */ - uint16_t max_out_frame_size; /* OUT-token direction */ - uint8_t is_simplex:1; - uint8_t support_multi_buffer:1; - uint8_t support_bulk:1; - uint8_t support_control:1; - uint8_t support_interrupt:1; - uint8_t support_isochronous:1; - uint8_t support_in:1; /* IN-token is supported */ - uint8_t support_out:1; /* OUT-token is supported */ -}; - -/* - * The following structure is used when trying to allocate hardware - * endpoints for an USB configuration in USB device side mode. - */ -struct usb2_hw_ep_scratch_sub { - const struct usb2_hw_ep_profile *pf; - uint16_t max_frame_size; - uint8_t hw_endpoint_out; - uint8_t hw_endpoint_in; - uint8_t needs_ep_type; - uint8_t needs_in:1; - uint8_t needs_out:1; -}; - -/* - * The following structure is used when trying to allocate hardware - * endpoints for an USB configuration in USB device side mode. - */ -struct usb2_hw_ep_scratch { - struct usb2_hw_ep_scratch_sub ep[USB_EP_MAX]; - struct usb2_hw_ep_scratch_sub *ep_max; - struct usb2_config_descriptor *cd; - struct usb2_device *udev; - struct usb2_bus_methods *methods; - uint8_t bmOutAlloc[(USB_EP_MAX + 15) / 16]; - uint8_t bmInAlloc[(USB_EP_MAX + 15) / 16]; -}; - -/* - * The following structure is used when generating USB descriptors - * from USB templates. - */ -struct usb2_temp_setup { - void *buf; - uint32_t size; - uint8_t usb2_speed; - uint8_t self_powered; - uint8_t bNumEndpoints; - uint8_t bInterfaceNumber; - uint8_t bAlternateSetting; - uint8_t bConfigurationValue; - usb2_error_t err; -}; - -/* prototypes */ - -void usb2_bus_mem_flush_all(struct usb2_bus *bus, usb2_bus_mem_cb_t *cb); -uint8_t usb2_bus_mem_alloc_all(struct usb2_bus *bus, bus_dma_tag_t dmat, usb2_bus_mem_cb_t *cb); -void usb2_bus_mem_free_all(struct usb2_bus *bus, usb2_bus_mem_cb_t *cb); -void usb2_bus_roothub_exec(struct usb2_bus *bus); -uint16_t usb2_isoc_time_expand(struct usb2_bus *bus, uint16_t isoc_time_curr); -uint16_t usb2_fs_isoc_schedule_isoc_time_expand(struct usb2_device *udev, struct usb2_fs_isoc_schedule **pp_start, struct usb2_fs_isoc_schedule **pp_end, uint16_t isoc_time); -uint8_t usb2_fs_isoc_schedule_alloc(struct usb2_fs_isoc_schedule *fss, uint8_t *pstart, uint16_t len); - -#endif /* _USB2_CONTROLLER_H_ */ diff --git a/sys/dev/usb2/controller/usb2_pci.h b/sys/dev/usb2/controller/usb2_pci.h deleted file mode 100644 index 9297c29..0000000 --- a/sys/dev/usb2/controller/usb2_pci.h +++ /dev/null @@ -1,39 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _USB2_PCI_H_ -#define _USB2_PCI_H_ - -/* - * We don't want the following files included everywhere, that's why - * they are in a separate file. - */ -#include <dev/pci/pcireg.h> -#include <dev/pci/pcivar.h> - -#include <sys/rman.h> - -#endif /* _USB2_PCI_H_ */ diff --git a/sys/dev/usb2/controller/uss820dci.c b/sys/dev/usb2/controller/uss820dci.c deleted file mode 100644 index 1e034bf..0000000 --- a/sys/dev/usb2/controller/uss820dci.c +++ /dev/null @@ -1,2489 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2008 Hans Petter Selasky <hselasky@freebsd.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * This file contains the driver for the USS820 series USB Device - * Controller - * - * NOTE: The datasheet does not document everything! - */ - -#include <dev/usb2/include/usb2_standard.h> -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_revision.h> -#include <dev/usb2/include/usb2_error.h> -#include <dev/usb2/include/usb2_defs.h> - -#define USB_DEBUG_VAR uss820dcidebug - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_debug.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_transfer.h> -#include <dev/usb2/core/usb2_device.h> -#include <dev/usb2/core/usb2_hub.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/uss820dci.h> - -#define USS820_DCI_BUS2SC(bus) \ - ((struct uss820dci_softc *)(((uint8_t *)(bus)) - \ - USB_P2U(&(((struct uss820dci_softc *)0)->sc_bus)))) - -#define USS820_DCI_PC2SC(pc) \ - USS820_DCI_BUS2SC((pc)->tag_parent->info->bus) - -#if USB_DEBUG -static int uss820dcidebug = 0; - -SYSCTL_NODE(_hw_usb2, OID_AUTO, uss820dci, CTLFLAG_RW, 0, "USB uss820dci"); -SYSCTL_INT(_hw_usb2_uss820dci, OID_AUTO, debug, CTLFLAG_RW, - &uss820dcidebug, 0, "uss820dci debug level"); -#endif - -#define USS820_DCI_INTR_ENDPT 1 - -/* prototypes */ - -struct usb2_bus_methods uss820dci_bus_methods; -struct usb2_pipe_methods uss820dci_device_bulk_methods; -struct usb2_pipe_methods uss820dci_device_ctrl_methods; -struct usb2_pipe_methods uss820dci_device_intr_methods; -struct usb2_pipe_methods uss820dci_device_isoc_fs_methods; -struct usb2_pipe_methods uss820dci_root_ctrl_methods; -struct usb2_pipe_methods uss820dci_root_intr_methods; - -static uss820dci_cmd_t uss820dci_setup_rx; -static uss820dci_cmd_t uss820dci_data_rx; -static uss820dci_cmd_t uss820dci_data_tx; -static uss820dci_cmd_t uss820dci_data_tx_sync; -static void uss820dci_device_done(struct usb2_xfer *, usb2_error_t); -static void uss820dci_do_poll(struct usb2_bus *); -static void uss820dci_root_ctrl_poll(struct uss820dci_softc *); -static void uss820dci_standard_done(struct usb2_xfer *); -static void uss820dci_intr_set(struct usb2_xfer *, uint8_t); -static void uss820dci_update_shared_1(struct uss820dci_softc *, uint8_t, - uint8_t, uint8_t); - -static usb2_sw_transfer_func_t uss820dci_root_intr_done; -static usb2_sw_transfer_func_t uss820dci_root_ctrl_done; - -/* - * Here is a list of what the USS820D chip can support. The main - * limitation is that the sum of the buffer sizes must be less than - * 1120 bytes. - */ -static const struct usb2_hw_ep_profile - uss820dci_ep_profile[] = { - - [0] = { - .max_in_frame_size = 32, - .max_out_frame_size = 32, - .is_simplex = 0, - .support_control = 1, - }, - [1] = { - .max_in_frame_size = 64, - .max_out_frame_size = 64, - .is_simplex = 0, - .support_multi_buffer = 1, - .support_bulk = 1, - .support_interrupt = 1, - .support_in = 1, - .support_out = 1, - }, - [2] = { - .max_in_frame_size = 8, - .max_out_frame_size = 8, - .is_simplex = 0, - .support_multi_buffer = 1, - .support_bulk = 1, - .support_interrupt = 1, - .support_in = 1, - .support_out = 1, - }, - [3] = { - .max_in_frame_size = 256, - .max_out_frame_size = 256, - .is_simplex = 0, - .support_multi_buffer = 1, - .support_isochronous = 1, - .support_in = 1, - .support_out = 1, - }, -}; - -static void -uss820dci_update_shared_1(struct uss820dci_softc *sc, uint8_t reg, - uint8_t keep_mask, uint8_t set_mask) -{ - uint8_t temp; - - USS820_WRITE_1(sc, USS820_PEND, 1); - temp = USS820_READ_1(sc, reg); - temp &= (keep_mask); - temp |= (set_mask); - USS820_WRITE_1(sc, reg, temp); - USS820_WRITE_1(sc, USS820_PEND, 0); -} - -static void -uss820dci_get_hw_ep_profile(struct usb2_device *udev, - const struct usb2_hw_ep_profile **ppf, uint8_t ep_addr) -{ - if (ep_addr == 0) { - *ppf = uss820dci_ep_profile + 0; - } else if (ep_addr < 5) { - *ppf = uss820dci_ep_profile + 1; - } else if (ep_addr < 7) { - *ppf = uss820dci_ep_profile + 2; - } else if (ep_addr == 7) { - *ppf = uss820dci_ep_profile + 3; - } else { - *ppf = NULL; - } -} - -static void -uss820dci_pull_up(struct uss820dci_softc *sc) -{ - uint8_t temp; - - /* pullup D+, if possible */ - - if (!sc->sc_flags.d_pulled_up && - sc->sc_flags.port_powered) { - sc->sc_flags.d_pulled_up = 1; - - DPRINTF("\n"); - - temp = USS820_READ_1(sc, USS820_MCSR); - temp |= USS820_MCSR_DPEN; - USS820_WRITE_1(sc, USS820_MCSR, temp); - } -} - -static void -uss820dci_pull_down(struct uss820dci_softc *sc) -{ - uint8_t temp; - - /* pulldown D+, if possible */ - - if (sc->sc_flags.d_pulled_up) { - sc->sc_flags.d_pulled_up = 0; - - DPRINTF("\n"); - - temp = USS820_READ_1(sc, USS820_MCSR); - temp &= ~USS820_MCSR_DPEN; - USS820_WRITE_1(sc, USS820_MCSR, temp); - } -} - -static void -uss820dci_wakeup_peer(struct uss820dci_softc *sc) -{ - if (!(sc->sc_flags.status_suspend)) { - return; - } - DPRINTFN(0, "not supported\n"); -} - -static void -uss820dci_set_address(struct uss820dci_softc *sc, uint8_t addr) -{ - DPRINTFN(5, "addr=%d\n", addr); - - USS820_WRITE_1(sc, USS820_FADDR, addr); -} - -static uint8_t -uss820dci_setup_rx(struct uss820dci_td *td) -{ - struct uss820dci_softc *sc; - struct usb2_device_request req; - uint16_t count; - uint8_t rx_stat; - uint8_t temp; - - /* select the correct endpoint */ - bus_space_write_1(td->io_tag, td->io_hdl, - td->ep_reg, td->ep_index); - - /* read out FIFO status */ - rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_stat_reg); - - /* get pointer to softc */ - sc = USS820_DCI_PC2SC(td->pc); - - DPRINTFN(5, "rx_stat=0x%02x rem=%u\n", rx_stat, td->remainder); - - if (!(rx_stat & USS820_RXSTAT_RXSETUP)) { - /* abort any ongoing transfer */ - if (!td->did_stall) { - DPRINTFN(5, "stalling\n"); - - /* set stall */ - - uss820dci_update_shared_1(sc, USS820_EPCON, 0xFF, - (USS820_EPCON_TXSTL | USS820_EPCON_RXSTL)); - - td->did_stall = 1; - } - goto not_complete; - } - /* clear stall and all I/O */ - uss820dci_update_shared_1(sc, USS820_EPCON, - 0xFF ^ (USS820_EPCON_TXSTL | - USS820_EPCON_RXSTL | - USS820_EPCON_RXIE | - USS820_EPCON_TXOE), 0); - - /* clear end overwrite flag */ - uss820dci_update_shared_1(sc, USS820_RXSTAT, - 0xFF ^ USS820_RXSTAT_EDOVW, 0); - - /* get the packet byte count */ - count = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_count_low_reg); - count |= (bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_count_high_reg) << 8); - count &= 0x3FF; - - /* verify data length */ - if (count != td->remainder) { - DPRINTFN(0, "Invalid SETUP packet " - "length, %d bytes\n", count); - goto not_complete; - } - if (count != sizeof(req)) { - DPRINTFN(0, "Unsupported SETUP packet " - "length, %d bytes\n", count); - goto not_complete; - } - /* receive data */ - bus_space_read_multi_1(td->io_tag, td->io_hdl, - td->rx_fifo_reg, (void *)&req, sizeof(req)); - - /* read out FIFO status */ - rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_stat_reg); - - if (rx_stat & (USS820_RXSTAT_EDOVW | - USS820_RXSTAT_STOVW)) { - DPRINTF("new SETUP packet received\n"); - return (1); /* not complete */ - } - /* clear receive setup bit */ - uss820dci_update_shared_1(sc, USS820_RXSTAT, - 0xFF ^ (USS820_RXSTAT_RXSETUP | - USS820_RXSTAT_EDOVW | - USS820_RXSTAT_STOVW), 0); - - /* set RXFFRC bit */ - temp = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_cntl_reg); - temp |= USS820_RXCON_RXFFRC; - bus_space_write_1(td->io_tag, td->io_hdl, - td->rx_cntl_reg, temp); - - /* copy data into real buffer */ - usb2_copy_in(td->pc, 0, &req, sizeof(req)); - - td->offset = sizeof(req); - td->remainder = 0; - - /* sneak peek the set address */ - if ((req.bmRequestType == UT_WRITE_DEVICE) && - (req.bRequest == UR_SET_ADDRESS)) { - sc->sc_dv_addr = req.wValue[0] & 0x7F; - } else { - sc->sc_dv_addr = 0xFF; - } - return (0); /* complete */ - -not_complete: - /* clear end overwrite flag, if any */ - if (rx_stat & USS820_RXSTAT_RXSETUP) { - uss820dci_update_shared_1(sc, USS820_RXSTAT, - 0xFF ^ (USS820_RXSTAT_EDOVW | - USS820_RXSTAT_STOVW | - USS820_RXSTAT_RXSETUP), 0); - } - return (1); /* not complete */ - -} - -static uint8_t -uss820dci_data_rx(struct uss820dci_td *td) -{ - struct usb2_page_search buf_res; - uint16_t count; - uint8_t rx_flag; - uint8_t rx_stat; - uint8_t rx_cntl; - uint8_t to; - uint8_t got_short; - - to = 2; /* don't loop forever! */ - got_short = 0; - - /* select the correct endpoint */ - bus_space_write_1(td->io_tag, td->io_hdl, td->ep_reg, td->ep_index); - - /* check if any of the FIFO banks have data */ -repeat: - /* read out FIFO flag */ - rx_flag = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_flag_reg); - /* read out FIFO status */ - rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_stat_reg); - - DPRINTFN(5, "rx_stat=0x%02x rx_flag=0x%02x rem=%u\n", - rx_stat, rx_flag, td->remainder); - - if (rx_stat & (USS820_RXSTAT_RXSETUP | - USS820_RXSTAT_RXSOVW | - USS820_RXSTAT_EDOVW)) { - if (td->remainder == 0) { - /* - * We are actually complete and have - * received the next SETUP - */ - DPRINTFN(5, "faking complete\n"); - return (0); /* complete */ - } - /* - * USB Host Aborted the transfer. - */ - td->error = 1; - return (0); /* complete */ - } - /* check for errors */ - if (rx_flag & (USS820_RXFLG_RXOVF | - USS820_RXFLG_RXURF)) { - DPRINTFN(5, "overflow or underflow\n"); - /* should not happen */ - td->error = 1; - return (0); /* complete */ - } - /* check status */ - if (!(rx_flag & (USS820_RXFLG_RXFIF0 | - USS820_RXFLG_RXFIF1))) { - - /* read out EPCON register */ - /* enable RX input */ - if (!td->did_stall) { - uss820dci_update_shared_1(USS820_DCI_PC2SC(td->pc), - USS820_EPCON, 0xFF, USS820_EPCON_RXIE); - td->did_stall = 1; - } - return (1); /* not complete */ - } - /* get the packet byte count */ - count = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_count_low_reg); - - count |= (bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_count_high_reg) << 8); - count &= 0x3FF; - - DPRINTFN(5, "count=0x%04x\n", count); - - /* verify the packet byte count */ - if (count != td->max_packet_size) { - if (count < td->max_packet_size) { - /* we have a short packet */ - td->short_pkt = 1; - got_short = 1; - } else { - /* invalid USB packet */ - td->error = 1; - return (0); /* we are complete */ - } - } - /* verify the packet byte count */ - if (count > td->remainder) { - /* invalid USB packet */ - td->error = 1; - return (0); /* we are complete */ - } - while (count > 0) { - usb2_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* receive data */ - bus_space_read_multi_1(td->io_tag, td->io_hdl, - td->rx_fifo_reg, buf_res.buffer, buf_res.length); - - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } - - /* set RXFFRC bit */ - rx_cntl = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_cntl_reg); - rx_cntl |= USS820_RXCON_RXFFRC; - bus_space_write_1(td->io_tag, td->io_hdl, - td->rx_cntl_reg, rx_cntl); - - /* check if we are complete */ - if ((td->remainder == 0) || got_short) { - if (td->short_pkt) { - /* we are complete */ - return (0); - } - /* else need to receive a zero length packet */ - } - if (--to) { - goto repeat; - } - return (1); /* not complete */ -} - -static uint8_t -uss820dci_data_tx(struct uss820dci_td *td) -{ - struct usb2_page_search buf_res; - uint16_t count; - uint16_t count_copy; - uint8_t rx_stat; - uint8_t tx_flag; - uint8_t to; - - /* select the correct endpoint */ - bus_space_write_1(td->io_tag, td->io_hdl, - td->ep_reg, td->ep_index); - - to = 2; /* don't loop forever! */ - -repeat: - /* read out TX FIFO flags */ - tx_flag = bus_space_read_1(td->io_tag, td->io_hdl, - td->tx_flag_reg); - - /* read out RX FIFO status last */ - rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_stat_reg); - - DPRINTFN(5, "rx_stat=0x%02x tx_flag=0x%02x rem=%u\n", - rx_stat, tx_flag, td->remainder); - - if (rx_stat & (USS820_RXSTAT_RXSETUP | - USS820_RXSTAT_RXSOVW | - USS820_RXSTAT_EDOVW)) { - /* - * The current transfer was aborted - * by the USB Host - */ - td->error = 1; - return (0); /* complete */ - } - if (tx_flag & (USS820_TXFLG_TXOVF | - USS820_TXFLG_TXURF)) { - td->error = 1; - return (0); /* complete */ - } - if (tx_flag & USS820_TXFLG_TXFIF0) { - if (tx_flag & USS820_TXFLG_TXFIF1) { - return (1); /* not complete */ - } - } - if ((!td->support_multi_buffer) && - (tx_flag & (USS820_TXFLG_TXFIF0 | - USS820_TXFLG_TXFIF1))) { - return (1); /* not complete */ - } - count = td->max_packet_size; - if (td->remainder < count) { - /* we have a short packet */ - td->short_pkt = 1; - count = td->remainder; - } - count_copy = count; - while (count > 0) { - - usb2_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) { - buf_res.length = count; - } - /* transmit data */ - bus_space_write_multi_1(td->io_tag, td->io_hdl, - td->tx_fifo_reg, buf_res.buffer, buf_res.length); - - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } - - /* post-write high packet byte count first */ - bus_space_write_1(td->io_tag, td->io_hdl, - td->tx_count_high_reg, count_copy >> 8); - - /* post-write low packet byte count last */ - bus_space_write_1(td->io_tag, td->io_hdl, - td->tx_count_low_reg, count_copy); - - /* - * Enable TX output, which must happen after that we have written - * data into the FIFO. This is undocumented. - */ - if (!td->did_stall) { - uss820dci_update_shared_1(USS820_DCI_PC2SC(td->pc), - USS820_EPCON, 0xFF, USS820_EPCON_TXOE); - td->did_stall = 1; - } - /* check remainder */ - if (td->remainder == 0) { - if (td->short_pkt) { - return (0); /* complete */ - } - /* else we need to transmit a short packet */ - } - if (--to) { - goto repeat; - } - return (1); /* not complete */ -} - -static uint8_t -uss820dci_data_tx_sync(struct uss820dci_td *td) -{ - struct uss820dci_softc *sc; - uint8_t rx_stat; - uint8_t tx_flag; - - /* select the correct endpoint */ - bus_space_write_1(td->io_tag, td->io_hdl, - td->ep_reg, td->ep_index); - - /* read out TX FIFO flag */ - tx_flag = bus_space_read_1(td->io_tag, td->io_hdl, - td->tx_flag_reg); - - /* read out RX FIFO status last */ - rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_stat_reg); - - DPRINTFN(5, "rx_stat=0x%02x rem=%u\n", rx_stat, td->remainder); - - if (rx_stat & (USS820_RXSTAT_RXSETUP | - USS820_RXSTAT_RXSOVW | - USS820_RXSTAT_EDOVW)) { - DPRINTFN(5, "faking complete\n"); - /* Race condition */ - return (0); /* complete */ - } - DPRINTFN(5, "tx_flag=0x%02x rem=%u\n", - tx_flag, td->remainder); - - if (tx_flag & (USS820_TXFLG_TXOVF | - USS820_TXFLG_TXURF)) { - td->error = 1; - return (0); /* complete */ - } - if (tx_flag & (USS820_TXFLG_TXFIF0 | - USS820_TXFLG_TXFIF1)) { - return (1); /* not complete */ - } - sc = USS820_DCI_PC2SC(td->pc); - if (sc->sc_dv_addr != 0xFF) { - /* write function address */ - uss820dci_set_address(sc, sc->sc_dv_addr); - } - return (0); /* complete */ -} - -static uint8_t -uss820dci_xfer_do_fifo(struct usb2_xfer *xfer) -{ - struct uss820dci_td *td; - - DPRINTFN(9, "\n"); - - td = xfer->td_transfer_cache; - while (1) { - if ((td->func) (td)) { - /* operation in progress */ - break; - } - if (((void *)td) == xfer->td_transfer_last) { - goto done; - } - if (td->error) { - goto done; - } else if (td->remainder > 0) { - /* - * We had a short transfer. If there is no alternate - * next, stop processing ! - */ - if (!td->alt_next) { - goto done; - } - } - /* - * Fetch the next transfer descriptor. - */ - td = td->obj_next; - xfer->td_transfer_cache = td; - } - return (1); /* not complete */ - -done: - /* compute all actual lengths */ - - uss820dci_standard_done(xfer); - - return (0); /* complete */ -} - -static void -uss820dci_interrupt_poll(struct uss820dci_softc *sc) -{ - struct usb2_xfer *xfer; - -repeat: - TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - if (!uss820dci_xfer_do_fifo(xfer)) { - /* queue has been modified */ - goto repeat; - } - } -} - -static void -uss820dci_wait_suspend(struct uss820dci_softc *sc, uint8_t on) -{ - uint8_t scr; - uint8_t scratch; - - scr = USS820_READ_1(sc, USS820_SCR); - scratch = USS820_READ_1(sc, USS820_SCRATCH); - - if (on) { - scr |= USS820_SCR_IE_SUSP; - scratch &= ~USS820_SCRATCH_IE_RESUME; - } else { - scr &= ~USS820_SCR_IE_SUSP; - scratch |= USS820_SCRATCH_IE_RESUME; - } - - USS820_WRITE_1(sc, USS820_SCR, scr); - USS820_WRITE_1(sc, USS820_SCRATCH, scratch); -} - -void -uss820dci_interrupt(struct uss820dci_softc *sc) -{ - uint8_t ssr; - uint8_t event; - - USB_BUS_LOCK(&sc->sc_bus); - - ssr = USS820_READ_1(sc, USS820_SSR); - - ssr &= (USS820_SSR_SUSPEND | - USS820_SSR_RESUME | - USS820_SSR_RESET); - - /* acknowledge all interrupts */ - - uss820dci_update_shared_1(sc, USS820_SSR, 0, 0); - - /* check for any bus state change interrupts */ - - if (ssr) { - - event = 0; - - if (ssr & USS820_SSR_RESET) { - sc->sc_flags.status_bus_reset = 1; - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 0; - sc->sc_flags.change_connect = 1; - - /* disable resume interrupt */ - uss820dci_wait_suspend(sc, 1); - - event = 1; - } - /* - * If "RESUME" and "SUSPEND" is set at the same time - * we interpret that like "RESUME". Resume is set when - * there is at least 3 milliseconds of inactivity on - * the USB BUS. - */ - if (ssr & USS820_SSR_RESUME) { - if (sc->sc_flags.status_suspend) { - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 1; - /* disable resume interrupt */ - uss820dci_wait_suspend(sc, 1); - event = 1; - } - } else if (ssr & USS820_SSR_SUSPEND) { - if (!sc->sc_flags.status_suspend) { - sc->sc_flags.status_suspend = 1; - sc->sc_flags.change_suspend = 1; - /* enable resume interrupt */ - uss820dci_wait_suspend(sc, 0); - event = 1; - } - } - if (event) { - - DPRINTF("real bus interrupt 0x%02x\n", ssr); - - /* complete root HUB interrupt endpoint */ - - usb2_sw_transfer(&sc->sc_root_intr, - &uss820dci_root_intr_done); - } - } - /* acknowledge all SBI interrupts */ - uss820dci_update_shared_1(sc, USS820_SBI, 0, 0); - - /* acknowledge all SBI1 interrupts */ - uss820dci_update_shared_1(sc, USS820_SBI1, 0, 0); - - /* poll all active transfers */ - uss820dci_interrupt_poll(sc); - - USB_BUS_UNLOCK(&sc->sc_bus); -} - -static void -uss820dci_setup_standard_chain_sub(struct uss820_std_temp *temp) -{ - struct uss820dci_td *td; - - /* get current Transfer Descriptor */ - td = temp->td_next; - temp->td = td; - - /* prepare for next TD */ - temp->td_next = td->obj_next; - - /* fill out the Transfer Descriptor */ - td->func = temp->func; - td->pc = temp->pc; - td->offset = temp->offset; - td->remainder = temp->len; - td->error = 0; - td->did_stall = 0; - td->short_pkt = temp->short_pkt; - td->alt_next = temp->setup_alt_next; -} - -static void -uss820dci_setup_standard_chain(struct usb2_xfer *xfer) -{ - struct uss820_std_temp temp; - struct uss820dci_softc *sc; - struct uss820dci_td *td; - uint32_t x; - uint8_t ep_no; - - DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", - xfer->address, UE_GET_ADDR(xfer->endpoint), - xfer->sumlen, usb2_get_speed(xfer->xroot->udev)); - - temp.max_frame_size = xfer->max_frame_size; - - td = xfer->td_start[0]; - xfer->td_transfer_first = td; - xfer->td_transfer_cache = td; - - /* setup temp */ - - temp.td = NULL; - temp.td_next = xfer->td_start[0]; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; - temp.offset = 0; - - sc = USS820_DCI_BUS2SC(xfer->xroot->bus); - ep_no = (xfer->endpoint & UE_ADDR); - - /* check if we should prepend a setup message */ - - if (xfer->flags_int.control_xfr) { - if (xfer->flags_int.control_hdr) { - - temp.func = &uss820dci_setup_rx; - temp.len = xfer->frlengths[0]; - temp.pc = xfer->frbuffers + 0; - temp.short_pkt = temp.len ? 1 : 0; - - uss820dci_setup_standard_chain_sub(&temp); - } - x = 1; - } else { - x = 0; - } - - if (x != xfer->nframes) { - if (xfer->endpoint & UE_DIR_IN) { - temp.func = &uss820dci_data_tx; - } else { - temp.func = &uss820dci_data_rx; - } - - /* setup "pc" pointer */ - temp.pc = xfer->frbuffers + x; - } - while (x != xfer->nframes) { - - /* DATA0 / DATA1 message */ - - temp.len = xfer->frlengths[x]; - - x++; - - if (x == xfer->nframes) { - temp.setup_alt_next = 0; - } - if (temp.len == 0) { - - /* make sure that we send an USB packet */ - - temp.short_pkt = 0; - - } else { - - /* regular data transfer */ - - temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; - } - - uss820dci_setup_standard_chain_sub(&temp); - - if (xfer->flags_int.isochronous_xfr) { - temp.offset += temp.len; - } else { - /* get next Page Cache pointer */ - temp.pc = xfer->frbuffers + x; - } - } - - /* always setup a valid "pc" pointer for status and sync */ - temp.pc = xfer->frbuffers + 0; - - /* check if we should append a status stage */ - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - uint8_t need_sync; - - /* - * Send a DATA1 message and invert the current - * endpoint direction. - */ - if (xfer->endpoint & UE_DIR_IN) { - temp.func = &uss820dci_data_rx; - need_sync = 0; - } else { - temp.func = &uss820dci_data_tx; - need_sync = 1; - } - temp.len = 0; - temp.short_pkt = 0; - - uss820dci_setup_standard_chain_sub(&temp); - if (need_sync) { - /* we need a SYNC point after TX */ - temp.func = &uss820dci_data_tx_sync; - temp.len = 0; - temp.short_pkt = 0; - - uss820dci_setup_standard_chain_sub(&temp); - } - } - /* must have at least one frame! */ - td = temp.td; - xfer->td_transfer_last = td; -} - -static void -uss820dci_timeout(void *arg) -{ - struct usb2_xfer *xfer = arg; - - DPRINTF("xfer=%p\n", xfer); - - USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); - - /* transfer is transferred */ - uss820dci_device_done(xfer, USB_ERR_TIMEOUT); -} - -static void -uss820dci_intr_set(struct usb2_xfer *xfer, uint8_t set) -{ - struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus); - uint8_t ep_no = (xfer->endpoint & UE_ADDR); - uint8_t ep_reg; - uint8_t temp; - - DPRINTFN(15, "endpoint 0x%02x\n", xfer->endpoint); - - if (ep_no > 3) { - ep_reg = USS820_SBIE1; - } else { - ep_reg = USS820_SBIE; - } - - ep_no &= 3; - ep_no = 1 << (2 * ep_no); - - if (xfer->flags_int.control_xfr) { - if (xfer->flags_int.control_hdr) { - ep_no <<= 1; /* RX interrupt only */ - } else { - ep_no |= (ep_no << 1); /* RX and TX interrupt */ - } - } else { - if (!(xfer->endpoint & UE_DIR_IN)) { - ep_no <<= 1; - } - } - temp = USS820_READ_1(sc, ep_reg); - if (set) { - temp |= ep_no; - } else { - temp &= ~ep_no; - } - USS820_WRITE_1(sc, ep_reg, temp); -} - -static void -uss820dci_start_standard_chain(struct usb2_xfer *xfer) -{ - DPRINTFN(9, "\n"); - - /* poll one time */ - if (uss820dci_xfer_do_fifo(xfer)) { - - /* - * Only enable the endpoint interrupt when we are - * actually waiting for data, hence we are dealing - * with level triggered interrupts ! - */ - uss820dci_intr_set(xfer, 1); - - /* put transfer on interrupt queue */ - usb2_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); - - /* start timeout, if any */ - if (xfer->timeout != 0) { - usb2_transfer_timeout_ms(xfer, - &uss820dci_timeout, xfer->timeout); - } - } -} - -static void -uss820dci_root_intr_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus); - - DPRINTFN(9, "\n"); - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_PRE_DATA) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - uss820dci_device_done(xfer, std->err); - } - goto done; - } - /* setup buffer */ - std->ptr = sc->sc_hub_idata; - std->len = sizeof(sc->sc_hub_idata); - - /* set port bit */ - sc->sc_hub_idata[0] = 0x02; /* we only have one port */ - -done: - return; -} - -static usb2_error_t -uss820dci_standard_done_sub(struct usb2_xfer *xfer) -{ - struct uss820dci_td *td; - uint32_t len; - uint8_t error; - - DPRINTFN(9, "\n"); - - td = xfer->td_transfer_cache; - - do { - len = td->remainder; - - if (xfer->aframes != xfer->nframes) { - /* - * Verify the length and subtract - * the remainder from "frlengths[]": - */ - if (len > xfer->frlengths[xfer->aframes]) { - td->error = 1; - } else { - xfer->frlengths[xfer->aframes] -= len; - } - } - /* Check for transfer error */ - if (td->error) { - /* the transfer is finished */ - error = 1; - td = NULL; - break; - } - /* Check for short transfer */ - if (len > 0) { - if (xfer->flags_int.short_frames_ok) { - /* follow alt next */ - if (td->alt_next) { - td = td->obj_next; - } else { - td = NULL; - } - } else { - /* the transfer is finished */ - td = NULL; - } - error = 0; - break; - } - td = td->obj_next; - - /* this USB frame is complete */ - error = 0; - break; - - } while (0); - - /* update transfer cache */ - - xfer->td_transfer_cache = td; - - return (error ? - USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); -} - -static void -uss820dci_standard_done(struct usb2_xfer *xfer) -{ - usb2_error_t err = 0; - - DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", - xfer, xfer->pipe); - - /* reset scanner */ - - xfer->td_transfer_cache = xfer->td_transfer_first; - - if (xfer->flags_int.control_xfr) { - - if (xfer->flags_int.control_hdr) { - - err = uss820dci_standard_done_sub(xfer); - } - xfer->aframes = 1; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - while (xfer->aframes != xfer->nframes) { - - err = uss820dci_standard_done_sub(xfer); - xfer->aframes++; - - if (xfer->td_transfer_cache == NULL) { - goto done; - } - } - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - err = uss820dci_standard_done_sub(xfer); - } -done: - uss820dci_device_done(xfer, err); -} - -/*------------------------------------------------------------------------* - * uss820dci_device_done - * - * NOTE: this function can be called more than one time on the - * same USB transfer! - *------------------------------------------------------------------------*/ -static void -uss820dci_device_done(struct usb2_xfer *xfer, usb2_error_t error) -{ - USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); - - DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", - xfer, xfer->pipe, error); - - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { - uss820dci_intr_set(xfer, 0); - } - /* dequeue transfer and start next transfer */ - usb2_transfer_done(xfer, error); -} - -static void -uss820dci_set_stall(struct usb2_device *udev, struct usb2_xfer *xfer, - struct usb2_pipe *pipe) -{ - struct uss820dci_softc *sc; - uint8_t ep_no; - uint8_t ep_type; - uint8_t ep_dir; - uint8_t temp; - - USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); - - DPRINTFN(5, "pipe=%p\n", pipe); - - if (xfer) { - /* cancel any ongoing transfers */ - uss820dci_device_done(xfer, USB_ERR_STALLED); - } - /* set FORCESTALL */ - sc = USS820_DCI_BUS2SC(udev->bus); - ep_no = (pipe->edesc->bEndpointAddress & UE_ADDR); - ep_dir = (pipe->edesc->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT)); - ep_type = (pipe->edesc->bmAttributes & UE_XFERTYPE); - - if (ep_type == UE_CONTROL) { - /* should not happen */ - return; - } - USS820_WRITE_1(sc, USS820_EPINDEX, ep_no); - - if (ep_dir == UE_DIR_IN) { - temp = USS820_EPCON_TXSTL; - } else { - temp = USS820_EPCON_RXSTL; - } - uss820dci_update_shared_1(sc, USS820_EPCON, 0xFF, temp); -} - -static void -uss820dci_clear_stall_sub(struct uss820dci_softc *sc, - uint8_t ep_no, uint8_t ep_type, uint8_t ep_dir) -{ - uint8_t temp; - - if (ep_type == UE_CONTROL) { - /* clearing stall is not needed */ - return; - } - /* select endpoint index */ - USS820_WRITE_1(sc, USS820_EPINDEX, ep_no); - - /* clear stall and disable I/O transfers */ - if (ep_dir == UE_DIR_IN) { - temp = 0xFF ^ (USS820_EPCON_TXOE | - USS820_EPCON_TXSTL); - } else { - temp = 0xFF ^ (USS820_EPCON_RXIE | - USS820_EPCON_RXSTL); - } - uss820dci_update_shared_1(sc, USS820_EPCON, temp, 0); - - if (ep_dir == UE_DIR_IN) { - /* reset data toggle */ - USS820_WRITE_1(sc, USS820_TXSTAT, - USS820_TXSTAT_TXSOVW); - - /* reset FIFO */ - temp = USS820_READ_1(sc, USS820_TXCON); - temp |= USS820_TXCON_TXCLR; - USS820_WRITE_1(sc, USS820_TXCON, temp); - temp &= ~USS820_TXCON_TXCLR; - USS820_WRITE_1(sc, USS820_TXCON, temp); - } else { - - /* reset data toggle */ - uss820dci_update_shared_1(sc, USS820_RXSTAT, - 0, USS820_RXSTAT_RXSOVW); - - /* reset FIFO */ - temp = USS820_READ_1(sc, USS820_RXCON); - temp |= USS820_RXCON_RXCLR; - temp &= ~USS820_RXCON_RXFFRC; - USS820_WRITE_1(sc, USS820_RXCON, temp); - temp &= ~USS820_RXCON_RXCLR; - USS820_WRITE_1(sc, USS820_RXCON, temp); - } -} - -static void -uss820dci_clear_stall(struct usb2_device *udev, struct usb2_pipe *pipe) -{ - struct uss820dci_softc *sc; - struct usb2_endpoint_descriptor *ed; - - USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); - - DPRINTFN(5, "pipe=%p\n", pipe); - - /* check mode */ - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { - /* not supported */ - return; - } - /* get softc */ - sc = USS820_DCI_BUS2SC(udev->bus); - - /* get endpoint descriptor */ - ed = pipe->edesc; - - /* reset endpoint */ - uss820dci_clear_stall_sub(sc, - (ed->bEndpointAddress & UE_ADDR), - (ed->bmAttributes & UE_XFERTYPE), - (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); -} - -usb2_error_t -uss820dci_init(struct uss820dci_softc *sc) -{ - const struct usb2_hw_ep_profile *pf; - uint8_t n; - uint8_t temp; - - DPRINTF("start\n"); - - /* set up the bus structure */ - sc->sc_bus.usbrev = USB_REV_1_1; - sc->sc_bus.methods = &uss820dci_bus_methods; - - USB_BUS_LOCK(&sc->sc_bus); - - /* we always have VBUS */ - sc->sc_flags.status_vbus = 1; - - /* reset the chip */ - USS820_WRITE_1(sc, USS820_SCR, USS820_SCR_SRESET); - DELAY(100); - USS820_WRITE_1(sc, USS820_SCR, 0); - - /* wait for reset to complete */ - for (n = 0;; n++) { - - temp = USS820_READ_1(sc, USS820_MCSR); - - if (temp & USS820_MCSR_INIT) { - break; - } - if (n == 100) { - USB_BUS_UNLOCK(&sc->sc_bus); - return (USB_ERR_INVAL); - } - /* wait a little for things to stabilise */ - DELAY(100); - } - - /* do a pulldown */ - uss820dci_pull_down(sc); - - /* wait 10ms for pulldown to stabilise */ - usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100); - - /* check hardware revision */ - temp = USS820_READ_1(sc, USS820_REV); - - if (temp < 0x13) { - USB_BUS_UNLOCK(&sc->sc_bus); - return (USB_ERR_INVAL); - } - /* enable interrupts */ - USS820_WRITE_1(sc, USS820_SCR, - USS820_SCR_T_IRQ | - USS820_SCR_IE_RESET | - /* USS820_SCR_RWUPE | */ - USS820_SCR_IE_SUSP | - USS820_SCR_IRQPOL); - - /* enable interrupts */ - USS820_WRITE_1(sc, USS820_SCRATCH, - USS820_SCRATCH_IE_RESUME); - - /* enable features */ - USS820_WRITE_1(sc, USS820_MCSR, - USS820_MCSR_BDFEAT | - USS820_MCSR_FEAT); - - sc->sc_flags.mcsr_feat = 1; - - /* disable interrupts */ - USS820_WRITE_1(sc, USS820_SBIE, 0); - - /* disable interrupts */ - USS820_WRITE_1(sc, USS820_SBIE1, 0); - - /* disable all endpoints */ - for (n = 0; n != USS820_EP_MAX; n++) { - - /* select endpoint */ - USS820_WRITE_1(sc, USS820_EPINDEX, n); - - /* disable endpoint */ - uss820dci_update_shared_1(sc, USS820_EPCON, 0, 0); - } - - /* - * Initialise default values for some registers that cannot be - * changed during operation! - */ - for (n = 0; n != USS820_EP_MAX; n++) { - - uss820dci_get_hw_ep_profile(NULL, &pf, n); - - /* the maximum frame sizes should be the same */ - if (pf->max_in_frame_size != pf->max_out_frame_size) { - DPRINTF("Max frame size mismatch %u != %u\n", - pf->max_in_frame_size, pf->max_out_frame_size); - } - if (pf->support_isochronous) { - if (pf->max_in_frame_size <= 64) { - temp = (USS820_TXCON_FFSZ_16_64 | - USS820_TXCON_TXISO | - USS820_TXCON_ATM); - } else if (pf->max_in_frame_size <= 256) { - temp = (USS820_TXCON_FFSZ_64_256 | - USS820_TXCON_TXISO | - USS820_TXCON_ATM); - } else if (pf->max_in_frame_size <= 512) { - temp = (USS820_TXCON_FFSZ_8_512 | - USS820_TXCON_TXISO | - USS820_TXCON_ATM); - } else { /* 1024 bytes */ - temp = (USS820_TXCON_FFSZ_32_1024 | - USS820_TXCON_TXISO | - USS820_TXCON_ATM); - } - } else { - if ((pf->max_in_frame_size <= 8) && - (sc->sc_flags.mcsr_feat)) { - temp = (USS820_TXCON_FFSZ_8_512 | - USS820_TXCON_ATM); - } else if (pf->max_in_frame_size <= 16) { - temp = (USS820_TXCON_FFSZ_16_64 | - USS820_TXCON_ATM); - } else if ((pf->max_in_frame_size <= 32) && - (sc->sc_flags.mcsr_feat)) { - temp = (USS820_TXCON_FFSZ_32_1024 | - USS820_TXCON_ATM); - } else { /* 64 bytes */ - temp = (USS820_TXCON_FFSZ_64_256 | - USS820_TXCON_ATM); - } - } - - /* need to configure the chip early */ - - USS820_WRITE_1(sc, USS820_EPINDEX, n); - USS820_WRITE_1(sc, USS820_TXCON, temp); - USS820_WRITE_1(sc, USS820_RXCON, temp); - - if (pf->support_control) { - temp = USS820_EPCON_CTLEP | - USS820_EPCON_RXSPM | - USS820_EPCON_RXIE | - USS820_EPCON_RXEPEN | - USS820_EPCON_TXOE | - USS820_EPCON_TXEPEN; - } else { - temp = USS820_EPCON_RXEPEN | USS820_EPCON_TXEPEN; - } - - uss820dci_update_shared_1(sc, USS820_EPCON, 0xFF, temp); - } - - USB_BUS_UNLOCK(&sc->sc_bus); - - /* catch any lost interrupts */ - - uss820dci_do_poll(&sc->sc_bus); - - return (0); /* success */ -} - -void -uss820dci_uninit(struct uss820dci_softc *sc) -{ - uint8_t temp; - - USB_BUS_LOCK(&sc->sc_bus); - - /* disable all interrupts */ - temp = USS820_READ_1(sc, USS820_SCR); - temp &= ~USS820_SCR_T_IRQ; - USS820_WRITE_1(sc, USS820_SCR, temp); - - sc->sc_flags.port_powered = 0; - sc->sc_flags.status_vbus = 0; - sc->sc_flags.status_bus_reset = 0; - sc->sc_flags.status_suspend = 0; - sc->sc_flags.change_suspend = 0; - sc->sc_flags.change_connect = 1; - - uss820dci_pull_down(sc); - USB_BUS_UNLOCK(&sc->sc_bus); -} - -void -uss820dci_suspend(struct uss820dci_softc *sc) -{ - return; -} - -void -uss820dci_resume(struct uss820dci_softc *sc) -{ - return; -} - -static void -uss820dci_do_poll(struct usb2_bus *bus) -{ - struct uss820dci_softc *sc = USS820_DCI_BUS2SC(bus); - - USB_BUS_LOCK(&sc->sc_bus); - uss820dci_interrupt_poll(sc); - uss820dci_root_ctrl_poll(sc); - USB_BUS_UNLOCK(&sc->sc_bus); -} - -/*------------------------------------------------------------------------* - * at91dci bulk support - *------------------------------------------------------------------------*/ -static void -uss820dci_device_bulk_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_device_bulk_close(struct usb2_xfer *xfer) -{ - uss820dci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -uss820dci_device_bulk_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_device_bulk_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - uss820dci_setup_standard_chain(xfer); - uss820dci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods uss820dci_device_bulk_methods = -{ - .open = uss820dci_device_bulk_open, - .close = uss820dci_device_bulk_close, - .enter = uss820dci_device_bulk_enter, - .start = uss820dci_device_bulk_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci control support - *------------------------------------------------------------------------*/ -static void -uss820dci_device_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_device_ctrl_close(struct usb2_xfer *xfer) -{ - uss820dci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -uss820dci_device_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_device_ctrl_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - uss820dci_setup_standard_chain(xfer); - uss820dci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods uss820dci_device_ctrl_methods = -{ - .open = uss820dci_device_ctrl_open, - .close = uss820dci_device_ctrl_close, - .enter = uss820dci_device_ctrl_enter, - .start = uss820dci_device_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci interrupt support - *------------------------------------------------------------------------*/ -static void -uss820dci_device_intr_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_device_intr_close(struct usb2_xfer *xfer) -{ - uss820dci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -uss820dci_device_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_device_intr_start(struct usb2_xfer *xfer) -{ - /* setup TDs */ - uss820dci_setup_standard_chain(xfer); - uss820dci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods uss820dci_device_intr_methods = -{ - .open = uss820dci_device_intr_open, - .close = uss820dci_device_intr_close, - .enter = uss820dci_device_intr_enter, - .start = uss820dci_device_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci full speed isochronous support - *------------------------------------------------------------------------*/ -static void -uss820dci_device_isoc_fs_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_device_isoc_fs_close(struct usb2_xfer *xfer) -{ - uss820dci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -uss820dci_device_isoc_fs_enter(struct usb2_xfer *xfer) -{ - struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus); - uint32_t temp; - uint32_t nframes; - - DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", - xfer, xfer->pipe->isoc_next, xfer->nframes); - - /* get the current frame index - we don't need the high bits */ - - nframes = USS820_READ_1(sc, USS820_SOFL); - - /* - * check if the frame index is within the window where the - * frames will be inserted - */ - temp = (nframes - xfer->pipe->isoc_next) & USS820_SOFL_MASK; - - if ((xfer->pipe->is_synced == 0) || - (temp < xfer->nframes)) { - /* - * If there is data underflow or the pipe queue is - * empty we schedule the transfer a few frames ahead - * of the current frame position. Else two isochronous - * transfers might overlap. - */ - xfer->pipe->isoc_next = (nframes + 3) & USS820_SOFL_MASK; - xfer->pipe->is_synced = 1; - DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next); - } - /* - * compute how many milliseconds the insertion is ahead of the - * current frame position: - */ - temp = (xfer->pipe->isoc_next - nframes) & USS820_SOFL_MASK; - - /* - * pre-compute when the isochronous transfer will be finished: - */ - xfer->isoc_time_complete = - usb2_isoc_time_expand(&sc->sc_bus, nframes) + temp + - xfer->nframes; - - /* compute frame number for next insertion */ - xfer->pipe->isoc_next += xfer->nframes; - - /* setup TDs */ - uss820dci_setup_standard_chain(xfer); -} - -static void -uss820dci_device_isoc_fs_start(struct usb2_xfer *xfer) -{ - /* start TD chain */ - uss820dci_start_standard_chain(xfer); -} - -struct usb2_pipe_methods uss820dci_device_isoc_fs_methods = -{ - .open = uss820dci_device_isoc_fs_open, - .close = uss820dci_device_isoc_fs_close, - .enter = uss820dci_device_isoc_fs_enter, - .start = uss820dci_device_isoc_fs_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -/*------------------------------------------------------------------------* - * at91dci root control support - *------------------------------------------------------------------------* - * simulate a hardware HUB by handling - * all the necessary requests - *------------------------------------------------------------------------*/ - -static void -uss820dci_root_ctrl_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_root_ctrl_close(struct usb2_xfer *xfer) -{ - struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_ctrl.xfer == xfer) { - sc->sc_root_ctrl.xfer = NULL; - } - uss820dci_device_done(xfer, USB_ERR_CANCELLED); -} - -/* - * USB descriptors for the virtual Root HUB: - */ - -static const struct usb2_device_descriptor uss820dci_devd = { - .bLength = sizeof(struct usb2_device_descriptor), - .bDescriptorType = UDESC_DEVICE, - .bcdUSB = {0x00, 0x02}, - .bDeviceClass = UDCLASS_HUB, - .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_HSHUBSTT, - .bMaxPacketSize = 64, - .bcdDevice = {0x00, 0x01}, - .iManufacturer = 1, - .iProduct = 2, - .bNumConfigurations = 1, -}; - -static const struct usb2_device_qualifier uss820dci_odevd = { - .bLength = sizeof(struct usb2_device_qualifier), - .bDescriptorType = UDESC_DEVICE_QUALIFIER, - .bcdUSB = {0x00, 0x02}, - .bDeviceClass = UDCLASS_HUB, - .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_FSHUB, - .bMaxPacketSize0 = 0, - .bNumConfigurations = 0, -}; - -static const struct uss820dci_config_desc uss820dci_confd = { - .confd = { - .bLength = sizeof(struct usb2_config_descriptor), - .bDescriptorType = UDESC_CONFIG, - .wTotalLength[0] = sizeof(uss820dci_confd), - .bNumInterface = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = UC_SELF_POWERED, - .bMaxPower = 0, - }, - .ifcd = { - .bLength = sizeof(struct usb2_interface_descriptor), - .bDescriptorType = UDESC_INTERFACE, - .bNumEndpoints = 1, - .bInterfaceClass = UICLASS_HUB, - .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_HSHUBSTT, - }, - - .endpd = { - .bLength = sizeof(struct usb2_endpoint_descriptor), - .bDescriptorType = UDESC_ENDPOINT, - .bEndpointAddress = (UE_DIR_IN | USS820_DCI_INTR_ENDPT), - .bmAttributes = UE_INTERRUPT, - .wMaxPacketSize[0] = 8, - .bInterval = 255, - }, -}; - -static const struct usb2_hub_descriptor_min uss820dci_hubd = { - .bDescLength = sizeof(uss820dci_hubd), - .bDescriptorType = UDESC_HUB, - .bNbrPorts = 1, - .wHubCharacteristics[0] = - (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) & 0xFF, - .wHubCharacteristics[1] = - (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) >> 8, - .bPwrOn2PwrGood = 50, - .bHubContrCurrent = 0, - .DeviceRemovable = {0}, /* port is removable */ -}; - -#define STRING_LANG \ - 0x09, 0x04, /* American English */ - -#define STRING_VENDOR \ - 'A', 0, 'G', 0, 'E', 0, 'R', 0, 'E', 0 - -#define STRING_PRODUCT \ - 'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \ - 'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \ - 'U', 0, 'B', 0, - -USB_MAKE_STRING_DESC(STRING_LANG, uss820dci_langtab); -USB_MAKE_STRING_DESC(STRING_VENDOR, uss820dci_vendor); -USB_MAKE_STRING_DESC(STRING_PRODUCT, uss820dci_product); - -static void -uss820dci_root_ctrl_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_root_ctrl_start(struct usb2_xfer *xfer) -{ - struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus); - - sc->sc_root_ctrl.xfer = xfer; - - usb2_bus_roothub_exec(xfer->xroot->bus); -} - -static void -uss820dci_root_ctrl_task(struct usb2_bus *bus) -{ - uss820dci_root_ctrl_poll(USS820_DCI_BUS2SC(bus)); -} - -static void -uss820dci_root_ctrl_done(struct usb2_xfer *xfer, - struct usb2_sw_transfer *std) -{ - struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus); - uint16_t value; - uint16_t index; - uint8_t use_polling; - - USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); - - if (std->state != USB_SW_TR_SETUP) { - if (std->state == USB_SW_TR_PRE_CALLBACK) { - /* transfer transferred */ - uss820dci_device_done(xfer, std->err); - } - goto done; - } - /* buffer reset */ - std->ptr = USB_ADD_BYTES(&sc->sc_hub_temp, 0); - std->len = 0; - - value = UGETW(std->req.wValue); - index = UGETW(std->req.wIndex); - - use_polling = mtx_owned(xfer->xroot->xfer_mtx) ? 1 : 0; - - /* demultiplex the control request */ - - switch (std->req.bmRequestType) { - case UT_READ_DEVICE: - switch (std->req.bRequest) { - case UR_GET_DESCRIPTOR: - goto tr_handle_get_descriptor; - case UR_GET_CONFIG: - goto tr_handle_get_config; - case UR_GET_STATUS: - goto tr_handle_get_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_DEVICE: - switch (std->req.bRequest) { - case UR_SET_ADDRESS: - goto tr_handle_set_address; - case UR_SET_CONFIG: - goto tr_handle_set_config; - case UR_CLEAR_FEATURE: - goto tr_valid; /* nop */ - case UR_SET_DESCRIPTOR: - goto tr_valid; /* nop */ - case UR_SET_FEATURE: - default: - goto tr_stalled; - } - break; - - case UT_WRITE_ENDPOINT: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - switch (UGETW(std->req.wValue)) { - case UF_ENDPOINT_HALT: - goto tr_handle_clear_halt; - case UF_DEVICE_REMOTE_WAKEUP: - goto tr_handle_clear_wakeup; - default: - goto tr_stalled; - } - break; - case UR_SET_FEATURE: - switch (UGETW(std->req.wValue)) { - case UF_ENDPOINT_HALT: - goto tr_handle_set_halt; - case UF_DEVICE_REMOTE_WAKEUP: - goto tr_handle_set_wakeup; - default: - goto tr_stalled; - } - break; - case UR_SYNCH_FRAME: - goto tr_valid; /* nop */ - default: - goto tr_stalled; - } - break; - - case UT_READ_ENDPOINT: - switch (std->req.bRequest) { - case UR_GET_STATUS: - goto tr_handle_get_ep_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_INTERFACE: - switch (std->req.bRequest) { - case UR_SET_INTERFACE: - goto tr_handle_set_interface; - case UR_CLEAR_FEATURE: - goto tr_valid; /* nop */ - case UR_SET_FEATURE: - default: - goto tr_stalled; - } - break; - - case UT_READ_INTERFACE: - switch (std->req.bRequest) { - case UR_GET_INTERFACE: - goto tr_handle_get_interface; - case UR_GET_STATUS: - goto tr_handle_get_iface_status; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_CLASS_INTERFACE: - case UT_WRITE_VENDOR_INTERFACE: - /* XXX forward */ - break; - - case UT_READ_CLASS_INTERFACE: - case UT_READ_VENDOR_INTERFACE: - /* XXX forward */ - break; - - case UT_WRITE_CLASS_DEVICE: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - goto tr_valid; - case UR_SET_DESCRIPTOR: - case UR_SET_FEATURE: - break; - default: - goto tr_stalled; - } - break; - - case UT_WRITE_CLASS_OTHER: - switch (std->req.bRequest) { - case UR_CLEAR_FEATURE: - goto tr_handle_clear_port_feature; - case UR_SET_FEATURE: - goto tr_handle_set_port_feature; - case UR_CLEAR_TT_BUFFER: - case UR_RESET_TT: - case UR_STOP_TT: - goto tr_valid; - - default: - goto tr_stalled; - } - break; - - case UT_READ_CLASS_OTHER: - switch (std->req.bRequest) { - case UR_GET_TT_STATE: - goto tr_handle_get_tt_state; - case UR_GET_STATUS: - goto tr_handle_get_port_status; - default: - goto tr_stalled; - } - break; - - case UT_READ_CLASS_DEVICE: - switch (std->req.bRequest) { - case UR_GET_DESCRIPTOR: - goto tr_handle_get_class_descriptor; - case UR_GET_STATUS: - goto tr_handle_get_class_status; - - default: - goto tr_stalled; - } - break; - default: - goto tr_stalled; - } - goto tr_valid; - -tr_handle_get_descriptor: - switch (value >> 8) { - case UDESC_DEVICE: - if (value & 0xff) { - goto tr_stalled; - } - std->len = sizeof(uss820dci_devd); - std->ptr = USB_ADD_BYTES(&uss820dci_devd, 0); - goto tr_valid; - case UDESC_CONFIG: - if (value & 0xff) { - goto tr_stalled; - } - std->len = sizeof(uss820dci_confd); - std->ptr = USB_ADD_BYTES(&uss820dci_confd, 0); - goto tr_valid; - case UDESC_STRING: - switch (value & 0xff) { - case 0: /* Language table */ - std->len = sizeof(uss820dci_langtab); - std->ptr = USB_ADD_BYTES(&uss820dci_langtab, 0); - goto tr_valid; - - case 1: /* Vendor */ - std->len = sizeof(uss820dci_vendor); - std->ptr = USB_ADD_BYTES(&uss820dci_vendor, 0); - goto tr_valid; - - case 2: /* Product */ - std->len = sizeof(uss820dci_product); - std->ptr = USB_ADD_BYTES(&uss820dci_product, 0); - goto tr_valid; - default: - break; - } - break; - default: - goto tr_stalled; - } - goto tr_stalled; - -tr_handle_get_config: - std->len = 1; - sc->sc_hub_temp.wValue[0] = sc->sc_conf; - goto tr_valid; - -tr_handle_get_status: - std->len = 2; - USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); - goto tr_valid; - -tr_handle_set_address: - if (value & 0xFF00) { - goto tr_stalled; - } - sc->sc_rt_addr = value; - goto tr_valid; - -tr_handle_set_config: - if (value >= 2) { - goto tr_stalled; - } - sc->sc_conf = value; - goto tr_valid; - -tr_handle_get_interface: - std->len = 1; - sc->sc_hub_temp.wValue[0] = 0; - goto tr_valid; - -tr_handle_get_tt_state: -tr_handle_get_class_status: -tr_handle_get_iface_status: -tr_handle_get_ep_status: - std->len = 2; - USETW(sc->sc_hub_temp.wValue, 0); - goto tr_valid; - -tr_handle_set_halt: -tr_handle_set_interface: -tr_handle_set_wakeup: -tr_handle_clear_wakeup: -tr_handle_clear_halt: - goto tr_valid; - -tr_handle_clear_port_feature: - if (index != 1) { - goto tr_stalled; - } - DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index); - - switch (value) { - case UHF_PORT_SUSPEND: - uss820dci_wakeup_peer(sc); - break; - - case UHF_PORT_ENABLE: - sc->sc_flags.port_enabled = 0; - break; - - case UHF_PORT_TEST: - case UHF_PORT_INDICATOR: - case UHF_C_PORT_ENABLE: - case UHF_C_PORT_OVER_CURRENT: - case UHF_C_PORT_RESET: - /* nops */ - break; - case UHF_PORT_POWER: - sc->sc_flags.port_powered = 0; - uss820dci_pull_down(sc); - break; - case UHF_C_PORT_CONNECTION: - sc->sc_flags.change_connect = 0; - break; - case UHF_C_PORT_SUSPEND: - sc->sc_flags.change_suspend = 0; - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - goto tr_valid; - -tr_handle_set_port_feature: - if (index != 1) { - goto tr_stalled; - } - DPRINTFN(9, "UR_SET_PORT_FEATURE\n"); - - switch (value) { - case UHF_PORT_ENABLE: - sc->sc_flags.port_enabled = 1; - break; - case UHF_PORT_SUSPEND: - case UHF_PORT_RESET: - case UHF_PORT_TEST: - case UHF_PORT_INDICATOR: - /* nops */ - break; - case UHF_PORT_POWER: - sc->sc_flags.port_powered = 1; - break; - default: - std->err = USB_ERR_IOERROR; - goto done; - } - goto tr_valid; - -tr_handle_get_port_status: - - DPRINTFN(9, "UR_GET_PORT_STATUS\n"); - - if (index != 1) { - goto tr_stalled; - } - if (sc->sc_flags.status_vbus) { - uss820dci_pull_up(sc); - } else { - uss820dci_pull_down(sc); - } - - /* Select FULL-speed and Device Side Mode */ - - value = UPS_PORT_MODE_DEVICE; - - if (sc->sc_flags.port_powered) { - value |= UPS_PORT_POWER; - } - if (sc->sc_flags.port_enabled) { - value |= UPS_PORT_ENABLED; - } - if (sc->sc_flags.status_vbus && - sc->sc_flags.status_bus_reset) { - value |= UPS_CURRENT_CONNECT_STATUS; - } - if (sc->sc_flags.status_suspend) { - value |= UPS_SUSPEND; - } - USETW(sc->sc_hub_temp.ps.wPortStatus, value); - - value = 0; - - if (sc->sc_flags.change_connect) { - value |= UPS_C_CONNECT_STATUS; - } - if (sc->sc_flags.change_suspend) { - value |= UPS_C_SUSPEND; - } - USETW(sc->sc_hub_temp.ps.wPortChange, value); - std->len = sizeof(sc->sc_hub_temp.ps); - goto tr_valid; - -tr_handle_get_class_descriptor: - if (value & 0xFF) { - goto tr_stalled; - } - std->ptr = USB_ADD_BYTES(&uss820dci_hubd, 0); - std->len = sizeof(uss820dci_hubd); - goto tr_valid; - -tr_stalled: - std->err = USB_ERR_STALLED; -tr_valid: -done: - return; -} - -static void -uss820dci_root_ctrl_poll(struct uss820dci_softc *sc) -{ - usb2_sw_transfer(&sc->sc_root_ctrl, - &uss820dci_root_ctrl_done); -} - -struct usb2_pipe_methods uss820dci_root_ctrl_methods = -{ - .open = uss820dci_root_ctrl_open, - .close = uss820dci_root_ctrl_close, - .enter = uss820dci_root_ctrl_enter, - .start = uss820dci_root_ctrl_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 0, -}; - -/*------------------------------------------------------------------------* - * at91dci root interrupt support - *------------------------------------------------------------------------*/ -static void -uss820dci_root_intr_open(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_root_intr_close(struct usb2_xfer *xfer) -{ - struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus); - - if (sc->sc_root_intr.xfer == xfer) { - sc->sc_root_intr.xfer = NULL; - } - uss820dci_device_done(xfer, USB_ERR_CANCELLED); -} - -static void -uss820dci_root_intr_enter(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_root_intr_start(struct usb2_xfer *xfer) -{ - struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus); - - sc->sc_root_intr.xfer = xfer; -} - -struct usb2_pipe_methods uss820dci_root_intr_methods = -{ - .open = uss820dci_root_intr_open, - .close = uss820dci_root_intr_close, - .enter = uss820dci_root_intr_enter, - .start = uss820dci_root_intr_start, - .enter_is_cancelable = 1, - .start_is_cancelable = 1, -}; - -static void -uss820dci_xfer_setup(struct usb2_setup_params *parm) -{ - const struct usb2_hw_ep_profile *pf; - struct uss820dci_softc *sc; - struct usb2_xfer *xfer; - void *last_obj; - uint32_t ntd; - uint32_t n; - uint8_t ep_no; - - sc = USS820_DCI_BUS2SC(parm->udev->bus); - xfer = parm->curr_xfer; - - /* - * NOTE: This driver does not use any of the parameters that - * are computed from the following values. Just set some - * reasonable dummies: - */ - parm->hc_max_packet_size = 0x500; - parm->hc_max_packet_count = 1; - parm->hc_max_frame_size = 0x500; - - usb2_transfer_setup_sub(parm); - - /* - * compute maximum number of TDs - */ - if (parm->methods == &uss820dci_device_ctrl_methods) { - - ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC */ ; - - } else if (parm->methods == &uss820dci_device_bulk_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else if (parm->methods == &uss820dci_device_intr_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else if (parm->methods == &uss820dci_device_isoc_fs_methods) { - - ntd = xfer->nframes + 1 /* SYNC */ ; - - } else { - - ntd = 0; - } - - /* - * check if "usb2_transfer_setup_sub" set an error - */ - if (parm->err) { - return; - } - /* - * allocate transfer descriptors - */ - last_obj = NULL; - - /* - * get profile stuff - */ - if (ntd) { - - ep_no = xfer->endpoint & UE_ADDR; - uss820dci_get_hw_ep_profile(parm->udev, &pf, ep_no); - - if (pf == NULL) { - /* should not happen */ - parm->err = USB_ERR_INVAL; - return; - } - } else { - ep_no = 0; - pf = NULL; - } - - /* align data */ - parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); - - for (n = 0; n != ntd; n++) { - - struct uss820dci_td *td; - - if (parm->buf) { - - td = USB_ADD_BYTES(parm->buf, parm->size[0]); - - /* init TD */ - td->io_tag = sc->sc_io_tag; - td->io_hdl = sc->sc_io_hdl; - td->max_packet_size = xfer->max_packet_size; - td->rx_stat_reg = USS820_GET_REG(sc, USS820_RXSTAT); - td->tx_stat_reg = USS820_GET_REG(sc, USS820_TXSTAT); - td->rx_flag_reg = USS820_GET_REG(sc, USS820_RXFLG); - td->tx_flag_reg = USS820_GET_REG(sc, USS820_TXFLG); - td->rx_fifo_reg = USS820_GET_REG(sc, USS820_RXDAT); - td->tx_fifo_reg = USS820_GET_REG(sc, USS820_TXDAT); - td->rx_count_low_reg = USS820_GET_REG(sc, USS820_RXCNTL); - td->rx_count_high_reg = USS820_GET_REG(sc, USS820_RXCNTH); - td->tx_count_low_reg = USS820_GET_REG(sc, USS820_TXCNTL); - td->tx_count_high_reg = USS820_GET_REG(sc, USS820_TXCNTH); - td->rx_cntl_reg = USS820_GET_REG(sc, USS820_RXCON); - td->tx_cntl_reg = USS820_GET_REG(sc, USS820_TXCON); - td->pend_reg = USS820_GET_REG(sc, USS820_PEND); - td->ep_reg = USS820_GET_REG(sc, USS820_EPINDEX); - td->ep_index = ep_no; - if (pf->support_multi_buffer && - (parm->methods != &uss820dci_device_ctrl_methods)) { - td->support_multi_buffer = 1; - } - td->obj_next = last_obj; - - last_obj = td; - } - parm->size[0] += sizeof(*td); - } - - xfer->td_start[0] = last_obj; -} - -static void -uss820dci_xfer_unsetup(struct usb2_xfer *xfer) -{ - return; -} - -static void -uss820dci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, - struct usb2_pipe *pipe) -{ - struct uss820dci_softc *sc = USS820_DCI_BUS2SC(udev->bus); - - DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", - pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, - sc->sc_rt_addr); - - if (udev->device_index == sc->sc_rt_addr) { - - if (udev->flags.usb2_mode != USB_MODE_HOST) { - /* not supported */ - return; - } - switch (edesc->bEndpointAddress) { - case USB_CONTROL_ENDPOINT: - pipe->methods = &uss820dci_root_ctrl_methods; - break; - case UE_DIR_IN | USS820_DCI_INTR_ENDPT: - pipe->methods = &uss820dci_root_intr_methods; - break; - default: - /* do nothing */ - break; - } - } else { - - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { - /* not supported */ - return; - } - if (udev->speed != USB_SPEED_FULL) { - /* not supported */ - return; - } - switch (edesc->bmAttributes & UE_XFERTYPE) { - case UE_CONTROL: - pipe->methods = &uss820dci_device_ctrl_methods; - break; - case UE_INTERRUPT: - pipe->methods = &uss820dci_device_intr_methods; - break; - case UE_ISOCHRONOUS: - pipe->methods = &uss820dci_device_isoc_fs_methods; - break; - case UE_BULK: - pipe->methods = &uss820dci_device_bulk_methods; - break; - default: - /* do nothing */ - break; - } - } -} - -struct usb2_bus_methods uss820dci_bus_methods = -{ - .pipe_init = &uss820dci_pipe_init, - .xfer_setup = &uss820dci_xfer_setup, - .xfer_unsetup = &uss820dci_xfer_unsetup, - .do_poll = &uss820dci_do_poll, - .get_hw_ep_profile = &uss820dci_get_hw_ep_profile, - .set_stall = &uss820dci_set_stall, - .clear_stall = &uss820dci_clear_stall, - .roothub_exec = &uss820dci_root_ctrl_task, -}; diff --git a/sys/dev/usb2/controller/uss820dci.h b/sys/dev/usb2/controller/uss820dci.h deleted file mode 100644 index f99e2d5..0000000 --- a/sys/dev/usb2/controller/uss820dci.h +++ /dev/null @@ -1,377 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2007 Hans Petter Selasky <hselasky@freebsd.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _USS820_DCI_H_ -#define _USS820_DCI_H_ - -#define USS820_MAX_DEVICES (USB_MIN_DEVICES + 1) - -#define USS820_EP_MAX 8 /* maximum number of endpoints */ - -#define USS820_TXDAT 0x00 /* Transmit FIFO data */ - -#define USS820_TXCNTL 0x01 /* Transmit FIFO byte count low */ -#define USS820_TXCNTL_MASK 0xFF - -#define USS820_TXCNTH 0x02 /* Transmit FIFO byte count high */ -#define USS820_TXCNTH_MASK 0x03 -#define USS820_TXCNTH_UNUSED 0xFC - -#define USS820_TXCON 0x03 /* USB transmit FIFO control */ -#define USS820_TXCON_REVRP 0x01 -#define USS820_TXCON_ADVRM 0x02 -#define USS820_TXCON_ATM 0x04 /* Automatic Transmit Management */ -#define USS820_TXCON_TXISO 0x08 /* Transmit Isochronous Data */ -#define USS820_TXCON_UNUSED 0x10 -#define USS820_TXCON_FFSZ_16_64 0x00 -#define USS820_TXCON_FFSZ_64_256 0x20 -#define USS820_TXCON_FFSZ_8_512 0x40 -#define USS820_TXCON_FFSZ_32_1024 0x60 -#define USS820_TXCON_FFSZ_MASK 0x60 -#define USS820_TXCON_TXCLR 0x80 /* Transmit FIFO clear */ - -#define USS820_TXFLG 0x04 /* Transmit FIFO flag (Read Only) */ -#define USS820_TXFLG_TXOVF 0x01 /* TX overrun */ -#define USS820_TXFLG_TXURF 0x02 /* TX underrun */ -#define USS820_TXFLG_TXFULL 0x04 /* TX full */ -#define USS820_TXFLG_TXEMP 0x08 /* TX empty */ -#define USS820_TXFLG_UNUSED 0x30 -#define USS820_TXFLG_TXFIF0 0x40 -#define USS820_TXFLG_TXFIF1 0x80 - -#define USS820_RXDAT 0x05 /* Receive FIFO data */ - -#define USS820_RXCNTL 0x06 /* Receive FIFO byte count low */ -#define USS820_RXCNTL_MASK 0xFF - -#define USS820_RXCNTH 0x07 /* Receive FIFO byte count high */ -#define USS820_RXCNTH_MASK 0x03 -#define USS820_RXCNTH_UNUSED 0xFC - -#define USS820_RXCON 0x08 /* Receive FIFO control */ -#define USS820_RXCON_REVWP 0x01 -#define USS820_RXCON_ADVWM 0x02 -#define USS820_RXCON_ARM 0x04 /* Auto Receive Management */ -#define USS820_RXCON_RXISO 0x08 /* Receive Isochronous Data */ -#define USS820_RXCON_RXFFRC 0x10 /* FIFO Read Complete */ -#define USS820_RXCON_FFSZ_16_64 0x00 -#define USS820_RXCON_FFSZ_64_256 0x20 -#define USS820_RXCON_FFSZ_8_512 0x40 -#define USS820_RXCON_FFSZ_32_1024 0x60 -#define USS820_RXCON_RXCLR 0x80 /* Receive FIFO clear */ - -#define USS820_RXFLG 0x09 /* Receive FIFO flag (Read Only) */ -#define USS820_RXFLG_RXOVF 0x01 /* RX overflow */ -#define USS820_RXFLG_RXURF 0x02 /* RX underflow */ -#define USS820_RXFLG_RXFULL 0x04 /* RX full */ -#define USS820_RXFLG_RXEMP 0x08 /* RX empty */ -#define USS820_RXFLG_RXFLUSH 0x10 /* RX flush */ -#define USS820_RXFLG_UNUSED 0x20 -#define USS820_RXFLG_RXFIF0 0x40 -#define USS820_RXFLG_RXFIF1 0x80 - -#define USS820_EPINDEX 0x0a /* Endpoint index selection */ -#define USS820_EPINDEX_MASK 0x07 -#define USS820_EPINDEX_UNUSED 0xF8 - -#define USS820_EPCON 0x0b /* Endpoint control */ -#define USS820_EPCON_TXEPEN 0x01 /* Transmit Endpoint Enable */ -#define USS820_EPCON_TXOE 0x02 /* Transmit Output Enable */ -#define USS820_EPCON_RXEPEN 0x04 /* Receive Endpoint Enable */ -#define USS820_EPCON_RXIE 0x08 /* Receive Input Enable */ -#define USS820_EPCON_RXSPM 0x10 /* Receive Single-Packet Mode */ -#define USS820_EPCON_CTLEP 0x20 /* Control Endpoint */ -#define USS820_EPCON_TXSTL 0x40 /* Stall Transmit Endpoint */ -#define USS820_EPCON_RXSTL 0x80 /* Stall Receive Endpoint */ - -#define USS820_TXSTAT 0x0c /* Transmit status */ -#define USS820_TXSTAT_TXACK 0x01 /* Transmit Acknowledge */ -#define USS820_TXSTAT_TXERR 0x02 /* Transmit Error */ -#define USS820_TXSTAT_TXVOID 0x04 /* Transmit Void */ -#define USS820_TXSTAT_TXSOVW 0x08 /* Transmit Data Sequence Overwrite - * Bit */ -#define USS820_TXSTAT_TXFLUSH 0x10 /* Transmit FIFO Packet Flushed */ -#define USS820_TXSTAT_TXNAKE 0x20 /* Transmit NAK Mode Enable */ -#define USS820_TXSTAT_TXDSAM 0x40 /* Transmit Data-Set-Available Mode */ -#define USS820_TXSTAT_TXSEQ 0x80 /* Transmitter Current Sequence Bit */ - -#define USS820_RXSTAT 0x0d /* Receive status */ -#define USS820_RXSTAT_RXACK 0x01 /* Receive Acknowledge */ -#define USS820_RXSTAT_RXERR 0x02 /* Receive Error */ -#define USS820_RXSTAT_RXVOID 0x04 /* Receive Void */ -#define USS820_RXSTAT_RXSOVW 0x08 /* Receive Data Sequence Overwrite Bit */ -#define USS820_RXSTAT_EDOVW 0x10 /* End Overwrite Flag */ -#define USS820_RXSTAT_STOVW 0x20 /* Start Overwrite Flag */ -#define USS820_RXSTAT_RXSETUP 0x40 /* Received SETUP token */ -#define USS820_RXSTAT_RXSEQ 0x80 /* Receiver Endpoint Sequence Bit */ - -#define USS820_SOFL 0x0e /* Start Of Frame counter low */ -#define USS820_SOFL_MASK 0xFF - -#define USS820_SOFH 0x0f /* Start Of Frame counter high */ -#define USS820_SOFH_MASK 0x07 -#define USS820_SOFH_SOFDIS 0x08 /* SOF Pin Output Disable */ -#define USS820_SOFH_FTLOCK 0x10 /* Frame Timer Lock */ -#define USS820_SOFH_SOFIE 0x20 /* SOF Interrupt Enable */ -#define USS820_SOFH_ASOF 0x40 /* Any Start of Frame */ -#define USS820_SOFH_SOFACK 0x80 /* SOF Token Received Without Error */ - -#define USS820_FADDR 0x10 /* Function Address */ -#define USS820_FADDR_MASK 0x7F -#define USS820_FADDR_UNUSED 0x80 - -#define USS820_SCR 0x11 /* System Control */ -#define USS820_SCR_UNUSED 0x01 -#define USS820_SCR_T_IRQ 0x02 /* Global Interrupt Enable */ -#define USS820_SCR_IRQLVL 0x04 /* Interrupt Mode */ -#define USS820_SCR_SRESET 0x08 /* Software reset */ -#define USS820_SCR_IE_RESET 0x10 /* Enable Reset Interrupt */ -#define USS820_SCR_IE_SUSP 0x20 /* Enable Suspend Interrupt */ -#define USS820_SCR_RWUPE 0x40 /* Enable Remote Wake-Up Feature */ -#define USS820_SCR_IRQPOL 0x80 /* IRQ polarity */ - -#define USS820_SSR 0x12 /* System Status */ -#define USS820_SSR_RESET 0x01 /* Reset Condition Detected on USB - * cable */ -#define USS820_SSR_SUSPEND 0x02 /* Suspend Detected */ -#define USS820_SSR_RESUME 0x04 /* Resume Detected */ -#define USS820_SSR_SUSPDIS 0x08 /* Suspend Disable */ -#define USS820_SSR_SUSPPO 0x10 /* Suspend Power Off */ -#define USS820_SSR_UNUSED 0xE0 - -#define USS820_UNK0 0x13 /* Unknown */ -#define USS820_UNK0_UNUSED 0xFF - -#define USS820_SBI 0x14 /* Serial bus interrupt low */ -#define USS820_SBI_FTXD0 0x01 /* Function Transmit Done, EP 0 */ -#define USS820_SBI_FRXD0 0x02 /* Function Receive Done, EP 0 */ -#define USS820_SBI_FTXD1 0x04 -#define USS820_SBI_FRXD1 0x08 -#define USS820_SBI_FTXD2 0x10 -#define USS820_SBI_FRXD2 0x20 -#define USS820_SBI_FTXD3 0x40 -#define USS820_SBI_FRXD3 0x80 - -#define USS820_SBI1 0x15 /* Serial bus interrupt high */ -#define USS820_SBI1_FTXD4 0x01 -#define USS820_SBI1_FRXD4 0x02 -#define USS820_SBI1_FTXD5 0x04 -#define USS820_SBI1_FRXD5 0x08 -#define USS820_SBI1_FTXD6 0x10 -#define USS820_SBI1_FRXD6 0x20 -#define USS820_SBI1_FTXD7 0x40 -#define USS820_SBI1_FRXD7 0x80 - -#define USS820_SBIE 0x16 /* Serial bus interrupt enable low */ -#define USS820_SBIE_FTXIE0 0x01 -#define USS820_SBIE_FRXIE0 0x02 -#define USS820_SBIE_FTXIE1 0x04 -#define USS820_SBIE_FRXIE1 0x08 -#define USS820_SBIE_FTXIE2 0x10 -#define USS820_SBIE_FRXIE2 0x20 -#define USS820_SBIE_FTXIE3 0x40 -#define USS820_SBIE_FRXIE3 0x80 - -#define USS820_SBIE1 0x17 /* Serial bus interrupt enable high */ -#define USS820_SBIE1_FTXIE4 0x01 -#define USS820_SBIE1_FRXIE4 0x02 -#define USS820_SBIE1_FTXIE5 0x04 -#define USS820_SBIE1_FRXIE5 0x08 -#define USS820_SBIE1_FTXIE6 0x10 -#define USS820_SBIE1_FRXIE6 0x20 -#define USS820_SBIE1_FTXIE7 0x40 -#define USS820_SBIE1_FRXIE7 0x80 - -#define USS820_REV 0x18 /* Hardware revision */ -#define USS820_REV_MIN 0x0F -#define USS820_REV_MAJ 0xF0 - -#define USS820_LOCK 0x19 /* Suspend power-off locking */ -#define USS820_LOCK_UNLOCKED 0x01 -#define USS820_LOCK_UNUSED 0xFE - -#define USS820_PEND 0x1a /* Pend hardware status update */ -#define USS820_PEND_PEND 0x01 -#define USS820_PEND_UNUSED 0xFE - -#define USS820_SCRATCH 0x1b /* Scratch firmware information */ -#define USS820_SCRATCH_MASK 0x7F -#define USS820_SCRATCH_IE_RESUME 0x80 /* Enable Resume Interrupt */ - -#define USS820_MCSR 0x1c /* Miscellaneous control and status */ -#define USS820_MCSR_DPEN 0x01 /* DPLS Pull-Up Enable */ -#define USS820_MCSR_SUSPLOE 0x02 /* Suspend Lock Out Enable */ -#define USS820_MCSR_BDFEAT 0x04 /* Board Feature Enable */ -#define USS820_MCSR_FEAT 0x08 /* Feature Enable */ -#define USS820_MCSR_PKGID 0x10 /* Package Identification */ -#define USS820_MCSR_SUSPS 0x20 /* Suspend Status */ -#define USS820_MCSR_INIT 0x40 /* Device Initialized */ -#define USS820_MCSR_RWUPR 0x80 /* Remote Wakeup-Up Remember */ - -#define USS820_DSAV 0x1d /* Data set available low (Read Only) */ -#define USS820_DSAV_TXAV0 0x01 -#define USS820_DSAV_RXAV0 0x02 -#define USS820_DSAV_TXAV1 0x04 -#define USS820_DSAV_RXAV1 0x08 -#define USS820_DSAV_TXAV2 0x10 -#define USS820_DSAV_RXAV2 0x20 -#define USS820_DSAV_TXAV3 0x40 -#define USS820_DSAV_RXAV3 0x80 - -#define USS820_DSAV1 0x1e /* Data set available high */ -#define USS820_DSAV1_TXAV4 0x01 -#define USS820_DSAV1_RXAV4 0x02 -#define USS820_DSAV1_TXAV5 0x04 -#define USS820_DSAV1_RXAV5 0x08 -#define USS820_DSAV1_TXAV6 0x10 -#define USS820_DSAV1_RXAV6 0x20 -#define USS820_DSAV1_TXAV7 0x40 -#define USS820_DSAV1_RXAV7 0x80 - -#define USS820_UNK1 0x1f /* Unknown */ -#define USS820_UNK1_UNKNOWN 0xFF - -#define USS820_GET_REG(sc,reg) \ - ((reg) << (sc)->sc_reg_shift) - -#define USS820_READ_1(sc, reg) \ - bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \ - USS820_GET_REG(sc,reg)) - -#define USS820_WRITE_1(sc, reg, data) \ - bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \ - USS820_GET_REG(sc,reg), data) - -struct uss820dci_td; - -typedef uint8_t (uss820dci_cmd_t)(struct uss820dci_td *td); - -struct uss820dci_td { - bus_space_tag_t io_tag; - bus_space_handle_t io_hdl; - struct uss820dci_td *obj_next; - uss820dci_cmd_t *func; - struct usb2_page_cache *pc; - uint32_t offset; - uint32_t remainder; - uint16_t max_packet_size; - uint8_t rx_stat_reg; - uint8_t tx_stat_reg; - uint8_t rx_flag_reg; - uint8_t tx_flag_reg; - uint8_t rx_fifo_reg; - uint8_t tx_fifo_reg; - uint8_t rx_count_low_reg; - uint8_t rx_count_high_reg; - uint8_t tx_count_low_reg; - uint8_t tx_count_high_reg; - uint8_t rx_cntl_reg; - uint8_t tx_cntl_reg; - uint8_t ep_reg; - uint8_t pend_reg; - uint8_t ep_index; - uint8_t error:1; - uint8_t alt_next:1; - uint8_t short_pkt:1; - uint8_t support_multi_buffer:1; - uint8_t did_stall:1; -}; - -struct uss820_std_temp { - uss820dci_cmd_t *func; - struct usb2_page_cache *pc; - struct uss820dci_td *td; - struct uss820dci_td *td_next; - uint32_t len; - uint32_t offset; - uint16_t max_frame_size; - uint8_t short_pkt; - /* - * short_pkt = 0: transfer should be short terminated - * short_pkt = 1: transfer should not be short terminated - */ - uint8_t setup_alt_next; -}; - -struct uss820dci_config_desc { - struct usb2_config_descriptor confd; - struct usb2_interface_descriptor ifcd; - struct usb2_endpoint_descriptor endpd; -} __packed; - -union uss820_hub_temp { - uWord wValue; - struct usb2_port_status ps; -}; - -struct uss820_flags { - uint8_t change_connect:1; - uint8_t change_suspend:1; - uint8_t status_suspend:1; /* set if suspended */ - uint8_t status_vbus:1; /* set if present */ - uint8_t status_bus_reset:1; /* set if reset complete */ - uint8_t clocks_off:1; - uint8_t port_powered:1; - uint8_t port_enabled:1; - uint8_t d_pulled_up:1; - uint8_t mcsr_feat:1; -}; - -struct uss820dci_softc { - struct usb2_bus sc_bus; - union uss820_hub_temp sc_hub_temp; - LIST_HEAD(, usb2_xfer) sc_interrupt_list_head; - struct usb2_sw_transfer sc_root_ctrl; - struct usb2_sw_transfer sc_root_intr; - - struct usb2_device *sc_devices[USS820_MAX_DEVICES]; - struct resource *sc_io_res; - struct resource *sc_irq_res; - void *sc_intr_hdl; - bus_size_t sc_io_size; - bus_space_tag_t sc_io_tag; - bus_space_handle_t sc_io_hdl; - - uint8_t sc_rt_addr; /* root HUB address */ - uint8_t sc_dv_addr; /* device address */ - uint8_t sc_conf; /* root HUB config */ - uint8_t sc_reg_shift; - - uint8_t sc_hub_idata[1]; - - struct uss820_flags sc_flags; -}; - -/* prototypes */ - -usb2_error_t uss820dci_init(struct uss820dci_softc *sc); -void uss820dci_uninit(struct uss820dci_softc *sc); -void uss820dci_suspend(struct uss820dci_softc *sc); -void uss820dci_resume(struct uss820dci_softc *sc); -void uss820dci_interrupt(struct uss820dci_softc *sc); - -#endif /* _USS820_DCI_H_ */ diff --git a/sys/dev/usb2/controller/uss820dci_atmelarm.c b/sys/dev/usb2/controller/uss820dci_atmelarm.c deleted file mode 100644 index 387c167..0000000 --- a/sys/dev/usb2/controller/uss820dci_atmelarm.c +++ /dev/null @@ -1,239 +0,0 @@ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/*- - * Copyright (c) 2008 Hans Petter Selasky <hselasky@freebsd.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_defs.h> -#include <dev/usb2/include/usb2_standard.h> - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/uss820dci.h> - -#include <sys/rman.h> - -static device_probe_t uss820_atmelarm_probe; -static device_attach_t uss820_atmelarm_attach; -static device_detach_t uss820_atmelarm_detach; -static device_suspend_t uss820_atmelarm_suspend; -static device_resume_t uss820_atmelarm_resume; -static device_shutdown_t uss820_atmelarm_shutdown; - -static device_method_t uss820dci_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, uss820_atmelarm_probe), - DEVMETHOD(device_attach, uss820_atmelarm_attach), - DEVMETHOD(device_detach, uss820_atmelarm_detach), - DEVMETHOD(device_suspend, uss820_atmelarm_suspend), - DEVMETHOD(device_resume, uss820_atmelarm_resume), - DEVMETHOD(device_shutdown, uss820_atmelarm_shutdown), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - {0, 0} -}; - -static driver_t uss820dci_driver = { - .name = "uss820", - .methods = uss820dci_methods, - .size = sizeof(struct uss820dci_softc), -}; - -static devclass_t uss820dci_devclass; - -DRIVER_MODULE(uss820, atmelarm, uss820dci_driver, uss820dci_devclass, 0, 0); -MODULE_DEPEND(uss820, usb2_controller, 1, 1, 1); -MODULE_DEPEND(uss820, usb2_core, 1, 1, 1); - -static const char *const uss820_desc = "USS820 USB Device Controller"; - -static int -uss820_atmelarm_suspend(device_t dev) -{ - struct uss820dci_softc *sc = device_get_softc(dev); - int err; - - err = bus_generic_suspend(dev); - if (err == 0) { - uss820dci_suspend(sc); - } - return (err); -} - -static int -uss820_atmelarm_resume(device_t dev) -{ - struct uss820dci_softc *sc = device_get_softc(dev); - int err; - - uss820dci_resume(sc); - - err = bus_generic_resume(dev); - - return (err); -} - -static int -uss820_atmelarm_shutdown(device_t dev) -{ - struct uss820dci_softc *sc = device_get_softc(dev); - int err; - - err = bus_generic_shutdown(dev); - if (err) - return (err); - - uss820dci_uninit(sc); - - return (0); -} - -static int -uss820_atmelarm_probe(device_t dev) -{ - device_set_desc(dev, uss820_desc); - return (0); /* success */ -} - -static int -uss820_atmelarm_attach(device_t dev) -{ - struct uss820dci_softc *sc = device_get_softc(dev); - int err; - int rid; - - /* initialise some bus fields */ - sc->sc_bus.parent = dev; - sc->sc_bus.devices = sc->sc_devices; - sc->sc_bus.devices_max = USS820_MAX_DEVICES; - - /* get all DMA memory */ - if (usb2_bus_mem_alloc_all(&sc->sc_bus, - USB_GET_DMA_TAG(dev), NULL)) { - return (ENOMEM); - } - rid = 0; - sc->sc_io_res = - bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); - - if (!sc->sc_io_res) { - goto error; - } - sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); - sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); - sc->sc_io_size = rman_get_size(sc->sc_io_res); - - /* multiply all addresses by 4 */ - sc->sc_reg_shift = 2; - - rid = 0; - sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (sc->sc_irq_res == NULL) { - goto error; - } - sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); - if (!(sc->sc_bus.bdev)) { - goto error; - } - device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); - -#if (__FreeBSD_version >= 700031) - err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); -#else - err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); -#endif - if (err) { - sc->sc_intr_hdl = NULL; - goto error; - } - err = uss820dci_init(sc); - if (err) { - device_printf(dev, "Init failed\n"); - goto error; - } - err = device_probe_and_attach(sc->sc_bus.bdev); - if (err) { - device_printf(dev, "USB probe and attach failed\n"); - goto error; - } - return (0); - -error: - uss820_atmelarm_detach(dev); - return (ENXIO); -} - -static int -uss820_atmelarm_detach(device_t dev) -{ - struct uss820dci_softc *sc = device_get_softc(dev); - device_t bdev; - int err; - - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } - /* during module unload there are lots of children leftover */ - device_delete_all_children(dev); - - if (sc->sc_irq_res && sc->sc_intr_hdl) { - /* - * only call at91_udp_uninit() after at91_udp_init() - */ - uss820dci_uninit(sc); - - err = bus_teardown_intr(dev, sc->sc_irq_res, - sc->sc_intr_hdl); - sc->sc_intr_hdl = NULL; - } - if (sc->sc_irq_res) { - bus_release_resource(dev, SYS_RES_IRQ, 0, - sc->sc_irq_res); - sc->sc_irq_res = NULL; - } - if (sc->sc_io_res) { - bus_release_resource(dev, SYS_RES_IOPORT, 0, - sc->sc_io_res); - sc->sc_io_res = NULL; - } - usb2_bus_mem_free_all(&sc->sc_bus, NULL); - - return (0); -} diff --git a/sys/dev/usb2/controller/uss820dci_pccard.c b/sys/dev/usb2/controller/uss820dci_pccard.c deleted file mode 100644 index f57935d..0000000 --- a/sys/dev/usb2/controller/uss820dci_pccard.c +++ /dev/null @@ -1,266 +0,0 @@ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/*- - * Copyright (c) 2008 Hans Petter Selasky <hselasky@freebsd.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <dev/usb2/include/usb2_mfunc.h> -#include <dev/usb2/include/usb2_defs.h> -#include <dev/usb2/include/usb2_standard.h> - -#include <dev/usb2/core/usb2_core.h> -#include <dev/usb2/core/usb2_busdma.h> -#include <dev/usb2/core/usb2_process.h> -#include <dev/usb2/core/usb2_config_td.h> -#include <dev/usb2/core/usb2_sw_transfer.h> -#include <dev/usb2/core/usb2_util.h> - -#include <dev/usb2/controller/usb2_controller.h> -#include <dev/usb2/controller/usb2_bus.h> -#include <dev/usb2/controller/uss820dci.h> - -#include <dev/pccard/pccardreg.h> -#include <dev/pccard/pccardvar.h> - -#include <sys/rman.h> - -static device_probe_t uss820_pccard_probe; -static device_attach_t uss820_pccard_attach; -static device_detach_t uss820_pccard_detach; -static device_suspend_t uss820_pccard_suspend; -static device_resume_t uss820_pccard_resume; -static device_shutdown_t uss820_pccard_shutdown; - -static uint8_t uss820_pccard_lookup(device_t dev); - -static device_method_t uss820dci_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, uss820_pccard_probe), - DEVMETHOD(device_attach, uss820_pccard_attach), - DEVMETHOD(device_detach, uss820_pccard_detach), - DEVMETHOD(device_suspend, uss820_pccard_suspend), - DEVMETHOD(device_resume, uss820_pccard_resume), - DEVMETHOD(device_shutdown, uss820_pccard_shutdown), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - {0, 0} -}; - -static driver_t uss820dci_driver = { - .name = "uss820", - .methods = uss820dci_methods, - .size = sizeof(struct uss820dci_softc), -}; - -static devclass_t uss820dci_devclass; - -DRIVER_MODULE(uss820, pccard, uss820dci_driver, uss820dci_devclass, 0, 0); -MODULE_DEPEND(uss820, usb2_core, 1, 1, 1); - -static const char *const uss820_desc = "USS820 USB Device Controller"; - -static int -uss820_pccard_suspend(device_t dev) -{ - struct uss820dci_softc *sc = device_get_softc(dev); - int err; - - err = bus_generic_suspend(dev); - if (err == 0) { - uss820dci_suspend(sc); - } - return (err); -} - -static int -uss820_pccard_resume(device_t dev) -{ - struct uss820dci_softc *sc = device_get_softc(dev); - int err; - - uss820dci_resume(sc); - - err = bus_generic_resume(dev); - - return (err); -} - -static int -uss820_pccard_shutdown(device_t dev) -{ - struct uss820dci_softc *sc = device_get_softc(dev); - int err; - - err = bus_generic_shutdown(dev); - if (err) - return (err); - - uss820dci_uninit(sc); - - return (0); -} - -static uint8_t -uss820_pccard_lookup(device_t dev) -{ - uint32_t prod; - uint32_t vend; - - pccard_get_vendor(dev, &vend); - pccard_get_product(dev, &prod); - - /* ID's will be added later */ - return (0); -} - -static int -uss820_pccard_probe(device_t dev) -{ - if (uss820_pccard_lookup(dev)) { - device_set_desc(dev, uss820_desc); - return (0); - } - return (ENXIO); -} -static int -uss820_pccard_attach(device_t dev) -{ - struct uss820dci_softc *sc = device_get_softc(dev); - int err; - int rid; - - if (sc == NULL) { - return (ENXIO); - } - /* get all DMA memory */ - - if (usb2_bus_mem_alloc_all(&sc->sc_bus, - USB_GET_DMA_TAG(dev), NULL)) { - return (ENOMEM); - } - rid = 0; - sc->sc_io_res = - bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); - - if (!sc->sc_io_res) { - goto error; - } - sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); - sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); - sc->sc_io_size = rman_get_size(sc->sc_io_res); - - /* multiply all addresses by 4 */ - sc->sc_reg_shift = 2; - - rid = 0; - sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (sc->sc_irq_res == NULL) { - goto error; - } - sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); - if (!(sc->sc_bus.bdev)) { - goto error; - } - device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); - - err = usb2_config_td_setup(&sc->sc_config_td, sc, - &sc->sc_bus.mtx, NULL, 0, 4); - if (err) { - device_printf(dev, "could not setup config thread!\n"); - goto error; - } -#if (__FreeBSD_version >= 700031) - err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); -#else - err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); -#endif - if (err) { - sc->sc_intr_hdl = NULL; - goto error; - } - err = uss820dci_init(sc); - if (err) { - device_printf(dev, "Init failed\n"); - goto error; - } - err = device_probe_and_attach(sc->sc_bus.bdev); - if (err) { - device_printf(dev, "USB probe and attach failed\n"); - goto error; - } - return (0); - -error: - uss820_pccard_detach(dev); - return (ENXIO); -} - -static int -uss820_pccard_detach(device_t dev) -{ - struct uss820dci_softc *sc = device_get_softc(dev); - device_t bdev; - int err; - - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } - /* during module unload there are lots of children leftover */ - device_delete_all_children(dev); - - if (sc->sc_irq_res && sc->sc_intr_hdl) { - /* - * only call at91_udp_uninit() after at91_udp_init() - */ - uss820dci_uninit(sc); - - err = bus_teardown_intr(dev, sc->sc_irq_res, - sc->sc_intr_hdl); - sc->sc_intr_hdl = NULL; - } - if (sc->sc_irq_res) { - bus_release_resource(dev, SYS_RES_IRQ, 0, - sc->sc_irq_res); - sc->sc_irq_res = NULL; - } - if (sc->sc_io_res) { - bus_release_resource(dev, SYS_RES_IOPORT, 0, - sc->sc_io_res); - sc->sc_io_res = NULL; - } - usb2_config_td_unsetup(&sc->sc_config_td); - - usb2_bus_mem_free_all(&sc->sc_bus, NULL); - - return (0); -} |