Merge usb changes for Gateworks Cambria boards:
o add support to byte swap EHCI descriptor contents; the IXP435 has dual-EHCI controllers integral but descriptor contents are in big-endian format; this support is configured with the USB_EHCI_BIG_ENDIAN_DESC option and enabled with EHCI_SCFLG_BIGEDESC o clean up EHCI USBMODE register setup during init; add #defines for bit values o split debug support out into a new file and enable use through ddb o while here remove a bunch of lingering netbsd-isms Reviewed by: imp
This commit is contained in:
commit
bfa98d2bd1
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=186351
@ -1476,6 +1476,7 @@ dev/ubsec/ubsec.c optional ubsec
|
||||
#
|
||||
# USB support
|
||||
dev/usb/ehci.c optional ehci
|
||||
dev/usb/ehci_ddb.c optional ehci
|
||||
dev/usb/ehci_pci.c optional ehci pci
|
||||
dev/usb/hid.c optional usb
|
||||
dev/usb/if_aue.c optional aue
|
||||
|
@ -627,6 +627,7 @@ BUS_DEBUG opt_bus.h
|
||||
# options for USB support
|
||||
USB_DEBUG opt_usb.h
|
||||
USBVERBOSE opt_usb.h
|
||||
USB_EHCI_BIG_ENDIAN_DESC opt_usb.h
|
||||
U3G_DEBUG opt_u3g.h
|
||||
UKBD_DFLT_KEYMAP opt_ukbd.h
|
||||
UPLCOM_INTR_INTERVAL opt_uplcom.h
|
||||
|
File diff suppressed because it is too large
Load Diff
255
sys/dev/usb/ehci_ddb.c
Normal file
255
sys/dev/usb/ehci_ddb.c
Normal file
@ -0,0 +1,255 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/lockmgr.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/endian.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
|
||||
#include <dev/usb/ehcireg.h>
|
||||
#include <dev/usb/ehcivar.h>
|
||||
|
||||
#ifdef DDB
|
||||
#include <ddb/ddb.h>
|
||||
#include <ddb/db_sym.h>
|
||||
#else
|
||||
#define db_printf printf
|
||||
#endif
|
||||
|
||||
extern ehci_softc_t *theehci; /* XXX */
|
||||
|
||||
void
|
||||
ehci_dump_regs(ehci_softc_t *sc)
|
||||
{
|
||||
int i;
|
||||
db_printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n",
|
||||
EOREAD4(sc, EHCI_USBCMD),
|
||||
EOREAD4(sc, EHCI_USBSTS),
|
||||
EOREAD4(sc, EHCI_USBINTR));
|
||||
db_printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n",
|
||||
EOREAD4(sc, EHCI_FRINDEX),
|
||||
EOREAD4(sc, EHCI_CTRLDSSEGMENT),
|
||||
EOREAD4(sc, EHCI_PERIODICLISTBASE),
|
||||
EOREAD4(sc, EHCI_ASYNCLISTADDR));
|
||||
for (i = 1; i <= sc->sc_noport; i++)
|
||||
db_printf("port %d status=0x%08x\n", i,
|
||||
EOREAD4(sc, EHCI_PORTSC(i)));
|
||||
}
|
||||
|
||||
static void
|
||||
ehci_dump_link(ehci_softc_t *sc, ehci_link_t link, int type)
|
||||
{
|
||||
link = hc32toh(sc, link);
|
||||
db_printf("0x%08x", link);
|
||||
if (link & EHCI_LINK_TERMINATE)
|
||||
db_printf("<T>");
|
||||
else {
|
||||
db_printf("<");
|
||||
if (type) {
|
||||
switch (EHCI_LINK_TYPE(link)) {
|
||||
case EHCI_LINK_ITD: db_printf("ITD"); break;
|
||||
case EHCI_LINK_QH: db_printf("QH"); break;
|
||||
case EHCI_LINK_SITD: db_printf("SITD"); break;
|
||||
case EHCI_LINK_FSTN: db_printf("FSTN"); break;
|
||||
}
|
||||
}
|
||||
db_printf(">");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_sqtds(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
|
||||
{
|
||||
int i;
|
||||
u_int32_t stop;
|
||||
|
||||
stop = 0;
|
||||
for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) {
|
||||
ehci_dump_sqtd(sc, sqtd);
|
||||
stop = sqtd->qtd.qtd_next & htohc32(sc, EHCI_LINK_TERMINATE);
|
||||
}
|
||||
if (sqtd)
|
||||
db_printf("dump aborted, too many TDs\n");
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_qtd(ehci_softc_t *sc, ehci_qtd_t *qtd)
|
||||
{
|
||||
u_int32_t s;
|
||||
|
||||
db_printf(" next="); ehci_dump_link(sc, qtd->qtd_next, 0);
|
||||
db_printf(" altnext="); ehci_dump_link(sc, qtd->qtd_altnext, 0);
|
||||
db_printf("\n");
|
||||
s = hc32toh(sc, qtd->qtd_status);
|
||||
db_printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n",
|
||||
s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s),
|
||||
EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s));
|
||||
db_printf(" cerr=%d pid=%d stat=%b\n", EHCI_QTD_GET_CERR(s),
|
||||
EHCI_QTD_GET_PID(s),
|
||||
EHCI_QTD_GET_STATUS(s), EHCI_QTD_STATUS_BITS);
|
||||
for (s = 0; s < 5; s++)
|
||||
db_printf(" buffer[%d]=0x%08x\n", s, hc32toh(sc, qtd->qtd_buffer[s]));
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
|
||||
{
|
||||
db_printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr);
|
||||
ehci_dump_qtd(sc, &sqtd->qtd);
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_sqh(ehci_softc_t *sc, ehci_soft_qh_t *sqh)
|
||||
{
|
||||
ehci_qh_t *qh = &sqh->qh;
|
||||
u_int32_t endp, endphub;
|
||||
|
||||
db_printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr);
|
||||
db_printf(" sqtd=%p inactivesqtd=%p\n", sqh->sqtd, sqh->inactivesqtd);
|
||||
db_printf(" link="); ehci_dump_link(sc, qh->qh_link, 1); db_printf("\n");
|
||||
endp = hc32toh(sc, qh->qh_endp);
|
||||
db_printf(" endp=0x%08x\n", endp);
|
||||
db_printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n",
|
||||
EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp),
|
||||
EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp),
|
||||
EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp));
|
||||
db_printf(" mpl=0x%x ctl=%d nrl=%d\n",
|
||||
EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp),
|
||||
EHCI_QH_GET_NRL(endp));
|
||||
endphub = hc32toh(sc, qh->qh_endphub);
|
||||
db_printf(" endphub=0x%08x\n", endphub);
|
||||
db_printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n",
|
||||
EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub),
|
||||
EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub),
|
||||
EHCI_QH_GET_MULT(endphub));
|
||||
db_printf(" curqtd="); ehci_dump_link(sc, qh->qh_curqtd, 0); db_printf("\n");
|
||||
db_printf("Overlay qTD:\n");
|
||||
ehci_dump_qtd(sc, &qh->qh_qtd);
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_itd(ehci_softc_t *sc, struct ehci_soft_itd *itd)
|
||||
{
|
||||
ehci_isoc_trans_t t;
|
||||
ehci_isoc_bufr_ptr_t b, b2, b3;
|
||||
int i;
|
||||
|
||||
db_printf("ITD: next phys=%X\n", itd->itd.itd_next);
|
||||
|
||||
for (i = 0; i < 8;i++) {
|
||||
t = hc32toh(sc, itd->itd.itd_ctl[i]);
|
||||
db_printf("ITDctl %d: stat=%X len=%X ioc=%X pg=%X offs=%X\n", i,
|
||||
EHCI_ITD_GET_STATUS(t), EHCI_ITD_GET_LEN(t),
|
||||
EHCI_ITD_GET_IOC(t), EHCI_ITD_GET_PG(t),
|
||||
EHCI_ITD_GET_OFFS(t));
|
||||
}
|
||||
db_printf("ITDbufr: ");
|
||||
for (i = 0; i < 7; i++)
|
||||
db_printf("%X,", EHCI_ITD_GET_BPTR(hc32toh(sc, itd->itd.itd_bufr[i])));
|
||||
|
||||
b = hc32toh(sc, itd->itd.itd_bufr[0]);
|
||||
b2 = hc32toh(sc, itd->itd.itd_bufr[1]);
|
||||
b3 = hc32toh(sc, itd->itd.itd_bufr[2]);
|
||||
db_printf("\nep=%X daddr=%X dir=%d maxpkt=%X multi=%X\n",
|
||||
EHCI_ITD_GET_EP(b), EHCI_ITD_GET_DADDR(b), EHCI_ITD_GET_DIR(b2),
|
||||
EHCI_ITD_GET_MAXPKT(b2), EHCI_ITD_GET_MULTI(b3));
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_sitd(ehci_softc_t *sc, struct ehci_soft_itd *itd)
|
||||
{
|
||||
db_printf("SITD %p next=%p prev=%p xfernext=%p physaddr=%X slot=%d\n",
|
||||
itd, itd->u.frame_list.next, itd->u.frame_list.prev,
|
||||
itd->xfer_next, itd->physaddr, itd->slot);
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_exfer(struct ehci_xfer *ex)
|
||||
{
|
||||
#ifdef DIAGNOSTIC
|
||||
db_printf("%p: sqtdstart %p end %p itdstart %p end %p isdone %d\n",
|
||||
ex, ex->sqtdstart, ex->sqtdend, ex->itdstart,
|
||||
ex->itdend, ex->isdone);
|
||||
#else
|
||||
db_printf("%p: sqtdstart %p end %p itdstart %p end %p\n",
|
||||
ex, ex->sqtdstart, ex->sqtdend, ex->itdstart, ex->itdend);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DDB
|
||||
DB_SHOW_COMMAND(ehci, db_show_ehci)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_regs((ehci_softc_t *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_sqtds, db_show_ehci_sqtds)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_sqtds <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_sqtds(theehci, (ehci_soft_qtd_t *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_qtd, db_show_ehci_qtd)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_qtd <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_qtd(theehci, (ehci_qtd_t *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_sqh, db_show_ehci_sqh)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_sqh <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_sqh(theehci, (ehci_soft_qh_t *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_itd, db_show_ehci_itd)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_itd <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_itd(theehci, (struct ehci_soft_itd *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_sitd, db_show_ehci_sitd)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_sitd <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_itd(theehci, (struct ehci_soft_itd *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_xfer, db_show_ehci_xfer)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_xfer <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_exfer((struct ehci_xfer *) addr);
|
||||
}
|
||||
#endif /* DDB */
|
@ -61,8 +61,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/bus.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/lockmgr.h>
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
@ -173,6 +173,15 @@
|
||||
#define EHCI_PS_CS 0x00000001 /* RO connect status */
|
||||
#define EHCI_PS_CLEAR (EHCI_PS_OCC|EHCI_PS_PEC|EHCI_PS_CSC)
|
||||
|
||||
#define EHCI_USBMODE 0x68 /* RW USB Device mode register */
|
||||
#define EHCI_UM_CM 0x00000003 /* R/WO Controller Mode */
|
||||
#define EHCI_UM_CM_IDLE 0x0 /* Idle */
|
||||
#define EHCI_UM_CM_HOST 0x3 /* Host Controller */
|
||||
#define EHCI_UM_ES 0x00000004 /* R/WO Endian Select */
|
||||
#define EHCI_UM_ES_LE 0x0 /* Little-endian byte alignment */
|
||||
#define EHCI_UM_ES_BE 0x4 /* Big-endian byte alignment */
|
||||
#define EHCI_UM_SDIS 0x00000010 /* R/WO Stream Disable Mode */
|
||||
|
||||
#define EHCI_PORT_RESET_COMPLETE 2 /* ms */
|
||||
|
||||
#define EHCI_FLALIGN_ALIGN 0x1000
|
||||
@ -279,6 +288,9 @@ typedef struct {
|
||||
} ehci_qtd_t;
|
||||
#define EHCI_QTD_ALIGN 32
|
||||
|
||||
#define EHCI_QTD_STATUS_BITS \
|
||||
"\20\10ACTIVE\7HALTED\6BUFERR\5BABBLE\4XACTERR\3MISSED\2SPLIT\1PING"
|
||||
|
||||
/* Queue Head */
|
||||
typedef struct {
|
||||
ehci_link_t qh_link;
|
||||
|
@ -125,6 +125,7 @@ struct ehci_soft_islot {
|
||||
#define EHCI_SCFLG_SETMODE 0x0004 /* set bridge mode again after init (Marvell) */
|
||||
#define EHCI_SCFLG_FORCESPEED 0x0008 /* force speed (Marvell) */
|
||||
#define EHCI_SCFLG_NORESTERM 0x0010 /* don't terminate reset sequence (Marvell) */
|
||||
#define EHCI_SCFLG_BIGEDESC 0x0020 /* big-endian byte order descriptors */
|
||||
|
||||
typedef struct ehci_softc {
|
||||
struct usbd_bus sc_bus; /* base device */
|
||||
@ -132,22 +133,16 @@ typedef struct ehci_softc {
|
||||
bus_space_tag_t iot;
|
||||
bus_space_handle_t ioh;
|
||||
bus_size_t sc_size;
|
||||
#if defined(__FreeBSD__)
|
||||
void *ih;
|
||||
|
||||
struct resource *io_res;
|
||||
struct resource *irq_res;
|
||||
#endif
|
||||
u_int sc_offs; /* offset to operational regs */
|
||||
|
||||
char sc_vendor[32]; /* vendor string for root hub */
|
||||
int sc_id_vendor; /* vendor ID for root hub */
|
||||
|
||||
u_int32_t sc_cmd; /* shadow of cmd reg during suspend */
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
void *sc_powerhook; /* cookie from power hook */
|
||||
void *sc_shutdownhook; /* cookie from shutdown hook */
|
||||
#endif
|
||||
|
||||
u_int sc_ncomp;
|
||||
u_int sc_npcomp;
|
||||
@ -156,9 +151,6 @@ typedef struct ehci_softc {
|
||||
usb_dma_t sc_fldma;
|
||||
ehci_link_t *sc_flist;
|
||||
u_int sc_flsize;
|
||||
#ifndef __FreeBSD__
|
||||
u_int sc_rand; /* XXX need proper intr scheduling */
|
||||
#endif
|
||||
|
||||
struct ehci_soft_islot sc_islots[EHCI_INTRQHS];
|
||||
|
||||
@ -192,9 +184,6 @@ typedef struct ehci_softc {
|
||||
struct callout sc_tmo_intrlist;
|
||||
|
||||
char sc_dying;
|
||||
#if defined(__NetBSD__)
|
||||
struct usb_dma_reserve sc_dma_reserve;
|
||||
#endif
|
||||
} ehci_softc_t;
|
||||
|
||||
#define EREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
|
||||
@ -210,14 +199,77 @@ typedef struct ehci_softc {
|
||||
#define EOWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
|
||||
#define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
|
||||
|
||||
#ifdef USB_EHCI_BIG_ENDIAN_DESC
|
||||
/*
|
||||
* Handle byte order conversion between host and ``host controller''.
|
||||
* Typically the latter is little-endian but some controllers require
|
||||
* big-endian in which case we may need to manually swap.
|
||||
*/
|
||||
static __inline uint32_t
|
||||
htohc32(const struct ehci_softc *sc, const uint32_t v)
|
||||
{
|
||||
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? htobe32(v) : htole32(v);
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
htohc16(const struct ehci_softc *sc, const uint16_t v)
|
||||
{
|
||||
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? htobe16(v) : htole16(v);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
hc32toh(const struct ehci_softc *sc, const uint32_t v)
|
||||
{
|
||||
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? be32toh(v) : le32toh(v);
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
hc16toh(const struct ehci_softc *sc, const uint16_t v)
|
||||
{
|
||||
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? be16toh(v) : le16toh(v);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Normal little-endian only conversion routines.
|
||||
*/
|
||||
static __inline uint32_t
|
||||
htohc32(const struct ehci_softc *sc, const uint32_t v)
|
||||
{
|
||||
return htole32(v);
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
htohc16(const struct ehci_softc *sc, const uint16_t v)
|
||||
{
|
||||
return htole16(v);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
hc32toh(const struct ehci_softc *sc, const uint32_t v)
|
||||
{
|
||||
return le32toh(v);
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
hc16toh(const struct ehci_softc *sc, const uint16_t v)
|
||||
{
|
||||
return le16toh(v);
|
||||
}
|
||||
#endif
|
||||
|
||||
usbd_status ehci_init(ehci_softc_t *);
|
||||
int ehci_intr(void *);
|
||||
int ehci_detach(ehci_softc_t *, int);
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
int ehci_activate(device_t, enum devact);
|
||||
#endif
|
||||
void ehci_power(int state, void *priv);
|
||||
void ehci_shutdown(void *v);
|
||||
|
||||
#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
|
||||
|
||||
void ehci_dump_regs(ehci_softc_t *);
|
||||
void ehci_dump_sqtds(ehci_softc_t *, ehci_soft_qtd_t *);
|
||||
void ehci_dump_qtd(ehci_softc_t *, ehci_qtd_t *);
|
||||
void ehci_dump_sqtd(ehci_softc_t *, ehci_soft_qtd_t *);
|
||||
void ehci_dump_sqh(ehci_softc_t *, ehci_soft_qh_t *);
|
||||
void ehci_dump_itd(ehci_softc_t *, struct ehci_soft_itd *);
|
||||
void ehci_dump_sitd(ehci_softc_t *, struct ehci_soft_itd *);
|
||||
void ehci_dump_exfer(struct ehci_xfer *);
|
||||
|
@ -256,7 +256,8 @@ struct usb_attach_arg {
|
||||
#define USBD_SHOW_DEVICE_CLASS 0x1
|
||||
#define USBD_SHOW_INTERFACE_CLASS 0x2
|
||||
|
||||
int usbd_driver_load(module_t mod, int what, void *arg);
|
||||
struct module;
|
||||
int usbd_driver_load(struct module *mod, int what, void *arg);
|
||||
|
||||
static inline int
|
||||
usb_get_port(device_t dev)
|
||||
|
Loading…
Reference in New Issue
Block a user