{
key_down = (nextstate & (1< 0;
input_report_key(lp->idev, lp->btncode, key_down);
//printk("[PCF8574]report key %d state %dn",lp->btncode,key_down);
}
}
input_sync(lp->idev);
lp->laststate = nextstate;
}
return IRQ_HANDLED;
}
static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int i, ret;
struct input_dev *idev;
struct kp_data *lp;
if (i2c_smbus_read_byte(client) < 0) {
dev_err(&client->dev, "probe: read failn");
return -ENODEV;
}
lp = kzalloc(sizeof(*lp), GFP_KERNEL);
if (!lp)
return -ENOMEM;
idev = input_allocate_device();
if (!idev) {
dev_err(&client->dev, "Can\'t allocate input devicen");
ret = -ENOMEM;
goto fail_allocate;
}
lp->idev = idev;
lp->client = client;
lp->index = (client->addr & 0x3);
idev->evbit[0] = BIT_MASK(EV_KEY);
idev->keycode = lp->btncode;
idev->keycodesize = sizeof(lp->btncode[0]);
idev->keycodemax = KEYS_PER_PCF8574;
for (i = 0; i < KEYS_PER_PCF8574; i++)
{
lp->btncode = pcf8574_kp_btncode[lp->index];
__set_bit(lp->btncode & KEY_MAX, idev->keybit);
}
sprintf(lp->name,DRV_NAME);
sprintf(lp->phys,"kp_data/input0");
idev->name = lp->name;
idev->phys = lp->phys;
idev->id.bustype = BUS_I2C;
idev->id.vendor = 0x0001;
idev->id.product = 0x0001;
idev->id.version = 0x0100;
lp->laststate = read_state(lp);
ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
DRV_NAME, lp);
if (ret) {
dev_err(&client->dev, "IRQ %d is not freen", client->irq);
goto fail_free_device;
}
ret = input_register_device(idev);
if (ret) {
dev_err(&client->dev, "input_register_device() failedn");
goto fail_free_irq;
}
i2c_set_clientdata(client, lp);
printk("[PCF8574] probe device %s,addr 0x%x ,irq %dn",lp->name,client->addr,client->irq);
return 0;
fail_free_irq:
free_irq(client->irq, lp);
fail_free_device:
input_free_device(idev);
fail_allocate:
kfree(lp);
return ret;
}
static int __devexit pcf8574_kp_remove(struct i2c_client *client)
{
struct kp_data *lp = i2c_get_clientdata(client);
free_irq(client->irq, lp);
input_unregister_device(lp->idev);
kfree(lp);
return 0;
}
#ifdef CONFIG_PM
static int pcf8574_kp_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
enable_irq(client->irq);
return 0;
}
static int pcf8574_kp_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
disable_irq(client->irq);
return 0;
}
static const struct dev_pm_ops pcf8574_kp_pm_ops = {
.suspend = pcf8574_kp_suspend,
.resume = pcf8574_kp_resume,
};
#else
# define pcf8574_kp_resume NULL
# define pcf8574_kp_suspend NULL
#endif
static const struct i2c_device_id pcf8574_kp_id[] = {
{ DRV_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id);
static struct i2c_driver pcf8574_kp_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &pcf8574_kp_pm_ops,
#endif
},
.probe = pcf8574_kp_probe,
.remove = __devexit_p(pcf8574_kp_remove),
.id_table = pcf8574_kp_id,
};
static int __init pcf8574_kp_init(void)
{
int ret;
ret = i2c_add_driver(&pcf8574_kp_driver);
return ret;
}
module_init(pcf8574_kp_init);
static void __exit pcf8574_kp_exit(void)
{
i2c_del_driver(&pcf8574_kp_driver);
}
module_exit(pcf8574_kp_exit);
MODULE_AUTHOR("Michael Hennerich");
MODULE_DESCRIPTION("Keypad input driver for PCF8574");
MODULE_LICENSE("GPL");
实际使用时候还要在BSP中为PCF8574注册GPIO口作为INT线并指定i2c_client的irq号。
最后使用标准Linux的输入输出系统就可以读取键盘了。
#ifndef _INPUT_API_H
#define _INPUT_API_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct
{
int fd;
struct input_event ev;
char *device;
}INPUT_HANDLE;
int input_open(INPUT_HANDLE *h,char *device);
struct input_event * input_read(INPUT_HANDLE *h);
int input_close(INPUT_HANDLE *h);
struct input_event * input_get(INPUT_HANDLE *h,char *device);
#endif
#include "input_api.h"
int input_open(INPUT_HANDLE *h,char *device)
{
h->fd = open(device,O_RDONLY);
if (h->fd < 0)
{
return h->fd;
}
return h->fd;
}
struct input_event * input_read(INPUT_HANDLE *h)
{
int ret;
ret = read(h->fd,&(h->ev),sizeof(struct input_event));
if(ret < 0 )
{
perror("read event fail");
return NULL;
}
if(ret < sizeof(struct input_event) )
{
return NULL;
}
return &(h->ev);
}
int input_close(INPUT_HANDLE *h)
{
if (h->fd)
{
close(h->fd);
h->fd = 0;
}
return 0;
}
int main(int argc, char *argv[])
{
int ret;
INPUT_HANDLE h;
char *dev;
if(argc<2)
{
return -1;
}
dev = argv[1];
struct input_event * ev;
char *type = "unknown";
char *action = "unknown";
ret = input_open(&h,dev);
if(ret < 0)
{
perror("open fail");
return 0;
}
int i = 0;
while(1)
{
ev = input_read(&h);
if(ev)
{
i = 0;
printf("[%2d-%02d-%08d]",ev->type,ev->code,ev->value);
switch(ev->type)
{
case EV_SYN: type = "syn"; break;
case EV_KEY: type = "keys/buttons"; break;
case EV_REL: type = "relative"; break;
case EV_ABS: type = "absolute"; break;
case EV_MSC: type = "reserved"; break;
case EV_FF_STATUS: type = "ff state"; break;
default:type = "unknow"; break;
}
printf("%s ",type);
if(ev->type == EV_REL)
{
switch(ev->code)
{
case ABS_X: action = "X"; break;
case ABS_Y: action = "Y"; break;
case REL_DIAL: action = "DIAL"; break;
case REL_WHEEL: action = "WHEEL"; break;
default: action = "unknow"; break;
}
printf("%s %d",action,ev->value);
}
if(ev->type == EV_KEY)
{
if (ev->code > BTN_MISC)
{
printf("Btn %d %s", ev->code & 0xff,ev->value ? "press" : "release");
}
else
{
printf("Key %d %s", ev->code & 0xff,ev->value ? "press" : "release");
}
}
printf("n");
}
else
{
printf("input device invalidn");
break;
}
}
input_close(&h);
return 0;
}