MFp4 //depot/projects/usb; 157100

1. Move most of the ifnet logic into the usb2_ethernet module, this includes,
 - make all usb ethernet interfaces named ue%d
 - handle all threading in usb2_ethernet
 - provide default ioctl handler
 - handle mbuf rx
 - provide locked callbacks for init,start,stop,etc

2. Cleanup CDC-Ethernet driver.

Submitted by:	Hans Petter Selasky
Obtained from:	svn.freebsd.org/base/user/thompsa/usb [1]
This commit is contained in:
thompsa 2009-02-09 22:02:38 +00:00
parent 1267fde951
commit cf8291f423
18 changed files with 2789 additions and 5418 deletions

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@
* are 8 bits wide.
*
* Packet transfer is done in 64 byte chunks. The last chunk in a
* transfer is denoted by having a length less that 64 bytes. For
* transfer is denoted by having a length less that 64 bytes. For
* the RX case, the data includes an optional RX status word.
*/
@ -63,11 +63,8 @@
enum {
AUE_BULK_DT_WR,
AUE_BULK_DT_RD,
AUE_BULK_CS_WR,
AUE_BULK_CS_RD,
AUE_INTR_DT_RD,
AUE_INTR_CS_RD,
AUE_N_TRANSFER = 6,
AUE_N_TRANSFER,
};
#define AUE_INTR_PKTLEN 0x8
@ -186,8 +183,7 @@ enum {
#define AUE_RXSTAT_DRIBBLE 0x10
#define AUE_RXSTAT_MASK 0x1E
#define GET_MII(sc) ((sc)->sc_miibus ? \
device_get_softc((sc)->sc_miibus) : NULL)
#define GET_MII(sc) usb2_ether_getmii(&(sc)->sc_ue)
struct aue_intrpkt {
uint8_t aue_txstat0;
@ -202,37 +198,23 @@ struct aue_intrpkt {
struct aue_rxpkt {
uint16_t aue_pktlen;
uint8_t aue_rxstat;
uint8_t pad;
} __packed;
struct aue_softc {
struct ifnet *sc_ifp;
struct usb2_ether sc_ue;
struct mtx sc_mtx;
struct usb2_xfer *sc_xfer[AUE_N_TRANSFER];
struct usb2_config_td sc_config_td;
struct usb2_callout sc_watchdog;
struct mtx sc_mtx;
struct aue_rxpkt sc_rxpkt;
struct usb2_device *sc_udev;
struct usb2_xfer *sc_xfer[AUE_N_TRANSFER];
device_t sc_miibus;
device_t sc_dev;
uint32_t sc_unit;
uint32_t sc_media_active;
uint32_t sc_media_status;
uint16_t sc_flags;
int sc_flags;
#define AUE_FLAG_LSYS 0x0001 /* use Linksys reset */
#define AUE_FLAG_PNA 0x0002 /* has Home PNA */
#define AUE_FLAG_PII 0x0004 /* Pegasus II chip */
#define AUE_FLAG_WAIT_LINK 0x0008 /* wait for link to come up */
#define AUE_FLAG_READ_STALL 0x0010 /* wait for clearing of stall */
#define AUE_FLAG_WRITE_STALL 0x0020 /* wait for clearing of stall */
#define AUE_FLAG_LL_READY 0x0040 /* Lower Layer Ready */
#define AUE_FLAG_HL_READY 0x0080 /* Higher Layer Ready */
#define AUE_FLAG_INTR_STALL 0x0100 /* wait for clearing of stall */
#define AUE_FLAG_LINK 0x0008 /* wait for link to come up */
#define AUE_FLAG_VER_2 0x0200 /* chip is version 2 */
#define AUE_FLAG_DUAL_PHY 0x0400 /* chip has two transcivers */
uint8_t sc_name[16];
};
#define AUE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define AUE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define AUE_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->sc_mtx, t)

File diff suppressed because it is too large Load Diff

View File

@ -166,50 +166,31 @@ struct axe_sframe_hdr {
uint16_t ilen;
} __packed;
#define GET_MII(sc) ((sc)->sc_miibus ? \
device_get_softc((sc)->sc_miibus) : NULL)
#define GET_MII(sc) usb2_ether_getmii(&(sc)->sc_ue)
/* The interrupt endpoint is currently unused by the ASIX part. */
enum {
AXE_BULK_DT_WR,
AXE_BULK_DT_RD,
AXE_BULK_CS_WR,
AXE_BULK_CS_RD,
AXE_INTR_DT_RD,
AXE_INTR_CS_RD,
AXE_N_TRANSFER = 6,
AXE_N_TRANSFER,
};
struct axe_softc {
struct ifnet *sc_ifp;
struct usb2_ether sc_ue;
struct mtx sc_mtx;
struct usb2_xfer *sc_xfer[AXE_N_TRANSFER];
int sc_phyno;
struct usb2_config_td sc_config_td;
struct usb2_callout sc_watchdog;
struct mtx sc_mtx;
struct usb2_device *sc_udev;
struct usb2_xfer *sc_xfer[AXE_N_TRANSFER];
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;
int sc_flags;
#define AXE_FLAG_LINK 0x0001
#define AXE_FLAG_INTR_STALL 0x0002
#define AXE_FLAG_READ_STALL 0x0004
#define AXE_FLAG_WRITE_STALL 0x0008
#define AXE_FLAG_LL_READY 0x0010
#define AXE_FLAG_HL_READY 0x0020
#define AXE_FLAG_772 0x0040 /* AX88772 */
#define AXE_FLAG_178 0x0080 /* AX88178 */
#define AXE_FLAG_772 0x1000 /* AX88772 */
#define AXE_FLAG_178 0x2000 /* AX88178 */
uint8_t sc_ipgs[3];
uint8_t sc_phyaddrs[2];
uint8_t sc_name[16];
uint8_t sc_ipgs[3];
uint8_t sc_phyaddrs[2];
};
#define AXE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define AXE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define AXE_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->sc_mtx, t)

File diff suppressed because it is too large Load Diff

View File

@ -35,58 +35,34 @@
#ifndef _USB_IF_CDCEREG_H_
#define _USB_IF_CDCEREG_H_
#define CDCE_IND_SIZE_MAX 32 /* bytes */
#define CDCE_512X4_IFQ_MAXLEN MAX((2*CDCE_512X4_FRAMES_MAX), IFQ_MAXLEN)
union cdce_eth_rx { /* multiframe header */
struct usb2_cdc_mf_eth_512x4_header hdr;
uint8_t data[MCLBYTES];
} __aligned(USB_HOST_ALIGN);
union cdce_eth_tx { /* multiframe header */
struct usb2_cdc_mf_eth_512x4_header hdr;
} __aligned(USB_HOST_ALIGN);
struct cdce_mq { /* mini-queue */
struct mbuf *ifq_head;
struct mbuf *ifq_tail;
uint16_t ifq_len;
};
#define CDCE_FRAMES_MAX 8 /* units */
#define CDCE_IND_SIZE_MAX 32 /* bytes */
enum {
CDCE_BULK_A,
CDCE_BULK_B,
CDCE_INTR,
CDCE_N_TRANSFER = 3,
CDCE_N_TRANSFER,
};
struct cdce_softc {
struct ifnet *sc_ifp;
struct usb2_ether sc_ue;
struct mtx sc_mtx;
struct usb2_xfer *sc_xfer[CDCE_N_TRANSFER];
struct mbuf *sc_rx_buf[CDCE_FRAMES_MAX];
struct mbuf *sc_tx_buf[CDCE_FRAMES_MAX];
union cdce_eth_tx sc_tx;
union cdce_eth_rx sc_rx;
struct ifmedia sc_ifmedia;
struct mtx sc_mtx;
struct cdce_mq sc_rx_mq;
struct cdce_mq sc_tx_mq;
struct usb2_xfer *sc_xfer[CDCE_N_TRANSFER];
struct usb2_device *sc_udev;
device_t sc_dev;
uint32_t sc_unit;
uint16_t sc_flags;
int sc_flags;
#define CDCE_FLAG_ZAURUS 0x0001
#define CDCE_FLAG_NO_UNION 0x0002
#define CDCE_FLAG_LL_READY 0x0004
#define CDCE_FLAG_HL_READY 0x0008
#define CDCE_FLAG_RX_DATA 0x0010
uint8_t sc_name[16];
uint8_t sc_eaddr_str_index;
uint8_t sc_data_iface_no;
uint8_t sc_ifaces_index[2];
uint8_t sc_iface_protocol;
};
#define CDCE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define CDCE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define CDCE_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->sc_mtx, t)
#endif /* _USB_IF_CDCEREG_H_ */

View File

@ -51,25 +51,16 @@ __FBSDID("$FreeBSD$");
* transaction, which helps performance a great deal.
*/
/*
* NOTE: all function names beginning like "cue_cfg_" can only
* be called from within the config thread function !
*/
#include <dev/usb2/include/usb2_devid.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#define usb2_config_td_cc usb2_ether_cc
#define usb2_config_td_softc cue_softc
#define USB_DEBUG_VAR cue_debug
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_lookup.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_config_td.h>
#include <dev/usb2/core/usb2_debug.h>
#include <dev/usb2/core/usb2_request.h>
#include <dev/usb2/core/usb2_busdma.h>
@ -97,35 +88,24 @@ static device_attach_t cue_attach;
static device_detach_t cue_detach;
static device_shutdown_t cue_shutdown;
static usb2_callback_t cue_bulk_read_clear_stall_callback;
static usb2_callback_t cue_bulk_read_callback;
static usb2_callback_t cue_bulk_write_clear_stall_callback;
static usb2_callback_t cue_bulk_write_callback;
static usb2_config_td_command_t cue_cfg_promisc_upd;
static usb2_config_td_command_t cue_config_copy;
static usb2_config_td_command_t cue_cfg_first_time_setup;
static usb2_config_td_command_t cue_cfg_tick;
static usb2_config_td_command_t cue_cfg_pre_init;
static usb2_config_td_command_t cue_cfg_init;
static usb2_config_td_command_t cue_cfg_pre_stop;
static usb2_config_td_command_t cue_cfg_stop;
static usb2_ether_fn_t cue_attach_post;
static usb2_ether_fn_t cue_init;
static usb2_ether_fn_t cue_stop;
static usb2_ether_fn_t cue_start;
static usb2_ether_fn_t cue_tick;
static usb2_ether_fn_t cue_setmulti;
static usb2_ether_fn_t cue_setpromisc;
static void cue_cfg_do_request(struct cue_softc *,
struct usb2_device_request *, void *);
static uint8_t cue_cfg_csr_read_1(struct cue_softc *, uint16_t);
static uint16_t cue_cfg_csr_read_2(struct cue_softc *, uint8_t);
static void cue_cfg_csr_write_1(struct cue_softc *, uint16_t, uint16_t);
static void cue_cfg_mem(struct cue_softc *, uint8_t, uint16_t, void *,
uint16_t);
static void cue_cfg_getmac(struct cue_softc *, void *);
static void cue_mchash(struct usb2_config_td_cc *, const uint8_t *);
static void cue_cfg_reset(struct cue_softc *);
static void cue_start_cb(struct ifnet *);
static void cue_start_transfers(struct cue_softc *);
static void cue_init_cb(void *);
static int cue_ioctl_cb(struct ifnet *, u_long, caddr_t);
static void cue_watchdog(void *);
static uint8_t cue_csr_read_1(struct cue_softc *, uint16_t);
static uint16_t cue_csr_read_2(struct cue_softc *, uint8_t);
static int cue_csr_write_1(struct cue_softc *, uint16_t, uint16_t);
static int cue_mem(struct cue_softc *, uint8_t, uint16_t, void *, int);
static int cue_getmac(struct cue_softc *, void *);
static uint32_t cue_mchash(const uint8_t *);
static void cue_reset(struct cue_softc *);
#if USB_DEBUG
static int cue_debug = 0;
@ -143,7 +123,7 @@ static const struct usb2_config cue_config[CUE_N_TRANSFER] = {
.direction = UE_DIR_OUT,
.mh.bufsize = (MCLBYTES + 2),
.mh.flags = {.pipe_bof = 1,},
.mh.callback = &cue_bulk_write_callback,
.mh.callback = cue_bulk_write_callback,
.mh.timeout = 10000, /* 10 seconds */
},
@ -153,29 +133,7 @@ static const struct usb2_config cue_config[CUE_N_TRANSFER] = {
.direction = UE_DIR_IN,
.mh.bufsize = (MCLBYTES + 2),
.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
.mh.callback = &cue_bulk_read_callback,
},
[CUE_BULK_CS_WR] = {
.type = UE_CONTROL,
.endpoint = 0x00, /* Control pipe */
.direction = UE_DIR_ANY,
.mh.bufsize = sizeof(struct usb2_device_request),
.mh.flags = {},
.mh.callback = &cue_bulk_write_clear_stall_callback,
.mh.timeout = 1000, /* 1 second */
.mh.interval = 50, /* 50ms */
},
[CUE_BULK_CS_RD] = {
.type = UE_CONTROL,
.endpoint = 0x00, /* Control pipe */
.direction = UE_DIR_ANY,
.mh.bufsize = sizeof(struct usb2_device_request),
.mh.flags = {},
.mh.callback = &cue_bulk_read_clear_stall_callback,
.mh.timeout = 1000, /* 1 second */
.mh.interval = 50, /* 50ms */
.mh.callback = cue_bulk_read_callback,
},
};
@ -202,41 +160,24 @@ MODULE_DEPEND(cue, usb2_ethernet, 1, 1, 1);
MODULE_DEPEND(cue, usb2_core, 1, 1, 1);
MODULE_DEPEND(cue, ether, 1, 1, 1);
static void
cue_cfg_do_request(struct cue_softc *sc, struct usb2_device_request *req,
void *data)
{
uint16_t length;
usb2_error_t err;
static const struct usb2_ether_methods cue_ue_methods = {
.ue_attach_post = cue_attach_post,
.ue_start = cue_start,
.ue_init = cue_init,
.ue_stop = cue_stop,
.ue_tick = cue_tick,
.ue_setmulti = cue_setmulti,
.ue_setpromisc = cue_setpromisc,
};
if (usb2_config_td_is_gone(&sc->sc_config_td)) {
goto error;
}
err = usb2_do_request_flags
(sc->sc_udev, &sc->sc_mtx, req, data, 0, NULL, 1000);
#define CUE_SETBIT(sc, reg, x) \
cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x))
if (err) {
DPRINTF("device request failed, err=%s "
"(ignored)\n", usb2_errstr(err));
error:
length = UGETW(req->wLength);
if ((req->bmRequestType & UT_READ) && length) {
bzero(data, length);
}
}
}
#define CUE_CFG_SETBIT(sc, reg, x) \
cue_cfg_csr_write_1(sc, reg, cue_cfg_csr_read_1(sc, reg) | (x))
#define CUE_CFG_CLRBIT(sc, reg, x) \
cue_cfg_csr_write_1(sc, reg, cue_cfg_csr_read_1(sc, reg) & ~(x))
#define CUE_CLRBIT(sc, reg, x) \
cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x))
static uint8_t
cue_cfg_csr_read_1(struct cue_softc *sc, uint16_t reg)
cue_csr_read_1(struct cue_softc *sc, uint16_t reg)
{
struct usb2_device_request req;
uint8_t val;
@ -247,12 +188,14 @@ cue_cfg_csr_read_1(struct cue_softc *sc, uint16_t reg)
USETW(req.wIndex, reg);
USETW(req.wLength, 1);
cue_cfg_do_request(sc, &req, &val);
if (usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000)) {
/* ignore any errors */
}
return (val);
}
static uint16_t
cue_cfg_csr_read_2(struct cue_softc *sc, uint8_t reg)
cue_csr_read_2(struct cue_softc *sc, uint8_t reg)
{
struct usb2_device_request req;
uint16_t val;
@ -263,12 +206,12 @@ cue_cfg_csr_read_2(struct cue_softc *sc, uint8_t reg)
USETW(req.wIndex, reg);
USETW(req.wLength, 2);
cue_cfg_do_request(sc, &req, &val);
(void)usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000);
return (le16toh(val));
}
static void
cue_cfg_csr_write_1(struct cue_softc *sc, uint16_t reg, uint16_t val)
static int
cue_csr_write_1(struct cue_softc *sc, uint16_t reg, uint16_t val)
{
struct usb2_device_request req;
@ -278,30 +221,28 @@ cue_cfg_csr_write_1(struct cue_softc *sc, uint16_t reg, uint16_t val)
USETW(req.wIndex, reg);
USETW(req.wLength, 0);
cue_cfg_do_request(sc, &req, NULL);
return (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000));
}
static void
cue_cfg_mem(struct cue_softc *sc, uint8_t cmd, uint16_t addr,
void *buf, uint16_t len)
static int
cue_mem(struct cue_softc *sc, uint8_t cmd, uint16_t addr, void *buf, int len)
{
struct usb2_device_request req;
if (cmd == CUE_CMD_READSRAM) {
if (cmd == CUE_CMD_READSRAM)
req.bmRequestType = UT_READ_VENDOR_DEVICE;
} else {
else
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
}
req.bRequest = cmd;
USETW(req.wValue, 0);
USETW(req.wIndex, addr);
USETW(req.wLength, len);
cue_cfg_do_request(sc, &req, buf);
return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000));
}
static void
cue_cfg_getmac(struct cue_softc *sc, void *buf)
static int
cue_getmac(struct cue_softc *sc, void *buf)
{
struct usb2_device_request req;
@ -311,49 +252,84 @@ cue_cfg_getmac(struct cue_softc *sc, void *buf)
USETW(req.wIndex, 0);
USETW(req.wLength, ETHER_ADDR_LEN);
cue_cfg_do_request(sc, &req, buf);
return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000));
}
#define CUE_BITS 9
static void
cue_mchash(struct usb2_config_td_cc *cc, const uint8_t *addr)
static uint32_t
cue_mchash(const uint8_t *addr)
{
uint16_t h;
uint32_t crc;
h = ether_crc32_le(addr, ETHER_ADDR_LEN) &
((1 << CUE_BITS) - 1);
cc->if_hash[h >> 3] |= 1 << (h & 0x7);
/* Compute CRC for the address value. */
crc = ether_crc32_le(addr, ETHER_ADDR_LEN);
return (crc & ((1 << CUE_BITS) - 1));
}
static void
cue_cfg_promisc_upd(struct cue_softc *sc,
struct usb2_config_td_cc *cc, uint16_t refcount)
cue_setpromisc(struct usb2_ether *ue)
{
/* if we want promiscuous mode, set the allframes bit */
struct cue_softc *sc = usb2_ether_getsc(ue);
struct ifnet *ifp = usb2_ether_getifp(ue);
if (cc->if_flags & IFF_PROMISC) {
CUE_CFG_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
} else {
CUE_CFG_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
}
CUE_LOCK_ASSERT(sc, MA_OWNED);
/* if we want promiscuous mode, set the allframes bit */
if (ifp->if_flags & IFF_PROMISC)
CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
else
CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
/* write multicast hash-bits */
cue_cfg_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
cc->if_hash, CUE_MCAST_TABLE_LEN);
cue_setmulti(ue);
}
static void
cue_config_copy(struct cue_softc *sc,
struct usb2_config_td_cc *cc, uint16_t refcount)
cue_setmulti(struct usb2_ether *ue)
{
bzero(cc, sizeof(*cc));
usb2_ether_cc(sc->sc_ifp, &cue_mchash, cc);
struct cue_softc *sc = usb2_ether_getsc(ue);
struct ifnet *ifp = usb2_ether_getifp(ue);
struct ifmultiaddr *ifma;
uint32_t h = 0, i;
uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
CUE_LOCK_ASSERT(sc, MA_OWNED);
if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
for (i = 0; i < 8; i++)
hashtbl[i] = 0xff;
cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
&hashtbl, 8);
return;
}
/* now program new ones */
IF_ADDR_LOCK(ifp);
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
{
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
h = cue_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
hashtbl[h >> 3] |= 1 << (h & 0x7);
}
IF_ADDR_UNLOCK(ifp);
/*
* Also include the broadcast address in the filter
* so we can receive broadcast frames.
*/
if (ifp->if_flags & IFF_BROADCAST) {
h = cue_mchash(ifp->if_broadcastaddr);
hashtbl[h >> 3] |= 1 << (h & 0x7);
}
cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, &hashtbl, 8);
}
static void
cue_cfg_reset(struct cue_softc *sc)
cue_reset(struct cue_softc *sc)
{
struct usb2_device_request req;
@ -363,13 +339,22 @@ cue_cfg_reset(struct cue_softc *sc)
USETW(req.wIndex, 0);
USETW(req.wLength, 0);
cue_cfg_do_request(sc, &req, NULL);
if (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000)) {
/* ignore any errors */
}
/*
* wait a little while for the chip to get its brains in order:
*/
usb2_ether_pause(&sc->sc_ue, hz / 100);
}
(void)usb2_config_td_sleep(&sc->sc_config_td, hz / 100);
static void
cue_attach_post(struct usb2_ether *ue)
{
struct cue_softc *sc = usb2_ether_getsc(ue);
cue_getmac(sc, ue->ue_eaddr);
}
static int
@ -377,60 +362,51 @@ cue_probe(device_t dev)
{
struct usb2_attach_arg *uaa = device_get_ivars(dev);
if (uaa->usb2_mode != USB_MODE_HOST) {
if (uaa->usb2_mode != USB_MODE_HOST)
return (ENXIO);
}
if (uaa->info.bConfigIndex != CUE_CONFIG_IDX) {
if (uaa->info.bConfigIndex != CUE_CONFIG_IDX)
return (ENXIO);
}
if (uaa->info.bIfaceIndex != CUE_IFACE_IDX) {
if (uaa->info.bIfaceIndex != CUE_IFACE_IDX)
return (ENXIO);
}
return (usb2_lookup_id_by_uaa(cue_devs, sizeof(cue_devs), uaa));
}
/*
* Attach the interface. Allocate softc structures, do ifmedia
* setup and ethernet/BPF attach.
*/
static int
cue_attach(device_t dev)
{
struct usb2_attach_arg *uaa = device_get_ivars(dev);
struct cue_softc *sc = device_get_softc(dev);
struct usb2_ether *ue = &sc->sc_ue;
uint8_t iface_index;
int32_t error;
sc->sc_udev = uaa->device;
sc->sc_dev = dev;
sc->sc_unit = device_get_unit(dev);
int error;
device_set_usb2_desc(dev);
mtx_init(&sc->sc_mtx, "cue lock", NULL, MTX_DEF | MTX_RECURSE);
usb2_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0);
mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
iface_index = CUE_IFACE_IDX;
error = usb2_transfer_setup(uaa->device, &iface_index,
sc->sc_xfer, cue_config, CUE_N_TRANSFER, sc, &sc->sc_mtx);
if (error) {
device_printf(dev, "allocating USB "
"transfers failed!\n");
device_printf(dev, "allocating USB transfers failed!\n");
goto detach;
}
error = usb2_config_td_setup(&sc->sc_config_td, sc, &sc->sc_mtx,
NULL, sizeof(struct usb2_config_td_cc), 16);
ue->ue_sc = sc;
ue->ue_dev = dev;
ue->ue_udev = uaa->device;
ue->ue_mtx = &sc->sc_mtx;
ue->ue_methods = &cue_ue_methods;
error = usb2_ether_ifattach(ue);
if (error) {
device_printf(dev, "could not setup config "
"thread!\n");
device_printf(dev, "could not attach interface\n");
goto detach;
}
mtx_lock(&sc->sc_mtx);
/* start setup */
usb2_config_td_queue_command
(&sc->sc_config_td, NULL, &cue_cfg_first_time_setup, 0, 0);
cue_watchdog(sc);
mtx_unlock(&sc->sc_mtx);
return (0); /* success */
detach:
@ -438,117 +414,27 @@ detach:
return (ENXIO); /* failure */
}
static void
cue_cfg_first_time_setup(struct cue_softc *sc,
struct usb2_config_td_cc *cc, uint16_t refcount)
{
uint8_t eaddr[ETHER_ADDR_LEN];
struct ifnet *ifp;
#if 0
/* Reset the adapter. */
cue_cfg_reset(sc);
#endif
/*
* Get station address.
*/
cue_cfg_getmac(sc, eaddr);
mtx_unlock(&sc->sc_mtx);
ifp = if_alloc(IFT_ETHER);
mtx_lock(&sc->sc_mtx);
if (ifp == NULL) {
printf("cue%d: could not if_alloc()\n",
sc->sc_unit);
goto done;
}
ifp->if_softc = sc;
if_initname(ifp, "cue", sc->sc_unit);
ifp->if_mtu = ETHERMTU;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = cue_ioctl_cb;
ifp->if_start = cue_start_cb;
ifp->if_watchdog = NULL;
ifp->if_init = cue_init_cb;
ifp->if_baudrate = 10000000;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_READY(&ifp->if_snd);
sc->sc_ifp = ifp;
mtx_unlock(&sc->sc_mtx);
ether_ifattach(ifp, eaddr);
mtx_lock(&sc->sc_mtx);
done:
return;
}
static int
cue_detach(device_t dev)
{
struct cue_softc *sc = device_get_softc(dev);
struct ifnet *ifp;
struct usb2_ether *ue = &sc->sc_ue;
usb2_config_td_drain(&sc->sc_config_td);
mtx_lock(&sc->sc_mtx);
usb2_callout_stop(&sc->sc_watchdog);
cue_cfg_pre_stop(sc, NULL, 0);
ifp = sc->sc_ifp;
mtx_unlock(&sc->sc_mtx);
/* stop all USB transfers first */
usb2_transfer_unsetup(sc->sc_xfer, CUE_N_TRANSFER);
/* get rid of any late children */
bus_generic_detach(dev);
if (ifp) {
ether_ifdetach(ifp);
if_free(ifp);
}
usb2_config_td_unsetup(&sc->sc_config_td);
usb2_callout_drain(&sc->sc_watchdog);
usb2_ether_ifdetach(ue);
mtx_destroy(&sc->sc_mtx);
return (0);
}
static void
cue_bulk_read_clear_stall_callback(struct usb2_xfer *xfer)
{
struct cue_softc *sc = xfer->priv_sc;
struct usb2_xfer *xfer_other = sc->sc_xfer[CUE_BULK_DT_RD];
if (usb2_clear_stall_callback(xfer, xfer_other)) {
DPRINTF("stall cleared\n");
sc->sc_flags &= ~CUE_FLAG_READ_STALL;
usb2_transfer_start(xfer_other);
}
}
static void
cue_bulk_read_callback(struct usb2_xfer *xfer)
{
struct cue_softc *sc = xfer->priv_sc;
struct ifnet *ifp = sc->sc_ifp;
struct mbuf *m = NULL;
struct usb2_ether *ue = &sc->sc_ue;
struct ifnet *ifp = usb2_ether_getifp(ue);
uint8_t buf[2];
uint16_t len;
int len;
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
@ -558,150 +444,55 @@ cue_bulk_read_callback(struct usb2_xfer *xfer)
goto tr_setup;
}
usb2_copy_out(xfer->frbuffers, 0, buf, 2);
len = buf[0] | (buf[1] << 8);
xfer->actlen -= 2;
len = buf[0] | (buf[1] << 8);
len = min(xfer->actlen, len);
m = usb2_ether_get_mbuf();
if (m == NULL) {
ifp->if_ierrors++;
goto tr_setup;
}
xfer->actlen = min(xfer->actlen, m->m_len);
xfer->actlen = min(xfer->actlen, len);
usb2_copy_out(xfer->frbuffers, 2, m->m_data, xfer->actlen);
ifp->if_ipackets++;
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = m->m_len = xfer->actlen;
usb2_ether_rxbuf(ue, xfer->frbuffers, 2, len);
/* FALLTHROUGH */
case USB_ST_SETUP:
tr_setup:
if (sc->sc_flags & CUE_FLAG_READ_STALL) {
usb2_transfer_start(sc->sc_xfer[CUE_BULK_CS_RD]);
} else {
xfer->frlengths[0] = xfer->max_data_length;
usb2_start_hardware(xfer);
}
/*
* At the end of a USB callback it is always safe to unlock
* the private mutex of a device! That is why we do the
* "if_input" here, and not some lines up!
*/
if (m) {
mtx_unlock(&sc->sc_mtx);
(ifp->if_input) (ifp, m);
mtx_lock(&sc->sc_mtx);
}
xfer->frlengths[0] = xfer->max_data_length;
usb2_start_hardware(xfer);
usb2_ether_rxflush(ue);
return;
default: /* Error */
if (xfer->error != USB_ERR_CANCELLED) {
/* try to clear stall first */
sc->sc_flags |= CUE_FLAG_READ_STALL;
usb2_transfer_start(sc->sc_xfer[CUE_BULK_CS_RD]);
}
DPRINTF("bulk read error, %s\n",
usb2_errstr(xfer->error));
if (xfer->error != USB_ERR_CANCELLED) {
/* try to clear stall first */
xfer->flags.stall_pipe = 1;
goto tr_setup;
}
return;
}
}
static void
cue_cfg_tick(struct cue_softc *sc,
struct usb2_config_td_cc *cc, uint16_t refcount)
{
struct ifnet *ifp = sc->sc_ifp;
if ((ifp == NULL)) {
/* not ready */
return;
}
ifp->if_collisions += cue_cfg_csr_read_2(sc, CUE_TX_SINGLECOLL);
ifp->if_collisions += cue_cfg_csr_read_2(sc, CUE_TX_MULTICOLL);
ifp->if_collisions += cue_cfg_csr_read_2(sc, CUE_TX_EXCESSCOLL);
if (cue_cfg_csr_read_2(sc, CUE_RX_FRAMEERR)) {
ifp->if_ierrors++;
}
/* start stopped transfers, if any */
cue_start_transfers(sc);
}
static void
cue_start_cb(struct ifnet *ifp)
{
struct cue_softc *sc = ifp->if_softc;
mtx_lock(&sc->sc_mtx);
cue_start_transfers(sc);
mtx_unlock(&sc->sc_mtx);
}
static void
cue_start_transfers(struct cue_softc *sc)
{
if ((sc->sc_flags & CUE_FLAG_LL_READY) &&
(sc->sc_flags & CUE_FLAG_HL_READY)) {
/*
* start the USB transfers, if not already started:
*/
usb2_transfer_start(sc->sc_xfer[CUE_BULK_DT_RD]);
usb2_transfer_start(sc->sc_xfer[CUE_BULK_DT_WR]);
}
}
static void
cue_bulk_write_clear_stall_callback(struct usb2_xfer *xfer)
{
struct cue_softc *sc = xfer->priv_sc;
struct usb2_xfer *xfer_other = sc->sc_xfer[CUE_BULK_DT_WR];
if (usb2_clear_stall_callback(xfer, xfer_other)) {
DPRINTF("stall cleared\n");
sc->sc_flags &= ~CUE_FLAG_WRITE_STALL;
usb2_transfer_start(xfer_other);
}
}
static void
cue_bulk_write_callback(struct usb2_xfer *xfer)
{
struct cue_softc *sc = xfer->priv_sc;
struct ifnet *ifp = sc->sc_ifp;
struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue);
struct mbuf *m;
uint8_t buf[2];
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
DPRINTFN(11, "transfer complete\n");
ifp->if_opackets++;
/* FALLTHROUGH */
case USB_ST_SETUP:
if (sc->sc_flags & CUE_FLAG_WRITE_STALL) {
usb2_transfer_start(sc->sc_xfer[CUE_BULK_CS_WR]);
goto done;
}
tr_setup:
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
if (m == NULL) {
goto done;
}
if (m->m_pkthdr.len > MCLBYTES) {
if (m == NULL)
return;
if (m->m_pkthdr.len > MCLBYTES)
m->m_pkthdr.len = MCLBYTES;
}
xfer->frlengths[0] = (m->m_pkthdr.len + 2);
/* the first two bytes are the frame length */
@ -724,154 +515,95 @@ cue_bulk_write_callback(struct usb2_xfer *xfer)
usb2_start_hardware(xfer);
done:
return;
default: /* Error */
DPRINTFN(11, "transfer error, %s\n",
usb2_errstr(xfer->error));
ifp->if_oerrors++;
if (xfer->error != USB_ERR_CANCELLED) {
/* try to clear stall first */
sc->sc_flags |= CUE_FLAG_WRITE_STALL;
usb2_transfer_start(sc->sc_xfer[CUE_BULK_CS_WR]);
xfer->flags.stall_pipe = 1;
goto tr_setup;
}
ifp->if_oerrors++;
return;
}
}
static void
cue_init_cb(void *arg)
cue_tick(struct usb2_ether *ue)
{
struct cue_softc *sc = arg;
struct cue_softc *sc = usb2_ether_getsc(ue);
struct ifnet *ifp = usb2_ether_getifp(ue);
mtx_lock(&sc->sc_mtx);
usb2_config_td_queue_command
(&sc->sc_config_td, &cue_cfg_pre_init,
&cue_cfg_init, 0, 0);
mtx_unlock(&sc->sc_mtx);
CUE_LOCK_ASSERT(sc, MA_OWNED);
ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL);
ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL);
ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL);
if (cue_csr_read_2(sc, CUE_RX_FRAMEERR))
ifp->if_ierrors++;
}
static void
cue_cfg_pre_init(struct cue_softc *sc,
struct usb2_config_td_cc *cc, uint16_t refcount)
cue_start(struct usb2_ether *ue)
{
struct ifnet *ifp = sc->sc_ifp;
struct cue_softc *sc = usb2_ether_getsc(ue);
/* immediate configuration */
cue_cfg_pre_stop(sc, cc, 0);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
sc->sc_flags |= CUE_FLAG_HL_READY;
/*
* start the USB transfers, if not already started:
*/
usb2_transfer_start(sc->sc_xfer[CUE_BULK_DT_RD]);
usb2_transfer_start(sc->sc_xfer[CUE_BULK_DT_WR]);
}
static void
cue_cfg_init(struct cue_softc *sc,
struct usb2_config_td_cc *cc, uint16_t refcount)
cue_init(struct usb2_ether *ue)
{
uint8_t i;
struct cue_softc *sc = usb2_ether_getsc(ue);
struct ifnet *ifp = usb2_ether_getifp(ue);
int i;
CUE_LOCK_ASSERT(sc, MA_OWNED);
/*
* Cancel pending I/O and free all RX/TX buffers.
*/
cue_cfg_stop(sc, cc, 0);
cue_stop(ue);
#if 0
cue_cfg_reset(sc);
cue_reset(sc);
#endif
/* Set MAC address */
for (i = 0; i < ETHER_ADDR_LEN; i++) {
cue_cfg_csr_write_1(sc, CUE_PAR0 - i, cc->if_lladdr[i]);
}
for (i = 0; i < ETHER_ADDR_LEN; i++)
cue_csr_write_1(sc, CUE_PAR0 - i, IF_LLADDR(ifp)[i]);
/* Enable RX logic. */
cue_cfg_csr_write_1(sc, CUE_ETHCTL, CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON);
cue_csr_write_1(sc, CUE_ETHCTL, CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON);
/* Load the multicast filter */
cue_cfg_promisc_upd(sc, cc, 0);
cue_setpromisc(ue);
/*
* Set the number of RX and TX buffers that we want
* to reserve inside the ASIC.
*/
cue_cfg_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES);
cue_cfg_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES);
cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES);
cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES);
/* Set advanced operation modes. */
cue_cfg_csr_write_1(sc, CUE_ADVANCED_OPMODES,
cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
CUE_AOP_EMBED_RXLEN | 0x01);/* 1 wait state */
/* Program the LED operation. */
cue_cfg_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
sc->sc_flags |= (CUE_FLAG_READ_STALL |
CUE_FLAG_WRITE_STALL |
CUE_FLAG_LL_READY);
usb2_transfer_set_stall(sc->sc_xfer[CUE_BULK_DT_WR]);
cue_start_transfers(sc);
}
static int
cue_ioctl_cb(struct ifnet *ifp, u_long command, caddr_t data)
{
struct cue_softc *sc = ifp->if_softc;
int error = 0;
switch (command) {
case SIOCSIFFLAGS:
mtx_lock(&sc->sc_mtx);
if (ifp->if_flags & IFF_UP) {
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
usb2_config_td_queue_command
(&sc->sc_config_td, &cue_config_copy,
&cue_cfg_promisc_upd, 0, 0);
} else {
usb2_config_td_queue_command
(&sc->sc_config_td, &cue_cfg_pre_init,
&cue_cfg_init, 0, 0);
}
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
usb2_config_td_queue_command
(&sc->sc_config_td, &cue_cfg_pre_stop,
&cue_cfg_stop, 0, 0);
}
}
mtx_unlock(&sc->sc_mtx);
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
mtx_lock(&sc->sc_mtx);
usb2_config_td_queue_command
(&sc->sc_config_td, &cue_config_copy,
&cue_cfg_promisc_upd, 0, 0);
mtx_unlock(&sc->sc_mtx);
break;
default:
error = ether_ioctl(ifp, command, data);
break;
}
return (error);
}
static void
cue_watchdog(void *arg)
{
struct cue_softc *sc = arg;
mtx_assert(&sc->sc_mtx, MA_OWNED);
usb2_config_td_queue_command
(&sc->sc_config_td, NULL, &cue_cfg_tick, 0, 0);
usb2_callout_reset(&sc->sc_watchdog,
hz, &cue_watchdog, sc);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
cue_start(ue);
}
/*
@ -879,39 +611,23 @@ cue_watchdog(void *arg)
* RX and TX lists.
*/
static void
cue_cfg_pre_stop(struct cue_softc *sc,
struct usb2_config_td_cc *cc, uint16_t refcount)
cue_stop(struct usb2_ether *ue)
{
struct ifnet *ifp = sc->sc_ifp;
struct cue_softc *sc = usb2_ether_getsc(ue);
struct ifnet *ifp = usb2_ether_getifp(ue);
if (cc) {
/* copy the needed configuration */
cue_config_copy(sc, cc, refcount);
}
/* immediate configuration */
CUE_LOCK_ASSERT(sc, MA_OWNED);
if (ifp) {
/* clear flags */
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
}
sc->sc_flags &= ~(CUE_FLAG_HL_READY |
CUE_FLAG_LL_READY);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
/*
* stop all the transfers, if not already stopped:
*/
usb2_transfer_stop(sc->sc_xfer[CUE_BULK_DT_WR]);
usb2_transfer_stop(sc->sc_xfer[CUE_BULK_DT_RD]);
usb2_transfer_stop(sc->sc_xfer[CUE_BULK_CS_WR]);
usb2_transfer_stop(sc->sc_xfer[CUE_BULK_CS_RD]);
}
static void
cue_cfg_stop(struct cue_softc *sc,
struct usb2_config_td_cc *cc, uint16_t refcount)
{
cue_cfg_csr_write_1(sc, CUE_ETHCTL, 0);
cue_cfg_reset(sc);
cue_csr_write_1(sc, CUE_ETHCTL, 0);
cue_reset(sc);
}
/*
@ -923,13 +639,7 @@ cue_shutdown(device_t dev)
{
struct cue_softc *sc = device_get_softc(dev);
mtx_lock(&sc->sc_mtx);
usb2_config_td_queue_command
(&sc->sc_config_td, &cue_cfg_pre_stop,
&cue_cfg_stop, 0, 0);
mtx_unlock(&sc->sc_mtx);
usb2_ether_ifshutdown(&sc->sc_ue);
return (0);
}

View File

@ -99,7 +99,6 @@
* reception of broadcast frames.
*/
#define CUE_MCAST_TABLE_ADDR 0xFA80
#define CUE_MCAST_TABLE_LEN 64
#define CUE_TIMEOUT 1000
#define CUE_MIN_FRAMELEN 60
@ -116,28 +115,18 @@
enum {
CUE_BULK_DT_WR,
CUE_BULK_DT_RD,
CUE_BULK_CS_WR,
CUE_BULK_CS_RD,
CUE_N_TRANSFER = 4,
CUE_N_TRANSFER,
};
struct cue_softc {
struct ifnet *sc_ifp;
struct usb2_ether sc_ue;
struct mtx sc_mtx;
struct usb2_xfer *sc_xfer[CUE_N_TRANSFER];
struct usb2_config_td sc_config_td;
struct usb2_callout sc_watchdog;
struct mtx sc_mtx;
device_t sc_dev;
struct usb2_device *sc_udev;
struct usb2_xfer *sc_xfer[CUE_N_TRANSFER];
uint32_t sc_unit;
uint16_t sc_flags;
#define CUE_FLAG_READ_STALL 0x0010 /* wait for clearing of stall */
#define CUE_FLAG_WRITE_STALL 0x0020 /* wait for clearing of stall */
#define CUE_FLAG_LL_READY 0x0040 /* Lower Layer Ready */
#define CUE_FLAG_HL_READY 0x0080 /* Higher Layer Ready */
#define CUE_FLAG_INTR_STALL 0x0100 /* wait for clearing of stall */
int sc_flags;
#define CUE_FLAG_LINK 0x0001 /* got a link */
};
#define CUE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define CUE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define CUE_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->sc_mtx, t)

