按键中断的platform bus设备和驱动

platform_device

 

/*
程序说明:基于platform bus的按键中断设备程序,与platform BUS的按键驱动程序匹配使用
作者:谢思源
时间:2010.7.16
*/

#include
#include
#include
#include
//中断
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

MODULE_AUTHOR("ECJTU CERT XIESIYUAN");
MODULE_LICENSE("GPL");

//适用于平台设备的按键设备资源
struct resource button_res[]={
 [0]={
   .start=IRQ_EINT8,
   .end=IRQ_EINT8,
   .name="0",
   .flags= IORESOURCE_IRQ,
  },
 [1]={
   .start=IRQ_EINT11,
   .end=IRQ_EINT11,
   .name="1",
   .flags= IORESOURCE_IRQ,
  },
 [2]={
   .start=IRQ_EINT13,
   .end=IRQ_EINT13,
   .name="2",
   .flags= IORESOURCE_IRQ,
  },
 [3]={
   .start=IRQ_EINT15,
   .end=IRQ_EINT15,
   .name="3",
   .flags= IORESOURCE_IRQ,
  },
 [4]={
   .start=IRQ_EINT14,
   .end=IRQ_EINT14,
   .name="4",
   .flags= IORESOURCE_IRQ,
  }, 
 [5]={
   .start=IRQ_EINT19,
   .end=IRQ_EINT19,
   .name="5",
   .flags= IORESOURCE_IRQ,
  },  
};


//struct platform_device *button;
struct platform_device button ={
 .name = "button_plat",
    .id =-1,
    .num_resources=ARRAY_SIZE(button_res),
    .resource = button_res,

};


static int __init button_init(void)
{
 int ret;
// button=platform_device_alloc("button_plat",-1);
// button->resource=button_res;
// button->num_resources=ARRAY_SIZE(button_res),
// ret=platform_device_add(button);
 ret = platform_device_register(&button);
 if(ret)
    {
     platform_device_put(&button);
        printk(KERN_ALERT "device add error %d/n",ret);
 }
 else
 printk(KERN_INFO"button device has hanged on the platform bus!/n");
 return ret;
}

static void __exit button_exit(void)
{
 platform_device_unregister(&button);
 printk(KERN_INFO"button device has hanged off the platform bus!/n");
}

module_init(button_init);
module_exit(button_exit);

 

platform_driver

/*
程序说明:platform bus上的button device的驱动
作者:谢思源
时间:2010.7.16
*/

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

bool en_button=0;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);  //申明一个等待队列
static char data_old[6]={'1','1','1','1','1','1'};
struct button_irq_desc {
    int irq;
    int pin;
    int pin_setting;
    int number;
    char *name;
};

static struct button_irq_desc button_irq[]={
 {IRQ_EINT8,  S3C2410_GPG(0),   S3C2410_GPG0_EINT8,  0, "KEY0"},
 {IRQ_EINT11, S3C2410_GPG(3) ,  S3C2410_GPG3_EINT11 , 1, "KEY1"},
 {IRQ_EINT13, S3C2410_GPG(5),  S3C2410_GPG5_EINT13 , 2, "KEY2"},
 {IRQ_EINT15, S3C2410_GPG(7) ,  S3C2410_GPG7_EINT15 , 4, "KEY4"},
    {IRQ_EINT14, S3C2410_GPG(6) ,  S3C2410_GPG6_EINT14 , 3, "KEY3"},
    {IRQ_EINT19, S3C2410_GPG(11),  S3C2410_GPG11_EINT19, 5, "KEY5"},
};

static irqreturn_t button_irq_func(int irq,void *dev)
{
 struct button_irq_desc *button=(struct button_irq_desc *)dev;
 int data; //保存读取出来的数值
 char ch;
 data=!s3c2410_gpio_getpin(button->pin);
 if(data==1)  //按键被按下
  ch='0';
 else if(data==0)
  ch='1';
 if(ch!=data_old[button->number])
 {
  data_old[button->number]=ch;
  en_button=1;
  wake_up(&button_waitq);
  printk(KERN_INFO"driver read data=%d!/n",data);
 }
 
 return IRQ_RETVAL(IRQ_HANDLED);
}

