BigW Consortium Gitlab

Commit 93b0aedf by Forest Godfrey

Working evdev and more complete access to the device. Should work with real keypad.

Also fixes a bug causing the device driver to be unable to be unloaded.
parent 39e41950
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
typedef struct arduino_i2c_keyboard_platform_data { typedef struct arduino_i2c_keyboard_platform_data {
int gpio_intr_pin; int gpio_intr_pin;
int *keymap; int *keymap;
int numkeys;
} arduino_i2c_keyboard_platform_data_t; } arduino_i2c_keyboard_platform_data_t;
#endif /* _AI2C_PLATFORM_DATA_H */ #endif /* _AI2C_PLATFORM_DATA_H */
...@@ -44,10 +44,29 @@ ...@@ -44,10 +44,29 @@
#define IRQ_GPIO_PIN 9 #define IRQ_GPIO_PIN 9
#define GPIO_IRQ_NAME "ai2c_keyboard_irq" #define GPIO_IRQ_NAME "ai2c_keyboard_irq"
const int default_keymap[] = { static int default_keymap[] = {
0, KEY_UP,
KEY_DOWN,
KEY_LEFT,
KEY_RIGHT,
KEY_A,
KEY_B,
BTN_START,
KEY_SELECT,
KEY_DISPLAYTOGGLE,
KEY_1,
KEY_2,
KEY_3,
KEY_4,
KEY_5,
KEY_6,
KEY_7,
KEY_8,
KEY_9
}; };
static int default_numkeys = sizeof(default_keymap) / sizeof(int);
static LIST_HEAD(driver_list); static LIST_HEAD(driver_list);
static DEFINE_MUTEX(driver_list_lock); static DEFINE_MUTEX(driver_list_lock);
...@@ -61,6 +80,7 @@ device_write_register(struct i2c_client *client, uint8_t raddr, uint8_t value) { ...@@ -61,6 +80,7 @@ device_write_register(struct i2c_client *client, uint8_t raddr, uint8_t value) {
} }
#if 0 #if 0
/* ifdef'd out to pacify gcc until we need there */
static uint8_t static uint8_t
device_read_byte(struct i2c_client *client) { device_read_byte(struct i2c_client *client) {
uint8_t tmp; uint8_t tmp;
...@@ -89,16 +109,45 @@ device_read_register(struct i2c_client *client, void *buffer, uint8_t raddr, uin ...@@ -89,16 +109,45 @@ device_read_register(struct i2c_client *client, void *buffer, uint8_t raddr, uin
static void static void
ai2c_intr(struct work_struct *work) { ai2c_intr(struct work_struct *work) {
int i;
uint8_t key_status[6];
uint16_t cur, down, up;
arduino_i2c_driver_data_t *drv_info = container_of( arduino_i2c_driver_data_t *drv_info = container_of(
work, arduino_i2c_driver_data_t, intr_upper_work); work, arduino_i2c_driver_data_t, intr_upper_work);
BUG_ON(!drv_info->client); BUG_ON(!drv_info->client);
dev_info(&drv_info->client->dev, "ai2c_intr: entered\n"); dev_info(&drv_info->client->dev, "ai2c_intr: entered\n");
i2c_smbus_write_byte_data(drv_info->client, 50, 48); memset(key_status, 0, sizeof(key_status));
input_report_key(drv_info->indev, BTN_0, 1); for (i = 0; i < 6; i++) {
input_sync(drv_info->indev); device_read_register(drv_info->client, &(key_status[i]), AI2C_REGISTER_KEY_STATUS_LOW + i, 1);
input_report_key(drv_info->indev, BTN_0, 0); }
cur = (uint16_t)key_status[0] | ((uint16_t)key_status[1] << 8);
down = (uint16_t)key_status[2] | ((uint16_t)key_status[3] << 8);
up = (uint16_t)key_status[4] | ((uint16_t)key_status[5] << 8);
for (i = 0; i < 16; i++) {
if ((down & (1 << i)) && (up & (1 << i))) {
/* Key went down and up since last check - see what it is currently to decide order */
if (cur & (1 << i)) {
/* The button is currently up so it must have gone down first, then up */
input_report_key(drv_info->indev, default_keymap[i], 0);
input_sync(drv_info->indev);
input_report_key(drv_info->indev, default_keymap[i], 1);
} else {
/* Other way agound - up first, then down */
input_report_key(drv_info->indev, default_keymap[i], 1);
input_sync(drv_info->indev);
input_report_key(drv_info->indev, default_keymap[i], 0);
}
} else if (down & (1 << i)) {
/* New key down */
input_report_key(drv_info->indev, default_keymap[i], 0);
} else if (up & (1 << i)) {
/* New key up */
input_report_key(drv_info->indev, default_keymap[i], 1);
}
}
/* All events before this happened at the "same" time */
input_sync(drv_info->indev); input_sync(drv_info->indev);
return; return;
...@@ -118,7 +167,7 @@ ai2c_intr_lower(int irq, void *data) { ...@@ -118,7 +167,7 @@ ai2c_intr_lower(int irq, void *data) {
static int static int
ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) {
int i; int i, keymax;
int ret = 0; int ret = 0;
int flags = 0; int flags = 0;
uint16_t dev_id; uint16_t dev_id;
...@@ -148,6 +197,9 @@ ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { ...@@ -148,6 +197,9 @@ ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) {
dev_info(&client->dev, "Device ID: 0x%04x\nDevice Revision: 0x%02x\nDevice Firmware Build: \"%s\"\n", dev_info(&client->dev, "Device ID: 0x%04x\nDevice Revision: 0x%02x\nDevice Firmware Build: \"%s\"\n",
dev_id, dev_rev, dev_build_str); dev_id, dev_rev, dev_build_str);
/*
* Allocate/initialize driver data
*/
drv_info = (arduino_i2c_driver_data_t *)kmalloc(sizeof(arduino_i2c_driver_data_t), GFP_KERNEL); drv_info = (arduino_i2c_driver_data_t *)kmalloc(sizeof(arduino_i2c_driver_data_t), GFP_KERNEL);
if (!drv_info) { if (!drv_info) {
dev_err(&client->dev, "Unable to allocate driver memory"); dev_err(&client->dev, "Unable to allocate driver memory");
...@@ -156,6 +208,9 @@ ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { ...@@ -156,6 +208,9 @@ ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) {
} }
memset(drv_info, 0, sizeof(arduino_i2c_driver_data_t)); memset(drv_info, 0, sizeof(arduino_i2c_driver_data_t));
/*
* Get GPIO pin for interrupts
*/
ret = gpio_request(pdata->gpio_intr_pin, GPIO_IRQ_NAME); ret = gpio_request(pdata->gpio_intr_pin, GPIO_IRQ_NAME);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "ai2c: IRQ pin reservation of %d failed: error %d", pdata->gpio_intr_pin, ret); dev_err(&client->dev, "ai2c: IRQ pin reservation of %d failed: error %d", pdata->gpio_intr_pin, ret);
...@@ -175,6 +230,9 @@ ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { ...@@ -175,6 +230,9 @@ ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) {
dev_dbg(&client->dev, "ai2c: Reserved pin [%d]: irq = %d\n", pdata->gpio_intr_pin, drv_info->irq_num); dev_dbg(&client->dev, "ai2c: Reserved pin [%d]: irq = %d\n", pdata->gpio_intr_pin, drv_info->irq_num);
/*
* Register for key press IRQ
*/
flags |= IRQF_TRIGGER_FALLING; flags |= IRQF_TRIGGER_FALLING;
ret = request_irq(drv_info->irq_num, ai2c_intr_lower, flags, "ai2c_keyboard", drv_info); ret = request_irq(drv_info->irq_num, ai2c_intr_lower, flags, "ai2c_keyboard", drv_info);
if (ret < 0) { if (ret < 0) {
...@@ -189,17 +247,32 @@ ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { ...@@ -189,17 +247,32 @@ ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) {
goto out_cleanirq; goto out_cleanirq;
} }
/*
* Set up input device
*/
if (pdata->keymap) {
drv_info->keymap = pdata->keymap;
drv_info->numkeys = pdata->numkeys;
} else {
drv_info->keymap = default_keymap;
drv_info->numkeys = default_numkeys;
}
drv_info->indev->name = "arduino_i2c"; drv_info->indev->name = "arduino_i2c";
drv_info->indev->phys = "arduino_i2c/input0"; drv_info->indev->phys = "arduino_i2c/input0";
drv_info->indev->dev.parent = &client->dev; drv_info->indev->dev.parent = &client->dev;
drv_info->indev->id.bustype = BUS_I2C; drv_info->indev->id.bustype = BUS_I2C;
drv_info->indev->id.vendor = 0x4242; drv_info->indev->id.vendor = AI2C_ID;
drv_info->indev->id.product = 0x4242; drv_info->indev->id.product = AI2C_ID;
drv_info->indev->id.version = 0x0001; drv_info->indev->id.version = 0x0001;
drv_info->indev->keycodesize = sizeof(unsigned short); drv_info->indev->keycodesize = sizeof(unsigned short);
drv_info->indev->keycodemax = BTN_0 + 1;
drv_info->indev->evbit[0] = BIT_MASK(EV_KEY); drv_info->indev->evbit[0] = BIT_MASK(EV_KEY);
drv_info->indev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); keymax = -1;
for (i = 0; i < drv_info->numkeys; i++) {
drv_info->indev->keybit[BIT_WORD(drv_info->keymap[i])] |= BIT_MASK(drv_info->keymap[i]);
keymax = (drv_info->keymap[i] > keymax) ? drv_info->keymap[i] : keymax;
}
drv_info->indev->keycodemax = keymax + 1;
ret = input_register_device(drv_info->indev); ret = input_register_device(drv_info->indev);
if (ret) { if (ret) {
dev_err(&client->dev, "ai2c: unable to register input device: %d", ret); dev_err(&client->dev, "ai2c: unable to register input device: %d", ret);
...@@ -225,7 +298,7 @@ out_cleanindev: ...@@ -225,7 +298,7 @@ out_cleanindev:
out_cleanirq: out_cleanirq:
free_irq(drv_info->irq_num, drv_info); free_irq(drv_info->irq_num, drv_info);
out_cleanup: out_cleanup:
gpio_free(drv_info->irq_num); gpio_free(drv_info->irq_pin);
out_dealloc: out_dealloc:
kfree(drv_info); kfree(drv_info);
out: out:
...@@ -241,7 +314,7 @@ ai2c_remove(struct i2c_client *client) { ...@@ -241,7 +314,7 @@ ai2c_remove(struct i2c_client *client) {
flush_work(&drv_info->intr_upper_work); flush_work(&drv_info->intr_upper_work);
gpio_free(drv_info->irq_num); gpio_free(drv_info->irq_pin);
dev_set_drvdata(&drv_info->client->dev, NULL); dev_set_drvdata(&drv_info->client->dev, NULL);
...@@ -273,7 +346,7 @@ static struct i2c_driver ai2c_driver = { ...@@ -273,7 +346,7 @@ static struct i2c_driver ai2c_driver = {
.id_table = ai2c_id, .id_table = ai2c_id,
}; };
int static int
ai2c_init(void) { ai2c_init(void) {
int ret; int ret;
printk(KERN_INFO "Arduino I2C Keyboard Starting\n"); printk(KERN_INFO "Arduino I2C Keyboard Starting\n");
...@@ -284,7 +357,7 @@ ai2c_init(void) { ...@@ -284,7 +357,7 @@ ai2c_init(void) {
return ret; return ret;
} }
void static void
ai2c_shutdown(void) { ai2c_shutdown(void) {
printk(KERN_INFO "Arduino I2C Keyboard Shutting Down\n"); printk(KERN_INFO "Arduino I2C Keyboard Shutting Down\n");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment