一、流程框架
1.头文件
linux/cdev
.h
2.封装结构体
struct cdev {
struct module *owner;
const struct file_operations *ops;
dev_t dev;
unsigned
int count;
}
3.系统提供的一些接口
struct cdev *cdev_alloc(
void);
void cdev_put(
struct cdev *p);
void cdev_init(
struct cdev *,
const struct file_operations *);
int cdev_add(
struct cdev *, dev_t, unsgned
int);
voidcdev_del(
struct cdev *);
4.自定函数
static int __init demo_init(
void)
{
obj = cdev_alloc();
cdev_init(obj,&fops);
alloc_chrdev_region();
cdev_add(obj,dev_t);
return 0;
}
static void __exit demo_exit(
void)
{
void cdev_put(
struct cdev *);
void cdev_del(
struct cdev *);
}
这里写代码片
二、 一些术语
【设备号】
标识一个具体设备 无符号整型 类型别名dev_t
设备号 = 主设备号+次设备号
主设备号:表一类设备
次设备号:表示某一类设备中的一个具体的设备
通常用一个宏将其拼凑
dev_t MKDEV(int major, int minor);
也有一个宏,可以从中提取主次设备号
int MAJOR(dev_t);
int MINOR(dev_t);
函数中也有提取出主设备号和次设备号的函数:
imajor();iminor();
设备号怎么得来? A.静态申请:
/*
* 功能:静态分配设备号
* 输入参数: dev_t *: 想要申请到的主设备号
* unsigned int: 数量
* const char *: 设备名
* 返回值: 成功: 0 失败:负数,其绝对值是错误号
*/
int register
_chrdev_region(dev_t
*, unsigned int, const char *);
B:动态分配
int alloc_chrdev_region(dev_t *,
unsigned int first_minor,
unsigned int,
const char *);
设备号怎么释放?
/*
* 功能:释放设备
* 输入参数: dev_t *: 要释放的设备
* unsigned int: 数量
* 返回值: none
*/
void unregister
_chrdev_region(dev_t *, unsigned int);
三、操作方法集
struct file_operations {
struct module *owner;
loff_t (*llseek) (
struct file *, loff_t,
int);
ssize_t (*read) (
struct file *,
char __user *, size_t, loff_t *);
ssize_t (*write) (
struct file *,
const char __user *, size_t, loff_t *);
ssize_t (*read_iter) (
struct kiocb *,
struct iov_iter *);
ssize_t (*write_iter) (
struct kiocb *,
struct iov_iter *);
int (*iterate) (
struct file *,
struct dir_context *);
int (*iterate_shared) (
struct file *,
struct dir_context *);*
unsigned int (*poll) (
struct file *,
struct poll_table_struct *);
long (*unlocked_ioctl) (
struct file *,
unsigned int,
unsigned long);
long (*compat_ioctl) (
struct file *,
unsigned int,
unsigned long);
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 *);
int (*fsync) (
struct file *, loff_t, loff_t,
int datasync);
int (*aio_fsync) (
struct kiocb *,
int datasync);
int (*fasync) (
int,
struct file *,
int);
int (*lock) (
struct file *,
int,
struct file_lock *);
ssize_t (*sendpage) (
struct file *,
struct page *,
int, size_t, loff_t *,
int);
unsigned long (*get_unmapped_area)(
struct file *,
unsigned long,
unsigned long,
unsigned long,
unsigned long);
int (*check_flags)(
int);
int (*flock) (
struct file *,
int,
struct file_lock *);
ssize_t (*splice_write)(
struct pipe_inode_info *,
struct file *, loff_t *, size_t,
unsigned int);
ssize_t (*splice_read)(
struct file *, loff_t *,
struct pipe_inode_info *, size_t,
unsigned int);
int (*setlease)(
struct file *,
long,
struct file_lock **,
void **);
long (*fallocate)(
struct file *file,
int mode, loff_t offset,
loff_t len);
void (*show_fdinfo)(
struct seq_file *m,
struct file *f);
#ifndef CONFIG_MMU
unsigned (*mmap_capabilities)(
struct file *);
#endif
ssize_t (*copy_file_range)(
struct file *, loff_t,
struct file *,
loff_t, size_t,
unsigned int);
int (*clone_file_range)(
struct file *, loff_t,
struct file *, loff_t,
u64);
ssize_t (*dedupe_file_range)(
struct file *, u64, u64,
struct file *,
u64);
};
四、设备文件
1.作用: 用来找设备的 2、内容 设备号+设备类型 3、设备文件怎么生成? A、手工生成: #mknod /设备文件名 设备类型 主设备号 次设备号
mknod /dev/demo0 c 250 0
B、自动生成: 内核有函数可用,man 2 mknod 看详情。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int mknod(
const char *pathname, mode_t mode, dev_t dev);
五、工程实例
#include <linux/init.h>
#include <linux/
module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
static int major =
0;
static int minor =
0;
const int count =
3;
#define DEVNAME
"demo"
static struct cdev *demop = NULL;
/*打开设备
static int demo_open(
struct inode *inode,
struct file *filp)
{
printk(KERN_INFO
"%s : %s : %d\n", __FILE__, __func__, __LINE__);
return 0;
}
static int demo_release(
struct inode *inode,
struct file *filp)
{
printk(KERN_INFO
"%s : %s : %d\n", __FILE__, __func__, __LINE__);
return 0;
}
static ssize_t demo_read(
struct file *filp, char __user *buf, size_t size, loff_t *offset)
{
printk(KERN_INFO
"%s : %s : %d\n", __FILE__, __func__, __LINE__);
printk(KERN_INFO
"%p : %d\n", buf, size);
return 123;
}
static ssize_t demo_write(
struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{
printk(KERN_INFO
"%s : %s : %d\n", __FILE__, __func__, __LINE__);
printk(KERN_INFO
"%p : %d\n", buf, size);
return 321;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.
open = demo_open,
.release= demo_release,
.read = demo_read,
.write = demo_write,
};
static int __init demo_init(
void)
{
dev_t devnum;
int ret;
printk(KERN_INFO
"%s : %s : %d --- entry\n", __FILE__, __func__, __LINE__);
demop = cdev_alloc();
if(NULL == demop){
return -ENOMEM;
}
cdev_init(demop, &fops);
ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME);
if(ret){
goto ERR_STEP;
}
major = MAJOR(devnum);
ret = cdev_add(demop, devnum, count);
if(ret){
goto ERR_STEP1;
}
printk(KERN_INFO
"%s : %s : %d --- done.\n", __FILE__, __func__, __LINE__);
return 0;
ERR_STEP1:
unregister_chrdev_region(devnum, count);
ERR_STEP:
cdev_del(demop);
printk(KERN_INFO
"%s : %s : %d --- fail.\n", __FILE__, __func__, __LINE__);
return ret;
}
static void __exit demo_exit(
void)
{
printk(KERN_INFO
"%s : %s : %d\n", __FILE__, __func__, __LINE__);
unregister_chrdev_region(MKDEV(major, minor), count);
cdev_del(demop);
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE(
"GPL");
MODULE_AUTHOR(
"xxg");
MODULE_DESCRIPTION(
"Demo for kernel module");
六、本课相关的一些linux命令
1、将模块加载入内核:
sudo insmod xxgdemo.ko
2、查看已加载的模块:
lsmod
3、查看加载时内核有什么打印信息:
sudo dmesg | tail -
9
4、查看内核符号表:
sudo cat /proc/kallsyms
5、卸载模块:
sudo rmmod xxgdemo
6、手动创建设备:
sudo mknod /dev/xxgdemo1 c
250 0
7、查看设备对应的设备号:
sudo cat /proc/devices