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:
parent
1267fde951
commit
cf8291f423
File diff suppressed because it is too large
Load Diff
@ -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
@ -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
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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
@ -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
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
@ -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[] = {
|
||||
ð_control_interface,
|
||||
ð_control_if_512x4,
|
||||
ð_data_null_interface,
|
||||
ð_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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user