~mil/ppbbq10

ec4348e6ef4fe21352d1ea76afc8ce1180f367f1 — Miles Alan 3 years ago 192866b
Working symbols layer with shifting functionality as well
1 files changed, 101 insertions(+), 19 deletions(-)

M ppbbq10.c
M ppbbq10.c => ppbbq10.c +101 -19
@@ 45,11 45,13 @@
#define WRITE_MASK	BIT(7)
#define _KEY_CAPSLOCK	BIT(5)
#define _KEY_NUMLOCK	BIT(6)
//#define DEBUG
#define DEBUG

/* structs */
struct ppbbq10_data {
	unsigned int is_symed;
	unsigned short keymap_norm[NUM_KEYCODES];
	short keymap_sym[NUM_KEYCODES];
	struct i2c_client *client;
	struct input_dev *input;
};


@@ 64,6 66,7 @@ static int ppbbq10_poll_kthread(void *data);
static int ppbbq10_probe(struct i2c_client *client);
static void ppbbq10_read_fifo(struct ppbbq10_data *drv_data);
static int ppbbq10_read_reg(struct ppbbq10_data *drv_data, u8 reg, u8 *buf, u8 len);
static void ppbbq10_report_keyevent(struct ppbbq10_data *drv_data, u8 keystate, u8 keycode);
static void ppbbq10_update_locks(struct ppbbq10_data *drv_data);
static int ppbbq10_write_data(struct ppbbq10_data *drv_data, u8 reg, const u8 *buf, u8 len);
static int ppbbq10_write_reg(struct ppbbq10_data *drv_data, u8 reg);


@@ 113,6 116,49 @@ static unsigned short keymap_norm[NUM_KEYCODES] = {
	['\b'] = KEY_BACKSPACE,
	['\n'] = KEY_ENTER,
};
static short keymap_sym[NUM_KEYCODES] = {
	[0x01] = KEY_UP,
	[0x02] = KEY_DOWN,
	[0x03] = KEY_LEFT,
	[0x04] = KEY_RIGHT,
	[0x05] = KEY_ENTER,
	[0x06] = KEY_MENU,
	[0x07] = KEY_BACK,
	[26] = KEY_LEFTALT,
	[27] = KEY_LEFTSHIFT,
	[28] = KEY_LEFTCTRL,
	['A'] = KEY_A,
	['B'] = KEY_1 * -1, // (!)
	['C'] = KEY_9,
	['D'] = KEY_5,
	['E'] = KEY_2,
	['F'] = KEY_6,
	['G'] = KEY_G,
	['H'] = KEY_H,
	['I'] = KEY_I,
	['J'] = KEY_J,
	['K'] = KEY_K,
	['L'] = KEY_L,
	['M'] = KEY_M,
	['N'] = KEY_N,
	['O'] = KEY_O,
	['P'] = KEY_P,
	['Q'] = KEY_Q,
	['R'] = KEY_3,
	['S'] = KEY_4,
	['T'] = KEY_T,
	['U'] = KEY_U,
	['W'] = KEY_1,
	['V'] = KEY_V,
	['X'] = KEY_8,
	['Y'] = KEY_Y,
	['Z'] = KEY_7,
	[' '] = KEY_SPACE,
	['~'] = KEY_0,
	['$'] = KEY_GRAVE,
	['\b'] = KEY_BACKSPACE,
	['\n'] = KEY_ENTER,
};
static struct i2c_board_info ppbbq10_i2c_board_info[] __initdata = {
	{ I2C_BOARD_INFO("ppbbq10", 0x1f), /*.irq = gpio_to_irq(11)*/ }
};


