PowerPC架构下Linux系统读写PCI设备
2016-01-21 10:50
826 查看
最近需要完成一个linux系统下的PCI驱动程序,然而处理器是PowerPC架构,以为在linux用户态就可以实现,但是发现不行。
上一篇文章中通过I/O端口访问了PCI设备,但是x86家族之外的的处理器都不为端口提供独立的地址空间,因此PowerPC下无法直接通过地址用in/out方法来访问PCI设备。
于是我使用另外一种机制:将PCI设备的空间映射到内存中。
同时 还需要创建一个 字符设备驱动 可以让用户从用户空间传数据
先从 用户空间传数据到内核空间 然后 在内核空间操作PCI的内存
操作PCI内存的方式 是 读取 bar0的基地址 然后 ioremap 返回的地址 之后就可以在内核空间读写
原理图如下:
同时在内核模块加载时调用pci_register_driver 和卸载时调用pci_unregister_driver 函数。一个简单的模板代码如下:
字符驱动
上一篇文章中通过I/O端口访问了PCI设备,但是x86家族之外的的处理器都不为端口提供独立的地址空间,因此PowerPC下无法直接通过地址用in/out方法来访问PCI设备。
于是我使用另外一种机制:将PCI设备的空间映射到内存中。
实现思路
完成PCI驱动代码,确保特定的PCI设备被linux识别同时 还需要创建一个 字符设备驱动 可以让用户从用户空间传数据
先从 用户空间传数据到内核空间 然后 在内核空间操作PCI的内存
操作PCI内存的方式 是 读取 bar0的基地址 然后 ioremap 返回的地址 之后就可以在内核空间读写
原理图如下:
PCI驱动
pci驱动代码很简单,我们提供设备ID和厂商ID,并指定数据结构pci_driver中的id_table以及初始化函数probe和移除函数remove。同时在内核模块加载时调用pci_register_driver 和卸载时调用pci_unregister_driver 函数。一个简单的模板代码如下:
#define PCI_VENDOR_ID_XILINX 0x10ee //change to your pci device #define PCI_DEVICE_ID_XILINX 0x7021 #define MODULE_NAME "xilinx_7021" static int __init xilinx_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id); static int xilinx_release(struct inode *inode, struct file *file); static struct pci_device_id xilinx_pci_tbl [] __initdata = { {PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILINX, PCI_ANY_ID, PCI_ANY_ID}, {0,} }; static struct pci_driver xilinx_pci_driver = { name: MODULE_NAME, id_table: xilinx_pci_tbl, probe: xilinx_probe, remove: xilinx_release };
字符驱动
字符驱动提供了操作设备内存的方法,包括读写,从而用户打开设备后可以方便的读写设备内存。本文不谈及实现linux字符驱动实现的细节,详情可以参考博客:字符驱动
ioremap
ioremap函数将PCI内存空间转换到内核空间,从而驱动程序可以访问任意的PCI内存地址。因此当我们加载了PCI设备时,我们可以将PCI配置空间的bar0地址保存,之后读写的时候将bar0地址用ioremap函数转换,然后用ioread/iowrite函数进行读写,如下例:virt_addr =ioremap(bar0_s,bar0_l); read_result = ioread32(virt_addr+4*size); iowrite32(writenum,virt_addr+4*size);
用户空间代码
用户空间代码相对简单,只要就行代开对应大的字符设备驱动,然后读写即可。代码如下:int main(int argc, const char *argv[]) { int fd ; int n; fd = open("/dev/dev_driver",O_RDWR);//对应的字符设备名称,由自己定义 if(fd < 0){ perror("Fail ot open"); return -1; } printf("open successful ,fd = %d\n",fd); unsigned long writenum=2112; n = write(fd,&writenum,sizeof(long)); if(n < 0){ perror("Fail to write"); return -1; } printf("write %d bytes!\n",n); unsigned long read_result; read(fd,&read_result,sizeof(long)); printf("the my_driver is %d\n",read_result); return 0; }
完整的代码:
#include <linux/init.h> #include <linux/module.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/slab.h> #include <asm/uaccess.h> #include <linux/pci.h> #include <asm/io.h> #include <linux/ioport.h> #define MAJOR_NUM 250 struct pci_dev *g_pci_dev; MODULE_LICENSE("GPL"); struct mycdev { int len; unsigned char buffer[50]; struct cdev cdev; }; static dev_t dev_num = {0}; struct mycdev *gcd; struct class *cls; unsigned long bar0_ss; void * virt_addr; bool request_mem; unsigned long bar0_s; unsigned long bar0_e; unsigned long bar0_l; unsigned long bar1_s; unsigned long bar1_e; unsigned long bar1_l; #define PCI_VENDOR_ID_XILINX 0x10ee #define PCI_DEVICE_ID_XILINX 0x7021 #define MODULE_NAME "xilinx_7021" static int __init xilinx_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id); static int xilinx_release(struct inode *inode, struct file *file); static struct pci_device_id xilinx_pci_tbl [] __initdata = { {PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILINX, PCI_ANY_ID, PCI_ANY_ID}, {0,} }; struct xilinx_card { unsigned int magic; struct xilinx_card *next; }; static struct pci_driver xilinx_pci_driver = { name: MODULE_NAME, id_table: xilinx_pci_tbl, probe: xilinx_probe, remove: xilinx_release }; static int xilinx_probe_pci(struct pci_dev *pci_dev) { int err; void * virt_addr; unsigned long read_result; if (pci_enable_device(pci_dev)) return -EIO; pci_set_master(pci_dev); err = pci_set_dma_mask(pci_dev, 0xFFFFFFFFULL); if (err) { printk(KERN_ERR "xilinx: No usable DMA configuration, " "aborting.\n"); } printk("**************************************\n"); printk("**************************************\n"); printk("vendor:%0x\n", pci_dev->vendor); printk("device:%0x\n", pci_dev->device); printk("subvendor:%0x\n", pci_dev->subsystem_vendor); printk("subdevice:%0x\n", pci_dev->subsystem_device); printk("class:%0x\n", pci_dev->class); printk("revision:%0x\n", pci_dev->revision); printk("rom_base_reg:%0x\n", pci_dev->rom_base_reg); printk("pin:%0x\n", pci_dev->pin); printk("irq:%0x\n", pci_dev->irq); printk("**************************************\n"); printk("------------------------------------------\n"); bar0_s = pci_resource_start(pci_dev, 0); bar0_ss = pci_resource_start(pci_dev, 0); bar0_e = pci_resource_end(pci_dev, 0); bar0_l = pci_resource_len(pci_dev, 0); bar1_s = pci_resource_start(pci_dev, 1); bar1_e = pci_resource_end(pci_dev, 1); bar1_l = pci_resource_len(pci_dev, 1); printk("bar%d_s:0x%0x\n", 0, bar0_s); printk("bar%d_e:0x%0x\n", 0, bar0_e); printk("bar%d_l:0x%0x\n", 0, bar0_l); printk("bar%d_s:0x%0x\n", 1, bar1_s); printk("bar%d_e:0x%0x\n", 1, bar1_e); printk("bar%d_l:0x%0x\n", 1, bar1_l); int bar = bar0_l>>20; printk("size of the bar0/20 is: (%d) \n", bar); printk("------------------\n"); return 0; } static int __init xilinx_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { xilinx_probe_pci(pci_dev); printk("do something pci xilinx module init \n"); if(bar0_l != 0x0) { printk("this memory is not being used ! \n"); if(true)//request_mem_region(bar0_s,sizeof(long),"dev_driver")) { request_mem = true; printk("request this memory success \n"); virt_addr =ioremap(bar0_s,bar0_l); printk("ioremap success \n"); } else { request_mem = false; printk("request this memory failed \n"); return -ENODEV; } }else { printk("bar0_l is 0 \n"); } } static int xilinx_release(struct inode *inode, struct file *file) { if(bar0_l != 0x0) { if(request_mem) { iounmap(bar0_s); //release_mem_region(bar0_s, sizeof(long)); } //iounmap(bar0_s); printk("pci xilinx module release\n"); } return 0; } /////////////////////////////////////////////////////////////////////// //open static int dev_fifo_open(struct inode *inode, struct file *file) { printk("dev_fifo_open success!\n"); return 0; } static ssize_t dev_fifo_read(struct file *file, char __user *ubuf, size_t size, loff_t *ppos) { int n; int ret; unsigned long read_result; if (bar0_l != 0x0) { if(request_mem) { read_result = ioread32(virt_addr); printk("Value at (0x%0x): 0x%X\n", virt_addr, read_result); printk("dev_fifo_read success!\n"); }else{ printk("can't use this region \n"); read_result =1; } ret = copy_to_user(ubuf,&read_result, sizeof(long)); if(ret != 0) { printk("dev_fifo_read failed!\n"); return -EFAULT; } } return sizeof(long); } static ssize_t dev_fifo_write(struct file *file, const char __user *ubuf, size_t size, loff_t *ppos) { int n; int ret; unsigned long writenum; ret = copy_from_user(&writenum, ubuf, sizeof(long)); if(ret != 0) return -EFAULT; printk("user write values :%d \n",writenum); unsigned long read_result; //int writenum = ; if (bar0_l != 0x0) { if (request_mem) { int i=0; int size = sizeof(long); read_result = ioread32(virt_addr+i); printk("Value at (0x%0x): 0x%X ", virt_addr+i, read_result); int bar = bar0_l>>15; printk("size of the bar0/15 is: (%d) ", bar); for(;i<bar;) { read_result = ioread32(virt_addr+i); printk("0x%X ",read_result); if(i %32 == 0) printk("\n"); i+=size; } // read 0 read_result = ioread32(virt_addr); printk("Value at (0x%0x): 0x%X ", virt_addr, read_result); iowrite32(writenum,virt_addr); read_result = ioread32(virt_addr); printk("Written 0x%X; readback %d\n", virt_addr, read_result); printk("Written 0x%X; readback %0x\n", virt_addr, read_result); //read +4 read_result = ioread32(virt_addr+4*size); printk("Value at (0x%0x): 0x%X ", virt_addr+4*size, read_result); iowrite32(writenum,virt_addr+4*size); read_result = ioread32(virt_addr+4*size); printk("Written 0x%X; readback %d\n", virt_addr+4*size, read_result); printk("Written 0x%X; readback %0x\n", virt_addr+4*size, read_result); printk("dev_fifo_write success!\n"); }else{ printk("this memeory space can't be used ! \n"); } } return sizeof(long); } static const struct file_operations fifo_operations = { .owner = THIS_MODULE, .open = dev_fifo_open, .read = dev_fifo_read, .write = dev_fifo_write, }; int __init dev_fifo_init(void) { pci_register_driver(&xilinx_pci_driver); int ret; struct device *device; gcd = kzalloc(sizeof(struct mycdev), GFP_KERNEL); if(!gcd){ return -ENOMEM; } dev_num = MKDEV(MAJOR_NUM, 0); ret = register_chrdev_region(dev_num,1,"dev_driver"); if(ret < 0){ ret = alloc_chrdev_region(&dev_num,0,1,"dev_driver"); if(ret < 0){ printk("Fail to register_chrdev_region\n"); goto err_register_chrdev_region; } } cls = class_create(THIS_MODULE, "dev_driver"); if(IS_ERR(cls)){ ret = PTR_ERR(cls); goto err_class_create; } cdev_init(&gcd->cdev,&fifo_operations); ret = cdev_add(&gcd->cdev,dev_num,1); if (ret < 0) { goto err_cdev_add; } device = device_create(cls,NULL,dev_num,NULL,"dev_driver"); if(IS_ERR(device)){ ret = PTR_ERR(device); printk("Fail to device_create\n"); goto err_device_create; } printk("*******************************\n"); printk("Register dev_fifo to system,ok!\n"); return 0; err_device_create: cdev_del(&gcd->cdev); err_cdev_add: class_destroy(cls); err_class_create: unregister_chrdev_region(dev_num, 1); err_register_chrdev_region: return ret; } void __exit dev_fifo_exit(void) { pci_unregister_driver(&xilinx_pci_driver); device_destroy(cls,dev_num ); class_destroy(cls); cdev_del(&gcd->cdev); unregister_chrdev_region(dev_num, 1); printk("unregister this fifo module \n"); return; } module_init(dev_fifo_init); module_exit(dev_fifo_exit);
相关文章推荐
- Linux socket 初步
- Linux Kernel 4.0 RC5 发布!
- linux lsof详解
- linux 文件权限
- Linux 执行数学运算
- 10 篇对初学者和专家都有用的 Linux 命令教程
- Linux 与 Windows 对UNICODE 的处理方式
- Ubuntu12.04下QQ完美走起啊!走起啊!有木有啊!
- 解決Linux下Android开发真机调试设备不被识别问题
- 运维入门
- 运维提升
- Linux 自检和 SystemTap
- Ubuntu Linux使用体验
- c语言实现hashmap(转载)
- Linux 信号signal处理机制
- linux下mysql添加用户
- Scientific Linux 5.5 图形安装教程
- Linux 下无损图片压缩小工具介绍