日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

PCI驱动程序实现

發(fā)布時(shí)間:2023/12/18 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PCI驱动程序实现 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、數(shù)據(jù)結(jié)構(gòu):
PCI設(shè)備上有三種地址空間:PCI的I/O空間、PCI的存儲(chǔ)空間和PCI的配置空間。CPU可以訪問PCI設(shè)備上的所有地址空間,其中I/O空間和存儲(chǔ)空間提供給設(shè)備驅(qū)動(dòng)程序使用,而配置空間則由Linux內(nèi)核中的PCI初始化代碼使用。內(nèi)核在啟動(dòng)時(shí)負(fù)責(zé)對(duì)所有PCI設(shè)備進(jìn)行初始化,配置好所有的PCI設(shè)備,包括中斷號(hào)以及I/O基址,并在文件/proc/pci中列出所有找到的PCI設(shè)備,以及這些設(shè)備的參數(shù)和屬性。
- pci_driver
這個(gè)數(shù)據(jù)結(jié)構(gòu)在文件include/linux/pci.h里,這是Linux內(nèi)核版本2.4之后為新型的PCI設(shè)備驅(qū)動(dòng)程序所添加的,其中最主要的是用于識(shí)別設(shè)備的id_table結(jié)構(gòu),以及用于檢測設(shè)備的函數(shù)probe( )和卸載設(shè)備的函數(shù)remove( ):

struct pci_driver {struct list_head node;char *name;const struct pci_device_id *id_table;int (*probe) (struct pci_dev *dev, const struct pci_device_id *id);void (*remove) (struct pci_dev *dev);int (*save_state) (struct pci_dev *dev, u32 state);int (*suspend)(struct pci_dev *dev, u32 state);int (*resume) (struct pci_dev *dev);int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); };
  • pci_dev
    這個(gè)數(shù)據(jù)結(jié)構(gòu)也在文件include/linux/pci.h里,它詳細(xì)描述了一個(gè)PCI設(shè)備幾乎所有的硬件信息,包括廠商ID、設(shè)備ID、各種資源等:
struct pci_dev {struct list_head global_list;struct list_head bus_list;struct pci_bus *bus;struct pci_bus *subordinate;void *sysdata;struct proc_dir_entry *procent;unsigned int devfn;unsigned short vendor;unsigned short device;unsigned short subsystem_vendor;unsigned short subsystem_device;unsigned int class;u8 hdr_type;u8 rom_base_reg;struct pci_driver *driver;void *driver_data;u64 dma_mask;u32 current_state;unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];unsigned int irq;struct resource resource[DEVICE_COUNT_RESOURCE];struct resource dma_resource[DEVICE_COUNT_DMA];struct resource irq_resource[DEVICE_COUNT_IRQ];char name[80];char slot_name[8];int active;int ro;unsigned short regs;int (*prepare)(struct pci_dev *dev);int (*activate)(struct pci_dev *dev);int (*deactivate)(struct pci_dev *dev); };

2、基本框架
在用模塊方式實(shí)現(xiàn)PCI設(shè)備驅(qū)動(dòng)程序時(shí),通常至少要實(shí)現(xiàn)以下幾個(gè)部分:初始化設(shè)備模塊、設(shè)備打開模塊、數(shù)據(jù)讀寫和控制模塊、中斷處理模塊、設(shè)備釋放模塊、設(shè)備卸載模塊。下面給出一個(gè)典型的PCI設(shè)備驅(qū)動(dòng)程序的基本框架,從中不難體會(huì)到這幾個(gè)關(guān)鍵模塊是如何組織起來的:

