Results 1 to 3 of 3
Hi i am developing a PCI driver based on an example. But on that example pci_resource_start is called inside _init and not inside probe function. Is that correct? Should i ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
- 09-08-2010 #1Just Joined!
- Join Date
- May 2010
- Posts
- 11
When should i call pci_resource_start?
Hi i am developing a PCI driver based on an example. But on that example pci_resource_start is called inside _init and not inside probe function. Is that correct? Should i change it to probe?
Second question, if i call insmod to register my driver on kernel without a device conected to computer will i have any problem?
Thank you!!
- 09-14-2010 #2Just Joined!
- Join Date
- Nov 2006
- Posts
- 7
Thats is correct. it should be called from init funtions.
For second question, its should work.
- 09-14-2010 #3Just Joined!
- Join Date
- May 2010
- Posts
- 11
Hmm i am having a problem, take a look at this code:
When i try to register it with insmod bet dev->pcvidev is null so i canot call pci_resource_start. I think thats is happening becouse the probe is not being called. The reason i belive is becouse the device is not connected to the PC. How this should be made?Code:#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/pci.h> #include <linux/init.h> #include <linux/cdev.h> //#include <asm/byteorder.h> /* PCI is little endian */ #include <asm/uaccess.h> /* copy to/from user */ #include "kint.h" #define PCI_BRIDGE_DEVICE_ID 0x0001 #define PCI_BRIDGE_VENDOR_ID 0x1895 #define PCI_DRIVER_NAME "pci_bridge" /* driver name */ #define BRIDGE_MEM_MAPPED 0 #define BRIDGE_IO_MAPPED 1 /* * PCI device IDs supported by this driver. The PCI_DEVICE macro sets * the vendor and device fields to its input arguments, sets subvendor * and subdevice to PCI_ANY_ID. It does not set the class fields. */ static struct pci_device_id pci_bridge_ids[] = { { PCI_DEVICE(PCI_BRIDGE_VENDOR_ID, PCI_BRIDGE_DEVICE_ID), }, { 0, } }; /* * For completeness, tell the module loading and hotplug systems * what PCI devices this module supports. */ MODULE_DEVICE_TABLE(pci, pci_bridge_ids); /* * pci_register_driver parameter. */ static int pci_bridge_probe(struct pci_dev *, const struct pci_device_id *); static void pci_bridge_remove(struct pci_dev *); static struct pci_driver pci_bridge_driver = { .name = PCI_DRIVER_NAME, .id_table = pci_bridge_ids, .probe = pci_bridge_probe, .remove = pci_bridge_remove, }; /* * File operations i/f. */ int pci_bridge_open(struct inode *, struct file *); int pci_bridge_release(struct inode *, struct file *); ssize_t pci_bridge_read(struct file *, char __user *, size_t, loff_t *); ssize_t pci_bridge_write(struct file *, const char __user *, size_t, loff_t *); int pci_bridge_ioctl(struct inode *pnode, struct file *filp, unsigned int cmd, unsigned long arg); // seek file operation function loff_t bridge_lseek(struct file *filp, loff_t offset, int origin); static struct file_operations pci_bridge_fops = { .owner = THIS_MODULE, .read = pci_bridge_read, .write = pci_bridge_write, .open = pci_bridge_open, .release = pci_bridge_release, .ioctl = pci_bridge_ioctl, .llseek = bridge_lseek }; static int __init pci_bridge_init(void); static void __exit pci_bridge_exit(void); /* * Driver major number. 0 = allocate dynamically. */ static int pci_bridge_init_major = 0; static int pci_bridge_major; /* * Per-device structure. */ static struct pci_bridge_dev { struct cdev cdev; /* Char device structure */ struct pci_dev *pcidev; /* PCI device pointer */ int current_resource; u32 page_addr; u8 num_of_bases; int base_map[6]; u32 bases[6]; u32 base_size[6]; u32 base_page_offset; u32 offset; } *pci_bridge_devices; /* * pci_bridge_probe - pci_driver probe function. Just enable the PCI device. * Could also check various configuration registers, find a specific PCI * device, request a specific region, etc. */ static int __devinit pci_bridge_probe(struct pci_dev *pcidev, const struct pci_device_id *id) { struct pci_bridge_dev *dev; printk("pci_bridge_probe called ...\n"); if(pcidev == NULL) { printk(KERN_NOTICE "pci_bridge_probe: PCI DEV is NULL\n"); return -EINVAL; } dev = pci_bridge_devices; // only one device for now if(dev == NULL) printk("pci_bridge_probe: device structure not allocated\n"); else { pci_enable_device(pcidev); dev->pcidev = pcidev; } return 0; } /* * pci_bridge_remove - pci_driver remove function. Release allocated resources, * etc. */ static void __devexit pci_bridge_remove(struct pci_dev *dev) { printk("pci_bridge_remove called ...\n"); } /* * pci_bridge_init - module init function. By convention, the function is * declared static, even though it is not exported to the rest of the * kernel unless explicitly requested via the EXPORT_SYMBOL macro. The * __init qualifier tells the loader that the function is only used at * module initialization time. */ static int __init pci_bridge_init(void) { struct pci_bridge_dev *dev; dev_t devno; int result; int flag = 0; unsigned short num_of_bases; u32 base_address; printk("pci_bridge_init called ...\n"); /* * Allocate the per-device structure(s). */ pci_bridge_devices = kmalloc(sizeof(struct pci_bridge_dev), GFP_KERNEL); if(pci_bridge_devices == NULL) { result = -ENOMEM; goto fail; } /* * Get a range of minor numbers to work with, asking for a dynamic * major unless directed otherwise at load time. */ if(pci_bridge_init_major) { pci_bridge_major = pci_bridge_init_major; devno = MKDEV(pci_bridge_major, 0); result = register_chrdev_region(devno, 1, PCI_DRIVER_NAME); } else { result = alloc_chrdev_region(&devno, 0, 1, PCI_DRIVER_NAME); pci_bridge_major = MAJOR(devno); } if(result < 0) { printk(KERN_NOTICE "pci_bridge: can't get major %d\n", pci_bridge_major); goto fail; } dev = pci_bridge_devices;/* only one device for now */ /* * Initialize and add this device's character device table entry. */ //dev->pcidev = NULL; cdev_init(&dev->cdev, &pci_bridge_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &pci_bridge_fops; dev->offset = 0; result = cdev_add(&dev->cdev, devno, 1); if(result) { printk(KERN_NOTICE "Error %d adding %s device", result, PCI_DRIVER_NAME); goto fail; } else { flag = 1; } if((result = pci_register_driver(&pci_bridge_driver)) != 0) { printk(KERN_NOTICE "Error %d registering %s PCI device",result, PCI_DRIVER_NAME); goto fail; } if(dev->pcidev == NULL) { printk(KERN_NOTICE "PCI DEV is NULL, probe failed?\n"); goto fail; } base_address = pci_resource_start(dev->pcidev, 0); printk("<1> First base address register found at %08X \n ", pci_resource_start(dev->pcidev, 0)); num_of_bases = 0; while ((base_address = pci_resource_start(dev->pcidev, num_of_bases))!= 0x00000000 && (num_of_bases < 6)) { unsigned long flags; flags = pci_resource_flags(dev->pcidev, num_of_bases); dev->bases[num_of_bases] = base_address; dev->base_size[num_of_bases] = pci_resource_end(dev->pcidev, num_of_bases) - base_address + 1; // check if resource is IO mapped if (flags & IORESOURCE_IO) dev->base_map[num_of_bases] = BRIDGE_IO_MAPPED; else dev->base_map[num_of_bases] = BRIDGE_MEM_MAPPED; num_of_bases++; } if (num_of_bases < 1) printk("<1>No implemented base address registers found! \n "); dev->current_resource = - 1; // store number of bases in structure dev->num_of_bases = num_of_bases; printk("num_of_bases found %d \n", num_of_bases); // display information about all base addresses found in this procedure for (num_of_bases = 0; num_of_bases < dev->num_of_bases; num_of_bases++) { printk("<1>BAR%d range from %08X to %08X \n ", num_of_bases, dev->bases[num_of_bases], dev->bases[num_of_bases] + dev->base_size[num_of_bases]); } return 0; fail: pci_bridge_exit(); return result; } /* * pci_bridge_exit - module exit function. Release resources allocated * by pci_bridge_init. */ static void __exit pci_bridge_exit(void) { printk("pci_bridge_exit called ...\n"); if(pci_bridge_devices) { struct pci_bridge_dev *dev; dev = &pci_bridge_devices[0]; cdev_del(&dev->cdev); kfree(pci_bridge_devices); pci_bridge_devices = NULL; } unregister_chrdev_region(MKDEV(pci_bridge_major, 0), 1); pci_bridge_major = 0; pci_unregister_driver(&pci_bridge_driver); } /* * pci_bridge_open - open file processing. */ int pci_bridge_open(struct inode *inode, struct file *filep) { struct pci_bridge_dev *dev; dev = container_of(inode->i_cdev, struct pci_bridge_dev, cdev); filep->private_data = dev; // used by read, write, etc dev->current_resource = -1; /* Success */ return 0; } /* * pci_bridge_release - close processing. */ int pci_bridge_release(struct inode *inode, struct file *filep) { /* Success */ return 0; } /* * seek file operation function */ loff_t bridge_lseek(struct file *filp, loff_t offset, int origin) { struct pci_bridge_dev *dev; loff_t requested_offset; int resource_num; dev = filp->private_data; resource_num = dev->current_resource; switch (origin) { case SEEK_CUR:requested_offset = dev->offset + offset; break; case SEEK_END:requested_offset = dev->base_size[resource_num] + offset; break; default:requested_offset = offset; break; } if ((requested_offset < 0) || (requested_offset > dev->base_size[resource_num])) return -EFAULT; dev->offset = requested_offset; return requested_offset; } /* * pci_bridge_read - read processing. */ ssize_t pci_bridge_read (struct file *filp, char *buf, size_t count, loff_t *offset_out ) { struct pci_bridge_dev *dev; unsigned long current_address; unsigned long actual_count; unsigned long offset; int resource_num; int i; unsigned int value; unsigned int *kern_buf; unsigned int *kern_buf_tmp; unsigned long size; int result; dev = filp->private_data; offset = dev->offset; resource_num = dev->current_resource; size = dev->base_size[resource_num]; current_address = dev->page_addr + dev->base_page_offset + dev->offset; if (dev->current_resource < 0) return -ENODEV; if (offset == size) return 0; if ( (offset + count) > size ) actual_count = size - offset; else actual_count = count; // verify range if it is OK to copy from if ((result = access_ok(VERIFY_WRITE, buf, actual_count)) ==0) return result; kern_buf = kmalloc(actual_count, GFP_KERNEL | GFP_DMA); kern_buf_tmp = kern_buf; if (kern_buf <= 0) return 0; memcpy_fromio(kern_buf, current_address, actual_count); i = actual_count/4; while(i--) { // value = readl(current_address); value = *(kern_buf); put_user(value, ((unsigned int *)buf)); buf += 4; ++kern_buf; // current_address += 4; } kfree(kern_buf_tmp); dev->offset = dev->offset + actual_count; *(offset_out) = dev->offset; return actual_count; } /* * pci_bridge_write - write processing. */ ssize_t pci_bridge_write (struct file *filp, const char *buf, size_t count, loff_t *offset_out) { struct pci_bridge_dev *dev; unsigned long current_address; unsigned long actual_count; unsigned long offset; int resource_num; int i; int value; unsigned long size; int result; int *kern_buf; int *kern_buf_tmp; dev = filp->private_data; current_address = dev->page_addr + dev->base_page_offset + dev->offset; resource_num = dev->current_resource; size = dev->base_size[resource_num]; offset = dev->offset; if (dev->current_resource < 0) return -ENODEV; if (offset == size) return 0; if ( (offset + count) > size ) actual_count = size - offset; else actual_count = count; // verify range if it is OK to copy from if ((result = access_ok(VERIFY_READ, buf, actual_count)) == 0) return result; kern_buf = kmalloc(actual_count, GFP_KERNEL | GFP_DMA); kern_buf_tmp = kern_buf; if (kern_buf <= 0) return 0; i = actual_count/4; while(i--) { get_user(value, ((int *)buf)); //writel(value, current_address); *kern_buf = value; buf += 4; //current_address += 4; ++kern_buf; } memcpy_toio(current_address, kern_buf_tmp, actual_count); kfree(kern_buf_tmp); dev->offset = dev->offset + actual_count; *(offset_out) = dev->offset; return actual_count; } /* * helper function for memory remaping */ int open_mem_mapped(struct pci_bridge_dev *dev) { int resource_num = dev->current_resource; unsigned long num_of_pages = 0; unsigned long base = dev->bases[resource_num]; unsigned long size = dev->base_size[resource_num]; //printk("\n current resource=%d , size = %d, base=%08X", dev->current_resource , size, dev->bases[resource_num]); if (!(num_of_pages = (unsigned long)(size/PAGE_SIZE))); num_of_pages++; dev->base_page_offset = base & ~PAGE_MASK; if ((dev->base_page_offset + size) < (num_of_pages*PAGE_SIZE)) num_of_pages++; // remap memory mapped space dev->page_addr = (unsigned long)ioremap(base & PAGE_MASK, num_of_pages * PAGE_SIZE); if (dev->page_addr == 0x00000000) return -ENOMEM; return 0; } /* * ioctl: see kint.h for the meaning of args */ int pci_bridge_ioctl(struct inode *pnode, struct file *filp, unsigned int cmd, unsigned long arg) { int error = 0; unsigned long base; unsigned long base_size; struct pci_bridge_dev *dev; dev = filp->private_data; if (_IOC_TYPE(cmd) != BRIDGE_IOC_NUM) return -EINVAL; if (_IOC_NR(cmd) > BRIDGE_IOC_MAX_NUM) return -EINVAL; switch (cmd) { case BRIDGE_IOC_CURRESGET: // current resource - they start at 1 return (dev->current_resource + 1); case BRIDGE_IOC_CURRESSET: // check if resource is in a range of implemented resources if (arg < 0 ) return -EINVAL; // unmap previous resource if it was mapped if (dev->current_resource >= 0) { iounmap((void *)dev->page_addr); } if (arg == 0) { // previous resource unmaped - that's all dev->current_resource = -1; return 0; } if (dev->num_of_bases < arg) return -ENODEV; // IO mapped not supported yet if (dev->base_map[arg-1] == BRIDGE_IO_MAPPED) { // set current resource to none, since it was unmapped dev->current_resource = -1; return -ENODEV; } dev->current_resource= (int)(arg-1); // remap new resource if ( (error = open_mem_mapped(dev)) ) { dev->current_resource = -1; return error; } return 0; case BRIDGE_IOC_CURBASE: // check if any resource is currently activated if (dev->current_resource>=0) { base = dev->bases[dev->current_resource]; printk("\n CURR_RES = %d",dev->current_resource ); } else base = 0x00000000; *(unsigned long *)arg = base; return 0; case BRIDGE_IOC_CURBASEMAP: // check if any resource is currently activated if (dev->current_resource>=0) base = dev->page_addr; else base = 0x00000000; *(unsigned long *)arg = base; return 0; case BRIDGE_IOC_CURBASESIZE: // check if any resource is currently activated if (dev->current_resource>=0) base_size = dev->base_size[dev->current_resource]; else base_size = 0x00000000; *(unsigned long *)arg = base_size; return 0; case BRIDGE_IOC_NUMOFRES: return (dev->num_of_bases); default: return -EINVAL; } } MODULE_LICENSE("GPL"); module_init(pci_bridge_init); module_exit(pci_bridge_exit);
Thank you!


Reply With Quote
