Linux - KernelThis forum is for all discussion relating to the Linux kernel.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Hi i am developing a PCI driver based on an example and LDD book and i have some questions.
Can i register my driver with insmod if my PCI card is not conected?
Looking the example code i got on hands the function pci_resource_start is called inside the init but to that work the probe is suposed to be already called. If do not have my card on the PC will probe be called? If not, what will happen if i call pci_resource_start with a null pointer? Am i doing any mess? I did build my module and tryed register it. it worked and i could see it with lsmod. But when i use rmmod and look with lsmod again he is still there. Whats wrong?
The driver code i am following as example:
/*
* pci_bridge-driver.c - template Linux driver for the opencores' pci bridge . Works on * kernel 2.6.x
*
* tested on Xubuntu, kernel 2.6.20-15-generic
*
* Author: Paolo Prete <p4olo_prete@yahoo.it>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
* RIGHTS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* Build/use notes (you'll probably need to be superuser to run most of
* the steps below):
*
* 1) How to build the driver:
*
* $ make
*
* 2) How to install the driver:
*
* $ insmod pci_bridge-driver.ko
*
* TODO: change the code and use misc device and udev, so to avoid the stuff below (3-4) !!
* 3) If pci_bridge_init_major (below) is 0, then obtain the major number:
*
* $ cat /proc/devices
*
* Look for the line that contains the string "pci_bridge". The major
* number is to the left.
*
* 4) Make the pci_bridge device special file. Substitute the major
* number obtained above for <major_number>.
*
* $ mknod /dev/pci_bridge c <major_number> 0
*
* 5) How to remove the driver:
*
* $ rmmod pci_bridge-driver
*/
#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 */
/*
* 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_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;
}
/*
* 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");
/*
* 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 */
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]);
}
/*
* 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;
/*
* 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;
/*
* 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++;
/*
* 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);
A full pci driver I haven't, I only edit existing ones for my devices. Yes you have to recompile, make clean first on that folder to ensure the configuration takes effect.
Include it in your kernel source, .config, and Makefile. If it is already there, run make menuconfig and specify Y not M on its menu.
I am noob on linux, can you help me on this taks? Actually i just got my driver to work but i have to register it every time i want to use my pci card. How can i include it on kernel source, .config and Makefile, actually which Makefile? There are so many!!! Thank you
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.