驱动开发入手手册2

1 、字符设备驱动框架

1.1字符设备

定义:是指只能以一个字节一个字节的方式读写的设备,不能随机读取设备中的某一段数据,读取数据需要按照先后顺序。字符设备是面向字节流的。

常见的字符设备:鼠标 键盘 串口 控制台 LED。。。

块设备:可以从设备的任意位置读取一定长度的数据的设备。

常见的块设备:硬盘 磁盘 光盘 U盘 sd卡。。。

1.2字符设备驱动框架

init:--->HelloModule

{

申请设备号(静态申请  动态申请)

创建一个字符设备

初始化字符设备

将设备号和字符设备关联起来

}

exit:

{

销毁字符设备

删除申请的设备号

}

举个栗子:

车:

买车:

1)申请车牌号(静态 动态)陕U.A08B16  

2)买车

3)将车牌号和车关联

   销毁车:

1)销毁车

2)注销车牌号

1.2.1 设备号

定义:设备号是设备在内核中的身份和标志,是内核区分不同设备的唯一标识信息,设备号是由主设备号和次设备号构成,主设备号表示一类设备,次设备号表示该类设备中的某一个设备。

设备号:是一个32bit的无符号整数,高12位是主设备号,低20位是次设备号 #define MINORBITS 20

#define MINORMASK ((1U << MINORBITS) - 1)

#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))

#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))

#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))

1.2.2申请设备号

方法:静态申请  动态申请

静态申请

int register_chrdev_region(dev_t from, unsigned count, const char *name)

from:设备号

count:子设备个数

*name:设备名称

返回值:成功为0

void unregister_chrdev_region(dev_t from, unsigned count)

作用:去注册设备号

from:设备号

count:子设备个数

动态申请

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)

*dev:指向设备号的指针

baseminor:子设备的第一个编号

count:子设备的个数

*name:设备名称

返回值:成功为0

注意:cat  /proc/devices-->查看系统中所有的已申请的设备号

1.2.3创建字符设备

函数:struct cdev *cdev_alloc(void)

作用:用来创建一块存放字符设备的内存空间;无参数,返回值是指向字符设备的指针

在Linux内核中,用struct cdev来描述一个字符设备。

struct cdev {---》描述一个字符设备

struct kobject kobj;--》内嵌的内核对象

struct module *owner;--》该字符设备所在的内核模块的对象指针

const struct file_operations *ops;--》该结构描述了字符设备所能实现的所有的方法

struct list_head list;--》用来将已向内核注册的所有的字符设备形成链表

dev_t dev;--》字符设备的设备号,由主设备号和次设备号构成。

unsigned int count;--》隶属于同一个主设备号的次设备个数

};

void cdev_del(struct cdev *p)

作用:删除字符设备

 *p:指向字符设备的指针

1.2.4 初始化字符设备

void cdev_init(struct cdev *cdev, const struct file_operations *fops)

*cdev:指向字符设备的指针

*fops:指向字符设备操作函数集的指针

struct file_operations {--》是存放操作字符设备的函数集

struct module *owner;

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

int (*mmap) (struct file *, struct vm_area_struct *);

int (*open) (struct inode *, struct file *);

int (*flush) (struct file *, fl_owner_t id);

int (*release) (struct inode *, struct file *);

。。。。。

}

字符设备需要实现哪一个操作动作,只需要将struct file_operations的对应函数指针指向外部实现的相应函数即可。

 字符设备驱动框架中使用的三个结构体:   

1):struct file:代表内核中一个打开的文件。系统中每个打开的文件在内核中都有一个关联的struct file.它由内核在打开文件时创建,在文件关闭后释放。

2):struct inode:用来记录文件在物理上的信息。它和代表打开文件的struct file结构不同,一个物理上的文件可以对应多个struct file,但是只有一个inode结构。

3):struct file_operations:是一个函数指针的集合,定义能在设备上进行的所有操作,结构中的成员指向驱动中的函数,每个函数实现一个特定的操作。

1.2.5将字符设备和设备号关联

函数:int cdev_add(struct cdev *p, dev_t dev, unsigned count)

作用:将字符设备和设备号关联,添加字符设备到内核中

*p:指向字符设备的指针

dev:设备号

count:子设备的个数

返回值:成功为0

2 、用户空间和内核空间的数据拷贝

用户代码对字符设备的任何操作,都要落实到该设备对应的底层操作函数上

read-->helloread;write-->hellowrite

内核空间数据拷贝到用户空间:HelloRead

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

ssize_t  HelloRead(struct file *pFile,char __user *buf,size_t count,loff_t *pOffset);

*pFile:内核已打开的文件

*buf:用户空间指针

count:用户期望读取的字节数

*pOffset:文件读写位置

unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)

作用:将内核空间数据拷贝到用户空间

*to:指向用户空间的指针

*from:内核空间指针--》数据源

n:拷贝的字节数

返回值:0 成功

unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)

作用:将用户空间数据拷贝到内核空间

*to:内核空间指针

*from:用户空间数据源指针

n:拷贝的字节数

返回值:0 成功

  


 


        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一条小白码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值