- add power management code.

- use ether_ioctl instead of its own code.
  (make ifconfig down works properly.)
This commit is contained in:
yamt 2001-11-26 11:14:50 +00:00
parent e75321130b
commit 7af704bf48
2 changed files with 159 additions and 72 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: cs89x0.c,v 1.21 2001/11/24 20:18:55 yamt Exp $ */
/* $NetBSD: cs89x0.c,v 1.22 2001/11/26 11:14:50 yamt Exp $ */
/*
* Copyright 1997
@ -186,7 +186,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cs89x0.c,v 1.21 2001/11/24 20:18:55 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: cs89x0.c,v 1.22 2001/11/26 11:14:50 yamt Exp $");
#include "opt_inet.h"
@ -249,7 +249,7 @@ void cs_get_default_media __P((struct cs_softc *));
int cs_get_params __P((struct cs_softc *));
int cs_get_enaddr __P((struct cs_softc *));
int cs_reset_chip __P((struct cs_softc *));
int cs_init __P((struct cs_softc *));
int cs_init __P((struct ifnet *));
void cs_reset __P((void *));
int cs_ioctl __P((struct ifnet *, u_long, caddr_t));
void cs_initChip __P((struct cs_softc *));
@ -270,6 +270,11 @@ void cs_print_rx_errors __P((struct cs_softc *, u_int16_t));
int cs_mediachange __P((struct ifnet *));
void cs_mediastatus __P((struct ifnet *, struct ifmediareq *));
static int cs_enable __P((struct cs_softc *));
static void cs_disable __P((struct cs_softc *));
static void cs_stop __P((struct ifnet *, int));
static void cs_power __P((int, void *));
/*
* GLOBAL DECLARATIONS
*/
@ -377,7 +382,9 @@ cs_attach(sc, enaddr, media, nmedia, defmedia)
strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
ifp->if_softc = sc;
ifp->if_start = cs_start_output;
ifp->if_init = cs_init;
ifp->if_ioctl = cs_ioctl;
ifp->if_stop = cs_stop;
ifp->if_watchdog = NULL; /* no watchdog at this stage */
ifp->if_flags = IFF_SIMPLEX | IFF_NOTRAILERS |
IFF_BROADCAST | IFF_MULTICAST;
@ -511,6 +518,11 @@ cs_attach(sc, enaddr, media, nmedia, defmedia)
return 1;
}
sc->sc_powerhook = powerhook_establish(cs_power, sc);
if (sc->sc_powerhook == 0)
printf("%s: warning: powerhook_establish failed\n",
sc->sc_dev.dv_xname);
return 0;
}
@ -520,6 +532,11 @@ cs_detach(sc)
{
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
if (sc->sc_powerhook) {
powerhook_disestablish(sc->sc_powerhook);
sc->sc_powerhook = 0;
}
if (sc->sc_cfgflags & CFGFLG_ATTACHED) {
#if NRND > 0
rnd_detach_source(&sc->rnd_source);
@ -1027,16 +1044,24 @@ cs_initChip(sc)
}
int
cs_init(sc)
struct cs_softc *sc;
cs_init(ifp)
struct ifnet *ifp;
{
int intState;
int error = CS_OK;
struct cs_softc *sc = ifp->if_softc;
if (cs_enable(sc))
goto out;
cs_stop(ifp, 0);
intState = splnet();
#if 0
/* Mark the interface as down */
sc->sc_ethercom.ec_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
#endif
#ifdef CS_DEBUG
/* Enable debugging */
@ -1048,8 +1073,8 @@ cs_init(sc)
/* Initialize the chip */
cs_initChip(sc);
/* Mark the interface as up and running */
sc->sc_ethercom.ec_if.if_flags |= (IFF_UP | IFF_RUNNING);
/* Mark the interface as running */
sc->sc_ethercom.ec_if.if_flags |= IFF_RUNNING;
sc->sc_ethercom.ec_if.if_flags &= ~IFF_OACTIVE;
sc->sc_ethercom.ec_if.if_timer = 0;
@ -1060,7 +1085,10 @@ cs_init(sc)
}
splx(intState);
return error;
out:
if (error == CS_OK)
return 0;
return EIO;
}
void
@ -1209,7 +1237,6 @@ cs_ioctl(ifp, cmd, data)
caddr_t data;
{
struct cs_softc *sc = ifp->if_softc;
struct ifaddr *ifa = (struct ifaddr *) data;
struct ifreq *ifr = (struct ifreq *) data;
int state;
int result;
@ -1219,70 +1246,23 @@ cs_ioctl(ifp, cmd, data)
result = 0; /* only set if something goes wrong */
switch (cmd) {
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
cs_init(sc);
arp_ifinit(ifp, ifa);
break;
#endif
default:
cs_init(sc);
break;
}
break;
case SIOCSIFFLAGS:
if ((ifp->if_flags & IFF_UP) == 0 &&
(ifp->if_flags & IFF_RUNNING) != 0) {
/*
* If interface is marked down and it is running,
* then stop it.
*/
cs_reset_chip(sc);
ifp->if_flags &= ~IFF_RUNNING;
} else if ((ifp->if_flags & IFF_UP) != 0 &&
(ifp->if_flags & IFF_RUNNING) == 0) {
/*
* If interface is marked up and it is stopped,
* start it.
*/
cs_init(sc);
} else {
/*
* Reset the interface to pick up any changes in
* any other flags that affect hardware registers.
*/
cs_init(sc);
}
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
result = (cmd == SIOCADDMULTI) ?
ether_addmulti(ifr, &sc->sc_ethercom) :
ether_delmulti(ifr, &sc->sc_ethercom);
if (result == ENETRESET) {
/*
* Multicast list has changed; set the hardware filter
* accordingly.
*/
cs_init(sc);
result = 0;
}
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
result = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
break;
default:
result = EINVAL;
result = ether_ioctl(ifp, cmd, data);
if (result == ENETRESET) {
if (CS_IS_ENABLED(sc)) {
/*
* Multicast list has changed. Set the
* hardware filter accordingly.
*/
cs_set_ladr_filt(sc, &sc->sc_ethercom);
}
result = 0;
}
break;
}
@ -1300,7 +1280,7 @@ cs_mediachange(ifp)
* Current media is already set up. Just reset the interface
* to let the new value take hold.
*/
cs_init((struct cs_softc *)ifp->if_softc);
cs_init(ifp);
return (0);
}
@ -1804,7 +1784,7 @@ cs_process_rx_dma(sc)
isa_dmaabort(sc->sc_ic, sc->sc_drq);
/* now reset the chip and reinitialise */
cs_init(sc);
cs_init(&sc->sc_ethercom.ec_if);
return;
}
/* Check the status of the received packet. */
@ -1830,7 +1810,7 @@ cs_process_rx_dma(sc)
* now reset the chip and
* reinitialise
*/
cs_init(sc);
cs_init(&sc->sc_ethercom.ec_if);
return;
}
/*
@ -1852,7 +1832,7 @@ cs_process_rx_dma(sc)
* now reset the chip and
* reinitialise
*/
cs_init(sc);
cs_init(&sc->sc_ethercom.ec_if);
return;
}
m->m_pkthdr.rcvif = ifp;
@ -2308,3 +2288,101 @@ cs_copy_tx_frame(sc, m0)
}
}
}
static int
cs_enable(sc)
struct cs_softc *sc;
{
if (!CS_IS_ENABLED(sc) && sc->sc_enable) {
int error;
error = (*sc->sc_enable)(sc);
if (error)
return error;
sc->sc_cfgflags |= CFGFLG_ENABLED;
}
return 0;
}
static void
cs_disable(sc)
struct cs_softc *sc;
{
if (CS_IS_ENABLED(sc) && sc->sc_disable) {
(*sc->sc_disable)(sc);
sc->sc_cfgflags &= ~CFGFLG_ENABLED;
}
}
static void
cs_stop(ifp, disable)
struct ifnet *ifp;
int disable;
{
struct cs_softc *sc = ifp->if_softc;
CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, 0);
CS_WRITE_PACKET_PAGE(sc, PKTPG_TX_CFG, 0);
CS_WRITE_PACKET_PAGE(sc, PKTPG_BUF_CFG, 0);
CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, 0);
if (disable) {
cs_disable(sc);
}
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
}
int
cs_activate(self, act)
struct device *self;
enum devact act;
{
struct cs_softc *sc = (void *)self;
int s, error = 0;
s = splnet();
switch (act) {
case DVACT_ACTIVATE:
error = EOPNOTSUPP;
break;
case DVACT_DEACTIVATE:
if_deactivate(&sc->sc_ethercom.ec_if);
break;
}
splx(s);
return error;
}
static void
cs_power(why, arg)
int why;
void *arg;
{
struct cs_softc *sc = arg;
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
int s;
s = splnet();
switch (why) {
case PWR_STANDBY:
case PWR_SUSPEND:
cs_stop(ifp, 1);
break;
case PWR_RESUME:
if (ifp->if_flags & IFF_UP) {
cs_init(ifp);
}
break;
case PWR_SOFTSUSPEND:
case PWR_SOFTSTANDBY:
case PWR_SOFTRESUME:
break;
}
splx(s);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: cs89x0var.h,v 1.10 2001/11/24 20:18:55 yamt Exp $ */
/* $NetBSD: cs89x0var.h,v 1.11 2001/11/26 11:14:50 yamt Exp $ */
/*
* Copyright 1997
@ -109,6 +109,11 @@ struct cs_softc {
#if NRND > 0
rndsource_element_t rnd_source; /* random source */
#endif
/* power management */
int (*sc_enable) __P((struct cs_softc *));
void (*sc_disable) __P((struct cs_softc *));
void *sc_powerhook;
};
@ -121,6 +126,7 @@ struct cs_softc {
#define CFGFLG_DMA_MODE 0x0020
#define CFGFLG_ATTACHED 0x0040 /* XXX should not be here? */
#define CFGFLG_CARDBUS_HACK 0x0080
#define CFGFLG_ENABLED 0x0100 /* XXX should not be here? */
#define CFGFLG_NOT_EEPROM 0x8000
@ -233,5 +239,8 @@ int cs_verify_eeprom __P((bus_space_tag_t, bus_space_handle_t));
int cs_read_eeprom __P((bus_space_tag_t, bus_space_handle_t, int,
u_int16_t *));
int cs_intr __P((void *));
int cs_activate __P((struct device *, enum devact));
#define CS_IS_ENABLED(sc) ((sc)->sc_cfgflags & CFGFLG_ENABLED)
#endif /* _DEV_ISA_CS89X0VAR_H_ */