summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2001-03-03 08:31:37 +0000
committerimp <imp@FreeBSD.org>2001-03-03 08:31:37 +0000
commitc2257f6c8a69b4a7cae98128bd89f28f3893f3c5 (patch)
tree6a6e8077b17a02e0d83e4b1fad4660dd6562ccad /sys/dev
parent5f89669270bed456c02457eab0709fc74466f733 (diff)
downloadFreeBSD-src-c2257f6c8a69b4a7cae98128bd89f28f3893f3c5.zip
FreeBSD-src-c2257f6c8a69b4a7cae98128bd89f28f3893f3c5.tar.gz
Add support for Dlink DL10022 to the ed driver. This is a mii part
bolted to a ne-2000 chip. This is necessary for the NetGear FA-410TX and other cards. This also requires you add mii to your kernel if you have an ed driver configured. This code will result in a couple of timeout messages for ed on the impacted cards. Additional work will be needed, but this does work right now, and many people need these cards. Submitted by: Ian Dowse <iedowse@maths.tcd.ie>
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ed/if_ed.c144
-rw-r--r--sys/dev/ed/if_ed_pccard.c94
-rw-r--r--sys/dev/ed/if_ed_pci.c1
-rw-r--r--sys/dev/ed/if_edreg.h29
-rw-r--r--sys/dev/ed/if_edvar.h9
5 files changed, 277 insertions, 0 deletions
diff --git a/sys/dev/ed/if_ed.c b/sys/dev/ed/if_ed.c
index 604c287..11843d7 100644
--- a/sys/dev/ed/if_ed.c
+++ b/sys/dev/ed/if_ed.c
@@ -41,6 +41,7 @@
#include <sys/systm.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
+#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/syslog.h>
@@ -55,6 +56,10 @@
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_mib.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
#include <net/bpf.h>
#include "opt_bdg.h"
@@ -74,6 +79,7 @@ static int ed_ioctl __P((struct ifnet *, u_long, caddr_t));
static void ed_start __P((struct ifnet *));
static void ed_reset __P((struct ifnet *));
static void ed_watchdog __P((struct ifnet *));
+static void ed_tick __P((void *));
static void ds_getmcaf __P((struct ed_softc *, u_int32_t *));
@@ -1586,6 +1592,7 @@ ed_attach(sc, unit, flags)
{
struct ifnet *ifp = &sc->arpcom.ac_if;
+ callout_handle_init(&sc->tick_ch);
/*
* Set interface to stopped condition (reset)
*/
@@ -1695,6 +1702,8 @@ ed_stop(sc)
{
int n = 5000;
+ untimeout(ed_tick, sc, sc->tick_ch);
+ callout_handle_init(&sc->tick_ch);
if (sc->gone)
return;
/*
@@ -1729,6 +1738,27 @@ ed_watchdog(ifp)
ed_reset(ifp);
}
+static void
+ed_tick(arg)
+ void *arg;
+{
+ struct ed_softc *sc = arg;
+ struct mii_data *mii;
+ int s;
+
+ if (sc->gone) {
+ callout_handle_init(&sc->tick_ch);
+ return;
+ }
+ s = splimp();
+ if (sc->miibus != NULL) {
+ mii = device_get_softc(sc->miibus);
+ mii_tick(mii);
+ }
+ sc->tick_ch = timeout(ed_tick, sc, hz);
+ splx(s);
+}
+
/*
* Initialize device.
*/
@@ -1870,6 +1900,11 @@ ed_init(xsc)
}
}
+ if (sc->miibus != NULL) {
+ struct mii_data *mii;
+ mii = device_get_softc(sc->miibus);
+ mii_mediachg(mii);
+ }
/*
* Set 'running' flag, and clear output active flag.
*/
@@ -1881,6 +1916,8 @@ ed_init(xsc)
*/
ed_start(ifp);
+ untimeout(ed_tick, sc, sc->tick_ch);
+ sc->tick_ch = timeout(ed_tick, sc, hz);
(void) splx(s);
}
@@ -2492,6 +2529,8 @@ ed_ioctl(ifp, command, data)
caddr_t data;
{
struct ed_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct mii_data *mii;
int s, error = 0;
if (sc == NULL || sc->gone) {
@@ -2554,6 +2593,16 @@ ed_ioctl(ifp, command, data)
error = 0;
break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ if (sc->miibus == NULL) {
+ error = EINVAL;
+ break;
+ }
+ mii = device_get_softc(sc->miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+
default:
error = EINVAL;
}
@@ -3173,6 +3222,101 @@ ed_hpp_write_mbufs(struct ed_softc *sc, struct mbuf *m, int dst)
return (total_len);
}
+/*
+ * MII bus support routines.
+ */
+int
+ed_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct ed_softc *sc;
+ int val;
+ int failed;
+
+ sc = device_get_softc(dev);
+ if (sc->gone)
+ return 0;
+
+ (*sc->mii_writebits)(sc, 0xffffffff, 32);
+ (*sc->mii_writebits)(sc, ED_MII_STARTDELIM, ED_MII_STARTDELIM_BITS);
+ (*sc->mii_writebits)(sc, ED_MII_READOP, ED_MII_OP_BITS);
+ (*sc->mii_writebits)(sc, phy, ED_MII_PHY_BITS);
+ (*sc->mii_writebits)(sc, reg, ED_MII_REG_BITS);
+
+ failed = (*sc->mii_readbits)(sc, ED_MII_ACK_BITS);
+ val = (*sc->mii_readbits)(sc, ED_MII_DATA_BITS);
+ (*sc->mii_writebits)(sc, ED_MII_IDLE, ED_MII_IDLE_BITS);
+
+ return (failed ? 0 : val);
+}
+
+void
+ed_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ struct ed_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (sc->gone)
+ return;
+
+ (*sc->mii_writebits)(sc, 0xffffffff, 32);
+ (*sc->mii_writebits)(sc, ED_MII_STARTDELIM, ED_MII_STARTDELIM_BITS);
+ (*sc->mii_writebits)(sc, ED_MII_WRITEOP, ED_MII_OP_BITS);
+ (*sc->mii_writebits)(sc, phy, ED_MII_PHY_BITS);
+ (*sc->mii_writebits)(sc, reg, ED_MII_REG_BITS);
+ (*sc->mii_writebits)(sc, ED_MII_TURNAROUND, ED_MII_TURNAROUND_BITS);
+ (*sc->mii_writebits)(sc, data, ED_MII_DATA_BITS);
+ (*sc->mii_writebits)(sc, ED_MII_IDLE, ED_MII_IDLE_BITS);
+}
+
+int
+ed_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct ed_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ if (sc->gone || sc->miibus == NULL)
+ return (ENXIO);
+
+ mii = device_get_softc(sc->miibus);
+ return mii_mediachg(mii);
+}
+
+void
+ed_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct ed_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ if (sc->gone || sc->miibus == NULL)
+ return;
+
+ mii = device_get_softc(sc->miibus);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+}
+
+void
+ed_child_detached(dev, child)
+ device_t dev;
+ device_t child;
+{
+ struct ed_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (child == sc->miibus)
+ sc->miibus = NULL;
+}
+
static void
ed_setrcr(sc)
struct ed_softc *sc;
diff --git a/sys/dev/ed/if_ed_pccard.c b/sys/dev/ed/if_ed_pccard.c
index d579d16..23ef71d 100644
--- a/sys/dev/ed/if_ed_pccard.c
+++ b/sys/dev/ed/if_ed_pccard.c
@@ -44,13 +44,20 @@
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_mib.h>
+#include <net/if_media.h>
#include <dev/ed/if_edreg.h>
#include <dev/ed/if_edvar.h>
#include <dev/pccard/pccardvar.h>
#include <dev/pccard/pccarddevs.h>
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
#include "card_if.h"
+/* "device miibus" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+MODULE_DEPEND(ed, miibus, 1, 1, 1);
/*
* PC-Card (PCMCIA) specific code.
@@ -65,6 +72,10 @@ static int ed_pccard_ax88190(device_t dev);
static void ax88190_geteprom(struct ed_softc *);
static int ed_pccard_memwrite(device_t dev, off_t offset, u_char byte);
+static void ed_pccard_dlink_mii_reset(struct ed_softc *sc);
+static u_int ed_pccard_dlink_mii_readbits(struct ed_softc *sc, int nbits);
+static void ed_pccard_dlink_mii_writebits(struct ed_softc *sc, u_int val,
+ int nbits);
static int linksys;
/*
@@ -659,6 +670,13 @@ ed_pccard_Linksys(device_t dev)
sc->isa16bit = 1;
sc->type = ED_TYPE_NE2000;
sc->type_str = "Linksys";
+
+ /* Probe for an MII bus, but continue as normal if there isn't one. */
+ ed_pccard_dlink_mii_reset(sc);
+ sc->mii_readbits = ed_pccard_dlink_mii_readbits;
+ sc->mii_writebits = ed_pccard_dlink_mii_writebits;
+ mii_phy_probe(dev, &sc->miibus, ed_ifmedia_upd, ed_ifmedia_sts);
+
return (1);
}
@@ -694,12 +712,87 @@ ed_pccard_ax88190(device_t dev)
return (error);
}
+/* MII bit-twiddling routines for cards using Dlink chipset */
+#define DLINK_MIISET(sc, x) ed_asic_outb(sc, ED_DLINK_MIIBUS, \
+ ed_asic_inb(sc, ED_DLINK_MIIBUS) | (x))
+#define DLINK_MIICLR(sc, x) ed_asic_outb(sc, ED_DLINK_MIIBUS, \
+ ed_asic_inb(sc, ED_DLINK_MIIBUS) & ~(x))
+
+static void
+ed_pccard_dlink_mii_reset(sc)
+ struct ed_softc *sc;
+{
+ ed_asic_outb(sc, ED_DLINK_MIIBUS, 0);
+ DELAY(10);
+ DLINK_MIISET(sc, ED_DLINK_MII_RESET2);
+ DELAY(10);
+ DLINK_MIISET(sc, ED_DLINK_MII_RESET1);
+ DELAY(10);
+ DLINK_MIICLR(sc, ED_DLINK_MII_RESET1);
+ DELAY(10);
+ DLINK_MIICLR(sc, ED_DLINK_MII_RESET2);
+ DELAY(10);
+}
+
+static void
+ed_pccard_dlink_mii_writebits(sc, val, nbits)
+ struct ed_softc *sc;
+ u_int val;
+ int nbits;
+{
+ int i;
+
+ DLINK_MIISET(sc, ED_DLINK_MII_DIROUT);
+
+ for (i = nbits - 1; i >= 0; i--) {
+ if ((val >> i) & 1)
+ DLINK_MIISET(sc, ED_DLINK_MII_DATAOUT);
+ else
+ DLINK_MIICLR(sc, ED_DLINK_MII_DATAOUT);
+ DELAY(10);
+ DLINK_MIISET(sc, ED_DLINK_MII_CLK);
+ DELAY(10);
+ DLINK_MIICLR(sc, ED_DLINK_MII_CLK);
+ DELAY(10);
+ }
+}
+
+static u_int
+ed_pccard_dlink_mii_readbits(sc, nbits)
+ struct ed_softc *sc;
+ int nbits;
+{
+ int i;
+ u_int val = 0;
+
+ DLINK_MIICLR(sc, ED_DLINK_MII_DIROUT);
+
+ for (i = nbits - 1; i >= 0; i--) {
+ DLINK_MIISET(sc, ED_DLINK_MII_CLK);
+ DELAY(10);
+ val <<= 1;
+ if (ed_asic_inb(sc, ED_DLINK_MIIBUS) & ED_DLINK_MII_DATATIN)
+ val++;
+ DLINK_MIICLR(sc, ED_DLINK_MII_CLK);
+ DELAY(10);
+ }
+
+ return val;
+}
+
static device_method_t ed_pccard_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, pccard_compat_probe),
DEVMETHOD(device_attach, pccard_compat_attach),
DEVMETHOD(device_detach, ed_pccard_detach),
+ /* Bus interface */
+ DEVMETHOD(bus_child_detached, ed_child_detached),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, ed_miibus_readreg),
+ DEVMETHOD(miibus_writereg, ed_miibus_writereg),
+
/* Card interface */
DEVMETHOD(card_compat_match, ed_pccard_match),
DEVMETHOD(card_compat_probe, ed_pccard_probe),
@@ -714,3 +807,4 @@ static driver_t ed_pccard_driver = {
};
DRIVER_MODULE(if_ed, pccard, ed_pccard_driver, ed_devclass, 0, 0);
+DRIVER_MODULE(miibus, ed, miibus_driver, miibus_devclass, 0, 0);
diff --git a/sys/dev/ed/if_ed_pci.c b/sys/dev/ed/if_ed_pci.c
index 08d1e80..144ba82 100644
--- a/sys/dev/ed/if_ed_pci.c
+++ b/sys/dev/ed/if_ed_pci.c
@@ -21,6 +21,7 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/kernel.h>
diff --git a/sys/dev/ed/if_edreg.h b/sys/dev/ed/if_edreg.h
index e42ef42d2..a2e1882 100644
--- a/sys/dev/ed/if_edreg.h
+++ b/sys/dev/ed/if_edreg.h
@@ -1113,3 +1113,32 @@ struct ed_ring {
#define ED_AX88190_IOBASE0 0x3ca
#define ED_AX88190_IOBASE1 0x3cc
+
+/*
+ * MII bus definitions.
+ */
+#define ED_MII_STARTDELIM 0x01
+#define ED_MII_WRITEOP 0x01
+#define ED_MII_READOP 0x02
+#define ED_MII_TURNAROUND 0x02
+#define ED_MII_IDLE 0x01
+
+#define ED_MII_STARTDELIM_BITS 2
+#define ED_MII_OP_BITS 2
+#define ED_MII_PHY_BITS 5
+#define ED_MII_REG_BITS 5
+#define ED_MII_TURNAROUND_BITS 2
+#define ED_MII_DATA_BITS 16
+#define ED_MII_ACK_BITS 1
+#define ED_MII_IDLE_BITS 1
+
+/* Dlink chipset used on some Netgear and Dlink PCMCIA cards */
+#define ED_DLINK_MIIBUS 0x0c /* MII bus register on ASIC */
+
+#define ED_DLINK_MII_RESET1 0x04
+#define ED_DLINK_MII_RESET2 0x08
+
+#define ED_DLINK_MII_DATATIN 0x10
+#define ED_DLINK_MII_DIROUT 0x20
+#define ED_DLINK_MII_DATAOUT 0x40
+#define ED_DLINK_MII_CLK 0x80
diff --git a/sys/dev/ed/if_edvar.h b/sys/dev/ed/if_edvar.h
index d4e896f..8c58b64 100644
--- a/sys/dev/ed/if_edvar.h
+++ b/sys/dev/ed/if_edvar.h
@@ -49,6 +49,10 @@ struct ed_softc {
int irq_rid; /* resource id for irq */
struct resource* irq_res; /* resource for irq */
void* irq_handle; /* handle for irq handler */
+ device_t miibus; /* MII bus for cards with MII. */
+ void (*mii_writebits)__P((struct ed_softc *, u_int, int));
+ u_int (*mii_readbits)__P((struct ed_softc *, int));
+ struct callout_handle tick_ch; /* Callout handle for ed_tick */
int nic_offset; /* NIC (DS8390) I/O bus address offset */
int asic_offset; /* ASIC I/O bus address offset */
@@ -205,6 +209,11 @@ void ed_pio_readmem __P((struct ed_softc *, int, unsigned char *,
unsigned short));
void ed_pio_writemem __P((struct ed_softc *, char *,
unsigned short, unsigned short));
+int ed_miibus_readreg __P((device_t, int, int));
+void ed_miibus_writereg __P((device_t, int, int, int));
+int ed_ifmedia_upd __P((struct ifnet *));
+void ed_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
+void ed_child_detached __P((device_t, device_t));
driver_intr_t edintr;
OpenPOWER on IntegriCloud