patch-2.4.0-test11 linux/drivers/net/sis900.c

Next file: linux/drivers/net/sis900.h
Previous file: linux/drivers/net/seeq8005.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test10/linux/drivers/net/sis900.c linux/drivers/net/sis900.c
@@ -1,6 +1,6 @@
 /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
    Copyright 1999 Silicon Integrated System Corporation 
-   Revision:	1.07.04	Sep. 6 2000
+   Revision:	1.07.06	Nov. 7 2000
 
    Modified from the driver which is originally written by Donald Becker.
    
@@ -18,6 +18,8 @@
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
 
+   Rev 1.07.06 Nov.  7 2000 Jeff Garzik <jgarzik@mandrakesoft.com> some bug fix and cleaning
+   Rev 1.07.05 Nov.  6 2000 metapirat<metapirat@gmx.de> contribute media type select by ifconfig
    Rev 1.07.04 Sep.  6 2000 Lei-Chun Chang added ICS1893 PHY support
    Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E eqaulizer workaroung rule
    Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update for SiS 630E and SiS 630E A1
@@ -56,21 +58,19 @@
 #include "sis900.h"
 
 static const char *version =
-"sis900.c: v1.07.04  09/06/2000\n";
+"sis900.c: v1.07.06  11/07/2000\n";
 
 static int max_interrupt_work = 20;
 static int multicast_filter_limit = 128;
 
 #define sis900_debug debug
-static int sis900_debug = 0;
+static int sis900_debug;
 
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (4*HZ)
 /* SiS 900 is capable of 32 bits BM DMA */
 #define SIS900_DMA_MASK 0xffffffff
 
-static struct net_device * sis900_mac_probe (struct pci_dev * pci_dev,
-					     char *card_name);
 enum {
 	SIS_900 = 0,
 	SIS_7016
@@ -140,7 +140,6 @@
 	BufferDesc rx_ring[NUM_RX_DESC];
 
 	unsigned int tx_full;			/* The Tx queue is full.    */
-	int LinkOn;
 };
 
 MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>, Ollie Lho <ollie@sis.com.tw>");
@@ -171,39 +170,10 @@
 static void set_rx_mode(struct net_device *net_dev);
 static void sis900_reset(struct net_device *net_dev);
 static void sis630e_set_eq(struct net_device *net_dev);
-
-/* walk through every ethernet PCI devices to see if some of them are matched with our card list*/
-static int __init sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
-	u32 pci_io_base;
-
-	if (!pci_dma_supported(pci_dev, SIS900_DMA_MASK)) {
-		printk(KERN_ERR "sis900.c: architecture does not support "
-		       "32bit PCI busmaster DMA\n");
-		return -ENODEV;
-	}
-
-	pci_io_base = pci_resource_start(pci_dev, 0);
-	if (check_region(pci_io_base, SIS900_TOTAL_SIZE)) {
-		printk(KERN_ERR "sis900.c: can't allocate I/O space at 0x%08x\n",
-		       pci_io_base);
-		return -ENODEV;
-	}
-
-	/* setup various bits in PCI command register */
-	if (pci_enable_device (pci_dev))
-		return -ENODEV;
-	pci_set_master(pci_dev);
-
-	/* do the real low level jobs */
-	if (sis900_mac_probe(pci_dev, card_names[pci_id->driver_data]) == NULL)
-		return -ENODEV;
-
-	return 0;
-}
+static int sis900_set_config(struct net_device *dev, struct ifmap *map);
 
 /* older SiS900 and friends, use EEPROM to store MAC address */
-static int sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
+static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
 {
 	long ioaddr = pci_resource_start(pci_dev, 0);
 	u16 signature;
@@ -225,7 +195,7 @@
 }
 
 /* SiS630E model, use APC CMOS RAM to store MAC address */
-static int sis630e_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
+static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
 {
 	struct pci_dev *isa_bridge = NULL;
 	u8 reg;
@@ -247,17 +217,36 @@
 	return 1;
 }
 
