Find the answer to your Linux question:
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.
  1. #1
    Just 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!!

  2. #2
    Just Joined!
    Join Date
    Nov 2006
    Posts
    7
    Thats is correct. it should be called from init funtions.

    For second question, its should work.

  3. #3
    Just Joined!
    Join Date
    May 2010
    Posts
    11
    Hmm i am having a problem, take a look at this code:

    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);
    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?

    Thank you!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •