* [PATCH 2/4] input: mc13783: Use module_platform_driver_probe()
From: Alexander Shiyan @ 2014-02-10 4:22 UTC (permalink / raw)
To: linux-input
Cc: Dmitry Torokhov, Shawn Guo, Sascha Hauer, Samuel Ortiz, Lee Jones,
Alexander Shiyan
Driver should be probed from MC13XXX MFD core only, so change
driver declaration to use module_platform_driver_probe().
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/input/misc/mc13783-pwrbutton.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index 60be67a..a1e45235 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -88,7 +88,7 @@ static irqreturn_t button_irq(int irq, void *_priv)
return IRQ_HANDLED;
}
-static int mc13783_pwrbutton_probe(struct platform_device *pdev)
+static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
{
const struct mc13xxx_buttons_platform_data *pdata;
struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
@@ -229,7 +229,7 @@ free_input_dev:
return err;
}
-static int mc13783_pwrbutton_remove(struct platform_device *pdev)
+static int mc13xxx_pwrbutton_remove(struct platform_device *pdev)
{
struct mc13783_pwrb *priv = platform_get_drvdata(pdev);
const struct mc13xxx_buttons_platform_data *pdata;
@@ -253,18 +253,15 @@ static int mc13783_pwrbutton_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver mc13783_pwrbutton_driver = {
- .probe = mc13783_pwrbutton_probe,
- .remove = mc13783_pwrbutton_remove,
+static struct platform_driver mc13xxx_pwrbutton_driver = {
.driver = {
.name = "mc13783-pwrbutton",
.owner = THIS_MODULE,
},
+ .remove = mc13xxx_pwrbutton_remove,
};
+module_platform_driver_probe(mc13xxx_pwrbutton_driver, mc13xxx_pwrbutton_probe);
-module_platform_driver(mc13783_pwrbutton_driver);
-
-MODULE_ALIAS("platform:mc13783-pwrbutton");
MODULE_DESCRIPTION("MC13783 Power Button");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Philippe Retornaz");
--
1.8.3.2
^ permalink raw reply related
* [PATCH 3/4] input: mc13783: Prepare driver to support MC13892
From: Alexander Shiyan @ 2014-02-10 4:22 UTC (permalink / raw)
To: linux-input
Cc: Dmitry Torokhov, Shawn Guo, Sascha Hauer, Samuel Ortiz, Lee Jones,
Alexander Shiyan
This patch rewrite driver code to be ready to add support for
MC13892 buttons and probe from devicetree.
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/input/misc/mc13783-pwrbutton.c | 311 +++++++++++++--------------------
1 file changed, 120 insertions(+), 191 deletions(-)
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index a1e45235..f9e2bfb 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -23,245 +23,174 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/input.h>
-#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/mfd/mc13783.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-struct mc13783_pwrb {
- struct input_dev *pwr;
- struct mc13xxx *mc13783;
-#define MC13783_PWRB_B1_POL_INVERT (1 << 0)
-#define MC13783_PWRB_B2_POL_INVERT (1 << 1)
-#define MC13783_PWRB_B3_POL_INVERT (1 << 2)
- int flags;
- unsigned short keymap[MAX13XXX_NUM_BUTTONS];
+
+struct mc13xxx_button_def {
+ unsigned int irq;
+ unsigned int sense_bit;
+};
+
+struct mc13xxx_pwrb_devtype {
+ struct mc13xxx_button_def btn_def[MAX13XXX_NUM_BUTTONS];
};
-#define MC13783_REG_INTERRUPT_SENSE_1 5
-#define MC13783_IRQSENSE1_ONOFD1S (1 << 3)
-#define MC13783_IRQSENSE1_ONOFD2S (1 << 4)
-#define MC13783_IRQSENSE1_ONOFD3S (1 << 5)
+struct mc13xxx_pwrb {
+ struct mc13xxx_pwrb_devtype *devtype;
+ unsigned int enabled;
+ unsigned int inverted;
+ u16 btn_code[MAX13XXX_NUM_BUTTONS];
+ struct input_dev *input;
+ struct mc13xxx *mc13xxx;
+};
-#define MC13783_REG_POWER_CONTROL_2 15
-#define MC13783_POWER_CONTROL_2_ON1BDBNC 4
-#define MC13783_POWER_CONTROL_2_ON2BDBNC 6
-#define MC13783_POWER_CONTROL_2_ON3BDBNC 8
-#define MC13783_POWER_CONTROL_2_ON1BRSTEN (1 << 1)
-#define MC13783_POWER_CONTROL_2_ON2BRSTEN (1 << 2)
-#define MC13783_POWER_CONTROL_2_ON3BRSTEN (1 << 3)
+#define MC13XXX_REG_INTERRUPT_SENSE_1 5
+#define MC13XXX_REG_POWER_CONTROL_2 15
-static irqreturn_t button_irq(int irq, void *_priv)
+static irqreturn_t mc13xxx_pwrbutton_irq(int irq, void *data)
{
- struct mc13783_pwrb *priv = _priv;
- int val;
-
- mc13xxx_irq_ack(priv->mc13783, irq);
- mc13xxx_reg_read(priv->mc13783, MC13783_REG_INTERRUPT_SENSE_1, &val);
-
- switch (irq) {
- case MC13783_IRQ_ONOFD1:
- val = val & MC13783_IRQSENSE1_ONOFD1S ? 1 : 0;
- if (priv->flags & MC13783_PWRB_B1_POL_INVERT)
- val ^= 1;
- input_report_key(priv->pwr, priv->keymap[0], val);
- break;
-
- case MC13783_IRQ_ONOFD2:
- val = val & MC13783_IRQSENSE1_ONOFD2S ? 1 : 0;
- if (priv->flags & MC13783_PWRB_B2_POL_INVERT)
- val ^= 1;
- input_report_key(priv->pwr, priv->keymap[1], val);
- break;
-
- case MC13783_IRQ_ONOFD3:
- val = val & MC13783_IRQSENSE1_ONOFD3S ? 1 : 0;
- if (priv->flags & MC13783_PWRB_B3_POL_INVERT)
- val ^= 1;
- input_report_key(priv->pwr, priv->keymap[2], val);
- break;
- }
-
- input_sync(priv->pwr);
+ struct mc13xxx_pwrb *priv = data;
+ unsigned int i, val;
+
+ mc13xxx_irq_ack(priv->mc13xxx, irq);
+ mc13xxx_reg_read(priv->mc13xxx, MC13XXX_REG_INTERRUPT_SENSE_1, &val);
+
+ for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
+ if (irq == priv->devtype->btn_def[i].irq) {
+ val = !!(val & priv->devtype->btn_def[i].sense_bit);
+ if (priv->inverted & BIT(i))
+ val = !val;
+ input_report_key(priv->input, priv->btn_code[i], val);
+ input_sync(priv->input);
+ break;
+ }
return IRQ_HANDLED;
}
static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
{
- const struct mc13xxx_buttons_platform_data *pdata;
- struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
- struct input_dev *pwr;
- struct mc13783_pwrb *priv;
- int err = 0;
- int reg = 0;
-
- pdata = dev_get_platdata(&pdev->dev);
+ struct mc13xxx_buttons_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct mc13xxx *mc13xxx = dev_get_drvdata(pdev->dev.parent);
+ struct mc13xxx_pwrb_devtype *devtype =
+ (struct mc13xxx_pwrb_devtype *)pdev->id_entry->driver_data;
+ struct mc13xxx_pwrb *priv;
+ int i, reg = 0;
+
if (!pdata) {
dev_err(&pdev->dev, "missing platform data\n");
return -ENODEV;
}
- pwr = input_allocate_device();
- if (!pwr) {
- dev_dbg(&pdev->dev, "Can't allocate power button\n");
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- }
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- err = -ENOMEM;
- dev_dbg(&pdev->dev, "Can't allocate power button\n");
- goto free_input_dev;
- }
-
- reg |= (pdata->buttons[0].flags & 0x3) << MC13783_POWER_CONTROL_2_ON1BDBNC;
- reg |= (pdata->buttons[1].flags & 0x3) << MC13783_POWER_CONTROL_2_ON2BDBNC;
- reg |= (pdata->buttons[2].flags & 0x3) << MC13783_POWER_CONTROL_2_ON3BDBNC;
- priv->pwr = pwr;
- priv->mc13783 = mc13783;
-
- mc13xxx_lock(mc13783);
-
- if (pdata->buttons[0].flags & MC13XXX_BUTTON_ENABLE) {
- priv->keymap[0] = pdata->buttons[0].keycode;
- if (priv->keymap[0] != KEY_RESERVED)
- __set_bit(priv->keymap[0], pwr->keybit);
-
- if (pdata->buttons[0].flags & MC13XXX_BUTTON_POL_INVERT)
- priv->flags |= MC13783_PWRB_B1_POL_INVERT;
-
- if (pdata->buttons[0].flags & MC13XXX_BUTTON_RESET_EN)
- reg |= MC13783_POWER_CONTROL_2_ON1BRSTEN;
-
- err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD1,
- button_irq, "b1on", priv);
- if (err) {
- dev_dbg(&pdev->dev, "Can't request irq\n");
- goto free_priv;
- }
- }
-
- if (pdata->buttons[1].flags & MC13XXX_BUTTON_ENABLE) {
- priv->keymap[1] = pdata->buttons[1].keycode;
- if (priv->keymap[1] != KEY_RESERVED)
- __set_bit(priv->keymap[1], pwr->keybit);
-
- if (pdata->buttons[1].flags & MC13XXX_BUTTON_POL_INVERT)
- priv->flags |= MC13783_PWRB_B2_POL_INVERT;
+ priv->input = devm_input_allocate_device(&pdev->dev);
+ if (!priv->input)
+ return -ENOMEM;
- if (pdata->buttons[1].flags & MC13XXX_BUTTON_RESET_EN)
- reg |= MC13783_POWER_CONTROL_2_ON2BRSTEN;
+ priv->mc13xxx = mc13xxx;
+ priv->devtype = devtype;
+ platform_set_drvdata(pdev, priv);
- err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD2,
- button_irq, "b2on", priv);
- if (err) {
- dev_dbg(&pdev->dev, "Can't request irq\n");
- goto free_irq_b1;
- }
+ for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++) {
+ u16 code, invert, reset, debounce;
+
+ if (!(pdata->buttons[i].flags & MC13XXX_BUTTON_ENABLE))
+ continue;
+ code = pdata->buttons[i].keycode;
+ invert = !!(pdata->buttons[i].flags &
+ MC13XXX_BUTTON_POL_INVERT);
+ reset = !!(pdata->buttons[i].flags &
+ MC13XXX_BUTTON_RESET_EN);
+ debounce = pdata->buttons[i].flags;
+
+ priv->btn_code[i] = code;
+ if (code != KEY_RESERVED)
+ __set_bit(code, priv->input->keybit);
+
+ priv->enabled |= BIT(i);
+ priv->inverted |= invert << i;
+ reg |= reset << (i + 1);
+ reg |= (debounce & 0x03) << (4 + i * 2);
}
- if (pdata->buttons[2].flags & MC13XXX_BUTTON_ENABLE) {
- priv->keymap[2] = pdata->buttons[2].keycode;
- if (priv->keymap[2] != KEY_RESERVED)
- __set_bit(priv->keymap[2], pwr->keybit);
+ mc13xxx_lock(mc13xxx);
- if (pdata->buttons[2].flags & MC13XXX_BUTTON_POL_INVERT)
- priv->flags |= MC13783_PWRB_B3_POL_INVERT;
+ mc13xxx_reg_rmw(mc13xxx, MC13XXX_REG_POWER_CONTROL_2, 0x3fe, reg);
- if (pdata->buttons[2].flags & MC13XXX_BUTTON_RESET_EN)
- reg |= MC13783_POWER_CONTROL_2_ON3BRSTEN;
+ for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
+ if (priv->enabled & BIT(i)) {
+ int ret;
- err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD3,
- button_irq, "b3on", priv);
- if (err) {
- dev_dbg(&pdev->dev, "Can't request irq: %d\n", err);
- goto free_irq_b2;
+ ret = mc13xxx_irq_request(mc13xxx,
+ devtype->btn_def[i].irq,
+ mc13xxx_pwrbutton_irq, NULL,
+ priv);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't request IRQ%i: %i\n",
+ devtype->btn_def[i].irq, ret);
+ priv->enabled &= ~BIT(i);
+ }
}
- }
-
- mc13xxx_reg_rmw(mc13783, MC13783_REG_POWER_CONTROL_2, 0x3FE, reg);
-
- mc13xxx_unlock(mc13783);
-
- pwr->name = "mc13783_pwrbutton";
- pwr->phys = "mc13783_pwrbutton/input0";
- pwr->dev.parent = &pdev->dev;
-
- pwr->keycode = priv->keymap;
- pwr->keycodemax = ARRAY_SIZE(priv->keymap);
- pwr->keycodesize = sizeof(priv->keymap[0]);
- __set_bit(EV_KEY, pwr->evbit);
-
- err = input_register_device(pwr);
- if (err) {
- dev_dbg(&pdev->dev, "Can't register power button: %d\n", err);
- goto free_irq;
- }
-
- platform_set_drvdata(pdev, priv);
-
- return 0;
-free_irq:
- mc13xxx_lock(mc13783);
+ mc13xxx_unlock(mc13xxx);
- if (pdata->buttons[2].flags & MC13XXX_BUTTON_ENABLE)
- mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD3, priv);
+ priv->input->name = pdev->name;
+ priv->input->dev.parent = &pdev->dev;
+ priv->input->id.bustype = BUS_HOST;
+ priv->input->id.vendor = 0x0001;
+ priv->input->id.product = 0x0001;
+ priv->input->id.version = 0x0100;
+ priv->input->keycode = priv->btn_code;
+ priv->input->keycodemax = ARRAY_SIZE(priv->btn_code);
+ priv->input->keycodesize = sizeof(priv->btn_code[0]);
+ __set_bit(EV_KEY, priv->input->evbit);
-free_irq_b2:
- if (pdata->buttons[1].flags & MC13XXX_BUTTON_ENABLE)
- mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD2, priv);
+ input_set_drvdata(priv->input, priv);
-free_irq_b1:
- if (pdata->buttons[0].flags & MC13XXX_BUTTON_ENABLE)
- mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD1, priv);
-
-free_priv:
- mc13xxx_unlock(mc13783);
- kfree(priv);
-
-free_input_dev:
- input_free_device(pwr);
-
- return err;
+ return input_register_device(priv->input);
}
static int mc13xxx_pwrbutton_remove(struct platform_device *pdev)
{
- struct mc13783_pwrb *priv = platform_get_drvdata(pdev);
- const struct mc13xxx_buttons_platform_data *pdata;
-
- pdata = dev_get_platdata(&pdev->dev);
-
- mc13xxx_lock(priv->mc13783);
-
- if (pdata->buttons[2].flags & MC13XXX_BUTTON_ENABLE)
- mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD3, priv);
- if (pdata->buttons[1].flags & MC13XXX_BUTTON_ENABLE)
- mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD2, priv);
- if (pdata->buttons[0].flags & MC13XXX_BUTTON_ENABLE)
- mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD1, priv);
+ struct mc13xxx_pwrb *priv = platform_get_drvdata(pdev);
+ int i;
- mc13xxx_unlock(priv->mc13783);
-
- input_unregister_device(priv->pwr);
- kfree(priv);
+ mc13xxx_lock(priv->mc13xxx);
+ for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
+ if (priv->enabled & BIT(i))
+ mc13xxx_irq_free(priv->mc13xxx,
+ priv->devtype->btn_def[i].irq, priv);
+ mc13xxx_unlock(priv->mc13xxx);
return 0;
}
+static const struct mc13xxx_pwrb_devtype mc13783_pwrb_devtype = {
+ .btn_def[0] = { MC13783_IRQ_ONOFD1, BIT(3), },
+ .btn_def[1] = { MC13783_IRQ_ONOFD2, BIT(4), },
+ .btn_def[2] = { MC13783_IRQ_ONOFD3, BIT(5), },
+};
+
+static const struct platform_device_id mc13xxx_pwrbutton_id_table[] = {
+ { "mc13783-pwrbutton", (kernel_ulong_t)&mc13783_pwrb_devtype },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, mc13xxx_pwrbutton_id_table);
+
static struct platform_driver mc13xxx_pwrbutton_driver = {
.driver = {
- .name = "mc13783-pwrbutton",
+ .name = "mc13xxx-pwrbutton",
.owner = THIS_MODULE,
},
+ .id_table = mc13xxx_pwrbutton_id_table,
.remove = mc13xxx_pwrbutton_remove,
};
module_platform_driver_probe(mc13xxx_pwrbutton_driver, mc13xxx_pwrbutton_probe);
-MODULE_DESCRIPTION("MC13783 Power Button");
+MODULE_DESCRIPTION("MC13XXX Power Button");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Philippe Retornaz");
--
1.8.3.2
^ permalink raw reply related
* [PATCH 4/4] input: mc13783: Add MC13892 support
From: Alexander Shiyan @ 2014-02-10 4:22 UTC (permalink / raw)
To: linux-input
Cc: Dmitry Torokhov, Shawn Guo, Sascha Hauer, Samuel Ortiz, Lee Jones,
Alexander Shiyan
This patch adds support for MC13892 PMIC to mc13783-pwrbutton driver.
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/input/misc/Kconfig | 4 ++--
drivers/input/misc/mc13783-pwrbutton.c | 8 ++++++++
include/linux/mfd/mc13892.h | 4 ++++
3 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7904ab0..3d91660 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -167,10 +167,10 @@ config INPUT_MAX8997_HAPTIC
module will be called max8997-haptic.
config INPUT_MC13783_PWRBUTTON
- tristate "MC13783 ON buttons"
+ tristate "MC13783/MC13892 ON buttons"
depends on MFD_MC13XXX
help
- Support the ON buttons of MC13783 PMIC as an input device
+ Support the ON buttons of MC13783/MC13892 PMIC as an input device
reporting power button status.
To compile this driver as a module, choose M here: the module
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index f9e2bfb..03308b0 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -25,6 +25,7 @@
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/mfd/mc13783.h>
+#include <linux/mfd/mc13892.h>
struct mc13xxx_button_def {
unsigned int irq;
@@ -175,8 +176,15 @@ static const struct mc13xxx_pwrb_devtype mc13783_pwrb_devtype = {
.btn_def[2] = { MC13783_IRQ_ONOFD3, BIT(5), },
};
+static const struct mc13xxx_pwrb_devtype mc13892_pwrb_devtype = {
+ .btn_def[0] = { MC13892_IRQ_ONOFD1, BIT(3), },
+ .btn_def[1] = { MC13892_IRQ_ONOFD2, BIT(4), },
+ .btn_def[2] = { MC13892_IRQ_ONOFD3, BIT(2), },
+};
+
static const struct platform_device_id mc13xxx_pwrbutton_id_table[] = {
{ "mc13783-pwrbutton", (kernel_ulong_t)&mc13783_pwrb_devtype },
+ { "mc13892-pwrbutton", (kernel_ulong_t)&mc13892_pwrb_devtype },
{ }
};
MODULE_DEVICE_TABLE(platform, mc13xxx_pwrbutton_id_table);
diff --git a/include/linux/mfd/mc13892.h b/include/linux/mfd/mc13892.h
index a00f2be..bdc3baf 100644
--- a/include/linux/mfd/mc13892.h
+++ b/include/linux/mfd/mc13892.h
@@ -36,4 +36,8 @@
#define MC13892_PWGT2SPI 22
#define MC13892_VCOINCELL 23
+#define MC13892_IRQ_ONOFD3 26
+#define MC13892_IRQ_ONOFD1 27
+#define MC13892_IRQ_ONOFD2 28
+
#endif
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH 2/4] input: mc13783: Use module_platform_driver_probe()
From: Uwe Kleine-König @ 2014-02-10 7:18 UTC (permalink / raw)
To: Alexander Shiyan
Cc: linux-input, Dmitry Torokhov, Shawn Guo, Sascha Hauer,
Samuel Ortiz, Lee Jones
In-Reply-To: <1392006138-10341-1-git-send-email-shc_work@mail.ru>
On Mon, Feb 10, 2014 at 08:22:18AM +0400, Alexander Shiyan wrote:
> Driver should be probed from MC13XXX MFD core only, so change
> driver declaration to use module_platform_driver_probe().
That reasoning is broken I think. At least it doesn't mean that a
button-device is only created at boot or module load time. I didn't test
it, but I'd expect that you can unbind/bind the mc13xxx driver via sysfs
and that makes the button support disappear.
(That doesn't necessarily means your change is wrong, just the reason
you provided to justify it is invalid.)
Best regards
Uwe
> Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
> ---
> drivers/input/misc/mc13783-pwrbutton.c | 13 +++++--------
> 1 file changed, 5 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
> index 60be67a..a1e45235 100644
> --- a/drivers/input/misc/mc13783-pwrbutton.c
> +++ b/drivers/input/misc/mc13783-pwrbutton.c
> @@ -88,7 +88,7 @@ static irqreturn_t button_irq(int irq, void *_priv)
> return IRQ_HANDLED;
> }
>
> -static int mc13783_pwrbutton_probe(struct platform_device *pdev)
> +static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
> {
> const struct mc13xxx_buttons_platform_data *pdata;
> struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
> @@ -229,7 +229,7 @@ free_input_dev:
> return err;
> }
>
> -static int mc13783_pwrbutton_remove(struct platform_device *pdev)
> +static int mc13xxx_pwrbutton_remove(struct platform_device *pdev)
> {
> struct mc13783_pwrb *priv = platform_get_drvdata(pdev);
> const struct mc13xxx_buttons_platform_data *pdata;
> @@ -253,18 +253,15 @@ static int mc13783_pwrbutton_remove(struct platform_device *pdev)
> return 0;
> }
>
> -static struct platform_driver mc13783_pwrbutton_driver = {
> - .probe = mc13783_pwrbutton_probe,
> - .remove = mc13783_pwrbutton_remove,
> +static struct platform_driver mc13xxx_pwrbutton_driver = {
> .driver = {
> .name = "mc13783-pwrbutton",
> .owner = THIS_MODULE,
> },
> + .remove = mc13xxx_pwrbutton_remove,
> };
> +module_platform_driver_probe(mc13xxx_pwrbutton_driver, mc13xxx_pwrbutton_probe);
>
> -module_platform_driver(mc13783_pwrbutton_driver);
> -
> -MODULE_ALIAS("platform:mc13783-pwrbutton");
> MODULE_DESCRIPTION("MC13783 Power Button");
> MODULE_LICENSE("GPL v2");
> MODULE_AUTHOR("Philippe Retornaz");
> --
> 1.8.3.2
>
>
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
--
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
* [PATCH] input: sirfsoc-onkey - report onkey untouch event by detecting pin status
From: Barry Song @ 2014-02-10 10:07 UTC (permalink / raw)
To: dmitry.torokhov, linux-input
Cc: linux-arm-kernel, workgroup.linux, Xianglong Du, Rongjun Ying,
Barry Song
From: Xianglong Du <Xianglong.Du@csr.com>
this patch adds a delayed_work to detect the untouch of onkey since HW will
not generate interrupt for it.
at the same time, we move the KEY event to POWER instead of SUSPEND, which
will be suitable for both Android and Linux. Userspace PowerManager Daemon
will decide to suspend or shutdown based on how long we have touched onkey
Signed-off-by: Xianglong Du <Xianglong.Du@csr.com>
Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
---
drivers/input/misc/sirfsoc-onkey.c | 48 ++++++++++++++++++++++++++++-------
1 files changed, 38 insertions(+), 10 deletions(-)
diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c
index e8897c3..9cd810b 100644
--- a/drivers/input/misc/sirfsoc-onkey.c
+++ b/drivers/input/misc/sirfsoc-onkey.c
@@ -13,16 +13,44 @@
#include <linux/input.h>
#include <linux/rtc/sirfsoc_rtciobrg.h>
#include <linux/of.h>
+#include <linux/workqueue.h>
struct sirfsoc_pwrc_drvdata {
u32 pwrc_base;
struct input_dev *input;
+ struct delayed_work work;
};
#define PWRC_ON_KEY_BIT (1 << 0)
#define PWRC_INT_STATUS 0xc
#define PWRC_INT_MASK 0x10
+#define PWRC_PIN_STATUS 0x14
+#define PWRC_KEY_DETECT_UP_TIME 20 /* ms*/
+
+static inline int sirfsoc_pwrc_is_on_key_down(
+ struct sirfsoc_pwrc_drvdata *pwrcdrv)
+{
+ int state = sirfsoc_rtc_iobrg_readl(
+ pwrcdrv->pwrc_base + PWRC_PIN_STATUS)
+ & PWRC_ON_KEY_BIT;
+ return !state; /* ON_KEY is active low */
+}
+
+static void sirfsoc_pwrc_report_event(struct work_struct *work)
+{
+ struct sirfsoc_pwrc_drvdata *pwrcdrv =
+ container_of((struct delayed_work *)work,
+ struct sirfsoc_pwrc_drvdata, work);
+
+ if (!sirfsoc_pwrc_is_on_key_down(pwrcdrv)) {
+ input_event(pwrcdrv->input, EV_PWR, KEY_POWER, 0);
+ input_sync(pwrcdrv->input);
+ } else {
+ schedule_delayed_work(&pwrcdrv->work,
+ msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
+ }
+}
static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
{
@@ -34,17 +62,11 @@ static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_STATUS);
- /*
- * For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c
- * to queue a SUSPEND APM event
- */
- input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1);
- input_sync(pwrcdrv->input);
- /*
- * Todo: report KEY_POWER event for Android platforms, Android PowerManager
- * will handle the suspend and powerdown/hibernation
- */
+ input_event(pwrcdrv->input, EV_PWR, KEY_POWER, 1);
+ input_sync(pwrcdrv->input);
+ schedule_delayed_work(&pwrcdrv->work,
+ msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
return IRQ_HANDLED;
}
@@ -88,6 +110,8 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
pwrcdrv->input->phys = "pwrc/input0";
pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR);
+ INIT_DELAYED_WORK(&pwrcdrv->work, sirfsoc_pwrc_report_event);
+
irq = platform_get_irq(pdev, 0);
error = devm_request_irq(&pdev->dev, irq,
sirfsoc_pwrc_isr, IRQF_SHARED,
@@ -119,8 +143,12 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
static int sirfsoc_pwrc_remove(struct platform_device *pdev)
{
+ struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_get_drvdata(&pdev->dev);
+
device_init_wakeup(&pdev->dev, 0);
+ cancel_delayed_work_sync(&pwrcdrv->work);
+
return 0;
}
--
1.7.5.4
^ permalink raw reply related
* Re: [PATCH 4/4] input: mc13783: Add MC13892 support
From: Lee Jones @ 2014-02-10 11:23 UTC (permalink / raw)
To: Alexander Shiyan
Cc: linux-input, Dmitry Torokhov, Shawn Guo, Sascha Hauer,
Samuel Ortiz
In-Reply-To: <1392006148-10417-1-git-send-email-shc_work@mail.ru>
> This patch adds support for MC13892 PMIC to mc13783-pwrbutton driver.
>
> Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
> ---
> drivers/input/misc/Kconfig | 4 ++--
> drivers/input/misc/mc13783-pwrbutton.c | 8 ++++++++
> include/linux/mfd/mc13892.h | 4 ++++
For the MFD changes:
Acked-by: Lee Jones <lee.jones@linaro.org>
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
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 1/4] input: mc13783: Make mc13xxx_buttons_platform_data more flexible
From: Lee Jones @ 2014-02-10 11:29 UTC (permalink / raw)
To: Alexander Shiyan
Cc: linux-input, Dmitry Torokhov, Shawn Guo, Sascha Hauer,
Samuel Ortiz
In-Reply-To: <1392006129-10227-1-git-send-email-shc_work@mail.ru>
> Instead of define each button in separate variable, make an array
> for storing all buttons. This change will help to add support for
> other types of PMIC and add support for probing with devicetree
> in the future.
>
> Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
> ---
> arch/arm/mach-imx/mach-mx31moboard.c | 9 ++++--
> drivers/input/misc/mc13783-pwrbutton.c | 56 +++++++++++++++++-----------------
> include/linux/mfd/mc13xxx.h | 28 +++++++++--------
Are all the changes in these files entangled? If there is any way to
make them orthogonal, then all the better.
<snip>
> --- a/include/linux/mfd/mc13xxx.h
> +++ b/include/linux/mfd/mc13xxx.h
> @@ -172,20 +172,22 @@ struct mc13xxx_leds_platform_data {
> u32 led_control[MAX_LED_CONTROL_REGS];
> };
>
> +#define MAX13XXX_NUM_BUTTONS 3
> +
> +struct mc13xxx_button {
> + u16 keycode;
> + unsigned int flags;
> +#define MC13XXX_BUTTON_DBNC_0MS 0
> +#define MC13XXX_BUTTON_DBNC_30MS 1
> +#define MC13XXX_BUTTON_DBNC_150MS 2
> +#define MC13XXX_BUTTON_DBNC_750MS 3
> +#define MC13XXX_BUTTON_ENABLE (1 << 2)
> +#define MC13XXX_BUTTON_POL_INVERT (1 << 3)
> +#define MC13XXX_BUTTON_RESET_EN (1 << 4)
> +};
> +
Please take the opportunity to remove this slab list of #defines from
the centre of the struct definition. Just above will be fine.
> struct mc13xxx_buttons_platform_data {
> -#define MC13783_BUTTON_DBNC_0MS 0
> -#define MC13783_BUTTON_DBNC_30MS 1
> -#define MC13783_BUTTON_DBNC_150MS 2
> -#define MC13783_BUTTON_DBNC_750MS 3
> -#define MC13783_BUTTON_ENABLE (1 << 2)
> -#define MC13783_BUTTON_POL_INVERT (1 << 3)
> -#define MC13783_BUTTON_RESET_EN (1 << 4)
> - int b1on_flags;
> - unsigned short b1on_key;
> - int b2on_flags;
> - unsigned short b2on_key;
> - int b3on_flags;
> - unsigned short b3on_key;
> + struct mc13xxx_button buttons[MAX13XXX_NUM_BUTTONS];
> };
>
> struct mc13xxx_ts_platform_data {
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
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: Re: [PATCH] Introduce Naming Convention in Input Subsystem
From: Aniroop Mathur @ 2014-02-10 15:54 UTC (permalink / raw)
To: Dmitry Torokhov, Benjamin Tissoires
Cc: linux-input@vger.kernel.org, cpgs ., Aniroop Mathur
In-Reply-To: <20140120214933.GA4270@core.coreip.homeip.net>
Dear Mr. Torokhov, Mr. Benjamin,
Greetings!
I sent a mail on January 25th, but still waiting for the reply.
Therefore, sending it again.
I hope to hear soon ~
On Tue, Jan 21, 2014 at 3:19 AM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> Hi Aniroop,
>
> On Tue, Jan 21, 2014 at 01:34:07AM +0530, Aniroop Mathur wrote:
>> Hello Mr Tissoires
>> Greetings !!
>>
>> On Jan 20, 2014 11:54 PM, "Benjamin Tissoires" <benjamin.tissoires@gmail.com>
>> wrote:
>> >
>> > Hi Aniroop,
>> >
>> > [sorry for top posting, but I really don't know where to put this
>> regarding your answers].
>> >
>> No problem at all.
>> In fact I am quite happy to hear from
>> Linux community again
>> Its my pleasure.
>>
>> > I _think_ I get one of the reasons you don't understand Dmitry, and why
>> Dmitry does not understand you. From the different mails, I would say that
>> you are referring to an Android platform.
>> > If it's not the case, then sorry for the noise.
>> >
>> No I am not specifically referring to
>> Android platform
>> But yes, I am from android background
>> and through android only I came up with
>> this idea.
>>
>> > So, the last time I checked with android, this system does _not_ have an
>> udev user-space daemon, which means that what you seem to be doing is
>> parsing manually the sysfs tree to retrieve the inputs and their properties.
>> > This, IMO, is a very bad idea. Parsing the entire sysfs tree is indeed
>> costly and you will have to build everything by hand.
>> >
>> No, Android also have a daemon but it is not udev daemon. There is a
>> separate daemon in android different from generic
>> udev daemon. It is different but basic is
>> still same.
>> Just like udev daemon, android daemon
>> also receives uevents from kernel
>> and creates devfs nodes for us,
>> that is /Dev/input/event1/2/3... based
>> on uevent env variables.
>> Android daemon is different from generic
>> daemon in a sense it does not see any file
>> like udev rules before creating nodes. Instead it directly create nodes as
>> per uevent env variables in the structure.
>> So without opening any extra udev rule
>> file, it create nodes.
>> So I understand it has also a limitation that it only has to be dependent
>> only on default uevents and cannot read any sysfs attribute to identify the
>> device if default uevents are not sufficient.
>
> Why can it not?
>
It cannot because currently in android code, it does not read any
sysfs attribute.
It only reads default kernel uevents. I think functionality may be added to read
sysfs attribute also but this functionality is currently not added in
android code.
I think it is not added because in embedded system mostly there are only single
and unique devices and this manipulation might add extra time during android
initialization.
>>
>> But the problem I am referring is for both in case of generic kernel and
>> android kernel.
>
> So far I really do not see it as generic kernel problem since we do have
> existing infrastructure in userspace that is quite efficient.
>
The existing way is also there but there is always a scope of improvement.
Tell me which is more efficient ?
1. existing method in which udev opens and read udev files for setting name
or
2. Directly set name without doing extra calculations
Its correct existing method will also do the same task but why not to use
more efficient way.
I just want to improve efficiency.
>>
>> > On regular distros, we use udev. This daemon builds its device database
>> from the events generated by the kernels directly (the uevents). Once the
>> events are emitted, we never (except for some user-space drivers) use them
>> in the kernel drivers (at least, I never saw that).
>> >
>> > So if you want to create symlinks, then indeed, you just add 2 or 3 rules
>> in /etc/udev/rules.d, and then the user space (and the system integrator)
>> can see the different devices with the "correct" symlink.
>> > However, the kernel developer will never see them (and especially in the
>> ->probe callback). However, the user-space tools which receives the udev
>> events (emitted from udev, not the kernel this time) can easily retrieve
>> many information from the event. Just run "udevadm info --export-db" on a
>> regular Linux, and you will see that the device which presents the event
>> node (/dev/input/eventX) has all the requirements to identify itself (VID,
>> PID, path, etc...)
>> >
>> Yes udev gives so many uevents but as I checked through logs specifically
>> in case of /Dev/input/event1/2/3/4....it does not give sufficient uevents
>> to identify the device.
>> As I found in logs it gives only 7 env variable like action, subsystem, Dev
>> name, Dev path, major, minor and seq number.
>> It does not give vendor Id or pid.
>> Now with these uevent we cannot identify the input device whether its
>> accelerometer or touchscreen. Can we ??
>
> While information sent in uevent emitted for creation of event device
> might not be enough to identify and classify input device you can:
>
> 1. Capture udevent sent a few moments earlier for the input device
> itself, or
>
> 2. Read /sys/class/$DEVNAME/device/uevent to retrieve input device's
> uevent data:
>
> [dtor@dtor-d630 work]$ cat /sys/class/input/event6/uevent
> MAJOR=13
> MINOR=70
> DEVNAME=input/event6
> [dtor@dtor-d630 work]$ cat /sys/class/input/event6/device/uevent
> PRODUCT=11/2/8/300
> NAME="AlpsPS/2 ALPS DualPoint TouchPad"
> PHYS="isa0060/serio1/input0"
> PROP=8
> EV=b
> KEY=e420 70000 0 0 0 0
> ABS=260800001000003
> MODALIAS=input:b0011v0002p0008e0300-e0,1,3,k110,111,112,145,14A,14D,14E,14F,ra0,1,18,2F,35,36,39,mlsfw
> [dtor@dtor-d630 work]$
>
> That should give you plenty data to work with. Yes, the 2nd option
> involves additional filesystem operations, but this is sysfs (so you are
> not hitting real media) and you only need a few (open, read, and close)
> per device.
Yes this method can surely solve the task , but not the purpose.
My query is why not to use more efficient way when we can ?
( Already discussed this way is backward compatible and is optional to use)
Apart from above, Could you please tell me the role/use of init_name variable,
which is defined in "struct device" ?
(I think, it is also used to set name of device node)
Thanks,
Aniroop Mathur
>
> Thanks.
>
> --
> Dmitry
^ permalink raw reply
* [PATCH 1/2] gpio: adp5588: get value from data out when dir is out
From: Jean-Francois Dagenais @ 2014-02-10 17:05 UTC (permalink / raw)
To: michael.hennerich, dmitry.torokhov, dtor, linus.walleij, gnurou
Cc: linux-gpio, linux-input, Jean-Francois Dagenais
As discussed here: http://ez.analog.com/message/35852,
the 5587 revC and 5588 revB spec sheets contain a mistake
in the GPIO_DAT_STATx register description.
According to R.Shnell at ADI, as well as my own
observations, it should read:
"GPIO data status (shows GPIO state when read for inputs)".
This commit changes the get value function accordingly.
Signed-off-by: Jean-Francois Dagenais <jeff.dagenais@gmail.com>
---
drivers/gpio/gpio-adp5588.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c
index 3f190e6..7d3c8d9 100644
--- a/drivers/gpio/gpio-adp5588.c
+++ b/drivers/gpio/gpio-adp5588.c
@@ -67,9 +67,20 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
{
struct adp5588_gpio *dev =
container_of(chip, struct adp5588_gpio, gpio_chip);
+ unsigned bank = ADP5588_BANK(off);
+ unsigned bit = ADP5588_BIT(off);
+ int val;
- return !!(adp5588_gpio_read(dev->client,
- GPIO_DAT_STAT1 + ADP5588_BANK(off)) & ADP5588_BIT(off));
+ mutex_lock(&dev->lock);
+
+ if (dev->dir[bank] & bit)
+ val = dev->dat_out[bank];
+ else
+ val = adp5588_gpio_read(dev->client, GPIO_DAT_STAT1 + bank);
+
+ mutex_unlock(&dev->lock);
+
+ return !!(val & bit);
}
static void adp5588_gpio_set_value(struct gpio_chip *chip,
--
1.8.5.3
^ permalink raw reply related
* [PATCH 2/2] input: adp5588-keys: get value from data out when dir is out
From: Jean-Francois Dagenais @ 2014-02-10 17:05 UTC (permalink / raw)
To: michael.hennerich, dmitry.torokhov, dtor, linus.walleij, gnurou
Cc: linux-gpio, linux-input, Jean-Francois Dagenais
In-Reply-To: <1392051929-32290-1-git-send-email-jeff.dagenais@gmail.com>
As discussed here: http://ez.analog.com/message/35852,
the 5587 revC and 5588 revB spec sheets contain a mistake
in the GPIO_DAT_STATx register description.
According to R.Shnell at ADI, as well as my own
observations, it should read:
"GPIO data status (shows GPIO state when read for inputs)".
This commit changes the get value function accordingly.
Signed-off-by: Jean-Francois Dagenais <jeff.dagenais@gmail.com>
---
drivers/input/keyboard/adp5588-keys.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index bb3b57b..5ef7fcf 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -76,8 +76,18 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
+ int val;
- return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
+ mutex_lock(&kpad->gpio_lock);
+
+ if (kpad->dir[bank] & bit)
+ val = kpad->dat_out[bank];
+ else
+ val = adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank);
+
+ mutex_unlock(&kpad->gpio_lock);
+
+ return !!(val & bit);
}
static void adp5588_gpio_set_value(struct gpio_chip *chip,
--
1.8.5.3
^ permalink raw reply related
* [PATCH 2/2] gpio: adp5588 - add support for gpio names
From: Jean-Francois Dagenais @ 2014-02-10 17:24 UTC (permalink / raw)
To: michael.hennerich, dmitry.torokhov, dtor, linus.walleij, gnurou
Cc: linux-gpio, linux-input, Jean-Francois Dagenais
In-Reply-To: <1392053045-12121-1-git-send-email-jeff.dagenais@gmail.com>
which is already found in the common header for adp5588
Signed-off-by: Jean-Francois Dagenais <jeff.dagenais@gmail.com>
---
drivers/gpio/gpio-adp5588.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c
index 7d3c8d9..d974020 100644
--- a/drivers/gpio/gpio-adp5588.c
+++ b/drivers/gpio/gpio-adp5588.c
@@ -397,6 +397,7 @@ static int adp5588_gpio_probe(struct i2c_client *client,
gc->ngpio = ADP5588_MAXGPIO;
gc->label = client->name;
gc->owner = THIS_MODULE;
+ gc->names = pdata->names;
mutex_init(&dev->lock);
--
1.8.5.3
^ permalink raw reply related
* [PATCH 1/2] gpio: adp5588 - use "unsigned" for the setup and teardown callbacks
From: Jean-Francois Dagenais @ 2014-02-10 17:24 UTC (permalink / raw)
To: michael.hennerich, dmitry.torokhov, dtor, linus.walleij, gnurou
Cc: linux-gpio, linux-input, Jean-Francois Dagenais
to comply with the rest of the GPIO drivers.
Signed-off-by: Jean-Francois Dagenais <jeff.dagenais@gmail.com>
---
include/linux/i2c/adp5588.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h
index d8341cb..c215304 100644
--- a/include/linux/i2c/adp5588.h
+++ b/include/linux/i2c/adp5588.h
@@ -161,10 +161,10 @@ struct adp5588_gpio_platform_data {
unsigned irq_base; /* interrupt base # */
unsigned pullup_dis_mask; /* Pull-Up Disable Mask */
int (*setup)(struct i2c_client *client,
- int gpio, unsigned ngpio,
+ unsigned gpio, unsigned ngpio,
void *context);
int (*teardown)(struct i2c_client *client,
- int gpio, unsigned ngpio,
+ unsigned gpio, unsigned ngpio,
void *context);
void *context;
};
--
1.8.5.3
^ permalink raw reply related
* [PATCH 00/14] HID: low-level transport cleanup, round 2
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
Hi guys,
this is the second part of the low-level HID transport cleanup.
The series goes on top of the previous one I sent last week.
Some highlights:
- remove hid_output_raw_report from struct hid_device
- uniformization of all transport driver by having only 2 mandatory
communication functions to implement: .raw_request and .output_report
Cheers,
Benjamin
Benjamin Tissoires (14):
HID: uHID: remove duplicated code
HID: uHID: implement .raw_request
HID: core: implement generic .request()
HID: i2c-hid: implement ll_driver transport-layer callbacks
HID: i2c-hid: use generic .request() implementation
HID: usbhid: change return error of usbhid_output_report
HID: input: hid-input remove hid_output_raw_report call
HID: logitech-dj: remove hid_output_raw_report call
HID: replace hid_output_raw_report with hid_hw_raw_request for feature
requests
HID: wiimote: replace hid_output_raw_report with hid_hw_output_report
for output requests
HID: sony: remove hid_output_raw_report calls
HID: hidraw: replace hid_output_raw_report() calls by appropriates
ones
HID: remove hid_output_raw_report
HID: core: check parameters when sending/receiving data from the
device
drivers/hid/hid-core.c | 45 +++++++++++++++++++++++-
drivers/hid/hid-input.c | 10 ++++--
drivers/hid/hid-lg.c | 8 ++---
drivers/hid/hid-logitech-dj.c | 21 ++++-------
drivers/hid/hid-magicmouse.c | 4 +--
drivers/hid/hid-sony.c | 79 +++++++++++++++++++++++++++++-------------
drivers/hid/hid-thingm.c | 4 +--
drivers/hid/hid-wacom.c | 26 ++++++++------
drivers/hid/hid-wiimote-core.c | 4 +--
drivers/hid/hidraw.c | 22 +++++++++---
drivers/hid/i2c-hid/i2c-hid.c | 70 ++++++++++++++++++++-----------------
drivers/hid/uhid.c | 37 +++++++++-----------
drivers/hid/usbhid/hid-core.c | 14 +-------
include/linux/hid.h | 30 ++++++----------
net/bluetooth/hidp/core.c | 14 --------
15 files changed, 218 insertions(+), 170 deletions(-)
--
1.8.3.1
^ permalink raw reply
* [PATCH 01/14] HID: uHID: remove duplicated code
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
uhid_hid_output_report() can be implemented through a simple call
to uhid_hid_output_raw().
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/uhid.c | 22 +---------------------
1 file changed, 1 insertion(+), 21 deletions(-)
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 12439e1..b6de903 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -247,27 +247,7 @@ static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
size_t count)
{
- struct uhid_device *uhid = hid->driver_data;
- unsigned long flags;
- struct uhid_event *ev;
-
- if (count < 1 || count > UHID_DATA_MAX)
- return -EINVAL;
-
- ev = kzalloc(sizeof(*ev), GFP_KERNEL);
- if (!ev)
- return -ENOMEM;
-
- ev->type = UHID_OUTPUT;
- ev->u.output.size = count;
- ev->u.output.rtype = UHID_OUTPUT_REPORT;
- memcpy(ev->u.output.data, buf, count);
-
- spin_lock_irqsave(&uhid->qlock, flags);
- uhid_queue(uhid, ev);
- spin_unlock_irqrestore(&uhid->qlock, flags);
-
- return count;
+ return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT);
}
static struct hid_ll_driver uhid_hid_driver = {
--
1.8.3.1
^ permalink raw reply related
* [PATCH 02/14] HID: uHID: implement .raw_request
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
uHID is missing a SET_REPORT protocol implementation, but as
.hid_get_raw_report() as been removed from struct hid_device,
there were no means to access GET_REPORT in uhid.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/uhid.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index b6de903..60acee4 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -250,6 +250,21 @@ static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT);
}
+static int uhid_raw_request(struct hid_device *hid, unsigned char reportnum,
+ __u8 *buf, size_t len, unsigned char rtype,
+ int reqtype)
+{
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ return uhid_hid_get_raw(hid, reportnum, buf, len, rtype);
+ case HID_REQ_SET_REPORT:
+ /* TODO: implement proper SET_REPORT functionality */
+ return -ENOSYS;
+ default:
+ return -EIO;
+ }
+}
+
static struct hid_ll_driver uhid_hid_driver = {
.start = uhid_hid_start,
.stop = uhid_hid_stop,
@@ -257,6 +272,7 @@ static struct hid_ll_driver uhid_hid_driver = {
.close = uhid_hid_close,
.parse = uhid_hid_parse,
.output_report = uhid_hid_output_report,
+ .raw_request = uhid_raw_request,
};
#ifdef CONFIG_COMPAT
--
1.8.3.1
^ permalink raw reply related
* [PATCH 03/14] HID: core: implement generic .request()
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
.request() can be emulated through .raw_request()
we can implement this emulation in hid-core, and make .request
not mandatory for transport layer drivers.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/hid-core.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
include/linux/hid.h | 5 ++++-
2 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 18fe49b..f36778a 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1248,6 +1248,11 @@ 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)
+{
+ return ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
+}
+
/*
* Allocator for buffer that is going to be passed to hid_output_report()
*/
@@ -1258,7 +1263,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
* of implement() working on 8 byte chunks
*/
- int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
+ int len = hid_report_len(report);
return kmalloc(len, flags);
}
@@ -1314,6 +1319,44 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
return report;
}
+/*
+ * Implement a generic .request() callback, using .raw_request()
+ * DO NOT USE in hid drivers directly, but through hid_hw_request instead.
+ */
+void __hid_request(struct hid_device *hid, struct hid_report *report,
+ int reqtype)
+{
+ char *buf;
+ int ret;
+ int len;
+
+ if (!hid->ll_driver->raw_request)
+ return;
+
+ buf = hid_alloc_report_buf(report, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ len = hid_report_len(report);
+
+ if (reqtype == HID_REQ_SET_REPORT)
+ hid_output_report(report, buf);
+
+ ret = hid->ll_driver->raw_request(hid, report->id, buf, len,
+ report->type, reqtype);
+ if (ret < 0) {
+ dbg_hid("unable to complete request: %d\n", ret);
+ goto out;
+ }
+
+ if (reqtype == HID_REQ_GET_REPORT)
+ hid_input_report(hid, report->type, buf, ret, 0);
+
+out:
+ kfree(buf);
+}
+EXPORT_SYMBOL_GPL(__hid_request);
+
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
int interrupt)
{
diff --git a/include/linux/hid.h b/include/linux/hid.h
index a837ede..09fbbd7 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -753,6 +753,7 @@ struct hid_field *hidinput_get_led_field(struct hid_device *hid);
unsigned int hidinput_count_leds(struct hid_device *hid);
__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);
void hid_output_report(struct hid_report *report, __u8 *data);
+void __hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype);
u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
@@ -965,7 +966,9 @@ static inline void hid_hw_request(struct hid_device *hdev,
struct hid_report *report, int reqtype)
{
if (hdev->ll_driver->request)
- hdev->ll_driver->request(hdev, report, reqtype);
+ return hdev->ll_driver->request(hdev, report, reqtype);
+
+ __hid_request(hdev, report, reqtype);
}
/**
--
1.8.3.1
^ permalink raw reply related
* [PATCH 04/14] HID: i2c-hid: implement ll_driver transport-layer callbacks
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
Add output_report and raw_request to i2c-hid.
The current implementation of i2c_hid_output_raw_report decides
by itself if it should use a direct send of the output report
or use the data register (SET_REPORT). Split that by reimplement
the logic in __i2c_hid_output_raw_report() which will be dropped
soon.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/i2c-hid/i2c-hid.c | 69 +++++++++++++++++++++++++++++++++++++------
1 file changed, 60 insertions(+), 9 deletions(-)
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index f57de7f..07a054a 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -257,12 +257,21 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
return 0;
}
-static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
- u8 reportID, unsigned char *buf, size_t data_len)
+/**
+ * i2c_hid_set_or_send_report: forward an incoming report to the device
+ * @client: the i2c_client of the device
+ * @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT
+ * @reportID: the report ID
+ * @buf: the actual data to transfer, without the report ID
+ * @len: size of buf
+ * @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report
+ */
+static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType,
+ u8 reportID, unsigned char *buf, size_t data_len, bool use_data)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
u8 *args = ihid->argsbuf;
- const struct i2c_hid_cmd * hidcmd = &hid_set_report_cmd;
+ const struct i2c_hid_cmd *hidcmd;
int ret;
u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
@@ -279,6 +288,9 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
i2c_hid_dbg(ihid, "%s\n", __func__);
+ if (!use_data && maxOutputLength == 0)
+ return -ENOSYS;
+
if (reportID >= 0x0F) {
args[index++] = reportID;
reportID = 0x0F;
@@ -288,9 +300,10 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
* use the data register for feature reports or if the device does not
* support the output register
*/
- if (reportType == 0x03 || maxOutputLength == 0) {
+ if (use_data) {
args[index++] = dataRegister & 0xFF;
args[index++] = dataRegister >> 8;
+ hidcmd = &hid_set_report_cmd;
} else {
args[index++] = outputRegister & 0xFF;
args[index++] = outputRegister >> 8;
@@ -559,7 +572,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid,
}
static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
- size_t count, unsigned char report_type)
+ size_t count, unsigned char report_type, bool use_data)
{
struct i2c_client *client = hid->driver_data;
int report_id = buf[0];
@@ -573,9 +586,9 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
count--;
}
- ret = i2c_hid_set_report(client,
+ ret = i2c_hid_set_or_send_report(client,
report_type == HID_FEATURE_REPORT ? 0x03 : 0x02,
- report_id, buf, count);
+ report_id, buf, count, use_data);
if (report_id && ret >= 0)
ret++; /* add report_id to the number of transfered bytes */
@@ -583,6 +596,42 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
return ret;
}
+static int __i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
+ size_t count, unsigned char report_type)
+{
+ struct i2c_client *client = hid->driver_data;
+ struct i2c_hid *ihid = i2c_get_clientdata(client);
+ bool data = true; /* SET_REPORT */
+
+ if (report_type == HID_OUTPUT_REPORT)
+ data = le16_to_cpu(ihid->hdesc.wMaxOutputLength) == 0;
+
+ return i2c_hid_output_raw_report(hid, buf, count, report_type, data);
+}
+
+static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf,
+ size_t count)
+{
+ return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT,
+ false);
+}
+
+static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
+ __u8 *buf, size_t len, unsigned char rtype,
+ int reqtype)
+{
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype);
+ case HID_REQ_SET_REPORT:
+ if (buf[0] != reportnum)
+ return -EINVAL;
+ return i2c_hid_output_raw_report(hid, buf, len, rtype, true);
+ default:
+ return -EIO;
+ }
+}
+
static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep,
int reqtype)
{
@@ -606,7 +655,7 @@ static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep,
break;
case HID_REQ_SET_REPORT:
hid_output_report(rep, buf);
- i2c_hid_output_raw_report(hid, buf, len, rep->type);
+ i2c_hid_output_raw_report(hid, buf, len, rep->type, true);
break;
}
@@ -769,6 +818,8 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
.close = i2c_hid_close,
.power = i2c_hid_power,
.request = i2c_hid_request,
+ .output_report = i2c_hid_output_report,
+ .raw_request = i2c_hid_raw_request,
};
static int i2c_hid_init_irq(struct i2c_client *client)
@@ -1003,7 +1054,7 @@ static int i2c_hid_probe(struct i2c_client *client,
hid->driver_data = client;
hid->ll_driver = &i2c_hid_ll_driver;
- hid->hid_output_raw_report = i2c_hid_output_raw_report;
+ hid->hid_output_raw_report = __i2c_hid_output_raw_report;
hid->dev.parent = &client->dev;
ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev));
hid->bus = BUS_I2C;
--
1.8.3.1
^ permalink raw reply related
* [PATCH 05/14] HID: i2c-hid: use generic .request() implementation
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
Having our own .request() implementation does not give anything,
so use the generic binding.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/i2c-hid/i2c-hid.c | 31 -------------------------------
1 file changed, 31 deletions(-)
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 07a054a..925fb8d 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -632,36 +632,6 @@ static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
}
}
-static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep,
- int reqtype)
-{
- struct i2c_client *client = hid->driver_data;
- char *buf;
- int ret;
- int len = i2c_hid_get_report_length(rep) - 2;
-
- buf = kzalloc(len, GFP_KERNEL);
- if (!buf)
- return;
-
- switch (reqtype) {
- case HID_REQ_GET_REPORT:
- ret = i2c_hid_get_raw_report(hid, rep->id, buf, len, rep->type);
- if (ret < 0)
- dev_err(&client->dev, "%s: unable to get report: %d\n",
- __func__, ret);
- else
- hid_input_report(hid, rep->type, buf, ret, 0);
- break;
- case HID_REQ_SET_REPORT:
- hid_output_report(rep, buf);
- i2c_hid_output_raw_report(hid, buf, len, rep->type, true);
- break;
- }
-
- kfree(buf);
-}
-
static int i2c_hid_parse(struct hid_device *hid)
{
struct i2c_client *client = hid->driver_data;
@@ -817,7 +787,6 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
.open = i2c_hid_open,
.close = i2c_hid_close,
.power = i2c_hid_power,
- .request = i2c_hid_request,
.output_report = i2c_hid_output_report,
.raw_request = i2c_hid_raw_request,
};
--
1.8.3.1
^ permalink raw reply related
* [PATCH 06/14] HID: usbhid: change return error of usbhid_output_report
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
If there is no urbout when sending a output report, ENOSYS (Function
not implemented) is a better error than EIO (I/O error).
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/usbhid/hid-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index b9a770f..0d1d875 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -922,7 +922,7 @@ static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
int actual_length, skipped_report_id = 0, ret;
if (!usbhid->urbout)
- return -EIO;
+ return -ENOSYS;
if (buf[0] == 0x0) {
/* Don't send the Report ID */
--
1.8.3.1
^ permalink raw reply related
* [PATCH 09/14] HID: replace hid_output_raw_report with hid_hw_raw_request for feature requests
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
ret = hid_output_raw_report(A, B, C, HID_FEATURE_REPORT);
is equivalent to
ret = hid_hw_raw_request(A, B[0], B, C, HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
whatever the transport layer is.
So use the new API where available
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/hid-lg.c | 8 ++++----
drivers/hid/hid-magicmouse.c | 4 ++--
drivers/hid/hid-sony.c | 4 ++--
drivers/hid/hid-thingm.c | 4 ++--
drivers/hid/hid-wacom.c | 26 +++++++++++++++-----------
5 files changed, 25 insertions(+), 21 deletions(-)
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index 76ed7e5..a976f48 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -692,8 +692,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- ret = hid_output_raw_report(hdev, buf, sizeof(buf),
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret >= 0) {
/* insert a little delay of 10 jiffies ~ 40ms */
@@ -705,8 +705,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
buf[1] = 0xB2;
get_random_bytes(&buf[2], 2);
- ret = hid_output_raw_report(hdev, buf, sizeof(buf),
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
}
}
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index cb5db3a..ecc2cbf 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -538,8 +538,8 @@ static int magicmouse_probe(struct hid_device *hdev,
* but there seems to be no other way of switching the mode.
* Thus the super-ugly hacky success check below.
*/
- ret = hid_output_raw_report(hdev, feature, sizeof(feature),
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, feature[0], feature, sizeof(feature),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret != -EIO && ret != sizeof(feature)) {
hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw;
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index d275c0d..d980943 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -824,8 +824,8 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
static int sixaxis_set_operational_bt(struct hid_device *hdev)
{
unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 };
- return hid_output_raw_report(hdev, buf, sizeof(buf),
- HID_FEATURE_REPORT);
+ return hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
}
static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
index 7dd3197..a97c788 100644
--- a/drivers/hid/hid-thingm.c
+++ b/drivers/hid/hid-thingm.c
@@ -48,8 +48,8 @@ static int blink1_send_command(struct blink1_data *data,
buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]);
- ret = hid_output_raw_report(data->hdev, buf, BLINK1_CMD_SIZE,
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
return ret < 0 ? ret : 0;
}
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index c720db9..902013e 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -128,7 +128,8 @@ static void wacom_set_image(struct hid_device *hdev, const char *image,
rep_data[0] = WAC_CMD_ICON_START_STOP;
rep_data[1] = 0;
- ret = hid_output_raw_report(hdev, rep_data, 2, HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret < 0)
goto err;
@@ -142,14 +143,15 @@ static void wacom_set_image(struct hid_device *hdev, const char *image,
rep_data[j + 3] = p[(i << 6) + j];
rep_data[2] = i;
- ret = hid_output_raw_report(hdev, rep_data, 67,
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 67,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
}
rep_data[0] = WAC_CMD_ICON_START_STOP;
rep_data[1] = 0;
- ret = hid_output_raw_report(hdev, rep_data, 2, HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
err:
return;
@@ -181,7 +183,8 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev,
buf[3] = value;
/* use fixed brightness for OLEDs */
buf[4] = 0x08;
- hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
+ hid_hw_raw_request(hdev, buf[0], buf, 9, HID_FEATURE_REPORT,
+ HID_REQ_SET_REPORT);
kfree(buf);
}
@@ -337,8 +340,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[0] = 0x03 ; rep_data[1] = 0x00;
limit = 3;
do {
- ret = hid_output_raw_report(hdev, rep_data, 2,
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
@@ -350,8 +353,9 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[1] = 0x00;
limit = 3;
do {
- ret = hid_output_raw_report(hdev,
- rep_data, 2, HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0],
+ rep_data, 2, HID_FEATURE_REPORT,
+ HID_REQ_SET_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
@@ -376,8 +380,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[0] = 0x03;
rep_data[1] = wdata->features;
- ret = hid_output_raw_report(hdev, rep_data, 2,
- HID_FEATURE_REPORT);
+ ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret >= 0)
wdata->high_speed = speed;
break;
--
1.8.3.1
^ permalink raw reply related
* [PATCH 10/14] HID: wiimote: replace hid_output_raw_report with hid_hw_output_report for output requests
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
For BT transport layer,
ret = hid_output_raw_report(A, B, C, HID_OUTPUT_REPORT);
is equivalent to
ret = hid_hw_output_report(A, B, C);
So use the new API where available
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/hid-wiimote-core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index d7dc6c5b..d003914 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -28,14 +28,14 @@ static int wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
__u8 *buf;
int ret;
- if (!hdev->hid_output_raw_report)
+ if (!hdev->ll_driver->output_report)
return -ENODEV;
buf = kmemdup(buffer, count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- ret = hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT);
+ ret = hid_hw_output_report(hdev, buf, count);
kfree(buf);
return ret;
--
1.8.3.1
^ permalink raw reply related
* [PATCH 11/14] HID: sony: remove hid_output_raw_report calls
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
We can not directly change the underlying struct hid_ll_driver here
as we did for hdev->hid_output_raw_report.
So allocate a struct ll_driver, and replace the old one when removing
the device.
To get a fully functional driver, we must also split the function
sixaxis_usb_output_raw_report() in 2, one regarding output_report, and
the other for raw_request.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/hid-sony.c | 75 ++++++++++++++++++++++++++++++++++----------------
1 file changed, 52 insertions(+), 23 deletions(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index d980943..dbbcd0c8 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -507,6 +507,8 @@ struct sony_sc {
struct work_struct state_worker;
struct power_supply battery;
+ struct hid_ll_driver *prev_ll_driver;
+
#ifdef CONFIG_SONY_FF
__u8 left;
__u8 right;
@@ -760,38 +762,52 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
/*
* The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP
- * like it should according to usbhid/hid-core.c::usbhid_output_raw_report()
+ * like it should according to usbhid/hid-core.c::usbhid_output_report()
* so we need to override that forcing HID Output Reports on the Control EP.
- *
- * There is also another issue about HID Output Reports via USB, the Sixaxis
- * does not want the report_id as part of the data packet, so we have to
- * discard buf[0] when sending the actual control message, even for numbered
- * reports, humpf!
*/
-static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
- size_t count, unsigned char report_type)
+static int sixaxis_usb_output_report(struct hid_device *hid, __u8 *buf,
+ size_t count)
+{
+ return hid_hw_raw_request(hid, buf[0], buf, count, HID_OUTPUT_REPORT,
+ HID_REQ_SET_REPORT);
+}
+
+/*
+ * There is also another issue about the SET_REPORT command via USB,
+ * the Sixaxis does not want the report_id as part of the data packet, so
+ * we have to discard buf[0] when sending the actual control message, even
+ * for numbered reports, humpf!
+ */
+static int sixaxis_usb_raw_request(struct hid_device *hid,
+ unsigned char reportnum, __u8 *buf,
+ size_t len, unsigned char rtype, int reqtype)
{
struct usb_interface *intf = to_usb_interface(hid->dev.parent);
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface = intf->cur_altsetting;
- int report_id = buf[0];
int ret;
+ u8 usb_dir;
+ unsigned int usb_pipe;
- if (report_type == HID_OUTPUT_REPORT) {
+ if (reqtype == HID_REQ_SET_REPORT) {
/* Don't send the Report ID */
buf++;
- count--;
+ len--;
+ usb_dir = USB_DIR_OUT;
+ usb_pipe = usb_sndctrlpipe(dev, 0);
+ } else {
+ usb_dir = USB_DIR_IN;
+ usb_pipe = usb_rcvctrlpipe(dev, 0);
}
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- HID_REQ_SET_REPORT,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ((report_type + 1) << 8) | report_id,
- interface->desc.bInterfaceNumber, buf, count,
+ ret = usb_control_msg(dev, usb_pipe, reqtype,
+ usb_dir | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ((rtype + 1) << 8) | reportnum,
+ interface->desc.bInterfaceNumber, buf, len,
USB_CTRL_SET_TIMEOUT);
- /* Count also the Report ID, in case of an Output report. */
- if (ret > 0 && report_type == HID_OUTPUT_REPORT)
+ /* Count also the Report ID. */
+ if (ret > 0 && reqtype == HID_REQ_SET_REPORT)
ret++;
return ret;
@@ -1047,7 +1063,7 @@ static void sixaxis_state_worker(struct work_struct *work)
buf[10] |= sc->led_state[2] << 3;
buf[10] |= sc->led_state[3] << 4;
- hid_output_raw_report(sc->hdev, buf, sizeof(buf), HID_OUTPUT_REPORT);
+ hid_hw_output_report(sc->hdev, buf, sizeof(buf));
}
static void dualshock4_state_worker(struct work_struct *work)
@@ -1254,6 +1270,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
unsigned long quirks = id->driver_data;
struct sony_sc *sc;
unsigned int connect_mask = HID_CONNECT_DEFAULT;
+ struct hid_ll_driver *ll_driver;
sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL);
if (sc == NULL) {
@@ -1285,13 +1302,20 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
- hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
+ ll_driver = devm_kzalloc(&hdev->dev, sizeof(*ll_driver),
+ GFP_KERNEL);
+ if (ll_driver == NULL)
+ return -ENOMEM;
+ sc->prev_ll_driver = hdev->ll_driver;
+ *ll_driver = *hdev->ll_driver;
+ hdev->ll_driver = ll_driver;
+ ll_driver->output_report = sixaxis_usb_output_report;
+ ll_driver->raw_request = sixaxis_usb_raw_request;
ret = sixaxis_set_operational_usb(hdev);
INIT_WORK(&sc->state_worker, sixaxis_state_worker);
- }
- else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
+ } else if (sc->quirks & SIXAXIS_CONTROLLER_BT) {
ret = sixaxis_set_operational_bt(hdev);
- else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
+ } else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
/* Report 5 (31 bytes) is used to send data to the controller via USB */
ret = sony_set_output_report(sc, 0x05, 248);
if (ret < 0)
@@ -1339,6 +1363,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
err_close:
hid_hw_close(hdev);
err_stop:
+ if (sc->prev_ll_driver)
+ hdev->ll_driver = sc->prev_ll_driver;
if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(hdev);
if (sc->quirks & SONY_BATTERY_SUPPORT)
@@ -1351,6 +1377,9 @@ static void sony_remove(struct hid_device *hdev)
{
struct sony_sc *sc = hid_get_drvdata(hdev);
+ if (sc->prev_ll_driver)
+ hdev->ll_driver = sc->prev_ll_driver;
+
if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(hdev);
--
1.8.3.1
^ permalink raw reply related
* [PATCH 12/14] HID: hidraw: replace hid_output_raw_report() calls by appropriates ones
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
Remove hid_output_raw_report() call as it is not a ll_driver callbacj,
and switch to the hid_hw_* implementation. USB-HID used to fallback
into SET_REPORT when there were no output interrupt endpoint,
so emulating this if hid_hw_output_report() returns -ENOSYS.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/hidraw.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index f8708c9..704718b 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -123,10 +123,8 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
dev = hidraw_table[minor]->hid;
- if (!dev->hid_output_raw_report) {
- ret = -ENODEV;
- goto out;
- }
+ if (!dev->ll_driver->raw_request || !dev->ll_driver->output_report)
+ return -ENODEV;
if (count > HID_MAX_BUFFER_SIZE) {
hid_warn(dev, "pid %d passed too large report\n",
@@ -153,7 +151,21 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
goto out_free;
}
- ret = hid_output_raw_report(dev, buf, count, report_type);
+ if (report_type == HID_OUTPUT_REPORT) {
+ ret = hid_hw_output_report(dev, buf, count);
+ /*
+ * compatibility with old implementation of USB-HID and I2C-HID:
+ * if the device does not support receiving output reports,
+ * on an interrupt endpoint, then fallback to the SET_REPORT
+ * HID command.
+ */
+ if (ret != -ENOSYS)
+ goto out_free;
+ }
+
+ ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type,
+ HID_REQ_SET_REPORT);
+
out_free:
kfree(buf);
out:
--
1.8.3.1
^ permalink raw reply related
* [PATCH 13/14] HID: remove hid_output_raw_report
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
hid_output_raw_report() is not used anymore, delete it.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/i2c-hid/i2c-hid.c | 14 --------------
drivers/hid/uhid.c | 1 -
drivers/hid/usbhid/hid-core.c | 12 ------------
include/linux/hid.h | 19 -------------------
net/bluetooth/hidp/core.c | 14 --------------
5 files changed, 60 deletions(-)
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 925fb8d..d3b8d7a 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -596,19 +596,6 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
return ret;
}
-static int __i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
- size_t count, unsigned char report_type)
-{
- struct i2c_client *client = hid->driver_data;
- struct i2c_hid *ihid = i2c_get_clientdata(client);
- bool data = true; /* SET_REPORT */
-
- if (report_type == HID_OUTPUT_REPORT)
- data = le16_to_cpu(ihid->hdesc.wMaxOutputLength) == 0;
-
- return i2c_hid_output_raw_report(hid, buf, count, report_type, data);
-}
-
static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf,
size_t count)
{
@@ -1023,7 +1010,6 @@ static int i2c_hid_probe(struct i2c_client *client,
hid->driver_data = client;
hid->ll_driver = &i2c_hid_ll_driver;
- hid->hid_output_raw_report = __i2c_hid_output_raw_report;
hid->dev.parent = &client->dev;
ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev));
hid->bus = BUS_I2C;
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 60acee4..7ed79be 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -400,7 +400,6 @@ static int uhid_dev_create(struct uhid_device *uhid,
hid->uniq[63] = 0;
hid->ll_driver = &uhid_hid_driver;
- hid->hid_output_raw_report = uhid_hid_output_raw;
hid->bus = ev->u.create.bus;
hid->vendor = ev->u.create.vendor;
hid->product = ev->u.create.product;
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 0d1d875..02b3256 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -945,17 +945,6 @@ static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
return ret;
}
-static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf,
- size_t count, unsigned char report_type)
-{
- struct usbhid_device *usbhid = hid->driver_data;
-
- if (usbhid->urbout && report_type != HID_FEATURE_REPORT)
- return usbhid_output_report(hid, buf, count);
-
- return usbhid_set_raw_report(hid, buf[0], buf, count, report_type);
-}
-
static void usbhid_restart_queues(struct usbhid_device *usbhid)
{
if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
@@ -1289,7 +1278,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
usb_set_intfdata(intf, hid);
hid->ll_driver = &usb_hid_driver;
- hid->hid_output_raw_report = usbhid_output_raw_report;
hid->ff_init = hid_pidff_init;
#ifdef CONFIG_USB_HIDDEV
hid->hiddev_connect = hiddev_connect;
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 09fbbd7..fa07639 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -508,9 +508,6 @@ struct hid_device { /* device report descriptor */
struct hid_usage *, __s32);
void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
- /* handler for raw output data, used by hidraw */
- int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t, unsigned char);
-
/* debugging support via debugfs */
unsigned short debug;
struct dentry *debug_dir;
@@ -1015,22 +1012,6 @@ static inline int hid_hw_output_report(struct hid_device *hdev, __u8 *buf,
}
/**
- * hid_output_raw_report - send an output or a feature report to the device
- *
- * @hdev: hid device
- * @buf: raw data to transfer
- * @len: length of buf
- * @report_type: HID_FEATURE_REPORT or HID_OUTPUT_REPORT
- *
- * @return: count of data transfered, negative if error
- */
-static inline int hid_output_raw_report(struct hid_device *hdev, __u8 *buf,
- size_t len, unsigned char report_type)
-{
- return hdev->hid_output_raw_report(hdev, buf, len, report_type);
-}
-
-/**
* hid_hw_idle - send idle request to device
*
* @hdev: hid device
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 77c4bad..89da18d 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -382,18 +382,6 @@ static int hidp_output_report(struct hid_device *hid, __u8 *data, size_t count)
data, count);
}
-static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data,
- size_t count, unsigned char report_type)
-{
- if (report_type == HID_OUTPUT_REPORT) {
- return hidp_output_report(hid, data, count);
- } else if (report_type != HID_FEATURE_REPORT) {
- return -EINVAL;
- }
-
- return hidp_set_raw_report(hid, data[0], data, count, report_type);
-}
-
static int hidp_raw_request(struct hid_device *hid, unsigned char reportnum,
__u8 *buf, size_t len, unsigned char rtype,
int reqtype)
@@ -773,8 +761,6 @@ static int hidp_setup_hid(struct hidp_session *session,
hid->dev.parent = &session->conn->hcon->dev;
hid->ll_driver = &hidp_hid_driver;
- hid->hid_output_raw_report = hidp_output_raw_report;
-
/* True if device is blacklisted in drivers/hid/hid-core.c */
if (hid_ignore(hid)) {
hid_destroy_device(session->hid);
--
1.8.3.1
^ permalink raw reply related
* [PATCH 14/14] HID: core: check parameters when sending/receiving data from the device
From: Benjamin Tissoires @ 2014-02-10 17:58 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, David Herrmann, linux-input,
linux-kernel
In-Reply-To: <1392055139-19631-1-git-send-email-benjamin.tissoires@redhat.com>
It is better to check them soon enough before triggering any kernel panic.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/i2c-hid/i2c-hid.c | 2 +-
include/linux/hid.h | 6 ++++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index d3b8d7a..b50860d 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -277,7 +277,7 @@ static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType,
u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength);
- /* hidraw already checked that data_len < HID_MAX_BUFFER_SIZE */
+ /* hid_hw_* already checked that data_len < HID_MAX_BUFFER_SIZE */
u16 size = 2 /* size */ +
(reportID ? 1 : 0) /* reportID */ +
data_len /* buf */;
diff --git a/include/linux/hid.h b/include/linux/hid.h
index fa07639..f801506 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -986,6 +986,9 @@ static inline int hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
size_t len, unsigned char rtype, int reqtype)
{
+ if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
+ return -EINVAL;
+
if (hdev->ll_driver->raw_request)
return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
rtype, reqtype);
@@ -1005,6 +1008,9 @@ static inline int hid_hw_raw_request(struct hid_device *hdev,
static inline int hid_hw_output_report(struct hid_device *hdev, __u8 *buf,
size_t len)
{
+ if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
+ return -EINVAL;
+
if (hdev->ll_driver->output_report)
return hdev->ll_driver->output_report(hdev, buf, len);
--
1.8.3.1
^ permalink raw reply related
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