开发环境:OK6410板卡,linux2.6.36
Device 和Driver 分成两个文件编写生成两个.ko文件,其中二者的名称必须完全一致;安装驱动成功后会调用driver的probe函数,卸载驱动时会调用driver的remove函数和device 的Release函数。
driver如下:
struct input_dev *button_dev = NULL;
struct timer_list button_timer;
volatile struct gpio_keys_button *irq_pd = NULL;
struct gpio_keys_platform_data *platform_data = NULL;
volatile unsigned int __iomem *gpn0_base =NULL;
static irqreturn_t button_isr(int irq ,void* devid )
{
//devid 传按键的首地址
irq_pd = (struct gpio_keys_button*)devid;
mod_timer(&button_timer, jiffies+HZ/100);
return IRQ_HANDLED;
}
void button_timer_function (unsigned long data)
{
unsigned int pinval;
volatile unsigned int __iomem* gpn0_con = gpn0_base;
volatile unsigned int __iomem* gpn0_dat = gpn0_con+1;
int index = 0;
unsigned int con_tmp = 0;
struct gpio_keys_button *pdesc = (struct gpio_keys_button *)irq_pd;
if(!pdesc) return ;
index = pdesc->gpio - S3C64XX_GPN(0);
con_tmp = *gpn0_con;
*gpn0_con&= (0x0f<< (2*index) ); //设置输入模式
pinval = *gpn0_dat &( 0x00000000 | (0x01 << index) );
*gpn0_con = con_tmp; //恢复
pinval>>= index;
if( !pinval)
{
input_event(button_dev , pdesc->type, pdesc->code,pinval);//低电平
input_event(button_dev, EV_SYN,0,0);
}
else
{
input_event(button_dev , pdesc->type, pdesc->code,pinval);//高电平
input_event(button_dev, EV_SYN,0,0);
}
}
static int kx_key_open(struct input_dev *pdev)
{
init_timer(& button_timer);
//button_timer.expires = jiffies+HZ*5;
button_timer.function = button_timer_function;
//button_timer.data = 100;
add_timer(&button_timer);
printk("kx_key_open\n");
return 0;
}
static void kx_key_release(struct input_dev *dev);
static int __devinit gpio_keys_probe(struct platform_device *pdev)
{
int i = 0;
int err;
unsigned int irq;
platform_data = pdev->dev.platform_data;
gpn0_base = ioremap(0x7F008830 , 12) ;
button_dev=input_allocate_device();
if(!button_dev)
{
return -ENOMEM;
}
set_bit(EV_KEY,button_dev->evbit);
set_bit(EV_SYN,button_dev->evbit);
for(i = 0; i< platform_data->nbuttons ; i++)
{
set_bit(platform_data->buttons[i].code ,button_dev->keybit);
}
button_dev->name=pdev->name ;
button_dev->phys = "gpio-keys/input0";
button_dev->dev.parent = &pdev->dev;
button_dev->open=kx_key_open;
button_dev->close=kx_key_release;
err=input_register_device(button_dev);
if(err)
{
return err;
}
for(i = 0; i< platform_data->nbuttons ; i++)
{
irq = gpio_to_irq(platform_data->buttons[i].gpio);
err = request_irq( irq ,button_isr,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
platform_data->buttons[i].desc,&platform_data->buttons[i]);
}
printk("---gpio_keys_probe-----\n");
return 0;
}
static void kx_key_release(struct input_dev *dev)
{
printk("kx_key_release \n");
}
static int __devexit gpio_keys_remove(struct platform_device *pdev)
{
int i;
int irq;
//注销中断
for(i = 0; i< platform_data->nbuttons ; i++)
{
irq = gpio_to_irq(platform_data->buttons[i].gpio);
//disable_irq_nosync(irq);
free_irq(irq,&platform_data->buttons[i] );
}
del_timer(&button_timer);
input_unregister_device( button_dev);
input_free_device(button_dev ) ;
iounmap(gpn0_base);
printk("-----gpio_keys_remove\n");
return 0;
}
static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove),
.driver = {
.name = "kx-key-pad",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &gpio_keys_pm_ops,
#endif
}
};
static int __init gpio_keys_init(void)
{
return platform_driver_register(&gpio_keys_device_driver);
}
static void __exit gpio_keys_exit(void)
{
platform_driver_unregister(&gpio_keys_device_driver);
}
module_init(gpio_keys_init);
module_exit(gpio_keys_exit);
device 如下:
static struct gpio_keys_button kx_buttons[] = {
{
.gpio = S3C64XX_GPN(0),
.code = KEY_UP,
.desc = "Power",
.active_low = 1,
.debounce_interval = 5,
.type = EV_KEY,
},
{
.gpio = S3C64XX_GPN(1),
.code = KEY_FN,
.desc = "Function",
.active_low = 1,
.debounce_interval = 5,
.type = EV_KEY,
},
{
.gpio = S3C64XX_GPN(2),
.code = KEY_KPMINUS,
.desc = "Minus",
.active_low = 1,
.debounce_interval = 5,
.type = EV_KEY,
},
{
.gpio = S3C64XX_GPN(3),
.code = KEY_KPPLUS,
.desc = "Plus",
.active_low = 1,
.debounce_interval = 5,
.type = EV_KEY,
},
{
.gpio = S3C64XX_GPN(4),
.code = KEY_ENTER,
.desc = "Enter",
.active_low = 1,
.debounce_interval = 5,
.type = EV_KEY,
},
{
.gpio = S3C64XX_GPN(5),
.code = KEY_ESC,
.desc = "Cancel",
.active_low = 1,
.debounce_interval = 5,
.type = EV_KEY,
},
};
void plat_key_release(struct device *dev)
{
printk( "plat_key_release\n");
}
static struct gpio_keys_platform_data kx_buttons_data = {
.buttons = kx_buttons,
.nbuttons = ARRAY_SIZE(kx_buttons),
};
static struct platform_device kx_buttons_device = {
.name = "kx-key-pad",
.id = 0,
.num_resources = 0,
.dev = {
.platform_data = &kx_buttons_data,
.release = &plat_key_release,
}
};
static int __init plat_key_dev_init(void)
{
platform_device_register(&kx_buttons_device); return 0;
}
static void __exit plat_key_dev_exit(void)
{
platform_device_unregister(&kx_buttons_device);
}
module_init(plat_key_dev_init);
module_exit(plat_key_dev_exit);