总线设备驱动模型
既然上下分层,左右分离设计思想这么好用,Linux 内核基于这两个设计思想,给我们提供了总线设备驱动模型
引入platform_device/platform_driver,将“资源”与“驱动”分离开来。

总线设备驱动模型常用函数
注册/反注册
platform_device_register/ platform_device_unregister
platform_device_register(struct platform_device *)
platform_device_unregister(struct platform_device *)
platform_driver_register/ platform_driver_unregister
platform_device_unregister(struct platform_driver *)
platform_driver_unregister(struct platform_driver *)
获得资源:
返回该dev中某类型(type)资源中的第几个(num)
struct resource * platform_get_resource(struct platform_device *, unsigned int type, unsigned int num)
返回该dev所用的第几个(num)中断:
int platform_get_irq(struct platform_device *, unsigned int num)
通过名字(name)返回该dev的某类型(type)资源
struct resource * platform_get_resource_byname(struct platform_device *, unsigned int type, const char *name)
通过名字(name)返回该dev的中断号:
int platform_get_irq_byname(struct platform_device *, const char *name)
总线设备驱动模型函数调用过程
入口函数:注册platform_driver
中的probe()函数,probe() 函数中获得对应platform_device的资源
总线设备驱动模型实现LED驱动程序
led_drv.c led_drv_test.c 不变
broad_A_led.c 注册platform_device
chipY_gpio.c 注册platform_driver
对比上一个程序的区别:核心区别:内核帮助我们实现资源和驱动一一对应,作为驱动开发者,只需要注册
platform_device和platform_driver即可
broad_A_led.c:注册platform_device代替原来自己指定引脚
chipY_gpio.c:注册platform_driver代替自己获取资源,其余与上一个程序相同
分配/设置/注册platform_device结构体
在里面定义所用资源,指定设备名字。
分配/设置/注册platform_driver结构体
在其中的probe函数里,分配/设置/注册file_operations结构体,并从platform_device中确实所用硬件资源。
指定platform_driver的名字。
两个名字要相同
led_resource.h
#ifndef _LED_RESOURCE_H
#define _LED_RESOURCE_H
#define GROUP(x) (x>>16)
#define PIN(x) (x&0xFFFF)
#define GROUP_PIN(g,p) ((g<<16) | (p))
#endif
led_opr.h
#ifndef _LED_OPR_H
#define _LED_OPR_H
struct led_operations {
int (*init) (int which); /* 初始化LED, which-哪个LED */
int (*ctl) (int which, char status); /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
};
struct led_operations *get_board_led_opr(void);
#endif
broad_A_led.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>
#include "led_resource.h"
static void led_dev_release(struct device *dev)
{
}
static struct resource resources[] = {
{
.start = GROUP_PIN(3,1),
.flags = IORESOURCE_IRQ,
.name = "100ask_led_pin",
},
{
.start = GROUP_PIN(5,8),
.flags = IORESOURCE_IRQ,
.name = "100ask_led_pin",
},
};
static struct platform_device board_A_led_dev = {
.name = "100ask_led",
.num_resources = ARRAY_SIZE(resources),
.resource = resources,
.dev = {
.release = led_dev_release,
},
};
static int __init led_dev_init(void)
{
int err;
err = platform_device_register(&board_A_led_dev);
return 0;
}
static void __exit led_dev_exit(void)
{
platform_device_unregister(&board_A_led_dev);
}
module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");
chipY_gpio.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>
#include "led_opr.h"
#include "leddrv.h"
#include "led_resource.h"
static int g_ledpins[100];
static int g_ledcnt = 0;
static int board_demo_led_init (int which)
{
printk("init gpio: group %d, pin %d\n", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));
switch(GROUP(g_ledpins[which]))
{
case 0:
{
printk("init pin of group 0 ...\n");
break;
}
case 1:
{
printk("init pin of group 1 ...\n");
break;
}
case 2:
{
printk("init pin of group 2 ...\n");
break;
}
case 3:
{
printk("init pin of group 3 ...\n");
break;
}
}
return 0;
}
static int board_demo_led_ctl (int which, char status)
{
printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));
switch(GROUP(g_ledpins[which]))
{
case 0:
{
printk("set pin of group 0 ...\n");
break;
}
case 1:
{
printk("set pin of group 1 ...\n");
break;
}
case 2:
{
printk("set pin of group 2 ...\n");
break;
}
case 3:
{
printk("set pin of group 3 ...\n");
break;
}
}
return 0;
}
static struct led_operations board_demo_led_opr = {
.init = board_demo_led_init,
.ctl = board_demo_led_ctl,
};
struct led_operations *get_board_led_opr(void)
{
return &board_demo_led_opr;
}
static int chip_demo_gpio_probe(struct platform_device *pdev)
{
struct resource *res;
int i = 0;
while (1)
{
res = platform_get_resource(pdev, IORESOURCE_IRQ, i++);
if (!res)
break;
g_ledpins[g_ledcnt] = res->start;
led_class_create_device(g_ledcnt);
g_ledcnt++;
}
return 0;
}
static int chip_demo_gpio_remove(struct platform_device *pdev)
{
struct resource *res;
int i = 0;
while (1)
{
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
if (!res)
break;
led_class_destroy_device(i);
i++;
g_ledcnt--;
}
return 0;
}
static struct platform_driver chip_demo_gpio_driver = {
.probe = chip_demo_gpio_probe,
.remove = chip_demo_gpio_remove,
.driver = {
.name = "100ask_led",
},
};
static int __init chip_demo_gpio_drv_init(void)
{
int err;
err = platform_driver_register(&chip_demo_gpio_driver);
register_led_operations(&board_demo_led_opr);
return 0;
}
static void __exit lchip_demo_gpio_drv_exit(void)
{
platform_driver_unregister(&chip_demo_gpio_driver);
}
module_init(chip_demo_gpio_drv_init);
module_exit(lchip_demo_gpio_drv_exit);
MODULE_LICENSE("GPL");