155e76c21SAndrew Thompson /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
455e76c21SAndrew Thompson * Copyright (c) 2009 Hans Petter Selasky. All rights reserved.
555e76c21SAndrew Thompson *
655e76c21SAndrew Thompson * Redistribution and use in source and binary forms, with or without
755e76c21SAndrew Thompson * modification, are permitted provided that the following conditions
855e76c21SAndrew Thompson * are met:
955e76c21SAndrew Thompson * 1. Redistributions of source code must retain the above copyright
1055e76c21SAndrew Thompson * notice, this list of conditions and the following disclaimer.
1155e76c21SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright
1255e76c21SAndrew Thompson * notice, this list of conditions and the following disclaimer in the
1355e76c21SAndrew Thompson * documentation and/or other materials provided with the distribution.
1455e76c21SAndrew Thompson *
1555e76c21SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1655e76c21SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1755e76c21SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1855e76c21SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1955e76c21SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2055e76c21SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2155e76c21SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2255e76c21SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2355e76c21SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2455e76c21SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2555e76c21SAndrew Thompson * SUCH DAMAGE.
2655e76c21SAndrew Thompson */
2755e76c21SAndrew Thompson
2855e76c21SAndrew Thompson /*
2955e76c21SAndrew Thompson * This file contains the driver for the AVR32 series USB Device
3055e76c21SAndrew Thompson * Controller
3155e76c21SAndrew Thompson */
3255e76c21SAndrew Thompson
3355e76c21SAndrew Thompson /*
3455e76c21SAndrew Thompson * NOTE: When the chip detects BUS-reset it will also reset the
3555e76c21SAndrew Thompson * endpoints, Function-address and more.
3655e76c21SAndrew Thompson */
37d2b99310SHans Petter Selasky #ifdef USB_GLOBAL_INCLUDE_FILE
38d2b99310SHans Petter Selasky #include USB_GLOBAL_INCLUDE_FILE
39d2b99310SHans Petter Selasky #else
40ed6d949aSAndrew Thompson #include <sys/stdint.h>
41ed6d949aSAndrew Thompson #include <sys/stddef.h>
42ed6d949aSAndrew Thompson #include <sys/param.h>
43ed6d949aSAndrew Thompson #include <sys/queue.h>
44ed6d949aSAndrew Thompson #include <sys/types.h>
45ed6d949aSAndrew Thompson #include <sys/systm.h>
46ed6d949aSAndrew Thompson #include <sys/kernel.h>
47ed6d949aSAndrew Thompson #include <sys/bus.h>
48ed6d949aSAndrew Thompson #include <sys/module.h>
49ed6d949aSAndrew Thompson #include <sys/lock.h>
50ed6d949aSAndrew Thompson #include <sys/mutex.h>
51ed6d949aSAndrew Thompson #include <sys/condvar.h>
52ed6d949aSAndrew Thompson #include <sys/sysctl.h>
53ed6d949aSAndrew Thompson #include <sys/sx.h>
54ed6d949aSAndrew Thompson #include <sys/unistd.h>
55ed6d949aSAndrew Thompson #include <sys/callout.h>
56ed6d949aSAndrew Thompson #include <sys/malloc.h>
57ed6d949aSAndrew Thompson #include <sys/priv.h>
58ed6d949aSAndrew Thompson
5955e76c21SAndrew Thompson #include <dev/usb/usb.h>
60ed6d949aSAndrew Thompson #include <dev/usb/usbdi.h>
6155e76c21SAndrew Thompson
6255e76c21SAndrew Thompson #define USB_DEBUG_VAR avr32dci_debug
6355e76c21SAndrew Thompson
6455e76c21SAndrew Thompson #include <dev/usb/usb_core.h>
6555e76c21SAndrew Thompson #include <dev/usb/usb_debug.h>
6655e76c21SAndrew Thompson #include <dev/usb/usb_busdma.h>
6755e76c21SAndrew Thompson #include <dev/usb/usb_process.h>
6855e76c21SAndrew Thompson #include <dev/usb/usb_transfer.h>
6955e76c21SAndrew Thompson #include <dev/usb/usb_device.h>
7055e76c21SAndrew Thompson #include <dev/usb/usb_hub.h>
7155e76c21SAndrew Thompson #include <dev/usb/usb_util.h>
7255e76c21SAndrew Thompson
7355e76c21SAndrew Thompson #include <dev/usb/usb_controller.h>
7455e76c21SAndrew Thompson #include <dev/usb/usb_bus.h>
75d2b99310SHans Petter Selasky #endif /* USB_GLOBAL_INCLUDE_FILE */
76d2b99310SHans Petter Selasky
7755e76c21SAndrew Thompson #include <dev/usb/controller/avr32dci.h>
7855e76c21SAndrew Thompson
7955e76c21SAndrew Thompson #define AVR32_BUS2SC(bus) \
80a3cea156SAndrew Turner __containerof(bus, struct avr32dci_softc, sc_bus)
8155e76c21SAndrew Thompson
8255e76c21SAndrew Thompson #define AVR32_PC2SC(pc) \
8355e76c21SAndrew Thompson AVR32_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus)
8455e76c21SAndrew Thompson
85ed6d949aSAndrew Thompson #ifdef USB_DEBUG
8655e76c21SAndrew Thompson static int avr32dci_debug = 0;
8755e76c21SAndrew Thompson
88f8d2b1f3SPawel Biernacki static SYSCTL_NODE(_hw_usb, OID_AUTO, avr32dci,
89f8d2b1f3SPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
90f8d2b1f3SPawel Biernacki "USB AVR32 DCI");
91ece4b0bdSHans Petter Selasky SYSCTL_INT(_hw_usb_avr32dci, OID_AUTO, debug, CTLFLAG_RWTUN,
9255e76c21SAndrew Thompson &avr32dci_debug, 0, "AVR32 DCI debug level");
9355e76c21SAndrew Thompson #endif
9455e76c21SAndrew Thompson
9555e76c21SAndrew Thompson #define AVR32_INTR_ENDPT 1
9655e76c21SAndrew Thompson
9755e76c21SAndrew Thompson /* prototypes */
9855e76c21SAndrew Thompson
99e892b3feSHans Petter Selasky static const struct usb_bus_methods avr32dci_bus_methods;
100e892b3feSHans Petter Selasky static const struct usb_pipe_methods avr32dci_device_non_isoc_methods;
101e892b3feSHans Petter Selasky static const struct usb_pipe_methods avr32dci_device_isoc_fs_methods;
10255e76c21SAndrew Thompson
10355e76c21SAndrew Thompson static avr32dci_cmd_t avr32dci_setup_rx;
10455e76c21SAndrew Thompson static avr32dci_cmd_t avr32dci_data_rx;
10555e76c21SAndrew Thompson static avr32dci_cmd_t avr32dci_data_tx;
10655e76c21SAndrew Thompson static avr32dci_cmd_t avr32dci_data_tx_sync;
107e0a69b51SAndrew Thompson static void avr32dci_device_done(struct usb_xfer *, usb_error_t);
108760bc48eSAndrew Thompson static void avr32dci_do_poll(struct usb_bus *);
109760bc48eSAndrew Thompson static void avr32dci_standard_done(struct usb_xfer *);
11055e76c21SAndrew Thompson static void avr32dci_root_intr(struct avr32dci_softc *sc);
11155e76c21SAndrew Thompson
11255e76c21SAndrew Thompson /*
11355e76c21SAndrew Thompson * Here is a list of what the chip supports:
11455e76c21SAndrew Thompson */
115760bc48eSAndrew Thompson static const struct usb_hw_ep_profile
11655e76c21SAndrew Thompson avr32dci_ep_profile[4] = {
11755e76c21SAndrew Thompson [0] = {
11855e76c21SAndrew Thompson .max_in_frame_size = 64,
11955e76c21SAndrew Thompson .max_out_frame_size = 64,
12055e76c21SAndrew Thompson .is_simplex = 1,
12155e76c21SAndrew Thompson .support_control = 1,
12255e76c21SAndrew Thompson },
12355e76c21SAndrew Thompson
12455e76c21SAndrew Thompson [1] = {
12555e76c21SAndrew Thompson .max_in_frame_size = 512,
12655e76c21SAndrew Thompson .max_out_frame_size = 512,
12755e76c21SAndrew Thompson .is_simplex = 1,
12855e76c21SAndrew Thompson .support_bulk = 1,
12955e76c21SAndrew Thompson .support_interrupt = 1,
13055e76c21SAndrew Thompson .support_isochronous = 1,
13155e76c21SAndrew Thompson .support_in = 1,
13255e76c21SAndrew Thompson .support_out = 1,
13355e76c21SAndrew Thompson },
13455e76c21SAndrew Thompson
13555e76c21SAndrew Thompson [2] = {
13655e76c21SAndrew Thompson .max_in_frame_size = 64,
13755e76c21SAndrew Thompson .max_out_frame_size = 64,
13855e76c21SAndrew Thompson .is_simplex = 1,
13955e76c21SAndrew Thompson .support_bulk = 1,
14055e76c21SAndrew Thompson .support_interrupt = 1,
14155e76c21SAndrew Thompson .support_in = 1,
14255e76c21SAndrew Thompson .support_out = 1,
14355e76c21SAndrew Thompson },
14455e76c21SAndrew Thompson
14555e76c21SAndrew Thompson [3] = {
14655e76c21SAndrew Thompson .max_in_frame_size = 1024,
14755e76c21SAndrew Thompson .max_out_frame_size = 1024,
14855e76c21SAndrew Thompson .is_simplex = 1,
14955e76c21SAndrew Thompson .support_bulk = 1,
15055e76c21SAndrew Thompson .support_interrupt = 1,
15155e76c21SAndrew Thompson .support_isochronous = 1,
15255e76c21SAndrew Thompson .support_in = 1,
15355e76c21SAndrew Thompson .support_out = 1,
15455e76c21SAndrew Thompson },
15555e76c21SAndrew Thompson };
15655e76c21SAndrew Thompson
15755e76c21SAndrew Thompson static void
avr32dci_get_hw_ep_profile(struct usb_device * udev,const struct usb_hw_ep_profile ** ppf,uint8_t ep_addr)158760bc48eSAndrew Thompson avr32dci_get_hw_ep_profile(struct usb_device *udev,
159760bc48eSAndrew Thompson const struct usb_hw_ep_profile **ppf, uint8_t ep_addr)
16055e76c21SAndrew Thompson {
16155e76c21SAndrew Thompson if (ep_addr == 0)
16255e76c21SAndrew Thompson *ppf = avr32dci_ep_profile;
16355e76c21SAndrew Thompson else if (ep_addr < 3)
16455e76c21SAndrew Thompson *ppf = avr32dci_ep_profile + 1;
16555e76c21SAndrew Thompson else if (ep_addr < 5)
16655e76c21SAndrew Thompson *ppf = avr32dci_ep_profile + 2;
16755e76c21SAndrew Thompson else if (ep_addr < 7)
16855e76c21SAndrew Thompson *ppf = avr32dci_ep_profile + 3;
16955e76c21SAndrew Thompson else
17055e76c21SAndrew Thompson *ppf = NULL;
17155e76c21SAndrew Thompson }
17255e76c21SAndrew Thompson
17355e76c21SAndrew Thompson static void
avr32dci_mod_ctrl(struct avr32dci_softc * sc,uint32_t set,uint32_t clear)17455e76c21SAndrew Thompson avr32dci_mod_ctrl(struct avr32dci_softc *sc, uint32_t set, uint32_t clear)
17555e76c21SAndrew Thompson {
17655e76c21SAndrew Thompson uint32_t temp;
17755e76c21SAndrew Thompson
17855e76c21SAndrew Thompson temp = AVR32_READ_4(sc, AVR32_CTRL);
17955e76c21SAndrew Thompson temp |= set;
18055e76c21SAndrew Thompson temp &= ~clear;
18155e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_CTRL, temp);
18255e76c21SAndrew Thompson }
18355e76c21SAndrew Thompson
18455e76c21SAndrew Thompson static void
avr32dci_mod_ien(struct avr32dci_softc * sc,uint32_t set,uint32_t clear)18555e76c21SAndrew Thompson avr32dci_mod_ien(struct avr32dci_softc *sc, uint32_t set, uint32_t clear)
18655e76c21SAndrew Thompson {
18755e76c21SAndrew Thompson uint32_t temp;
18855e76c21SAndrew Thompson
18955e76c21SAndrew Thompson temp = AVR32_READ_4(sc, AVR32_IEN);
19055e76c21SAndrew Thompson temp |= set;
19155e76c21SAndrew Thompson temp &= ~clear;
19255e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_IEN, temp);
19355e76c21SAndrew Thompson }
19455e76c21SAndrew Thompson
19555e76c21SAndrew Thompson static void
avr32dci_clocks_on(struct avr32dci_softc * sc)19655e76c21SAndrew Thompson avr32dci_clocks_on(struct avr32dci_softc *sc)
19755e76c21SAndrew Thompson {
19855e76c21SAndrew Thompson if (sc->sc_flags.clocks_off &&
19955e76c21SAndrew Thompson sc->sc_flags.port_powered) {
20055e76c21SAndrew Thompson DPRINTFN(5, "\n");
20155e76c21SAndrew Thompson
20255e76c21SAndrew Thompson /* turn on clocks */
20355e76c21SAndrew Thompson (sc->sc_clocks_on) (&sc->sc_bus);
20455e76c21SAndrew Thompson
20555e76c21SAndrew Thompson avr32dci_mod_ctrl(sc, AVR32_CTRL_DEV_EN_USBA, 0);
20655e76c21SAndrew Thompson
20755e76c21SAndrew Thompson sc->sc_flags.clocks_off = 0;
20855e76c21SAndrew Thompson }
20955e76c21SAndrew Thompson }
21055e76c21SAndrew Thompson
21155e76c21SAndrew Thompson static void
avr32dci_clocks_off(struct avr32dci_softc * sc)21255e76c21SAndrew Thompson avr32dci_clocks_off(struct avr32dci_softc *sc)
21355e76c21SAndrew Thompson {
21455e76c21SAndrew Thompson if (!sc->sc_flags.clocks_off) {
21555e76c21SAndrew Thompson DPRINTFN(5, "\n");
21655e76c21SAndrew Thompson
21755e76c21SAndrew Thompson avr32dci_mod_ctrl(sc, 0, AVR32_CTRL_DEV_EN_USBA);
21855e76c21SAndrew Thompson
21955e76c21SAndrew Thompson /* turn clocks off */
22055e76c21SAndrew Thompson (sc->sc_clocks_off) (&sc->sc_bus);
22155e76c21SAndrew Thompson
22255e76c21SAndrew Thompson sc->sc_flags.clocks_off = 1;
22355e76c21SAndrew Thompson }
22455e76c21SAndrew Thompson }
22555e76c21SAndrew Thompson
22655e76c21SAndrew Thompson static void
avr32dci_pull_up(struct avr32dci_softc * sc)22755e76c21SAndrew Thompson avr32dci_pull_up(struct avr32dci_softc *sc)
22855e76c21SAndrew Thompson {
22955e76c21SAndrew Thompson /* pullup D+, if possible */
23055e76c21SAndrew Thompson
23155e76c21SAndrew Thompson if (!sc->sc_flags.d_pulled_up &&
23255e76c21SAndrew Thompson sc->sc_flags.port_powered) {
23355e76c21SAndrew Thompson sc->sc_flags.d_pulled_up = 1;
23455e76c21SAndrew Thompson avr32dci_mod_ctrl(sc, 0, AVR32_CTRL_DEV_DETACH);
23555e76c21SAndrew Thompson }
23655e76c21SAndrew Thompson }
23755e76c21SAndrew Thompson
23855e76c21SAndrew Thompson static void
avr32dci_pull_down(struct avr32dci_softc * sc)23955e76c21SAndrew Thompson avr32dci_pull_down(struct avr32dci_softc *sc)
24055e76c21SAndrew Thompson {
24155e76c21SAndrew Thompson /* pulldown D+, if possible */
24255e76c21SAndrew Thompson
24355e76c21SAndrew Thompson if (sc->sc_flags.d_pulled_up) {
24455e76c21SAndrew Thompson sc->sc_flags.d_pulled_up = 0;
24555e76c21SAndrew Thompson avr32dci_mod_ctrl(sc, AVR32_CTRL_DEV_DETACH, 0);
24655e76c21SAndrew Thompson }
24755e76c21SAndrew Thompson }
24855e76c21SAndrew Thompson
24955e76c21SAndrew Thompson static void
avr32dci_wakeup_peer(struct avr32dci_softc * sc)25055e76c21SAndrew Thompson avr32dci_wakeup_peer(struct avr32dci_softc *sc)
25155e76c21SAndrew Thompson {
25255e76c21SAndrew Thompson if (!sc->sc_flags.status_suspend) {
25355e76c21SAndrew Thompson return;
25455e76c21SAndrew Thompson }
25555e76c21SAndrew Thompson avr32dci_mod_ctrl(sc, AVR32_CTRL_DEV_REWAKEUP, 0);
25655e76c21SAndrew Thompson
25755e76c21SAndrew Thompson /* wait 8 milliseconds */
25855e76c21SAndrew Thompson /* Wait for reset to complete. */
259a593f6b8SAndrew Thompson usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125);
26055e76c21SAndrew Thompson
26155e76c21SAndrew Thompson /* hardware should have cleared RMWKUP bit */
26255e76c21SAndrew Thompson }
26355e76c21SAndrew Thompson
26455e76c21SAndrew Thompson static void
avr32dci_set_address(struct avr32dci_softc * sc,uint8_t addr)26555e76c21SAndrew Thompson avr32dci_set_address(struct avr32dci_softc *sc, uint8_t addr)
26655e76c21SAndrew Thompson {
26755e76c21SAndrew Thompson DPRINTFN(5, "addr=%d\n", addr);
26855e76c21SAndrew Thompson
2692e141748SHans Petter Selasky avr32dci_mod_ctrl(sc, AVR32_CTRL_DEV_FADDR_EN | addr, 0);
27055e76c21SAndrew Thompson }
27155e76c21SAndrew Thompson
27255e76c21SAndrew Thompson static uint8_t
avr32dci_setup_rx(struct avr32dci_td * td)27355e76c21SAndrew Thompson avr32dci_setup_rx(struct avr32dci_td *td)
27455e76c21SAndrew Thompson {
27555e76c21SAndrew Thompson struct avr32dci_softc *sc;
276760bc48eSAndrew Thompson struct usb_device_request req;
27755e76c21SAndrew Thompson uint16_t count;
27855e76c21SAndrew Thompson uint32_t temp;
27955e76c21SAndrew Thompson
28055e76c21SAndrew Thompson /* get pointer to softc */
28155e76c21SAndrew Thompson sc = AVR32_PC2SC(td->pc);
28255e76c21SAndrew Thompson
28355e76c21SAndrew Thompson /* check endpoint status */
28455e76c21SAndrew Thompson temp = AVR32_READ_4(sc, AVR32_EPTSTA(td->ep_no));
28555e76c21SAndrew Thompson
28655e76c21SAndrew Thompson DPRINTFN(5, "EPTSTA(%u)=0x%08x\n", td->ep_no, temp);
28755e76c21SAndrew Thompson
28855e76c21SAndrew Thompson if (!(temp & AVR32_EPTSTA_RX_SETUP)) {
28955e76c21SAndrew Thompson goto not_complete;
29055e76c21SAndrew Thompson }
29155e76c21SAndrew Thompson /* clear did stall */
29255e76c21SAndrew Thompson td->did_stall = 0;
29355e76c21SAndrew Thompson /* get the packet byte count */
29455e76c21SAndrew Thompson count = AVR32_EPTSTA_BYTE_COUNT(temp);
29555e76c21SAndrew Thompson
29655e76c21SAndrew Thompson /* verify data length */
29755e76c21SAndrew Thompson if (count != td->remainder) {
29855e76c21SAndrew Thompson DPRINTFN(0, "Invalid SETUP packet "
29955e76c21SAndrew Thompson "length, %d bytes\n", count);
30055e76c21SAndrew Thompson goto not_complete;
30155e76c21SAndrew Thompson }
30255e76c21SAndrew Thompson if (count != sizeof(req)) {
30355e76c21SAndrew Thompson DPRINTFN(0, "Unsupported SETUP packet "
30455e76c21SAndrew Thompson "length, %d bytes\n", count);
30555e76c21SAndrew Thompson goto not_complete;
30655e76c21SAndrew Thompson }
30755e76c21SAndrew Thompson /* receive data */
30855e76c21SAndrew Thompson memcpy(&req, sc->physdata, sizeof(req));
30955e76c21SAndrew Thompson
31055e76c21SAndrew Thompson /* copy data into real buffer */
311a593f6b8SAndrew Thompson usbd_copy_in(td->pc, 0, &req, sizeof(req));
31255e76c21SAndrew Thompson
31355e76c21SAndrew Thompson td->offset = sizeof(req);
31455e76c21SAndrew Thompson td->remainder = 0;
31555e76c21SAndrew Thompson
31655e76c21SAndrew Thompson /* sneak peek the set address */
31755e76c21SAndrew Thompson if ((req.bmRequestType == UT_WRITE_DEVICE) &&
31855e76c21SAndrew Thompson (req.bRequest == UR_SET_ADDRESS)) {
31955e76c21SAndrew Thompson sc->sc_dv_addr = req.wValue[0] & 0x7F;
32055e76c21SAndrew Thompson /* must write address before ZLP */
32155e76c21SAndrew Thompson avr32dci_mod_ctrl(sc, 0, AVR32_CTRL_DEV_FADDR_EN |
32255e76c21SAndrew Thompson AVR32_CTRL_DEV_ADDR);
32355e76c21SAndrew Thompson avr32dci_mod_ctrl(sc, sc->sc_dv_addr, 0);
32455e76c21SAndrew Thompson } else {
32555e76c21SAndrew Thompson sc->sc_dv_addr = 0xFF;
32655e76c21SAndrew Thompson }
32755e76c21SAndrew Thompson
32855e76c21SAndrew Thompson /* clear SETUP packet interrupt */
32955e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(td->ep_no), AVR32_EPTSTA_RX_SETUP);
33055e76c21SAndrew Thompson return (0); /* complete */
33155e76c21SAndrew Thompson
33255e76c21SAndrew Thompson not_complete:
33355e76c21SAndrew Thompson if (temp & AVR32_EPTSTA_RX_SETUP) {
33455e76c21SAndrew Thompson /* clear SETUP packet interrupt */
33555e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(td->ep_no), AVR32_EPTSTA_RX_SETUP);
33655e76c21SAndrew Thompson }
33755e76c21SAndrew Thompson /* abort any ongoing transfer */
33855e76c21SAndrew Thompson if (!td->did_stall) {
33955e76c21SAndrew Thompson DPRINTFN(5, "stalling\n");
34055e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTSETSTA(td->ep_no),
34155e76c21SAndrew Thompson AVR32_EPTSTA_FRCESTALL);
34255e76c21SAndrew Thompson td->did_stall = 1;
34355e76c21SAndrew Thompson }
34455e76c21SAndrew Thompson return (1); /* not complete */
34555e76c21SAndrew Thompson }
34655e76c21SAndrew Thompson
34755e76c21SAndrew Thompson static uint8_t
avr32dci_data_rx(struct avr32dci_td * td)34855e76c21SAndrew Thompson avr32dci_data_rx(struct avr32dci_td *td)
34955e76c21SAndrew Thompson {
35055e76c21SAndrew Thompson struct avr32dci_softc *sc;
351760bc48eSAndrew Thompson struct usb_page_search buf_res;
35255e76c21SAndrew Thompson uint16_t count;
35355e76c21SAndrew Thompson uint32_t temp;
35455e76c21SAndrew Thompson uint8_t to;
35555e76c21SAndrew Thompson uint8_t got_short;
35655e76c21SAndrew Thompson
35755e76c21SAndrew Thompson to = 4; /* don't loop forever! */
35855e76c21SAndrew Thompson got_short = 0;
35955e76c21SAndrew Thompson
36055e76c21SAndrew Thompson /* get pointer to softc */
36155e76c21SAndrew Thompson sc = AVR32_PC2SC(td->pc);
36255e76c21SAndrew Thompson
36355e76c21SAndrew Thompson repeat:
36455e76c21SAndrew Thompson /* check if any of the FIFO banks have data */
36555e76c21SAndrew Thompson /* check endpoint status */
36655e76c21SAndrew Thompson temp = AVR32_READ_4(sc, AVR32_EPTSTA(td->ep_no));
36755e76c21SAndrew Thompson
36855e76c21SAndrew Thompson DPRINTFN(5, "EPTSTA(%u)=0x%08x\n", td->ep_no, temp);
36955e76c21SAndrew Thompson
37055e76c21SAndrew Thompson if (temp & AVR32_EPTSTA_RX_SETUP) {
37155e76c21SAndrew Thompson if (td->remainder == 0) {
37255e76c21SAndrew Thompson /*
37355e76c21SAndrew Thompson * We are actually complete and have
37455e76c21SAndrew Thompson * received the next SETUP
37555e76c21SAndrew Thompson */
37655e76c21SAndrew Thompson DPRINTFN(5, "faking complete\n");
37755e76c21SAndrew Thompson return (0); /* complete */
37855e76c21SAndrew Thompson }
37955e76c21SAndrew Thompson /*
38055e76c21SAndrew Thompson * USB Host Aborted the transfer.
38155e76c21SAndrew Thompson */
38255e76c21SAndrew Thompson td->error = 1;
38355e76c21SAndrew Thompson return (0); /* complete */
38455e76c21SAndrew Thompson }
38555e76c21SAndrew Thompson /* check status */
38655e76c21SAndrew Thompson if (!(temp & AVR32_EPTSTA_RX_BK_RDY)) {
38755e76c21SAndrew Thompson /* no data */
38855e76c21SAndrew Thompson goto not_complete;
38955e76c21SAndrew Thompson }
39055e76c21SAndrew Thompson /* get the packet byte count */
39155e76c21SAndrew Thompson count = AVR32_EPTSTA_BYTE_COUNT(temp);
39255e76c21SAndrew Thompson
39355e76c21SAndrew Thompson /* verify the packet byte count */
39455e76c21SAndrew Thompson if (count != td->max_packet_size) {
39555e76c21SAndrew Thompson if (count < td->max_packet_size) {
39655e76c21SAndrew Thompson /* we have a short packet */
39755e76c21SAndrew Thompson td->short_pkt = 1;
39855e76c21SAndrew Thompson got_short = 1;
39955e76c21SAndrew Thompson } else {
40055e76c21SAndrew Thompson /* invalid USB packet */
40155e76c21SAndrew Thompson td->error = 1;
40255e76c21SAndrew Thompson return (0); /* we are complete */
40355e76c21SAndrew Thompson }
40455e76c21SAndrew Thompson }
40555e76c21SAndrew Thompson /* verify the packet byte count */
40655e76c21SAndrew Thompson if (count > td->remainder) {
40755e76c21SAndrew Thompson /* invalid USB packet */
40855e76c21SAndrew Thompson td->error = 1;
40955e76c21SAndrew Thompson return (0); /* we are complete */
41055e76c21SAndrew Thompson }
41155e76c21SAndrew Thompson while (count > 0) {
412a593f6b8SAndrew Thompson usbd_get_page(td->pc, td->offset, &buf_res);
41355e76c21SAndrew Thompson
41455e76c21SAndrew Thompson /* get correct length */
41555e76c21SAndrew Thompson if (buf_res.length > count) {
41655e76c21SAndrew Thompson buf_res.length = count;
41755e76c21SAndrew Thompson }
41855e76c21SAndrew Thompson /* receive data */
419271ae033SHans Petter Selasky memcpy(buf_res.buffer, sc->physdata +
42055e76c21SAndrew Thompson (AVR32_EPTSTA_CURRENT_BANK(temp) << td->bank_shift) +
421271ae033SHans Petter Selasky (td->ep_no << 16) + (td->offset % td->max_packet_size), buf_res.length);
42255e76c21SAndrew Thompson /* update counters */
42355e76c21SAndrew Thompson count -= buf_res.length;
42455e76c21SAndrew Thompson td->offset += buf_res.length;
42555e76c21SAndrew Thompson td->remainder -= buf_res.length;
42655e76c21SAndrew Thompson }
42755e76c21SAndrew Thompson
42855e76c21SAndrew Thompson /* clear OUT packet interrupt */
42955e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(td->ep_no), AVR32_EPTSTA_RX_BK_RDY);
43055e76c21SAndrew Thompson
43155e76c21SAndrew Thompson /* check if we are complete */
43255e76c21SAndrew Thompson if ((td->remainder == 0) || got_short) {
43355e76c21SAndrew Thompson if (td->short_pkt) {
43455e76c21SAndrew Thompson /* we are complete */
43555e76c21SAndrew Thompson return (0);
43655e76c21SAndrew Thompson }
43755e76c21SAndrew Thompson /* else need to receive a zero length packet */
43855e76c21SAndrew Thompson }
43955e76c21SAndrew Thompson if (--to) {
44055e76c21SAndrew Thompson goto repeat;
44155e76c21SAndrew Thompson }
44255e76c21SAndrew Thompson not_complete:
44355e76c21SAndrew Thompson return (1); /* not complete */
44455e76c21SAndrew Thompson }
44555e76c21SAndrew Thompson
44655e76c21SAndrew Thompson static uint8_t
avr32dci_data_tx(struct avr32dci_td * td)44755e76c21SAndrew Thompson avr32dci_data_tx(struct avr32dci_td *td)
44855e76c21SAndrew Thompson {
44955e76c21SAndrew Thompson struct avr32dci_softc *sc;
450760bc48eSAndrew Thompson struct usb_page_search buf_res;
45155e76c21SAndrew Thompson uint16_t count;
45255e76c21SAndrew Thompson uint8_t to;
45355e76c21SAndrew Thompson uint32_t temp;
45455e76c21SAndrew Thompson
45555e76c21SAndrew Thompson to = 4; /* don't loop forever! */
45655e76c21SAndrew Thompson
45755e76c21SAndrew Thompson /* get pointer to softc */
45855e76c21SAndrew Thompson sc = AVR32_PC2SC(td->pc);
45955e76c21SAndrew Thompson
46055e76c21SAndrew Thompson repeat:
46155e76c21SAndrew Thompson
46255e76c21SAndrew Thompson /* check endpoint status */
46355e76c21SAndrew Thompson temp = AVR32_READ_4(sc, AVR32_EPTSTA(td->ep_no));
46455e76c21SAndrew Thompson
46555e76c21SAndrew Thompson DPRINTFN(5, "EPTSTA(%u)=0x%08x\n", td->ep_no, temp);
46655e76c21SAndrew Thompson
46755e76c21SAndrew Thompson if (temp & AVR32_EPTSTA_RX_SETUP) {
46855e76c21SAndrew Thompson /*
46955e76c21SAndrew Thompson * The current transfer was aborted
47055e76c21SAndrew Thompson * by the USB Host
47155e76c21SAndrew Thompson */
47255e76c21SAndrew Thompson td->error = 1;
47355e76c21SAndrew Thompson return (0); /* complete */
47455e76c21SAndrew Thompson }
47555e76c21SAndrew Thompson if (temp & AVR32_EPTSTA_TX_PK_RDY) {
47655e76c21SAndrew Thompson /* cannot write any data - all banks are busy */
47755e76c21SAndrew Thompson goto not_complete;
47855e76c21SAndrew Thompson }
47955e76c21SAndrew Thompson count = td->max_packet_size;
48055e76c21SAndrew Thompson if (td->remainder < count) {
48155e76c21SAndrew Thompson /* we have a short packet */
48255e76c21SAndrew Thompson td->short_pkt = 1;
48355e76c21SAndrew Thompson count = td->remainder;
48455e76c21SAndrew Thompson }
48555e76c21SAndrew Thompson while (count > 0) {
486a593f6b8SAndrew Thompson usbd_get_page(td->pc, td->offset, &buf_res);
48755e76c21SAndrew Thompson
48855e76c21SAndrew Thompson /* get correct length */
48955e76c21SAndrew Thompson if (buf_res.length > count) {
49055e76c21SAndrew Thompson buf_res.length = count;
49155e76c21SAndrew Thompson }
49255e76c21SAndrew Thompson /* transmit data */
493271ae033SHans Petter Selasky memcpy(sc->physdata +
49455e76c21SAndrew Thompson (AVR32_EPTSTA_CURRENT_BANK(temp) << td->bank_shift) +
49555e76c21SAndrew Thompson (td->ep_no << 16) + (td->offset % td->max_packet_size),
496271ae033SHans Petter Selasky buf_res.buffer, buf_res.length);
49755e76c21SAndrew Thompson /* update counters */
49855e76c21SAndrew Thompson count -= buf_res.length;
49955e76c21SAndrew Thompson td->offset += buf_res.length;
50055e76c21SAndrew Thompson td->remainder -= buf_res.length;
50155e76c21SAndrew Thompson }
50255e76c21SAndrew Thompson
50355e76c21SAndrew Thompson /* allocate FIFO bank */
5042e141748SHans Petter Selasky AVR32_WRITE_4(sc, AVR32_EPTCTL(td->ep_no), AVR32_EPTCTL_TX_PK_RDY);
50555e76c21SAndrew Thompson
50655e76c21SAndrew Thompson /* check remainder */
50755e76c21SAndrew Thompson if (td->remainder == 0) {
50855e76c21SAndrew Thompson if (td->short_pkt) {
50955e76c21SAndrew Thompson return (0); /* complete */
51055e76c21SAndrew Thompson }
51155e76c21SAndrew Thompson /* else we need to transmit a short packet */
51255e76c21SAndrew Thompson }
51355e76c21SAndrew Thompson if (--to) {
51455e76c21SAndrew Thompson goto repeat;
51555e76c21SAndrew Thompson }
51655e76c21SAndrew Thompson not_complete:
51755e76c21SAndrew Thompson return (1); /* not complete */
51855e76c21SAndrew Thompson }
51955e76c21SAndrew Thompson
52055e76c21SAndrew Thompson static uint8_t
avr32dci_data_tx_sync(struct avr32dci_td * td)52155e76c21SAndrew Thompson avr32dci_data_tx_sync(struct avr32dci_td *td)
52255e76c21SAndrew Thompson {
52355e76c21SAndrew Thompson struct avr32dci_softc *sc;
52455e76c21SAndrew Thompson uint32_t temp;
52555e76c21SAndrew Thompson
52655e76c21SAndrew Thompson /* get pointer to softc */
52755e76c21SAndrew Thompson sc = AVR32_PC2SC(td->pc);
52855e76c21SAndrew Thompson
52955e76c21SAndrew Thompson /* check endpoint status */
53055e76c21SAndrew Thompson temp = AVR32_READ_4(sc, AVR32_EPTSTA(td->ep_no));
53155e76c21SAndrew Thompson
53255e76c21SAndrew Thompson DPRINTFN(5, "EPTSTA(%u)=0x%08x\n", td->ep_no, temp);
53355e76c21SAndrew Thompson
53455e76c21SAndrew Thompson if (temp & AVR32_EPTSTA_RX_SETUP) {
53555e76c21SAndrew Thompson DPRINTFN(5, "faking complete\n");
53655e76c21SAndrew Thompson /* Race condition */
53755e76c21SAndrew Thompson return (0); /* complete */
53855e76c21SAndrew Thompson }
53955e76c21SAndrew Thompson /*
54055e76c21SAndrew Thompson * The control endpoint has only got one bank, so if that bank
54155e76c21SAndrew Thompson * is free the packet has been transferred!
54255e76c21SAndrew Thompson */
54355e76c21SAndrew Thompson if (AVR32_EPTSTA_BUSY_BANK_STA(temp) != 0) {
54455e76c21SAndrew Thompson /* cannot write any data - a bank is busy */
54555e76c21SAndrew Thompson goto not_complete;
54655e76c21SAndrew Thompson }
54755e76c21SAndrew Thompson if (sc->sc_dv_addr != 0xFF) {
54855e76c21SAndrew Thompson /* set new address */
54955e76c21SAndrew Thompson avr32dci_set_address(sc, sc->sc_dv_addr);
55055e76c21SAndrew Thompson }
55155e76c21SAndrew Thompson return (0); /* complete */
55255e76c21SAndrew Thompson
55355e76c21SAndrew Thompson not_complete:
55455e76c21SAndrew Thompson return (1); /* not complete */
55555e76c21SAndrew Thompson }
55655e76c21SAndrew Thompson
55755e76c21SAndrew Thompson static uint8_t
avr32dci_xfer_do_fifo(struct usb_xfer * xfer)558760bc48eSAndrew Thompson avr32dci_xfer_do_fifo(struct usb_xfer *xfer)
55955e76c21SAndrew Thompson {
56055e76c21SAndrew Thompson struct avr32dci_td *td;
56155e76c21SAndrew Thompson
56255e76c21SAndrew Thompson DPRINTFN(9, "\n");
56355e76c21SAndrew Thompson
56455e76c21SAndrew Thompson td = xfer->td_transfer_cache;
56555e76c21SAndrew Thompson while (1) {
56655e76c21SAndrew Thompson if ((td->func) (td)) {
56755e76c21SAndrew Thompson /* operation in progress */
56855e76c21SAndrew Thompson break;
56955e76c21SAndrew Thompson }
57055e76c21SAndrew Thompson if (((void *)td) == xfer->td_transfer_last) {
57155e76c21SAndrew Thompson goto done;
57255e76c21SAndrew Thompson }
57355e76c21SAndrew Thompson if (td->error) {
57455e76c21SAndrew Thompson goto done;
57555e76c21SAndrew Thompson } else if (td->remainder > 0) {
57655e76c21SAndrew Thompson /*
57755e76c21SAndrew Thompson * We had a short transfer. If there is no alternate
57855e76c21SAndrew Thompson * next, stop processing !
57955e76c21SAndrew Thompson */
58055e76c21SAndrew Thompson if (!td->alt_next) {
58155e76c21SAndrew Thompson goto done;
58255e76c21SAndrew Thompson }
58355e76c21SAndrew Thompson }
58455e76c21SAndrew Thompson /*
58555e76c21SAndrew Thompson * Fetch the next transfer descriptor and transfer
58655e76c21SAndrew Thompson * some flags to the next transfer descriptor
58755e76c21SAndrew Thompson */
58855e76c21SAndrew Thompson td = td->obj_next;
58955e76c21SAndrew Thompson xfer->td_transfer_cache = td;
59055e76c21SAndrew Thompson }
59155e76c21SAndrew Thompson return (1); /* not complete */
59255e76c21SAndrew Thompson
59355e76c21SAndrew Thompson done:
59455e76c21SAndrew Thompson /* compute all actual lengths */
59555e76c21SAndrew Thompson
59655e76c21SAndrew Thompson avr32dci_standard_done(xfer);
59755e76c21SAndrew Thompson return (0); /* complete */
59855e76c21SAndrew Thompson }
59955e76c21SAndrew Thompson
60055e76c21SAndrew Thompson static void
avr32dci_interrupt_poll(struct avr32dci_softc * sc)60155e76c21SAndrew Thompson avr32dci_interrupt_poll(struct avr32dci_softc *sc)
60255e76c21SAndrew Thompson {
603760bc48eSAndrew Thompson struct usb_xfer *xfer;
60455e76c21SAndrew Thompson
60555e76c21SAndrew Thompson repeat:
60655e76c21SAndrew Thompson TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
60755e76c21SAndrew Thompson if (!avr32dci_xfer_do_fifo(xfer)) {
60855e76c21SAndrew Thompson /* queue has been modified */
60955e76c21SAndrew Thompson goto repeat;
61055e76c21SAndrew Thompson }
61155e76c21SAndrew Thompson }
61255e76c21SAndrew Thompson }
61355e76c21SAndrew Thompson
61455e76c21SAndrew Thompson void
avr32dci_vbus_interrupt(struct avr32dci_softc * sc,uint8_t is_on)61555e76c21SAndrew Thompson avr32dci_vbus_interrupt(struct avr32dci_softc *sc, uint8_t is_on)
61655e76c21SAndrew Thompson {
61755e76c21SAndrew Thompson DPRINTFN(5, "vbus = %u\n", is_on);
61855e76c21SAndrew Thompson
61955e76c21SAndrew Thompson if (is_on) {
62055e76c21SAndrew Thompson if (!sc->sc_flags.status_vbus) {
62155e76c21SAndrew Thompson sc->sc_flags.status_vbus = 1;
62255e76c21SAndrew Thompson
62355e76c21SAndrew Thompson /* complete root HUB interrupt endpoint */
62455e76c21SAndrew Thompson
62555e76c21SAndrew Thompson avr32dci_root_intr(sc);
62655e76c21SAndrew Thompson }
62755e76c21SAndrew Thompson } else {
62855e76c21SAndrew Thompson if (sc->sc_flags.status_vbus) {
62955e76c21SAndrew Thompson sc->sc_flags.status_vbus = 0;
63055e76c21SAndrew Thompson sc->sc_flags.status_bus_reset = 0;
63155e76c21SAndrew Thompson sc->sc_flags.status_suspend = 0;
63255e76c21SAndrew Thompson sc->sc_flags.change_suspend = 0;
63355e76c21SAndrew Thompson sc->sc_flags.change_connect = 1;
63455e76c21SAndrew Thompson
63555e76c21SAndrew Thompson /* complete root HUB interrupt endpoint */
63655e76c21SAndrew Thompson
63755e76c21SAndrew Thompson avr32dci_root_intr(sc);
63855e76c21SAndrew Thompson }
63955e76c21SAndrew Thompson }
64055e76c21SAndrew Thompson }
64155e76c21SAndrew Thompson
64255e76c21SAndrew Thompson void
avr32dci_interrupt(struct avr32dci_softc * sc)64355e76c21SAndrew Thompson avr32dci_interrupt(struct avr32dci_softc *sc)
64455e76c21SAndrew Thompson {
64555e76c21SAndrew Thompson uint32_t status;
64655e76c21SAndrew Thompson
64755e76c21SAndrew Thompson USB_BUS_LOCK(&sc->sc_bus);
64855e76c21SAndrew Thompson
64955e76c21SAndrew Thompson /* read interrupt status */
65055e76c21SAndrew Thompson status = AVR32_READ_4(sc, AVR32_INTSTA);
65155e76c21SAndrew Thompson
65255e76c21SAndrew Thompson /* clear all set interrupts */
65355e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_CLRINT, status);
65455e76c21SAndrew Thompson
65555e76c21SAndrew Thompson DPRINTFN(14, "INTSTA=0x%08x\n", status);
65655e76c21SAndrew Thompson
65755e76c21SAndrew Thompson /* check for any bus state change interrupts */
65855e76c21SAndrew Thompson if (status & AVR32_INT_ENDRESET) {
65955e76c21SAndrew Thompson DPRINTFN(5, "end of reset\n");
66055e76c21SAndrew Thompson
66155e76c21SAndrew Thompson /* set correct state */
66255e76c21SAndrew Thompson sc->sc_flags.status_bus_reset = 1;
66355e76c21SAndrew Thompson sc->sc_flags.status_suspend = 0;
66455e76c21SAndrew Thompson sc->sc_flags.change_suspend = 0;
66555e76c21SAndrew Thompson sc->sc_flags.change_connect = 1;
66655e76c21SAndrew Thompson
66755e76c21SAndrew Thompson /* disable resume interrupt */
66855e76c21SAndrew Thompson avr32dci_mod_ien(sc, AVR32_INT_DET_SUSPD |
66955e76c21SAndrew Thompson AVR32_INT_ENDRESET, AVR32_INT_WAKE_UP);
67055e76c21SAndrew Thompson
67155e76c21SAndrew Thompson /* complete root HUB interrupt endpoint */
67255e76c21SAndrew Thompson avr32dci_root_intr(sc);
67355e76c21SAndrew Thompson }
67455e76c21SAndrew Thompson /*
67555e76c21SAndrew Thompson * If resume and suspend is set at the same time we interpret
67655e76c21SAndrew Thompson * that like RESUME. Resume is set when there is at least 3
67755e76c21SAndrew Thompson * milliseconds of inactivity on the USB BUS.
67855e76c21SAndrew Thompson */
67955e76c21SAndrew Thompson if (status & AVR32_INT_WAKE_UP) {
68055e76c21SAndrew Thompson DPRINTFN(5, "resume interrupt\n");
68155e76c21SAndrew Thompson
68255e76c21SAndrew Thompson if (sc->sc_flags.status_suspend) {
68355e76c21SAndrew Thompson /* update status bits */
68455e76c21SAndrew Thompson sc->sc_flags.status_suspend = 0;
68555e76c21SAndrew Thompson sc->sc_flags.change_suspend = 1;
68655e76c21SAndrew Thompson
68755e76c21SAndrew Thompson /* disable resume interrupt */
68855e76c21SAndrew Thompson avr32dci_mod_ien(sc, AVR32_INT_DET_SUSPD |
68955e76c21SAndrew Thompson AVR32_INT_ENDRESET, AVR32_INT_WAKE_UP);
69055e76c21SAndrew Thompson
69155e76c21SAndrew Thompson /* complete root HUB interrupt endpoint */
69255e76c21SAndrew Thompson avr32dci_root_intr(sc);
69355e76c21SAndrew Thompson }
69455e76c21SAndrew Thompson } else if (status & AVR32_INT_DET_SUSPD) {
69555e76c21SAndrew Thompson DPRINTFN(5, "suspend interrupt\n");
69655e76c21SAndrew Thompson
69755e76c21SAndrew Thompson if (!sc->sc_flags.status_suspend) {
69855e76c21SAndrew Thompson /* update status bits */
69955e76c21SAndrew Thompson sc->sc_flags.status_suspend = 1;
70055e76c21SAndrew Thompson sc->sc_flags.change_suspend = 1;
70155e76c21SAndrew Thompson
70255e76c21SAndrew Thompson /* disable suspend interrupt */
70355e76c21SAndrew Thompson avr32dci_mod_ien(sc, AVR32_INT_WAKE_UP |
70455e76c21SAndrew Thompson AVR32_INT_ENDRESET, AVR32_INT_DET_SUSPD);
70555e76c21SAndrew Thompson
70655e76c21SAndrew Thompson /* complete root HUB interrupt endpoint */
70755e76c21SAndrew Thompson avr32dci_root_intr(sc);
70855e76c21SAndrew Thompson }
70955e76c21SAndrew Thompson }
71055e76c21SAndrew Thompson /* check for any endpoint interrupts */
71155e76c21SAndrew Thompson if (status & -AVR32_INT_EPT_INT(0)) {
71255e76c21SAndrew Thompson DPRINTFN(5, "real endpoint interrupt\n");
71355e76c21SAndrew Thompson
71455e76c21SAndrew Thompson avr32dci_interrupt_poll(sc);
71555e76c21SAndrew Thompson }
71655e76c21SAndrew Thompson USB_BUS_UNLOCK(&sc->sc_bus);
71755e76c21SAndrew Thompson }
71855e76c21SAndrew Thompson
71955e76c21SAndrew Thompson static void
avr32dci_setup_standard_chain_sub(struct avr32dci_std_temp * temp)72055e76c21SAndrew Thompson avr32dci_setup_standard_chain_sub(struct avr32dci_std_temp *temp)
72155e76c21SAndrew Thompson {
72255e76c21SAndrew Thompson struct avr32dci_td *td;
72355e76c21SAndrew Thompson
72455e76c21SAndrew Thompson /* get current Transfer Descriptor */
72555e76c21SAndrew Thompson td = temp->td_next;
72655e76c21SAndrew Thompson temp->td = td;
72755e76c21SAndrew Thompson
72855e76c21SAndrew Thompson /* prepare for next TD */
72955e76c21SAndrew Thompson temp->td_next = td->obj_next;
73055e76c21SAndrew Thompson
73155e76c21SAndrew Thompson /* fill out the Transfer Descriptor */
73255e76c21SAndrew Thompson td->func = temp->func;
73355e76c21SAndrew Thompson td->pc = temp->pc;
73455e76c21SAndrew Thompson td->offset = temp->offset;
73555e76c21SAndrew Thompson td->remainder = temp->len;
73655e76c21SAndrew Thompson td->error = 0;
73755e76c21SAndrew Thompson td->did_stall = temp->did_stall;
73855e76c21SAndrew Thompson td->short_pkt = temp->short_pkt;
73955e76c21SAndrew Thompson td->alt_next = temp->setup_alt_next;
74055e76c21SAndrew Thompson }
74155e76c21SAndrew Thompson
74255e76c21SAndrew Thompson static void
avr32dci_setup_standard_chain(struct usb_xfer * xfer)743760bc48eSAndrew Thompson avr32dci_setup_standard_chain(struct usb_xfer *xfer)
74455e76c21SAndrew Thompson {
74555e76c21SAndrew Thompson struct avr32dci_std_temp temp;
74655e76c21SAndrew Thompson struct avr32dci_softc *sc;
74755e76c21SAndrew Thompson struct avr32dci_td *td;
74855e76c21SAndrew Thompson uint32_t x;
74955e76c21SAndrew Thompson uint8_t ep_no;
75055e76c21SAndrew Thompson uint8_t need_sync;
75155e76c21SAndrew Thompson
75255e76c21SAndrew Thompson DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n",
7532e141748SHans Petter Selasky xfer->address, UE_GET_ADDR(xfer->endpointno),
754a593f6b8SAndrew Thompson xfer->sumlen, usbd_get_speed(xfer->xroot->udev));
75555e76c21SAndrew Thompson
75655e76c21SAndrew Thompson temp.max_frame_size = xfer->max_frame_size;
75755e76c21SAndrew Thompson
75855e76c21SAndrew Thompson td = xfer->td_start[0];
75955e76c21SAndrew Thompson xfer->td_transfer_first = td;
76055e76c21SAndrew Thompson xfer->td_transfer_cache = td;
76155e76c21SAndrew Thompson
76255e76c21SAndrew Thompson /* setup temp */
76355e76c21SAndrew Thompson
76478c94708SAndrew Thompson temp.pc = NULL;
76555e76c21SAndrew Thompson temp.td = NULL;
76655e76c21SAndrew Thompson temp.td_next = xfer->td_start[0];
76755e76c21SAndrew Thompson temp.offset = 0;
76840ba168dSHans Petter Selasky temp.setup_alt_next = xfer->flags_int.short_frames_ok ||
76940ba168dSHans Petter Selasky xfer->flags_int.isochronous_xfr;
77055e76c21SAndrew Thompson temp.did_stall = !xfer->flags_int.control_stall;
77155e76c21SAndrew Thompson
77255e76c21SAndrew Thompson sc = AVR32_BUS2SC(xfer->xroot->bus);
7732e141748SHans Petter Selasky ep_no = (xfer->endpointno & UE_ADDR);
77455e76c21SAndrew Thompson
77555e76c21SAndrew Thompson /* check if we should prepend a setup message */
77655e76c21SAndrew Thompson
77755e76c21SAndrew Thompson if (xfer->flags_int.control_xfr) {
77855e76c21SAndrew Thompson if (xfer->flags_int.control_hdr) {
77955e76c21SAndrew Thompson temp.func = &avr32dci_setup_rx;
78055e76c21SAndrew Thompson temp.len = xfer->frlengths[0];
78155e76c21SAndrew Thompson temp.pc = xfer->frbuffers + 0;
78255e76c21SAndrew Thompson temp.short_pkt = temp.len ? 1 : 0;
78355e76c21SAndrew Thompson /* check for last frame */
78455e76c21SAndrew Thompson if (xfer->nframes == 1) {
78555e76c21SAndrew Thompson /* no STATUS stage yet, SETUP is last */
78655e76c21SAndrew Thompson if (xfer->flags_int.control_act)
78755e76c21SAndrew Thompson temp.setup_alt_next = 0;
78855e76c21SAndrew Thompson }
78955e76c21SAndrew Thompson avr32dci_setup_standard_chain_sub(&temp);
79055e76c21SAndrew Thompson }
79155e76c21SAndrew Thompson x = 1;
79255e76c21SAndrew Thompson } else {
79355e76c21SAndrew Thompson x = 0;
79455e76c21SAndrew Thompson }
79555e76c21SAndrew Thompson
79655e76c21SAndrew Thompson if (x != xfer->nframes) {
7972e141748SHans Petter Selasky if (xfer->endpointno & UE_DIR_IN) {
79855e76c21SAndrew Thompson temp.func = &avr32dci_data_tx;
79955e76c21SAndrew Thompson need_sync = 1;
80055e76c21SAndrew Thompson } else {
80155e76c21SAndrew Thompson temp.func = &avr32dci_data_rx;
80255e76c21SAndrew Thompson need_sync = 0;
80355e76c21SAndrew Thompson }
80455e76c21SAndrew Thompson
80555e76c21SAndrew Thompson /* setup "pc" pointer */
80655e76c21SAndrew Thompson temp.pc = xfer->frbuffers + x;
80755e76c21SAndrew Thompson } else {
80855e76c21SAndrew Thompson need_sync = 0;
80955e76c21SAndrew Thompson }
81055e76c21SAndrew Thompson while (x != xfer->nframes) {
81155e76c21SAndrew Thompson /* DATA0 / DATA1 message */
81255e76c21SAndrew Thompson
81355e76c21SAndrew Thompson temp.len = xfer->frlengths[x];
81455e76c21SAndrew Thompson
81555e76c21SAndrew Thompson x++;
81655e76c21SAndrew Thompson
81755e76c21SAndrew Thompson if (x == xfer->nframes) {
81855e76c21SAndrew Thompson if (xfer->flags_int.control_xfr) {
81955e76c21SAndrew Thompson if (xfer->flags_int.control_act) {
82055e76c21SAndrew Thompson temp.setup_alt_next = 0;
82155e76c21SAndrew Thompson }
82255e76c21SAndrew Thompson } else {
82355e76c21SAndrew Thompson temp.setup_alt_next = 0;
82455e76c21SAndrew Thompson }
82555e76c21SAndrew Thompson }
82655e76c21SAndrew Thompson if (temp.len == 0) {
82755e76c21SAndrew Thompson /* make sure that we send an USB packet */
82855e76c21SAndrew Thompson
82955e76c21SAndrew Thompson temp.short_pkt = 0;
83055e76c21SAndrew Thompson
83155e76c21SAndrew Thompson } else {
83255e76c21SAndrew Thompson /* regular data transfer */
83355e76c21SAndrew Thompson
83455e76c21SAndrew Thompson temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1;
83555e76c21SAndrew Thompson }
83655e76c21SAndrew Thompson
83755e76c21SAndrew Thompson avr32dci_setup_standard_chain_sub(&temp);
83855e76c21SAndrew Thompson
83955e76c21SAndrew Thompson if (xfer->flags_int.isochronous_xfr) {
84055e76c21SAndrew Thompson temp.offset += temp.len;
84155e76c21SAndrew Thompson } else {
84255e76c21SAndrew Thompson /* get next Page Cache pointer */
84355e76c21SAndrew Thompson temp.pc = xfer->frbuffers + x;
84455e76c21SAndrew Thompson }
84555e76c21SAndrew Thompson }
84655e76c21SAndrew Thompson
84755e76c21SAndrew Thompson if (xfer->flags_int.control_xfr) {
84855e76c21SAndrew Thompson /* always setup a valid "pc" pointer for status and sync */
84955e76c21SAndrew Thompson temp.pc = xfer->frbuffers + 0;
85055e76c21SAndrew Thompson temp.len = 0;
85155e76c21SAndrew Thompson temp.short_pkt = 0;
85255e76c21SAndrew Thompson temp.setup_alt_next = 0;
85355e76c21SAndrew Thompson
85455e76c21SAndrew Thompson /* check if we need to sync */
85555e76c21SAndrew Thompson if (need_sync) {
85655e76c21SAndrew Thompson /* we need a SYNC point after TX */
85755e76c21SAndrew Thompson temp.func = &avr32dci_data_tx_sync;
85855e76c21SAndrew Thompson avr32dci_setup_standard_chain_sub(&temp);
85955e76c21SAndrew Thompson }
86055e76c21SAndrew Thompson /* check if we should append a status stage */
86155e76c21SAndrew Thompson if (!xfer->flags_int.control_act) {
86255e76c21SAndrew Thompson /*
86355e76c21SAndrew Thompson * Send a DATA1 message and invert the current
86455e76c21SAndrew Thompson * endpoint direction.
86555e76c21SAndrew Thompson */
8662e141748SHans Petter Selasky if (xfer->endpointno & UE_DIR_IN) {
86755e76c21SAndrew Thompson temp.func = &avr32dci_data_rx;
86855e76c21SAndrew Thompson need_sync = 0;
86955e76c21SAndrew Thompson } else {
87055e76c21SAndrew Thompson temp.func = &avr32dci_data_tx;
87155e76c21SAndrew Thompson need_sync = 1;
87255e76c21SAndrew Thompson }
87355e76c21SAndrew Thompson
87455e76c21SAndrew Thompson avr32dci_setup_standard_chain_sub(&temp);
87555e76c21SAndrew Thompson if (need_sync) {
87655e76c21SAndrew Thompson /* we need a SYNC point after TX */
87755e76c21SAndrew Thompson temp.func = &avr32dci_data_tx_sync;
87855e76c21SAndrew Thompson avr32dci_setup_standard_chain_sub(&temp);
87955e76c21SAndrew Thompson }
88055e76c21SAndrew Thompson }
88155e76c21SAndrew Thompson }
88255e76c21SAndrew Thompson /* must have at least one frame! */
88355e76c21SAndrew Thompson td = temp.td;
88455e76c21SAndrew Thompson xfer->td_transfer_last = td;
88555e76c21SAndrew Thompson }
88655e76c21SAndrew Thompson
88755e76c21SAndrew Thompson static void
avr32dci_timeout(void * arg)88855e76c21SAndrew Thompson avr32dci_timeout(void *arg)
88955e76c21SAndrew Thompson {
890760bc48eSAndrew Thompson struct usb_xfer *xfer = arg;
89155e76c21SAndrew Thompson
89255e76c21SAndrew Thompson DPRINTF("xfer=%p\n", xfer);
89355e76c21SAndrew Thompson
89455e76c21SAndrew Thompson USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
89555e76c21SAndrew Thompson
89655e76c21SAndrew Thompson /* transfer is transferred */
89755e76c21SAndrew Thompson avr32dci_device_done(xfer, USB_ERR_TIMEOUT);
89855e76c21SAndrew Thompson }
89955e76c21SAndrew Thompson
90055e76c21SAndrew Thompson static void
avr32dci_start_standard_chain(struct usb_xfer * xfer)901760bc48eSAndrew Thompson avr32dci_start_standard_chain(struct usb_xfer *xfer)
90255e76c21SAndrew Thompson {
90355e76c21SAndrew Thompson DPRINTFN(9, "\n");
90455e76c21SAndrew Thompson
90555e76c21SAndrew Thompson /* poll one time - will turn on interrupts */
90655e76c21SAndrew Thompson if (avr32dci_xfer_do_fifo(xfer)) {
9072e141748SHans Petter Selasky uint8_t ep_no = xfer->endpointno & UE_ADDR;
9082e141748SHans Petter Selasky struct avr32dci_softc *sc = AVR32_BUS2SC(xfer->xroot->bus);
90955e76c21SAndrew Thompson
91055e76c21SAndrew Thompson avr32dci_mod_ien(sc, AVR32_INT_EPT_INT(ep_no), 0);
91155e76c21SAndrew Thompson
91255e76c21SAndrew Thompson /* put transfer on interrupt queue */
913a593f6b8SAndrew Thompson usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
91455e76c21SAndrew Thompson
91555e76c21SAndrew Thompson /* start timeout, if any */
91655e76c21SAndrew Thompson if (xfer->timeout != 0) {
917a593f6b8SAndrew Thompson usbd_transfer_timeout_ms(xfer,
91855e76c21SAndrew Thompson &avr32dci_timeout, xfer->timeout);
91955e76c21SAndrew Thompson }
92055e76c21SAndrew Thompson }
92155e76c21SAndrew Thompson }
92255e76c21SAndrew Thompson
92355e76c21SAndrew Thompson static void
avr32dci_root_intr(struct avr32dci_softc * sc)92455e76c21SAndrew Thompson avr32dci_root_intr(struct avr32dci_softc *sc)
92555e76c21SAndrew Thompson {
92655e76c21SAndrew Thompson DPRINTFN(9, "\n");
92755e76c21SAndrew Thompson
92855e76c21SAndrew Thompson USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
92955e76c21SAndrew Thompson
93055e76c21SAndrew Thompson /* set port bit */
93155e76c21SAndrew Thompson sc->sc_hub_idata[0] = 0x02; /* we only have one port */
93255e76c21SAndrew Thompson
93355e76c21SAndrew Thompson uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata,
93455e76c21SAndrew Thompson sizeof(sc->sc_hub_idata));
93555e76c21SAndrew Thompson }
93655e76c21SAndrew Thompson
937e0a69b51SAndrew Thompson static usb_error_t
avr32dci_standard_done_sub(struct usb_xfer * xfer)938760bc48eSAndrew Thompson avr32dci_standard_done_sub(struct usb_xfer *xfer)
93955e76c21SAndrew Thompson {
94055e76c21SAndrew Thompson struct avr32dci_td *td;
94155e76c21SAndrew Thompson uint32_t len;
94255e76c21SAndrew Thompson uint8_t error;
94355e76c21SAndrew Thompson
94455e76c21SAndrew Thompson DPRINTFN(9, "\n");
94555e76c21SAndrew Thompson
94655e76c21SAndrew Thompson td = xfer->td_transfer_cache;
94755e76c21SAndrew Thompson
94855e76c21SAndrew Thompson do {
94955e76c21SAndrew Thompson len = td->remainder;
95055e76c21SAndrew Thompson
95155e76c21SAndrew Thompson if (xfer->aframes != xfer->nframes) {
95255e76c21SAndrew Thompson /*
95355e76c21SAndrew Thompson * Verify the length and subtract
95455e76c21SAndrew Thompson * the remainder from "frlengths[]":
95555e76c21SAndrew Thompson */
95655e76c21SAndrew Thompson if (len > xfer->frlengths[xfer->aframes]) {
95755e76c21SAndrew Thompson td->error = 1;
95855e76c21SAndrew Thompson } else {
95955e76c21SAndrew Thompson xfer->frlengths[xfer->aframes] -= len;
96055e76c21SAndrew Thompson }
96155e76c21SAndrew Thompson }
96255e76c21SAndrew Thompson /* Check for transfer error */
96355e76c21SAndrew Thompson if (td->error) {
96455e76c21SAndrew Thompson /* the transfer is finished */
96555e76c21SAndrew Thompson error = 1;
96655e76c21SAndrew Thompson td = NULL;
96755e76c21SAndrew Thompson break;
96855e76c21SAndrew Thompson }
96955e76c21SAndrew Thompson /* Check for short transfer */
97055e76c21SAndrew Thompson if (len > 0) {
97140ba168dSHans Petter Selasky if (xfer->flags_int.short_frames_ok ||
97240ba168dSHans Petter Selasky xfer->flags_int.isochronous_xfr) {
97355e76c21SAndrew Thompson /* follow alt next */
97455e76c21SAndrew Thompson if (td->alt_next) {
97555e76c21SAndrew Thompson td = td->obj_next;
97655e76c21SAndrew Thompson } else {
97755e76c21SAndrew Thompson td = NULL;
97855e76c21SAndrew Thompson }
97955e76c21SAndrew Thompson } else {
98055e76c21SAndrew Thompson /* the transfer is finished */
98155e76c21SAndrew Thompson td = NULL;
98255e76c21SAndrew Thompson }
98355e76c21SAndrew Thompson error = 0;
98455e76c21SAndrew Thompson break;
98555e76c21SAndrew Thompson }
98655e76c21SAndrew Thompson td = td->obj_next;
98755e76c21SAndrew Thompson
98855e76c21SAndrew Thompson /* this USB frame is complete */
98955e76c21SAndrew Thompson error = 0;
99055e76c21SAndrew Thompson break;
99155e76c21SAndrew Thompson
99255e76c21SAndrew Thompson } while (0);
99355e76c21SAndrew Thompson
99455e76c21SAndrew Thompson /* update transfer cache */
99555e76c21SAndrew Thompson
99655e76c21SAndrew Thompson xfer->td_transfer_cache = td;
99755e76c21SAndrew Thompson
99855e76c21SAndrew Thompson return (error ?
99955e76c21SAndrew Thompson USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION);
100055e76c21SAndrew Thompson }
100155e76c21SAndrew Thompson
100255e76c21SAndrew Thompson static void
avr32dci_standard_done(struct usb_xfer * xfer)1003760bc48eSAndrew Thompson avr32dci_standard_done(struct usb_xfer *xfer)
100455e76c21SAndrew Thompson {
1005e0a69b51SAndrew Thompson usb_error_t err = 0;
100655e76c21SAndrew Thompson
100755e76c21SAndrew Thompson DPRINTFN(13, "xfer=%p pipe=%p transfer done\n",
10082e141748SHans Petter Selasky xfer, xfer->endpoint);
100955e76c21SAndrew Thompson
101055e76c21SAndrew Thompson /* reset scanner */
101155e76c21SAndrew Thompson
101255e76c21SAndrew Thompson xfer->td_transfer_cache = xfer->td_transfer_first;
101355e76c21SAndrew Thompson
101455e76c21SAndrew Thompson if (xfer->flags_int.control_xfr) {
101555e76c21SAndrew Thompson if (xfer->flags_int.control_hdr) {
101655e76c21SAndrew Thompson err = avr32dci_standard_done_sub(xfer);
101755e76c21SAndrew Thompson }
101855e76c21SAndrew Thompson xfer->aframes = 1;
101955e76c21SAndrew Thompson
102055e76c21SAndrew Thompson if (xfer->td_transfer_cache == NULL) {
102155e76c21SAndrew Thompson goto done;
102255e76c21SAndrew Thompson }
102355e76c21SAndrew Thompson }
102455e76c21SAndrew Thompson while (xfer->aframes != xfer->nframes) {
102555e76c21SAndrew Thompson err = avr32dci_standard_done_sub(xfer);
102655e76c21SAndrew Thompson xfer->aframes++;
102755e76c21SAndrew Thompson
102855e76c21SAndrew Thompson if (xfer->td_transfer_cache == NULL) {
102955e76c21SAndrew Thompson goto done;
103055e76c21SAndrew Thompson }
103155e76c21SAndrew Thompson }
103255e76c21SAndrew Thompson
103355e76c21SAndrew Thompson if (xfer->flags_int.control_xfr &&
103455e76c21SAndrew Thompson !xfer->flags_int.control_act) {
103555e76c21SAndrew Thompson err = avr32dci_standard_done_sub(xfer);
103655e76c21SAndrew Thompson }
103755e76c21SAndrew Thompson done:
103855e76c21SAndrew Thompson avr32dci_device_done(xfer, err);
103955e76c21SAndrew Thompson }
104055e76c21SAndrew Thompson
104155e76c21SAndrew Thompson /*------------------------------------------------------------------------*
104255e76c21SAndrew Thompson * avr32dci_device_done
104355e76c21SAndrew Thompson *
104455e76c21SAndrew Thompson * NOTE: this function can be called more than one time on the
104555e76c21SAndrew Thompson * same USB transfer!
104655e76c21SAndrew Thompson *------------------------------------------------------------------------*/
104755e76c21SAndrew Thompson static void
avr32dci_device_done(struct usb_xfer * xfer,usb_error_t error)1048e0a69b51SAndrew Thompson avr32dci_device_done(struct usb_xfer *xfer, usb_error_t error)
104955e76c21SAndrew Thompson {
105055e76c21SAndrew Thompson struct avr32dci_softc *sc = AVR32_BUS2SC(xfer->xroot->bus);
105155e76c21SAndrew Thompson uint8_t ep_no;
105255e76c21SAndrew Thompson
105355e76c21SAndrew Thompson USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
105455e76c21SAndrew Thompson
105555e76c21SAndrew Thompson DPRINTFN(9, "xfer=%p, pipe=%p, error=%d\n",
10562e141748SHans Petter Selasky xfer, xfer->endpoint, error);
105755e76c21SAndrew Thompson
105855e76c21SAndrew Thompson if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
10592e141748SHans Petter Selasky ep_no = (xfer->endpointno & UE_ADDR);
106055e76c21SAndrew Thompson
106155e76c21SAndrew Thompson /* disable endpoint interrupt */
106255e76c21SAndrew Thompson avr32dci_mod_ien(sc, 0, AVR32_INT_EPT_INT(ep_no));
106355e76c21SAndrew Thompson
106455e76c21SAndrew Thompson DPRINTFN(15, "disabled interrupts!\n");
106555e76c21SAndrew Thompson }
106655e76c21SAndrew Thompson /* dequeue transfer and start next transfer */
1067a593f6b8SAndrew Thompson usbd_transfer_done(xfer, error);
106855e76c21SAndrew Thompson }
106955e76c21SAndrew Thompson
107055e76c21SAndrew Thompson static void
avr32dci_xfer_stall(struct usb_xfer * xfer)1071a5cf1aaaSHans Petter Selasky avr32dci_xfer_stall(struct usb_xfer *xfer)
1072a5cf1aaaSHans Petter Selasky {
1073a5cf1aaaSHans Petter Selasky avr32dci_device_done(xfer, USB_ERR_STALLED);
1074a5cf1aaaSHans Petter Selasky }
1075a5cf1aaaSHans Petter Selasky
1076a5cf1aaaSHans Petter Selasky static void
avr32dci_set_stall(struct usb_device * udev,struct usb_endpoint * pipe,uint8_t * did_stall)1077a5cf1aaaSHans Petter Selasky avr32dci_set_stall(struct usb_device *udev,
10782e141748SHans Petter Selasky struct usb_endpoint *pipe, uint8_t *did_stall)
107955e76c21SAndrew Thompson {
108055e76c21SAndrew Thompson struct avr32dci_softc *sc;
108155e76c21SAndrew Thompson uint8_t ep_no;
108255e76c21SAndrew Thompson
108355e76c21SAndrew Thompson USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
108455e76c21SAndrew Thompson
108555e76c21SAndrew Thompson DPRINTFN(5, "pipe=%p\n", pipe);
108655e76c21SAndrew Thompson
108755e76c21SAndrew Thompson sc = AVR32_BUS2SC(udev->bus);
108855e76c21SAndrew Thompson /* get endpoint number */
108955e76c21SAndrew Thompson ep_no = (pipe->edesc->bEndpointAddress & UE_ADDR);
109055e76c21SAndrew Thompson /* set stall */
109155e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTSETSTA(ep_no), AVR32_EPTSTA_FRCESTALL);
109255e76c21SAndrew Thompson }
109355e76c21SAndrew Thompson
109455e76c21SAndrew Thompson static void
avr32dci_clear_stall_sub(struct avr32dci_softc * sc,uint8_t ep_no,uint8_t ep_type,uint8_t ep_dir)109555e76c21SAndrew Thompson avr32dci_clear_stall_sub(struct avr32dci_softc *sc, uint8_t ep_no,
109655e76c21SAndrew Thompson uint8_t ep_type, uint8_t ep_dir)
109755e76c21SAndrew Thompson {
1098760bc48eSAndrew Thompson const struct usb_hw_ep_profile *pf;
109955e76c21SAndrew Thompson uint32_t temp;
110055e76c21SAndrew Thompson uint32_t epsize;
110155e76c21SAndrew Thompson uint8_t n;
110255e76c21SAndrew Thompson
110355e76c21SAndrew Thompson if (ep_type == UE_CONTROL) {
110455e76c21SAndrew Thompson /* clearing stall is not needed */
110555e76c21SAndrew Thompson return;
110655e76c21SAndrew Thompson }
110755e76c21SAndrew Thompson /* set endpoint reset */
110855e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTRST, AVR32_EPTRST_MASK(ep_no));
110955e76c21SAndrew Thompson
111055e76c21SAndrew Thompson /* set stall */
111155e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTSETSTA(ep_no), AVR32_EPTSTA_FRCESTALL);
111255e76c21SAndrew Thompson
111355e76c21SAndrew Thompson /* reset data toggle */
111455e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(ep_no), AVR32_EPTSTA_TOGGLESQ);
111555e76c21SAndrew Thompson
111655e76c21SAndrew Thompson /* clear stall */
111755e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(ep_no), AVR32_EPTSTA_FRCESTALL);
111855e76c21SAndrew Thompson
111955e76c21SAndrew Thompson if (ep_type == UE_BULK) {
112055e76c21SAndrew Thompson temp = AVR32_EPTCFG_TYPE_BULK;
112155e76c21SAndrew Thompson } else if (ep_type == UE_INTERRUPT) {
112255e76c21SAndrew Thompson temp = AVR32_EPTCFG_TYPE_INTR;
112355e76c21SAndrew Thompson } else {
112455e76c21SAndrew Thompson temp = AVR32_EPTCFG_TYPE_ISOC |
112555e76c21SAndrew Thompson AVR32_EPTCFG_NB_TRANS(1);
112655e76c21SAndrew Thompson }
112755e76c21SAndrew Thompson if (ep_dir & UE_DIR_IN) {
112855e76c21SAndrew Thompson temp |= AVR32_EPTCFG_EPDIR_IN;
112955e76c21SAndrew Thompson }
113055e76c21SAndrew Thompson avr32dci_get_hw_ep_profile(NULL, &pf, ep_no);
113155e76c21SAndrew Thompson
113255e76c21SAndrew Thompson /* compute endpoint size (use maximum) */
113355e76c21SAndrew Thompson epsize = pf->max_in_frame_size | pf->max_out_frame_size;
113455e76c21SAndrew Thompson n = 0;
113555e76c21SAndrew Thompson while ((epsize /= 2))
113655e76c21SAndrew Thompson n++;
113755e76c21SAndrew Thompson temp |= AVR32_EPTCFG_EPSIZE(n);
113855e76c21SAndrew Thompson
113955e76c21SAndrew Thompson /* use the maximum number of banks supported */
114055e76c21SAndrew Thompson if (ep_no < 1)
114155e76c21SAndrew Thompson temp |= AVR32_EPTCFG_NBANK(1);
114255e76c21SAndrew Thompson else if (ep_no < 3)
114355e76c21SAndrew Thompson temp |= AVR32_EPTCFG_NBANK(2);
114455e76c21SAndrew Thompson else
114555e76c21SAndrew Thompson temp |= AVR32_EPTCFG_NBANK(3);
114655e76c21SAndrew Thompson
114755e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCFG(ep_no), temp);
114855e76c21SAndrew Thompson
114955e76c21SAndrew Thompson temp = AVR32_READ_4(sc, AVR32_EPTCFG(ep_no));
115055e76c21SAndrew Thompson
115155e76c21SAndrew Thompson if (!(temp & AVR32_EPTCFG_EPT_MAPD)) {
1152767cb2e2SAndrew Thompson device_printf(sc->sc_bus.bdev, "Chip rejected configuration\n");
115355e76c21SAndrew Thompson } else {
115455e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCTLENB(ep_no),
115555e76c21SAndrew Thompson AVR32_EPTCTL_EPT_ENABL);
115655e76c21SAndrew Thompson }
115755e76c21SAndrew Thompson }
115855e76c21SAndrew Thompson
115955e76c21SAndrew Thompson static void
avr32dci_clear_stall(struct usb_device * udev,struct usb_endpoint * pipe)11602e141748SHans Petter Selasky avr32dci_clear_stall(struct usb_device *udev, struct usb_endpoint *pipe)
116155e76c21SAndrew Thompson {
116255e76c21SAndrew Thompson struct avr32dci_softc *sc;
1163760bc48eSAndrew Thompson struct usb_endpoint_descriptor *ed;
116455e76c21SAndrew Thompson
116555e76c21SAndrew Thompson DPRINTFN(5, "pipe=%p\n", pipe);
116655e76c21SAndrew Thompson
116755e76c21SAndrew Thompson USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
116855e76c21SAndrew Thompson
116955e76c21SAndrew Thompson /* check mode */
117055e76c21SAndrew Thompson if (udev->flags.usb_mode != USB_MODE_DEVICE) {
117155e76c21SAndrew Thompson /* not supported */
117255e76c21SAndrew Thompson return;
117355e76c21SAndrew Thompson }
117455e76c21SAndrew Thompson /* get softc */
117555e76c21SAndrew Thompson sc = AVR32_BUS2SC(udev->bus);
117655e76c21SAndrew Thompson
117755e76c21SAndrew Thompson /* get endpoint descriptor */
117855e76c21SAndrew Thompson ed = pipe->edesc;
117955e76c21SAndrew Thompson
118055e76c21SAndrew Thompson /* reset endpoint */
118155e76c21SAndrew Thompson avr32dci_clear_stall_sub(sc,
118255e76c21SAndrew Thompson (ed->bEndpointAddress & UE_ADDR),
118355e76c21SAndrew Thompson (ed->bmAttributes & UE_XFERTYPE),
118455e76c21SAndrew Thompson (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT)));
118555e76c21SAndrew Thompson }
118655e76c21SAndrew Thompson
1187e0a69b51SAndrew Thompson usb_error_t
avr32dci_init(struct avr32dci_softc * sc)118855e76c21SAndrew Thompson avr32dci_init(struct avr32dci_softc *sc)
118955e76c21SAndrew Thompson {
119055e76c21SAndrew Thompson uint8_t n;
119155e76c21SAndrew Thompson
119255e76c21SAndrew Thompson DPRINTF("start\n");
119355e76c21SAndrew Thompson
119455e76c21SAndrew Thompson /* set up the bus structure */
119555e76c21SAndrew Thompson sc->sc_bus.usbrev = USB_REV_1_1;
119655e76c21SAndrew Thompson sc->sc_bus.methods = &avr32dci_bus_methods;
119755e76c21SAndrew Thompson
119855e76c21SAndrew Thompson USB_BUS_LOCK(&sc->sc_bus);
119955e76c21SAndrew Thompson
120055e76c21SAndrew Thompson /* make sure USB is enabled */
120155e76c21SAndrew Thompson avr32dci_mod_ctrl(sc, AVR32_CTRL_DEV_EN_USBA, 0);
120255e76c21SAndrew Thompson
120355e76c21SAndrew Thompson /* turn on clocks */
120455e76c21SAndrew Thompson (sc->sc_clocks_on) (&sc->sc_bus);
120555e76c21SAndrew Thompson
120655e76c21SAndrew Thompson /* make sure device is re-enumerated */
120755e76c21SAndrew Thompson avr32dci_mod_ctrl(sc, AVR32_CTRL_DEV_DETACH, 0);
120855e76c21SAndrew Thompson
120955e76c21SAndrew Thompson /* wait a little for things to stabilise */
1210a593f6b8SAndrew Thompson usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 20);
121155e76c21SAndrew Thompson
121255e76c21SAndrew Thompson /* disable interrupts */
121355e76c21SAndrew Thompson avr32dci_mod_ien(sc, 0, 0xFFFFFFFF);
121455e76c21SAndrew Thompson
121555e76c21SAndrew Thompson /* enable interrupts */
121655e76c21SAndrew Thompson avr32dci_mod_ien(sc, AVR32_INT_DET_SUSPD |
121755e76c21SAndrew Thompson AVR32_INT_ENDRESET, 0);
121855e76c21SAndrew Thompson
121955e76c21SAndrew Thompson /* reset all endpoints */
12202e141748SHans Petter Selasky AVR32_WRITE_4(sc, AVR32_EPTRST, (1 << AVR32_EP_MAX) - 1);
122155e76c21SAndrew Thompson
122255e76c21SAndrew Thompson /* disable all endpoints */
122355e76c21SAndrew Thompson for (n = 0; n != AVR32_EP_MAX; n++) {
122455e76c21SAndrew Thompson /* disable endpoint */
122555e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCTLDIS(n), AVR32_EPTCTL_EPT_ENABL);
122655e76c21SAndrew Thompson }
122755e76c21SAndrew Thompson
122855e76c21SAndrew Thompson /* turn off clocks */
122955e76c21SAndrew Thompson
123055e76c21SAndrew Thompson avr32dci_clocks_off(sc);
123155e76c21SAndrew Thompson
123255e76c21SAndrew Thompson USB_BUS_UNLOCK(&sc->sc_bus);
123355e76c21SAndrew Thompson
123455e76c21SAndrew Thompson /* catch any lost interrupts */
123555e76c21SAndrew Thompson
123655e76c21SAndrew Thompson avr32dci_do_poll(&sc->sc_bus);
123755e76c21SAndrew Thompson
123855e76c21SAndrew Thompson return (0); /* success */
123955e76c21SAndrew Thompson }
124055e76c21SAndrew Thompson
124155e76c21SAndrew Thompson void
avr32dci_uninit(struct avr32dci_softc * sc)124255e76c21SAndrew Thompson avr32dci_uninit(struct avr32dci_softc *sc)
124355e76c21SAndrew Thompson {
124455e76c21SAndrew Thompson uint8_t n;
124555e76c21SAndrew Thompson
124655e76c21SAndrew Thompson USB_BUS_LOCK(&sc->sc_bus);
124755e76c21SAndrew Thompson
124855e76c21SAndrew Thompson /* turn on clocks */
124955e76c21SAndrew Thompson (sc->sc_clocks_on) (&sc->sc_bus);
125055e76c21SAndrew Thompson
125155e76c21SAndrew Thompson /* disable interrupts */
125255e76c21SAndrew Thompson avr32dci_mod_ien(sc, 0, 0xFFFFFFFF);
125355e76c21SAndrew Thompson
125455e76c21SAndrew Thompson /* reset all endpoints */
12552e141748SHans Petter Selasky AVR32_WRITE_4(sc, AVR32_EPTRST, (1 << AVR32_EP_MAX) - 1);
125655e76c21SAndrew Thompson
125755e76c21SAndrew Thompson /* disable all endpoints */
125855e76c21SAndrew Thompson for (n = 0; n != AVR32_EP_MAX; n++) {
125955e76c21SAndrew Thompson /* disable endpoint */
126055e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCTLDIS(n), AVR32_EPTCTL_EPT_ENABL);
126155e76c21SAndrew Thompson }
126255e76c21SAndrew Thompson
126355e76c21SAndrew Thompson sc->sc_flags.port_powered = 0;
126455e76c21SAndrew Thompson sc->sc_flags.status_vbus = 0;
126555e76c21SAndrew Thompson sc->sc_flags.status_bus_reset = 0;
126655e76c21SAndrew Thompson sc->sc_flags.status_suspend = 0;
126755e76c21SAndrew Thompson sc->sc_flags.change_suspend = 0;
126855e76c21SAndrew Thompson sc->sc_flags.change_connect = 1;
126955e76c21SAndrew Thompson
127055e76c21SAndrew Thompson avr32dci_pull_down(sc);
127155e76c21SAndrew Thompson avr32dci_clocks_off(sc);
127255e76c21SAndrew Thompson
127355e76c21SAndrew Thompson USB_BUS_UNLOCK(&sc->sc_bus);
127455e76c21SAndrew Thompson }
127555e76c21SAndrew Thompson
12762e141748SHans Petter Selasky static void
avr32dci_suspend(struct avr32dci_softc * sc)127755e76c21SAndrew Thompson avr32dci_suspend(struct avr32dci_softc *sc)
127855e76c21SAndrew Thompson {
12792e141748SHans Petter Selasky /* TODO */
128055e76c21SAndrew Thompson }
128155e76c21SAndrew Thompson
12822e141748SHans Petter Selasky static void
avr32dci_resume(struct avr32dci_softc * sc)128355e76c21SAndrew Thompson avr32dci_resume(struct avr32dci_softc *sc)
128455e76c21SAndrew Thompson {
12852e141748SHans Petter Selasky /* TODO */
128655e76c21SAndrew Thompson }
128755e76c21SAndrew Thompson
128855e76c21SAndrew Thompson static void
avr32dci_do_poll(struct usb_bus * bus)1289760bc48eSAndrew Thompson avr32dci_do_poll(struct usb_bus *bus)
129055e76c21SAndrew Thompson {
129155e76c21SAndrew Thompson struct avr32dci_softc *sc = AVR32_BUS2SC(bus);
129255e76c21SAndrew Thompson
129355e76c21SAndrew Thompson USB_BUS_LOCK(&sc->sc_bus);
129455e76c21SAndrew Thompson avr32dci_interrupt_poll(sc);
129555e76c21SAndrew Thompson USB_BUS_UNLOCK(&sc->sc_bus);
129655e76c21SAndrew Thompson }
129755e76c21SAndrew Thompson
129855e76c21SAndrew Thompson /*------------------------------------------------------------------------*
129940ba168dSHans Petter Selasky * avr32dci bulk support
130040ba168dSHans Petter Selasky * avr32dci control support
130140ba168dSHans Petter Selasky * avr32dci interrupt support
130255e76c21SAndrew Thompson *------------------------------------------------------------------------*/
130355e76c21SAndrew Thompson static void
avr32dci_device_non_isoc_open(struct usb_xfer * xfer)1304760bc48eSAndrew Thompson avr32dci_device_non_isoc_open(struct usb_xfer *xfer)
130555e76c21SAndrew Thompson {
130655e76c21SAndrew Thompson return;
130755e76c21SAndrew Thompson }
130855e76c21SAndrew Thompson
130955e76c21SAndrew Thompson static void
avr32dci_device_non_isoc_close(struct usb_xfer * xfer)1310760bc48eSAndrew Thompson avr32dci_device_non_isoc_close(struct usb_xfer *xfer)
131155e76c21SAndrew Thompson {
131255e76c21SAndrew Thompson avr32dci_device_done(xfer, USB_ERR_CANCELLED);
131355e76c21SAndrew Thompson }
131455e76c21SAndrew Thompson
131555e76c21SAndrew Thompson static void
avr32dci_device_non_isoc_enter(struct usb_xfer * xfer)1316760bc48eSAndrew Thompson avr32dci_device_non_isoc_enter(struct usb_xfer *xfer)
131755e76c21SAndrew Thompson {
131855e76c21SAndrew Thompson return;
131955e76c21SAndrew Thompson }
132055e76c21SAndrew Thompson
132155e76c21SAndrew Thompson static void
avr32dci_device_non_isoc_start(struct usb_xfer * xfer)1322760bc48eSAndrew Thompson avr32dci_device_non_isoc_start(struct usb_xfer *xfer)
132355e76c21SAndrew Thompson {
132455e76c21SAndrew Thompson /* setup TDs */
132555e76c21SAndrew Thompson avr32dci_setup_standard_chain(xfer);
132655e76c21SAndrew Thompson avr32dci_start_standard_chain(xfer);
132755e76c21SAndrew Thompson }
132855e76c21SAndrew Thompson
1329e892b3feSHans Petter Selasky static const struct usb_pipe_methods avr32dci_device_non_isoc_methods =
133055e76c21SAndrew Thompson {
133155e76c21SAndrew Thompson .open = avr32dci_device_non_isoc_open,
133255e76c21SAndrew Thompson .close = avr32dci_device_non_isoc_close,
133355e76c21SAndrew Thompson .enter = avr32dci_device_non_isoc_enter,
133455e76c21SAndrew Thompson .start = avr32dci_device_non_isoc_start,
133555e76c21SAndrew Thompson };
133655e76c21SAndrew Thompson
133755e76c21SAndrew Thompson /*------------------------------------------------------------------------*
133840ba168dSHans Petter Selasky * avr32dci full speed isochronous support
133955e76c21SAndrew Thompson *------------------------------------------------------------------------*/
134055e76c21SAndrew Thompson static void
avr32dci_device_isoc_fs_open(struct usb_xfer * xfer)1341760bc48eSAndrew Thompson avr32dci_device_isoc_fs_open(struct usb_xfer *xfer)
134255e76c21SAndrew Thompson {
134355e76c21SAndrew Thompson return;
134455e76c21SAndrew Thompson }
134555e76c21SAndrew Thompson
134655e76c21SAndrew Thompson static void
avr32dci_device_isoc_fs_close(struct usb_xfer * xfer)1347760bc48eSAndrew Thompson avr32dci_device_isoc_fs_close(struct usb_xfer *xfer)
134855e76c21SAndrew Thompson {
134955e76c21SAndrew Thompson avr32dci_device_done(xfer, USB_ERR_CANCELLED);
135055e76c21SAndrew Thompson }
135155e76c21SAndrew Thompson
135255e76c21SAndrew Thompson static void
avr32dci_device_isoc_fs_enter(struct usb_xfer * xfer)1353760bc48eSAndrew Thompson avr32dci_device_isoc_fs_enter(struct usb_xfer *xfer)
135455e76c21SAndrew Thompson {
135555e76c21SAndrew Thompson struct avr32dci_softc *sc = AVR32_BUS2SC(xfer->xroot->bus);
135655e76c21SAndrew Thompson uint32_t nframes;
135755e76c21SAndrew Thompson uint8_t ep_no;
135855e76c21SAndrew Thompson
135955e76c21SAndrew Thompson DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
13602e141748SHans Petter Selasky xfer, xfer->endpoint->isoc_next, xfer->nframes);
136155e76c21SAndrew Thompson
136255e76c21SAndrew Thompson /* get the current frame index */
13632e141748SHans Petter Selasky ep_no = xfer->endpointno & UE_ADDR;
136455e76c21SAndrew Thompson nframes = (AVR32_READ_4(sc, AVR32_FNUM) / 8);
136555e76c21SAndrew Thompson
13668fc2a3c4SHans Petter Selasky if (usbd_xfer_get_isochronous_start_frame(
13678fc2a3c4SHans Petter Selasky xfer, nframes, 0, 1, AVR32_FRAME_MASK, NULL))
13682e141748SHans Petter Selasky DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
136955e76c21SAndrew Thompson
137055e76c21SAndrew Thompson /* setup TDs */
137155e76c21SAndrew Thompson avr32dci_setup_standard_chain(xfer);
137255e76c21SAndrew Thompson }
137355e76c21SAndrew Thompson
137455e76c21SAndrew Thompson static void
avr32dci_device_isoc_fs_start(struct usb_xfer * xfer)1375760bc48eSAndrew Thompson avr32dci_device_isoc_fs_start(struct usb_xfer *xfer)
137655e76c21SAndrew Thompson {
137755e76c21SAndrew Thompson /* start TD chain */
137855e76c21SAndrew Thompson avr32dci_start_standard_chain(xfer);
137955e76c21SAndrew Thompson }
138055e76c21SAndrew Thompson
1381e892b3feSHans Petter Selasky static const struct usb_pipe_methods avr32dci_device_isoc_fs_methods =
138255e76c21SAndrew Thompson {
138355e76c21SAndrew Thompson .open = avr32dci_device_isoc_fs_open,
138455e76c21SAndrew Thompson .close = avr32dci_device_isoc_fs_close,
138555e76c21SAndrew Thompson .enter = avr32dci_device_isoc_fs_enter,
138655e76c21SAndrew Thompson .start = avr32dci_device_isoc_fs_start,
138755e76c21SAndrew Thompson };
138855e76c21SAndrew Thompson
138955e76c21SAndrew Thompson /*------------------------------------------------------------------------*
139040ba168dSHans Petter Selasky * avr32dci root control support
139155e76c21SAndrew Thompson *------------------------------------------------------------------------*
139255e76c21SAndrew Thompson * Simulate a hardware HUB by handling all the necessary requests.
139355e76c21SAndrew Thompson *------------------------------------------------------------------------*/
139455e76c21SAndrew Thompson
1395760bc48eSAndrew Thompson static const struct usb_device_descriptor avr32dci_devd = {
1396760bc48eSAndrew Thompson .bLength = sizeof(struct usb_device_descriptor),
139755e76c21SAndrew Thompson .bDescriptorType = UDESC_DEVICE,
139855e76c21SAndrew Thompson .bcdUSB = {0x00, 0x02},
139955e76c21SAndrew Thompson .bDeviceClass = UDCLASS_HUB,
140055e76c21SAndrew Thompson .bDeviceSubClass = UDSUBCLASS_HUB,
140155e76c21SAndrew Thompson .bDeviceProtocol = UDPROTO_HSHUBSTT,
140255e76c21SAndrew Thompson .bMaxPacketSize = 64,
140355e76c21SAndrew Thompson .bcdDevice = {0x00, 0x01},
140455e76c21SAndrew Thompson .iManufacturer = 1,
140555e76c21SAndrew Thompson .iProduct = 2,
140655e76c21SAndrew Thompson .bNumConfigurations = 1,
140755e76c21SAndrew Thompson };
140855e76c21SAndrew Thompson
1409760bc48eSAndrew Thompson static const struct usb_device_qualifier avr32dci_odevd = {
1410760bc48eSAndrew Thompson .bLength = sizeof(struct usb_device_qualifier),
141155e76c21SAndrew Thompson .bDescriptorType = UDESC_DEVICE_QUALIFIER,
141255e76c21SAndrew Thompson .bcdUSB = {0x00, 0x02},
141355e76c21SAndrew Thompson .bDeviceClass = UDCLASS_HUB,
141455e76c21SAndrew Thompson .bDeviceSubClass = UDSUBCLASS_HUB,
141555e76c21SAndrew Thompson .bDeviceProtocol = UDPROTO_FSHUB,
141655e76c21SAndrew Thompson .bMaxPacketSize0 = 0,
141755e76c21SAndrew Thompson .bNumConfigurations = 0,
141855e76c21SAndrew Thompson };
141955e76c21SAndrew Thompson
142055e76c21SAndrew Thompson static const struct avr32dci_config_desc avr32dci_confd = {
142155e76c21SAndrew Thompson .confd = {
1422760bc48eSAndrew Thompson .bLength = sizeof(struct usb_config_descriptor),
142355e76c21SAndrew Thompson .bDescriptorType = UDESC_CONFIG,
142455e76c21SAndrew Thompson .wTotalLength[0] = sizeof(avr32dci_confd),
142555e76c21SAndrew Thompson .bNumInterface = 1,
142655e76c21SAndrew Thompson .bConfigurationValue = 1,
142755e76c21SAndrew Thompson .iConfiguration = 0,
142855e76c21SAndrew Thompson .bmAttributes = UC_SELF_POWERED,
142955e76c21SAndrew Thompson .bMaxPower = 0,
143055e76c21SAndrew Thompson },
143155e76c21SAndrew Thompson .ifcd = {
1432760bc48eSAndrew Thompson .bLength = sizeof(struct usb_interface_descriptor),
143355e76c21SAndrew Thompson .bDescriptorType = UDESC_INTERFACE,
143455e76c21SAndrew Thompson .bNumEndpoints = 1,
143555e76c21SAndrew Thompson .bInterfaceClass = UICLASS_HUB,
143655e76c21SAndrew Thompson .bInterfaceSubClass = UISUBCLASS_HUB,
14373b6f59eeSHans Petter Selasky .bInterfaceProtocol = 0,
143855e76c21SAndrew Thompson },
143955e76c21SAndrew Thompson .endpd = {
1440760bc48eSAndrew Thompson .bLength = sizeof(struct usb_endpoint_descriptor),
144155e76c21SAndrew Thompson .bDescriptorType = UDESC_ENDPOINT,
144255e76c21SAndrew Thompson .bEndpointAddress = (UE_DIR_IN | AVR32_INTR_ENDPT),
144355e76c21SAndrew Thompson .bmAttributes = UE_INTERRUPT,
144455e76c21SAndrew Thompson .wMaxPacketSize[0] = 8,
144555e76c21SAndrew Thompson .bInterval = 255,
144655e76c21SAndrew Thompson },
144755e76c21SAndrew Thompson };
14486d917491SHans Petter Selasky #define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
14496d917491SHans Petter Selasky
1450760bc48eSAndrew Thompson static const struct usb_hub_descriptor_min avr32dci_hubd = {
145155e76c21SAndrew Thompson .bDescLength = sizeof(avr32dci_hubd),
145255e76c21SAndrew Thompson .bDescriptorType = UDESC_HUB,
145355e76c21SAndrew Thompson .bNbrPorts = 1,
14546d917491SHans Petter Selasky HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)),
145555e76c21SAndrew Thompson .bPwrOn2PwrGood = 50,
145655e76c21SAndrew Thompson .bHubContrCurrent = 0,
145755e76c21SAndrew Thompson .DeviceRemovable = {0}, /* port is removable */
145855e76c21SAndrew Thompson };
145955e76c21SAndrew Thompson
146055e76c21SAndrew Thompson #define STRING_VENDOR \
1461b51875c9SHans Petter Selasky "A\0V\0R\0003\0002"
146255e76c21SAndrew Thompson
146355e76c21SAndrew Thompson #define STRING_PRODUCT \
1464b51875c9SHans Petter Selasky "D\0C\0I\0 \0R\0o\0o\0t\0 \0H\0U\0B"
146555e76c21SAndrew Thompson
146655e76c21SAndrew Thompson USB_MAKE_STRING_DESC(STRING_VENDOR, avr32dci_vendor);
146755e76c21SAndrew Thompson USB_MAKE_STRING_DESC(STRING_PRODUCT, avr32dci_product);
146855e76c21SAndrew Thompson
1469e0a69b51SAndrew Thompson static usb_error_t
avr32dci_roothub_exec(struct usb_device * udev,struct usb_device_request * req,const void ** pptr,uint16_t * plength)1470760bc48eSAndrew Thompson avr32dci_roothub_exec(struct usb_device *udev,
1471760bc48eSAndrew Thompson struct usb_device_request *req, const void **pptr, uint16_t *plength)
147255e76c21SAndrew Thompson {
147355e76c21SAndrew Thompson struct avr32dci_softc *sc = AVR32_BUS2SC(udev->bus);
147455e76c21SAndrew Thompson const void *ptr;
147555e76c21SAndrew Thompson uint16_t len;
147655e76c21SAndrew Thompson uint16_t value;
147755e76c21SAndrew Thompson uint16_t index;
147855e76c21SAndrew Thompson uint32_t temp;
1479e0a69b51SAndrew Thompson usb_error_t err;
148055e76c21SAndrew Thompson
148155e76c21SAndrew Thompson USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
148255e76c21SAndrew Thompson
148355e76c21SAndrew Thompson /* buffer reset */
148455e76c21SAndrew Thompson ptr = (const void *)&sc->sc_hub_temp;
148555e76c21SAndrew Thompson len = 0;
148655e76c21SAndrew Thompson err = 0;
148755e76c21SAndrew Thompson
148855e76c21SAndrew Thompson value = UGETW(req->wValue);
148955e76c21SAndrew Thompson index = UGETW(req->wIndex);
149055e76c21SAndrew Thompson
149155e76c21SAndrew Thompson /* demultiplex the control request */
149255e76c21SAndrew Thompson
149355e76c21SAndrew Thompson switch (req->bmRequestType) {
149455e76c21SAndrew Thompson case UT_READ_DEVICE:
149555e76c21SAndrew Thompson switch (req->bRequest) {
149655e76c21SAndrew Thompson case UR_GET_DESCRIPTOR:
149755e76c21SAndrew Thompson goto tr_handle_get_descriptor;
149855e76c21SAndrew Thompson case UR_GET_CONFIG:
149955e76c21SAndrew Thompson goto tr_handle_get_config;
150055e76c21SAndrew Thompson case UR_GET_STATUS:
150155e76c21SAndrew Thompson goto tr_handle_get_status;
150255e76c21SAndrew Thompson default:
150355e76c21SAndrew Thompson goto tr_stalled;
150455e76c21SAndrew Thompson }
150555e76c21SAndrew Thompson break;
150655e76c21SAndrew Thompson
150755e76c21SAndrew Thompson case UT_WRITE_DEVICE:
150855e76c21SAndrew Thompson switch (req->bRequest) {
150955e76c21SAndrew Thompson case UR_SET_ADDRESS:
151055e76c21SAndrew Thompson goto tr_handle_set_address;
151155e76c21SAndrew Thompson case UR_SET_CONFIG:
151255e76c21SAndrew Thompson goto tr_handle_set_config;
151355e76c21SAndrew Thompson case UR_CLEAR_FEATURE:
151455e76c21SAndrew Thompson goto tr_valid; /* nop */
151555e76c21SAndrew Thompson case UR_SET_DESCRIPTOR:
151655e76c21SAndrew Thompson goto tr_valid; /* nop */
151755e76c21SAndrew Thompson case UR_SET_FEATURE:
151855e76c21SAndrew Thompson default:
151955e76c21SAndrew Thompson goto tr_stalled;
152055e76c21SAndrew Thompson }
152155e76c21SAndrew Thompson break;
152255e76c21SAndrew Thompson
152355e76c21SAndrew Thompson case UT_WRITE_ENDPOINT:
152455e76c21SAndrew Thompson switch (req->bRequest) {
152555e76c21SAndrew Thompson case UR_CLEAR_FEATURE:
152655e76c21SAndrew Thompson switch (UGETW(req->wValue)) {
152755e76c21SAndrew Thompson case UF_ENDPOINT_HALT:
152855e76c21SAndrew Thompson goto tr_handle_clear_halt;
152955e76c21SAndrew Thompson case UF_DEVICE_REMOTE_WAKEUP:
153055e76c21SAndrew Thompson goto tr_handle_clear_wakeup;
153155e76c21SAndrew Thompson default:
153255e76c21SAndrew Thompson goto tr_stalled;
153355e76c21SAndrew Thompson }
153455e76c21SAndrew Thompson break;
153555e76c21SAndrew Thompson case UR_SET_FEATURE:
153655e76c21SAndrew Thompson switch (UGETW(req->wValue)) {
153755e76c21SAndrew Thompson case UF_ENDPOINT_HALT:
153855e76c21SAndrew Thompson goto tr_handle_set_halt;
153955e76c21SAndrew Thompson case UF_DEVICE_REMOTE_WAKEUP:
154055e76c21SAndrew Thompson goto tr_handle_set_wakeup;
154155e76c21SAndrew Thompson default:
154255e76c21SAndrew Thompson goto tr_stalled;
154355e76c21SAndrew Thompson }
154455e76c21SAndrew Thompson break;
154555e76c21SAndrew Thompson case UR_SYNCH_FRAME:
154655e76c21SAndrew Thompson goto tr_valid; /* nop */
154755e76c21SAndrew Thompson default:
154855e76c21SAndrew Thompson goto tr_stalled;
154955e76c21SAndrew Thompson }
155055e76c21SAndrew Thompson break;
155155e76c21SAndrew Thompson
155255e76c21SAndrew Thompson case UT_READ_ENDPOINT:
155355e76c21SAndrew Thompson switch (req->bRequest) {
155455e76c21SAndrew Thompson case UR_GET_STATUS:
155555e76c21SAndrew Thompson goto tr_handle_get_ep_status;
155655e76c21SAndrew Thompson default:
155755e76c21SAndrew Thompson goto tr_stalled;
155855e76c21SAndrew Thompson }
155955e76c21SAndrew Thompson break;
156055e76c21SAndrew Thompson
156155e76c21SAndrew Thompson case UT_WRITE_INTERFACE:
156255e76c21SAndrew Thompson switch (req->bRequest) {
156355e76c21SAndrew Thompson case UR_SET_INTERFACE:
156455e76c21SAndrew Thompson goto tr_handle_set_interface;
156555e76c21SAndrew Thompson case UR_CLEAR_FEATURE:
156655e76c21SAndrew Thompson goto tr_valid; /* nop */
156755e76c21SAndrew Thompson case UR_SET_FEATURE:
156855e76c21SAndrew Thompson default:
156955e76c21SAndrew Thompson goto tr_stalled;
157055e76c21SAndrew Thompson }
157155e76c21SAndrew Thompson break;
157255e76c21SAndrew Thompson
157355e76c21SAndrew Thompson case UT_READ_INTERFACE:
157455e76c21SAndrew Thompson switch (req->bRequest) {
157555e76c21SAndrew Thompson case UR_GET_INTERFACE:
157655e76c21SAndrew Thompson goto tr_handle_get_interface;
157755e76c21SAndrew Thompson case UR_GET_STATUS:
157855e76c21SAndrew Thompson goto tr_handle_get_iface_status;
157955e76c21SAndrew Thompson default:
158055e76c21SAndrew Thompson goto tr_stalled;
158155e76c21SAndrew Thompson }
158255e76c21SAndrew Thompson break;
158355e76c21SAndrew Thompson
158455e76c21SAndrew Thompson case UT_WRITE_CLASS_INTERFACE:
158555e76c21SAndrew Thompson case UT_WRITE_VENDOR_INTERFACE:
158655e76c21SAndrew Thompson /* XXX forward */
158755e76c21SAndrew Thompson break;
158855e76c21SAndrew Thompson
158955e76c21SAndrew Thompson case UT_READ_CLASS_INTERFACE:
159055e76c21SAndrew Thompson case UT_READ_VENDOR_INTERFACE:
159155e76c21SAndrew Thompson /* XXX forward */
159255e76c21SAndrew Thompson break;
159355e76c21SAndrew Thompson
159455e76c21SAndrew Thompson case UT_WRITE_CLASS_DEVICE:
159555e76c21SAndrew Thompson switch (req->bRequest) {
159655e76c21SAndrew Thompson case UR_CLEAR_FEATURE:
159755e76c21SAndrew Thompson goto tr_valid;
159855e76c21SAndrew Thompson case UR_SET_DESCRIPTOR:
159955e76c21SAndrew Thompson case UR_SET_FEATURE:
160055e76c21SAndrew Thompson break;
160155e76c21SAndrew Thompson default:
160255e76c21SAndrew Thompson goto tr_stalled;
160355e76c21SAndrew Thompson }
160455e76c21SAndrew Thompson break;
160555e76c21SAndrew Thompson
160655e76c21SAndrew Thompson case UT_WRITE_CLASS_OTHER:
160755e76c21SAndrew Thompson switch (req->bRequest) {
160855e76c21SAndrew Thompson case UR_CLEAR_FEATURE:
160955e76c21SAndrew Thompson goto tr_handle_clear_port_feature;
161055e76c21SAndrew Thompson case UR_SET_FEATURE:
161155e76c21SAndrew Thompson goto tr_handle_set_port_feature;
161255e76c21SAndrew Thompson case UR_CLEAR_TT_BUFFER:
161355e76c21SAndrew Thompson case UR_RESET_TT:
161455e76c21SAndrew Thompson case UR_STOP_TT:
161555e76c21SAndrew Thompson goto tr_valid;
161655e76c21SAndrew Thompson
161755e76c21SAndrew Thompson default:
161855e76c21SAndrew Thompson goto tr_stalled;
161955e76c21SAndrew Thompson }
162055e76c21SAndrew Thompson break;
162155e76c21SAndrew Thompson
162255e76c21SAndrew Thompson case UT_READ_CLASS_OTHER:
162355e76c21SAndrew Thompson switch (req->bRequest) {
162455e76c21SAndrew Thompson case UR_GET_TT_STATE:
162555e76c21SAndrew Thompson goto tr_handle_get_tt_state;
162655e76c21SAndrew Thompson case UR_GET_STATUS:
162755e76c21SAndrew Thompson goto tr_handle_get_port_status;
162855e76c21SAndrew Thompson default:
162955e76c21SAndrew Thompson goto tr_stalled;
163055e76c21SAndrew Thompson }
163155e76c21SAndrew Thompson break;
163255e76c21SAndrew Thompson
163355e76c21SAndrew Thompson case UT_READ_CLASS_DEVICE:
163455e76c21SAndrew Thompson switch (req->bRequest) {
163555e76c21SAndrew Thompson case UR_GET_DESCRIPTOR:
163655e76c21SAndrew Thompson goto tr_handle_get_class_descriptor;
163755e76c21SAndrew Thompson case UR_GET_STATUS:
163855e76c21SAndrew Thompson goto tr_handle_get_class_status;
163955e76c21SAndrew Thompson
164055e76c21SAndrew Thompson default:
164155e76c21SAndrew Thompson goto tr_stalled;
164255e76c21SAndrew Thompson }
164355e76c21SAndrew Thompson break;
164455e76c21SAndrew Thompson default:
164555e76c21SAndrew Thompson goto tr_stalled;
164655e76c21SAndrew Thompson }
164755e76c21SAndrew Thompson goto tr_valid;
164855e76c21SAndrew Thompson
164955e76c21SAndrew Thompson tr_handle_get_descriptor:
165055e76c21SAndrew Thompson switch (value >> 8) {
165155e76c21SAndrew Thompson case UDESC_DEVICE:
165255e76c21SAndrew Thompson if (value & 0xff) {
165355e76c21SAndrew Thompson goto tr_stalled;
165455e76c21SAndrew Thompson }
165555e76c21SAndrew Thompson len = sizeof(avr32dci_devd);
165655e76c21SAndrew Thompson ptr = (const void *)&avr32dci_devd;
165755e76c21SAndrew Thompson goto tr_valid;
16583f505486SHans Petter Selasky case UDESC_DEVICE_QUALIFIER:
16593f505486SHans Petter Selasky if (value & 0xff)
16603f505486SHans Petter Selasky goto tr_stalled;
16613f505486SHans Petter Selasky len = sizeof(avr32dci_odevd);
16623f505486SHans Petter Selasky ptr = (const void *)&avr32dci_odevd;
16633f505486SHans Petter Selasky goto tr_valid;
166455e76c21SAndrew Thompson case UDESC_CONFIG:
166555e76c21SAndrew Thompson if (value & 0xff) {
166655e76c21SAndrew Thompson goto tr_stalled;
166755e76c21SAndrew Thompson }
166855e76c21SAndrew Thompson len = sizeof(avr32dci_confd);
166955e76c21SAndrew Thompson ptr = (const void *)&avr32dci_confd;
167055e76c21SAndrew Thompson goto tr_valid;
167155e76c21SAndrew Thompson case UDESC_STRING:
167255e76c21SAndrew Thompson switch (value & 0xff) {
167355e76c21SAndrew Thompson case 0: /* Language table */
167423ab0871SHans Petter Selasky len = sizeof(usb_string_lang_en);
167523ab0871SHans Petter Selasky ptr = (const void *)&usb_string_lang_en;
167655e76c21SAndrew Thompson goto tr_valid;
167755e76c21SAndrew Thompson
167855e76c21SAndrew Thompson case 1: /* Vendor */
167955e76c21SAndrew Thompson len = sizeof(avr32dci_vendor);
168055e76c21SAndrew Thompson ptr = (const void *)&avr32dci_vendor;
168155e76c21SAndrew Thompson goto tr_valid;
168255e76c21SAndrew Thompson
168355e76c21SAndrew Thompson case 2: /* Product */
168455e76c21SAndrew Thompson len = sizeof(avr32dci_product);
168555e76c21SAndrew Thompson ptr = (const void *)&avr32dci_product;
168655e76c21SAndrew Thompson goto tr_valid;
168755e76c21SAndrew Thompson default:
168855e76c21SAndrew Thompson break;
168955e76c21SAndrew Thompson }
169055e76c21SAndrew Thompson break;
169155e76c21SAndrew Thompson default:
169255e76c21SAndrew Thompson goto tr_stalled;
169355e76c21SAndrew Thompson }
169455e76c21SAndrew Thompson goto tr_stalled;
169555e76c21SAndrew Thompson
169655e76c21SAndrew Thompson tr_handle_get_config:
169755e76c21SAndrew Thompson len = 1;
169855e76c21SAndrew Thompson sc->sc_hub_temp.wValue[0] = sc->sc_conf;
169955e76c21SAndrew Thompson goto tr_valid;
170055e76c21SAndrew Thompson
170155e76c21SAndrew Thompson tr_handle_get_status:
170255e76c21SAndrew Thompson len = 2;
170355e76c21SAndrew Thompson USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED);
170455e76c21SAndrew Thompson goto tr_valid;
170555e76c21SAndrew Thompson
170655e76c21SAndrew Thompson tr_handle_set_address:
170755e76c21SAndrew Thompson if (value & 0xFF00) {
170855e76c21SAndrew Thompson goto tr_stalled;
170955e76c21SAndrew Thompson }
171055e76c21SAndrew Thompson sc->sc_rt_addr = value;
171155e76c21SAndrew Thompson goto tr_valid;
171255e76c21SAndrew Thompson
171355e76c21SAndrew Thompson tr_handle_set_config:
171455e76c21SAndrew Thompson if (value >= 2) {
171555e76c21SAndrew Thompson goto tr_stalled;
171655e76c21SAndrew Thompson }
171755e76c21SAndrew Thompson sc->sc_conf = value;
171855e76c21SAndrew Thompson goto tr_valid;
171955e76c21SAndrew Thompson
172055e76c21SAndrew Thompson tr_handle_get_interface:
172155e76c21SAndrew Thompson len = 1;
172255e76c21SAndrew Thompson sc->sc_hub_temp.wValue[0] = 0;
172355e76c21SAndrew Thompson goto tr_valid;
172455e76c21SAndrew Thompson
172555e76c21SAndrew Thompson tr_handle_get_tt_state:
172655e76c21SAndrew Thompson tr_handle_get_class_status:
172755e76c21SAndrew Thompson tr_handle_get_iface_status:
172855e76c21SAndrew Thompson tr_handle_get_ep_status:
172955e76c21SAndrew Thompson len = 2;
173055e76c21SAndrew Thompson USETW(sc->sc_hub_temp.wValue, 0);
173155e76c21SAndrew Thompson goto tr_valid;
173255e76c21SAndrew Thompson
173355e76c21SAndrew Thompson tr_handle_set_halt:
173455e76c21SAndrew Thompson tr_handle_set_interface:
173555e76c21SAndrew Thompson tr_handle_set_wakeup:
173655e76c21SAndrew Thompson tr_handle_clear_wakeup:
173755e76c21SAndrew Thompson tr_handle_clear_halt:
173855e76c21SAndrew Thompson goto tr_valid;
173955e76c21SAndrew Thompson
174055e76c21SAndrew Thompson tr_handle_clear_port_feature:
174155e76c21SAndrew Thompson if (index != 1) {
174255e76c21SAndrew Thompson goto tr_stalled;
174355e76c21SAndrew Thompson }
174455e76c21SAndrew Thompson DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index);
174555e76c21SAndrew Thompson
174655e76c21SAndrew Thompson switch (value) {
174755e76c21SAndrew Thompson case UHF_PORT_SUSPEND:
174855e76c21SAndrew Thompson avr32dci_wakeup_peer(sc);
174955e76c21SAndrew Thompson break;
175055e76c21SAndrew Thompson
175155e76c21SAndrew Thompson case UHF_PORT_ENABLE:
175255e76c21SAndrew Thompson sc->sc_flags.port_enabled = 0;
175355e76c21SAndrew Thompson break;
175455e76c21SAndrew Thompson
175555e76c21SAndrew Thompson case UHF_PORT_TEST:
175655e76c21SAndrew Thompson case UHF_PORT_INDICATOR:
175755e76c21SAndrew Thompson case UHF_C_PORT_ENABLE:
175855e76c21SAndrew Thompson case UHF_C_PORT_OVER_CURRENT:
175955e76c21SAndrew Thompson case UHF_C_PORT_RESET:
176055e76c21SAndrew Thompson /* nops */
176155e76c21SAndrew Thompson break;
176255e76c21SAndrew Thompson case UHF_PORT_POWER:
176355e76c21SAndrew Thompson sc->sc_flags.port_powered = 0;
176455e76c21SAndrew Thompson avr32dci_pull_down(sc);
176555e76c21SAndrew Thompson avr32dci_clocks_off(sc);
176655e76c21SAndrew Thompson break;
176755e76c21SAndrew Thompson case UHF_C_PORT_CONNECTION:
176855e76c21SAndrew Thompson /* clear connect change flag */
176955e76c21SAndrew Thompson sc->sc_flags.change_connect = 0;
177055e76c21SAndrew Thompson
177155e76c21SAndrew Thompson if (!sc->sc_flags.status_bus_reset) {
177255e76c21SAndrew Thompson /* we are not connected */
177355e76c21SAndrew Thompson break;
177455e76c21SAndrew Thompson }
177555e76c21SAndrew Thompson /* configure the control endpoint */
177655e76c21SAndrew Thompson /* set endpoint reset */
177755e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTRST, AVR32_EPTRST_MASK(0));
177855e76c21SAndrew Thompson
177955e76c21SAndrew Thompson /* set stall */
178055e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTSETSTA(0), AVR32_EPTSTA_FRCESTALL);
178155e76c21SAndrew Thompson
178255e76c21SAndrew Thompson /* reset data toggle */
178355e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(0), AVR32_EPTSTA_TOGGLESQ);
178455e76c21SAndrew Thompson
178555e76c21SAndrew Thompson /* clear stall */
178655e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(0), AVR32_EPTSTA_FRCESTALL);
178755e76c21SAndrew Thompson
178855e76c21SAndrew Thompson /* configure */
17892e141748SHans Petter Selasky AVR32_WRITE_4(sc, AVR32_EPTCFG(0), AVR32_EPTCFG_TYPE_CTRL |
179055e76c21SAndrew Thompson AVR32_EPTCFG_NBANK(1) | AVR32_EPTCFG_EPSIZE(6));
179155e76c21SAndrew Thompson
179255e76c21SAndrew Thompson temp = AVR32_READ_4(sc, AVR32_EPTCFG(0));
179355e76c21SAndrew Thompson
179455e76c21SAndrew Thompson if (!(temp & AVR32_EPTCFG_EPT_MAPD)) {
1795767cb2e2SAndrew Thompson device_printf(sc->sc_bus.bdev,
1796767cb2e2SAndrew Thompson "Chip rejected configuration\n");
179755e76c21SAndrew Thompson } else {
179855e76c21SAndrew Thompson AVR32_WRITE_4(sc, AVR32_EPTCTLENB(0),
179955e76c21SAndrew Thompson AVR32_EPTCTL_EPT_ENABL);
180055e76c21SAndrew Thompson }
180155e76c21SAndrew Thompson break;
180255e76c21SAndrew Thompson case UHF_C_PORT_SUSPEND:
180355e76c21SAndrew Thompson sc->sc_flags.change_suspend = 0;
180455e76c21SAndrew Thompson break;
180555e76c21SAndrew Thompson default:
180655e76c21SAndrew Thompson err = USB_ERR_IOERROR;
180755e76c21SAndrew Thompson goto done;
180855e76c21SAndrew Thompson }
180955e76c21SAndrew Thompson goto tr_valid;
181055e76c21SAndrew Thompson
181155e76c21SAndrew Thompson tr_handle_set_port_feature:
181255e76c21SAndrew Thompson if (index != 1) {
181355e76c21SAndrew Thompson goto tr_stalled;
181455e76c21SAndrew Thompson }
181555e76c21SAndrew Thompson DPRINTFN(9, "UR_SET_PORT_FEATURE\n");
181655e76c21SAndrew Thompson
181755e76c21SAndrew Thompson switch (value) {
181855e76c21SAndrew Thompson case UHF_PORT_ENABLE:
181955e76c21SAndrew Thompson sc->sc_flags.port_enabled = 1;
182055e76c21SAndrew Thompson break;
182155e76c21SAndrew Thompson case UHF_PORT_SUSPEND:
182255e76c21SAndrew Thompson case UHF_PORT_RESET:
182355e76c21SAndrew Thompson case UHF_PORT_TEST:
182455e76c21SAndrew Thompson case UHF_PORT_INDICATOR:
182555e76c21SAndrew Thompson /* nops */
182655e76c21SAndrew Thompson break;
182755e76c21SAndrew Thompson case UHF_PORT_POWER:
182855e76c21SAndrew Thompson sc->sc_flags.port_powered = 1;
182955e76c21SAndrew Thompson break;
183055e76c21SAndrew Thompson default:
183155e76c21SAndrew Thompson err = USB_ERR_IOERROR;
183255e76c21SAndrew Thompson goto done;
183355e76c21SAndrew Thompson }
183455e76c21SAndrew Thompson goto tr_valid;
183555e76c21SAndrew Thompson
183655e76c21SAndrew Thompson tr_handle_get_port_status:
183755e76c21SAndrew Thompson
183855e76c21SAndrew Thompson DPRINTFN(9, "UR_GET_PORT_STATUS\n");
183955e76c21SAndrew Thompson
184055e76c21SAndrew Thompson if (index != 1) {
184155e76c21SAndrew Thompson goto tr_stalled;
184255e76c21SAndrew Thompson }
184355e76c21SAndrew Thompson if (sc->sc_flags.status_vbus) {
184455e76c21SAndrew Thompson avr32dci_clocks_on(sc);
184555e76c21SAndrew Thompson avr32dci_pull_up(sc);
184655e76c21SAndrew Thompson } else {
184755e76c21SAndrew Thompson avr32dci_pull_down(sc);
184855e76c21SAndrew Thompson avr32dci_clocks_off(sc);
184955e76c21SAndrew Thompson }
185055e76c21SAndrew Thompson
185155e76c21SAndrew Thompson /* Select Device Side Mode */
185255e76c21SAndrew Thompson
185355e76c21SAndrew Thompson value = UPS_PORT_MODE_DEVICE;
185455e76c21SAndrew Thompson
185555e76c21SAndrew Thompson /* Check for High Speed */
185655e76c21SAndrew Thompson if (AVR32_READ_4(sc, AVR32_INTSTA) & AVR32_INT_SPEED)
185755e76c21SAndrew Thompson value |= UPS_HIGH_SPEED;
185855e76c21SAndrew Thompson
185955e76c21SAndrew Thompson if (sc->sc_flags.port_powered) {
186055e76c21SAndrew Thompson value |= UPS_PORT_POWER;
186155e76c21SAndrew Thompson }
186255e76c21SAndrew Thompson if (sc->sc_flags.port_enabled) {
186355e76c21SAndrew Thompson value |= UPS_PORT_ENABLED;
186455e76c21SAndrew Thompson }
186555e76c21SAndrew Thompson if (sc->sc_flags.status_vbus &&
186655e76c21SAndrew Thompson sc->sc_flags.status_bus_reset) {
186755e76c21SAndrew Thompson value |= UPS_CURRENT_CONNECT_STATUS;
186855e76c21SAndrew Thompson }
186955e76c21SAndrew Thompson if (sc->sc_flags.status_suspend) {
187055e76c21SAndrew Thompson value |= UPS_SUSPEND;
187155e76c21SAndrew Thompson }
187255e76c21SAndrew Thompson USETW(sc->sc_hub_temp.ps.wPortStatus, value);
187355e76c21SAndrew Thompson
187455e76c21SAndrew Thompson value = 0;
187555e76c21SAndrew Thompson
187655e76c21SAndrew Thompson if (sc->sc_flags.change_connect) {
187755e76c21SAndrew Thompson value |= UPS_C_CONNECT_STATUS;
187855e76c21SAndrew Thompson }
187955e76c21SAndrew Thompson if (sc->sc_flags.change_suspend) {
188055e76c21SAndrew Thompson value |= UPS_C_SUSPEND;
188155e76c21SAndrew Thompson }
188255e76c21SAndrew Thompson USETW(sc->sc_hub_temp.ps.wPortChange, value);
188355e76c21SAndrew Thompson len = sizeof(sc->sc_hub_temp.ps);
188455e76c21SAndrew Thompson goto tr_valid;
188555e76c21SAndrew Thompson
188655e76c21SAndrew Thompson tr_handle_get_class_descriptor:
188755e76c21SAndrew Thompson if (value & 0xFF) {
188855e76c21SAndrew Thompson goto tr_stalled;
188955e76c21SAndrew Thompson }
189055e76c21SAndrew Thompson ptr = (const void *)&avr32dci_hubd;
189155e76c21SAndrew Thompson len = sizeof(avr32dci_hubd);
189255e76c21SAndrew Thompson goto tr_valid;
189355e76c21SAndrew Thompson
189455e76c21SAndrew Thompson tr_stalled:
189555e76c21SAndrew Thompson err = USB_ERR_STALLED;
189655e76c21SAndrew Thompson tr_valid:
189755e76c21SAndrew Thompson done:
189855e76c21SAndrew Thompson *plength = len;
189955e76c21SAndrew Thompson *pptr = ptr;
190055e76c21SAndrew Thompson return (err);
190155e76c21SAndrew Thompson }
190255e76c21SAndrew Thompson
190355e76c21SAndrew Thompson static void
avr32dci_xfer_setup(struct usb_setup_params * parm)1904760bc48eSAndrew Thompson avr32dci_xfer_setup(struct usb_setup_params *parm)
190555e76c21SAndrew Thompson {
1906760bc48eSAndrew Thompson const struct usb_hw_ep_profile *pf;
190755e76c21SAndrew Thompson struct avr32dci_softc *sc;
1908760bc48eSAndrew Thompson struct usb_xfer *xfer;
190955e76c21SAndrew Thompson void *last_obj;
191055e76c21SAndrew Thompson uint32_t ntd;
191155e76c21SAndrew Thompson uint32_t n;
191255e76c21SAndrew Thompson uint8_t ep_no;
191355e76c21SAndrew Thompson
191455e76c21SAndrew Thompson sc = AVR32_BUS2SC(parm->udev->bus);
191555e76c21SAndrew Thompson xfer = parm->curr_xfer;
191655e76c21SAndrew Thompson
191755e76c21SAndrew Thompson /*
191855e76c21SAndrew Thompson * NOTE: This driver does not use any of the parameters that
191955e76c21SAndrew Thompson * are computed from the following values. Just set some
192055e76c21SAndrew Thompson * reasonable dummies:
192155e76c21SAndrew Thompson */
192255e76c21SAndrew Thompson parm->hc_max_packet_size = 0x400;
192355e76c21SAndrew Thompson parm->hc_max_packet_count = 1;
192455e76c21SAndrew Thompson parm->hc_max_frame_size = 0x400;
192555e76c21SAndrew Thompson
1926a593f6b8SAndrew Thompson usbd_transfer_setup_sub(parm);
192755e76c21SAndrew Thompson
192855e76c21SAndrew Thompson /*
192955e76c21SAndrew Thompson * compute maximum number of TDs
193055e76c21SAndrew Thompson */
19312e141748SHans Petter Selasky if ((xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) {
193255e76c21SAndrew Thompson ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */
193355e76c21SAndrew Thompson + 1 /* SYNC 2 */ ;
193455e76c21SAndrew Thompson } else {
193555e76c21SAndrew Thompson ntd = xfer->nframes + 1 /* SYNC */ ;
193655e76c21SAndrew Thompson }
193755e76c21SAndrew Thompson
193855e76c21SAndrew Thompson /*
1939a593f6b8SAndrew Thompson * check if "usbd_transfer_setup_sub" set an error
194055e76c21SAndrew Thompson */
194155e76c21SAndrew Thompson if (parm->err)
194255e76c21SAndrew Thompson return;
194355e76c21SAndrew Thompson
194455e76c21SAndrew Thompson /*
194555e76c21SAndrew Thompson * allocate transfer descriptors
194655e76c21SAndrew Thompson */
194755e76c21SAndrew Thompson last_obj = NULL;
194855e76c21SAndrew Thompson
194955e76c21SAndrew Thompson /*
195055e76c21SAndrew Thompson * get profile stuff
195155e76c21SAndrew Thompson */
19522e141748SHans Petter Selasky ep_no = xfer->endpointno & UE_ADDR;
195355e76c21SAndrew Thompson avr32dci_get_hw_ep_profile(parm->udev, &pf, ep_no);
195455e76c21SAndrew Thompson
195555e76c21SAndrew Thompson if (pf == NULL) {
195655e76c21SAndrew Thompson /* should not happen */
195755e76c21SAndrew Thompson parm->err = USB_ERR_INVAL;
195855e76c21SAndrew Thompson return;
195955e76c21SAndrew Thompson }
196055e76c21SAndrew Thompson /* align data */
196155e76c21SAndrew Thompson parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
196255e76c21SAndrew Thompson
196355e76c21SAndrew Thompson for (n = 0; n != ntd; n++) {
196455e76c21SAndrew Thompson struct avr32dci_td *td;
196555e76c21SAndrew Thompson
196655e76c21SAndrew Thompson if (parm->buf) {
196755e76c21SAndrew Thompson uint32_t temp;
196855e76c21SAndrew Thompson
196955e76c21SAndrew Thompson td = USB_ADD_BYTES(parm->buf, parm->size[0]);
197055e76c21SAndrew Thompson
197155e76c21SAndrew Thompson /* init TD */
197255e76c21SAndrew Thompson td->max_packet_size = xfer->max_packet_size;
197355e76c21SAndrew Thompson td->ep_no = ep_no;
197455e76c21SAndrew Thompson temp = pf->max_in_frame_size | pf->max_out_frame_size;
197555e76c21SAndrew Thompson td->bank_shift = 0;
197655e76c21SAndrew Thompson while ((temp /= 2))
197755e76c21SAndrew Thompson td->bank_shift++;
197855e76c21SAndrew Thompson if (pf->support_multi_buffer) {
197955e76c21SAndrew Thompson td->support_multi_buffer = 1;
198055e76c21SAndrew Thompson }
198155e76c21SAndrew Thompson td->obj_next = last_obj;
198255e76c21SAndrew Thompson
198355e76c21SAndrew Thompson last_obj = td;
198455e76c21SAndrew Thompson }
198555e76c21SAndrew Thompson parm->size[0] += sizeof(*td);
198655e76c21SAndrew Thompson }
198755e76c21SAndrew Thompson
198855e76c21SAndrew Thompson xfer->td_start[0] = last_obj;
198955e76c21SAndrew Thompson }
199055e76c21SAndrew Thompson
199155e76c21SAndrew Thompson static void
avr32dci_xfer_unsetup(struct usb_xfer * xfer)1992760bc48eSAndrew Thompson avr32dci_xfer_unsetup(struct usb_xfer *xfer)
199355e76c21SAndrew Thompson {
199455e76c21SAndrew Thompson return;
199555e76c21SAndrew Thompson }
199655e76c21SAndrew Thompson
199755e76c21SAndrew Thompson static void
avr32dci_ep_init(struct usb_device * udev,struct usb_endpoint_descriptor * edesc,struct usb_endpoint * pipe)1998ae60fdfbSAndrew Thompson avr32dci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,
19992e141748SHans Petter Selasky struct usb_endpoint *pipe)
200055e76c21SAndrew Thompson {
200155e76c21SAndrew Thompson struct avr32dci_softc *sc = AVR32_BUS2SC(udev->bus);
200255e76c21SAndrew Thompson
200355e76c21SAndrew Thompson DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d,%d)\n",
200455e76c21SAndrew Thompson pipe, udev->address,
200555e76c21SAndrew Thompson edesc->bEndpointAddress, udev->flags.usb_mode,
200655e76c21SAndrew Thompson sc->sc_rt_addr, udev->device_index);
200755e76c21SAndrew Thompson
200855e76c21SAndrew Thompson if (udev->device_index != sc->sc_rt_addr) {
200955e76c21SAndrew Thompson if ((udev->speed != USB_SPEED_FULL) &&
201055e76c21SAndrew Thompson (udev->speed != USB_SPEED_HIGH)) {
201155e76c21SAndrew Thompson /* not supported */
201255e76c21SAndrew Thompson return;
201355e76c21SAndrew Thompson }
201455e76c21SAndrew Thompson if ((edesc->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS)
201555e76c21SAndrew Thompson pipe->methods = &avr32dci_device_isoc_fs_methods;
201655e76c21SAndrew Thompson else
201755e76c21SAndrew Thompson pipe->methods = &avr32dci_device_non_isoc_methods;
201855e76c21SAndrew Thompson }
201955e76c21SAndrew Thompson }
202055e76c21SAndrew Thompson
20212e141748SHans Petter Selasky static void
avr32dci_set_hw_power_sleep(struct usb_bus * bus,uint32_t state)20222e141748SHans Petter Selasky avr32dci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
20232e141748SHans Petter Selasky {
20242e141748SHans Petter Selasky struct avr32dci_softc *sc = AVR32_BUS2SC(bus);
20252e141748SHans Petter Selasky
20262e141748SHans Petter Selasky switch (state) {
20272e141748SHans Petter Selasky case USB_HW_POWER_SUSPEND:
20282e141748SHans Petter Selasky avr32dci_suspend(sc);
20292e141748SHans Petter Selasky break;
20302e141748SHans Petter Selasky case USB_HW_POWER_SHUTDOWN:
20312e141748SHans Petter Selasky avr32dci_uninit(sc);
20322e141748SHans Petter Selasky break;
20332e141748SHans Petter Selasky case USB_HW_POWER_RESUME:
20342e141748SHans Petter Selasky avr32dci_resume(sc);
20352e141748SHans Petter Selasky break;
20362e141748SHans Petter Selasky default:
20372e141748SHans Petter Selasky break;
20382e141748SHans Petter Selasky }
20392e141748SHans Petter Selasky }
20402e141748SHans Petter Selasky
2041e892b3feSHans Petter Selasky static const struct usb_bus_methods avr32dci_bus_methods =
204255e76c21SAndrew Thompson {
2043ae60fdfbSAndrew Thompson .endpoint_init = &avr32dci_ep_init,
204455e76c21SAndrew Thompson .xfer_setup = &avr32dci_xfer_setup,
204555e76c21SAndrew Thompson .xfer_unsetup = &avr32dci_xfer_unsetup,
204655e76c21SAndrew Thompson .get_hw_ep_profile = &avr32dci_get_hw_ep_profile,
2047a5cf1aaaSHans Petter Selasky .xfer_stall = &avr32dci_xfer_stall,
204855e76c21SAndrew Thompson .set_stall = &avr32dci_set_stall,
204955e76c21SAndrew Thompson .clear_stall = &avr32dci_clear_stall,
205055e76c21SAndrew Thompson .roothub_exec = &avr32dci_roothub_exec,
2051dddb25f9SAlfred Perlstein .xfer_poll = &avr32dci_do_poll,
20522e141748SHans Petter Selasky .set_hw_power_sleep = &avr32dci_set_hw_power_sleep,
205355e76c21SAndrew Thompson };
2054