Linux下驅(qū)動開發(fā)
1.簡介
驅(qū)動,是指驅(qū)動計(jì)算機(jī)里軟件的程序。驅(qū)動程序全稱設(shè)備驅(qū)動程序,是添加到操作系統(tǒng)中的特殊程序,其中包含有關(guān)硬件設(shè)備的信息。驅(qū)動程序是操作系統(tǒng)與硬件連接的橋梁。
設(shè)備驅(qū)動最通俗的解釋就是“驅(qū)使硬件設(shè)備行動”。驅(qū)動與底層硬件直接打交道,按照硬件設(shè)備的具體工作方式,讀寫設(shè)備的寄存器,完成設(shè)備的輪詢、中斷處理、DMA通信,進(jìn)行物理內(nèi)存向虛擬內(nèi)存的映射等,最終讓通信設(shè)備能收發(fā)數(shù)據(jù),讓顯示設(shè)備能顯示文字和畫面,讓存儲設(shè)備能記錄文件和數(shù)據(jù)。
2.驅(qū)動分類
Linux驅(qū)動分類:
字符設(shè)備、塊設(shè)備、網(wǎng)絡(luò)設(shè)備。
網(wǎng)絡(luò)設(shè)備: 有線網(wǎng)卡、無線網(wǎng)卡、其它與網(wǎng)絡(luò)相關(guān)的設(shè)備。
塊設(shè)備: U盤、SD卡、硬盤、光盤等。
字符設(shè)備: 除了塊設(shè)備和網(wǎng)絡(luò)設(shè)備,其它都?xì)w結(jié)于字符設(shè)備。
字符設(shè)備中分類: 雜項(xiàng)設(shè)備、輸入設(shè)備(鍵盤、鼠標(biāo)、觸摸屏)、幀緩沖(顯示類設(shè)備)、RTC設(shè)備、串口設(shè)備等。
3.雜項(xiàng)設(shè)備
驅(qū)動程序是應(yīng)用層和硬件層的連接橋梁,應(yīng)用層只管完成應(yīng)用邏輯開發(fā)和界面設(shè)計(jì),驅(qū)動層則處理硬件配置,實(shí)現(xiàn)應(yīng)用層相關(guān)接口函數(shù)。
雜項(xiàng)設(shè)備:字符設(shè)備類的一種,是除了上述輸入設(shè)備、幀緩沖設(shè)備、RTC設(shè)備后的其它設(shè)備,例LED設(shè)備,由于不好歸結(jié)于上述分類,則可將LED設(shè)備按雜項(xiàng)設(shè)備類進(jìn)行注冊。雜項(xiàng)設(shè)備主設(shè)備號為10。
在生成的設(shè)備節(jié)點(diǎn)中,主設(shè)備號用來區(qū)分設(shè)備類。如字符設(shè)備中雜項(xiàng)設(shè)備主設(shè)備號為10,幀緩沖設(shè)備主設(shè)備號為29;次設(shè)備號用來區(qū)分這個類中的具體硬件。
4.驅(qū)動注冊框架
4.1開發(fā)平臺
開發(fā)平臺:Ubuntu18.04
編譯器:arm-linux-gcc
硬件平臺:tiny4412基于Cortex-A9 4核1.5GHZ
開發(fā)板內(nèi)核:Linux3.5
4.2 驅(qū)動模板
#include
#include
/*驅(qū)動初始化*/
static int __init wbyq_hello_module_init(void)
{
printk("驅(qū)動入口,驅(qū)動注冊成功n");
return 0;
}
/*驅(qū)動釋放*/
static void __exit wbyq_hello_module_cleanup(void)
{
printk("驅(qū)動出口,驅(qū)動注銷成功n");
}
module_init(wbyq_hello_module_init);//驅(qū)動入口函數(shù)
module_exit(wbyq_hello_module_cleanup);//驅(qū)動出口函數(shù)
MODULE_LICENSE("GPL");//驅(qū)動注冊協(xié)議
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 hello Driver");
4.3 驅(qū)動編譯
KER_ADD=/home/wbyq/src_pack/linux-3.5 #linux3.5內(nèi)核的Makefile位置
all:
make -C $(KER_ADD) M=`pwd` modules #通過調(diào)用linux3.5內(nèi)核的Makefile文件進(jìn)行編譯
cp ./*.ko /home/wbyq/src_pack/rootfs/code #將驅(qū)動文件拷貝到code目錄下
make -C $(KER_ADD) M=`pwd` modules clean #清空文件
obj-m +=hello_drv.o #添加依賴文件
4.4 驅(qū)動安裝
[root@wbyq code]# insmod hello_drv.ko #安裝驅(qū)動
[ 4684.795000] 驅(qū)動入口,驅(qū)動注冊成功
[root@wbyq code]# modinfo hello_drv.ko #查看驅(qū)動詳細(xì)信息
modinfo: can't open '/lib/modules/3.5.0-FriendlyARM/modules.dep': No such file or directory
[root@wbyq code]# mkdir /lib/modules/3.5.0-FriendlyARM/ -p
[root@wbyq code]# touch /lib/modules/3.5.0-FriendlyARM/modules.dep
[root@wbyq code]# lsmod #查看動態(tài)安裝的驅(qū)動
hello_drv 612 0 - Live 0xbf000000 (O)
[root@wbyq code]# rmmod hello_drv.ko #注銷驅(qū)動
[ 5610.635000] 驅(qū)動出口,驅(qū)動注銷成功
5 編寫蜂鳴器驅(qū)動
5.1 硬件接口
??蜂鳴接口:BP1 – GPD0_0 高電平驅(qū)動。
?? GPD0_CON:0x1140 0000+0x00A0 --配置寄存器
5.2 蜂鳴器驅(qū)動層
?? 1.調(diào)用驅(qū)動注冊和注銷函數(shù),在驅(qū)動入口函數(shù)中實(shí)現(xiàn)BEEP硬件接口配置。在驅(qū)動出口函數(shù)中完成硬件資源釋放。
?? 2.通調(diào)用雜項(xiàng)設(shè)備驅(qū)動框架完成雜項(xiàng)設(shè)備注冊,注冊成功后在/dev生成beep的設(shè)備節(jié)點(diǎn)。完成應(yīng)用層相關(guān)接口函數(shù)編寫。
#include
#include
#include
#include
#include
/*驅(qū)動初始化*/
unsigned int *GPDO_CON;
unsigned int *GPDO_DAT;
int beep_open(struct inode *inode, struct file *file)/*對應(yīng)應(yīng)用層open函數(shù)*/
{
printk("open函數(shù)調(diào)用成功n");
return 0;
}
int beep_release(struct inode *inode, struct file *file) /*對應(yīng)應(yīng)用層close*/
{
printk("releasse函數(shù)調(diào)用成功n");
*GPDO_DAT&=~(1<<0);
return 0;
}
ssize_t beep_read(struct file *file, char __user * data, size_t size, loff_t *offset)/*對應(yīng)應(yīng)用層read*/
{
int *p=(int *)data;
*p=123;
printk("read函數(shù)調(diào)用成功n");
return 4;
}
ssize_t beep_write(struct file *file, const char __user *data, size_t size, loff_t *offset)/*對應(yīng)應(yīng)用層write*/
{
char buff[20];
memcpy(buff,data,size);
buff[size]='';
printk("buff=%sn",buff);
if(strcmp(buff,"beep_on")==0)//開蜂鳴器
{
*GPDO_DAT|=1<<0;
}
else if(strcmp(buff,"beep_off")==0)//關(guān)蜂鳴器
{
*GPDO_DAT&=~(1<<0);
}
return size;//返回寫入成功的字節(jié)數(shù)
}
/*文件操作集合結(jié)構(gòu)體*/
static struct file_operations beep_fops=
{
.owner = THIS_MODULE,/*當(dāng)前模塊*/
.open = beep_open,
.release = beep_release,
.read =beep_read,
.write =beep_write
};
/*雜項(xiàng)設(shè)備結(jié)構(gòu)體*/
static struct miscdevice tiny4412_beep = {
.minor = MISC_DYNAMIC_MINOR,//次設(shè)備號,255表示由系統(tǒng)自動分配
.name = "beep", /*在/dev生成的設(shè)備節(jié)點(diǎn)名字*/
.fops = &beep_fops,
};
static int __init wbyq_beep_init(void)
{
printk("驅(qū)動入口,驅(qū)動注冊成功n");
/*蜂鳴器配置*/
GPDO_CON=ioremap(0x114000A0, 4);//將GPDO_CON物理地址轉(zhuǎn)換虛擬地址
GPDO_DAT=ioremap(0x114000A4, 4);//將GPDO_DAT物理地址轉(zhuǎn)換虛擬地址
/*蜂鳴器*/
*GPDO_CON&=0xfffffff0;//清除當(dāng)前GPD0_0的配置
*GPDO_CON|=0x00000001;//設(shè)置為輸出模式
/*注冊雜項(xiàng)設(shè)備:在/dev下生成設(shè)備節(jié)點(diǎn),實(shí)現(xiàn)應(yīng)用層接口函數(shù)*/
misc_register(&tiny4412_beep);
return 0;
}
/*驅(qū)動釋放*/
static void __exit wbyq_beep_cleanup(void)
{
printk("驅(qū)動出口,驅(qū)動注銷成功n");
/*注銷雜項(xiàng)設(shè)備*/
misc_deregister(&tiny4412_beep);
iounmap(GPDO_CON);
iounmap(GPDO_DAT);
}
module_init(wbyq_beep_init);//驅(qū)動入口函數(shù)
module_exit(wbyq_beep_cleanup);//驅(qū)動出口函數(shù)
MODULE_LICENSE("GPL");//驅(qū)動注冊協(xié)議
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 beep Driver");
?? 雜項(xiàng)設(shè)備主設(shè)備為10,次設(shè)備可填值為0~254;當(dāng)次設(shè)備號填255時(shí)表示有系統(tǒng)分配。
5.3 蜂鳴器應(yīng)用層
?? Linux下一切皆文件,操作設(shè)備就和操作文件一樣。只需要open打開設(shè)備、讀寫設(shè)備、操作完成關(guān)閉設(shè)備即可。
#include
#include
#include
#include
#include
#include
int main()
{
/*1.打開設(shè)備*/
int fd=open("/dev/beep",2);
if(fd<0)
{
printf("/dev/beep 設(shè)備打開失敗n");
return 0;
}
int data=0;
int size;
/*讀寫文件*/
size=read(fd,&data,4);
printf("size=%d,data=%dn",size,data);
while(1)
{
write(fd,"beep_on",strlen("beep_on"));//開蜂鳴器
sleep(1);
write(fd,"beep_off",strlen("beep_off"));//關(guān)蜂鳴器
sleep(1);
}
close(fd);//關(guān)閉文件
}
? 在Linux內(nèi)核中,設(shè)備節(jié)點(diǎn)的訪問是通過主設(shè)備+次設(shè)備號的組合來完成的,占32位,主設(shè)備號是20 ~ 31位。次設(shè)備號是0 ~ 19位。
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1372瀏覽量
40275 -
Linux
+關(guān)注
關(guān)注
87文章
11292瀏覽量
209318 -
驅(qū)動開發(fā)
+關(guān)注
關(guān)注
0文章
130瀏覽量
12072
發(fā)布評論請先 登錄
相關(guān)推薦
評論