omapl138在中斷基礎上實現異步通知的按鍵驅動(針對開發板上的SW8和SW9按鍵)

目標:按下按鍵時,驅動程序通知應用程序,而不是應用程序自己查詢
步驟:
1.應用程序註冊信號處理函數;
2.誰發?驅動程序發;
3.發給誰?應用程序要告訴驅動它的pid號;
4.怎麼發?驅動程序調用某個函數,kill_fasync函數。
驅動程序:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/irqreturn.h>
#include <mach/irqs.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <mach/gpio-davinci.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <asm/atomic.h>
#include <linux/semaphore.h>
static struct class *fifthdrv_class;
static struct device *fifthdrv_class_dev;
volatile unsigned long *gpfcon;
volatile unsigned long *gpgcon;
volatile unsigned long *gpfdat;
volatile unsigned long *gpgdat;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static volatile int ev_press=0;
static struct fasync_struct *button_async;
struct pin_desc{
	unsigned int pin;
	unsigned char key_val;
};
static unsigned char key_val;
struct pin_desc pins_desc[2]={
	{GPIO_TO_PIN(6, 1),0x01},
	{GPIO_TO_PIN(0, 6),0x02},
};
#if 0
static atomic_t canopen=ATOMIC_INIT(1);
#endif
static DEFINE_SEMAPHORE(button_lock);

static irqreturn_t buttons_irq(int irq,void *dev_id)
{
	struct pin_desc *pindesc=(struct pin_desc*)dev_id;
	unsigned int pinval;
	pinval=gpio_get_value(pindesc->pin);
	if(pinval)
	      {
		key_val=0x80|pindesc->key_val;
		}
	else 
		{
		key_val=pindesc->key_val;
		}
	ev_press=1;
	wake_up_interruptible(&button_waitq);
	kill_fasync(&button_async,SIGIO,POLL_IN);//在驅動程序中發
	return IRQ_RETVAL(IRQ_HANDLED);
}

struct gpio_irq_desc {

	int irq;
	unsigned long flags;
	char *name;

};
struct gpio_irq_desc press_dev_desc0 = {

		IRQ_DA8XX_GPIO6,
		IRQ_TYPE_EDGE_BOTH,
		"sw9_push_button"

};
struct gpio_irq_desc press_dev_desc1 = {

		IRQ_DA8XX_GPIO0,
		IRQ_TYPE_EDGE_BOTH,
		"sw8_push_button"

};

static int fifth_drv_open(struct inode *inode,struct file *file)
{
#if 0
	if(!atomic_dec_and_test(&canopen))
		{
		atomic_inc(&canopen);
		return -EBUSY;
		}
#endif

        down(&button_lock);

        press_dev_desc0.irq=gpio_to_irq(GPIO_TO_PIN(6, 1));
        request_irq(press_dev_desc0.irq,buttons_irq,press_dev_desc0.flags,press_dev_desc0.name,&pins_desc[0]);
	    press_dev_desc1.irq=gpio_to_irq(GPIO_TO_PIN(0, 6));
	    request_irq(press_dev_desc1.irq,buttons_irq,press_dev_desc1.flags,press_dev_desc1.name,&pins_desc[1]);
        return 0;      


}
static int fifth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos )
{
        if(size!=1)
	return -EINVAL;
	wait_event_interruptible(button_waitq, ev_press);
	copy_to_user(buf, &key_val, 1);
	ev_press=0;
 	return 0;
}
int fifth_drv_close(struct inode *inode,struct file *file)
{
	//atomic_inc(&canopen);
	up(&button_lock);
	free_irq(press_dev_desc0.irq,&pins_desc[0]);
	free_irq(press_dev_desc1.irq,&pins_desc[1]);
	return 0;
}
static unsigned fifth_drv_poll(struct file *file,poll_table *wait)
{
	unsigned int mask=0;
	poll_wait(file,&button_waitq,wait);
	if(ev_press)
		mask|=POLLIN | POLLRDNORM;
	return mask;
}
/*初始化button_async結構體*/
static int fifth_drv_fasync(int fd, struct file *filp,int on)
{
	printk("driver: fifth_drv_fasync\n");
	return fasync_helper( fd, filp,  on, &button_async);
}
static struct file_operations fifth_drv_fops={
	.owner = THIS_MODULE,
	.open  =fifth_drv_open,
	.read = fifth_drv_read,
	.release=fifth_drv_close,
	.poll=fifth_drv_poll,
	.fasync=fifth_drv_fasync,
};
int major=0;
static int fifth_drv_init(void)
{
	major=register_chrdev(0,"fifth_drv",&fifth_drv_fops);
	fifthdrv_class=class_create(THIS_MODULE,"fifth_drv");
	fifthdrv_class_dev=device_create(fifthdrv_class,NULL,MKDEV(major, 0),NULL,"buttons");
	return 0;
}
static int fifth_drv_exit(void)
{
 	unregister_chrdev(major,"fifth_drv");
	device_destroy(fifthdrv_class,MKDEV(major, 0));
	class_destroy(fifthdrv_class);
	return 0;
}
module_init(fifth_drv_init);
module_exit(fifth_drv_exit);
MODULE_LICENSE("GPL");

測試程序:

#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fd;
void my_signal_fun(int signum)
{
 	unsigned char key_val;
 	read(fd,&key_val,1);
 	printf("key_val: 0x%x\n",key_val);
}
int main(int argc,char **argv)
{

 unsigned char key_val;
 int ret;
 int oflags;
 signal(SIGIO,my_signal_fun);
 fd=open("/dev/buttons",O_RDWR);
 if(fd<0)
 {
     printf("can't open !\n");
	return -1;
 }
 /*F_SETOWN (long)
Set the process ID or process group ID that will  receive  SIGIO
and  SIGURG  signals  for events on file descriptor fd to the ID
given in arg.  A process ID is specified as a positive value;  a
process  group  ID  is specified as a negative value. */

 fcntl(fd,F_SETOWN,getpid());
 oflags=fcntl(fd,F_GETFL);
 fcntl(fd,F_SETFL,oflags|FASYNC);
 while(1)
 {
  sleep(1000);
 }
 return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章