123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- #include <linux/string.h>
- #include <linux/slab.h>
- #include <linux/types.h>
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/pci.h>
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/fs.h>
- #include <linux/cdev.h>
- #include <linux/sysfs.h>
- #include <asm/atomic.h>
- #include <linux/pagemap.h>
- #include <linux/spinlock.h>
- #include <linux/list.h>
- #include <linux/scatterlist.h>
- #include <linux/vmalloc.h>
- #include <linux/stat.h>
- #include <linux/interrupt.h>
- #include <linux/wait.h>
- #include "pcilib/version.h"
- #include "build.h"
- #include "base.h"
- /* Module info */
- MODULE_AUTHOR("Guillermo Marcus");
- MODULE_DESCRIPTION("Simple PCI Driver");
- MODULE_LICENSE("GPL v2");
- /*
- * This is the table of PCI devices handled by this driver by default
- * If you want to add devices dynamically to this list, do:
- *
- * echo "vendor device" > /sys/bus/pci/drivers/pciDriver/new_id
- * where vendor and device are in hex, without leading '0x'.
- */
- static const __devinitdata struct pci_device_id pcidriver_ids[] = {
- { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_ML605_DEVICE_ID ) }, // PCI-E Xilinx ML605
- { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_IPECAMERA_DEVICE_ID ) }, // PCI-E IPE Camera
- { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_KAPTURE_DEVICE_ID ) }, // PCI-E KAPTURE board for HEB
- {0,0,0,0},
- };
- MODULE_DEVICE_TABLE(pci, pcidriver_ids);
- /* Module class */
- static struct class *pcidriver_class;
- #ifdef PCIDRIVER_DUMMY_DEVICE
- pcidriver_privdata_t *pcidriver_dummydata = NULL;
- #else /* PCIDRIVER_DUMMY_DEVICE */
- static struct pci_driver pcidriver_driver;
- #endif /* PCIDRIVER_DUMMY_DEVICE */
- /* Hold the allocated major & minor numbers */
- static dev_t pcidriver_devt;
- /* Number of devices allocated */
- static atomic_t pcidriver_deviceCount;
- /* Private data for probed devices */
- static pcidriver_privdata_t* pcidriver_privdata[MAXDEVICES];
- pcidriver_privdata_t *pcidriver_get_privdata(int devid) {
- if (devid >= MAXDEVICES)
- return NULL;
- return pcidriver_privdata[devid];
- }
- void pcidriver_put_privdata(pcidriver_privdata_t *privdata) {
- }
- /**
- * This function is called when installing the driver for a device
- * @param pdev Pointer to the PCI device
- */
- static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_device_id *id)
- {
- int err = 0;
- int devno;
- pcidriver_privdata_t *privdata;
- int devid;
- /* At the moment there is no difference between these boards here, other than
- * printing a different message in the log.
- *
- * However, there is some difference in the interrupt handling functions.
- */
- #ifdef PCIDRIVER_DUMMY_DEVICE
- mod_info("Emulated device\n");
- #else /* PCIDRIVER_DUMMY_DEVICE */
- if (id->vendor == PCIE_XILINX_VENDOR_ID) {
- if (id->device == PCIE_ML605_DEVICE_ID) {
- mod_info("Found ML605 board at %s\n", dev_name(&pdev->dev));
- } else if (id->device == PCIE_IPECAMERA_DEVICE_ID) {
- mod_info("Found IPE Camera at %s\n", dev_name(&pdev->dev));
- } else if (id->device == PCIE_KAPTURE_DEVICE_ID) {
- mod_info("Found KAPTURE board at %s\n", dev_name(&pdev->dev));
- } else {
- mod_info("Found unknown Xilinx device (%x) at %s\n", id->device, dev_name(&pdev->dev));
- }
- } else {
- /* It is something else */
- mod_info("Found unknown board (%x:%x) at %s\n", id->vendor, id->device, dev_name(&pdev->dev));
- }
- /* Enable the device */
- if ((err = pci_enable_device(pdev)) != 0) {
- mod_info("Couldn't enable device\n");
- goto probe_pcien_fail;
- }
- /* Bus master & dma */
- pci_set_master(pdev);
- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (err < 0) {
- printk(KERN_ERR "pci_set_dma_mask failed\n");
- goto probe_dma_fail;
- }
- /* Set Memory-Write-Invalidate support */
- if ((err = pci_set_mwi(pdev)) != 0)
- mod_info("MWI not supported. Continue without enabling MWI.\n");
- #endif /* PCIDRIVER_DUMMY_DEVICE */
- /* Get / Increment the device id */
- devid = atomic_inc_return(&pcidriver_deviceCount) - 1;
- if (devid >= MAXDEVICES) {
- mod_info("Maximum number of devices reached! Increase MAXDEVICES.\n");
- err = -ENOMSG;
- goto probe_maxdevices_fail;
- }
- /* Allocate and initialize the private data for this device */
- if ((privdata = kcalloc(1, sizeof(*privdata), GFP_KERNEL)) == NULL) {
- err = -ENOMEM;
- goto probe_nomem;
- }
- privdata->devid = devid;
- INIT_LIST_HEAD(&(privdata->kmem_list));
- spin_lock_init(&(privdata->kmemlist_lock));
- atomic_set(&privdata->kmem_count, 0);
- INIT_LIST_HEAD(&(privdata->umem_list));
- spin_lock_init(&(privdata->umemlist_lock));
- atomic_set(&privdata->umem_count, 0);
- #ifdef PCIDRIVER_DUMMY_DEVICE
- pcidriver_dummydata = privdata;
- #else /* PCIDRIVER_DUMMY_DEVICE */
- pci_set_drvdata(pdev, privdata);
- privdata->pdev = pdev;
- #endif /* PCIDRIVER_DUMMY_DEVICE */
- /* Device add to sysfs */
- devno = MKDEV(MAJOR(pcidriver_devt), MINOR(pcidriver_devt) + devid);
- privdata->devno = devno;
- /* FIXME: some error checking missing here */
- privdata->class_dev = device_create(pcidriver_class, NULL, devno, privdata, NODENAMEFMT, MINOR(pcidriver_devt) + devid);
- dev_set_drvdata(privdata->class_dev, privdata);
- mod_info("Device /dev/%s%d added\n",NODENAME,MINOR(pcidriver_devt) + devid);
- #ifndef PCIDRIVER_DUMMY_DEVICE
- /* Setup mmaped BARs into kernel space */
- if ((err = pcidriver_probe_irq(privdata)) != 0)
- goto probe_irq_probe_fail;
- #endif /* ! PCIDRIVER_DUMMY_DEVICE */
- /* TODO: correct errorhandling. ewww. must remove the files in reversed order :-( */
- if (pcidriver_create_sysfs_attributes(privdata) != 0)
- goto probe_device_create_fail;
- /* Register character device */
- cdev_init(&(privdata->cdev), pcidriver_get_fops());
- privdata->cdev.owner = THIS_MODULE;
- privdata->cdev.ops = pcidriver_get_fops();
- err = cdev_add( &privdata->cdev, devno, 1 );
- if (err) {
- mod_info( "Couldn't add character device.\n" );
- goto probe_cdevadd_fail;
- }
- pcidriver_privdata[devid] = privdata;
- return 0;
- probe_device_create_fail:
- probe_cdevadd_fail:
- #ifndef PCIDRIVER_DUMMY_DEVICE
- probe_irq_probe_fail:
- pcidriver_irq_unmap_bars(privdata);
- #endif /* ! PCIDRIVER_DUMMY_DEVICE */
- kfree(privdata);
- probe_nomem:
- atomic_dec(&pcidriver_deviceCount);
- probe_maxdevices_fail:
- #ifndef PCIDRIVER_DUMMY_DEVICE
- probe_dma_fail:
- pci_disable_device(pdev);
- probe_pcien_fail:
- #endif /* ! PCIDRIVER_DUMMY_DEVICE */
- return err;
- }
- /**
- *
- * This function is called when disconnecting a device
- *
- */
- static void __devexit pcidriver_remove(struct pci_dev *pdev)
- {
- pcidriver_privdata_t *privdata;
- #ifdef PCIDRIVER_DUMMY_DEVICE
- privdata = pcidriver_dummydata;
- pcidriver_dummydata = NULL;
- #else /* PCIDRIVER_DUMMY_DEVICE */
- /* Get private data from the device */
- privdata = pci_get_drvdata(pdev);
- #endif /* PCIDRIVER_DUMMY_DEVICE */
- // Theoretically we should lock here and when using...
- pcidriver_privdata[privdata->devid] = NULL;
- /* Removing sysfs attributes from class device */
- pcidriver_remove_sysfs_attributes(privdata);
- /* Free all allocated kmem buffers before leaving */
- pcidriver_kmem_free_all( privdata );
- #ifndef PCIDRIVER_DUMMY_DEVICE
- # ifdef ENABLE_IRQ
- pcidriver_remove_irq(privdata);
- # endif
- #endif /* ! PCIDRIVER_DUMMY_DEVICE */
- /* Removing Character device */
- cdev_del(&(privdata->cdev));
- /* Removing the device from sysfs */
- device_destroy(pcidriver_class, privdata->devno);
- /* Releasing privdata */
- kfree(privdata);
- #ifdef PCIDRIVER_DUMMY_DEVICE
- mod_info("Device at " NODENAMEFMT " removed\n", 0);
- #else /* PCIDRIVER_DUMMY_DEVICE */
- /* Disabling PCI device */
- pci_disable_device(pdev);
- mod_info("Device at %s removed\n", dev_name(&pdev->dev));
- #endif /* PCIDRIVER_DUMMY_DEVICE */
- }
- #ifndef PCIDRIVER_DUMMY_DEVICE
- static struct pci_driver pcidriver_driver = {
- .name = MODNAME,
- .id_table = pcidriver_ids,
- .probe = pcidriver_probe,
- .remove = pcidriver_remove,
- };
- #endif /* ! PCIDRIVER_DUMMY_DEVICE */
- static int __init pcidriver_init(void)
- {
- int err = 0;
- /* Initialize the device count */
- atomic_set(&pcidriver_deviceCount, 0);
- memset(pcidriver_privdata, 0, sizeof(pcidriver_privdata));
- /* Allocate character device region dynamically */
- if ((err = alloc_chrdev_region(&pcidriver_devt, MINORNR, MAXDEVICES, NODENAME)) != 0) {
- mod_info("Couldn't allocate chrdev region. Module not loaded.\n");
- goto init_alloc_fail;
- }
- mod_info("Major %d allocated to nodename '%s'\n", MAJOR(pcidriver_devt), NODENAME);
- /* Register driver class */
- pcidriver_class = class_create(THIS_MODULE, NODENAME);
- if (IS_ERR(pcidriver_class)) {
- mod_info("No sysfs support. Module not loaded.\n");
- goto init_class_fail;
- }
- /* Register PCI driver. This function returns the number of devices on some
- * systems, therefore check for errors as < 0. */
- #ifdef PCIDRIVER_DUMMY_DEVICE
- if ((err = pcidriver_probe(NULL, NULL)) < 0) {
- #else /* PCIDRIVER_DUMMY_DEVICE */
- if ((err = pci_register_driver(&pcidriver_driver)) < 0) {
- #endif /* PCIDRIVER_DUMMY_DEVICE */
- mod_info("Couldn't register PCI driver. Module not loaded.\n");
- goto init_pcireg_fail;
- }
- mod_info("pcidriver %u.%u.%u loaded\n", PCILIB_VERSION_GET_MAJOR(PCILIB_VERSION), PCILIB_VERSION_GET_MINOR(PCILIB_VERSION), PCILIB_VERSION_GET_MICRO(PCILIB_VERSION));
- mod_info("%s\n", PCIDRIVER_BUILD);
- mod_info("%s\n", PCIDRIVER_REVISION);
- if (strlen(PCIDRIVER_CHANGES)) {
- mod_info("Extra changes - %s\n", PCIDRIVER_CHANGES);
- }
- return 0;
- init_pcireg_fail:
- class_destroy(pcidriver_class);
- init_class_fail:
- unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
- init_alloc_fail:
- return err;
- }
- static void pcidriver_exit(void)
- {
- #ifdef PCIDRIVER_DUMMY_DEVICE
- pcidriver_remove(NULL);
- #else
- pci_unregister_driver(&pcidriver_driver);
- #endif /* PCIDRIVER_DUMMY_DEVICE */
- unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
- if (pcidriver_class != NULL)
- class_destroy(pcidriver_class);
- mod_info("Module unloaded\n");
- }
- module_init(pcidriver_init);
- module_exit(pcidriver_exit);
|