【1】复习
1. 内核模块
-1- 模块的编写
三要素:
入口 :module_init() --->>> int __init xxx(void);
出口 :module_exit() --->>> void __exit xxx(void);
GPL声明 :MODULE_LICENSE("GPL")
模块传参:
include --->>> linux
<linux/moduleparam.h>
module_param()
module_param_string()
module_param_array()
符号表导出:
EXPORT_SYMBOL(sym)
EXPORT_SYMBOL_GPL(sym)
-2- 模块的编译
内部编译
外部编译
动态编译
静态编译
-3- 模块的使用
加载 --->>> insmod --->>> module_init注册的函数
卸载 --->>> rmmod --->>> module_exit注册的函数
【2】作业
【一】、字符设备驱动重要结构体
设备分类:
1. 字符设备
以字节流的形式进行数据读写
2. 块设备
存储设备
3. 网络设备
网卡
[1]. 描述字符设备的结构体cdev
<linux/cdev.h>
struct cdev {
struct module *owner; //THIS_MODULE
struct file_operations *ops; //操作方法集
dev_t dev; //设备号
unsigned int count; //设备计数
};
[2]. 操作方法集
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
/* read 接口 */
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
/* write 接口 */
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
/* poll接口 */
unsigned int (*poll) (struct file *, struct poll_table_struct *);
/* ioctl接口 */
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
/* open 接口 */
int (*open) (struct inode *, struct file *);
/* release 接口*/
int (*release) (struct inode *, struct file *);
/* 异步通知接口 */
int (*fasync) (int, struct file *, int);
};
[3]. 设备号
dev_t dev; __u32
主设备和次设备号组成
主设备号:高12bit
MAJOR(dev_t dev)
#define MINORBITS 20
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
MINOR(dev_t dev)
#define MINORMASK ((1U << MINORBITS) - 1)
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
MKDEV(int major,int minor)
【二】、字符设备驱动编写(重点)
0. 申请设备号
-1- 自动分配设备号
/****************************************************************************
*参数:
* @dev dev_t类型的指针
* @baseminor 次设备号的起始
* @count 设备个数
* @name 设备名
*返回值:成功返回0,失败返回负数错误码
***************************************************************************/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name)
-2- 手动指定设备号
/****************************************************************************
*参数:
* @from 设备号 MKDEV(int major , int minor)
* @count 设备个数
* @name 设备名
*返回值:成功返回0,失败返回负数错误码
***************************************************************************/
int register_chrdev_region(dev_t from, unsigned count, const char *name)
void unregister_chrdev_region(dev_t from, unsigned count)
1. 分配cdev结构体
/***************************************
*参数:
* @void
*返回值:成功返回cdev结构体指针,失败
* 返回NULL
**************************************/
struct cdev *cdev_alloc(void)
2. 初始化cdev结构体
/**********************************************************************
*参数:
* @cdev cdev结构体指针
* @fops 操作方法集指针
*返回值:void
*********************************************************************/
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
3. 将cdev添加到内核中
/***************************************************************
*参数:
* @p cdev结构指针
* @dev 设备号
* @count 设备个数
*返回值:成功返回0,失败返回负数错误码
**************************************************************/
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
void cdev_del(struct cdev *p)
【三】、字符设备驱动文件创建
[1]. 通过命令创建设备文件
mknod - make block or character special files
mknod NAME TYPE [MAJOR MINOR]
TYPE : c 字符设备 b :块设备
NAME : 设备文件名
[2]. 通过udev守护进程创建
class_create
device_crete
[作业]:
使用register_chrdev_region注册设备号
[附录]:
结构体变量初始化:
struct stu{
int a;
int b;
int c;
};
struct stu stu1 = {1,2,3}; //全部初始化
//部分初始化
struct stu stu2 = {
.a = 3,
.c = 4,
};
struct stu stu3;
stu3.a = 10; //结构体成员变量赋值
stu3.c = 20;