Chinaunix首页 | 论坛 | 博客
  • 博客访问: 437610
  • 博文数量: 113
  • 博客积分: 446
  • 博客等级: 下士
  • 技术积分: 1229
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-09 16:01
个人简介

Let's go!!!!!

文章分类

全部博文(113)

文章存档

2019年(5)

2018年(4)

2017年(9)

2016年(5)

2015年(39)

2014年(6)

2013年(28)

2012年(17)

分类: LINUX

2013-09-30 12:42:19

//驱动程序
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define DEV_NAME                 "button"

#ifndef DEV_MAJOR
#define DEV_MAJOR                 0
#endif

#define BUTTON_UP                 0
#define BUTTON_DOWN               1
#define BUTTON_UNCERTAIN          2

#define TIMER_DELAY_DOWN          (HZ/50)  
#define TIMER_DELAY_UP            (HZ/10)  

#define HIGHLEVEL                   1
#define LOWLEVEL                    0

static int dev_major = DEV_MAJOR;
static int dev_minor = 0;


/*============================ Platform Device part ===============================*/
struct s3c_button_info
{
   unsigned char           num;       /*Button nubmer  */
   char *                  name;      /*Button nubmer  */
   int                     nIRQ;      /*Button IRQ number*/
   unsigned int            setting;   /*Button IRQ Pin Setting*/
   unsigned int            gpio;      /*Button GPIO port */
};

struct s3c_button_platform_data
{
   struct s3c_button_info *buttons;
   int                     nbuttons;
};

static struct s3c_button_info  s3c_buttons[] = {
   [0] = {
       .num = 1,
       .name = "KEY1",
       .nIRQ = IRQ_EINT0,
       .gpio = S3C2410_GPF(0),
       .setting = S3C2410_GPF0_EINT0,
   },
   [1] = {
       .num = 2,
       .name = "KEY2",
       .nIRQ = IRQ_EINT2,
       .gpio = S3C2410_GPF(2),
       .setting = S3C2410_GPF2_EINT2,
   },
   [2] = {
       .num = 3,
       .name = "KEY3",
       .nIRQ = IRQ_EINT3,
       .gpio = S3C2410_GPF(3),
       .setting = S3C2410_GPF3_EINT3,
   },
   [3] = {
       .num = 4,
       .name = "KEY4",
       .nIRQ = IRQ_EINT4,
       .gpio = S3C2410_GPF(4),
       .setting = S3C2410_GPF4_EINT4,
   },
};

static struct s3c_button_platform_data s3c_button_data = {
   .buttons = s3c_buttons,
   .nbuttons = ARRAY_SIZE(s3c_buttons),
};

struct button_device
{
   unsigned char                      *status;      
   struct s3c_button_platform_data    *data;        

   struct timer_list                  *timers;    
   wait_queue_head_t                  waitq;          
   volatile int                       ev_press;    

   struct cdev                        cdev;          
   struct class                       *dev_class;
} button_device;

static void platform_button_release(struct device * dev)
{
   return;
}

static struct platform_device s3c_button_device = {
   .name    = "s3c_button",
   .id      = 1,
   .dev     =
   {
       .platform_data = &s3c_button_data,
       .release = platform_button_release,
   },
};

static irqreturn_t s3c_button_intterupt(int irq,void *de_id)
{
   int i;
   int found = 0;
   struct s3c_button_platform_data *pdata = button_device.data;


   for(i=0; inbuttons; i++)
   {
       if(irq == pdata->buttons[i].nIRQ)
       {
           found = 1;
           break;
       }
   }

   if(!found) /* An ERROR interrupt  */
       return IRQ_NONE;

   if(BUTTON_UP  == button_device.status[i])
   {
      button_device.status[i] = BUTTON_UNCERTAIN;
      mod_timer(&(button_device.timers[i]), jiffies+TIMER_DELAY_DOWN);
   }
   return IRQ_HANDLED;
}


