uClinux設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)與編寫
1設(shè)備驅(qū)動(dòng)程序的一般編寫步驟
(1) 確定設(shè)備的主設(shè)備號(hào)
(2) 填充static struct file_operation這樣的結(jié)構(gòu)
(3) 定義一個(gè)類似__init mydriver_init(void)這樣的注冊(cè)函數(shù),大體如下:
int __init mydriver_init(void)
{
int rc;
rc = register_chrdev(mydevice_Major, "mydev", &mydriver_fops);
if (rc < 0) {
printk(KERN_WARNING "mydevice: can\'t get Major %d\\n",
mydevice_Major);
return rc;
}
printk("mydevice Driver Support.\\n");
return 0;
}
其中mydev表示的設(shè)備文件為/dev/mydev X X,即習(xí)慣上起名為mydev mydev01 mydev02……如had hda1 hda2 hda3。不過(guò)名字是可以隨意的。如果成功就返回0,否則返回-1
2 填充驅(qū)動(dòng)程序子函數(shù)集struct file_operation結(jié)構(gòu)
(1)驅(qū)動(dòng)程序子函數(shù)集struct file_operation結(jié)構(gòu)
struct file_operation結(jié)構(gòu)共有11個(gè)成員,分別表示一函數(shù)指針,內(nèi)容及作用說(shuō)明如下:
struct file_operations {
/*需要改變文件位置時(shí)調(diào)用*/
loff_t (*llseek) (struct file *, loff_t, int);
/*執(zhí)行read(2)系統(tǒng)調(diào)用時(shí)調(diào)用*/
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
/*執(zhí)行write(2)系統(tǒng)調(diào)用時(shí)調(diào)用*/
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
/*讀目錄內(nèi)容時(shí)調(diào)用*/
int (*readdir) (struct file *, void *, filldir_t);
/*執(zhí)行poll 系統(tǒng)調(diào)用時(shí)調(diào)用*/
unsigned int (*poll) (struct file *, struct poll_table_struct *);
/*執(zhí)行ioctl(2) 系統(tǒng)調(diào)用時(shí)調(diào)用*/
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
/*執(zhí)行mmap(2) 系統(tǒng)調(diào)用時(shí)調(diào)用*/
int (*mmap) (struct file *, struct vm_area_struct *);
/*打開(kāi)設(shè)備時(shí)調(diào)用*/
int (*open) (struct inode *, struct file *);
/*只在file的使用計(jì)數(shù)為0時(shí)調(diào)用,它用來(lái)釋放file結(jié)構(gòu)*/
int (*release) (struct inode *, struct file *);
/*執(zhí)行fsync(2)系統(tǒng)調(diào)用時(shí)調(diào)用*/
int (*fsync) (struct file *, struct dentry *);
/*執(zhí)行fcntl(2)系統(tǒng)調(diào)用時(shí)調(diào)用*/
int (*fasync) (int, struct file *, int);
};
(2)根據(jù)需要,按以下方法構(gòu)造上述函數(shù),如:
static int ReadPower(struct inode * inode, struct file * file, char * buffer, int count)
{
if (!Ready)
return -EAGAIN;
if (count != sizeof(int))
return -EINVAL;
copy_to_user(buffer, &myvar, sizeof(int));
return sizeof(int);
}
這里定義成static是因?yàn)樵擈?qū)動(dòng)程序子函數(shù)在文件外是通過(guò)上述的間接方法被調(diào)用的,文件外不需要該符號(hào)。
(3)把相關(guān)操作對(duì)應(yīng)的函數(shù)名填入mydevice_operations中
填充static struct file_operations mydevice_operations時(shí),用以上構(gòu)造的函數(shù)名填充相應(yīng)成員,例如:
struct file_operations TouchPanel_fops = {
read: ReadTouchPanel,
poll: TouchPanelSelect,
ioctl: TouchPanelIoctl,
open: OpenTouchPanel,
release: CloseTouchPanel,
};
3 中斷處理
首先,中斷不是必須的。如果設(shè)備要用中斷模式,就要構(gòu)造中斷處理函數(shù),并注冊(cè)中斷處理函數(shù)。
Linux中斷處理過(guò)程由中斷子系統(tǒng)完成;而中斷處理函數(shù)只是處理具體操作,即讀寫數(shù)據(jù)等。成功注冊(cè)該中斷處理函數(shù),就掛接到中斷子系統(tǒng)上了。
中斷處理一般由兩個(gè)主要部分組成:
(1)構(gòu)造中斷處理函數(shù)void MyDriverInterrupt(int irq, void *dev_id, struct pt_regs *regs),
一般說(shuō)來(lái),Linux中斷處理函數(shù)完成工作一方面把設(shè)備來(lái)的數(shù)據(jù)讀出并保存起來(lái),另一方面把內(nèi)核中的數(shù)據(jù)寫入設(shè)備。這樣,驅(qū)動(dòng)程序只需從內(nèi)核讀出數(shù)據(jù),把用戶提交的數(shù)據(jù)寫入內(nèi)核;這里可以使用一個(gè)簡(jiǎn)單的數(shù)組。
中斷處理函數(shù)時(shí)要防止其他中斷的干擾,可用"save_flags(flags); cli();"來(lái)關(guān)閉中斷,相關(guān)處理完畢,用"restore_flags(flags)"來(lái)恢復(fù)。
(2) 注冊(cè)中斷可在mydriver_init()中,也 可在 mydriver_open()中,例如:
if (request_irq(
MYDEVICE_IRQ_NUM,
MyDeviceInterrupt,
IRQ_FLG_STD,
"mydevice",
NULL
)
) {
printk("TouchPanel: Cannot register interrupt.\\n");
return -EBUSY;
}
其中:
MYDEVICE_IRQ_NUM: 注冊(cè)中斷號(hào)碼
MyDeviceInterrupt: 中斷處理程序
mydevice: 中斷說(shuō)明(可隨便寫)
如果返回0,表示成功,否則失敗。
4 時(shí)間處理
在驅(qū)動(dòng)程序中可以使用定時(shí)器來(lái)調(diào)度函數(shù)在未來(lái)某個(gè)特定時(shí)間執(zhí)行。定時(shí)器包括它的超時(shí)值(timeout, 單位是jiffies)和超時(shí)時(shí)調(diào)用的函數(shù)。定時(shí)器列表的數(shù)據(jù)結(jié)構(gòu)如下:
struct timer_list {
struct list_head list;
unsigned long expires; /*timeout超時(shí)值,以jiffies值為單位*/
unsigned long data; /*傳遞給定時(shí)器處理程序的參數(shù)*/
void (*function)(unsigned long); /*超時(shí)調(diào)用的定時(shí)器處理程序*/
};
定時(shí)器的timeout是個(gè)"jiffy"值,當(dāng)jiffies值大于等于timer->expires時(shí),timer->function函數(shù)就會(huì)執(zhí)行,timeout值是個(gè)絕對(duì)數(shù)值,它與當(dāng)前時(shí)間無(wú)關(guān),不需要更新。
操作定時(shí)器有下面幾個(gè)函數(shù):
void init_timer(struct timer_list *timer);
該函數(shù)初始化新分配的定時(shí)器隊(duì)列。
void add_timer(struct timer_list *timer);
該函數(shù)將定時(shí)器插入掛起的定時(shí)器的全局隊(duì)列。
void del_timer(struct timer_list *timer);
如果需要在定時(shí)器超時(shí)前將它從列表中刪除,應(yīng)調(diào)用del_timer函數(shù)。但當(dāng)定時(shí)器超時(shí)時(shí),系統(tǒng)會(huì)自動(dòng)地將它從列表中刪除。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)
點(diǎn)擊舉報(bào)。