MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver");
MODULE_LICENSE("GPL");
-#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
/*
Transceiver/media type.
*/
INT_MODULE_PARM(if_port, 0);
-/* Bit map of interrupts to choose from. */
-INT_MODULE_PARM(irq_mask, 0xdeb8);
-static int irq_list[4] = { -1 };
-MODULE_PARM(irq_list, "1-4i");
-
#ifdef PCMCIA_DEBUG
INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
static const char *version =
dev_node_t node;
struct sk_buff *saved_skb;
int packets_waiting;
- caddr_t base;
+ void __iomem *base;
u_short cfg;
struct timer_list media;
int watchdog, tx_err;
static void smc_set_xcvr(struct net_device *dev, int if_port);
static void smc_reset(struct net_device *dev);
static void media_check(u_long arg);
-static void mdio_sync(ioaddr_t addr);
+static void mdio_sync(kio_addr_t addr);
static int mdio_read(struct net_device *dev, int phy_id, int loc);
static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
static int smc_link_ok(struct net_device *dev);
+static struct ethtool_ops ethtool_ops;
/*======================================================================
struct smc_private *smc;
dev_link_t *link;
struct net_device *dev;
- int i, ret;
+ int ret;
DEBUG(0, "smc91c92_attach()\n");
link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
link->io.IOAddrLines = 4;
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
- link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
- if (irq_list[0] == -1)
- link->irq.IRQInfo2 = irq_mask;
- else
- for (i = 0; i < 4; i++)
- link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = &smc_interrupt;
link->irq.Instance = dev;
link->conf.Attributes = CONF_ENABLE_IRQ;
dev->open = &smc_open;
dev->stop = &smc_close;
dev->do_ioctl = &smc_ioctl;
+ SET_ETHTOOL_OPS(dev, ðtool_ops);
#ifdef HAVE_TX_TIMEOUT
dev->tx_timeout = smc_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
if (*linkp == NULL)
return;
+ if (link->dev)
+ unregister_netdev(dev);
+
if (link->state & DEV_CONFIG)
smc91c92_release(link);
/* Unlink device structure, free bits */
*linkp = link->next;
- if (link->dev)
- unregister_netdev(dev);
free_netdev(dev);
} /* smc91c92_detach */
{
struct net_device *dev = link->priv;
struct smc_private *smc = netdev_priv(dev);
- ioaddr_t ioaddr = dev->base_addr;
- ioaddr_t iouart = link->io.BasePort2;
+ kio_addr_t ioaddr = dev->base_addr;
+ kio_addr_t iouart = link->io.BasePort2;
/* Set UART base address and force map with COR bit 1 */
writeb(iouart & 0xff, smc->base + MOT_UART + CISREG_IOBASE_0);
static int mot_setup(dev_link_t *link)
{
struct net_device *dev = link->priv;
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
int i, wait, loop;
u_int addr;
static int osi_config(dev_link_t *link)
{
struct net_device *dev = link->priv;
- static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+ static kio_addr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
int i, j;
link->conf.Attributes |= CONF_ENABLE_SPKR;
static int check_sig(dev_link_t *link)
{
struct net_device *dev = link->priv;
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
int width;
u_short s;
u_short buf[32];
char *name;
int i, j, rev;
- ioaddr_t ioaddr;
+ kio_addr_t ioaddr;
u_long mir;
DEBUG(0, "smc91c92_config(0x%p)\n", link);
link->dev = &smc->node;
link->state &= ~DEV_CONFIG_PENDING;
+ SET_NETDEV_DEV(dev, &handle_to_dev(handle));
if (register_netdev(dev) != 0) {
printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
switch (event) {
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
- if (link->state & DEV_CONFIG) {
+ if (link->state & DEV_CONFIG)
netif_device_detach(dev);
- smc91c92_release(link);
- }
break;
case CS_EVENT_CARD_INSERTION:
link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT)
#define MDIO_DATA_READ 0x02
-static void mdio_sync(ioaddr_t addr)
+static void mdio_sync(kio_addr_t addr)
{
int bits;
for (bits = 0; bits < 32; bits++) {
static int mdio_read(struct net_device *dev, int phy_id, int loc)
{
- ioaddr_t addr = dev->base_addr + MGMT;
+ kio_addr_t addr = dev->base_addr + MGMT;
u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
int i, retval = 0;
static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
{
- ioaddr_t addr = dev->base_addr + MGMT;
+ kio_addr_t addr = dev->base_addr + MGMT;
u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
int i;
#ifdef PCMCIA_DEBUG
static void smc_dump(struct net_device *dev)
{
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
u_short i, w, save;
save = inw(ioaddr + BANK_SELECT);
for (w = 0; w < 4; w++) {
link->open++;
netif_start_queue(dev);
- smc->saved_skb = 0;
+ smc->saved_skb = NULL;
smc->packets_waiting = 0;
smc_reset(dev);
{
struct smc_private *smc = netdev_priv(dev);
dev_link_t *link = &smc->link;
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
DEBUG(0, "%s: smc_close(), status %4.4x.\n",
dev->name, inw(ioaddr + BANK_SELECT));
{
struct smc_private *smc = netdev_priv(dev);
struct sk_buff *skb = smc->saved_skb;
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
u_char packet_no;
if (!skb) {
static void smc_tx_timeout(struct net_device *dev)
{
struct smc_private *smc = netdev_priv(dev);
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
"Tx_status %2.2x status %4.4x.\n",
static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct smc_private *smc = netdev_priv(dev);
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
u_short num_pages;
short time_out, ir;
static void smc_tx_err(struct net_device * dev)
{
struct smc_private *smc = netdev_priv(dev);
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
int tx_status;
static void smc_eph_irq(struct net_device *dev)
{
struct smc_private *smc = netdev_priv(dev);
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
u_short card_stats, ephs;
SMC_SELECT_BANK(0);
{
struct net_device *dev = dev_id;
struct smc_private *smc = netdev_priv(dev);
- ioaddr_t ioaddr;
+ kio_addr_t ioaddr;
u_short saved_bank, saved_pointer, mask, status;
unsigned int handled = 1;
char bogus_cnt = INTR_WORK; /* Work we are willing to do. */
static void smc_rx(struct net_device *dev)
{
struct smc_private *smc = netdev_priv(dev);
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
int rx_status;
int packet_length; /* Caution: not frame length, rather words
to transfer from the chip. */
static void set_rx_mode(struct net_device *dev)
{
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
struct smc_private *smc = netdev_priv(dev);
u_int multicast_table[ 2 ] = { 0, };
unsigned long flags;
static void smc_set_xcvr(struct net_device *dev, int if_port)
{
struct smc_private *smc = netdev_priv(dev);
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
u_short saved_bank;
saved_bank = inw(ioaddr + BANK_SELECT);
static void smc_reset(struct net_device *dev)
{
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
struct smc_private *smc = netdev_priv(dev);
int i;
{
struct net_device *dev = (struct net_device *) arg;
struct smc_private *smc = netdev_priv(dev);
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
u_short i, media, saved_bank;
u_short link;
static int smc_link_ok(struct net_device *dev)
{
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
struct smc_private *smc = netdev_priv(dev);
if (smc->cfg & CFG_MII_SELECT) {
static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
{
u16 tmp;
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
{
u16 tmp;
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
if (ecmd->speed != SPEED_10)
return -EINVAL;
tmp |= TCR_FDUPLX;
else
tmp &= ~TCR_FDUPLX;
- outw(ioaddr + TCR, tmp);
+ outw(tmp, ioaddr + TCR);
return 0;
}
-static int smc_ethtool_ioctl (struct net_device *dev, void __user *useraddr)
+static int check_if_running(struct net_device *dev)
{
- u32 ethcmd;
- struct smc_private *smc = netdev_priv(dev);
-
- if (get_user(ethcmd, (u32 __user *)useraddr))
- return -EFAULT;
-
- switch (ethcmd) {
-
- case ETHTOOL_GDRVINFO: {
- struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
- strcpy(info.driver, DRV_NAME);
- strcpy(info.version, DRV_VERSION);
- if (copy_to_user(useraddr, &info, sizeof(info)))
- return -EFAULT;
+ if (!netif_running(dev))
+ return -EINVAL;
return 0;
- }
+}
+
+static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+}
- /* get settings */
- case ETHTOOL_GSET: {
+static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ struct smc_private *smc = netdev_priv(dev);
+ kio_addr_t ioaddr = dev->base_addr;
+ u16 saved_bank = inw(ioaddr + BANK_SELECT);
int ret;
- struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+
+ SMC_SELECT_BANK(3);
spin_lock_irq(&smc->lock);
if (smc->cfg & CFG_MII_SELECT)
- ret = mii_ethtool_gset(&smc->mii_if, &ecmd);
+ ret = mii_ethtool_gset(&smc->mii_if, ecmd);
else
- ret = smc_netdev_get_ecmd(dev, &ecmd);
+ ret = smc_netdev_get_ecmd(dev, ecmd);
spin_unlock_irq(&smc->lock);
- if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
- return -EFAULT;
+ SMC_SELECT_BANK(saved_bank);
return ret;
- }
+}
- /* set settings */
- case ETHTOOL_SSET: {
+static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ struct smc_private *smc = netdev_priv(dev);
+ kio_addr_t ioaddr = dev->base_addr;
+ u16 saved_bank = inw(ioaddr + BANK_SELECT);
int ret;
- struct ethtool_cmd ecmd;
- if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
- return -EFAULT;
+
+ SMC_SELECT_BANK(3);
spin_lock_irq(&smc->lock);
if (smc->cfg & CFG_MII_SELECT)
- ret = mii_ethtool_sset(&smc->mii_if, &ecmd);
+ ret = mii_ethtool_sset(&smc->mii_if, ecmd);
else
- ret = smc_netdev_set_ecmd(dev, &ecmd);
+ ret = smc_netdev_set_ecmd(dev, ecmd);
spin_unlock_irq(&smc->lock);
+ SMC_SELECT_BANK(saved_bank);
return ret;
- }
+}
- /* get link status */
- case ETHTOOL_GLINK: {
- struct ethtool_value edata = { ETHTOOL_GLINK };
+static u32 smc_get_link(struct net_device *dev)
+{
+ struct smc_private *smc = netdev_priv(dev);
+ kio_addr_t ioaddr = dev->base_addr;
+ u16 saved_bank = inw(ioaddr + BANK_SELECT);
+ u32 ret;
+
+ SMC_SELECT_BANK(3);
spin_lock_irq(&smc->lock);
- edata.data = smc_link_ok(dev);
+ ret = smc_link_ok(dev);
spin_unlock_irq(&smc->lock);
- if (copy_to_user(useraddr, &edata, sizeof(edata)))
- return -EFAULT;
- return 0;
- }
+ SMC_SELECT_BANK(saved_bank);
+ return ret;
+}
#ifdef PCMCIA_DEBUG
- /* get message-level */
- case ETHTOOL_GMSGLVL: {
- struct ethtool_value edata = { ETHTOOL_GMSGLVL };
- edata.data = pc_debug;
- if (copy_to_user(useraddr, &edata, sizeof(edata)))
- return -EFAULT;
- return 0;
- }
+static u32 smc_get_msglevel(struct net_device *dev)
+{
+ return pc_debug;
+}
- /* set message-level */
- case ETHTOOL_SMSGLVL: {
- struct ethtool_value edata;
- if (copy_from_user(&edata, useraddr, sizeof(edata)))
- return -EFAULT;
- pc_debug = edata.data;
- return 0;
- }
+static void smc_set_msglevel(struct net_device *dev, u32 val)
+{
+ pc_debug = val;
+}
#endif
- /* restart autonegotiation */
- case ETHTOOL_NWAY_RST: {
- if (smc->cfg & CFG_MII_SELECT)
- return mii_nway_restart(&smc->mii_if);
- else
- return -EOPNOTSUPP;
- }
-
- default:
- break;
- }
- return -EOPNOTSUPP;
+static int smc_nway_reset(struct net_device *dev)
+{
+ struct smc_private *smc = netdev_priv(dev);
+ if (smc->cfg & CFG_MII_SELECT) {
+ kio_addr_t ioaddr = dev->base_addr;
+ u16 saved_bank = inw(ioaddr + BANK_SELECT);
+ int res;
+
+ SMC_SELECT_BANK(3);
+ res = mii_nway_restart(&smc->mii_if);
+ SMC_SELECT_BANK(saved_bank);
+
+ return res;
+ } else
+ return -EOPNOTSUPP;
}
+static struct ethtool_ops ethtool_ops = {
+ .begin = check_if_running,
+ .get_drvinfo = smc_get_drvinfo,
+ .get_settings = smc_get_settings,
+ .set_settings = smc_set_settings,
+ .get_link = smc_get_link,
+#ifdef PCMCIA_DEBUG
+ .get_msglevel = smc_get_msglevel,
+ .set_msglevel = smc_set_msglevel,
+#endif
+ .nway_reset = smc_nway_reset,
+};
+
static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct smc_private *smc = netdev_priv(dev);
- struct mii_ioctl_data *mii;
- int rc = 0;
- u_short saved_bank;
- ioaddr_t ioaddr = dev->base_addr;
-
- mii = if_mii(rq);
- if (!netif_running(dev))
- return -EINVAL;
+ struct smc_private *smc = netdev_priv(dev);
+ struct mii_ioctl_data *mii = if_mii(rq);
+ int rc = 0;
+ u16 saved_bank;
+ kio_addr_t ioaddr = dev->base_addr;
- switch (cmd) {
- case SIOCETHTOOL:
- saved_bank = inw(ioaddr + BANK_SELECT);
- SMC_SELECT_BANK(3);
- rc = smc_ethtool_ioctl(dev, rq->ifr_data);
- SMC_SELECT_BANK(saved_bank);
- break;
+ if (!netif_running(dev))
+ return -EINVAL;
- default:
spin_lock_irq(&smc->lock);
saved_bank = inw(ioaddr + BANK_SELECT);
SMC_SELECT_BANK(3);
rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
SMC_SELECT_BANK(saved_bank);
spin_unlock_irq(&smc->lock);
- break;
- }
-
- return rc;
+ return rc;
}
static struct pcmcia_driver smc91c92_cs_driver = {
static void __exit exit_smc91c92_cs(void)
{
pcmcia_unregister_driver(&smc91c92_cs_driver);
- while (dev_list != NULL)
- smc91c92_detach(dev_list);
+ BUG_ON(dev_list != NULL);
}
module_init(init_smc91c92_cs);