字符设备驱动 基本要点

一般的关于设备号的代码就是这样子

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语句执行需要把前面四步申请的东西全部都要释放

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值