static int btn_open(struct inode *inode,struct file *filp)
{
 //打开设备,为中断做准备
 int i,ret,j;
 for(i=0;i<6;i++)
 {
  if(button_irq[i].irq<0)
   continue;
  ret=request_irq(button_irq[i].irq,button_irq_func,IRQ_TYPE_EDGE_BOTH,button_irq[i].name,(void *)&button_irq[i]);
  if(ret<0)
  {
   printk(KERN_INFO"%d interrupt request error!/n",button_irq[i].irq);
   for(j=0;j<=i;j++)
   {
    disable_irq(button_irq[i].irq);
    free_irq(button_irq[i].irq,(void *)&button_irq[i]);
   }
   return -1;
  }
 }
 en_button=1;
 return 0;
}

static int btn_read(struct file *filp,char __user *buf,size_t len,loff_t *offp)
{
 int ret;
 if(!en_button)  //没有按下按键
 {
  if(filp->f_flags&O_NONBLOCK)
  {
   return -EAGAIN;
  }
  //.阻塞进程
  wait_event_interruptible(button_waitq,en_button);
 }
 en_button=0;
 ret=copy_to_user(buf,(void *)data_old,(len>sizeof(data_old))?sizeof(data_old):len);
 if(ret!=0)
 {
  printk(KERN_INFO"copy_to_user error!/n");
  return -1;
 }
 printk(KERN_INFO"read len = %d!/n",(len>sizeof(data_old))?sizeof(data_old):len);
 return (len>sizeof(data_old))?sizeof(data_old):len;
}

static int btn_close(struct inode *inode,struct file *filp)
{
 //关闭文件时候要关闭中断
 int i;
 for(i=0;i<6;i++)
 {
  if(button_irq[i].irq<0)
   continue;
  disable_irq(button_irq[i].irq);
  free_irq(button_irq[i].irq,(void *)&button_irq[i]);
 }
 printk(KERN_INFO"xsy-plat-buttons released!/n");
 return 0;
}

static unsigned int btn_poll(struct file *filp,struct poll_table_struct *wait)
{
 int mask;
 poll_wait(filp,&button_waitq,wait);
 if(en_button)
  mask=POLLIN|POLLRDNORM;
 return mask; 
}

static struct file_operations button_fops={
 .open=btn_open,
 .read=btn_read,
 .release=btn_close,
 .owner=THIS_MODULE,
 .poll=btn_poll,
};

//为按键申请混杂设备
static struct miscdevice button_misc={
 .minor=250,  //混杂设备次设备号
 .name="xsy-plat-buttons",
 .fops=&button_fops,
};

static int __devinit btn_probe(struct platform_device *pdev)
{
 int i,ret;
// struct device *dev;
// dev=&pdev->dev;
// struct resource *button_res
 //匹配成功,进入probe,首先获取设备中断资源
 for(i=0;i<6;i++)
 {
  button_irq[i].irq=platform_get_irq(pdev,i);
  if(button_irq[i].irq<0)
  {
   printk(KERN_INFO"error:platform_get_irq: %d %d/n",i,button_irq[i].irq);
   return -ENOENT;
  }
  printk("button_irq[%d] is %d/n",i,button_irq[i].irq);
 }
 //注册misc设备,只有在发现设备和驱动匹配时候才创建misc设备,
 ret=misc_register(&button_misc);  
 return ret;
}

static int __devexit btn_remove(struct platform_device *dev)
{
 misc_deregister(&button_misc);
 return 0;
}

static struct platform_driver button={
 .probe=btn_probe,
 .remove=btn_remove,
 .driver={
  .name="button_plat",
  .owner=THIS_MODULE,
 },
};

static int __init button_init(void)
{
 int ret;
 ret=platform_driver_register(&button);
 printk(KERN_INFO"按键驱动已经注册!/n");
 return 0;
}

static void __exit button_exit(void)
{
 platform_driver_unregister(&button);
}
module_init(button_init);
module_exit(button_exit);
MODULE_AUTHOR("ECJTU CERT XIESIYUAN");
MODULE_LICENSE("GPL");

你可能感兴趣的:(Linux设备驱动)