1. 程式人生 > >平臺裝置驅動開發流程設計

平臺裝置驅動開發流程設計

1平臺匯流排概述
2.平臺裝置
3.平臺驅動
4.範例程式
1平臺匯流排概述
1.1平臺匯流排概述
平臺匯流排(Platform bus)是linux2.6核心加入的一種虛擬匯流排,是在linxu系統中最為重要的一種匯流排。
linux系統中除了去支援這些實際的匯流排,USB匯流排,PCI匯流排,還支援虛擬匯流排,之前是自己建立匯流排並基於匯流排去建立驅動和裝置。
linux提供了虛擬匯流排,平臺匯流排(Platform bus)是linux為我們建立的虛擬匯流排,我們只需要去掛載驅動程式和裝置。其同樣具備匯流排的優勢在於採用了匯流排的模型對裝置與驅動進行了管理,這樣提高了程式的可移植性
通過平臺匯流排機制開發裝置驅動的流程


建立和註冊裝置,將平臺裝置掛載到平臺總線上
建立驅動
平臺匯流排驅動與裝置的匹配機制,前面自己建立匯流排,通過裝置和驅動的名稱匹配。platform大多數依然使用平臺的裝置和驅動名稱相同進行匹配。
2.平臺裝置
平臺裝置使用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;
};
2.2註冊平臺裝置
註冊平臺裝置,使用函式:
int platform_device_register(struct platform_device *pdev)

4.範例程式
將按鍵程式進行改寫,採用平臺裝置方式編寫。
key_dev.c

#include<linux/module.h>
#include<linux/init.h>
#include<linux/platform_device.h>
#define GPXCON  0x11000C20
#include<linux/interrupt.h> #include<linux/irq.h> #define GPXCON 0x11000C20 #define GPXDAT 0x11000C24 MODULE_LICENSE("GPL"); struct resource key_resource[]={ [0]= { .start = GPXCON, .end = GPXCON+8, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_EINT(9), .end = IRQ_EINT(10), .flags = IORESOURCE_IRQ, }, }; struct platform_device key_device = { .name = "my-key", .id = 0, .num_resources = 2, .resource = key_resource, }; int keydev_init() { platform_device_register(&key_device); } void keydev_exit() { platform_device_unregister(&key_device); } module_init(keydev_init); module_exit(keydev_exit);

insmod key_dev.ko
ls /sys/bus/platform/device
平臺裝置已經掛載到平臺總線上
現在將平臺驅動建立和註冊
3.平臺驅動
平臺匯流排裝置只是起到找到裝置的作用,當匹配成功再按裝置型別進行相應的註冊。
3.1平臺驅動描述
平臺驅動使用struct platform_driver 描述:
struct platform_driver {
int (probe)(struct platform_device );//載入驅動,匯流排會將平臺裝置和裝置驅動進行匹配,匹配成功則驅動呼叫probe。
int (remove)(struct platform_device );當裝置移出時,驅動呼叫
……
}
3.2平臺驅動註冊
int platform_driver_register(struct platform_driver *)
下面將一個雜項裝置採用平臺裝置的方式改寫
key_drv

#include<linux/module.h>
#include<linux/init.h>
#include<linux/miscdevice.h>
#include<linux/fs.h>
#include<linux/interrupt.h>
#include<linux/io.h>
#include<linux/irq.h>
#include<linux/platform_device.h>
#include<linux/sched.h>
#include<linux/uaccess.h>
#include<linux/vmalloc.h>
#include<linux/slab.h>
MODULE_LICENSE("GPL");

unsigned int key_num = 0;
wait_queue_head_t key_queue;
struct work_struct *work1;
struct resource *res_irq;
struct resource *res_mem;
struct timer_list key_timer;
unsigned int *key_base;
void work1_fun(struct work_struct *work)
{
    mod_timer(&key_timer,jiffies+(HZ/10));
}
void key_timer_func(unsigned long data)
{
    unsigned int key_val;
    key_val = readl(key_base+1)&(0x1<<1);
    if(key_val==0)
    {
        key_num = 1;
    }
    key_val = readl(key_base+1)&(0x1<<2);
    if(key_val==0)
    {
        key_num = 2;

    }

    wake_up(&key_queue);

}
irqreturn_t key_int(int irq,void *dev_id)
{
    //檢測是否發生了按鍵中斷


    //清除按鍵中斷

    //提交下半部
    schedule_work(work1);
    return 0;
}
void keyint()
{

    writel(readl(key_base)&~(0xff<<4)|(0xff<<4),key_base);
}
ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
{
    wait_event(key_queue,key_num);
    printk("in kernel :key num is %d\n",key_num);
    copy_to_user(buf, &key_num, 4);
    key_num = 0;
    return 4;
}

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

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

    .minor = 200,
    .name = "my-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 *)1);
    request_irq(res_irq->end,key_int,IRQF_TRIGGER_FALLING,"key",(void *)2);
    size =res_mem->end -res_mem->start;
    key_base = ioremap(res_mem->start,size);//將物理基地址轉化為虛擬地址

    keyint();
    work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);//建立工作

    INIT_WORK(work1,work1_fun);

init_timer(&key_timer);//初始化定時器

    key_timer.function = key_timer_func;//新增超時函式

    add_timer(&key_timer);//向核心註冊

    init_waitqueue_head(&key_queue);//初始化等待佇列

    return ret;
}
int key_remove(struct platform_device *pdev)
{
    free_irq(res_irq->start, 0);
    free_irq(res_irq->end,0);
    iounmap(key_base);
     misc_deregister(&key_miscdev);
    return 0;
}

struct platform_driver key_driver = {
    .probe =key_probe,
    .remove =key_remove,
    .driver = {
            .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_dev.ko
insmod key_drv.ko
mknod /dev/mykey c 10 200
./key_app
應用程式執行成功,平臺匯流排裝置模型對程式進行了優化。驅動程式可能包含幾個層次,從匯流排方式看可以分為平臺裝置,從功能上看屬於字元裝置。USB從匯流排看裝置上看,從功能上看有屬於網路裝置。直接放核心。