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 @@
typedef struct arduino_i2c_keyboard_platform_data {
int gpio_intr_pin;
int *keymap;
int numkeys;
} arduino_i2c_keyboard_platform_data_t;
#endif /* _AI2C_PLATFORM_DATA_H */
......@@ -44,10 +44,29 @@
#define IRQ_GPIO_PIN 9
#define GPIO_IRQ_NAME "ai2c_keyboard_irq"
const int default_keymap[] = {
0,
static int default_keymap[] = {
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 DEFINE_MUTEX(driver_list_lock);
......@@ -61,6 +80,7 @@ device_write_register(struct i2c_client *client, uint8_t raddr, uint8_t value) {
}
#if 0
/* ifdef'd out to pacify gcc until we need there */
static uint8_t
device_read_byte(struct i2c_client *client) {
uint8_t tmp;
......@@ -89,16 +109,45 @@ device_read_register(struct i2c_client *client, void *buffer, uint8_t raddr, uin
static void
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(
work, arduino_i2c_driver_data_t, intr_upper_work);
BUG_ON(!drv_info->client);
dev_info(&drv_info->client->dev, "ai2c_intr: entered\n");
i2c_smbus_write_byte_data(drv_info->client, 50, 48);
input_report_key(drv_info->indev, BTN_0, 1);
input_sync(drv_info->indev);
input_report_key(drv_info->indev, BTN_0, 0);
memset(key_status, 0, sizeof(key_status));
for (i = 0; i < 6; i++) {
device_read_register(drv_info->client, &(key_status[i]), AI2C_REGISTER_KEY_STATUS_LOW + i, 1);
}
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);
return;
......@@ -118,7 +167,7 @@ ai2c_intr_lower(int irq, void *data) {
static int
ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) {
int i;
int i, keymax;
int ret = 0;
int flags = 0;
uint16_t dev_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_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);
if (!drv_info) {
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) {
}
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);
if (ret < 0) {
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) {
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;
ret = request_irq(drv_info->irq_num, ai2c_intr_lower, flags, "ai2c_keyboard", drv_info);
if (ret < 0) {
......@@ -189,17 +247,32 @@ ai2c_probe(struct i2c_client *client, const struct i2c_device_id *id) {
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->phys = "arduino_i2c/input0";
drv_info->indev->dev.parent = &client->dev;
drv_info->indev->id.bustype = BUS_I2C;
drv_info->indev->id.vendor = 0x4242;
drv_info->indev->id.product = 0x4242;
drv_info->indev->id.vendor = AI2C_ID;
drv_info->indev->id.product = AI2C_ID;
drv_info->indev->id.version = 0x0001;
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->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);
if (ret) {
dev_err(&client->dev, "ai2c: unable to register input device: %d", ret);
......@@ -225,7 +298,7 @@ out_cleanindev:
out_cleanirq:
free_irq(drv_info->irq_num, drv_info);
out_cleanup:
gpio_free(drv_info->irq_num);
gpio_free(drv_info->irq_pin);
out_dealloc:
kfree(drv_info);
out:
......@@ -241,7 +314,7 @@ ai2c_remove(struct i2c_client *client) {
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);
......@@ -273,7 +346,7 @@ static struct i2c_driver ai2c_driver = {
.id_table = ai2c_id,
};
int
static int
ai2c_init(void) {
int ret;
printk(KERN_INFO "Arduino I2C Keyboard Starting\n");
......@@ -284,7 +357,7 @@ ai2c_init(void) {
return ret;
}
void
static void
ai2c_shutdown(void) {
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