static void button_timer_handler(unsigned long data)
{
   struct s3c_button_platform_data *pdata = button_device.data;
   int num =(int)data;
   int status = s3c2410_gpio_getpin( pdata->buttons[num].gpio );

   if(LOWLEVEL == status)
   {
       if(BUTTON_UNCERTAIN == button_device.status[num]) /* Come from interrupt */
       {
           button_device.status[num] = BUTTON_DOWN;
           button_device.ev_press = 1;
           wake_up_interruptible(&(button_device.waitq));
       }
       mod_timer(&(button_device.timers[num]), jiffies+TIMER_DELAY_UP);
   }
   else
   {
       button_device.status[num] = BUTTON_UP;
   }
   return ;
}


/*===================== Button device driver part ===========================*/
static int button_open(struct inode *inode, struct file *file)
{
   struct button_device *pdev ;
   struct s3c_button_platform_data *pdata;
   int i, result;

   pdev = container_of(inode->i_cdev,struct button_device, cdev);
   pdata = pdev->data;
   file->private_data = pdev;

   pdev->timers = (struct timer_list *) kmalloc(pdata->nbuttons*sizeof(struct timer_list), GFP_KERNEL);
   if(NULL == pdev->timers)
   {
       printk("Alloc %s driver for timers failure.\n", DEV_NAME);
       return -ENOMEM;
   }
   memset(pdev->timers, 0, pdata->nbuttons*sizeof(struct timer_list));

   pdev->status = (unsigned char *)kmalloc(pdata->nbuttons*sizeof(unsigned char), GFP_KERNEL);
   if(NULL == pdev->status)
   {
       printk("Alloc %s driver for status failure.\n", DEV_NAME);
       result = -ENOMEM;
       goto  ERROR;
   }
   memset(pdev->status, 0, pdata->nbuttons*sizeof(unsigned char));

   init_waitqueue_head(&(pdev->waitq));

   for(i=0; inbuttons; i++)
   {
       pdev->status[i] = BUTTON_UP;
       setup_timer(&(pdev->timers[i]), button_timer_handler, i);
       s3c2410_gpio_cfgpin(pdata->buttons[i].gpio, pdata->buttons[i].setting);
       irq_set_irq_type(pdata->buttons[i].nIRQ, IRQ_TYPE_EDGE_FALLING);
       result = request_irq(pdata->buttons[i].nIRQ, s3c_button_intterupt, IRQF_DISABLED, DEV_NAME, (void *)i);
       if( result )
       {
           result = -EBUSY;
           goto ERROR1;
       }
   }

   return 0;

ERROR1:
    kfree((unsigned char *)pdev->status);
    while(--i)
    {
        disable_irq(pdata->buttons[i].nIRQ);
        free_irq(pdata->buttons[i].nIRQ, (void *)i);
    }

ERROR:
    kfree(pdev->timers);

    return result;
}

static int button_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
   struct button_device *pdev = file->private_data;
   struct s3c_button_platform_data *pdata;
   int   i, ret;
   unsigned int status = 0;

   pdata = pdev->data;

   if(!pdev->ev_press)
   {
        if(file->f_flags & O_NONBLOCK)
        {
            return -EAGAIN;
        }
        else
        {
            wait_event_interruptible(pdev->waitq, pdev->ev_press);
        }
   }

   pdev->ev_press = 0;

   for(i=0; inbuttons; i++)
   {
       status |= (pdev->status[i]<    }

   ret = copy_to_user(buf, (void *)&status, min(sizeof(status), count));

   return ret ? -EFAULT : min(sizeof(status), count);
}

static unsigned int button_poll(struct file *file, poll_table * wait)
{
   struct button_device *pdev = file->private_data;
   unsigned int mask = 0;

   poll_wait(file, &(pdev->waitq), wait);
   if(pdev->ev_press)
   {
       mask |= POLLIN | POLLRDNORM; /* The data aviable */
   }

   return mask;
}

static int button_release(struct inode *inode, struct file *file)
{
   int i;
   struct button_device *pdev = file->private_data;
   struct s3c_button_platform_data *pdata;
   pdata = pdev->data;

   for(i=0; inbuttons; i++)
   {
       disable_irq(pdata->buttons[i].nIRQ);
       free_irq(pdata->buttons[i].nIRQ, (void *)i);
       del_timer(&(pdev->timers[i]));
   }

   kfree(pdev->timers);
   kfree((unsigned char *)pdev->status);

   return 0;
}


static struct file_operations button_fops = {
   .owner = THIS_MODULE,
   .open = button_open,
   .read = button_read,
   .poll = button_poll,
   .release = button_release,
};