-static struct net_device * __init sis900_mac_probe (struct pci_dev * pci_dev, char * card_name)
+static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
 {
 	struct sis900_private *sis_priv;
 	long ioaddr = pci_resource_start(pci_dev, 0);
-	struct net_device *net_dev = NULL;
+	struct net_device *net_dev;
 	int irq = pci_dev->irq;
 	int i, ret = 0;
 	u8 revision;
+	char *card_name = card_names[pci_id->driver_data];
+
+	if (!pci_dma_supported(pci_dev, SIS900_DMA_MASK)) {
+		printk(KERN_ERR "sis900.c: architecture does not support "
+		       "32bit PCI busmaster DMA\n");
+		return -ENODEV;
+	}
 
-	if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
-		return NULL;
+	/* setup various bits in PCI command register */
+	if (pci_enable_device (pci_dev))
+		return -ENODEV;
+	pci_set_master(pci_dev);
+
+	net_dev = init_etherdev(NULL, sizeof(struct sis900_private));
+	if (!net_dev)
+		return -ENOMEM;
+
+	if (!request_region(ioaddr, SIS900_TOTAL_SIZE, net_dev->name)) {
+		printk(KERN_ERR "sis900.c: can't allocate I/O space at 0x%lX\n", ioaddr);
+		ret = -EBUSY;
+		goto err_out;
+	}
 
 	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
 	if (revision == SIS630E_REV || revision == SIS630EA1_REV)
@@ -268,8 +257,8 @@
 		ret = sis900_get_mac_addr(pci_dev, net_dev);
 
 	if (ret == 0) {
-		unregister_netdevice(net_dev);
-		return NULL;
+		ret = -ENODEV;
+		goto err_out_region;
 	}
 
 	/* print some information about our NIC */
@@ -279,16 +268,9 @@
 		printk("%2.2x:", (u8)net_dev->dev_addr[i]);
 	printk("%2.2x.\n", net_dev->dev_addr[i]);
 
-	if ((net_dev->priv = kmalloc(sizeof(struct sis900_private), GFP_KERNEL)) == NULL) {
-		unregister_netdevice(net_dev);
-		return NULL;
-	}
-	
 	sis_priv = net_dev->priv;
-	memset(sis_priv, 0, sizeof(struct sis900_private));
 
 	/* We do a request_region() to register /proc/ioports info. */
-	request_region(ioaddr, SIS900_TOTAL_SIZE, net_dev->name);
 	net_dev->base_addr = ioaddr;
 	net_dev->irq = irq;
 	sis_priv->pci_dev = pci_dev;
@@ -296,10 +278,8 @@
 	
 	/* probe for mii transciver */
 	if (sis900_mii_probe(net_dev) == 0) {
-		unregister_netdev(net_dev);
-		kfree(sis_priv);
-		release_region(ioaddr, SIS900_TOTAL_SIZE);
-		return NULL;
+		ret = -ENODEV;
+		goto err_out_region;
 	}
 
 	pci_dev->driver_data = net_dev;
@@ -310,12 +290,20 @@
 	net_dev->hard_start_xmit = &sis900_start_xmit;
 	net_dev->stop = &sis900_close;
 	net_dev->get_stats = &sis900_get_stats;
+	net_dev->set_config = &sis900_set_config;
 	net_dev->set_multicast_list = &set_rx_mode;
 	net_dev->do_ioctl = &mii_ioctl;
 	net_dev->tx_timeout = sis900_tx_timeout;
 	net_dev->watchdog_timeo = TX_TIMEOUT;
 
-	return net_dev;
+	return 0;
+
+err_out_region:
+	release_region(ioaddr, SIS900_TOTAL_SIZE);
+err_out:
+	unregister_netdev(net_dev);
+	kfree(net_dev);
+	return ret;
 }
 
 static int __init sis900_mii_probe (struct net_device * net_dev)
@@ -385,9 +373,9 @@
 	}
 
 	if (sis_priv->mii->status & MII_STAT_LINK)
-		sis_priv->LinkOn = TRUE;
+		netif_carrier_on(net_dev);
 	else
-		sis_priv->LinkOn = FALSE;
+		netif_carrier_off(net_dev);
 
 	return 1;
 }
@@ -720,7 +708,7 @@
 	u16 reg14h, eq_value, max_value=0, min_value=0;
 	int i, maxcount=10;
 
