【1】复习
字符设备框架:
1. cdev结构体
2. 编写
[1]. 申请/注册设备号
alloc_chrdev_region
--->>> unregister_chrdev_region
register_chrdev_region
[2]. 分配cdev结构体
cdev_alloc
[3]. cdev初始化
cdev_init
[4]. 添加到内核
cdev_add --->>> cdev_del
open的系统调用过程
open --(设备文件)设备号-->>> demo_open
应用层的open()返回文件描述符fd(非负整数)
xxx.c --->>> gcc xxx.c --->>> a.out --->>> ./a.out --->>> 进程
struct task_struct{
pid_t pid;
struct files_struct *files;
};
struct files_struct {
struct file *fd_array[NR_OPEN_DEFAULT];
}
struct file{
const struct file_operations *f_op //从inode结构体中获取的
}
inode结构体 --->>> 创建文件的时候创建(mknod --->>> major minor)
fs/open.c
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
--->>> o_sys_open(AT_FDCWD, filename, flags, mode);
--->>> do_filp_open(dfd, tmp, &op, lookup);
--->>> path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
--->>> do_last(nd, &path, op, pathname)
--->>> nameidata_to_filp(nd);
--->>> __dentry_open(nd->path.dentry, nd->path.mnt, filp,
NULL, cred);
--->>> if (!open && f->f_op)
open = f->f_op->open;
--->>> if (open) {
error = (*open)(inode, f);
【一】、创建设备文件
通过udev(应用层的守护进程)创建 --->>> 通过内核提供的函数创建设备文件
1. class_create
/****************************************************
*功能:在/sys/class目录下创建目录文件(以name命名)
*参数:
* @owner THIS_MODULE
* @name 目录名字
*返回值:成功返回struct class *结构体指针,失败
* 返回ERR_PTR,long IS_ERR(const void *ptr)
***************************************************/
class_create(owner, name)
void class_destroy(struct class *cls)
2. device_crete
/*****************************************************************************
*功能:在/sys/class/name目录下创建链接文件
*参数:
* @class struct class *结构体指针
* @parent NULL
* @devt 设备号
* @drvdata 私有数据
* @fmt 格式化内容
* @... 不定参数
*返回值:成功返回struct device *结构体指针,失败
* 返回ERR_PTR,long IS_ERR(const void *ptr)
****************************************************************************/
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
void device_destroy(struct class *class, dev_t devt)
【二】、字符设备驱动接口 ———— read & write & ioctl
应用层:
ssize_t read(int fd, void *buf, size_t count);
--->>> 驱动 fops -> read
ssize_t xxx_name(struct file *filp, char *buf , size_t size, loff_t *off)
{
}
ssize_t write(int fd, const void *buf, size_t count);
ssize_t xxx_name(struct file *filp, const char *buf, size_t, loff_t *);
copy_to_user©_from_user
/**************************************************************
*功能:从内核空间拷贝数据到用户空间
*参数:
* @to 用户空间地址
* @from 内核空间地址
* @n 拷贝的个数
*返回值:成功返回0,失败返回非0
*************************************************************/
int copy_to_user(void __user *to, const void *from, int n)
/**************************************************************
*功能:从用户空间拷贝数据到内核空间
*参数:
* @to 内核空间地址
* @from 用户空间地址
* @n 拷贝的个数
*返回值:成功返回0,失败返回非0
*************************************************************/
int copy_from_user(void *to, const void __user *from, int n)
#include <sys/ioctl.h>
ioctl - control device
int ioctl(int fd, int request, ...);
long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long xxxx)
{
return 0;
}
ioctl命令码生成:
# define _IOC_NONE 0U
# define _IOC_WRITE 1U
# define _IOC_READ 2U
dir size type nr
方向 大小 类型 编号
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOC(dir,type,nr,size) \
(((dir) << 30) | \
((type) << 8) | \
((nr) << 0) | \
((size) << 16))
#define _IOC_DIR(cmd)
#define _IOC_TYPE(cmd)
#define _IOC_NR(cmd)
#define _IOC_SIZE(cmd)
【三】、GPIO操作 --- LED
/*******************************************************************
*功能:将物理地址映射成虚拟地址
*参数:
* @offset 物理地址
* @size 映射的大小
*返回值:返回映射后的虚拟地址
*******************************************************************/
void __iomem *ioremap(phys_addr_t offset, unsigned long size)
void iounmap(void __iomem *addr) //虚拟地址
xxx_ioremap()
{
}
xxx_iounmap()
{
}
led_init()
{
}
led_on()
{
}
led_off()
{
}
【1】作业
1. 区分一对多(一个驱动程序对应多个同类设备)情况下,到底应用层操作的是哪个设备
提示:通过设备号的次设备号区分
2. struct mydata{
int a;
int b;
};
应用层:
struct mydata aaa = {
.a = 10,
.b = 20
};
ioclt(fd,11,&aaa);
--->>> demo_ioctl{
printk("a:%d,b:%d\n",...);
}
3. led驱动