本文也即是《Linux Device Drivers》一书第三章Char Drivers的读书笔记之一。
我们在/dev中可以查看设备节点,每个设备有一个主号码(major)以及一个副号码(minor),通常一个major号码对应某一种设备,虽然linux允许多种设备共享一个major号码。minor号码用于kernel具体进行设备的对应,kernel并不了解对应在minor后面设备具体的应用。
在一个kenrel module的程序中,我们需要将我们的程序和某个或某组设备节点对应起来。在这个scull的例子中,使用的是char型的设备节点,他是内存中的某一个部分(这样无需特别的设备)。这些设备可能已经有固定的主号码,也可能没有而采用系统自动分配的方式。通过下面的例子来学习。
头文件scull.h如下:如果major不为0,则为指定的major号码,如果为0,则采用系统自行动态分配的方式。我们的模块包括4个设备,minor号码从0-3。
#ifndef _WEI_SCULL_H
#define _WEI_SCULL_H
#define SCULL_MAJOR 0
#define SCULL_MINOR_MIN 0
#define SCULL_DEV_NUM 4
#endif
源文件scull.c如下,我们学习三个函数:
int register_chrdev_region(dev_t first,unsigned int count,char *name);
int alloc_chrdev_region(dev_t * dev, unsigned int firstminor, unisgned int count ,char *name);
void unregister_chrdev_region(dev_t first, unsigned int count);
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include "scull.h"
MODULE_LICENSE("Dual BSD/GPL");
dev_t dev;
int is_get_dev = -1;
static int scull_major = SCULL_MAJOR;
static int __init scull_init(void)
{
printk("Scull module init enter/n");
if(scull_major){ /* 根据major和minor号码获得dev */
dev = MKDEV(scull_major,SCULL_MINOR_MIN );
is_get_dev = register_chrdev_region (dev, SCULL_DEV_NUM,"scull");//注册
}else{ /* 系统动态分配 */
is_get_dev = alloc_chrdev_region (&dev,SCULL_MINOR_MIN, SCULL_DEV_NUM,"scull");
scull_major = MAJOR(dev ); //获取主号码,MINOR()可获取minor号码
}
if(is_get_dev < 0){
printk(KERN_WARNING "scull: can't get device major number %d/n",scull_major);
}
return is_get_dev;
}
/*在模块结束的时候,应该释放注册的资源*/
static void __exit scull_exit(void)
{
if(is_get_dev < 0){
return ;
}else{
unregister_chrdev_region(dev,SCULL_DEV_NUM );
printk("Scull module exit/n");
}
}
module_init(scull_init);
module_exit(scull_exit);
如果这些设备节点已经存在于系统中,可以在/dev中查看,也可以在/proc/devices中查看major号码和设备名称的对应。我们手动去mknod我们的设备节点,这种情况,major号码为我们手动配置的主号码,在scull.h的宏定义中去定义,或者我们也可以在加载模块的时候作为参数带入。如果我们由系统进行动态分配,那么需等待系统分配后,知道主号码,才能创建设备节点。我们可以利用脚本来完成这个工作,下面是加载模块,并自动创建节点的脚本scull_load
[wei@wei ~]$ cat scull_load
#!/bin/sh
module="scull"
device="scull"
mode="644"#加载节点,如果加载不成功(可能已经load过),则退出
/sbin/insmod ./$module.ko $* || exit 1
#如果/dev中含有以前创建的节点,删除它们,当然我们也可以判断major号是否和分配的一直,来决定保留或者删除
rm -f /dev/${device}[0-3]
#这是获取major号的过程,awk的使用,可以参考文档:http://www.ibm.com/developerworks/cn/linux/shell/awk/awk-1/ 将/proc/devices作为输入,按行输入,如果第二个参数匹配$module,这打印第一个参数,也即赋值给major
major=$(awk "/$2==/"$module/" {print /$1}" /proc/devices)
echo major=${major}
#mknod四个设备节点
mknod /dev/${device}0 c $major 0
mknod /dev/${device}1 c $major 1
mknod /dev/${device}2 c $major 2
mknod /dev/${device}3 c $major 3
#一般而言,kernel模块的操作权限都是root,但是有时候我们希望某些用户也可以有读取的权限需要修改设备节点的权限。下面允许组wei的操作,如果组wei不存在,则为组moblin。
group="wei"
grep -q '^wei:' /etc/group|| group="moblin"
chgrp $group /dev/${device}[0-3]
chmod $mode /dev/${device}[0-3]
下面是卸载是的脚本scull_unload,我们需要删除创建的设备节点。
[wei@wei ~]$ cat scull_unload
#!/bin/sh
module="scull"
device="scull"
#如果没有加载该模块结束,否则卸载模块,并删除相关的节点。
/sbin/lsmod | grep $module || exit 1/sbin/rmmod $module
rm -f /dev/${device}[0-3]
相关链接:我的与kernel module有关的文章