1. 程式人生 > >linuxPci驅動獲取指定裝置bus、device以及devfn資料方式

linuxPci驅動獲取指定裝置bus、device以及devfn資料方式

在vxworks系統中,呼叫pciFindDevice()函式可以直接獲取到指定裝置的bus、deviceNo以及devfn資料資訊。相對於linux系統,vxworks編寫驅動相對簡單一些。

linux系統下bus、deviceNo以及devfn資料由驅動內部函式使用 (編寫驅動過程中這些資料幾乎用不到),並且沒有提供明確的介面,需要我們自己分析驅動函式呼叫這些資料的方式。

首先在Terminal輸入: lspci -vmmD;
這裡寫圖片描述
我們看到裝置資訊第一行Slot:顯示的這些資訊,0000表示裝置域,02表示bus資訊,05表示deviceNo資訊,0表示devfn資訊;

瞭解到要得到資料資訊後,開始追蹤Pci相關檔案,首先跟蹤到linux/pci.h標頭檔案找到
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
#define PCI_FUNC(devfn) ((devfn) & 0x07),

根據定義名稱我們知道 PCI_SLOT表示PCI槽,PCI_FUNC表示PCI函式資訊(或者稱為描述資訊),我們得到了deviceNo和devfn的轉換方法,
下面繼續跟蹤找到struct pci_dev結構體,結構體內找到了unsigned int devfn; , 到這裡可以確定devfn和deviceNo就是用這個變數轉換過來的,
現在還需要得到bus號,在pci_dev結構體中沒有定義bus變數,說明我們的裝置bus號應該不能直接獲取到,
繼續檢查pci_dev結構體發現struct pci_bus bus; / bus this device is on /,看到這個註釋明白了我們要找的裝置bus號在pci_bus結構體內 , 跟蹤 pci_bus結構體 找到unsigned char number; /

bus number */。

  現在我們知道這些資料的獲取方式,想要獲取到資料需要用到struct pci_dev *dev指標。Pci入口函式static int __init pci_probe(struct pci_dev *dev, const struct pci_device_id *id)第一引數就是我們要用到的指標資料,結合上一篇的Pci驅動例項來描述具體實現方式,下面貼上程式碼:

define DevName “test”

define ClassName “class_test”

define VendorID 0xFA01

define DeviceID 0x1234

unsigned char bus;//增加bus號定義
unsigned int deviceNo;
unsigned int devfn;

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驅動入口函式 在這個函式中增加bus、device和devfn資料獲取方法
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;
}

//在這裡增加獲取bus、deviceNo和devfn資料的方法
bus = dev->bus->number;
deviceNo = (((dev->devfn) >> 3 ) && 0x1f);
devfn = ((dev->devfn) && 0x07);

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

相關推薦

linuxPci驅動獲取指定裝置busdevice以及devfn資料方式

在vxworks系統中,呼叫pciFindDevice()函式可以直接獲取到指定裝置的bus、deviceNo以及devfn資料資訊。相對於linux系統,vxworks編寫驅動相對簡單一些。 linux系統下bus、deviceNo以及devfn資料由驅動內

安卓獲取手機裝置硬體系統程式等資訊

真正的死亡是世界上再沒有一個人記得你。 —《尋夢環遊記》 分類 文章目錄 一、獲取手機系統資訊 1、獲取手機型號 2、獲取

QT中QString 類的使用--獲取指定字元位置擷取子字串等

QString 類中各函式的作用。 一、字串連線函式。 1、QString也過載的+和+=運算子。這兩個運算子可以把兩個字串連線到一起。      2、QString的append()函式則提供了類似的操作,例如:    str = "User: ";      str

iOS獲取當前裝置ID版本號build號

廢話不多說、直接上程式碼 //獲取裝置ID NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor

獲取手機裝置型號系統版本手機型號等資訊

// 獲取當前App的基本資訊字典 NSDictionary *infoDictionary = [[NSBundlemainBundle] infoDictionary]; //app名稱

獲取IMEI裝置的唯一標識以及異常提交

TelephonyManager manager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); //IMEI String deviceId = manag

Android 獲取當前裝置外網IP以及DNS.

如題,最近做個專案,需要獲取當前裝置IP地址和DNS地址.但是按照Android提供的方法獲取的都是內網.網易提供了一個解決方案:請求地址:http://xx.nstool.netease.comxx為當前格林威治時間,請求返回結果是一個html內容,需要解析中間的src欄位

