Signed-off-by: Denis Kirjanov <kirjanov@gmail.com> --- src/pcnet.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 72 insertions(+), 15 deletions(-) diff --git a/src/pcnet.c b/src/pcnet.c index bdb463c..93fd4d1 100644 --- a/src/pcnet.c +++ b/src/pcnet.c @@ -9,6 +9,9 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/spinlock.h> #define DRV_NAME "pcnet_dummy" #define DRV_VERSION "dev" @@ -24,38 +27,86 @@ static DEFINE_PCI_DEVICE_TABLE(pcnet_dummy_pci_tbl) = { { } }; -static int pcnet_dummy_init_netdev(struct pci_dev *pdev, unsigned int ioaddr); +enum { + PCNET_IOSIZE_LEN = 0x20, +}; + +struct pcnet_private { + /* TODO: + * DMA buffer management operations + */ + spinlock_t lock; + struct pci_dev *pci_dev; + void __iomem *base; +}; + +/* Why do we need to create protos like this? */ +static int pcnet_dummy_init_netdev(struct pci_dev *pdev, unsigned long ioaddr); static int __devinit pcnet_dummy_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - unsigned int ioaddr; - int err; + struct pcnet_private *pp; + struct net_device *ndev; + void __iomem *ioaddr; +#ifdef USE_IO_OPS + int bar = 0; +#else + int bar = 1; +#endif if (pci_enable_device(pdev)) return -ENODEV; /* enables bus-mastering for device pdev */ pci_set_master(pdev); - if (pci_request_regions(pdev, DRV_NAME)) { - pci_disable_device(pdev); - return -EBUSY; + ndev = alloc_etherdev(sizeof(*pp)); + if (!ndev) { + goto out; } + /* register ourself under /sys/class/net/ */ + SET_NETDEV_DEV(ndev, &pdev->dev); - ioaddr = pci_resource_start(pdev, 0); + if (pci_request_regions(pdev, DRV_NAME)) + goto out_netdev; - err = pcnet_dummy_init_netdev(pdev, ioaddr); - if (err) { - pci_disable_device(pdev); - pci_release_regions(pdev); - } + ioaddr = pci_iomap(pdev, bar, PCNET_IOSIZE_LEN); + if (!ioaddr) + goto out_res; + pci_set_drvdata(pdev, ndev); + + if (pcnet_dummy_init_netdev(pdev, (unsigned long)ioaddr)) + goto out_res_unmap; - return err; + return 0; + +out_res_unmap: + pci_iounmap(pdev, ioaddr); +out_res: + pci_release_regions(pdev); +out_netdev: + free_netdev(ndev); +out: + pci_disable_device(pdev); + return -ENODEV; } static int __devinit pcnet_dummy_init_netdev(struct pci_dev *pdev, - unsigned int ioaddr) + unsigned long ioaddr) { + struct net_device *ndev = pci_get_drvdata(pdev); + struct pcnet_private *pp; + int irq; + + irq = pdev->irq; + pp = netdev_priv(ndev); + ndev->base_addr = ioaddr; + ndev->irq = irq; + pp->pci_dev = pdev; + spin_lock_init(&pp->lock); + + /* init DMA rings */ + /* init net_dev_ops */ /* registers net_device and returns err */ /* TODO: reset the chip at the end */ @@ -64,10 +115,16 @@ static int __devinit pcnet_dummy_init_netdev(struct pci_dev *pdev, static void __devexit pcnet_dummy_remove_one(struct pci_dev *pdev) { - /* TODO: ensure pdev is enabled */ + struct net_device *ndev = pci_get_drvdata(pdev); + struct pcnet_private *pp; + pp = netdev_priv(ndev); + pci_iounmap(pdev, pp->base); + free_netdev(ndev); + /* TODO: ensure pdev is enabled */ pci_disable_device(pdev); pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); } static struct pci_driver pcnet_dummy_driver = { -- 1.7.0.4