一般的关于设备号的代码就是这样子
int major; /* 主设备号 */
int minor; /* 次设备号 */
dev_t devid; /* 设备号 */
if (major) { /* 定义了主设备号 */
devid = MKDEV(major, 0); /* 大部分驱动次设备号都选择0 */
register_chrdev_region(devid, 1, "test");
} else { /* 没有定义设备号 */
alloc_chrdev_region(&devid, 0, 1, "test"); /* 申请设备号 */
major = MAJOR(devid); /* 获取分配号的主设备号 */
minor = MINOR(devid); /* 获取分配号的次设备号 */ 12 }
注销就是
unregister_chrdev_region(devid, 1);
字符设备结构
struct cdev{
struct kobject kobj;
struct module *owner; //一般等于THIS_MOUDLE
const struct file_operations *ops; //文件系统
struct class *class; //创建的类和自动创建设备节点有关 创建函数返回的是指针
struct list_head list;
dev_t dev; //设备号
unsigned int count;
}
struct cdev test_cdev;
cdev_init()函数
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
/***********使用方法***************/
struct cdev testcdev;
/* 设备操作函数 */
static struct file_operations test_fops = { .owner = THIS_MODULE,
/* 其他具体的初始项 */
};
testcdev.owner = THIS_MODULE;
cdev_init(&testcdev, &test_fops); /* 初始化cdev结构体变量 */
其实就是建立cdev和file_operations的联系
cdev_add() 把字符设备添加到内核
int cdev_add(struct cdev *p, dev_t dev, unsigned count) //就是上面的结构体里面的cdev和 dev设备号 设备数
cdev_del () 删除设备 在驱动注销的时候要先删除设备 然后在注销设备号
void cdev_del(struct cdev *p) //函数原型
__exit xxx(void)
{
iounmap() //取消硬件地址的映射
cdev_del(&xxx); /注销设备/
unregister_chrdev_region(newchrled.devid, NEWCHRLED_CNT); /* 注销设备号 */
}
驱动自动创建设备节点 原本是mknod 手动创建设备节点
udev 管理/dev下的节点 提供热插拔管理 在加载驱动时候自动创建/dev/xxx 创建节点
busybox提供了udev的简化版本mdev 两个是类似的
test_cdev.class=clss_create(THIS_MOUDLE,MOUDLE_NAME);
if(IS_ERR(test_cdev.class))
return PIR_ERR(test_cdev.class);
//这个就是 类的创建的模板
class_destory(test_cdev.class); //这个用在类的摧毁 就是最后的注销函数里面
在类的下面创建设备 device_create()是一个可变参函数
struct device *device_create(
struct class *class, //就是我们创建的类
struct device *parent, //一般是NULL 没有父设备
dev_t devt, //设备号
void *drvdata, //设备可能使用的一些数据 一般是NULL
const char *fmt, //如果fmt=xxx 就会生成 /dev/xxx这个设备文件
...) //这个就是设备创建函数的原型
void device_destroy(struct class *class, dev_t devt) //驱动卸载函数原型
eg:
/* 4、创建类 */
dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);
if (IS_ERR(dtsled.class)) {
return PTR_ERR(dtsled.class);
}
/* 5、创建设备 */
dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);
if (IS_ERR(dtsled.device)) {
return PTR_ERR(dtsled.device);
}
//!!!!!需要先摧毁设备在摧毁类
文件私有数据 在open函数中 设置file->private_data 为设备变量
就可以直接在 其他函数中 使用struct xxx_dev dev=file->private
任何具有返回值的函数 得到了返回值都要去进行判断 然后尽量使用goto语句进行处理
比如 程序进行到了第五步 但是出错了 我们的goto语句执行需要把前面四步申请的东西全部都要释放