@@ 212,7 258,7 @@ ppbbq10_irq_handler(int irq, void *dev_id)
static int ppbbq10_poll_kthread(void *data)
{
	while (!kthread_should_stop()) {
		usleep_range(1000 * 10, (1000 * 10) + 1); // 10ms poll
		usleep_range(1000 * 1, (1000 * 1) + 1); // 5ms poll
		ppbbq10_irq_handler(0, NULL);
	}
	return 0;


@@ 234,6 280,8 @@ ppbbq10_probe(struct i2c_client *client)

	drv_data->client = client;
	memcpy(drv_data->keymap_norm, keymap_norm, sizeof(drv_data->keymap_norm));
	memcpy(drv_data->keymap_sym, keymap_sym, sizeof(drv_data->keymap_sym));
	drv_data->is_symed = 0;

	error = ppbbq10_write_reg(drv_data, REG_RST);
	if (error)


@@ 276,12 324,14 @@ ppbbq10_probe(struct i2c_client *client)
	input->id.vendor  = 0x0001;
	input->id.product = 0x0001;
	input->id.version = 0x0001;
	input->keycode= drv_data->keymap_norm;
	input->keycode = drv_data->keymap_norm;
	input->keycodesize = sizeof(drv_data->keymap_norm[0]);
	input->keycodemax = ARRAY_SIZE(drv_data->keymap_norm);
	input->keycodemax = ARRAY_SIZE(drv_data->keymap_norm) + ARRAY_SIZE(drv_data->keymap_sym) ;

	for (i = 0; i < NUM_KEYCODES; i++)
		__set_bit(drv_data->keymap_norm[i], input->keybit);
	for (i = 0; i < NUM_KEYCODES; i++)
		__set_bit(drv_data->keymap_sym[i], input->keybit);

	__clear_bit(KEY_RESERVED, input->keybit);



@@ 336,22 386,8 @@ ppbbq10_read_fifo(struct ppbbq10_data *drv_data)
				__func__, error);
			return;
		}

		pr_debug("%s key %d/%c, state: %d\n",
			__func__, data[1], data[1], data[0]);

		count -= 1;

		if (data[0] == STATE_PRESS || data[0] == STATE_RELEASE) {
			input_event(input, EV_MSC, MSC_SCAN, data[1]);

			keycode = drv_data->keymap_norm[data[1]];
			if (keycode == KEY_UNKNOWN) {
				pr_warn("%s code 0x%02X UNKNOWN\n", __func__, data[1]);
			} else {
				input_report_key(input, keycode, data[0] == STATE_PRESS);
			}
		}
		ppbbq10_report_keyevent(drv_data, data[0], data[1]);
	}

	input_sync(input);


@@ 380,6 416,52 @@ ppbbq10_read_reg(struct ppbbq10_data *drv_data, u8 reg, u8 *buf, u8 len)
}

static void
ppbbq10_report_keyevent(struct ppbbq10_data *drv_data, u8 keystate, u8 keycode)
{
	unsigned int key_mapped;
	int send_shift = 0;

	printk(KERN_INFO "%s key %d/%c, state: %d\n", __func__, keycode, keycode, keystate);

	// Determine key_mapped
	if (drv_data->is_symed) {
		send_shift = drv_data->keymap_sym[keycode] < 0;
		key_mapped = abs(drv_data->keymap_sym[keycode]);
		if (drv_data->is_symed && keystate == STATE_RELEASE) drv_data->is_symed = 0;
		printk(KERN_INFO "Sending sym'd: %s key %d/%c, state: %d and !! %d and is_shifted %d\n", __func__, keycode, keycode, keystate, drv_data->keymap_sym[keycode], send_shift);
	} else {
		key_mapped = drv_data->keymap_norm[keycode];
	}

	// Reset is_symed after 1 keypress
	if (drv_data->is_symed && keystate == STATE_RELEASE) drv_data->is_symed = 0;

	// Symbol layer tap, activates symbol for next pressed key
	if (keycode == 29 && keystate == STATE_RELEASE) {
		printk(KERN_INFO "SYM press - next key symbol.\n");
		drv_data->is_symed = 1;
	} else if (keystate == STATE_PRESS || keystate == STATE_RELEASE) {
		input_event(drv_data->input, EV_MSC, MSC_SCAN, key_mapped);
		if (key_mapped == KEY_UNKNOWN) {
			pr_warn("%s code 0x%02X UNKNOWN\n", __func__, key_mapped);
		} else if (drv_data->is_symed && send_shift) {
			ppbbq10_report_keyevent(drv_data, STATE_PRESS, 27);
			usleep_range(10, 20);
			ppbbq10_report_keyevent(drv_data, STATE_HOLD, 27);
			usleep_range(10, 20);
			input_report_key(drv_data->input, key_mapped, keystate == STATE_PRESS);
			usleep_range(10, 20);
			input_report_key(drv_data->input, key_mapped, keystate == STATE_RELEASE);
			usleep_range(10, 20);
			ppbbq10_report_keyevent(drv_data, STATE_RELEASE, 27);
		} else if ((drv_data->is_symed&& !send_shift) || !drv_data->is_symed) {
			input_report_key(drv_data->input, key_mapped, keystate == STATE_PRESS);
		}
	}
}


static void
ppbbq10_update_locks(struct ppbbq10_data *drv_data)
{
	struct input_dev *input = drv_data->input;