38#ifdef USB_GLOBAL_INCLUDE_FILE
39#include USB_GLOBAL_INCLUDE_FILE
41#include <sys/stdint.h>
42#include <sys/stddef.h>
47#include <sys/kernel.h>
49#include <sys/module.h>
52#include <sys/condvar.h>
53#include <sys/sysctl.h>
55#include <sys/unistd.h>
56#include <sys/callout.h>
57#include <sys/malloc.h>
63#define USB_DEBUG_VAR ohcidebug
81#define OHCI_BUS2SC(bus) \
82 __containerof(bus, ohci_softc_t, sc_bus)
85static int ohcidebug = 0;
87static SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
90 &ohcidebug, 0,
"ohci debug level");
101#define OBARR(sc) bus_space_barrier((sc)->sc_io_tag, (sc)->sc_io_hdl, 0, (sc)->sc_io_size, \
102 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
103#define OWRITE1(sc, r, x) \
104 do { OBARR(sc); bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0)
105#define OWRITE2(sc, r, x) \
106 do { OBARR(sc); bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0)
107#define OWRITE4(sc, r, x) \
108 do { OBARR(sc); bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0)
109#define OREAD1(sc, r) (OBARR(sc), bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r)))
110#define OREAD2(sc, r) (OBARR(sc), bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r)))
111#define OREAD4(sc, r) (OBARR(sc), bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r)))
113#define OHCI_INTR_ENDPT 1
187 DPRINTF(
"SMM active, request owner change\n");
189 for (i = 0; (i < 100) && (ctl &
OHCI_IR); i++) {
195 "SMM does not respond, resetting\n");
222 for (i = 0; i < 10; i++) {
230 device_printf(sc->
sc_bus.
bdev,
"reset timeout\n");
234 if (ohcidebug > 15) {
291 for (i = 0; (i < 10) && (sc->
sc_noport == 0); i++) {
315 ed->
ed_self = htole32(buf_res.physaddr);
364 y = (x ^ bit) | (bit / 2);
388 ed_int->
next = ed_isc;
413 if (ohcidebug > 15) {
491 DPRINTF(
"ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n",
495 DPRINTF(
" intrstat=0x%08x intre=0x%08x intrd=0x%08x\n",
499 DPRINTF(
" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n",
503 DPRINTF(
" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n",
507 DPRINTF(
" done=0x%08x fmival=0x%08x fmrem=0x%08x\n",
511 DPRINTF(
" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n",
515 DPRINTF(
" desca=0x%08x descb=0x%08x stat=0x%08x\n",
519 DPRINTF(
" port1=0x%08x port2=0x%08x\n",
525 DPRINTF(
" HCCA: frame_number=0x%04x done_head=0x%08x\n",
533 if (ohci_dump_td(std)) {
550 printf(
"TD(%p) at 0x%08x: %s%s%s%s%s delay=%d ec=%d "
551 "cc=%d\ncbp=0x%08x next=0x%08x be=0x%08x\n",
563 le32toh(std->
td_be));
580 printf(
"ITD(%p) at 0x%08x: sf=%d di=%d fc=%d cc=%d\n"
581 "bp0=0x%08x next=0x%08x be=0x%08x\n",
591 printf(
"offs[%d]=0x%04x ", i,
602 for (; sitd; sitd = sitd->
obj_next) {
603 if (ohci_dump_itd(sitd)) {
620 printf(
"ED(%p) at 0x%08x: addr=%d endpt=%d maxp=%d flags=%s%s%s%s%s\n"
621 "tailp=0x%08x headflags=%s%s headp=0x%08x nexted=0x%08x\n",
656#define OHCI_APPEND_QH(sed,last) (last) = _ohci_append_qh(sed,last)
660 DPRINTFN(11,
"%p to %p\n", sed, last);
662 if (sed->
prev != NULL) {
664 DPRINTFN(0,
"ED already linked!\n");
689#define OHCI_REMOVE_QH(sed,last) (last) = _ohci_remove_qh(sed,last)
693 DPRINTFN(11,
"%p from %p\n", sed, last);
708 last = ((last == sed) ? sed->
prev : last);
722 volatile uint16_t *olen;
728 panic(
"%s:%d: out of TD's\n",
729 __FUNCTION__, __LINE__);
746 len = le16toh(*olen);
751 len &= ((1 << 12) - 1);
773static const char *
const
779 "DATA_TOGGLE_MISMATCH",
782 "DEVICE_NOT_RESPONDING",
819 phy_start = le32toh(td->
td_cbp);
828 phy_end = le32toh(td->
td_be);
834 if (temp > td->
len) {
874 if (td->alt_next != td_alt_next) {
884 DPRINTFN(16,
"error cc=%d (%s)\n",
885 cc, ohci_cc_strs[cc]);
896 DPRINTFN(13,
"xfer=%p endpoint=%p transfer done\n",
900 if (ohcidebug > 10) {
953 phy_start = le32toh(td->
td_cbp);
993 DPRINTFN(13,
"xfer=%p following alt next\n", xfer);
1028 DPRINTFN(13,
"xfer=%p checking transfer\n", xfer);
1061 DPRINTFN(13,
"xfer=%p is still active\n", xfer);
1087 TAILQ_FOREACH(xfer, &sc->
sc_bus.
intr_q.head, wait_entry) {
1116 DPRINTFN(16,
"real interrupt\n");
1119 if (ohcidebug > 15) {
1175 printf(
"%s: resume detect\n", __FUNCTION__);
1179 printf(
"%s: unrecoverable error, "
1180 "controller halted\n", __FUNCTION__);
1204 printf(
"%s: blocking intrs 0x%x\n",
1247 uint32_t buf_offset;
1250 uint8_t shortpkt_old;
1256 len_old = temp->
len;
1273 if (temp->
len == 0) {
1285 if (temp->
len < average) {
1289 average = temp->
len;
1294 panic(
"%s: out of OHCI transfer descriptors!", __FUNCTION__);
1306 temp->
len -= average;
1327 td->td_cbp = htole32(buf_res.physaddr);
1328 buf_offset += (average - 1);
1331 td->td_be = htole32(buf_res.physaddr);
1338 temp->
len -= average;
1349 td->td_next =
td_next->td_self;
1353 td->alt_next = td_alt_next;
1372 temp->
len = len_old;
1389 DPRINTFN(9,
"addr=%d endpt=%d sumlen=%d speed=%d\n",
1480 if (temp.
len == 0) {
1535 if (ohcidebug > 8) {
1536 DPRINTF(
"nexttog=%d; data before transfer:\n",
1591 DPRINTF(
"sc=%p hstatus=0x%08x\n",
1599 for (i = 1; i < m; i++) {
1603 DPRINTF(
"port %d changed\n", i);
1623 DPRINTFN(2,
"xfer=%p, endpoint=%p, error=%d\n",
1763 DPRINTFN(3,
"best=%d interval=%d\n",
1825 uint32_t buf_offset;
1827 uint32_t startframe;
1841 DPRINTFN(6,
"xfer=%p isoc_next=%u nframes=%u hcca_fn=%u\n",
1845 xfer, nframes, 0, 1, 0xFFFF, &startframe))
1846 DPRINTFN(3,
"start next=%d\n", startframe);
1869 panic(
"%s:%d: out of TD's\n",
1870 __FUNCTION__, __LINE__);
1873 buf_offset += *
plen;
1881 (length & 0xF000) ||
1908 td->
itd_bp0 = htole32(buf_res.physaddr);
1910 td->
itd_be = htole32(buf_res.physaddr);
1943 if (ohcidebug > 8) {
1944 DPRINTF(
"data before transfer:\n");
2005 {0}, {0}, {0x00, 0x01},
2029 .bInterfaceProtocol = 0,
2036 .wMaxPacketSize[0] = 32,
2054 const char *str_ptr;
2073 DPRINTFN(3,
"type=0x%02x request=0x%02x wLen=0x%04x "
2074 "wValue=0x%04x wIndex=0x%04x\n",
2075 req->bmRequestType,
req->bRequest,
2078#define C(x,y) ((x) | ((y) << 8))
2079 switch (
C(
req->bRequest,
req->bmRequestType)) {
2093 switch (
value >> 8) {
2095 if ((
value & 0xff) != 0) {
2104 if ((
value & 0xff) != 0) {
2113 switch (
value & 0xff) {
2123 str_ptr =
"OHCI root HUB";
2184 DPRINTFN(9,
"UR_CLEAR_PORT_FEATURE "
2185 "port=%d feature=%d\n",
2230 if ((
OREAD4(sc, port) >> 16) == 0)
2238 if ((
value & 0xff) != 0) {
2270 DPRINTFN(9,
"get port status i=%d\n",
2278 DPRINTFN(9,
"port status=0x%04x\n", v);
2279 v &= ~UPS_PORT_MODE_DEVICE;
2304 DPRINTFN(6,
"reset port %d\n",
index);
2319 DPRINTFN(9,
"ohci port %d reset, status = 0x%04x\n",
2323 DPRINTFN(3,
"set port power %d\n",
index);
2368 ntd = ((2 * xfer->
nframes) + 1
2425 for (
n = 0;
n != ntd;
n++) {
2433 td->
td_self = htole32(page_info.physaddr);
2449 for (
n = 0;
n != nitd;
n++) {
2457 itd->
itd_self = htole32(page_info.physaddr);
2477 for (
n = 0;
n != nqh;
n++) {
2485 ed->
ed_self = htole32(page_info.physaddr);
2508 DPRINTFN(2,
"endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n",
2564 TAILQ_FOREACH(xfer, &sc->
sc_bus.
intr_q.head, wait_entry) {
2600 TAILQ_FOREACH(xfer, &sc->
sc_bus.
intr_q.head, wait_entry) {
2651 flags =
bus->hw_power_state;
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+")
static void ohci_root_intr(ohci_softc_t *sc)
static usb_error_t ohci_controller_init(ohci_softc_t *sc, int do_suspend)
static void ohci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, struct usb_endpoint *ep)
static ohci_ed_t * _ohci_remove_qh(ohci_ed_t *sed, ohci_ed_t *last)
static const struct usb_pipe_methods ohci_device_isoc_methods
static void ohci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
static void ohci_set_hw_power(struct usb_bus *bus)
static void ohci_check_transfer_sub(struct usb_xfer *xfer)
static void ohci_device_intr_open(struct usb_xfer *xfer)
#define OWRITE4(sc, r, x)
static void ohci_timeout(void *arg)
static void ohci_device_bulk_close(struct usb_xfer *xfer)
static void ohci_device_isoc_start(struct usb_xfer *xfer)
static void ohci_rhsc_enable(ohci_softc_t *sc)
void ohci_interrupt(ohci_softc_t *sc)
#define OHCI_REMOVE_QH(sed, last)
static void ohci_device_suspend(struct usb_device *udev)
static void ohci_device_intr_close(struct usb_xfer *xfer)
static void ohci_device_intr_start(struct usb_xfer *xfer)
void ohci_detach(struct ohci_softc *sc)
static void ohci_device_ctrl_start(struct usb_xfer *xfer)
static void ohci_non_isoc_done(struct usb_xfer *xfer)
static void ohci_device_isoc_open(struct usb_xfer *xfer)
static void ohci_get_dma_delay(struct usb_device *udev, uint32_t *pus)
static const struct usb_device_descriptor ohci_devd
static void ohci_device_ctrl_open(struct usb_xfer *xfer)
static struct ohci_ed * ohci_init_ed(struct usb_page_cache *pc)
static void ohci_device_bulk_start(struct usb_xfer *xfer)
static void ohci_do_poll(struct usb_bus *bus)
static void ohci_device_resume(struct usb_device *udev)
static void ohci_xfer_setup(struct usb_setup_params *parm)
static void ohci_device_ctrl_close(struct usb_xfer *xfer)
static void ohci_isoc_done(struct usb_xfer *xfer)
static const struct usb_bus_methods ohci_bus_methods
#define OHCI_APPEND_QH(sed, last)
static const struct usb_hub_descriptor ohci_hubd
static void ohci_transfer_intr_enqueue(struct usb_xfer *xfer)
static void ohci_setup_standard_chain(struct usb_xfer *xfer, ohci_ed_t **ed_last)
static const struct usb_pipe_methods ohci_device_intr_methods
static void ohci_device_isoc_enter(struct usb_xfer *xfer)
usb_error_t ohci_init(ohci_softc_t *sc)
static void ohci_device_done(struct usb_xfer *xfer, usb_error_t error)
static void ohci_device_isoc_close(struct usb_xfer *xfer)
static void ohci_device_intr_enter(struct usb_xfer *xfer)
static void ohci_device_bulk_open(struct usb_xfer *xfer)
static const struct usb_pipe_methods ohci_device_ctrl_methods
static void ohci_setup_standard_chain_sub(struct ohci_std_temp *temp)
static usb_error_t ohci_non_isoc_done_sub(struct usb_xfer *xfer)
void ohci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb)
static void ohci_device_bulk_enter(struct usb_xfer *xfer)
static void ohci_suspend(ohci_softc_t *sc)
static usb_error_t ohci_roothub_exec(struct usb_device *udev, struct usb_device_request *req, const void **pptr, uint16_t *plength)
static const struct ohci_config_desc ohci_confd
static uint8_t ohci_check_transfer(struct usb_xfer *xfer)
static void ohci_interrupt_poll(ohci_softc_t *sc)
static void ohci_device_ctrl_enter(struct usb_xfer *xfer)
static ohci_ed_t * _ohci_append_qh(ohci_ed_t *sed, ohci_ed_t *last)
static const struct usb_pipe_methods ohci_device_bulk_methods
static void ohci_xfer_unsetup(struct usb_xfer *xfer)
static void ohci_resume(ohci_softc_t *sc)
static struct ohci_hcca * ohci_get_hcca(ohci_softc_t *sc)
#define OHCI_TD_SET_DI(x)
#define OHCI_ITD_GET_CC(x)
#define OHCI_ITD_SET_FC(x)
volatile uint32_t itd_flags
volatile uint32_t ed_tailp
#define OHCI_ITD_MK_OFFS(len)
volatile uint32_t td_next
#define OHCI_PAGE_OFFSET(x)
#define OHCI_TD_GET_EC(x)
#define OHCI_ITD_GET_FC(x)
#define OHCI_ED_FORMAT_GEN
#define OHCI_ITD_GET_DI(x)
#define OHCI_TD_GET_DI(x)
volatile uint32_t ed_headp
volatile uint32_t ed_flags
#define OHCI_ED_GET_FA(s)
#define OHCI_TD_GET_CC(x)
#define OHCI_READ_DESC_DELAY
#define OHCI_ITD_SET_SF(x)
#define OHCI_ED_SET_FA(s)
#define OHCI_ENABLE_POWER_DELAY
#define OHCI_PAGE_MASK(x)
volatile uint16_t itd_offset[OHCI_ITD_NOFFSET]
#define OHCI_ED_SET_EN(s)
#define OHCI_ED_SET_MAXP(s)
#define OHCI_ED_GET_EN(s)
#define OHCI_CC_NOT_ACCESSED
#define OHCI_ED_FORMAT_ISO
#define OHCI_ITD_SET_DI(x)
#define OHCI_ED_GET_MAXP(s)
#define OHCI_TD_TOGGLE_MASK
#define OHCI_TD_INTR_MASK
#define OHCI_ITD_GET_SF(x)
volatile uint32_t td_flags
#define OHCI_INTERRUPT_STATUS
#define OHCI_RH_PORT_STATUS(n)
#define OHCI_CONTROL_CURRENT_ED
#define OHCI_LS_THRESHOLD
#define OHCI_BULK_HEAD_ED
#define OHCI_RH_DESCRIPTOR_B
#define OHCI_RH_DESCRIPTOR_A
#define OHCI_PERIOD_CURRENT_ED
#define OHCI_NORMAL_INTRS
#define OHCI_HCFS_OPERATIONAL
#define OHCI_INTERRUPT_DISABLE
#define OHCI_FM_REMAINING
#define OHCI_INTERRUPT_ENABLE
#define OHCI_BULK_CURRENT_ED
#define OHCI_COMMAND_STATUS
#define OHCI_HCFS_SUSPEND
#define OHCI_CONTROL_HEAD_ED
#define OHCI_GET_POTPGT(s)
#define OHCI_PERIODIC_START
struct usb_config_descriptor confd
volatile uint32_t ed_flags
struct usb_page_cache * page_cache
volatile uint32_t ed_next
struct ohci_ed * obj_next
volatile uint32_t ed_tailp
volatile uint32_t ed_headp
volatile uint32_t hcca_interrupt_table[OHCI_NO_INTRS]
volatile uint32_t hcca_done_head
volatile uint32_t hcca_frame_number
struct usb_page_cache bulk_start_pc
struct usb_page_cache ctrl_start_pc
struct usb_page bulk_start_pg
struct usb_page_cache hcca_pc
struct usb_page_cache intr_start_pc[OHCI_NO_EDS]
struct usb_page isoc_start_pg
struct usb_page intr_start_pg[OHCI_NO_EDS]
struct usb_page_cache isoc_start_pc
struct usb_page ctrl_start_pg
volatile uint32_t itd_next
struct ohci_itd * obj_next
volatile uint32_t itd_bp0
volatile uint32_t itd_flags
volatile uint16_t itd_offset[OHCI_ITD_NOFFSET]
struct usb_page_cache * page_cache
struct ohci_ed * sc_intr_p_last[OHCI_NO_EDS]
struct usb_callout sc_tmo_rhsc
struct ohci_ed * sc_bulk_p_last
struct ohci_hw_softc sc_hw
struct ohci_ed * sc_isoc_p_last
union ohci_hub_desc sc_hub_desc
struct ohci_hcca * sc_hcca_p
struct ohci_ed * sc_ctrl_p_last
uint16_t sc_intr_stat[OHCI_NO_EDS]
struct usb_page_cache * pc
struct ohci_td * alt_next
struct ohci_td * obj_next
volatile uint32_t td_flags
volatile uint32_t td_next
struct usb_page_cache * page_cache
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
uByte DeviceRemovable[32]
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
usb_frlength_t * frlengths
usb_frlength_t max_data_length
struct usb_page_cache * frbuffers
struct usb_endpoint * endpoint
struct usb_xfer_flags_int flags_int
struct usb_xfer_flags flags
struct usb_xfer_root * xroot
usb_frlength_t max_hc_frame_size
struct usb_port_status ps
struct usb_hub_descriptor hubd
#define UHD_PWR_INDIVIDUAL
#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_C_PORT_SUSPEND
#define USB_BUS_RESET_DELAY
#define UHF_C_PORT_OVER_CURRENT
#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_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 usb_pc_cpu_invalidate(struct usb_page_cache *pc)
void usb_pc_cpu_flush(struct usb_page_cache *pc)
#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_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_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)
#define usb_callout_stop(c)