📄 at91_ps2.c
字号:
/*
* Driver for PS/2 keyboard on GPIO lines capable of generating interrupts.
*
* Copyright 2008 zhixiong peng
*
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/gpio_keys.h>
#include <linux/PS2.h>
#include <linux/lib_AT91SAM9261s.h>
#include <asm/gpio.h>
#include <asm/mach/arch.h>
#include <linux/platform_device.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include <asm/arch/at91sam9261.h>
#include <asm/arch/at91sam9261_matrix.h>
#include <asm/arch/at91sam926x_mc.h>
#include <linux/clk.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <asm/arch/at91_pio.h>
#define irq_no 5
//#define AT91C_BASE_AIC 0x00000000
extern void fiq_asm_handler(void);
extern void irq2_asm_irq_handler(void);
PS2_BUF PS2Buf; // PS/2 键盘
static void at91_ps2_tasklet(unsigned long data);
DECLARE_TASKLET_DISABLED(ps2_tasklet, at91_ps2_tasklet,0);
//定义一个tasket结构ps2_tasklet,并把ps2_tasket与at91_ps2_tasklet绑定
static void at91_ps2_tasklet(unsigned long data)
{
printk(KERN_INFO"at91_ps2_tasklet_ISR test!\n");
}
static irqreturn_t at91_ps2_isr(int irq, void *dev_id)//struct pt_regs *regs)
{
int j;
struct platform_device *pdev = dev_id;
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input = platform_get_drvdata(pdev);
for (j = 0; j < pdata->nbuttons; j++)
{
int gpio = pdata->buttons[j].gpio;
if (irq == gpio_to_irq(gpio))
{
int state = (gpio_get_value(gpio) ? 1 : 0) ^ (pdata->buttons[j].active_low);
//(gpio_get_value(gpio)成立取1不成立取0
//异或(pdata->buttons[j].active_low)相同为0不同为 1
input_report_key(input, pdata->buttons[j].keycode, state);
input_sync(input);
}
}
printk(KERN_INFO"at91_ps2_isr_show\n");
return IRQ_HANDLED;
}
static int __devinit at91_ps2_probe(struct platform_device *pdev) //探测设备
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input;
int i, error;
input = input_allocate_device();
if (!input)
return -ENOMEM;
platform_set_drvdata(pdev, input);
input->evbit[0] = BIT(EV_KEY);
input->name = pdev->name;
input->phys = "gpio-keys/input0";
input->cdev.dev = &pdev->dev;
input->private = pdata;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
for (i = 0; i < pdata->nbuttons; i++) {
int code = pdata->buttons[i].keycode;
int irq = gpio_to_irq(pdata->buttons[i].gpio);
set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
error = request_irq(irq, at91_ps2_isr, IRQF_SAMPLE_RANDOM,
pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys",
pdev);
if (error) {
printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
irq, error);
goto fail;
}
set_bit(code, input->keybit); //告知input子系统 支持的事件
}
error = input_register_device(input);
if (error)
{
printk(KERN_ERR "Unable to register gpio-keys input device\n");
goto fail;
}
return 0;
fail:
for (i = i - 1; i >= 0; i--)
free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
input_free_device(input);
printk(KERN_INFO"at91_ps2_probe\n");
return 0;
}
static int __devexit at91_ps2_remove(struct platform_device *pdev) //移除/卸载
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input = platform_get_drvdata(pdev);
int i;
for (i = 0; i < pdata->nbuttons; i++) {
int irq = gpio_to_irq(pdata->buttons[i].gpio);
free_irq(irq, pdev);
}
input_unregister_device(input);
return 0;
}
struct platform_driver at91_ps2_device_driver =
{
.probe = at91_ps2_probe,
.remove = __devexit_p(at91_ps2_remove),
.driver = {
.name = "at91_ps2_keyboard",
},
};
static int __init at91_ps2_init(void)
{
int result,ret;
result = platform_driver_register(&at91_ps2_device_driver); //设备号注册
if (result == 0)
{
printk(KERN_INFO"at91_ps2_keyboard registered new interface driver\n");
}
if (result != 0)
{
printk(KERN_INFO"AT91_PS2_KEYBOARD_can't registered\n");
}
ret = request_irq(irq_no,at91_ps2_isr,SA_INTERRUPT,
"at91_ps2_irq",&at91_ps2_device_driver);//中断号注册
if(ret == 0) //注册成功
{
printk(KERN_INFO"at91_ps2_irq registered\n");
}
if(ret != 0) //注册失败
{
printk(KERN_INFO"IRQ_ERROR\n");
}
PS2_Init();
tasklet_enable(&ps2_tasklet);
tasklet_schedule(&ps2_tasklet); //调度ps2_tasklet
try_module_get(THIS_MODULE); //此函数为linux 2.6内核增加的,不同于2.4内核,功能是设备计数器的值加1
return 0;
}
static void __exit at91_ps2_exit(void)
{
platform_driver_unregister(&at91_ps2_device_driver);
printk(KERN_INFO"at91_ps2_exit\n");
free_irq(irq_no,&at91_ps2_device_driver);
printk(KERN_INFO"at91_ps2_KeyBoard_isr\n");
}
//*----------------------------------------------------------------------------
//* Function Name : PS2_Init
//* Object : PS2接口初始化
//* Input Parameters :
//* Output Parameters :
//*----------------------------------------------------------------------------
void PS2_Init( void )
{
PS2_BUF *pBuf;
pBuf = &PS2Buf;
pBuf->pBufInPtr = pBuf->pBufOutPtr = &pBuf->Buf[0];
pBuf->BufCtr = 0;
pBuf->Flag_Kbd = 0;
pBuf->Flag_Shift = 0;
pBuf->Flag_Caps = 0;
pBuf->Flag_Ctrl = 0;
pBuf->Flag_Fn = 0;
pBuf->Flag_Alt = 0;
pBuf->Flag_NumLock = 0xff;
pBuf->Flag_ScrollLock = 0;
// open external IRQ2 interrupt 开外部中断IRQ2
// AT91F_AIC_ConfigureIt ( AT91C_BASE_AIC, AT91C_ID_IRQ2,
// IRQ2_INTERRUPT_LEVEL,
// AT91C_AIC_SRCTYPE_EXT_POSITIVE_EDGE, // 设置IRQ2中断为上升沿触发
// irq2_asm_irq_handler);
//
// open FIQ interrupt
// AT91F_PIO_CfgPeriph(
// AT91C_BASE_PIOC, // PIO controller base address PIO控制器基地址
// 0, // Peripheral A 外围A
// PS2_CLK1); // Peripheral B 外围B
//
// AT91F_AIC_ConfigureIt ( AT91C_BASE_AIC, AT91C_ID_FIQ,
// FIQ_INTERRUPT_LEVEL,
// AT91C_AIC_SRCTYPE_EXT_POSITIVE_EDGE, // 设置FIQ中断为上升沿触发
// fiq_asm_handler);
printk(KERN_INFO"at91_ps2_init\n");
}
module_init(at91_ps2_init);
module_exit(at91_ps2_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("zhixiong peng");
MODULE_DESCRIPTION("PS/2 Keyboard driver for CPU GPIOs");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -