浅谈linux驱动2字符设备驱动程序Word下载.docx
《浅谈linux驱动2字符设备驱动程序Word下载.docx》由会员分享,可在线阅读,更多相关《浅谈linux驱动2字符设备驱动程序Word下载.docx(9页珍藏版)》请在冰豆网上搜索。
接下来我们看看在内核当中是如何表述设备号的,其实在linux内核当中,这个主次设备号是有规律的,主次设备号加在一起,实质就是unsignedint32位整数,它用dev_t来描述。
其中高12位是主设备号,低20位是次设备号。
一般情况下,我们不会说出现上千个设备的,所有主设备号是够用的,2的12次方是多少?
4096,也就是说最多支持4096种类型的设备。
我们是怎样从dev_t分离出主设备号和次设备号的呢?
用MAJOR(dev_tdev)这个宏分离出主设备号,用MINOR(dev_tdev)这个宏分离出次设备号。
linux内核如何给设备分配设备号呢?
分两种:
静态申请,动态分配。
如何静态申请呢?
首先我们要知道设备号存放在哪里?
我们来看下图
然后打开这个文挡
上面描述可能还有点问题,总之你选用的设备号,是前面没有出现过的才行。
然后使用register_chrdev_region这个函数去注册去申请设备号。
intregister_chrdev_region(dev_from,unsignedcount,constchar*name)
from代表你希望使用的设备号是多少?
比如我选个500,总之前面没出现过就行。
count表示希望申请使用设备号的数目,比如我们申请了5个,那么系统就会给你留5个号出来,打个比方,5000,5001,5002,5003,5004.
name是设备名,比如serial。
接下来我们谈谈动态分配,我们常常会担心自己选的设备号前面已经用过了,担心设备号选错引起不必要的麻烦,那么我们现在就采取动态分配设备号的方式,让内核来分配设备号,内核一定比我们清楚哪些设备号是空闲的.我们用alloc_chrdev_region这个函数来分配设备号。
这里有个需要注意的,这里动态分配设备号,一定是要在驱动安装之后才能执行的。
动态分配intalloc_chrdev_region(dev_t*dev,unsignedbaseminor,unsignedcount,constchar*name),意思就是请求内核分配count个设备号,且次设备号从baseminor开始。
(dev是主设备号,baseminor是起始次设备号,count是分配的设备号数目,name是设备名)。
设备号是相当宝贵的,不用的时候请注销掉,voidunregister_chrdev_region(dev_tfrom,unsignedcount)
有了设备号之后我们要创建设备文件了,创建设备文件的办法有两种:
1.mknod,命令手工创建
2.自动创建
mknod用法,mknodfilenametypemajorminor,这里filename表示设备名,type表示设备类型(比如clock,char啊),major是主设备号,minor是次设备号。
打个比方
在linux字符驱动程序设计中,有三种非常重要的数据结构:
structfile(表示打开的文件,系统每个打开的文件内核都有一个关联的structfile,内核打开文件的时候创建,在文件关闭之后是自动释放)
structinode(记录文件物理信息,比如文件的位置,比如一个设备文件的设备号是多少,一个文件可以有多个file结构,但只有一个inode)
structfile_operations(一个函数指针的集合,定义能在设备上进行的操作,结构中的成员指向驱动中的函数,这些函数实现一个特别的操作,对于不支持的操作,保存为null)打个比方,我们应用程序需要通过驱动程序来对硬件进行操作,比如我们应用程序发出一个read的调用,那么我们驱动程序凭什么对你发出的read做出反应?
那么请看下面的一张图
还是拿read来做例子,应用程序发出read,全凭这张图里函数的转换,驱动程序做出反应,调用memoryread。
我这里拿了个led的例子供大家参考对照理解
#include<
linux/kernel.h>
linux/module.h>
linux/init.h>
linux/proc_fs.h>
linux/seq_file.h>
linux/string.h>
linux/jiffies.h>
linux/timer.h>
linux/uaccess.h>
asm/auxio.h>
#defineLED_MAX_LENGTH8/*maximumcharswrittentoprocfile*/
staticinlinevoidled_toggle(void)
{
unsignedcharval=get_auxio();
unsignedcharon,off;
if(val&
AUXIO_LED){
on=0;
off=AUXIO_LED;
}else{
on=AUXIO_LED;
off=0;
}
set_auxio(on,off);
}
staticstructtimer_listled_blink_timer;
staticvoidled_blink(unsignedlongtimeout)
led_toggle();
/*reschedule*/
if(!
timeout){/*blinkaccordingtoload*/
led_blink_timer.expires=jiffies+
((1+(avenrun[0]>
>
FSHIFT))*HZ);
led_blink_timer.data=0;
}else{/*blinkatuserspecifiedinterval*/
led_blink_timer.expires=jiffies+(timeout*HZ);
led_blink_timer.data=timeout;
add_timer(&
led_blink_timer);
staticintled_proc_show(structseq_file*m,void*v)
if(get_auxio()&
AUXIO_LED)
seq_puts(m,"
on\n"
);
else
off\n"
return0;
staticintled_proc_open(structinode*inode,structfile*file)
returnsingle_open(file,led_proc_show,NULL);
staticssize_tled_proc_write(structfile*file,constchar__user*buffer,
size_tcount,loff_t*ppos)
char*buf=NULL;
if(count>
LED_MAX_LENGTH)
count=LED_MAX_LENGTH;
buf=kmalloc(sizeof(char)*(count+1),GFP_KERNEL);
buf)
return-ENOMEM;
if(copy_from_user(buf,buffer,count)){
kfree(buf);
return-EFAULT;
buf[count]='
\0'
;
/*workaround\nwhenecho'
ingintoproc*/
if(buf[count-1]=='
\n'
)
buf[count-1]='
/*beforewechangeanythingwewanttostopanyrunningtimers,
*otherwisecallssuchasonwillhavenopersistenteffect
*/
del_timer_sync(&
strcmp(buf,"
on"
)){
auxio_set_led(AUXIO_LED_ON);
}elseif(!
toggle"
led_toggle();
}elseif((*buf>
'
0'
)&
&
(*buf<
='
9'
led_blink(simple_strtoul(buf,NULL,10));
load"
led_blink(0);
auxio_set_led(AUXIO_LED_OFF);
kfree(buf);
returncount;
staticconststructfile_operationsled_proc_fops={
.owner=THIS_MODULE,
.open=led_proc_open,
.read=seq_read,
.llseek=seq_lseek,
.release=single_release,
.write=led_proc_write,
};
staticstructproc_dir_entry*led;
#defineLED_VERSION"
0.1"
staticint__initled_init(void)
init_timer(&
led_blink_timer.function=led_blink;
led=proc_create("
led"
0,NULL,&
led_proc_fops);
led)
led->
owner=THIS_MODULE;
printk(KERN_INFO
"
led:
version%s,LarsKotthoff<
metalhead@metalhead.ws>
\n"
LED_VERSION);
staticvoid__exitled_exit(void)
remove_proc_entry("
NULL);
module_init(led_init);
module_exit(led_exit);
MODULE_AUTHOR("
LarsKotthoff<
"
MODULE_DESCRIPTION("
ProvidescontrolofthefrontLEDonSPARCsystems."
MODULE_LICENSE("
GPL"
MODULE_VERSION(LED_VERSION);