bus_drv_dev笔记
本模型为总线驱动设备模型
bus_drv_dev模型 bus drv链表
1.把device放入bus的dev链表 device_add /.match\ 1.放入drv链表 2.从dv链表取出一一比较(match)
2.从bus的drv链表取出每一个drv / \driver_register
用bus的match函数判断drv能否支持dev / \3.若支持,调用probe
3.若可以支持,调用drv的probe device driver
硬件相关 .probe比较稳定的代码
.name
可以把这个模型分为左右两边:左边为硬件相关的代码(device),右边为:比较稳定的代码(配置和注册设备号)
我们先对左边进行分析(硬件相关代码device):
一:/* 分配/设置/注册一个platform_device */
a:
static int led_dev_init(void) //驱动入口函数
{
platform_device_register(&led_dev); //注册一个device结构体到bus的链表中(platform_device)
return 0;
}
static void led_dev_exit(void) //驱动退出函数
{
platform_device_unregister(&led_dev); //退出bus的链表
}
module_init(led_dev_init); //修饰入口函数,让内核知道有这样个驱动
module_exit(led_dev_exit); //修饰出口函数,让内核知道有这样个驱动
MODULE_LICENSE("GPL"); //协议
b:
通过上面入口函数注册了一个结构体,结构体如下
static struct platform_device led_dev = {
.name = "myled", //deice设备名字,这个名字很重要必须和platform_drive结构体里面相同才可以匹配
.id = -1,
.num_resources = ARRAY_SIZE(led_resource), //设备所用资源的数量(资源:硬件相关联的东西)
.resource = led_resource, //资源
.dev = {
.release = led_release, //dev是一个platform_device结构体
},
};
c:
resource :硬件相关代码
static struct resource led_resource[] = {
[0] = {
.start = 0x56000050, //GPF控制寄存器的物理地址
.end = 0x56000050 + 8 - 1, //结束8个字节
.flags = IORESOURCE_MEM, //属于外设或者用于和设备通讯的支持直接寻址的地址空间
},
[1] = {
.start = 5, //开始GPF的第几个引脚
.end = 5, //结束GPF的第几个引脚
.flags = IORESOURCE_IRQ, //
}
};
led_release:这个可以扩展硬件相关的代码
static void led_release(struct device * dev)
{
}
一些头文件:
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
通过上面平台设备:led_device我们通过这个platform_device_register(&led_dev)函数,注册一个结构体(led_dev)到bus的链表里面去,函数执行的过程中调用了platform_device_add(&led_dev),把他放在了链表中(platform_bus_type)。
我们在对右边进行分析:比较稳定的代码(配置和注册设备号)
二:/* 分配/设置/注册一个platform_driver */ 平台驱动
a:
static int led_drv_init(void) ////驱动入口函数
{
platform_driver_register(&led_drv); // //注册一个led_drv结构体到bus的链表中(platform_device)
return 0;
}
static void led_drv_exit(void) //驱动出口口函数
{
platform_driver_unregister(&led_drv); //led_drv结构体退出bus链表
}
module_init(led_drv_init); //修饰入口函数
module_exit(led_drv_exit); //修饰出口函数
MODULE_LICENSE("GPL"); //协议
b:
struct platform_driver led_drv = {
.probe = led_probe, //装载设备驱动程序
.remove = led_remove, //卸载设备驱动程序
.driver = {
.name = "myled", //这个名字必须和led_dev这个结构体里面的名字一样,不然匹配不成功
}
};
C:
static int led_probe(struct platform_device *pdev)
{
struct resource *res; //定义一个resource指针结构
/* 根据platform_device的资源进行ioremap */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //得到平台设备控制寄存器的地址
gpio_con = ioremap(res->start, res->end - res->start + 1); //把物理地址转换成虚拟地址
gpio_dat = gpio_con + 1; //把物理地址转换成虚拟地址
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); //得到引脚数
pin = res->start; //把第一个引脚付给PIN
/* 注册字符设备驱动程序 */
printk("led_probe, found led\n");
major = register_chrdev(0, "myled", &led_fops); //
cls = class_create(THIS_MODULE, "myled");
class_device_create(cls, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
return 0;
}
static int led_remove(struct platform_device *pdev)
{
/* 卸载字符设备驱动程序 */
/* iounmap */
printk("led_remove, remove led\n");
class_device_destroy(cls, MKDEV(major, 0)); //卸载类
class_destroy(cls); //卸载窗体
unregister_chrdev(major, "myled"); //卸载主设备号
iounmap(gpio_con); //释放虚拟地址
return 0;
}
c:
/* 分配/设置/注册一个platform_driver */
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
static int major;
static struct class *cls;
static volatile unsigned long *gpio_con;
static volatile unsigned long *gpio_dat;
static int pin;
static int led_open(struct inode *inode, struct file *file)
{
//printk("first_drv_open\n");
/* 配置为输出 */
*gpio_con &= ~(0x3<<(pin*2));
*gpio_con |= (0x1<<(pin*2));
return 0;
}
static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
int val;
//printk("first_drv_write\n");
copy_from_user(&val, buf, count); // copy_to_user();
if (val == 1)
{
// 点灯
*gpio_dat &= ~(1<<pin);
}
else
{
// 灭灯
*gpio_dat |= (1<<pin);
}
return 0;
}
static struct file_operations led_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = led_open,
.write = led_write,
};