1.总线
driver/base/platform.c
bus_register(&platform_bus_type);
2.设备
struct platform_device{ //platform_device.h 派生类
const char *name;
struct device dev; // 基类
u32 num_resoutces; //资源个数
struct resource *resoutce; //资源信息的地址
...
}
int platform_device_register(struct platform_device *); //注册
void platform_device_unregister(struct platform_device *); //注销
3.设备驱动
struct platform_driver{ //platform_device.h 派生类
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver; //基类
const struct platform_device_id *id_table;
}
int platform_driver_register(struct platform_driver *); //注册
void platform_driver_unregister(struct platform_driver *); //注销
示例代码:
vi btn_dev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
MODULE_LICENSE("GPL");
void btn_release(struct device *dev)
{
printk("<2>" "enter %s \n", __func__);
}
struct platform_device btn_dev =
{
.name = "mybuttons",
.dev =
{
.release = btn_release,
},
};
int __init btn_dev_init(void)
{
platform_device_register(&btn_dev);
return 0;
}
void __exit btn_dev_exit(void)
{
platform_device_unregister(&btn_dev);
}
module_init(btn_dev_init);
module_exit(btn_dev_exit);
vi btn_drv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
MODULE_LICENSE("GPL");
int btn_probe(struct platform_device *pdev)
{
printk("<2>" "enter %s\n", __func__);
return 0;
}
int btn_remove(struct platform_device *pdev)
{
printk("<2>" "enter %s\n", __func__);
return 0;
}
struct platform_driver btn_drv =
{
.driver =
{
.name = "mybuttons", //一定和platform_device.name相同 否则匹配不成功
},
.probe = btn_probe,
.remove = btn_remove,
};
int __init btn_drv_init(void)
{
platform_driver_register(&btn_drv);
return 0;
}
void __exit btn_drv_exit(void)
{
platform_driver_unregister(&btn_drv);
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);
注意:
1)name字段不同会有什么效果?
答:安装后无效果
2)观察probe remove release 何时被调用?
答:probe,在安装设备时被调用,remove,在卸载设备时被调用,release,。。。
3)btn_drv.ko btn_dev.ko 安装顺序不同实验结果有影响吗?
答:。。。
platform_device
用于描述硬件:存储那些以硬件的可变信息
例如按键使用的中断号 gpio 按键的编码
struct resource
{
/*资源的类型 ,常用取值
IORESOURCE_MEM,物理地址类型的资源
IORESOURCE_IRQ,IRQ类型的资源*/
unsigned long flags;
/*资源的起始值*/
resource_size_t start;
/*资源的结束值*/
resource_size_t end;
...
}
struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num)
dev,去哪个device中取资源
type,去哪种类型的资源
num, 找指定资源中的第几个
platform_driver
用于描述硬件的驱动逻辑:
申请input_dev
设置
注册
中断注册
延时去抖
报告事件
…
在完成驱动逻辑过程中使用到的可变信息都是去platform_device中取
按照platform架构存在的意义:
1)能够使得那些没有具体挂在总线的设备也可以按照总线驱动模型实现驱动程序
从而统一了驱动编程框架
2)实现了软硬件非分离 ,使得驱动程序更便于移植
platform_device, 用于描述硬件设备 (存储了设备的可变信息)
platform_driver, 用于描述设备的驱动逻辑(软件)
描述驱动逻辑过程中使用到的硬件信息统一去platform_device中取
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include "btn_desc.h"
MODULE_LICENSE("GPL");
struct input_dev *btn_input = NULL;
struct timer_list btn_timer;
irqreturn_t btn_isr(int irq, void *dev)
{
/*传递按键描述信息*/
btn_timer.data = (unsigned long)dev;
mod_timer(&btn_timer, jiffies+HZ/100);
return IRQ_HANDLED;
}
void btn_timer_func(unsigned long data)
{
int stat = 0;
/*获取哪个按键触发的*/
btn_desc_t *pdata = (btn_desc_t *)data;
/*判断是按下触发还是释放触发*/
stat = gpio_get_value(pdata->gpio);
/*5 报告事件*/
input_event(btn_input, EV_KEY, pdata->code, !stat);
input_event(btn_input, EV_SYN, 0, 0);
}
int btn_probe(struct platform_device *pdev)
{
/*获取可变信息二*/
btn_desc_t *pdata = pdev->dev.platform_data;
/*获取按键的个数*/
int num = pdev->num_resources;
int i = 0;
int ret = 0;
struct resource *res = NULL;
/*1 申请input_dev变量空间*/
btn_input = input_allocate_device();
/*2 设置input_dev变量*/
btn_input->name = "buttons";
__set_bit(EV_SYN, btn_input->evbit);
__set_bit(EV_KEY, btn_input->evbit);
__set_bit(EV_REP, btn_input->evbit);
for(; i<num; i++)
{
__set_bit(pdata[i].code, btn_input->keybit);
}
/*3 注册input_dev 变量*/
ret = input_register_device(btn_input);
/*4 硬件操作*/
for(i=0; i<num; i++)
{
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
ret = request_irq(res->start, btn_isr,
IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
pdata[i].name, pdata+i);
}
init_timer(&btn_timer);
btn_timer.function = btn_timer_func;
return 0;
}
int btn_remove(struct platform_device *pdev)
{
/*获取可变信息二*/
btn_desc_t *pdata = pdev->dev.platform_data;
/*获取按键的个数*/
int num = pdev->num_resources;
int i = 0;
struct resource *res = NULL;
del_timer(&btn_timer);
for(; i<num; i++)
{
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
free_irq(res->start, pdata+i);
}
/*6 注销input_dev变量*/
input_unregister_device(btn_input);
/*7 释放input_dev变量空间*/
input_free_device(btn_input);
return 0;
}
struct platform_driver btn_drv =
{
.driver =
{
.name = "mybuttons", //一定和platform_device.name相同 否则匹配不成功
},
.probe = btn_probe,
.remove = btn_remove,
};
int __init btn_drv_init(void)
{
platform_driver_register(&btn_drv);
return 0;
}
void __exit btn_drv_exit(void)
{
platform_driver_unregister(&btn_drv);
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <mach/platform.h>
#include "btn_desc.h"
MODULE_LICENSE("GPL");
void btn_release(struct device *dev)
{
printk("<2>" "enter %s \n", __func__);
}
struct resource btn_res[]={
{
.flags = IORESOURCE_IRQ,
.start = IRQ_GPIO_A_START+28,
.end = IRQ_GPIO_A_START+28,
},
{
.flags = IORESOURCE_IRQ,
.start = IRQ_GPIO_B_START+30,
.end = IRQ_GPIO_B_START+30,
},
{
.flags = IORESOURCE_IRQ,
.start = IRQ_GPIO_B_START+31,
.end = IRQ_GPIO_B_START+31,
},
{
.flags = IORESOURCE_IRQ,
.start = IRQ_GPIO_B_START+9,
.end = IRQ_GPIO_B_START+9,
},
};
btn_desc_t buttons[]={
{"up", PAD_GPIO_A+28, KEY_UP},
{"down", PAD_GPIO_B+30, KEY_DOWN},
{"left", PAD_GPIO_B+31, KEY_LEFT},
{"right", PAD_GPIO_B+9, KEY_RIGHT},
};
/*描述硬件*/
struct platform_device btn_dev =
{
.name = "mybuttons",
.dev =
{
.release = btn_release,
/*描述硬件可变信息二*/
.platform_data = buttons,
},
/*描述硬件可变信息一*/
.resource = btn_res,
.num_resources = ARRAY_SIZE(btn_res),
};
int __init btn_dev_init(void)
{
platform_device_register(&btn_dev);
return 0;
}
void __exit btn_dev_exit(void)
{
platform_device_unregister(&btn_dev);
}
module_init(btn_dev_init);
module_exit(btn_dev_exit);
#ifndef __BTN_DESC_H__
#define __BTN_DESC_H__
typedef struct btn_desc
{
char *name;
int gpio;
unsigned short code;
}btn_desc_t;
#endif