#pragma pack(1)
/dev 目录下存放 设备节点
/sys 目录下存放 所有的设备文件
/proc 目录下存放 所有的内核
//动态加载模块
insmod hello.ko
//动态卸载模块
rmmod hello
2.linux下设备的分类
字符设备:
块设备:
网络设备:
3.编写驱动时如何区分设备的:
4.注册字符设备驱动的流程:
(1)确定设备号: 动态注册:alloc_chrdev_region
静态注册:首先通过 cat /proc/devices 命令查看已经被使用的设备号,选用没用被用过的。
register_chrdev_region(); //向系统注册设备号
int register_chrdev_region(dev_t from,unsigned count, const char *name);
返回值:0 成功 负数失败。
参数:dev_t from 设备号起点。
(2)编写操作方法(构建file_operations)
(3) 构建cdev, 将cdev增加到系统。
5.内核中每个字符设备都会有一个专门管理的结构体:
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops; //操作方法集合
struct list_head list;
dev_t dev; //设备号
unsigned int count;
};
6.cdev_init// 初始化cdev结构体
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
参数:struct cdev *cdev 需要初始化的cdev
const struct file_operations *fops 操作方法集合
cdev_add 向系统增加cdev设备
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
返回值:0 成功 负数 失败
参数:struct cdev *p 需要增加的cdev
dev_t dev 设备号
unsigned count 设备个数
cdev_del //删除设备
void cdev_del(struct cdev *p)
参数: struct cdev *p 需要删除的cdev
open成功时,用户空间 有了fd
内核创建一个struct file *file 记录本次的信息 --》私有指针
ssize_t read(int fd, void *buf, size_t count);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
返回: 返回给用户的read函数
参数:struct file *
char __user * read的第二个参数
size_t read的第三个参数
loff_t * 文件描述符指针
ssize_t write(int fd, const void *buf, size_t count);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
返回: 返回给用户的write函数
参数:struct file *
char __user * write的第二个参数
size_t write的第三个参数
loff_t * 文件描述符指针
mknod /dev/mytest c 253 0
设备节点 字符 主号 次号
内核空间不能直接使用用户空间指针
unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) ;完成从用户空间到内核空间数据拷贝
返回值 : 0 成功 负数失败
参数:void *to 内核空间
const void __user *from 用户空间
unsigned long n 字节数
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
完成从内核到用户
返回值 : 0 成功 负数失败
void __user *to 用户空间
const void *from 内核空间
unsigned long n 字节数