File diff suppressed because it is too large Load Diff

View File

@ -67,7 +67,8 @@ struct kue_ether_desc {
#define KUE_ETHERSTATS(x) UGETDW((x)->sc_desc.kue_etherstats)
#define KUE_MAXSEG(x) UGETW((x)->sc_desc.kue_maxseg)
#define KUE_MCFILTCNT(x) (UGETW((x)->sc_desc.kue_mcastfilt) & 0x7FFF)
#define KUE_MCFILT_MAX (USB_ETHER_HASH_MAX / ETHER_ADDR_LEN)
#define KUE_MCFILT(x, y) \
(char *)&(sc->sc_mcfilters[y * ETHER_ADDR_LEN])
#define KUE_STAT_TX_OK 0x00000001
#define KUE_STAT_RX_OK 0x00000002
@ -119,30 +120,22 @@ struct kue_ether_desc {
enum {
KUE_BULK_DT_WR,
KUE_BULK_DT_RD,
KUE_BULK_CS_WR,
KUE_BULK_CS_RD,
KUE_N_TRANSFER = 4,
KUE_N_TRANSFER,
};
struct kue_softc {
struct ifnet *sc_ifp;
struct usb2_ether sc_ue;
struct mtx sc_mtx;
struct kue_ether_desc sc_desc;
struct usb2_xfer *sc_xfer[KUE_N_TRANSFER];
uint8_t *sc_mcfilters;
struct usb2_config_td sc_config_td;
struct usb2_callout sc_watchdog;
struct mtx sc_mtx;
struct kue_ether_desc sc_desc;
int sc_flags;
#define KUE_FLAG_LINK 0x0001
device_t sc_dev;
struct usb2_device *sc_udev;
struct usb2_xfer *sc_xfer[KUE_N_TRANSFER];
uint32_t sc_unit;
uint16_t sc_mcfilt_max;
uint16_t sc_flags;
#define KUE_FLAG_READ_STALL 0x0010 /* wait for clearing of stall */
#define KUE_FLAG_WRITE_STALL 0x0020 /* wait for clearing of stall */
#define KUE_FLAG_LL_READY 0x0040 /* Lower Layer Ready */
#define KUE_FLAG_HL_READY 0x0080 /* Higher Layer Ready */
#define KUE_FLAG_INTR_STALL 0x0100 /* wait for clearing of stall */
uint16_t sc_rxfilt;
};
#define KUE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define KUE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define KUE_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->sc_mtx, t)

File diff suppressed because it is too large Load Diff

View File

@ -144,8 +144,7 @@
#define RUE_RXSTAT_PMATCH (0x04 << 12)
#define RUE_RXSTAT_MCAST (0x08 << 12)
#define GET_MII(sc) ((sc)->sc_miibus ? \
device_get_softc((sc)->sc_miibus) : NULL)
#define GET_MII(sc) usb2_ether_getmii(&(sc)->sc_ue)
struct rue_intrpkt {
uint8_t rue_tsr;
@ -166,36 +165,19 @@ struct rue_type {
enum {
RUE_BULK_DT_WR,
RUE_BULK_DT_RD,
RUE_BULK_CS_WR,
RUE_BULK_CS_RD,
RUE_INTR_DT_RD,
RUE_INTR_CS_RD,
RUE_N_TRANSFER = 6,
RUE_N_TRANSFER,
};
struct rue_softc {
struct ifnet *sc_ifp;
struct usb2_ether sc_ue;
struct mtx sc_mtx;
struct usb2_xfer *sc_xfer[RUE_N_TRANSFER];
struct usb2_config_td sc_config_td;
struct usb2_callout sc_watchdog;
struct mtx sc_mtx;
struct usb2_device *sc_udev;
struct usb2_xfer *sc_xfer[RUE_N_TRANSFER];
device_t sc_miibus;
device_t sc_dev;
uint32_t sc_unit;
uint32_t sc_media_active;
uint32_t sc_media_status;
uint16_t sc_flags;
#define RUE_FLAG_WAIT_LINK 0x0001
#define RUE_FLAG_INTR_STALL 0x0002
#define RUE_FLAG_READ_STALL 0x0004
#define RUE_FLAG_WRITE_STALL 0x0008
#define RUE_FLAG_LL_READY 0x0010
#define RUE_FLAG_HL_READY 0x0020
uint8_t sc_name[16];
int sc_flags;
#define RUE_FLAG_LINK 0x0001
};
#define RUE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define RUE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define RUE_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->sc_mtx, t)

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,12 @@
#define UDAV_IFACE_INDEX 0
#define UDAV_CONFIG_INDEX 0 /* config number 1 */
#define UDAV_TX_TIMEOUT 1000
#define UDAV_TIMEOUT 10000
#define UDAV_TX_TIMEOUT 1000
#define UDAV_TIMEOUT 10000
/* Packet length */
#define UDAV_MIN_FRAME_LEN 60
@ -131,43 +137,30 @@
#define UDAV_GPR_GEPIO1 (1<<1) /* General purpose 1 */
#define UDAV_GPR_GEPIO0 (1<<0) /* General purpose 0 */
#define GET_MII(sc) ((sc)->sc_miibus ? \
device_get_softc((sc)->sc_miibus) : NULL)
#define GET_MII(sc) usb2_ether_getmii(&(sc)->sc_ue)
struct udav_rxpkt {
uint8_t rxstat;
uint16_t pktlen;
} __packed;
enum {
UDAV_BULK_DT_WR,
UDAV_BULK_DT_RD,
UDAV_BULK_CS_WR,
UDAV_BULK_CS_RD,
UDAV_INTR_DT_RD,
UDAV_INTR_CS_RD,
UDAV_N_TRANSFER = 6,
UDAV_N_TRANSFER,
};
struct udav_softc {
struct ifnet *sc_ifp;
struct usb2_ether sc_ue;
struct mtx sc_mtx;
struct usb2_xfer *sc_xfer[UDAV_N_TRANSFER];
struct usb2_config_td sc_config_td;
struct usb2_callout sc_watchdog;
struct mtx sc_mtx;
struct usb2_device *sc_udev;
struct usb2_xfer *sc_xfer[UDAV_N_TRANSFER];
device_t sc_miibus;
device_t sc_dev;
uint32_t sc_unit;
uint32_t sc_media_active;
uint32_t sc_media_status;
uint16_t sc_flags;
#define UDAV_FLAG_WAIT_LINK 0x0001
#define UDAV_FLAG_INTR_STALL 0x0002
#define UDAV_FLAG_READ_STALL 0x0004
#define UDAV_FLAG_WRITE_STALL 0x0008
#define UDAV_FLAG_LL_READY 0x0010
#define UDAV_FLAG_HL_READY 0x0020
int sc_flags;
#define UDAV_FLAG_LINK 0x0001
#define UDAV_FLAG_EXT_PHY 0x0040
uint8_t sc_name[16];
};
#define UDAV_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define UDAV_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define UDAV_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->sc_mtx, t)

View File

@ -1,6 +1,6 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
* Copyright (c) 2009 Andrew Thompson (thompsa@FreeBSD.org)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -24,77 +24,562 @@
* SUCH DAMAGE.
*/
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/include/usb2_endian.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_request.h>
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/ethernet/usb2_ethernet.h>
MODULE_VERSION(usb2_ethernet, 1);
MODULE_DEPEND(usb2_ethernet, usb2_core, 1, 1, 1);
SYSCTL_NODE(_net, OID_AUTO, ue, CTLFLAG_RD, 0, "USB Ethernet parameters");
/*------------------------------------------------------------------------*
* usb2_ether_get_mbuf - get a new ethernet aligned mbuf
*------------------------------------------------------------------------*/
struct mbuf *
usb2_ether_get_mbuf(void)
#define UE_LOCK(_ue) mtx_lock((_ue)->ue_mtx)
#define UE_UNLOCK(_ue) mtx_unlock((_ue)->ue_mtx)
#define UE_LOCK_ASSERT(_ue, t) mtx_assert((_ue)->ue_mtx, t)
static struct unrhdr *ueunit;
static usb2_proc_callback_t ue_attach_post_task;
static usb2_proc_callback_t ue_promisc_task;
static usb2_proc_callback_t ue_setmulti_task;
static usb2_proc_callback_t ue_ifmedia_task;
static usb2_proc_callback_t ue_tick_task;
static usb2_proc_callback_t ue_start_task;
static usb2_proc_callback_t ue_stop_task;
static void ue_init(void *);
static void ue_start(struct ifnet *);
static int ue_ifmedia_upd(struct ifnet *);
static void ue_watchdog(void *);
/*
* Return values:
* 0: success
* Else: device has been detached
*/
uint8_t
usb2_ether_pause(struct usb2_ether *ue, unsigned int _ticks)
{
if (usb2_proc_is_gone(&ue->ue_tq)) {
/* nothing to do */
return (1);
}
usb2_pause_mtx(ue->ue_mtx, _ticks);
return (0);
}
static void
ue_queue_command(struct usb2_ether *ue,
usb2_proc_callback_t *fn,
struct usb2_proc_msg *t0, struct usb2_proc_msg *t1)
{
struct usb2_ether_cfg_task *task;
UE_LOCK_ASSERT(ue, MA_OWNED);
if (usb2_proc_is_gone(&ue->ue_tq)) {
return; /* nothing to do */
}
/*
* NOTE: The task cannot get executed before we drop the
* "sc_mtx" mutex. It is safe to update fields in the message
* structure after that the message got queued.
*/
task = (struct usb2_ether_cfg_task *)
usb2_proc_msignal(&ue->ue_tq, t0, t1);
/* Setup callback and self pointers */
task->hdr.pm_callback = fn;
task->ue = ue;
/*
* Start and stop must be synchronous!
*/
if ((fn == ue_start_task) || (fn == ue_stop_task))
usb2_proc_mwait(&ue->ue_tq, t0, t1);
}
struct ifnet *
usb2_ether_getifp(struct usb2_ether *ue)
{
return (ue->ue_ifp);
}
struct mii_data *
usb2_ether_getmii(struct usb2_ether *ue)
{
return (device_get_softc(ue->ue_miibus));
}
void *
usb2_ether_getsc(struct usb2_ether *ue)
{
return (ue->ue_sc);
}
static int
ue_sysctl_parent(SYSCTL_HANDLER_ARGS)
{
struct usb2_ether *ue = arg1;
const char *name;
name = device_get_nameunit(ue->ue_dev);
return SYSCTL_OUT(req, name, strlen(name));
}
int
usb2_ether_ifattach(struct usb2_ether *ue)
{
int error;
/* check some critical parameters */
if ((ue->ue_dev == NULL) ||
(ue->ue_udev == NULL) ||
(ue->ue_mtx == NULL) ||
(ue->ue_methods == NULL))
return (EINVAL);
error = usb2_proc_create(&ue->ue_tq, ue->ue_mtx,
device_get_nameunit(ue->ue_dev), USB_PRI_MED);
if (error) {
device_printf(ue->ue_dev, "could not setup taskqueue\n");
goto error;
}
/* fork rest of the attach code */
UE_LOCK(ue);
ue_queue_command(ue, ue_attach_post_task,
&ue->ue_sync_task[0].hdr,
&ue->ue_sync_task[1].hdr);
UE_UNLOCK(ue);
error:
return (error);
}
static void
ue_attach_post_task(struct usb2_proc_msg *_task)
{
struct usb2_ether_cfg_task *task =
(struct usb2_ether_cfg_task *)_task;
struct usb2_ether *ue = task->ue;
struct ifnet *ifp;
int error;
char num[14]; /* sufficient for 32 bits */
/* first call driver's post attach routine */
ue->ue_methods->ue_attach_post(ue);
UE_UNLOCK(ue);
ue->ue_unit = alloc_unr(ueunit);
usb2_callout_init_mtx(&ue->ue_watchdog, ue->ue_mtx, 0);
sysctl_ctx_init(&ue->ue_sysctl_ctx);
ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
device_printf(ue->ue_dev, "could not allocate ifnet\n");
goto error;
}
ifp->if_softc = ue;
if_initname(ifp, "ue", ue->ue_unit);
ifp->if_mtu = ETHERMTU;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
if (ue->ue_methods->ue_ioctl != NULL)
ifp->if_ioctl = ue->ue_methods->ue_ioctl;
else
ifp->if_ioctl = usb2_ether_ioctl;
ifp->if_start = ue_start;
ifp->if_init = ue_init;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_READY(&ifp->if_snd);
ue->ue_ifp = ifp;
if (ue->ue_methods->ue_mii_upd != NULL &&
ue->ue_methods->ue_mii_sts != NULL) {
mtx_lock(&Giant); /* device_xxx() depends on this */
error = mii_phy_probe(ue->ue_dev, &ue->ue_miibus,
ue_ifmedia_upd, ue->ue_methods->ue_mii_sts);
mtx_unlock(&Giant);
if (error) {
device_printf(ue->ue_dev, "MII without any PHY\n");
goto error;
}
}
if_printf(ifp, "<USB Ethernet> on %s\n", device_get_nameunit(ue->ue_dev));
ether_ifattach(ifp, ue->ue_eaddr);
snprintf(num, sizeof(num), "%u", ue->ue_unit);
ue->ue_sysctl_oid = SYSCTL_ADD_NODE(&ue->ue_sysctl_ctx,
&SYSCTL_NODE_CHILDREN(_net, ue),
OID_AUTO, num, CTLFLAG_RD, NULL, "");
SYSCTL_ADD_PROC(&ue->ue_sysctl_ctx,
SYSCTL_CHILDREN(ue->ue_sysctl_oid), OID_AUTO,
"%parent", CTLFLAG_RD, ue, 0,
ue_sysctl_parent, "A", "parent device");
UE_LOCK(ue);
return;
error:
free_unr(ueunit, ue->ue_unit);
if (ue->ue_ifp != NULL) {
if_free(ue->ue_ifp);
ue->ue_ifp = NULL;
}
UE_LOCK(ue);
return;
}
void
usb2_ether_ifdetach(struct usb2_ether *ue)
{
struct ifnet *ifp;
/* wait for any post attach or other command to complete */
usb2_proc_drain(&ue->ue_tq);
/* read "ifnet" pointer after taskqueue drain */
ifp = ue->ue_ifp;
if (ifp != NULL) {
/* we are not running any more */
UE_LOCK(ue);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
UE_UNLOCK(ue);
/* drain any callouts */
usb2_callout_drain(&ue->ue_watchdog);
/* detach miibus */
if (ue->ue_miibus != NULL) {
mtx_lock(&Giant); /* device_xxx() depends on this */
device_delete_child(ue->ue_dev, ue->ue_miibus);
mtx_unlock(&Giant);
}
/* detach ethernet */
ether_ifdetach(ifp);
/* free interface instance */
if_free(ifp);
/* free sysctl */
sysctl_ctx_free(&ue->ue_sysctl_ctx);
/* free unit */
free_unr(ueunit, ue->ue_unit);
}
/* free taskqueue, if any */
usb2_proc_free(&ue->ue_tq);
}
void
usb2_ether_ifshutdown(struct usb2_ether *ue)
{
struct ifnet *ifp = ue->ue_ifp;
UE_LOCK(ue);
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
ue_queue_command(ue, ue_stop_task,
&ue->ue_sync_task[0].hdr,
&ue->ue_sync_task[1].hdr);
UE_UNLOCK(ue);
}
uint8_t
usb2_ether_is_gone(struct usb2_ether *ue)
{
return (usb2_proc_is_gone(&ue->ue_tq));
}
static void
ue_init(void *arg)
{
struct usb2_ether *ue = arg;
UE_LOCK(ue);
ue_queue_command(ue, ue_start_task,
&ue->ue_sync_task[0].hdr,
&ue->ue_sync_task[1].hdr);
UE_UNLOCK(ue);
}
static void
ue_start_task(struct usb2_proc_msg *_task)
{
struct usb2_ether_cfg_task *task =
(struct usb2_ether_cfg_task *)_task;
struct usb2_ether *ue = task->ue;
struct ifnet *ifp = ue->ue_ifp;
UE_LOCK_ASSERT(ue, MA_OWNED);
ue->ue_methods->ue_init(ue);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return;
if (ue->ue_methods->ue_tick != NULL)
usb2_callout_reset(&ue->ue_watchdog, hz, ue_watchdog, ue);
}
static void
ue_stop_task(struct usb2_proc_msg *_task)
{
struct usb2_ether_cfg_task *task =
(struct usb2_ether_cfg_task *)_task;
struct usb2_ether *ue = task->ue;
UE_LOCK_ASSERT(ue, MA_OWNED);
usb2_callout_stop(&ue->ue_watchdog);
ue->ue_methods->ue_stop(ue);
}
static void
ue_start(struct ifnet *ifp)
{
struct usb2_ether *ue = ifp->if_softc;
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return;
UE_LOCK(ue);
ue->ue_methods->ue_start(ue);
UE_UNLOCK(ue);
}
static void
ue_promisc_task(struct usb2_proc_msg *_task)
{
struct usb2_ether_cfg_task *task =
(struct usb2_ether_cfg_task *)_task;
struct usb2_ether *ue = task->ue;
ue->ue_methods->ue_setpromisc(ue);
}
static void
ue_setmulti_task(struct usb2_proc_msg *_task)
{
struct usb2_ether_cfg_task *task =
(struct usb2_ether_cfg_task *)_task;
struct usb2_ether *ue = task->ue;
ue->ue_methods->ue_setmulti(ue);
}
static int
ue_ifmedia_upd(struct ifnet *ifp)
{
struct usb2_ether *ue = ifp->if_softc;
/* Defer to process context */
UE_LOCK(ue);
ue_queue_command(ue, ue_ifmedia_task,
&ue->ue_media_task[0].hdr,
&ue->ue_media_task[1].hdr);
UE_UNLOCK(ue);
return (0);
}
static void
ue_ifmedia_task(struct usb2_proc_msg *_task)
{
struct usb2_ether_cfg_task *task =
(struct usb2_ether_cfg_task *)_task;
struct usb2_ether *ue = task->ue;
struct ifnet *ifp = ue->ue_ifp;
ue->ue_methods->ue_mii_upd(ifp);
}
static void
ue_watchdog(void *arg)
{
struct usb2_ether *ue = arg;
struct ifnet *ifp = ue->ue_ifp;
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return;
ue_queue_command(ue, ue_tick_task,
&ue->ue_tick_task[0].hdr,
&ue->ue_tick_task[1].hdr);
usb2_callout_reset(&ue->ue_watchdog, hz, ue_watchdog, ue);
}
static void
ue_tick_task(struct usb2_proc_msg *_task)
{
struct usb2_ether_cfg_task *task =
(struct usb2_ether_cfg_task *)_task;
struct usb2_ether *ue = task->ue;
struct ifnet *ifp = ue->ue_ifp;
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return;
ue->ue_methods->ue_tick(ue);
}
int
usb2_ether_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
{
struct usb2_ether *ue = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
struct mii_data *mii;
int error = 0;
switch (command) {
case SIOCSIFFLAGS:
UE_LOCK(ue);
if (ifp->if_flags & IFF_UP) {
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
ue_queue_command(ue, ue_promisc_task,
&ue->ue_promisc_task[0].hdr,
&ue->ue_promisc_task[1].hdr);
else
ue_queue_command(ue, ue_start_task,
&ue->ue_sync_task[0].hdr,
&ue->ue_sync_task[1].hdr);
} else {
ue_queue_command(ue, ue_stop_task,
&ue->ue_sync_task[0].hdr,
&ue->ue_sync_task[1].hdr);
}
UE_UNLOCK(ue);
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
UE_LOCK(ue);
ue_queue_command(ue, ue_setmulti_task,
&ue->ue_multi_task[0].hdr,
&ue->ue_multi_task[1].hdr);
UE_UNLOCK(ue);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
if (ue->ue_miibus != NULL) {
mii = device_get_softc(ue->ue_miibus);
error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
} else
error = ether_ioctl(ifp, command, data);
break;
default:
error = ether_ioctl(ifp, command, data);
break;
}
return (error);
}
static int
usb2_ether_modevent(module_t mod, int type, void *data)
{
switch (type) {
case MOD_LOAD:
ueunit = new_unrhdr(0, INT_MAX, NULL);
break;
case MOD_UNLOAD:
break;
default:
return (EOPNOTSUPP);
}
return (0);
}
static moduledata_t usb2_ether_mod = {
"usb2_ethernet",
usb2_ether_modevent,
0
};
int
usb2_ether_rxmbuf(struct usb2_ether *ue, struct mbuf *m,
unsigned int len)
{
struct ifnet *ifp = ue->ue_ifp;
UE_LOCK_ASSERT(ue, MA_OWNED);
/* finalize mbuf */
ifp->if_ipackets++;
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = m->m_len = len;
/* enqueue for later when the lock can be released */
_IF_ENQUEUE(&ue->ue_rxq, m);
return (0);
}
int
usb2_ether_rxbuf(struct usb2_ether *ue, struct usb2_page_cache *pc,
unsigned int offset, unsigned int len)
{
struct ifnet *ifp = ue->ue_ifp;
struct mbuf *m;
UE_LOCK_ASSERT(ue, MA_OWNED);
if (len < ETHER_HDR_LEN || len > MCLBYTES)
return (1);
m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
if (m) {
m->m_len = m->m_pkthdr.len = MCLBYTES;
m_adj(m, ETHER_ALIGN);
if (m == NULL) {
ifp->if_ierrors++;
return (ENOMEM);
}
return (m);
m_adj(m, ETHER_ALIGN);
usb2_copy_out(pc, offset, mtod(m, uint8_t *), len);
/* finalize mbuf */
ifp->if_ipackets++;
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = m->m_len = len;
/* enqueue for later when the lock can be released */
_IF_ENQUEUE(&ue->ue_rxq, m);
return (0);
}
/*------------------------------------------------------------------------*
* usb2_ether_cc - common ethernet config copy
*------------------------------------------------------------------------*/
void
usb2_ether_cc(struct ifnet *ifp, usb2_ether_mchash_t *fhash,
struct usb2_ether_cc *cc)
usb2_ether_rxflush(struct usb2_ether *ue)
{
struct ifmultiaddr *ifma;
uint8_t i;
struct ifnet *ifp = ue->ue_ifp;
struct mbuf *m;
if (ifp == NULL) {
/* Nothing to do */
return;
}
/* Copy interface flags */
UE_LOCK_ASSERT(ue, MA_OWNED);
cc->if_flags = ifp->if_flags;
for (;;) {
_IF_DEQUEUE(&ue->ue_rxq, m);
if (m == NULL)
break;
/* Copy link layer address */
for (i = 0; i != ETHER_ADDR_LEN; i++) {
cc->if_lladdr[i] = IF_LLADDR(ifp)[i];
}
/* Check hash filter disable bits */
if ((ifp->if_flags & IFF_ALLMULTI) ||
(ifp->if_flags & IFF_PROMISC)) {
memset(cc->if_hash, 0xFF, sizeof(cc->if_hash));
} else if (fhash) {
/* Compute hash bits for multicast filter */
IF_ADDR_LOCK(ifp);
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK) {
continue;
}
fhash(cc, LLADDR((struct sockaddr_dl *)
(ifma->ifma_addr)));
}
IF_ADDR_UNLOCK(ifp);
/* Compute hash bits for broadcast address */
if (ifp->if_flags & IFF_BROADCAST) {
fhash(cc, ifp->if_broadcastaddr);
}
/*
* The USB xfer has been resubmitted so its safe to unlock now.
*/
UE_UNLOCK(ue);
ifp->if_input(ifp, m);
UE_LOCK(ue);
}
}
DECLARE_MODULE(usb2_ethernet, usb2_ether_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
MODULE_VERSION(usb2_ethernet, 1);
MODULE_DEPEND(usb2_ethernet, usb2_core, 1, 1, 1);

View File

@ -34,6 +34,7 @@
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/limits.h>
#include <net/if.h>
#include <net/if_arp.h>
@ -48,21 +49,74 @@
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
#define USB_ETHER_HASH_MAX 64 /* bytes */
struct usb2_ether;
struct usb2_device_request;
typedef void (usb2_ether_fn_t)(struct usb2_ether *);
struct usb2_ether_methods {
usb2_ether_fn_t *ue_attach_post;
usb2_ether_fn_t *ue_start;
usb2_ether_fn_t *ue_init;
usb2_ether_fn_t *ue_stop;
usb2_ether_fn_t *ue_setmulti;
usb2_ether_fn_t *ue_setpromisc;
usb2_ether_fn_t *ue_tick;
int (*ue_mii_upd)(struct ifnet *);
void (*ue_mii_sts)(struct ifnet *,
struct ifmediareq *);
int (*ue_ioctl)(struct ifnet *, u_long, caddr_t);
struct usb2_ether_cc {
uint32_t if_flags;
uint16_t if_rxfilt;
uint8_t if_lladdr[ETHER_ADDR_LEN];
uint8_t if_mhash;
uint8_t if_nhash;
uint8_t if_hash[USB_ETHER_HASH_MAX];
};
typedef void (usb2_ether_mchash_t)(struct usb2_ether_cc *cc, const uint8_t *ptr);
struct usb2_ether_cfg_task {
struct usb2_proc_msg hdr;
struct usb2_ether *ue;
};
struct mbuf *usb2_ether_get_mbuf(void);
void usb2_ether_cc(struct ifnet *ifp, usb2_ether_mchash_t *fhash,
struct usb2_ether_cc *cc);
struct usb2_ether {
/* NOTE: the "ue_ifp" pointer must be first --hps */
struct ifnet *ue_ifp;
struct mtx *ue_mtx;
const struct usb2_ether_methods *ue_methods;
struct sysctl_oid *ue_sysctl_oid;
void *ue_sc;
struct usb2_device *ue_udev; /* used by usb2_ether_do_request() */
device_t ue_dev;
device_t ue_miibus;
struct usb2_process ue_tq;
struct sysctl_ctx_list ue_sysctl_ctx;
struct ifqueue ue_rxq;
struct usb2_callout ue_watchdog;
struct usb2_ether_cfg_task ue_sync_task[2];
struct usb2_ether_cfg_task ue_media_task[2];
struct usb2_ether_cfg_task ue_multi_task[2];
struct usb2_ether_cfg_task ue_promisc_task[2];
struct usb2_ether_cfg_task ue_tick_task[2];
int ue_unit;
/* ethernet address from eeprom */
uint8_t ue_eaddr[ETHER_ADDR_LEN];
};
#define usb2_ether_do_request(ue,req,data,timo) \
usb2_do_request_proc((ue)->ue_udev,&(ue)->ue_tq,req,data,0,NULL,timo)
uint8_t usb2_ether_pause(struct usb2_ether *, unsigned int);
struct ifnet *usb2_ether_getifp(struct usb2_ether *);
struct mii_data *usb2_ether_getmii(struct usb2_ether *);
void *usb2_ether_getsc(struct usb2_ether *);
int usb2_ether_ifattach(struct usb2_ether *);
void usb2_ether_ifdetach(struct usb2_ether *);
int usb2_ether_ioctl(struct ifnet *, u_long, caddr_t);
int usb2_ether_rxmbuf(struct usb2_ether *, struct mbuf *,
unsigned int);
int usb2_ether_rxbuf(struct usb2_ether *,
struct usb2_page_cache *,
unsigned int, unsigned int);
void usb2_ether_rxflush(struct usb2_ether *);
void usb2_ether_ifshutdown(struct usb2_ether *);
uint8_t usb2_ether_is_gone(struct usb2_ether *);
#endif /* _USB2_ETHERNET_H_ */

View File

@ -188,18 +188,4 @@ struct usb2_cdc_notification {
#define UCDC_MDM_PARITY_ERR 0x20
#define UCDC_MDM_OVERRUN_ERR 0x40
/* 512x4 Multi Frame Ethernet Header */
struct usb2_cdc_mf_eth_512x4_header {
uByte bSig[2]; /* "FL" - Frag List */
uByte bReserved[4];
uWord wFragLength[511 * 4];
#define CDCE_512X4_FRAG_LENGTH_OFFSET 6 /* bytes */
#define CDCE_512X4_FRAG_LAST_MASK 0x8000
#define CDCE_512X4_FRAG_LENGTH_MASK 0x1FFF /* bytes */
#define CDCE_512X4_FRAME_FRAG_MAX 4 /* fragments */
#define CDCE_512X4_FRAMES_MAX 511 /* frames */
#define CDCE_512X4_FRAGS_MAX (511 * 4) /* fragments */
uWord wPadding; /* used to make transfer short */
} __packed;
#endif /* _USB_CDC_H_ */

View File

@ -43,7 +43,6 @@ enum {
STRING_LANG_INDEX,
STRING_MAC_INDEX,
STRING_ETH_CONTROL_INDEX,
STRING_ETH_CONTROL_512X4_INDEX,
STRING_ETH_DATA_INDEX,
STRING_ETH_CONFIG_INDEX,
STRING_ETH_VENDOR_INDEX,
@ -69,24 +68,6 @@ enum {
't', 0, 'e', 0, 'r', 0, 'f', 0, \
'a', 0, 'c', 0, 'e', 0,
/*
* Hardware Accelerated Zero Copy CDC ethernet. Buffer capacity: 512
* frames by 4 fragments per USB transfer.
*/
#define STRING_ETH_512X4_CONTROL \
'U', 0, 'S', 0, 'B', 0, ' ', 0, \
'E', 0, 't', 0, 'h', 0, 'e', 0, \
'r', 0, 'n', 0, 'e', 0, 't', 0, \
' ', 0, 'C', 0, 'o', 0, 'm', 0, \
'm', 0, ' ', 0, 'i', 0, 'n', 0, \
't', 0, 'e', 0, 'r', 0, 'f', 0, \
'a', 0, 'c', 0, 'e', 0, ' ', 0, \
'5', 0, '1', 0, '2', 0, 'x', 0, \
'4', 0, ' ', 0, 'H', 0, 'W', 0, \
' ', 0, 'A', 0, 'c', 0, 'c', 0, \
'e', 0, 'l', 0, 'e', 0, 'r', 0, \
'a', 0, 't', 0, 'e', 0, 'd', 0,
#define STRING_ETH_DATA \
'U', 0, 'S', 0, 'B', 0, ' ', 0, \
'E', 0, 't', 0, 'h', 0, 'e', 0, \
@ -127,7 +108,6 @@ enum {
USB_MAKE_STRING_DESC(STRING_LANG, string_lang);
USB_MAKE_STRING_DESC(STRING_MAC, string_mac);
USB_MAKE_STRING_DESC(STRING_ETH_CONTROL, string_eth_control);
USB_MAKE_STRING_DESC(STRING_ETH_512X4_CONTROL, string_eth_512x4_control);
USB_MAKE_STRING_DESC(STRING_ETH_DATA, string_eth_data);
USB_MAKE_STRING_DESC(STRING_ETH_CONFIG, string_eth_config);
USB_MAKE_STRING_DESC(STRING_ETH_VENDOR, string_eth_vendor);
@ -222,17 +202,6 @@ static const struct usb2_temp_interface_desc eth_control_interface = {
.iInterface = STRING_ETH_CONTROL_INDEX,
};
static const struct usb2_temp_interface_desc eth_control_if_512x4 = {
.ppEndpoints = eth_intr_endpoints,
.ppRawDesc = eth_control_if_desc,
.bInterfaceClass = UICLASS_CDC,
.bInterfaceSubClass = UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL,
.bInterfaceProtocol = UIPROTO_CDC_ETH_512X4,
.iInterface = STRING_ETH_CONTROL_512X4_INDEX,
.isAltInterface = 1, /* this is an alternate setting */
};
static const struct usb2_temp_endpoint_desc *eth_data_endpoints[] = {
&bulk_in_ep,
&bulk_out_ep,
@ -258,7 +227,6 @@ static const struct usb2_temp_interface_desc eth_data_interface = {
static const struct usb2_temp_interface_desc *eth_interfaces[] = {
&eth_control_interface,
&eth_control_if_512x4,
&eth_data_null_interface,
&eth_data_interface,
NULL,
@ -304,7 +272,6 @@ eth_get_string_desc(uint16_t lang_id, uint8_t string_index)
[STRING_LANG_INDEX] = &string_lang,
[STRING_MAC_INDEX] = &string_mac,
[STRING_ETH_CONTROL_INDEX] = &string_eth_control,
[STRING_ETH_CONTROL_512X4_INDEX] = &string_eth_512x4_control,
[STRING_ETH_DATA_INDEX] = &string_eth_data,
[STRING_ETH_CONFIG_INDEX] = &string_eth_config,
[STRING_ETH_VENDOR_INDEX] = &string_eth_vendor,