平臺總線概述
平臺總線(Platform bus)是linux2.6內核加入的一種虛擬總線,其優勢在於採用了總線的模型對設備與驅動進行了管理,這樣提高了程序的可移植性。
通過平臺總線機制開發設備驅動的 流程 如圖:
平臺設備
平臺設備使用 struct platform_device 結構 來描述:
struct platform_device {
const char *name; /* 設備名 */
int id; /* 設備編號,配合設備名使用 */
struct device dev;
u32 num_resources;
struct resource *resource; /* 設備資源 */
}
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags; /* 資源的類型 */
struct resource *parent, *sibling, *child;
};
註冊平臺設備,使用函數:
int platform_device_register(struct platform_device *pdev)
平臺驅動
平臺驅動使用 struct platform_driver 結構體 描述:
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
//……
}
平臺驅動註冊使用函數:
int platform_driver_register(struct platform_driver *)
代碼範例:
以按鍵中斷驅動程序爲例,平臺總線驅動定義了程序的結構,混雜設備驅動定義了程序的功能。
驅動程序:
#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;
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);
設備程序:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h> //平臺設備需要該頭文件
MODULE_LICENSE("GPL");
#define GPFCON 0x56000050 //寄存器物理地址
static struct resource key_resource[] = { //定義平臺設備的資源,注意數組的寫法
[0] = {
.start = GPFCON,
.end = GPFCON + 8,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_EINT0, //中斷
.end = IRQ_EINT2,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device key_device = { //定義平臺設備
.name = "my-key",
.id = 0,
.num_resources = ARRAY_SIZE(key_resource), //平臺設備資源數目
.resource = key_resource,
};
static int button_init()
{
platform_device_register(&key_device); //平臺設備註冊
return 0;
}
static void button_exit()
{
platform_device_unregister(&key_device);//註銷平臺設備
}
module_init(button_init);
module_exit(button_exit);