注意事项:sizeof(button_irqs[current_press])并不是指针
内核版本:Linux 2.6.38
开发板: Mini 6410
驱动程序:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
/*
Kernel Version: Linux 2.6.38
Arm Version: Mini 6410
*/
#define MyPrintk printk
static struct fasync_struct * button_fapp;
struct button_irq_desc {
int irq;
unsigned long flags;
char name[20];
unsigned long count;
};
static struct button_irq_desc button_irqs [] = {
{IRQ_EINT(0), IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "K1", 0},
{IRQ_EINT(1), IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "K2", 0},
{IRQ_EINT(2), IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "K3", 0},
{IRQ_EINT(3), IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "K4", 0},
};
static unsigned int ledsvalue []= {
~ ((1<<4) | (0<<5) | (0<<6) | (0<<7)) ,
~ ((0<<4) | (1<<5) | (0<<6) | (0<<7)),
~ ((0<<4) | (0<<5) | (1<<6) | (0<<7)),
~ ((0<<4) | (0<<5) | (0<<6) | (1<<7))
};
static DECLARE_WAIT_QUEUE_HEAD(buttons_waitq);
static volatile int buttons_press = 0;
static dev_t Leds_Major ;
static char * DEVICE_NAME = "FasyncsLeds";
static int current_press;
volatile unsigned long *gpkcon0 = NULL;
volatile unsigned long *gpkdat = NULL;
volatile unsigned long *gpncon = NULL;
volatile unsigned long *gpndat = NULL;
static struct class *leds_class;
static irqreturn_t buttons_hander(int irq, void * dev)
{
int i;
for (i=0; i < sizeof(button_irqs) /sizeof(button_irqs[0]); i++)
{
if(irq == button_irqs[i].irq){
break;
}
}
//MyPrintk (KERN_EMERG "gpkndata: %lu\n", *gpndat);
*gpkdat |= (1<<4) | (1<<5) | (1<<6) | (1<<7) ;
*gpkdat &= ledsvalue[i];
//MyPrintk (KERN_EMERG "gpkkdata: %lu %d\n", *gpkdat, i);
buttons_press = 1;
volatile int *count = (volatile int *)dev;
*count = *count + 1;
current_press = i ;
wake_up_interruptible(&buttons_waitq);
kill_fasync (&button_fapp, SIGIO, POLL_IN);
return IRQ_RETVAL(IRQ_HANDLED);
}
static int buttons_leds_init (struct inode *inode, struct file *file)
{
*gpkcon0 &= ~( (0xF<<4*4) | (0xF<<5*4) | (0xF<<6*4) | (0xF<<7*4));
*gpkcon0 |= ( (0x1<<4*4) |(0x1<<5*4) | (0x1<<6*4) | (0x1<<7*4));
*gpkdat |= (1<<4) | (1<<5) | (1<<6) | (1<<7) ;
int i;
int err;
for (i=0; i < sizeof(button_irqs) /sizeof(button_irqs[0]); i++)
{
err = request_irq(button_irqs[i].irq, buttons_hander, button_irqs[i].flags,
button_irqs[i].name, (void *)&button_irqs[i].count);
if(err){
break;
}
printk("register this interrupt %d \n", button_irqs[i].irq);
}
if(err){
i--;
for(; i >= 0; i--)
{
free_irq(button_irqs[i].irq, (void *)&button_irqs[i].count);
}
printk("Sorry, can not register these interrupts");
}
return 0;
}
static ssize_t buttons_leds_read(struct file *file, const char __user *buffer, size_t count, loff_t * ppos)
{
printk("\nwait............. \n");
wait_event_interruptible(buttons_waitq, buttons_press);
printk("\nwake............. \n");
buttons_press = 0;
int err;
printk("button_irqs[current_press]:%d\n", sizeof(button_irqs[current_press]));
printk("interrupt irq: %d, flags: %lu, name: %s, count: %lu\n",button_irqs[current_press].irq,
button_irqs[current_press].flags, button_irqs[current_press].name, button_irqs[current_press].count);
err = copy_to_user( buffer, (void *)&button_irqs[current_press], sizeof( struct button_irq_desc));
if(err){
printk("Sorry, copy to user failure!");
}
return 0;
}
int buttons_leds_close (struct inode * inode, struct file *file)
{
int i;
for (i=0; i < sizeof(button_irqs) /sizeof(button_irqs[0]); i++)
{
free_irq(button_irqs[i].irq, (void *)&button_irqs[i].count);
}
return 0;
}
int buttons_leds_fasync (int fd, struct file *file, int datasync)
{
return fasync_helper(fd, file, datasync, &button_fapp );
}
static struct file_operations s3c64XX_leds_fops = {
.owner = THIS_MODULE,
.read = buttons_leds_read,
.open = buttons_leds_init,
.release = buttons_leds_close,
.fasync = buttons_leds_fasync,
};
static int myleds_init(void)
{
Leds_Major = register_chrdev(Leds_Major,DEVICE_NAME , &s3c64XX_leds_fops);
if(Leds_Major < 0){
MyPrintk (KERN_EMERG "Sorry, Can not register the fasyc leds device!\n");
}
MyPrintk (KERN_EMERG " Register the fasyc leds device\n");
leds_class = class_create(THIS_MODULE, "InterruptLeds");
device_create(leds_class, NULL , MKDEV(Leds_Major, 0), NULL, DEVICE_NAME);
gpkcon0 = (volatile unsigned long *)ioremap(0x7F008800,12);
gpkdat = gpkcon0 + 2;
return 0;
}
static int myleds_exit(void)
{
unregister_chrdev(Leds_Major, DEVICE_NAME);
device_destroy(leds_class, MKDEV(Leds_Major, 0));
class_destroy(leds_class);
iounmap(gpkcon0);
iounmap(gpncon);
MyPrintk (KERN_EMERG "fasyc Leds Linux Byebye\n");
return 0;
}
module_init(myleds_init);
module_exit(myleds_exit);
MODULE_LICENSE("GPL");
测试程序:
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include <signal.h>
struct button_irq_desc {
int irq;
unsigned long flags;
char name[20];
unsigned long count;
};
int fd;
void my_signal_fun(int signum)
{
int ret;
struct button_irq_desc button_data;
ret = read(fd, &button_data, sizeof(button_data));
if(ret < 0){
printf("Sorry, read error!\n");
}
printf("ird:%d, flags:%lu, name: %s, count:%lu\n", button_data.irq, button_data.flags,
button_data.name, button_data.count);
memset(&button_data, 0, sizeof(button_data));
printf("ird:%d, flags:%lu, name: %s, count:%lu\n", button_data.irq, button_data.flags,
button_data.name, button_data.count);
}
int main(int argc, char **argv)
{
int val = 1;
int ret;
int Oflags;
fd = open("/dev/FasyncsLeds", O_RDWR);
if (fd < 0){
printf("Sorry, can't open!\n");
}
signal(SIGIO, my_signal_fun);
fcntl(fd, F_SETOWN, getpid());
Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC);
while(1){
sleep(1000);
}
return 0;
}