类型定义
// hello_def.h
#ifndef __HELLO_DEF_H__
#define__HELLO_DEF_H__
#define HELLO_OPEN (0X10001001U)
#define HELLO_CLOSE (0X10001002U)
#define HELLO_INFO (0X10001003U)
// 声明描述 hello 硬件相关的数据结构(自定义硬件信息)
struct hello_resource
{
int phys_addr; // 寄存器的物理地址
int size; // 寄存器的内存大小
int pin; // 管脚编号
};
#endif // __HELLO_DEF_H__
硬件部分
// hello_dev.c
#include #include #include #include "hello_def.h"
// 定义hello的硬件信息
// 此为对应的硬件的固有信息
static struct hello_resource hello_info = {
.phys_addr = 0xE0200000,
.size = 8,
.pin = 3
};
static void hello_release(struct device *dev)
{
printk("=[frocheng]=[%s]=[%s]=\n", __FILE__, __func__);
}
// 定义初始化硬件节点
static struct platform_device hello_dev = {
.name = "hello", // 用于匹配
.id = -1,
.dev = {
.platform_data = &hello_info, // 装载自定义的硬件信息
.release = hello_release // 避免内核警告
}
};
static int __init hello_dev_init(void)
{
printk("=[frocheng]=[%s]=[%s]=\n", __FILE__, __func__);
// 注册硬件节点到dev链表,内核进行遍历和匹配
platform_device_register(&hello_dev);
return 0;
}
static void __exit hello_dev_exit(void)
{
// 删除节点
platform_device_unregister(&hello_dev);
printk("=[frocheng]=[%s]=[%s]=\n", __FILE__, __func__);
}
module_init(hello_dev_init);
module_exit(hello_dev_exit);
MODULE_LICENSE("GPL");
软件部分
// hello_drv.c
#include #include #include #include #include #include #include "hello_def.h"
static struct hello_resource hello_info;
static long hello_unlocked_ioctl(struct file * f, unsigned int cmd, unsigned long arg)
{
switch (cmd)
{
case HELLO_OPEN:
{
printk("===[frocheng]===[%s]===[%s]===[open]===\n",__FILE__, __func__);
}
break;
case HELLO_CLOSE:
{
printk("===[frocheng]===[%s]===[%s]===[close]===\n",__FILE__, __func__);
}
break;
case HELLO_INFO:
{
// info 命令,我们将我们的固有的硬件信息,返回给用户空间
printk("===[frocheng]===[%s]===[%s]===[info]===\n",__FILE__, __func__);
copy_to_user((void*)arg, &hello_info, sizeof(hello_info));
}
break;
default:
{
printk("===[frocheng]===[%s]===[%s]===[Unkown Command]===\n",__FILE__, __func__);
}
return -1;
}
return 0;
}
// 定义初始化hello的硬件操作对象
static struct file_operations hello_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = hello_unlocked_ioctl
};
static const char name[] = "hello";
// 定义初始化混杂设备对象
static struct miscdevice hello_misc =
{
.minor = MISC_DYNAMIC_MINOR,
.name = name,
.fops = &hello_fops
};
// pdev指向匹配成功的硬件节点(hello_dev.c的hello_dev)
static int hello_probe(struct platform_device *pdev)
{
struct hello_resource *pdata;
printk("=[frocheng]=[%s]=[%s]=\n", __FILE__, __func__);
pdata = pdev->dev.platform_data;
// 获取 硬件信息,进行处理,此处进行打印展示处理
printk("=[frocheng]=[%s]=[%s]=[0X%X]=[%d]=[%d]=\n",
__FILE__, __func__, pdata->phys_addr, pdata->size, pdata->pin);
hello_info.phys_addr = pdata->phys_addr;
hello_info.pin = pdata->pin;
hello_info.size = pdata->size;
misc_register(&hello_misc); // 注册
return 0;
}
// pdev指向匹配成功的硬件节点(hello_dev.c的hello_dev)
static int hello_remove(struct platform_device *pdev)
{
misc_deregister(&hello_misc); // 卸载
printk("=[frocheng]=[%s]=[%s]=\n", __FILE__, __func__);
return 0;
}
// 定义初始化软件节点
static struct platform_driver hello_drv = {
.driver = {
.name = "hello" // 用于匹配
},
.probe = hello_probe, // 匹配成功调用
.remove = hello_remove // 卸载软件或者硬件调用
};
static int __init hello_drv_init(void)
{
printk("=[frocheng]=[%s]=[%s]=\n", __FILE__, __func__);
// 注册硬件节点到drv链表,内核进行遍历和匹配
platform_driver_register(&hello_drv);
return 0;
}
static void __exit hello_drv_exit(void)
{
// 删除节点
platform_driver_unregister(&hello_drv);
printk("=[frocheng]=[%s]=[%s]=\n", __FILE__, __func__);
}
module_init(hello_drv_init);
module_exit(hello_drv_exit);
MODULE_LICENSE("GPL");
测试代码
// test.c
#include #include #include #include #include #include #include #define HELLO_OPEN (0X10001001UL)
#define HELLO_CLOSE (0X10001002UL)
#define HELLO_INFO (0X10001003UL)
struct dev_info
{
int pysy;
int size;
int pin;
};
int main()
{
int fd = open("/dev/hello", O_RDWR);
if (fd < 0)
{
perror("open");
return 0;
}
do
{
int ret = 0;
ret = ioctl(fd, HELLO_OPEN);
if (ret != 0)
{
perror("ioctl");
break;
}
printf("open success!\n");
sleep(1);
ret = ioctl(fd, HELLO_CLOSE);
if (ret != 0)
{
perror("ioctl");
break;
}
printf("close success!\n");
sleep(1);
struct dev_info info;
ret = ioctl(fd, HELLO_INFO, &info);
if (ret != 0)
{
perror("ioctl");
break;
}
printf("info success, 0X%X, %d, %d!\n",info.pysy, info.size, info.pin);
ret = ioctl(fd, 234);
if (ret != 0)
{
perror("ioctl");
printf("Other command error!\n");
break;
}
} while(0);
close(fd);
return 0;
}
编译
测试程序
(不要跟驱动代码放到一个目录下)
gcc -g tets.c -o ioctl_test
驱动
Makefile
KERNDIR:= /lib/modules/`uname -r`/build/
PWD:= $(shell pwd)
obj-m+= hello_dev.o
obj-m+= hello_drv.o
all:
make -C $(KERNDIR) M=$(PWD) modules
clean:
make -C $(KERNDIR) M=$(PWD) clean
测试
1. sudo insmod hello_dev.ko
2. sudo insmod hello_drv.o
3. sudo ./test
4. sudo rmmod hello_drv
5. sudo rmmod hello_dev
结果
上面两个红色框中,其实是我这把 ioctrl_test应用程序运行了两次。如果运行一次,红色框中几条日志就只会打印一遍。