bus_drv_dev 模型笔记

                                                                                          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,   
};






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值