* Re: [PATCH v2 03/10] dt-bindings: input: touchscreen: touch_adc: create bindings
From: Rob Herring @ 2018-04-09 18:46 UTC (permalink / raw)
To: Eugen Hristev
Cc: jic23, ludovic.desroches, alexandre.belloni, linux-arm-kernel,
devicetree, linux-kernel, linux-iio, linux-input, nicolas.ferre,
dmitry.torokhov
In-Reply-To: <1522153963-1121-4-git-send-email-eugen.hristev@microchip.com>
On Tue, Mar 27, 2018 at 03:32:36PM +0300, Eugen Hristev wrote:
> Added bindings for generic resistive touchscreen ADC.
>
> Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
> ---
> Changes in v2:
> - modified bindings to have a generic resistive touchscreen adc driver
> instead of specific architecture one.
>
> .../bindings/input/touchscreen/touch_adc.txt | 33 ++++++++++++++++++++++
> 1 file changed, 33 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/input/touchscreen/touch_adc.txt
>
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/touch_adc.txt b/Documentation/devicetree/bindings/input/touchscreen/touch_adc.txt
> new file mode 100644
> index 0000000..27abcdc
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/touchscreen/touch_adc.txt
> @@ -0,0 +1,33 @@
> +Generic resistive touchscreen ADC
> +
> +Required properties:
> +
> + - compatible: must be "generic-resistive-adc-touch"
Drop "generic-" and rename the file after the compatible string.
> +The device must be connected to an IIO device that provides channels for
s/IIO/ADC/
> +position measurement and optional pressure.
> +Refer to ../iio/iio-bindings.txt for details
> + - iio-channels: must have at least two channels connected to an IIO device.
> +These should correspond to the channels exposed by the IIO device and should
> +have the right index as the IIO device registers them. These channels
> +represent the relative position on the "x" and "y" axes.
> + - iio-channel-names: must have all the channels' names. Mandatory channels
> +are "x" and "y".
> +
> +Optional properties:
> + - iio-channels: The third channel named "pressure" is optional and can be
> +used if the IIO device also measures pressure besides position.
> +If this channel is missing, pressure will be ignored and the touchscreen
> +will only report position.
> + - iio-channel-names: optional channel named "pressure".
> + - generic-resistive-adc-touch,pressure-threshold: a pressure threshold for
> +the touchscreen, if we are using the "pressure" channel as well.
> +Represented by an integer value.
Define a common touchscreen property for this. We already have several
definitions.
It seems to me that "contact-threshold" would have been the same thing,
but it is deprecated in favor of "touchscreen-fuzz-pressure" which
doesn't really sound like the same thing.
Rob
^ permalink raw reply
* [PATCH] Input: i8042 - Never reset on Sony VAIO VGN-CS series
From: Ondrej Zary @ 2018-04-09 17:42 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, linux-kernel
Resetting i8042 breaks MUX on Sony VAIO VGN-CS. Never reset i8042 on
these machines to fix MUX after suspend.
Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
---
drivers/input/serio/i8042-x86ia64io.h | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 56644c74828c..34793e8bf636 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -544,16 +544,23 @@ static const struct dmi_system_id __initconst i8042_dmi_forcemux_table[] = {
{ }
};
-/*
- * On some Asus laptops, just running self tests cause problems.
- */
static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
{
+ /*
+ * On some Asus laptops, just running self tests cause problems.
+ */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
},
},
+ {
+ /* reset breaks MUX on Sony Vaio VGN-CS series */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"),
+ },
+ },
{ }
};
static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
--
Ondrej Zary
^ permalink raw reply related
* Re: [PATCH 2/2] HID: i2c-hid: Silently fail probe for CHPN0001 touchscreen
From: Sasha Levin @ 2018-04-09 17:07 UTC (permalink / raw)
To: Hans de Goede
Cc: Jiri Kosina, linux-input@vger.kernel.org, stable@vger.kernel.org
In-Reply-To: <585b5f34-8b00-bf84-5b99-fa204a3e3e75@redhat.com>
On Sat, Apr 07, 2018 at 11:42:03AM +0200, Hans de Goede wrote:
>Hi,
>
>On 06-04-18 22:05, Sasha Levin wrote:
>>Hi,
>>
>>[This is an automated email]
>>
>>This commit has been processed by the -stable helper bot and determined
>>to be a high probability candidate for -stable trees. (score: 20.8863)
>>
>>The bot has tested the following trees: v4.16, v4.15.15, v4.14.32, v4.9.92, v4.4.126.
>>
>>v4.16: Build OK!
>>v4.15.15: Build OK!
>>v4.14.32: Build OK!
>>v4.9.92: Failed to apply! Possible dependencies:
>> 94116f8126de ("ACPI: Switch to use generic guid_t in acpi_evaluate_dsm()")
>>
>>v4.4.126: Failed to apply! Possible dependencies:
>> 94116f8126de ("ACPI: Switch to use generic guid_t in acpi_evaluate_dsm()")
>
>Cool, first time I see this bot in action, nice work.
I'll leave it out, thanks!
>>Please let us know if you'd like to have this patch included in a stable tree.
>
>So FWIW this commit is NOT stable material (it cannot hurt, but it is not
>necessary). This commit really only makes sense together with a new touchscreen
>driver which does actually know how to handle the CHPN0001 touchscreen.
>
>For future mails like this, do I understand the mail correctly that if I
>do NOT want a patch picked up by the -stable helper bot to go to stable
>I do not have to do anything?
I would probably try and pick it up without an ack. If possible, even a
brief "no" reply if you don't want it in stable would be great. Thanks!
^ permalink raw reply
* Re: [PATCH v3 1/3] resource: Use list_head to link resource sibling
From: Nicolas Pitre @ 2018-04-09 16:05 UTC (permalink / raw)
To: Rob Herring
Cc: Brijesh Singh, devicetree, David Airlie, linux-pci, Wei Yang,
Keith Busch, Yaowei Bai, Frank Rowand, Thomas Gleixner,
Lorenzo Pieralisi, Stephen Hemminger, Baoquan He, linux-nvdimm,
Patrik Jakobsson, linux-input, Borislav Petkov, Tom Lendacky,
Haiyang Zhang, Jérôme Glisse, Bjorn Helgaas,
Dan Williams, Jonathan Derrick, Greg Kroah-Hartman
In-Reply-To: <CAL_Jsq+xxa9ep2LK3H6YWhwrZtc-T73Y84ry6Hs-JJ3XEXoGsw@mail.gmail.com>
On Mon, 9 Apr 2018, Rob Herring wrote:
> +Nico who has been working on tinification of the kernel.
>
> On Mon, Apr 9, 2018 at 4:08 AM, Baoquan He <bhe@redhat.com> wrote:
> > The struct resource uses singly linked list to link siblings. It's not
> > easy to do reverse iteration on sibling list. So replace it with list_head.
>
> Why is reverse iteration needed?
>
> > And code refactoring makes codes in kernel/resource.c more readable than
> > pointer operation.
>
> resource_for_each_* helpers could solve that without the size increase.
>
> > Besides, type of member variables of struct resource, sibling and child, are
> > changed from 'struct resource *' to 'struct list_head'. Kernel size will
> > increase because of those statically defined struct resource instances.
>
> The DT struct device_node also has the same tree structure with
> parent, child, sibling pointers and converting to list_head had been
> on the todo list for a while. ACPI also has some tree walking
> functions (drivers/acpi/acpica/pstree.c). Perhaps there should be a
> common tree struct and helpers defined either on top of list_head or a
> new struct if that saves some size.
>
> >
> > Signed-off-by: Baoquan He <bhe@redhat.com>
> > ---
> > v2->v3:
> > Make sibling() and first_child() global so that they can be called
> > out of kernel/resource.c to simplify code.
>
> These should probably be inline functions. Or exported if not.
>
> >
> > Fix several code bugs found by kbuild test robot.
> >
> > Got report from lkp that kernel size increased. It's on purpose since
> > the type change of sibling and child inside struct resource{}. For
> > each struct resource variable, it will cost another 16 bytes on x86 64.
>
> The size increase should be mentioned in the commit log. More
> generally, the size increase is 2 pointers.
Tiny kernels have much fewer resources anyway, and usually run on
platforms with 32-bit pointers, so this probably won't matter much in
the end.
This is if reverse iteration is actually needed as you say though.
Unless I'm mistaken, resource iteration doesn't happen that often, and
not in critical paths either.
Making the code clearer while keeping the same structure size could be
considered with the help of llist.h instead.
Nicolas
^ permalink raw reply
* Re: [PATCH v3 1/3] resource: Use list_head to link resource sibling
From: Dan Williams @ 2018-04-09 15:38 UTC (permalink / raw)
To: Baoquan He
Cc: Brijesh Singh, Device Tree, David Airlie,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Wei Yang, Keith Busch,
Yaowei Bai, K. Y. Srinivasan, Frank Rowand, Lorenzo Pieralisi,
Stephen Hemminger, linux-nvdimm, Patrik Jakobsson,
linux-input-u79uwXL29TY76Z2rM5mHXA, Borislav Petkov, Tom Lendacky,
Haiyang Zhang, Jérôme Glisse, Rob Herring,
Bjorn Helgaas, Thomas Gleixner, Jonathan Derrick
In-Reply-To: <20180409090853.GJ19345-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
On Mon, Apr 9, 2018 at 2:08 AM, Baoquan He <bhe-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> The struct resource uses singly linked list to link siblings. It's not
> easy to do reverse iteration on sibling list. So replace it with list_head.
>
> And code refactoring makes codes in kernel/resource.c more readable than
> pointer operation.
>
> Besides, type of member variables of struct resource, sibling and child, are
> changed from 'struct resource *' to 'struct list_head'. Kernel size will
> increase because of those statically defined struct resource instances.
>
> Signed-off-by: Baoquan He <bhe-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> ---
[..]
> diff --git a/kernel/resource.c b/kernel/resource.c
> index e270b5048988..473c624606f9 100644
> --- a/kernel/resource.c
> +++ b/kernel/resource.c
> @@ -31,6 +31,8 @@ struct resource ioport_resource = {
> .start = 0,
> .end = IO_SPACE_LIMIT,
> .flags = IORESOURCE_IO,
> + .sibling = LIST_HEAD_INIT(ioport_resource.sibling),
> + .child = LIST_HEAD_INIT(ioport_resource.child),
> };
> EXPORT_SYMBOL(ioport_resource);
>
> @@ -39,6 +41,8 @@ struct resource iomem_resource = {
> .start = 0,
> .end = -1,
> .flags = IORESOURCE_MEM,
> + .sibling = LIST_HEAD_INIT(iomem_resource.sibling),
> + .child = LIST_HEAD_INIT(iomem_resource.child),
> };
> EXPORT_SYMBOL(iomem_resource);
>
> @@ -57,20 +61,32 @@ static DEFINE_RWLOCK(resource_lock);
> * by boot mem after the system is up. So for reusing the resource entry
> * we need to remember the resource.
> */
> -static struct resource *bootmem_resource_free;
> +static struct list_head bootmem_resource_free = LIST_HEAD_INIT(bootmem_resource_free);
> static DEFINE_SPINLOCK(bootmem_resource_lock);
>
> +struct resource *sibling(struct resource *res)
> +{
> + if (res->parent && !list_is_last(&res->sibling, &res->parent->child))
> + return list_next_entry(res, sibling);
> + return NULL;
> +}
> +
> +struct resource *first_child(struct list_head *head)
> +{
> + return list_first_entry_or_null(head, struct resource, sibling);
> +}
> +
These names are too generic for new global symbols. A "resource_"
prefix is warranted.
^ permalink raw reply
* Re: [PATCH v3 1/3] resource: Use list_head to link resource sibling
From: Rob Herring @ 2018-04-09 14:49 UTC (permalink / raw)
To: Baoquan He, Nicolas Pitre
Cc: Brijesh Singh, devicetree-u79uwXL29TY76Z2rM5mHXA, David Airlie,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Wei Yang, Keith Busch,
Yaowei Bai, K. Y. Srinivasan, Frank Rowand, Thomas Gleixner,
Lorenzo Pieralisi, Stephen Hemminger,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw, Patrik Jakobsson,
linux-input-u79uwXL29TY76Z2rM5mHXA, Borislav Petkov, Tom Lendacky,
Haiyang Zhang, Jérôme Glisse, Bjorn Helgaas,
Jonathan Derrick, Greg Kroah-Hartman
In-Reply-To: <20180409090853.GJ19345-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
+Nico who has been working on tinification of the kernel.
On Mon, Apr 9, 2018 at 4:08 AM, Baoquan He <bhe-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> The struct resource uses singly linked list to link siblings. It's not
> easy to do reverse iteration on sibling list. So replace it with list_head.
Why is reverse iteration needed?
> And code refactoring makes codes in kernel/resource.c more readable than
> pointer operation.
resource_for_each_* helpers could solve that without the size increase.
> Besides, type of member variables of struct resource, sibling and child, are
> changed from 'struct resource *' to 'struct list_head'. Kernel size will
> increase because of those statically defined struct resource instances.
The DT struct device_node also has the same tree structure with
parent, child, sibling pointers and converting to list_head had been
on the todo list for a while. ACPI also has some tree walking
functions (drivers/acpi/acpica/pstree.c). Perhaps there should be a
common tree struct and helpers defined either on top of list_head or a
new struct if that saves some size.
>
> Signed-off-by: Baoquan He <bhe-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> ---
> v2->v3:
> Make sibling() and first_child() global so that they can be called
> out of kernel/resource.c to simplify code.
These should probably be inline functions. Or exported if not.
>
> Fix several code bugs found by kbuild test robot.
>
> Got report from lkp that kernel size increased. It's on purpose since
> the type change of sibling and child inside struct resource{}. For
> each struct resource variable, it will cost another 16 bytes on x86 64.
The size increase should be mentioned in the commit log. More
generally, the size increase is 2 pointers.
Rob
>
> arch/sparc/kernel/ioport.c | 2 +-
> drivers/gpu/drm/drm_memory.c | 3 +-
> drivers/gpu/drm/gma500/gtt.c | 5 +-
> drivers/hv/vmbus_drv.c | 52 ++++----
> drivers/input/joystick/iforce/iforce-main.c | 4 +-
> drivers/nvdimm/e820.c | 2 +-
> drivers/nvdimm/namespace_devs.c | 6 +-
> drivers/nvdimm/nd.h | 5 +-
> drivers/of/address.c | 4 +-
> drivers/parisc/lba_pci.c | 4 +-
> drivers/pci/host/vmd.c | 8 +-
> drivers/pci/probe.c | 2 +
> drivers/pci/setup-bus.c | 2 +-
> include/linux/ioport.h | 6 +-
> kernel/resource.c | 193 ++++++++++++++--------------
> 15 files changed, 149 insertions(+), 149 deletions(-)
>
> diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
> index 3bcef9ce74df..4e91fbbbedcc 100644
> --- a/arch/sparc/kernel/ioport.c
> +++ b/arch/sparc/kernel/ioport.c
> @@ -669,7 +669,7 @@ static int sparc_io_proc_show(struct seq_file *m, void *v)
> struct resource *root = m->private, *r;
> const char *nm;
>
> - for (r = root->child; r != NULL; r = r->sibling) {
> + list_for_each_entry(r, &root->child, sibling) {
> if ((nm = r->name) == NULL) nm = "???";
> seq_printf(m, "%016llx-%016llx: %s\n",
> (unsigned long long)r->start,
> diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c
> index 3c54044214db..53e300a993dc 100644
> --- a/drivers/gpu/drm/drm_memory.c
> +++ b/drivers/gpu/drm/drm_memory.c
> @@ -155,9 +155,8 @@ u64 drm_get_max_iomem(void)
> struct resource *tmp;
> resource_size_t max_iomem = 0;
>
> - for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) {
> + list_for_each_entry(tmp, &iomem_resource.child, sibling)
> max_iomem = max(max_iomem, tmp->end);
> - }
>
> return max_iomem;
> }
> diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c
> index 3949b0990916..addd3bc009af 100644
> --- a/drivers/gpu/drm/gma500/gtt.c
> +++ b/drivers/gpu/drm/gma500/gtt.c
> @@ -565,7 +565,7 @@ int psb_gtt_init(struct drm_device *dev, int resume)
> int psb_gtt_restore(struct drm_device *dev)
> {
> struct drm_psb_private *dev_priv = dev->dev_private;
> - struct resource *r = dev_priv->gtt_mem->child;
> + struct resource *r;
> struct gtt_range *range;
> unsigned int restored = 0, total = 0, size = 0;
>
> @@ -573,14 +573,13 @@ int psb_gtt_restore(struct drm_device *dev)
> mutex_lock(&dev_priv->gtt_mutex);
> psb_gtt_init(dev, 1);
>
> - while (r != NULL) {
> + list_for_each_entry(r, &dev_priv->gtt_mem->child, sibling) {
> range = container_of(r, struct gtt_range, resource);
> if (range->pages) {
> psb_gtt_insert(dev, range, 1);
> size += range->resource.end - range->resource.start;
> restored++;
> }
> - r = r->sibling;
> total++;
> }
> mutex_unlock(&dev_priv->gtt_mutex);
> diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
> index bc65c4d79c1f..7ba8a25520d9 100644
> --- a/drivers/hv/vmbus_drv.c
> +++ b/drivers/hv/vmbus_drv.c
> @@ -1413,9 +1413,8 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
> {
> resource_size_t start = 0;
> resource_size_t end = 0;
> - struct resource *new_res;
> + struct resource *new_res, *tmp;
> struct resource **old_res = &hyperv_mmio;
> - struct resource **prev_res = NULL;
>
> switch (res->type) {
>
> @@ -1462,44 +1461,36 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
> /*
> * If two ranges are adjacent, merge them.
> */
> - do {
> - if (!*old_res) {
> - *old_res = new_res;
> - break;
> - }
> -
> - if (((*old_res)->end + 1) == new_res->start) {
> - (*old_res)->end = new_res->end;
> + if (!*old_res) {
> + *old_res = new_res;
> + return AE_OK;
> + }
> + tmp = *old_res;
> + list_for_each_entry_from(tmp, &tmp->parent->child, sibling) {
> + if ((tmp->end + 1) == new_res->start) {
> + tmp->end = new_res->end;
> kfree(new_res);
> break;
> }
>
> - if ((*old_res)->start == new_res->end + 1) {
> - (*old_res)->start = new_res->start;
> + if (tmp->start == new_res->end + 1) {
> + tmp->start = new_res->start;
> kfree(new_res);
> break;
> }
>
> - if ((*old_res)->start > new_res->end) {
> - new_res->sibling = *old_res;
> - if (prev_res)
> - (*prev_res)->sibling = new_res;
> - *old_res = new_res;
> + if (tmp->start > new_res->end) {
> + list_add(&new_res->sibling, tmp->sibling.prev);
> break;
> }
> -
> - prev_res = old_res;
> - old_res = &(*old_res)->sibling;
> -
> - } while (1);
> + }
>
> return AE_OK;
> }
>
> static int vmbus_acpi_remove(struct acpi_device *device)
> {
> - struct resource *cur_res;
> - struct resource *next_res;
> + struct resource *res;
>
> if (hyperv_mmio) {
> if (fb_mmio) {
> @@ -1508,10 +1499,9 @@ static int vmbus_acpi_remove(struct acpi_device *device)
> fb_mmio = NULL;
> }
>
> - for (cur_res = hyperv_mmio; cur_res; cur_res = next_res) {
> - next_res = cur_res->sibling;
> - kfree(cur_res);
> - }
> + res = hyperv_mmio;
> + list_for_each_entry_from(res, &res->parent->child, sibling)
> + kfree(res);
> }
>
> return 0;
> @@ -1597,7 +1587,8 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
> }
> }
>
> - for (iter = hyperv_mmio; iter; iter = iter->sibling) {
> + iter = hyperv_mmio;
> + list_for_each_entry_from(iter, &iter->parent->child, sibling) {
> if ((iter->start >= max) || (iter->end <= min))
> continue;
>
> @@ -1640,7 +1631,8 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size)
> struct resource *iter;
>
> down(&hyperv_mmio_lock);
> - for (iter = hyperv_mmio; iter; iter = iter->sibling) {
> + iter = hyperv_mmio;
> + list_for_each_entry_from(iter, &iter->parent->child, sibling) {
> if ((iter->start >= start + size) || (iter->end <= start))
> continue;
>
> diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
> index daeeb4c7e3b0..5c0be27b33ff 100644
> --- a/drivers/input/joystick/iforce/iforce-main.c
> +++ b/drivers/input/joystick/iforce/iforce-main.c
> @@ -305,8 +305,8 @@ int iforce_init_device(struct iforce *iforce)
> iforce->device_memory.end = 200;
> iforce->device_memory.flags = IORESOURCE_MEM;
> iforce->device_memory.parent = NULL;
> - iforce->device_memory.child = NULL;
> - iforce->device_memory.sibling = NULL;
> + INIT_LIST_HEAD(&iforce->device_memory.child);
> + INIT_LIST_HEAD(&iforce->device_memory.sibling);
>
> /*
> * Wait until device ready - until it sends its first response.
> diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c
> index 6f9a6ffd7cde..513e661bb0d8 100644
> --- a/drivers/nvdimm/e820.c
> +++ b/drivers/nvdimm/e820.c
> @@ -53,7 +53,7 @@ static int e820_pmem_probe(struct platform_device *pdev)
> goto err;
> platform_set_drvdata(pdev, nvdimm_bus);
>
> - for (p = iomem_resource.child; p ; p = p->sibling) {
> + list_for_each_entry(p, &iomem_resource.child, sibling) {
> struct nd_region_desc ndr_desc;
>
> if (p->desc != IORES_DESC_PERSISTENT_MEMORY_LEGACY)
> diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
> index 658ada497be0..bcbdf5335909 100644
> --- a/drivers/nvdimm/namespace_devs.c
> +++ b/drivers/nvdimm/namespace_devs.c
> @@ -637,7 +637,7 @@ static resource_size_t scan_allocate(struct nd_region *nd_region,
> retry:
> first = 0;
> for_each_dpa_resource(ndd, res) {
> - struct resource *next = res->sibling, *new_res = NULL;
> + struct resource *next = sibling(res), *new_res = NULL;
> resource_size_t allocate, available = 0;
> enum alloc_loc loc = ALLOC_ERR;
> const char *action;
> @@ -763,7 +763,7 @@ static resource_size_t scan_allocate(struct nd_region *nd_region,
> * an initial "pmem-reserve pass". Only do an initial BLK allocation
> * when none of the DPA space is reserved.
> */
> - if ((is_pmem || !ndd->dpa.child) && n == to_allocate)
> + if ((is_pmem || list_empty(&ndd->dpa.child)) && n == to_allocate)
> return init_dpa_allocation(label_id, nd_region, nd_mapping, n);
> return n;
> }
> @@ -779,7 +779,7 @@ static int merge_dpa(struct nd_region *nd_region,
> retry:
> for_each_dpa_resource(ndd, res) {
> int rc;
> - struct resource *next = res->sibling;
> + struct resource *next = sibling(res);
> resource_size_t end = res->start + resource_size(res);
>
> if (!next || strcmp(res->name, label_id->id) != 0
> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
> index 184e070d50a2..1dc0b2370bd1 100644
> --- a/drivers/nvdimm/nd.h
> +++ b/drivers/nvdimm/nd.h
> @@ -102,11 +102,10 @@ unsigned sizeof_namespace_label(struct nvdimm_drvdata *ndd);
> (unsigned long long) (res ? res->start : 0), ##arg)
>
> #define for_each_dpa_resource(ndd, res) \
> - for (res = (ndd)->dpa.child; res; res = res->sibling)
> + list_for_each_entry(res, &(ndd)->dpa.child, sibling)
>
> #define for_each_dpa_resource_safe(ndd, res, next) \
> - for (res = (ndd)->dpa.child, next = res ? res->sibling : NULL; \
> - res; res = next, next = next ? next->sibling : NULL)
> + list_for_each_entry_safe(res, next, &(ndd)->dpa.child, sibling)
>
> struct nd_percpu_lane {
> int count;
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index 53349912ac75..e2e25719ab52 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -330,7 +330,9 @@ int of_pci_range_to_resource(struct of_pci_range *range,
> {
> int err;
> res->flags = range->flags;
> - res->parent = res->child = res->sibling = NULL;
> + res->parent = NULL;
> + INIT_LIST_HEAD(&res->child);
> + INIT_LIST_HEAD(&res->sibling);
> res->name = np->full_name;
>
> if (res->flags & IORESOURCE_IO) {
> diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
> index 69bd98421eb1..84f04418ae0b 100644
> --- a/drivers/parisc/lba_pci.c
> +++ b/drivers/parisc/lba_pci.c
> @@ -170,8 +170,8 @@ lba_dump_res(struct resource *r, int d)
> for (i = d; i ; --i) printk(" ");
> printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r,
> (long)r->start, (long)r->end, r->flags);
> - lba_dump_res(r->child, d+2);
> - lba_dump_res(r->sibling, d);
> + lba_dump_res(first_child(&r->child), d+2);
> + lba_dump_res(sibling(r), d);
> }
>
>
> diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c
> index 930a8fa08bd6..c3000af903ea 100644
> --- a/drivers/pci/host/vmd.c
> +++ b/drivers/pci/host/vmd.c
> @@ -520,14 +520,14 @@ static struct pci_ops vmd_ops = {
>
> static void vmd_attach_resources(struct vmd_dev *vmd)
> {
> - vmd->dev->resource[VMD_MEMBAR1].child = &vmd->resources[1];
> - vmd->dev->resource[VMD_MEMBAR2].child = &vmd->resources[2];
> + list_add(&vmd->resources[1].sibling, &vmd->dev->resource[VMD_MEMBAR1].child);
> + list_add(&vmd->resources[2].sibling, &vmd->dev->resource[VMD_MEMBAR2].child);
> }
>
> static void vmd_detach_resources(struct vmd_dev *vmd)
> {
> - vmd->dev->resource[VMD_MEMBAR1].child = NULL;
> - vmd->dev->resource[VMD_MEMBAR2].child = NULL;
> + INIT_LIST_HEAD(&vmd->dev->resource[VMD_MEMBAR1].child);
> + INIT_LIST_HEAD(&vmd->dev->resource[VMD_MEMBAR2].child);
> }
>
> /*
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index ac91b6fd0bcd..d162c77bec29 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -59,6 +59,8 @@ static struct resource *get_pci_domain_busn_res(int domain_nr)
> r->res.start = 0;
> r->res.end = 0xff;
> r->res.flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED;
> + INIT_LIST_HEAD(&r->res.child);
> + INIT_LIST_HEAD(&r->res.sibling);
>
> list_add_tail(&r->list, &pci_domain_busn_res_list);
>
> diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> index 072784f55ea5..0d5e30004ca6 100644
> --- a/drivers/pci/setup-bus.c
> +++ b/drivers/pci/setup-bus.c
> @@ -2107,7 +2107,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
> continue;
>
> /* Ignore BARs which are still in use */
> - if (res->child)
> + if (!list_empty(&res->child))
> continue;
>
> ret = add_to_list(&saved, bridge, res, 0, 0);
> diff --git a/include/linux/ioport.h b/include/linux/ioport.h
> index da0ebaec25f0..03d1510f03e0 100644
> --- a/include/linux/ioport.h
> +++ b/include/linux/ioport.h
> @@ -22,7 +22,8 @@ struct resource {
> const char *name;
> unsigned long flags;
> unsigned long desc;
> - struct resource *parent, *sibling, *child;
> + struct list_head child, sibling;
> + struct resource *parent;
> };
>
> /*
> @@ -189,6 +190,8 @@ extern int allocate_resource(struct resource *root, struct resource *new,
> resource_size_t,
> resource_size_t),
> void *alignf_data);
> +extern struct resource *sibling(struct resource *res);
> +extern struct resource *first_child(struct list_head *head);
> struct resource *lookup_resource(struct resource *root, resource_size_t start);
> int adjust_resource(struct resource *res, resource_size_t start,
> resource_size_t size);
> @@ -215,7 +218,6 @@ static inline bool resource_contains(struct resource *r1, struct resource *r2)
> return r1->start <= r2->start && r1->end >= r2->end;
> }
>
> -
> /* Convenience shorthand with allocation */
> #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0)
> #define request_muxed_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED)
> diff --git a/kernel/resource.c b/kernel/resource.c
> index e270b5048988..473c624606f9 100644
> --- a/kernel/resource.c
> +++ b/kernel/resource.c
> @@ -31,6 +31,8 @@ struct resource ioport_resource = {
> .start = 0,
> .end = IO_SPACE_LIMIT,
> .flags = IORESOURCE_IO,
> + .sibling = LIST_HEAD_INIT(ioport_resource.sibling),
> + .child = LIST_HEAD_INIT(ioport_resource.child),
> };
> EXPORT_SYMBOL(ioport_resource);
>
> @@ -39,6 +41,8 @@ struct resource iomem_resource = {
> .start = 0,
> .end = -1,
> .flags = IORESOURCE_MEM,
> + .sibling = LIST_HEAD_INIT(iomem_resource.sibling),
> + .child = LIST_HEAD_INIT(iomem_resource.child),
> };
> EXPORT_SYMBOL(iomem_resource);
>
> @@ -57,20 +61,32 @@ static DEFINE_RWLOCK(resource_lock);
> * by boot mem after the system is up. So for reusing the resource entry
> * we need to remember the resource.
> */
> -static struct resource *bootmem_resource_free;
> +static struct list_head bootmem_resource_free = LIST_HEAD_INIT(bootmem_resource_free);
> static DEFINE_SPINLOCK(bootmem_resource_lock);
>
> +struct resource *sibling(struct resource *res)
> +{
> + if (res->parent && !list_is_last(&res->sibling, &res->parent->child))
> + return list_next_entry(res, sibling);
> + return NULL;
> +}
> +
> +struct resource *first_child(struct list_head *head)
> +{
> + return list_first_entry_or_null(head, struct resource, sibling);
> +}
> +
> static struct resource *next_resource(struct resource *p, bool sibling_only)
> {
> /* Caller wants to traverse through siblings only */
> if (sibling_only)
> - return p->sibling;
> + return sibling(p);
>
> - if (p->child)
> - return p->child;
> - while (!p->sibling && p->parent)
> + if (!list_empty(&p->child))
> + return first_child(&p->child);
> + while (!sibling(p) && p->parent)
> p = p->parent;
> - return p->sibling;
> + return sibling(p);
> }
>
> static void *r_next(struct seq_file *m, void *v, loff_t *pos)
> @@ -90,7 +106,7 @@ static void *r_start(struct seq_file *m, loff_t *pos)
> struct resource *p = m->private;
> loff_t l = 0;
> read_lock(&resource_lock);
> - for (p = p->child; p && l < *pos; p = r_next(m, p, &l))
> + for (p = first_child(&p->child); p && l < *pos; p = r_next(m, p, &l))
> ;
> return p;
> }
> @@ -186,8 +202,7 @@ static void free_resource(struct resource *res)
>
> if (!PageSlab(virt_to_head_page(res))) {
> spin_lock(&bootmem_resource_lock);
> - res->sibling = bootmem_resource_free;
> - bootmem_resource_free = res;
> + list_add(&res->sibling, &bootmem_resource_free);
> spin_unlock(&bootmem_resource_lock);
> } else {
> kfree(res);
> @@ -199,10 +214,9 @@ static struct resource *alloc_resource(gfp_t flags)
> struct resource *res = NULL;
>
> spin_lock(&bootmem_resource_lock);
> - if (bootmem_resource_free) {
> - res = bootmem_resource_free;
> - bootmem_resource_free = res->sibling;
> - }
> + res = first_child(&bootmem_resource_free);
> + if (res)
> + list_del(&res->sibling);
> spin_unlock(&bootmem_resource_lock);
>
> if (res)
> @@ -210,6 +224,8 @@ static struct resource *alloc_resource(gfp_t flags)
> else
> res = kzalloc(sizeof(struct resource), flags);
>
> + INIT_LIST_HEAD(&res->child);
> + INIT_LIST_HEAD(&res->sibling);
> return res;
> }
>
> @@ -218,7 +234,7 @@ static struct resource * __request_resource(struct resource *root, struct resour
> {
> resource_size_t start = new->start;
> resource_size_t end = new->end;
> - struct resource *tmp, **p;
> + struct resource *tmp;
>
> if (end < start)
> return root;
> @@ -226,64 +242,62 @@ static struct resource * __request_resource(struct resource *root, struct resour
> return root;
> if (end > root->end)
> return root;
> - p = &root->child;
> - for (;;) {
> - tmp = *p;
> - if (!tmp || tmp->start > end) {
> - new->sibling = tmp;
> - *p = new;
> +
> + if (list_empty(&root->child)) {
> + list_add(&new->sibling, &root->child);
> + new->parent = root;
> + INIT_LIST_HEAD(&new->child);
> + return NULL;
> + }
> +
> + list_for_each_entry(tmp, &root->child, sibling) {
> + if (tmp->start > end) {
> + list_add(&new->sibling, tmp->sibling.prev);
> new->parent = root;
> + INIT_LIST_HEAD(&new->child);
> return NULL;
> }
> - p = &tmp->sibling;
> if (tmp->end < start)
> continue;
> return tmp;
> }
> +
> + list_add_tail(&new->sibling, &root->child);
> + new->parent = root;
> + INIT_LIST_HEAD(&new->child);
> + return NULL;
> }
>
> static int __release_resource(struct resource *old, bool release_child)
> {
> - struct resource *tmp, **p, *chd;
> + struct resource *tmp, *next, *chd;
>
> - p = &old->parent->child;
> - for (;;) {
> - tmp = *p;
> - if (!tmp)
> - break;
> + list_for_each_entry_safe(tmp, next, &old->parent->child, sibling) {
> if (tmp == old) {
> - if (release_child || !(tmp->child)) {
> - *p = tmp->sibling;
> + if (release_child || list_empty(&tmp->child)) {
> + list_del(&tmp->sibling);
> } else {
> - for (chd = tmp->child;; chd = chd->sibling) {
> + list_for_each_entry(chd, &tmp->child, sibling)
> chd->parent = tmp->parent;
> - if (!(chd->sibling))
> - break;
> - }
> - *p = tmp->child;
> - chd->sibling = tmp->sibling;
> + list_splice(&tmp->child, tmp->sibling.prev);
> + list_del(&tmp->sibling);
> }
> +
> old->parent = NULL;
> return 0;
> }
> - p = &tmp->sibling;
> }
> return -EINVAL;
> }
>
> static void __release_child_resources(struct resource *r)
> {
> - struct resource *tmp, *p;
> + struct resource *tmp, *next;
> resource_size_t size;
>
> - p = r->child;
> - r->child = NULL;
> - while (p) {
> - tmp = p;
> - p = p->sibling;
> -
> + list_for_each_entry_safe(tmp, next, &r->child, sibling) {
> tmp->parent = NULL;
> - tmp->sibling = NULL;
> + INIT_LIST_HEAD(&tmp->sibling);
> __release_child_resources(tmp);
>
> printk(KERN_DEBUG "release child resource %pR\n", tmp);
> @@ -292,6 +306,8 @@ static void __release_child_resources(struct resource *r)
> tmp->start = 0;
> tmp->end = size - 1;
> }
> +
> + INIT_LIST_HEAD(&tmp->child);
> }
>
> void release_child_resources(struct resource *r)
> @@ -376,7 +392,8 @@ static int find_next_iomem_res(struct resource *res, unsigned long desc,
>
> read_lock(&resource_lock);
>
> - for (p = iomem_resource.child; p; p = next_resource(p, sibling_only)) {
> + for (p = first_child(&iomem_resource.child); p;
> + p = next_resource(p, sibling_only)) {
> if ((p->flags & res->flags) != res->flags)
> continue;
> if ((desc != IORES_DESC_NONE) && (desc != p->desc))
> @@ -564,7 +581,7 @@ int region_intersects(resource_size_t start, size_t size, unsigned long flags,
> struct resource *p;
>
> read_lock(&resource_lock);
> - for (p = iomem_resource.child; p ; p = p->sibling) {
> + list_for_each_entry(p, &iomem_resource.child, sibling) {
> bool is_type = (((p->flags & flags) == flags) &&
> ((desc == IORES_DESC_NONE) ||
> (desc == p->desc)));
> @@ -618,7 +635,7 @@ static int __find_resource(struct resource *root, struct resource *old,
> resource_size_t size,
> struct resource_constraint *constraint)
> {
> - struct resource *this = root->child;
> + struct resource *this = first_child(&root->child);
> struct resource tmp = *new, avail, alloc;
>
> tmp.start = root->start;
> @@ -628,7 +645,7 @@ static int __find_resource(struct resource *root, struct resource *old,
> */
> if (this && this->start == root->start) {
> tmp.start = (this == old) ? old->start : this->end + 1;
> - this = this->sibling;
> + this = sibling(this);
> }
> for(;;) {
> if (this)
> @@ -663,7 +680,7 @@ next: if (!this || this->end == root->end)
>
> if (this != old)
> tmp.start = this->end + 1;
> - this = this->sibling;
> + this = sibling(this);
> }
> return -EBUSY;
> }
> @@ -707,7 +724,7 @@ static int reallocate_resource(struct resource *root, struct resource *old,
> goto out;
> }
>
> - if (old->child) {
> + if (!list_empty(&old->child)) {
> err = -EBUSY;
> goto out;
> }
> @@ -788,7 +805,7 @@ struct resource *lookup_resource(struct resource *root, resource_size_t start)
> struct resource *res;
>
> read_lock(&resource_lock);
> - for (res = root->child; res; res = res->sibling) {
> + list_for_each_entry(res, &root->child, sibling) {
> if (res->start == start)
> break;
> }
> @@ -821,32 +838,27 @@ static struct resource * __insert_resource(struct resource *parent, struct resou
> break;
> }
>
> - for (next = first; ; next = next->sibling) {
> + for (next = first; ; next = sibling(next)) {
> /* Partial overlap? Bad, and unfixable */
> if (next->start < new->start || next->end > new->end)
> return next;
> - if (!next->sibling)
> + if (!sibling(next))
> break;
> - if (next->sibling->start > new->end)
> + if (sibling(next)->start > new->end)
> break;
> }
> -
> new->parent = parent;
> - new->sibling = next->sibling;
> - new->child = first;
> + list_add(&new->sibling, &next->sibling);
> + INIT_LIST_HEAD(&new->child);
>
> - next->sibling = NULL;
> - for (next = first; next; next = next->sibling)
> + /*
> + * From first to next, they all fall into new's region, so change them
> + * as new's children.
> + */
> + list_cut_position(&new->child, first->sibling.prev, &next->sibling);
> + list_for_each_entry(next, &new->child, sibling)
> next->parent = new;
>
> - if (parent->child == first) {
> - parent->child = new;
> - } else {
> - next = parent->child;
> - while (next->sibling != first)
> - next = next->sibling;
> - next->sibling = new;
> - }
> return NULL;
> }
>
> @@ -968,19 +980,17 @@ static int __adjust_resource(struct resource *res, resource_size_t start,
> if ((start < parent->start) || (end > parent->end))
> goto out;
>
> - if (res->sibling && (res->sibling->start <= end))
> + if (sibling(res) && (sibling(res)->start <= end))
> goto out;
>
> - tmp = parent->child;
> - if (tmp != res) {
> - while (tmp->sibling != res)
> - tmp = tmp->sibling;
> + if (res->sibling.prev != &parent->child) {
> + tmp = list_prev_entry(res, sibling);
> if (start <= tmp->end)
> goto out;
> }
>
> skip:
> - for (tmp = res->child; tmp; tmp = tmp->sibling)
> + list_for_each_entry(tmp, &res->child, sibling)
> if ((tmp->start < start) || (tmp->end > end))
> goto out;
>
> @@ -1205,34 +1215,32 @@ EXPORT_SYMBOL(__request_region);
> void __release_region(struct resource *parent, resource_size_t start,
> resource_size_t n)
> {
> - struct resource **p;
> + struct resource *res;
> resource_size_t end;
>
> - p = &parent->child;
> + res = first_child(&parent->child);
> end = start + n - 1;
>
> write_lock(&resource_lock);
>
> for (;;) {
> - struct resource *res = *p;
> -
> if (!res)
> break;
> if (res->start <= start && res->end >= end) {
> if (!(res->flags & IORESOURCE_BUSY)) {
> - p = &res->child;
> + res = first_child(&res->child);
> continue;
> }
> if (res->start != start || res->end != end)
> break;
> - *p = res->sibling;
> + list_del(&res->sibling);
> write_unlock(&resource_lock);
> if (res->flags & IORESOURCE_MUXED)
> wake_up(&muxed_resource_wait);
> free_resource(res);
> return;
> }
> - p = &res->sibling;
> + res = sibling(res);
> }
>
> write_unlock(&resource_lock);
> @@ -1267,9 +1275,7 @@ EXPORT_SYMBOL(__release_region);
> int release_mem_region_adjustable(struct resource *parent,
> resource_size_t start, resource_size_t size)
> {
> - struct resource **p;
> - struct resource *res;
> - struct resource *new_res;
> + struct resource *res, *new_res;
> resource_size_t end;
> int ret = -EINVAL;
>
> @@ -1280,16 +1286,16 @@ int release_mem_region_adjustable(struct resource *parent,
> /* The alloc_resource() result gets checked later */
> new_res = alloc_resource(GFP_KERNEL);
>
> - p = &parent->child;
> + res = first_child(&parent->child);
> write_lock(&resource_lock);
>
> - while ((res = *p)) {
> + while ((res)) {
> if (res->start >= end)
> break;
>
> /* look for the next resource if it does not fit into */
> if (res->start > start || res->end < end) {
> - p = &res->sibling;
> + res = sibling(res);
> continue;
> }
>
> @@ -1297,14 +1303,14 @@ int release_mem_region_adjustable(struct resource *parent,
> break;
>
> if (!(res->flags & IORESOURCE_BUSY)) {
> - p = &res->child;
> + res = first_child(&res->child);
> continue;
> }
>
> /* found the target resource; let's adjust accordingly */
> if (res->start == start && res->end == end) {
> /* free the whole entry */
> - *p = res->sibling;
> + list_del(&res->sibling);
> free_resource(res);
> ret = 0;
> } else if (res->start == start && res->end != end) {
> @@ -1327,14 +1333,13 @@ int release_mem_region_adjustable(struct resource *parent,
> new_res->flags = res->flags;
> new_res->desc = res->desc;
> new_res->parent = res->parent;
> - new_res->sibling = res->sibling;
> - new_res->child = NULL;
> + INIT_LIST_HEAD(&new_res->child);
>
> ret = __adjust_resource(res, res->start,
> start - res->start);
> if (ret)
> break;
> - res->sibling = new_res;
> + list_add(&new_res->sibling, &res->sibling);
> new_res = NULL;
> }
>
> @@ -1515,7 +1520,7 @@ static int __init reserve_setup(char *str)
> res->end = io_start + io_num - 1;
> res->flags |= IORESOURCE_BUSY;
> res->desc = IORES_DESC_NONE;
> - res->child = NULL;
> + INIT_LIST_HEAD(&res->child);
> if (request_resource(parent, res) == 0)
> reserved = x+1;
> }
> @@ -1535,7 +1540,7 @@ int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
> loff_t l;
>
> read_lock(&resource_lock);
> - for (p = p->child; p ; p = r_next(NULL, p, &l)) {
> + for (p = first_child(&p->child); p; p = r_next(NULL, p, &l)) {
> /*
> * We can probably skip the resources without
> * IORESOURCE_IO attribute?
> @@ -1591,7 +1596,7 @@ bool iomem_is_exclusive(u64 addr)
> addr = addr & PAGE_MASK;
>
> read_lock(&resource_lock);
> - for (p = p->child; p ; p = r_next(NULL, p, &l)) {
> + for (p = first_child(&p->child); p; p = r_next(NULL, p, &l)) {
> /*
> * We can probably skip the resources without
> * IORESOURCE_IO attribute?
> --
> 2.13.6
>
^ permalink raw reply
* [PATCH v2 9/9] input: psmouse-smbus: allow to control psmouse_deactivate
From: Benjamin Tissoires @ 2018-04-09 9:10 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: kt.liao, Oliver Haessler, Benjamin Berg, Rob Herring, devicetree,
linux-input, linux-kernel, Benjamin Tissoires
In-Reply-To: <20180409091051.2944-1-benjamin.tissoires@redhat.com>
This seems to be Synaptics specific, as some Elan touchpads are not
correctly switching to SMBus if we call deactivate before switching to
SMBus on cold boot and on resume.
Tested with the T480s
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
changes in v2:
- rebased on top of previous
---
drivers/input/mouse/elantech.c | 2 +-
drivers/input/mouse/psmouse-smbus.c | 13 ++++++++++---
drivers/input/mouse/psmouse.h | 1 +
drivers/input/mouse/synaptics.c | 2 +-
4 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 07e40a58e66c..fb4d902c4403 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1774,7 +1774,7 @@ static int elantech_create_smbus(struct psmouse *psmouse,
if (info->has_trackpoint)
smbus_board.properties = i2c_properties;
- return psmouse_smbus_init(psmouse, &smbus_board, NULL, 0,
+ return psmouse_smbus_init(psmouse, &smbus_board, NULL, 0, false,
leave_breadcrumbs);
}
diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c
index c8a3b1f35ce3..852d4b486ddb 100644
--- a/drivers/input/mouse/psmouse-smbus.c
+++ b/drivers/input/mouse/psmouse-smbus.c
@@ -23,6 +23,7 @@ struct psmouse_smbus_dev {
struct i2c_client *client;
struct list_head node;
bool dead;
+ bool need_deactivate;
};
static LIST_HEAD(psmouse_smbus_list);
@@ -118,7 +119,10 @@ static psmouse_ret_t psmouse_smbus_process_byte(struct psmouse *psmouse)
static int psmouse_smbus_reconnect(struct psmouse *psmouse)
{
- psmouse_deactivate(psmouse);
+ struct psmouse_smbus_dev *smbdev = psmouse->private;
+
+ if (smbdev->need_deactivate)
+ psmouse_deactivate(psmouse);
return 0;
}
@@ -225,6 +229,7 @@ void psmouse_smbus_cleanup(struct psmouse *psmouse)
int psmouse_smbus_init(struct psmouse *psmouse,
const struct i2c_board_info *board,
const void *pdata, size_t pdata_size,
+ bool need_deactivate,
bool leave_breadcrumbs)
{
struct psmouse_smbus_dev *smbdev;
@@ -236,6 +241,7 @@ int psmouse_smbus_init(struct psmouse *psmouse,
smbdev->psmouse = psmouse;
smbdev->board = *board;
+ smbdev->need_deactivate = need_deactivate;
if (pdata) {
smbdev->board.platform_data = kmemdup(pdata, pdata_size,
@@ -246,6 +252,9 @@ int psmouse_smbus_init(struct psmouse *psmouse,
}
}
+ if (need_deactivate)
+ psmouse_deactivate(psmouse);
+
psmouse->private = smbdev;
psmouse->protocol_handler = psmouse_smbus_process_byte;
psmouse->reconnect = psmouse_smbus_reconnect;
@@ -253,8 +262,6 @@ int psmouse_smbus_init(struct psmouse *psmouse,
psmouse->disconnect = psmouse_smbus_disconnect;
psmouse->resync_time = 0;
- psmouse_deactivate(psmouse);
-
mutex_lock(&psmouse_smbus_mutex);
list_add_tail(&smbdev->node, &psmouse_smbus_list);
mutex_unlock(&psmouse_smbus_mutex);
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index dd4ec1f602d7..64c3a5d3fb3e 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -225,6 +225,7 @@ struct i2c_board_info;
int psmouse_smbus_init(struct psmouse *psmouse,
const struct i2c_board_info *board,
const void *pdata, size_t pdata_size,
+ bool need_deactivate,
bool leave_breadcrumbs);
void psmouse_smbus_cleanup(struct psmouse *psmouse);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 14a1188561aa..6b1ed53a8b03 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1751,7 +1751,7 @@ static int synaptics_create_intertouch(struct psmouse *psmouse,
};
return psmouse_smbus_init(psmouse, &intertouch_board,
- &pdata, sizeof(pdata),
+ &pdata, sizeof(pdata), true,
leave_breadcrumbs);
}
--
2.14.3
^ permalink raw reply related
* [PATCH v2 8/9] Input: elantech - detect new ICs and setup Host Notify for them
From: Benjamin Tissoires @ 2018-04-09 9:10 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: kt.liao, Oliver Haessler, Benjamin Berg, Rob Herring, devicetree,
linux-input, linux-kernel, Benjamin Tissoires
In-Reply-To: <20180409091051.2944-1-benjamin.tissoires@redhat.com>
New ICs are using a different scheme for the alternate bus parameter.
Given that they are new and are only using either PS2 only or PS2 + SMBus
Host Notify, we force those new ICs to use the SMBus solution for enhanced
reporting.
This allows the touchpad found on the Lenovo T480s to report 5 fingers
every 8 ms, instead of having a limit of 2 every 8 ms.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v2
drivers/input/mouse/elantech.c | 11 +++++++----
drivers/input/mouse/elantech.h | 15 +++++++++++++++
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 510e7c0622d3..07e40a58e66c 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1793,11 +1793,11 @@ static int elantech_setup_smbus(struct psmouse *psmouse,
if (elantech_smbus == ELANTECH_SMBUS_NOT_SET) {
/*
- * FIXME:
- * constraint the I2C capable devices by using FW version,
- * board version, or by using DMI matching
+ * New ICs are enabled by default.
+ * Old ICs are up to the user to decide.
*/
- return -ENXIO;
+ if (!ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version))
+ return -ENXIO;
}
psmouse_info(psmouse, "Trying to set up SMBus access\n");
@@ -1818,6 +1818,9 @@ static int elantech_setup_smbus(struct psmouse *psmouse,
static bool elantech_use_host_notify(struct psmouse *psmouse,
struct elantech_device_info *info)
{
+ if (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version))
+ return true;
+
switch (info->bus) {
case ETP_BUS_PS2_ONLY:
/* expected case */
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index f9b1c485e8d9..119727085a60 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -115,6 +115,21 @@
#define ETP_BUS_PS2_SMB_ALERT 3
#define ETP_BUS_PS2_SMB_HST_NTFY 4
+/*
+ * New ICs are either using SMBus Host Notify or just plain PS2.
+ *
+ * ETP_FW_VERSION_QUERY is:
+ * Byte 1:
+ * - bit 0..3: IC BODY
+ * Byte 2:
+ * - bit 4: HiddenButton
+ * - bit 5: PS2_SMBUS_NOTIFY
+ * - bit 6: PS2CRCCheck
+ */
+#define ETP_NEW_IC_SMBUS_HOST_NOTIFY(fw_version) \
+ ((((fw_version) & 0x0f2000) == 0x0f2000) && \
+ ((fw_version) & 0x0000ff) > 0)
+
/*
* The base position for one finger, v4 hardware
*/
--
2.14.3
^ permalink raw reply related
* [PATCH v2 7/9] Input: elantech - add support for SMBus devices
From: Benjamin Tissoires @ 2018-04-09 9:10 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: kt.liao, Oliver Haessler, Benjamin Berg, Rob Herring, devicetree,
linux-input, linux-kernel, Benjamin Tissoires
In-Reply-To: <20180409091051.2944-1-benjamin.tissoires@redhat.com>
Many of the Elantech devices are connected through PS/2 and a different
bus (SMBus or plain I2C).
To not break any existing device, we only enable SMBus based
on a module parameter. If some laptops require the quirk to
be set, we will have to rely on a list of PNPIds or MDI matching
to individually expose those hardware over SMBus.
the parameter mentioned above is elantech_smbus from the psmouse
module.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
changes in v2:
- use of device property instead of platform data
---
drivers/input/mouse/Kconfig | 12 +++
drivers/input/mouse/elantech.c | 188 +++++++++++++++++++++++++++++++++++-
drivers/input/mouse/elantech.h | 24 +++++
drivers/input/mouse/psmouse-base.c | 21 +++-
drivers/input/mouse/psmouse-smbus.c | 11 ++-
drivers/input/mouse/psmouse.h | 1 +
6 files changed, 246 insertions(+), 11 deletions(-)
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 89ebb8f39fee..f27f23f2d99a 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -133,6 +133,18 @@ config MOUSE_PS2_ELANTECH
If unsure, say N.
+config MOUSE_PS2_ELANTECH_SMBUS
+ bool "Elantech PS/2 SMbus companion" if EXPERT
+ default y
+ depends on MOUSE_PS2 && MOUSE_PS2_ELANTECH
+ depends on I2C=y || I2C=MOUSE_PS2
+ select MOUSE_PS2_SMBUS
+ help
+ Say Y here if you have a Elantech touchpad connected to
+ to an SMBus, but enumerated through PS/2.
+
+ If unsure, say Y.
+
config MOUSE_PS2_SENTELIC
bool "Sentelic Finger Sensing Pad PS/2 protocol extension"
depends on MOUSE_PS2
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index a2a14a31edb5..510e7c0622d3 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -14,13 +14,16 @@
#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
+#include <linux/platform_device.h>
#include <linux/serio.h>
#include <linux/libps2.h>
#include <asm/unaligned.h>
#include "psmouse.h"
#include "elantech.h"
+#include "elan_i2c.h"
#define elantech_debug(fmt, ...) \
do { \
@@ -1084,7 +1087,8 @@ static unsigned int elantech_convert_res(unsigned int val)
static int elantech_get_resolution_v4(struct psmouse *psmouse,
unsigned int *x_res,
- unsigned int *y_res)
+ unsigned int *y_res,
+ unsigned int *bus)
{
unsigned char param[3];
@@ -1093,6 +1097,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
*x_res = elantech_convert_res(param[1] & 0x0f);
*y_res = elantech_convert_res((param[1] & 0xf0) >> 4);
+ *bus = param[2];
return 0;
}
@@ -1474,6 +1479,12 @@ static void elantech_disconnect(struct psmouse *psmouse)
{
struct elantech_data *etd = psmouse->private;
+ /*
+ * We might have left a breadcrumb when trying to
+ * set up SMbus companion.
+ */
+ psmouse_smbus_cleanup(psmouse);
+
if (etd->tp_dev)
input_unregister_device(etd->tp_dev);
sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
@@ -1659,6 +1670,8 @@ static int elantech_query_info(struct psmouse *psmouse,
{
unsigned char param[3];
+ memset(info, 0, sizeof(*info));
+
/*
* Do the version query again so we can store the result
*/
@@ -1717,7 +1730,8 @@ static int elantech_query_info(struct psmouse *psmouse,
if (info->hw_version == 4) {
if (elantech_get_resolution_v4(psmouse,
&info->x_res,
- &info->y_res)) {
+ &info->y_res,
+ &info->bus)) {
psmouse_warn(psmouse,
"failed to query resolution data.\n");
}
@@ -1726,6 +1740,129 @@ static int elantech_query_info(struct psmouse *psmouse,
return 0;
}
+#if defined(CONFIG_MOUSE_PS2_ELANTECH_SMBUS)
+
+/*
+ * The newest Elantech device can use a secondary bus (over SMBus) which
+ * provides a better bandwidth and allow a better control of the touchpads.
+ * This is used to decide if we need to use this bus or not.
+ */
+enum {
+ ELANTECH_SMBUS_NOT_SET = -1,
+ ELANTECH_SMBUS_OFF,
+ ELANTECH_SMBUS_ON,
+};
+
+static int elantech_smbus = IS_ENABLED(CONFIG_MOUSE_ELAN_I2C_SMBUS) ?
+ ELANTECH_SMBUS_NOT_SET : ELANTECH_SMBUS_OFF;
+module_param_named(elantech_smbus, elantech_smbus, int, 0644);
+MODULE_PARM_DESC(elantech_smbus, "Use a secondary bus for the Elantech device.");
+
+static int elantech_create_smbus(struct psmouse *psmouse,
+ struct elantech_device_info *info,
+ bool leave_breadcrumbs)
+{
+ const struct property_entry i2c_properties[] = {
+ PROPERTY_ENTRY_BOOL("elan,trackpoint"),
+ { },
+ };
+ struct i2c_board_info smbus_board = {
+ I2C_BOARD_INFO("elan_i2c", 0x15),
+ .flags = I2C_CLIENT_HOST_NOTIFY,
+ };
+
+ if (info->has_trackpoint)
+ smbus_board.properties = i2c_properties;
+
+ return psmouse_smbus_init(psmouse, &smbus_board, NULL, 0,
+ leave_breadcrumbs);
+}
+
+/**
+ * elantech_setup_smbus - called once the PS/2 devices are enumerated
+ * and decides to instantiate a SMBus InterTouch device.
+ */
+static int elantech_setup_smbus(struct psmouse *psmouse,
+ struct elantech_device_info *info,
+ bool leave_breadcrumbs)
+{
+ int error;
+
+ if (elantech_smbus == ELANTECH_SMBUS_OFF)
+ return -ENXIO;
+
+ if (elantech_smbus == ELANTECH_SMBUS_NOT_SET) {
+ /*
+ * FIXME:
+ * constraint the I2C capable devices by using FW version,
+ * board version, or by using DMI matching
+ */
+ return -ENXIO;
+ }
+
+ psmouse_info(psmouse, "Trying to set up SMBus access\n");
+
+ error = elantech_create_smbus(psmouse, info, leave_breadcrumbs);
+ if (error) {
+ if (error == -EAGAIN)
+ psmouse_info(psmouse, "SMbus companion is not ready yet\n");
+ else
+ psmouse_err(psmouse, "unable to create intertouch device\n");
+
+ return error;
+ }
+
+ return 0;
+}
+
+static bool elantech_use_host_notify(struct psmouse *psmouse,
+ struct elantech_device_info *info)
+{
+ switch (info->bus) {
+ case ETP_BUS_PS2_ONLY:
+ /* expected case */
+ break;
+ case ETP_BUS_SMB_ALERT_ONLY:
+ /* fall-through */
+ case ETP_BUS_PS2_SMB_ALERT:
+ psmouse_dbg(psmouse, "Ignoring SMBus provider through alert protocol.\n");
+ break;
+ case ETP_BUS_SMB_HST_NTFY_ONLY:
+ /* fall-through */
+ case ETP_BUS_PS2_SMB_HST_NTFY:
+ return true;
+ default:
+ psmouse_dbg(psmouse,
+ "Ignoring SMBus bus provider %d.\n",
+ info->bus);
+ }
+
+ return false;
+}
+
+int elantech_init_smbus(struct psmouse *psmouse)
+{
+ struct elantech_device_info info;
+ int error = -EINVAL;
+
+ psmouse_reset(psmouse);
+
+ error = elantech_query_info(psmouse, &info);
+ if (error)
+ goto init_fail;
+
+ if (info.hw_version < 4) {
+ error = -ENXIO;
+ goto init_fail;
+ }
+
+ return elantech_create_smbus(psmouse, &info, false);
+ init_fail:
+ psmouse_reset(psmouse);
+ return error;
+}
+#endif /* CONFIG_MOUSE_PS2_ELANTECH_SMBUS */
+
/*
* Initialize the touchpad and create sysfs entries
*/
@@ -1734,7 +1871,7 @@ static int elantech_setup_ps2(struct psmouse *psmouse,
{
struct elantech_data *etd;
int i;
- int error;
+ int error = -EINVAL;
struct input_dev *tp_dev;
psmouse->private = etd = kzalloc(sizeof(*etd), GFP_KERNEL);
@@ -1821,7 +1958,7 @@ static int elantech_setup_ps2(struct psmouse *psmouse,
return error;
}
-int elantech_init(struct psmouse *psmouse)
+int elantech_init_ps2(struct psmouse *psmouse)
{
struct elantech_device_info info;
int error = -EINVAL;
@@ -1841,3 +1978,46 @@ int elantech_init(struct psmouse *psmouse)
psmouse_reset(psmouse);
return error;
}
+
+int elantech_init(struct psmouse *psmouse)
+{
+ struct elantech_device_info info;
+ int error = -EINVAL;
+
+ psmouse_reset(psmouse);
+
+ error = elantech_query_info(psmouse, &info);
+ if (error)
+ goto init_fail;
+
+#if defined(CONFIG_MOUSE_PS2_ELANTECH_SMBUS)
+
+ if (elantech_use_host_notify(psmouse, &info)) {
+ if (!IS_ENABLED(CONFIG_MOUSE_ELAN_I2C_SMBUS) ||
+ !IS_ENABLED(CONFIG_MOUSE_PS2_ELANTECH_SMBUS)) {
+ psmouse_warn(psmouse,
+ "The touchpad can support a better bus than the too old PS/2 protocol. "
+ "Make sure MOUSE_PS2_ELANTECH_SMBUS and MOUSE_ELAN_I2C_SMBUS are enabled to get a better touchpad experience.\n");
+ }
+ error = elantech_setup_smbus(psmouse, &info, true);
+ if (!error)
+ return PSMOUSE_ELANTECH_SMBUS;
+ }
+
+#endif /* CONFIG_MOUSE_PS2_ELANTECH_SMBUS */
+
+ error = elantech_setup_ps2(psmouse, &info);
+ if (error < 0) {
+ /*
+ * Not using any flavor of Elantech support, so clean up
+ * SMbus breadcrumbs, if any.
+ */
+ psmouse_smbus_cleanup(psmouse);
+ goto init_fail;
+ }
+
+ return PSMOUSE_ELANTECH;
+ init_fail:
+ psmouse_reset(psmouse);
+ return error;
+}
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index 851df4ce6232..f9b1c485e8d9 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -106,6 +106,15 @@
*/
#define ETP_WEIGHT_VALUE 5
+/*
+ * Bus information on 3rd byte of query ETP_RESOLUTION_QUERY(0x04)
+ */
+#define ETP_BUS_PS2_ONLY 0
+#define ETP_BUS_SMB_ALERT_ONLY 1
+#define ETP_BUS_SMB_HST_NTFY_ONLY 2
+#define ETP_BUS_PS2_SMB_ALERT 3
+#define ETP_BUS_PS2_SMB_HST_NTFY 4
+
/*
* The base position for one finger, v4 hardware
*/
@@ -122,6 +131,7 @@ struct elantech_device_info {
unsigned int fw_version;
unsigned int x_res;
unsigned int y_res;
+ unsigned int bus;
bool paritycheck;
bool jumpy_cursor;
bool reports_pressure;
@@ -156,6 +166,7 @@ struct elantech_data {
#ifdef CONFIG_MOUSE_PS2_ELANTECH
int elantech_detect(struct psmouse *psmouse, bool set_properties);
+int elantech_init_ps2(struct psmouse *psmouse);
int elantech_init(struct psmouse *psmouse);
#else
static inline int elantech_detect(struct psmouse *psmouse, bool set_properties)
@@ -166,6 +177,19 @@ static inline int elantech_init(struct psmouse *psmouse)
{
return -ENOSYS;
}
+static inline int elantech_init_ps2(struct psmouse *psmouse)
+{
+ return -ENOSYS;
+}
#endif /* CONFIG_MOUSE_PS2_ELANTECH */
+#if defined(CONFIG_MOUSE_PS2_ELANTECH_SMBUS)
+int elantech_init_smbus(struct psmouse *psmouse);
+#else
+static inline int elantech_init_smbus(struct psmouse *psmouse)
+{
+ return -ENOSYS;
+}
+#endif /* CONFIG_MOUSE_PS2_ELANTECH_SMBUS */
+
#endif
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 8900c3166ebf..5ff5b1952be0 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -856,7 +856,17 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.name = "ETPS/2",
.alias = "elantech",
.detect = elantech_detect,
- .init = elantech_init,
+ .init = elantech_init_ps2,
+ },
+#endif
+#ifdef CONFIG_MOUSE_PS2_ELANTECH_SMBUS
+ {
+ .type = PSMOUSE_ELANTECH_SMBUS,
+ .name = "ETSMBus",
+ .alias = "elantech-smbus",
+ .detect = elantech_detect,
+ .init = elantech_init_smbus,
+ .smbus_companion = true,
},
#endif
#ifdef CONFIG_MOUSE_PS2_SENTELIC
@@ -1158,8 +1168,13 @@ static int psmouse_extensions(struct psmouse *psmouse,
/* Try Elantech touchpad */
if (max_proto > PSMOUSE_IMEX &&
psmouse_try_protocol(psmouse, PSMOUSE_ELANTECH,
- &max_proto, set_properties, true)) {
- return PSMOUSE_ELANTECH;
+ &max_proto, set_properties, false)) {
+ if (!set_properties)
+ return PSMOUSE_ELANTECH;
+
+ ret = elantech_init(psmouse);
+ if (ret >= 0)
+ return ret;
}
if (max_proto > PSMOUSE_IMEX) {
diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c
index c7ac24d119c1..c8a3b1f35ce3 100644
--- a/drivers/input/mouse/psmouse-smbus.c
+++ b/drivers/input/mouse/psmouse-smbus.c
@@ -237,10 +237,13 @@ int psmouse_smbus_init(struct psmouse *psmouse,
smbdev->psmouse = psmouse;
smbdev->board = *board;
- smbdev->board.platform_data = kmemdup(pdata, pdata_size, GFP_KERNEL);
- if (!smbdev->board.platform_data) {
- kfree(smbdev);
- return -ENOMEM;
+ if (pdata) {
+ smbdev->board.platform_data = kmemdup(pdata, pdata_size,
+ GFP_KERNEL);
+ if (!smbdev->board.platform_data) {
+ kfree(smbdev);
+ return -ENOMEM;
+ }
}
psmouse->private = smbdev;
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 71ac50082c8b..dd4ec1f602d7 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -68,6 +68,7 @@ enum psmouse_type {
PSMOUSE_VMMOUSE,
PSMOUSE_BYD,
PSMOUSE_SYNAPTICS_SMBUS,
+ PSMOUSE_ELANTECH_SMBUS,
PSMOUSE_AUTO /* This one should always be last */
};
--
2.14.3
^ permalink raw reply related
* [PATCH v2 6/9] Input: elantech - query the resolution in query_info
From: Benjamin Tissoires @ 2018-04-09 9:10 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: kt.liao, Oliver Haessler, Benjamin Berg, Rob Herring, devicetree,
linux-input, linux-kernel, Benjamin Tissoires
In-Reply-To: <20180409091051.2944-1-benjamin.tissoires@redhat.com>
The command ETP_RESOLUTION_QUERY also contains the bus information.
It is better to fetch it once, while we are querying for device
information.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v2
drivers/input/mouse/elantech.c | 27 +++++++++++++++------------
drivers/input/mouse/elantech.h | 2 ++
2 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 980dfd7e861e..a2a14a31edb5 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1179,7 +1179,6 @@ static int elantech_set_input_params(struct psmouse *psmouse)
struct elantech_data *etd = psmouse->private;
struct elantech_device_info *info = &etd->info;
unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
- unsigned int x_res = 31, y_res = 31;
if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width))
return -1;
@@ -1232,13 +1231,6 @@ static int elantech_set_input_params(struct psmouse *psmouse)
break;
case 4:
- if (elantech_get_resolution_v4(psmouse, &x_res, &y_res)) {
- /*
- * if query failed, print a warning and leave the values
- * zero to resemble synaptics.c behavior.
- */
- psmouse_warn(psmouse, "couldn't query resolution data.\n");
- }
elantech_set_buttonpad_prop(psmouse);
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
/* For X to recognize me as touchpad. */
@@ -1267,11 +1259,11 @@ static int elantech_set_input_params(struct psmouse *psmouse)
break;
}
- input_abs_set_res(dev, ABS_X, x_res);
- input_abs_set_res(dev, ABS_Y, y_res);
+ input_abs_set_res(dev, ABS_X, info->x_res);
+ input_abs_set_res(dev, ABS_Y, info->y_res);
if (info->hw_version > 1) {
- input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
- input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
+ input_abs_set_res(dev, ABS_MT_POSITION_X, info->x_res);
+ input_abs_set_res(dev, ABS_MT_POSITION_Y, info->y_res);
}
etd->y_max = y_max;
@@ -1720,6 +1712,17 @@ static int elantech_query_info(struct psmouse *psmouse,
/* The MSB indicates the presence of the trackpoint */
info->has_trackpoint = (info->capabilities[0] & 0x80) == 0x80;
+ info->x_res = 31;
+ info->y_res = 31;
+ if (info->hw_version == 4) {
+ if (elantech_get_resolution_v4(psmouse,
+ &info->x_res,
+ &info->y_res)) {
+ psmouse_warn(psmouse,
+ "failed to query resolution data.\n");
+ }
+ }
+
return 0;
}
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index d8ac27fe4597..851df4ce6232 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -120,6 +120,8 @@ struct elantech_device_info {
unsigned char debug;
unsigned char hw_version;
unsigned int fw_version;
+ unsigned int x_res;
+ unsigned int y_res;
bool paritycheck;
bool jumpy_cursor;
bool reports_pressure;
--
2.14.3
^ permalink raw reply related
* [PATCH v2 5/9] Input: elantech_query_info() can be static
From: Benjamin Tissoires @ 2018-04-09 9:10 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: kt.liao, Oliver Haessler, Benjamin Berg, Rob Herring, devicetree,
linux-input, linux-kernel, Benjamin Tissoires, Fengguang Wu
In-Reply-To: <20180409091051.2944-1-benjamin.tissoires@redhat.com>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
new in v2, raised by kbuild test robot
---
drivers/input/mouse/elantech.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index d485664f1563..980dfd7e861e 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1662,8 +1662,8 @@ static int elantech_set_properties(struct elantech_device_info *info)
return 0;
}
-int elantech_query_info(struct psmouse *psmouse,
- struct elantech_device_info *info)
+static int elantech_query_info(struct psmouse *psmouse,
+ struct elantech_device_info *info)
{
unsigned char param[3];
--
2.14.3
^ permalink raw reply related
* [PATCH v2 4/9] Input: elantech - split device info into a separate structure
From: Benjamin Tissoires @ 2018-04-09 9:10 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: kt.liao, Oliver Haessler, Benjamin Berg, Rob Herring, devicetree,
linux-input, linux-kernel, Benjamin Tissoires
In-Reply-To: <20180409091051.2944-1-benjamin.tissoires@redhat.com>
In preparation for SMBus device support, move static device
information that we query form the touchpad upon initialization into
separate structure. This will allow us to query the device without
allocating memory first.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v2
drivers/input/mouse/elantech.c | 271 ++++++++++++++++++++++++-----------------
drivers/input/mouse/elantech.h | 28 +++--
2 files changed, 175 insertions(+), 124 deletions(-)
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index db47a5e1d114..d485664f1563 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -24,7 +24,7 @@
#define elantech_debug(fmt, ...) \
do { \
- if (etd->debug) \
+ if (etd->info.debug) \
psmouse_printk(KERN_DEBUG, psmouse, \
fmt, ##__VA_ARGS__); \
} while (0)
@@ -105,7 +105,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
if (reg > 0x11 && reg < 0x20)
return -1;
- switch (etd->hw_version) {
+ switch (etd->info.hw_version) {
case 1:
if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_READ) ||
ps2_sliced_command(&psmouse->ps2dev, reg) ||
@@ -137,7 +137,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
if (rc)
psmouse_err(psmouse, "failed to read register 0x%02x.\n", reg);
- else if (etd->hw_version != 4)
+ else if (etd->info.hw_version != 4)
*val = param[0];
else
*val = param[1];
@@ -160,7 +160,7 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
if (reg > 0x11 && reg < 0x20)
return -1;
- switch (etd->hw_version) {
+ switch (etd->info.hw_version) {
case 1:
if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_WRITE) ||
ps2_sliced_command(&psmouse->ps2dev, reg) ||
@@ -237,7 +237,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
unsigned char *packet = psmouse->packet;
int fingers;
- if (etd->fw_version < 0x020000) {
+ if (etd->info.fw_version < 0x020000) {
/*
* byte 0: D U p1 p2 1 p3 R L
* byte 1: f 0 th tw x9 x8 y9 y8
@@ -252,7 +252,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
fingers = (packet[0] & 0xc0) >> 6;
}
- if (etd->jumpy_cursor) {
+ if (etd->info.jumpy_cursor) {
if (fingers != 1) {
etd->single_finger_reports = 0;
} else if (etd->single_finger_reports < 2) {
@@ -282,8 +282,8 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
psmouse_report_standard_buttons(dev, packet[0]);
- if (etd->fw_version < 0x020000 &&
- (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) {
+ if (etd->info.fw_version < 0x020000 &&
+ (etd->info.capabilities[0] & ETP_CAP_HAS_ROCKER)) {
/* rocker up */
input_report_key(dev, BTN_FORWARD, packet[0] & 0x40);
/* rocker down */
@@ -391,7 +391,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
psmouse_report_standard_buttons(dev, packet[0]);
- if (etd->reports_pressure) {
+ if (etd->info.reports_pressure) {
input_report_abs(dev, ABS_PRESSURE, pres);
input_report_abs(dev, ABS_TOOL_WIDTH, width);
}
@@ -444,7 +444,7 @@ static void elantech_report_trackpoint(struct psmouse *psmouse,
default:
/* Dump unexpected packet sequences if debug=1 (default) */
- if (etd->debug == 1)
+ if (etd->info.debug == 1)
elantech_packet_dump(psmouse);
break;
@@ -523,7 +523,7 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
/* For clickpads map both buttons to BTN_LEFT */
- if (etd->fw_version & 0x001000)
+ if (etd->info.fw_version & 0x001000)
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
else
psmouse_report_standard_buttons(dev, packet[0]);
@@ -541,7 +541,7 @@ static void elantech_input_sync_v4(struct psmouse *psmouse)
unsigned char *packet = psmouse->packet;
/* For clickpads map both buttons to BTN_LEFT */
- if (etd->fw_version & 0x001000)
+ if (etd->info.fw_version & 0x001000)
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
else
psmouse_report_standard_buttons(dev, packet[0]);
@@ -669,7 +669,7 @@ static int elantech_packet_check_v1(struct psmouse *psmouse)
unsigned char p1, p2, p3;
/* Parity bits are placed differently */
- if (etd->fw_version < 0x020000) {
+ if (etd->info.fw_version < 0x020000) {
/* byte 0: D U p1 p2 1 p3 R L */
p1 = (packet[0] & 0x20) >> 5;
p2 = (packet[0] & 0x10) >> 4;
@@ -714,7 +714,7 @@ static int elantech_packet_check_v2(struct psmouse *psmouse)
* With all three cases, if the constant bits are not exactly what I
* expected, I consider them invalid.
*/
- if (etd->reports_pressure)
+ if (etd->info.reports_pressure)
return (packet[0] & 0x0c) == 0x04 &&
(packet[3] & 0x0f) == 0x02;
@@ -751,7 +751,7 @@ static int elantech_packet_check_v3(struct psmouse *psmouse)
* If the hardware flag 'crc_enabled' is set the packets have
* different signatures.
*/
- if (etd->crc_enabled) {
+ if (etd->info.crc_enabled) {
if ((packet[3] & 0x09) == 0x08)
return PACKET_V3_HEAD;
@@ -782,7 +782,7 @@ static int elantech_packet_check_v4(struct psmouse *psmouse)
return PACKET_TRACKPOINT;
/* This represents the version of IC body. */
- ic_version = (etd->fw_version & 0x0f0000) >> 16;
+ ic_version = (etd->info.fw_version & 0x0f0000) >> 16;
/*
* Sanity check based on the constant bits of a packet.
@@ -791,9 +791,9 @@ static int elantech_packet_check_v4(struct psmouse *psmouse)
* the IC body, but are the same for every packet,
* regardless of the type.
*/
- if (etd->crc_enabled)
+ if (etd->info.crc_enabled)
sanity_check = ((packet[3] & 0x08) == 0x00);
- else if (ic_version == 7 && etd->samples[1] == 0x2A)
+ else if (ic_version == 7 && etd->info.samples[1] == 0x2A)
sanity_check = ((packet[3] & 0x1c) == 0x10);
else
sanity_check = ((packet[0] & 0x0c) == 0x04 &&
@@ -827,12 +827,12 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
if (psmouse->pktcnt < psmouse->pktsize)
return PSMOUSE_GOOD_DATA;
- if (etd->debug > 1)
+ if (etd->info.debug > 1)
elantech_packet_dump(psmouse);
- switch (etd->hw_version) {
+ switch (etd->info.hw_version) {
case 1:
- if (etd->paritycheck && !elantech_packet_check_v1(psmouse))
+ if (etd->info.paritycheck && !elantech_packet_check_v1(psmouse))
return PSMOUSE_BAD_DATA;
elantech_report_absolute_v1(psmouse);
@@ -843,7 +843,7 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
if (elantech_debounce_check_v2(psmouse))
return PSMOUSE_FULL_PACKET;
- if (etd->paritycheck && !elantech_packet_check_v2(psmouse))
+ if (etd->info.paritycheck && !elantech_packet_check_v2(psmouse))
return PSMOUSE_BAD_DATA;
elantech_report_absolute_v2(psmouse);
@@ -916,7 +916,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
int tries = ETP_READ_BACK_TRIES;
int rc = 0;
- switch (etd->hw_version) {
+ switch (etd->info.hw_version) {
case 1:
etd->reg_10 = 0x16;
etd->reg_11 = 0x8f;
@@ -939,7 +939,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
break;
case 3:
- if (etd->set_hw_resolution)
+ if (etd->info.set_hw_resolution)
etd->reg_10 = 0x0b;
else
etd->reg_10 = 0x01;
@@ -976,7 +976,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
if (rc) {
psmouse_err(psmouse,
"failed to read back register 0x10.\n");
- } else if (etd->hw_version == 1 &&
+ } else if (etd->info.hw_version == 1 &&
!(val & ETP_R10_ABSOLUTE_MODE)) {
psmouse_err(psmouse,
"touchpad refuses to switch to absolute mode.\n");
@@ -997,10 +997,11 @@ static int elantech_set_range(struct psmouse *psmouse,
unsigned int *width)
{
struct elantech_data *etd = psmouse->private;
+ struct elantech_device_info *info = &etd->info;
unsigned char param[3];
unsigned char traces;
- switch (etd->hw_version) {
+ switch (info->hw_version) {
case 1:
*x_min = ETP_XMIN_V1;
*y_min = ETP_YMIN_V1;
@@ -1009,9 +1010,9 @@ static int elantech_set_range(struct psmouse *psmouse,
break;
case 2:
- if (etd->fw_version == 0x020800 ||
- etd->fw_version == 0x020b00 ||
- etd->fw_version == 0x020030) {
+ if (info->fw_version == 0x020800 ||
+ info->fw_version == 0x020b00 ||
+ info->fw_version == 0x020030) {
*x_min = ETP_XMIN_V2;
*y_min = ETP_YMIN_V2;
*x_max = ETP_XMAX_V2;
@@ -1020,35 +1021,35 @@ static int elantech_set_range(struct psmouse *psmouse,
int i;
int fixed_dpi;
- i = (etd->fw_version > 0x020800 &&
- etd->fw_version < 0x020900) ? 1 : 2;
+ i = (info->fw_version > 0x020800 &&
+ info->fw_version < 0x020900) ? 1 : 2;
- if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+ if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
return -1;
fixed_dpi = param[1] & 0x10;
- if (((etd->fw_version >> 16) == 0x14) && fixed_dpi) {
- if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
+ if (((info->fw_version >> 16) == 0x14) && fixed_dpi) {
+ if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
return -1;
- *x_max = (etd->capabilities[1] - i) * param[1] / 2;
- *y_max = (etd->capabilities[2] - i) * param[2] / 2;
- } else if (etd->fw_version == 0x040216) {
+ *x_max = (info->capabilities[1] - i) * param[1] / 2;
+ *y_max = (info->capabilities[2] - i) * param[2] / 2;
+ } else if (info->fw_version == 0x040216) {
*x_max = 819;
*y_max = 405;
- } else if (etd->fw_version == 0x040219 || etd->fw_version == 0x040215) {
+ } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) {
*x_max = 900;
*y_max = 500;
} else {
- *x_max = (etd->capabilities[1] - i) * 64;
- *y_max = (etd->capabilities[2] - i) * 64;
+ *x_max = (info->capabilities[1] - i) * 64;
+ *y_max = (info->capabilities[2] - i) * 64;
}
}
break;
case 3:
- if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+ if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
return -1;
*x_max = (0x0f & param[0]) << 8 | param[1];
@@ -1056,12 +1057,12 @@ static int elantech_set_range(struct psmouse *psmouse,
break;
case 4:
- if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+ if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
return -1;
*x_max = (0x0f & param[0]) << 8 | param[1];
*y_max = (0xf0 & param[0]) << 4 | param[2];
- traces = etd->capabilities[1];
+ traces = info->capabilities[1];
if ((traces < 2) || (traces > *x_max))
return -1;
@@ -1140,7 +1141,7 @@ static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
struct input_dev *dev = psmouse->dev;
struct elantech_data *etd = psmouse->private;
- if (etd->fw_version & 0x001000) {
+ if (etd->info.fw_version & 0x001000) {
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
__clear_bit(BTN_RIGHT, dev->keybit);
}
@@ -1176,6 +1177,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
struct elantech_data *etd = psmouse->private;
+ struct elantech_device_info *info = &etd->info;
unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
unsigned int x_res = 31, y_res = 31;
@@ -1197,11 +1199,11 @@ static int elantech_set_input_params(struct psmouse *psmouse)
__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
- switch (etd->hw_version) {
+ switch (info->hw_version) {
case 1:
/* Rocker button */
- if (etd->fw_version < 0x020000 &&
- (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) {
+ if (info->fw_version < 0x020000 &&
+ (info->capabilities[0] & ETP_CAP_HAS_ROCKER)) {
__set_bit(BTN_FORWARD, dev->keybit);
__set_bit(BTN_BACK, dev->keybit);
}
@@ -1214,11 +1216,11 @@ static int elantech_set_input_params(struct psmouse *psmouse)
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
/* fall through */
case 3:
- if (etd->hw_version == 3)
+ if (info->hw_version == 3)
elantech_set_buttonpad_prop(psmouse);
input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
- if (etd->reports_pressure) {
+ if (info->reports_pressure) {
input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
ETP_PMAX_V2, 0, 0);
input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
@@ -1267,7 +1269,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_abs_set_res(dev, ABS_X, x_res);
input_abs_set_res(dev, ABS_Y, y_res);
- if (etd->hw_version > 1) {
+ if (info->hw_version > 1) {
input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
}
@@ -1317,7 +1319,7 @@ static ssize_t elantech_set_int_attr(struct psmouse *psmouse,
return err;
/* Do we need to preserve some bits for version 2 hardware too? */
- if (etd->hw_version == 1) {
+ if (etd->info.hw_version == 1) {
if (attr->reg == 0x10)
/* Force absolute mode always on */
value |= ETP_R10_ABSOLUTE_MODE;
@@ -1337,11 +1339,22 @@ static ssize_t elantech_set_int_attr(struct psmouse *psmouse,
.field_offset = offsetof(struct elantech_data, _name), \
.reg = _register, \
}; \
- PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
+ PSMOUSE_DEFINE_ATTR(_name, 0644, \
&elantech_attr_##_name, \
elantech_show_int_attr, \
elantech_set_int_attr)
+#define ELANTECH_INFO_ATTR(_name) \
+ static struct elantech_attr_data elantech_attr_##_name = { \
+ .field_offset = offsetof(struct elantech_data, info) + \
+ offsetof(struct elantech_device_info, _name), \
+ .reg = 0, \
+ }; \
+ PSMOUSE_DEFINE_ATTR(_name, 0644, \
+ &elantech_attr_##_name, \
+ elantech_show_int_attr, \
+ elantech_set_int_attr)
+
ELANTECH_INT_ATTR(reg_07, 0x07);
ELANTECH_INT_ATTR(reg_10, 0x10);
ELANTECH_INT_ATTR(reg_11, 0x11);
@@ -1352,9 +1365,9 @@ ELANTECH_INT_ATTR(reg_23, 0x23);
ELANTECH_INT_ATTR(reg_24, 0x24);
ELANTECH_INT_ATTR(reg_25, 0x25);
ELANTECH_INT_ATTR(reg_26, 0x26);
-ELANTECH_INT_ATTR(debug, 0);
-ELANTECH_INT_ATTR(paritycheck, 0);
-ELANTECH_INT_ATTR(crc_enabled, 0);
+ELANTECH_INFO_ATTR(debug);
+ELANTECH_INFO_ATTR(paritycheck);
+ELANTECH_INFO_ATTR(crc_enabled);
static struct attribute *elantech_attrs[] = {
&psmouse_attr_reg_07.dattr.attr,
@@ -1588,25 +1601,25 @@ static const struct dmi_system_id no_hw_res_dmi_table[] = {
/*
* determine hardware version and set some properties according to it.
*/
-static int elantech_set_properties(struct elantech_data *etd)
+static int elantech_set_properties(struct elantech_device_info *info)
{
/* This represents the version of IC body. */
- int ver = (etd->fw_version & 0x0f0000) >> 16;
+ int ver = (info->fw_version & 0x0f0000) >> 16;
/* Early version of Elan touchpads doesn't obey the rule. */
- if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600)
- etd->hw_version = 1;
+ if (info->fw_version < 0x020030 || info->fw_version == 0x020600)
+ info->hw_version = 1;
else {
switch (ver) {
case 2:
case 4:
- etd->hw_version = 2;
+ info->hw_version = 2;
break;
case 5:
- etd->hw_version = 3;
+ info->hw_version = 3;
break;
case 6 ... 15:
- etd->hw_version = 4;
+ info->hw_version = 4;
break;
default:
return -1;
@@ -1614,100 +1627,86 @@ static int elantech_set_properties(struct elantech_data *etd)
}
/* decide which send_cmd we're gonna use early */
- etd->send_cmd = etd->hw_version >= 3 ? elantech_send_cmd :
- synaptics_send_cmd;
+ info->send_cmd = info->hw_version >= 3 ? elantech_send_cmd :
+ synaptics_send_cmd;
/* Turn on packet checking by default */
- etd->paritycheck = 1;
+ info->paritycheck = 1;
/*
* This firmware suffers from misreporting coordinates when
* a touch action starts causing the mouse cursor or scrolled page
* to jump. Enable a workaround.
*/
- etd->jumpy_cursor =
- (etd->fw_version == 0x020022 || etd->fw_version == 0x020600);
+ info->jumpy_cursor =
+ (info->fw_version == 0x020022 || info->fw_version == 0x020600);
- if (etd->hw_version > 1) {
+ if (info->hw_version > 1) {
/* For now show extra debug information */
- etd->debug = 1;
+ info->debug = 1;
- if (etd->fw_version >= 0x020800)
- etd->reports_pressure = true;
+ if (info->fw_version >= 0x020800)
+ info->reports_pressure = true;
}
/*
* The signatures of v3 and v4 packets change depending on the
* value of this hardware flag.
*/
- etd->crc_enabled = (etd->fw_version & 0x4000) == 0x4000 ||
- dmi_check_system(elantech_dmi_force_crc_enabled);
+ info->crc_enabled = (info->fw_version & 0x4000) == 0x4000 ||
+ dmi_check_system(elantech_dmi_force_crc_enabled);
/* Enable real hardware resolution on hw_version 3 ? */
- etd->set_hw_resolution = !dmi_check_system(no_hw_res_dmi_table);
+ info->set_hw_resolution = !dmi_check_system(no_hw_res_dmi_table);
return 0;
}
-/*
- * Initialize the touchpad and create sysfs entries
- */
-int elantech_init(struct psmouse *psmouse)
+int elantech_query_info(struct psmouse *psmouse,
+ struct elantech_device_info *info)
{
- struct elantech_data *etd;
- int i;
- int error = -EINVAL;
unsigned char param[3];
- struct input_dev *tp_dev;
-
- psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
- if (!etd)
- return -ENOMEM;
-
- psmouse_reset(psmouse);
-
- etd->parity[0] = 1;
- for (i = 1; i < 256; i++)
- etd->parity[i] = etd->parity[i & (i - 1)] ^ 1;
/*
* Do the version query again so we can store the result
*/
if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) {
psmouse_err(psmouse, "failed to query firmware version.\n");
- goto init_fail;
+ return -EINVAL;
}
- etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2];
+ info->fw_version = (param[0] << 16) | (param[1] << 8) | param[2];
- if (elantech_set_properties(etd)) {
+ if (elantech_set_properties(info)) {
psmouse_err(psmouse, "unknown hardware version, aborting...\n");
- goto init_fail;
+ return -EINVAL;
}
psmouse_info(psmouse,
"assuming hardware version %d (with firmware version 0x%02x%02x%02x)\n",
- etd->hw_version, param[0], param[1], param[2]);
+ info->hw_version, param[0], param[1], param[2]);
- if (etd->send_cmd(psmouse, ETP_CAPABILITIES_QUERY,
- etd->capabilities)) {
+ if (info->send_cmd(psmouse, ETP_CAPABILITIES_QUERY,
+ info->capabilities)) {
psmouse_err(psmouse, "failed to query capabilities.\n");
- goto init_fail;
+ return -EINVAL;
}
psmouse_info(psmouse,
"Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n",
- etd->capabilities[0], etd->capabilities[1],
- etd->capabilities[2]);
+ info->capabilities[0], info->capabilities[1],
+ info->capabilities[2]);
- if (etd->hw_version != 1) {
- if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, etd->samples)) {
+ if (info->hw_version != 1) {
+ if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, info->samples)) {
psmouse_err(psmouse, "failed to query sample data\n");
- goto init_fail;
+ return -EINVAL;
}
psmouse_info(psmouse,
"Elan sample query result %02x, %02x, %02x\n",
- etd->samples[0], etd->samples[1], etd->samples[2]);
+ info->samples[0],
+ info->samples[1],
+ info->samples[2]);
}
- if (etd->samples[1] == 0x74 && etd->hw_version == 0x03) {
+ if (info->samples[1] == 0x74 && info->hw_version == 0x03) {
/*
* This module has a bug which makes absolute mode
* unusable, so let's abort so we'll be using standard
@@ -1715,16 +1714,43 @@ int elantech_init(struct psmouse *psmouse)
*/
psmouse_info(psmouse,
"absolute mode broken, forcing standard PS/2 protocol\n");
- goto init_fail;
+ return -ENODEV;
}
+ /* The MSB indicates the presence of the trackpoint */
+ info->has_trackpoint = (info->capabilities[0] & 0x80) == 0x80;
+
+ return 0;
+}
+
+/*
+ * Initialize the touchpad and create sysfs entries
+ */
+static int elantech_setup_ps2(struct psmouse *psmouse,
+ struct elantech_device_info *info)
+{
+ struct elantech_data *etd;
+ int i;
+ int error;
+ struct input_dev *tp_dev;
+
+ psmouse->private = etd = kzalloc(sizeof(*etd), GFP_KERNEL);
+ if (!etd)
+ return -ENOMEM;
+
+ etd->info = *info;
+
+ etd->parity[0] = 1;
+ for (i = 1; i < 256; i++)
+ etd->parity[i] = etd->parity[i & (i - 1)] ^ 1;
+
if (elantech_set_absolute_mode(psmouse)) {
psmouse_err(psmouse,
"failed to put touchpad into absolute mode.\n");
goto init_fail;
}
- if (etd->fw_version == 0x381f17) {
+ if (info->fw_version == 0x381f17) {
etd->original_set_rate = psmouse->set_rate;
psmouse->set_rate = elantech_set_rate_restore_reg_07;
}
@@ -1743,8 +1769,7 @@ int elantech_init(struct psmouse *psmouse)
goto init_fail;
}
- /* The MSB indicates the presence of the trackpoint */
- if ((etd->capabilities[0] & 0x80) == 0x80) {
+ if (info->has_trackpoint) {
tp_dev = input_allocate_device();
if (!tp_dev) {
@@ -1780,7 +1805,7 @@ int elantech_init(struct psmouse *psmouse)
psmouse->protocol_handler = elantech_process_byte;
psmouse->disconnect = elantech_disconnect;
psmouse->reconnect = elantech_reconnect;
- psmouse->pktsize = etd->hw_version > 1 ? 6 : 4;
+ psmouse->pktsize = info->hw_version > 1 ? 6 : 4;
return 0;
init_fail_tp_reg:
@@ -1789,7 +1814,27 @@ int elantech_init(struct psmouse *psmouse)
sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
&elantech_attr_group);
init_fail:
- psmouse_reset(psmouse);
kfree(etd);
return error;
}
+
+int elantech_init(struct psmouse *psmouse)
+{
+ struct elantech_device_info info;
+ int error = -EINVAL;
+
+ psmouse_reset(psmouse);
+
+ error = elantech_query_info(psmouse, &info);
+ if (error)
+ goto init_fail;
+
+ error = elantech_setup_ps2(psmouse, &info);
+ if (error)
+ goto init_fail;
+
+ return 0;
+ init_fail:
+ psmouse_reset(psmouse);
+ return error;
+}
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index e1cbf409d9c8..d8ac27fe4597 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -114,6 +114,22 @@ struct finger_pos {
unsigned int y;
};
+struct elantech_device_info {
+ unsigned char capabilities[3];
+ unsigned char samples[3];
+ unsigned char debug;
+ unsigned char hw_version;
+ unsigned int fw_version;
+ bool paritycheck;
+ bool jumpy_cursor;
+ bool reports_pressure;
+ bool crc_enabled;
+ bool set_hw_resolution;
+ bool has_trackpoint;
+ int (*send_cmd)(struct psmouse *psmouse, unsigned char c,
+ unsigned char *param);
+};
+
struct elantech_data {
struct input_dev *tp_dev; /* Relative device for trackpoint */
char tp_phys[32];
@@ -127,22 +143,12 @@ struct elantech_data {
unsigned char reg_24;
unsigned char reg_25;
unsigned char reg_26;
- unsigned char debug;
- unsigned char capabilities[3];
- unsigned char samples[3];
- bool paritycheck;
- bool jumpy_cursor;
- bool reports_pressure;
- bool crc_enabled;
- bool set_hw_resolution;
- unsigned char hw_version;
- unsigned int fw_version;
unsigned int single_finger_reports;
unsigned int y_max;
unsigned int width;
struct finger_pos mt[ETP_MAX_FINGERS];
unsigned char parity[256];
- int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param);
+ struct elantech_device_info info;
void (*original_set_rate)(struct psmouse *psmouse, unsigned int rate);
};
--
2.14.3
^ permalink raw reply related
* [PATCH v2 3/9] Input: elan_i2c - add trackstick report
From: Benjamin Tissoires @ 2018-04-09 9:10 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: kt.liao, Oliver Haessler, Benjamin Berg, Rob Herring, devicetree,
linux-input, linux-kernel, Benjamin Tissoires
In-Reply-To: <20180409091051.2944-1-benjamin.tissoires@redhat.com>
The Elan touchpads over I2C/SMBus also can handle a
trackstick. Unfortunately, nothing tells us if the
device supports trackstick (the information lies in
the PS/2 node), so rely on a platform data to enable
or not the trackstick node.
Link: https://bugzilla.redhat.com/show_bug.cgi?id=1313939
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
changes in v2:
- use of generic device property instead of platform data so
device tree can also make use of it
---
.../devicetree/bindings/input/elan_i2c.txt | 1 +
drivers/input/mouse/elan_i2c_core.c | 90 +++++++++++++++++++++-
2 files changed, 88 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/elan_i2c.txt b/Documentation/devicetree/bindings/input/elan_i2c.txt
index ee3242c4ba67..d80a83583238 100644
--- a/Documentation/devicetree/bindings/input/elan_i2c.txt
+++ b/Documentation/devicetree/bindings/input/elan_i2c.txt
@@ -14,6 +14,7 @@ Optional properties:
- pinctrl-0: a phandle pointing to the pin settings for the device (see
pinctrl binding [1]).
- vcc-supply: a phandle for the regulator supplying 3.3V power.
+- elan,trackpoint: touchpad can support a trackpoint (boolean)
[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 75e757520ef0..44e970931926 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -36,6 +36,7 @@
#include <linux/jiffies.h>
#include <linux/completion.h>
#include <linux/of.h>
+#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <asm/unaligned.h>
@@ -51,6 +52,7 @@
#define ETP_MAX_FINGERS 5
#define ETP_FINGER_DATA_LEN 5
#define ETP_REPORT_ID 0x5D
+#define ETP_TP_REPORT_ID 0x5E
#define ETP_REPORT_ID_OFFSET 2
#define ETP_TOUCH_INFO_OFFSET 3
#define ETP_FINGER_DATA_OFFSET 4
@@ -61,6 +63,7 @@
struct elan_tp_data {
struct i2c_client *client;
struct input_dev *input;
+ struct input_dev *tp_input; /* trackpoint input node */
struct regulator *vcc;
const struct elan_transport_ops *ops;
@@ -930,6 +933,34 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
input_sync(input);
}
+static void elan_report_trackpoint(struct elan_tp_data *data, u8 *report)
+{
+ struct input_dev *input = data->tp_input;
+ u8 *packet = &report[ETP_REPORT_ID_OFFSET + 1];
+ int x, y;
+
+ if (!data->tp_input) {
+ dev_warn_once(&data->client->dev,
+ "received a trackpoint report while no trackpoint device has been created.\n"
+ "Please report upstream.\n");
+ return;
+ }
+
+ input_report_key(input, BTN_LEFT, packet[0] & 0x01);
+ input_report_key(input, BTN_RIGHT, packet[0] & 0x02);
+ input_report_key(input, BTN_MIDDLE, packet[0] & 0x04);
+
+ if ((packet[3] & 0x0F) == 0x06) {
+ x = packet[4] - (int)((packet[1]^0x80) << 1);
+ y = (int)((packet[2]^0x80) << 1) - packet[5];
+
+ input_report_rel(input, REL_X, x);
+ input_report_rel(input, REL_Y, y);
+ }
+
+ input_sync(input);
+}
+
static irqreturn_t elan_isr(int irq, void *dev_id)
{
struct elan_tp_data *data = dev_id;
@@ -951,11 +982,17 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
if (error)
goto out;
- if (report[ETP_REPORT_ID_OFFSET] != ETP_REPORT_ID)
+ switch (report[ETP_REPORT_ID_OFFSET]) {
+ case ETP_REPORT_ID:
+ elan_report_absolute(data, report);
+ break;
+ case ETP_TP_REPORT_ID:
+ elan_report_trackpoint(data, report);
+ break;
+ default:
dev_err(dev, "invalid report id data (%x)\n",
report[ETP_REPORT_ID_OFFSET]);
- else
- elan_report_absolute(data, report);
+ }
out:
return IRQ_HANDLED;
@@ -966,6 +1003,37 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
* Elan initialization functions
******************************************************************
*/
+
+static int elan_setup_trackpoint_input_device(struct elan_tp_data *data)
+{
+ struct device *dev = &data->client->dev;
+ struct input_dev *input;
+
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return -ENOMEM;
+
+ input->name = "Elan TrackPoint";
+ input->id.bustype = BUS_I2C;
+ input->id.vendor = ELAN_VENDOR_ID;
+ input->id.product = data->product_id;
+ input_set_drvdata(input, data);
+
+ input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ input->relbit[BIT_WORD(REL_X)] =
+ BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+ input->keybit[BIT_WORD(BTN_LEFT)] =
+ BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) |
+ BIT_MASK(BTN_RIGHT);
+
+ __set_bit(INPUT_PROP_POINTER, input->propbit);
+ __set_bit(INPUT_PROP_POINTING_STICK, input->propbit);
+
+ data->tp_input = input;
+
+ return 0;
+}
+
static int elan_setup_input_device(struct elan_tp_data *data)
{
struct device *dev = &data->client->dev;
@@ -1140,6 +1208,12 @@ static int elan_probe(struct i2c_client *client,
if (error)
return error;
+ if (device_property_read_bool(&client->dev, "elan,trackpoint")) {
+ error = elan_setup_trackpoint_input_device(data);
+ if (error)
+ return error;
+ }
+
/*
* Platform code (ACPI, DTS) should normally set up interrupt
* for us, but in case it did not let's fall back to using falling
@@ -1177,6 +1251,16 @@ static int elan_probe(struct i2c_client *client,
return error;
}
+ if (data->tp_input) {
+ error = input_register_device(data->tp_input);
+ if (error) {
+ dev_err(&client->dev,
+ "failed to register TrackPoint input device: %d\n",
+ error);
+ return error;
+ }
+ }
+
/*
* Systems using device tree should set up wakeup via DTS,
* the rest will configure device as wakeup source by default.
--
2.14.3
^ permalink raw reply related
* [PATCH v2 2/9] input: elan_i2c_smbus - fix corrupted stack
From: Benjamin Tissoires @ 2018-04-09 9:10 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: kt.liao, Oliver Haessler, Benjamin Berg, Rob Herring, devicetree,
linux-input, linux-kernel, Benjamin Tissoires, stable
In-Reply-To: <20180409091051.2944-1-benjamin.tissoires@redhat.com>
New ICs (like the one on the Lenovo T480s) answer to
ETP_SMBUS_IAP_VERSION_CMD 4 bytes instead of 3. This corrupts the stack
as i2c_smbus_read_block_data() uses the values returned by the i2c
device to know how many data it need to return.
i2c_smbus_read_block_data() can read up to 32 bytes (I2C_SMBUS_BLOCK_MAX)
and there is no safeguard on how many bytes are provided in the return
value. Ensure we always have enough space for any future firmware.
Also 0-initialize the values to prevent any access to uninitialized memory.
Cc: <stable@vger.kernel.org> # v4.4.x, v4.9.x, v4.14.x, v4.15.x, v4.16.x
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v2
drivers/input/mouse/elan_i2c_smbus.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c
index 29f99529b187..cfcb32559925 100644
--- a/drivers/input/mouse/elan_i2c_smbus.c
+++ b/drivers/input/mouse/elan_i2c_smbus.c
@@ -130,7 +130,7 @@ static int elan_smbus_get_baseline_data(struct i2c_client *client,
bool max_baseline, u8 *value)
{
int error;
- u8 val[3];
+ u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
error = i2c_smbus_read_block_data(client,
max_baseline ?
@@ -149,7 +149,7 @@ static int elan_smbus_get_version(struct i2c_client *client,
bool iap, u8 *version)
{
int error;
- u8 val[3];
+ u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
error = i2c_smbus_read_block_data(client,
iap ? ETP_SMBUS_IAP_VERSION_CMD :
@@ -170,7 +170,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client,
u8 *clickpad)
{
int error;
- u8 val[3];
+ u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
error = i2c_smbus_read_block_data(client,
ETP_SMBUS_SM_VERSION_CMD, val);
@@ -188,7 +188,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client,
static int elan_smbus_get_product_id(struct i2c_client *client, u16 *id)
{
int error;
- u8 val[3];
+ u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
error = i2c_smbus_read_block_data(client,
ETP_SMBUS_UNIQUEID_CMD, val);
@@ -205,7 +205,7 @@ static int elan_smbus_get_checksum(struct i2c_client *client,
bool iap, u16 *csum)
{
int error;
- u8 val[3];
+ u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
error = i2c_smbus_read_block_data(client,
iap ? ETP_SMBUS_FW_CHECKSUM_CMD :
@@ -226,7 +226,7 @@ static int elan_smbus_get_max(struct i2c_client *client,
{
int ret;
int error;
- u8 val[3];
+ u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val);
if (ret != 3) {
@@ -246,7 +246,7 @@ static int elan_smbus_get_resolution(struct i2c_client *client,
{
int ret;
int error;
- u8 val[3];
+ u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RESOLUTION_CMD, val);
if (ret != 3) {
@@ -267,7 +267,7 @@ static int elan_smbus_get_num_traces(struct i2c_client *client,
{
int ret;
int error;
- u8 val[3];
+ u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
ret = i2c_smbus_read_block_data(client, ETP_SMBUS_XY_TRACENUM_CMD, val);
if (ret != 3) {
@@ -294,7 +294,7 @@ static int elan_smbus_iap_get_mode(struct i2c_client *client,
{
int error;
u16 constant;
- u8 val[3];
+ u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
error = i2c_smbus_read_block_data(client, ETP_SMBUS_IAP_CTRL_CMD, val);
if (error < 0) {
@@ -345,7 +345,7 @@ static int elan_smbus_prepare_fw_update(struct i2c_client *client)
int len;
int error;
enum tp_mode mode;
- u8 val[3];
+ u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
u8 cmd[4] = {0x0F, 0x78, 0x00, 0x06};
u16 password;
@@ -419,7 +419,7 @@ static int elan_smbus_write_fw_block(struct i2c_client *client,
struct device *dev = &client->dev;
int error;
u16 result;
- u8 val[3];
+ u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
/*
* Due to the limitation of smbus protocol limiting
--
2.14.3
^ permalink raw reply related
* [PATCH v2 1/9] Input: synaptics - add Lenovo 80 series ids to SMBus
From: Benjamin Tissoires @ 2018-04-09 9:10 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: kt.liao, Oliver Haessler, Benjamin Berg, Rob Herring, devicetree,
linux-input, linux-kernel, Benjamin Tissoires, stable
In-Reply-To: <20180409091051.2944-1-benjamin.tissoires@redhat.com>
This time, Lenovo decided to go with different pieces in its latest series
of Thinkpads.
For those we have been able to test:
- the T480 is using Synaptics with an IBM trackpoint
-> it behaves properly with or without intertouch, there is no point
not using RMI4
- the X1 Carbon 6th gen is using Synaptics with an IBM trackpoint
-> the touchpad doesn't behave properly under PS/2 so we have to
switch it to RMI4 if we do not want to have disappointed users
- the X280 is using Synaptics with an ALPS trackpoint
-> the recent fixes in the trackpoint handling fixed it so upstream
now works fine with or without RMI4, and there is no point not
using RMI4
- the T480s is using an Elan touchpad, so that's a different story
Cc: <stable@vger.kernel.org> # v4.14.x, v4.15.x, v4.16.x
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
no changes in v2
drivers/input/mouse/synaptics.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 60f2c463d1cc..14a1188561aa 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -173,6 +173,9 @@ static const char * const smbus_pnp_ids[] = {
"LEN0046", /* X250 */
"LEN004a", /* W541 */
"LEN200f", /* T450s */
+ "LEN0071", /* T480 */
+ "LEN0092", /* X1 Carbon 6th gen */
+ "LEN0097", /* X280 -> ALPS trackpoint */
NULL
};
--
2.14.3
^ permalink raw reply related
* [PATCH v2 0/9] Input: support for latest Lenovo thinkpads (series 80)
From: Benjamin Tissoires @ 2018-04-09 9:10 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: kt.liao, Oliver Haessler, Benjamin Berg, Rob Herring, devicetree,
linux-input, linux-kernel, Benjamin Tissoires
Hi Dmitry,
Here is the v2 of the Lenovo 80 series.
Changes from v1:
- included patch to convert a function to static from build bot
- use of device property instead of platform data (thus the new device tree
binding)
BTW, KT, if you want to add your Signed-off-by on the patches, feel free to
do so. You were of tremendous help :)
Cheers,
Benjamin
Benjamin Tissoires (9):
Input: synaptics - add Lenovo 80 series ids to SMBus
input: elan_i2c_smbus - fix corrupted stack
Input: elan_i2c - add trackstick report
Input: elantech - split device info into a separate structure
Input: elantech_query_info() can be static
Input: elantech - query the resolution in query_info
Input: elantech - add support for SMBus devices
Input: elantech - detect new ICs and setup Host Notify for them
input: psmouse-smbus: allow to control psmouse_deactivate
.../devicetree/bindings/input/elan_i2c.txt | 1 +
drivers/input/mouse/Kconfig | 12 +
drivers/input/mouse/elan_i2c_core.c | 90 +++-
drivers/input/mouse/elan_i2c_smbus.c | 22 +-
drivers/input/mouse/elantech.c | 479 +++++++++++++++------
drivers/input/mouse/elantech.h | 69 ++-
drivers/input/mouse/psmouse-base.c | 21 +-
drivers/input/mouse/psmouse-smbus.c | 24 +-
drivers/input/mouse/psmouse.h | 2 +
drivers/input/mouse/synaptics.c | 5 +-
10 files changed, 565 insertions(+), 160 deletions(-)
--
2.14.3
^ permalink raw reply
* Re: [PATCH v3 1/3] resource: Use list_head to link resource sibling
From: Baoquan He @ 2018-04-09 9:08 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Brijesh Singh, devicetree-u79uwXL29TY76Z2rM5mHXA, David Airlie,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Wei Yang, Keith Busch,
Yaowei Bai, K. Y. Srinivasan, Frank Rowand, Thomas Gleixner,
Lorenzo Pieralisi, Stephen Hemminger,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw, Patrik Jakobsson,
linux-input-u79uwXL29TY76Z2rM5mHXA, Borislav Petkov, Tom Lendacky,
Haiyang Zhang, Jérôme Glisse, Rob Herring,
Bjorn Helgaas, Jonathan Derrick, Greg Kroah-Hartman
In-Reply-To: <20180408024724.16812-2-bhe-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
The struct resource uses singly linked list to link siblings. It's not
easy to do reverse iteration on sibling list. So replace it with list_head.
And code refactoring makes codes in kernel/resource.c more readable than
pointer operation.
Besides, type of member variables of struct resource, sibling and child, are
changed from 'struct resource *' to 'struct list_head'. Kernel size will
increase because of those statically defined struct resource instances.
Signed-off-by: Baoquan He <bhe-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
v2->v3:
Make sibling() and first_child() global so that they can be called
out of kernel/resource.c to simplify code.
Fix several code bugs found by kbuild test robot.
Got report from lkp that kernel size increased. It's on purpose since
the type change of sibling and child inside struct resource{}. For
each struct resource variable, it will cost another 16 bytes on x86 64.
arch/sparc/kernel/ioport.c | 2 +-
drivers/gpu/drm/drm_memory.c | 3 +-
drivers/gpu/drm/gma500/gtt.c | 5 +-
drivers/hv/vmbus_drv.c | 52 ++++----
drivers/input/joystick/iforce/iforce-main.c | 4 +-
drivers/nvdimm/e820.c | 2 +-
drivers/nvdimm/namespace_devs.c | 6 +-
drivers/nvdimm/nd.h | 5 +-
drivers/of/address.c | 4 +-
drivers/parisc/lba_pci.c | 4 +-
drivers/pci/host/vmd.c | 8 +-
drivers/pci/probe.c | 2 +
drivers/pci/setup-bus.c | 2 +-
include/linux/ioport.h | 6 +-
kernel/resource.c | 193 ++++++++++++++--------------
15 files changed, 149 insertions(+), 149 deletions(-)
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 3bcef9ce74df..4e91fbbbedcc 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -669,7 +669,7 @@ static int sparc_io_proc_show(struct seq_file *m, void *v)
struct resource *root = m->private, *r;
const char *nm;
- for (r = root->child; r != NULL; r = r->sibling) {
+ list_for_each_entry(r, &root->child, sibling) {
if ((nm = r->name) == NULL) nm = "???";
seq_printf(m, "%016llx-%016llx: %s\n",
(unsigned long long)r->start,
diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c
index 3c54044214db..53e300a993dc 100644
--- a/drivers/gpu/drm/drm_memory.c
+++ b/drivers/gpu/drm/drm_memory.c
@@ -155,9 +155,8 @@ u64 drm_get_max_iomem(void)
struct resource *tmp;
resource_size_t max_iomem = 0;
- for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) {
+ list_for_each_entry(tmp, &iomem_resource.child, sibling)
max_iomem = max(max_iomem, tmp->end);
- }
return max_iomem;
}
diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c
index 3949b0990916..addd3bc009af 100644
--- a/drivers/gpu/drm/gma500/gtt.c
+++ b/drivers/gpu/drm/gma500/gtt.c
@@ -565,7 +565,7 @@ int psb_gtt_init(struct drm_device *dev, int resume)
int psb_gtt_restore(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
- struct resource *r = dev_priv->gtt_mem->child;
+ struct resource *r;
struct gtt_range *range;
unsigned int restored = 0, total = 0, size = 0;
@@ -573,14 +573,13 @@ int psb_gtt_restore(struct drm_device *dev)
mutex_lock(&dev_priv->gtt_mutex);
psb_gtt_init(dev, 1);
- while (r != NULL) {
+ list_for_each_entry(r, &dev_priv->gtt_mem->child, sibling) {
range = container_of(r, struct gtt_range, resource);
if (range->pages) {
psb_gtt_insert(dev, range, 1);
size += range->resource.end - range->resource.start;
restored++;
}
- r = r->sibling;
total++;
}
mutex_unlock(&dev_priv->gtt_mutex);
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index bc65c4d79c1f..7ba8a25520d9 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -1413,9 +1413,8 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
{
resource_size_t start = 0;
resource_size_t end = 0;
- struct resource *new_res;
+ struct resource *new_res, *tmp;
struct resource **old_res = &hyperv_mmio;
- struct resource **prev_res = NULL;
switch (res->type) {
@@ -1462,44 +1461,36 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
/*
* If two ranges are adjacent, merge them.
*/
- do {
- if (!*old_res) {
- *old_res = new_res;
- break;
- }
-
- if (((*old_res)->end + 1) == new_res->start) {
- (*old_res)->end = new_res->end;
+ if (!*old_res) {
+ *old_res = new_res;
+ return AE_OK;
+ }
+ tmp = *old_res;
+ list_for_each_entry_from(tmp, &tmp->parent->child, sibling) {
+ if ((tmp->end + 1) == new_res->start) {
+ tmp->end = new_res->end;
kfree(new_res);
break;
}
- if ((*old_res)->start == new_res->end + 1) {
- (*old_res)->start = new_res->start;
+ if (tmp->start == new_res->end + 1) {
+ tmp->start = new_res->start;
kfree(new_res);
break;
}
- if ((*old_res)->start > new_res->end) {
- new_res->sibling = *old_res;
- if (prev_res)
- (*prev_res)->sibling = new_res;
- *old_res = new_res;
+ if (tmp->start > new_res->end) {
+ list_add(&new_res->sibling, tmp->sibling.prev);
break;
}
-
- prev_res = old_res;
- old_res = &(*old_res)->sibling;
-
- } while (1);
+ }
return AE_OK;
}
static int vmbus_acpi_remove(struct acpi_device *device)
{
- struct resource *cur_res;
- struct resource *next_res;
+ struct resource *res;
if (hyperv_mmio) {
if (fb_mmio) {
@@ -1508,10 +1499,9 @@ static int vmbus_acpi_remove(struct acpi_device *device)
fb_mmio = NULL;
}
- for (cur_res = hyperv_mmio; cur_res; cur_res = next_res) {
- next_res = cur_res->sibling;
- kfree(cur_res);
- }
+ res = hyperv_mmio;
+ list_for_each_entry_from(res, &res->parent->child, sibling)
+ kfree(res);
}
return 0;
@@ -1597,7 +1587,8 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
}
}
- for (iter = hyperv_mmio; iter; iter = iter->sibling) {
+ iter = hyperv_mmio;
+ list_for_each_entry_from(iter, &iter->parent->child, sibling) {
if ((iter->start >= max) || (iter->end <= min))
continue;
@@ -1640,7 +1631,8 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size)
struct resource *iter;
down(&hyperv_mmio_lock);
- for (iter = hyperv_mmio; iter; iter = iter->sibling) {
+ iter = hyperv_mmio;
+ list_for_each_entry_from(iter, &iter->parent->child, sibling) {
if ((iter->start >= start + size) || (iter->end <= start))
continue;
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index daeeb4c7e3b0..5c0be27b33ff 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -305,8 +305,8 @@ int iforce_init_device(struct iforce *iforce)
iforce->device_memory.end = 200;
iforce->device_memory.flags = IORESOURCE_MEM;
iforce->device_memory.parent = NULL;
- iforce->device_memory.child = NULL;
- iforce->device_memory.sibling = NULL;
+ INIT_LIST_HEAD(&iforce->device_memory.child);
+ INIT_LIST_HEAD(&iforce->device_memory.sibling);
/*
* Wait until device ready - until it sends its first response.
diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c
index 6f9a6ffd7cde..513e661bb0d8 100644
--- a/drivers/nvdimm/e820.c
+++ b/drivers/nvdimm/e820.c
@@ -53,7 +53,7 @@ static int e820_pmem_probe(struct platform_device *pdev)
goto err;
platform_set_drvdata(pdev, nvdimm_bus);
- for (p = iomem_resource.child; p ; p = p->sibling) {
+ list_for_each_entry(p, &iomem_resource.child, sibling) {
struct nd_region_desc ndr_desc;
if (p->desc != IORES_DESC_PERSISTENT_MEMORY_LEGACY)
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 658ada497be0..bcbdf5335909 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -637,7 +637,7 @@ static resource_size_t scan_allocate(struct nd_region *nd_region,
retry:
first = 0;
for_each_dpa_resource(ndd, res) {
- struct resource *next = res->sibling, *new_res = NULL;
+ struct resource *next = sibling(res), *new_res = NULL;
resource_size_t allocate, available = 0;
enum alloc_loc loc = ALLOC_ERR;
const char *action;
@@ -763,7 +763,7 @@ static resource_size_t scan_allocate(struct nd_region *nd_region,
* an initial "pmem-reserve pass". Only do an initial BLK allocation
* when none of the DPA space is reserved.
*/
- if ((is_pmem || !ndd->dpa.child) && n == to_allocate)
+ if ((is_pmem || list_empty(&ndd->dpa.child)) && n == to_allocate)
return init_dpa_allocation(label_id, nd_region, nd_mapping, n);
return n;
}
@@ -779,7 +779,7 @@ static int merge_dpa(struct nd_region *nd_region,
retry:
for_each_dpa_resource(ndd, res) {
int rc;
- struct resource *next = res->sibling;
+ struct resource *next = sibling(res);
resource_size_t end = res->start + resource_size(res);
if (!next || strcmp(res->name, label_id->id) != 0
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 184e070d50a2..1dc0b2370bd1 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -102,11 +102,10 @@ unsigned sizeof_namespace_label(struct nvdimm_drvdata *ndd);
(unsigned long long) (res ? res->start : 0), ##arg)
#define for_each_dpa_resource(ndd, res) \
- for (res = (ndd)->dpa.child; res; res = res->sibling)
+ list_for_each_entry(res, &(ndd)->dpa.child, sibling)
#define for_each_dpa_resource_safe(ndd, res, next) \
- for (res = (ndd)->dpa.child, next = res ? res->sibling : NULL; \
- res; res = next, next = next ? next->sibling : NULL)
+ list_for_each_entry_safe(res, next, &(ndd)->dpa.child, sibling)
struct nd_percpu_lane {
int count;
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 53349912ac75..e2e25719ab52 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -330,7 +330,9 @@ int of_pci_range_to_resource(struct of_pci_range *range,
{
int err;
res->flags = range->flags;
- res->parent = res->child = res->sibling = NULL;
+ res->parent = NULL;
+ INIT_LIST_HEAD(&res->child);
+ INIT_LIST_HEAD(&res->sibling);
res->name = np->full_name;
if (res->flags & IORESOURCE_IO) {
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 69bd98421eb1..84f04418ae0b 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -170,8 +170,8 @@ lba_dump_res(struct resource *r, int d)
for (i = d; i ; --i) printk(" ");
printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r,
(long)r->start, (long)r->end, r->flags);
- lba_dump_res(r->child, d+2);
- lba_dump_res(r->sibling, d);
+ lba_dump_res(first_child(&r->child), d+2);
+ lba_dump_res(sibling(r), d);
}
diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c
index 930a8fa08bd6..c3000af903ea 100644
--- a/drivers/pci/host/vmd.c
+++ b/drivers/pci/host/vmd.c
@@ -520,14 +520,14 @@ static struct pci_ops vmd_ops = {
static void vmd_attach_resources(struct vmd_dev *vmd)
{
- vmd->dev->resource[VMD_MEMBAR1].child = &vmd->resources[1];
- vmd->dev->resource[VMD_MEMBAR2].child = &vmd->resources[2];
+ list_add(&vmd->resources[1].sibling, &vmd->dev->resource[VMD_MEMBAR1].child);
+ list_add(&vmd->resources[2].sibling, &vmd->dev->resource[VMD_MEMBAR2].child);
}
static void vmd_detach_resources(struct vmd_dev *vmd)
{
- vmd->dev->resource[VMD_MEMBAR1].child = NULL;
- vmd->dev->resource[VMD_MEMBAR2].child = NULL;
+ INIT_LIST_HEAD(&vmd->dev->resource[VMD_MEMBAR1].child);
+ INIT_LIST_HEAD(&vmd->dev->resource[VMD_MEMBAR2].child);
}
/*
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ac91b6fd0bcd..d162c77bec29 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -59,6 +59,8 @@ static struct resource *get_pci_domain_busn_res(int domain_nr)
r->res.start = 0;
r->res.end = 0xff;
r->res.flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED;
+ INIT_LIST_HEAD(&r->res.child);
+ INIT_LIST_HEAD(&r->res.sibling);
list_add_tail(&r->list, &pci_domain_busn_res_list);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 072784f55ea5..0d5e30004ca6 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -2107,7 +2107,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
continue;
/* Ignore BARs which are still in use */
- if (res->child)
+ if (!list_empty(&res->child))
continue;
ret = add_to_list(&saved, bridge, res, 0, 0);
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index da0ebaec25f0..03d1510f03e0 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -22,7 +22,8 @@ struct resource {
const char *name;
unsigned long flags;
unsigned long desc;
- struct resource *parent, *sibling, *child;
+ struct list_head child, sibling;
+ struct resource *parent;
};
/*
@@ -189,6 +190,8 @@ extern int allocate_resource(struct resource *root, struct resource *new,
resource_size_t,
resource_size_t),
void *alignf_data);
+extern struct resource *sibling(struct resource *res);
+extern struct resource *first_child(struct list_head *head);
struct resource *lookup_resource(struct resource *root, resource_size_t start);
int adjust_resource(struct resource *res, resource_size_t start,
resource_size_t size);
@@ -215,7 +218,6 @@ static inline bool resource_contains(struct resource *r1, struct resource *r2)
return r1->start <= r2->start && r1->end >= r2->end;
}
-
/* Convenience shorthand with allocation */
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0)
#define request_muxed_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED)
diff --git a/kernel/resource.c b/kernel/resource.c
index e270b5048988..473c624606f9 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -31,6 +31,8 @@ struct resource ioport_resource = {
.start = 0,
.end = IO_SPACE_LIMIT,
.flags = IORESOURCE_IO,
+ .sibling = LIST_HEAD_INIT(ioport_resource.sibling),
+ .child = LIST_HEAD_INIT(ioport_resource.child),
};
EXPORT_SYMBOL(ioport_resource);
@@ -39,6 +41,8 @@ struct resource iomem_resource = {
.start = 0,
.end = -1,
.flags = IORESOURCE_MEM,
+ .sibling = LIST_HEAD_INIT(iomem_resource.sibling),
+ .child = LIST_HEAD_INIT(iomem_resource.child),
};
EXPORT_SYMBOL(iomem_resource);
@@ -57,20 +61,32 @@ static DEFINE_RWLOCK(resource_lock);
* by boot mem after the system is up. So for reusing the resource entry
* we need to remember the resource.
*/
-static struct resource *bootmem_resource_free;
+static struct list_head bootmem_resource_free = LIST_HEAD_INIT(bootmem_resource_free);
static DEFINE_SPINLOCK(bootmem_resource_lock);
+struct resource *sibling(struct resource *res)
+{
+ if (res->parent && !list_is_last(&res->sibling, &res->parent->child))
+ return list_next_entry(res, sibling);
+ return NULL;
+}
+
+struct resource *first_child(struct list_head *head)
+{
+ return list_first_entry_or_null(head, struct resource, sibling);
+}
+
static struct resource *next_resource(struct resource *p, bool sibling_only)
{
/* Caller wants to traverse through siblings only */
if (sibling_only)
- return p->sibling;
+ return sibling(p);
- if (p->child)
- return p->child;
- while (!p->sibling && p->parent)
+ if (!list_empty(&p->child))
+ return first_child(&p->child);
+ while (!sibling(p) && p->parent)
p = p->parent;
- return p->sibling;
+ return sibling(p);
}
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
@@ -90,7 +106,7 @@ static void *r_start(struct seq_file *m, loff_t *pos)
struct resource *p = m->private;
loff_t l = 0;
read_lock(&resource_lock);
- for (p = p->child; p && l < *pos; p = r_next(m, p, &l))
+ for (p = first_child(&p->child); p && l < *pos; p = r_next(m, p, &l))
;
return p;
}
@@ -186,8 +202,7 @@ static void free_resource(struct resource *res)
if (!PageSlab(virt_to_head_page(res))) {
spin_lock(&bootmem_resource_lock);
- res->sibling = bootmem_resource_free;
- bootmem_resource_free = res;
+ list_add(&res->sibling, &bootmem_resource_free);
spin_unlock(&bootmem_resource_lock);
} else {
kfree(res);
@@ -199,10 +214,9 @@ static struct resource *alloc_resource(gfp_t flags)
struct resource *res = NULL;
spin_lock(&bootmem_resource_lock);
- if (bootmem_resource_free) {
- res = bootmem_resource_free;
- bootmem_resource_free = res->sibling;
- }
+ res = first_child(&bootmem_resource_free);
+ if (res)
+ list_del(&res->sibling);
spin_unlock(&bootmem_resource_lock);
if (res)
@@ -210,6 +224,8 @@ static struct resource *alloc_resource(gfp_t flags)
else
res = kzalloc(sizeof(struct resource), flags);
+ INIT_LIST_HEAD(&res->child);
+ INIT_LIST_HEAD(&res->sibling);
return res;
}
@@ -218,7 +234,7 @@ static struct resource * __request_resource(struct resource *root, struct resour
{
resource_size_t start = new->start;
resource_size_t end = new->end;
- struct resource *tmp, **p;
+ struct resource *tmp;
if (end < start)
return root;
@@ -226,64 +242,62 @@ static struct resource * __request_resource(struct resource *root, struct resour
return root;
if (end > root->end)
return root;
- p = &root->child;
- for (;;) {
- tmp = *p;
- if (!tmp || tmp->start > end) {
- new->sibling = tmp;
- *p = new;
+
+ if (list_empty(&root->child)) {
+ list_add(&new->sibling, &root->child);
+ new->parent = root;
+ INIT_LIST_HEAD(&new->child);
+ return NULL;
+ }
+
+ list_for_each_entry(tmp, &root->child, sibling) {
+ if (tmp->start > end) {
+ list_add(&new->sibling, tmp->sibling.prev);
new->parent = root;
+ INIT_LIST_HEAD(&new->child);
return NULL;
}
- p = &tmp->sibling;
if (tmp->end < start)
continue;
return tmp;
}
+
+ list_add_tail(&new->sibling, &root->child);
+ new->parent = root;
+ INIT_LIST_HEAD(&new->child);
+ return NULL;
}
static int __release_resource(struct resource *old, bool release_child)
{
- struct resource *tmp, **p, *chd;
+ struct resource *tmp, *next, *chd;
- p = &old->parent->child;
- for (;;) {
- tmp = *p;
- if (!tmp)
- break;
+ list_for_each_entry_safe(tmp, next, &old->parent->child, sibling) {
if (tmp == old) {
- if (release_child || !(tmp->child)) {
- *p = tmp->sibling;
+ if (release_child || list_empty(&tmp->child)) {
+ list_del(&tmp->sibling);
} else {
- for (chd = tmp->child;; chd = chd->sibling) {
+ list_for_each_entry(chd, &tmp->child, sibling)
chd->parent = tmp->parent;
- if (!(chd->sibling))
- break;
- }
- *p = tmp->child;
- chd->sibling = tmp->sibling;
+ list_splice(&tmp->child, tmp->sibling.prev);
+ list_del(&tmp->sibling);
}
+
old->parent = NULL;
return 0;
}
- p = &tmp->sibling;
}
return -EINVAL;
}
static void __release_child_resources(struct resource *r)
{
- struct resource *tmp, *p;
+ struct resource *tmp, *next;
resource_size_t size;
- p = r->child;
- r->child = NULL;
- while (p) {
- tmp = p;
- p = p->sibling;
-
+ list_for_each_entry_safe(tmp, next, &r->child, sibling) {
tmp->parent = NULL;
- tmp->sibling = NULL;
+ INIT_LIST_HEAD(&tmp->sibling);
__release_child_resources(tmp);
printk(KERN_DEBUG "release child resource %pR\n", tmp);
@@ -292,6 +306,8 @@ static void __release_child_resources(struct resource *r)
tmp->start = 0;
tmp->end = size - 1;
}
+
+ INIT_LIST_HEAD(&tmp->child);
}
void release_child_resources(struct resource *r)
@@ -376,7 +392,8 @@ static int find_next_iomem_res(struct resource *res, unsigned long desc,
read_lock(&resource_lock);
- for (p = iomem_resource.child; p; p = next_resource(p, sibling_only)) {
+ for (p = first_child(&iomem_resource.child); p;
+ p = next_resource(p, sibling_only)) {
if ((p->flags & res->flags) != res->flags)
continue;
if ((desc != IORES_DESC_NONE) && (desc != p->desc))
@@ -564,7 +581,7 @@ int region_intersects(resource_size_t start, size_t size, unsigned long flags,
struct resource *p;
read_lock(&resource_lock);
- for (p = iomem_resource.child; p ; p = p->sibling) {
+ list_for_each_entry(p, &iomem_resource.child, sibling) {
bool is_type = (((p->flags & flags) == flags) &&
((desc == IORES_DESC_NONE) ||
(desc == p->desc)));
@@ -618,7 +635,7 @@ static int __find_resource(struct resource *root, struct resource *old,
resource_size_t size,
struct resource_constraint *constraint)
{
- struct resource *this = root->child;
+ struct resource *this = first_child(&root->child);
struct resource tmp = *new, avail, alloc;
tmp.start = root->start;
@@ -628,7 +645,7 @@ static int __find_resource(struct resource *root, struct resource *old,
*/
if (this && this->start == root->start) {
tmp.start = (this == old) ? old->start : this->end + 1;
- this = this->sibling;
+ this = sibling(this);
}
for(;;) {
if (this)
@@ -663,7 +680,7 @@ next: if (!this || this->end == root->end)
if (this != old)
tmp.start = this->end + 1;
- this = this->sibling;
+ this = sibling(this);
}
return -EBUSY;
}
@@ -707,7 +724,7 @@ static int reallocate_resource(struct resource *root, struct resource *old,
goto out;
}
- if (old->child) {
+ if (!list_empty(&old->child)) {
err = -EBUSY;
goto out;
}
@@ -788,7 +805,7 @@ struct resource *lookup_resource(struct resource *root, resource_size_t start)
struct resource *res;
read_lock(&resource_lock);
- for (res = root->child; res; res = res->sibling) {
+ list_for_each_entry(res, &root->child, sibling) {
if (res->start == start)
break;
}
@@ -821,32 +838,27 @@ static struct resource * __insert_resource(struct resource *parent, struct resou
break;
}
- for (next = first; ; next = next->sibling) {
+ for (next = first; ; next = sibling(next)) {
/* Partial overlap? Bad, and unfixable */
if (next->start < new->start || next->end > new->end)
return next;
- if (!next->sibling)
+ if (!sibling(next))
break;
- if (next->sibling->start > new->end)
+ if (sibling(next)->start > new->end)
break;
}
-
new->parent = parent;
- new->sibling = next->sibling;
- new->child = first;
+ list_add(&new->sibling, &next->sibling);
+ INIT_LIST_HEAD(&new->child);
- next->sibling = NULL;
- for (next = first; next; next = next->sibling)
+ /*
+ * From first to next, they all fall into new's region, so change them
+ * as new's children.
+ */
+ list_cut_position(&new->child, first->sibling.prev, &next->sibling);
+ list_for_each_entry(next, &new->child, sibling)
next->parent = new;
- if (parent->child == first) {
- parent->child = new;
- } else {
- next = parent->child;
- while (next->sibling != first)
- next = next->sibling;
- next->sibling = new;
- }
return NULL;
}
@@ -968,19 +980,17 @@ static int __adjust_resource(struct resource *res, resource_size_t start,
if ((start < parent->start) || (end > parent->end))
goto out;
- if (res->sibling && (res->sibling->start <= end))
+ if (sibling(res) && (sibling(res)->start <= end))
goto out;
- tmp = parent->child;
- if (tmp != res) {
- while (tmp->sibling != res)
- tmp = tmp->sibling;
+ if (res->sibling.prev != &parent->child) {
+ tmp = list_prev_entry(res, sibling);
if (start <= tmp->end)
goto out;
}
skip:
- for (tmp = res->child; tmp; tmp = tmp->sibling)
+ list_for_each_entry(tmp, &res->child, sibling)
if ((tmp->start < start) || (tmp->end > end))
goto out;
@@ -1205,34 +1215,32 @@ EXPORT_SYMBOL(__request_region);
void __release_region(struct resource *parent, resource_size_t start,
resource_size_t n)
{
- struct resource **p;
+ struct resource *res;
resource_size_t end;
- p = &parent->child;
+ res = first_child(&parent->child);
end = start + n - 1;
write_lock(&resource_lock);
for (;;) {
- struct resource *res = *p;
-
if (!res)
break;
if (res->start <= start && res->end >= end) {
if (!(res->flags & IORESOURCE_BUSY)) {
- p = &res->child;
+ res = first_child(&res->child);
continue;
}
if (res->start != start || res->end != end)
break;
- *p = res->sibling;
+ list_del(&res->sibling);
write_unlock(&resource_lock);
if (res->flags & IORESOURCE_MUXED)
wake_up(&muxed_resource_wait);
free_resource(res);
return;
}
- p = &res->sibling;
+ res = sibling(res);
}
write_unlock(&resource_lock);
@@ -1267,9 +1275,7 @@ EXPORT_SYMBOL(__release_region);
int release_mem_region_adjustable(struct resource *parent,
resource_size_t start, resource_size_t size)
{
- struct resource **p;
- struct resource *res;
- struct resource *new_res;
+ struct resource *res, *new_res;
resource_size_t end;
int ret = -EINVAL;
@@ -1280,16 +1286,16 @@ int release_mem_region_adjustable(struct resource *parent,
/* The alloc_resource() result gets checked later */
new_res = alloc_resource(GFP_KERNEL);
- p = &parent->child;
+ res = first_child(&parent->child);
write_lock(&resource_lock);
- while ((res = *p)) {
+ while ((res)) {
if (res->start >= end)
break;
/* look for the next resource if it does not fit into */
if (res->start > start || res->end < end) {
- p = &res->sibling;
+ res = sibling(res);
continue;
}
@@ -1297,14 +1303,14 @@ int release_mem_region_adjustable(struct resource *parent,
break;
if (!(res->flags & IORESOURCE_BUSY)) {
- p = &res->child;
+ res = first_child(&res->child);
continue;
}
/* found the target resource; let's adjust accordingly */
if (res->start == start && res->end == end) {
/* free the whole entry */
- *p = res->sibling;
+ list_del(&res->sibling);
free_resource(res);
ret = 0;
} else if (res->start == start && res->end != end) {
@@ -1327,14 +1333,13 @@ int release_mem_region_adjustable(struct resource *parent,
new_res->flags = res->flags;
new_res->desc = res->desc;
new_res->parent = res->parent;
- new_res->sibling = res->sibling;
- new_res->child = NULL;
+ INIT_LIST_HEAD(&new_res->child);
ret = __adjust_resource(res, res->start,
start - res->start);
if (ret)
break;
- res->sibling = new_res;
+ list_add(&new_res->sibling, &res->sibling);
new_res = NULL;
}
@@ -1515,7 +1520,7 @@ static int __init reserve_setup(char *str)
res->end = io_start + io_num - 1;
res->flags |= IORESOURCE_BUSY;
res->desc = IORES_DESC_NONE;
- res->child = NULL;
+ INIT_LIST_HEAD(&res->child);
if (request_resource(parent, res) == 0)
reserved = x+1;
}
@@ -1535,7 +1540,7 @@ int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
loff_t l;
read_lock(&resource_lock);
- for (p = p->child; p ; p = r_next(NULL, p, &l)) {
+ for (p = first_child(&p->child); p; p = r_next(NULL, p, &l)) {
/*
* We can probably skip the resources without
* IORESOURCE_IO attribute?
@@ -1591,7 +1596,7 @@ bool iomem_is_exclusive(u64 addr)
addr = addr & PAGE_MASK;
read_lock(&resource_lock);
- for (p = p->child; p ; p = r_next(NULL, p, &l)) {
+ for (p = first_child(&p->child); p; p = r_next(NULL, p, &l)) {
/*
* We can probably skip the resources without
* IORESOURCE_IO attribute?
--
2.13.6
^ permalink raw reply related
* [PATCH] HID: i2c-hid: Fix resume issue on Raydium touchscreen device
From: Aaron Ma @ 2018-04-09 7:41 UTC (permalink / raw)
To: jikos, benjamin.tissoires, aaron.ma, linux-input, linux-kernel
When Rayd touchscreen resumed from S3, it issues too many errors like:
i2c_hid i2c-RAYD0001:00: i2c_hid_get_input: incomplete report (58/5442)
And all the report data are corrupted, touchscreen is unresponsive.
Fix this by re-sending report description command after resume.
Add device ID as a quirk.
Cc: stable@vger.kernel.org
Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
---
drivers/hid/hid-ids.h | 3 +++
drivers/hid/i2c-hid/i2c-hid.c | 13 +++++++++++++
2 files changed, 16 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 5a3a7ead3012..0b5cc910f62e 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -525,6 +525,9 @@
#define I2C_VENDOR_ID_HANTICK 0x0911
#define I2C_PRODUCT_ID_HANTICK_5288 0x5288
+#define I2C_VENDOR_ID_RAYD 0x2386
+#define I2C_PRODUCT_ID_RAYD_3118 0x3118
+
#define USB_VENDOR_ID_HANWANG 0x0b57
#define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000
#define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 97689e98e53f..615a91ac93bd 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -47,6 +47,7 @@
/* quirks to control the device */
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1)
+#define I2C_HID_QUIRK_RESEND_REPORT_DESCR BIT(2)
/* flags */
#define I2C_HID_STARTED 0
@@ -171,6 +172,8 @@ static const struct i2c_hid_quirks {
I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
{ I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
+ { I2C_VENDOR_ID_RAYD, I2C_PRODUCT_ID_RAYD_3118,
+ I2C_HID_QUIRK_RESEND_REPORT_DESCR },
{ 0, 0 }
};
@@ -1220,6 +1223,16 @@ static int i2c_hid_resume(struct device *dev)
if (ret)
return ret;
+ /* RAYDIUM device (2386:3118) need to re-send report descr cmd
+ * after resume, after this it will be back normal.
+ * otherwise it issues too many incomplete reports.
+ */
+ if (ihid->quirks & I2C_HID_QUIRK_RESEND_REPORT_DESCR) {
+ ret = i2c_hid_command(client, &hid_report_descr_cmd, NULL, 0);
+ if (!ret)
+ return ret;
+ }
+
if (hid->driver && hid->driver->reset_resume) {
ret = hid->driver->reset_resume(hid);
return ret;
--
2.14.3
^ permalink raw reply related
* Re: [PATCH 2/2] HID: i2c-hid: Fix resume issue on Raydium touchscreen device
From: Aaron Ma @ 2018-04-09 7:31 UTC (permalink / raw)
To: linux-kernel, linux-input, jikos, benjamin.tissoires
In-Reply-To: <20180102173006.506-2-aaron.ma@canonical.com>
Hi Jiri:
Re-send this patch.
Thanks,
Aaron
On 01/03/2018 01:30 AM, Aaron Ma wrote:
> When Rayd touchscreen resumed from S3, it issues too many errors like:
> i2c_hid i2c-RAYD0001:00: i2c_hid_get_input: incomplete report (58/5442)
>
> And all the report data are corrupted, touchscreen is unresponsive.
>
> Fix this by re-sending report description command after resume.
> Add device ID as a quirk.
>
> Cc: stable@vger.kernel.org
> Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
> ---
> drivers/hid/hid-ids.h | 3 +++
> drivers/hid/i2c-hid/i2c-hid.c | 13 +++++++++++++
> 2 files changed, 16 insertions(+)
>
> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> index 5da3d6256d25..753cc10aa699 100644
> --- a/drivers/hid/hid-ids.h
> +++ b/drivers/hid/hid-ids.h
> @@ -516,6 +516,9 @@
> #define I2C_VENDOR_ID_HANTICK 0x0911
> #define I2C_PRODUCT_ID_HANTICK_5288 0x5288
>
> +#define I2C_VENDOR_ID_RAYD 0x2386
> +#define I2C_PRODUCT_ID_RAYD_3118 0x3118
> +
> #define USB_VENDOR_ID_HANWANG 0x0b57
> #define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000
> #define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff
> diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
> index 09404ffdb08b..57a447a9d40e 100644
> --- a/drivers/hid/i2c-hid/i2c-hid.c
> +++ b/drivers/hid/i2c-hid/i2c-hid.c
> @@ -47,6 +47,7 @@
> /* quirks to control the device */
> #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
> #define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1)
> +#define I2C_HID_QUIRK_RESEND_REPORT_DESCR BIT(2)
>
> /* flags */
> #define I2C_HID_STARTED 0
> @@ -171,6 +172,8 @@ static const struct i2c_hid_quirks {
> I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
> { I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
> I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
> + { I2C_VENDOR_ID_RAYD, I2C_PRODUCT_ID_RAYD_3118,
> + I2C_HID_QUIRK_RESEND_REPORT_DESCR },
> { 0, 0 }
> };
>
> @@ -1211,6 +1214,16 @@ static int i2c_hid_resume(struct device *dev)
> if (ret)
> return ret;
>
> + /* RAYDIUM device (2386:3118) need to re-send report descr cmd
> + * after resume, after this it will be back normal.
> + * otherwise it issues too many incomplete reports.
> + */
> + if (ihid->quirks & I2C_HID_QUIRK_RESEND_REPORT_DESCR) {
> + ret = i2c_hid_command(client, &hid_report_descr_cmd, NULL, 0);
> + if (!ret)
> + return ret;
> + }
> +
> if (hid->driver && hid->driver->reset_resume) {
> ret = hid->driver->reset_resume(hid);
> return ret;
> -- 2.14.3
>
^ permalink raw reply
* Re: [PATCH] hidraw: Fix crash on HIDIOCGFEATURE with a destroyed device
From: Jiri Kosina @ 2018-04-09 7:30 UTC (permalink / raw)
To: Rodrigo Rivas Costa; +Cc: Benjamin Tissoires, linux-input, linux-kernel
In-Reply-To: <20180405230936.4572-1-rodrigorivascosta@gmail.com>
On Fri, 6 Apr 2018, Rodrigo Rivas Costa wrote:
> Doing `ioctl(HIDIOCGFEATURE)` in a tight loop on a hidraw device
> and then disconnecting the device, or unloading the driver, can
> cause a NULL pointer dereference.
>
> When a hidraw device is destroyed it sets 0 to `dev->exist`.
> Most functions check 'dev->exist' before doing its work, but
> `hidraw_get_report()` was missing that check.
>
> Signed-off-by: Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>
Applied, thank you.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH 2/2] HID: i2c-hid: Fix resume issue on Raydium touchscreen device
From: Jiri Kosina @ 2018-04-09 7:29 UTC (permalink / raw)
To: Aaron Ma; +Cc: Benjamin Tissoires, lkml, linux-input
In-Reply-To: <f9becc3a-516f-7eed-06a9-c9e5610b9fd3@canonical.com>
On Tue, 3 Apr 2018, Aaron Ma wrote:
> Hi Jiri:
>
> This patch is pending for long time.
>
> Could you merge this single patch to upstream?
I don't this I am seeing it in my inbox. Could you please resend? Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH] HID: input: fix battery level reporting on BT mice
From: Jiri Kosina @ 2018-04-09 7:26 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Martin, Benjamin Tissoires, linux-input, linux-kernel
In-Reply-To: <20180403175220.GA148162@dtor-ws>
On Tue, 3 Apr 2018, Dmitry Torokhov wrote:
> The commit 581c4484769e ("HID: input: map digitizer battery usage")
> assumed that devices having input (qas opposed to feature) report for
> battery strength would report the data on their own, without the need to
> be polled by the kernel; unfortunately it is not so. Many wireless mice
> do not send unsolicited reports with battery strength data and have to
> be polled explicitly. As a complication, stylus devices on digitizers
> are not normally connected to the base and thus can not be polled - the
> base can only determine battery strength in the stylus when it is in
> proximity.
>
> To solve this issue, we add a special flag that tells the kernel
> to avoid polling the device (and expect unsolicited reports) and set it
> when report field with physical usage of digitizer stylus (HID_DG_STYLUS).
> Unless this flag is set, and we have not seen the unsolicited reports,
> the kernel will attempt to poll the device when userspace attempts to
> read "capacity" and "state" attributes of power_supply object
> corresponding to the devices battery.
>
> Fixes: 581c4484769e ("HID: input: map digitizer battery usage")
> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=198095
> Cc: stable@vger.kernel.org
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Applied for 4.17, thanks.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* [PATCH] Input: alps - Fix reporting pressure of v3 trackstick
From: Pali Rohár @ 2018-04-08 15:53 UTC (permalink / raw)
To: Dmitry Torokhov, Masaki Ota; +Cc: linux-input, linux-kernel
According to documentation, all 7 lower bits represents trackpoint pressure.
Fixes: 4621c9660459 ("Input: alps - report pressure of v3 and v7 trackstick")
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
---
drivers/input/mouse/alps.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 0a9e6a3a2f9f..1e28d9fc5492 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -583,7 +583,7 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
x = (s8)(((packet[0] & 0x20) << 2) | (packet[1] & 0x7f));
y = (s8)(((packet[0] & 0x10) << 3) | (packet[2] & 0x7f));
- z = packet[4] & 0x7c;
+ z = packet[4] & 0x7f;
/*
* The x and y values tend to be quite large, and when used
--
2.11.0
^ permalink raw reply related
* Re: [PATCH v2 1/3] resource: Use list_head to link sibling resource
From: Baoquan He @ 2018-04-08 9:09 UTC (permalink / raw)
To: kbuild test robot
Cc: Brijesh Singh, devicetree-u79uwXL29TY76Z2rM5mHXA, David Airlie,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Wei Yang, Keith Busch,
Yaowei Bai, K. Y. Srinivasan, Frank Rowand, Thomas Gleixner,
Lorenzo Pieralisi, Stephen Hemminger,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw, Patrik Jakobsson,
linux-input-u79uwXL29TY76Z2rM5mHXA, Borislav Petkov, Tom Lendacky,
Haiyang Zhang, Jérôme Glisse, Rob Herring,
Bjorn Helgaas, Jonathan Derrick, Greg Kroah-Hartman
In-Reply-To: <201804081223.lLuGQOqa%fengguang.wu-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
On 04/08/18 at 01:55pm, kbuild test robot wrote:
> Hi Baoquan,
>
> I love your patch! Yet something to improve:
>
> [auto build test ERROR on linus/master]
> [also build test ERROR on v4.16 next-20180406]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url: https://github.com/0day-ci/linux/commits/Baoquan-He/resource-Use-list_head-to-link-sibling-resource/20180408-110108
> config: sparc-defconfig (attached as .config)
> compiler: sparc-linux-gcc (GCC) 7.2.0
> reproduce:
> wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # save the attached .config to linux build tree
> make.cross ARCH=sparc
>
> All errors (new ones prefixed by >>):
>
> arch/sparc/kernel/ioport.c: In function 'sparc_io_proc_show':
> >> arch/sparc/kernel/ioport.c:672:9: error: incompatible types when assigning to type 'struct resource *' from type 'struct list_head'
> for (r = root->child; r != NULL; r = r->sibling) {
> ^
> arch/sparc/kernel/ioport.c:672:37: error: incompatible types when assigning to type 'struct resource *' from type 'struct list_head'
> for (r = root->child; r != NULL; r = r->sibling) {
> ^
Thanks, will change and repost.
>
> vim +672 arch/sparc/kernel/ioport.c
>
> ^1da177e4 Linus Torvalds 2005-04-16 666
> e7a088f93 Alexey Dobriyan 2009-09-01 667 static int sparc_io_proc_show(struct seq_file *m, void *v)
> ^1da177e4 Linus Torvalds 2005-04-16 668 {
> e7a088f93 Alexey Dobriyan 2009-09-01 669 struct resource *root = m->private, *r;
> ^1da177e4 Linus Torvalds 2005-04-16 670 const char *nm;
> ^1da177e4 Linus Torvalds 2005-04-16 671
> e7a088f93 Alexey Dobriyan 2009-09-01 @672 for (r = root->child; r != NULL; r = r->sibling) {
> c31f76518 Sam Ravnborg 2014-04-21 673 if ((nm = r->name) == NULL) nm = "???";
> e7a088f93 Alexey Dobriyan 2009-09-01 674 seq_printf(m, "%016llx-%016llx: %s\n",
> 685143ac1 Greg Kroah-Hartman 2006-06-12 675 (unsigned long long)r->start,
> 685143ac1 Greg Kroah-Hartman 2006-06-12 676 (unsigned long long)r->end, nm);
> ^1da177e4 Linus Torvalds 2005-04-16 677 }
> ^1da177e4 Linus Torvalds 2005-04-16 678
> e7a088f93 Alexey Dobriyan 2009-09-01 679 return 0;
> ^1da177e4 Linus Torvalds 2005-04-16 680 }
> ^1da177e4 Linus Torvalds 2005-04-16 681
>
> :::::: The code at line 672 was first introduced by commit
> :::::: e7a088f935180b90cfe6ab0aaae8a556f46885fe sparc: convert /proc/io_map, /proc/dvma_map to seq_file
>
> :::::: TO: Alexey Dobriyan <adobriyan-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> :::::: CC: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all Intel Corporation
^ permalink raw reply
* Re: [PATCH v2 1/3] resource: Use list_head to link sibling resource
From: Baoquan He @ 2018-04-08 9:09 UTC (permalink / raw)
To: kbuild test robot
Cc: Brijesh Singh, devicetree-u79uwXL29TY76Z2rM5mHXA, David Airlie,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Wei Yang, Keith Busch,
Yaowei Bai, K. Y. Srinivasan, Frank Rowand, Thomas Gleixner,
Lorenzo Pieralisi, Stephen Hemminger,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw, Patrik Jakobsson,
linux-input-u79uwXL29TY76Z2rM5mHXA, Borislav Petkov, Tom Lendacky,
Haiyang Zhang, Jérôme Glisse, Rob Herring,
Bjorn Helgaas, Jonathan Derrick, Greg Kroah-Hartman
In-Reply-To: <201804081247.F3eqBMih%fengguang.wu-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Hi,
Thanks for telling!
On 04/08/18 at 12:12pm, kbuild test robot wrote:
> Hi Baoquan,
>
> I love your patch! Yet something to improve:
>
> [auto build test ERROR on linus/master]
> [also build test ERROR on v4.16 next-20180406]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url: https://github.com/0day-ci/linux/commits/Baoquan-He/resource-Use-list_head-to-link-sibling-resource/20180408-110108
> config: parisc-c3000_defconfig (attached as .config)
> compiler: hppa-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
> reproduce:
> wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # save the attached .config to linux build tree
> make.cross ARCH=parisc
>
> All errors (new ones prefixed by >>):
>
> drivers//parisc/lba_pci.c: In function 'lba_dump_res':
> >> drivers//parisc/lba_pci.c:173:15: error: incompatible type for argument 1 of 'lba_dump_res'
> lba_dump_res(r->child, d+2);
I compiled with allyesconfig, don't know why this was missed. Will
change and repost.
> ^
> drivers//parisc/lba_pci.c:162:1: note: expected 'struct resource *' but argument is of type 'struct list_head'
> lba_dump_res(struct resource *r, int d)
> ^~~~~~~~~~~~
> drivers//parisc/lba_pci.c:174:15: error: incompatible type for argument 1 of 'lba_dump_res'
> lba_dump_res(r->sibling, d);
> ^
> drivers//parisc/lba_pci.c:162:1: note: expected 'struct resource *' but argument is of type 'struct list_head'
> lba_dump_res(struct resource *r, int d)
> ^~~~~~~~~~~~
>
> vim +/lba_dump_res +173 drivers//parisc/lba_pci.c
>
> ^1da177e Linus Torvalds 2005-04-16 159
> ^1da177e Linus Torvalds 2005-04-16 160
> ^1da177e Linus Torvalds 2005-04-16 161 static void
> ^1da177e Linus Torvalds 2005-04-16 162 lba_dump_res(struct resource *r, int d)
> ^1da177e Linus Torvalds 2005-04-16 163 {
> ^1da177e Linus Torvalds 2005-04-16 164 int i;
> ^1da177e Linus Torvalds 2005-04-16 165
> ^1da177e Linus Torvalds 2005-04-16 166 if (NULL == r)
> ^1da177e Linus Torvalds 2005-04-16 167 return;
> ^1da177e Linus Torvalds 2005-04-16 168
> ^1da177e Linus Torvalds 2005-04-16 169 printk(KERN_DEBUG "(%p)", r->parent);
> ^1da177e Linus Torvalds 2005-04-16 170 for (i = d; i ; --i) printk(" ");
> 645d11d4 Matthew Wilcox 2006-12-24 171 printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r,
> 645d11d4 Matthew Wilcox 2006-12-24 172 (long)r->start, (long)r->end, r->flags);
> ^1da177e Linus Torvalds 2005-04-16 @173 lba_dump_res(r->child, d+2);
> ^1da177e Linus Torvalds 2005-04-16 174 lba_dump_res(r->sibling, d);
> ^1da177e Linus Torvalds 2005-04-16 175 }
> ^1da177e Linus Torvalds 2005-04-16 176
>
> :::::: The code at line 173 was first introduced by commit
> :::::: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Linux-2.6.12-rc2
>
> :::::: TO: Linus Torvalds <torvalds-gWtpgVMusWVb5UGfqNBoRg@public.gmane.org>
> :::::: CC: Linus Torvalds <torvalds-gWtpgVMusWVb5UGfqNBoRg@public.gmane.org>
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all Intel Corporation
^ 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