1. 程式人生 > >linux PCI驅動呼叫字元裝置驅動方式

linux PCI驅動呼叫字元裝置驅動方式

上一篇文章寫了字元裝置驅動的基本結構及訪問方式,在實際應用時首先需要繫結自己的硬體裝置。本篇主要描述字元裝置驅動與PCI介面型別的裝置訪問方式(核心為2.6.24及以上的方法,測試核心為2.6.32)。

首先介紹下PCI驅動結構:

//PCI裝置id描述結構:這裡有兩個引數 第一個是VendorID,第二個是DeviceID(在linux Terminal中輸入 lspci -vmm可以看到裝置資訊) 
static struct pci_device_id pci_ids[] = {
    { PCI_DEVICE(Vendor,Device) },
    { 0 }
};

//PCI裝置描述結構:指定PCI裝置函式
static struct pci_driver driver_ops = { .name = DevName,//驅動名稱 .id_table = pci_ids,//PCI裝置id描述結構 .probe = pci_probe,//PCI入口函式 .remove = pci_remove,//PCI退出函式 }; //PCI驅動註冊函式 //注意項:如果沒有探測到 PCI裝置id描述結構(指定的VendorID或DeviceID在Terminal中查詢不到)或者指定的裝置已經綁定了驅動,那麼PCI入口函式以及PCI退出函式不會執行(PCI裝置描述結構內指定的別的函式也是如此) pci_register_driver(&driver_ops);

下面展示PCI驅動呼叫字元裝置驅動的例項:

#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/device.h>

#define DevName     "test"
#define ClassName   "class_test"
#define VendorID 0xFA01 #define DeviceID 0x1234 struct class *mem_class; struct Pci_Test { struct cdev _cdev; dev_t dev; char msi_enabled; }*pci_test; static int Test_open(struct inode *inode,struct file *filp) { return 0; } static int Test_release(struct inode *inode,struct file *filp) { return 0; } static struct file_operations test_fops = { .owner = THIS_MODULE, //.ioctl = Test_ioctl, .open = Test_open, .release = Test_release, }; //字元驅動 static init_chrdev(struct Pci_Test *test_ptr) { int result = alloc_chrdev_region(&test_ptr->dev, 0, 2, DevName); if (result < 0) { printk("Err:failed in alloc_chrdev_region!\n"); return result; } mem_class = class_create(THIS_MODULE,ClassName);// /dev/ create devfile if (IS_ERR(mem_class)) { printk("Err:failed in creating class!\n"); } device_create(mem_class,NULL,test_ptr->dev,NULL,DevName); cdev_init(&test_ptr->_cdev,&test_fops); test_ptr->_cdev.owner = THIS_MODULE; test_ptr->_cdev.ops = &test_fops;//Create Dev and file_operations Connected result = cdev_add(&test_ptr->_cdev,test_ptr->dev,1); return result; } //PCI驅動入口函式 static int __init pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { int rc = 0; pci_test = dev; pci_set_drvdata(dev, pci_test); //在這裡建立字元裝置驅動 rc = init_chrdev(pci_test); if (rc) { dev_err(&dev->dev, "init_chrdev() failed\n"); return -1; } rc = pci_enable_device(dev); if (rc) { dev_err(&dev->dev, "pci_enable_device() failed\n"); return -1; } rc = pci_request_regions(dev, DevName); if (rc) { dev_err(&dev->dev, "pci_request_regions() failed\n"); return -1; } pci_set_master(dev); rc = pci_enable_msi(dev); if (rc) { dev_info(&dev->dev, "pci_enable_msi() failed\n"); pci_test->msi_enabled = 0; } else { dev_info(&dev->dev, "pci_enable_msi() successful\n"); pci_test->msi_enabled = 1; } return rc; } static void __exit pci_remove(struct pci_dev *dev) { if (0 != mem_class) { device_destroy(mem_class,pci_test->dev); class_destroy(mem_class); mem_class = 0; } pci_test = pci_get_drvdata(dev); cdev_del(&pci_test->_cdev); unregister_chrdev_region(pci_test->dev, 1); pci_disable_device(dev); if(pci_test) { if(pci_test->msi_enabled) { pci_disable_msi(dev); pci_test->msi_enabled = 0; } } pci_release_regions(dev); } static struct pci_device_id pci_ids[] = { { PCI_DEVICE( VendorID, DeviceID) }, { 0 } }; static struct pci_driver driver_ops = { .name = DevName, .id_table = pci_ids, .probe = pci_probe, .remove = pci_remove, }; //驅動模組入口函式 static int Test_init_module(void) { int rc = 0; pci_test = kzalloc(sizeof(struct Pci_Test), GFP_KERNEL); //配對裝置以及註冊PCI驅動,如果找到對應裝置呼叫PCI入口函式 rc = pci_register_driver(&driver_ops); if (rc) { printk(KERN_ALERT ": PCI driver registration failed\n"); } return rc; } static void Test_exit_module(void) { pci_unregister_driver(&driver_ops); kfree(pci_test); } module_init(Test_init_module); module_exit(Test_exit_module); MODULE_AUTHOR(DevName); MODULE_LICENSE("GPL");
當PCI驅動與硬體裝置繫結成功時,便可以通過字元裝置驅動訪問裝置了。

上一篇linux使用open開啟字元裝置驅動:http://blog.csdn.net/a29562268/article/details/78443087!