请选择 进入手机版 | 继续访问电脑版
    查看: 55|回复: 0

    Linux下的platform总线驱动(二)

    [复制链接]

    883

    主题

    941

    帖子

    3575

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    3575
    基情
    1843
    发表于 2016-9-18 15:32:41 | 显示全部楼层 |阅读模式
    版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127

    三.平台设备驱动测试
    这里我们采用Mini2440开发板,编写基于平台设备的按键驱动,要求按键驱动触发方式为单边沿触发,同时要求添加设备属性项。因为这个驱动比较简单,我就不去细致分析了,如果对硬件不理解可以参考mini2440开发板数据手册,如果对软件不理解,可以参考上文平台设备的讲解。在此,我提供platform设备模块代码,platform驱动模块代码,应用层测试代码,需要注意的是在动态加载测试时需要先加载设备模块,再加载驱动模块。

    1. platform设备模块代码
    #include <linux/device.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/string.h>
    #include <linux/platform_device.h>
    #include <linux/interrupt.h>
    #include <linux/sysfs.h>
    #include <linux/stat.h>
    #define GPGCON   0x56000060   //控制端口地址
    #define GPGDAT   0x56000064  //数据端口地址
    ssize_t test_show(struct device *dev, struct attribute *attr, char *buf);
    ssize_t test_store(struct device *dev, struct attribute *attr, char *buf,size_t count);

    static DEVICE_ATTR(buttons, S_IRWXUGO, test_show, test_store);  //设备属性

    ssize_t test_show(struct device *dev, struct attribute *attr, char *buf)  //读设备属性
    {
           printk("call :  test_show . \n");
           printk("attrname:%s . \n",attr->name);
           sprintf(buf,"%s\n",attr->name);
           return strlen(attr->name)&#43;2;
    }

    ssize_t test_store(struct device *dev, struct attribute *attr, char *buf,size_t count) //写设备属性
    {
           printk("call :  test_store . \n");
           printk("write : %s . \n",buf);
           strcpy(attr->name,buf);
           return count;
    }

    static struct resource s3c_buttons_resource[]=                 
    {
           [0]={                                   //内存资源
                  .start = GPGCON,
                  .end = GPGDAT,
                  .flags=IORESOURCE_MEM,
                  },
           [1]={                                   //中断号
                  //KEY1
                  .start = IRQ_EINT8,
                  .end = IRQ_EINT8,
                  .flags=IORESOURCE_IRQ,
                  },   
           [2]={
                  //KEY2
                  .start = IRQ_EINT11,
                  .end = IRQ_EINT11,
                  .flags=IORESOURCE_IRQ,
                  },
    };

    MODULE_AUTHOR("WJB");
    MODULE_LICENSE("Dual BSD/GPL");

    static struct platform_device *my_device = NULL;

    static int __init my_device_init(void)
    {
         int ret = 0;
         my_device = platform_device_alloc("s3c2410-buttons", -1);   //申请平台设备
         platform_device_add_resources(my_device, s3c_buttons_resource, 3);  //添加资源
         ret =  platform_device_add(my_device);       //注册平台设备
            device_create_file(&my_device->dev,&dev_attr_buttons);  //添加设备属性
         if(ret)
             platform_device_put(my_device);
         return ret;
    }

    static void my_device_exit(void)
    {
         platform_device_unregister(my_device);
            device_remove_file(&my_device->dev,&dev_attr_buttons);
    }

    module_init(my_device_init);
    module_exit(my_device_exit);

    2. platform驱动模块代码
    #include <linux/device.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/string.h>
    #include <linux/platform_device.h>
    #include <asm/io.h>
    #include <linux/poll.h>        
    #include <linux/irq.h>
    #include <linux/interrupt.h>
    #include <linux/miscdevice.h>
    #include <linux/sched.h>
    MODULE_AUTHOR("WJB");
    MODULE_LICENSE("Dual BSD/GPL");

    #define BUTTONS_12INPUT_MASK   0x41
    struct button_irq_desc {               //私有数据结构体
        int number;
        char *name;   
    };
    static struct button_irq_desc buttons_irqs [] = {  //私有数据
        { 0, "KEY1"},
        { 1, "KEY2"},
    };

    static volatile char key_values [] = {'0', '0'};
    static DECLARE_WAIT_QUEUE_HEAD(button_waitq);      //定义等待队列
    static volatile int ev_press = 0;

    static struct resource     *buttons_irq1;
    static struct resource     *buttons_irq2;
    static struct resource *buttons_mem;
    static void __iomem *buttons_base;

    static irqreturn_t s3c2410buttons_irq(int irq, void *dev_id)
    {   
        struct button_irq_desc *buttons_irqs = (struct button_irq_desc *)dev_id;
        unsigned int tmp;
        void __iomem *base = buttons_base;
       tmp=readb(base&#43;0x04);
       if(buttons_irqs->number==0)
       {
         tmp &=0x01;
       }else{
         tmp &=0x08;
        }   
        // process data
        if (tmp == (key_values[buttons_irqs->number] & 1)) { // Changed
           key_values[buttons_irqs->number] = '1' ;
        }
            ev_press = 1;
          wake_up_interruptible(&button_waitq);
        return IRQ_RETVAL(IRQ_HANDLED);
    }

    static int s3c24xx_buttons_open(struct inode *inode, struct file *file)
    {   int ret;
        unsigned int tmp;
        void __iomem *base = buttons_base;
        // set key1 and key2 input
        tmp=readb(base);
        writeb(tmp|BUTTONS_12INPUT_MASK ,base);
           ret = request_irq(buttons_irq1->start, s3c2410buttons_irq,IRQ_TYPE_EDGE_FALLING, "KET1", (void *)&buttons_irqs[0]);
           if (ret != 0) {
                  printk( "failed to install irq (%d)\n", ret);
                  goto err1;
           }
         ret = request_irq(buttons_irq2->start, s3c2410buttons_irq, IRQ_TYPE_EDGE_FALLING, "KET2", (void *)&buttons_irqs[1]);
           if (ret != 0) {
                  printk( "failed to install irq (%d)\n", ret);
                  goto err2;
           }
           ev_press = 1;
       
            return 0;
    err2: disable_irq(buttons_irq2->start);
                free_irq(buttons_irq2->start, (void *)&buttons_irqs[1]);
    err1: disable_irq(buttons_irq1->start);
                free_irq(buttons_irq1->start, (void *)&buttons_irqs[0]);
          
            return -EBUSY;
    }

    static int s3c24xx_buttons_close(struct inode *inode, struct file *file)
    {
               disable_irq(buttons_irq2->start);
            free_irq(buttons_irq2->start, (void *)&buttons_irqs[1]);
               disable_irq(buttons_irq1->start);
            free_irq(buttons_irq1->start, (void *)&buttons_irqs[0]);
        return 0;
    }

    static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
    {
        unsigned long err;
        int i;
        if (!ev_press) {
           if (filp->f_flags & O_NONBLOCK)
               return -EAGAIN;
           else
               wait_event_interruptible(button_waitq, ev_press);
        }   
        ev_press = 0;
        err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));
       for (i=0;i<2;i&#43;&#43;)
        {
        key_values='0';
        }   
        return err ? -EFAULT : min(sizeof(key_values), count);
    }

    static struct file_operations dev_fops = {
        .owner   =   THIS_MODULE,
        .open    =   s3c24xx_buttons_open,
        .release =   s3c24xx_buttons_close,
        .read    =   s3c24xx_buttons_read,
    };
    static struct miscdevice s3c2410buttons_miscdev = {
           .minor = MISC_DYNAMIC_MINOR,
           .name = "s3c2410-buttons",
           .fops = &dev_fops,
    };

    static int my_probe(struct platform_device* pdev)
    {   
          int ret;
            struct resource *res;
           struct device *dev;
           dev = &pdev->dev;
    // get resource
           res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
           if (res == NULL) {
                  dev_err(&pdev->dev, "failed to get memory region resource\n");
                  return -ENOENT;
           }
           buttons_mem = request_mem_region(res->start,
                                        res->end-res->start&#43;1,
                                        pdev->name);
           if (buttons_mem == NULL) {
                  dev_err(&pdev->dev, "failed to reserve memory region\n");
                  ret = -ENOENT;
                  goto err_nores;
           }
           buttons_base = ioremap(res->start, res->end - res->start &#43; 1);
           if (buttons_base == NULL) {
                  dev_err(&pdev->dev, "failed ioremap()\n");
                  ret = -EINVAL;
                  goto err_nores;
           }
    //get key1 interrupt
           buttons_irq1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
           if (buttons_irq1 == NULL) {
                  dev_err(dev, "no irq resource specified\n");
                  ret = -ENOENT;
                  goto err_map;
           }
    //get key2 interrupt
           buttons_irq2 = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
           if (buttons_irq2 == NULL) {
                  dev_err(dev, "no irq resource specified\n");
                  ret = -ENOENT;
                  goto err_map;
           }
    // register misc device
           ret = misc_register(&s3c2410buttons_miscdev);
           if (ret) {
                  dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",
                         WATCHDOG_MINOR, ret);
                  goto err_map;
           }

         printk("driver found device which my driver can handle!\n");
    err_map:
           iounmap(buttons_base);
    err_nores:
           release_resource(buttons_mem);
           kfree(buttons_mem);

         return ret;
    }


    static int my_remove(struct platform_device* pdev)
    {
        release_resource(buttons_mem);
           kfree(buttons_mem);
           buttons_mem = NULL;
           free_irq(buttons_irq1->start, (void *)&buttons_irqs[0]);
           buttons_irq1 = NULL;
           free_irq(buttons_irq2->start, (void *)&buttons_irqs[1]);
           buttons_irq2 = NULL;
           iounmap(buttons_base);
           misc_deregister(&s3c2410buttons_miscdev);
        printk("drvier found device unpluged!/n");
        return 0;
    }

    static struct platform_driver my_driver = {
         .probe = my_probe,
         .remove = my_remove,
         .driver = {
              .owner = THIS_MODULE,
              .name = "s3c2410-buttons",
         },
    };

    static int __init my_driver_init(void)
    {
         return platform_driver_register(&my_driver);
    }

    static void my_driver_exit(void)
    {
         platform_driver_unregister(&my_driver);
    }

    module_init(my_driver_init);
    module_exit(my_driver_exit);


    3.应用层测试代码
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/select.h>
    #include <sys/time.h>
    #include <errno.h>
    int main(void)
    {
           int buttons_fd;
           char buttons[2] = {'0', '0'};
           buttons_fd = open("/dev/s3c2410-buttons", 0);
           if (buttons_fd < 0) {
                  perror("open device buttons");
                  exit(1);
           }
           for (;;) {
                  char current_buttons[2];
                  int count_of_changed_key;
                  int i;
                  if (read(buttons_fd, current_buttons, sizeof current_buttons) != sizeof current_buttons) {
                         perror("read buttons:");
                         exit(1);
                  }
                  for (i = 0, count_of_changed_key = 0; i < sizeof buttons / sizeof buttons[0]; i&#43;&#43;) {
                         if (buttons != current_buttons) {
                                printf("%skey %d is %s", count_of_changed_key? ", ": "", i&#43;1, buttons == '0' ? "up" : "down");
                                count_of_changed_key&#43;&#43;;
                         }
                  }
                  if (count_of_changed_key) {
                         printf("\n");
                  }           
           }
           close(buttons_fd);
           return 0;
    }

    平台设备测试:
    在超级终端下:
    cd  /home/platform/device
    insmod device.ko
    cd  ../driver
    insmod driver.ko
    cd ../
    ./buttons
    然后通过Mini2440开发板的按键,观察到超级终端的按键信息。

    设备属性项测试:
    在超级终端下:
    cd /sys/platform/ s3c2410-buttons
    ls后,会显示buttons这一目录
    读取设备属性:cat buttons
    修改设备属性:echo modify>buttons
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|小黑屋|网站地图|DZ商业模板|VR福利资源|嵌入式Linux论坛 ( 粤ICP备15085165号-2 )

    GMT+8, 2017-10-21 07:58 , Processed in 0.094473 second(s), 23 queries .

    Powered by 深嵌论坛 X3.4

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表