字符设备注册过程自用.docx
- 文档编号:16992419
- 上传时间:2023-07-21
- 格式:DOCX
- 页数:9
- 大小:17.20KB
字符设备注册过程自用.docx
《字符设备注册过程自用.docx》由会员分享,可在线阅读,更多相关《字符设备注册过程自用.docx(9页珍藏版)》请在冰点文库上搜索。
字符设备注册过程自用
字符设备的注册:
1》杂项设备
主设备号:
10
需要一个核心结构体变量来描述这个设备。
structmiscdevicedev_misc={
.minor=次设备号/255
.name=设备节点名
.f_ops=操作函数集
};
次设备为255时,自动分配一个次设备号,其它值则是分配一个固定的设备号。
杂项设备注册时自动生成设备节点。
.name就是设备节点的名字。
基础函数不用管,只看注册方面:
/*使用杂项设备方式注册分设备,主设备号固定为10设备名:
misc
structmiscdevice{
intminor;//次设备号
constchar*name;//设备节点名
conststructfile_operations*fops;
//操作函数集指针
};*/
/*这是gcc编译器对C语言的语法扩充*/
staticstructmiscdeviceled_dev={
.fops=&led_fops,
.name="myled",
.minor=255,//表示自动分配
};
staticintmyled_init(void)
{
/*注册:
往登记表中添加设备*/
/*使用杂项设备的注册方式*/
intret;
ret=misc_register(&led_dev);
if(ret<0){
printk("registererror\n");
return-1;
}
//物理地址到虚拟地址的映射
gpbbase=ioremap(0x56000010,16);
printk("led_driverregisterdone\n");
return0;
}
staticvoidmyled_exit(void)
{
/*注销卸载*/
misc_deregister(&led_dev);
iounmap(gpbbase);
}
2》经典注册方式
注册函数:
intregister_chrdev(unsignedintmajor,
constchar*name,
conststructfile_operations*fops)
向内核注册一类字符设备:
major:
主设备号
name:
设备名
fops:
操作函数集
返回值为0表示让内核自动分配一个没使用的设备号,执行make成功,则把分配的的设备号返回,失败则返回负值。
如果是非0值则表示向内核注册设备使用主设备号为该值。
如果执行成功,则返回值为0,执行失败则返回负值。
Make成功之后[@linux/home]#insmodold_leds_driver.ko先加载与一下,然后查看cat/proc/devices你可以找到注册的模块的信息。
来了解已经注册的设备类型。
然后进行手动创建设备节点。
它不能自动创建设备节点,需使用mknod手动创建;
Mknod+设备名+类型(字符,块)+主设备号+次设备号
在当前目录下执行:
[@linux/dev]#mknodmyledc2551
在别的目录下:
[@linux/dev]#mknod/dev/myledc2551
部分代码:
(操作函数集指针不写出来了)
staticstructfile_operationsled_fops={
.owner=THIS_MODULE,
.open=leds_open,
.release=leds_release,
.ioctl=leds_ioctl,
.write=leds_write,
.read=leds_read,
.llseek=leds_lseek,
};
#defineDEV_NAME"led_old"
#defineLED_MAJOR0
staticintmajor;
staticintmyled_init(void)
{
/*注册:
往登记表中添加设备*/
major=register_chrdev(LED_MAJOR,DEV_NAME,&led_fops);
if(major<0){
printk("register_chrdeverror\n");
return-EINVAL;
}
printk("themajoris%d\n",major);
//物理地址到虚拟地址的映射
gpbbase=ioremap(0x56000010,16);
printk("led_driverregisterdone\n");
return0;
}
staticvoidmyled_exit(void)
{
/*注销卸载*/
//misc_deregister(&led_dev);
unregister_chrdev(major,DEV_NAME);
iounmap(gpbbase);
}
3》2.6版本的注册方式
从2.6版本以来新加入的一种注册方式
使用一个核心结构体cdev描述该类设备:
structcdev{
structkobjectkobj;
structmodule*owner;//拥有者指针
conststructfile_operations*ops;//操作函数集
structlist_headlist;//链表头
dev_tdev;//设备号
unsignedintcount;//次设备号数量
};
在编程中需要程序员填充的:
opsdevcount
>使用dev_t类型来表示一个设备号,实际上就是unsignedlong
typedefu_longdev_t;
unsignedlong:
此处是4个字节.
32位:
(12|20)
高12位是主设备号,范围是0~4095;低20位是次设备号,范围0~1M-1。
使用下列宏可以从dev_t获得主设备号和次设备号。
MAJOR(dev_tdev);//获取主设备号
MINOR(dev_tdev);//获取次设备号
而使用下列宏则可以通过主设备号和设备号生成dev_t。
MKDEV(intmajor,intminor);//生成设备号
led设备为例:
MKDEV(252,0)10
内核提供的申请设备号的函数:
>静态申请:
intregister_chrdev_region(dev_tfrom,unsignedcount,constchar*name)
from:
设备号的指定值(起始值)
count:
连续申请多少个次设备号
name:
设备名。
返回值:
0:
成功;负数:
失败
dev_tmajor;
>动态申请:
intalloc_chrdev_region(dev_t*dev,unsignedbaseminor,unsignedcount,constchar*name)
dev:
存放分配成功的第一个设备号的指针。
baseminor:
起始次设备号
count:
连续申请多少个次设备号
name:
设备名。
返回值:
0:
成功;负数:
失败
注销设备号:
voidunregister_chrdev_region(dev_tfrom,unsignedcount);
from:
设备号的起始值
count:
连续申请多少个次设备号
-------------------------------------部分代码如下
staticstructclass*dev_class;//创建一个指向class类型的结构体的指针
staticstructdevice*dev_device;//创建一个指向device类型的结构体的指针
staticstructcdevcdev_led;创建一个结构体cdev_led
staticintmajor=0;//major用来判断进行静态申请,还是动态申请
staticintmyled_init(void)
{
/*注册:
往登记表中添加设备*/
intret;
dev_tdev;//定义一个结构体
/*linux2.6的注册方式*/
/*申请设备号*/
if(major){
ret=register_chrdev_region(MKDEV(major,0),5,"led_26");//major.>0是静态申请设备号
if(ret<0){
printk("register_chrdev_regionerror\n");
gotofree_return;
}
}
else{
ret=alloc_chrdev_region(&dev,0,5,"led_26");//major=0n动态申请
if(ret<0){
printk("register_chrdev_regionerror\n");
gotofree_return;//申请失败,直接跳到最后,返回一个负值
}
major=MAJOR(dev);//取主设备号,并把主设备号赋值给major
}
/*初始化核心结构体*/
cdev_init(&cdev_led,&led_fops);
/*真正向内核注册*/
ret=cdev_add(&cdev_led,MKDEV(major,0),5);//这个函数是向内核注册的函数
if(ret<0){
printk("cdev_adderror\n");
gotofree_chrdev_region;//注册失败,说明上一步是成功的,要相应的把上一步的,撤销掉,就goto到了下面的释放阶段
}
dev_class=class_create(THIS_MODULE,"dev_26");//创建一个类,和下面1的函数一起为的是自动注册一个设备节点
if(IS_ERR(dev_class))
{ret=PTR_ERR(dev_class);
gotofree_cdev_add;//同理,和上面的一样,这一步失败了,应该相应的把上一步的释放掉。
}
dev_device=device_create(dev_class,NULL,MKDEV(major,0),NULL,"led_26");
if(IS_ERR(dev_device))
{ret=PTR_ERR(dev_device);
gotofree_class_create;
}
printk("themajoris%d\n",major);
//物理地址到虚拟地址的映射
gpbbase=ioremap(0x56000010,16);
printk("led_driverregisterdone\n");
return0;
//下面的都相应的做释放的工作,上面步骤可以直接goto到这里,进行释放
free_class_create:
class_destroy(dev_class);
free_cdev_add:
cdev_del(&cdev_led);
free_chrdev_region:
unregister_chrdev_region(MKDEV(major,0),5);
free_return:
returnret;
}
staticvoidmyled_exit(void)
{
/*注销卸载*/
device_destroy(dev_class,MKDEV(major,0));//毁掉
class_destroy(dev_class);//把那个结构体毁掉
cdev_del(&cdev_led);//删掉建立的结构体
unregister_chrdev_region(MKDEV(major,0),5);//将申请的设备号,释放掉,只有这一种释放函数。
iounmap(gpbbase);//不在虚拟映射地址
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 字符 设备 注册 过程 自用