Linux驅(qū)動(dòng)總結(jié)3
我的平臺(tái)是虛擬機(jī),fedora14,內(nèi)核版本為2.6.38.1.其中較之前的版本存在較大的差別,具體的實(shí)現(xiàn)已經(jīng)在上一次總結(jié)中給出了。今天主要總結(jié)的是ioctl和堵塞讀寫(xiě)函數(shù)的實(shí)現(xiàn)。
一、ioctl函數(shù)的實(shí)現(xiàn)
首先說(shuō)明在2.6.36以后ioctl函數(shù)已經(jīng)不再存在了,而是用unlocked_ioctl和compat_ioctl兩個(gè)函數(shù)實(shí)現(xiàn)以前版本的ioctl函數(shù)。同時(shí)在參數(shù)方面也發(fā)生了一定程度的改變,去除了原來(lái)ioctl中的struct inode參數(shù),同時(shí)改變了返回值。
但是驅(qū)動(dòng)設(shè)計(jì)過(guò)程中存在的問(wèn)題變化并不是很大,同樣在應(yīng)用程序設(shè)計(jì)中我們還是采用ioctl實(shí)現(xiàn)訪問(wèn),而并不是unlocked_ioctl函數(shù),因此我們還可以稱之為ioctl函數(shù)的實(shí)現(xiàn)。
ioctl函數(shù)的實(shí)現(xiàn)主要是用來(lái)實(shí)現(xiàn)具體的硬件控制,采用相應(yīng)的命令控制硬件的具體操作,這樣就能使得硬件的操作不再是單調(diào)的讀寫(xiě)操作。使得硬件的使用更加的方便。
ioctl函數(shù)實(shí)現(xiàn)主要包括兩個(gè)部分,首先是命令的定義,然后才是ioctl函數(shù)的實(shí)現(xiàn),命令的定義是采用一定的規(guī)則。
ioctl的命令主要用于應(yīng)用程序通過(guò)該命令操作具體的硬件設(shè)備,實(shí)現(xiàn)具體的操作,在驅(qū)動(dòng)中主要是對(duì)命令進(jìn)行解析,通過(guò)switch-case語(yǔ)句實(shí)現(xiàn)不同命令的控制,進(jìn)而實(shí)現(xiàn)不同的硬件操作。
ioctl函數(shù)的命令定義方法:
int (*unlocked_ioctl)(struct file*filp,unsigned int cmd,unsigned long arg)
雖然其中沒(méi)有指針的參數(shù),但是通常采用arg傳遞指針參數(shù)。cmd是一個(gè)命令。每一個(gè)命令由一個(gè)整形數(shù)據(jù)構(gòu)成(32bits),將一個(gè)命令分成四部分,每一部分實(shí)現(xiàn)具體的配置,設(shè)備類型(幻數(shù))8bits,方向2bits,序號(hào)8bits,數(shù)據(jù)大小13/14bits。命令的實(shí)現(xiàn)實(shí)質(zhì)上就是通過(guò)簡(jiǎn)單的移位操作,將各個(gè)部分組合起來(lái)而已。
一個(gè)命令的分布的大概情況如下:
|---方向位(31-30)|----數(shù)據(jù)長(zhǎng)度(29-16)----------------|---------設(shè)備類型(15-8)------|----------序號(hào)(7-0)----------|
|----------------------------------------------------------------------------------------------------------------------------------------|
其中方向位主要是表示對(duì)設(shè)備的操作,比如讀設(shè)備,寫(xiě)設(shè)備等操作以及讀寫(xiě)設(shè)備等都具有一定的方向,2個(gè)bits只有4種方向。
數(shù)據(jù)長(zhǎng)度表示每一次操作(讀、寫(xiě))數(shù)據(jù)的大小,一般而已每一個(gè)命令對(duì)應(yīng)的數(shù)據(jù)大小都是一個(gè)固定的值,不會(huì)經(jīng)常改變,14bits說(shuō)明可以選擇的數(shù)據(jù)長(zhǎng)度最大為16k。
設(shè)備類型類似于主設(shè)備號(hào)(由于8bits,剛好組成一個(gè)字節(jié),因此經(jīng)常采用字符作為幻數(shù),表示某一類設(shè)備的命令),用來(lái)區(qū)別不同的命令類型,也就是特定的設(shè)備類型對(duì)應(yīng)特定的設(shè)備。序號(hào)主要是這一類命令中的具體某一個(gè),類似于次設(shè)備號(hào)(256個(gè)命令),也就是一個(gè)設(shè)備支持的命令多達(dá)256個(gè)。
同時(shí)在內(nèi)核中也存在具體的宏用來(lái)定義命令以及解析命令。
但是大部分的宏都只是定義具體的方向,其他的都需要設(shè)計(jì)者定義。
主要的宏如下:
#include
_IO(type,nr) 表示定義一個(gè)沒(méi)有方向的命令,
_IOR(type,nr,size) 表示定義一個(gè)類型為type,序號(hào)為nr,數(shù)據(jù)大小為size的讀命令
_IOW(type,nr,size) 表示定義一個(gè)類型為type,序號(hào)為nr,數(shù)據(jù)大小為size的寫(xiě)命令
_IOWR(type,nr,size) 表示定義一個(gè)類型為type,序號(hào)為nr,數(shù)據(jù)大小為size的寫(xiě)讀命令
通常的type可采用某一個(gè)字母或者數(shù)字作為設(shè)備命令類型。
是實(shí)際運(yùn)用中通常采用如下的方法定義一個(gè)具體的命令:
//頭文件
#include
/*定義一系列的命令*/
/*幻數(shù),主要用于表示類型*/
#define MAGIC_NUM k
/*打印命令*/
#define MEMDEV_PRINTF _IO(MAGIC_NUM,1)
/*從設(shè)備讀一個(gè)int數(shù)據(jù)*/
#define MEMDEV_READ _IOR(MAGIC_NUM,2,int)
/*往設(shè)備寫(xiě)一個(gè)int數(shù)據(jù)*/
#define MEMDEV_WRITE _IOW(MAGIC_NUM,3,int)
/*最大的序列號(hào)*/
#define MEM_MAX_CMD 3
還有對(duì)命令進(jìn)行解析的宏,用來(lái)確定具體命令的四個(gè)部分(方向,大小,類型,序號(hào))具體如下所示:
/*確定命令的方向*/
_IOC_DIR(nr)
/*確定命令的類型*/
_IOC_TYPE(nr)
/*確定命令的序號(hào)*/
_IOC_NR(nr)
/*確定命令的大小*/
_IOC_SIZE(nr)
上面的幾個(gè)宏可以用來(lái)命令,實(shí)現(xiàn)命令正確性的檢查。
ioctl的實(shí)現(xiàn)過(guò)程主要包括如下的過(guò)程:
1、命令的檢測(cè)
2、指針參數(shù)的檢測(cè)
3、命令的控制switch-case語(yǔ)句
1、命令的檢測(cè)主要包括類型的檢查,數(shù)據(jù)大小,序號(hào)的檢測(cè),通過(guò)結(jié)合上面的命令解析宏可以快速的確定。
/*檢查類型,幻數(shù)是否正確*/
if(_IOC_TYPE(cmd)!=MAGIC_NUM)
return -EINVAL;
/*檢測(cè)命令序號(hào)是否大于允許的最大序號(hào)*/
if(_IOC_NR(cmd)> MEM_MAX_CMD)
return -EINVAL;
2、主要是指針參數(shù)的檢測(cè)。指針參數(shù)主要是因?yàn)閮?nèi)核空間和用戶空間的差異性導(dǎo)致的,因此需要來(lái)自用戶空間指針的有效性。使用copy_from_user,copy_to_user,get_user,put_user之類的函數(shù)時(shí),由于函數(shù)會(huì)實(shí)現(xiàn)指針參量的檢測(cè),因此可以省略,但是采用__get_user(),__put_user()之類的函數(shù)時(shí)一定要進(jìn)行檢測(cè)。具體的檢測(cè)方法如下所示:
if(_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE,(void *)args,_IOC_SIZE(cmd));
else if(_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ,(void *)args,_IOC_SIZE(cmd));
if(err)/*返回錯(cuò)誤*/
return -EFAULT;
當(dāng)方向是讀時(shí),說(shuō)明是從設(shè)備讀數(shù)據(jù)到用戶空間,因此要檢測(cè)用戶空間的指針是否可寫(xiě),采用VERIFY_WRITE,而當(dāng)方向是寫(xiě)時(shí),說(shuō)明是往設(shè)備中寫(xiě)數(shù)據(jù),因此需要檢測(cè)用戶空間中的指針的可讀性VERIFY_READ。檢查通常采用access_ok()實(shí)現(xiàn)檢測(cè),第一個(gè)參數(shù)為讀寫(xiě),第二個(gè)為檢測(cè)的指針,第三個(gè)為數(shù)據(jù)的大小。
3、命名的控制:
命令的控制主要是采用switch和case相結(jié)合實(shí)現(xiàn)的,這于window編程中的檢測(cè)各種消息的實(shí)現(xiàn)方式是相同的。
/*根據(jù)命令執(zhí)行相應(yīng)的操作*/
switch(cmd)
{
case MEMDEV_PRINTF:
printk("<--------CMD MEMDEV_PRINTF Done------------>");
...
break;
case MEMDEV_READ:
ioarg = &mem_devp->data;
...
ret = __put_user(ioarg,(int *)args);
ioarg = 0;
...
break;
case MEMDEV_WRITE:
...
ret = __get_user(ioarg,(int *)args);
printk("<--------CMD MEMDEV_WRITE Done ioarg = %d--------->",ioarg);
ioarg = 0;
...
break;
default:
ret = -EINVAL;
printk("<-------INVAL CMD--------->");
break;
}
關(guān)鍵詞:
Linux驅(qū)動(dòng)總
相關(guān)推薦
技術(shù)專區(qū)
- FPGA
- DSP
- MCU
- 示波器
- 步進(jìn)電機(jī)
- Zigbee
- LabVIEW
- Arduino
- RFID
- NFC
- STM32
- Protel
- GPS
- MSP430
- Multisim
- 濾波器
- CAN總線
- 開(kāi)關(guān)電源
- 單片機(jī)
- PCB
- USB
- ARM
- CPLD
- 連接器
- MEMS
- CMOS
- MIPS
- EMC
- EDA
- ROM
- 陀螺儀
- VHDL
- 比較器
- Verilog
- 穩(wěn)壓電源
- RAM
- AVR
- 傳感器
- 可控硅
- IGBT
- 嵌入式開(kāi)發(fā)
- 逆變器
- Quartus
- RS-232
- Cyclone
- 電位器
- 電機(jī)控制
- 藍(lán)牙
- PLC
- PWM
- 汽車電子
- 轉(zhuǎn)換器
- 電源管理
- 信號(hào)放大器
評(píng)論