[PATCH] Continue pcnet probing. Introduce driver's private block
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
В Fri, 17 Sep 2010 19:02:38 +0400 Denis Kirjanov <kirjanov@gmail.com> пишет:
+/* Why do we need to create protos like this? */ +static int pcnet_dummy_init_netdev(struct pci_dev *pdev, unsigned long ioaddr);
Нужны ли вообще прототипы функций? Мне показалось, что удобнее разместить pcnet_dummy_init_netdev после функции инициализации, но я тут больше на правах ученика, так что рад выслушать любые предложения :).
+ ndev = alloc_etherdev(sizeof(*pp)); + SET_NETDEV_DEV(ndev, &pdev->dev);
Почему мы выполняем действия с net_device не закончив инициализацию pci устройства? Здесь есть какая-то специфика? Я планировал вынести подобные действия в pcnet_dummy_init_netdev() или здесь я не прав?
static void __devexit pcnet_dummy_remove_one(struct pci_dev *pdev)
Будет ли вызвана эта функция, если инициализация устройства завершилась неудачей и мы возвратили -ENODEV?
2010/9/18 Dmitry Podgorny <pasis.ua@gmail.com>:
В Fri, 17 Sep 2010 19:02:38 +0400 Denis Kirjanov <kirjanov@gmail.com> пишет:
+/* Why do we need to create protos like this? */ +static int pcnet_dummy_init_netdev(struct pci_dev *pdev, unsigned long ioaddr);
Нужны ли вообще прототипы функций? Мне показалось, что удобнее разместить pcnet_dummy_init_netdev после функции инициализации, но я тут больше на правах ученика, так что рад выслушать любые предложения :).
Прототипы - личное дело каждого. У меня насчет них такое представление - создать абстракцию в текущем месте(ф-ию, структуру etc) и описать её выше. Мне кажется что в данном случае эти прототипы не особо полезны и занимают лишнее место в коде.
+ ndev = alloc_etherdev(sizeof(*pp)); + SET_NETDEV_DEV(ndev, &pdev->dev);
Почему мы выполняем действия с net_device не закончив инициализацию pci устройства? Здесь есть какая-то специфика? Я планировал вынести подобные действия в pcnet_dummy_init_netdev() или здесь я не прав? Специфика такая что автор сам решает как ему поступить :) Вообще правильное место для этого макроса - после функции pci_set_drvdata ;) Но в данном случае это безопасно.
static void __devexit pcnet_dummy_remove_one(struct pci_dev *pdev)
Будет ли вызвана эта функция, если инициализация устройства завершилась неудачей и мы возвратили -ENODEV? Почему мы должны вызывать remove для драйвера, который не смог успешно зарегестрироваться? ;) _______________________________________________ Kernel-russian mailing list Kernel-russian@kernelnewbies.org http://lists.kernelnewbies.org/mailman/listinfo/kernel-russian
-- Regards, Denis
participants (2)
-
Denis Kirjanov -
Dmitry Podgorny