ithink.chan 80093e080e 增加和调整内容,包括:
增加注释;
修改宏名;
检测 IOCTL cmd 的合法性.

Signed-off-by: ithink.chan <chenyang@autoai.com>
2020-04-27 11:12:46 +08:00

162 lines
4.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file demo_misc.c
* @author Rick Chan (cy187lion@sina.com)
* @brief Linux misc driver demo.
在 Linux 驱动中,会把一些无法归类的设备定义为混杂设备,它们是拥
有着共同的特性的简单字符设备。它们的特点是共享统一的主设备号 10
但每个设备可以选择一个单独的次设备号。
通常情况下,一个字符设备都不得不在初始化的过程中进行下面的步骤:
1.通过alloc_chrdev_region()分配主/次设备号
2.使用cdev_init()和cdev_add()来以一个字符设备注册自己
而一个misc驱动则可以只用一个调用misc_register()来完成这所有
的步骤。
所有的 miscdevice 设备形成一个链表,对设备访问时,内核根据次设
备号查找对应的 miscdevice 设备,然后调用其 file_operations
中注册的文件操作方法进行操作。
* @version 0.1.1
* @date 2020-04-27
*
* @copyright Copyright (c) 2020
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
MODULE_AUTHOR("Rick Chan");
MODULE_LICENSE("GPL");
#define DEMO_MAGIC 'R'
#define DEMO_IOC_SIZE 8
#define DEMO_CTL_IOC _IOC(_IOC_READ|_IOC_WRITE, DEMO_MAGIC, 0, DEMO_IOC_SIZE)
#define DEMO_CTL_IO _IO(DEMO_MAGIC, 1)
#define DEMO_CTL_IOR _IOR(DEMO_MAGIC, 2, uint16_t)
#define DEMO_CTL_IOW _IOW(DEMO_MAGIC, 3, int32_t)
#define DEMO_CTL_IOWR _IOWR(DEMO_MAGIC, 4, uint32_t)
#define DEMO_CTL_MAX 5
static int demo_open(struct inode *inode, struct file* filp)
{
return 0;
}
static int demo_release(struct inode *inode, struct file* filp)
{
return 0;
}
static loff_t demo_llseek(struct file *filp, loff_t offset, int origin)
{
return filp->f_pos;
}
static ssize_t demo_read(struct file *filp, char __user *buffer, size_t count, loff_t *offset)
{
const char __user *p = buffer;
return p-buffer;
}
static ssize_t demo_write(struct file *filp, const char __user *buffer, size_t count, loff_t *offset)
{
const char __user *p = buffer;
return p-buffer;
}
static long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
static int err = 0;
// 检测 cmd 合法性.
if(DEMO_MAGIC!=_IOC_TYPE(cmd))
return -EINVAL;
if(DEMO_CTL_MAX<_IOC_NR(cmd))
return -EINVAL;
// 根据命令类型, 检测参数空间是否可以访问.
if(_IOC_DIR(cmd)&_IOC_READ)
err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
else if(_IOC_DIR(cmd)&_IOC_WRITE)
err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
// 根据命令, 来选择执行哪个分支.
switch(cmd)
{
case DEMO_CTL_IOC:
{
uint8_t tmp[DEMO_IOC_SIZE];
copy_from_user(&tmp, (void*)arg, _IOC_SIZE(cmd));
copy_to_user((void*)arg, &tmp, _IOC_SIZE(cmd));
}
break;
case DEMO_CTL_IO:
break;
case DEMO_CTL_IOR:
{
uint16_t tmp = 0x55AA;
copy_to_user((void*)arg, &tmp, _IOC_SIZE(cmd));
}
break;
case DEMO_CTL_IOW:
{
int32_t tmp = 0;
copy_from_user(&tmp, (void*)arg, _IOC_SIZE(cmd));
}
break;
case DEMO_CTL_IOWR:
{
uint32_t tmp = 0;
copy_from_user(&tmp, (void*)arg, _IOC_SIZE(cmd));
copy_to_user((void*)arg, &tmp, _IOC_SIZE(cmd));
}
break;
default:
return -ENOIOCTLCMD;
}
return 0;
}
static int demo_mmap(struct file* filp, struct vm_area_struct* vma)
{
return 0;
}
static struct file_operations demo_fops = {
.owner = THIS_MODULE,
.open = demo_open,
.release = demo_release,
.llseek = demo_llseek,
.read = demo_read,
.write = demo_write,
.unlocked_ioctl = demo_ioctl,
.mmap = demo_mmap
};
static struct miscdevice demo_dev = {
.minor = MISC_DYNAMIC_MINOR, // Dynamically allocate minor.
.name = "demo_misc",
.fops = &demo_fops,
};
static int __init demo_init(void)
{
misc_register(&demo_dev); // 注册混杂设备驱动.
return 0;
}
static void __exit demo_exit(void)
{
misc_deregister(&demo_dev); // 撤销混杂设备驱动.
}
module_init(demo_init);
module_exit(demo_exit);