|
@@ -1,13 +1,3 @@
|
|
|
-/**
|
|
|
- *
|
|
|
- * @file base.c
|
|
|
- * @author Guillermo Marcus
|
|
|
- * @date 2009-04-05
|
|
|
- * @brief Contains the main code which connects all the different parts and does
|
|
|
- * basic driver tasks like initialization.
|
|
|
- */
|
|
|
-
|
|
|
-
|
|
|
#include <linux/string.h>
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/types.h>
|
|
@@ -30,139 +20,66 @@
|
|
|
#include <linux/wait.h>
|
|
|
|
|
|
#include "../pcilib/version.h"
|
|
|
-
|
|
|
-#include "config.h"
|
|
|
-#include "compat.h"
|
|
|
-#include "pciDriver.h"
|
|
|
-#include "common.h"
|
|
|
-#include "base.h"
|
|
|
-#include "int.h"
|
|
|
-#include "kmem.h"
|
|
|
-#include "umem.h"
|
|
|
-#include "ioctl.h"
|
|
|
#include "build.h"
|
|
|
+#include "base.h"
|
|
|
|
|
|
-/*************************************************************************/
|
|
|
-/* Module device table associated with this driver */
|
|
|
-MODULE_DEVICE_TABLE(pci, pcidriver_ids);
|
|
|
|
|
|
-/* Module init and exit points */
|
|
|
-module_init(pcidriver_init);
|
|
|
-module_exit(pcidriver_exit);
|
|
|
|
|
|
/* Module info */
|
|
|
MODULE_AUTHOR("Guillermo Marcus");
|
|
|
MODULE_DESCRIPTION("Simple PCI Driver");
|
|
|
MODULE_LICENSE("GPL v2");
|
|
|
|
|
|
-/* Module class */
|
|
|
-static struct class_compat *pcidriver_class;
|
|
|
-
|
|
|
-#ifdef PCIDRIVER_DUMMY_DEVICE
|
|
|
-pcidriver_privdata_t *pcidriver_dummydata = NULL;
|
|
|
-#endif /* PCIDRIVER_DUMMY_DEVICE */
|
|
|
-
|
|
|
-/**
|
|
|
- *
|
|
|
- * Called when loading the driver
|
|
|
+/*
|
|
|
+ * 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 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);
|
|
|
+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},
|
|
|
+};
|
|
|
|
|
|
- /* Register driver class */
|
|
|
- pcidriver_class = class_create(THIS_MODULE, NODENAME);
|
|
|
+MODULE_DEVICE_TABLE(pci, pcidriver_ids);
|
|
|
|
|
|
- if (IS_ERR(pcidriver_class)) {
|
|
|
- mod_info("No sysfs support. Module not loaded.\n");
|
|
|
- goto init_class_fail;
|
|
|
- }
|
|
|
+/* Module class */
|
|
|
+static struct class *pcidriver_class;
|
|
|
|
|
|
- /* 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) {
|
|
|
+pcidriver_privdata_t *pcidriver_dummydata = NULL;
|
|
|
#else /* PCIDRIVER_DUMMY_DEVICE */
|
|
|
- if ((err = pci_register_driver(&pcidriver_driver)) < 0) {
|
|
|
+static struct pci_driver pcidriver_driver;
|
|
|
#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;
|
|
|
+/* Hold the allocated major & minor numbers */
|
|
|
+static dev_t pcidriver_devt;
|
|
|
|
|
|
-init_pcireg_fail:
|
|
|
- class_destroy(pcidriver_class);
|
|
|
-init_class_fail:
|
|
|
- unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
|
|
|
-init_alloc_fail:
|
|
|
- return err;
|
|
|
-}
|
|
|
+/* Number of devices allocated */
|
|
|
+static atomic_t pcidriver_deviceCount;
|
|
|
|
|
|
-/**
|
|
|
- *
|
|
|
- * Called when unloading the driver
|
|
|
- *
|
|
|
- */
|
|
|
-static void pcidriver_exit(void)
|
|
|
-{
|
|
|
-#ifdef PCIDRIVER_DUMMY_DEVICE
|
|
|
- pcidriver_remove(NULL);
|
|
|
-#else
|
|
|
- pci_unregister_driver(&pcidriver_driver);
|
|
|
-#endif /* PCIDRIVER_DUMMY_DEVICE */
|
|
|
+/* Private data for probed devices */
|
|
|
+static pcidriver_privdata_t* pcidriver_privdata[MAXDEVICES];
|
|
|
|
|
|
- unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
|
|
|
|
|
|
- if (pcidriver_class != NULL)
|
|
|
- class_destroy(pcidriver_class);
|
|
|
+pcidriver_privdata_t *pcidriver_get_privdata(int devid) {
|
|
|
+ if (devid >= MAXDEVICES)
|
|
|
+ return NULL;
|
|
|
|
|
|
- mod_info("Module unloaded\n");
|
|
|
+ return pcidriver_privdata[devid];
|
|
|
}
|
|
|
|
|
|
-/*************************************************************************/
|
|
|
-/* Driver functions */
|
|
|
+void pcidriver_put_privdata(pcidriver_privdata_t *privdata) {
|
|
|
|
|
|
-/**
|
|
|
- *
|
|
|
- * This struct defines the PCI entry points.
|
|
|
- * Will be registered at module init.
|
|
|
- *
|
|
|
- */
|
|
|
-#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 */
|
|
|
+}
|
|
|
|
|
|
/**
|
|
|
- *
|
|
|
* 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)
|
|
|
{
|
|
@@ -250,12 +167,8 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi
|
|
|
privdata->devno = devno;
|
|
|
|
|
|
/* FIXME: some error checking missing here */
|
|
|
-#ifdef PCIDRIVER_DUMMY_DEVICE
|
|
|
- privdata->class_dev = class_device_create(pcidriver_class, NULL, devno, NULL, NODENAMEFMT, MINOR(pcidriver_devt) + devid, privdata);
|
|
|
-#else /* PCIDRIVER_DUMMY_DEVICE */
|
|
|
- privdata->class_dev = class_device_create(pcidriver_class, NULL, devno, &(pdev->dev), NODENAMEFMT, MINOR(pcidriver_devt) + devid, privdata);
|
|
|
-#endif /* PCIDRIVER_DUMMY_DEVICE */
|
|
|
- class_set_devdata( privdata->class_dev, privdata );
|
|
|
+ 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
|
|
@@ -264,31 +177,14 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi
|
|
|
goto probe_irq_probe_fail;
|
|
|
#endif /* ! PCIDRIVER_DUMMY_DEVICE */
|
|
|
|
|
|
- /* Populate sysfs attributes for the class device */
|
|
|
/* TODO: correct errorhandling. ewww. must remove the files in reversed order :-( */
|
|
|
-#define sysfs_attr(name) do { \
|
|
|
- if (class_device_create_file(sysfs_attr_def_pointer, &sysfs_attr_def_name(name)) != 0) \
|
|
|
- goto probe_device_create_fail; \
|
|
|
- } while (0)
|
|
|
-#ifdef ENABLE_IRQ
|
|
|
- sysfs_attr(irq_count);
|
|
|
- sysfs_attr(irq_queues);
|
|
|
-#endif
|
|
|
-
|
|
|
- sysfs_attr(mmap_mode);
|
|
|
- sysfs_attr(mmap_area);
|
|
|
- sysfs_attr(kmem_count);
|
|
|
- sysfs_attr(kmem_alloc);
|
|
|
- sysfs_attr(kmem_free);
|
|
|
- sysfs_attr(kbuffers);
|
|
|
- sysfs_attr(umappings);
|
|
|
- sysfs_attr(umem_unmap);
|
|
|
-#undef sysfs_attr
|
|
|
+ if (pcidriver_create_sysfs_attributes(privdata) != 0)
|
|
|
+ goto probe_device_create_fail;
|
|
|
|
|
|
/* Register character device */
|
|
|
- cdev_init( &(privdata->cdev), &pcidriver_fops );
|
|
|
+ cdev_init(&(privdata->cdev), pcidriver_get_fops());
|
|
|
privdata->cdev.owner = THIS_MODULE;
|
|
|
- privdata->cdev.ops = &pcidriver_fops;
|
|
|
+ privdata->cdev.ops = pcidriver_get_fops();
|
|
|
err = cdev_add( &privdata->cdev, devno, 1 );
|
|
|
if (err) {
|
|
|
mod_info( "Couldn't add character device.\n" );
|
|
@@ -338,23 +234,7 @@ static void __devexit pcidriver_remove(struct pci_dev *pdev)
|
|
|
pcidriver_privdata[privdata->devid] = NULL;
|
|
|
|
|
|
/* Removing sysfs attributes from class device */
|
|
|
-#define sysfs_attr(name) do { \
|
|
|
- class_device_remove_file(sysfs_attr_def_pointer, &sysfs_attr_def_name(name)); \
|
|
|
- } while (0)
|
|
|
-#ifdef ENABLE_IRQ
|
|
|
- sysfs_attr(irq_count);
|
|
|
- sysfs_attr(irq_queues);
|
|
|
-#endif
|
|
|
-
|
|
|
- sysfs_attr(mmap_mode);
|
|
|
- sysfs_attr(mmap_area);
|
|
|
- sysfs_attr(kmem_count);
|
|
|
- sysfs_attr(kmem_alloc);
|
|
|
- sysfs_attr(kmem_free);
|
|
|
- sysfs_attr(kbuffers);
|
|
|
- sysfs_attr(umappings);
|
|
|
- sysfs_attr(umem_unmap);
|
|
|
-#undef sysfs_attr
|
|
|
+ pcidriver_remove_sysfs_attributes(privdata);
|
|
|
|
|
|
/* Free all allocated kmem buffers before leaving */
|
|
|
pcidriver_kmem_free_all( privdata );
|
|
@@ -369,7 +249,7 @@ static void __devexit pcidriver_remove(struct pci_dev *pdev)
|
|
|
cdev_del(&(privdata->cdev));
|
|
|
|
|
|
/* Removing the device from sysfs */
|
|
|
- class_device_destroy(pcidriver_class, privdata->devno);
|
|
|
+ device_destroy(pcidriver_class, privdata->devno);
|
|
|
|
|
|
/* Releasing privdata */
|
|
|
kfree(privdata);
|
|
@@ -384,213 +264,82 @@ static void __devexit pcidriver_remove(struct pci_dev *pdev)
|
|
|
|
|
|
}
|
|
|
|
|
|
-/*************************************************************************/
|
|
|
-/* File operations */
|
|
|
-/*************************************************************************/
|
|
|
-
|
|
|
-/**
|
|
|
- * This struct defines the file operation entry points.
|
|
|
- *
|
|
|
- * @see pcidriver_ioctl
|
|
|
- * @see pcidriver_mmap
|
|
|
- * @see pcidriver_open
|
|
|
- * @see pcidriver_release
|
|
|
- *
|
|
|
- */
|
|
|
-static struct file_operations pcidriver_fops = {
|
|
|
- .owner = THIS_MODULE,
|
|
|
- .unlocked_ioctl = pcidriver_ioctl,
|
|
|
- .mmap = pcidriver_mmap,
|
|
|
- .open = pcidriver_open,
|
|
|
- .release = pcidriver_release,
|
|
|
+#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 */
|
|
|
|
|
|
-void pcidriver_module_get(pcidriver_privdata_t *privdata) {
|
|
|
- atomic_inc(&(privdata->refs));
|
|
|
-// mod_info("Ref: %i\n", atomic_read(&(privdata->refs)));
|
|
|
-}
|
|
|
-
|
|
|
-void pcidriver_module_put(pcidriver_privdata_t *privdata) {
|
|
|
- if (atomic_add_negative(-1, &(privdata->refs))) {
|
|
|
- atomic_inc(&(privdata->refs));
|
|
|
- mod_info("Reference counting error...");
|
|
|
- } else {
|
|
|
-// mod_info("Unref: %i\n", atomic_read(&(privdata->refs)));
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- *
|
|
|
- * Called when an application open()s a /dev/fpga*, attaches the private data
|
|
|
- * with the file pointer.
|
|
|
- *
|
|
|
- */
|
|
|
-int pcidriver_open(struct inode *inode, struct file *filp)
|
|
|
+static int __init pcidriver_init(void)
|
|
|
{
|
|
|
- pcidriver_privdata_t *privdata;
|
|
|
-
|
|
|
- /* Set the private data area for the file */
|
|
|
- privdata = container_of( inode->i_cdev, pcidriver_privdata_t, cdev);
|
|
|
- filp->private_data = privdata;
|
|
|
-
|
|
|
- pcidriver_module_get(privdata);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
+ int err = 0;
|
|
|
|
|
|
-/**
|
|
|
- *
|
|
|
- * Called when the application close()s the file descriptor. Does nothing at
|
|
|
- * the moment.
|
|
|
- *
|
|
|
- */
|
|
|
-int pcidriver_release(struct inode *inode, struct file *filp)
|
|
|
-{
|
|
|
- pcidriver_privdata_t *privdata;
|
|
|
+ /* Initialize the device count */
|
|
|
+ atomic_set(&pcidriver_deviceCount, 0);
|
|
|
|
|
|
- /* Get the private data area */
|
|
|
- privdata = filp->private_data;
|
|
|
+ memset(pcidriver_privdata, 0, sizeof(pcidriver_privdata));
|
|
|
|
|
|
- pcidriver_module_put(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);
|
|
|
|
|
|
- return 0;
|
|
|
-}
|
|
|
+ /* Register driver class */
|
|
|
+ pcidriver_class = class_create(THIS_MODULE, NODENAME);
|
|
|
|
|
|
-/**
|
|
|
- *
|
|
|
- * This function is the entry point for mmap() and calls either pcidriver_mmap_pci
|
|
|
- * or pcidriver_mmap_kmem
|
|
|
- *
|
|
|
- * @see pcidriver_mmap_pci
|
|
|
- * @see pcidriver_mmap_kmem
|
|
|
- *
|
|
|
- */
|
|
|
-int pcidriver_mmap(struct file *filp, struct vm_area_struct *vma)
|
|
|
-{
|
|
|
- pcidriver_privdata_t *privdata;
|
|
|
- int ret = 0, bar;
|
|
|
-
|
|
|
- mod_info_dbg("Entering mmap\n");
|
|
|
-
|
|
|
- /* Get the private data area */
|
|
|
- privdata = filp->private_data;
|
|
|
-
|
|
|
- /* Check the current mmap mode */
|
|
|
- switch (privdata->mmap_mode) {
|
|
|
- case PCIDRIVER_MMAP_PCI:
|
|
|
- /* Mmap a PCI region */
|
|
|
- switch (privdata->mmap_area) {
|
|
|
- case PCIDRIVER_BAR0:
|
|
|
- bar = 0;
|
|
|
- break;
|
|
|
- case PCIDRIVER_BAR1:
|
|
|
- bar = 1;
|
|
|
- break;
|
|
|
- case PCIDRIVER_BAR2:
|
|
|
- bar = 2;
|
|
|
- break;
|
|
|
- case PCIDRIVER_BAR3:
|
|
|
- bar = 3;
|
|
|
- break;
|
|
|
- case PCIDRIVER_BAR4:
|
|
|
- bar = 4;
|
|
|
- break;
|
|
|
- case PCIDRIVER_BAR5:
|
|
|
- bar = 5;
|
|
|
- break;
|
|
|
- default:
|
|
|
- mod_info("Attempted to mmap a PCI area with the wrong mmap_area value: %d\n",privdata->mmap_area);
|
|
|
- return -EINVAL; /* invalid parameter */
|
|
|
- break;
|
|
|
- }
|
|
|
- ret = pcidriver_mmap_pci(privdata, vma, bar);
|
|
|
- break;
|
|
|
- case PCIDRIVER_MMAP_KMEM:
|
|
|
- /* mmap a Kernel buffer */
|
|
|
- ret = pcidriver_mmap_kmem(privdata, vma);
|
|
|
- break;
|
|
|
- default:
|
|
|
- mod_info( "Invalid mmap_mode value (%d)\n",privdata->mmap_mode );
|
|
|
- return -EINVAL; /* Invalid parameter (mode) */
|
|
|
+ if (IS_ERR(pcidriver_class)) {
|
|
|
+ mod_info("No sysfs support. Module not loaded.\n");
|
|
|
+ goto init_class_fail;
|
|
|
}
|
|
|
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-/*************************************************************************/
|
|
|
-/* Internal driver functions */
|
|
|
-int pcidriver_mmap_pci(pcidriver_privdata_t *privdata, struct vm_area_struct *vmap, int bar)
|
|
|
-{
|
|
|
+ /* Register PCI driver. This function returns the number of devices on some
|
|
|
+ * systems, therefore check for errors as < 0. */
|
|
|
#ifdef PCIDRIVER_DUMMY_DEVICE
|
|
|
- return -ENXIO;
|
|
|
+ if ((err = pcidriver_probe(NULL, NULL)) < 0) {
|
|
|
#else /* PCIDRIVER_DUMMY_DEVICE */
|
|
|
- int ret = 0;
|
|
|
- unsigned long bar_addr;
|
|
|
- unsigned long bar_length, vma_size;
|
|
|
- unsigned long bar_flags;
|
|
|
-
|
|
|
- mod_info_dbg("Entering mmap_pci\n");
|
|
|
-
|
|
|
-
|
|
|
- /* Get info of the BAR to be mapped */
|
|
|
- bar_addr = pci_resource_start(privdata->pdev, bar);
|
|
|
- bar_length = pci_resource_len(privdata->pdev, bar);
|
|
|
- bar_flags = pci_resource_flags(privdata->pdev, bar);
|
|
|
-
|
|
|
- /* Check sizes */
|
|
|
- vma_size = (vmap->vm_end - vmap->vm_start);
|
|
|
-
|
|
|
- if ((vma_size != bar_length) &&
|
|
|
- ((bar_length < PAGE_SIZE) && (vma_size != PAGE_SIZE))) {
|
|
|
- mod_info( "mmap size is not correct! bar: %lu - vma: %lu\n", bar_length, vma_size );
|
|
|
- return -EINVAL;
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
- if (bar_flags & IORESOURCE_IO) {
|
|
|
- /* Unlikely case, we will mmap a IO region */
|
|
|
-
|
|
|
- /* IO regions are never cacheable */
|
|
|
- vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot);
|
|
|
-
|
|
|
- /* Map the BAR */
|
|
|
- ret = io_remap_pfn_range_compat(vmap, vmap->vm_start, bar_addr, bar_length, vmap->vm_page_prot);
|
|
|
- } else {
|
|
|
- /* Normal case, mmap a memory region */
|
|
|
-
|
|
|
- /* Ensure this VMA is non-cached, if it is not flaged as prefetchable.
|
|
|
- * If it is prefetchable, caching is allowed and will give better performance.
|
|
|
- * This should be set properly by the BIOS, but we want to be sure. */
|
|
|
- /* adapted from drivers/char/mem.c, mmap function. */
|
|
|
-
|
|
|
- /* Setting noncached disables MTRR registers, and we want to use them.
|
|
|
- * So we take this code out. This can lead to caching problems if and only if
|
|
|
- * the System BIOS set something wrong. Check LDDv3, page 425.
|
|
|
- */
|
|
|
-
|
|
|
-// if (!(bar_flags & IORESOURCE_PREFETCH))
|
|
|
-// vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot);
|
|
|
-
|
|
|
-
|
|
|
- /* Map the BAR */
|
|
|
- ret = remap_pfn_range_compat(vmap, vmap->vm_start, bar_addr, bar_length, vmap->vm_page_prot);
|
|
|
+ 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);
|
|
|
}
|
|
|
|
|
|
- if (ret) {
|
|
|
- mod_info("remap_pfn_range failed\n");
|
|
|
- return -EAGAIN;
|
|
|
- }
|
|
|
+ return 0;
|
|
|
|
|
|
- return 0; /* success */
|
|
|
-#endif /* PCIDRIVER_DUMMY_DEVICE */
|
|
|
+init_pcireg_fail:
|
|
|
+ class_destroy(pcidriver_class);
|
|
|
+init_class_fail:
|
|
|
+ unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
|
|
|
+init_alloc_fail:
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
-pcidriver_privdata_t *pcidriver_get_privdata(int devid) {
|
|
|
- if (devid >= MAXDEVICES)
|
|
|
- return NULL;
|
|
|
+static void pcidriver_exit(void)
|
|
|
+{
|
|
|
+#ifdef PCIDRIVER_DUMMY_DEVICE
|
|
|
+ pcidriver_remove(NULL);
|
|
|
+#else
|
|
|
+ pci_unregister_driver(&pcidriver_driver);
|
|
|
+#endif /* PCIDRIVER_DUMMY_DEVICE */
|
|
|
|
|
|
- return pcidriver_privdata[devid];
|
|
|
-}
|
|
|
+ unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
|
|
|
|
|
|
-void pcidriver_put_privdata(pcidriver_privdata_t *privdata) {
|
|
|
+ if (pcidriver_class != NULL)
|
|
|
+ class_destroy(pcidriver_class);
|
|
|
|
|
|
+ mod_info("Module unloaded\n");
|
|
|
}
|
|
|
+
|
|
|
+module_init(pcidriver_init);
|
|
|
+module_exit(pcidriver_exit);
|