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
This commit is contained in:
Alfred Perlstein 2009-01-04 00:12:01 +00:00
parent 17c98d6dab
commit d5474fd85f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=186730
48 changed files with 2458 additions and 858 deletions

View file

@ -238,23 +238,37 @@ const uint8_t *
libusb20_desc_foreach(const struct libusb20_me_struct *pdesc,
const uint8_t *psubdesc)
{
const void *end;
const uint8_t *start;
const uint8_t *end;
const uint8_t *desc_next;
if (pdesc == NULL) {
/* be NULL safe */
if (pdesc == NULL)
return (NULL);
}
end = LIBUSB20_ADD_BYTES(pdesc->ptr, pdesc->len);
if (psubdesc == NULL) {
psubdesc = LIBUSB20_ADD_BYTES(pdesc->ptr, 0);
} else {
psubdesc = LIBUSB20_ADD_BYTES(psubdesc, psubdesc[0]);
}
return (((((const void *)psubdesc) >= ((void *)(pdesc->ptr))) &&
(((const void *)psubdesc) < end) &&
(LIBUSB20_ADD_BYTES(psubdesc, psubdesc[0]) >= ((void *)(pdesc->ptr))) &&
(LIBUSB20_ADD_BYTES(psubdesc, psubdesc[0]) <= end) &&
(psubdesc[0] >= 3)) ? psubdesc : NULL);
start = (const uint8_t *)pdesc->ptr;
end = LIBUSB20_ADD_BYTES(start, pdesc->len);
/* get start of next descriptor */
if (psubdesc == NULL)
psubdesc = start;
else
psubdesc = psubdesc + psubdesc[0];
/* check that the next USB descriptor is within the range */
if ((psubdesc < start) || (psubdesc >= end))
return (NULL); /* out of range, or EOD */
/* check start of the second next USB descriptor, if any */
desc_next = psubdesc + psubdesc[0];
if ((desc_next < start) || (desc_next > end))
return (NULL); /* out of range */
/* check minimum descriptor length */
if (psubdesc[0] < 3)
return (NULL); /* too short descriptor */
return (psubdesc); /* return start of next descriptor */
}
/*------------------------------------------------------------------------*

View file

@ -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);
use_polling = mtx_owned(xfer->xfer_mtx) ? 1 : 0;
if (!(temp & AT91_UDP_GSTATE_ESR)) {
return;
}
AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, temp);
}
AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, AT91_UDP_GSTATE_ESR);
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);
temp = AT91_UDP_READ_4(sc, AT91_UDP_GSTATE);
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 @@ at91dci_root_ctrl_done(struct usb2_xfer *xfer,
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,
};

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -235,12 +235,6 @@ musbotg_wakeup_peer(struct usb2_xfer *xfer)
MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp);
}
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)
{
@ -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,
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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];

View file

@ -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 */

View file

@ -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);
@ -197,6 +200,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,

View file

@ -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 */

View file

@ -222,29 +222,6 @@ uss820dci_wakeup_peer(struct uss820dci_softc *sc)
DPRINTFN(0, "not supported\n");
}
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)
{
@ -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,
};

View file

@ -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++;

View file

@ -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_ */

View file

@ -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 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus,
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 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus,
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 */
}

View file

@ -82,6 +82,18 @@ struct usb2_device_flags {
uint8_t uq_power_claim:1; /* set if power claim quirk is present */
};
/*
* 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_ */

View file

@ -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);
}

View file

@ -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 *);

View file

@ -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 */
}

View file

@ -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 */
}

View file

@ -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 @@ uhub_reattach_port(struct uhub_softc *sc, uint8_t portno)
/* 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 @@ uhub_reattach_port(struct uhub_softc *sc, uint8_t portno)
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 @@ uhub_reattach_port(struct uhub_softc *sc, uint8_t portno)
/* 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 @@ uhub_reattach_port(struct uhub_softc *sc, uint8_t portno)
}
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;
}

View file

@ -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_ */

View file