static int s3c_button_probe(struct platform_device *dev)
{
   int result = 0;
   dev_t devno;

   /* Alloc the device for driver  */
   if (0 != dev_major)
   {
       devno = MKDEV(dev_major, dev_minor);
       result = register_chrdev_region(devno, 1, DEV_NAME);
   }
   else
   {
       result = alloc_chrdev_region(&devno, dev_minor, 1, DEV_NAME);
       dev_major = MAJOR(devno);
   }

   /* Alloc for device major failure */
   if (result < 0)
   {
       printk("%s driver can't get major %d\n", DEV_NAME, dev_major);
       return result;
   }

   /*  Initialize button_device structure and register cdev*/
    memset(&button_device, 0, sizeof(button_device));
    button_device.data = dev->dev.platform_data;
    cdev_init (&(button_device.cdev), &button_fops);
    button_device.cdev.owner  = THIS_MODULE;

    result = cdev_add (&(button_device.cdev), devno , 1);
    if (result)
    {
        printk (KERN_NOTICE "error %d add %s device", result, DEV_NAME);
        goto ERROR;
    }

    button_device.dev_class = class_create(THIS_MODULE, DEV_NAME);
    if(IS_ERR(button_device.dev_class))
    {
        printk("%s driver create class failture\n",DEV_NAME);
        result =  -ENOMEM;
        goto ERROR;
    }

    device_create(button_device.dev_class, NULL, devno, NULL, DEV_NAME);
    return 0;

ERROR:
    cdev_del(&(button_device.cdev));
    unregister_chrdev_region(devno, 1);
    return result;
}


static int s3c_button_remove(struct platform_device *dev)
{
   dev_t devno = MKDEV(dev_major, dev_minor);

   cdev_del(&(button_device.cdev));
   device_destroy(button_device.dev_class, devno);
   class_destroy(button_device.dev_class);

   unregister_chrdev_region(devno, 1);
   printk("S3C %s driver removed\n", DEV_NAME);

   return 0;
}


/*===================== Platform Device and driver regist part ===========================*/
static struct platform_driver s3c_button_driver = {
   .probe      = s3c_button_probe,
   .remove     = s3c_button_remove,
   .driver     = {
       .name       = "s3c_button",
       .owner      = THIS_MODULE,
   },
};


static int __init s3c_button_init(void)
{
  int       ret = 0;

  ret = platform_device_register(&s3c_button_device);
  if(ret)
  {
       goto fail_reg_plat_dev;
  }

  ret = platform_driver_register(&s3c_button_driver);
  if(ret)
  {
       goto fail_reg_plat_drv;
  }

  return 0;

fail_reg_plat_drv:
  platform_device_unregister(&s3c_button_device);
fail_reg_plat_dev:
  return ret;
}


static void s3c_button_exit(void)
{
   platform_driver_unregister(&s3c_button_driver);
   platform_device_unregister(&s3c_button_device);
}

module_init(s3c_button_init);
module_exit(s3c_button_exit);

module_param(dev_major, int, S_IRUGO);
module_param(dev_minor, int, S_IRUGO);

MODULE_AUTHOR("CJ");
MODULE_LICENSE("GPL");



应用程序:
#include
#include
#include
#include
#include
#include
#include
#include

int main()
{
   int fd = 0,retval = 0;
   ssize_t ret = 0;
   unsigned int status = 0;
   fd_set rfds;
   struct timeval tv;
   
   fd = open("/dev/button",O_RDWR);
   if(fd < 0)
   {
       perror("Open error!");
       exit(1);
   }

   while(1)
   {
       FD_ZERO(&rfds);
       FD_SET(fd, &rfds);
       tv.tv_sec = 0;
       tv.tv_usec = 0;
       retval = select(fd + 1, &rfds, NULL, NULL, &tv);
       if(retval < 0)
       {
           perror("Retval error!\n");
           exit(1);
       }
       else if(FD_ISSET(fd,&rfds))
       {
           ret = read(fd, &status, sizeof(unsigned int));
           printf("status=%d\n",status);
       }
   }
   return 0;
}


运行结果:
/lib/modules/3.0.0 >: ./a.out
status=1
status=2
status=4
status=8
阅读(1346) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~