zoukankan      html  css  js  c++  java
  • 平台总线驱动设计

    平台总线驱动设计
    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! ");


    //获取资源
    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

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

  • 相关阅读:
    Docker 简单部署 ElasticSearch
    Anaconda更新失败简单解决[CondaHTTPError: HTTP 000 CONNECTION FAILED for url]
    TermKit的新一代Mac终端,在Ubuntu 11.04 轻松安装TermKit
    Linux下如何测试网速
    centos7安装yum
    Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
    yum 安装指定版本Docker
    如何在 Apache Hive 中解析 Json 数组
    unzip解压失败( cannot find zipfile directory)
    Linux 定时任务crontab_014
  • 原文地址:https://www.cnblogs.com/defen/p/4824051.html
Copyright © 2011-2022 走看看