主设备号--驱动模块与设备节点联系的纽带

一、如何对设备操作

    linux   中对设备进行操作是通过文件的方式进行的,包括open、read、wri     te  

对于设备文件,一般称其为设备节点,

 主设备号__驱动模块与设备节点联系的纽带_设计制作_可编程逻辑

节点有一个属性是设备号(主设备号、次设备号),其中主设备号将设备文件与驱动模块对应起来

当我们open一个设备节点时,告诉了kernel要操作的是是主设备号为XX的节点,然后kernel会通过过XX来寻找合适的内存模块,进而调用内存模块中定义的open函数

由于操作节点之前kernel就需要有主设备号的信息,因此主设备号的申请、具有该主设备号的     字符   设备的添加都需要在驱动模块的初始化函数中执行

二、主设备号的申请

建议采用动态申请的主设备号的方式,linux中有很多设备,每一个设备对应着一个主设备号,动态申请是由内核分配一个没用的主

设备号,

动态申请函数为alloc_chrdev_region,相对应的释放函数为unregister_chrdev_region。

申请完后,可以从/proc/devices中读到分配的主设备号,后面建立设备节点时还需要用到

三、向kernle添加字符设备

上一步向内核申请了主设备号,就可以向kernel中添加字符设备了

kennel中一个字符设备对应了一个结构体cdev,这个结构体中定义了对字符设备的操作方式file_opera     ti   ons(包括open、read、write),这些操作方式也需要在驱动模块中事先定义好。

字符设备结构体cdev的添加步骤:

cdev初始化:cdev_init,该函数将file_opera  TI ons与cdev对应起来

向kernel添加:cdev_add,该函数将主设备号与cdev结构体对应起来

当对open设备节点时,首先通过节点找到主设备号,然后再kernel中搜索与主设备号相对应的字符设备cdev,然后动过cdev中file_opera  TI ons结构体定义的open方法(这个open是需要自己实现的)

四、3个重要的结构体

一个是file_opera  TI ons,这里面主要包含了驱动的主要实现方法

一个是inode,这个是节点的信息,包含了主设备号和cdev结构体

一个是file,当节点首次被打开时,就会在内核中创建一个file结构体,file结构其充当了file_opera  TI ons中方法的纽带,要不然read和wirte方法怎么知道操作的是那个设备的数据。

file中的自定义内容(驱动需要的数据)一般是在open中定义,然后read和write就可以操作自定义的数据了。

下面是一个简单的实例,可以看到驱动是怎样把自定义的open方法和主设备号对应起来的

#include /*它定义了模块的 A     PI   、类型和宏(MODULE_LICENSE、MODULE_AUTHOR等等),所有的内核模块都必须包含这个头文件。*/

#include

#include //设备号相关函数

#include //内存分配相关函数

#include

#include //设备号相关函数

#include //字符设备头文件

#include

struct char_dev

{

int size;

char *data;

struct cdev cdev;//内核中的字符设备

};

int major = 0;

int     mi   nor = 0;

struct char_dev char_devices;

int char_open(struct inode *inode, struct file *filep)

{

int Major = 0;

Major = MAJOR(inode-》i_rdev);

printk(“open my_char_dev major: %d\n”, Major);

return 0;

}

struct file_operations char_fops = {

.owner = THIS_MODULE,

.open = char_open,

};

static void char_exit(void) //如果init函数中调用了该函数,则不应有 __exit

{

dev_t dev;

printk(“char device driver exit \n”);

//释放设备号

dev = MKDEV(major, minor);

unregister_chrdev_region(dev, 1);

printk(“release major %d\n”, major);

//释放内存

if(char_devices.data){

kfree(char_devices.data);

}

//从内核中删除字符设备

cdev_del(&(char_devices.cdev));

}

static int __init char_init(void)//__init一个     标记   ,表明是初始化函数

{

//初始化的代码

dev_t dev;

int result;

printk(“char device driver init \n”);

//动态向内核申请设备号

result = alloc_chrdev_region(&dev, 0, 1, “my_char_dev”);

major = MAJOR(dev);

minor = MINOR(dev);

printk(“alloc major %d\n”, major);

if (result 《 0) {

printk(KERN_WARNING “my_char_dev:     can   ‘t get major %d\n”, major);

return result;

}

//为设备分配一块内存

char_devices.size = 100;

char_devices.data = (char*)kmalloc(char_devices.size, GFP_KERNEL);

if (!char_devices.data) {

result = -ENOMEM;

goto f     ai   l; //不能直接退出函数,需要释放设备号

}

//向内核中添加字符设备cdev

cdev_init(&(char_devices.cdev), &char_fops);

char_devices.cdev.owner = THIS_MODULE;

char_devices.cdev.ops = &char_fops;

result = cdev_add(&(char_devices.cdev), dev, 1);

if((result 《 0)) {

printk(KERN_WARNING “Error %d adding my_char_dev\n”, result);

goto fail;

}

return 0; //成功

fail:

char_exit();

return result;

}

MODULE_LICENSE(“Dual BSD/GPL”);

//当模块被加载时,执行moudle_init函数,该函数会调用初始化函数

module_init(char_init);

//模块卸载时,调用,释放资源

module_exit(char_exit);

KDIR=/usr/src/linux-heade     rs   -$(shell uname -r)

PWD=$(shell pwd)

obj-m = CharDevice.o

all:

$(MAKE) -C $(KDIR) M=$(PWD)

注:驱动insmod后,通过/proc/devices查看主设备号,然后通过mknod在/dev下创建设备节点,注意保持主设备好的一致,当前的节点只支持open方法,可以在demsg中进行验证。

50
146
0
17

相关资讯

  1. 1、移动互联网时代,网易该如何网聚人的力量2627
  2. 2、五大指标衡量移动应用是否成功4782
  3. 3、算法PK内容,短视频的市场红利期还能延续多久?1486
  4. 4、从星巴克和COSTA的产品策略说“锚定效应”3350
  5. 5、张小龙演讲内容深度解析&微信新功能预测334
  6. 6、看你的面试官如何考验你2969
  7. 7、社交领域不会有终局,除非人类停止前进4933
  8. 8、内容运营的标准化:内容即商品1123
  9. 9、美团给创业者的启示5000
  10. 10、黎万强:小米式口碑的7个内部铁规2117
全部评论(0)
我也有话说
0
收藏
点赞
顶部