-	if (sis_priv->LinkOn == TRUE) {
+	if (netif_carrier_ok(net_dev)) {
 		reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
 		mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (0x2200 | reg14h) & 0xBFFF);
 		for (i=0; i < maxcount; i++) {
@@ -764,10 +752,10 @@
 	/* current mii phy is failed to link, try another one */
 	while (!(status & MII_STAT_LINK)) {
 		if (mii_phy->next == NULL) {
-			if (sis_priv->LinkOn) {
+			if (netif_carrier_ok(net_dev)) {
 				/* link stat change from ON to OFF */
 				next_tick = HZ;
-				sis_priv->LinkOn = FALSE;
+				netif_carrier_off(net_dev);
 
 				/* Equalizer workaroung Rule */
 				pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
@@ -785,9 +773,9 @@
 		status = mdio_read(net_dev, mii_phy->phy_addr, MII_STATUS);
 	}
 
-	if (!sis_priv->LinkOn) {
+	if (!netif_carrier_ok(net_dev)) {
 		/* link stat change forn OFF to ON, read and report link mode */
-		sis_priv->LinkOn = TRUE;
+		netif_carrier_on(net_dev);
 		next_tick = 5*HZ;
 
 		/* Equalizer workaroung Rule */
@@ -1326,6 +1314,96 @@
 	return &sis_priv->stats;
 }
 
+/* Support for media type changes via net_device->set_config */
+static int sis900_set_config(struct net_device *dev, struct ifmap *map)
+{    
+	struct sis900_private *sis_priv = (struct sis900_private *)dev->priv;
+	struct mii_phy *mii_phy = sis_priv->mii;
+        
+	u16 status;
+
+	/* we support only port changes. All other runtime configuration
+	   changes will be ignored (io base and interrupt changes for example)*/    
+	if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+        /* we switch on the ifmap->port field. I couldn't find anything
+           like a definition or standard for the values of that field.
+           I think the meaning of those values is device specific. But
+           since I would like to change the media type via the ifconfig
+           command I use the definition from linux/netdevice.h 
+           (which seems to be different from the ifport(pcmcia) definition) 
+        */
+		switch(map->port){
+			case IF_PORT_UNKNOWN: /* use auto here */   
+                		dev->if_port = map->port;
+                		/* we are going to change the media type, so the Link will
+                		be temporary down and we need to reflect that here. When
+                		the Link comes up again, it will be sensed by the sis_timer
+                		procedure, which also does all the rest for us */
+				netif_carrier_off(dev);
+                
+                		/* read current state */
+                		status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+                
+                		/* enable auto negotiation and reset the negotioation
+                		(I dont really know what the auto negatiotiation reset
+                		really means, but it sounds for me right to do one here)*/
+                		mdio_write(dev, mii_phy->phy_addr,
+                                           MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO);
+
+            			break;
+            
+            		case IF_PORT_10BASET: /* 10BaseT */         
+                		dev->if_port = map->port;
+                
+                		/* we are going to change the media type, so the Link will
+                		be temporary down and we need to reflect that here. When
+                		the Link comes up again, it will be sensed by the sis_timer
+                		procedure, which also does all the rest for us */
+				netif_carrier_off(dev);
+        
+                		/* set Speed to 10Mbps */
+                		/* read current state */
+                		status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+                
+                		/* disable auto negotiation and force 10MBit mode*/
+                		mdio_write(dev, mii_phy->phy_addr,
+                                           MII_CONTROL, status & ~(MII_CNTL_SPEED | MII_CNTL_AUTO));
+            			break;
+            
+            		case IF_PORT_100BASET: /* 100BaseT */
+            		case IF_PORT_100BASETX: /* 100BaseTx */ 
+                		dev->if_port = map->port;
+                
+                		/* we are going to change the media type, so the Link will
+                		be temporary down and we need to reflect that here. When
+                		the Link comes up again, it will be sensed by the sis_timer
+                		procedure, which also does all the rest for us */
+				netif_carrier_off(dev);
+                
+                		/* set Speed to 100Mbps */
+                		/* disable auto negotiation and enable 100MBit Mode */
+                		status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+                		mdio_write(dev, mii_phy->phy_addr,
+                                           MII_CONTROL, (status & ~MII_CNTL_SPEED) | MII_CNTL_SPEED);
+                
+            			break;
+            
+            		case IF_PORT_10BASE2: /* 10Base2 */
+            		case IF_PORT_AUI: /* AUI */
+            		case IF_PORT_100BASEFX: /* 100BaseFx */
+                	/* These Modes are not supported (are they?)*/
+                		printk(KERN_INFO "Not supported");
+                		return -EOPNOTSUPP;
+            			break;
+            
+            		default:
+                		printk(KERN_INFO "Invalid");
+                		return -EINVAL;
+		}
+	}
+	return 0;
+}
+
 /* SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast hash table, which makes
    this function a little bit different from other drivers */
 static u16 sis900_compute_hashtable_index(u8 *addr)
@@ -1431,15 +1509,12 @@
 	outl(PESEL, ioaddr + cfg);
 }
 
-static void __exit sis900_remove(struct pci_dev *pci_dev)
+static void __devexit sis900_remove(struct pci_dev *pci_dev)
 {
 	struct net_device *net_dev = pci_dev->driver_data;
-	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
 		
 	unregister_netdev(net_dev);
 	release_region(net_dev->base_addr, SIS900_TOTAL_SIZE);
-
-	kfree(sis_priv);
 	kfree(net_dev);
 }
 
@@ -1454,16 +1529,9 @@
 
 static int __init sis900_init_module(void)
 {
-	if (!pci_present())   /* No PCI bus in this machine! */
-		return -ENODEV;
-
 	printk(KERN_INFO "%s", version);
 
-	if (!pci_register_driver(&sis900_pci_driver)) {
-		pci_unregister_driver(&sis900_pci_driver);
-                return -ENODEV;
-	}
-	return 0;
+	return pci_module_init(&sis900_pci_driver);
 }
 
 static void __exit sis900_cleanup_module(void)
@@ -1473,3 +1541,4 @@
 
 module_init(sis900_init_module);
 module_exit(sis900_cleanup_module);
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)