@ -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 @@ usb2_test_autoinstall(struct usb2_device *udev, uint8_t iface_index,
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 */
}

View file

@ -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_ */

View file

@ -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));
}

View file

@ -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)

View file

@ -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) {

View file

@ -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_ */

View file

@ -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_phyno != phy) {
val = 0;
goto done;
}
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)) {
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:

View file

@ -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

View file

@ -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)},

View file

@ -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 */

View file

@ -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 $ */
@ -622,6 +622,12 @@ const struct usb_knowndev usb_knowndevs[] = {
"Alcor Micro",
"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,
@ -2494,6 +2500,12 @@ const struct usb_knowndev usb_knowndevs[] = {
"Future Technology Devices",
"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,
@ -3040,6 +3052,12 @@ const struct usb_knowndev usb_knowndevs[] = {
"Hewlett Packard",
"Scanjet 4400C",
},
{
USB_VENDOR_HP, USB_PRODUCT_HP_4470C,
0,
"Hewlett Packard",
"Scanjet 4470C",
},
{
USB_VENDOR_HP, USB_PRODUCT_HP_82x0C,
0,
@ -5470,6 +5488,12 @@ const struct usb_knowndev usb_knowndevs[] = {
"Qualcomm, Incorporated",
"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,
@ -7144,6 +7168,12 @@ const struct usb_knowndev usb_knowndevs[] = {
"Yano",
"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,
@ -10054,6 +10084,12 @@ const struct usb_knowndev usb_knowndevs[] = {
"Ours Technology",
NULL,
},
{
USB_VENDOR_YISO, 0,
USB_KNOWNDEV_NOPROD,
"Yiso Wireless Co.",
NULL,
},
{
USB_VENDOR_PILOTECH, 0,
USB_KNOWNDEV_NOPROD,

View file

@ -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;

View file

@ -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 */

View file

@ -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

View file

@ -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)
{

View file

@ -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) "

View file

@ -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)
{

View file

@ -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)
{

View file

@ -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,43 +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] = {
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,
.mh.frames = UAUDIO_MINFRAMES,
.mh.flags = {.short_xfer_ok = 1,},
.mh.callback = &uaudio_chan_play_callback,
},
@ -451,30 +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,
.mh.flags = {.short_xfer_ok = 1,},
.mh.callback = &uaudio_chan_play_callback,
},
};
static const struct usb2_config
uaudio_cfg_play_high_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 * 8),
.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 * 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",

View file

@ -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

View file

@ -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);
}

View file

@ -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:

View file

@ -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;
/* init RF-dependent PHY registers */
for (i = 0; i != INDEXES(phyini); i++) {
zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
}
for (i = 0; i != INDEXES(phy1); i++)
zyd_cfg_write16(sc, phy1[i].reg, phy1[i].val);
/* init AL2230 radio */
for (i = 0; i != INDEXES(rfini); i++) {
zyd_cfg_rfwrite(sc, rfini[i]);
}
/* init RF-dependent PHY registers */
for (i = 0; i != INDEXES(phyini); i++)
zyd_cfg_write16(sc, phyini[i].reg, phyini[i].val);
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);
@ -1800,6 +1947,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)
{
@ -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)

View file

@ -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];

View file

@ -57,7 +57,7 @@ SUBDIR += misc_fm
SUBDIR += quirk
SUBDIR += scanner
SUBDIR += serial
#SUBDIR += serial_3g
SUBDIR += serial_3g
SUBDIR += serial_ark
SUBDIR += serial_bsa
SUBDIR += serial_bser

View file

@ -0,0 +1,38 @@
#
# $FreeBSD$
#
# Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
S=${.CURDIR}/../../..
.PATH: $S/dev/usb2/serial
KMOD=usb2_serial_3g
SRCS=
SRCS+= bus_if.h usb2_if.h device_if.h vnode_if.h
SRCS+= opt_usb.h opt_bus.h opt_compat.h
SRCS+= u3g2.c
.include <bsd.kmod.mk>