platform_bus
来源:互联网 发布:淘宝在国外 编辑:程序博客网 时间:2024/06/10 12:47
静态编译驱动:
1. 首先把led.c 放到内核中放到 driver/char目录中
2. 添加一个编译的选项
修改driver/char/Kconfig 文件
config S5PV210_LED
bool "s5pv210 led device support"
tristate "s5pv210 led device support"
help
s5pv210 led driver
3. 把led.c 编译到内核中去,
修改driver/char/Makefile 文件
obj-$(CONFIG_S5PV210_LED) += led.o
4. 配置内核 make menuconfig
Device Drivers --->
Character devices --->
[*] s5pv210 led device support
5. 编译内核
make zImage -j2
动态编译
config S5PV210_LED
bool "s5pv210 led device support"
tristate "s5pv210 led device support"
help
s5pv210 led driver
make zImage modules -j2
platform_bus 的机制
现在Linux中大部分的设备驱动都可以使用这套机制,总线为platform_bus,
设备用platform_device表示,驱动用platform_driver进行注册。
和传统的驱动一样,platform机制也分为三个步骤:
1. 内核启动初始化时的main.c文件中的start_kernel() →rest_init() →kernel_init()→do_basic_setup()
→driver_init()→platform_bus_init()→bus_register(&platform_bus_type),
注册了一条platform总线(虚拟总线,platform_bus)。
2. 添加设备阶段:platform_device
依赖头文件<linux/platform_device.h>
struct platform_device {
const char * name; // 这个设备的名称 ,和驱动的名称一致
int id; // 这个设备的ID id = -1 这个唯一
// 如果设备不是唯一 用0,1,2,3,4
struct device dev;
u32 num_resources; //ARRAY_SIZE(resources),
struct resource * resource;
};
在platform_device中的resource 的结构体
/*
* Resources are tree-like, allowing
* nesting etc..
*/
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
我们关心的字段:
start : 资源的开始
end : 资源的结束
flag : 资源的类型
资源的类型如下:
#define IORESOURCE_MEM 0x00000200 内存资源
#define IORESOURCE_IRQ 0x00000400 中断资源
#define IORESOURCE_DMA 0x00000800 dma的资源
把platform_device注册到platform_bus上
int platform_device_register(struct platform_device *pdev); // 注册一个设备到platform_bus上
int platform_add_devices(struct platform_device **devs, int num)
// 添加一批的设备到platform_bus上
3. 添加platform_driver注册到platform_bus上
int platform_driver_register(struct platform_driver *drv) // 添加一个驱动到platform_bus
void platform_driver_unregister(struct platform_driver *drv) //卸载函数
结构体定义如下:
struct platform_driver {
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; // device_driver的结构体
const struct platform_device_id *id_table;
};
struct device_driver {
const char *name; // 是和platform_device进行匹配的名称
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
const struct of_device_id *of_match_table;
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
};
用platform机制实现led的驱动
1. 在内核中添加led 的platform_device
arch/arm/mach-s5pv210/mach-smdkv210.c
static struct platform_device *smdkv210_devices[] __initdata = {
这个功能是把开发板上的资源用一个结构体指针数组,把所有的platform_device放到
这个数组中进行批量的注册
在进行平台设备初始化时,对启动的platform_device进行批量的注册
static void __init smdkv210_machine_init(void)
-> platform_add_devices(smdkv210_devices, ARRAY_SIZE(smdkv210_devices));
// 批量向内核注册platform_device
smdkv210_machine_init什么时候执行,在平台初始化时执行 ,内核启动后会执行平台的初始化,
会调用smdkv210_machine_init,
实现platform_device如下:
static struct resource s5pv210_led_resource[] ={
[0] ={
.start =0xE0200060 ,
.end =0xE0200074 ,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device s5pv210_device_led ={
.name = "s5pv210-led",
.id = -1,
.num_resources = ARRAY_SIZE(s5pv210_led_resource),
.resource = s5pv210_led_resource,
};
2. 把创建的platform_device 加到平台数组中
static struct platform_device *smdkv210_devices[] __initdata = {
3. 把platform_driver添加到platform_bus上
static struct platform_driver platform_driver_led ={
.driver.name = "s5pv210-led" , // 这个名称要和platform_device 中的名称一致
.probe = led_probe,
};
static int platform_driver_init(void)
{
int ret =0 ;
platform_driver_register(&platform_driver_led);
return ret;
}
static void platform_driver_exit(void)
{
platform_driver_unregister(&platform_driver_led);
}
module_init(platform_driver_init);
module_exit(platform_driver_exit);
设备名称platfrom_device和platform_driver名称一致时,platfrom总线会进行一次匹配,
匹配后会执行驱动中的probe函数
4. probe函数要执行的操作
对驱动进行注册
并获取资源
/**
* platform_get_resource - get a resource for a device
* @dev: platform device
* @type: resource type
* @num: resource index
*/
struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num)
mem_res = platform_get_resource(pdev,IORESOURCE_MEM,0);
gpc0base = ioremap(mem_res->start,mem_res->end - mem_res->start );
基于platform_bus 的key的实现:
1. 在arch/arm/mach-s5pv210/mach-smdkv210.c 添加platform_device信息
static struct resource s5pv210_key_resource[] ={
[0] ={
.start =0xE0200C00 ,
.end =0xE0200C00 + 4,
.flags = IORESOURCE_MEM,
},
[1] ={
.start =0xE0200F40 ,
.end =0xE0200F40 + 4,
.flags = IORESOURCE_MEM,
},
[2] ={
.start = IRQ_EINT(0) ,
.end = IRQ_EINT(0) ,
.flags = IORESOURCE_IRQ,
},
[3] ={
.start = IRQ_EINT(1) ,
.end = IRQ_EINT(1) ,
.flags = IORESOURCE_IRQ ,
},
};
static struct platform_device s5pv210_device_key ={
.name = "s5pv210-key",
.id = -1,
.num_resources = ARRAY_SIZE(s5pv210_key_resource),
.resource = s5pv210_key_resource,
};
2. 在资源结构体中添加这个成员
&s5pv210_device_key,
3. 修改驱动,使驱动支持platform机制
驱动的中的时钟机制:
1. 关于时钟的头文件
<linux/clk.h>
2. 获取时钟函数
struct clk *clk_get(struct device *dev, const char *id);
dev : 时钟的名称 一般不用,为NULL
id : 时钟的匹配名称 ,需要传入相应的字符串
要找匹配的名称是去下面的文件中去找
vi arch/arm/mach-s5pv210/clock.c
static struct clk init_clocks_off[] = {
//这个数组内的时钟都是关闭的,需要手动打开
.name = "timers",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<23),
如是实例:
struct clk *myclk = clk_get(null,"timers")
3. 时钟的使能
int clk_enable(struct clk *clk);
实例: clk_enable(myclk);
时钟关闭 :
void clk_disable(struct clk *clk);
实例: clk_enable(myclk);
显示时钟大小:
unsigned long clk_get_rate(struct clk *clk);
实例: printk("clk is %lu",long clk_get_rate(myclk))
0 0
- platform_bus
- platform_bus,platform_driver,platform_bus
- LINUX驱动模型中bus与platform_bus区别和异同
- [linux driver]驱动模型中为什么用一个虚拟的platform_bus/device?
- 以RTC为例分析linux platform_bus platform_device和platform_driver注册过程
- 查看Linux系统信息版本
- 委托与事件
- jquery的bind跟on绑定事件的区别
- test
- DOM树
- platform_bus
- Top命令中各个种内存的含义
- windows下安装nutch2.1
- 九度OJ 1096 日期差值
- angular学习(三)—— Controller
- opencv2 直方图 calchist函数
- oracle 数据库,表空间的问题,临时表空间清理的问题
- SQL 数据类型
- 深度抠图--Deep Image Matting