平台总线驱动设计

平台总线驱动设计
1.平台总线概述(总线驱动中最为重要的一个总线)
平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其
优势在于采用了总线的模型对设备与驱动进行了管理,这总线的模
型对设备与驱动进行了管理,这样提高了程序的可移植性。
通过平台总线机制开发设备驱动的流程:
定义platform_device->注册platform_device->定义
platform_drivre->注册platform_driver

屏台总线驱动与设备匹配机制:内核代
码/drviver/base:platform.c中,主要是用来实现平台总线的。
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
下面我们来看看平台总线是怎么匹配的。
static int platform_match(struct device *dev, struct
device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);

/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;

/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;

/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
我们可以看到它共有两个匹配规则-》
一个是如果驱动带有id_table->那么驱动和设备就会按id_table来
匹配。另一个是按照驱动和设备的名字来进行匹配(这个是主要的
)。

2.平台设备
2.1平台设备描述
struct platform_device {
const char * name;//设备名
int id;//设备编号,配合设备名使用
struct device dev;
u32 num_resources;
struct resource * resource;//设备资源(包括寄存器
的基地址,中断号,)
const struct platform_device_id *id_entry;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
struct resource的结构:
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;//资源的类型
struct resource *parent, *sibling, *child;
};
2.2.注册平台设备
int platform_device_register(struct platform_device *pdev)

2.3.注销平台设备
void platform_device_unregister(struct platform_device
*pdev)

3.平台驱动
3.1平台驱动描述
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;
const struct platform_device_id *id_table;
};

3.2.平台驱动注册
int platform_driver_register(struct platform_driver *drv)

3.3.平台驱动注销
void platform_driver_unregister(struct platform_driver
*drv)
下面我们来完成一个按键注册平台的程序
touch key_dev.c
chmod 777 key_dev.c
#include<linux/init.d>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/device.h>
#include<linux/platform_device.h>
#include<linux/interrupt.h>

MODULE_LICENSE("GPL");
#define GPFCON 0x56000050 //按键基地址
struct resource key_resource[] = {
[0] = { //按键资源
.start = GPFCON,
.end = GPFCON+8,
.flags = IORESOURCE_MEM,//内存资源
},
[1] = { //中断号
.start = IRQ_EINT0,
.end = IRQ_EINT2,//使用这两个宏需要包含头文件interrupt
.flags = IORESOURCE_IRQ,//中断资源

};

};

//定义平台设备
struct platform_device key_device =
{
.name = "my-key",
.id = 0,
.num_resource = 2,
.resource = key_resource,
}

int keydev_init()
{
platform_device_register(&key_device);
}
void keydev_exit()
{
platform_driver_unregister(&key_device);
}

module_init(keydev_init);
module_exit(keydev_exit);

cp key_dev.ko rootfs
insmod key_dev.ko
ls /sys/bus/platform/device/my-key.o
接下来是平台驱动:平台驱动的概述在上面已有说明。
将之前编写好的按键驱动复制过来
mv key.c key_drv.c
vim Makefile +key_drv.o
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>

MODULE_LICENSE("GPL");

struct work_struct *work;

struct timer_list buttons_timer;

unsigned int key_num = 0;

wait_queue_head_t key_q;

struct resource *res;
struct resource *res_irq;
unsigned int *key_base;

void work_func(struct work_struct *work)
{
mod_timer(&buttons_timer, jiffies + (HZ /10));
}

void buttons_timer_function(unsigned long data)
{
unsigned int key_val;

key_val = readw(key_base+1)&0x1; //整形+1=+4
if (key_val == 0)
key_num = 4;

key_val = readw(key_base+1)&0x4;
if (key_val == 0)
key_num = 3;

wake_up(&key_q);
}


irqreturn_t key_int(int irq, void *dev_id)
{
//1. 检测是否发生了按键中断

//2. 清除已经发生的按键中断

//3. 提交下半部
schedule_work(work);

//return 0;
return IRQ_HANDLED;

}

void key_hw_init()
{
unsigned short data;

data = readw(key_base);//直接读取虚拟地址
data &= ~0b110011;
data |= 0b100010;

writew(data,key_base);
}


int key_open(struct inode *node,struct file *filp)
{
return 0;
}

ssize_t key_read(struct file *filp, char __user *buf,
size_t size, loff_t *pos)
{
wait_event(key_q,key_num);

copy_to_user(buf, &key_num, 4);

key_num = 0;

return 4;
}

struct file_operations key_fops =
{
.open = key_open,
.read = key_read,
};

struct miscdevice key_miscdev = {
.minor = 200,
.name = "key",
.fops = &key_fops,
};

int key_probe(struct platform_device *pdev)
{
int ret,size;
//注册混杂设备
ret = misc_register(&key_miscdev);

if (ret !=0)
printk("register fail!\n");


//获取资源
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ,
0);
//注册中断处理程序
request_irq(res_irq-
>start,key_int,IRQF_TRIGGER_FALLING,"key",(void *)4);
request_irq(res_irq-
>end,key_int,IRQF_TRIGGER_FALLING,"key",(void *)3);

//按键初始化
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
size = (res->end - res->start) + 1;//资源要映射的长度
key_base = ioremap(res->start, size);

key_hw_init();

//. 创建工作
work = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(work, work_func);

/* 初始化定时器 */
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;

/* 向内核注册一个定时器 */
add_timer(&buttons_timer);

/*初始化等待队列*/
init_waitqueue_head(&key_q);

return 0;
}

int key_remove(struct platform_device *dev)
{
free_irq(res_irq->start, (void *)4);
free_irq(res_irq->end, (void *)3);

iounmap(key_base);
misc_deregister(&key_miscdev);
return 0;
}
//平台驱动定义
static struct platform_driver key_driver = {
.probe = key_probe,
.remove = key_remove,
.driver = {
.owner = THIS_MODULE,
.name = "my-key",
},
};

static int button_init()
{
return platform_driver_register(&key_driver);//平台驱
动注册
}


static void button_exit()
{
platform_driver_unregister(&key_driver);//平台驱动注销
}


module_init(button_init);
module_exit(button_exit);

insmod key_drv.ko
mknod /dev/2440key c 10 200
./key_app

平台设备不一定是一个模块,可以直接放到内核的初始化程序中去

posted @ 2015-09-20 19:17  高傲的monkey  阅读(253)  评论(0编辑  收藏  举报