GO 獲取時間的年份月份以及日期

網上很多資料提供time將時間戳轉成字串的例子,但如何將獲得的時間分為年、月、日分別展示,例如: ,上面顯示的是日期,下面顯示的是月份。作為初學者,表示網上的資料有點看不懂,記錄一下,還望斧正。 首先要獲取一個Time型別的變數,平時要獲取現在的時間的話,直

Linux系統下建立tomcat快捷啟動停止以及檢視日誌方式方式

1.建立bash指令碼tomcat檔案 vi /etc/init.d/tomcat 2.在tomcat中寫入一下指令碼內容 # !/bin/bash # Description: start or stop the tomcat # Usage: tom

python在arcgis中案例開發(空間求交連線以及excel資料匯出)

這是使用python寫的第二工具了,可以說這麼計算機語言也是初次接觸,還好使用過c、 c#、JAVA等計算機語言,所以在使用python的使用也不是完全找不到北。 這是國慶之前做的一個專案。首先我來說一下我所用到的資料:山最高點(shapefile點資料)、山底座資料(sh

C++型別的結構陣列以及列舉的方式

想知道技術類知識,請百度【鏈客區塊鏈技術問答社群】 C++型別–結構.陣列.列舉 感覺社群寫筆記的都是大神,我是個初學者,就寫一些簡單點的吧,說不定以後我也會在這裡成為大神呢~嘿嘿。 一.結構 結構型別定義 struct <結構型別名> {<成員表>

JTAG各類介面針腳定義含義以及SWD接線方式

 JTAG有10pin的、14pin的和20pin的,儘管引腳數和引腳的排列順序不同,但是其中有一些引腳是一樣的,各個引腳的定義如下。一、引腳定義Test Clock Input (TCK) -----強制要求1TCK在IEEE1149.1標準裡是強制要求的。TCK為TAP的操作提供了一個獨立的、基本的時鐘訊

U3D獲取IOS裝置所在時區是否安裝指定APP判斷真機還是模擬器

  unity是無法直接獲取ios裝置資訊的,但是unity可以與IOS程式碼進行互動,這就可以完成你想要實現的功能了。   直接上程式碼: CheckCountry.h檔案: #import <Foundation/Foundation.h> @interface CheckCountry

(二)裝置結構模型_高階部分(BusClassDeviceDriver)

高階部分(Bus、Class、Device、Driver) 深入,並且廣泛 -沉默犀牛 這篇文章只分析Bus、Class的作用,和表示它們的結構體。不分析介面函式 Bus Bus是處理器與一個或者多個device之間的通道。在裝置模型中,所有的devi

Linux裝置驅動模型框架分析(三)——LDDM的實體bus_typedevice和device_driver

在Linux裝置模型中,Bus(匯流排)是一類特殊的裝置,它是連線處理器和其它裝置之間的通道(channel)。為了方便裝置模型的實現,核心規定,系統中的每個裝置都要連線在一個Bus上,這個Bus可以是一個內部Bus、虛擬Bus或者Platform Bus。 device

Linux spi驅動分析(二)----SPI核心(busdevice_driver和device)

struct device {     struct device        *parent;     struct device_private    *p;     struct kobject kobj;     const char        *init_name; /* init

Windows下USB磁碟開發系列三:列舉系統中U盤獲取裝置資訊

前面我們介紹了列舉系統中的U盤碟符(見《Windows下USB磁碟開發系列一:列舉系統中U盤的碟符》)、以及獲取USB裝置的資訊(見《Windows下USB磁碟開發系列二:列舉系統中所有USB裝置》)。有個時候我們不僅僅需要獲取U盤碟符(路徑),而且需要獲取該U盤的硬體資訊,比如廠商、friendl

獲取指定USB裝置的VID PID和SerialNumber

裝置廠商ID 查詢, google www.usb.org + vendor id list    所需標頭檔案庫檔案: #include <Setupapi.h> , Setupapi.lib void CCamera

驅動】第1課字元裝置驅動

=====節一、字元裝置驅動程式之概念介紹=====1、模組(即某單一驅動)是如何構建的?答:構建一個最基本的驅動模組,只需要4函式+1標頭檔案:模組裝載函式xx_init(), 模組解除安裝函式xx_exit(), module_init(), module_exit(), <linux/init.h

js獲取指定Date的週一周天季度半年

//獲取當前周從星期一到星期天的日期 function getDates(date) { var currentDate = new Date(date); var timesStamp = currentDate.getTime();