Linux下的platform总线驱动(二)

转自 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)+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+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++)
    {
    key_values[i]='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+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 + 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++) {
                     if (buttons[i] != current_buttons[i]) {
                            printf("%skey %d is %s", count_of_changed_key? ", ": "", i+1, buttons[i] == '0' ? "up" : "down");
                            count_of_changed_key++;
                     }
              }
              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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值