/* 指明該驅(qū)動(dòng)程序適用于哪一些PCI設(shè)備 */ static struct pci_device_id demo_pci_tbl [] __initdata = {{PCI_VENDOR_ID_DEMO, PCI_DEVICE_ID_DEMO,PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEMO},{0,} }; /* 對(duì)特定PCI設(shè)備進(jìn)行描述的數(shù)據(jù)結(jié)構(gòu) */ struct demo_card {unsigned int magic;/* 使用鏈表保存所有同類的PCI設(shè)備 */struct demo_card *next;/* ... */ } /* 中斷處理模塊 */ static void demo_interrupt(int irq, void *dev_id, struct pt_regs *regs) {/* ... */ } /* 設(shè)備文件操作接口 */ static struct file_operations demo_fops = {owner: THIS_MODULE, /* demo_fops所屬的設(shè)備模塊 */read: demo_read, /* 讀設(shè)備操作*/write: demo_write, /* 寫設(shè)備操作*/ioctl: demo_ioctl, /* 控制設(shè)備操作*/mmap: demo_mmap, /* 內(nèi)存重映射操作*/open: demo_open, /* 打開設(shè)備操作*/release: demo_release /* 釋放設(shè)備操作*//* ... */ }; /* 設(shè)備模塊信息 */ static struct pci_driver demo_pci_driver = {name: demo_MODULE_NAME, /* 設(shè)備模塊名稱 */id_table: demo_pci_tbl, /* 能夠驅(qū)動(dòng)的設(shè)備列表 */probe: demo_probe, /* 查找并初始化設(shè)備 */remove: demo_remove /* 卸載設(shè)備模塊 *//* ... */ }; static int __init demo_init_module (void) {/* ... */ } static void __exit demo_cleanup_module (void) {pci_unregister_driver(&demo_pci_driver); } /* 加載驅(qū)動(dòng)程序模塊入口 */ module_init(demo_init_module); /* 卸載驅(qū)動(dòng)程序模塊入口 */ module_exit(demo_cleanup_module);

3、初始化設(shè)備模塊
當(dāng)Linux內(nèi)核啟動(dòng)并完成對(duì)所有PCI設(shè)備進(jìn)行掃描、登錄和分配資源等初始化操作的同時(shí),會(huì)建立起系統(tǒng)中所有PCI設(shè)備的拓?fù)浣Y(jié)構(gòu),此后當(dāng)PCI驅(qū)動(dòng)程序需要對(duì)設(shè)備進(jìn)行初始化時(shí),一般都會(huì)調(diào)用如下的代碼:

static int __init demo_init_module (void) {/* 檢查系統(tǒng)是否支持PCI總線 */if (!pci_present())return -ENODEV;/* 注冊(cè)硬件驅(qū)動(dòng)程序 */if (!pci_register_driver(&demo_pci_driver)) {pci_unregister_driver(&demo_pci_driver);return -ENODEV;}/* ... */return 0; }

驅(qū)動(dòng)程序首先調(diào)用函數(shù)pci_present( )檢查PCI總線是否已經(jīng)被Linux內(nèi)核支持,如果系統(tǒng)支持PCI總線結(jié)構(gòu),這個(gè)函數(shù)的返回值為0,如果驅(qū)動(dòng)程序在調(diào)用這個(gè)函數(shù)時(shí)得到了一個(gè)非0的返回值,那么驅(qū)動(dòng)程序就必須得中止自己的任務(wù)了。在2.4內(nèi)核以后更好的辦法是調(diào)用pci_register_driver( )函數(shù)來注冊(cè)PCI設(shè)備的驅(qū)動(dòng)程序,此時(shí)需要提供一個(gè)pci_driver結(jié)構(gòu),在該結(jié)構(gòu)中給出的probe探測例程將負(fù)責(zé)完成對(duì)硬件的檢測工作。

static int __init demo_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) {struct demo_card *card;/* 啟動(dòng)PCI設(shè)備 */if (pci_enable_device(pci_dev))return -EIO;/* 設(shè)備DMA標(biāo)識(shí) */if (pci_set_dma_mask(pci_dev, DEMO_DMA_MASK)) {return -ENODEV;}/* 在內(nèi)核空間中動(dòng)態(tài)申請(qǐng)內(nèi)存 */if ((card = kmalloc(sizeof(struct demo_card), GFP_KERNEL)) == NULL) {printk(KERN_ERR "pci_demo: out of memory\n");return -ENOMEM;}memset(card, 0, sizeof(*card));/* 讀取PCI配置信息 */card->iobase = pci_resource_start (pci_dev, 1);card->pci_dev = pci_dev;card->pci_id = pci_id->device;card->irq = pci_dev->irq;card->next = devs;card->magic = DEMO_CARD_MAGIC;/* 設(shè)置成總線主DMA模式 */ pci_set_master(pci_dev);/* 申請(qǐng)I/O資源 */request_region(card->iobase, 64, card_names[pci_id->driver_data]);return 0; }

