阅读:3387回复:13
请教Linux下PCI驱动初始化问题
rt
在做一块PCI采集卡的驱动,2.4下,用的9052,碰到个问题,请教一下 PCI驱动的file_operations结构是如何被初始化的啊?在网上找了几个驱动看了看,没看到这部分,pci_module_init()初始化的是一个pci_driver结构,而常规的char设备初始化(register_chrdev())的是file_operations结构,这里如何与file_operations联系到一起的啊? 请高手指教一下,或者能提供一个完整的PCI驱动学习一下,谢谢的说! |
|
沙发#
发布于:2007-05-04 10:18
pci只有sysfs文件系统
1 bus_register(&pci_bus_type) : 注册bus总线 2 int __pci_register_driver(struct pci_driver *drv, struct module *owner)注册pci驱动 int __pci_register_driver(struct pci_driver *drv, struct module *owner) { int error; /* initialize common driver fields */ drv->driver.name = drv->name; drv->driver.bus = &pci_bus_type; drv->driver.owner = owner; drv->driver.kobj.ktype = &pci_driver_kobj_type;//注意这里 spin_lock_init(&drv->dynids.lock); INIT_LIST_HEAD(&drv->dynids.list); /* register with core */ error = driver_register(&drv->driver); //注意这里 if (!error) error = pci_create_newid_file(drv);//注意这里 return error; } 3 driver_register中调用了 int bus_add_driver(struct device_driver * drv) { struct bus_type * bus = get_bus(drv->bus); int error = 0; if (bus) { pr_debug("bus %s: add driver %s\n", bus->name, drv->name); error = kobject_set_name(&drv->kobj, "%s", drv->name); if (error) { put_bus(bus); return error; } drv->kobj.kset = &bus->drivers; if ((error = kobject_register(&drv->kobj))) { put_bus(bus); return error; } driver_attach(drv); klist_add_tail(&drv->knode_bus, &bus->klist_drivers); module_add_driver(drv->owner, drv); driver_add_attrs(bus, drv); add_bind_files(drv);//注意这里 } return error; } 4 static void add_bind_files(struct device_driver *drv) { driver_create_file(drv, &driver_attr_unbind); driver_create_file(drv, &driver_attr_bind); } int driver_create_file(struct device_driver * drv, struct driver_attribute * attr) { int error; if (get_driver(drv)) { error = sysfs_create_file(&drv->kobj, &attr->attr); //注册sysfs文件系统 put_driver(drv); } else error = -EINVAL; return error; } 5 pci_create_newid_file同样也注册了文件系统 |
|
|
板凳#
发布于:2007-05-09 10:46
先感谢一下,hoho
但是还没看的很清楚,需要在阅读一下代码 先说一下偶看到的东西,pci_module_init()中仅完成了驱动和设备的关联啊,从代码上看,仅仅能probe,能remove,但是设备的具体操作,就是那些open,close,ioctrl等函数(file_operations结构成员)是如何和设备关联的啊,当然在chr设备中是在初始化时调用register_chrdev(&file_operations)将设备和操作建立关联的。但是PCI设备呢?当用户在应用程序中open设备时,这个open动作是怎么调用到或者说怎么找到驱动里的open函数呢?还是有些不明白 驱动结构参照 http://industry.ccidnet.com/art/302/20050518/252693_3.html 这篇文章 下面是对pci_module_init()的分析 pci_module_init(struct pci_driver *drv)->pci_register_driver(struct pci_driver *drv); pci_register_driver(struct pci_driver *drv)的原型如下: int pci_register_driver(struct pci_driver *drv) { struct pci_dev *dev; int count = 0; list_add_tail(&drv->node, &pci_drivers); //把drv链接到双向链表pci_drivers pci_for_each_dev(dev) { //正向遍历全局设备链表pce_devices中的每一个PCI 设备 if (!pci_dev_driver(dev)) //如果设备还没有相应的驱动 count += pci_announce_device(drv, dev); //如果找到相应的驱动则返回1 } return count; } 函数pci_dev_driver() struct pci_driver * pci_dev_driver(const struct pci_dev *dev) { if (dev->driver) return dev->driver; else { int i; for(i=0; i<=PCI_ROM_RESOURCE; i++) if (dev->resource.flags & IORESOURCE_BUSY) return &pci_compat_driver; } return NULL; } |
|
地板#
发布于:2007-05-09 15:31
晕。
不知道你用的那个版本,我说的是2.6内核的。2.6内核的改为sysfs系统了。主要看 int driver_create_file(struct device_driver * drv, struct driver_attribute * attr) { int error; if (get_driver(drv)) { error = sysfs_create_file(&drv->kobj, &attr->attr); //注册sysfs文件系统 put_driver(drv); } else error = -EINVAL; return error; } |
|
|
地下室#
发布于:2007-05-09 16:10
说过了啊,2.4下啊,hoho,redhat9
一样感谢!!! 也希望其他朋友帮忙解答一下了 |
|
5楼#
发布于:2007-05-09 19:52
sorry,没看到。呵呵
|
|
|
6楼#
发布于:2007-05-09 22:29
没看到无所谓啊
问题呢?hoho 问了好几个地方了,就你和学校的一个兄弟给个回答,而且都是斑竹... |
|
7楼#
发布于:2007-05-10 13:09
static int __init pci_proc_init(void)
{ if (pci_present()) { struct proc_dir_entry *entry; struct pci_dev *dev; /* 创建文件操作 */ proc_bus_pci_dir = proc_mkdir("pci", proc_bus); entry = create_proc_entry("devices", 0, proc_bus_pci_dir); if (entry) entry->proc_fops = &proc_bus_pci_dev_operations; /* 这里pci_proc_init是__init操作,而其他pci设备初始化应该是__devinit, * * 因此把该文件操作附加到所有已经创建的pci设备上。 * * 可以看到pci_proc_attach_device是导出符号,对于hotplug设备,他们热差把时调用pci_bus_add_device等附加到设备 */ pci_for_each_dev(dev) { pci_proc_attach_device(dev); } entry = create_proc_entry("pci", 0, NULL); if (entry) entry->proc_fops = &proc_pci_operations; } return 0; } |
|
|
8楼#
发布于:2007-05-10 13:46
先感谢一下,hoho
斑竹的意见是不是通过proc实现?刚找到一个利用proc实现的例子(后面会给出) 现在假设用户的动作有2个,一个是配置本地寄存器(local端),另外一个是读写数据 在配置空间内,要用到基地址1(本地配置寄存器的PCI地址-映射到I/O的)、基地址2(本地地址空间0) 用基地址0进行动作一,也就是通过这个地址对本地寄存器进行配置 用基地址2进行动作二,也就是通过这个地址进行数据读写,假设卡是个32位的I/O卡,那么对基地址2到基地址2+3范围内的存储空间进行读写就是实现了数据的读写 那么write函数结构 write() { 。。。 读配置空间,得到需要的地址(基地址1或2) 将数据写入得到的地址范围内 。。。 } read() { 。。。 读配置空间,得到需要的地址(基地址1或2) 将数据从得到的地址范围内读出 。。。 } 想的不仔细,大概样子就这样,不知道成不成,呵呵 前面说到的驱动框架 #ifndef CONFIG_PCI #define CONFIG_PCI #endif #ifndef CONFIG_PROC_FS #define CONFIG_PROC_FS #endif #include <linux/pci.h> #include <linux/proc_fs.h> #include <linux/module.h> #include <asm/uaccess.h> /*****************************************\ |* IOCTL MACRO DEFINITIONS *| \*****************************************/ #define TRNDRV_IOC_MAGIC 'k' #define TRNDRV_IOCREADCONFREGS _IOR(TRNDRV_IOC_MAGIC, 0, 0x40) #define TRNDRV_IOCREADOPERREGS _IOR(TRNDRV_IOC_MAGIC, 1, 0x40) #define TRNDRV_IOC_MAXNR 2 /*****************************************\ |* IOCTL MACRO DEFINITIONS *| \*****************************************/ #define VENDORID 0x1234 // unsigned short for vendor id of the PCI card #define DEVICEID 0x4321 // unsigned short for device id of the PCI card /*****************************************\ |* GLOBAL DEFINITIONS *| \*****************************************/ struct pci_dev *pdev = NULL; int readconfregs(u8 *regs); int readoperregs(u8 *regs); /****************************************\ |* Driver "trndrv.o"`s entries *| \****************************************/ loff_t trndrv_llseek(struct file *filp, loff_t off, int whence) { loff_t newpos = -EINVAL; return newpos; } int trndrv_open(struct inode *inode, struct file *filp) { return 0; } int trndrv_release(struct inode *inode, struct file *filp) { return 0; } ssize_t trndrv_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) { return 0; } ssize_t trndrv_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) { return 0; } int trndrv_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { u8 regs[256]; int i; switch (cmd) { case TRNDRV_IOCREADCONFREGS: if (readconfregs(regs)) return -PCIBIOS_BAD_REGISTER_NUMBER; for (i = 0; i < 256; i ++) put_user(regs, (u8 *)(arg + i)); break; case TRNDRV_IOCREADOPERREGS: readoperregs(regs); break; default: return -EINVAL; } return 0; } struct file_operations trndrv_fops = { llseek: trndrv_llseek, read: trndrv_read, write: trndrv_write, ioctl: trndrv_ioctl, open: trndrv_open, release: trndrv_release, }; /*****************************************\ |* Self-defined Functions *| \*****************************************/ struct proc_dir_entry *create_proc_fops_entry(const char *name, mode_t mode, struct proc_dir_entry *base, void * data) { struct proc_dir_entry *result = create_proc_entry(name, mode, base); if (result) { result->proc_fops = &trndrv_fops; result->data = data; } return result; } int readconfregs(u8 *regs) { int result; int i; for (i = 0; i < 256; i ++) { result = pci_read_config_byte(pdev, i, regs + i); if (result) { printk(KERN_EMERG "reading config regs error\n"); return result; } } return 0; } int readoperregs(u8 *regs) { return 0; } void cleanup_module(void) remove_proc_entry("trndrv", 0); } int init_module(void) { create_proc_fops_entry("trndrv", 0, NULL, NULL); pdev = pci_find_device(VENDORID, DEVICEID, NULL); if (pdev == NULL) { printk(KERN_EMERG "no pci card specified\n"); return -PCIBIOS_DEVICE_NOT_FOUND; } return 0; } 用户部分程序片段 ... int fd; char *fname = "/proc/trndrv"; void configview(unsigned char *confregs); void oprview(char *arg); int main(int argc, char **argv) { unsigned char confregs[256]; unsigned long base_address; unsigned char interrupt_line; int result; fd = open(fname, O_RDONLY); if (fd < 0) { printf("%s: %s: %s\n", argv[0], fname, strerror(errno)); exit(1); } result = ioctl(fd, TRNDRV_IOCREADCONFREGS, confregs); if (result < 0) { printf("%s: %s: reading config regs error\n", argv[0], fname); exit(1); } ... |
|
9楼#
发布于:2007-05-10 13:49
在这个驱动代码内,偶终于看到了file_operations结构和设备关联起来了,网上看到的大部分PCI驱动结构都是一个人的,在里面没发现这个关联过程,不知道利用proc来实现PCI驱动可行不?不过在个例子里,用户程序用的也是proc,按照这个做法,似乎不用建立设备文件,即不需要mknod了,不知道偶的想法是否正确
再一次感谢 |
|
10楼#
发布于:2007-05-10 14:21
首先文件系统仅是方便用户对设备操作而提供的外部接口,不提供设备那么你想操作什么? 系统又如何获取设备的中断处理等?
其次对设备的配置一般采用ioctl,对设备的数据读取采用read/write,否则在read/write中自己区分想要让驱动工作。 最后建议对看看Linux内核自带的pci驱动,了解他们如何工作的,尽量不要去看编外的代码。原理可以,但是现实实现最好还是看kernel自己成熟的code。 |
|
|
11楼#
发布于:2007-06-21 11:51
proc只是个伪文件系统,做调试用的吧?
|
|
|
12楼#
发布于:2007-09-03 20:29
IO卡简单的数字量读写得话。都用ioctl就挺好。
|
|
|
13楼#
发布于:2007-09-30 10:46
1.首先想咨询一下楼主,你有没有尝试过proc文件系统,能否实现对PCI设备的读写操作,因为在很多资料里都介绍proc是调试文件。
2.如果这样不行PCI数据是怎样收发的。 谢谢! |
|