一、字符设备驱动框架

1、注册模块加载函数和卸载函数:

/* 将上面两个函数指定为驱动的入口和出口函数 */
module_init(xxx_init);    //注册模块加载函数
module_exit(xxx_exit);    //注册模块卸载函数

定义一个设备结构体:

/* dtsled设备结构体 */ 
struct dtsled_dev
{ 
    dev_t devid; /* 设备号 */ 
    struct cdev cdev; /* cdev */ 
    struct class *class; /* 类 */ 
    struct device *device; /* 设备 */ 
    int major; /* 主设备号 */ 
    int minor; /* 次设备号 */ 
    struct device_node *nd; /* 设备节点 */ 
};

2、在模块加载函数里,进行以下步骤操作:
(1)创建设备号:

若定义了主设备号,则利用register_chrdev_region函数注册设备号:

if (dtsled.major) { /* 定义了设备号 */ 
    dtsled.devid = MKDEV(dtsled.major, 0); 
    register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME); 
    }

若没有定义主设备号,则利用alloc_chrdev_region函数申请设备号:

alloc_chrdev_region(&dtsled.devid, 0, DTSLED_CNT, DTSLED_NAME); /* 申请设备号 */ 
dtsled.major = MAJOR(dtsled.devid); /* 获取分配号的主设备号 */ 
dtsled.minor = MINOR(dtsled.devid); /* 获取分配号的次设备号 */

(2)初始化cdev:cdev_init

dtsled.cdev.owner = THIS_MODULE; 
cdev_init(&dtsled.cdev, &dtsled_fops);

(3)添加一个cdev:cdev_add

cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);

(4)创建类(这应该是为了自动创建设备节点):class_create

        这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

dtsled.class = class_create(THIS_MODULE, DTSLED_NAME); 
if (IS_ERR(dtsled.class)) 
{ 
    return PTR_ERR(dtsled.class); 
}

(5)创建设备:device_create

dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);
if (IS_ERR(dtsled.device)) {
    return PTR_ERR(dtsled.device); 
}

3、设备操作函数写法:

static struct file_operations dtsled_fops = { 
    .owner = THIS_MODULE, 
    .open = led_open,
    .read = led_read, 
    .write = led_write, 
    .release = led_release, 
};

各操作函数的原型如下:

static int led_open(struct inode *inode, struct file *filp)
{ 
    filp->private_data = &dtsled; /* 设置私有数据 */ 
    return 0; 
}


/* @description : 从设备读取数据 
 * @param – filp : 要打开的设备文件(文件描述符) 
 * @param - buf : 返回给用户空间的数据缓冲区 
 * @param - cnt : 要读取的数据长度 
 * @param – offt : 相对于文件首地址的偏移 
 * @return : 读取的字节数,如果为负值,表示读取失败 */
static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)


/* @description : 向设备写数据
 * @param - filp : 设备文件,表示打开的文件描述符 
 * @param - buf : 要写给设备写入的数据 
 * @param - cnt : 要写入的数据长度 
 * @param – offt : 相对于文件首地址的偏移 
 * @return : 写入的字节数,如果为负值,表示写入失败 */ 
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)


static int led_release(struct inode *inode, struct file *filp)

4、在模块卸载函数里,按以下顺序注销字符设备驱动:

/* 注销字符设备驱动 */
cdev_del(&dtsled.cdev);/* 删除cdev */ 
unregister_chrdev_region(dtsled.devid, DTSLED_CNT);/*注销设备号*/ 

device_destroy(dtsled.class, dtsled.devid); 
class_destroy(dtsled.class);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值