41#ifdef USB_GLOBAL_INCLUDE_FILE
42#include USB_GLOBAL_INCLUDE_FILE
44#include <sys/stdint.h>
45#include <sys/stddef.h>
50#include <sys/kernel.h>
52#include <sys/module.h>
55#include <sys/condvar.h>
56#include <sys/sysctl.h>
58#include <sys/unistd.h>
59#include <sys/callout.h>
60#include <sys/malloc.h>
66#define USB_DEBUG_VAR uhcidebug
85#define UHCI_BUS2SC(bus) \
86 __containerof(bus, uhci_softc_t, sc_bus)
89static int uhcidebug = 0;
90static int uhcinoloop = 0;
92static SYSCTL_NODE(_hw_usb, OID_AUTO, uhci, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
95 &uhcidebug, 0,
"uhci debug level");
96SYSCTL_INT(_hw_usb_uhci, OID_AUTO, loop, CTLFLAG_RWTUN,
97 &uhcinoloop, 0,
"uhci noloop");
104#define UBARR(sc) bus_space_barrier((sc)->sc_io_tag, (sc)->sc_io_hdl, 0, (sc)->sc_io_size, \
105 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
106#define UWRITE1(sc, r, x) \
107 do { UBARR(sc); bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); \
109#define UWRITE2(sc, r, x) \
110 do { UBARR(sc); bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); \
112#define UWRITE4(sc, r, x) \
113 do { UBARR(sc); bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); \
115#define UREAD1(sc, r) (UBARR(sc), bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r)))
116#define UREAD2(sc, r) (UBARR(sc), bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r)))
117#define UREAD4(sc, r) (UBARR(sc), bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r)))
119#define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd)
120#define UHCISTS(sc) UREAD2(sc, UHCI_STS)
122#define UHCI_RESET_TIMEOUT 100
124#define UHCI_INTR_ENDPT 1
284 DPRINTFN(2,
"Already started\n");
288 DPRINTFN(2,
"Restarting\n");
307 DPRINTFN(2,
"Failed\n");
353 "controller did not reset\n");
370 "controller did not stop\n");
392 DPRINTFN(2,
"enabling\n");
404 "cannot start HC controller\n");
422 htole32(buf_res.physaddr) |
441 htole32(buf_res.physaddr) |
512 y = (x ^ bit) | (bit / 2);
709 DPRINTFN(0,
"%s regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, "
710 "flbase=%08x, sof=%04x, portsc1=%04x, portsc2=%04x\n",
742 printf(
"TD(%p) at 0x%08x = link=0x%08x status=0x%08x "
743 "token=0x%08x buffer=0x%08x\n",
751 printf(
"TD(%p) td_next=%s%s%s td_status=%s%s%s%s%s%s%s%s%s%s%s, errcnt=%d, actlen=%d pid=%02x,"
752 "addr=%d,endpt=%d,D=%d,maxlen=%d\n",
791 DPRINTFN(0,
"QH(%p) at 0x%08x: h_next=0x%08x e_next=0x%08x\n", sqh,
816 if (uhci_dump_td(td)) {
842 DPRINTFN(6,
"add\n");
865 DPRINTFN(6,
"remove\n");
889#define UHCI_APPEND_TD(std,last) (last) = _uhci_append_td(std,last)
893 DPRINTFN(11,
"%p to %p\n", std, last);
915#define UHCI_APPEND_QH(sqh,last) (last) = _uhci_append_qh(sqh,last)
919 DPRINTFN(11,
"%p to %p\n", sqh, last);
921 if (sqh->
h_prev != NULL) {
923 DPRINTFN(0,
"QH already linked!\n");
951#define UHCI_REMOVE_TD(std,last) (last) = _uhci_remove_td(std,last)
955 DPRINTFN(11,
"%p from %p\n", std, last);
968 return ((last == std) ? std->
prev : last);
971#define UHCI_REMOVE_QH(sqh,last) (last) = _uhci_remove_qh(sqh,last)
975 DPRINTFN(11,
"%p from %p\n", sqh, last);
990 last = ((last == sqh) ? sqh->
h_prev : last);
1003 uint32_t nframes = xfer->
nframes;
1011 DPRINTFN(13,
"xfer=%p endpoint=%p transfer done\n",
1020 panic(
"%s:%d: out of TD's\n",
1021 __FUNCTION__, __LINE__);
1027 if (uhcidebug > 5) {
1076 td_alt_next = td->alt_next;
1083 status = le32toh(td->td_status);
1084 token = le32toh(td->td_token);
1092 if (
len > td->len) {
1094 DPRINTF(
"Invalid status length, "
1095 "0x%04x/0x%04x bytes\n",
len, td->len);
1127 if (
len != td->len) {
1139 if (td->alt_next != td_alt_next) {
1155 DPRINTFN(11,
"error, addr=%d, endpt=0x%02x, frame=0x%02x "
1156 "status=%s%s%s%s%s%s%s%s%s%s%s\n",
1185 DPRINTFN(13,
"xfer=%p endpoint=%p transfer done\n",
1189 if (uhcidebug > 10) {
1252 td_alt_next = td->alt_next;
1273 if (td->alt_next != td_alt_next) {
1284 DPRINTFN(13,
"xfer=%p following alt next\n", xfer);
1301 DPRINTFN(16,
"xfer=%p checking transfer\n", xfer);
1382 DPRINTFN(13,
"xfer=%p is still active\n", xfer);
1395 TAILQ_FOREACH(xfer, &sc->
sc_bus.
intr_q.head, wait_entry) {
1420 DPRINTFN(16,
"real interrupt\n");
1423 if (uhcidebug > 15) {
1436 printf(
"%s: resume detect\n",
1441 printf(
"%s: host system error\n",
1445 printf(
"%s: host controller process error\n",
1450 DPRINTF(
"%s: host controller halted\n",
1453 if (uhcidebug > 0) {
1515 uint8_t shortpkt_old;
1520 len_old = temp->
len;
1542 if (temp->
len == 0) {
1555 if (temp->
len < average) {
1559 average = temp->
len;
1564 panic(
"%s: out of UHCI transfer descriptors!", __FUNCTION__);
1576 temp->
len -= average;
1597 temp->
len -= average;
1606 td->alt_next = td_alt_next;
1635 temp->
len = len_old;
1649 DPRINTFN(9,
"addr=%d endpt=%d sumlen=%d speed=%d\n",
1742 if (temp.
len == 0) {
1804 if (uhcidebug > 8) {
1805 DPRINTF(
"nexttog=%d; data before transfer:\n",
1826 DPRINTFN(2,
"xfer=%p, endpoint=%p, error=%d\n",
2017 DPRINTFN(3,
"best=%d interval=%d\n",
2091 for (ds = 0; ds != 2; ds++) {
2114 uint32_t startframe;
2125 DPRINTFN(6,
"xfer=%p next=%d nframes=%d\n",
2132 DPRINTFN(3,
"start next=%d\n", startframe);
2149 pp_last = &sc->sc_isoc_p_last[startframe];
2153 xfer->
qh_pos = startframe;
2157 panic(
"%s:%d: out of TD's\n",
2158 __FUNCTION__, __LINE__);
2161 pp_last = &sc->sc_isoc_p_last[0];
2167 printf(
"%s: frame length(%d) exceeds %d "
2168 "bytes (frame truncated)\n",
2169 __FUNCTION__, *
plen,
2215 if (uhcidebug > 5) {
2263 {0}, {0}, {0x00, 0x01},
2292 .wMaxPacketSize[0] = 8,
2304 .bPwrOn2PwrGood = 50,
2327 else if (
index == 2)
2344 DPRINTFN(4,
"uhci port %d reset, status0 = 0x%04x\n",
2360 DPRINTFN(4,
"uhci port %d reset, status1 = 0x%04x\n",
2366 for (lim = 0; lim < 12; lim++) {
2372 DPRINTFN(4,
"uhci port %d iteration %u, status = 0x%04x\n",
2384 DPRINTFN(4,
"uhci port %d loop %u, device detached\n",
2406 DPRINTFN(2,
"uhci port %d reset timed out\n",
index);
2410 DPRINTFN(4,
"uhci port %d reset, status2 = 0x%04x\n",
2423 const char *str_ptr;
2443 DPRINTFN(3,
"type=0x%02x request=0x%02x wLen=0x%04x "
2444 "wValue=0x%04x wIndex=0x%04x\n",
2445 req->bmRequestType,
req->bRequest,
2448#define C(x,y) ((x) | ((y) << 8))
2449 switch (
C(
req->bRequest,
req->bmRequestType)) {
2463 switch (
value >> 8) {
2465 if ((
value & 0xff) != 0) {
2474 if ((
value & 0xff) != 0) {
2483 switch (
value & 0xff) {
2493 str_ptr =
"UHCI root HUB";
2554 DPRINTFN(4,
"UR_CLEAR_PORT_FEATURE "
2555 "port=%d feature=%d\n",
2559 else if (
index == 2)
2609 else if (
index == 2)
2621 if ((
value & 0xff) != 0) {
2635 else if (
index == 2)
2693 else if (
index == 2)
2803 ntd = ((2 * xfer->
nframes) + 1
2902 for (
n = 0;
n != ntd;
n++) {
2914 td->
td_self = htole32(page_info.physaddr |
2917 td->
td_self = htole32(page_info.physaddr |
2940 for (
n = 0;
n != nqh;
n++) {
2971 DPRINTFN(2,
"endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n",
3027 TAILQ_FOREACH(xfer, &sc->
sc_bus.
intr_q.head, wait_entry) {
3067 TAILQ_FOREACH(xfer, &sc->
sc_bus.
intr_q.head, wait_entry) {
3125 flags =
bus->hw_power_state;
3137 DPRINTF(
"Some USB transfer is "
3138 "active on unit %u.\n",
3142 DPRINTF(
"Power save on unit %u.\n",
static SYSCTL_NODE(_hw_usb, OID_AUTO, dwc_otg, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "USB DWC OTG")
SYSCTL_INT(_hw_usb_dwc_otg, OID_AUTO, phy_type, CTLFLAG_RDTUN, &dwc_otg_phy_type, 0, "DWC OTG PHY TYPE - 0/1/2/3 - ULPI/HSIC/INTERNAL/UTMI+")
volatile uint32_t td_next
struct usb_config_descriptor confd
struct usb_page last_td_pg
struct usb_page bulk_start_pg
struct usb_page last_qh_pg
struct usb_page pframes_pg
struct usb_page intr_start_pg[UHCI_IFRAMELIST_COUNT]
struct usb_page_cache ls_ctl_start_pc
struct usb_page_cache last_qh_pc
struct usb_page_cache fs_ctl_start_pc
struct usb_page ls_ctl_start_pg
struct usb_page isoc_start_pg[UHCI_VFRAMELIST_COUNT]
struct usb_page_cache intr_start_pc[UHCI_IFRAMELIST_COUNT]
struct usb_page_cache pframes_pc
struct usb_page_cache bulk_start_pc
struct usb_page fs_ctl_start_pg
struct usb_page_cache isoc_start_pc[UHCI_VFRAMELIST_COUNT]
struct usb_page_cache last_td_pc
struct usb_page_cache * fix_pc
struct usb_page_search fix_res
struct usb_page_cache * buf_pc
struct usb_page_search buf_res
volatile uint32_t qh_h_next
volatile uint32_t qh_e_next
struct uhci_qh * obj_next
struct usb_page_cache * page_cache
union uhci_hub_desc sc_hub_desc
struct uhci_qh * sc_fs_ctl_p_last
struct uhci_qh * sc_last_qh_p
struct uhci_qh * sc_ls_ctl_p_last
struct uhci_td * sc_isoc_p_last[UHCI_VFRAMELIST_COUNT]
uint16_t sc_intr_stat[UHCI_IFRAMELIST_COUNT]
struct uhci_qh * sc_intr_p_last[UHCI_IFRAMELIST_COUNT]
struct uhci_qh * sc_bulk_p_last
struct uhci_qh * sc_reclaim_qh_p
struct uhci_td * sc_last_td_p
struct uhci_hw_softc sc_hw
struct usb_callout sc_root_intr
struct uhci_mem_layout ml
volatile uint32_t td_buffer
struct usb_page_cache * page_cache
struct usb_page_cache * fix_pc
volatile uint32_t td_token
struct uhci_td * obj_next
volatile uint32_t td_status
volatile uint32_t td_next
void(* endpoint_init)(struct usb_device *, struct usb_endpoint_descriptor *, struct usb_endpoint *)
const struct usb_bus_methods * methods
struct usb_xfer_queue intr_q
uByte bConfigurationValue
enum usb_hc_mode usb_mode
struct usb_device_flags flags
const struct usb_pipe_methods * methods
uWord wHubCharacteristics
void(* open)(struct usb_xfer *)
uint32_t hc_max_frame_size
uint8_t hc_max_packet_count
struct usb_xfer * curr_xfer
uint16_t hc_max_packet_size
const struct usb_pipe_methods * methods
uint8_t bandwidth_reclaimed
usb_frlength_t * frlengths
usb_frlength_t max_data_length
struct usb_page_cache * frbuffers
struct usb_page_cache * buf_fixup
struct usb_endpoint * endpoint
struct usb_xfer_flags_int flags_int
struct usb_xfer_flags flags
struct usb_xfer_root * xroot
usb_error_t uhci_init(uhci_softc_t *sc)
static void uhci_add_loop(uhci_softc_t *sc)
static usb_error_t uhci_roothub_exec(struct usb_device *udev, struct usb_device_request *req, const void **pptr, uint16_t *plength)
static void uhci_device_ctrl_start(struct usb_xfer *xfer)
static const struct usb_bus_methods uhci_bus_methods
static void uhci_xfer_setup(struct usb_setup_params *parm)
static void uhci_check_transfer_sub(struct usb_xfer *xfer)
static void uhci_device_bulk_start(struct usb_xfer *xfer)
#define UHCI_RESET_TIMEOUT
static uhci_qh_t * _uhci_remove_qh(uhci_qh_t *sqh, uhci_qh_t *last)
static void uhci_device_ctrl_open(struct usb_xfer *xfer)
#define UHCI_REMOVE_QH(sqh, last)
static void uhci_xfer_unsetup(struct usb_xfer *xfer)
static void uhci_device_bulk_open(struct usb_xfer *xfer)
static uhci_td_t * uhci_setup_standard_chain(struct usb_xfer *xfer)
static void uhci_start(uhci_softc_t *sc)
static const struct usb_device_descriptor uhci_devd
#define UHCI_REMOVE_TD(std, last)
static const struct usb_hub_descriptor_min uhci_hubd_piix
static uhci_td_t * _uhci_append_td(uhci_td_t *std, uhci_td_t *last)
static void uhci_transfer_intr_enqueue(struct usb_xfer *)
static void uhci_device_intr_close(struct usb_xfer *xfer)
static uhci_qh_t * _uhci_append_qh(uhci_qh_t *sqh, uhci_qh_t *last)
static usb_error_t uhci_portreset(uhci_softc_t *sc, uint16_t index)
#define UHCI_APPEND_QH(sqh, last)
static void uhci_do_poll(struct usb_bus *)
static void uhci_device_isoc_enter(struct usb_xfer *xfer)
static void uhci_mem_layout_init(struct uhci_mem_layout *ml, struct usb_xfer *xfer)
#define UWRITE2(sc, r, x)
static void uhci_device_isoc_close(struct usb_xfer *xfer)
#define UWRITE1(sc, r, x)
static uint8_t uhci_check_transfer(struct usb_xfer *)
static void uhci_device_intr_open(struct usb_xfer *xfer)
static void uhci_interrupt_poll(uhci_softc_t *sc)
#define UHCI_APPEND_TD(std, last)
static void uhci_root_intr(uhci_softc_t *sc)
void uhci_interrupt(uhci_softc_t *sc)
static void uhci_device_isoc_open(struct usb_xfer *xfer)
static void uhci_device_intr_enter(struct usb_xfer *xfer)
static const struct usb_pipe_methods uhci_device_intr_methods
static void uhci_isoc_done(uhci_softc_t *sc, struct usb_xfer *xfer)
static const struct usb_pipe_methods uhci_device_bulk_methods
static void uhci_device_suspend(struct usb_device *udev)
static void uhci_device_bulk_close(struct usb_xfer *xfer)
static void uhci_resume(uhci_softc_t *sc)
static void uhci_mem_layout_fixup(struct uhci_mem_layout *ml, struct uhci_td *td)
static void uhci_timeout(void *)
#define UWRITE4(sc, r, x)
static void uhci_device_resume(struct usb_device *udev)
static const struct usb_pipe_methods uhci_device_ctrl_methods
static void uhci_device_ctrl_enter(struct usb_xfer *xfer)
static void uhci_device_ctrl_close(struct usb_xfer *xfer)
static const struct uhci_config_desc uhci_confd
void uhci_reset(uhci_softc_t *sc)
static void uhci_device_intr_start(struct usb_xfer *xfer)
static void uhci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, struct usb_endpoint *ep)
static void uhci_device_isoc_start(struct usb_xfer *xfer)
static void uhci_device_bulk_enter(struct usb_xfer *xfer)
static usb_error_t uhci_non_isoc_done_sub(struct usb_xfer *xfer)
static void uhci_rem_loop(uhci_softc_t *sc)
static uhci_td_t * _uhci_remove_td(uhci_td_t *std, uhci_td_t *last)
static void uhci_device_done(struct usb_xfer *, usb_error_t)
static void uhci_suspend(uhci_softc_t *sc)
static uint8_t uhci_restart(uhci_softc_t *sc)
void uhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb)
static void uhci_set_hw_power(struct usb_bus *bus)
static void uhci_get_dma_delay(struct usb_device *udev, uint32_t *pus)
static struct uhci_qh * uhci_init_qh(struct usb_page_cache *pc)
static void uhci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
static struct uhci_td * uhci_init_td(struct usb_page_cache *pc)
static void uhci_non_isoc_done(struct usb_xfer *xfer)
static const struct usb_pipe_methods uhci_device_isoc_methods
static void uhci_setup_standard_chain_sub(struct uhci_std_temp *temp)
#define UHCI_TD_PID_SETUP
#define UHCI_TD_SET_MAXLEN(l)
#define UHCI_TD_SET_ERRCNT(n)
#define UHCI_FRAMELIST_COUNT
#define UHCI_TD_GET_PID(s)
#define UHCI_TD_GET_ACTLEN(s)
volatile uint32_t qh_e_next
#define UHCI_IFRAMELIST_COUNT
#define UHCI_TD_GET_ENDPT(s)
volatile uint32_t td_status
#define UHCI_TD_SET_ENDPT(e)
volatile uint32_t qh_h_next
#define UHCI_TD_SET_DT(t)
#define UHCI_FRAMELIST_ALIGN
#define UHCI_TD_IN(len, endp, dev, dt)
#define UHCI_TD_ZERO_ACTLEN(t)
#define UHCI_TD_GET_MAXLEN(s)
#define UHCI_TD_SET_DEVADDR(a)
#define UHCI_VFRAMELIST_COUNT
#define UHCI_TD_MAXLEN_MASK
#define UHCI_TD_GET_DT(s)
volatile uint32_t td_token
#define UHCI_TD_GET_ERRCNT(s)
#define UHCI_TD_OUT(len, endp, dev, dt)
#define UHCI_TD_GET_DEVADDR(s)
#define UHCI_PORTSC_LS_SHIFT
#define UHCI_PORTSC_POEDC
#define UHCI_INTR_TOCRCIE
#define UHCI_STS_ALLINTRS
struct usb_port_status ps
#define UHF_PORT_OVER_CURRENT
#define UT_WRITE_INTERFACE
#define UR_SET_DESCRIPTOR
#define UT_WRITE_CLASS_OTHER
#define UT_WRITE_CLASS_DEVICE
#define UPS_C_PORT_ENABLED
#define UPS_C_OVERCURRENT_INDICATOR
#define UHF_PORT_LOW_SPEED
#define UHF_C_PORT_SUSPEND
#define USB_BUS_RESET_DELAY
#define UHF_C_PORT_OVER_CURRENT
#define UHD_OC_INDIVIDUAL
#define UT_WRITE_ENDPOINT
#define UT_READ_CLASS_DEVICE
#define UT_READ_CLASS_OTHER
#define UHD_PWR_NO_SWITCH
#define UPS_C_CONNECT_STATUS
#define UPS_CURRENT_CONNECT_STATUS
#define UHF_PORT_CONNECTION
#define UHF_C_PORT_ENABLE
#define UPS_OVERCURRENT_INDICATOR
#define UT_READ_INTERFACE
#define UR_GET_DESCRIPTOR
#define UHF_C_PORT_CONNECTION
void usbd_get_page(struct usb_page_cache *pc, usb_frlength_t offset, struct usb_page_search *res)
void usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset, const void *ptr, usb_frlength_t len)
void usbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset, void *ptr, usb_frlength_t len)
void usb_pc_cpu_invalidate(struct usb_page_cache *pc)
void usb_pc_cpu_flush(struct usb_page_cache *pc)
void usb_bdma_post_sync(struct usb_xfer *xfer)
#define USB_HW_POWER_RESUME
void usb_bus_mem_flush_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb)
#define USB_HW_POWER_BULK
#define USB_HW_POWER_NON_ROOT_HUB
#define USB_HW_POWER_CONTROL
#define USB_HW_POWER_SUSPEND
#define USB_HW_POWER_SHUTDOWN
void() usb_bus_mem_sub_cb_t(struct usb_bus *bus, struct usb_page_cache *pc, struct usb_page *pg, usb_size_t size, usb_size_t align)
#define USB_HW_POWER_ISOC
#define USB_HW_POWER_INTERRUPT
#define USB_BUS_UNLOCK(_b)
#define USB_BUS_LOCK_ASSERT(_b, _t)
#define usb_port_reset_delay
#define usb_port_root_reset_delay
enum usb_dev_speed usbd_get_speed(struct usb_device *udev)
void uhub_root_intr(struct usb_bus *bus, const uint8_t *ptr, uint8_t len)
void usbd_transfer_setup_sub(struct usb_setup_params *parm)
void usbd_transfer_done(struct usb_xfer *xfer, usb_error_t error)
void usbd_xfer_set_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex, usb_frlength_t len)
void usbd_transfer_enqueue(struct usb_xfer_queue *pq, struct usb_xfer *xfer)
uint8_t usbd_xfer_get_isochronous_start_frame(struct usb_xfer *xfer, uint32_t frame_curr, uint32_t frame_min, uint32_t frame_ms, uint32_t frame_mask, uint32_t *p_frame_start)
void usbd_transfer_timeout_ms(struct usb_xfer *xfer, void(*cb)(void *arg), usb_timeout_t ms)
uint8_t usbd_transfer_setup_sub_malloc(struct usb_setup_params *parm, struct usb_page_cache **ppc, usb_size_t size, usb_size_t align, usb_size_t count)
void usb_pause_mtx(struct mtx *mtx, int timo)
uint8_t usb_make_str_desc(void *ptr, uint16_t max_len, const char *s)
#define usb_callout_init_mtx(c, m, f)
#define usb_callout_reset(c,...)
@ USB_ERR_NORMAL_COMPLETION
#define usb_callout_drain(c)
#define USB_MS_TO_TICKS(ms)