4、打開設(shè)備模塊
在這個(gè)模塊里主要實(shí)現(xiàn)申請(qǐng)中斷、檢查讀寫模式以及申請(qǐng)對(duì)設(shè)備的控制權(quán)等。在申請(qǐng)控制權(quán)的時(shí)候,非阻塞方式遇忙返回,否則進(jìn)程主動(dòng)接受調(diào)度,進(jìn)入睡眠狀態(tài),等待其它進(jìn)程釋放對(duì)設(shè)備的控制權(quán)。

static int demo_open(struct inode *inode, struct file *file) {/* 申請(qǐng)中斷,注冊(cè)中斷處理程序 */request_irq(card->irq, &demo_interrupt, SA_SHIRQ,card_names[pci_id->driver_data], card)) {/* 檢查讀寫模式 */if(file->f_mode & FMODE_READ) {/* ... */}if(file->f_mode & FMODE_WRITE) {/* ... */}/* 申請(qǐng)對(duì)設(shè)備的控制權(quán) */down(&card->open_sem);while(card->open_mode & file->f_mode) {if (file->f_flags & O_NONBLOCK) {/* NONBLOCK模式,返回-EBUSY */up(&card->open_sem);return -EBUSY;} else {/* 等待調(diào)度,獲得控制權(quán) */card->open_mode |= f_mode & (FMODE_READ | FMODE_WRITE);up(&card->open_sem);/* 設(shè)備打開計(jì)數(shù)增1 */MOD_INC_USE_COUNT;/* ... */}} }

5、數(shù)據(jù)讀寫和控制模塊
PCI設(shè)備驅(qū)動(dòng)程序可以通過demo_fops 結(jié)構(gòu)中的函數(shù)demo_ioctl( ),向應(yīng)用程序提供對(duì)硬件進(jìn)行控制的接口。例如,通過它可以從I/O寄存器里讀取一個(gè)數(shù)據(jù),并傳送到用戶空間里:

static int demo_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) {/* ... */switch(cmd) {case DEMO_RDATA:/* 從I/O端口讀取4字節(jié)的數(shù)據(jù) */val = inl(card->iobae + 0x10);/* 將讀取的數(shù)據(jù)傳輸?shù)接脩艨臻g */return 0;}/* ... */ }

事實(shí)上,在demo_fops里還可以實(shí)現(xiàn)諸如demo_read( )、demo_mmap( )等操作,Linux內(nèi)核源碼中的driver目錄里提供了許多設(shè)備驅(qū)動(dòng)程序的源代碼,找那里可以找到類似的例子。在對(duì)資源的訪問方式上,除了有I/O指令以外,還有對(duì)外設(shè)I/O內(nèi)存的訪問。對(duì)這些內(nèi)存的操作一方面可以通過把I/O內(nèi)存重新映射后作為普通內(nèi)存進(jìn)行操作,另一方面也可以通過總線主DMA(Bus Master DMA)的方式讓設(shè)備把數(shù)據(jù)通過DMA傳送到系統(tǒng)內(nèi)存中。

6、中斷處理模塊
PC的中斷資源比較有限,只有0~15的中斷號(hào),因此大部分外部設(shè)備都是以共享的形式申請(qǐng)中斷號(hào)的。當(dāng)中斷發(fā)生的時(shí)候,中斷處理程序首先負(fù)責(zé)對(duì)中斷進(jìn)行識(shí)別,然后再做進(jìn)一步的處理。

static void demo_interrupt(int irq, void *dev_id, struct pt_regs *regs) {struct demo_card *card = (struct demo_card *)dev_id;u32 status;spin_lock(&card->lock);/* 識(shí)別中斷 */status = inl(card->iobase + GLOB_STA);if(!(status & INT_MASK)){spin_unlock(&card->lock);return; /* not for us */}/* 告訴設(shè)備已經(jīng)收到中斷 */outl(status & INT_MASK, card->iobase + GLOB_STA);spin_unlock(&card->lock);/* 其它進(jìn)一步的處理,如更新DMA緩沖區(qū)指針等 */ }

7、釋放設(shè)備模塊
釋放設(shè)備模塊主要負(fù)責(zé)釋放對(duì)設(shè)備的控制權(quán),釋放占用的內(nèi)存和中斷等,所做的事情正好與打開設(shè)備模塊相反:

