* [PATCH] driver: input: touchscreen: add Raydium i2c touchscreen driver
From: jeffrey.lin @ 2014-12-01 10:17 UTC (permalink / raw)
To: dmitry.torokhov, rydberg, shc_work, bleung, lee.jones,
charliemooney
Cc: KP.li, linux-kernel, linux-input, jeffrey.lin
From: "jeffrey.lin" <jeffrey.lin@rad-ic.com>
This patch is porting Raydium I2C touch driver. Developer can enable
raydium touch driver by modifying define "CONFIG_TOUCHSCREEN_RM_TS".
Change-Id: I5f33cfdf0e895de6e7d535c11dd4b3ce8b49fa48
Signed-off-by: jeffrey.lin@rad-ic.com
---
drivers/input/touchscreen/Kconfig | 12 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/rm31100_ts.c | 968 +++++++++++++++++++++++++++++++++
include/linux/input/rm31100_ts.h | 60 ++
4 files changed, 1041 insertions(+)
create mode 100644 drivers/input/touchscreen/rm31100_ts.c
create mode 100644 include/linux/input/rm31100_ts.h
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 3ce9181..d0324d2 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -955,4 +955,16 @@ config TOUCHSCREEN_ZFORCE
To compile this driver as a module, choose M here: the
module will be called zforce_ts.
+config TOUCHSCREEN_RM_TS
+ tristate "Raydium I2C Touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have Raydium series I2C touchscreen,
+ such as RM31100 , connected to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rm31100_ts.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 687d5a7..aae4af2 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o
+obj-$(CONFIG_TOUCHSCREEN_RM_TS) += rm31100_ts.o
diff --git a/drivers/input/touchscreen/rm31100_ts.c b/drivers/input/touchscreen/rm31100_ts.c
new file mode 100644
index 0000000..6cb09a4
--- /dev/null
+++ b/drivers/input/touchscreen/rm31100_ts.c
@@ -0,0 +1,968 @@
+/* Source for:
+ * Raydium rm31100_ts Prototype touchscreen driver.
+ * drivers/input/touchscreen/rm31100_ts.c
+ *
+ * Copyright (C) 2012,
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Raydium reserves the right to make changes without further notice
+ * to the materials described herein. Raydium does not assume any
+ * liability arising out of the application described herein.
+ *
+ * Contact Raydium Semiconductor Corporation at www.rad-ic.com
+ *
+ * History:
+ * (C) 2012 Raydium - Update for GPL distribution
+ * (C) 2009 Enea - Original prototype
+ *
+ */
+#include <linux/async.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/input/rm31100_ts.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+/*#include <plat/gpio-cfg.h>*/
+#ifdef CONFIG_MISC_DEV
+#include <linux/miscdevice.h>
+#endif
+/*#include <asm/uaccess.h> copy_to_user() */
+#include <linux/uaccess.h>
+
+#define rm31100 0x0
+#define rm3110x 0x1
+
+#define INVALID_DATA 0xff
+#define MAX_REPORT_TOUCHED_POINTS 10
+
+#define TOUCHSCREEN_TIMEOUT (msecs_to_jiffies(10))
+#define INITIAL_DELAY (msecs_to_jiffies(25000))
+
+#define EVAL_REPORT_RATE 1
+
+#define I2C_CLIENT_ADDR 0x39
+#define I2C_DMA_CLIENT_ADDR 0x5A
+#undef CONFIG_PM
+struct rm31100_ts_data {
+ u8 x_index;
+ u8 y_index;
+ u8 z_index;
+ u8 id_index;
+ u8 touch_index;
+ u8 data_reg;
+ u8 status_reg;
+ u8 data_size;
+ u8 touch_bytes;
+ u8 update_data;
+ u8 touch_meta_data;
+ u8 finger_size;
+};
+
+static struct rm31100_ts_data devices[] = {
+ [0] = {
+ .x_index = 2,
+ .y_index = 4,
+ .z_index = 6,
+ .id_index = 1,
+ .data_reg = 0x1,
+ .status_reg = 0,
+ .update_data = 0x0,/*0x4*/
+ .touch_bytes = 6,
+ .touch_meta_data = 1,
+ .finger_size = 70,
+ },
+};
+
+struct rm31100_ts {
+ struct i2c_client *client;
+ struct input_dev *input;
+ struct delayed_work work;
+ struct rm3110x_ts_platform_data *pdata;
+ struct rm31100_ts_data *dd;
+ u8 *touch_data;
+ u8 device_id;
+ u8 prev_touches;
+ bool is_suspended;
+ bool int_pending;
+ struct mutex sus_lock;
+ struct mutex access_lock;
+ u32 pen_irq;
+};
+
+struct rm31100_ts *pts;
+/*
+static inline u16 join_bytes(u8 a, u8 b)
+{
+ u16 ab = 0;
+ ab = ab | a;
+ ab = ab << 8 | b;
+ return ab;
+}
+*/
+static s32 rm31100_ts_write_reg_u8(struct i2c_client *client, u8 reg, u8 val)
+{
+ s32 data;
+
+ data = i2c_smbus_write_byte_data(client, reg, val);
+ if (data < 0)
+ dev_err(&client->dev, "error %d in writing reg 0x%x\n",
+ data, reg);
+
+ return data;
+}
+
+static s32 rm31100_ts_read_reg_u8(struct i2c_client *client, u8 reg)
+{
+ s32 data;
+
+ data = i2c_smbus_read_byte_data(client, reg);
+ if (data < 0)
+ dev_err(&client->dev, "error %d in reading reg 0x%x\n",
+ data, reg);
+
+ return data;
+}
+
+static int rm31100_ts_read(struct i2c_client *client, u8 reg, u8 *buf, int num)
+{
+ struct i2c_msg xfer_msg[2];
+
+ xfer_msg[0].addr = client->addr;
+ xfer_msg[0].len = 1;
+ xfer_msg[0].flags = 0;
+ xfer_msg[0].buf = ®
+
+ xfer_msg[1].addr = client->addr;
+ xfer_msg[1].len = num;
+ xfer_msg[1].flags = I2C_M_RD;
+ xfer_msg[1].buf = buf;
+
+ return i2c_transfer(client->adapter, xfer_msg, 2);
+}
+
+static int rm31100_ts_write(struct i2c_client *client, u8 *buf, int num)
+{
+ struct i2c_msg xfer_msg[1];
+
+ xfer_msg[0].addr = client->addr;
+ xfer_msg[0].len = num;
+ xfer_msg[0].flags = 0;
+ xfer_msg[0].buf = buf;
+
+ return i2c_transfer(client->adapter, xfer_msg, 1);
+}
+
+#ifdef CONFIG_MISC_DEV
+static int dev_open(struct inode *inode, struct file *filp)
+{
+ mutex_lock(&pts->access_lock);
+ return 0;
+}
+
+static int dev_release(struct inode *inode, struct file *filp)
+{
+ mutex_unlock(&pts->access_lock);
+ return 0;
+}
+static ssize_t
+dev_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
+{
+ u8 *kbuf;
+ struct i2c_msg xfer_msg;
+ /*static char out[] = "1234567890";*/
+ /*static int idx;*//*= 0; remove by checkpatch*/
+ int i;
+
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (kbuf == NULL)
+ return -ENOMEM;
+
+ /*xfer_msg.addr = pts->client->addr;*/
+ xfer_msg.addr = I2C_CLIENT_ADDR;
+ xfer_msg.len = count;
+ xfer_msg.flags = I2C_M_RD;
+ xfer_msg.buf = kbuf;
+
+ i2c_transfer(pts->client->adapter, &xfer_msg, 1);
+
+ if (copy_to_user(buf, kbuf, count) == 0)
+ return count;
+ else
+ return -EFAULT;
+}
+
+static ssize_t
+dev_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
+{
+ u8 *kbuf;
+ ssize_t status = 0;
+ int i;
+
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (kbuf == NULL) {
+ dev_err("kmalloc() fail\n");
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(kbuf, buf, count) == 0) {
+ pts->client->addr = I2C_CLIENT_ADDR;
+ if (rm31100_ts_write(pts->client, kbuf, count) < 0)
+ status = -EFAULT;
+ else
+ status = count;
+ } else {
+ dev_err("copy_from_user() fail\n");
+ status = -EFAULT;
+ }
+
+ kfree(kbuf);
+ return status;
+}
+
+static struct file_operations dev_fops = {
+ .owner = THIS_MODULE,
+ .open = dev_open,
+ .release = dev_release,
+ .read = dev_read,
+ .write = dev_write,
+ /*.unlocked_ioctl = dev_ioctl,*/
+};
+
+static struct miscdevice raydium_ts_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "raydium_ts",
+ .fops = &dev_fops,
+};
+#endif
+
+
+ssize_t show(struct device_driver *drv, char *buff)
+{
+ struct i2c_msg xfer_msg;
+ int num = 10;
+ char buf[100];
+ /*int i;*/
+
+ xfer_msg.addr = pts->client->addr;
+ xfer_msg.len = num;
+ xfer_msg.flags = I2C_M_RD;
+ xfer_msg.buf = buf;
+ pts->client->addr = I2C_CLIENT_ADDR;
+ i2c_transfer(pts->client->adapter, &xfer_msg, 1);
+
+ return 0;
+}
+
+ssize_t store(struct device_driver *drv, const char *buf, size_t count)
+{
+ /*unsigned char pkt[] = { 0xF2, 5, 1, 1 };*/
+ unsigned char pkt[] = { 0xF1, 5, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
+
+ pts->client->addr = I2C_CLIENT_ADDR;
+ rm31100_ts_write(pts->client, pkt, sizeof(pkt));
+
+ return sizeof(pkt);
+}
+
+DRIVER_ATTR(myAttr, 0x777, show, store);
+
+static void report_data(struct rm31100_ts *ts, u16 x, u16 y, u8 pressure, u8 id)
+{
+ if (ts->pdata->swap_xy)
+ swap(x, y);
+
+ /* handle inverting coordinates */
+ if (ts->pdata->invert_x)
+ x = ts->pdata->res_x - x;
+ if (ts->pdata->invert_y)
+ y = ts->pdata->res_y - y;
+/*
+ input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);
+ input_report_abs(ts->input, ABS_MT_POSITION_X, x);
+ input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
+ input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pressure);
+ input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, ts->dd->finger_size);
+ input_mt_sync(ts->input);
+*/
+/*For protocol B*/
+ input_mt_slot(ts->input_dev, id);
+ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(ts->input_dev, ABS_MT_PRESSURE, pressure);
+/*
+ dev_dbg("%s(): id =%2hhd, x =%4hd, y =%4hd, pressure = %hhd\n",
+ __func__, id, x, y, pressure);
+*/
+}
+
+static void process_rm31100_data(struct RM31100_ts *ts)
+{
+ u8 id, pressure, touches, i;
+ u16 x, y;
+
+ touches = ts->touch_data[ts->dd->touch_index];
+
+ if (touches > 0) {
+ for (i = 0; i < touches; i++) {
+ id = ts->touch_data[i * ts->dd->touch_bytes +
+ ts->dd->id_index];
+ pressure = ts->touch_data[i * ts->dd->touch_bytes +
+ ts->dd->z_index];
+ /*
+ x = join_bytes(ts->touch_data[i * ts->dd->touch_bytes +
+ ts->dd->x_index + 1],
+ ts->touch_data[i * ts->dd->touch_bytes +
+ ts->dd->x_index]);
+ y = join_bytes(ts->touch_data[i * ts->dd->touch_bytes +
+ ts->dd->y_index + 1],
+ ts->touch_data[i * ts->dd->touch_bytes +
+ ts->dd->y_index]);
+ */
+ x = get_unaligned_le16(ts->touch_data[i * ts->dd->
+ touch_bytes + ts->dd->x_index]);
+ y = get_unaligned_le16(ts->touch_data[i * ts->dd->
+ touch_bytes + ts->dd->y_index]);
+ report_data(ts, x, y, pressure, id);
+ }
+ } else
+ input_mt_sync(ts->input);
+
+ ts->prev_touches = touches;
+ input_report_key(ts->input, BTN_TOUCH, 1);
+ input_sync(ts->input);
+}
+
+static void rm31100_ts_xy_worker(struct work_struct *work)
+{
+ int rc;
+ u8 DMAAddress[4];
+ struct rm31100_ts *ts;
+#if EVAL_REPORT_RATE
+ static struct timeval tv_start;
+ struct timeval tv_now;
+ static int cnt = -1;
+ int us;
+#endif /* EVAL_REPORT_RATE*/
+
+ /*dev_dbg("****rm31100_ts_xy_worker******\n");*/
+ mutex_lock(&ts->sus_lock);
+ if (ts->is_suspended == true) {
+ dev_dbg(&ts->client->dev, "TS is supended\n");
+ ts->int_pending = true;
+ mutex_unlock(&ts->sus_lock);
+ return;
+ }
+ mutex_unlock(&ts->sus_lock);
+
+ mutex_lock(&ts->access_lock);
+ /* read data from DATA_REG */
+ /*RM31100 DMA Mode*/
+ /*T010 OR w001+T012*/
+ DMAAddress[0] = 0x0F;
+ DMAAddress[1] = 0x00;
+ DMAAddress[2] = 0x20;
+ DMAAddress[3] = 0x81;/* Turn on DMA Mode*/
+ ts->client->addr = I2C_DMA_CLIENT_ADDR;
+ rc = rm31100_ts_write(ts->client, DMAAddress, 0x04);
+ if (rc < 0) {
+ dev_err(&ts->client->dev, "write failed\n");
+ goto schedule;
+ }
+ ts->client->addr = I2C_CLIENT_ADDR;
+ rc = rm31100_ts_read(ts->client, ts->dd->data_reg, ts->touch_data,
+ ts->dd->data_size);
+
+ if (rc < 0) {
+ dev_err(&ts->client->dev, "read failed\n");
+ goto schedule;
+ }
+
+ if (ts->touch_data[ts->dd->touch_index] == INVALID_DATA)
+ goto schedule;
+
+ /* write to STATUS_REG to release lock */
+ rc = rm31100_ts_write_reg_u8(ts->client,
+ ts->dd->status_reg, ts->dd->update_data);
+ if (rc < 0) {
+ dev_err(&ts->client->dev, "write failed, try once more\n");
+
+ rc = rm31100_ts_write_reg_u8(ts->client,
+ ts->dd->status_reg, ts->dd->update_data);
+ if (rc < 0)
+ dev_err(&ts->client->dev, "write failed, exiting\n");
+ }
+
+ process_rm31100_data(ts);
+
+#if EVAL_REPORT_RATE
+ cnt++;
+
+ if (cnt == 0)/* first time this function is executed.*/
+ do_gettimeofday(&tv_start);
+ else if (cnt == 100) {
+ do_gettimeofday(&tv_now);
+ us = 1000000 * (tv_now.tv_sec - tv_start.tv_sec)
+ + tv_now.tv_usec - tv_start.tv_usec;
+ tv_start.tv_sec = tv_now.tv_sec;
+ tv_start.tv_usec = tv_now.tv_usec;
+ cnt = 0;
+ }
+#endif /* EVAL_REPORT_RATE*/
+schedule:
+
+ mutex_unlock(&ts->access_lock);
+ /*dev_dbg("****Leave rm31100_ts_xy_worker******\n");*/
+}
+
+static irqreturn_t rm31100_ts_irq(int irq, void *dev_id)
+{
+ struct rm31100_ts *ts = dev_id;
+
+/*For protocol B*/
+ input_sync(g_input_dev);
+
+ rm31100_ts_xy_worker(&ts->work);
+ return IRQ_HANDLED;
+}
+
+static int rm31100_ts_init_ts(struct i2c_client *client, struct rm31100_ts *ts)
+{
+ struct input_dev *input_device;
+ int rc = 0;
+
+ ts->dd = &devices[ts->device_id];
+
+ if (!ts->pdata->nfingers) {
+ dev_err(&client->dev, "Touches information not specified\n");
+ return -EINVAL;
+ }
+
+ if (ts->device_id == rm3110x) {
+ if (ts->pdata->nfingers > 2) {
+ dev_err(&client->dev, "Touches >=1 & <= 2\n");
+ return -EINVAL;
+ }
+ ts->dd->data_size = ts->dd->touch_bytes;
+ ts->dd->touch_index = 0x0;
+ } else if (ts->device_id == rm31100) {
+ if (ts->pdata->nfingers > 10) {
+ dev_err(&client->dev, "Touches >=1 & <= 10\n");
+ return -EINVAL;
+ }
+ ts->dd->data_size = ts->pdata->nfingers * ts->dd->touch_bytes +
+ ts->dd->touch_meta_data;
+ ts->dd->touch_index = 0x0;
+ }
+ /* w001 */
+ else {
+ ts->dd->data_size = ts->pdata->nfingers * ts->dd->touch_bytes +
+ ts->dd->touch_meta_data;
+ ts->dd->touch_index = 0x0;
+ }
+
+ ts->touch_data = kzalloc(ts->dd->data_size, GFP_KERNEL);
+ if (!ts->touch_data) {
+ pr_err("%s: Unable to allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rm31100_ts_suspend(struct device *dev)
+{
+ struct rm31100_ts *ts = dev_get_drvdata(dev);
+ int rc = 0, i;
+
+ if (device_may_wakeup(dev)) {
+ /* mark suspend flag */
+ mutex_lock(&ts->sus_lock);
+ ts->is_suspended = true;
+ mutex_unlock(&ts->sus_lock);
+
+ enable_irq_wake(ts->pen_irq);
+ } else {
+ disable_irq_nosync(ts->pen_irq);
+/*For protocol B*/
+ for (i = 0; i < MAX_REPORT_TOUCHED_POINTS; i++) {
+ input_mt_slot(ts->input_dev, i);
+
+ input_mt_report_slot_state(
+ ts->input_dev,
+ MT_TOOL_FINGER, false);
+
+ input_report_key(
+ ts->input_dev,
+ BTN_TOOL_RUBBER, false);
+ }
+ input_sync(ts->input_dev);
+
+ if (rc) {
+ /* missed the worker, write to STATUS_REG to
+ acknowledge interrupt */
+ rc = rm31100_ts_write_reg_u8(ts->client,
+ ts->dd->status_reg, ts->dd->update_data);
+ if (rc < 0) {
+ dev_err(&ts->client->dev,
+ "write failed, try once more\n");
+
+ rc = rm31100_ts_write_reg_u8(ts->client,
+ ts->dd->status_reg,
+ ts->dd->update_data);
+ if (rc < 0)
+ dev_err(&ts->client->dev,
+ "write failed, exiting\n");
+ }
+
+ enable_irq(ts->pen_irq);
+ }
+
+ gpio_free(ts->pdata->irq_gpio);
+
+ if (ts->pdata->power_on) {
+ rc = ts->pdata->power_on(0);
+ if (rc) {
+ dev_err(dev, "unable to goto suspend\n");
+ return rc;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int rm31100_ts_resume(struct device *dev)
+{
+ struct rm31100_ts *ts = dev_get_drvdata(dev);
+
+ int rc = 0;
+
+ if (device_may_wakeup(dev)) {
+ disable_irq_wake(ts->pen_irq);
+
+ mutex_lock(&ts->sus_lock);
+ ts->is_suspended = false;
+
+ if (ts->int_pending == true)
+ ts->int_pending = false;
+
+ mutex_unlock(&ts->sus_lock);
+
+ } else {
+ if (ts->pdata->power_on) {
+ rc = ts->pdata->power_on(1);
+ if (rc) {
+ dev_err(dev, "unable to resume\n");
+ return rc;
+ }
+ }
+
+ /* configure touchscreen interrupt gpio */
+ rc = gpio_request(ts->pdata->irq_gpio, "rm31100_irq_gpio");
+ if (rc) {
+ pr_err("%s: unable to request gpio %d\n",
+ __func__, ts->pdata->irq_gpio);
+ goto err_power_off;
+ }
+ if (ts->pdata->irq_cfg) {
+ s3c_gpio_cfgpin(ts->pdata->irq_gpio,
+ ts->pdata->irq_cfg);
+ s3c_gpio_setpull(ts->pdata->irq_gpio,
+ S3C_GPIO_PULL_NONE);
+ }
+
+ rc = gpio_direction_input(ts->pdata->irq_gpio);
+ if (rc) {
+ pr_err("%s: unable to set direction for gpio %d\n",
+ __func__, ts->pdata->irq_gpio);
+ goto err_gpio_free;
+ }
+
+ enable_irq(ts->pen_irq);
+
+ /* Clear the status register of the TS controller */
+ rc = rm31100_ts_write_reg_u8(ts->client,
+ ts->dd->status_reg, ts->dd->update_data);
+ if (rc < 0) {
+ dev_err(&ts->client->dev,
+ "write failed, try once more\n");
+
+ rc = rm31100_ts_write_reg_u8(ts->client,
+ ts->dd->status_reg,
+ ts->dd->update_data);
+ if (rc < 0)
+ dev_err(&ts->client->dev,
+ "write failed, exiting\n");
+ }
+ }
+
+ return 0;
+err_gpio_free:
+ gpio_free(ts->pdata->irq_gpio);
+err_power_off:
+ if (ts->pdata->power_on)
+ rc = ts->pdata->power_on(0);
+ return rc;
+}
+
+static struct dev_pm_ops rm31100_ts_pm_ops = {
+ .suspend = rm31100_ts_suspend,
+ .resume = rm31100_ts_resume,
+};
+#endif
+
+static int rm_input_dev_create(struct rm31100_ts *ts)
+{
+ struct input_dev *input_device;
+ int rc = 0;
+ ts->prev_touches = 0;
+
+ input_device = input_allocate_device();
+ if (!input_device) {
+ rc = -ENOMEM;
+ goto error_alloc_dev;
+ }
+
+ ts->input = input_device;
+ input_device->name = "raydium_ts"/*ts->pdata->ts_name*/;
+ input_device->id.bustype = BUS_I2C;
+ input_device->dev.parent = &client->dev;
+ input_set_drvdata(input_device, ts);
+
+ __set_bit(EV_ABS, input_device->evbit);
+ __set_bit(INPUT_PROP_DIRECT, input_device->propbit);
+ /*__set_bit(EV_SYN, input_device->evbit);*/
+ /*__set_bit(BTN_TOUCH, input_device->keybit);*/
+
+
+ if (ts->device_id == rm31100) {
+ /* set up virtual key */
+ __set_bit(EV_KEY, input_device->evbit);
+ /* set dummy key to make driver work with virtual keys */
+ input_set_capability(input_device, EV_KEY, KEY_PROG1);
+ }
+ /*For protocol B*/
+ input_mt_init_slots(input_device,
+ MAX_REPORT_TOUCHED_POINTS,
+ 0);
+ input_set_abs_params(input_device, ABS_MT_POSITION_X,
+ ts->pdata->dis_min_x, ts->pdata->dis_max_x, 0, 0);
+ input_set_abs_params(input_device, ABS_MT_POSITION_Y,
+ ts->pdata->dis_min_y, ts->pdata->dis_max_y, 0, 0);
+ input_set_abs_params(input_device, ABS_MT_PRESSURE,
+ 0, 0xFF, 0, 0);
+ /*input_set_abs_params(input_device, ABS_MT_TRACKING_ID,
+ ts->pdata->min_tid, ts->pdata->max_tid, 0, 0);*/
+ rc = input_register_device(input_device);
+ if (rc)
+ goto error_unreg_device;
+
+ return 0;
+
+error_unreg_device:
+error_wq_create:
+ input_free_device(input_device);
+error_alloc_dev:
+ kfree(ts->touch_data);
+ return rc;
+}
+
+static int rm31100_initialize(struct i2c_client *client)
+{
+ struct rm31100_ts *ts = i2c_get_clientdata(client);
+ int rc = 0, retry_cnt = 0, temp_reg;
+ /* power on the device */
+ if (ts->pdata->power_on) {
+ rc = ts->pdata->power_on(1);
+ if (rc) {
+ pr_err("%s: Unable to power on the device\n", __func__);
+ goto error_dev_setup;
+ }
+ }
+
+ /* read one byte to make sure i2c device exists */
+ if (ts->device_id == rm3110x)
+ temp_reg = 0x01;
+ else if (ts->device_id == rm31100)
+ temp_reg = 0x00;
+ else
+ temp_reg = 0x05;
+
+ rc = rm31100_ts_read_reg_u8(client, temp_reg);
+ if (rc < 0) {
+ dev_err(&client->dev, "i2c sanity check failed\n");
+ goto error_power_on;
+ }
+
+ rc = rm31100_ts_init_ts(client, ts);
+ if (rc < 0) {
+ dev_err(&client->dev, "rm31100_ts init failed\n");
+ goto error_mutex_destroy;
+ }
+
+ if (ts->pdata->resout_gpio < 0)
+ goto config_irq_gpio;
+
+ /* configure touchscreen reset out gpio */
+ rc = gpio_request(ts->pdata->resout_gpio, "rm31100_resout_gpio");
+ if (rc) {
+ pr_err("%s: unable to request gpio %d\n",
+ __func__, ts->pdata->resout_gpio);
+ goto error_uninit_ts;
+ }
+
+ rc = gpio_direction_output(ts->pdata->resout_gpio, 0);
+ if (rc) {
+ pr_err("%s: unable to set direction for gpio %d\n",
+ __func__, ts->pdata->resout_gpio);
+ goto error_resout_gpio_dir;
+ }
+ /* reset gpio stabilization time */
+ msleep(20);
+
+ return 0;
+error_resout_gpio_dir:
+ if (ts->pdata->resout_gpio >= 0)
+ gpio_free(ts->pdata->resout_gpio);
+error_uninit_ts:
+ input_unregister_device(ts->input);
+ kfree(ts->touch_data);
+error_mutex_destroy:
+ mutex_destroy(&ts->sus_lock);
+ mutex_destroy(&ts->access_lock);
+error_power_on:
+/* if (ts->pdata->power_on)
+ ts->pdata->power_on(0);*/
+error_dev_setup:
+ if (ts->pdata->dev_setup)
+ ts->pdata->dev_setup(0);
+
+}
+
+static void rm_initialize_async(void *data, async_cookie_t cookie)
+{
+ struct rm31100_ts *ts = data;
+ struct i2c_client *client = ts->client;
+ unsigned long irqflags;
+ int err = 0;
+
+ mutex_lock(&ts->sus_lock);
+
+ err = rm31100_initialize(client);
+ if (err < 0) {
+ dev_err(&client->dev, "probe failed! unbind device.\n");
+ goto error_free_mem;
+ }
+
+ err = rm_input_dev_create(ts);
+ if (err) {
+ dev_err(&client->dev, "%s crated failed, %d\n", __func__, err);
+ goto err_release;
+ }
+
+ irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING;
+
+ err = request_threaded_irq(ts->pen_irq, NULL,
+ rm31100_ts_irq,
+ irqflags | IRQF_ONESHOT,
+ ts->client->dev.driver->name, ts);
+ if (err) {
+ dev_err(&client->dev, "Failed to register interrupt\n");
+ goto err_release;
+ }
+
+ mutex_unlock(&ts->sus_lock);
+
+ return;
+err_release:
+error_free_mem:
+ kfree(ts);
+ mutex_unlock(&ts->sus_lock);
+ rm31100_ts_remove(client);
+ return;
+}
+
+
+/*static int __devinit rm31100_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)*/
+static int rm31100_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct rm31100_ts *ts;
+ struct rm3110x_ts_platform_data *pdata = client->dev.platform_data;
+ int rc/*, temp_reg*/;
+
+ if (!pdata) {
+ dev_err(&client->dev, "platform data is required!\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ dev_err(&client->dev, "I2C functionality not supported\n");
+ return -EIO;
+ }
+ /* Make sure there is something at this address */
+ if (i2c_smbus_xfer(client->adapter, client->addr, 0,
+ I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0)
+ return -ENODEV;
+
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+ pts = ts;
+
+ /* Enable runtime PM ops, start in ACTIVE mode */
+ rc = pm_runtime_set_active(&client->dev);
+ if (rc < 0)
+ dev_warn(&client->dev, "unable to set runtime pm state\n");
+ pm_runtime_enable(&client->dev);
+
+ ts->client = client;
+ ts->pdata = pdata;
+ i2c_set_clientdata(client, ts);
+ ts->device_id = id->driver_data;
+
+ if (ts->pdata->dev_setup) {
+ rc = ts->pdata->dev_setup(1);
+ if (rc < 0) {
+ dev_err(&client->dev, "dev setup failed\n");
+ goto error_touch_data_alloc;
+ }
+ }
+
+
+ ts->is_suspended = false;
+ ts->int_pending = false;
+ mutex_init(&ts->sus_lock);
+ mutex_init(&ts->access_lock);
+
+ async_schedule(rm_initialize_async, ts);
+
+ device_init_wakeup(&client->dev, ts->pdata->wakeup);
+ return 0;
+error_reg_misc_dev:
+error_req_irq_fail:
+
+error_resout_gpio_dir:
+ if (ts->pdata->resout_gpio >= 0)
+ gpio_free(ts->pdata->resout_gpio);
+error_uninit_ts:
+ input_unregister_device(ts->input);
+ kfree(ts->touch_data);
+error_mutex_destroy:
+ mutex_destroy(&ts->sus_lock);
+ mutex_destroy(&ts->access_lock);
+error_power_on:
+/* if (ts->pdata->power_on)
+ ts->pdata->power_on(0);*/
+error_dev_setup:
+ if (ts->pdata->dev_setup)
+ ts->pdata->dev_setup(0);
+error_touch_data_alloc:
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_disable(&client->dev);
+ kfree(ts);
+ return rc;
+}
+
+/*static int __devexit RM31100_ts_remove(struct i2c_client *client)*/
+static int __exit rm31100_ts_remove(struct i2c_client *client)
+{
+ struct rm31100_ts *ts = i2c_get_clientdata(client);
+
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_disable(&client->dev);
+
+ device_init_wakeup(&client->dev, 0);
+ free_irq(ts->pen_irq, ts);
+
+ gpio_free(ts->pdata->irq_gpio);
+
+ if (ts->pdata->resout_gpio >= 0)
+ gpio_free(ts->pdata->resout_gpio);
+ input_unregister_device(ts->input);
+
+ mutex_destroy(&ts->sus_lock);
+ mutex_destroy(&ts->access_lock);
+
+ if (ts->pdata->power_on)
+ ts->pdata->power_on(0);
+
+ if (ts->pdata->dev_setup)
+ ts->pdata->dev_setup(0);
+
+ kfree(ts->touch_data);
+ kfree(ts);
+
+ return 0;
+}
+
+static const struct i2c_device_id rm31100_ts_id[] = {
+ {"RM31100", rm31100},
+ {"RM3110x", rm3110x},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, RM31100_ts_id);
+
+
+static struct i2c_driver rm31100_ts_driver = {
+ .driver = {
+ .name = "raydium_ts",/*rm31100_ts*/
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &rm31100_ts_pm_ops,
+#endif
+ },
+ .probe = rm31100_ts_probe,
+ /*.remove = __devexit_p(RM31100_ts_remove),*/
+ .remove = __exit_p(rm31100_ts_remove),
+ .id_table = rm31100_ts_id,
+};
+
+static int __init rm31100_ts_init(void)
+{
+ int rc;
+ int rc2;
+
+ rc = i2c_add_driver(&rm31100_ts_driver);
+
+ rc2 = driver_create_file(&rm31100_ts_driver.driver,
+ &driver_attr_myAttr);
+
+ return rc;
+}
+/* Making this as late init to avoid power fluctuations
+ * during LCD initialization.
+ */
+late_initcall(RM31100_ts_init);
+
+static void __exit rm31100_ts_exit(void)
+{
+ return i2c_del_driver(&RM31100_ts_driver);
+}
+module_exit(RM31100_ts_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("rm31100-rm3110x touchscreen controller driver");
+MODULE_AUTHOR("Raydium");
+MODULE_ALIAS("platform:rm31100_ts");
diff --git a/include/linux/input/rm31100_ts.h b/include/linux/input/rm31100_ts.h
new file mode 100644
index 0000000..2397436
--- /dev/null
+++ b/include/linux/input/rm31100_ts.h
@@ -0,0 +1,60 @@
+/* Header file for:
+ * Raydium rm31100 Prototype touchscreen driver.
+ *
+ * Copyright (C) 2012, Raydium Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Raydium reserves the right to make changes without further notice
+ * to the materials described herein. Raydium does not assume any
+ * liability arising out of the application described herein.
+ *
+ * Contact Raydium Semiconductor at www.rad-ic.com
+ *
+ * History:
+ * (C) 2012 Raydium - Update for GPL distribution
+ * (C) 2009 Enea - Original prototype
+ *
+ */
+#ifndef __RM3110xTS_H__
+#define __RM3110xTS_H__
+
+
+/* rm3110x platform data
+ */
+struct rm3110x_ts_platform_data {
+ int (*power_on)(int on);
+ int (*dev_setup)(bool on);
+ const char *ts_name;
+ u32 dis_min_x; /* display resoltion */
+ u32 dis_max_x;
+ u32 dis_min_y;
+ u32 dis_max_y;
+ u32 min_touch; /* no.of touches supported */
+ u32 max_touch;
+ u32 min_tid; /* track id */
+ u32 max_tid;
+ u32 min_width;/* size of the finger */
+ u32 max_width;
+ u32 res_x; /* TS resolution */
+ u32 res_y;
+ u32 swap_xy;
+ u32 flags;
+ u16 invert_x;
+ u16 invert_y;
+ u8 nfingers;
+ u32 irq_gpio;
+ int resout_gpio;
+ bool wakeup;
+ u32 irq_cfg;
+};
+
+#endif
--
2.1.2
^ permalink raw reply related
* Re: [PATCH v4 0/6] Touchscreen performance related fixes
From: Vignesh R @ 2014-12-01 10:29 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Benoit Cousson, Tony Lindgren, Russell King, Jonathan Cameron,
Hartmut Knaack, richardcochran, Dmitry Torokhov, Lee Jones,
Lars-Peter Clausen, Peter Meerwald, Samuel Ortiz, Felipe Balbi,
Brad Griffis, Sanjeev Sharma, Paul Gortmaker, Jan Kardell,
devicetree, linux-kernel, linux-omap
In-Reply-To: <547C3C19.5090501@linutronix.de>
Hi,
On Monday 01 December 2014 03:29 PM, Sebastian Andrzej Siewior wrote:
> On 12/01/2014 10:53 AM, Vignesh R wrote:
>> Hi Sebastian,
>
> Hi Vignesh,
>
>> I fixed the issue that was triggering the WARN_ON(). I think it would be
>> better if you tested these patches, before I posted them on the
>> mainline. I don't want to clutter the list with too main versions. Here
>> is the link to the tree with latest changes:
>
> awesome, thank you.
>
>>
>> git clone -b tsc-devel git://git.ti.com/kernel/tsc-adc.git
>> (tsc-devel branch)
>
> I will and let you know.
>
>> Please test the above tree and let me know the results.
>> I will post new version(v5) if there are no issues wrt IIO and TSC
>> working at the same time.
>
> Cool. Were you able to get in touch with someone who has a 5-wire touch?
I have asked Jeff Lance to verify 5-wire touch.
Regards
Vignesh
^ permalink raw reply
* [RFC] Input: Remove unused BUS IDs
From: Jarkko Nikula @ 2014-12-01 10:51 UTC (permalink / raw)
To: linux-input; +Cc: Dmitry Torokhov, Dmitry Torokhov, Jarkko Nikula
There are a few BUS IDs that are not used anywhere in kernel tree:
- BUS_ISAPNP
Has no changes or use in kernel git history
- BUS_GSC
Was added by commit 6ab0f5cd3644 ("[PARISC] Update parisc specific input
code from parisc tree") but never used
- BUS_ATARI
Became unused after commit 6615c5b25e0b ("m68k: Atari input drivers
cleanup")
Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
I'm not familiar with the input and don't know is there use for these in
userspace. Therefore I didn't sort these IDs after removal.
---
include/uapi/linux/input.h | 3 ---
1 file changed, 3 deletions(-)
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index 1874ebe9ac1e..39d535034169 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -940,7 +940,6 @@ struct input_keymap_entry {
#define ID_VERSION 3
#define BUS_PCI 0x01
-#define BUS_ISAPNP 0x02
#define BUS_USB 0x03
#define BUS_HIL 0x04
#define BUS_BLUETOOTH 0x05
@@ -956,8 +955,6 @@ struct input_keymap_entry {
#define BUS_ADB 0x17
#define BUS_I2C 0x18
#define BUS_HOST 0x19
-#define BUS_GSC 0x1A
-#define BUS_ATARI 0x1B
#define BUS_SPI 0x1C
/*
--
2.1.3
^ permalink raw reply related
* Re: [RFC] Input: Remove unused BUS IDs
From: Marcel Holtmann @ 2014-12-01 10:57 UTC (permalink / raw)
To: Jarkko Nikula; +Cc: linux-input, Dmitry Torokhov, Dmitry Torokhov
In-Reply-To: <1417431087-30330-1-git-send-email-jarkko.nikula@linux.intel.com>
Hi Jarkko,
> There are a few BUS IDs that are not used anywhere in kernel tree:
>
> - BUS_ISAPNP
> Has no changes or use in kernel git history
> - BUS_GSC
> Was added by commit 6ab0f5cd3644 ("[PARISC] Update parisc specific input
> code from parisc tree") but never used
> - BUS_ATARI
> Became unused after commit 6615c5b25e0b ("m68k: Atari input drivers
> cleanup")
>
> Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
> ---
> I'm not familiar with the input and don't know is there use for these in
> userspace. Therefore I didn't sort these IDs after removal.
actually /dev/uinput can still use these values if it wants to.
Regards
Marcel
^ permalink raw reply
* [PATCH v2] Drivers: input: mousedev.c: Fixed trailing statement on the next line
From: Athira Sharikkal @ 2014-12-01 12:36 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: linux-input, linux-kernel, Athira Sharikkal
Fixed checkpatch error:
trailing statements should be on next line
Signed-off-by: Athira Sharikkal <athirasnamby@gmail.com>
---
v2: corrected indentation
drivers/input/mousedev.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index b604564..28988f5 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -248,7 +248,8 @@ static void mousedev_key_event(struct mousedev *mousedev,
case BTN_4:
case BTN_EXTRA: index = 4; break;
- default: return;
+ default:
+ return;
}
if (value) {
--
1.9.1
^ permalink raw reply related
* [PATCH 2/2] HID: wacom: fix freeze on open when autosuspend is on
From: Benjamin Tissoires @ 2014-12-01 16:52 UTC (permalink / raw)
To: Jiri Kosina, Dmitry Torokhov, Jason Gerecke, Ping Cheng,
Hans Spath
Cc: linux-input, linux-kernel
In-Reply-To: <1417452760-2763-1-git-send-email-benjamin.tissoires@redhat.com>
Since the conversion from USB to HID (in v3.17), some people reported a
freeze on boot with the wacom driver. Hans managed to get a stacktrace:
[ 240.272331] Call Trace:
[ 240.272338] [<ffffffff813de7b9>] ? usb_hcd_submit_urb+0xa9/0xb10
[ 240.272347] [<ffffffff81555579>] schedule+0x29/0x70
[ 240.272355] [<ffffffff815559e6>] schedule_preempt_disabled+0x16/0x20
[ 240.272363] [<ffffffff81557365>] __mutex_lock_slowpath+0xe5/0x230
[ 240.272372] [<ffffffff815574c7>] mutex_lock+0x17/0x30
[ 240.272380] [<ffffffffa063c1d2>] wacom_resume+0x22/0x50 [wacom]
[ 240.272396] [<ffffffffa01aea8a>] hid_resume_common+0xba/0x110 [usbhid]
[ 240.272404] [<ffffffff813e5890>] ? usb_runtime_suspend+0x80/0x80
[ 240.272417] [<ffffffffa01aeb1d>] hid_resume+0x3d/0x70 [usbhid]
[ 240.272425] [<ffffffff813e44a6>] usb_resume_interface.isra.6+0xb6/0x120
[ 240.272432] [<ffffffff813e4774>] usb_resume_both+0x74/0x140
[ 240.272439] [<ffffffff813e58aa>] usb_runtime_resume+0x1a/0x20
[ 240.272446] [<ffffffff813b1912>] __rpm_callback+0x32/0x70
[ 240.272453] [<ffffffff813b1976>] rpm_callback+0x26/0xa0
[ 240.272460] [<ffffffff813b2d71>] rpm_resume+0x4b1/0x690
[ 240.272468] [<ffffffff812ab992>] ? radix_tree_lookup_slot+0x22/0x50
[ 240.272475] [<ffffffff813b2c1a>] rpm_resume+0x35a/0x690
[ 240.272482] [<ffffffff8116e9c9>] ? zone_statistics+0x89/0xa0
[ 240.272489] [<ffffffff813b2f90>] __pm_runtime_resume+0x40/0x60
[ 240.272497] [<ffffffff813e4272>] usb_autopm_get_interface+0x22/0x60
[ 240.272509] [<ffffffffa01ae8d9>] usbhid_open+0x59/0xe0 [usbhid]
[ 240.272517] [<ffffffffa063ac85>] wacom_open+0x35/0x50 [wacom]
[ 240.272525] [<ffffffff813f37b9>] input_open_device+0x79/0xa0
[ 240.272534] [<ffffffffa048d1c1>] evdev_open+0x1b1/0x200 [evdev]
[ 240.272543] [<ffffffff811c899e>] chrdev_open+0xae/0x1f0
[ 240.272549] [<ffffffff811c88f0>] ? cdev_put+0x30/0x30
[ 240.272556] [<ffffffff811c17e2>] do_dentry_open+0x1d2/0x320
[ 240.272562] [<ffffffff811c1cd1>] finish_open+0x31/0x50
[ 240.272571] [<ffffffff811d2202>] do_last.isra.36+0x652/0xe50
[ 240.272579] [<ffffffff811d2ac7>] path_openat+0xc7/0x6f0
[ 240.272586] [<ffffffff811cf012>] ? final_putname+0x22/0x50
[ 240.272594] [<ffffffff811d42d2>] ? user_path_at_empty+0x72/0xd0
[ 240.272602] [<ffffffff811d43fd>] do_filp_open+0x4d/0xc0
[...]
So here, wacom_open is called, and then wacom_resume is called by the
PM system. However, wacom_open already took the lock when wacom_resume
tries to get it. Freeze.
A little bit of history shows that this already happened in the past
- commit f6cd378372bf ("Input: wacom - fix runtime PM related deadlock"),
and the solution was to call first the PM function before taking the lock.
The lock was introduced in commit commit e722409445fb ("Input: wacom -
implement suspend and autosuspend") when the autosuspend feature has
been added. Given that usbhid already takes care of this very same
locking between suspend/resume, I think we can simply kill the lock
in open/close.
The lock is now used also with LEDs, so we can not remove it completely.
Reported-by: Hans Spath <inbox-546@hans-spath.de>
Tested-by: Hans Spath <inbox-546@hans-spath.de>
CC: stable@vger.kernel.org # v3.17+
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/wacom_sys.c | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index eb55316..17bf52b 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -70,22 +70,15 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
static int wacom_open(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
- int retval;
-
- mutex_lock(&wacom->lock);
- retval = hid_hw_open(wacom->hdev);
- mutex_unlock(&wacom->lock);
- return retval;
+ return hid_hw_open(wacom->hdev);
}
static void wacom_close(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
- mutex_lock(&wacom->lock);
hid_hw_close(wacom->hdev);
- mutex_unlock(&wacom->lock);
}
/*
--
2.1.0
^ permalink raw reply related
* [PATCH 1/2] HID: wacom: re-add accidentally dropped Lenovo PID
From: Benjamin Tissoires @ 2014-12-01 16:52 UTC (permalink / raw)
To: Jiri Kosina, Dmitry Torokhov, Jason Gerecke, Ping Cheng,
Hans Spath
Cc: linux-input, linux-kernel
Dropped in the following commit:
commit a3e6f6543d19 ("Input: wacom - keep wacom_ids ordered")
drivers/input/tablet/wacom_wac.c | 79 +++++++++++++++++++++++++++++++++++++++----------------------------------------
1 file changed, 39 insertions(+), 40 deletions(-)
> - { USB_DEVICE_LENOVO(0x6004) },
Reported-by: Hans Spath <inbox-546@hans-spath.de>
CC: stable@vger.kernel.org # v3.17+
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/wacom_wac.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 1468f00..2b8d1f8 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -3046,6 +3046,7 @@ const struct hid_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x4004) },
{ USB_DEVICE_WACOM(0x5000) },
{ USB_DEVICE_WACOM(0x5002) },
+ { USB_DEVICE_LENOVO(0x6004) },
{ USB_DEVICE_WACOM(HID_ANY_ID) },
{ }
--
2.1.0
^ permalink raw reply related
* Re: [PATCH] hid: export hid_report_len as an inline function in hid.h
From: Benjamin Tissoires @ 2014-12-01 18:22 UTC (permalink / raw)
To: Mathieu Magnaudet
Cc: Jiri Kosina, Benjamin Tissoires, linux-input,
linux-kernel@vger.kernel.org
In-Reply-To: <1417100556-7096-1-git-send-email-mathieu.magnaudet@enac.fr>
On Thu, Nov 27, 2014 at 10:02 AM, Mathieu Magnaudet
<mathieu.magnaudet@gmail.com> wrote:
> in several hid drivers it is necessary to calculate the length
> of an hid_report. This patch exports the existing static function
> hid_report_len of hid-core.c as an inline function in hid.h
>
> Signed-off-by: Mathieu Magnaudet <mathieu.magnaudet@enac.fr>
> ---
IIRC, there are a few more custom report length computations
throughout the HID tree. They are not straightforward to convert, so I
think we have a pretty good start here.
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
Thanks Mathieu!
Cheers,
Benjamin
> drivers/hid/hid-core.c | 6 ------
> drivers/hid/hid-input.c | 2 +-
> drivers/hid/hid-multitouch.c | 2 +-
> drivers/hid/usbhid/hid-core.c | 3 +--
> drivers/hid/wacom_sys.c | 8 +-------
> include/linux/hid.h | 11 +++++++++++
> 6 files changed, 15 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index 0ad2ac0..c3d0ac1 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -1282,12 +1282,6 @@ void hid_output_report(struct hid_report *report, __u8 *data)
> }
> EXPORT_SYMBOL_GPL(hid_output_report);
>
> -static int hid_report_len(struct hid_report *report)
> -{
> - /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
> - return ((report->size - 1) >> 3) + 1 + (report->id > 0);
> -}
> -
> /*
> * Allocator for buffer that is going to be passed to hid_output_report()
> */
> diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
> index be3eba8..e0a0f06 100644
> --- a/drivers/hid/hid-input.c
> +++ b/drivers/hid/hid-input.c
> @@ -1215,7 +1215,7 @@ static void hidinput_led_worker(struct work_struct *work)
> return hid->ll_driver->request(hid, report, HID_REQ_SET_REPORT);
>
> /* fall back to generic raw-output-report */
> - len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
> + len = hid_report_len(report);
> buf = hid_alloc_report_buf(report, GFP_KERNEL);
> if (!buf)
> return;
> diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
> index 683cda6..f65e78b 100644
> --- a/drivers/hid/hid-multitouch.c
> +++ b/drivers/hid/hid-multitouch.c
> @@ -827,7 +827,7 @@ static void mt_set_input_mode(struct hid_device *hdev)
> r = re->report_id_hash[td->inputmode];
> if (r) {
> if (cls->quirks & MT_QUIRK_FORCE_GET_FEATURE) {
> - report_len = ((r->size - 1) >> 3) + 1 + (r->id > 0);
> + report_len = hid_report_len(r);
> buf = hid_alloc_report_buf(r, GFP_KERNEL);
> if (!buf) {
> hid_err(hdev, "failed to allocate buffer for report\n");
> diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
> index 04e34b9..bfbe1be 100644
> --- a/drivers/hid/usbhid/hid-core.c
> +++ b/drivers/hid/usbhid/hid-core.c
> @@ -340,8 +340,7 @@ static int hid_submit_out(struct hid_device *hid)
> report = usbhid->out[usbhid->outtail].report;
> raw_report = usbhid->out[usbhid->outtail].raw_report;
>
> - usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) +
> - 1 + (report->id > 0);
> + usbhid->urbout->transfer_buffer_length = hid_report_len(report);
> usbhid->urbout->dev = hid_to_usb_dev(hid);
> if (raw_report) {
> memcpy(usbhid->outbuf, raw_report,
> diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
> index eb55316..358880b 100644
> --- a/drivers/hid/wacom_sys.c
> +++ b/drivers/hid/wacom_sys.c
> @@ -1328,12 +1328,6 @@ static void wacom_calculate_res(struct wacom_features *features)
> features->unitExpo);
> }
>
> -static int wacom_hid_report_len(struct hid_report *report)
> -{
> - /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
> - return ((report->size - 1) >> 3) + 1 + (report->id > 0);
> -}
> -
> static size_t wacom_compute_pktlen(struct hid_device *hdev)
> {
> struct hid_report_enum *report_enum;
> @@ -1343,7 +1337,7 @@ static size_t wacom_compute_pktlen(struct hid_device *hdev)
> report_enum = hdev->report_enum + HID_INPUT_REPORT;
>
> list_for_each_entry(report, &report_enum->report_list, list) {
> - size_t report_size = wacom_hid_report_len(report);
> + size_t report_size = hid_report_len(report);
> if (report_size > size)
> size = report_size;
> }
> diff --git a/include/linux/hid.h b/include/linux/hid.h
> index d585d02..06c4607 100644
> --- a/include/linux/hid.h
> +++ b/include/linux/hid.h
> @@ -1087,6 +1087,17 @@ static inline void hid_hw_wait(struct hid_device *hdev)
> hdev->ll_driver->wait(hdev);
> }
>
> +/**
> + * hid_report_len - calculate the report length
> + *
> + * @report: the report we want to know the length
> + */
> +static inline int hid_report_len(struct hid_report *report)
> +{
> + /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
> + return ((report->size - 1) >> 3) + 1 + (report->id > 0);
> +}
> +
> int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
> int interrupt);
>
> --
> 1.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] hid: export hid_report_len as an inline function in hid.h
From: David Herrmann @ 2014-12-01 19:04 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Mathieu Magnaudet, Jiri Kosina, Benjamin Tissoires, linux-input,
linux-kernel@vger.kernel.org
In-Reply-To: <CAN+gG=GZXNABPzFA=ivfoJDzd-=2X7t7FoQDGfo6g1b4bfwihA@mail.gmail.com>
Hi
On Mon, Dec 1, 2014 at 7:22 PM, Benjamin Tissoires
<benjamin.tissoires@gmail.com> wrote:
> On Thu, Nov 27, 2014 at 10:02 AM, Mathieu Magnaudet
> <mathieu.magnaudet@gmail.com> wrote:
>> in several hid drivers it is necessary to calculate the length
>> of an hid_report. This patch exports the existing static function
>> hid_report_len of hid-core.c as an inline function in hid.h
>>
>> Signed-off-by: Mathieu Magnaudet <mathieu.magnaudet@enac.fr>
>> ---
>
> IIRC, there are a few more custom report length computations
> throughout the HID tree. They are not straightforward to convert, so I
> think we have a pretty good start here.
>
> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
I fully agree!
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
Thanks
David
^ permalink raw reply
* Re: [PATCHv3 1/1] HID: add BETOP game controller force feedback support
From: Jiri Kosina @ 2014-12-01 20:11 UTC (permalink / raw)
To: Huang Bo; +Cc: linux-input, linux-kernel
In-Reply-To: <5477CDD4.8000908@163.com>
On Fri, 28 Nov 2014, Huang Bo wrote:
> On 11/27/2014 05:05 PM, Jiri Kosina wrote:
> > except ...
> thanks firstly.
> 1. tested the BETOP2185 gamecontroller, it really not need it.
> 2. check with engineers of Betop, they design only one report descriptor.
>
> so I modify it.
Thanks, but please put the comment into the code (jus before you are
zeroing the fields), so that it's immediately obvious to everybody who is
reading the code.
Other than that, I am OK with the patch and will be applying it once you
resend it with the comments added.
Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH] hid: export hid_report_len as an inline function in hid.h
From: Jiri Kosina @ 2014-12-01 20:36 UTC (permalink / raw)
To: Mathieu Magnaudet; +Cc: Benjamin Tissoires, linux-input, linux-kernel
In-Reply-To: <1417100556-7096-1-git-send-email-mathieu.magnaudet@enac.fr>
On Thu, 27 Nov 2014, Mathieu Magnaudet wrote:
> in several hid drivers it is necessary to calculate the length
> of an hid_report. This patch exports the existing static function
> hid_report_len of hid-core.c as an inline function in hid.h
>
> Signed-off-by: Mathieu Magnaudet <mathieu.magnaudet@enac.fr>
Applied, thanks.
[ ... snip ... ]
> diff --git a/include/linux/hid.h b/include/linux/hid.h
> index d585d02..06c4607 100644
> --- a/include/linux/hid.h
> +++ b/include/linux/hid.h
> @@ -1087,6 +1087,17 @@ static inline void hid_hw_wait(struct hid_device *hdev)
> hdev->ll_driver->wait(hdev);
> }
>
> +/**
> + * hid_report_len - calculate the report length
> + *
> + * @report: the report we want to know the length
> + */
> +static inline int hid_report_len(struct hid_report *report)
> +{
> + /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
> + return ((report->size - 1) >> 3) + 1 + (report->id > 0);
BTW this makes me -- being the person resposible for that ugly calculation
-- wonder whether we shouldn't, in the name of readability, just drop the
comment and make the code look that way instead.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH] driver: input: touchscreen: add Raydium i2c touchscreen driver
From: Benson Leung @ 2014-12-01 21:03 UTC (permalink / raw)
To: jeffrey.lin
Cc: Dmitry Torokhov, Henrik Rydberg, shc_work, lee.jones,
charliemooney, KP.li, linux-kernel@vger.kernel.org,
linux-input@vger.kernel.org, jeffrey.lin
In-Reply-To: <1417429031-4576-1-git-send-email-jeffrey.lin@rad-ic.com>
On Mon, Dec 1, 2014 at 2:17 AM, jeffrey.lin <yajohn@gmail.com> wrote:
> From: "jeffrey.lin" <jeffrey.lin@rad-ic.com>
>
> This patch is porting Raydium I2C touch driver. Developer can enable
> raydium touch driver by modifying define "CONFIG_TOUCHSCREEN_RM_TS".
>
> Change-Id: I5f33cfdf0e895de6e7d535c11dd4b3ce8b49fa48
Once again, please remove this bit of Gerrit change-id from your patch
submissions in the future.
> Signed-off-by: jeffrey.lin@rad-ic.com
--
Benson Leung
Software Engineer, Chrom* OS
bleung@chromium.org
^ permalink raw reply
* [PATCH] HID: wacom - add defines for new Cintiq and DTU outbound tracking
From: Ping Cheng @ 2014-12-01 21:44 UTC (permalink / raw)
To: jkosina; +Cc: linux-input, Ping Cheng
There are screen to tablet offsets for newer Cintiq and DTU models.
These offsets serve as outbound tracking for those display tablets.
Use defines instead of hardcoded numbers for the offsets.
Signed-off-by: Ping Cheng <pingc@wacom.com>
---
drivers/hid/wacom_wac.c | 37 ++++++++++++++++++++++++++-----------
1 file changed, 26 insertions(+), 11 deletions(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 9565d31..a56660b 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -25,6 +25,10 @@
#define WACOM_INTUOS_RES 100
#define WACOM_INTUOS3_RES 200
+/* Newer Cintiq and DTU have an offset between tablet and screen areas */
+#define WACOM_DTU_OFFSET 200
+#define WACOM_CINTIQ_OFFSET 400
+
/*
* Scale factor relating reported contact size to logical contact area.
* 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo
@@ -2678,10 +2682,12 @@ static const struct wacom_features wacom_features_0x317 =
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0xF4 =
{ "Wacom Cintiq 24HD", 104280, 65400, 2047, 63,
- WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
+ WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
static const struct wacom_features wacom_features_0xF8 =
{ "Wacom Cintiq 24HD touch", 104280, 65400, 2047, 63, /* Pen */
- WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
+ WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
static const struct wacom_features wacom_features_0xF6 =
{ "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */
@@ -2698,7 +2704,8 @@ static const struct wacom_features wacom_features_0xC6 =
WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x304 =
{ "Wacom Cintiq 13HD", 59352, 33648, 1023, 63,
- WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
+ WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
static const struct wacom_features wacom_features_0xC7 =
{ "Wacom DTU1931", 37832, 30305, 511, 0,
PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2711,13 +2718,16 @@ static const struct wacom_features wacom_features_0xF0 =
DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xFB =
{ "Wacom DTU1031", 22096, 13960, 511, 0,
- DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
static const struct wacom_features wacom_features_0x57 =
{ "Wacom DTK2241", 95640, 54060, 2047, 63,
- DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
+ DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
static const struct wacom_features wacom_features_0x59 = /* Pen */
{ "Wacom DTH2242", 95640, 54060, 2047, 63,
- DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
+ DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
static const struct wacom_features wacom_features_0x5D = /* Touch */
{ "Wacom DTH2242", .type = WACOM_24HDT,
@@ -2725,13 +2735,16 @@ static const struct wacom_features wacom_features_0x5D = /* Touch */
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0xCC =
{ "Wacom Cintiq 21UX2", 87000, 65400, 2047, 63,
- WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
+ WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
static const struct wacom_features wacom_features_0xFA =
{ "Wacom Cintiq 22HD", 95640, 54060, 2047, 63,
- WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
+ WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
static const struct wacom_features wacom_features_0x5B =
{ "Wacom Cintiq 22HDT", 95640, 54060, 2047, 63,
- WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
+ WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };
static const struct wacom_features wacom_features_0x5E =
{ "Wacom Cintiq 22HDT", .type = WACOM_24HDT,
@@ -2877,7 +2890,8 @@ static const struct wacom_features wacom_features_0x6004 =
TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x307 =
{ "Wacom ISDv5 307", 59352, 33648, 2047, 63,
- CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
+ CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 };
static const struct wacom_features wacom_features_0x309 =
{ "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */
@@ -2885,7 +2899,8 @@ static const struct wacom_features wacom_features_0x309 =
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0x30A =
{ "Wacom ISDv5 30A", 59352, 33648, 2047, 63,
- CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
+ CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30C };
static const struct wacom_features wacom_features_0x30C =
{ "Wacom ISDv5 30C", .type = WACOM_24HDT, /* Touch */
--
1.9.1
^ permalink raw reply related
* [PATCH] input/speaker: additional clicks and tones for future accessibility
From: Karl Dahlke @ 2014-12-02 5:17 UTC (permalink / raw)
To: dmitry.torokhov, vojtech; +Cc: linux-input
From: Karl Dahlke <eklhad@gmail.com>
Add clicks, tones, and tone sequences to the pc speaker.
The speaker driver can play a tone at a specified frequency,
or the standard control G bell,
which is a special case of TONE at 1000 hz 0.1 seconds.
Add kd_mkpulse() to generate a soft click.
This is introduced to support accessibility modules and adapters in the future.
It is a means to an end.
With this function in place, a module can easily provide soft clicks,
i.e. audible feedback, whenever a key is depressed,
or when that keystroke is echoed on screen.
This allows a blind user, for example, to have rapid feedback while typing,
even if he is, at the same time, listening to text that is already on screen.
It is faster and more convenient than having characters echoed verbally.
And it works all the time, even if speech or braille is not working
for whatever reason.
Also add the function kd_mknotes,
which plays a series of tones in the background.
Of course this can already be done with kd_mksound and timers,
but why should everyone reinvent the wheel?
It is better to write the function once, properly, in the kernel,
and let modules use it thereafter.
Again, this is a means to an end.
Accessibility modules can generate rapid sequences of notes
to indicate various conditions, sometimes error conditions,
especially if speech or braille is not working.
These notes may be the only feedback the user has to diagnose the problem.
This may be useful to other developers in other situations as well.
Finally add kd_mksteps to run something like a chromatic scale,
from one frequency to another in specified steps.
The half-tone scale, with a step of 6%, starting at middle C, is approximately
kd_mksteps(260, 530, 6, 150);
Signed-off-by: Karl Dahlke <eklhad@gmail.com>
---
Built and tested on 3.17.4, the latest stable kernel.
--- a/drivers/input/misc/pcspkr.c 2014-12-02 00:10:43.970435660 -0500
+++ b/drivers/input/misc/pcspkr.c 2014-12-02 00:10:43.974436209 -0500
@@ -18,6 +18,8 @@
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/timex.h>
+#include <linux/delay.h>
+
#include <asm/io.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
@@ -25,25 +27,26 @@ MODULE_DESCRIPTION("PC Speaker beeper dr
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pcspkr");
-static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+/* Toggle the speaker, but not if a tone is sounding */
+static void speaker_toggle(void)
{
- unsigned int count = 0;
+ char c;
unsigned long flags;
- if (type != EV_SND)
- return -1;
-
- switch (code) {
- case SND_BELL: if (value) value = 1000;
- case SND_TONE: break;
- default: return -1;
+ raw_spin_lock_irqsave(&i8253_lock, flags);
+ c = inb_p(0x61);
+ if ((c&3) != 3) {
+ c &= 0xfe;
+ c ^= 2; /* toggle */
+ outb(c, 0x61);
}
+ raw_spin_unlock_irqrestore(&i8253_lock, flags);
+}
- if (value > 20 && value < 32767)
- count = PIT_TICK_RATE / value;
-
+static void speaker_sing(unsigned int count)
+{
+ unsigned long flags;
raw_spin_lock_irqsave(&i8253_lock, flags);
-
if (count) {
/* set command for counter 2, 2 byte write */
outb_p(0xB6, 0x43);
@@ -56,8 +59,44 @@ static int pcspkr_event(struct input_dev
/* disable counter 2 */
outb(inb_p(0x61) & 0xFC, 0x61);
}
-
raw_spin_unlock_irqrestore(&i8253_lock, flags);
+}
+
+static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+ unsigned int count;
+
+ if (type != EV_SND)
+ return -1;
+
+ switch (code) {
+ case SND_BELL:
+ if (value)
+ value = 1000;
+ /* fall through */
+
+ case SND_TONE:
+ count = 0;
+ if (value > 20 && value < 32767)
+ count = PIT_TICK_RATE / value;
+ speaker_sing(count);
+ break;
+
+ case SND_PULSE:
+ /* Don't hold the cpu for more than 1ms */
+ /* no reason for a pulse to ever be longer than that. */
+ if (value > 1000)
+ value = 1000;
+ /* if a pulse is too short it can't be heard anyways. */
+ if (value < 20)
+ break;
+ speaker_toggle();
+ udelay(value);
+ speaker_toggle();
+ break;
+
+ default: return -1;
+ }
return 0;
}
@@ -80,7 +119,8 @@ static int pcspkr_probe(struct platform_
pcspkr_dev->dev.parent = &dev->dev;
pcspkr_dev->evbit[0] = BIT_MASK(EV_SND);
- pcspkr_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+ pcspkr_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE) |
+ BIT_MASK(SND_PULSE);
pcspkr_dev->event = pcspkr_event;
err = input_register_device(pcspkr_dev);
--- a/drivers/tty/vt/keyboard.c 2014-12-02 00:10:43.978436759 -0500
+++ b/drivers/tty/vt/keyboard.c 2014-12-02 00:10:43.982437308 -0500
@@ -261,6 +261,213 @@ void kd_mksound(unsigned int hz, unsigne
}
EXPORT_SYMBOL(kd_mksound);
+static int kd_pulse_helper(struct input_handle *handle, void *data)
+{
+ unsigned int *width = data;
+ struct input_dev *dev = handle->dev;
+
+ if (*width == 0)
+ return 0;
+
+ if (test_bit(EV_SND, dev->evbit)) {
+ if (test_bit(SND_PULSE, dev->sndbit)) {
+ input_inject_event(handle, EV_SND, SND_PULSE, *width);
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/* the width of the pulse is in microseconds, must be between 20 and 1000 */
+void kd_mkpulse(unsigned int width)
+{
+ input_handler_for_each_handle(&kbd_handler, &width, kd_pulse_helper);
+}
+EXPORT_SYMBOL(kd_mkpulse);
+
+/*
+ * Push notes onto a sound fifo and play them via an asynchronous thread.
+ * kd_mksound is a single tone, but kd_mknotes is a series of notes.
+ * this is used primarily by the accessibility modules, to sound
+ * various alerts and conditions for blind users.
+ * This is particularly helpful when the adapter is not working,
+ * for whatever reason. These functions are central to the kernel,
+ * and do not depend on sound cards, loadable modules, etc.
+ * These notes can also alert a system administrator to conditions
+ * that warrant immediate attention.
+ * Each note is specified by 2 shorts. The first is the frequency in hurtz,
+ * and the second is the duration in hundredths of a second.
+ * A frequency of -1 is a rest.
+ * A frequency of 0 ends the list of notes.
+ */
+
+#define SF_LEN 64 /* length of sound fifo */
+static short sf_fifo[SF_LEN];
+static int sf_head, sf_tail;
+static DEFINE_RAW_SPINLOCK(soundfifo_lock);
+
+/* Pop the next sound out of the sound fifo. */
+static void pop_soundfifo(unsigned long);
+static DEFINE_TIMER(kd_mknotes_timer, pop_soundfifo, 0, 0);
+static void pop_soundfifo(unsigned long notUsed)
+{
+ unsigned long flags;
+ int freq, duration;
+ int i;
+ long jifpause;
+
+ raw_spin_lock_irqsave(&soundfifo_lock, flags);
+
+ i = sf_tail;
+ if (i == sf_head) {
+ freq = 0;
+ duration = 0;
+ } else {
+ freq = sf_fifo[i];
+ duration = sf_fifo[i + 1];
+ i += 2;
+ if (i == SF_LEN)
+ i = 0;
+ sf_tail = i;
+ }
+
+ raw_spin_unlock_irqrestore(&soundfifo_lock, flags);
+
+ if (freq == 0) {
+ /* turn off singing speaker */
+ kd_nosound(0);
+ return;
+ }
+
+ jifpause = msecs_to_jiffies(duration);
+ /* not sure of the rounding, if duration < HZ */
+ if (jifpause == 0)
+ jifpause = 1;
+ mod_timer(&kd_mknotes_timer, jiffies + jifpause);
+
+ if (freq < 0) {
+ /* This is a rest between notes */
+ kd_nosound(0);
+ } else {
+ input_handler_for_each_handle(&kbd_handler, &freq,
+ kd_sound_helper);
+ }
+}
+
+/* Push a string of notes into the sound fifo. */
+void kd_mknotes(const short *p)
+{
+ int i;
+ bool wake = false;
+ unsigned long flags;
+
+ if (*p == 0)
+ return; /* empty list */
+
+ raw_spin_lock_irqsave(&soundfifo_lock, flags);
+
+ i = sf_head;
+ if (i == sf_tail)
+ wake = true;
+
+ /* Copy shorts into the fifo, until the terminating zero. */
+ while (*p) {
+ sf_fifo[i++] = *p++;
+ sf_fifo[i++] = (*p++) * 10;
+ if (i == SF_LEN)
+ i = 0; /* wrap around */
+ if (i == sf_tail) {
+ /* fifo is full */
+ goto done;
+ }
+ sf_head = i;
+ }
+
+ /* try to add on a rest, to carry the last note through */
+ sf_fifo[i++] = -1;
+ sf_fifo[i++] = 10;
+ if (i == SF_LEN)
+ i = 0; /* wrap around */
+ if (i != sf_tail)
+ sf_head = i;
+
+done:
+ raw_spin_unlock_irqrestore(&soundfifo_lock, flags);
+
+ /* first sound, get things started. */
+ if (wake)
+ pop_soundfifo(0);
+}
+EXPORT_SYMBOL(kd_mknotes);
+
+/* Push an ascending or descending sequence of notes into the sound fifo.
+ * Step is a geometric factor on frequency, increase by x percent.
+ * 100% goes up by octaves, -50% goes down by octaves.
+ * 12% is a wholetone scale, while 6% is a chromatic scale.
+ * Duration is in milliseconds, for very fast frequency sweeps. But this
+ * is based on jiffies timing, so is subject to the resolution of HZ. */
+void kd_mksteps(int f1, int f2, int step, int duration)
+{
+ int i;
+ bool wake = false;
+ unsigned long flags;
+
+ /* are the parameters in range? */
+ if (step != (char)step)
+ return;
+ if (duration <= 0 || duration > 2000)
+ return;
+ if (f1 < 50 || f1 > 8000)
+ return;
+ if (f2 < 50 || f2 > 8000)
+ return;
+
+ /* avoid infinite loops */
+ if (step == 0 ||
+ (f1 < f2 && step < 0) ||
+ (f1 > f2 && step > 0))
+ return;
+
+ raw_spin_lock_irqsave(&soundfifo_lock, flags);
+
+ i = sf_head;
+ if (i == sf_tail)
+ wake = true;
+
+ /* Copy shorts into the fifo, until start reaches end */
+ while ((step > 0 && f1 < f2) || (step < 0 && f1 > f2)) {
+ sf_fifo[i++] = f1;
+ sf_fifo[i++] = duration;
+ if (i == SF_LEN)
+ i = 0; /* wrap around */
+ if (i == sf_tail) {
+ /* fifo is full */
+ goto done;
+ }
+ sf_head = i;
+ f1 = f1 * (100+step) / 100;
+ if (f1 < 50 || f1 > 8000)
+ break;
+ }
+
+ /* try to add on a rest, to carry the last note through */
+ sf_fifo[i++] = -1;
+ sf_fifo[i++] = 10;
+ if (i == SF_LEN)
+ i = 0; /* wrap around */
+ if (i != sf_tail)
+ sf_head = i;
+
+done:
+ raw_spin_unlock_irqrestore(&soundfifo_lock, flags);
+
+ /* first sound, get things started. */
+ if (wake)
+ pop_soundfifo(0);
+}
+EXPORT_SYMBOL(kd_mksteps);
+
/*
* Setting the keyboard rate.
*/
--- a/include/linux/vt_kern.h 2014-12-02 00:10:43.987437995 -0500
+++ b/include/linux/vt_kern.h 2014-12-02 00:10:43.990438407 -0500
@@ -28,6 +28,9 @@
#endif
extern void kd_mksound(unsigned int hz, unsigned int ticks);
+extern void kd_mkpulse(unsigned int width);
+extern void kd_mknotes(const short *p);
+extern void kd_mksteps(int freq1, int freq2, int step, int duration);
extern int kbd_rate(struct kbd_repeat *rep);
extern int fg_console, last_console, want_console;
--- a/include/uapi/linux/input.h 2014-12-02 00:10:43.994438956 -0500
+++ b/include/uapi/linux/input.h 2014-12-02 00:10:43.998439505 -0500
@@ -934,6 +934,7 @@ struct input_keymap_entry {
#define SND_CLICK 0x00
#define SND_BELL 0x01
#define SND_TONE 0x02
+#define SND_PULSE 0x03
#define SND_MAX 0x07
#define SND_CNT (SND_MAX+1)
^ permalink raw reply
* Re: [PATCHv4 1/1] HID: add BETOP game controller force feedback support
From: Huang Bo @ 2014-12-02 5:58 UTC (permalink / raw)
To: Jiri Kosina; +Cc: linux-input, linux-kernel
In-Reply-To: <alpine.LNX.2.00.1412012111020.2524@pobox.suse.cz>
[-- Attachment #1: Type: text/plain, Size: 8560 bytes --]
On 12/02/2014 04:11 AM, Jiri Kosina wrote:
> On Fri, 28 Nov 2014, Huang Bo wrote:
>
>> On 11/27/2014 05:05 PM, Jiri Kosina wrote:
>>> except ...
>> thanks firstly.
>> 1. tested the BETOP2185 gamecontroller, it really not need it.
>> 2. check with engineers of Betop, they design only one report descriptor.
>>
>> so I modify it.
> Thanks, but please put the comment into the code (jus before you are
> zeroing the fields), so that it's immediately obvious to everybody who is
> reading the code.
>
> Other than that, I am OK with the patch and will be applying it once you
> resend it with the comments added.
>
> Thanks,
>
From: Huang Bo <huangbobupt@163.com>
Adds force feedback support for BETOP USB game controllers.
These devices are mass produced in China.
Signed-off-by: Huang Bo <huangbobupt@163.com>
---
drivers/hid/Kconfig | 10 +++
drivers/hid/Makefile | 1 +
drivers/hid/hid-betopff.c | 160 +++++++++++++++++++++++++++++++++++++++++++++
drivers/hid/hid-core.c | 4 ++
drivers/hid/hid-ids.h | 5 ++
5 files changed, 180 insertions(+)
create mode 100644 drivers/hid/hid-betopff.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 4938bd3..3b4c47d 100755
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -146,6 +146,16 @@ config HID_BELKIN
---help---
Support for Belkin Flip KVM and Wireless keyboard.
+config HID_BETOP_FF
+ tristate "Betop Production Inc. force feedback support"
+ depends on USB_HID
+ select INPUT_FF_MEMLESS
+ ---help---
+ Say Y here if you want to enable force feedback support for devices by
+ BETOP Production Ltd.
+ Currently the following devices are known to be supported:
+ - BETOP 2185 PC & BFM MODE
+
config HID_CHERRY
tristate "Cherry Cymotion keyboard" if EXPERT
depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 4113999..edd4825 100755
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
+obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
diff --git a/drivers/hid/hid-betopff.c b/drivers/hid/hid-betopff.c
new file mode 100644
index 0000000..69cfc8d
--- /dev/null
+++ b/drivers/hid/hid-betopff.c
@@ -0,0 +1,160 @@
+/*
+ * Force feedback support for Betop based devices
+ *
+ * The devices are distributed under various names and the same USB device ID
+ * can be used in both adapters and actual game controllers.
+ *
+ * 0x11c2:0x2208 "BTP2185 BFM mode Joystick"
+ * - tested with BTP2185 BFM Mode.
+ *
+ * 0x11C0:0x5506 "BTP2185 PC mode Joystick"
+ * - tested with BTP2185 PC Mode.
+ *
+ * 0x8380:0x1850 "BTP2185 V2 PC mode USB Gamepad"
+ * - tested with BTP2185 PC Mode with another version.
+ *
+ * 0x20bc:0x5500 "BTP2185 V2 BFM mode Joystick"
+ * - tested with BTP2171s.
+ * Copyright (c) 2014 Huang Bo <huangbobupt@163.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/hid.h>
+
+#include "hid-ids.h"
+
+struct betopff_device {
+ struct hid_report *report;
+};
+
+static int hid_betopff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct betopff_device *betopff = data;
+ __u16 left, right;
+
+ left = effect->u.rumble.strong_magnitude;
+ right = effect->u.rumble.weak_magnitude;
+
+ betopff->report->field[2]->value[0] = left / 256;
+ betopff->report->field[3]->value[0] = right / 256;
+
+ hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT);
+
+ return 0;
+}
+
+static int betopff_init(struct hid_device *hid)
+{
+ struct betopff_device *betopff;
+ struct hid_report *report;
+ struct hid_input *hidinput =
+ list_first_entry(&hid->inputs, struct hid_input, list);
+ struct list_head *report_list =
+ &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+ int field_count = 0;
+ int error;
+ int i, j;
+
+ if (list_empty(report_list)) {
+ hid_err(hid, "no output reports found\n");
+ return -ENODEV;
+ }
+
+ report = list_first_entry(report_list, struct hid_report, list);
+ /*
+ * Actually there are 4 fields for 4 Bytes as below:
+ * -----------------------------------------
+ * Byte0 Byte1 Byte2 Byte3
+ * 0x00 0x00 left_motor right_motor
+ * -----------------------------------------
+ * Do init them with default value.
+ */
+ for (i = 0; i < report->maxfield; i++) {
+ for (j = 0; j < report->field[i]->report_count; j++) {
+ report->field[i]->value[j] = 0x00;
+ field_count++;
+ }
+ }
+
+ if (field_count < 4) {
+ hid_err(hid, "not enough fields in the report: %d\n",
+ field_count);
+ return -ENODEV;
+ }
+
+ betopff = kzalloc(sizeof(*betopff), GFP_KERNEL);
+ if (!betopff)
+ return -ENOMEM;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ error = input_ff_create_memless(dev, betopff, hid_betopff_play);
+ if (error) {
+ kfree(betopff);
+ return error;
+ }
+
+ betopff->report = report;
+ hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT);
+
+ hid_info(hid, "Force feedback for betop devices by huangbo <huangbobupt@163.com>\n");
+
+ return 0;
+}
+
+static int betop_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ if (id->driver_data)
+ hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto err;
+ }
+
+ betopff_init(hdev);
+
+ return 0;
+err:
+ return ret;
+}
+
+static const struct hid_device_id betop_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, betop_devices);
+
+static struct hid_driver betop_driver = {
+ .name = "betop",
+ .id_table = betop_devices,
+ .probe = betop_probe,
+};
+module_hid_driver(betop_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index a622590..e64ccfc 100755
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1642,6 +1642,10 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 161ee89..c432be9 100755
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -185,6 +185,11 @@
#define USB_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
+#define USB_VENDOR_ID_BETOP_2185BFM 0x11c2
+#define USB_VENDOR_ID_BETOP_2185PC 0x11c0
+#define USB_VENDOR_ID_BETOP_2185V2PC 0x8380
+#define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc
+
#define USB_VENDOR_ID_BTC 0x046e
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
--
1.7.9.5
[-- Attachment #2: 0001-HID-add-BETOP-game-controller-force-feedback-support.patch --]
[-- Type: text/x-patch, Size: 7661 bytes --]
>From b362f0b16c2376103237931307f927eca32219b3 Mon Sep 17 00:00:00 2001
From: Huang Bo <huangbobupt@163.com>
Date: Wed, 26 Nov 2014 18:21:03 +0800
Subject: [PATCH] HID: add BETOP game controller force feedback support
Adds force feedback support for BETOP USB game controllers.
These devices are mass produced in China.
Signed-off-by: Huang Bo <huangbobupt@163.com>
---
drivers/hid/Kconfig | 10 +++
drivers/hid/Makefile | 1 +
drivers/hid/hid-betopff.c | 160 +++++++++++++++++++++++++++++++++++++++++++++
drivers/hid/hid-core.c | 4 ++
drivers/hid/hid-ids.h | 5 ++
5 files changed, 180 insertions(+)
create mode 100644 drivers/hid/hid-betopff.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 4938bd3..3b4c47d 100755
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -146,6 +146,16 @@ config HID_BELKIN
---help---
Support for Belkin Flip KVM and Wireless keyboard.
+config HID_BETOP_FF
+ tristate "Betop Production Inc. force feedback support"
+ depends on USB_HID
+ select INPUT_FF_MEMLESS
+ ---help---
+ Say Y here if you want to enable force feedback support for devices by
+ BETOP Production Ltd.
+ Currently the following devices are known to be supported:
+ - BETOP 2185 PC & BFM MODE
+
config HID_CHERRY
tristate "Cherry Cymotion keyboard" if EXPERT
depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 4113999..edd4825 100755
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
+obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
diff --git a/drivers/hid/hid-betopff.c b/drivers/hid/hid-betopff.c
new file mode 100644
index 0000000..69cfc8d
--- /dev/null
+++ b/drivers/hid/hid-betopff.c
@@ -0,0 +1,160 @@
+/*
+ * Force feedback support for Betop based devices
+ *
+ * The devices are distributed under various names and the same USB device ID
+ * can be used in both adapters and actual game controllers.
+ *
+ * 0x11c2:0x2208 "BTP2185 BFM mode Joystick"
+ * - tested with BTP2185 BFM Mode.
+ *
+ * 0x11C0:0x5506 "BTP2185 PC mode Joystick"
+ * - tested with BTP2185 PC Mode.
+ *
+ * 0x8380:0x1850 "BTP2185 V2 PC mode USB Gamepad"
+ * - tested with BTP2185 PC Mode with another version.
+ *
+ * 0x20bc:0x5500 "BTP2185 V2 BFM mode Joystick"
+ * - tested with BTP2171s.
+ * Copyright (c) 2014 Huang Bo <huangbobupt@163.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/hid.h>
+
+#include "hid-ids.h"
+
+struct betopff_device {
+ struct hid_report *report;
+};
+
+static int hid_betopff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct betopff_device *betopff = data;
+ __u16 left, right;
+
+ left = effect->u.rumble.strong_magnitude;
+ right = effect->u.rumble.weak_magnitude;
+
+ betopff->report->field[2]->value[0] = left / 256;
+ betopff->report->field[3]->value[0] = right / 256;
+
+ hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT);
+
+ return 0;
+}
+
+static int betopff_init(struct hid_device *hid)
+{
+ struct betopff_device *betopff;
+ struct hid_report *report;
+ struct hid_input *hidinput =
+ list_first_entry(&hid->inputs, struct hid_input, list);
+ struct list_head *report_list =
+ &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+ int field_count = 0;
+ int error;
+ int i, j;
+
+ if (list_empty(report_list)) {
+ hid_err(hid, "no output reports found\n");
+ return -ENODEV;
+ }
+
+ report = list_first_entry(report_list, struct hid_report, list);
+ /*
+ * Actually there are 4 fields for 4 Bytes as below:
+ * -----------------------------------------
+ * Byte0 Byte1 Byte2 Byte3
+ * 0x00 0x00 left_motor right_motor
+ * -----------------------------------------
+ * Do init them with default value.
+ */
+ for (i = 0; i < report->maxfield; i++) {
+ for (j = 0; j < report->field[i]->report_count; j++) {
+ report->field[i]->value[j] = 0x00;
+ field_count++;
+ }
+ }
+
+ if (field_count < 4) {
+ hid_err(hid, "not enough fields in the report: %d\n",
+ field_count);
+ return -ENODEV;
+ }
+
+ betopff = kzalloc(sizeof(*betopff), GFP_KERNEL);
+ if (!betopff)
+ return -ENOMEM;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ error = input_ff_create_memless(dev, betopff, hid_betopff_play);
+ if (error) {
+ kfree(betopff);
+ return error;
+ }
+
+ betopff->report = report;
+ hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT);
+
+ hid_info(hid, "Force feedback for betop devices by huangbo <huangbobupt@163.com>\n");
+
+ return 0;
+}
+
+static int betop_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ if (id->driver_data)
+ hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto err;
+ }
+
+ betopff_init(hdev);
+
+ return 0;
+err:
+ return ret;
+}
+
+static const struct hid_device_id betop_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, betop_devices);
+
+static struct hid_driver betop_driver = {
+ .name = "betop",
+ .id_table = betop_devices,
+ .probe = betop_probe,
+};
+module_hid_driver(betop_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index a622590..e64ccfc 100755
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1642,6 +1642,10 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 161ee89..c432be9 100755
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -185,6 +185,11 @@
#define USB_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
+#define USB_VENDOR_ID_BETOP_2185BFM 0x11c2
+#define USB_VENDOR_ID_BETOP_2185PC 0x11c0
+#define USB_VENDOR_ID_BETOP_2185V2PC 0x8380
+#define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc
+
#define USB_VENDOR_ID_BTC 0x046e
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
--
1.7.9.5
^ permalink raw reply related
* [PATCH] i8042: prevent the loading of the i8042 driver on Intel NUC D54250WYK
From: Todor Minchev @ 2014-12-02 8:27 UTC (permalink / raw)
To: linux-kernel; +Cc: dmitry.torokhov, linux-input, Todor Minchev
The Intel NUC D54250WYK has no PS/2 controller, however the DSDT declares
PS/2 devices which trigger the loading of the i8042 driver.
Signed-off-by: Todor Minchev <todor.minchev@intel.com>
---
drivers/input/serio/i8042-x86ia64io.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index faeeb13..5182008 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -579,6 +579,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nopnp_table[] = {
},
},
{
+ /* Intel NUC D54250WYK */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "D54250WYK"),
+ DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
+ },
+ },
+ {
/* MSI Wind U-100 */
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "U-100"),
--
2.1.3
^ permalink raw reply related
* Re: [PATCH 1/2] HID: wacom: re-add accidentally dropped Lenovo PID
From: Jiri Kosina @ 2014-12-02 10:40 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, Jason Gerecke, Ping Cheng, Hans Spath,
linux-input, linux-kernel
In-Reply-To: <1417452760-2763-1-git-send-email-benjamin.tissoires@redhat.com>
I have now applied both to for-3.18/upstream-fixes, but I am not sure
whether there will be any pull request before 3.18 release. But -stable
markers are there, so it will then eventually be fixed in first -stable.
Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH] HID: wacom - add defines for new Cintiq and DTU outbound tracking
From: Jiri Kosina @ 2014-12-02 10:42 UTC (permalink / raw)
To: Ping Cheng; +Cc: linux-input, Ping Cheng
In-Reply-To: <1417470268-13635-1-git-send-email-pingc@wacom.com>
On Mon, 1 Dec 2014, Ping Cheng wrote:
> There are screen to tablet offsets for newer Cintiq and DTU models.
> These offsets serve as outbound tracking for those display tablets.
>
> Use defines instead of hardcoded numbers for the offsets.
>
> Signed-off-by: Ping Cheng <pingc@wacom.com>
Applied, thanks.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* [PATCH] Input : Initialize input_no by -1
From: Aniroop Mathur @ 2014-12-02 16:45 UTC (permalink / raw)
To: dmitry.torokhov, dtor, linux-input; +Cc: aniroop.mathur, a.mathur
This patch initializes input_no by -1 in order to avoid extra subtraction
operation performed everytime for allocation of an input device.
Signed-off-by: Aniroop Mathur <aniroop.mathur@gmail.com>
---
drivers/input/input.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 29ca0bb..01fe49e 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -1774,7 +1774,7 @@ EXPORT_SYMBOL_GPL(input_class);
*/
struct input_dev *input_allocate_device(void)
{
- static atomic_t input_no = ATOMIC_INIT(0);
+ static atomic_t input_no = ATOMIC_INIT(-1);
struct input_dev *dev;
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
@@ -1789,7 +1789,7 @@ struct input_dev *input_allocate_device(void)
INIT_LIST_HEAD(&dev->node);
dev_set_name(&dev->dev, "input%ld",
- (unsigned long) atomic_inc_return(&input_no) - 1);
+ (unsigned long) atomic_inc_return(&input_no));
__module_get(THIS_MODULE);
}
--
1.9.1
^ permalink raw reply related
* [patch] Input: lm8323 - missing error check in lm8323_set_disable()
From: Dan Carpenter @ 2014-12-02 21:17 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Jingoo Han, Fugang Duan, Johan Hovold, Bryan Wu, linux-input,
kernel-janitors
The missing error handling here is not especially harmful but static
checkers complain that "i" can be used uninitialized.
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
index cb32e2b..21bea52 100644
--- a/drivers/input/keyboard/lm8323.c
+++ b/drivers/input/keyboard/lm8323.c
@@ -616,6 +616,8 @@ static ssize_t lm8323_set_disable(struct device *dev,
unsigned int i;
ret = kstrtouint(buf, 10, &i);
+ if (ret)
+ return ret;
mutex_lock(&lm->lock);
lm->kp_enabled = !i;
^ permalink raw reply related
* [PATCH] i2c-hid / PM: Replace CONFIG_PM_RUNTIME with CONFIG_PM
From: Rafael J. Wysocki @ 2014-12-03 1:56 UTC (permalink / raw)
To: Jiri Kosina
Cc: linux-input, Mika Westerberg, Linux Kernel Mailing List,
Linux PM list
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
After commit b2b49ccbdd54 (PM: Kconfig: Set PM_RUNTIME if PM_SLEEP is
selected) PM_RUNTIME is always set if PM is set, so #ifdef blocks
depending on CONFIG_PM_RUNTIME may now be changed to depend on
CONFIG_PM.
Replace CONFIG_PM_RUNTIME with CONFIG_PM in drivers/hid/i2c-hid/i2c-hid.c.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
Note: This depends on commit b2b49ccbdd54 (PM: Kconfig: Set PM_RUNTIME if
PM_SLEEP is selected) which is only in linux-next at the moment (via the
linux-pm tree).
Please let me know if it is OK to take this one into linux-pm.
---
drivers/hid/i2c-hid/i2c-hid.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: linux-pm/drivers/hid/i2c-hid/i2c-hid.c
===================================================================
--- linux-pm.orig/drivers/hid/i2c-hid/i2c-hid.c
+++ linux-pm/drivers/hid/i2c-hid/i2c-hid.c
@@ -1095,7 +1095,7 @@ static int i2c_hid_resume(struct device
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int i2c_hid_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
^ permalink raw reply
* Re: [PATCH] input / PM: Replace CONFIG_PM_RUNTIME with CONFIG_PM
From: Jingoo Han @ 2014-12-03 2:02 UTC (permalink / raw)
To: 'Rafael J. Wysocki', 'Dmitry Torokhov'
Cc: linux-input, 'Paul Gortmaker', 'Ferruh Yigit',
'Linux Kernel Mailing List', 'Linux PM list',
'Jingoo Han'
In-Reply-To: <8119438.MdkFLx3Wvh@vostro.rjw.lan>
On Wednesday, December 03, 2014 11:09 AM, Rafael J. Wysocki wrote:
>
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> After commit b2b49ccbdd54 (PM: Kconfig: Set PM_RUNTIME if PM_SLEEP is
> selected) PM_RUNTIME is always set if PM is set, so #ifdef blocks
> depending on CONFIG_PM_RUNTIME may now be changed to depend on
> CONFIG_PM.
>
> The alternative of CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME may be
> replaced with CONFIG_PM too.
>
> Make these changes in 2 files under drivers/input/.
>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Jingoo Han <jg1.han@samsung.com>
Best regards,
Jingoo Han
> ---
>
> Note: This depends on commit b2b49ccbdd54 (PM: Kconfig: Set PM_RUNTIME if
> PM_SLEEP is selected) which is only in linux-next at the moment (via the
> linux-pm tree).
>
> Please let me know if it is OK to take this one into linux-pm.
>
> ---
> drivers/input/keyboard/samsung-keypad.c | 2 +-
> drivers/input/touchscreen/cyttsp4_core.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> Index: linux-pm/drivers/input/keyboard/samsung-keypad.c
> ===================================================================
> --- linux-pm.orig/drivers/input/keyboard/samsung-keypad.c
> +++ linux-pm/drivers/input/keyboard/samsung-keypad.c
> @@ -463,7 +463,7 @@ static int samsung_keypad_remove(struct
> return 0;
> }
>
> -#ifdef CONFIG_PM_RUNTIME
> +#ifdef CONFIG_PM
> static int samsung_keypad_runtime_suspend(struct device *dev)
> {
> struct platform_device *pdev = to_platform_device(dev);
> Index: linux-pm/drivers/input/touchscreen/cyttsp4_core.c
> ===================================================================
> --- linux-pm.orig/drivers/input/touchscreen/cyttsp4_core.c
> +++ linux-pm/drivers/input/touchscreen/cyttsp4_core.c
> @@ -1716,7 +1716,7 @@ static void cyttsp4_free_si_ptrs(struct
> kfree(si->btn_rec_data);
> }
>
> -#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
> +#ifdef CONFIG_PM
> static int cyttsp4_core_sleep(struct cyttsp4 *cd)
> {
> int rc;
^ permalink raw reply
* [PATCH] input / PM: Replace CONFIG_PM_RUNTIME with CONFIG_PM
From: Rafael J. Wysocki @ 2014-12-03 2:09 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: linux-input, Jingoo Han, Paul Gortmaker, Ferruh Yigit,
Linux Kernel Mailing List, Linux PM list
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
After commit b2b49ccbdd54 (PM: Kconfig: Set PM_RUNTIME if PM_SLEEP is
selected) PM_RUNTIME is always set if PM is set, so #ifdef blocks
depending on CONFIG_PM_RUNTIME may now be changed to depend on
CONFIG_PM.
The alternative of CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME may be
replaced with CONFIG_PM too.
Make these changes in 2 files under drivers/input/.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
Note: This depends on commit b2b49ccbdd54 (PM: Kconfig: Set PM_RUNTIME if
PM_SLEEP is selected) which is only in linux-next at the moment (via the
linux-pm tree).
Please let me know if it is OK to take this one into linux-pm.
---
drivers/input/keyboard/samsung-keypad.c | 2 +-
drivers/input/touchscreen/cyttsp4_core.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
Index: linux-pm/drivers/input/keyboard/samsung-keypad.c
===================================================================
--- linux-pm.orig/drivers/input/keyboard/samsung-keypad.c
+++ linux-pm/drivers/input/keyboard/samsung-keypad.c
@@ -463,7 +463,7 @@ static int samsung_keypad_remove(struct
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int samsung_keypad_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
Index: linux-pm/drivers/input/touchscreen/cyttsp4_core.c
===================================================================
--- linux-pm.orig/drivers/input/touchscreen/cyttsp4_core.c
+++ linux-pm/drivers/input/touchscreen/cyttsp4_core.c
@@ -1716,7 +1716,7 @@ static void cyttsp4_free_si_ptrs(struct
kfree(si->btn_rec_data);
}
-#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
+#ifdef CONFIG_PM
static int cyttsp4_core_sleep(struct cyttsp4 *cd)
{
int rc;
^ permalink raw reply
* Re: [PATCH v2] Drivers: input: mousedev.c: Fixed trailing statement on the next line
From: Dmitry Torokhov @ 2014-12-02 23:04 UTC (permalink / raw)
To: Athira Sharikkal; +Cc: linux-input, linux-kernel
In-Reply-To: <1417437402-3365-1-git-send-email-athirasnamby@gmail.com>
Hi Athira,
On Mon, Dec 01, 2014 at 06:06:42PM +0530, Athira Sharikkal wrote:
> Fixed checkpatch error:
> trailing statements should be on next line
>
> Signed-off-by: Athira Sharikkal <athirasnamby@gmail.com>
> ---
> v2: corrected indentation
> drivers/input/mousedev.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
> index b604564..28988f5 100644
> --- a/drivers/input/mousedev.c
> +++ b/drivers/input/mousedev.c
> @@ -248,7 +248,8 @@ static void mousedev_key_event(struct mousedev *mousedev,
> case BTN_4:
> case BTN_EXTRA: index = 4; break;
>
> - default: return;
> + default:
> + return;
Changing one bit in a file while leaving the rest of it unchanged does not
make much sense. That said, I believe that in this particular case the
original style is fine and does not need changing.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] i8042: prevent the loading of the i8042 driver on Intel NUC D54250WYK
From: Dmitry Torokhov @ 2014-12-02 23:22 UTC (permalink / raw)
To: Todor Minchev; +Cc: linux-kernel, linux-input
In-Reply-To: <1417508822-8243-1-git-send-email-todor.minchev@intel.com>
On Tue, Dec 02, 2014 at 08:27:02AM +0000, Todor Minchev wrote:
> The Intel NUC D54250WYK has no PS/2 controller, however the DSDT declares
> PS/2 devices which trigger the loading of the i8042 driver.
>
> Signed-off-by: Todor Minchev <todor.minchev@intel.com>
Applied, thank you.
> ---
> drivers/input/serio/i8042-x86ia64io.h | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
> index faeeb13..5182008 100644
> --- a/drivers/input/serio/i8042-x86ia64io.h
> +++ b/drivers/input/serio/i8042-x86ia64io.h
> @@ -579,6 +579,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nopnp_table[] = {
> },
> },
> {
> + /* Intel NUC D54250WYK */
> + .matches = {
> + DMI_MATCH(DMI_BOARD_NAME, "D54250WYK"),
> + DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
> + },
> + },
> + {
> /* MSI Wind U-100 */
> .matches = {
> DMI_MATCH(DMI_BOARD_NAME, "U-100"),
> --
> 2.1.3
>
--
Dmitry
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox