summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb2
diff options
context:
space:
mode:
authoralfred <alfred@FreeBSD.org>2009-01-04 00:12:01 +0000
committeralfred <alfred@FreeBSD.org>2009-01-04 00:12:01 +0000
commit29029a97b0f154c8bdeb9ce2cd9cf875d1c7206c (patch)
tree6a212d791777cd056f5b3466272b0be92152182e /sys/dev/usb2
parente21427fbffccb679cf56cf4596ee409a9ab71340 (diff)
downloadFreeBSD-src-29029a97b0f154c8bdeb9ce2cd9cf875d1c7206c.zip
FreeBSD-src-29029a97b0f154c8bdeb9ce2cd9cf875d1c7206c.tar.gz
Sync with usb4bsd:
src/lib/libusb20/libusb20_desc.c Make "libusb20_desc_foreach()" more readable. src/sys/dev/usb2/controller/*.[ch] src/sys/dev/usb2/core/*.[ch] Implement support for USB power save for all HC's. Implement support for Big-endian EHCI. Move Huawei quirks back into "u3g" driver. Improve device enumeration. src/sys/dev/usb2/ethernet/*[ch] Patches for supporting new AXE Gigabit chipset. src/sys/dev/usb2/serial/*[ch] Fix IOCTL return code. src/sys/dev/usb2/wlan/*[ch] Sync with old USB stack. Submitted by: hps
Diffstat (limited to 'sys/dev/usb2')
-rw-r--r--sys/dev/usb2/controller/at91dci.c41
-rw-r--r--sys/dev/usb2/controller/ehci2.c542
-rw-r--r--sys/dev/usb2/controller/ehci2.h20
-rw-r--r--sys/dev/usb2/controller/musb2_otg.c7
-rw-r--r--sys/dev/usb2/controller/ohci2.c157
-rw-r--r--sys/dev/usb2/controller/uhci2.c232
-rw-r--r--sys/dev/usb2/controller/uhci2.h3
-rw-r--r--sys/dev/usb2/controller/usb2_bus.h9
-rw-r--r--sys/dev/usb2/controller/usb2_controller.c88
-rw-r--r--sys/dev/usb2/controller/usb2_controller.h25
-rw-r--r--sys/dev/usb2/controller/uss820dci.c25
-rw-r--r--sys/dev/usb2/core/usb2_busdma.c25
-rw-r--r--sys/dev/usb2/core/usb2_core.h2
-rw-r--r--sys/dev/usb2/core/usb2_device.c80
-rw-r--r--sys/dev/usb2/core/usb2_device.h14
-rw-r--r--sys/dev/usb2/core/usb2_dynamic.c23
-rw-r--r--sys/dev/usb2/core/usb2_dynamic.h4
-rw-r--r--sys/dev/usb2/core/usb2_generic.c16
-rw-r--r--sys/dev/usb2/core/usb2_handle_request.c6
-rw-r--r--sys/dev/usb2/core/usb2_hub.c530
-rw-r--r--sys/dev/usb2/core/usb2_hub.h2
-rw-r--r--sys/dev/usb2/core/usb2_msctest.c161
-rw-r--r--sys/dev/usb2/core/usb2_msctest.h25
-rw-r--r--sys/dev/usb2/core/usb2_request.c58
-rw-r--r--sys/dev/usb2/core/usb2_request.h2
-rw-r--r--sys/dev/usb2/core/usb2_transfer.c9
-rw-r--r--sys/dev/usb2/core/usb2_transfer.h2
-rw-r--r--sys/dev/usb2/ethernet/if_axe2.c147
-rw-r--r--sys/dev/usb2/ethernet/if_axe2_reg.h23
-rw-r--r--sys/dev/usb2/image/uscanner2.c1
-rw-r--r--sys/dev/usb2/include/usb2_devid.h10
-rw-r--r--sys/dev/usb2/include/usb2_devtable.h38
-rw-r--r--sys/dev/usb2/include/usb2_ioctl.h7
-rw-r--r--sys/dev/usb2/include/usb2_standard.h9
-rw-r--r--sys/dev/usb2/serial/u3g2.c209
-rw-r--r--sys/dev/usb2/serial/uchcom2.c10
-rw-r--r--sys/dev/usb2/serial/uftdi2.c14
-rw-r--r--sys/dev/usb2/serial/uplcom2.c10
-rw-r--r--sys/dev/usb2/serial/uvscom2.c10
-rw-r--r--sys/dev/usb2/sound/uaudio2.c170
-rw-r--r--sys/dev/usb2/storage/umass2.c12
-rw-r--r--sys/dev/usb2/storage/ustorage2_fs.c2
-rw-r--r--sys/dev/usb2/wlan/if_ural2.c11
-rw-r--r--sys/dev/usb2/wlan/if_zyd2.c271
-rw-r--r--sys/dev/usb2/wlan/if_zyd2_reg.h164
45 files changed, 2387 insertions, 839 deletions
diff --git a/sys/dev/usb2/controller/at91dci.c b/sys/dev/usb2/controller/at91dci.c
index a4e43df..5ed6924 100644
--- a/sys/dev/usb2/controller/at91dci.c
+++ b/sys/dev/usb2/controller/at91dci.c
@@ -261,42 +261,28 @@ at91dci_pull_down(struct at91dci_softc *sc)
}
static void
-at91dci_wakeup_peer(struct at91dci_softc *sc)
+at91dci_wakeup_peer(struct usb2_xfer *xfer)
{
- uint32_t temp;
+ struct at91dci_softc *sc = xfer->usb2_sc;
+ uint8_t use_polling;
if (!(sc->sc_flags.status_suspend)) {
return;
}
- temp = AT91_UDP_READ_4(sc, AT91_UDP_GSTATE);
-
- if (!(temp & AT91_UDP_GSTATE_ESR)) {
- return;
- }
- AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, temp);
-}
-
-static void
-at91dci_rem_wakeup_set(struct usb2_device *udev, uint8_t is_on)
-{
- struct at91dci_softc *sc;
- uint32_t temp;
-
- DPRINTFN(5, "is_on=%u\n", is_on);
-
- USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
-
- sc = AT9100_DCI_BUS2SC(udev->bus);
+ use_polling = mtx_owned(xfer->xfer_mtx) ? 1 : 0;
- temp = AT91_UDP_READ_4(sc, AT91_UDP_GSTATE);
+ AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, AT91_UDP_GSTATE_ESR);
- if (is_on) {
- temp |= AT91_UDP_GSTATE_ESR;
+ /* wait 8 milliseconds */
+ if (use_polling) {
+ /* polling */
+ DELAY(8000);
} else {
- temp &= ~AT91_UDP_GSTATE_ESR;
+ /* Wait for reset to complete. */
+ usb2_pause_mtx(&sc->sc_bus.bus_mtx, 8);
}
- AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, temp);
+ AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, 0);
}
static void
@@ -2120,7 +2106,7 @@ tr_handle_clear_port_feature:
switch (value) {
case UHF_PORT_SUSPEND:
- at91dci_wakeup_peer(sc);
+ at91dci_wakeup_peer(xfer);
break;
case UHF_PORT_ENABLE:
@@ -2492,5 +2478,4 @@ struct usb2_bus_methods at91dci_bus_methods =
.set_stall = &at91dci_set_stall,
.clear_stall = &at91dci_clear_stall,
.vbus_interrupt = &at91dci_vbus_interrupt,
- .rem_wakeup_set = &at91dci_rem_wakeup_set,
};
diff --git a/sys/dev/usb2/controller/ehci2.c b/sys/dev/usb2/controller/ehci2.c
index fdecd7c..d41fde7 100644
--- a/sys/dev/usb2/controller/ehci2.c
+++ b/sys/dev/usb2/controller/ehci2.c
@@ -84,7 +84,7 @@ SYSCTL_INT(_hw_usb2_ehci, OID_AUTO, no_hs, CTLFLAG_RW,
&ehcinohighspeed, 0, "Disable High Speed USB");
static void ehci_dump_regs(ehci_softc_t *sc);
-static void ehci_dump_sqh(ehci_qh_t *sqh);
+static void ehci_dump_sqh(ehci_softc_t *sc, ehci_qh_t *sqh);
#endif
@@ -101,7 +101,7 @@ extern struct usb2_pipe_methods ehci_root_intr_methods;
static usb2_config_td_command_t ehci_root_ctrl_task;
static void ehci_do_poll(struct usb2_bus *bus);
-static void ehci_root_ctrl_poll(struct ehci_softc *sc);
+static void ehci_root_ctrl_poll(ehci_softc_t *sc);
static void ehci_device_done(struct usb2_xfer *xfer, usb2_error_t error);
static uint8_t ehci_check_transfer(struct usb2_xfer *xfer);
static void ehci_timeout(void *arg);
@@ -110,6 +110,7 @@ static usb2_sw_transfer_func_t ehci_root_intr_done;
static usb2_sw_transfer_func_t ehci_root_ctrl_done;
struct ehci_std_temp {
+ ehci_softc_t *sc;
struct usb2_page_cache *pc;
ehci_qtd_t *td;
ehci_qtd_t *td_next;
@@ -123,10 +124,27 @@ struct ehci_std_temp {
uint8_t short_frames_ok;
};
+/*
+ * Byte-order conversion functions.
+ */
+static uint32_t
+htoehci32(ehci_softc_t *sc, const uint32_t v)
+{
+ return ((sc->sc_flags & EHCI_SCFLG_BIGEDESC) ?
+ htobe32(v) : htole32(v));
+}
+
+static uint32_t
+ehci32toh(ehci_softc_t *sc, const uint32_t v)
+{
+ return ((sc->sc_flags & EHCI_SCFLG_BIGEDESC) ?
+ be32toh(v) : le32toh(v));
+}
+
void
ehci_iterate_hw_softc(struct usb2_bus *bus, usb2_bus_mem_sub_cb_t *cb)
{
- struct ehci_softc *sc = EHCI_BUS2SC(bus);
+ ehci_softc_t *sc = EHCI_BUS2SC(bus);
uint32_t i;
cb(bus, &sc->sc_hw.pframes_pc, &sc->sc_hw.pframes_pg,
@@ -280,21 +298,21 @@ ehci_init(ehci_softc_t *sc)
sc->sc_intr_p_last[i] = qh;
qh->qh_self =
- htole32(buf_res.physaddr) |
- htole32(EHCI_LINK_QH);
+ htoehci32(sc, buf_res.physaddr) |
+ htoehci32(sc, EHCI_LINK_QH);
qh->qh_endp =
- htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH));
+ htoehci32(sc, EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH));
qh->qh_endphub =
- htole32(EHCI_QH_SET_MULT(1));
+ htoehci32(sc, EHCI_QH_SET_MULT(1));
qh->qh_curqtd = 0;
qh->qh_qtd.qtd_next =
- htole32(EHCI_LINK_TERMINATE);
+ htoehci32(sc, EHCI_LINK_TERMINATE);
qh->qh_qtd.qtd_altnext =
- htole32(EHCI_LINK_TERMINATE);
+ htoehci32(sc, EHCI_LINK_TERMINATE);
qh->qh_qtd.qtd_status =
- htole32(EHCI_QTD_HALTED);
+ htoehci32(sc, EHCI_QTD_HALTED);
}
/*
@@ -329,7 +347,7 @@ ehci_init(ehci_softc_t *sc)
qh = sc->sc_intr_p_last[0];
/* the last (1ms) QH terminates */
- qh->qh_link = htole32(EHCI_LINK_TERMINATE);
+ qh->qh_link = htoehci32(sc, EHCI_LINK_TERMINATE);
}
for (i = 0; i < EHCI_VIRTUAL_FRAMELIST_COUNT; i++) {
ehci_sitd_t *sitd;
@@ -350,11 +368,11 @@ ehci_init(ehci_softc_t *sc)
/* initialize full speed isochronous */
sitd->sitd_self =
- htole32(buf_res.physaddr) |
- htole32(EHCI_LINK_SITD);
+ htoehci32(sc, buf_res.physaddr) |
+ htoehci32(sc, EHCI_LINK_SITD);
sitd->sitd_back =
- htole32(EHCI_LINK_TERMINATE);
+ htoehci32(sc, EHCI_LINK_TERMINATE);
sitd->sitd_next =
sc->sc_intr_p_last[i | (EHCI_VIRTUAL_FRAMELIST_COUNT / 2)]->qh_self;
@@ -375,8 +393,8 @@ ehci_init(ehci_softc_t *sc)
/* initialize high speed isochronous */
itd->itd_self =
- htole32(buf_res.physaddr) |
- htole32(EHCI_LINK_ITD);
+ htoehci32(sc, buf_res.physaddr) |
+ htoehci32(sc, EHCI_LINK_ITD);
itd->itd_next =
sitd->sitd_self;
@@ -421,20 +439,20 @@ ehci_init(ehci_softc_t *sc)
/* init dummy QH that starts the async list */
qh->qh_self =
- htole32(buf_res.physaddr) |
- htole32(EHCI_LINK_QH);
+ htoehci32(sc, buf_res.physaddr) |
+ htoehci32(sc, EHCI_LINK_QH);
/* fill the QH */
qh->qh_endp =
- htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL);
- qh->qh_endphub = htole32(EHCI_QH_SET_MULT(1));
+ htoehci32(sc, EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL);
+ qh->qh_endphub = htoehci32(sc, EHCI_QH_SET_MULT(1));
qh->qh_link = qh->qh_self;
qh->qh_curqtd = 0;
/* fill the overlay qTD */
- qh->qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
- qh->qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
- qh->qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
+ qh->qh_qtd.qtd_next = htoehci32(sc, EHCI_LINK_TERMINATE);
+ qh->qh_qtd.qtd_altnext = htoehci32(sc, EHCI_LINK_TERMINATE);
+ qh->qh_qtd.qtd_status = htoehci32(sc, EHCI_QTD_HALTED);
}
/* flush all cache into memory */
@@ -442,7 +460,7 @@ ehci_init(ehci_softc_t *sc)
#if USB_DEBUG
if (ehcidebug) {
- ehci_dump_sqh(sc->sc_async_p_last);
+ ehci_dump_sqh(sc, sc->sc_async_p_last);
}
#endif
@@ -490,7 +508,7 @@ done:
* shut down the controller when the system is going down
*/
void
-ehci_detach(struct ehci_softc *sc)
+ehci_detach(ehci_softc_t *sc)
{
USB_BUS_LOCK(&sc->sc_bus);
@@ -510,7 +528,7 @@ ehci_detach(struct ehci_softc *sc)
}
void
-ehci_suspend(struct ehci_softc *sc)
+ehci_suspend(ehci_softc_t *sc)
{
uint32_t cmd;
uint32_t hcr;
@@ -564,7 +582,7 @@ ehci_suspend(struct ehci_softc *sc)
}
void
-ehci_resume(struct ehci_softc *sc)
+ehci_resume(ehci_softc_t *sc)
{
struct usb2_page_search buf_res;
uint32_t cmd;
@@ -723,9 +741,9 @@ ehci_dump_regs(ehci_softc_t *sc)
}
static void
-ehci_dump_link(uint32_t link, int type)
+ehci_dump_link(ehci_softc_t *sc, uint32_t link, int type)
{
- link = le32toh(link);
+ link = ehci32toh(sc, link);
printf("0x%08x", link);
if (link & EHCI_LINK_TERMINATE)
printf("<T>");
@@ -752,16 +770,16 @@ ehci_dump_link(uint32_t link, int type)
}
static void
-ehci_dump_qtd(ehci_qtd_t *qtd)
+ehci_dump_qtd(ehci_softc_t *sc, ehci_qtd_t *qtd)
{
uint32_t s;
printf(" next=");
- ehci_dump_link(qtd->qtd_next, 0);
+ ehci_dump_link(sc, qtd->qtd_next, 0);
printf(" altnext=");
- ehci_dump_link(qtd->qtd_altnext, 0);
+ ehci_dump_link(sc, qtd->qtd_altnext, 0);
printf("\n");
- s = le32toh(qtd->qtd_status);
+ s = ehci32toh(sc, qtd->qtd_status);
printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n",
s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s),
EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s));
@@ -778,35 +796,35 @@ ehci_dump_qtd(ehci_qtd_t *qtd)
for (s = 0; s < 5; s++) {
printf(" buffer[%d]=0x%08x\n", s,
- le32toh(qtd->qtd_buffer[s]));
+ ehci32toh(sc, qtd->qtd_buffer[s]));
}
for (s = 0; s < 5; s++) {
printf(" buffer_hi[%d]=0x%08x\n", s,
- le32toh(qtd->qtd_buffer_hi[s]));
+ ehci32toh(sc, qtd->qtd_buffer_hi[s]));
}
}
static uint8_t
-ehci_dump_sqtd(ehci_qtd_t *sqtd)
+ehci_dump_sqtd(ehci_softc_t *sc, ehci_qtd_t *sqtd)
{
uint8_t temp;
usb2_pc_cpu_invalidate(sqtd->page_cache);
- printf("QTD(%p) at 0x%08x:\n", sqtd, le32toh(sqtd->qtd_self));
- ehci_dump_qtd(sqtd);
- temp = (sqtd->qtd_next & htole32(EHCI_LINK_TERMINATE)) ? 1 : 0;
+ printf("QTD(%p) at 0x%08x:\n", sqtd, ehci32toh(sc, sqtd->qtd_self));
+ ehci_dump_qtd(sc, sqtd);
+ temp = (sqtd->qtd_next & htoehci32(sc, EHCI_LINK_TERMINATE)) ? 1 : 0;
return (temp);
}
static void
-ehci_dump_sqtds(ehci_qtd_t *sqtd)
+ehci_dump_sqtds(ehci_softc_t *sc, ehci_qtd_t *sqtd)
{
uint16_t i;
uint8_t stop;
stop = 0;
for (i = 0; sqtd && (i < 20) && !stop; sqtd = sqtd->obj_next, i++) {
- stop = ehci_dump_sqtd(sqtd);
+ stop = ehci_dump_sqtd(sc, sqtd);
}
if (sqtd) {
printf("dump aborted, too many TDs\n");
@@ -814,16 +832,17 @@ ehci_dump_sqtds(ehci_qtd_t *sqtd)
}
static void
-ehci_dump_sqh(ehci_qh_t *qh)
+ehci_dump_sqh(ehci_softc_t *sc, ehci_qh_t *qh)
{
- uint32_t endp, endphub;
+ uint32_t endp;
+ uint32_t endphub;
usb2_pc_cpu_invalidate(qh->page_cache);
- printf("QH(%p) at 0x%08x:\n", qh, le32toh(qh->qh_self) & ~0x1F);
+ printf("QH(%p) at 0x%08x:\n", qh, ehci32toh(sc, qh->qh_self) & ~0x1F);
printf(" link=");
- ehci_dump_link(qh->qh_link, 1);
+ ehci_dump_link(sc, qh->qh_link, 1);
printf("\n");
- endp = le32toh(qh->qh_endp);
+ endp = ehci32toh(sc, qh->qh_endp);
printf(" endp=0x%08x\n", endp);
printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n",
EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp),
@@ -832,90 +851,90 @@ ehci_dump_sqh(ehci_qh_t *qh)
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 = le32toh(qh->qh_endphub);
+ endphub = ehci32toh(sc, qh->qh_endphub);
printf(" endphub=0x%08x\n", endphub);
printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n",
EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub),
EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub),
EHCI_QH_GET_MULT(endphub));
printf(" curqtd=");
- ehci_dump_link(qh->qh_curqtd, 0);
+ ehci_dump_link(sc, qh->qh_curqtd, 0);
printf("\n");
printf("Overlay qTD:\n");
- ehci_dump_qtd((void *)&qh->qh_qtd);
+ ehci_dump_qtd(sc, (void *)&qh->qh_qtd);
}
static void
-ehci_dump_sitd(ehci_sitd_t *sitd)
+ehci_dump_sitd(ehci_softc_t *sc, ehci_sitd_t *sitd)
{
usb2_pc_cpu_invalidate(sitd->page_cache);
- printf("SITD(%p) at 0x%08x\n", sitd, le32toh(sitd->sitd_self) & ~0x1F);
- printf(" next=0x%08x\n", le32toh(sitd->sitd_next));
+ printf("SITD(%p) at 0x%08x\n", sitd, ehci32toh(sc, sitd->sitd_self) & ~0x1F);
+ printf(" next=0x%08x\n", ehci32toh(sc, sitd->sitd_next));
printf(" portaddr=0x%08x dir=%s addr=%d endpt=0x%x port=0x%x huba=0x%x\n",
- le32toh(sitd->sitd_portaddr),
- (sitd->sitd_portaddr & htole32(EHCI_SITD_SET_DIR_IN))
+ ehci32toh(sc, sitd->sitd_portaddr),
+ (sitd->sitd_portaddr & htoehci32(sc, EHCI_SITD_SET_DIR_IN))
? "in" : "out",
- EHCI_SITD_GET_ADDR(le32toh(sitd->sitd_portaddr)),
- EHCI_SITD_GET_ENDPT(le32toh(sitd->sitd_portaddr)),
- EHCI_SITD_GET_PORT(le32toh(sitd->sitd_portaddr)),
- EHCI_SITD_GET_HUBA(le32toh(sitd->sitd_portaddr)));
- printf(" mask=0x%08x\n", le32toh(sitd->sitd_mask));
- printf(" status=0x%08x <%s> len=0x%x\n", le32toh(sitd->sitd_status),
- (sitd->sitd_status & htole32(EHCI_SITD_ACTIVE)) ? "ACTIVE" : "",
- EHCI_SITD_GET_LEN(le32toh(sitd->sitd_status)));
+ EHCI_SITD_GET_ADDR(ehci32toh(sc, sitd->sitd_portaddr)),
+ EHCI_SITD_GET_ENDPT(ehci32toh(sc, sitd->sitd_portaddr)),
+ EHCI_SITD_GET_PORT(ehci32toh(sc, sitd->sitd_portaddr)),
+ EHCI_SITD_GET_HUBA(ehci32toh(sc, sitd->sitd_portaddr)));
+ printf(" mask=0x%08x\n", ehci32toh(sc, sitd->sitd_mask));
+ printf(" status=0x%08x <%s> len=0x%x\n", ehci32toh(sc, sitd->sitd_status),
+ (sitd->sitd_status & htoehci32(sc, EHCI_SITD_ACTIVE)) ? "ACTIVE" : "",
+ EHCI_SITD_GET_LEN(ehci32toh(sc, sitd->sitd_status)));
printf(" back=0x%08x, bp=0x%08x,0x%08x,0x%08x,0x%08x\n",
- le32toh(sitd->sitd_back),
- le32toh(sitd->sitd_bp[0]),
- le32toh(sitd->sitd_bp[1]),
- le32toh(sitd->sitd_bp_hi[0]),
- le32toh(sitd->sitd_bp_hi[1]));
+ ehci32toh(sc, sitd->sitd_back),
+ ehci32toh(sc, sitd->sitd_bp[0]),
+ ehci32toh(sc, sitd->sitd_bp[1]),
+ ehci32toh(sc, sitd->sitd_bp_hi[0]),
+ ehci32toh(sc, sitd->sitd_bp_hi[1]));
}
static void
-ehci_dump_itd(ehci_itd_t *itd)
+ehci_dump_itd(ehci_softc_t *sc, ehci_itd_t *itd)
{
usb2_pc_cpu_invalidate(itd->page_cache);
- printf("ITD(%p) at 0x%08x\n", itd, le32toh(itd->itd_self) & ~0x1F);
- printf(" next=0x%08x\n", le32toh(itd->itd_next));
- printf(" status[0]=0x%08x; <%s>\n", le32toh(itd->itd_status[0]),
- (itd->itd_status[0] & htole32(EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
- printf(" status[1]=0x%08x; <%s>\n", le32toh(itd->itd_status[1]),
- (itd->itd_status[1] & htole32(EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
- printf(" status[2]=0x%08x; <%s>\n", le32toh(itd->itd_status[2]),
- (itd->itd_status[2] & htole32(EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
- printf(" status[3]=0x%08x; <%s>\n", le32toh(itd->itd_status[3]),
- (itd->itd_status[3] & htole32(EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
- printf(" status[4]=0x%08x; <%s>\n", le32toh(itd->itd_status[4]),
- (itd->itd_status[4] & htole32(EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
- printf(" status[5]=0x%08x; <%s>\n", le32toh(itd->itd_status[5]),
- (itd->itd_status[5] & htole32(EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
- printf(" status[6]=0x%08x; <%s>\n", le32toh(itd->itd_status[6]),
- (itd->itd_status[6] & htole32(EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
- printf(" status[7]=0x%08x; <%s>\n", le32toh(itd->itd_status[7]),
- (itd->itd_status[7] & htole32(EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
- printf(" bp[0]=0x%08x\n", le32toh(itd->itd_bp[0]));
+ printf("ITD(%p) at 0x%08x\n", itd, ehci32toh(sc, itd->itd_self) & ~0x1F);
+ printf(" next=0x%08x\n", ehci32toh(sc, itd->itd_next));
+ printf(" status[0]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[0]),
+ (itd->itd_status[0] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
+ printf(" status[1]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[1]),
+ (itd->itd_status[1] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
+ printf(" status[2]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[2]),
+ (itd->itd_status[2] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
+ printf(" status[3]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[3]),
+ (itd->itd_status[3] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
+ printf(" status[4]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[4]),
+ (itd->itd_status[4] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
+ printf(" status[5]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[5]),
+ (itd->itd_status[5] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
+ printf(" status[6]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[6]),
+ (itd->itd_status[6] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
+ printf(" status[7]=0x%08x; <%s>\n", ehci32toh(sc, itd->itd_status[7]),
+ (itd->itd_status[7] & htoehci32(sc, EHCI_ITD_ACTIVE)) ? "ACTIVE" : "");
+ printf(" bp[0]=0x%08x\n", ehci32toh(sc, itd->itd_bp[0]));
printf(" addr=0x%02x; endpt=0x%01x\n",
- EHCI_ITD_GET_ADDR(le32toh(itd->itd_bp[0])),
- EHCI_ITD_GET_ENDPT(le32toh(itd->itd_bp[0])));
- printf(" bp[1]=0x%08x\n", le32toh(itd->itd_bp[1]));
+ EHCI_ITD_GET_ADDR(ehci32toh(sc, itd->itd_bp[0])),
+ EHCI_ITD_GET_ENDPT(ehci32toh(sc, itd->itd_bp[0])));
+ printf(" bp[1]=0x%08x\n", ehci32toh(sc, itd->itd_bp[1]));
printf(" dir=%s; mpl=0x%02x\n",
- (le32toh(itd->itd_bp[1]) & EHCI_ITD_SET_DIR_IN) ? "in" : "out",
- EHCI_ITD_GET_MPL(le32toh(itd->itd_bp[1])));
+ (ehci32toh(sc, itd->itd_bp[1]) & EHCI_ITD_SET_DIR_IN) ? "in" : "out",
+ EHCI_ITD_GET_MPL(ehci32toh(sc, itd->itd_bp[1])));
printf(" bp[2..6]=0x%08x,0x%08x,0x%08x,0x%08x,0x%08x\n",
- le32toh(itd->itd_bp[2]),
- le32toh(itd->itd_bp[3]),
- le32toh(itd->itd_bp[4]),
- le32toh(itd->itd_bp[5]),
- le32toh(itd->itd_bp[6]));
+ ehci32toh(sc, itd->itd_bp[2]),
+ ehci32toh(sc, itd->itd_bp[3]),
+ ehci32toh(sc, itd->itd_bp[4]),
+ ehci32toh(sc, itd->itd_bp[5]),
+ ehci32toh(sc, itd->itd_bp[6]));
printf(" bp_hi=0x%08x,0x%08x,0x%08x,0x%08x,\n"
" 0x%08x,0x%08x,0x%08x\n",
- le32toh(itd->itd_bp_hi[0]),
- le32toh(itd->itd_bp_hi[1]),
- le32toh(itd->itd_bp_hi[2]),
- le32toh(itd->itd_bp_hi[3]),
- le32toh(itd->itd_bp_hi[4]),
- le32toh(itd->itd_bp_hi[5]),
- le32toh(itd->itd_bp_hi[6]));
+ ehci32toh(sc, itd->itd_bp_hi[0]),
+ ehci32toh(sc, itd->itd_bp_hi[1]),
+ ehci32toh(sc, itd->itd_bp_hi[2]),
+ ehci32toh(sc, itd->itd_bp_hi[3]),
+ ehci32toh(sc, itd->itd_bp_hi[4]),
+ ehci32toh(sc, itd->itd_bp_hi[5]),
+ ehci32toh(sc, itd->itd_bp_hi[6]));
}
static void
@@ -936,12 +955,12 @@ ehci_dump_isoc(ehci_softc_t *sc)
sitd = sc->sc_isoc_fs_p_last[pos];
while (itd && max && max--) {
- ehci_dump_itd(itd);
+ ehci_dump_itd(sc, itd);
itd = itd->prev;
}
while (sitd && max && max--) {
- ehci_dump_sitd(sitd);
+ ehci_dump_sitd(sc, sitd);
sitd = sitd->prev;
}
}
@@ -1022,6 +1041,11 @@ _ehci_append_qh(ehci_qh_t *sqh, ehci_qh_t *last)
{
DPRINTFN(11, "%p to %p\n", sqh, last);
+ if (sqh->prev != NULL) {
+ /* should not happen */
+ DPRINTFN(0, "QH already linked!\n");
+ return (last);
+ }
/* (sc->sc_bus.mtx) must be locked */
sqh->next = last->next;
@@ -1040,12 +1064,6 @@ _ehci_append_qh(ehci_qh_t *sqh, ehci_qh_t *last)
usb2_pc_cpu_flush(last->page_cache);
-#if USB_DEBUG
- if (ehcidebug > 5) {
- printf("%s:\n", __FUNCTION__);
- ehci_dump_sqh(sqh);
- }
-#endif
return (sqh);
}
@@ -1109,14 +1127,6 @@ _ehci_remove_qh(ehci_qh_t *sqh, ehci_qh_t *last)
sqh->next->prev = sqh->prev;
usb2_pc_cpu_flush(sqh->next->page_cache);
}
- /*
- * set the Terminate-bit in the e_next of the QH, in case
- * the transferred packet was short so that the QH still
- * points at the last used TD
- */
-
- sqh->qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
-
last = ((last == sqh) ? sqh->prev : last);
sqh->prev = 0;
@@ -1129,6 +1139,7 @@ _ehci_remove_qh(ehci_qh_t *sqh, ehci_qh_t *last)
static usb2_error_t
ehci_non_isoc_done_sub(struct usb2_xfer *xfer)
{
+ ehci_softc_t *sc = xfer->usb2_sc;
ehci_qtd_t *td;
ehci_qtd_t *td_alt_next;
uint32_t status;
@@ -1140,7 +1151,7 @@ ehci_non_isoc_done_sub(struct usb2_xfer *xfer)
while (1) {
usb2_pc_cpu_invalidate(td->page_cache);
- status = le32toh(td->qtd_status);
+ status = ehci32toh(sc, td->qtd_status);
len = EHCI_QTD_GET_BYTES(status);
@@ -1232,7 +1243,9 @@ ehci_non_isoc_done(struct usb2_xfer *xfer)
#if USB_DEBUG
if (ehcidebug > 10) {
- ehci_dump_sqtds(xfer->td_transfer_first);
+ ehci_softc_t *sc = xfer->usb2_sc;
+
+ ehci_dump_sqtds(sc, xfer->td_transfer_first);
}
#endif
@@ -1282,6 +1295,7 @@ static uint8_t
ehci_check_transfer(struct usb2_xfer *xfer)
{
struct usb2_pipe_methods *methods = xfer->pipe->methods;
+ ehci_softc_t *sc = xfer->usb2_sc;
uint32_t status;
@@ -1294,13 +1308,13 @@ ehci_check_transfer(struct usb2_xfer *xfer)
td = xfer->td_transfer_last;
usb2_pc_cpu_invalidate(td->page_cache);
- status = le32toh(td->sitd_status);
+ status = ehci32toh(sc, td->sitd_status);
/* also check if first is complete */
td = xfer->td_transfer_first;
usb2_pc_cpu_invalidate(td->page_cache);
- status |= le32toh(td->sitd_status);
+ status |= ehci32toh(sc, td->sitd_status);
if (!(status & EHCI_SITD_ACTIVE)) {
ehci_device_done(xfer, USB_ERR_NORMAL_COMPLETION);
@@ -1329,7 +1343,7 @@ ehci_check_transfer(struct usb2_xfer *xfer)
td->itd_status[6] | td->itd_status[7];
/* if no transactions are active we continue */
- if (!(status & htole32(EHCI_ITD_ACTIVE))) {
+ if (!(status & htoehci32(sc, EHCI_ITD_ACTIVE))) {
ehci_device_done(xfer, USB_ERR_NORMAL_COMPLETION);
goto transferred;
}
@@ -1346,7 +1360,7 @@ ehci_check_transfer(struct usb2_xfer *xfer)
while (1) {
usb2_pc_cpu_invalidate(td->page_cache);
- status = le32toh(td->qtd_status);
+ status = ehci32toh(sc, td->qtd_status);
/*
* if there is an active TD the transfer isn't done
@@ -1520,7 +1534,7 @@ ehci_timeout(void *arg)
static void
ehci_do_poll(struct usb2_bus *bus)
{
- struct ehci_softc *sc = EHCI_BUS2SC(bus);
+ ehci_softc_t *sc = EHCI_BUS2SC(bus);
USB_BUS_LOCK(&sc->sc_bus);
ehci_interrupt_poll(sc);
@@ -1542,7 +1556,7 @@ ehci_setup_standard_chain_sub(struct ehci_std_temp *temp)
uint8_t shortpkt_old;
uint8_t precompute;
- qtd_altnext = htole32(EHCI_LINK_TERMINATE);
+ qtd_altnext = htoehci32(temp->sc, EHCI_LINK_TERMINATE);
td_alt_next = NULL;
buf_offset = 0;
shortpkt_old = temp->shortpkt;
@@ -1599,7 +1613,8 @@ restart:
/* fill out current TD */
td->qtd_status =
- temp->qtd_status | htole32(EHCI_QTD_SET_BYTES(average));
+ temp->qtd_status |
+ htoehci32(temp->sc, EHCI_QTD_SET_BYTES(average));
if (average == 0) {
@@ -1607,7 +1622,8 @@ restart:
/* update data toggle, ZLP case */
- temp->qtd_status ^= htole32(EHCI_QTD_TOGGLE_MASK);
+ temp->qtd_status ^=
+ htoehci32(temp->sc, EHCI_QTD_TOGGLE_MASK);
}
td->len = 0;
@@ -1627,7 +1643,8 @@ restart:
if (((average + temp->max_frame_size - 1) /
temp->max_frame_size) & 1) {
- temp->qtd_status ^= htole32(EHCI_QTD_TOGGLE_MASK);
+ temp->qtd_status ^=
+ htoehci32(temp->sc, EHCI_QTD_TOGGLE_MASK);
}
}
td->len = average;
@@ -1639,7 +1656,8 @@ restart:
/* fill out buffer pointers */
usb2_get_page(temp->pc, buf_offset, &buf_res);
- td->qtd_buffer[0] = htole32(buf_res.physaddr);
+ td->qtd_buffer[0] =
+ htoehci32(temp->sc, buf_res.physaddr);
td->qtd_buffer_hi[0] = 0;
x = 1;
@@ -1648,7 +1666,9 @@ restart:
average -= EHCI_PAGE_SIZE;
buf_offset += EHCI_PAGE_SIZE;
usb2_get_page(temp->pc, buf_offset, &buf_res);
- td->qtd_buffer[x] = htole32(buf_res.physaddr & (~0xFFF));
+ td->qtd_buffer[x] =
+ htoehci32(temp->sc,
+ buf_res.physaddr & (~0xFFF));
td->qtd_buffer_hi[x] = 0;
x++;
}
@@ -1663,7 +1683,9 @@ restart:
*/
buf_offset += average;
usb2_get_page(temp->pc, buf_offset - 1, &buf_res);
- td->qtd_buffer[x] = htole32(buf_res.physaddr & (~0xFFF));
+ td->qtd_buffer[x] =
+ htoehci32(temp->sc,
+ buf_res.physaddr & (~0xFFF));
td->qtd_buffer_hi[x] = 0;
}
@@ -1717,6 +1739,7 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last)
temp.average = xfer->max_usb2_frame_size;
temp.max_frame_size = xfer->max_frame_size;
+ temp.sc = xfer->usb2_sc;
/* toggle the DMA set we are using */
xfer->flags_int.curr_dma_set ^= 1;
@@ -1736,7 +1759,8 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last)
if (xfer->flags_int.control_xfr) {
if (xfer->pipe->toggle_next) {
/* DATA1 is next */
- temp.qtd_status |= htole32(EHCI_QTD_SET_TOGGLE(1));
+ temp.qtd_status |=
+ htoehci32(temp.sc, EHCI_QTD_SET_TOGGLE(1));
}
temp.auto_data_toggle = 0;
} else {
@@ -1745,14 +1769,16 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last)
if (usb2_get_speed(xfer->udev) != USB_SPEED_HIGH) {
/* max 3 retries */
- temp.qtd_status |= htole32(EHCI_QTD_SET_CERR(3));
+ temp.qtd_status |=
+ htoehci32(temp.sc, EHCI_QTD_SET_CERR(3));
}
/* check if we should prepend a setup message */
if (xfer->flags_int.control_xfr) {
if (xfer->flags_int.control_hdr) {
- temp.qtd_status &= htole32(EHCI_QTD_SET_CERR(3));
+ temp.qtd_status &=
+ htoehci32(temp.sc, EHCI_QTD_SET_CERR(3));
temp.qtd_status |= htole32
(EHCI_QTD_ACTIVE |
EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) |
@@ -1783,7 +1809,8 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last)
}
/* keep previous data toggle and error count */
- temp.qtd_status &= htole32(EHCI_QTD_SET_CERR(3) |
+ temp.qtd_status &=
+ htoehci32(temp.sc, EHCI_QTD_SET_CERR(3) |
EHCI_QTD_SET_TOGGLE(1));
if (temp.len == 0) {
@@ -1803,9 +1830,9 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last)
temp.qtd_status |=
(UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) ?
- htole32(EHCI_QTD_ACTIVE |
+ htoehci32(temp.sc, EHCI_QTD_ACTIVE |
EHCI_QTD_SET_PID(EHCI_QTD_PID_IN)) :
- htole32(EHCI_QTD_ACTIVE |
+ htoehci32(temp.sc, EHCI_QTD_ACTIVE |
EHCI_QTD_SET_PID(EHCI_QTD_PID_OUT));
ehci_setup_standard_chain_sub(&temp);
@@ -1821,14 +1848,14 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last)
* direction.
*/
- temp.qtd_status &= htole32(EHCI_QTD_SET_CERR(3) |
+ temp.qtd_status &= htoehci32(temp.sc, EHCI_QTD_SET_CERR(3) |
EHCI_QTD_SET_TOGGLE(1));
temp.qtd_status |=
(UE_GET_DIR(xfer->endpoint) == UE_DIR_OUT) ?
- htole32(EHCI_QTD_ACTIVE |
+ htoehci32(temp.sc, EHCI_QTD_ACTIVE |
EHCI_QTD_SET_PID(EHCI_QTD_PID_IN) |
EHCI_QTD_SET_TOGGLE(1)) :
- htole32(EHCI_QTD_ACTIVE |
+ htoehci32(temp.sc, EHCI_QTD_ACTIVE |
EHCI_QTD_SET_PID(EHCI_QTD_PID_OUT) |
EHCI_QTD_SET_TOGGLE(1));
@@ -1841,9 +1868,9 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last)
td = temp.td;
/* the last TD terminates the transfer: */
- td->qtd_next = htole32(EHCI_LINK_TERMINATE);
- td->qtd_altnext = htole32(EHCI_LINK_TERMINATE);
- td->qtd_status |= htole32(EHCI_QTD_IOC);
+ td->qtd_next = htoehci32(temp.sc, EHCI_LINK_TERMINATE);
+ td->qtd_altnext = htoehci32(temp.sc, EHCI_LINK_TERMINATE);
+ td->qtd_status |= htoehci32(temp.sc, EHCI_QTD_IOC);
usb2_pc_cpu_flush(td->page_cache);
@@ -1855,7 +1882,8 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last)
if (ehcidebug > 8) {
DPRINTF("nexttog=%d; data before transfer:\n",
xfer->pipe->toggle_next);
- ehci_dump_sqtds(xfer->td_transfer_first);
+ ehci_dump_sqtds(temp.sc,
+ xfer->td_transfer_first);
}
#endif
@@ -1892,7 +1920,7 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last)
}
}
- qh->qh_endp = htole32(qh_endp);
+ qh->qh_endp = htoehci32(temp.sc, qh_endp);
qh_endphub =
(EHCI_QH_SET_MULT(xfer->max_packet_count & 3) |
@@ -1901,38 +1929,42 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last)
EHCI_QH_SET_HUBA(xfer->udev->hs_hub_addr) |
EHCI_QH_SET_PORT(xfer->udev->hs_port_no));
- qh->qh_endphub = htole32(qh_endphub);
- qh->qh_curqtd = htole32(0);
+ qh->qh_endphub = htoehci32(temp.sc, qh_endphub);
+ qh->qh_curqtd = htoehci32(temp.sc, 0);
/* fill the overlay qTD */
- qh->qh_qtd.qtd_status = htole32(0);
+ qh->qh_qtd.qtd_status = htoehci32(temp.sc, 0);
if (temp.auto_data_toggle) {
/* let the hardware compute the data toggle */
- qh->qh_endp &= ~htole32(EHCI_QH_DTC);
+ qh->qh_endp &= htoehci32(temp.sc, ~EHCI_QH_DTC);
if (xfer->pipe->toggle_next) {
/* DATA1 is next */
- qh->qh_qtd.qtd_status |= htole32(EHCI_QTD_SET_TOGGLE(1));
+ qh->qh_qtd.qtd_status |=
+ htoehci32(temp.sc, EHCI_QTD_SET_TOGGLE(1));
}
}
td = xfer->td_transfer_first;
qh->qh_qtd.qtd_next = td->qtd_self;
- qh->qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
+ qh->qh_qtd.qtd_altnext =
+ htoehci32(temp.sc, EHCI_LINK_TERMINATE);
usb2_pc_cpu_flush(qh->page_cache);
- EHCI_APPEND_QH(qh, *qh_last);
+ if (xfer->udev->pwr_save.suspended == 0) {
+ EHCI_APPEND_QH(qh, *qh_last);
+ }
}
static void
ehci_root_intr_done(struct usb2_xfer *xfer,
struct usb2_sw_transfer *std)
{
- struct ehci_softc *sc = xfer->usb2_sc;
+ ehci_softc_t *sc = xfer->usb2_sc;
uint16_t i;
uint16_t m;
@@ -1992,11 +2024,11 @@ ehci_isoc_fs_done(ehci_softc_t *sc, struct usb2_xfer *xfer)
#if USB_DEBUG
if (ehcidebug > 15) {
DPRINTF("isoc FS-TD\n");
- ehci_dump_sitd(td);
+ ehci_dump_sitd(sc, td);
}
#endif
usb2_pc_cpu_invalidate(td->page_cache);
- status = le32toh(td->sitd_status);
+ status = ehci32toh(sc, td->sitd_status);
len = EHCI_SITD_GET_LEN(status);
@@ -2044,12 +2076,12 @@ ehci_isoc_hs_done(ehci_softc_t *sc, struct usb2_xfer *xfer)
#if USB_DEBUG
if (ehcidebug > 15) {
DPRINTF("isoc HS-TD\n");
- ehci_dump_itd(td);
+ ehci_dump_itd(sc, td);
}
#endif
usb2_pc_cpu_invalidate(td->page_cache);
- status = le32toh(td->itd_status[td_no]);
+ status = ehci32toh(sc, td->itd_status[td_no]);
len = EHCI_ITD_GET_LEN(status);
@@ -2102,7 +2134,8 @@ ehci_device_done(struct usb2_xfer *xfer, usb2_error_t error)
if (ehcidebug > 8) {
DPRINTF("nexttog=%d; data after transfer:\n",
xfer->pipe->toggle_next);
- ehci_dump_sqtds(xfer->td_transfer_first);
+ ehci_dump_sqtds(xfer->usb2_sc,
+ xfer->td_transfer_first);
}
#endif
@@ -2322,6 +2355,7 @@ struct usb2_pipe_methods ehci_device_intr_methods =
static void
ehci_device_isoc_fs_open(struct usb2_xfer *xfer)
{
+ ehci_softc_t *sc = xfer->usb2_sc;
ehci_sitd_t *td;
uint32_t sitd_portaddr;
uint8_t ds;
@@ -2335,7 +2369,7 @@ ehci_device_isoc_fs_open(struct usb2_xfer *xfer)
if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) {
sitd_portaddr |= EHCI_SITD_SET_DIR_IN;
}
- sitd_portaddr = htole32(sitd_portaddr);
+ sitd_portaddr = htoehci32(sc, sitd_portaddr);
/* initialize all TD's */
@@ -2352,7 +2386,7 @@ ehci_device_isoc_fs_open(struct usb2_xfer *xfer)
*
* micro-frame usage (8 microframes per 1ms)
*/
- td->sitd_back = htole32(EHCI_LINK_TERMINATE);
+ td->sitd_back = htoehci32(sc, EHCI_LINK_TERMINATE);
usb2_pc_cpu_flush(td->page_cache);
}
@@ -2499,7 +2533,7 @@ ehci_device_isoc_fs_enter(struct usb2_xfer *xfer)
* non-zero length
*/
usb2_get_page(xfer->frbuffers, buf_offset, &buf_res);
- td->sitd_bp[0] = htole32(buf_res.physaddr);
+ td->sitd_bp[0] = htoehci32(sc, buf_res.physaddr);
buf_offset += *plen;
/*
* NOTE: We need to subtract one from the offset so
@@ -2544,9 +2578,9 @@ ehci_device_isoc_fs_enter(struct usb2_xfer *xfer)
sitd_mask = (EHCI_SITD_SET_SMASK(sa) |
EHCI_SITD_SET_CMASK(sb));
- td->sitd_bp[1] = htole32(temp);
+ td->sitd_bp[1] = htoehci32(sc, temp);
- td->sitd_mask = htole32(sitd_mask);
+ td->sitd_mask = htoehci32(sc, sitd_mask);
if (nframes == 0) {
td->sitd_status = htole32
@@ -2563,7 +2597,7 @@ ehci_device_isoc_fs_enter(struct usb2_xfer *xfer)
#if USB_DEBUG
if (ehcidebug > 15) {
DPRINTF("FS-TD %d\n", nframes);
- ehci_dump_sitd(td);
+ ehci_dump_sitd(sc, td);
}
#endif
/* insert TD into schedule */
@@ -2606,6 +2640,7 @@ struct usb2_pipe_methods ehci_device_isoc_fs_methods =
static void
ehci_device_isoc_hs_open(struct usb2_xfer *xfer)
{
+ ehci_softc_t *sc = xfer->usb2_sc;
ehci_itd_t *td;
uint32_t temp;
uint8_t ds;
@@ -2639,10 +2674,10 @@ ehci_device_isoc_hs_open(struct usb2_xfer *xfer)
temp |= EHCI_ITD_SET_DIR_IN;
}
/* set maximum packet size */
- td->itd_bp[1] = htole32(temp);
+ td->itd_bp[1] = htoehci32(sc, temp);
/* set transfer multiplier */
- td->itd_bp[2] = htole32(xfer->max_packet_count & 3);
+ td->itd_bp[2] = htoehci32(sc, xfer->max_packet_count & 3);
usb2_pc_cpu_flush(td->page_cache);
}
@@ -2764,7 +2799,7 @@ ehci_device_isoc_hs_enter(struct usb2_xfer *xfer)
status = (EHCI_ITD_SET_LEN(*plen) |
EHCI_ITD_ACTIVE |
EHCI_ITD_SET_PG(0));
- td->itd_status[td_no] = htole32(status);
+ td->itd_status[td_no] = htoehci32(sc, status);
itd_offset[td_no] = buf_offset;
buf_offset += *plen;
plen++;
@@ -2787,14 +2822,14 @@ ehci_device_isoc_hs_enter(struct usb2_xfer *xfer)
/* get page address */
page_addr = buf_res.physaddr & ~0xFFF;
/* update page address */
- td->itd_bp[0] &= htole32(0xFFF);
- td->itd_bp[0] |= htole32(page_addr);
+ td->itd_bp[0] &= htoehci32(sc, 0xFFF);
+ td->itd_bp[0] |= htoehci32(sc, page_addr);
for (x = 0; x != td_no; x++) {
/* set page number and page offset */
status = (EHCI_ITD_SET_PG(page_no) |
(buf_res.physaddr & 0xFFF));
- td->itd_status[x] |= htole32(status);
+ td->itd_status[x] |= htoehci32(sc, status);
/* get next page offset */
if (itd_offset[x + 1] == buf_offset) {
@@ -2817,20 +2852,20 @@ ehci_device_isoc_hs_enter(struct usb2_xfer *xfer)
}
page_no++;
/* update page address */
- td->itd_bp[page_no] &= htole32(0xFFF);
- td->itd_bp[page_no] |= htole32(page_addr);
+ td->itd_bp[page_no] &= htoehci32(sc, 0xFFF);
+ td->itd_bp[page_no] |= htoehci32(sc, page_addr);
}
}
}
/* set IOC bit if we are complete */
if (nframes == 0) {
- td->itd_status[7] |= htole32(EHCI_ITD_IOC);
+ td->itd_status[7] |= htoehci32(sc, EHCI_ITD_IOC);
}
usb2_pc_cpu_flush(td->page_cache);
#if USB_DEBUG
if (ehcidebug > 15) {
DPRINTF("HS-TD %d\n", nframes);
- ehci_dump_itd(td);
+ ehci_dump_itd(sc, td);
}
#endif
/* insert TD into schedule */
@@ -3001,7 +3036,7 @@ ehci_root_ctrl_start(struct usb2_xfer *xfer)
}
static void
-ehci_root_ctrl_task(struct ehci_softc *sc,
+ehci_root_ctrl_task(ehci_softc_t *sc,
struct usb2_config_td_cc *cc, uint16_t refcount)
{
ehci_root_ctrl_poll(sc);
@@ -3011,7 +3046,7 @@ static void
ehci_root_ctrl_done(struct usb2_xfer *xfer,
struct usb2_sw_transfer *std)
{
- struct ehci_softc *sc = xfer->usb2_sc;
+ ehci_softc_t *sc = xfer->usb2_sc;
char *ptr;
uint32_t port;
uint32_t v;
@@ -3176,7 +3211,32 @@ ehci_root_ctrl_done(struct usb2_xfer *xfer,
EOWRITE4(sc, port, v & ~EHCI_PS_PE);
break;
case UHF_PORT_SUSPEND:
- EOWRITE4(sc, port, v & ~EHCI_PS_SUSP);
+ if ((v & EHCI_PS_SUSP) && (!(v & EHCI_PS_FPR))) {
+
+ /*
+ * waking up a High Speed device is rather
+ * complicated if
+ */
+ EOWRITE4(sc, port, v | EHCI_PS_FPR);
+ }
+ /* wait 20ms for resume sequence to complete */
+ if (use_polling) {
+ /* polling */
+ DELAY(20 * 1000);
+ } else {
+ usb2_pause_mtx(&sc->sc_bus.bus_mtx, 20);
+ }
+
+ EOWRITE4(sc, port, v & ~(EHCI_PS_SUSP |
+ EHCI_PS_FPR | (3 << 10) /* High Speed */ ));
+
+ /* settle time */
+ if (use_polling) {
+ /* polling */
+ DELAY(4 * 1000);
+ } else {
+ usb2_pause_mtx(&sc->sc_bus.bus_mtx, 4);
+ }
break;
case UHF_PORT_POWER:
EOWRITE4(sc, port, v & ~EHCI_PS_PP);
@@ -3223,7 +3283,8 @@ ehci_root_ctrl_done(struct usb2_xfer *xfer,
(EHCI_HCS_PPC(v) ? UHD_PWR_INDIVIDUAL : UHD_PWR_NO_SWITCH) |
(EHCI_HCS_P_INDICATOR(EREAD4(sc, EHCI_HCSPARAMS)) ?
UHD_PORT_IND : 0));
- sc->sc_hub_desc.hubd.bPwrOn2PwrGood = 200; /* XXX can't find out? */
+ /* XXX can't find out? */
+ sc->sc_hub_desc.hubd.bPwrOn2PwrGood = 200;
for (l = 0; l < sc->sc_noport; l++) {
/* XXX can't find out? */
sc->sc_hub_desc.hubd.DeviceRemovable[l / 8] &= ~(1 << (l % 8));
@@ -3260,7 +3321,7 @@ ehci_root_ctrl_done(struct usb2_xfer *xfer,
i |= UPS_CURRENT_CONNECT_STATUS;
if (v & EHCI_PS_PE)
i |= UPS_PORT_ENABLED;
- if (v & EHCI_PS_SUSP)
+ if ((v & EHCI_PS_SUSP) && !(v & EHCI_PS_FPR))
i |= UPS_SUSPEND;
if (v & EHCI_PS_OCA)
i |= UPS_OVERCURRENT_INDICATOR;
@@ -3276,6 +3337,8 @@ ehci_root_ctrl_done(struct usb2_xfer *xfer,
i |= UPS_C_PORT_ENABLED;
if (v & EHCI_PS_OCC)
i |= UPS_C_OVERCURRENT_INDICATOR;
+ if (v & EHCI_PS_FPR)
+ i |= UPS_C_SUSPEND;
if (sc->sc_isreset)
i |= UPS_C_PORT_RESET;
USETW(sc->sc_hub_desc.ps.wPortChange, i);
@@ -3398,7 +3461,7 @@ done:
}
static void
-ehci_root_ctrl_poll(struct ehci_softc *sc)
+ehci_root_ctrl_poll(ehci_softc_t *sc)
{
usb2_sw_transfer(&sc->sc_root_ctrl,
&ehci_root_ctrl_done);
@@ -3621,7 +3684,7 @@ alloc_dma_set:
td = page_info.buffer;
/* init TD */
- td->itd_self = htole32(page_info.physaddr | EHCI_LINK_ITD);
+ td->itd_self = htoehci32(sc, page_info.physaddr | EHCI_LINK_ITD);
td->obj_next = last_obj;
td->page_cache = pc + n;
@@ -3645,7 +3708,7 @@ alloc_dma_set:
td = page_info.buffer;
/* init TD */
- td->sitd_self = htole32(page_info.physaddr | EHCI_LINK_SITD);
+ td->sitd_self = htoehci32(sc, page_info.physaddr | EHCI_LINK_SITD);
td->obj_next = last_obj;
td->page_cache = pc + n;
@@ -3669,7 +3732,7 @@ alloc_dma_set:
qtd = page_info.buffer;
/* init TD */
- qtd->qtd_self = htole32(page_info.physaddr);
+ qtd->qtd_self = htoehci32(sc, page_info.physaddr);
qtd->obj_next = last_obj;
qtd->page_cache = pc + n;
@@ -3697,7 +3760,7 @@ alloc_dma_set:
qh = page_info.buffer;
/* init QH */
- qh->qh_self = htole32(page_info.physaddr | EHCI_LINK_QH);
+ qh->qh_self = htoehci32(sc, page_info.physaddr | EHCI_LINK_QH);
qh->obj_next = last_obj;
qh->page_cache = pc + n;
@@ -3794,6 +3857,108 @@ ehci_get_dma_delay(struct usb2_bus *bus, uint32_t *pus)
*pus = (188); /* microseconds */
}
+static void
+ehci_device_resume(struct usb2_device *udev)
+{
+ ehci_softc_t *sc = EHCI_BUS2SC(udev->bus);
+ struct usb2_xfer *xfer;
+ struct usb2_pipe_methods *methods;
+
+ DPRINTF("\n");
+
+ USB_BUS_LOCK(udev->bus);
+
+ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+ if (xfer->udev == udev) {
+
+ methods = xfer->pipe->methods;
+
+ if ((methods == &ehci_device_bulk_methods) ||
+ (methods == &ehci_device_ctrl_methods)) {
+ EHCI_APPEND_QH(xfer->qh_start[xfer->flags_int.curr_dma_set],
+ sc->sc_async_p_last);
+ }
+ if (methods == &ehci_device_intr_methods) {
+ EHCI_APPEND_QH(xfer->qh_start[xfer->flags_int.curr_dma_set],
+ sc->sc_intr_p_last[xfer->qh_pos]);
+ }
+ }
+ }
+
+ USB_BUS_UNLOCK(udev->bus);
+
+ return;
+}
+
+static void
+ehci_device_suspend(struct usb2_device *udev)
+{
+ ehci_softc_t *sc = EHCI_BUS2SC(udev->bus);
+ struct usb2_xfer *xfer;
+ struct usb2_pipe_methods *methods;
+
+ DPRINTF("\n");
+
+ USB_BUS_LOCK(udev->bus);
+
+ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+ if (xfer->udev == udev) {
+
+ methods = xfer->pipe->methods;
+
+ if ((methods == &ehci_device_bulk_methods) ||
+ (methods == &ehci_device_ctrl_methods)) {
+ EHCI_REMOVE_QH(xfer->qh_start[xfer->flags_int.curr_dma_set],
+ sc->sc_async_p_last);
+ }
+ if (methods == &ehci_device_intr_methods) {
+ EHCI_REMOVE_QH(xfer->qh_start[xfer->flags_int.curr_dma_set],
+ sc->sc_intr_p_last[xfer->qh_pos]);
+ }
+ }
+ }
+
+ USB_BUS_UNLOCK(udev->bus);
+
+ return;
+}
+
+static void
+ehci_set_hw_power(struct usb2_bus *bus)
+{
+ ehci_softc_t *sc = EHCI_BUS2SC(bus);
+ uint32_t temp;
+ uint32_t flags;
+
+ DPRINTF("\n");
+
+ USB_BUS_LOCK(bus);
+
+ flags = bus->hw_power_state;
+
+ temp = EOREAD4(sc, EHCI_USBCMD);
+
+ temp &= ~(EHCI_CMD_ASE | EHCI_CMD_PSE);
+
+ if (flags & (USB_HW_POWER_CONTROL |
+ USB_HW_POWER_BULK)) {
+ DPRINTF("Async is active\n");
+ temp |= EHCI_CMD_ASE;
+ }
+ if (flags & (USB_HW_POWER_INTERRUPT |
+ USB_HW_POWER_ISOC)) {
+ DPRINTF("Periodic is active\n");
+ temp |= EHCI_CMD_PSE;
+ }
+ EOWRITE4(sc, EHCI_USBCMD, temp);
+
+ USB_BUS_UNLOCK(bus);
+
+ return;
+}
+
struct usb2_bus_methods ehci_bus_methods =
{
.pipe_init = ehci_pipe_init,
@@ -3801,4 +3966,7 @@ struct usb2_bus_methods ehci_bus_methods =
.xfer_unsetup = ehci_xfer_unsetup,
.do_poll = ehci_do_poll,
.get_dma_delay = ehci_get_dma_delay,
+ .device_resume = ehci_device_resume,
+ .device_suspend = ehci_device_suspend,
+ .set_hw_power = ehci_set_hw_power,
};
diff --git a/sys/dev/usb2/controller/ehci2.h b/sys/dev/usb2/controller/ehci2.h
index 6765ace..3dee6bd 100644
--- a/sys/dev/usb2/controller/ehci2.h
+++ b/sys/dev/usb2/controller/ehci2.h
@@ -160,6 +160,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 */
/*
@@ -469,11 +478,12 @@ typedef struct ehci_softc {
uint16_t sc_intr_stat[EHCI_VIRTUAL_FRAMELIST_COUNT];
uint16_t sc_id_vendor; /* vendor ID for root hub */
uint16_t sc_flags; /* chip specific flags */
-#define EHCI_SCFLG_SETMODE 0x0001 /* set bridge mode again after init
- * (Marvell) */
-#define EHCI_SCFLG_FORCESPEED 0x0002 /* force speed (Marvell) */
-#define EHCI_SCFLG_NORESTERM 0x0004 /* don't terminate reset sequence
- * (Marvell) */
+#define EHCI_SCFLG_SETMODE 0x0001 /* set bridge mode again after init */
+#define EHCI_SCFLG_FORCESPEED 0x0002 /* force speed */
+#define EHCI_SCFLG_NORESTERM 0x0004 /* don't terminate reset sequence */
+#define EHCI_SCFLG_BIGEDESC 0x0008 /* big-endian byte order descriptors */
+#define EHCI_SCFLG_BIGEMMIO 0x0010 /* big-endian byte order MMIO */
+#define EHCI_SCFLG_TT 0x0020 /* transaction translator present */
uint8_t sc_offs; /* offset to operational registers */
uint8_t sc_doorbell_disable; /* set on doorbell failure */
diff --git a/sys/dev/usb2/controller/musb2_otg.c b/sys/dev/usb2/controller/musb2_otg.c
index e7119bf..e2a36e3 100644
--- a/sys/dev/usb2/controller/musb2_otg.c
+++ b/sys/dev/usb2/controller/musb2_otg.c
@@ -236,12 +236,6 @@ musbotg_wakeup_peer(struct usb2_xfer *xfer)
}
static void
-musbotg_rem_wakeup_set(struct usb2_device *udev, uint8_t is_on)
-{
- DPRINTFN(4, "is_on=%u\n", is_on);
-}
-
-static void
musbotg_set_address(struct musbotg_softc *sc, uint8_t addr)
{
DPRINTFN(4, "addr=%d\n", addr);
@@ -2891,5 +2885,4 @@ struct usb2_bus_methods musbotg_bus_methods =
.set_stall = &musbotg_set_stall,
.clear_stall = &musbotg_clear_stall,
.vbus_interrupt = &musbotg_vbus_interrupt,
- .rem_wakeup_set = &musbotg_rem_wakeup_set,
};
diff --git a/sys/dev/usb2/controller/ohci2.c b/sys/dev/usb2/controller/ohci2.c
index b3f2f0e..99076d4 100644
--- a/sys/dev/usb2/controller/ohci2.c
+++ b/sys/dev/usb2/controller/ohci2.c
@@ -681,18 +681,22 @@ ohci_transfer_intr_enqueue(struct usb2_xfer *xfer)
}
}
-#define OHCI_APPEND_QH(sed,td_self,last) (last) = _ohci_append_qh(sed,td_self,last)
+#define OHCI_APPEND_QH(sed,last) (last) = _ohci_append_qh(sed,last)
static ohci_ed_t *
-_ohci_append_qh(ohci_ed_t *sed, uint32_t td_self, ohci_ed_t *last)
+_ohci_append_qh(ohci_ed_t *sed, ohci_ed_t *last)
{
DPRINTFN(11, "%p to %p\n", sed, last);
+ if (sed->prev != NULL) {
+ /* should not happen */
+ DPRINTFN(0, "ED already linked!\n");
+ return (last);
+ }
/* (sc->sc_bus.bus_mtx) must be locked */
sed->next = last->next;
sed->ed_next = last->ed_next;
sed->ed_tailp = 0;
- sed->ed_headp = td_self;
sed->prev = last;
@@ -730,13 +734,6 @@ _ohci_remove_qh(ohci_ed_t *sed, ohci_ed_t *last)
sed->next->prev = sed->prev;
usb2_pc_cpu_flush(sed->next->page_cache);
}
- /*
- * terminate transfer in case the transferred packet was
- * short so that the ED still points at the last used TD
- */
- sed->ed_flags |= htole32(OHCI_ED_SKIP);
- sed->ed_headp = sed->ed_tailp;
-
last = ((last == sed) ? sed->prev : last);
sed->prev = 0;
@@ -1565,17 +1562,23 @@ ohci_setup_standard_chain(struct usb2_xfer *xfer, ohci_ed_t **ed_last)
td = xfer->td_transfer_first;
- OHCI_APPEND_QH(ed, td->td_self, *ed_last);
+ ed->ed_headp = td->td_self;
- if (methods == &ohci_device_bulk_methods) {
- ohci_softc_t *sc = xfer->usb2_sc;
+ if (xfer->udev->pwr_save.suspended == 0) {
+ OHCI_APPEND_QH(ed, *ed_last);
- OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
- }
- if (methods == &ohci_device_ctrl_methods) {
- ohci_softc_t *sc = xfer->usb2_sc;
+ if (methods == &ohci_device_bulk_methods) {
+ ohci_softc_t *sc = xfer->usb2_sc;
- OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
+ OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
+ }
+ if (methods == &ohci_device_ctrl_methods) {
+ ohci_softc_t *sc = xfer->usb2_sc;
+
+ OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
+ }
+ } else {
+ usb2_pc_cpu_flush(ed->page_cache);
}
}
@@ -2010,7 +2013,11 @@ ohci_device_isoc_enter(struct usb2_xfer *xfer)
td = xfer->td_transfer_first;
- OHCI_APPEND_QH(ed, td->itd_self, sc->sc_isoc_p_last);
+ ed->ed_headp = td->itd_self;
+
+ /* isochronous transfers are not affected by suspend / resume */
+
+ OHCI_APPEND_QH(ed, sc->sc_isoc_p_last);
}
static void
@@ -2740,6 +2747,115 @@ ohci_get_dma_delay(struct usb2_bus *bus, uint32_t *pus)
*pus = (1125); /* microseconds */
}
+static void
+ohci_device_resume(struct usb2_device *udev)
+{
+ struct ohci_softc *sc = OHCI_BUS2SC(udev->bus);
+ struct usb2_xfer *xfer;
+ struct usb2_pipe_methods *methods;
+ ohci_ed_t *ed;
+
+ DPRINTF("\n");
+
+ USB_BUS_LOCK(udev->bus);
+
+ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+ if (xfer->udev == udev) {
+
+ methods = xfer->pipe->methods;
+ ed = xfer->qh_start[xfer->flags_int.curr_dma_set];
+
+ if (methods == &ohci_device_bulk_methods) {
+ OHCI_APPEND_QH(ed, sc->sc_bulk_p_last);
+ OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
+ }
+ if (methods == &ohci_device_ctrl_methods) {
+ OHCI_APPEND_QH(ed, sc->sc_ctrl_p_last);
+ OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
+ }
+ if (methods == &ohci_device_intr_methods) {
+ OHCI_APPEND_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]);
+ }
+ }
+ }
+
+ USB_BUS_UNLOCK(udev->bus);
+
+ return;
+}
+
+static void
+ohci_device_suspend(struct usb2_device *udev)
+{
+ struct ohci_softc *sc = OHCI_BUS2SC(udev->bus);
+ struct usb2_xfer *xfer;
+ struct usb2_pipe_methods *methods;
+ ohci_ed_t *ed;
+
+ DPRINTF("\n");
+
+ USB_BUS_LOCK(udev->bus);
+
+ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+ if (xfer->udev == udev) {
+
+ methods = xfer->pipe->methods;
+ ed = xfer->qh_start[xfer->flags_int.curr_dma_set];
+
+ if (methods == &ohci_device_bulk_methods) {
+ OHCI_REMOVE_QH(ed, sc->sc_bulk_p_last);
+ }
+ if (methods == &ohci_device_ctrl_methods) {
+ OHCI_REMOVE_QH(ed, sc->sc_ctrl_p_last);
+ }
+ if (methods == &ohci_device_intr_methods) {
+ OHCI_REMOVE_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]);
+ }
+ }
+ }
+
+ USB_BUS_UNLOCK(udev->bus);
+
+ return;
+}
+
+static void
+ohci_set_hw_power(struct usb2_bus *bus)
+{
+ struct ohci_softc *sc = OHCI_BUS2SC(bus);
+ uint32_t temp;
+ uint32_t flags;
+
+ DPRINTF("\n");
+
+ USB_BUS_LOCK(bus);
+
+ flags = bus->hw_power_state;
+
+ temp = OREAD4(sc, OHCI_CONTROL);
+ temp &= ~(OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE);
+
+ if (flags & USB_HW_POWER_CONTROL)
+ temp |= OHCI_CLE;
+
+ if (flags & USB_HW_POWER_BULK)
+ temp |= OHCI_BLE;
+
+ if (flags & USB_HW_POWER_INTERRUPT)
+ temp |= OHCI_PLE;
+
+ if (flags & USB_HW_POWER_ISOC)
+ temp |= OHCI_IE | OHCI_PLE;
+
+ OWRITE4(sc, OHCI_CONTROL, temp);
+
+ USB_BUS_UNLOCK(bus);
+
+ return;
+}
+
struct usb2_bus_methods ohci_bus_methods =
{
.pipe_init = ohci_pipe_init,
@@ -2747,4 +2863,7 @@ struct usb2_bus_methods ohci_bus_methods =
.xfer_unsetup = ohci_xfer_unsetup,
.do_poll = ohci_do_poll,
.get_dma_delay = ohci_get_dma_delay,
+ .device_resume = ohci_device_resume,
+ .device_suspend = ohci_device_suspend,
+ .set_hw_power = ohci_set_hw_power,
};
diff --git a/sys/dev/usb2/controller/uhci2.c b/sys/dev/usb2/controller/uhci2.c
index 478e54f..be80619 100644
--- a/sys/dev/usb2/controller/uhci2.c
+++ b/sys/dev/usb2/controller/uhci2.c
@@ -916,17 +916,19 @@ _uhci_append_td(uhci_td_t *std, uhci_td_t *last)
return (std);
}
-#define UHCI_APPEND_QH(sqh,td,last) (last) = _uhci_append_qh(sqh,td,last)
+#define UHCI_APPEND_QH(sqh,last) (last) = _uhci_append_qh(sqh,last)
static uhci_qh_t *
-_uhci_append_qh(uhci_qh_t *sqh, uhci_td_t *td, uhci_qh_t *last)
+_uhci_append_qh(uhci_qh_t *sqh, uhci_qh_t *last)
{
DPRINTFN(11, "%p to %p\n", sqh, last);
+ if (sqh->h_prev != NULL) {
+ /* should not happen */
+ DPRINTFN(0, "QH already linked!\n");
+ return (last);
+ }
/* (sc->sc_bus.mtx) must be locked */
- sqh->e_next = td;
- sqh->qh_e_next = td->td_self;
-
sqh->h_next = last->h_next;
sqh->qh_h_next = last->qh_h_next;
@@ -990,13 +992,6 @@ _uhci_remove_qh(uhci_qh_t *sqh, uhci_qh_t *last)
sqh->h_next->h_prev = sqh->h_prev;
usb2_pc_cpu_flush(sqh->h_next->page_cache);
}
- /*
- * set the Terminate-bit in the e_next of the QH, in case
- * the transferred packet was short so that the QH still
- * points at the last used TD
- */
- sqh->qh_e_next = htole32(UHCI_PTR_T);
-
last = ((last == sqh) ? sqh->h_prev : last);
sqh->h_prev = 0;
@@ -1459,10 +1454,12 @@ uhci_interrupt(uhci_softc_t *sc)
}
if (status & UHCI_STS_HCH) {
/* no acknowledge needed */
- printf("%s: host controller halted\n",
+ DPRINTF("%s: host controller halted\n",
__FUNCTION__);
#if USB_DEBUG
- uhci_dump_all(sc);
+ if (uhcidebug > 0) {
+ uhci_dump_all(sc);
+ }
#endif
}
}
@@ -1834,11 +1831,6 @@ uhci_device_done(struct usb2_xfer *xfer, usb2_error_t error)
qh = xfer->qh_start[xfer->flags_int.curr_dma_set];
if (qh) {
usb2_pc_cpu_invalidate(qh->page_cache);
-
- qh->e_next = 0;
- qh->qh_e_next = htole32(UHCI_PTR_T);
-
- usb2_pc_cpu_flush(qh->page_cache);
}
if (xfer->flags_int.bandwidth_reclaimed) {
xfer->flags_int.bandwidth_reclaimed = 0;
@@ -1907,9 +1899,16 @@ uhci_device_bulk_start(struct usb2_xfer *xfer)
/* setup QH */
qh = xfer->qh_start[xfer->flags_int.curr_dma_set];
- UHCI_APPEND_QH(qh, td, sc->sc_bulk_p_last);
- uhci_add_loop(sc);
- xfer->flags_int.bandwidth_reclaimed = 1;
+ qh->e_next = td;
+ qh->qh_e_next = td->td_self;
+
+ if (xfer->udev->pwr_save.suspended == 0) {
+ UHCI_APPEND_QH(qh, sc->sc_bulk_p_last);
+ uhci_add_loop(sc);
+ xfer->flags_int.bandwidth_reclaimed = 1;
+ } else {
+ usb2_pc_cpu_flush(qh->page_cache);
+ }
/* put transfer on interrupt queue */
uhci_transfer_intr_enqueue(xfer);
@@ -1959,14 +1958,21 @@ uhci_device_ctrl_start(struct usb2_xfer *xfer)
/* setup QH */
qh = xfer->qh_start[xfer->flags_int.curr_dma_set];
+ qh->e_next = td;
+ qh->qh_e_next = td->td_self;
+
/*
* NOTE: some devices choke on bandwidth- reclamation for control
* transfers
*/
- if (xfer->udev->speed == USB_SPEED_LOW) {
- UHCI_APPEND_QH(qh, td, sc->sc_ls_ctl_p_last);
+ if (xfer->udev->pwr_save.suspended == 0) {
+ if (xfer->udev->speed == USB_SPEED_LOW) {
+ UHCI_APPEND_QH(qh, sc->sc_ls_ctl_p_last);
+ } else {
+ UHCI_APPEND_QH(qh, sc->sc_fs_ctl_p_last);
+ }
} else {
- UHCI_APPEND_QH(qh, td, sc->sc_fs_ctl_p_last);
+ usb2_pc_cpu_flush(qh->page_cache);
}
/* put transfer on interrupt queue */
uhci_transfer_intr_enqueue(xfer);
@@ -2047,8 +2053,17 @@ uhci_device_intr_start(struct usb2_xfer *xfer)
/* setup QH */
qh = xfer->qh_start[xfer->flags_int.curr_dma_set];
- /* enter QHs into the controller data structures */
- UHCI_APPEND_QH(qh, td, sc->sc_intr_p_last[xfer->qh_pos]);
+ qh->e_next = td;
+ qh->qh_e_next = td->td_self;
+
+ if (xfer->udev->pwr_save.suspended == 0) {
+
+ /* enter QHs into the controller data structures */
+ UHCI_APPEND_QH(qh, sc->sc_intr_p_last[xfer->qh_pos]);
+
+ } else {
+ usb2_pc_cpu_flush(qh->page_cache);
+ }
/* put transfer on interrupt queue */
uhci_transfer_intr_enqueue(xfer);
@@ -2659,7 +2674,7 @@ uhci_root_ctrl_done(struct usb2_xfer *xfer,
break;
case UHF_PORT_SUSPEND:
x = URWMASK(UREAD2(sc, port));
- UWRITE2(sc, port, x & ~UHCI_PORTSC_SUSP);
+ UWRITE2(sc, port, x & ~(UHCI_PORTSC_SUSP));
break;
case UHF_PORT_RESET:
x = URWMASK(UREAD2(sc, port));
@@ -2681,11 +2696,13 @@ uhci_root_ctrl_done(struct usb2_xfer *xfer,
sc->sc_isreset = 0;
std->err = USB_ERR_NORMAL_COMPLETION;
goto done;
+ case UHF_C_PORT_SUSPEND:
+ sc->sc_isresumed &= ~(1 << index);
+ break;
case UHF_PORT_CONNECTION:
case UHF_PORT_OVER_CURRENT:
case UHF_PORT_POWER:
case UHF_PORT_LOW_SPEED:
- case UHF_C_PORT_SUSPEND:
default:
std->err = USB_ERR_IOERROR;
goto done;
@@ -2740,11 +2757,35 @@ uhci_root_ctrl_done(struct usb2_xfer *xfer,
status |= UPS_OVERCURRENT_INDICATOR;
if (x & UHCI_PORTSC_OCIC)
change |= UPS_C_OVERCURRENT_INDICATOR;
- if (x & UHCI_PORTSC_SUSP)
- status |= UPS_SUSPEND;
if (x & UHCI_PORTSC_LSDA)
status |= UPS_LOW_SPEED;
+ if ((x & UHCI_PORTSC_PE) && (x & UHCI_PORTSC_RD)) {
+ /* need to do a write back */
+ UWRITE2(sc, port, URWMASK(x));
+
+ /* wait 20ms for resume sequence to complete */
+ if (use_polling) {
+ /* polling */
+ DELAY(20 * 1000);
+ } else {
+ usb2_pause_mtx(&sc->sc_bus.bus_mtx, 20);
+ }
+
+ /* clear suspend and resume detect */
+ UWRITE2(sc, port, URWMASK(x) & ~(UHCI_PORTSC_RD |
+ UHCI_PORTSC_SUSP));
+
+ /* wait a little bit */
+ usb2_pause_mtx(&sc->sc_bus.bus_mtx, 2);
+
+ sc->sc_isresumed |= (1 << index);
+
+ } else if (x & UHCI_PORTSC_SUSP) {
+ status |= UPS_SUSPEND;
+ }
status |= UPS_PORT_POWER;
+ if (sc->sc_isresumed & (1 << index))
+ change |= UPS_C_SUSPEND;
if (sc->sc_isreset)
change |= UPS_C_PORT_RESET;
USETW(sc->sc_hub_desc.ps.wPortStatus, status);
@@ -2894,13 +2935,15 @@ uhci_root_intr_check(void *arg)
sc->sc_hub_idata[0] = 0;
- if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC | UHCI_PORTSC_OCIC)) {
+ if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC |
+ UHCI_PORTSC_OCIC | UHCI_PORTSC_RD)) {
sc->sc_hub_idata[0] |= 1 << 1;
}
- if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC | UHCI_PORTSC_OCIC)) {
+ if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC |
+ UHCI_PORTSC_OCIC | UHCI_PORTSC_RD)) {
sc->sc_hub_idata[0] |= 1 << 2;
}
- if ((sc->sc_hub_idata[0] == 0) || !(UREAD2(sc, UHCI_CMD) & UHCI_CMD_RS)) {
+ if (sc->sc_hub_idata[0] == 0) {
/*
* no change or controller not running, try again in a while
*/
@@ -3190,6 +3233,124 @@ uhci_get_dma_delay(struct usb2_bus *bus, uint32_t *pus)
*pus = (1125); /* microseconds */
}
+static void
+uhci_device_resume(struct usb2_device *udev)
+{
+ struct uhci_softc *sc = UHCI_BUS2SC(udev->bus);
+ struct usb2_xfer *xfer;
+ struct usb2_pipe_methods *methods;
+ uhci_qh_t *qh;
+
+ DPRINTF("\n");
+
+ USB_BUS_LOCK(udev->bus);
+
+ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+ if (xfer->udev == udev) {
+
+ methods = xfer->pipe->methods;
+ qh = xfer->qh_start[xfer->flags_int.curr_dma_set];
+
+ if (methods == &uhci_device_bulk_methods) {
+ UHCI_APPEND_QH(qh, sc->sc_bulk_p_last);
+ uhci_add_loop(sc);
+ xfer->flags_int.bandwidth_reclaimed = 1;
+ }
+ if (methods == &uhci_device_ctrl_methods) {
+ if (xfer->udev->speed == USB_SPEED_LOW) {
+ UHCI_APPEND_QH(qh, sc->sc_ls_ctl_p_last);
+ } else {
+ UHCI_APPEND_QH(qh, sc->sc_fs_ctl_p_last);
+ }
+ }
+ if (methods == &uhci_device_intr_methods) {
+ UHCI_APPEND_QH(qh, sc->sc_intr_p_last[xfer->qh_pos]);
+ }
+ }
+ }
+
+ USB_BUS_UNLOCK(udev->bus);
+
+ return;
+}
+
+static void
+uhci_device_suspend(struct usb2_device *udev)
+{
+ struct uhci_softc *sc = UHCI_BUS2SC(udev->bus);
+ struct usb2_xfer *xfer;
+ struct usb2_pipe_methods *methods;
+ uhci_qh_t *qh;
+
+ DPRINTF("\n");
+
+ USB_BUS_LOCK(udev->bus);
+
+ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+ if (xfer->udev == udev) {
+
+ methods = xfer->pipe->methods;
+ qh = xfer->qh_start[xfer->flags_int.curr_dma_set];
+
+ if (xfer->flags_int.bandwidth_reclaimed) {
+ xfer->flags_int.bandwidth_reclaimed = 0;
+ uhci_rem_loop(sc);
+ }
+ if (methods == &uhci_device_bulk_methods) {
+ UHCI_REMOVE_QH(qh, sc->sc_bulk_p_last);
+ }
+ if (methods == &uhci_device_ctrl_methods) {
+ if (xfer->udev->speed == USB_SPEED_LOW) {
+ UHCI_REMOVE_QH(qh, sc->sc_ls_ctl_p_last);
+ } else {
+ UHCI_REMOVE_QH(qh, sc->sc_fs_ctl_p_last);
+ }
+ }
+ if (methods == &uhci_device_intr_methods) {
+ UHCI_REMOVE_QH(qh, sc->sc_intr_p_last[xfer->qh_pos]);
+ }
+ }
+ }
+
+ USB_BUS_UNLOCK(udev->bus);
+
+ return;
+}
+
+static void
+uhci_set_hw_power(struct usb2_bus *bus)
+{
+ struct uhci_softc *sc = UHCI_BUS2SC(bus);
+ uint32_t flags;
+
+ DPRINTF("\n");
+
+ USB_BUS_LOCK(bus);
+
+ flags = bus->hw_power_state;
+
+ if (flags & (USB_HW_POWER_CONTROL |
+ USB_HW_POWER_BULK |
+ USB_HW_POWER_INTERRUPT |
+ USB_HW_POWER_ISOC)) {
+ DPRINTF("Some USB transfer is "
+ "active on %u.\n",
+ device_get_unit(sc->sc_bus.bdev));
+ UHCICMD(sc, (UHCI_CMD_MAXP | UHCI_CMD_RS));
+ } else {
+ DPRINTF("Power save on %u.\n",
+ device_get_unit(sc->sc_bus.bdev));
+ UHCICMD(sc, UHCI_CMD_MAXP);
+ }
+
+ USB_BUS_UNLOCK(bus);
+
+ return;
+}
+
+
struct usb2_bus_methods uhci_bus_methods =
{
.pipe_init = uhci_pipe_init,
@@ -3197,4 +3358,7 @@ struct usb2_bus_methods uhci_bus_methods =
.xfer_unsetup = uhci_xfer_unsetup,
.do_poll = uhci_do_poll,
.get_dma_delay = uhci_get_dma_delay,
+ .device_resume = uhci_device_resume,
+ .device_suspend = uhci_device_suspend,
+ .set_hw_power = uhci_set_hw_power,
};
diff --git a/sys/dev/usb2/controller/uhci2.h b/sys/dev/usb2/controller/uhci2.h
index 9be89ed..ee0b36d 100644
--- a/sys/dev/usb2/controller/uhci2.h
+++ b/sys/dev/usb2/controller/uhci2.h
@@ -300,7 +300,8 @@ typedef struct uhci_softc {
uint8_t sc_addr; /* device address */
uint8_t sc_conf; /* device configuration */
- uint8_t sc_isreset;
+ uint8_t sc_isreset; /* bits set if a root hub is reset */
+ uint8_t sc_isresumed; /* bits set if a port was resumed */
uint8_t sc_saved_sof;
uint8_t sc_hub_idata[1];
diff --git a/sys/dev/usb2/controller/usb2_bus.h b/sys/dev/usb2/controller/usb2_bus.h
index d9dc74e..f30d61f 100644
--- a/sys/dev/usb2/controller/usb2_bus.h
+++ b/sys/dev/usb2/controller/usb2_bus.h
@@ -54,10 +54,14 @@ struct usb2_bus {
struct usb2_process explore_proc;
struct usb2_bus_msg explore_msg[2];
struct usb2_bus_msg detach_msg[2];
- struct mtx bus_mtx; /* This mutex protects the USB
- * hardware */
+ struct usb2_bus_msg attach_msg[2];
+ /*
+ * This mutex protects the USB hardware:
+ */
+ struct mtx bus_mtx;
struct usb2_perm perm;
struct usb2_xfer_queue intr_q;
+ struct usb2_callout power_wdog; /* power management */
device_t parent;
device_t bdev; /* filled by HC driver */
@@ -68,6 +72,7 @@ struct usb2_bus {
struct usb2_bus_methods *methods; /* filled by HC driver */
struct usb2_device *devices[USB_MAX_DEVICES];
+ uint32_t hw_power_state; /* see USB_HW_POWER_XXX */
uint32_t uframe_usage[USB_HS_MICRO_FRAMES_MAX];
uint32_t transfer_count[4];
uint16_t isoc_time_last; /* in milliseconds */
diff --git a/sys/dev/usb2/controller/usb2_controller.c b/sys/dev/usb2/controller/usb2_controller.c
index 5dd517d..ec1aff5 100644
--- a/sys/dev/usb2/controller/usb2_controller.c
+++ b/sys/dev/usb2/controller/usb2_controller.c
@@ -148,6 +148,9 @@ usb2_detach(device_t dev)
/* was never setup properly */
return (0);
}
+ /* Stop power watchdog */
+ usb2_callout_drain(&bus->power_wdog);
+
/* Let the USB explore process detach all devices. */
USB_BUS_LOCK(bus);
@@ -198,6 +201,11 @@ usb2_bus_explore(struct usb2_proc_msg *pm)
mtx_lock(&Giant);
/*
+ * First update the USB power state!
+ */
+ usb2_bus_powerd(bus);
+
+ /*
* Explore the Root USB HUB. This call can sleep,
* exiting Giant, which is actually Giant.
*/
@@ -246,24 +254,41 @@ usb2_bus_detach(struct usb2_proc_msg *pm)
bus->bdev = NULL;
}
+static void
+usb2_power_wdog(void *arg)
+{
+ struct usb2_bus *bus = arg;
+
+ USB_BUS_LOCK_ASSERT(bus, MA_OWNED);
+
+ usb2_callout_reset(&bus->power_wdog,
+ 4 * hz, usb2_power_wdog, arg);
+
+ USB_BUS_UNLOCK(bus);
+
+ usb2_bus_power_update(bus);
+
+ return;
+}
+
/*------------------------------------------------------------------------*
- * usb2_attach_sub
+ * usb2_bus_attach
*
- * This function is the real USB bus attach code. It is factored out,
- * hence it can be called at two different places in time. During
- * bootup this function is called from "usb2_post_init". During
- * hot-plug it is called directly from the "usb2_attach()" method.
+ * This function attaches USB in context of the explore thread.
*------------------------------------------------------------------------*/
static void
-usb2_attach_sub(device_t dev, struct usb2_bus *bus)
+usb2_bus_attach(struct usb2_proc_msg *pm)
{
+ struct usb2_bus *bus;
struct usb2_device *child;
+ device_t dev;
usb2_error_t err;
uint8_t speed;
- DPRINTF("\n");
+ bus = ((struct usb2_bus_msg *)pm)->bus;
+ dev = bus->bdev;
- mtx_assert(&Giant, MA_OWNED);
+ DPRINTF("\n");
switch (bus->usbrev) {
case USB_REV_1_0:
@@ -291,6 +316,9 @@ usb2_attach_sub(device_t dev, struct usb2_bus *bus)
return;
}
+ USB_BUS_UNLOCK(bus);
+ mtx_lock(&Giant); /* XXX not required by USB */
+
/* Allocate the Root USB device */
child = usb2_alloc_device(bus->bdev, bus, NULL, 0, 0, 1,
@@ -307,10 +335,36 @@ usb2_attach_sub(device_t dev, struct usb2_bus *bus)
err = USB_ERR_NOMEM;
}
+ mtx_unlock(&Giant);
+ USB_BUS_LOCK(bus);
+
if (err) {
device_printf(bus->bdev, "Root HUB problem, error=%s\n",
usb2_errstr(err));
}
+
+ /* set softc - we are ready */
+ device_set_softc(dev, bus);
+
+ /* start watchdog - this function will unlock the BUS lock ! */
+ usb2_power_wdog(bus);
+
+ /* need to return locked */
+ USB_BUS_LOCK(bus);
+}
+
+/*------------------------------------------------------------------------*
+ * usb2_attach_sub
+ *
+ * This function creates a thread which runs the USB attach code. It
+ * is factored out, hence it can be called at two different places in
+ * time. During bootup this function is called from
+ * "usb2_post_init". During hot-plug it is called directly from the
+ * "usb2_attach()" method.
+ *------------------------------------------------------------------------*/
+static void
+usb2_attach_sub(device_t dev, struct usb2_bus *bus)
+{
/* Initialise USB process messages */
bus->explore_msg[0].hdr.pm_callback = &usb2_bus_explore;
bus->explore_msg[0].bus = bus;
@@ -322,13 +376,24 @@ usb2_attach_sub(device_t dev, struct usb2_bus *bus)
bus->detach_msg[1].hdr.pm_callback = &usb2_bus_detach;
bus->detach_msg[1].bus = bus;
+ bus->attach_msg[0].hdr.pm_callback = &usb2_bus_attach;
+ bus->attach_msg[0].bus = bus;
+ bus->attach_msg[1].hdr.pm_callback = &usb2_bus_attach;
+ bus->attach_msg[1].bus = bus;
+
/* Create a new USB process */
if (usb2_proc_setup(&bus->explore_proc,
&bus->bus_mtx, USB_PRI_MED)) {
printf("WARNING: Creation of USB explore process failed.\n");
+ } else {
+ /* Get final attach going */
+ USB_BUS_LOCK(bus);
+ if (usb2_proc_msignal(&bus->explore_proc,
+ &bus->attach_msg[0], &bus->attach_msg[1])) {
+ /* ignore */
+ }
+ USB_BUS_UNLOCK(bus);
}
- /* set softc - we are ready */
- device_set_softc(dev, bus);
}
/*------------------------------------------------------------------------*
@@ -433,6 +498,9 @@ usb2_bus_mem_alloc_all(struct usb2_bus *bus, bus_dma_tag_t dmat,
mtx_init(&bus->bus_mtx, device_get_nameunit(bus->parent),
NULL, MTX_DEF | MTX_RECURSE);
+ usb2_callout_init_mtx(&bus->power_wdog,
+ &bus->bus_mtx, CALLOUT_RETURNUNLOCKED);
+
TAILQ_INIT(&bus->intr_q.head);
usb2_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags,
diff --git a/sys/dev/usb2/controller/usb2_controller.h b/sys/dev/usb2/controller/usb2_controller.h
index 496e8c2..d65c3d6 100644
--- a/sys/dev/usb2/controller/usb2_controller.h
+++ b/sys/dev/usb2/controller/usb2_controller.h
@@ -61,13 +61,35 @@ struct usb2_bus_methods {
void (*xfer_setup) (struct usb2_setup_params *parm);
void (*xfer_unsetup) (struct usb2_xfer *xfer);
void (*get_dma_delay) (struct usb2_bus *, uint32_t *pdelay);
+ void (*device_suspend) (struct usb2_device *udev);
+ void (*device_resume) (struct usb2_device *udev);
+ void (*set_hw_power) (struct usb2_bus *bus);
+ /*
+ * The following flag is set if one or more control transfers are
+ * active:
+ */
+#define USB_HW_POWER_CONTROL 0x01
+ /*
+ * The following flag is set if one or more bulk transfers are
+ * active:
+ */
+#define USB_HW_POWER_BULK 0x02
+ /*
+ * The following flag is set if one or more interrupt transfers are
+ * active:
+ */
+#define USB_HW_POWER_INTERRUPT 0x04
+ /*
+ * The following flag is set if one or more isochronous transfers
+ * are active:
+ */
+#define USB_HW_POWER_ISOC 0x08
/* USB Device mode only - Mandatory */
void (*get_hw_ep_profile) (struct usb2_device *udev, const struct usb2_hw_ep_profile **ppf, uint8_t ep_addr);
void (*set_stall) (struct usb2_device *udev, struct usb2_xfer *xfer, struct usb2_pipe *pipe);
void (*clear_stall) (struct usb2_device *udev, struct usb2_pipe *pipe);
- void (*rem_wakeup_set) (struct usb2_device *udev, uint8_t is_on);
/* USB Device mode only - Optional */
@@ -90,7 +112,6 @@ struct usb2_pipe_methods {
/* Optional */
- uint8_t (*isdone) (struct usb2_xfer *xfer);
void *info;
/* Flags */
diff --git a/sys/dev/usb2/controller/uss820dci.c b/sys/dev/usb2/controller/uss820dci.c
index d010a53..6db143a 100644
--- a/sys/dev/usb2/controller/uss820dci.c
+++ b/sys/dev/usb2/controller/uss820dci.c
@@ -223,29 +223,6 @@ uss820dci_wakeup_peer(struct uss820dci_softc *sc)
}
static void
-uss820dci_rem_wakeup_set(struct usb2_device *udev, uint8_t is_on)
-{
- struct uss820dci_softc *sc;
- uint8_t temp;
-
- DPRINTFN(5, "is_on=%u\n", is_on);
-
- USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
-
- sc = USS820_DCI_BUS2SC(udev->bus);
-
- temp = USS820_READ_1(sc, USS820_SCR);
-
- if (is_on) {
- temp |= USS820_SCR_RWUPE;
- } else {
- temp &= ~USS820_SCR_RWUPE;
- }
-
- USS820_WRITE_1(sc, USS820_SCR, temp);
-}
-
-static void
uss820dci_set_address(struct uss820dci_softc *sc, uint8_t addr)
{
DPRINTFN(5, "addr=%d\n", addr);
@@ -1375,6 +1352,7 @@ uss820dci_init(struct uss820dci_softc *sc)
USS820_WRITE_1(sc, USS820_SCR,
USS820_SCR_T_IRQ |
USS820_SCR_IE_RESET |
+ /* USS820_SCR_RWUPE | */
USS820_SCR_IE_SUSP |
USS820_SCR_IRQPOL);
@@ -2518,5 +2496,4 @@ struct usb2_bus_methods uss820dci_bus_methods =
.get_hw_ep_profile = &uss820dci_get_hw_ep_profile,
.set_stall = &uss820dci_set_stall,
.clear_stall = &uss820dci_clear_stall,
- .rem_wakeup_set = &uss820dci_rem_wakeup_set,
};
diff --git a/sys/dev/usb2/core/usb2_busdma.c b/sys/dev/usb2/core/usb2_busdma.c
index 33851f0..be99e00 100644
--- a/sys/dev/usb2/core/usb2_busdma.c
+++ b/sys/dev/usb2/core/usb2_busdma.c
@@ -29,12 +29,15 @@
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/include/usb2_defs.h>
+#define USB_DEBUG_VAR usb2_debug
+
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_transfer.h>
#include <dev/usb2/core/usb2_device.h>
#include <dev/usb2/core/usb2_util.h>
+#include <dev/usb2/core/usb2_debug.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
@@ -418,7 +421,16 @@ usb2_pc_common_mem_cb(void *arg, bus_dma_segment_t *segs,
pc->page_offset_buf = rem;
pc->page_offset_end += rem;
nseg--;
-
+#if (USB_DEBUG != 0)
+ if (rem != (USB_P2U(pc->buffer) & (USB_PAGE_SIZE - 1))) {
+ /*
+ * This check verifies that the physical address is correct:
+ */
+ DPRINTFN(0, "Page offset was not preserved!\n");
+ error = 1;
+ goto done;
+ }
+#endif
while (nseg > 0) {
nseg--;
segs++;
@@ -788,7 +800,16 @@ usb2_pc_common_mem_cb(struct usb2_page_cache *pc, bus_dma_segment_t *segs,
ext_seg = 0;
}
nseg--;
-
+#if (USB_DEBUG != 0)
+ if (rem != (USB_P2U(pc->buffer) & (USB_PAGE_SIZE - 1))) {
+ /*
+ * This check verifies that the physical address is correct:
+ */
+ DPRINTFN(0, "Page offset was not preserved!\n");
+ error = 1;
+ goto done;
+ }
+#endif
while (nseg > 0) {
nseg--;
segs++;
diff --git a/sys/dev/usb2/core/usb2_core.h b/sys/dev/usb2/core/usb2_core.h
index acc30a8..f1e5586 100644
--- a/sys/dev/usb2/core/usb2_core.h
+++ b/sys/dev/usb2/core/usb2_core.h
@@ -440,6 +440,7 @@ uint8_t usb2_get_interface_altindex(struct usb2_interface *iface);
usb2_error_t usb2_set_alt_interface_index(struct usb2_device *udev,
uint8_t iface_index, uint8_t alt_index);
uint8_t usb2_get_speed(struct usb2_device *udev);
+uint32_t usb2_get_isoc_fps(struct usb2_device *udev);
usb2_error_t usb2_transfer_setup(struct usb2_device *udev,
const uint8_t *ifaces, struct usb2_xfer **pxfer,
const struct usb2_config *setup_start, uint16_t n_setup,
@@ -464,5 +465,6 @@ void usb2_set_iface_perm(struct usb2_device *udev, uint8_t iface_index,
uint32_t uid, uint32_t gid, uint16_t mode);
uint8_t usb2_get_bus_index(struct usb2_device *udev);
uint8_t usb2_get_device_index(struct usb2_device *udev);
+void usb2_set_power_mode(struct usb2_device *udev, uint8_t power_mode);
#endif /* _USB2_CORE_H_ */
diff --git a/sys/dev/usb2/core/usb2_device.c b/sys/dev/usb2/core/usb2_device.c
index 2356cc5..805de0a 100644
--- a/sys/dev/usb2/core/usb2_device.c
+++ b/sys/dev/usb2/core/usb2_device.c
@@ -1186,7 +1186,7 @@ usb2_suspend_resume_sub(struct usb2_device *udev, device_t dev, uint8_t do_suspe
}
/*------------------------------------------------------------------------*
- * usb2_suspend_resume_device
+ * usb2_suspend_resume
*
* The following function will suspend or resume the USB device.
*
@@ -1339,7 +1339,13 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus,
udev->bus = bus;
udev->address = USB_START_ADDR; /* default value */
udev->plugtime = (uint32_t)ticks;
+ /*
+ * We need to force the power mode to "on" because there are plenty
+ * of USB devices out there that do not work very well with
+ * automatic suspend and resume!
+ */
udev->power_mode = USB_POWER_MODE_ON;
+ udev->pwr_save.last_xfer_time = ticks;
/* we are not ready yet */
udev->refcount = 1;
@@ -1450,7 +1456,11 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus,
if (err) {
DPRINTFN(0, "getting device descriptor "
"at addr %d failed!\n", udev->address);
- goto done;
+ /* XXX try to re-enumerate the device */
+ err = usb2_req_re_enumerate(udev, &Giant);
+ if (err) {
+ goto done;
+ }
}
DPRINTF("adding unit addr=%d, rev=%02x, class=%d, "
"subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n",
@@ -1546,6 +1556,7 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus,
if (udev->flags.usb2_mode == USB_MODE_HOST) {
uint8_t config_index;
uint8_t config_quirk;
+ uint8_t set_config_failed = 0;
/*
* Most USB devices should attach to config index 0 by
@@ -1580,11 +1591,27 @@ repeat_set_config:
err = usb2_set_config_index(udev, config_index);
sx_unlock(udev->default_sx + 1);
if (err) {
- DPRINTFN(0, "Failure selecting "
- "configuration index %u: %s, port %u, addr %u\n",
- config_index, usb2_errstr(err), udev->port_no,
- udev->address);
-
+ if (udev->ddesc.bNumConfigurations != 0) {
+ if (!set_config_failed) {
+ set_config_failed = 1;
+ /* XXX try to re-enumerate the device */
+ err = usb2_req_re_enumerate(
+ udev, &Giant);
+ if (err == 0)
+ goto repeat_set_config;
+ }
+ DPRINTFN(0, "Failure selecting "
+ "configuration index %u: %s, port %u, "
+ "addr %u (ignored)\n",
+ config_index, usb2_errstr(err), udev->port_no,
+ udev->address);
+ }
+ /*
+ * Some USB devices do not have any
+ * configurations. Ignore any set config
+ * failures!
+ */
+ err = 0;
} else if (config_quirk) {
/* user quirk selects configuration index */
} else if ((config_index + 1) < udev->ddesc.bNumConfigurations) {
@@ -1608,7 +1635,7 @@ repeat_set_config:
goto repeat_set_config;
}
}
- } else if (usb2_test_huawei(udev, &uaa) == 0) {
+ } else if (usb2_test_huawei_autoinst_p(udev, &uaa) == 0) {
DPRINTFN(0, "Found Huawei auto-install disk!\n");
err = USB_ERR_STALLED; /* fake an error */
}
@@ -1670,6 +1697,11 @@ usb2_free_device(struct usb2_device *udev)
bus = udev->bus;
+ printf("ugen%u.%u: <%s> at %s (disconnected)\n",
+ device_get_unit(bus->bdev),
+ udev->device_index, udev->manufacturer,
+ device_get_nameunit(bus->bdev));
+
/*
* Destroy UGEN symlink, if any
*/
@@ -1937,6 +1969,19 @@ usb2_get_speed(struct usb2_device *udev)
return (udev->speed);
}
+uint32_t
+usb2_get_isoc_fps(struct usb2_device *udev)
+{
+ ; /* indent fix */
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ return (1000);
+ default:
+ return (8000);
+ }
+}
+
struct usb2_device_descriptor *
usb2_get_device_descriptor(struct usb2_device *udev)
{
@@ -2123,3 +2168,22 @@ usb2_fifo_free_wrap(struct usb2_device *udev,
usb2_fifo_free(f);
}
}
+
+/*------------------------------------------------------------------------*
+ * usb2_peer_can_wakeup
+ *
+ * Return values:
+ * 0: Peer cannot do resume signalling.
+ * Else: Peer can do resume signalling.
+ *------------------------------------------------------------------------*/
+uint8_t
+usb2_peer_can_wakeup(struct usb2_device *udev)
+{
+ const struct usb2_config_descriptor *cdp;
+
+ cdp = udev->cdesc;
+ if ((cdp != NULL) && (udev->flags.usb2_mode == USB_MODE_HOST)) {
+ return (cdp->bmAttributes & UC_REMOTE_WAKEUP);
+ }
+ return (0); /* not supported */
+}
diff --git a/sys/dev/usb2/core/usb2_device.h b/sys/dev/usb2/core/usb2_device.h
index 96dcb50..11686e2 100644
--- a/sys/dev/usb2/core/usb2_device.h
+++ b/sys/dev/usb2/core/usb2_device.h
@@ -83,6 +83,18 @@ struct usb2_device_flags {
};
/*
+ * The following structure is used for power-save purposes. The data
+ * in this structure is protected by the USB BUS lock.
+ */
+struct usb2_power_save {
+ int last_xfer_time; /* copy of "ticks" */
+ uint32_t type_refs[4]; /* transfer reference count */
+ uint32_t read_refs; /* data read references */
+ uint32_t write_refs; /* data write references */
+ uint8_t suspended; /* set if USB device is suspended */
+};
+
+/*
* The following structure defines an USB device. There exists one of
* these structures for every USB device.
*/
@@ -96,6 +108,7 @@ struct usb2_device {
struct usb2_interface ifaces[USB_IFACE_MAX];
struct usb2_pipe default_pipe; /* Control Endpoint 0 */
struct usb2_pipe pipes[USB_EP_MAX];
+ struct usb2_power_save pwr_save;/* power save data */
struct usb2_bus *bus; /* our USB BUS */
device_t parent_dev; /* parent device */
@@ -169,5 +182,6 @@ void *usb2_find_descriptor(struct usb2_device *udev, void *id,
uint8_t iface_index, uint8_t type, uint8_t type_mask,
uint8_t subtype, uint8_t subtype_mask);
void usb_linux_free_device(struct usb_device *dev);
+uint8_t usb2_peer_can_wakeup(struct usb2_device *udev);
#endif /* _USB2_DEVICE_H_ */
diff --git a/sys/dev/usb2/core/usb2_dynamic.c b/sys/dev/usb2/core/usb2_dynamic.c
index bf7ce59..3e0bdf1 100644
--- a/sys/dev/usb2/core/usb2_dynamic.c
+++ b/sys/dev/usb2/core/usb2_dynamic.c
@@ -39,6 +39,7 @@ static usb2_temp_get_desc_t usb2_temp_get_desc_w;
static usb2_temp_setup_by_index_t usb2_temp_setup_by_index_w;
static usb2_temp_unsetup_t usb2_temp_unsetup_w;
static usb2_test_quirk_t usb2_test_quirk_w;
+static usb2_test_huawei_autoinst_t usb2_test_huawei_autoinst_w;
static usb2_quirk_ioctl_t usb2_quirk_ioctl_w;
/* global variables */
@@ -46,6 +47,7 @@ usb2_temp_get_desc_t *usb2_temp_get_desc_p = &usb2_temp_get_desc_w;
usb2_temp_setup_by_index_t *usb2_temp_setup_by_index_p = &usb2_temp_setup_by_index_w;
usb2_temp_unsetup_t *usb2_temp_unsetup_p = &usb2_temp_unsetup_w;
usb2_test_quirk_t *usb2_test_quirk_p = &usb2_test_quirk_w;
+usb2_test_huawei_autoinst_t *usb2_test_huawei_autoinst_p = &usb2_test_huawei_autoinst_w;
usb2_quirk_ioctl_t *usb2_quirk_ioctl_p = &usb2_quirk_ioctl_w;
devclass_t usb2_devclass_ptr = NULL;
@@ -86,6 +88,13 @@ usb2_temp_unsetup_w(struct usb2_device *udev)
}
}
+static uint8_t
+usb2_test_huawei_autoinst_w(struct usb2_device *udev,
+ struct usb2_attach_arg *uaa)
+{
+ return (USB_ERR_INVAL);
+}
+
void
usb2_quirk_unload(void *arg)
{
@@ -130,3 +139,17 @@ usb2_bus_unload(void *arg)
pause("WAIT", hz);
}
+
+void
+usb2_test_huawei_unload(void *arg)
+{
+ /* reset function pointers */
+
+ usb2_test_huawei_autoinst_p = &usb2_test_huawei_autoinst_w;
+
+ /* wait for CPU to exit the loaded functions, if any */
+
+ /* XXX this is a tradeoff */
+
+ pause("WAIT", 16*hz);
+}
diff --git a/sys/dev/usb2/core/usb2_dynamic.h b/sys/dev/usb2/core/usb2_dynamic.h
index 7496929..2c45d09 100644
--- a/sys/dev/usb2/core/usb2_dynamic.h
+++ b/sys/dev/usb2/core/usb2_dynamic.h
@@ -37,6 +37,8 @@ struct usb2_device_request;
typedef usb2_error_t (usb2_temp_setup_by_index_t)(struct usb2_device *udev,
uint16_t index);
+typedef usb2_error_t (usb2_test_huawei_autoinst_t)(struct usb2_device *udev,
+ struct usb2_attach_arg *uaa);
typedef uint8_t (usb2_test_quirk_t)(const struct usb2_lookup_info *info,
uint16_t quirk);
typedef int (usb2_quirk_ioctl_t)(unsigned long cmd, caddr_t data,
@@ -52,11 +54,13 @@ extern usb2_temp_get_desc_t *usb2_temp_get_desc_p;
extern usb2_temp_setup_by_index_t *usb2_temp_setup_by_index_p;
extern usb2_temp_unsetup_t *usb2_temp_unsetup_p;
extern usb2_test_quirk_t *usb2_test_quirk_p;
+extern usb2_test_huawei_autoinst_t *usb2_test_huawei_autoinst_p;
extern usb2_quirk_ioctl_t *usb2_quirk_ioctl_p;
extern devclass_t usb2_devclass_ptr;
/* function prototypes */
+void usb2_test_huawei_unload(void *);
void usb2_temp_unload(void *);
void usb2_quirk_unload(void *);
void usb2_bus_unload(void *);
diff --git a/sys/dev/usb2/core/usb2_generic.c b/sys/dev/usb2/core/usb2_generic.c
index fa09eef..9e5b34b 100644
--- a/sys/dev/usb2/core/usb2_generic.c
+++ b/sys/dev/usb2/core/usb2_generic.c
@@ -1711,24 +1711,21 @@ ugen_set_power_mode(struct usb2_fifo *f, int mode)
break;
case USB_POWER_MODE_ON:
- /* enable port */
- err = usb2_req_set_port_feature(udev->parent_hub,
- NULL, udev->port_no, UHF_PORT_ENABLE);
-
- /* FALLTHROUGH */
-
case USB_POWER_MODE_SAVE:
+ break;
+
case USB_POWER_MODE_RESUME:
- /* TODO: implement USB power save */
err = usb2_req_clear_port_feature(udev->parent_hub,
NULL, udev->port_no, UHF_PORT_SUSPEND);
+ mode = USB_POWER_MODE_SAVE;
break;
case USB_POWER_MODE_SUSPEND:
- /* TODO: implement USB power save */
err = usb2_req_set_port_feature(udev->parent_hub,
NULL, udev->port_no, UHF_PORT_SUSPEND);
+ mode = USB_POWER_MODE_SAVE;
break;
+
default:
return (EINVAL);
}
@@ -1736,7 +1733,8 @@ ugen_set_power_mode(struct usb2_fifo *f, int mode)
if (err)
return (ENXIO); /* I/O failure */
- udev->power_mode = mode; /* update copy of power mode */
+ /* set new power mode */
+ usb2_set_power_mode(udev, mode);
return (0); /* success */
}
diff --git a/sys/dev/usb2/core/usb2_handle_request.c b/sys/dev/usb2/core/usb2_handle_request.c
index d5714b4..c765997 100644
--- a/sys/dev/usb2/core/usb2_handle_request.c
+++ b/sys/dev/usb2/core/usb2_handle_request.c
@@ -390,10 +390,12 @@ usb2_handle_remote_wakeup(struct usb2_xfer *xfer, uint8_t is_on)
udev->flags.remote_wakeup = 0;
}
- (bus->methods->rem_wakeup_set) (xfer->udev, is_on);
-
USB_BUS_UNLOCK(bus);
+ /* In case we are out of sync, update the power state. */
+
+ usb2_bus_power_update(udev->bus);
+
return (0); /* success */
}
diff --git a/sys/dev/usb2/core/usb2_hub.c b/sys/dev/usb2/core/usb2_hub.c
index 34b275a..0d08b948 100644
--- a/sys/dev/usb2/core/usb2_hub.c
+++ b/sys/dev/usb2/core/usb2_hub.c
@@ -34,6 +34,7 @@
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/include/usb2_standard.h>
+#include <dev/usb2/include/usb2_ioctl.h>
#define USB_DEBUG_VAR uhub_debug
@@ -61,6 +62,11 @@ SYSCTL_INT(_hw_usb2_uhub, OID_AUTO, debug, CTLFLAG_RW, &uhub_debug, 0,
"Debug level");
#endif
+static int usb2_power_timeout = 30; /* seconds */
+
+SYSCTL_INT(_hw_usb2, OID_AUTO, power_timeout, CTLFLAG_RW,
+ &usb2_power_timeout, 0, "USB power timeout");
+
struct uhub_current_state {
uint16_t port_change;
uint16_t port_status;
@@ -86,6 +92,8 @@ struct uhub_softc {
static device_probe_t uhub_probe;
static device_attach_t uhub_attach;
static device_detach_t uhub_detach;
+static device_suspend_t uhub_suspend;
+static device_resume_t uhub_resume;
static bus_driver_added_t uhub_driver_added;
static bus_child_location_str_t uhub_child_location_string;
@@ -94,6 +102,9 @@ static bus_child_pnpinfo_str_t uhub_child_pnpinfo_string;
static usb2_callback_t uhub_intr_callback;
static usb2_callback_t uhub_intr_clear_stall_callback;
+static void usb2_dev_resume_peer(struct usb2_device *udev);
+static void usb2_dev_suspend_peer(struct usb2_device *udev);
+
static const struct usb2_config uhub_config[2] = {
[0] = {
@@ -133,8 +144,8 @@ static driver_t uhub_driver =
DEVMETHOD(device_attach, uhub_attach),
DEVMETHOD(device_detach, uhub_detach),
- DEVMETHOD(device_suspend, bus_generic_suspend),
- DEVMETHOD(device_resume, bus_generic_resume),
+ DEVMETHOD(device_suspend, uhub_suspend),
+ DEVMETHOD(device_resume, uhub_resume),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(bus_child_location_str, uhub_child_location_string),
@@ -302,8 +313,8 @@ repeat:
/* first clear the port connection change bit */
- err = usb2_req_clear_port_feature
- (udev, &Giant, portno, UHF_C_PORT_CONNECTION);
+ err = usb2_req_clear_port_feature(udev, &Giant,
+ portno, UHF_C_PORT_CONNECTION);
if (err) {
goto error;
@@ -338,6 +349,12 @@ repeat:
DPRINTF("Port %d is in Host Mode\n", portno);
+ if (sc->sc_st.port_status & UPS_SUSPEND) {
+ DPRINTF("Port %d was still "
+ "suspended, clearing.\n", portno);
+ err = usb2_req_clear_port_feature(sc->sc_udev,
+ &Giant, portno, UHF_PORT_SUSPEND);
+ }
/* USB Host Mode */
/* wait for maximum device power up time */
@@ -346,8 +363,7 @@ repeat:
/* reset port, which implies enabling it */
- err = usb2_req_reset_port
- (udev, &Giant, portno);
+ err = usb2_req_reset_port(udev, &Giant, portno);
if (err) {
DPRINTFN(0, "port %d reset "
@@ -411,8 +427,8 @@ error:
}
if (err == 0) {
if (sc->sc_st.port_status & UPS_PORT_ENABLED) {
- err = usb2_req_clear_port_feature
- (sc->sc_udev, &Giant,
+ err = usb2_req_clear_port_feature(
+ sc->sc_udev, &Giant,
portno, UHF_PORT_ENABLE);
}
}
@@ -446,16 +462,17 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno)
/* first clear the port suspend change bit */
- err = usb2_req_clear_port_feature
- (udev, &Giant, portno, UHF_C_PORT_SUSPEND);
-
+ err = usb2_req_clear_port_feature(udev, &Giant,
+ portno, UHF_C_PORT_SUSPEND);
if (err) {
+ DPRINTF("clearing suspend failed.\n");
goto done;
}
/* get fresh status */
err = uhub_read_port_status(sc, portno);
if (err) {
+ DPRINTF("reading port status failed.\n");
goto done;
}
/* get current state */
@@ -465,12 +482,21 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno)
} else {
is_suspend = 0;
}
+
+ DPRINTF("suspended=%u\n", is_suspend);
+
/* do the suspend or resume */
if (child) {
- sx_xlock(child->default_sx + 1);
- err = usb2_suspend_resume(child, is_suspend);
- sx_unlock(child->default_sx + 1);
+ /*
+ * This code handle two cases: 1) Host Mode - we can only
+ * receive resume here 2) Device Mode - we can receive
+ * suspend and resume here
+ */
+ if (is_suspend == 0)
+ usb2_dev_resume_peer(child);
+ else if (child->flags.usb2_mode == USB_MODE_DEVICE)
+ usb2_dev_suspend_peer(child);
}
done:
return (err);
@@ -502,6 +528,11 @@ uhub_explore(struct usb2_device *udev)
if (udev->depth > USB_HUB_MAX_DEPTH) {
return (USB_ERR_TOO_DEEP);
}
+ if (udev->pwr_save.suspended) {
+ /* need to wait until the child signals resume */
+ DPRINTF("Device is suspended!\n");
+ return (0);
+ }
for (x = 0; x != hub->nports; x++) {
up = hub->ports + x;
portno = x + 1;
@@ -511,6 +542,15 @@ uhub_explore(struct usb2_device *udev)
/* most likely the HUB is gone */
break;
}
+ if (sc->sc_st.port_change & UPS_C_OVERCURRENT_INDICATOR) {
+ DPRINTF("Overcurrent on port %u.\n", portno);
+ err = usb2_req_clear_port_feature(
+ udev, &Giant, portno, UHF_C_PORT_OVER_CURRENT);
+ if (err) {
+ /* most likely the HUB is gone */
+ break;
+ }
+ }
if (!(sc->sc_flags & UHUB_FLAG_DID_EXPLORE)) {
/*
* Fake a connect status change so that the
@@ -750,8 +790,8 @@ uhub_attach(device_t dev)
}
if (!err) {
/* turn the power on */
- err = usb2_req_set_port_feature
- (udev, &Giant, portno, UHF_PORT_POWER);
+ err = usb2_req_set_port_feature(udev, &Giant,
+ portno, UHF_PORT_POWER);
}
if (err) {
DPRINTFN(0, "port %d power on failed, %s\n",
@@ -774,6 +814,10 @@ uhub_attach(device_t dev)
usb2_transfer_start(sc->sc_xfer[0]);
USB_XFER_UNLOCK(sc->sc_xfer[0]);
+ /* Enable automatic power save on all USB HUBs */
+
+ usb2_set_power_mode(udev, USB_POWER_MODE_SAVE);
+
return (0);
error:
@@ -827,6 +871,22 @@ uhub_detach(device_t dev)
return (0);
}
+static int
+uhub_suspend(device_t dev)
+{
+ DPRINTF("\n");
+ /* Sub-devices are not suspended here! */
+ return (0);
+}
+
+static int
+uhub_resume(device_t dev)
+{
+ DPRINTF("\n");
+ /* Sub-devices are not resumed here! */
+ return (0);
+}
+
static void
uhub_driver_added(device_t dev, driver_t *driver)
{
@@ -1334,3 +1394,441 @@ usb2_needs_explore_all(void)
max--;
}
}
+
+/*------------------------------------------------------------------------*
+ * usb2_bus_power_update
+ *
+ * This function will ensure that all USB devices on the given bus are
+ * properly suspended or resumed according to the device transfer
+ * state.
+ *------------------------------------------------------------------------*/
+void
+usb2_bus_power_update(struct usb2_bus *bus)
+{
+ usb2_needs_explore(bus, 0 /* no probe */ );
+}
+
+/*------------------------------------------------------------------------*
+ * usb2_transfer_power_ref
+ *
+ * This function will modify the power save reference counts and
+ * wakeup the USB device associated with the given USB transfer, if
+ * needed.
+ *------------------------------------------------------------------------*/
+void
+usb2_transfer_power_ref(struct usb2_xfer *xfer, int val)
+{
+ static const uint32_t power_mask[4] = {
+ [UE_CONTROL] = USB_HW_POWER_CONTROL,
+ [UE_BULK] = USB_HW_POWER_BULK,
+ [UE_INTERRUPT] = USB_HW_POWER_INTERRUPT,
+ [UE_ISOCHRONOUS] = USB_HW_POWER_ISOC,
+ };
+ struct usb2_device *udev;
+ uint8_t needs_explore;
+ uint8_t needs_hw_power;
+ uint8_t xfer_type;
+
+ udev = xfer->udev;
+
+ if (udev->device_index == USB_ROOT_HUB_ADDR) {
+ /* no power save for root HUB */
+ return;
+ }
+ USB_BUS_LOCK(udev->bus);
+
+ xfer_type = xfer->pipe->edesc->bmAttributes & UE_XFERTYPE;
+
+ udev->pwr_save.last_xfer_time = ticks;
+ udev->pwr_save.type_refs[xfer_type] += val;
+
+ if (xfer->flags_int.control_xfr) {
+ udev->pwr_save.read_refs += val;
+ if (xfer->flags_int.usb2_mode == USB_MODE_HOST) {
+ /*
+ * it is not allowed to suspend during a control
+ * transfer
+ */
+ udev->pwr_save.write_refs += val;
+ }
+ } else if (USB_GET_DATA_ISREAD(xfer)) {
+ udev->pwr_save.read_refs += val;
+ } else {
+ udev->pwr_save.write_refs += val;
+ }
+
+ if (udev->pwr_save.suspended)
+ needs_explore =
+ (udev->pwr_save.write_refs != 0) ||
+ ((udev->pwr_save.read_refs != 0) &&
+ (usb2_peer_can_wakeup(udev) == 0));
+ else
+ needs_explore = 0;
+
+ if (!(udev->bus->hw_power_state & power_mask[xfer_type])) {
+ DPRINTF("Adding type %u to power state\n", xfer_type);
+ udev->bus->hw_power_state |= power_mask[xfer_type];
+ needs_hw_power = 1;
+ } else {
+ needs_hw_power = 0;
+ }
+
+ USB_BUS_UNLOCK(udev->bus);
+
+ if (needs_explore) {
+ DPRINTF("update\n");
+ usb2_bus_power_update(udev->bus);
+ } else if (needs_hw_power) {
+ DPRINTF("needs power\n");
+ if (udev->bus->methods->set_hw_power != NULL) {
+ (udev->bus->methods->set_hw_power) (udev->bus);
+ }
+ }
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * usb2_bus_powerd
+ *
+ * This function implements the USB power daemon and is called
+ * regularly from the USB explore thread.
+ *------------------------------------------------------------------------*/
+void
+usb2_bus_powerd(struct usb2_bus *bus)
+{
+ struct usb2_device *udev;
+ unsigned int temp;
+ unsigned int limit;
+ unsigned int mintime;
+ uint32_t type_refs[4];
+ uint8_t x;
+ uint8_t rem_wakeup;
+
+ limit = usb2_power_timeout;
+ if (limit == 0)
+ limit = hz;
+ else if (limit > 255)
+ limit = 255 * hz;
+ else
+ limit = limit * hz;
+
+ DPRINTF("bus=%p\n", bus);
+
+ USB_BUS_LOCK(bus);
+
+ /*
+ * The root HUB device is never suspended
+ * and we simply skip it.
+ */
+ for (x = USB_ROOT_HUB_ADDR + 1;
+ x != USB_MAX_DEVICES; x++) {
+
+ udev = bus->devices[x];
+ if (udev == NULL)
+ continue;
+
+ rem_wakeup = usb2_peer_can_wakeup(udev);
+
+ temp = ticks - udev->pwr_save.last_xfer_time;
+
+ if ((udev->power_mode == USB_POWER_MODE_ON) ||
+ (udev->pwr_save.type_refs[UE_ISOCHRONOUS] != 0) ||
+ (udev->pwr_save.write_refs != 0) ||
+ ((udev->pwr_save.read_refs != 0) &&
+ (rem_wakeup == 0))) {
+
+ /* check if we are suspended */
+ if (udev->pwr_save.suspended != 0) {
+ USB_BUS_UNLOCK(bus);
+ usb2_dev_resume_peer(udev);
+ USB_BUS_LOCK(bus);
+ }
+ } else if (temp >= limit) {
+
+ /* check if we are not suspended */
+ if (udev->pwr_save.suspended == 0) {
+ USB_BUS_UNLOCK(bus);
+ usb2_dev_suspend_peer(udev);
+ USB_BUS_LOCK(bus);
+ }
+ }
+ }
+
+ /* reset counters */
+
+ mintime = 0 - 1;
+ type_refs[0] = 0;
+ type_refs[1] = 0;
+ type_refs[2] = 0;
+ type_refs[3] = 0;
+
+ /* Re-loop all the devices to get the actual state */
+
+ for (x = USB_ROOT_HUB_ADDR + 1;
+ x != USB_MAX_DEVICES; x++) {
+
+ udev = bus->devices[x];
+ if (udev == NULL)
+ continue;
+
+ /* "last_xfer_time" can be updated by a resume */
+ temp = ticks - udev->pwr_save.last_xfer_time;
+
+ /*
+ * Compute minimum time since last transfer for the complete
+ * bus:
+ */
+ if (temp < mintime)
+ mintime = temp;
+
+ if (udev->pwr_save.suspended == 0) {
+ type_refs[0] += udev->pwr_save.type_refs[0];
+ type_refs[1] += udev->pwr_save.type_refs[1];
+ type_refs[2] += udev->pwr_save.type_refs[2];
+ type_refs[3] += udev->pwr_save.type_refs[3];
+ }
+ }
+
+ if (mintime >= (1 * hz)) {
+ /* recompute power masks */
+ DPRINTF("Recomputing power masks\n");
+ bus->hw_power_state = 0;
+ if (type_refs[UE_CONTROL] != 0)
+ bus->hw_power_state |= USB_HW_POWER_CONTROL;
+ if (type_refs[UE_BULK] != 0)
+ bus->hw_power_state |= USB_HW_POWER_BULK;
+ if (type_refs[UE_INTERRUPT] != 0)
+ bus->hw_power_state |= USB_HW_POWER_INTERRUPT;
+ if (type_refs[UE_ISOCHRONOUS] != 0)
+ bus->hw_power_state |= USB_HW_POWER_ISOC;
+ }
+ USB_BUS_UNLOCK(bus);
+
+ if (bus->methods->set_hw_power != NULL) {
+ /* always update hardware power! */
+ (bus->methods->set_hw_power) (bus);
+ }
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * usb2_dev_resume_peer
+ *
+ * This function will resume an USB peer and do the required USB
+ * signalling to get an USB device out of the suspended state.
+ *------------------------------------------------------------------------*/
+static void
+usb2_dev_resume_peer(struct usb2_device *udev)
+{
+ struct usb2_bus *bus;
+ int err;
+
+ /* be NULL safe */
+ if (udev == NULL)
+ return;
+
+ /* check if already resumed */
+ if (udev->pwr_save.suspended == 0)
+ return;
+
+ /* we need a parent HUB to do resume */
+ if (udev->parent_hub == NULL)
+ return;
+
+ DPRINTF("udev=%p\n", udev);
+
+ if ((udev->flags.usb2_mode == USB_MODE_DEVICE) &&
+ (udev->flags.remote_wakeup == 0)) {
+ /*
+ * If the host did not set the remote wakeup feature, we can
+ * not wake it up either!
+ */
+ DPRINTF("remote wakeup is not set!\n");
+ return;
+ }
+ /* get bus pointer */
+ bus = udev->bus;
+
+ /* resume parent hub first */
+ usb2_dev_resume_peer(udev->parent_hub);
+
+ /* resume current port (Valid in Host and Device Mode) */
+ err = usb2_req_clear_port_feature(udev->parent_hub,
+ &Giant, udev->port_no, UHF_PORT_SUSPEND);
+ if (err) {
+ DPRINTFN(0, "Resuming port failed!\n");
+ return;
+ }
+ /* resume settle time */
+ usb2_pause_mtx(&Giant, USB_PORT_RESUME_DELAY);
+
+ if (bus->methods->device_resume != NULL) {
+ /* resume USB device on the USB controller */
+ (bus->methods->device_resume) (udev);
+ }
+ USB_BUS_LOCK(bus);
+ /* set that this device is now resumed */
+ udev->pwr_save.suspended = 0;
+ /* make sure that we don't go into suspend right away */
+ udev->pwr_save.last_xfer_time = ticks;
+
+ /* make sure the needed power masks are on */
+ if (udev->pwr_save.type_refs[UE_CONTROL] != 0)
+ bus->hw_power_state |= USB_HW_POWER_CONTROL;
+ if (udev->pwr_save.type_refs[UE_BULK] != 0)
+ bus->hw_power_state |= USB_HW_POWER_BULK;
+ if (udev->pwr_save.type_refs[UE_INTERRUPT] != 0)
+ bus->hw_power_state |= USB_HW_POWER_INTERRUPT;
+ if (udev->pwr_save.type_refs[UE_ISOCHRONOUS] != 0)
+ bus->hw_power_state |= USB_HW_POWER_ISOC;
+ USB_BUS_UNLOCK(bus);
+
+ if (bus->methods->set_hw_power != NULL) {
+ /* always update hardware power! */
+ (bus->methods->set_hw_power) (bus);
+ }
+ sx_xlock(udev->default_sx + 1);
+ /* notify all sub-devices about resume */
+ err = usb2_suspend_resume(udev, 0);
+ sx_unlock(udev->default_sx + 1);
+
+ /* check if peer has wakeup capability */
+ if (usb2_peer_can_wakeup(udev)) {
+ /* clear remote wakeup */
+ err = usb2_req_clear_device_feature(udev,
+ &Giant, UF_DEVICE_REMOTE_WAKEUP);
+ if (err) {
+ DPRINTFN(0, "Clearing device "
+ "remote wakeup failed: %s!\n",
+ usb2_errstr(err));
+ }
+ }
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * usb2_dev_suspend_peer
+ *
+ * This function will suspend an USB peer and do the required USB
+ * signalling to get an USB device into the suspended state.
+ *------------------------------------------------------------------------*/
+static void
+usb2_dev_suspend_peer(struct usb2_device *udev)
+{
+ struct usb2_device *hub;
+ struct usb2_device *child;
+ uint32_t temp;
+ int err;
+ uint8_t x;
+ uint8_t nports;
+ uint8_t suspend_parent;
+
+repeat:
+ /* be NULL safe */
+ if (udev == NULL)
+ return;
+
+ /* check if already suspended */
+ if (udev->pwr_save.suspended)
+ return;
+
+ /* we need a parent HUB to do suspend */
+ if (udev->parent_hub == NULL)
+ return;
+
+ DPRINTF("udev=%p\n", udev);
+
+ /* check if all devices on the parent hub are suspended */
+ hub = udev->parent_hub;
+ if (hub != NULL) {
+ nports = hub->hub->nports;
+ suspend_parent = 1;
+
+ for (x = 0; x != nports; x++) {
+
+ child = usb2_bus_port_get_device(hub->bus,
+ hub->hub->ports + x);
+
+ if (child == NULL)
+ continue;
+
+ if (child->pwr_save.suspended)
+ continue;
+
+ if (child == udev)
+ continue;
+
+ /* another device on the HUB is not suspended */
+ suspend_parent = 0;
+
+ break;
+ }
+ } else {
+ suspend_parent = 0;
+ }
+
+ sx_xlock(udev->default_sx + 1);
+ /* notify all sub-devices about suspend */
+ err = usb2_suspend_resume(udev, 1);
+ sx_unlock(udev->default_sx + 1);
+
+ if (usb2_peer_can_wakeup(udev)) {
+ /* allow device to do remote wakeup */
+ err = usb2_req_set_device_feature(udev,
+ &Giant, UF_DEVICE_REMOTE_WAKEUP);
+ if (err) {
+ DPRINTFN(0, "Setting device "
+ "remote wakeup failed!\n");
+ }
+ }
+ USB_BUS_LOCK(udev->bus);
+ /*
+ * Set that this device is suspended. This variable must be set
+ * before calling USB controller suspend callbacks.
+ */
+ udev->pwr_save.suspended = 1;
+ USB_BUS_UNLOCK(udev->bus);
+
+ if (udev->bus->methods->device_suspend != NULL) {
+
+ /* suspend device on the USB controller */
+ (udev->bus->methods->device_suspend) (udev);
+
+ /* do DMA delay */
+ temp = usb2_get_dma_delay(udev->bus);
+ usb2_pause_mtx(&Giant, temp);
+
+ }
+ /* suspend current port */
+ err = usb2_req_set_port_feature(udev->parent_hub,
+ &Giant, udev->port_no, UHF_PORT_SUSPEND);
+ if (err) {
+ DPRINTFN(0, "Suspending port failed\n");
+ return;
+ }
+ if (suspend_parent) {
+ udev = udev->parent_hub;
+ goto repeat;
+ }
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * usb2_set_power_mode
+ *
+ * This function will set the power mode, see USB_POWER_MODE_XXX for a
+ * USB device.
+ *------------------------------------------------------------------------*/
+void
+usb2_set_power_mode(struct usb2_device *udev, uint8_t power_mode)
+{
+ /* filter input argument */
+ if (power_mode != USB_POWER_MODE_ON) {
+ power_mode = USB_POWER_MODE_SAVE;
+ }
+ udev->power_mode = power_mode; /* update copy of power mode */
+
+ usb2_bus_power_update(udev->bus);
+
+ return;
+}
diff --git a/sys/dev/usb2/core/usb2_hub.h b/sys/dev/usb2/core/usb2_hub.h
index 8ef618e..87d85b3 100644
--- a/sys/dev/usb2/core/usb2_hub.h
+++ b/sys/dev/usb2/core/usb2_hub.h
@@ -74,5 +74,7 @@ struct usb2_device *usb2_bus_port_get_device(struct usb2_bus *bus,
struct usb2_port *up);
void usb2_needs_explore(struct usb2_bus *bus, uint8_t do_probe);
void usb2_needs_explore_all(void);
+void usb2_bus_power_update(struct usb2_bus *bus);
+void usb2_bus_powerd(struct usb2_bus *bus);
#endif /* _USB2_HUB_H_ */
diff --git a/sys/dev/usb2/core/usb2_msctest.c b/sys/dev/usb2/core/usb2_msctest.c
index ef616ce..452f389 100644
--- a/sys/dev/usb2/core/usb2_msctest.c
+++ b/sys/dev/usb2/core/usb2_msctest.c
@@ -36,7 +36,6 @@
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/include/usb2_standard.h>
-#include <dev/usb2/include/usb2_devid.h>
#define USB_DEBUG_VAR usb2_debug
@@ -577,163 +576,3 @@ done:
free(sc, M_USB);
return (err);
}
-
-/*
- * NOTE: The entries marked with XXX should be checked for the correct
- * speed indication to set the buffer sizes.
- */
-static const struct usb2_device_id u3g_devs[] = {
- /* OEM: Option */
- {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3G, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
- {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUAD, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
- {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
- {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAX36, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))},
- {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAXHSUPA, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))},
- {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_VODAFONEMC3G, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
- /* OEM: Qualcomm, Inc. */
- {USB_VPI(USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_ZTE_STOR, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
- {USB_VPI(USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
- /* OEM: Huawei */
- {USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE, U3GINFO(U3GSP_HSDPA, U3GFL_HUAWEI_INIT))},
- {USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220, U3GINFO(U3GSP_HSPA, U3GFL_HUAWEI_INIT))},
- /* OEM: Novatel */
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC950D, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740_2, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V620, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V640, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
- {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ZEROCD, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
- {USB_VPI(USB_VENDOR_DELL, USB_PRODUCT_DELL_U740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
- /* OEM: Merlin */
- {USB_VPI(USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- /* OEM: Sierra Wireless: */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
- /* Sierra TruInstaller device ID */
- {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_TRUINSTALL, U3GINFO(U3GSP_UMTS, U3GFL_SIERRA_INIT))},
-};
-
-static void
-u3g_sierra_init(struct usb2_device *udev)
-{
- struct usb2_device_request req;
-
- DPRINTFN(0, "\n");
-
- req.bmRequestType = UT_VENDOR;
- req.bRequest = UR_SET_INTERFACE;
- USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
- USETW(req.wIndex, UHF_PORT_CONNECTION);
- USETW(req.wLength, 0);
-
- if (usb2_do_request_flags(udev, NULL, &req,
- NULL, 0, NULL, USB_MS_HZ)) {
- /* ignore any errors */
- }
- return;
-}
-
-static void
-u3g_huawei_init(struct usb2_device *udev)
-{
- struct usb2_device_request req;
-
- DPRINTFN(0, "\n");
-
- req.bmRequestType = UT_WRITE_DEVICE;
- req.bRequest = UR_SET_FEATURE;
- USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
- USETW(req.wIndex, UHF_PORT_SUSPEND);
- USETW(req.wLength, 0);
-
- if (usb2_do_request_flags(udev, NULL, &req,
- NULL, 0, NULL, USB_MS_HZ)) {
- /* ignore any errors */
- }
- return;
-}
-
-int
-usb2_lookup_huawei(struct usb2_attach_arg *uaa)
-{
- /* Calling the lookup function will also set the driver info! */
- return (usb2_lookup_id_by_uaa(u3g_devs, sizeof(u3g_devs), uaa));
-}
-
-/*
- * The following function handles 3G modem devices (E220, Mobile,
- * etc.) with auto-install flash disks for Windows/MacOSX on the first
- * interface. After some command or some delay they change appearance
- * to a modem.
- */
-usb2_error_t
-usb2_test_huawei(struct usb2_device *udev, struct usb2_attach_arg *uaa)
-{
- struct usb2_interface *iface;
- struct usb2_interface_descriptor *id;
- uint32_t flags;
-
- if (udev == NULL) {
- return (USB_ERR_INVAL);
- }
- iface = usb2_get_iface(udev, 0);
- if (iface == NULL) {
- return (USB_ERR_INVAL);
- }
- id = iface->idesc;
- if (id == NULL) {
- return (USB_ERR_INVAL);
- }
- if (id->bInterfaceClass != UICLASS_MASS) {
- return (USB_ERR_INVAL);
- }
- if (usb2_lookup_huawei(uaa)) {
- /* no device match */
- return (USB_ERR_INVAL);
- }
- flags = USB_GET_DRIVER_INFO(uaa);
-
- if (flags & U3GFL_HUAWEI_INIT) {
- u3g_huawei_init(udev);
- } else if (flags & U3GFL_SCSI_EJECT) {
- return (usb2_test_autoinstall(udev, 0, 1));
- } else if (flags & U3GFL_SIERRA_INIT) {
- u3g_sierra_init(udev);
- } else {
- /* no quirks */
- return (USB_ERR_INVAL);
- }
- return (0); /* success */
-}
diff --git a/sys/dev/usb2/core/usb2_msctest.h b/sys/dev/usb2/core/usb2_msctest.h
index cdd335f..5bf64d0 100644
--- a/sys/dev/usb2/core/usb2_msctest.h
+++ b/sys/dev/usb2/core/usb2_msctest.h
@@ -29,30 +29,5 @@
usb2_error_t usb2_test_autoinstall(struct usb2_device *udev,
uint8_t iface_index, uint8_t do_eject);
-usb2_error_t usb2_test_huawei(struct usb2_device *udev,
- struct usb2_attach_arg *uaa);
-int usb2_lookup_huawei(struct usb2_attach_arg *uaa);
-
-/* Huawei specific defines */
-
-#define U3GINFO(flag,speed) ((flag)|((speed) * 256))
-#define U3G_GET_SPEED(uaa) (USB_GET_DRIVER_INFO(uaa) / 256)
-
-#define U3GFL_NONE 0x00
-#define U3GFL_HUAWEI_INIT 0x01 /* Requires init command (Huawei
- * cards) */
-#define U3GFL_SCSI_EJECT 0x02 /* Requires SCSI eject command
- * (Novatel) */
-#define U3GFL_SIERRA_INIT 0x04 /* Requires init command (Sierra
- * cards) */
-
-#define U3GSP_GPRS 0
-#define U3GSP_EDGE 1
-#define U3GSP_CDMA 2
-#define U3GSP_UMTS 3
-#define U3GSP_HSDPA 4
-#define U3GSP_HSUPA 5
-#define U3GSP_HSPA 6
-#define U3GSP_MAX 7
#endif /* _USB2_MSCTEST_H_ */
diff --git a/sys/dev/usb2/core/usb2_request.c b/sys/dev/usb2/core/usb2_request.c
index 030a022..b1eb81f 100644
--- a/sys/dev/usb2/core/usb2_request.c
+++ b/sys/dev/usb2/core/usb2_request.c
@@ -611,7 +611,8 @@ usb2_req_get_desc(struct usb2_device *udev, struct mtx *mtx, void *desc,
}
USETW(req.wLength, min_len);
- err = usb2_do_request(udev, mtx, &req, desc);
+ err = usb2_do_request_flags(udev, mtx, &req,
+ desc, 0, NULL, 1000);
if (err) {
if (!retries) {
@@ -1326,6 +1327,7 @@ usb2_req_re_enumerate(struct usb2_device *udev, struct mtx *mtx)
struct usb2_device *parent_hub;
usb2_error_t err;
uint8_t old_addr;
+ uint8_t do_retry = 1;
if (udev->flags.usb2_mode != USB_MODE_HOST) {
return (USB_ERR_INVAL);
@@ -1335,6 +1337,7 @@ usb2_req_re_enumerate(struct usb2_device *udev, struct mtx *mtx)
if (parent_hub == NULL) {
return (USB_ERR_INVAL);
}
+retry:
err = usb2_req_reset_port(parent_hub, mtx, udev->port_no);
if (err) {
DPRINTFN(0, "addr=%d, port reset failed\n", old_addr);
@@ -1355,9 +1358,8 @@ usb2_req_re_enumerate(struct usb2_device *udev, struct mtx *mtx)
err = usb2_req_set_address(udev, mtx, old_addr);
if (err) {
/* XXX ignore any errors! */
- DPRINTFN(0, "addr=%d, set address failed\n",
+ DPRINTFN(0, "addr=%d, set address failed! (ignored)\n",
old_addr);
- err = 0;
}
/* restore device address */
udev->address = old_addr;
@@ -1381,7 +1383,57 @@ usb2_req_re_enumerate(struct usb2_device *udev, struct mtx *mtx)
goto done;
}
done:
+ if (err && do_retry) {
+ /* give the USB firmware some time to load */
+ usb2_pause_mtx(mtx, 500);
+ /* no more retries after this retry */
+ do_retry = 0;
+ /* try again */
+ goto retry;
+ }
/* restore address */
udev->address = old_addr;
return (err);
}
+
+/*------------------------------------------------------------------------*
+ * usb2_req_clear_device_feature
+ *
+ * Returns:
+ * 0: Success
+ * Else: Failure
+ *------------------------------------------------------------------------*/
+usb2_error_t
+usb2_req_clear_device_feature(struct usb2_device *udev, struct mtx *mtx,
+ uint16_t sel)
+{
+ struct usb2_device_request req;
+
+ req.bmRequestType = UT_WRITE_DEVICE;
+ req.bRequest = UR_CLEAR_FEATURE;
+ USETW(req.wValue, sel);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, 0);
+ return (usb2_do_request(udev, mtx, &req, 0));
+}
+
+/*------------------------------------------------------------------------*
+ * usb2_req_set_device_feature
+ *
+ * Returns:
+ * 0: Success
+ * Else: Failure
+ *------------------------------------------------------------------------*/
+usb2_error_t
+usb2_req_set_device_feature(struct usb2_device *udev, struct mtx *mtx,
+ uint16_t sel)
+{
+ struct usb2_device_request req;
+
+ req.bmRequestType = UT_WRITE_DEVICE;
+ req.bRequest = UR_SET_FEATURE;
+ USETW(req.wValue, sel);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, 0);
+ return (usb2_do_request(udev, mtx, &req, 0));
+}
diff --git a/sys/dev/usb2/core/usb2_request.h b/sys/dev/usb2/core/usb2_request.h
index 3869968..b33e0a1 100644
--- a/sys/dev/usb2/core/usb2_request.h
+++ b/sys/dev/usb2/core/usb2_request.h
@@ -89,6 +89,8 @@ usb2_error_t usb2_req_set_report(struct usb2_device *udev, struct mtx *mtx,
void *data, uint16_t len, uint8_t iface_index,
uint8_t type, uint8_t id);
usb2_error_t usb2_req_re_enumerate(struct usb2_device *udev, struct mtx *mtx);
+usb2_error_t usb2_req_clear_device_feature(struct usb2_device *udev, struct mtx *mtx, uint16_t sel);
+usb2_error_t usb2_req_set_device_feature(struct usb2_device *udev, struct mtx *mtx, uint16_t sel);
#define usb2_do_request(u,m,r,d) \
usb2_do_request_flags(u,m,r,d,0,NULL,USB_DEFAULT_TIMEOUT)
diff --git a/sys/dev/usb2/core/usb2_transfer.c b/sys/dev/usb2/core/usb2_transfer.c
index 1cf6956..f574436 100644
--- a/sys/dev/usb2/core/usb2_transfer.c
+++ b/sys/dev/usb2/core/usb2_transfer.c
@@ -120,7 +120,6 @@ static const struct usb2_config usb2_control_ep_cfg[USB_DEFAULT_XFER_MAX] = {
/* function prototypes */
static void usb2_update_max_frame_size(struct usb2_xfer *);
-static uint32_t usb2_get_dma_delay(struct usb2_bus *);
static void usb2_transfer_unsetup_sub(struct usb2_xfer_root *, uint8_t);
static void usb2_control_transfer_init(struct usb2_xfer *);
static uint8_t usb2_start_hardware_sub(struct usb2_xfer *);
@@ -161,7 +160,7 @@ usb2_update_max_frame_size(struct usb2_xfer *xfer)
* 0: no DMA delay required
* Else: milliseconds of DMA delay
*------------------------------------------------------------------------*/
-static uint32_t
+uint32_t
usb2_get_dma_delay(struct usb2_bus *bus)
{
uint32_t temp = 0;
@@ -1374,6 +1373,9 @@ usb2_start_hardware(struct usb2_xfer *xfer)
/* set "transferring" flag */
xfer->flags_int.transferring = 1;
+ /* increment power reference */
+ usb2_transfer_power_ref(xfer, 1);
+
/*
* Check if the transfer is waiting on a queue, most
* frequently the "done_q":
@@ -1886,6 +1888,9 @@ usb2_callback_wrapper(struct usb2_xfer_queue *pq)
USB_BUS_LOCK(xfer->udev->bus);
goto done;
}
+ /* decrement power reference */
+ usb2_transfer_power_ref(xfer, -1);
+
xfer->flags_int.transferring = 0;
if (xfer->error) {
diff --git a/sys/dev/usb2/core/usb2_transfer.h b/sys/dev/usb2/core/usb2_transfer.h
index 1351046..698509c 100644
--- a/sys/dev/usb2/core/usb2_transfer.h
+++ b/sys/dev/usb2/core/usb2_transfer.h
@@ -124,5 +124,7 @@ usb2_callback_t usb2_handle_request_callback;
usb2_callback_t usb2_do_clear_stall_callback;
void usb2_transfer_timeout_ms(struct usb2_xfer *xfer,
void (*cb) (void *arg), uint32_t ms);
+uint32_t usb2_get_dma_delay(struct usb2_bus *bus);
+void usb2_transfer_power_ref(struct usb2_xfer *xfer, int val);
#endif /* _USB2_TRANSFER_H_ */
diff --git a/sys/dev/usb2/ethernet/if_axe2.c b/sys/dev/usb2/ethernet/if_axe2.c
index 0231235..64f2376 100644
--- a/sys/dev/usb2/ethernet/if_axe2.c
+++ b/sys/dev/usb2/ethernet/if_axe2.c
@@ -186,6 +186,7 @@ static void axe_cfg_cmd(struct axe_softc *, uint16_t, uint16_t, uint16_t,
void *);
static void axe_cfg_ax88178_init(struct axe_softc *);
static void axe_cfg_ax88772_init(struct axe_softc *);
+static int axe_get_phyno(struct axe_softc *, int);
static const struct usb2_config axe_config[AXE_ENDPT_MAX] = {
@@ -335,34 +336,26 @@ axe_cfg_miibus_readreg(device_t dev, int phy, int reg)
do_unlock = 1;
}
-#if 0
- /*
- * The chip tells us the MII address of any supported
- * PHYs attached to the chip, so only read from those.
- */
-
- if ((sc->sc_phyaddrs[0] != AXE_NOPHY) && (phy != sc->sc_phyaddrs[0])) {
- val = 0;
- goto done;
- }
- if ((sc->sc_phyaddrs[1] != AXE_NOPHY) && (phy != sc->sc_phyaddrs[1])) {
- val = 0;
- goto done;
- }
-#endif
- if ((sc->sc_phyaddrs[0] != 0xFF) && (sc->sc_phyaddrs[0] != phy)) {
+ if (sc->sc_phyno != phy) {
val = 0;
goto done;
}
+
axe_cfg_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
axe_cfg_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, &val);
axe_cfg_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
val = le16toh(val);
-
- if (val && (val != 0xffff)) {
- sc->sc_phyaddrs[0] = phy;
+ if ((sc->sc_flags & AXE_FLAG_772) != 0 && reg == MII_BMSR) {
+ /*
+ * BMSR of AX88772 indicates that it supports extended
+ * capability but the extended status register is
+ * revered for embedded ethernet PHY. So clear the
+ * extended capability bit of BMSR.
+ */
+ val &= ~BMSR_EXTCAP;
}
+
done:
if (do_unlock) {
mtx_unlock(&sc->sc_mtx);
@@ -386,10 +379,14 @@ axe_cfg_miibus_writereg(device_t dev, int phy, int reg, int val)
do_unlock = 1;
}
+ if (sc->sc_phyno != phy)
+ goto done;
+
axe_cfg_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
axe_cfg_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, &val);
axe_cfg_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
+done:
if (do_unlock) {
mtx_unlock(&sc->sc_mtx);
}
@@ -401,6 +398,7 @@ axe_cfg_miibus_statchg(device_t dev)
{
struct axe_softc *sc = device_get_softc(dev);
struct mii_data *mii = GET_MII(sc);
+ struct ifnet *ifp;
uint16_t val;
uint8_t do_unlock;
@@ -412,15 +410,40 @@ axe_cfg_miibus_statchg(device_t dev)
do_unlock = 1;
}
- if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
- val = AXE_MEDIA_FULL_DUPLEX;
- else
- val = 0;
+ ifp = sc->sc_ifp;
+ if (mii == NULL || ifp == NULL ||
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ goto done;
- if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) {
+ sc->sc_flags &= ~AXE_FLAG_LINK;
+ if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
+ (IFM_ACTIVE | IFM_AVALID)) {
+ switch (IFM_SUBTYPE(mii->mii_media_active)) {
+ case IFM_10_T:
+ case IFM_100_TX:
+ sc->sc_flags |= AXE_FLAG_LINK;
+ break;
+ case IFM_1000_T:
+ if ((sc->sc_flags & AXE_FLAG_178) == 0)
+ break;
+ sc->sc_flags |= AXE_FLAG_LINK;
+ break;
+ default:
+ break;
+ }
+ }
- val |= (AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC);
+ /* Lost link, do nothing. */
+ if ((sc->sc_flags & AXE_FLAG_LINK) == 0)
+ goto done;
+ val = 0;
+ if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
+ val |= AXE_MEDIA_FULL_DUPLEX;
+ if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) {
+ val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC;
+ if ((sc->sc_flags & AXE_FLAG_178) != 0)
+ val |= AXE_178_MEDIA_ENCK;
switch (IFM_SUBTYPE(mii->mii_media_active)) {
case IFM_1000_T:
val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK;
@@ -434,6 +457,7 @@ axe_cfg_miibus_statchg(device_t dev)
}
}
axe_cfg_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL);
+done:
if (do_unlock) {
mtx_unlock(&sc->sc_mtx);
}
@@ -467,7 +491,6 @@ axe_cfg_ifmedia_upd(struct axe_softc *sc,
/* not ready */
return;
}
- sc->sc_flags |= AXE_FLAG_WAIT_LINK;
if (mii->mii_instance) {
struct mii_softc *miisc;
@@ -550,6 +573,30 @@ axe_cfg_reset(struct axe_softc *sc)
err = usb2_config_td_sleep(&sc->sc_config_td, hz / 100);
}
+static int
+axe_get_phyno(struct axe_softc *sc, int sel)
+{
+ int phyno;
+
+ switch (AXE_PHY_TYPE(sc->sc_phyaddrs[sel])) {
+ case PHY_TYPE_100_HOME:
+ case PHY_TYPE_GIG:
+ phyno = AXE_PHY_NO(sc->sc_phyaddrs[sel]);
+ break;
+ case PHY_TYPE_SPECIAL:
+ /* FALLTHROUGH */
+ case PHY_TYPE_RSVD:
+ /* FALLTHROUGH */
+ case PHY_TYPE_NON_SUP:
+ /* FALLTHROUGH */
+ default:
+ phyno = -1;
+ break;
+ }
+
+ return (phyno);
+}
+
/*
* Probe for a AX88172 chip.
*/
@@ -617,8 +664,6 @@ axe_attach(device_t dev)
}
mtx_lock(&sc->sc_mtx);
- sc->sc_flags |= AXE_FLAG_WAIT_LINK;
-
/* start setup */
usb2_config_td_queue_command
@@ -687,6 +732,9 @@ axe_cfg_ax88178_init(struct axe_softc *sc)
axe_cfg_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL);
err = usb2_config_td_sleep(&sc->sc_config_td, hz / 4);
+ /* Enable MII/GMII/RGMII interface to work with external PHY. */
+ axe_cfg_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL);
+ err = usb2_config_td_sleep(&sc->sc_config_td, hz / 4);
axe_cfg_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
}
@@ -701,7 +749,7 @@ axe_cfg_ax88772_init(struct axe_softc *sc)
axe_cfg_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL);
err = usb2_config_td_sleep(&sc->sc_config_td, hz / 16);
- if (sc->sc_phyaddrs[1] == AXE_INTPHY) {
+ if (sc->sc_phyno == AXE_772_PHY_NO_EPHY) {
/* ask for the embedded PHY */
axe_cfg_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL);
err = usb2_config_td_sleep(&sc->sc_config_td, hz / 64);
@@ -752,6 +800,19 @@ axe_cfg_first_time_setup(struct axe_softc *sc,
* Load PHY indexes first. Needed by axe_xxx_init().
*/
axe_cfg_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, sc->sc_phyaddrs);
+#if 1
+ device_printf(sc->sc_dev, "PHYADDR 0x%02x:0x%02x\n",
+ sc->sc_phyaddrs[0], sc->sc_phyaddrs[1]);
+#endif
+ sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI);
+ if (sc->sc_phyno == -1)
+ sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC);
+ if (sc->sc_phyno == -1) {
+ device_printf(sc->sc_dev,
+ "no valid PHY address found, "
+ "assuming PHY address 0\n");
+ sc->sc_phyno = 0;
+ }
if (sc->sc_flags & AXE_FLAG_178) {
axe_cfg_ax88178_init(sc);
@@ -771,12 +832,6 @@ axe_cfg_first_time_setup(struct axe_softc *sc,
*/
axe_cfg_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->sc_ipgs);
- /*
- * Work around broken adapters that appear to lie about
- * their PHY addresses.
- */
- sc->sc_phyaddrs[0] = sc->sc_phyaddrs[1] = 0xFF;
-
mtx_unlock(&sc->sc_mtx);
ifp = if_alloc(IFT_ETHER);
@@ -1108,7 +1163,7 @@ axe_bulk_write_callback(struct usb2_xfer *xfer)
usb2_transfer_start(sc->sc_xfer[2]);
goto done;
}
- if (sc->sc_flags & AXE_FLAG_WAIT_LINK) {
+ if ((sc->sc_flags & AXE_FLAG_LINK) == 0) {
/*
* don't send anything if there is no link !
*/
@@ -1204,19 +1259,17 @@ axe_cfg_tick(struct axe_softc *sc,
return;
}
mii_tick(mii);
-
- mii_pollstat(mii);
-
- if ((sc->sc_flags & AXE_FLAG_WAIT_LINK) &&
- (mii->mii_media_status & IFM_ACTIVE) &&
- (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)) {
- sc->sc_flags &= ~AXE_FLAG_WAIT_LINK;
- }
sc->sc_media_active = mii->mii_media_active;
sc->sc_media_status = mii->mii_media_status;
-
+ if ((sc->sc_flags & AXE_FLAG_LINK) == 0) {
+ axe_cfg_miibus_statchg(sc->sc_dev);
+ /* XXX */
+ if ((sc->sc_flags & AXE_FLAG_LINK) == 0) {
+ sc->sc_media_active = IFM_ETHER | IFM_NONE;
+ sc->sc_media_status = IFM_AVALID;
+ }
+ }
/* start stopped transfers, if any */
-
axe_start_transfers(sc);
}
@@ -1444,7 +1497,7 @@ axe_cfg_pre_stop(struct axe_softc *sc,
sc->sc_flags &= ~(AXE_FLAG_HL_READY |
AXE_FLAG_LL_READY);
- sc->sc_flags |= AXE_FLAG_WAIT_LINK;
+ sc->sc_flags &= ~AXE_FLAG_LINK;
/*
* stop all the transfers, if not already stopped:
diff --git a/sys/dev/usb2/ethernet/if_axe2_reg.h b/sys/dev/usb2/ethernet/if_axe2_reg.h
index 9228f77..79c745f 100644
--- a/sys/dev/usb2/ethernet/if_axe2_reg.h
+++ b/sys/dev/usb2/ethernet/if_axe2_reg.h
@@ -135,8 +135,23 @@
#define AXE_178_RXCMD_MFB_8192 0x0200
#define AXE_178_RXCMD_MFB_16384 0x0300
-#define AXE_NOPHY 0xE0
-#define AXE_INTPHY 0x10
+#define AXE_PHY_SEL_PRI 1
+#define AXE_PHY_SEL_SEC 0
+#define AXE_PHY_TYPE_MASK 0xE0
+#define AXE_PHY_TYPE_SHIFT 5
+#define AXE_PHY_TYPE(x) \
+ (((x) & AXE_PHY_TYPE_MASK) >> AXE_PHY_TYPE_SHIFT)
+
+#define PHY_TYPE_100_HOME 0 /* 10/100 or 1M HOME PHY */
+#define PHY_TYPE_GIG 1 /* Gigabit PHY */
+#define PHY_TYPE_SPECIAL 4 /* Special case */
+#define PHY_TYPE_RSVD 5 /* Reserved */
+#define PHY_TYPE_NON_SUP 7 /* Non-supported PHY */
+
+#define AXE_PHY_NO_MASK 0x1F
+#define AXE_PHY_NO(x) ((x) & AXE_PHY_NO_MASK)
+
+#define AXE_772_PHY_NO_EPHY 0x10 /* Embedded 10/100 PHY of AX88772 */
#define AXE_BULK_BUF_SIZE 16384 /* bytes */
@@ -170,12 +185,14 @@ struct axe_softc {
device_t sc_miibus;
device_t sc_dev;
+ int sc_phyno;
+
uint32_t sc_unit;
uint32_t sc_media_active;
uint32_t sc_media_status;
uint16_t sc_flags;
-#define AXE_FLAG_WAIT_LINK 0x0001
+#define AXE_FLAG_LINK 0x0001
#define AXE_FLAG_INTR_STALL 0x0002
#define AXE_FLAG_READ_STALL 0x0004
#define AXE_FLAG_WRITE_STALL 0x0008
diff --git a/sys/dev/usb2/image/uscanner2.c b/sys/dev/usb2/image/uscanner2.c
index fa939ef..4ce13a8 100644
--- a/sys/dev/usb2/image/uscanner2.c
+++ b/sys/dev/usb2/image/uscanner2.c
@@ -266,6 +266,7 @@ static const struct usb2_device_id uscanner_devs[] = {
{USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_4100C, 0)},
{USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_4200C, 0)},
{USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_4300C, 0)},
+ {USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_4470C, 0)},
{USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_4670V, 0)},
{USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_S20, 0)},
{USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_5200C, 0)},
diff --git a/sys/dev/usb2/include/usb2_devid.h b/sys/dev/usb2/include/usb2_devid.h
index 08c4b71..c5b5109 100644
--- a/sys/dev/usb2/include/usb2_devid.h
+++ b/sys/dev/usb2/include/usb2_devid.h
@@ -4,7 +4,7 @@
* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
*
* generated from:
- * FreeBSD: head/sys/dev/usb/usbdevs 185998 2008-12-12 18:34:27Z thompsa
+ * FreeBSD: src/sys/dev/usb/usbdevs,v 1.390 2008/12/23 13:09:17 remko Exp
*/
/* $NetBSD: usbdevs,v 1.392 2004/12/29 08:38:44 imp Exp $ */
@@ -533,6 +533,7 @@
#define USB_VENDOR_FOSSIL 0x0e67 /* Fossil, Inc */
#define USB_VENDOR_GMATE 0x0e7e /* G.Mate, Inc */
#define USB_VENDOR_OTI 0x0ea0 /* Ours Technology */
+#define USB_VENDOR_YISO 0x0eab /* Yiso Wireless Co. */
#define USB_VENDOR_PILOTECH 0x0eaf /* Pilotech */
#define USB_VENDOR_NOVATECH 0x0eb0 /* NovaTech */
#define USB_VENDOR_ITEGNO 0x0eba /* iTegno */
@@ -814,6 +815,7 @@
/* Alcor Micro, Inc. products */
#define USB_PRODUCT_ALCOR2_KBD_HUB 0x2802 /* Kbd Hub */
+#define USB_PRODUCT_ALCOR_TRANSCEND 0x6387 /* Transcend JetFlash Drive */
#define USB_PRODUCT_ALCOR_MA_KBD_HUB 0x9213 /* MacAlly Kbd Hub */
#define USB_PRODUCT_ALCOR_AU9814 0x9215 /* AU9814 Hub */
#define USB_PRODUCT_ALCOR_UMCR_9361 0x9361 /* USB Multimedia Card Reader */
@@ -1286,6 +1288,7 @@
#define USB_PRODUCT_FTDI_EMCU2D 0xe88a /* Expert mouseCLOCK USB II */
#define USB_PRODUCT_FTDI_PCMSFU 0xe88b /* Precision Clock MSF USB */
#define USB_PRODUCT_FTDI_EMCU2H 0xe88c /* Expert mouseCLOCK USB II HBG */
+#define USB_PRODUCT_FTDI_MAXSTREAM 0xee18 /* Maxstream PKG-U */
#define USB_PRODUCT_FTDI_USBSERIAL 0xfa00 /* Matrix Orbital USB Serial */
#define USB_PRODUCT_FTDI_MX2_3 0xfa01 /* Matrix Orbital MX2 or MX3 */
#define USB_PRODUCT_FTDI_MX4_5 0xfa02 /* Matrix Orbital MX4 or MX5 */
@@ -1423,6 +1426,7 @@
#define USB_PRODUCT_HP_2200C 0x0605 /* ScanJet 2200C */
#define USB_PRODUCT_HP_5300C 0x0701 /* Scanjet 5300C */
#define USB_PRODUCT_HP_4400C 0x0705 /* Scanjet 4400C */
+#define USB_PRODUCT_HP_4470C 0x0805 /* Scanjet 4470C */
#define USB_PRODUCT_HP_82x0C 0x0b01 /* Scanjet 82x0C */
#define USB_PRODUCT_HP_2300D 0x0b17 /* Laserjet 2300d */
#define USB_PRODUCT_HP_970CSE 0x1004 /* Deskjet 970Cse */
@@ -2008,6 +2012,7 @@
#define USB_PRODUCT_QUALCOMM2_CDMA_MSM 0x3196 /* CDMA Technologies MSM modem */
#define USB_PRODUCT_QUALCOMMINC_CDMA_MSM 0x0001 /* CDMA Technologies MSM modem */
#define USB_PRODUCT_QUALCOMMINC_ZTE_STOR 0x2000 /* USB ZTE Storage */
+#define USB_PRODUCT_QUALCOMMINC_AC8700 0xfffe /* CDMA 1xEVDO USB modem */
/* Qtronix products */
#define USB_PRODUCT_QTRONIX_980N 0x2011 /* Scorpion-980N keyboard */
@@ -2469,6 +2474,9 @@
#define USB_PRODUCT_YANO_U640MO 0x0101 /* U640MO-03 */
#define USB_PRODUCT_YANO_FW800HD 0x05fc /* METALWEAR-HDD */
+/* Yiso Wireless Co. products */
+#define USB_PRODUCT_YISO_C893 0xc893 /* CDMA 2000 1xEVDO PC Card */
+
/* Z-Com products */
#define USB_PRODUCT_ZCOM_M4Y750 0x0001 /* M4Y-750 */
#define USB_PRODUCT_ZCOM_XI725 0x0002 /* XI-725/726 */
diff --git a/sys/dev/usb2/include/usb2_devtable.h b/sys/dev/usb2/include/usb2_devtable.h
index e678540..afc9ba9 100644
--- a/sys/dev/usb2/include/usb2_devtable.h
+++ b/sys/dev/usb2/include/usb2_devtable.h
@@ -4,7 +4,7 @@
* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
*
* generated from:
- * FreeBSD: head/sys/dev/usb/usbdevs 185998 2008-12-12 18:34:27Z thompsa
+ * FreeBSD: src/sys/dev/usb/usbdevs,v 1.390 2008/12/23 13:09:17 remko Exp
*/
/* $NetBSD: usbdevs,v 1.392 2004/12/29 08:38:44 imp Exp $ */
@@ -623,6 +623,12 @@ const struct usb_knowndev usb_knowndevs[] = {
"Kbd Hub",
},
{
+ USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_TRANSCEND,
+ 0,
+ "Alcor Micro",
+ "Transcend JetFlash Drive",
+ },
+ {
USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_MA_KBD_HUB,
0,
"Alcor Micro",
@@ -2495,6 +2501,12 @@ const struct usb_knowndev usb_knowndevs[] = {
"Expert mouseCLOCK USB II HBG",
},
{
+ USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MAXSTREAM,
+ 0,
+ "Future Technology Devices",
+ "Maxstream PKG-U",
+ },
+ {
USB_VENDOR_FTDI, USB_PRODUCT_FTDI_USBSERIAL,
0,
"Future Technology Devices",
@@ -3041,6 +3053,12 @@ const struct usb_knowndev usb_knowndevs[] = {
"Scanjet 4400C",
},
{
+ USB_VENDOR_HP, USB_PRODUCT_HP_4470C,
+ 0,
+ "Hewlett Packard",
+ "Scanjet 4470C",
+ },
+ {
USB_VENDOR_HP, USB_PRODUCT_HP_82x0C,
0,
"Hewlett Packard",
@@ -5471,6 +5489,12 @@ const struct usb_knowndev usb_knowndevs[] = {
"USB ZTE Storage",
},
{
+ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_AC8700,
+ 0,
+ "Qualcomm, Incorporated",
+ "CDMA 1xEVDO USB modem",
+ },
+ {
USB_VENDOR_QTRONIX, USB_PRODUCT_QTRONIX_980N,
0,
"Qtronix",
@@ -7145,6 +7169,12 @@ const struct usb_knowndev usb_knowndevs[] = {
"METALWEAR-HDD",
},
{
+ USB_VENDOR_YISO, USB_PRODUCT_YISO_C893,
+ 0,
+ "Yiso Wireless Co.",
+ "CDMA 2000 1xEVDO PC Card",
+ },
+ {
USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_M4Y750,
0,
"Z-Com",
@@ -10055,6 +10085,12 @@ const struct usb_knowndev usb_knowndevs[] = {
NULL,
},
{
+ USB_VENDOR_YISO, 0,
+ USB_KNOWNDEV_NOPROD,
+ "Yiso Wireless Co.",
+ NULL,
+ },
+ {
USB_VENDOR_PILOTECH, 0,
USB_KNOWNDEV_NOPROD,
"Pilotech",
diff --git a/sys/dev/usb2/include/usb2_ioctl.h b/sys/dev/usb2/include/usb2_ioctl.h
index 2a679c9..a4ec979 100644
--- a/sys/dev/usb2/include/usb2_ioctl.h
+++ b/sys/dev/usb2/include/usb2_ioctl.h
@@ -39,13 +39,6 @@
#define USB_DEVICE_NAME "usb"
#define USB_GENERIC_NAME "ugen"
-/* definition of USB power mode */
-#define USB_POWER_MODE_OFF 0 /* turn off device */
-#define USB_POWER_MODE_ON 1 /* always on */
-#define USB_POWER_MODE_SAVE 2 /* automatic suspend and resume */
-#define USB_POWER_MODE_SUSPEND 3 /* force suspend */
-#define USB_POWER_MODE_RESUME 4 /* force resume */
-
struct usb2_read_dir {
void *urd_data;
uint32_t urd_startentry;
diff --git a/sys/dev/usb2/include/usb2_standard.h b/sys/dev/usb2/include/usb2_standard.h
index 3671a51..fbe6f36 100644
--- a/sys/dev/usb2/include/usb2_standard.h
+++ b/sys/dev/usb2/include/usb2_standard.h
@@ -48,12 +48,20 @@
#define USB_POWER_DOWN_TIME 200 /* ms */
#define USB_PORT_POWER_DOWN_TIME 100 /* ms */
+/* Definition of software USB power modes */
+#define USB_POWER_MODE_OFF 0 /* turn off device */
+#define USB_POWER_MODE_ON 1 /* always on */
+#define USB_POWER_MODE_SAVE 2 /* automatic suspend and resume */
+#define USB_POWER_MODE_SUSPEND 3 /* force suspend */
+#define USB_POWER_MODE_RESUME 4 /* force resume */
+
#if 0
/* These are the values from the USB specification. */
#define USB_PORT_RESET_DELAY 10 /* ms */
#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
#define USB_PORT_RESET_RECOVERY 10 /* ms */
#define USB_PORT_POWERUP_DELAY 100 /* ms */
+#define USB_PORT_RESUME_DELAY 20 /* ms */
#define USB_SET_ADDRESS_SETTLE 2 /* ms */
#define USB_RESUME_DELAY (20*5) /* ms */
#define USB_RESUME_WAIT 10 /* ms */
@@ -65,6 +73,7 @@
#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
#define USB_PORT_RESET_RECOVERY 250 /* ms */
#define USB_PORT_POWERUP_DELAY 300 /* ms */
+#define USB_PORT_RESUME_DELAY (20*2) /* ms */
#define USB_SET_ADDRESS_SETTLE 10 /* ms */
#define USB_RESUME_DELAY (50*5) /* ms */
#define USB_RESUME_WAIT 50 /* ms */
diff --git a/sys/dev/usb2/serial/u3g2.c b/sys/dev/usb2/serial/u3g2.c
index a15f081..4e0bfab 100644
--- a/sys/dev/usb2/serial/u3g2.c
+++ b/sys/dev/usb2/serial/u3g2.c
@@ -37,7 +37,7 @@
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
-#include <dev/usb2/include/usb2_cdc.h>
+#include <dev/usb2/include/usb2_defs.h>
#define USB_DEBUG_VAR u3g_debug
@@ -50,6 +50,8 @@
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_msctest.h>
+#include <dev/usb2/core/usb2_dynamic.h>
+#include <dev/usb2/core/usb2_device.h>
#include <dev/usb2/serial/usb2_serial.h>
@@ -66,6 +68,20 @@ SYSCTL_INT(_hw_usb2_u3g, OID_AUTO, debug, CTLFLAG_RW,
#define U3G_CONFIG_INDEX 0
#define U3G_BSIZE 2048
+#define U3GSP_GPRS 0
+#define U3GSP_EDGE 1
+#define U3GSP_CDMA 2
+#define U3GSP_UMTS 3
+#define U3GSP_HSDPA 4
+#define U3GSP_HSUPA 5
+#define U3GSP_HSPA 6
+#define U3GSP_MAX 7
+
+#define U3GFL_NONE 0x00 /* No flags */
+#define U3GFL_HUAWEI_INIT 0x01 /* Init command required */
+#define U3GFL_SCSI_EJECT 0x02 /* SCSI eject command required */
+#define U3GFL_SIERRA_INIT 0x04 /* Init command required */
+
struct u3g_speeds_s {
uint32_t ispeed;
uint32_t ospeed;
@@ -98,6 +114,8 @@ static void u3g_stop_read(struct usb2_com_softc *ucom);
static void u3g_start_write(struct usb2_com_softc *ucom);
static void u3g_stop_write(struct usb2_com_softc *ucom);
+static int u3g_driver_loaded(struct module *mod, int what, void *arg);
+
static const struct usb2_config u3g_config[U3G_N_TRANSFER] = {
[0] = {
@@ -151,10 +169,195 @@ static driver_t u3g_driver = {
.size = sizeof(struct u3g_softc),
};
-DRIVER_MODULE(u3g, ushub, u3g_driver, u3g_devclass, NULL, 0);
+DRIVER_MODULE(u3g, ushub, u3g_driver, u3g_devclass, u3g_driver_loaded, 0);
MODULE_DEPEND(u3g, usb2_serial, 1, 1, 1);
MODULE_DEPEND(u3g, usb2_core, 1, 1, 1);
+/* Huawei specific defines */
+
+#define U3GINFO(flag,speed) ((flag)|((speed) * 256))
+#define U3G_GET_SPEED(uaa) (USB_GET_DRIVER_INFO(uaa) / 256)
+
+/*
+ * NOTE: The entries marked with XXX should be checked for the correct
+ * speed indication to set the buffer sizes.
+ */
+static const struct usb2_device_id u3g_devs[] = {
+ /* OEM: Option */
+ {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3G, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
+ {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUAD, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
+ {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
+ {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAX36, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))},
+ {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAXHSUPA, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))},
+ {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_VODAFONEMC3G, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
+ /* OEM: Qualcomm, Inc. */
+ {USB_VPI(USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_ZTE_STOR, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
+ {USB_VPI(USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
+ /* OEM: Huawei */
+ {USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE, U3GINFO(U3GSP_HSDPA, U3GFL_HUAWEI_INIT))},
+ {USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220, U3GINFO(U3GSP_HSPA, U3GFL_HUAWEI_INIT))},
+ /* OEM: Novatel */
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC950D, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740_2, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V620, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V640, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))}, /* XXX */
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
+ {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ZEROCD, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
+ {USB_VPI(USB_VENDOR_DELL, USB_PRODUCT_DELL_U740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
+ /* OEM: Merlin */
+ {USB_VPI(USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ /* OEM: Sierra Wireless: */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_HS2300, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))},
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781, U3GINFO(U3GSP_UMTS, U3GFL_NONE))}, /* XXX */
+ {USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_HS2300, U3GINFO(U3GSP_HSPA, U3GFL_NONE))}, /* XXX */
+ /* Sierra TruInstaller device ID */
+ {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_TRUINSTALL, U3GINFO(U3GSP_UMTS, U3GFL_SIERRA_INIT))},
+};
+
+static void
+u3g_sierra_init(struct usb2_device *udev)
+{
+ struct usb2_device_request req;
+
+ DPRINTFN(0, "\n");
+
+ req.bmRequestType = UT_VENDOR;
+ req.bRequest = UR_SET_INTERFACE;
+ USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
+ USETW(req.wIndex, UHF_PORT_CONNECTION);
+ USETW(req.wLength, 0);
+
+ if (usb2_do_request_flags(udev, NULL, &req,
+ NULL, 0, NULL, USB_MS_HZ)) {
+ /* ignore any errors */
+ }
+ return;
+}
+
+static void
+u3g_huawei_init(struct usb2_device *udev)
+{
+ struct usb2_device_request req;
+
+ DPRINTFN(0, "\n");
+
+ req.bmRequestType = UT_WRITE_DEVICE;
+ req.bRequest = UR_SET_FEATURE;
+ USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
+ USETW(req.wIndex, UHF_PORT_SUSPEND);
+ USETW(req.wLength, 0);
+
+ if (usb2_do_request_flags(udev, NULL, &req,
+ NULL, 0, NULL, USB_MS_HZ)) {
+ /* ignore any errors */
+ }
+ return;
+}
+
+static int
+u3g_lookup_huawei(struct usb2_attach_arg *uaa)
+{
+ /* Calling the lookup function will also set the driver info! */
+ return (usb2_lookup_id_by_uaa(u3g_devs, sizeof(u3g_devs), uaa));
+}
+
+/*
+ * The following function handles 3G modem devices (E220, Mobile,
+ * etc.) with auto-install flash disks for Windows/MacOSX on the first
+ * interface. After some command or some delay they change appearance
+ * to a modem.
+ */
+static usb2_error_t
+u3g_test_huawei_autoinst(struct usb2_device *udev,
+ struct usb2_attach_arg *uaa)
+{
+ struct usb2_interface *iface;
+ struct usb2_interface_descriptor *id;
+ uint32_t flags;
+
+ if (udev == NULL) {
+ return (USB_ERR_INVAL);
+ }
+ iface = usb2_get_iface(udev, 0);
+ if (iface == NULL) {
+ return (USB_ERR_INVAL);
+ }
+ id = iface->idesc;
+ if (id == NULL) {
+ return (USB_ERR_INVAL);
+ }
+ if (id->bInterfaceClass != UICLASS_MASS) {
+ return (USB_ERR_INVAL);
+ }
+ if (u3g_lookup_huawei(uaa)) {
+ /* no device match */
+ return (USB_ERR_INVAL);
+ }
+ flags = USB_GET_DRIVER_INFO(uaa);
+
+ if (flags & U3GFL_HUAWEI_INIT) {
+ u3g_huawei_init(udev);
+ } else if (flags & U3GFL_SCSI_EJECT) {
+ return (usb2_test_autoinstall(udev, 0, 1));
+ } else if (flags & U3GFL_SIERRA_INIT) {
+ u3g_sierra_init(udev);
+ } else {
+ /* no quirks */
+ return (USB_ERR_INVAL);
+ }
+ return (0); /* success */
+}
+
+static int
+u3g_driver_loaded(struct module *mod, int what, void *arg)
+{
+ switch (what) {
+ case MOD_LOAD:
+ /* register our autoinstall handler */
+ usb2_test_huawei_autoinst_p = &u3g_test_huawei_autoinst;
+ break;
+ case MOD_UNLOAD:
+ usb2_test_huawei_unload(NULL);
+ break;
+ default:
+ return (EOPNOTSUPP);
+ }
+ return (0);
+}
+
static int
u3g_probe(device_t self)
{
@@ -169,7 +372,7 @@ u3g_probe(device_t self)
if (uaa->info.bInterfaceClass != UICLASS_VENDOR) {
return (ENXIO);
}
- return (usb2_lookup_huawei(uaa));
+ return (u3g_lookup_huawei(uaa));
}
static int
diff --git a/sys/dev/usb2/serial/uchcom2.c b/sys/dev/usb2/serial/uchcom2.c
index 2a49c72..fef2a89 100644
--- a/sys/dev/usb2/serial/uchcom2.c
+++ b/sys/dev/usb2/serial/uchcom2.c
@@ -196,8 +196,6 @@ static const struct usb2_device_id uchcom_devs[] = {
/* protypes */
-static int uchcom_ioctl(struct usb2_com_softc *, uint32_t, caddr_t, int,
- struct thread *);
static int uchcom_pre_param(struct usb2_com_softc *, struct termios *);
static void uchcom_cfg_get_status(struct usb2_com_softc *, uint8_t *,
uint8_t *);
@@ -297,7 +295,6 @@ struct usb2_com_callback uchcom_callback = {
.usb2_com_cfg_set_break = &uchcom_cfg_set_break,
.usb2_com_cfg_param = &uchcom_cfg_param,
.usb2_com_pre_param = &uchcom_pre_param,
- .usb2_com_ioctl = &uchcom_ioctl,
.usb2_com_start_read = &uchcom_start_read,
.usb2_com_stop_read = &uchcom_stop_read,
.usb2_com_start_write = &uchcom_start_write,
@@ -738,13 +735,6 @@ uchcom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
*msr = sc->sc_msr;
}
-static int
-uchcom_ioctl(struct usb2_com_softc *ucom, uint32_t cmd, caddr_t data, int flag,
- struct thread *td)
-{
- return (ENOTTY);
-}
-
static void
uchcom_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
{
diff --git a/sys/dev/usb2/serial/uftdi2.c b/sys/dev/usb2/serial/uftdi2.c
index 8484afe..b686ec5 100644
--- a/sys/dev/usb2/serial/uftdi2.c
+++ b/sys/dev/usb2/serial/uftdi2.c
@@ -249,6 +249,7 @@ static struct usb2_device_id uftdi_devs[] = {
{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2D, UFTDI_TYPE_8U232AM)},
{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_PCMSFU, UFTDI_TYPE_8U232AM)},
{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2H, UFTDI_TYPE_8U232AM)},
+ {USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MAXSTREAM, UFTDI_TYPE_8U232AM)},
{USB_VPI(USB_VENDOR_SIIG2, USB_PRODUCT_SIIG2_US2308, UFTDI_TYPE_8U232AM)},
{USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_VALUECAN, UFTDI_TYPE_8U232AM)},
{USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_NEOVI, UFTDI_TYPE_8U232AM)},
@@ -470,6 +471,7 @@ uftdi_read_callback(struct usb2_xfer *xfer)
{
struct uftdi_softc *sc = xfer->priv_sc;
uint8_t buf[2];
+ uint8_t ftdi_msr;
uint8_t msr;
uint8_t lsr;
@@ -481,9 +483,19 @@ uftdi_read_callback(struct usb2_xfer *xfer)
}
usb2_copy_out(xfer->frbuffers, 0, buf, 2);
- msr = FTDI_GET_MSR(buf);
+ ftdi_msr = FTDI_GET_MSR(buf);
lsr = FTDI_GET_LSR(buf);
+ msr = 0;
+ if (ftdi_msr & FTDI_SIO_CTS_MASK)
+ msr |= SER_CTS;
+ if (ftdi_msr & FTDI_SIO_DSR_MASK)
+ msr |= SER_DSR;
+ if (ftdi_msr & FTDI_SIO_RI_MASK)
+ msr |= SER_RI;
+ if (ftdi_msr & FTDI_SIO_RLSD_MASK)
+ msr |= SER_DCD;
+
if ((sc->sc_msr != msr) ||
((sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK))) {
DPRINTF("status change msr=0x%02x (0x%02x) "
diff --git a/sys/dev/usb2/serial/uplcom2.c b/sys/dev/usb2/serial/uplcom2.c
index 9a51eb5..6e556e5 100644
--- a/sys/dev/usb2/serial/uplcom2.c
+++ b/sys/dev/usb2/serial/uplcom2.c
@@ -171,8 +171,6 @@ static void uplcom_start_write(struct usb2_com_softc *);
static void uplcom_stop_write(struct usb2_com_softc *);
static void uplcom_cfg_get_status(struct usb2_com_softc *, uint8_t *,
uint8_t *);
-static int uplcom_ioctl(struct usb2_com_softc *, uint32_t, caddr_t, int,
- struct thread *);
static void uplcom_cfg_do_request(struct uplcom_softc *,
struct usb2_device_request *, void *);
@@ -260,7 +258,6 @@ struct usb2_com_callback uplcom_callback = {
.usb2_com_cfg_set_break = &uplcom_cfg_set_break,
.usb2_com_cfg_param = &uplcom_cfg_param,
.usb2_com_pre_param = &uplcom_pre_param,
- .usb2_com_ioctl = &uplcom_ioctl,
.usb2_com_start_read = &uplcom_start_read,
.usb2_com_stop_read = &uplcom_stop_read,
.usb2_com_start_write = &uplcom_start_write,
@@ -768,13 +765,6 @@ uplcom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
*msr = sc->sc_msr;
}
-static int
-uplcom_ioctl(struct usb2_com_softc *ucom, uint32_t cmd, caddr_t data, int flag,
- struct thread *td)
-{
- return (ENOTTY);
-}
-
static void
uplcom_intr_callback(struct usb2_xfer *xfer)
{
diff --git a/sys/dev/usb2/serial/uvscom2.c b/sys/dev/usb2/serial/uvscom2.c
index 8f4094f..92577d4 100644
--- a/sys/dev/usb2/serial/uvscom2.c
+++ b/sys/dev/usb2/serial/uvscom2.c
@@ -172,8 +172,6 @@ static void uvscom_start_write(struct usb2_com_softc *);
static void uvscom_stop_write(struct usb2_com_softc *);
static void uvscom_cfg_get_status(struct usb2_com_softc *, uint8_t *,
uint8_t *);
-static int uvscom_ioctl(struct usb2_com_softc *, uint32_t, caddr_t, int,
- struct thread *);
static void uvscom_cfg_write(struct uvscom_softc *, uint8_t, uint16_t);
static uint16_t uvscom_cfg_read_status(struct uvscom_softc *);
@@ -247,7 +245,6 @@ static const struct usb2_com_callback uvscom_callback = {
.usb2_com_cfg_close = &uvscom_cfg_close,
.usb2_com_pre_open = &uvscom_pre_open,
.usb2_com_pre_param = &uvscom_pre_param,
- .usb2_com_ioctl = &uvscom_ioctl,
.usb2_com_start_read = &uvscom_start_read,
.usb2_com_stop_read = &uvscom_stop_read,
.usb2_com_start_write = &uvscom_start_write,
@@ -753,13 +750,6 @@ uvscom_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
*msr = sc->sc_msr;
}
-static int
-uvscom_ioctl(struct usb2_com_softc *ucom, uint32_t cmd, caddr_t data, int fflag,
- struct thread *td)
-{
- return (ENOTTY);
-}
-
static void
uvscom_cfg_write(struct uvscom_softc *sc, uint8_t index, uint16_t value)
{
diff --git a/sys/dev/usb2/sound/uaudio2.c b/sys/dev/usb2/sound/uaudio2.c
index b843ef1..614db85 100644
--- a/sys/dev/usb2/sound/uaudio2.c
+++ b/sys/dev/usb2/sound/uaudio2.c
@@ -80,22 +80,27 @@
#include <dev/sound/chip.h>
#include "feeder_if.h"
+static int uaudio_default_rate = 96000;
+static int uaudio_default_bits = 32;
+static int uaudio_default_channels = 2;
+
#if USB_DEBUG
static int uaudio_debug = 0;
SYSCTL_NODE(_hw_usb2, OID_AUTO, uaudio, CTLFLAG_RW, 0, "USB uaudio");
SYSCTL_INT(_hw_usb2_uaudio, OID_AUTO, debug, CTLFLAG_RW,
&uaudio_debug, 0, "uaudio debug level");
+SYSCTL_INT(_hw_usb2_uaudio, OID_AUTO, default_rate, CTLFLAG_RW,
+ &uaudio_default_rate, 0, "uaudio default sample rate");
+SYSCTL_INT(_hw_usb2_uaudio, OID_AUTO, default_bits, CTLFLAG_RW,
+ &uaudio_default_bits, 0, "uaudio default sample bits");
+SYSCTL_INT(_hw_usb2_uaudio, OID_AUTO, default_channels, CTLFLAG_RW,
+ &uaudio_default_channels, 0, "uaudio default sample channels");
#endif
-static uint32_t uaudio_default_rate = 96000;
-static uint8_t uaudio_default_bits = 32;
-static uint8_t uaudio_default_channels = 2;
-
+#define UAUDIO_MINFRAMES 16 /* must be factor of 8 due HS-USB */
#define UAUDIO_NCHANBUFS 2 /* number of outstanding request */
-#define UAUDIO_NFRAMES 25 /* ms of sound in each request */
#define UAUDIO_RECURSE_LIMIT 24 /* rounds */
-#define UAUDIO_DEFAULT_BUFSZ ((2 * 96000 * 4 * 2) / (1000 / UAUDIO_NCHANBUFS)) /* bytes */
#define MAKE_WORD(h,l) (((h) << 8) | (l))
#define BIT_TEST(bm,bno) (((bm)[(bno) / 8] >> (7 - ((bno) % 8))) & 1)
@@ -154,6 +159,7 @@ struct uaudio_chan {
uint8_t *cur; /* current position in upper layer
* buffer */
+ uint32_t intr_size; /* in bytes */
uint32_t block_size;
uint32_t sample_rate;
uint32_t format;
@@ -389,13 +395,13 @@ static const char *uaudio_mixer_get_terminal_name(uint16_t);
#endif
static const struct usb2_config
- uaudio_cfg_record_full_speed[UAUDIO_NCHANBUFS] = {
+ uaudio_cfg_record[UAUDIO_NCHANBUFS] = {
[0] = {
.type = UE_ISOCHRONOUS,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
.mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
- .mh.frames = UAUDIO_NFRAMES,
+ .mh.frames = UAUDIO_MINFRAMES,
.mh.flags = {.short_xfer_ok = 1,},
.mh.callback = &uaudio_chan_record_callback,
},
@@ -405,66 +411,20 @@ static const struct usb2_config
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
.mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
- .mh.frames = UAUDIO_NFRAMES,
+ .mh.frames = UAUDIO_MINFRAMES,
.mh.flags = {.short_xfer_ok = 1,},
.mh.callback = &uaudio_chan_record_callback,
},
};
static const struct usb2_config
- uaudio_cfg_record_high_speed[UAUDIO_NCHANBUFS] = {
- [0] = {
- .type = UE_ISOCHRONOUS,
- .endpoint = UE_ADDR_ANY,
- .direction = UE_DIR_IN,
- .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
- .mh.frames = (UAUDIO_NFRAMES * 8),
- .mh.flags = {.short_xfer_ok = 1,},
- .mh.callback = &uaudio_chan_record_callback,
- },
-
- [1] = {
- .type = UE_ISOCHRONOUS,
- .endpoint = UE_ADDR_ANY,
- .direction = UE_DIR_IN,
- .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
- .mh.frames = (UAUDIO_NFRAMES * 8),
- .mh.flags = {.short_xfer_ok = 1,},
- .mh.callback = &uaudio_chan_record_callback,
- },
-};
-
-static const struct usb2_config
- uaudio_cfg_play_full_speed[UAUDIO_NCHANBUFS] = {
- [0] = {
- .type = UE_ISOCHRONOUS,
- .endpoint = UE_ADDR_ANY,
- .direction = UE_DIR_OUT,
- .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
- .mh.frames = UAUDIO_NFRAMES,
- .mh.flags = {.short_xfer_ok = 1,},
- .mh.callback = &uaudio_chan_play_callback,
- },
-
- [1] = {
- .type = UE_ISOCHRONOUS,
- .endpoint = UE_ADDR_ANY,
- .direction = UE_DIR_OUT,
- .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
- .mh.frames = UAUDIO_NFRAMES,
- .mh.flags = {.short_xfer_ok = 1,},
- .mh.callback = &uaudio_chan_play_callback,
- },
-};
-
-static const struct usb2_config
- uaudio_cfg_play_high_speed[UAUDIO_NCHANBUFS] = {
+ uaudio_cfg_play[UAUDIO_NCHANBUFS] = {
[0] = {
.type = UE_ISOCHRONOUS,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
.mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
- .mh.frames = (UAUDIO_NFRAMES * 8),
+ .mh.frames = UAUDIO_MINFRAMES,
.mh.flags = {.short_xfer_ok = 1,},
.mh.callback = &uaudio_chan_play_callback,
},
@@ -474,7 +434,7 @@ static const struct usb2_config
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
.mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
- .mh.frames = (UAUDIO_NFRAMES * 8),
+ .mh.frames = UAUDIO_MINFRAMES,
.mh.flags = {.short_xfer_ok = 1,},
.mh.callback = &uaudio_chan_play_callback,
},
@@ -706,10 +666,6 @@ uaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_clas
struct uaudio_softc *sc = device_get_softc(device_get_parent(dev));
char status[SND_STATUSLEN];
- if (bootverbose) {
- device_printf(dev, "using a default buffer "
- "size of %u bytes\n", UAUDIO_DEFAULT_BUFSZ);
- }
uaudio_mixer_init(sc);
if (sc->sc_uq_audio_swap_lr) {
@@ -1066,19 +1022,20 @@ uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb2_device *udev,
chan->iface_index = curidx;
chan->iface_alt_index = alt_index;
- chan->usb2_cfg =
- (ep_dir == UE_DIR_IN) ?
- ((fps == 1000) ?
- uaudio_cfg_record_full_speed :
- uaudio_cfg_record_high_speed) :
- ((fps == 1000) ?
- uaudio_cfg_play_full_speed :
- uaudio_cfg_play_high_speed);
-
+ if (ep_dir == UE_DIR_IN)
+ chan->usb2_cfg =
+ uaudio_cfg_record;
+ else
+ chan->usb2_cfg =
+ uaudio_cfg_play;
sample_size = ((chan->p_asf1d->bNrChannels *
chan->p_asf1d->bBitResolution) / 8);
+ /*
+ * NOTE: "chan->bytes_per_frame"
+ * should not be zero!
+ */
chan->bytes_per_frame = ((rate / fps) * sample_size);
if (sc->sc_sndstat_valid) {
@@ -1103,15 +1060,26 @@ uaudio_chan_fill_info(struct uaudio_softc *sc, struct usb2_device *udev)
{
uint32_t rate = uaudio_default_rate;
uint32_t z;
- uint16_t fps = (usb2_get_speed(udev) == USB_SPEED_HIGH) ? 8000 : 1000;
+ uint16_t fps = usb2_get_isoc_fps(udev);
uint8_t bits = uaudio_default_bits;
uint8_t y;
uint8_t channels = uaudio_default_channels;
uint8_t x;
bits -= (bits % 8);
+ if ((bits == 0) || (bits > 32)) {
+ /* set a valid value */
+ bits = 32;
+ }
rate -= (rate % fps);
-
+ if ((rate == 0) || (rate > 192000)) {
+ /* set a valid value */
+ rate = 192000 - (192000 % fps);
+ }
+ if ((channels == 0) || (channels > 2)) {
+ /* set a valid value */
+ channels = 2;
+ }
if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) {
sc->sc_sndstat_valid = 1;
}
@@ -1141,21 +1109,23 @@ uaudio_chan_play_callback(struct usb2_xfer *xfer)
{
struct uaudio_chan *ch = xfer->priv_sc;
uint32_t *p_len = xfer->frlengths;
- uint32_t total = (sndbuf_getblkcnt(ch->pcm_buf) *
- sndbuf_getblksz(ch->pcm_buf)) / 2;
+ uint32_t total;
uint32_t blockcount;
uint32_t n;
uint32_t offset;
/* allow dynamic sizing of play buffer */
+ total = ch->intr_size;
+
+ /* allow dynamic sizing of play buffer */
blockcount = total / ch->bytes_per_frame;
- /* align to 8 units */
- blockcount &= ~7;
+ /* align units */
+ blockcount -= (blockcount % UAUDIO_MINFRAMES);
/* range check - min */
if (blockcount == 0) {
- blockcount = 8;
+ blockcount = UAUDIO_MINFRAMES;
}
/* range check - max */
if (blockcount > xfer->max_frame_count) {
@@ -1230,21 +1200,23 @@ uaudio_chan_record_callback(struct usb2_xfer *xfer)
uint32_t *p_len = xfer->frlengths;
uint32_t n;
uint32_t m;
- uint32_t total = (sndbuf_getblkcnt(ch->pcm_buf) *
- sndbuf_getblksz(ch->pcm_buf)) / 2;
+ uint32_t total;
uint32_t blockcount;
uint32_t offset0;
uint32_t offset1;
/* allow dynamic sizing of play buffer */
+ total = ch->intr_size;
+
+ /* allow dynamic sizing of play buffer */
blockcount = total / ch->bytes_per_frame;
- /* align to 8 units */
- blockcount &= ~7;
+ /* align units */
+ blockcount -= (blockcount % UAUDIO_MINFRAMES);
/* range check - min */
if (blockcount == 0) {
- blockcount = 8;
+ blockcount = UAUDIO_MINFRAMES;
}
/* range check - max */
if (blockcount > xfer->max_frame_count) {
@@ -1326,21 +1298,30 @@ uaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b,
{
struct uaudio_chan *ch = ((dir == PCMDIR_PLAY) ?
&sc->sc_play_chan : &sc->sc_rec_chan);
+ uint32_t buf_size;
uint8_t endpoint;
uint8_t iface_index;
uint8_t alt_index;
usb2_error_t err;
- ch->buf = malloc(UAUDIO_DEFAULT_BUFSZ, M_DEVBUF, M_WAITOK | M_ZERO);
+ /* compute required buffer size */
+ buf_size = (ch->bytes_per_frame * UAUDIO_MINFRAMES);
+
+ /* setup interrupt interval */
+ ch->intr_size = buf_size;
+ /* double buffering */
+ buf_size *= 2;
+
+ ch->buf = malloc(buf_size, M_DEVBUF, M_WAITOK | M_ZERO);
if (ch->buf == NULL) {
goto error;
}
- if (sndbuf_setup(b, ch->buf, UAUDIO_DEFAULT_BUFSZ) != 0) {
+ if (sndbuf_setup(b, ch->buf, buf_size) != 0) {
goto error;
}
ch->start = ch->buf;
- ch->end = ch->buf + UAUDIO_DEFAULT_BUFSZ;
+ ch->end = ch->buf + buf_size;
ch->cur = ch->buf;
ch->pcm_ch = c;
ch->pcm_mtx = c->lock;
@@ -1437,16 +1418,14 @@ int
uaudio_chan_set_param_fragments(struct uaudio_chan *ch, uint32_t blocksize,
uint32_t blockcount)
{
- uint32_t max = sndbuf_getmaxsize(ch->pcm_buf);
-
- RANGE(blocksize, 128, max / 2);
-
- blockcount = max / blocksize;
- RANGE(blockcount, 2, 512);
+ /* we only support one size */
+ blocksize = ch->intr_size;
+ blockcount = 2;
if ((sndbuf_getblksz(ch->pcm_buf) != blocksize) ||
(sndbuf_getblkcnt(ch->pcm_buf) != blockcount)) {
-
+ DPRINTFN(1, "resizing to %u x "
+ "%u bytes\n", blockcount, blocksize);
if (sndbuf_resize(ch->pcm_buf, blockcount, blocksize)) {
DPRINTFN(0, "failed to resize sound buffer, count=%u, "
"size=%u\n", blockcount, blocksize);
@@ -2672,7 +2651,10 @@ uaudio_mixer_fill_info(struct uaudio_softc *sc, struct usb2_device *udev,
DPRINTF("invalid Audio Control header\n");
goto done;
}
- wTotalLen = UGETW(cd->wTotalLength);
+ /* "wTotalLen" is allowed to be corrupt */
+ wTotalLen = UGETW(acdp->wTotalLength) - acdp->bLength;
+
+ /* get USB audio revision */
sc->sc_audio_rev = UGETW(acdp->bcdADC);
DPRINTFN(3, "found AC header, vers=%03x, len=%d\n",
diff --git a/sys/dev/usb2/storage/umass2.c b/sys/dev/usb2/storage/umass2.c
index cfdfe77..1771982 100644
--- a/sys/dev/usb2/storage/umass2.c
+++ b/sys/dev/usb2/storage/umass2.c
@@ -400,6 +400,10 @@ static const struct umass_devdescr umass_devdescr[] = {
UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
NO_GETMAXLUN
},
+ {USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_TRANSCEND, RID_WILDCARD,
+ UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
+ NO_GETMAXLUN
+ },
{USB_VENDOR_ASAHIOPTICAL, USB_PRODUCT_ASAHIOPTICAL_OPTIO230, RID_WILDCARD,
UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
NO_INQUIRY
@@ -636,10 +640,10 @@ static const struct umass_devdescr umass_devdescr[] = {
UMASS_PROTO_SCSI,
NO_GETMAXLUN
},
- { USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_SDS_HOTFIND_D, RID_WILDCARD,
- UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
- NO_GETMAXLUN | NO_SYNCHRONIZE_CACHE
- },
+ {USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_SDS_HOTFIND_D, RID_WILDCARD,
+ UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
+ NO_GETMAXLUN | NO_SYNCHRONIZE_CACHE
+ },
{USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_CFMS_RW, RID_WILDCARD,
UMASS_PROTO_SCSI,
NO_QUIRKS
diff --git a/sys/dev/usb2/storage/ustorage2_fs.c b/sys/dev/usb2/storage/ustorage2_fs.c
index 62981d7..6c606d5 100644
--- a/sys/dev/usb2/storage/ustorage2_fs.c
+++ b/sys/dev/usb2/storage/ustorage2_fs.c
@@ -1301,6 +1301,7 @@ ustorage_fs_mode_select(struct ustorage_fs_softc *sc)
static uint8_t
ustorage_fs_synchronize_cache(struct ustorage_fs_softc *sc)
{
+#if 0
struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun;
uint8_t rc;
@@ -1311,6 +1312,7 @@ ustorage_fs_synchronize_cache(struct ustorage_fs_softc *sc)
if (rc) {
currlun->sense_data = SS_WRITE_ERROR;
}
+#endif
return (0);
}
diff --git a/sys/dev/usb2/wlan/if_ural2.c b/sys/dev/usb2/wlan/if_ural2.c
index 2213439..3279e42 100644
--- a/sys/dev/usb2/wlan/if_ural2.c
+++ b/sys/dev/usb2/wlan/if_ural2.c
@@ -189,7 +189,6 @@ static const struct usb2_device_id ural_devs[] = {
{USB_VPI(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2570, 0)},
{USB_VPI(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2570_2, 0)},
{USB_VPI(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2570_3, 0)},
- {USB_VPI(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2573, 0)},
{USB_VPI(USB_VENDOR_SIEMENS2, USB_PRODUCT_SIEMENS2_WL54G, 0)},
{USB_VPI(USB_VENDOR_SMC, USB_PRODUCT_SMC_2862WG, 0)},
{USB_VPI(USB_VENDOR_SPHAIRON, USB_PRODUCT_SPHAIRON_UB801R, 0)},
@@ -787,8 +786,9 @@ ural_cfg_first_time_setup(struct ural_softc *sc,
/* retrieve MAC address and various other things from EEPROM */
ural_cfg_read_eeprom(sc);
- printf("%s: MAC/BBP RT2570 (rev 0x%02x), RF %s\n",
- sc->sc_name, sc->sc_asic_rev, ural_get_rf(sc->sc_rf_rev));
+ printf("%s: MAC/BBP RT2570 (rev 0x%02x), RF %s (0x%02x)\n",
+ sc->sc_name, sc->sc_asic_rev, ural_get_rf(sc->sc_rf_rev),
+ sc->sc_rf_rev);
mtx_unlock(&sc->sc_mtx);
@@ -958,8 +958,11 @@ ural_config_copy(struct ural_softc *sc,
static const char *
ural_get_rf(int rev)
{
+ ; /* style fix */
+
switch (rev) {
- case RAL_RF_2522:return "RT2522";
+ case RAL_RF_2522:
+ return "RT2522";
case RAL_RF_2523:
return "RT2523";
case RAL_RF_2524:
diff --git a/sys/dev/usb2/wlan/if_zyd2.c b/sys/dev/usb2/wlan/if_zyd2.c
index 2e29d37..5615080 100644
--- a/sys/dev/usb2/wlan/if_zyd2.c
+++ b/sys/dev/usb2/wlan/if_zyd2.c
@@ -155,6 +155,7 @@ static int zyd_newstate_cb(struct ieee80211vap *,
static void zyd_cfg_amrr_start(struct zyd_softc *);
static void zyd_update_mcast_cb(struct ifnet *);
static void zyd_update_promisc_cb(struct ifnet *);
+static void zyd_cfg_get_macaddr(struct zyd_softc *sc);
static const struct zyd_phy_pair zyd_def_phy[] = ZYD_DEF_PHY;
static const struct zyd_phy_pair zyd_def_phyB[] = ZYD_DEF_PHYB;
@@ -758,6 +759,17 @@ zyd_cfg_rfwrite(struct zyd_softc *sc, uint32_t value)
zyd_cfg_cmd(sc, ZYD_CMD_RFCFG, &req, 4 + (2 * rf->width), NULL, 0, 0);
}
+/*------------------------------------------------------------------------*
+ * zyd_cfg_rfwrite_cr
+ *------------------------------------------------------------------------*/
+static void
+zyd_cfg_rfwrite_cr(struct zyd_softc *sc, uint32_t val)
+{
+ zyd_cfg_write16(sc, ZYD_CR244, (val >> 16) & 0xff);
+ zyd_cfg_write16(sc, ZYD_CR243, (val >> 8) & 0xff);
+ zyd_cfg_write16(sc, ZYD_CR242, (val >> 0) & 0xff);
+}
+
static void
zyd_bulk_read_clear_stall_callback(struct usb2_xfer *xfer)
{
@@ -1148,10 +1160,24 @@ zyd_cfg_unlock_phy(struct zyd_softc *sc)
static void
zyd_cfg_set_beacon_interval(struct zyd_softc *sc, uint32_t bintval)
{
- /* XXX this is probably broken.. */
- zyd_cfg_write32(sc, ZYD_CR_ATIM_WND_PERIOD, bintval - 2);
- zyd_cfg_write32(sc, ZYD_CR_PRE_TBTT, bintval - 1);
- zyd_cfg_write32(sc, ZYD_CR_BCN_INTERVAL, bintval);
+ uint32_t val;
+
+ zyd_cfg_read32(sc, ZYD_CR_ATIM_WND_PERIOD, &val);
+ sc->sc_atim_wnd = val;
+ zyd_cfg_read32(sc, ZYD_CR_PRE_TBTT, &val);
+ sc->sc_pre_tbtt = val;
+ sc->sc_bcn_int = bintval;
+
+ if (sc->sc_bcn_int <= 5)
+ sc->sc_bcn_int = 5;
+ if (sc->sc_pre_tbtt < 4 || sc->sc_pre_tbtt >= sc->sc_bcn_int)
+ sc->sc_pre_tbtt = sc->sc_bcn_int - 1;
+ if (sc->sc_atim_wnd >= sc->sc_pre_tbtt)
+ sc->sc_atim_wnd = sc->sc_pre_tbtt - 1;
+
+ zyd_cfg_write32(sc, ZYD_CR_ATIM_WND_PERIOD, sc->sc_atim_wnd);
+ zyd_cfg_write32(sc, ZYD_CR_PRE_TBTT, sc->sc_pre_tbtt);
+ zyd_cfg_write32(sc, ZYD_CR_BCN_INTERVAL, sc->sc_bcn_int);
}
/*
@@ -1163,7 +1189,7 @@ zyd_rf_name(uint8_t type)
static const char *const zyd_rfs[] = {
"unknown", "unknown", "UW2451", "UCHIP", "AL2230",
"AL7230B", "THETA", "AL2210", "MAXIM_NEW", "GCT",
- "PV2000", "RALINK", "INTERSIL", "RFMD", "MAXIM_NEW2",
+ "AL2230S", "RALINK", "INTERSIL", "RFMD", "MAXIM_NEW2",
"PHILIPS"
};
@@ -1235,36 +1261,106 @@ static void
zyd_cfg_rf_al2230_init(struct zyd_softc *sc, struct zyd_rf *rf)
{
static const struct zyd_phy_pair phyini[] = ZYD_AL2230_PHY;
- static const uint32_t rfini[] = ZYD_AL2230_RF;
+ static const struct zyd_phy_pair phy2230s[] = ZYD_AL2230S_PHY_INIT;
+ static const struct zyd_phy_pair phypll[] = {
+ {ZYD_CR251, 0x2f}, {ZYD_CR251, 0x3f},
+ {ZYD_CR138, 0x28}, {ZYD_CR203, 0x06}
+ };
+ static const uint32_t rfini1[] = ZYD_AL2230_RF_PART1;
+ static const uint32_t rfini2[] = ZYD_AL2230_RF_PART2;
+ static const uint32_t rfini3[] = ZYD_AL2230_RF_PART3;
uint32_t i;
/* init RF-dependent PHY registers */
- for (i = 0; i != INDEXES(phyini); i++) {
+ for (i = 0; i != INDEXES(phyini); i++)
zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
- }
- /* init AL2230 radio */
- for (i = 0; i != INDEXES(rfini); i++) {
- zyd_cfg_rfwrite(sc, rfini[i]);
+ if ((sc->sc_rf_rev == ZYD_RF_AL2230S) || (sc->sc_al2230s != 0)) {
+ for (i = 0; i != INDEXES(phy2230s); i++)
+ zyd_cfg_write16(sc, phy2230s[i].reg, phy2230s[i].val);
}
+ /* init AL2230 radio */
+ for (i = 0; i != INDEXES(rfini1); i++)
+ zyd_cfg_rfwrite(sc, rfini1[i]);
+
+ if ((sc->sc_rf_rev == ZYD_RF_AL2230S) || (sc->sc_al2230s != 0))
+ zyd_cfg_rfwrite(sc, 0x000824);
+ else
+ zyd_cfg_rfwrite(sc, 0x0005a4);
+
+ for (i = 0; i != INDEXES(rfini2); i++)
+ zyd_cfg_rfwrite(sc, rfini2[i]);
+
+ for (i = 0; i != INDEXES(phypll); i++)
+ zyd_cfg_write16(sc, phypll[i].reg, phypll[i].val);
+
+ for (i = 0; i != INDEXES(rfini3); i++)
+ zyd_cfg_rfwrite(sc, rfini3[i]);
+}
+
+static void
+zyd_cfg_rf_al2230_fini(struct zyd_softc *sc, struct zyd_rf *rf)
+{
+ static const struct zyd_phy_pair phy[] = ZYD_AL2230_PHY_FINI_PART1;
+ uint32_t i;
+
+ for (i = 0; i != INDEXES(phy); i++)
+ zyd_cfg_write16(sc, phy[i].reg, phy[i].val);
+
+ if (sc->sc_newphy != 0)
+ zyd_cfg_write16(sc, ZYD_CR9, 0xe1);
+ zyd_cfg_write16(sc, ZYD_CR203, 0x6);
}
static void
zyd_cfg_rf_al2230_init_b(struct zyd_softc *sc, struct zyd_rf *rf)
{
static const struct zyd_phy_pair phyini[] = ZYD_AL2230_PHY_B;
- static const uint32_t rfini[] = ZYD_AL2230_RF_B;
+ static const struct zyd_phy_pair phy1[] = ZYD_AL2230_PHY_PART1;
+ static const struct zyd_phy_pair phy2[] = ZYD_AL2230_PHY_PART2;
+ static const struct zyd_phy_pair phy3[] = ZYD_AL2230_PHY_PART3;
+ static const struct zyd_phy_pair phy2230s[] = ZYD_AL2230S_PHY_INIT;
+ static const uint32_t rfini_part1[] = ZYD_AL2230_RF_B_PART1;
+ static const uint32_t rfini_part2[] = ZYD_AL2230_RF_B_PART2;
+ static const uint32_t rfini_part3[] = ZYD_AL2230_RF_B_PART3;
+ static const uint32_t zyd_al2230_chtable[][3] = ZYD_AL2230_CHANTABLE;
uint32_t i;
+ for (i = 0; i != INDEXES(phy1); i++)
+ zyd_cfg_write16(sc, phy1[i].reg, phy1[i].val);
+
/* init RF-dependent PHY registers */
- for (i = 0; i != INDEXES(phyini); i++) {
+ for (i = 0; i != INDEXES(phyini); i++)
zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
- }
- /* init AL2230 radio */
- for (i = 0; i != INDEXES(rfini); i++) {
- zyd_cfg_rfwrite(sc, rfini[i]);
- }
+ if ((sc->sc_rf_rev == ZYD_RF_AL2230S) || (sc->sc_al2230s != 0))
+ for (i = 0; i != INDEXES(phy2230s); i++)
+ zyd_cfg_write16(sc, phy2230s[i].reg, phy2230s[i].val);
+
+ for (i = 0; i != 3; i++)
+ zyd_cfg_rfwrite_cr(sc, zyd_al2230_chtable[0][i]);
+
+ for (i = 0; i != INDEXES(rfini_part1); i++)
+ zyd_cfg_rfwrite_cr(sc, rfini_part1[i]);
+
+ if ((sc->sc_rf_rev == ZYD_RF_AL2230S) || (sc->sc_al2230s != 0))
+ zyd_cfg_rfwrite(sc, 0x241000);
+ else
+ zyd_cfg_rfwrite(sc, 0x25a000);
+
+ for (i = 0; i != INDEXES(rfini_part2); i++)
+ zyd_cfg_rfwrite_cr(sc, rfini_part2[i]);
+
+ for (i = 0; i != INDEXES(phy2); i++)
+ zyd_cfg_write16(sc, phy2[i].reg, phy2[i].val);
+
+ for (i = 0; i != INDEXES(rfini_part3); i++)
+ zyd_cfg_rfwrite_cr(sc, rfini_part3[i]);
+
+ for (i = 0; i < INDEXES(phy3); i++)
+ zyd_cfg_write16(sc, phy3[i].reg, phy3[i].val);
+
+ zyd_cfg_rf_al2230_fini(sc, rf);
}
/*
@@ -1274,16 +1370,60 @@ static void
zyd_cfg_rf_al2230_set_channel(struct zyd_softc *sc, struct zyd_rf *rf,
uint8_t channel)
{
+ static const struct zyd_phy_pair phy1[] = {
+ {ZYD_CR138, 0x28}, {ZYD_CR203, 0x06},
+ };
static const struct {
uint32_t r1, r2, r3;
} rfprog[] = ZYD_AL2230_CHANTABLE;
+ uint32_t i;
zyd_cfg_rfwrite(sc, rfprog[channel - 1].r1);
zyd_cfg_rfwrite(sc, rfprog[channel - 1].r2);
zyd_cfg_rfwrite(sc, rfprog[channel - 1].r3);
- zyd_cfg_write16(sc, ZYD_CR138, 0x28);
- zyd_cfg_write16(sc, ZYD_CR203, 0x06);
+ for (i = 0; i != INDEXES(phy1); i++)
+ zyd_cfg_write16(sc, phy1[i].reg, phy1[i].val);
+}
+
+static void
+zyd_cfg_rf_al2230_set_channel_b(struct zyd_softc *sc,
+ struct zyd_rf *rf, uint8_t chan)
+{
+ static const struct zyd_phy_pair phy1[] = ZYD_AL2230_PHY_PART1;
+ static const struct {
+ uint32_t r1, r2, r3;
+ } rfprog[] = ZYD_AL2230_CHANTABLE_B;
+ uint32_t i;
+
+ for (i = 0; i != INDEXES(phy1); i++)
+ zyd_cfg_write16(sc, phy1[i].reg, phy1[i].val);
+
+ zyd_cfg_rfwrite_cr(sc, rfprog[chan - 1].r1);
+ zyd_cfg_rfwrite_cr(sc, rfprog[chan - 1].r2);
+ zyd_cfg_rfwrite_cr(sc, rfprog[chan - 1].r3);
+
+ zyd_cfg_rf_al2230_fini(sc, rf);
+}
+
+#define ZYD_AL2230_PHY_BANDEDGE6 \
+{ \
+ { ZYD_CR128, 0x14 }, { ZYD_CR129, 0x12 }, { ZYD_CR130, 0x10 }, \
+ { ZYD_CR47, 0x1e } \
+}
+
+static void
+zyd_cfg_rf_al2230_bandedge6(struct zyd_softc *sc,
+ struct zyd_rf *rf, uint8_t chan)
+{
+ struct zyd_phy_pair r[] = ZYD_AL2230_PHY_BANDEDGE6;
+ uint32_t i;
+
+ if ((chan == 1) || (chan == 11))
+ r[0].val = 0x12;
+
+ for (i = 0; i < INDEXES(r); i++)
+ zyd_cfg_write16(sc, r[i].reg, r[i].val);
}
/*
@@ -1413,7 +1553,6 @@ zyd_cfg_rf_al2210_set_channel(struct zyd_softc *sc, struct zyd_rf *rf,
zyd_cfg_write32(sc, ZYD_CR_RADIO_PD, tmp & ~1);
zyd_cfg_write32(sc, ZYD_CR_RADIO_PD, tmp | 1);
zyd_cfg_write32(sc, ZYD_CR_RFCFG, 0x05);
-
zyd_cfg_write32(sc, ZYD_CR_RFCFG, 0x00);
zyd_cfg_write16(sc, ZYD_CR47, 0x1e);
@@ -1617,12 +1756,16 @@ zyd_cfg_rf_init_hw(struct zyd_softc *sc, struct zyd_rf *rf)
rf->width = 24; /* 24-bit RF values */
break;
case ZYD_RF_AL2230:
- if (sc->sc_mac_rev == ZYD_ZD1211B)
+ case ZYD_RF_AL2230S:
+ if (sc->sc_mac_rev == ZYD_ZD1211B) {
rf->cfg_init_hw = zyd_cfg_rf_al2230_init_b;
- else
+ rf->cfg_set_channel = zyd_cfg_rf_al2230_set_channel_b;
+ } else {
rf->cfg_init_hw = zyd_cfg_rf_al2230_init;
+ rf->cfg_set_channel = zyd_cfg_rf_al2230_set_channel;
+ }
rf->cfg_switch_radio = zyd_cfg_rf_al2230_switch_radio;
- rf->cfg_set_channel = zyd_cfg_rf_al2230_set_channel;
+ rf->cfg_bandedge6 = zyd_cfg_rf_al2230_bandedge6;
rf->width = 24; /* 24-bit RF values */
break;
case ZYD_RF_AL7230B:
@@ -1689,6 +1832,9 @@ zyd_cfg_hw_init(struct zyd_softc *sc)
zyd_cfg_write32(sc, ZYD_CR_GPI_EN, 0);
zyd_cfg_write32(sc, ZYD_MAC_CONT_WIN_LIMIT, 0x7f043f);
+ /* set mandatory rates - XXX assumes 802.11b/g */
+ zyd_cfg_write32(sc, ZYD_MAC_MAN_RATE, 0x150f);
+
/* disable interrupts */
zyd_cfg_write32(sc, ZYD_CR_INTERRUPT, 0);
@@ -1698,7 +1844,7 @@ zyd_cfg_hw_init(struct zyd_softc *sc)
for (; phyp->reg != 0; phyp++) {
zyd_cfg_write16(sc, phyp->reg, phyp->val);
}
- if (sc->sc_fix_cr157) {
+ if ((sc->sc_mac_rev == ZYD_ZD1211) && sc->sc_fix_cr157) {
zyd_cfg_read32(sc, ZYD_EEPROM_PHY_REG, &tmp);
zyd_cfg_write32(sc, ZYD_CR157, tmp >> 8);
}
@@ -1707,20 +1853,6 @@ zyd_cfg_hw_init(struct zyd_softc *sc)
/* HMAC init */
zyd_cfg_write32(sc, ZYD_MAC_ACK_EXT, 0x00000020);
zyd_cfg_write32(sc, ZYD_CR_ADDA_MBIAS_WT, 0x30000808);
-
- if (sc->sc_mac_rev == ZYD_ZD1211) {
- zyd_cfg_write32(sc, ZYD_MAC_RETRY, 0x00000002);
- } else {
- zyd_cfg_write32(sc, ZYD_MACB_MAX_RETRY, 0x02020202);
- zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL4, 0x007f003f);
- zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL3, 0x007f003f);
- zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL2, 0x003f001f);
- zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL1, 0x001f000f);
- zyd_cfg_write32(sc, ZYD_MACB_AIFS_CTL1, 0x00280028);
- zyd_cfg_write32(sc, ZYD_MACB_AIFS_CTL2, 0x008C003C);
- zyd_cfg_write32(sc, ZYD_MACB_TXOP, 0x01800824);
- }
-
zyd_cfg_write32(sc, ZYD_MAC_SNIFFER, 0x00000000);
zyd_cfg_write32(sc, ZYD_MAC_RXFILTER, 0x00000000);
zyd_cfg_write32(sc, ZYD_MAC_GHTBL, 0x00000000);
@@ -1732,12 +1864,28 @@ zyd_cfg_hw_init(struct zyd_softc *sc)
zyd_cfg_write32(sc, ZYD_MAC_ACK_EXT, 0x00000080);
zyd_cfg_write32(sc, ZYD_CR_ADDA_PWR_DWN, 0x00000000);
zyd_cfg_write32(sc, ZYD_MAC_SIFS_ACK_TIME, 0x00000100);
- zyd_cfg_write32(sc, ZYD_MAC_DIFS_EIFS_SIFS, 0x0547c032);
zyd_cfg_write32(sc, ZYD_CR_RX_PE_DELAY, 0x00000070);
zyd_cfg_write32(sc, ZYD_CR_PS_CTRL, 0x10000000);
zyd_cfg_write32(sc, ZYD_MAC_RTSCTSRATE, 0x02030203);
- zyd_cfg_write32(sc, ZYD_MAC_RX_THRESHOLD, 0x000c0640);
+ zyd_cfg_write32(sc, ZYD_MAC_AFTER_PNP, 1);
zyd_cfg_write32(sc, ZYD_MAC_BACKOFF_PROTECT, 0x00000114);
+ zyd_cfg_write32(sc, ZYD_MAC_DIFS_EIFS_SIFS, 0x0a47c032);
+ zyd_cfg_write32(sc, ZYD_MAC_CAM_MODE, 0x3);
+
+ if (sc->sc_mac_rev == ZYD_ZD1211) {
+ zyd_cfg_write32(sc, ZYD_MAC_RETRY, 0x00000002);
+ zyd_cfg_write32(sc, ZYD_MAC_RX_THRESHOLD, 0x000c0640);
+ } else {
+ zyd_cfg_write32(sc, ZYD_MACB_MAX_RETRY, 0x02020202);
+ zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL4, 0x007f003f);
+ zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL3, 0x007f003f);
+ zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL2, 0x003f001f);
+ zyd_cfg_write32(sc, ZYD_MACB_TXPWR_CTL1, 0x001f000f);
+ zyd_cfg_write32(sc, ZYD_MACB_AIFS_CTL1, 0x00280028);
+ zyd_cfg_write32(sc, ZYD_MACB_AIFS_CTL2, 0x008C003C);
+ zyd_cfg_write32(sc, ZYD_MACB_TXOP, 0x01800824);
+ zyd_cfg_write32(sc, ZYD_MAC_RX_THRESHOLD, 0x000c0eff);
+ }
/* init beacon interval to 100ms */
zyd_cfg_set_beacon_interval(sc, 100);
@@ -1756,20 +1904,19 @@ zyd_cfg_read_eeprom(struct zyd_softc *sc)
uint16_t val;
/* read MAC address */
- zyd_cfg_read32(sc, ZYD_EEPROM_MAC_ADDR_P1, &tmp);
- sc->sc_myaddr[0] = tmp & 0xff;
- sc->sc_myaddr[1] = tmp >> 8;
- sc->sc_myaddr[2] = tmp >> 16;
- sc->sc_myaddr[3] = tmp >> 24;
- zyd_cfg_read32(sc, ZYD_EEPROM_MAC_ADDR_P2, &tmp);
- sc->sc_myaddr[4] = tmp & 0xff;
- sc->sc_myaddr[5] = tmp >> 8;
+ zyd_cfg_get_macaddr(sc);
+ /* read product data */
zyd_cfg_read32(sc, ZYD_EEPROM_POD, &tmp);
sc->sc_rf_rev = tmp & 0x0f;
- sc->sc_fix_cr47 = (tmp >> 8) & 0x01;
+ sc->sc_ledtype = (tmp >> 4) & 0x01;
+ sc->sc_cckgain = (tmp >> 8) & 0x01;
sc->sc_fix_cr157 = (tmp >> 13) & 0x01;
sc->sc_pa_rev = (tmp >> 16) & 0x0f;
+ sc->sc_al2230s = (tmp >> 7) & 0x01;
+ sc->sc_bandedge6 = (tmp >> 21) & 0x01;
+ sc->sc_newphy = (tmp >> 31) & 0x01;
+ sc->sc_txled = ((tmp & (1 << 24)) && (tmp & (1 << 29))) ? 0 : 1;
/* read regulatory domain (currently unused) */
zyd_cfg_read32(sc, ZYD_EEPROM_SUBID, &tmp);
@@ -1801,6 +1948,21 @@ zyd_cfg_read_eeprom(struct zyd_softc *sc)
}
static void
+zyd_cfg_get_macaddr(struct zyd_softc *sc)
+{
+ struct usb2_device_request req;
+
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = ZYD_READFWDATAREQ;
+ USETW(req.wValue, ZYD_EEPROM_MAC_ADDR_P1);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, IEEE80211_ADDR_LEN);
+
+ zyd_cfg_usbrequest(sc, &req, sc->sc_myaddr);
+ return;
+}
+
+static void
zyd_cfg_set_mac_addr(struct zyd_softc *sc, const uint8_t *addr)
{
uint32_t tmp;
@@ -2270,17 +2432,18 @@ zyd_cfg_set_chan(struct zyd_softc *sc,
zyd_cfg_write16(sc, ZYD_CR67, sc->sc_ofdm36_cal[chan - 1]);
zyd_cfg_write16(sc, ZYD_CR66, sc->sc_ofdm48_cal[chan - 1]);
zyd_cfg_write16(sc, ZYD_CR65, sc->sc_ofdm54_cal[chan - 1]);
-
zyd_cfg_write16(sc, ZYD_CR68, sc->sc_pwr_cal[chan - 1]);
-
zyd_cfg_write16(sc, ZYD_CR69, 0x28);
zyd_cfg_write16(sc, ZYD_CR69, 0x2a);
}
- if (sc->sc_fix_cr47) {
+ if (sc->sc_cckgain) {
/* set CCK baseband gain from EEPROM */
zyd_cfg_read32(sc, ZYD_EEPROM_PHY_REG, &tmp);
zyd_cfg_write16(sc, ZYD_CR47, tmp & 0xff);
}
+ if (sc->sc_bandedge6 && (sc->sc_rf.cfg_bandedge6 != NULL)) {
+ (sc->sc_rf.cfg_bandedge6) (sc, &sc->sc_rf, chan);
+ }
zyd_cfg_write32(sc, ZYD_CR_CONFIG_PHILIPS, 0);
zyd_cfg_unlock_phy(sc);
@@ -2349,7 +2512,7 @@ zyd_cfg_init(struct zyd_softc *sc,
else if (cc->ic_curmode == IEEE80211_MODE_11A)
zyd_cfg_write32(sc, ZYD_MAC_BAS_RATE, 0x1500);
else /* assumes 802.11b/g */
- zyd_cfg_write32(sc, ZYD_MAC_BAS_RATE, 0x000f);
+ zyd_cfg_write32(sc, ZYD_MAC_BAS_RATE, 0xff0f);
/* set mandatory rates */
if (cc->ic_curmode == IEEE80211_MODE_11B)
diff --git a/sys/dev/usb2/wlan/if_zyd2_reg.h b/sys/dev/usb2/wlan/if_zyd2_reg.h
index bdf1bc0..de145f7 100644
--- a/sys/dev/usb2/wlan/if_zyd2_reg.h
+++ b/sys/dev/usb2/wlan/if_zyd2_reg.h
@@ -101,6 +101,7 @@
#define ZYD_MAC_CONT_WIN_LIMIT 0x96f0 /* Contention window limit */
#define ZYD_MAC_TX_PKT 0x96f4 /* Tx total packet count read */
#define ZYD_MAC_DL_CTRL 0x96f8 /* Download control */
+#define ZYD_MAC_CAM_MODE 0x9700 /* CAM: Continuous Access Mode */
#define ZYD_MACB_TXPWR_CTL1 0x9b00
#define ZYD_MACB_TXPWR_CTL2 0x9b04
#define ZYD_MACB_TXPWR_CTL3 0x9b08
@@ -127,8 +128,8 @@
#define ZYD_EEPROM_PWR_CAL 0xf81f /* Calibration */
#define ZYD_EEPROM_PWR_INT 0xf827 /* Calibration */
#define ZYD_EEPROM_ALLOWEDCHAN 0xf82f /* Allowed CH mask, 1 bit each */
-#define ZYD_EEPROM_PHY_REG 0xf831 /* PHY registers */
#define ZYD_EEPROM_DEVICE_VER 0xf837 /* Device version */
+#define ZYD_EEPROM_PHY_REG 0xf83c /* PHY registers */
#define ZYD_EEPROM_36M_CAL 0xf83f /* Calibration */
#define ZYD_EEPROM_11A_INT 0xf847 /* Interpolation */
#define ZYD_EEPROM_48M_CAL 0xf84f /* Calibration */
@@ -161,7 +162,7 @@
#define ZYD_RF_AL2210 0x7
#define ZYD_RF_MAXIM_NEW 0x8
#define ZYD_RF_GCT 0x9
-#define ZYD_RF_PV2000 0xa /* not supported yet */
+#define ZYD_RF_AL2230S 0xa
#define ZYD_RF_RALINK 0xb /* not supported yet */
#define ZYD_RF_INTERSIL 0xc /* not supported yet */
#define ZYD_RF_RFMD 0xd
@@ -437,7 +438,7 @@
{ ZYD_CR37, 0x00 }, { ZYD_CR38, 0x38 }, { ZYD_CR39, 0x0c }, \
{ ZYD_CR40, 0x84 }, { ZYD_CR41, 0x2a }, { ZYD_CR42, 0x80 }, \
{ ZYD_CR43, 0x10 }, { ZYD_CR44, 0x12 }, { ZYD_CR46, 0xff }, \
- { ZYD_CR47, 0x08 }, { ZYD_CR48, 0x26 }, { ZYD_CR49, 0x5b }, \
+ { ZYD_CR47, 0x1e }, { ZYD_CR48, 0x26 }, { ZYD_CR49, 0x5b }, \
{ ZYD_CR64, 0xd0 }, { ZYD_CR65, 0x04 }, { ZYD_CR66, 0x58 }, \
{ ZYD_CR67, 0xc9 }, { ZYD_CR68, 0x88 }, { ZYD_CR69, 0x41 }, \
{ ZYD_CR70, 0x23 }, { ZYD_CR71, 0x10 }, { ZYD_CR72, 0xff }, \
@@ -459,7 +460,7 @@
{ ZYD_CR5, 0x00 }, { ZYD_CR6, 0x00 }, { ZYD_CR7, 0x00 }, \
{ ZYD_CR8, 0x00 }, { ZYD_CR9, 0x20 }, { ZYD_CR12, 0xf0 }, \
{ ZYD_CR20, 0x0e }, { ZYD_CR21, 0x0e }, { ZYD_CR27, 0x10 }, \
- { ZYD_CR44, 0x33 }, { ZYD_CR47, 0x30 }, { ZYD_CR83, 0x24 }, \
+ { ZYD_CR44, 0x33 }, { ZYD_CR47, 0x1E }, { ZYD_CR83, 0x24 }, \
{ ZYD_CR84, 0x04 }, { ZYD_CR85, 0x00 }, { ZYD_CR86, 0x0C }, \
{ ZYD_CR87, 0x12 }, { ZYD_CR88, 0x0C }, { ZYD_CR89, 0x00 }, \
{ ZYD_CR90, 0x10 }, { ZYD_CR91, 0x08 }, { ZYD_CR93, 0x00 }, \
@@ -470,19 +471,18 @@
{ ZYD_CR111, 0x27 }, { ZYD_CR112, 0x27 }, { ZYD_CR113, 0x27 }, \
{ ZYD_CR114, 0x27 }, { ZYD_CR115, 0x26 }, { ZYD_CR116, 0x24 }, \
{ ZYD_CR117, 0xfc }, { ZYD_CR118, 0xfa }, { ZYD_CR120, 0x4f }, \
- { ZYD_CR123, 0x27 }, { ZYD_CR125, 0xaa }, { ZYD_CR127, 0x03 }, \
- { ZYD_CR128, 0x14 }, { ZYD_CR129, 0x12 }, { ZYD_CR130, 0x10 }, \
- { ZYD_CR131, 0x0C }, { ZYD_CR136, 0xdf }, { ZYD_CR137, 0x40 }, \
- { ZYD_CR138, 0xa0 }, { ZYD_CR139, 0xb0 }, { ZYD_CR140, 0x99 }, \
- { ZYD_CR141, 0x82 }, { ZYD_CR142, 0x54 }, { ZYD_CR143, 0x1c }, \
- { ZYD_CR144, 0x6c }, { ZYD_CR147, 0x07 }, { ZYD_CR148, 0x4c }, \
- { ZYD_CR149, 0x50 }, { ZYD_CR150, 0x0e }, { ZYD_CR151, 0x18 }, \
- { ZYD_CR160, 0xfe }, { ZYD_CR161, 0xee }, { ZYD_CR162, 0xaa }, \
- { ZYD_CR163, 0xfa }, { ZYD_CR164, 0xfa }, { ZYD_CR165, 0xea }, \
- { ZYD_CR166, 0xbe }, { ZYD_CR167, 0xbe }, { ZYD_CR168, 0x6a }, \
- { ZYD_CR169, 0xba }, { ZYD_CR170, 0xba }, { ZYD_CR171, 0xba }, \
- { ZYD_CR204, 0x7d }, { ZYD_CR203, 0x30 }, \
- { 0, 0 } \
+ { ZYD_CR125, 0xaa }, { ZYD_CR127, 0x03 }, { ZYD_CR128, 0x14 }, \
+ { ZYD_CR129, 0x12 }, { ZYD_CR130, 0x10 }, { ZYD_CR131, 0x0C }, \
+ { ZYD_CR136, 0xdf }, { ZYD_CR137, 0x40 }, { ZYD_CR138, 0xa0 }, \
+ { ZYD_CR139, 0xb0 }, { ZYD_CR140, 0x99 }, { ZYD_CR141, 0x82 }, \
+ { ZYD_CR142, 0x54 }, { ZYD_CR143, 0x1c }, { ZYD_CR144, 0x6c }, \
+ { ZYD_CR147, 0x07 }, { ZYD_CR148, 0x4c }, { ZYD_CR149, 0x50 }, \
+ { ZYD_CR150, 0x0e }, { ZYD_CR151, 0x18 }, { ZYD_CR160, 0xfe }, \
+ { ZYD_CR161, 0xee }, { ZYD_CR162, 0xaa }, { ZYD_CR163, 0xfa }, \
+ { ZYD_CR164, 0xfa }, { ZYD_CR165, 0xea }, { ZYD_CR166, 0xbe }, \
+ { ZYD_CR167, 0xbe }, { ZYD_CR168, 0x6a }, { ZYD_CR169, 0xba }, \
+ { ZYD_CR170, 0xba }, { ZYD_CR171, 0xba }, { ZYD_CR204, 0x7d }, \
+ { ZYD_CR203, 0x30 }, { 0, 0} \
}
#define ZYD_DEF_PHYB \
@@ -590,8 +590,6 @@
{ 0x181a60, 0x1c0000 } \
}
-
-
#define ZYD_AL2230_PHY \
{ \
{ ZYD_CR15, 0x20 }, { ZYD_CR23, 0x40 }, { ZYD_CR24, 0x20 }, \
@@ -617,34 +615,73 @@
#define ZYD_AL2230_PHY_B \
{ \
- { ZYD_CR10, 0x89 }, { ZYD_CR15, 0x20 }, { ZYD_CR17, 0x2b }, \
+ { ZYD_CR10, 0x89 }, { ZYD_CR15, 0x20 }, { ZYD_CR17, 0x2B }, \
{ ZYD_CR23, 0x40 }, { ZYD_CR24, 0x20 }, { ZYD_CR26, 0x93 }, \
{ ZYD_CR28, 0x3e }, { ZYD_CR29, 0x00 }, { ZYD_CR33, 0x28 }, \
{ ZYD_CR34, 0x30 }, { ZYD_CR35, 0x3e }, { ZYD_CR41, 0x24 }, \
{ ZYD_CR44, 0x32 }, { ZYD_CR46, 0x99 }, { ZYD_CR47, 0x1e }, \
- { ZYD_CR48, 0x00 }, { ZYD_CR49, 0x00 }, { ZYD_CR51, 0x01 }, \
+ { ZYD_CR48, 0x06 }, { ZYD_CR49, 0xf9 }, { ZYD_CR51, 0x01 }, \
{ ZYD_CR52, 0x80 }, { ZYD_CR53, 0x7e }, { ZYD_CR65, 0x00 }, \
{ ZYD_CR66, 0x00 }, { ZYD_CR67, 0x00 }, { ZYD_CR68, 0x00 }, \
{ ZYD_CR69, 0x28 }, { ZYD_CR79, 0x58 }, { ZYD_CR80, 0x30 }, \
{ ZYD_CR81, 0x30 }, { ZYD_CR87, 0x0a }, { ZYD_CR89, 0x04 }, \
{ ZYD_CR91, 0x00 }, { ZYD_CR92, 0x0a }, { ZYD_CR98, 0x8d }, \
- { ZYD_CR99, 0x00 }, { ZYD_CR101, 0x13 }, { ZYD_CR106, 0x24 }, \
- { ZYD_CR107, 0x2a }, { ZYD_CR109, 0x13 }, { ZYD_CR110, 0x1f }, \
- { ZYD_CR111, 0x1f }, { ZYD_CR114, 0x27 }, { ZYD_CR115, 0x26 }, \
+ { ZYD_CR99, 0x00 }, { ZYD_CR101, 0x13 }, { ZYD_CR102, 0x27 }, \
+ { ZYD_CR106, 0x24 }, { ZYD_CR107, 0x2a }, { ZYD_CR109, 0x13 }, \
+ { ZYD_CR110, 0x1f }, { ZYD_CR111, 0x1f }, { ZYD_CR112, 0x1f }, \
+ { ZYD_CR113, 0x27 }, { ZYD_CR114, 0x27 }, { ZYD_CR115, 0x26 }, \
{ ZYD_CR116, 0x24 }, { ZYD_CR117, 0xfa }, { ZYD_CR118, 0xfa }, \
{ ZYD_CR119, 0x10 }, { ZYD_CR120, 0x4f }, { ZYD_CR121, 0x6c }, \
{ ZYD_CR122, 0xfc }, { ZYD_CR123, 0x57 }, { ZYD_CR125, 0xad }, \
{ ZYD_CR126, 0x6c }, { ZYD_CR127, 0x03 }, { ZYD_CR137, 0x50 }, \
{ ZYD_CR138, 0xa8 }, { ZYD_CR144, 0xac }, { ZYD_CR150, 0x0d }, \
- { ZYD_CR252, 0x00 }, { ZYD_CR253, 0x00 } \
+ { ZYD_CR252, 0x34 }, { ZYD_CR253, 0x34 } \
}
-#define ZYD_AL2230_RF \
+#define ZYD_AL2230_PHY_PART1 \
+{ \
+ { ZYD_CR240, 0x57 }, { ZYD_CR9, 0xe0 } \
+}
+
+#define ZYD_AL2230_PHY_PART2 \
+{ \
+ { ZYD_CR251, 0x2f }, { ZYD_CR251, 0x7f }, \
+}
+
+#define ZYD_AL2230_PHY_PART3 \
+{ \
+ { ZYD_CR128, 0x14 }, { ZYD_CR129, 0x12 }, { ZYD_CR130, 0x10 }, \
+}
+
+#define ZYD_AL2230S_PHY_INIT \
+{ \
+ { ZYD_CR47, 0x1e }, { ZYD_CR106, 0x22 }, { ZYD_CR107, 0x2a }, \
+ { ZYD_CR109, 0x13 }, { ZYD_CR118, 0xf8 }, { ZYD_CR119, 0x12 }, \
+ { ZYD_CR122, 0xe0 }, { ZYD_CR128, 0x10 }, { ZYD_CR129, 0x0e }, \
+ { ZYD_CR130, 0x10 } \
+}
+
+#define ZYD_AL2230_PHY_FINI_PART1 \
+{ \
+ { ZYD_CR80, 0x30 }, { ZYD_CR81, 0x30 }, { ZYD_CR79, 0x58 }, \
+ { ZYD_CR12, 0xf0 }, { ZYD_CR77, 0x1b }, { ZYD_CR78, 0x58 }, \
+ { ZYD_CR203, 0x06 }, { ZYD_CR240, 0x80 }, \
+}
+
+#define ZYD_AL2230_RF_PART1 \
+{ \
+ 0x03f790, 0x033331, 0x00000d, 0x0b3331, 0x03b812, 0x00fff3 \
+}
+
+#define ZYD_AL2230_RF_PART2 \
{ \
- 0x03f790, 0x033331, 0x00000d, 0x0b3331, 0x03b812, 0x00fff3, \
0x000da4, 0x0f4dc5, 0x0805b6, 0x011687, 0x000688, 0x0403b9, \
- 0x00dbba, 0x00099b, 0x0bdffc, 0x00000d, 0x00500f, 0x00d00f, \
- 0x004c0f, 0x00540f, 0x00700f, 0x00500f \
+ 0x00dbba, 0x00099b, 0x0bdffc, 0x00000d, 0x00500f \
+}
+
+#define ZYD_AL2230_RF_PART3 \
+{ \
+ 0x00d00f, 0x004c0f, 0x00540f, 0x00700f, 0x00500f \
}
#define ZYD_AL2230_RF_B \
@@ -654,6 +691,22 @@
0x00dbba, 0x00099b, 0x0bdffc, 0x00000d, 0x00580f \
}
+#define ZYD_AL2230_RF_B_PART1 \
+{ \
+ 0x8cccd0, 0x481dc0, 0xcfff00, 0x25a000 \
+}
+
+#define ZYD_AL2230_RF_B_PART2 \
+{ \
+ 0x25a000, 0xa3b2f0, 0x6da010, 0xe36280, 0x116000, 0x9dc020, \
+ 0x5ddb00, 0xd99000, 0x3ffbd0, 0xb00000, 0xf01a00 \
+}
+
+#define ZYD_AL2230_RF_B_PART3 \
+{ \
+ 0xf01b00, 0xf01e00, 0xf01a00 \
+}
+
#define ZYD_AL2230_CHANTABLE \
{ \
{ 0x03f790, 0x033331, 0x00000d }, \
@@ -672,7 +725,23 @@
{ 0x03e7c0, 0x066661, 0x00000d } \
}
-
+#define ZYD_AL2230_CHANTABLE_B \
+{ \
+ { 0x09efc0, 0x8cccc0, 0xb00000 }, \
+ { 0x09efc0, 0x8cccd0, 0xb00000 }, \
+ { 0x09e7c0, 0x8cccc0, 0xb00000 }, \
+ { 0x09e7c0, 0x8cccd0, 0xb00000 }, \
+ { 0x05efc0, 0x8cccc0, 0xb00000 }, \
+ { 0x05efc0, 0x8cccd0, 0xb00000 }, \
+ { 0x05e7c0, 0x8cccc0, 0xb00000 }, \
+ { 0x05e7c0, 0x8cccd0, 0xb00000 }, \
+ { 0x0defc0, 0x8cccc0, 0xb00000 }, \
+ { 0x0defc0, 0x8cccd0, 0xb00000 }, \
+ { 0x0de7c0, 0x8cccc0, 0xb00000 }, \
+ { 0x0de7c0, 0x8cccd0, 0xb00000 }, \
+ { 0x03efc0, 0x8cccc0, 0xb00000 }, \
+ { 0x03e7c0, 0x866660, 0xb00000 } \
+}
#define ZYD_AL7230B_PHY_1 \
{ \
@@ -744,8 +813,6 @@
{ 0x03ec00, 0x866660 } \
}
-
-
#define ZYD_AL2210_PHY \
{ \
{ ZYD_CR9, 0xe0 }, { ZYD_CR10, 0x91 }, { ZYD_CR12, 0x90 }, \
@@ -771,8 +838,6 @@
0x019a80, 0x019b40 \
}
-
-
#define ZYD_GCT_PHY \
{ \
{ ZYD_CR47, 0x1e }, { ZYD_CR15, 0xdc }, { ZYD_CR113, 0xc0 }, \
@@ -801,8 +866,6 @@
0x1a3000, 0x1ab000 \
}
-
-
#define ZYD_MAXIM_PHY \
{ \
{ ZYD_CR23, 0x40 }, { ZYD_CR15, 0x20 }, { ZYD_CR28, 0x3e }, \
@@ -855,8 +918,6 @@
{ 0x199a4, 0x20a53 } \
}
-
-
#define ZYD_MAXIM2_PHY \
{ \
{ ZYD_CR23, 0x40 }, { ZYD_CR15, 0x20 }, { ZYD_CR28, 0x3e }, \
@@ -919,6 +980,7 @@
*/
#define ZYD_DOWNLOADREQ 0x30
#define ZYD_DOWNLOADSTS 0x31
+#define ZYD_READFWDATAREQ 0x32
/* possible values for register ZYD_CR_INTERRUPT */
#define ZYD_HWINT_MASK 0x004f0000
@@ -950,10 +1012,15 @@
/* helpers for register ZYD_MAC_RXFILTER */
#define ZYD_FILTER_MONITOR 0xffffffff
-#define ZYD_FILTER_BSS \
- (ZYD_FILTER_ASS_RSP | ZYD_FILTER_REASS_RSP | \
- ZYD_FILTER_PRB_RSP | ZYD_FILTER_BCN | ZYD_FILTER_DEASS | \
- ZYD_FILTER_AUTH | ZYD_FILTER_DEAUTH)
+#define ZYD_FILTER_BSS \
+ (ZYD_FILTER_ASS_REQ | ZYD_FILTER_ASS_RSP | \
+ ZYD_FILTER_REASS_REQ | ZYD_FILTER_REASS_RSP | \
+ ZYD_FILTER_PRB_REQ | ZYD_FILTER_PRB_RSP | \
+ (0x3 << 6) | \
+ ZYD_FILTER_BCN | ZYD_FILTER_ATIM | ZYD_FILTER_DEASS | \
+ ZYD_FILTER_AUTH | ZYD_FILTER_DEAUTH | \
+ (0x7 << 13) | \
+ ZYD_FILTER_PS_POLL | ZYD_FILTER_ACK)
#define ZYD_FILTER_HOSTAP \
(ZYD_FILTER_ASS_REQ | ZYD_FILTER_REASS_REQ | \
ZYD_FILTER_PRB_REQ | ZYD_FILTER_DEASS | ZYD_FILTER_AUTH | \
@@ -1138,6 +1205,8 @@ struct zyd_rf {
void (*cfg_init_hw) (struct zyd_softc *, struct zyd_rf *);
void (*cfg_switch_radio) (struct zyd_softc *, uint8_t on);
void (*cfg_set_channel) (struct zyd_softc *, struct zyd_rf *, uint8_t);
+ void (*cfg_bandedge6) (struct zyd_softc *, struct zyd_rf *, uint8_t);
+
uint8_t width;
};
@@ -1239,6 +1308,10 @@ struct zyd_softc {
uint32_t sc_rxtap_len;
uint32_t sc_txtap_len;
uint32_t sc_unit;
+ uint32_t sc_atim_wnd;
+ uint32_t sc_pre_tbtt;
+ uint32_t sc_bcn_int;
+
int sc_ns_arg;
uint16_t sc_firmware_base;
@@ -1254,7 +1327,12 @@ struct zyd_softc {
uint8_t sc_mac_rev;
uint8_t sc_rf_rev;
uint8_t sc_pa_rev;
- uint8_t sc_fix_cr47;
+ uint8_t sc_al2230s;
+ uint8_t sc_cckgain;
+ uint8_t sc_bandedge6;
+ uint8_t sc_newphy;
+ uint8_t sc_ledtype;
+ uint8_t sc_txled;
uint8_t sc_fix_cr157;
uint8_t sc_pwr_cal[14];
uint8_t sc_pwr_int[14];
OpenPOWER on IntegriCloud