From 50f58c0ddada558b1552d2d2a7b74f7e037aacd7 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Fri, 16 Jun 2017 08:45:19 +0100 Subject: [PATCH] pci attempt. It probes! --- kernel_module/pci.c | 264 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 kernel_module/pci.c diff --git a/kernel_module/pci.c b/kernel_module/pci.c new file mode 100644 index 0000000..423acd9 --- /dev/null +++ b/kernel_module/pci.c @@ -0,0 +1,264 @@ +/* +http://www.zarb.org/~trem/kernel/pci/pci-driver.c +http://nairobi-embedded.org/linux_pci_device_driver.html +*/ + +#include +#include +#include +#include +#include +#include /* cdev_ */ +#include /* put_user */ + +#define MAX_DEVICE 1 +#define DEVICE_NAME "virtual_pci" +#define BAR_IO 2 +#define BAR_MEM 3 + +MODULE_LICENSE("GPL"); + +static struct pci_device_id pci_ids[] = { + { PCI_DEVICE(0x1234, 0x11e8), }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, pci_ids); + +static dev_t devno; +static int major; + +struct pci_cdev { + int minor; + struct pci_dev *pci_dev; + struct cdev *cdev; +}; + +static struct pci_cdev pci_cdev[MAX_DEVICE]; + +static void pci_cdev_del(struct pci_cdev pci_cdev[], int size, struct pci_dev *pdev) +{ + int i; + + for (i=0; i not found + * others => found + */ +static int pci_cdev_search_minor(struct pci_cdev pci_cdev[], + int size, struct pci_dev *pdev) +{ + int i, minor = -1; + + for (i=0; iprivate_data = (void *)pci_cdev_search_pci_dev(pci_cdev, MAX_DEVICE, minor); + return 0; +} + +static ssize_t pci_read(struct file *file, + char *buffer, + size_t length, + loff_t * offset) +{ + int byte_read = 0; + unsigned char value; + struct pci_dev *pdev = (struct pci_dev *)file->private_data; + unsigned long pci_io_addr = 0; + + pci_io_addr = pci_resource_start(pdev,BAR_IO); + while (byte_read < length) { + value = inb(pci_io_addr + 1); + put_user(value, &buffer[byte_read]); + byte_read++; + } + return byte_read; +} + +static ssize_t pci_write(struct file *filp, const char *buffer, size_t len, loff_t * off) { + int i; + unsigned char value; + struct pci_dev *pdev = (struct pci_dev *)filp->private_data; + unsigned long pci_io_addr = 0; + + pci_io_addr = pci_resource_start(pdev,BAR_IO); + for (i=0; i this driver doesn't handle this device + * 1 => this driver handles this device + */ +static int pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int i, ret, minor; + struct cdev *cdev; + dev_t devno; + + pr_info("pci_probe\n"); + + ret = -1; + for (i=0; idev), "error pci_cdev_add"); + goto error; + } + + devno = MKDEV(major, minor); + cdev = cdev_alloc(); + cdev_init(cdev, &pci_ops); + cdev->owner = THIS_MODULE; + + /* register cdev */ + ret = cdev_add(cdev, devno, 1); + if (ret < 0) { + dev_err(&(dev->dev), "Can't register character device\n"); + goto error; + } + pci_cdev[minor].cdev = cdev; + + dev_info(&(dev->dev), "%s The major device number is %d (%d).\n", + "Registeration is a success", MAJOR(devno), MINOR(devno)); + dev_info(&(dev->dev), "If you want to talk to the device driver,\n"); + dev_info(&(dev->dev), "you'll have to create a device file. \n"); + dev_info(&(dev->dev), "We suggest you use:\n"); + dev_info(&(dev->dev), "mknod %s c %d %d\n", DEVICE_NAME, MAJOR(devno), MINOR(devno)); + dev_info(&(dev->dev), "The device file name is important, because\n"); + dev_info(&(dev->dev), "the ioctl program assumes that's the\n"); + dev_info(&(dev->dev), "file you'll use.\n"); + + /* enable the device */ + pci_enable_device(dev); + + /* 'alloc' IO to talk with the card */ + if (pci_request_region(dev, BAR_IO, "IO-pci") == 0) { + dev_err(&(dev->dev), "Can't request BAR2\n"); + cdev_del(cdev); + goto error; + } + + /* check that BAR_IO is *really* IO region */ + if ((pci_resource_flags(dev, BAR_IO) & IORESOURCE_IO) != IORESOURCE_IO) { + dev_err(&(dev->dev), "BAR2 isn't an IO region\n"); + cdev_del(cdev); + goto error; + } + + return 1; + +error: + return 0; +} + +static void pci_remove(struct pci_dev *dev) +{ + int minor; + struct cdev *cdev; + + minor = pci_cdev_search_minor(pci_cdev, MAX_DEVICE, dev); + cdev = pci_cdev_search_cdev(pci_cdev, MAX_DEVICE, minor); + if (cdev != NULL) + cdev_del(cdev); + pci_cdev_del(pci_cdev, MAX_DEVICE, dev); + pci_release_region(dev, BAR_IO); +} + +static struct pci_driver pci_driver = { + .name = "pci", + .id_table = pci_ids, + .probe = pci_probe, + .remove = pci_remove, +}; + +static int __init pci_init_module(void) +{ + int i, first_minor, ret; + + ret = alloc_chrdev_region(&devno, 0, MAX_DEVICE, "buffer"); + major = MAJOR(devno); + first_minor = MINOR(devno); + for (i=0; i < MAX_DEVICE; i++) { + pci_cdev[i].minor = first_minor++; + pci_cdev[i].pci_dev = NULL; + pci_cdev[i].cdev = NULL; + } + ret = pci_register_driver(&pci_driver); + return 0; +} + +static void pci_exit_module(void) +{ + int i; + + pci_unregister_driver(&pci_driver); + for(i=0; i< MAX_DEVICE; i++) { + if (pci_cdev[i].pci_dev != NULL) { + cdev_del(pci_cdev[i].cdev); + } + } + unregister_chrdev_region(devno, MAX_DEVICE); +} + +module_init(pci_init_module); +module_exit(pci_exit_module);