static int demo_release(struct inode *inode, struct file *file) {/* ... *//* 釋放對(duì)設(shè)備的控制權(quán) */card->open_mode &= (FMODE_READ | FMODE_WRITE);/* 喚醒其它等待獲取控制權(quán)的進(jìn)程 */wake_up(&card->open_wait);up(&card->open_sem);/* 釋放中斷 */free_irq(card->irq, card);/* 設(shè)備打開計(jì)數(shù)增1 */MOD_DEC_USE_COUNT;/* ... */ }

8、卸載設(shè)備模塊
卸載設(shè)備模塊與初始化設(shè)備模塊是相對(duì)應(yīng)的,實(shí)現(xiàn)起來相對(duì)比較簡單,主要是調(diào)用函數(shù)pci_unregister_driver( )從Linux內(nèi)核中注銷設(shè)備驅(qū)動(dòng)程序:

static void __exit demo_cleanup_module (void) {pci_unregister_driver(&demo_pci_driver); }

總結(jié)

以上是生活随笔為你收集整理的PCI驱动程序实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲日本国产精品 | 亚洲色图19p | 国产性生活网站 | 欧美老熟妇又粗又大 | 亚洲无码高清精品 | 影音先锋伦理片 | 久草免费在线视频 | 日韩一区二区三区精品视频 | 国产又粗又猛又黄又爽的视频 | 日韩视频欧美视频 | 色哟哟国产精品色哟哟 | 色欲AV无码精品一区二区久久 | 特大黑人巨交吊性xxxx视频 | 青青草狠狠操 | 东北高大丰满bbbbzbbb | 亚洲一区人妻 | 国产主播av在线 | 亚洲精品视频在线免费 | 久久精品免费在线 | 日韩欧美综合一区 | 欧美交换国产一区内射 | 欧美操穴 | 一级a性色生活片久久无 | 免费午夜网站 | 在线观看自拍 | 国产一区二区三区四区五区美女 | 欧美一级片一区二区 | 国产亚洲精品aaaaaaa片 | 久久精品视频国产 | 亚洲日本中文字幕在线 | 国产精品久久久久影院 | 亚洲欧美在线观看 | 精品视频站长推荐 | 韩国三级国产 | 午夜精品av | 水蜜桃亚洲精品 | 亚欧成人| 中文字幕精品视频在线观看 | 国产色无码精品视频国产 | 国产亚洲精品久久久久丝瓜 | 久久人人插 | 国产精品视频一区二区三区 | 狠狠躁天天躁夜夜躁婷婷 | 精品日本一区二区三区 | 在线观看h网站 | 亚洲天堂网络 | 一级网站在线观看 | 欧美透逼视频 | 日本欧美色 | 一区二区三区四区国产精品 | 欧洲一级视频 | 美女大黄网站 | 国产剧情av引诱维修工 | 福利一区视频 | 日韩欧美精品 | 欧美国产日韩一区二区三区 | 国产精品无码乱伦 | 公车激情云雨小说 | 男人的天堂日韩 | 成人精品电影 | 日本天堂网 | 97蜜桃网| 成人免费aaa | 欧美亚洲一区二区三区 | 涩涩999| 17c在线视频 | 欧美激情在线看 | 久久午夜伦理 | 夜夜久久| 亚洲av永久无码精品一区二区国产 | 亚洲国产一区在线观看 | 另类老妇性bbwbbw图片 | 情侣av | 国产女18毛片多18精品 | 999热精品视频 | 爱豆国产剧免费观看大全剧集 | 91丝袜在线 | 亚洲精品成人无码熟妇在线 | 日韩一区二区三区视频在线观看 | 国产69精品久久久久777 | 人妖一区二区三区 | 午夜在线国产 | 800av凹凸| 伊人网在线 | 午夜国产小视频 | 国产精品久久久久久久成人午夜 | 久久成人在线观看 | 国产一卡二 | 国产91一区二区三区 | 欧美日韩成人一区二区在线观看 | 国产女人和拘做受视频免费 | 久久精品一二区 | 欧美videos另类精品 | 激情图片在线视频 | 天天噜天天干 | 中文字幕无码乱码人妻日韩精品 | a级黄色片 | 天天色棕合合合合合合合 | 一区二区三区久久久久 |