注意事项:上报值时存在bug,只能输出一次
内核版本:Linux 2.6.38
开发板: Mini 6410
驱动程序:
(dev)
#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>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/input.h>
/*
Kernel Version: Linux 2.6.38
Arm Version: Mini 6410
*/
#define MyPrintk printk
static struct input_dev *buttons_dev;
static struct timer_list timer_leds;
struct button_irq_desc {
int irq;
unsigned long flags;
char name[20];
unsigned int key_value;
};
static struct button_irq_desc button_irqs [] = {
{IRQ_EINT(0), IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "K1", KEY_L},
{IRQ_EINT(1), IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "K2", KEY_S},
{IRQ_EINT(2), IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "K3", KEY_ENTER},
{IRQ_EINT(3), IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "K4", KEY_LEFTSHIFT},
};
static unsigned int pin[4];
static unsigned int ledsvalue [4];
volatile unsigned long *gpkcon0 = NULL;
volatile unsigned long *gpkdat = NULL;
static char *DEVICE_NAME = "INPUT_DRIVER";
static struct pin_desc *irq_pd;
void leds_ctl(unsigned long value)
{
struct button_irq_desc * pindesc = irq_pd;
unsigned int pinval;
if (!pindesc)
return;
//printk("interrupt irq: %d, flags: %lu, name: %s, count: %u\n",pindesc->irq,
// pindesc->flags, pindesc->name,pindesc->key_value);
input_event(buttons_dev, EV_KEY, pindesc->key_value, 0);
input_sync(buttons_dev);
}
static irqreturn_t buttons_hander(int irq, void * dev)
{
irq_pd = (struct button_irq_desc *)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<<pin[0]) | (1<<pin[1]) | (1<<pin[2]) | (1<<pin[3]) ;
*gpkdat &= ledsvalue[i];
//MyPrintk (KERN_EMERG "gpkkdata: %lu %d\n", *gpkdat, i);
mod_timer(&timer_leds, jiffies + HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
static int led_probe(struct platform_device *pdev)
{
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gpkcon0 = ioremap(res->start, res->end - res->start + 1);
gpkdat = gpkcon0 + 2;
int i;
for(i = 0;i < 4; i++){
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
pin[i] = res->start;
}
*gpkcon0 &= ~( (0xF<<pin[0]*4) | (0xF<<pin[1]*4) | (0xF<<pin[2]*4) | (0xF<<pin[3]*4));
*gpkcon0 |= ( (0x1<<pin[0]*4) |(0x1<<pin[1]*4) | (0x1<<pin[2]*4) | (0x1<<pin[3]*4));
*gpkdat |= (1<<pin[0]) | (1<<pin[1]) | (1<<pin[2]) | (1<<pin[3]) ;
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]);
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]);
}
printk("Sorry, can not register these interrupts");
}
buttons_dev = input_allocate_device();
set_bit(EV_KEY, buttons_dev->evbit);
set_bit(EV_REP, buttons_dev->evbit);
set_bit(KEY_L, buttons_dev->keybit);
set_bit(KEY_S, buttons_dev->keybit);
set_bit(KEY_ENTER, buttons_dev->keybit);
set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);
buttons_dev->name = "MyInput";
input_register_device(buttons_dev);
ledsvalue[0] = ~ ((1<<pin[0]) | (0<<pin[1]) | (0<<pin[2]) | (0<<pin[3])) ;
ledsvalue[1] = ~ ((0<<pin[0]) | (1<<pin[1]) | (0<<pin[2]) | (0<<pin[3])) ;
ledsvalue[2] = ~ ((0<<pin[0]) | (0<<pin[1]) | (1<<pin[2]) | (0<<pin[3])) ;
ledsvalue[3] = ~ ((0<<pin[0]) | (0<<pin[1]) | (0<<pin[2]) | (1<<pin[3])) ;
init_timer(&timer_leds);
timer_leds.data = 0;
timer_leds.function = leds_ctl;
add_timer(&timer_leds);
return 0;
}
static int led_remove(struct platform_device *pdev)
{
iounmap(gpkcon0);
del_timer(&timer_leds);
int i;
for (i=0; i < sizeof(button_irqs) /sizeof(button_irqs[0]); i++)
{
free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
}
return 0;
MyPrintk (KERN_EMERG "%s Linux Byebye\n", DEVICE_NAME);
return 0;
}
struct platform_driver my_led_drv = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "my",
}
};
static int myleds_init(void)
{
platform_driver_register(&my_led_drv);
return 0;
}
static int myleds_exit(void)
{
platform_driver_unregister(&my_led_drv);
return 0;
}
module_init(myleds_init);
module_exit(myleds_exit);
MODULE_LICENSE("GPL");
(dev)
#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>
#include <linux/platform_device.h>
/*
Kernel Version: Linux 2.6.38
Arm Version: Mini 6410
*/
#define MyPrintk printk
static struct resource led_resource[] = {
[0] = {
.start = 0x7F008800,
.end = 0x7F008800 + 12 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 4,
.end = 4,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = 5,
.end = 5,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = 6,
.end = 6,
.flags = IORESOURCE_IRQ,
},
[4] = {
.start = 7,
.end = 7,
.flags = IORESOURCE_IRQ,
},
};
static void led_release(struct device * dev)
{
}
static struct platform_device my_device = {
.name = "my",
.id = -1,
.num_resources = ARRAY_SIZE(led_resource),
.resource = led_resource,
.dev = {
.release = led_release,
},
};
static int myleds_init(void)
{
platform_device_register(&my_device);
MyPrintk (KERN_EMERG "platform device register\n");
return 0;
}
static int myleds_exit(void)
{
platform_device_unregister(&my_device);
MyPrintk (KERN_EMERG "platform device unregister\n");
return 0;
}
module_init(myleds_init);
module_exit(myleds_exit);
MODULE_LICENSE("GPL");