* Re: Regression post "HID: core: move Usage Page concatenation to Main item"
From: Nicolas Saenz Julienne @ 2019-06-14 8:29 UTC (permalink / raw)
To: Jean-Baptiste Théou, Jiri Kosina, linux-input, linux-kernel
In-Reply-To: <CAEXycp+Y-x7N_Yr==Xy_CT5K_a1DZYc85w1OUV+cKC5ZN+KB1g@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 629 bytes --]
On Fri, 2019-06-14 at 09:01 +0900, Jean-Baptiste Théou wrote:
> Hi,
>
> This patch (58e75155009cc800005629955d3482f36a1e0eec) is triggering a
> regression with the following descriptor (report not working as
> expected)
>
>
https://partner-android.googlesource.com/platform/cts/+/refs/heads/q-fs-release/tests/tests/hardware/res/raw/asus_gamepad_register.json
>
> Didn't see anything obviously wrong with this gamepad descriptor, so
> not sure what's trigger the regression.
>
I'll have a look at it.
Do you have any more information on the regression? What exactly isn't working?
Regards,
Nicolas
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH] Input: cros_ec_keyb: mask out extra flags in event_type
From: Ting Shen @ 2019-06-14 6:54 UTC (permalink / raw)
To: LKML
Cc: Nicolas Boichat, Pi-Hsun Shih, Enrico Granata, Ting Shen,
Enric Balletbo i Serra, Heiko Stuebner, Guenter Roeck,
Brian Norris, Benson Leung, Dmitry Torokhov, linux-input,
Colin Ian King
http://crosreview.com/1341159 added a EC_MKBP_HAS_MORE_EVENTS flag to
the event_type field, the receiver side should mask out this extra bit when
processing the event.
Signed-off-by: Ting Shen <phoenixshen@chromium.org>
---
drivers/input/keyboard/cros_ec_keyb.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index d5600118159835..38cb6d82d8fe67 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -237,7 +237,7 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
if (queued_during_suspend && !device_may_wakeup(ckdev->dev))
return NOTIFY_OK;
- switch (ckdev->ec->event_data.event_type) {
+ switch (ckdev->ec->event_data.event_type & EC_MKBP_EVENT_TYPE_MASK) {
case EC_MKBP_EVENT_KEY_MATRIX:
pm_wakeup_event(ckdev->dev, 0);
--
2.22.0.rc2.383.gf4fbbf30c2-goog
^ permalink raw reply related
* Re: [PATCH 1/2] Input: synaptics-rmi4 - clear irqs before set irqs
From: Aaron Ma @ 2019-06-14 4:26 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: linux-input, linux-kernel, Cheiny, aduggan, benjamin.tissoires
In-Reply-To: <20190611173545.GE143729@dtor-ws>
On 6/12/19 1:35 AM, Dmitry Torokhov wrote:
> On Tue, Jun 11, 2019 at 12:55:58AM +0800, Aaron Ma wrote:
>> On 6/10/19 12:55 AM, Dmitry Torokhov wrote:
>>> Hi Aaron,
>>>
>>> On Wed, Feb 20, 2019 at 05:41:59PM +0100, Aaron Ma wrote:
>>>> rmi4 got spam data after S3 resume on some ThinkPads.
>>>> Then TrackPoint lost when be detected by psmouse.
>>>> Clear irqs status before set irqs will make TrackPoint back.
>>> Could you please give me an idea as to what this spam data is?
>>>
>> It should be some data 0 during suspend/resume.
>> Actually I don't know how these data 0 is produced.
>> Not all synaptics touchpads have this issue.
>>
>>> In F03 probe we clear all pending data before enabling the function,
>> Yes we did, but not after resume.
> Yes, I understand that. The question I was asking: if we add code
> consuming all pending data to f03->suspend(), similarly to what we are
> doing at probe time, will it fix the issue with trackstick losing
> synchronization and attempting disconnect?
>
I just do some test via adding code in suspend or resume.
But they didn't work out.
>>> maybe the same needs to be done on resume, instead of changing the way
>>> we handle IRQ bits?
>> This patch is supposed to clear irq status like it in fn probe. Not
>> changing IRQ bits.
> What I meant is changing how we enable IRQ bits. I would really prefer
> we did not lose IRQ state for other functions when we enable interrupts
> for given function.
>
Not only F03 with problem, F12 too which is touchpad .
User verified this patch fixes problem of F12 too.
Clear IRQ status before enable IRQ should be safe.
Or we can add code before enable IRQ in F03/F12.
Thanks,
Aaron
> Thanks.
>
> -- Dmitry
>
^ permalink raw reply
* Re: Regression post "HID: core: move Usage Page concatenation to Main item"
From: Jean-Baptiste Théou @ 2019-06-14 0:02 UTC (permalink / raw)
To: Jiri Kosina, linux-input, linux-kernel, nsaenzjulienne
In-Reply-To: <CAEXycp+Y-x7N_Yr==Xy_CT5K_a1DZYc85w1OUV+cKC5ZN+KB1g@mail.gmail.com>
Sorry - Please find the public link:
https://android.googlesource.com/platform/cts/+/master/tests/tests/hardware/res/raw/asus_gamepad_register.json
Best regards
On Fri, Jun 14, 2019 at 9:01 AM Jean-Baptiste Théou <jb@essential.com> wrote:
>
> Hi,
>
> This patch (58e75155009cc800005629955d3482f36a1e0eec) is triggering a
> regression with the following descriptor (report not working as
> expected)
>
> https://partner-android.googlesource.com/platform/cts/+/refs/heads/q-fs-release/tests/tests/hardware/res/raw/asus_gamepad_register.json
>
> Didn't see anything obviously wrong with this gamepad descriptor, so
> not sure what's trigger the regression.
>
> Thanks a lot
>
> Best regards
--
Jean-Baptiste Théou
Principal System Software Engineer @ Essential
^ permalink raw reply
* Regression post "HID: core: move Usage Page concatenation to Main item"
From: Jean-Baptiste Théou @ 2019-06-14 0:01 UTC (permalink / raw)
To: Jiri Kosina, linux-input, linux-kernel, nsaenzjulienne
Hi,
This patch (58e75155009cc800005629955d3482f36a1e0eec) is triggering a
regression with the following descriptor (report not working as
expected)
https://partner-android.googlesource.com/platform/cts/+/refs/heads/q-fs-release/tests/tests/hardware/res/raw/asus_gamepad_register.json
Didn't see anything obviously wrong with this gamepad descriptor, so
not sure what's trigger the regression.
Thanks a lot
Best regards
^ permalink raw reply
* Re: [PATCH 2/2] dt-bindings: input: Add wakeup-source for atmel,maxtouch
From: Rob Herring @ 2019-06-13 22:52 UTC (permalink / raw)
Cc: nick, dmitry.torokhov, robh+dt, mark.rutland, Stefano Manni,
linux-input, devicetree, linux-kernel
In-Reply-To: <20190517211741.8906-2-stefano.manni@gmail.com>
On Fri, 17 May 2019 23:17:41 +0200, Stefano Manni wrote:
> Add wakeup support to the maxtouch driver.
>
> Signed-off-by: Stefano Manni <stefano.manni@gmail.com>
> ---
> Documentation/devicetree/bindings/input/atmel,maxtouch.txt | 5 +++++
> 1 file changed, 5 insertions(+)
>
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [RFC PATCH v2 1/4] dt-bindings: input: Add support for the MPR121 without interrupt line
From: Rob Herring @ 2019-06-13 22:39 UTC (permalink / raw)
To: Michal Vokáč
Cc: Dmitry Torokhov, Mark Rutland, Shawn Guo, Sascha Hauer,
Fabio Estevam, linux-input, devicetree, linux-kernel,
Pengutronix Kernel Team
In-Reply-To: <1558098773-47416-2-git-send-email-michal.vokac@ysoft.com>
On Fri, May 17, 2019 at 03:12:50PM +0200, Michal Vokáč wrote:
> Normally, the MPR121 controller uses separate interrupt line to notify
> the I2C host that a key was touched/released. To support platforms that
> can not use the interrupt line, polling of the MPR121 registers can be
> used.
'separate' from what?
>
> Signed-off-by: Michal Vokáč <michal.vokac@ysoft.com>
> ---
> Changes since v1:
> - Document the polled binding in the original file, do not create a new one.
> (Rob)
>
> Documentation/devicetree/bindings/input/mpr121-touchkey.txt | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/input/mpr121-touchkey.txt b/Documentation/devicetree/bindings/input/mpr121-touchkey.txt
> index b7c61ee5841b..97f55273d473 100644
> --- a/Documentation/devicetree/bindings/input/mpr121-touchkey.txt
> +++ b/Documentation/devicetree/bindings/input/mpr121-touchkey.txt
> @@ -1,9 +1,14 @@
> -* Freescale MPR121 Controllor
> +* Freescale MPR121 Controller
>
> Required Properties:
> -- compatible: Should be "fsl,mpr121-touchkey"
> +- compatible: Should be one of:
> + - "fsl,mpr121-touchkey" - MPR121 with interrupt line
> + - "fsl,mpr121-touchkey-polled" - MPR121 with polling
> - reg: The I2C slave address of the device.
> - interrupts: The interrupt number to the cpu.
> + In case of "fsl,mpr121-touchkey-polled" the interrupt
> + line is not used and hence the interrupts property is
> + not required.
Absence of the interrupts property is enough to determine polled mode
and you don't need a separate compatible string.
> - vdd-supply: Phandle to the Vdd power supply.
> - linux,keycodes: Specifies an array of numeric keycode values to
> be used for reporting button presses. The array can
> --
> 2.1.4
>
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: input: mtk-pmic-keys: add MT6392 binding definition
From: Rob Herring @ 2019-06-13 20:28 UTC (permalink / raw)
Cc: dmitry.torokhov, robh+dt, mark.rutland, matthias.bgg, linux-input,
devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
Fabien Parent
In-Reply-To: <20190513142120.6527-1-fparent@baylibre.com>
On Mon, 13 May 2019 16:21:19 +0200, Fabien Parent wrote:
> Add the binding documentation of the mtk-pmic-keys for the MT6392 PMICs.
>
> Signed-off-by: Fabien Parent <fparent@baylibre.com>
> ---
> .../devicetree/bindings/input/mtk-pmic-keys.txt | 11 +++++++----
> 1 file changed, 7 insertions(+), 4 deletions(-)
>
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v2] Input: atmel_mxt_ts - fix -Wunused-const-variable
From: Nick Desaulniers @ 2019-06-13 18:26 UTC (permalink / raw)
To: Nathan Huckleberry
Cc: nick, dmitry.torokhov, linux-input, LKML, clang-built-linux
In-Reply-To: <20190613182326.237391-1-nhuck@google.com>
On Thu, Jun 13, 2019 at 11:24 AM 'Nathan Huckleberry' via Clang Built
Linux <clang-built-linux@googlegroups.com> wrote:
> Changes from v1 -> v2
> * Moved definition of mxt_video_fops into existing ifdef
Thanks for the v2.
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -256,16 +256,6 @@ enum v4l_dbg_inputs {
> MXT_V4L_INPUT_MAX,
> };
>
> -static const struct v4l2_file_operations mxt_video_fops = {
> - .owner = THIS_MODULE,
> - .open = v4l2_fh_open,
> - .release = vb2_fop_release,
> - .unlocked_ioctl = video_ioctl2,
> - .read = vb2_fop_read,
> - .mmap = vb2_fop_mmap,
> - .poll = vb2_fop_poll,
> -};
> -
> enum mxt_suspend_mode {
> MXT_SUSPEND_DEEP_SLEEP = 0,
> MXT_SUSPEND_T9_CTRL = 1,
> @@ -2218,6 +2208,16 @@ static int mxt_init_t7_power_cfg(struct mxt_data *data)
> }
>
> #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
> +static const struct v4l2_file_operations mxt_video_fops = {
> + .owner = THIS_MODULE,
> + .open = v4l2_fh_open,
> + .release = vb2_fop_release,
> + .unlocked_ioctl = video_ioctl2,
> + .read = vb2_fop_read,
> + .mmap = vb2_fop_mmap,
> + .poll = vb2_fop_poll,
> +};
> +
--
Thanks,
~Nick Desaulniers
^ permalink raw reply
* [PATCH v2] Input: atmel_mxt_ts - fix -Wunused-const-variable
From: Nathan Huckleberry @ 2019-06-13 18:23 UTC (permalink / raw)
To: nick, dmitry.torokhov
Cc: linux-input, linux-kernel, Nathan Huckleberry, clang-built-linux
In-Reply-To: <CAKwvOdnjTxzXgPHQcC7K8N5YkTvh66sy86oorPJZc07b7UBhGw@mail.gmail.com>
Clang produces the following warning
drivers/input/touchscreen/atmel_mxt_ts.c:259:42: warning: unused
variable 'mxt_video_fops' [-Wunused-const-variable]
static const struct v4l2_file_operations mxt_video_fops = {
Since mxt_video_fops is only used inside an ifdef. It should
be moved inside the ifdef.
Cc: clang-built-linux@googlegroups.com
Link: https://github.com/ClangBuiltLinux/linux/issues/527
Signed-off-by: Nathan Huckleberry <nhuck@google.com>
---
Changes from v1 -> v2
* Moved definition of mxt_video_fops into existing ifdef
drivers/input/touchscreen/atmel_mxt_ts.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 19378f200c63..0dae381c6637 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -256,16 +256,6 @@ enum v4l_dbg_inputs {
MXT_V4L_INPUT_MAX,
};
-static const struct v4l2_file_operations mxt_video_fops = {
- .owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .release = vb2_fop_release,
- .unlocked_ioctl = video_ioctl2,
- .read = vb2_fop_read,
- .mmap = vb2_fop_mmap,
- .poll = vb2_fop_poll,
-};
-
enum mxt_suspend_mode {
MXT_SUSPEND_DEEP_SLEEP = 0,
MXT_SUSPEND_T9_CTRL = 1,
@@ -2218,6 +2208,16 @@ static int mxt_init_t7_power_cfg(struct mxt_data *data)
}
#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
+static const struct v4l2_file_operations mxt_video_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
+};
+
static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
unsigned int y)
{
--
2.22.0.rc2.383.gf4fbbf30c2-goog
^ permalink raw reply related
* Re: [PATCH] Input: atmel_mxt_ts - fix -Wunused-const-variable
From: Nick Desaulniers @ 2019-06-13 17:47 UTC (permalink / raw)
To: Nathan Huckleberry
Cc: nick, dmitry.torokhov, linux-input, LKML, clang-built-linux
In-Reply-To: <20190612235803.9290-1-nhuck@google.com>
On Wed, Jun 12, 2019 at 4:58 PM 'Nathan Huckleberry' via Clang Built
Linux <clang-built-linux@googlegroups.com> wrote:
> Since mxt_video_fops is only used inside an ifdef. It should
> be moved inside the ifdef.
Thanks for the patch! I agree. I think it would be better and clearer
to sink the definition of `mxt_video_fops` down closer to its use,
immediately before the definition of `mxt_video_device`. Then it
would be closer to its use and it would also be within the existing
ifdef.
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -256,6 +256,7 @@ enum v4l_dbg_inputs {
> MXT_V4L_INPUT_MAX,
> };
>
> +#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
> static const struct v4l2_file_operations mxt_video_fops = {
> .owner = THIS_MODULE,
> .open = v4l2_fh_open,
> @@ -265,6 +266,7 @@ static const struct v4l2_file_operations mxt_video_fops = {
> .mmap = vb2_fop_mmap,
> .poll = vb2_fop_poll,
> };
> +#endif
--
Thanks,
~Nick Desaulniers
^ permalink raw reply
* [PATCH v3 7/7] Input: add IOC3 serio driver
From: Thomas Bogendoerfer @ 2019-06-13 17:06 UTC (permalink / raw)
To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
Lee Jones, David S. Miller, Srinivas Kandagatla, Alessandro Zummo,
Alexandre Belloni, Greg Kroah-Hartman, Jiri Slaby, linux-mips,
linux-kernel, linux-input, netdev, linux-rtc, linux-serial
In-Reply-To: <20190613170636.6647-1-tbogendoerfer@suse.de>
This patch adds a platform driver for supporting keyboard and mouse
interface of SGI IOC3 chips.
Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
drivers/input/serio/Kconfig | 10 +++
drivers/input/serio/Makefile | 1 +
drivers/input/serio/ioc3kbd.c | 158 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 169 insertions(+)
create mode 100644 drivers/input/serio/ioc3kbd.c
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index f3e18f8ef9ca..373a1646019e 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -165,6 +165,16 @@ config SERIO_MACEPS2
To compile this driver as a module, choose M here: the
module will be called maceps2.
+config SERIO_SGI_IOC3
+ tristate "SGI IOC3 PS/2 controller"
+ depends on SGI_MFD_IOC3
+ help
+ Say Y here if you have an SGI Onyx2, SGI Octane or IOC3 PCI card
+ and you want to attach and use a keyboard, mouse, or both.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ioc3kbd.
+
config SERIO_LIBPS2
tristate "PS/2 driver library"
depends on SERIO_I8042 || SERIO_I8042=n
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 67950a5ccb3f..6d97bad7b844 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
obj-$(CONFIG_SERIO_PS2MULT) += ps2mult.o
obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
+obj-$(CONFIG_SERIO_SGI_IOC3) += ioc3kbd.o
obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
obj-$(CONFIG_SERIO_RAW) += serio_raw.o
obj-$(CONFIG_SERIO_AMS_DELTA) += ams_delta_serio.o
diff --git a/drivers/input/serio/ioc3kbd.c b/drivers/input/serio/ioc3kbd.c
new file mode 100644
index 000000000000..26fcf57465d6
--- /dev/null
+++ b/drivers/input/serio/ioc3kbd.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SGI IOC3 PS/2 controller driver for linux
+ *
+ * Copyright (C) 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de>
+ *
+ * Based on code Copyright (C) 2005 Stanislaw Skowronek <skylark@unaligned.org>
+ * Copyright (C) 2009 Johannes Dickgreber <tanzy@gmx.de>
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/serio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/sn/ioc3.h>
+
+struct ioc3kbd_data {
+ struct ioc3_serioregs __iomem *regs;
+ struct serio *kbd, *aux;
+};
+
+static int ioc3kbd_write(struct serio *dev, u8 val)
+{
+ struct ioc3kbd_data *d = dev->port_data;
+ unsigned long timeout = 0;
+ u32 mask;
+
+ mask = (dev == d->aux) ? KM_CSR_M_WRT_PEND : KM_CSR_K_WRT_PEND;
+ while ((readl(&d->regs->km_csr) & mask) && (timeout < 1000)) {
+ udelay(100);
+ timeout++;
+ }
+
+ if (timeout >= 1000)
+ return -1;
+
+ writel(val, dev == d->aux ? &d->regs->m_wd : &d->regs->k_wd);
+
+ return 0;
+}
+
+static irqreturn_t ioc3kbd_intr(int itq, void *dev_id)
+{
+ struct ioc3kbd_data *d = dev_id;
+ u32 data_k, data_m;
+
+ data_k = readl(&d->regs->k_rd);
+ data_m = readl(&d->regs->m_rd);
+
+ if (data_k & KM_RD_VALID_0)
+ serio_interrupt(d->kbd,
+ (data_k >> KM_RD_DATA_0_SHIFT) & 0xff, 0);
+ if (data_k & KM_RD_VALID_1)
+ serio_interrupt(d->kbd,
+ (data_k >> KM_RD_DATA_1_SHIFT) & 0xff, 0);
+ if (data_k & KM_RD_VALID_2)
+ serio_interrupt(d->kbd,
+ (data_k >> KM_RD_DATA_2_SHIFT) & 0xff, 0);
+ if (data_m & KM_RD_VALID_0)
+ serio_interrupt(d->aux,
+ (data_m >> KM_RD_DATA_0_SHIFT) & 0xff, 0);
+ if (data_m & KM_RD_VALID_1)
+ serio_interrupt(d->aux,
+ (data_m >> KM_RD_DATA_1_SHIFT) & 0xff, 0);
+ if (data_m & KM_RD_VALID_2)
+ serio_interrupt(d->aux,
+ (data_m >> KM_RD_DATA_2_SHIFT) & 0xff, 0);
+
+ return 0;
+}
+
+static int ioc3kbd_probe(struct platform_device *pdev)
+{
+ struct ioc3_serioregs __iomem *regs;
+ struct device *dev = &pdev->dev;
+ struct ioc3kbd_data *d;
+ struct serio *sk, *sa;
+ struct resource *mem;
+ int irq, ret;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -ENXIO;
+
+ d = devm_kzalloc(&pdev->dev, sizeof(struct ioc3kbd_data), GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
+
+ ret = devm_request_irq(&pdev->dev, irq, ioc3kbd_intr, IRQF_SHARED,
+ "ioc3-kbd", d);
+ if (ret) {
+ dev_err(&pdev->dev, "could not request IRQ %d\n", irq);
+ return ret;
+ }
+
+ sk = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!sk)
+ return -ENOMEM;
+
+ sa = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!sa) {
+ kfree(sk);
+ return -ENOMEM;
+ }
+
+ sk->id.type = SERIO_8042;
+ sk->write = ioc3kbd_write;
+ snprintf(sk->name, sizeof(sk->name), "IOC3 keyboard %d", pdev->id);
+ snprintf(sk->phys, sizeof(sk->phys), "ioc3/serio%dkbd", pdev->id);
+ sk->port_data = d;
+ sk->dev.parent = &pdev->dev;
+
+ sa->id.type = SERIO_8042;
+ sa->write = ioc3kbd_write;
+ snprintf(sa->name, sizeof(sa->name), "IOC3 auxiliary %d", pdev->id);
+ snprintf(sa->phys, sizeof(sa->phys), "ioc3/serio%daux", pdev->id);
+ sa->port_data = d;
+ sa->dev.parent = dev;
+
+ d->regs = regs;
+ d->kbd = sk;
+ d->aux = sa;
+
+ platform_set_drvdata(pdev, d);
+ serio_register_port(d->kbd);
+ serio_register_port(d->aux);
+ return 0;
+}
+
+static int ioc3kbd_remove(struct platform_device *pdev)
+{
+ struct ioc3kbd_data *d = platform_get_drvdata(pdev);
+
+ serio_unregister_port(d->kbd);
+ serio_unregister_port(d->aux);
+ return 0;
+}
+
+static struct platform_driver ioc3kbd_driver = {
+ .probe = ioc3kbd_probe,
+ .remove = ioc3kbd_remove,
+ .driver = {
+ .name = "ioc3-kbd",
+ },
+};
+module_platform_driver(ioc3kbd_driver);
+
+MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
+MODULE_DESCRIPTION("SGI IOC3 serio driver");
+MODULE_LICENSE("GPL");
--
2.13.7
^ permalink raw reply related
* [PATCH v3 6/7] MIPS: SGI-IP27: fix readb/writeb addressing
From: Thomas Bogendoerfer @ 2019-06-13 17:06 UTC (permalink / raw)
To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
Lee Jones, David S. Miller, Srinivas Kandagatla, Alessandro Zummo,
Alexandre Belloni, Greg Kroah-Hartman, Jiri Slaby, linux-mips,
linux-kernel, linux-input, netdev, linux-rtc, linux-serial
In-Reply-To: <20190613170636.6647-1-tbogendoerfer@suse.de>
Our chosen byte swapping, which is what firmware already uses, is to
do readl/writel by normal lw/sw intructions (data invariance). This
also means we need to mangle addresses for u8 and u16 accesses. The
mangling for 16bit has been done aready, but 8bit one was missing.
Correcting this causes different addresses for accesses to the
SuperIO and local bus of the IOC3 chip. This is fixed by changing
byte order in ioc3 and m48rtc_rtc structs.
Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
arch/mips/include/asm/mach-ip27/mangle-port.h | 4 +-
arch/mips/include/asm/sn/ioc3.h | 198 +++++++++++++-------------
arch/mips/sgi-ip27/ip27-console.c | 5 +-
drivers/rtc/rtc-m48t35.c | 11 ++
drivers/tty/serial/8250/8250_ioc3.c | 4 +-
5 files changed, 115 insertions(+), 107 deletions(-)
diff --git a/arch/mips/include/asm/mach-ip27/mangle-port.h b/arch/mips/include/asm/mach-ip27/mangle-port.h
index f6e4912ea062..27c56efa519f 100644
--- a/arch/mips/include/asm/mach-ip27/mangle-port.h
+++ b/arch/mips/include/asm/mach-ip27/mangle-port.h
@@ -8,7 +8,7 @@
#ifndef __ASM_MACH_IP27_MANGLE_PORT_H
#define __ASM_MACH_IP27_MANGLE_PORT_H
-#define __swizzle_addr_b(port) (port)
+#define __swizzle_addr_b(port) ((port) ^ 3)
#define __swizzle_addr_w(port) ((port) ^ 2)
#define __swizzle_addr_l(port) (port)
#define __swizzle_addr_q(port) (port)
@@ -20,6 +20,6 @@
# define ioswabl(a, x) (x)
# define __mem_ioswabl(a, x) cpu_to_le32(x)
# define ioswabq(a, x) (x)
-# define __mem_ioswabq(a, x) cpu_to_le32(x)
+# define __mem_ioswabq(a, x) cpu_to_le64(x)
#endif /* __ASM_MACH_IP27_MANGLE_PORT_H */
diff --git a/arch/mips/include/asm/sn/ioc3.h b/arch/mips/include/asm/sn/ioc3.h
index 89938fdce8ef..ac6d7e6e31e0 100644
--- a/arch/mips/include/asm/sn/ioc3.h
+++ b/arch/mips/include/asm/sn/ioc3.h
@@ -10,35 +10,35 @@
/* serial port register map */
struct ioc3_serialregs {
- uint32_t sscr;
- uint32_t stpir;
- uint32_t stcir;
- uint32_t srpir;
- uint32_t srcir;
- uint32_t srtr;
- uint32_t shadow;
+ u32 sscr;
+ u32 stpir;
+ u32 stcir;
+ u32 srpir;
+ u32 srcir;
+ u32 srtr;
+ u32 shadow;
};
/* SUPERIO uart register map */
struct ioc3_uartregs {
+ u8 iu_lcr;
union {
- char rbr; /* read only, DLAB == 0 */
- char thr; /* write only, DLAB == 0 */
- char dll; /* DLAB == 1 */
- } u1;
+ u8 iir; /* read only */
+ u8 fcr; /* write only */
+ };
union {
- char ier; /* DLAB == 0 */
- char dlm; /* DLAB == 1 */
- } u2;
+ u8 ier; /* DLAB == 0 */
+ u8 dlm; /* DLAB == 1 */
+ };
union {
- char iir; /* read only */
- char fcr; /* write only */
- } u3;
- char iu_lcr;
- char iu_mcr;
- char iu_lsr;
- char iu_msr;
- char iu_scr;
+ u8 rbr; /* read only, DLAB == 0 */
+ u8 thr; /* write only, DLAB == 0 */
+ u8 dll; /* DLAB == 1 */
+ } u1;
+ u8 iu_scr;
+ u8 iu_msr;
+ u8 iu_lsr;
+ u8 iu_mcr;
};
#define iu_rbr u1.rbr
@@ -50,122 +50,122 @@ struct ioc3_uartregs {
#define iu_fcr u3.fcr
struct ioc3_sioregs {
- char fill[0x141]; /* starts at 0x141 */
+ u8 fill[0x141]; /* starts at 0x141 */
- char uartc;
- char kbdcg;
+ u8 kbdcg;
+ u8 uartc;
- char fill0[0x150 - 0x142 - 1];
+ u8 fill0[0x151 - 0x142 - 1];
- char pp_data;
- char pp_dsr;
- char pp_dcr;
+ u8 pp_dcr;
+ u8 pp_dsr;
+ u8 pp_data;
- char fill1[0x158 - 0x152 - 1];
+ u8 fill1[0x159 - 0x153 - 1];
- char pp_fifa;
- char pp_cfgb;
- char pp_ecr;
+ u8 pp_ecr;
+ u8 pp_cfgb;
+ u8 pp_fifa;
- char fill2[0x168 - 0x15a - 1];
+ u8 fill2[0x16a - 0x15b - 1];
- char rtcad;
- char rtcdat;
+ u8 rtcdat;
+ u8 rtcad;
- char fill3[0x170 - 0x169 - 1];
+ u8 fill3[0x170 - 0x16b - 1];
struct ioc3_uartregs uartb; /* 0x20170 */
struct ioc3_uartregs uarta; /* 0x20178 */
};
struct ioc3_ethregs {
- uint32_t emcr; /* 0x000f0 */
- uint32_t eisr; /* 0x000f4 */
- uint32_t eier; /* 0x000f8 */
- uint32_t ercsr; /* 0x000fc */
- uint32_t erbr_h; /* 0x00100 */
- uint32_t erbr_l; /* 0x00104 */
- uint32_t erbar; /* 0x00108 */
- uint32_t ercir; /* 0x0010c */
- uint32_t erpir; /* 0x00110 */
- uint32_t ertr; /* 0x00114 */
- uint32_t etcsr; /* 0x00118 */
- uint32_t ersr; /* 0x0011c */
- uint32_t etcdc; /* 0x00120 */
- uint32_t ebir; /* 0x00124 */
- uint32_t etbr_h; /* 0x00128 */
- uint32_t etbr_l; /* 0x0012c */
- uint32_t etcir; /* 0x00130 */
- uint32_t etpir; /* 0x00134 */
- uint32_t emar_h; /* 0x00138 */
- uint32_t emar_l; /* 0x0013c */
- uint32_t ehar_h; /* 0x00140 */
- uint32_t ehar_l; /* 0x00144 */
- uint32_t micr; /* 0x00148 */
- uint32_t midr_r; /* 0x0014c */
- uint32_t midr_w; /* 0x00150 */
+ u32 emcr; /* 0x000f0 */
+ u32 eisr; /* 0x000f4 */
+ u32 eier; /* 0x000f8 */
+ u32 ercsr; /* 0x000fc */
+ u32 erbr_h; /* 0x00100 */
+ u32 erbr_l; /* 0x00104 */
+ u32 erbar; /* 0x00108 */
+ u32 ercir; /* 0x0010c */
+ u32 erpir; /* 0x00110 */
+ u32 ertr; /* 0x00114 */
+ u32 etcsr; /* 0x00118 */
+ u32 ersr; /* 0x0011c */
+ u32 etcdc; /* 0x00120 */
+ u32 ebir; /* 0x00124 */
+ u32 etbr_h; /* 0x00128 */
+ u32 etbr_l; /* 0x0012c */
+ u32 etcir; /* 0x00130 */
+ u32 etpir; /* 0x00134 */
+ u32 emar_h; /* 0x00138 */
+ u32 emar_l; /* 0x0013c */
+ u32 ehar_h; /* 0x00140 */
+ u32 ehar_l; /* 0x00144 */
+ u32 micr; /* 0x00148 */
+ u32 midr_r; /* 0x0014c */
+ u32 midr_w; /* 0x00150 */
};
struct ioc3_serioregs {
- uint32_t km_csr; /* 0x0009c */
- uint32_t k_rd; /* 0x000a0 */
- uint32_t m_rd; /* 0x000a4 */
- uint32_t k_wd; /* 0x000a8 */
- uint32_t m_wd; /* 0x000ac */
+ u32 km_csr; /* 0x0009c */
+ u32 k_rd; /* 0x000a0 */
+ u32 m_rd; /* 0x000a4 */
+ u32 k_wd; /* 0x000a8 */
+ u32 m_wd; /* 0x000ac */
};
/* Register layout of IOC3 in configuration space. */
struct ioc3 {
/* PCI Config Space registers */
- uint32_t pci_id; /* 0x00000 */
- uint32_t pci_scr; /* 0x00004 */
- uint32_t pci_rev; /* 0x00008 */
- uint32_t pci_lat; /* 0x0000c */
- uint32_t pci_addr; /* 0x00010 */
- uint32_t pci_err_addr_l; /* 0x00014 */
- uint32_t pci_err_addr_h; /* 0x00018 */
-
- uint32_t sio_ir; /* 0x0001c */
- uint32_t sio_ies; /* 0x00020 */
- uint32_t sio_iec; /* 0x00024 */
- uint32_t sio_cr; /* 0x00028 */
- uint32_t int_out; /* 0x0002c */
- uint32_t mcr; /* 0x00030 */
+ u32 pci_id; /* 0x00000 */
+ u32 pci_scr; /* 0x00004 */
+ u32 pci_rev; /* 0x00008 */
+ u32 pci_lat; /* 0x0000c */
+ u32 pci_addr; /* 0x00010 */
+ u32 pci_err_addr_l; /* 0x00014 */
+ u32 pci_err_addr_h; /* 0x00018 */
+
+ u32 sio_ir; /* 0x0001c */
+ u32 sio_ies; /* 0x00020 */
+ u32 sio_iec; /* 0x00024 */
+ u32 sio_cr; /* 0x00028 */
+ u32 int_out; /* 0x0002c */
+ u32 mcr; /* 0x00030 */
/* General Purpose I/O registers */
- uint32_t gpcr_s; /* 0x00034 */
- uint32_t gpcr_c; /* 0x00038 */
- uint32_t gpdr; /* 0x0003c */
- uint32_t gppr[16]; /* 0x00040 */
+ u32 gpcr_s; /* 0x00034 */
+ u32 gpcr_c; /* 0x00038 */
+ u32 gpdr; /* 0x0003c */
+ u32 gppr[16]; /* 0x00040 */
/* Parallel Port Registers */
- uint32_t ppbr_h_a; /* 0x00080 */
- uint32_t ppbr_l_a; /* 0x00084 */
- uint32_t ppcr_a; /* 0x00088 */
- uint32_t ppcr; /* 0x0008c */
- uint32_t ppbr_h_b; /* 0x00090 */
- uint32_t ppbr_l_b; /* 0x00094 */
- uint32_t ppcr_b; /* 0x00098 */
+ u32 ppbr_h_a; /* 0x00080 */
+ u32 ppbr_l_a; /* 0x00084 */
+ u32 ppcr_a; /* 0x00088 */
+ u32 ppcr; /* 0x0008c */
+ u32 ppbr_h_b; /* 0x00090 */
+ u32 ppbr_l_b; /* 0x00094 */
+ u32 ppcr_b; /* 0x00098 */
/* Keyboard and Mouse Registers */
struct ioc3_serioregs serio;
/* Serial Port Registers */
- uint32_t sbbr_h; /* 0x000b0 */
- uint32_t sbbr_l; /* 0x000b4 */
+ u32 sbbr_h; /* 0x000b0 */
+ u32 sbbr_l; /* 0x000b4 */
struct ioc3_serialregs port_a;
struct ioc3_serialregs port_b;
/* Ethernet Registers */
struct ioc3_ethregs eth;
- uint32_t pad1[(0x20000 - 0x00154) / 4];
+ u32 pad1[(0x20000 - 0x00154) / 4];
/* SuperIO Registers XXX */
struct ioc3_sioregs sregs; /* 0x20000 */
- uint32_t pad2[(0x40000 - 0x20180) / 4];
+ u32 pad2[(0x40000 - 0x20180) / 4];
/* SSRAM Diagnostic Access */
- uint32_t ssram[(0x80000 - 0x40000) / 4];
+ u32 ssram[(0x80000 - 0x40000) / 4];
/* Bytebus device offsets
0x80000 - Access to the generic devices selected with DEV0
@@ -598,10 +598,6 @@ struct ioc3_etxd {
#define MIDR_DATA_MASK 0x0000ffff
-#if defined(CONFIG_SGI_IP27) || defined(CONFIG_SGI_IP30)
-extern int bridge_alloc_irq(struct pci_dev *dev);
-#endif
-
/* subsystem IDs supplied by card detection in pci-xtalk-bridge */
#define IOC3_SUBSYS_IP27_BASEIO6G 0xc300
#define IOC3_SUBSYS_IP27_MIO 0xc301
diff --git a/arch/mips/sgi-ip27/ip27-console.c b/arch/mips/sgi-ip27/ip27-console.c
index 6bdb48d41276..5886bee89d06 100644
--- a/arch/mips/sgi-ip27/ip27-console.c
+++ b/arch/mips/sgi-ip27/ip27-console.c
@@ -35,6 +35,7 @@ void prom_putchar(char c)
{
struct ioc3_uartregs *uart = console_uart();
- while ((uart->iu_lsr & 0x20) == 0);
- uart->iu_thr = c;
+ while ((readb(&uart->iu_lsr) & 0x20) == 0)
+ ;
+ writeb(c, &uart->iu_thr);
}
diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c
index d3a75d447fce..e8194f1f01a8 100644
--- a/drivers/rtc/rtc-m48t35.c
+++ b/drivers/rtc/rtc-m48t35.c
@@ -20,6 +20,16 @@
struct m48t35_rtc {
u8 pad[0x7ff8]; /* starts at 0x7ff8 */
+#ifdef CONFIG_SGI_IP27
+ u8 hour;
+ u8 min;
+ u8 sec;
+ u8 control;
+ u8 year;
+ u8 month;
+ u8 date;
+ u8 day;
+#else
u8 control;
u8 sec;
u8 min;
@@ -28,6 +38,7 @@ struct m48t35_rtc {
u8 date;
u8 month;
u8 year;
+#endif
};
#define M48T35_RTC_SET 0x80
diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c
index 2be6ed2967e0..4c405f1b9c67 100644
--- a/drivers/tty/serial/8250/8250_ioc3.c
+++ b/drivers/tty/serial/8250/8250_ioc3.c
@@ -23,12 +23,12 @@ struct ioc3_8250_data {
static unsigned int ioc3_serial_in(struct uart_port *p, int offset)
{
- return readb(p->membase + offset);
+ return readb(p->membase + (offset ^ 3));
}
static void ioc3_serial_out(struct uart_port *p, int offset, int value)
{
- writeb(value, p->membase + offset);
+ writeb(value, p->membase + (offset ^ 3));
}
static int serial8250_ioc3_probe(struct platform_device *pdev)
--
2.13.7
^ permalink raw reply related
* [PATCH v3 5/7] mfd: ioc3: Add driver for SGI IOC3 chip
From: Thomas Bogendoerfer @ 2019-06-13 17:06 UTC (permalink / raw)
To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
Lee Jones, David S. Miller, Srinivas Kandagatla, Alessandro Zummo,
Alexandre Belloni, Greg Kroah-Hartman, Jiri Slaby, linux-mips,
linux-kernel, linux-input, netdev, linux-rtc, linux-serial
In-Reply-To: <20190613170636.6647-1-tbogendoerfer@suse.de>
SGI IOC3 chip has integrated ethernet, keyboard and mouse interface.
It also supports connecting a SuperIO chip for serial and parallel
interfaces. IOC3 is used inside various SGI systemboards and add-on
cards with different equipped external interfaces.
Support for ethernet and serial interfaces were implemented inside
the network driver. This patchset moves out the not network related
parts to a new MFD driver, which takes care of card detection,
setup of platform devices and interrupt distribution for the subdevices.
Serial portion: Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
arch/mips/include/asm/sn/ioc3.h | 345 +++----
arch/mips/sgi-ip27/ip27-timer.c | 20 -
drivers/mfd/Kconfig | 13 +
drivers/mfd/Makefile | 1 +
drivers/mfd/ioc3.c | 683 +++++++++++++
drivers/net/ethernet/sgi/Kconfig | 4 +-
drivers/net/ethernet/sgi/ioc3-eth.c | 1932 ++++++++++++++---------------------
drivers/tty/serial/8250/8250_ioc3.c | 98 ++
drivers/tty/serial/8250/Kconfig | 11 +
drivers/tty/serial/8250/Makefile | 1 +
10 files changed, 1693 insertions(+), 1415 deletions(-)
create mode 100644 drivers/mfd/ioc3.c
create mode 100644 drivers/tty/serial/8250/8250_ioc3.c
diff --git a/arch/mips/include/asm/sn/ioc3.h b/arch/mips/include/asm/sn/ioc3.h
index 5022b0ab2074..89938fdce8ef 100644
--- a/arch/mips/include/asm/sn/ioc3.h
+++ b/arch/mips/include/asm/sn/ioc3.h
@@ -3,32 +3,43 @@
* Copyright (C) 1999, 2000 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
-#ifndef _IOC3_H
-#define _IOC3_H
+#ifndef MIPS_SN_IOC3_H
+#define MIPS_SN_IOC3_H
#include <linux/types.h>
+/* serial port register map */
+struct ioc3_serialregs {
+ uint32_t sscr;
+ uint32_t stpir;
+ uint32_t stcir;
+ uint32_t srpir;
+ uint32_t srcir;
+ uint32_t srtr;
+ uint32_t shadow;
+};
+
/* SUPERIO uart register map */
-typedef volatile struct ioc3_uartregs {
+struct ioc3_uartregs {
union {
- volatile u8 rbr; /* read only, DLAB == 0 */
- volatile u8 thr; /* write only, DLAB == 0 */
- volatile u8 dll; /* DLAB == 1 */
+ char rbr; /* read only, DLAB == 0 */
+ char thr; /* write only, DLAB == 0 */
+ char dll; /* DLAB == 1 */
} u1;
union {
- volatile u8 ier; /* DLAB == 0 */
- volatile u8 dlm; /* DLAB == 1 */
+ char ier; /* DLAB == 0 */
+ char dlm; /* DLAB == 1 */
} u2;
union {
- volatile u8 iir; /* read only */
- volatile u8 fcr; /* write only */
+ char iir; /* read only */
+ char fcr; /* write only */
} u3;
- volatile u8 iu_lcr;
- volatile u8 iu_mcr;
- volatile u8 iu_lsr;
- volatile u8 iu_msr;
- volatile u8 iu_scr;
-} ioc3_uregs_t;
+ char iu_lcr;
+ char iu_mcr;
+ char iu_lsr;
+ char iu_msr;
+ char iu_scr;
+};
#define iu_rbr u1.rbr
#define iu_thr u1.thr
@@ -39,133 +50,122 @@ typedef volatile struct ioc3_uartregs {
#define iu_fcr u3.fcr
struct ioc3_sioregs {
- volatile u8 fill[0x141]; /* starts at 0x141 */
+ char fill[0x141]; /* starts at 0x141 */
- volatile u8 uartc;
- volatile u8 kbdcg;
+ char uartc;
+ char kbdcg;
- volatile u8 fill0[0x150 - 0x142 - 1];
+ char fill0[0x150 - 0x142 - 1];
- volatile u8 pp_data;
- volatile u8 pp_dsr;
- volatile u8 pp_dcr;
+ char pp_data;
+ char pp_dsr;
+ char pp_dcr;
- volatile u8 fill1[0x158 - 0x152 - 1];
+ char fill1[0x158 - 0x152 - 1];
- volatile u8 pp_fifa;
- volatile u8 pp_cfgb;
- volatile u8 pp_ecr;
+ char pp_fifa;
+ char pp_cfgb;
+ char pp_ecr;
- volatile u8 fill2[0x168 - 0x15a - 1];
+ char fill2[0x168 - 0x15a - 1];
- volatile u8 rtcad;
- volatile u8 rtcdat;
+ char rtcad;
+ char rtcdat;
- volatile u8 fill3[0x170 - 0x169 - 1];
+ char fill3[0x170 - 0x169 - 1];
struct ioc3_uartregs uartb; /* 0x20170 */
struct ioc3_uartregs uarta; /* 0x20178 */
};
+struct ioc3_ethregs {
+ uint32_t emcr; /* 0x000f0 */
+ uint32_t eisr; /* 0x000f4 */
+ uint32_t eier; /* 0x000f8 */
+ uint32_t ercsr; /* 0x000fc */
+ uint32_t erbr_h; /* 0x00100 */
+ uint32_t erbr_l; /* 0x00104 */
+ uint32_t erbar; /* 0x00108 */
+ uint32_t ercir; /* 0x0010c */
+ uint32_t erpir; /* 0x00110 */
+ uint32_t ertr; /* 0x00114 */
+ uint32_t etcsr; /* 0x00118 */
+ uint32_t ersr; /* 0x0011c */
+ uint32_t etcdc; /* 0x00120 */
+ uint32_t ebir; /* 0x00124 */
+ uint32_t etbr_h; /* 0x00128 */
+ uint32_t etbr_l; /* 0x0012c */
+ uint32_t etcir; /* 0x00130 */
+ uint32_t etpir; /* 0x00134 */
+ uint32_t emar_h; /* 0x00138 */
+ uint32_t emar_l; /* 0x0013c */
+ uint32_t ehar_h; /* 0x00140 */
+ uint32_t ehar_l; /* 0x00144 */
+ uint32_t micr; /* 0x00148 */
+ uint32_t midr_r; /* 0x0014c */
+ uint32_t midr_w; /* 0x00150 */
+};
+
+struct ioc3_serioregs {
+ uint32_t km_csr; /* 0x0009c */
+ uint32_t k_rd; /* 0x000a0 */
+ uint32_t m_rd; /* 0x000a4 */
+ uint32_t k_wd; /* 0x000a8 */
+ uint32_t m_wd; /* 0x000ac */
+};
+
/* Register layout of IOC3 in configuration space. */
struct ioc3 {
- volatile u32 pad0[7]; /* 0x00000 */
- volatile u32 sio_ir; /* 0x0001c */
- volatile u32 sio_ies; /* 0x00020 */
- volatile u32 sio_iec; /* 0x00024 */
- volatile u32 sio_cr; /* 0x00028 */
- volatile u32 int_out; /* 0x0002c */
- volatile u32 mcr; /* 0x00030 */
+ /* PCI Config Space registers */
+ uint32_t pci_id; /* 0x00000 */
+ uint32_t pci_scr; /* 0x00004 */
+ uint32_t pci_rev; /* 0x00008 */
+ uint32_t pci_lat; /* 0x0000c */
+ uint32_t pci_addr; /* 0x00010 */
+ uint32_t pci_err_addr_l; /* 0x00014 */
+ uint32_t pci_err_addr_h; /* 0x00018 */
+
+ uint32_t sio_ir; /* 0x0001c */
+ uint32_t sio_ies; /* 0x00020 */
+ uint32_t sio_iec; /* 0x00024 */
+ uint32_t sio_cr; /* 0x00028 */
+ uint32_t int_out; /* 0x0002c */
+ uint32_t mcr; /* 0x00030 */
/* General Purpose I/O registers */
- volatile u32 gpcr_s; /* 0x00034 */
- volatile u32 gpcr_c; /* 0x00038 */
- volatile u32 gpdr; /* 0x0003c */
- volatile u32 gppr_0; /* 0x00040 */
- volatile u32 gppr_1; /* 0x00044 */
- volatile u32 gppr_2; /* 0x00048 */
- volatile u32 gppr_3; /* 0x0004c */
- volatile u32 gppr_4; /* 0x00050 */
- volatile u32 gppr_5; /* 0x00054 */
- volatile u32 gppr_6; /* 0x00058 */
- volatile u32 gppr_7; /* 0x0005c */
- volatile u32 gppr_8; /* 0x00060 */
- volatile u32 gppr_9; /* 0x00064 */
- volatile u32 gppr_10; /* 0x00068 */
- volatile u32 gppr_11; /* 0x0006c */
- volatile u32 gppr_12; /* 0x00070 */
- volatile u32 gppr_13; /* 0x00074 */
- volatile u32 gppr_14; /* 0x00078 */
- volatile u32 gppr_15; /* 0x0007c */
+ uint32_t gpcr_s; /* 0x00034 */
+ uint32_t gpcr_c; /* 0x00038 */
+ uint32_t gpdr; /* 0x0003c */
+ uint32_t gppr[16]; /* 0x00040 */
/* Parallel Port Registers */
- volatile u32 ppbr_h_a; /* 0x00080 */
- volatile u32 ppbr_l_a; /* 0x00084 */
- volatile u32 ppcr_a; /* 0x00088 */
- volatile u32 ppcr; /* 0x0008c */
- volatile u32 ppbr_h_b; /* 0x00090 */
- volatile u32 ppbr_l_b; /* 0x00094 */
- volatile u32 ppcr_b; /* 0x00098 */
+ uint32_t ppbr_h_a; /* 0x00080 */
+ uint32_t ppbr_l_a; /* 0x00084 */
+ uint32_t ppcr_a; /* 0x00088 */
+ uint32_t ppcr; /* 0x0008c */
+ uint32_t ppbr_h_b; /* 0x00090 */
+ uint32_t ppbr_l_b; /* 0x00094 */
+ uint32_t ppcr_b; /* 0x00098 */
/* Keyboard and Mouse Registers */
- volatile u32 km_csr; /* 0x0009c */
- volatile u32 k_rd; /* 0x000a0 */
- volatile u32 m_rd; /* 0x000a4 */
- volatile u32 k_wd; /* 0x000a8 */
- volatile u32 m_wd; /* 0x000ac */
+ struct ioc3_serioregs serio;
/* Serial Port Registers */
- volatile u32 sbbr_h; /* 0x000b0 */
- volatile u32 sbbr_l; /* 0x000b4 */
- volatile u32 sscr_a; /* 0x000b8 */
- volatile u32 stpir_a; /* 0x000bc */
- volatile u32 stcir_a; /* 0x000c0 */
- volatile u32 srpir_a; /* 0x000c4 */
- volatile u32 srcir_a; /* 0x000c8 */
- volatile u32 srtr_a; /* 0x000cc */
- volatile u32 shadow_a; /* 0x000d0 */
- volatile u32 sscr_b; /* 0x000d4 */
- volatile u32 stpir_b; /* 0x000d8 */
- volatile u32 stcir_b; /* 0x000dc */
- volatile u32 srpir_b; /* 0x000e0 */
- volatile u32 srcir_b; /* 0x000e4 */
- volatile u32 srtr_b; /* 0x000e8 */
- volatile u32 shadow_b; /* 0x000ec */
-
- /* Ethernet Registers */
- volatile u32 emcr; /* 0x000f0 */
- volatile u32 eisr; /* 0x000f4 */
- volatile u32 eier; /* 0x000f8 */
- volatile u32 ercsr; /* 0x000fc */
- volatile u32 erbr_h; /* 0x00100 */
- volatile u32 erbr_l; /* 0x00104 */
- volatile u32 erbar; /* 0x00108 */
- volatile u32 ercir; /* 0x0010c */
- volatile u32 erpir; /* 0x00110 */
- volatile u32 ertr; /* 0x00114 */
- volatile u32 etcsr; /* 0x00118 */
- volatile u32 ersr; /* 0x0011c */
- volatile u32 etcdc; /* 0x00120 */
- volatile u32 ebir; /* 0x00124 */
- volatile u32 etbr_h; /* 0x00128 */
- volatile u32 etbr_l; /* 0x0012c */
- volatile u32 etcir; /* 0x00130 */
- volatile u32 etpir; /* 0x00134 */
- volatile u32 emar_h; /* 0x00138 */
- volatile u32 emar_l; /* 0x0013c */
- volatile u32 ehar_h; /* 0x00140 */
- volatile u32 ehar_l; /* 0x00144 */
- volatile u32 micr; /* 0x00148 */
- volatile u32 midr_r; /* 0x0014c */
- volatile u32 midr_w; /* 0x00150 */
- volatile u32 pad1[(0x20000 - 0x00154) / 4];
+ uint32_t sbbr_h; /* 0x000b0 */
+ uint32_t sbbr_l; /* 0x000b4 */
+ struct ioc3_serialregs port_a;
+ struct ioc3_serialregs port_b;
+
+ /* Ethernet Registers */
+ struct ioc3_ethregs eth;
+ uint32_t pad1[(0x20000 - 0x00154) / 4];
/* SuperIO Registers XXX */
struct ioc3_sioregs sregs; /* 0x20000 */
- volatile u32 pad2[(0x40000 - 0x20180) / 4];
+ uint32_t pad2[(0x40000 - 0x20180) / 4];
/* SSRAM Diagnostic Access */
- volatile u32 ssram[(0x80000 - 0x40000) / 4];
+ uint32_t ssram[(0x80000 - 0x40000) / 4];
/* Bytebus device offsets
0x80000 - Access to the generic devices selected with DEV0
@@ -178,6 +178,20 @@ struct ioc3 {
0xFFFFF bytebus DEV_SEL_3 */
};
+
+#define PCI_LAT 0xc /* Latency Timer */
+#define PCI_SCR_DROP_MODE_EN 0x00008000 /* drop pios on parity err */
+#define UARTA_BASE 0x178
+#define UARTB_BASE 0x170
+
+/*
+ * Bytebus device space
+ */
+#define IOC3_BYTEBUS_DEV0 0x80000L
+#define IOC3_BYTEBUS_DEV1 0xa0000L
+#define IOC3_BYTEBUS_DEV2 0xc0000L
+#define IOC3_BYTEBUS_DEV3 0xe0000L
+
/*
* Ethernet RX Buffer
*/
@@ -233,28 +247,20 @@ struct ioc3_etxd {
#define ETXD_B2CNT_MASK 0x7ff00000
#define ETXD_B2CNT_SHIFT 20
-/*
- * Bytebus device space
- */
-#define IOC3_BYTEBUS_DEV0 0x80000L
-#define IOC3_BYTEBUS_DEV1 0xa0000L
-#define IOC3_BYTEBUS_DEV2 0xc0000L
-#define IOC3_BYTEBUS_DEV3 0xe0000L
-
/* ------------------------------------------------------------------------- */
/* Superio Registers (PIO Access) */
#define IOC3_SIO_BASE 0x20000
#define IOC3_SIO_UARTC (IOC3_SIO_BASE+0x141) /* UART Config */
#define IOC3_SIO_KBDCG (IOC3_SIO_BASE+0x142) /* KBD Config */
-#define IOC3_SIO_PP_BASE (IOC3_SIO_BASE+PP_BASE) /* Parallel Port */
+#define IOC3_SIO_PP_BASE (IOC3_SIO_BASE+PP_BASE) /* Parallel Port */
#define IOC3_SIO_RTC_BASE (IOC3_SIO_BASE+0x168) /* Real Time Clock */
#define IOC3_SIO_UB_BASE (IOC3_SIO_BASE+UARTB_BASE) /* UART B */
#define IOC3_SIO_UA_BASE (IOC3_SIO_BASE+UARTA_BASE) /* UART A */
/* SSRAM Diagnostic Access */
#define IOC3_SSRAM IOC3_RAM_OFF /* base of SSRAM diagnostic access */
-#define IOC3_SSRAM_LEN 0x40000 /* 256kb (address space size, may not be fully populated) */
+#define IOC3_SSRAM_LEN 0x40000 /* 256kb (addrspc sz, may not be populated) */
#define IOC3_SSRAM_DM 0x0000ffff /* data mask */
#define IOC3_SSRAM_PM 0x00010000 /* parity mask */
@@ -294,10 +300,10 @@ struct ioc3_etxd {
SIO_IR to assert */
#define KM_CSR_M_TO_EN 0x00080000 /* KM_CSR_M_TO + KM_CSR_M_TO_EN = cause
SIO_IR to assert */
-#define KM_CSR_K_CLAMP_ONE 0x00100000 /* Pull K_CLK low after rec. one char */
-#define KM_CSR_M_CLAMP_ONE 0x00200000 /* Pull M_CLK low after rec. one char */
-#define KM_CSR_K_CLAMP_THREE 0x00400000 /* Pull K_CLK low after rec. three chars */
-#define KM_CSR_M_CLAMP_THREE 0x00800000 /* Pull M_CLK low after rec. three char */
+#define KM_CSR_K_CLAMP_1 0x00100000 /* Pull K_CLK low aft recv 1 char */
+#define KM_CSR_M_CLAMP_1 0x00200000 /* Pull M_CLK low aft recv 1 char */
+#define KM_CSR_K_CLAMP_3 0x00400000 /* Pull K_CLK low aft recv 3 chars */
+#define KM_CSR_M_CLAMP_3 0x00800000 /* Pull M_CLK low aft recv 3 chars */
/* bitmasks for IOC3_K_RD and IOC3_M_RD */
#define KM_RD_DATA_2 0x000000ff /* 3rd char recvd since last read */
@@ -440,10 +446,6 @@ struct ioc3_etxd {
SIO_IR_PP_INTB | SIO_IR_PP_MEMERR)
#define SIO_IR_RT (SIO_IR_RT_INT | SIO_IR_GEN_INT1)
-/* macro to load pending interrupts */
-#define IOC3_PENDING_INTRS(mem) (PCI_INW(&((mem)->sio_ir)) & \
- PCI_INW(&((mem)->sio_ies_ro)))
-
/* bitmasks for SIO_CR */
#define SIO_CR_SIO_RESET 0x00000001 /* reset the SIO */
#define SIO_CR_SER_A_BASE 0x000000fe /* DMA poll addr port A */
@@ -500,10 +502,11 @@ struct ioc3_etxd {
#define GPCR_UARTB_MODESEL 0x40 /* pin is output to port B mode sel */
#define GPCR_UARTA_MODESEL 0x80 /* pin is output to port A mode sel */
-#define GPPR_PHY_RESET_PIN 5 /* GIO pin controlling phy reset */
-#define GPPR_UARTB_MODESEL_PIN 6 /* GIO pin controlling uart b mode select */
-#define GPPR_UARTA_MODESEL_PIN 7 /* GIO pin controlling uart a mode select */
+#define GPPR_PHY_RESET_PIN 5 /* GIO pin cntrlling phy reset */
+#define GPPR_UARTB_MODESEL_PIN 6 /* GIO pin cntrlling uart b mode sel */
+#define GPPR_UARTA_MODESEL_PIN 7 /* GIO pin cntrlling uart a mode sel */
+/* ethernet */
#define EMCR_DUPLEX 0x00000001
#define EMCR_PROMISC 0x00000002
#define EMCR_PADEN 0x00000004
@@ -595,71 +598,9 @@ struct ioc3_etxd {
#define MIDR_DATA_MASK 0x0000ffff
-#define ERXBUF_IPCKSUM_MASK 0x0000ffff
-#define ERXBUF_BYTECNT_MASK 0x07ff0000
-#define ERXBUF_BYTECNT_SHIFT 16
-#define ERXBUF_V 0x80000000
-
-#define ERXBUF_CRCERR 0x00000001 /* aka RSV15 */
-#define ERXBUF_FRAMERR 0x00000002 /* aka RSV14 */
-#define ERXBUF_CODERR 0x00000004 /* aka RSV13 */
-#define ERXBUF_INVPREAMB 0x00000008 /* aka RSV18 */
-#define ERXBUF_LOLEN 0x00007000 /* aka RSV2_0 */
-#define ERXBUF_HILEN 0x03ff0000 /* aka RSV12_3 */
-#define ERXBUF_MULTICAST 0x04000000 /* aka RSV16 */
-#define ERXBUF_BROADCAST 0x08000000 /* aka RSV17 */
-#define ERXBUF_LONGEVENT 0x10000000 /* aka RSV19 */
-#define ERXBUF_BADPKT 0x20000000 /* aka RSV20 */
-#define ERXBUF_GOODPKT 0x40000000 /* aka RSV21 */
-#define ERXBUF_CARRIER 0x80000000 /* aka RSV22 */
-
-#define ETXD_BYTECNT_MASK 0x000007ff /* total byte count */
-#define ETXD_INTWHENDONE 0x00001000 /* intr when done */
-#define ETXD_D0V 0x00010000 /* data 0 valid */
-#define ETXD_B1V 0x00020000 /* buf 1 valid */
-#define ETXD_B2V 0x00040000 /* buf 2 valid */
-#define ETXD_DOCHECKSUM 0x00080000 /* insert ip cksum */
-#define ETXD_CHKOFF_MASK 0x07f00000 /* cksum byte offset */
-#define ETXD_CHKOFF_SHIFT 20
-
-#define ETXD_D0CNT_MASK 0x0000007f
-#define ETXD_B1CNT_MASK 0x0007ff00
-#define ETXD_B1CNT_SHIFT 8
-#define ETXD_B2CNT_MASK 0x7ff00000
-#define ETXD_B2CNT_SHIFT 20
-
-typedef enum ioc3_subdevs_e {
- ioc3_subdev_ether,
- ioc3_subdev_generic,
- ioc3_subdev_nic,
- ioc3_subdev_kbms,
- ioc3_subdev_ttya,
- ioc3_subdev_ttyb,
- ioc3_subdev_ecpp,
- ioc3_subdev_rt,
- ioc3_nsubdevs
-} ioc3_subdev_t;
-
-/* subdevice disable bits,
- * from the standard INFO_LBL_SUBDEVS
- */
-#define IOC3_SDB_ETHER (1<<ioc3_subdev_ether)
-#define IOC3_SDB_GENERIC (1<<ioc3_subdev_generic)
-#define IOC3_SDB_NIC (1<<ioc3_subdev_nic)
-#define IOC3_SDB_KBMS (1<<ioc3_subdev_kbms)
-#define IOC3_SDB_TTYA (1<<ioc3_subdev_ttya)
-#define IOC3_SDB_TTYB (1<<ioc3_subdev_ttyb)
-#define IOC3_SDB_ECPP (1<<ioc3_subdev_ecpp)
-#define IOC3_SDB_RT (1<<ioc3_subdev_rt)
-
-#define IOC3_ALL_SUBDEVS ((1<<ioc3_nsubdevs)-1)
-
-#define IOC3_SDB_SERIAL (IOC3_SDB_TTYA|IOC3_SDB_TTYB)
-
-#define IOC3_STD_SUBDEVS IOC3_ALL_SUBDEVS
-
-#define IOC3_INTA_SUBDEVS IOC3_SDB_ETHER
-#define IOC3_INTB_SUBDEVS (IOC3_SDB_GENERIC|IOC3_SDB_KBMS|IOC3_SDB_SERIAL|IOC3_SDB_ECPP|IOC3_SDB_RT)
+#if defined(CONFIG_SGI_IP27) || defined(CONFIG_SGI_IP30)
+extern int bridge_alloc_irq(struct pci_dev *dev);
+#endif
/* subsystem IDs supplied by card detection in pci-xtalk-bridge */
#define IOC3_SUBSYS_IP27_BASEIO6G 0xc300
@@ -670,4 +611,4 @@ typedef enum ioc3_subdevs_e {
#define IOC3_SUBSYS_MENET 0xc305
#define IOC3_SUBSYS_MENET4 0xc306
-#endif /* _IOC3_H */
+#endif /* MIPS_SN_IOC3_H */
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index 9b4b9ac621a3..5631e93ea350 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -188,23 +188,3 @@ void hub_rtc_init(cnodeid_t cnode)
LOCAL_HUB_S(PI_RT_PEND_B, 0);
}
}
-
-static int __init sgi_ip27_rtc_devinit(void)
-{
- struct resource res;
-
- memset(&res, 0, sizeof(res));
- res.start = XPHYSADDR(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base +
- IOC3_BYTEBUS_DEV0);
- res.end = res.start + 32767;
- res.flags = IORESOURCE_MEM;
-
- return IS_ERR(platform_device_register_simple("rtc-m48t35", -1,
- &res, 1));
-}
-
-/*
- * kludge make this a device_initcall after ioc3 resource conflicts
- * are resolved
- */
-late_initcall(sgi_ip27_rtc_devinit);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index a17d275bf1d4..5c9f1bd9bd0a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1989,5 +1989,18 @@ config RAVE_SP_CORE
Select this to get support for the Supervisory Processor
device found on several devices in RAVE line of hardware.
+config SGI_MFD_IOC3
+ tristate "SGI IOC3 core driver"
+ depends on PCI && MIPS
+ select MFD_CORE
+ help
+ This option enables basic support for the SGI IOC3-based
+ controller cards. This option does not enable any specific
+ functions on such a card, but provides necessary infrastructure
+ for other drivers to utilize.
+
+ If you have an SGI Origin, Octane, or a PCI IOC3 card,
+ then say Y. Otherwise say N.
+
endmenu
endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 52b1a90ff515..bba0d9eb0b18 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -249,3 +249,4 @@ obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o
obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
obj-$(CONFIG_MFD_STMFX) += stmfx.o
+obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
diff --git a/drivers/mfd/ioc3.c b/drivers/mfd/ioc3.c
new file mode 100644
index 000000000000..0c0d1b3475d0
--- /dev/null
+++ b/drivers/mfd/ioc3.c
@@ -0,0 +1,683 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SGI IOC3 multifunction device driver
+ *
+ * Copyright (C) 2018, 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de>
+ *
+ * Based on work by:
+ * Stanislaw Skowronek <skylark@unaligned.org>
+ * Joshua Kinard <kumba@gentoo.org>
+ * Brent Casavant <bcasavan@sgi.com> - IOC4 master driver
+ * Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/sgi-w1.h>
+#include <linux/rtc/ds1685.h>
+
+#include <asm/pci/bridge.h>
+#include <asm/sn/ioc3.h>
+
+#define IOC3_IRQ_SERIAL_A 6
+#define IOC3_IRQ_SERIAL_B 15
+#define IOC3_IRQ_KBD 22
+#define IOC3_IRQ_ETH_DOMAIN 23
+
+static int ioc3_serial_id;
+static int ioc3_eth_id;
+static int ioc3_kbd_id;
+
+struct ioc3_priv_data {
+ struct irq_domain *domain;
+ struct ioc3 __iomem *regs;
+ struct pci_dev *pdev;
+ int domain_irq;
+};
+
+static void ioc3_irq_ack(struct irq_data *d)
+{
+ struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
+ unsigned int hwirq = irqd_to_hwirq(d);
+
+ writel(BIT(hwirq), &ipd->regs->sio_ir);
+}
+
+static void ioc3_irq_mask(struct irq_data *d)
+{
+ struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
+ unsigned int hwirq = irqd_to_hwirq(d);
+
+ writel(BIT(hwirq), &ipd->regs->sio_iec);
+}
+
+static void ioc3_irq_unmask(struct irq_data *d)
+{
+ struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
+ unsigned int hwirq = irqd_to_hwirq(d);
+
+ writel(BIT(hwirq), &ipd->regs->sio_ies);
+}
+
+static struct irq_chip ioc3_irq_chip = {
+ .name = "IOC3",
+ .irq_ack = ioc3_irq_ack,
+ .irq_mask = ioc3_irq_mask,
+ .irq_unmask = ioc3_irq_unmask,
+};
+
+#define IOC3_LVL_MASK (BIT(IOC3_IRQ_SERIAL_A) | BIT(IOC3_IRQ_SERIAL_B))
+
+static int ioc3_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ /* use level irqs for every interrupt contained in IOC3_LVL_MASK */
+ if (BIT(hwirq) & IOC3_LVL_MASK)
+ irq_set_chip_and_handler(irq, &ioc3_irq_chip, handle_level_irq);
+ else
+ irq_set_chip_and_handler(irq, &ioc3_irq_chip, handle_edge_irq);
+
+ irq_set_chip_data(irq, d->host_data);
+ return 0;
+}
+
+static const struct irq_domain_ops ioc3_irq_domain_ops = {
+ .map = ioc3_irq_domain_map,
+};
+
+static void ioc3_irq_handler(struct irq_desc *desc)
+{
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+ struct ioc3_priv_data *ipd = domain->host_data;
+ struct ioc3 __iomem *regs = ipd->regs;
+ u32 pending, mask;
+ unsigned int irq;
+
+ pending = readl(®s->sio_ir);
+ mask = readl(®s->sio_ies);
+ pending &= mask; /* mask off not enabled but pending irqs */
+
+ if (mask & BIT(IOC3_IRQ_ETH_DOMAIN))
+ /* if eth irq is enabled we need to check in eth irq regs */
+ if (readl(®s->eth.eisr) & readl(®s->eth.eier))
+ pending |= IOC3_IRQ_ETH_DOMAIN;
+
+ if (pending) {
+ irq = irq_find_mapping(domain, __ffs(pending));
+ if (irq)
+ generic_handle_irq(irq);
+ } else {
+ spurious_interrupt();
+ }
+}
+
+/*
+ * System boards/BaseIOs use more interrupt pins of the bridge asic
+ * to which the IOC3 is connected. Since the IOC3 MFD driver
+ * knows wiring of these extra pins, we use the map_irq function
+ * to get interrupts activated
+ */
+static int ioc3_map_irq(struct pci_dev *pdev, int pin)
+{
+ struct pci_host_bridge *hbrg = pci_find_host_bridge(pdev->bus);
+
+ return hbrg->map_irq(pdev, pin, 0);
+}
+
+static int ioc3_irq_domain_setup(struct ioc3_priv_data *ipd, int irq)
+{
+ struct irq_domain *domain;
+ struct fwnode_handle *fn;
+
+ fn = irq_domain_alloc_named_fwnode("IOC3");
+ if (!fn)
+ goto err;
+
+ domain = irq_domain_create_linear(fn, 24, &ioc3_irq_domain_ops, ipd);
+ if (!domain)
+ goto err;
+
+ irq_domain_free_fwnode(fn);
+ ipd->domain = domain;
+
+ irq_set_chained_handler_and_data(irq, ioc3_irq_handler, domain);
+ ipd->domain_irq = irq;
+ return 0;
+err:
+ dev_err(&ipd->pdev->dev, "irq domain setup failed\n");
+ return -ENOMEM;
+}
+
+static struct resource ioc3_uarta_resources[] = {
+ DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uarta),
+ sizeof_field(struct ioc3, sregs.uarta)),
+ DEFINE_RES_IRQ(IOC3_IRQ_SERIAL_A)
+};
+
+static struct resource ioc3_uartb_resources[] = {
+ DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uartb),
+ sizeof_field(struct ioc3, sregs.uartb)),
+ DEFINE_RES_IRQ(IOC3_IRQ_SERIAL_B)
+};
+
+static struct mfd_cell ioc3_serial_cells[] = {
+ {
+ .name = "ioc3-serial8250",
+ .resources = ioc3_uarta_resources,
+ .num_resources = ARRAY_SIZE(ioc3_uarta_resources),
+ .id = 0,
+ },
+ {
+ .name = "ioc3-serial8250",
+ .resources = ioc3_uartb_resources,
+ .num_resources = ARRAY_SIZE(ioc3_uartb_resources),
+ .id = 1,
+ }
+};
+
+static int ioc3_serial_setup(struct ioc3_priv_data *ipd)
+{
+ int ret;
+
+ /* set gpio pins for RS232/RS422 mode selection */
+ writel(GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL,
+ &ipd->regs->gpcr_s);
+ /* select RS232 mode for uart a */
+ writel(0, &ipd->regs->gppr[6]);
+ /* select RS232 mode for uart b */
+ writel(0, &ipd->regs->gppr[7]);
+
+ /* switch both ports to 16650 mode */
+ writel(readl(&ipd->regs->port_a.sscr) & ~SSCR_DMA_EN,
+ &ipd->regs->port_a.sscr);
+ writel(readl(&ipd->regs->port_b.sscr) & ~SSCR_DMA_EN,
+ &ipd->regs->port_b.sscr);
+ udelay(1000); /* wait until mode switch is done */
+
+ ret = mfd_add_devices(&ipd->pdev->dev, ioc3_serial_id,
+ ioc3_serial_cells, ARRAY_SIZE(ioc3_serial_cells),
+ &ipd->pdev->resource[0], 0, ipd->domain);
+ if (ret) {
+ dev_err(&ipd->pdev->dev, "Failed to add 16550 subdevs\n");
+ return ret;
+ }
+ ioc3_serial_id += 2;
+ return 0;
+}
+
+static struct resource ioc3_kbd_resources[] = {
+ DEFINE_RES_MEM(offsetof(struct ioc3, serio),
+ sizeof_field(struct ioc3, serio)),
+ DEFINE_RES_IRQ(IOC3_IRQ_KBD)
+};
+
+static struct mfd_cell ioc3_kbd_cells[] = {
+ {
+ .name = "ioc3-kbd",
+ .resources = ioc3_kbd_resources,
+ .num_resources = ARRAY_SIZE(ioc3_kbd_resources),
+ }
+};
+
+static int ioc3_kbd_setup(struct ioc3_priv_data *ipd)
+{
+ int ret;
+
+ ret = mfd_add_devices(&ipd->pdev->dev, ioc3_kbd_id, ioc3_kbd_cells,
+ ARRAY_SIZE(ioc3_kbd_cells),
+ &ipd->pdev->resource[0], 0, ipd->domain);
+ if (ret) {
+ dev_err(&ipd->pdev->dev, "Failed to add 16550 subdevs\n");
+ return ret;
+ }
+ ioc3_kbd_id++;
+ return 0;
+}
+
+static struct resource ioc3_eth_resources[] = {
+ DEFINE_RES_MEM(offsetof(struct ioc3, eth),
+ sizeof_field(struct ioc3, eth)),
+ DEFINE_RES_MEM(offsetof(struct ioc3, ssram),
+ sizeof_field(struct ioc3, ssram)),
+ DEFINE_RES_IRQ(0)
+};
+
+static struct resource ioc3_w1_resources[] = {
+ DEFINE_RES_MEM(offsetof(struct ioc3, mcr),
+ sizeof_field(struct ioc3, mcr)),
+};
+static struct sgi_w1_platform_data ioc3_w1_platform_data;
+
+static struct mfd_cell ioc3_eth_cells[] = {
+ {
+ .name = "ioc3-eth",
+ .resources = ioc3_eth_resources,
+ .num_resources = ARRAY_SIZE(ioc3_eth_resources),
+ },
+ {
+ .name = "sgi_w1",
+ .resources = ioc3_w1_resources,
+ .num_resources = ARRAY_SIZE(ioc3_w1_resources),
+ .platform_data = &ioc3_w1_platform_data,
+ .pdata_size = sizeof(ioc3_w1_platform_data),
+ }
+};
+
+static int ioc3_eth_setup(struct ioc3_priv_data *ipd, bool use_domain)
+{
+ int irq = ipd->pdev->irq;
+ int ret;
+
+ /* enable One-Wire bus */
+ writel(GPCR_MLAN_EN, &ipd->regs->gpcr_s);
+
+ /* generate unique identifier */
+ snprintf(ioc3_w1_platform_data.dev_id,
+ sizeof(ioc3_w1_platform_data.dev_id), "ioc3-%012llx",
+ ipd->pdev->resource->start);
+
+ if (use_domain)
+ irq = irq_create_mapping(ipd->domain, IOC3_IRQ_ETH_DOMAIN);
+
+ ret = mfd_add_devices(&ipd->pdev->dev, ioc3_eth_id, ioc3_eth_cells,
+ ARRAY_SIZE(ioc3_eth_cells),
+ &ipd->pdev->resource[0], irq, NULL);
+ if (ret) {
+ dev_err(&ipd->pdev->dev, "Failed to add ETH/W1 subdev\n");
+ return ret;
+ }
+
+ ioc3_eth_id++;
+ return 0;
+}
+
+#define M48T35_REG_SIZE 32768 /* size of m48t35 registers */
+
+static struct resource ioc3_m48t35_resources[] = {
+ DEFINE_RES_MEM(IOC3_BYTEBUS_DEV0, M48T35_REG_SIZE)
+};
+
+static struct mfd_cell ioc3_m48t35_cells[] = {
+ {
+ .name = "rtc-m48t35",
+ .resources = ioc3_m48t35_resources,
+ .num_resources = ARRAY_SIZE(ioc3_m48t35_resources),
+ }
+};
+
+static int ioc3_m48t35_setup(struct ioc3_priv_data *ipd)
+{
+ int ret;
+
+ ret = mfd_add_devices(&ipd->pdev->dev, PLATFORM_DEVID_AUTO,
+ ioc3_m48t35_cells, ARRAY_SIZE(ioc3_m48t35_cells),
+ &ipd->pdev->resource[0], 0, ipd->domain);
+ if (ret)
+ dev_err(&ipd->pdev->dev, "Failed to add M48T35 subdev\n");
+
+ return ret;
+}
+
+/*
+ * On IP30 the RTC (a DS1687) is behind the IOC3 on the generic
+ * ByteBus regions. We have to write the RTC address of interest to
+ * IOC3_BYTEBUS_DEV1, then read the data from IOC3_BYTEBUS_DEV2.
+ * rtc->regs already points to IOC3_BYTEBUS_DEV1.
+ */
+#define IP30_RTC_ADDR(rtc) (rtc->regs)
+#define IP30_RTC_DATA(rtc) ((rtc->regs) + IOC3_BYTEBUS_DEV2 - IOC3_BYTEBUS_DEV1)
+
+static u8 ip30_rtc_read(struct ds1685_priv *rtc, int reg)
+{
+ writeb((reg & 0x7f), IP30_RTC_ADDR(rtc));
+ return readb(IP30_RTC_DATA(rtc));
+}
+
+static void ip30_rtc_write(struct ds1685_priv *rtc, int reg, u8 value)
+{
+ writeb((reg & 0x7f), IP30_RTC_ADDR(rtc));
+ writeb(value, IP30_RTC_DATA(rtc));
+}
+
+static struct ds1685_rtc_platform_data ip30_rtc_platform_data = {
+ .bcd_mode = false,
+ .no_irq = false,
+ .uie_unsupported = true,
+ .alloc_io_resources = true,
+ .plat_read = ip30_rtc_read,
+ .plat_write = ip30_rtc_write,
+};
+
+static struct resource ioc3_rtc_ds1685_resources[] = {
+ DEFINE_RES_MEM(IOC3_BYTEBUS_DEV1,
+ IOC3_BYTEBUS_DEV2 - IOC3_BYTEBUS_DEV1 + 1),
+ DEFINE_RES_IRQ(0)
+};
+
+static struct mfd_cell ioc3_ds1685_cells[] = {
+ {
+ .name = "rtc-ds1685",
+ .resources = ioc3_rtc_ds1685_resources,
+ .num_resources = ARRAY_SIZE(ioc3_rtc_ds1685_resources),
+ .platform_data = &ip30_rtc_platform_data,
+ .pdata_size = sizeof(ip30_rtc_platform_data),
+ .id = -1,
+ }
+};
+
+static int ioc3_ds1685_setup(struct ioc3_priv_data *ipd)
+{
+ int ret, irq;
+
+ irq = ioc3_map_irq(ipd->pdev, 6);
+ ret = mfd_add_devices(&ipd->pdev->dev, 0, ioc3_ds1685_cells,
+ ARRAY_SIZE(ioc3_ds1685_cells),
+ &ipd->pdev->resource[0], irq, NULL);
+ if (ret)
+ dev_err(&ipd->pdev->dev, "Failed to add DS1685 subdev\n");
+
+ return ret;
+};
+
+
+static struct resource ioc3_leds_resources[] = {
+ DEFINE_RES_MEM(offsetof(struct ioc3, gppr[0]),
+ sizeof_field(struct ioc3, gppr[0])),
+ DEFINE_RES_MEM(offsetof(struct ioc3, gppr[1]),
+ sizeof_field(struct ioc3, gppr[1])),
+};
+
+static struct mfd_cell ioc3_led_cells[] = {
+ {
+ .name = "ip30-leds",
+ .resources = ioc3_leds_resources,
+ .num_resources = ARRAY_SIZE(ioc3_leds_resources),
+ .id = -1,
+ }
+};
+
+static int ioc3_led_setup(struct ioc3_priv_data *ipd)
+{
+ int ret;
+
+ ret = mfd_add_devices(&ipd->pdev->dev, 0, ioc3_led_cells,
+ ARRAY_SIZE(ioc3_led_cells),
+ &ipd->pdev->resource[0], 0, ipd->domain);
+ if (ret)
+ dev_err(&ipd->pdev->dev, "Failed to add LED subdev\n");
+ return ret;
+}
+
+static int ip27_baseio_setup(struct ioc3_priv_data *ipd)
+{
+ int ret, io_irq;
+
+ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 2);
+ ret = ioc3_irq_domain_setup(ipd, io_irq);
+ if (ret)
+ return ret;
+ ret = ioc3_eth_setup(ipd, false);
+ if (ret)
+ return ret;
+ ret = ioc3_serial_setup(ipd);
+ if (ret)
+ return ret;
+ return ioc3_m48t35_setup(ipd);
+}
+
+static int ip27_baseio6g_setup(struct ioc3_priv_data *ipd)
+{
+ int ret, io_irq;
+
+ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 2);
+ ret = ioc3_irq_domain_setup(ipd, io_irq);
+ if (ret)
+ return ret;
+ ret = ioc3_eth_setup(ipd, false);
+ if (ret)
+ return ret;
+ ret = ioc3_serial_setup(ipd);
+ if (ret)
+ return ret;
+ ret = ioc3_m48t35_setup(ipd);
+ if (ret)
+ return ret;
+ return ioc3_kbd_setup(ipd);
+}
+
+static int ip27_mio_setup(struct ioc3_priv_data *ipd)
+{
+ int ret;
+
+ ret = ioc3_irq_domain_setup(ipd, ipd->pdev->irq);
+ if (ret)
+ return ret;
+ ret = ioc3_serial_setup(ipd);
+ if (ret)
+ return ret;
+ return ioc3_kbd_setup(ipd);
+}
+
+static int ip29_sysboard_setup(struct ioc3_priv_data *ipd)
+{
+ int ret, io_irq;
+
+ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 1);
+ ret = ioc3_irq_domain_setup(ipd, io_irq);
+ if (ret)
+ return ret;
+ ret = ioc3_eth_setup(ipd, false);
+ if (ret)
+ return ret;
+ ret = ioc3_serial_setup(ipd);
+ if (ret)
+ return ret;
+ ret = ioc3_m48t35_setup(ipd);
+ if (ret)
+ return ret;
+ return ioc3_kbd_setup(ipd);
+}
+
+static int ip30_sysboard_setup(struct ioc3_priv_data *ipd)
+{
+ int ret, io_irq;
+
+ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 2);
+ ret = ioc3_irq_domain_setup(ipd, io_irq);
+ if (ret)
+ return ret;
+ ret = ioc3_eth_setup(ipd, false);
+ if (ret)
+ return ret;
+ ret = ioc3_serial_setup(ipd);
+ if (ret)
+ return ret;
+ ret = ioc3_kbd_setup(ipd);
+ if (ret)
+ return ret;
+ ret = ioc3_ds1685_setup(ipd);
+ if (ret)
+ return ret;
+ return ioc3_led_setup(ipd);
+}
+
+static int ioc3_menet_setup(struct ioc3_priv_data *ipd)
+{
+ int ret, io_irq;
+
+ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 4);
+ ret = ioc3_irq_domain_setup(ipd, io_irq);
+ if (ret)
+ return ret;
+ ret = ioc3_eth_setup(ipd, false);
+ if (ret)
+ return ret;
+ return ioc3_serial_setup(ipd);
+}
+
+static int ioc3_menet4_setup(struct ioc3_priv_data *ipd)
+{
+ return ioc3_eth_setup(ipd, false);
+}
+
+static int ioc3_cad_duo_setup(struct ioc3_priv_data *ipd)
+{
+ int ret;
+
+ ret = ioc3_irq_domain_setup(ipd, ipd->pdev->irq);
+ if (ret)
+ return ret;
+ ret = ioc3_eth_setup(ipd, true);
+ if (ret)
+ return ret;
+ return ioc3_kbd_setup(ipd);
+}
+
+#define IOC3_SID(_name, _sid, _setup) \
+ { \
+ .name = _name, \
+ .sid = (PCI_VENDOR_ID_SGI << 16) | IOC3_SUBSYS_ ## _sid, \
+ .setup = _setup, \
+ }
+
+static struct {
+ const char *name;
+ u32 sid;
+ int (*setup)(struct ioc3_priv_data *ipd);
+} ioc3_infos[] = {
+ IOC3_SID("IP27 BaseIO6G", IP27_BASEIO6G, &ip27_baseio6g_setup),
+ IOC3_SID("IP27 MIO", IP27_MIO, &ip27_mio_setup),
+ IOC3_SID("IP27 BaseIO", IP27_BASEIO, &ip27_baseio_setup),
+ IOC3_SID("IP29 System Board", IP29_SYSBOARD, &ip29_sysboard_setup),
+ IOC3_SID("IP30 System Board", IP30_SYSBOARD, &ip30_sysboard_setup),
+ IOC3_SID("MENET", MENET, &ioc3_menet_setup),
+ IOC3_SID("MENET4", MENET4, &ioc3_menet4_setup)
+};
+
+static int ioc3_setup(struct ioc3_priv_data *ipd)
+{
+ u32 sid;
+ int i;
+
+ /* Clear IRQs */
+ writel(~0, &ipd->regs->sio_iec);
+ writel(~0, &ipd->regs->sio_ir);
+ writel(0, &ipd->regs->eth.eier);
+ writel(~0, &ipd->regs->eth.eisr);
+
+ /* read subsystem vendor id and subsystem id */
+ pci_read_config_dword(ipd->pdev, PCI_SUBSYSTEM_VENDOR_ID, &sid);
+
+ for (i = 0; i < ARRAY_SIZE(ioc3_infos); i++)
+ if (sid == ioc3_infos[i].sid) {
+ pr_info("ioc3: %s\n", ioc3_infos[i].name);
+ return ioc3_infos[i].setup(ipd);
+ }
+
+ /* treat everything not identified by PCI subid as CAD DUO */
+ pr_info("ioc3: CAD DUO\n");
+ return ioc3_cad_duo_setup(ipd);
+}
+
+static int ioc3_mfd_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_id)
+{
+ struct ioc3_priv_data *ipd;
+ struct ioc3 __iomem *regs;
+ int ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+ pci_set_master(pdev);
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (ret) {
+ dev_warn(&pdev->dev, "Warning: couldn_t set 64-bit DMA mask\n");
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pdev->dev, "Can't set DMA mask, aborting\n");
+ return ret;
+ }
+ }
+
+ /* Set up per-IOC3 data */
+ ipd = devm_kzalloc(&pdev->dev, sizeof(struct ioc3_priv_data),
+ GFP_KERNEL);
+ if (!ipd) {
+ ret = -ENOMEM;
+ goto out_disable_device;
+ }
+ ipd->pdev = pdev;
+
+ /*
+ * Map all IOC3 registers. These are shared between subdevices
+ * so the main IOC3 module manages them.
+ */
+ regs = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (!regs) {
+ pr_warn("ioc3: Unable to remap PCI BAR for %s.\n",
+ pci_name(pdev));
+ ret = -ENOMEM;
+ goto out_disable_device;
+ }
+ ipd->regs = regs;
+
+ /* Track PCI-device specific data */
+ pci_set_drvdata(pdev, ipd);
+
+ ret = ioc3_setup(ipd);
+ if (ret)
+ goto out_disable_device;
+
+ return 0;
+
+out_disable_device:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void ioc3_mfd_remove(struct pci_dev *pdev)
+{
+ struct ioc3_priv_data *ipd;
+
+ ipd = pci_get_drvdata(pdev);
+
+ /* Clear and disable all IRQs */
+ writel(~0, &ipd->regs->sio_iec);
+ writel(~0, &ipd->regs->sio_ir);
+
+ /* Release resources */
+ if (ipd->domain) {
+ irq_domain_remove(ipd->domain);
+ free_irq(ipd->domain_irq, (void *)ipd);
+ }
+ pci_disable_device(pdev);
+}
+
+static struct pci_device_id ioc3_mfd_id_table[] = {
+ { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, ioc3_mfd_id_table);
+
+static struct pci_driver ioc3_mfd_driver = {
+ .name = "IOC3",
+ .id_table = ioc3_mfd_id_table,
+ .probe = ioc3_mfd_probe,
+ .remove = ioc3_mfd_remove,
+};
+
+module_pci_driver(ioc3_mfd_driver);
+
+MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
+MODULE_DESCRIPTION("SGI IOC3 MFD driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/sgi/Kconfig b/drivers/net/ethernet/sgi/Kconfig
index 37f048e1230c..32a72b532605 100644
--- a/drivers/net/ethernet/sgi/Kconfig
+++ b/drivers/net/ethernet/sgi/Kconfig
@@ -6,7 +6,7 @@
config NET_VENDOR_SGI
bool "SGI devices"
default y
- depends on (PCI && SGI_IP27) || SGI_IP32
+ depends on (PCI && SGI_MFD_IOC3) || SGI_IP32
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
@@ -19,7 +19,7 @@ if NET_VENDOR_SGI
config SGI_IOC3_ETH
bool "SGI IOC3 Ethernet"
- depends on PCI && SGI_IP27
+ depends on PCI && SGI_MFD_IOC3
select CRC32
select MII
---help---
diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
index 358e66b81926..0e3f05373eae 100644
--- a/drivers/net/ethernet/sgi/ioc3-eth.c
+++ b/drivers/net/ethernet/sgi/ioc3-eth.c
@@ -7,6 +7,8 @@
*
* Copyright (C) 1999, 2000, 01, 03, 06 Ralf Baechle
* Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc.
+ * Copyright (C) 2005 Stanislaw Skowronek (port to meta-driver)
+ * 2009 Johannes Dickgreber <tanzy@gmx.de>
*
* References:
* o IOC3 ASIC specification 4.51, 1996-04-18
@@ -20,8 +22,6 @@
* o Use prefetching for large packets. What is a good lower limit for
* prefetching?
* o We're probably allocating a bit too much memory.
- * o Use hardware checksums.
- * o Convert to using a IOC3 meta driver.
* o Which PHYs might possibly be attached to the IOC3 in real live,
* which workarounds are required for them? Do we ever have Lucent's?
* o For the 2.5 branch kill the mii-tool ioctls.
@@ -30,484 +30,224 @@
#define IOC3_NAME "ioc3-eth"
#define IOC3_VERSION "2.6.3-4"
+#include <net/ip.h>
+
+#include <linux/crc16.h>
+#include <linux/crc32.h>
#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/crc32.h>
#include <linux/mii.h>
-#include <linux/in.h>
-#include <linux/ip.h>
+#include <linux/netdevice.h>
#include <linux/tcp.h>
#include <linux/udp.h>
-#include <linux/dma-mapping.h>
+#include <linux/module.h>
#include <linux/gfp.h>
+#include <linux/platform_device.h>
+#include <linux/nvmem-consumer.h>
-#ifdef CONFIG_SERIAL_8250
-#include <linux/serial_core.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_reg.h>
-#endif
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/skbuff.h>
-#include <net/ip.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <linux/uaccess.h>
-#include <asm/sn/types.h>
#include <asm/sn/ioc3.h>
#include <asm/pci/bridge.h>
+#define CRC16_INIT 0
+#define CRC16_VALID 0xb001
+
+#define IOC3_CACHELINE 128UL
+
/*
* 64 RX buffers. This is tunable in the range of 16 <= x < 512. The
* value must be a power of two.
*/
-#define RX_BUFFS 64
+#define RX_BUFFS 512
+#define RX_MASK (RX_BUFFS - 1)
+
+/* 128 TX buffers (not tunable) */
+#define TX_BUFFS 128
+#define TX_MASK (TX_BUFFS - 1)
-#define ETCSR_FD ((17<<ETCSR_IPGR2_SHIFT) | (11<<ETCSR_IPGR1_SHIFT) | 21)
-#define ETCSR_HD ((21<<ETCSR_IPGR2_SHIFT) | (21<<ETCSR_IPGR1_SHIFT) | 21)
+/* BEWARE: The IOC3 documentation documents the size of rx buffers as
+ * 1644 while it's actually 1664. This one was nasty to track down...
+ */
+#define RX_OFFSET 18
+#define RX_BUF_SIZE 1664
+#define RX_BUF_ALLOC_SIZE (RX_BUF_SIZE + RX_OFFSET + IOC3_CACHELINE)
-/* Private per NIC data of the driver. */
+/* Private per NIC data of the driver. */
struct ioc3_private {
- struct ioc3 *regs;
+ struct ioc3_ethregs *regs;
+ u32 *ssram;
unsigned long *rxr; /* pointer to receiver ring */
struct ioc3_etxd *txr;
- struct sk_buff *rx_skbs[512];
- struct sk_buff *tx_skbs[128];
+ struct sk_buff *rx_skbs[RX_BUFFS];
+ struct sk_buff *tx_skbs[TX_BUFFS];
int rx_ci; /* RX consumer index */
int rx_pi; /* RX producer index */
int tx_ci; /* TX consumer index */
int tx_pi; /* TX producer index */
- int txqlen;
+ int txbfree;
u32 emcr, ehar_h, ehar_l;
spinlock_t ioc3_lock;
struct mii_if_info mii;
+ unsigned long flags;
+ #define IOC3_FLAG_RX_CHECKSUMS 1
- struct net_device *dev;
- struct pci_dev *pdev;
-
- /* Members used by autonegotiation */
struct timer_list ioc3_timer;
};
-static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void ioc3_set_multicast_list(struct net_device *dev);
-static netdev_tx_t ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void ioc3_timeout(struct net_device *dev);
-static inline unsigned int ioc3_hash(const unsigned char *addr);
-static inline void ioc3_stop(struct ioc3_private *ip);
-static void ioc3_init(struct net_device *dev);
-
-static const char ioc3_str[] = "IOC3 Ethernet";
-static const struct ethtool_ops ioc3_ethtool_ops;
-
/* We use this to acquire receive skb's that we can DMA directly into. */
-
-#define IOC3_CACHELINE 128UL
-
static inline unsigned long aligned_rx_skb_addr(unsigned long addr)
{
- return (~addr + 1) & (IOC3_CACHELINE - 1UL);
+ return ((addr + 127) & ~127UL) - addr;
}
-static inline struct sk_buff * ioc3_alloc_skb(unsigned long length,
- unsigned int gfp_mask)
+static struct sk_buff *ioc3_alloc_skb(struct net_device *dev)
{
struct sk_buff *skb;
- skb = alloc_skb(length + IOC3_CACHELINE - 1, gfp_mask);
+ skb = alloc_skb(RX_BUF_ALLOC_SIZE + IOC3_CACHELINE - 1, GFP_ATOMIC);
if (likely(skb)) {
int offset = aligned_rx_skb_addr((unsigned long) skb->data);
if (offset)
skb_reserve(skb, offset);
+ skb->dev = dev;
}
return skb;
}
-static inline unsigned long ioc3_map(void *ptr, unsigned long vdev)
+static unsigned long ioc3_map(void *ptr, unsigned long dma_attr)
{
#ifdef CONFIG_SGI_IP27
- vdev <<= 57; /* Shift to PCI64_ATTR_VIRTUAL */
-
- return vdev | (0xaUL << PCI64_ATTR_TARG_SHFT) | PCI64_ATTR_PREF |
- ((unsigned long)ptr & TO_PHYS_MASK);
+ return ((0xaUL << PCI64_ATTR_TARG_SHFT) | dma_attr |
+ ((unsigned long)ptr & TO_PHYS_MASK));
#else
return virt_to_bus(ptr);
#endif
}
-/* BEWARE: The IOC3 documentation documents the size of rx buffers as
- 1644 while it's actually 1664. This one was nasty to track down ... */
-#define RX_OFFSET 10
-#define RX_BUF_ALLOC_SIZE (1664 + RX_OFFSET + IOC3_CACHELINE)
-
-/* DMA barrier to separate cached and uncached accesses. */
-#define BARRIER() \
- __asm__("sync" ::: "memory")
-
-
-#define IOC3_SIZE 0x100000
-
-/*
- * IOC3 is a big endian device
- *
- * Unorthodox but makes the users of these macros more readable - the pointer
- * to the IOC3's memory mapped registers is expected as struct ioc3 * ioc3
- * in the environment.
- */
-#define ioc3_r_mcr() be32_to_cpu(ioc3->mcr)
-#define ioc3_w_mcr(v) do { ioc3->mcr = cpu_to_be32(v); } while (0)
-#define ioc3_w_gpcr_s(v) do { ioc3->gpcr_s = cpu_to_be32(v); } while (0)
-#define ioc3_r_emcr() be32_to_cpu(ioc3->emcr)
-#define ioc3_w_emcr(v) do { ioc3->emcr = cpu_to_be32(v); } while (0)
-#define ioc3_r_eisr() be32_to_cpu(ioc3->eisr)
-#define ioc3_w_eisr(v) do { ioc3->eisr = cpu_to_be32(v); } while (0)
-#define ioc3_r_eier() be32_to_cpu(ioc3->eier)
-#define ioc3_w_eier(v) do { ioc3->eier = cpu_to_be32(v); } while (0)
-#define ioc3_r_ercsr() be32_to_cpu(ioc3->ercsr)
-#define ioc3_w_ercsr(v) do { ioc3->ercsr = cpu_to_be32(v); } while (0)
-#define ioc3_r_erbr_h() be32_to_cpu(ioc3->erbr_h)
-#define ioc3_w_erbr_h(v) do { ioc3->erbr_h = cpu_to_be32(v); } while (0)
-#define ioc3_r_erbr_l() be32_to_cpu(ioc3->erbr_l)
-#define ioc3_w_erbr_l(v) do { ioc3->erbr_l = cpu_to_be32(v); } while (0)
-#define ioc3_r_erbar() be32_to_cpu(ioc3->erbar)
-#define ioc3_w_erbar(v) do { ioc3->erbar = cpu_to_be32(v); } while (0)
-#define ioc3_r_ercir() be32_to_cpu(ioc3->ercir)
-#define ioc3_w_ercir(v) do { ioc3->ercir = cpu_to_be32(v); } while (0)
-#define ioc3_r_erpir() be32_to_cpu(ioc3->erpir)
-#define ioc3_w_erpir(v) do { ioc3->erpir = cpu_to_be32(v); } while (0)
-#define ioc3_r_ertr() be32_to_cpu(ioc3->ertr)
-#define ioc3_w_ertr(v) do { ioc3->ertr = cpu_to_be32(v); } while (0)
-#define ioc3_r_etcsr() be32_to_cpu(ioc3->etcsr)
-#define ioc3_w_etcsr(v) do { ioc3->etcsr = cpu_to_be32(v); } while (0)
-#define ioc3_r_ersr() be32_to_cpu(ioc3->ersr)
-#define ioc3_w_ersr(v) do { ioc3->ersr = cpu_to_be32(v); } while (0)
-#define ioc3_r_etcdc() be32_to_cpu(ioc3->etcdc)
-#define ioc3_w_etcdc(v) do { ioc3->etcdc = cpu_to_be32(v); } while (0)
-#define ioc3_r_ebir() be32_to_cpu(ioc3->ebir)
-#define ioc3_w_ebir(v) do { ioc3->ebir = cpu_to_be32(v); } while (0)
-#define ioc3_r_etbr_h() be32_to_cpu(ioc3->etbr_h)
-#define ioc3_w_etbr_h(v) do { ioc3->etbr_h = cpu_to_be32(v); } while (0)
-#define ioc3_r_etbr_l() be32_to_cpu(ioc3->etbr_l)
-#define ioc3_w_etbr_l(v) do { ioc3->etbr_l = cpu_to_be32(v); } while (0)
-#define ioc3_r_etcir() be32_to_cpu(ioc3->etcir)
-#define ioc3_w_etcir(v) do { ioc3->etcir = cpu_to_be32(v); } while (0)
-#define ioc3_r_etpir() be32_to_cpu(ioc3->etpir)
-#define ioc3_w_etpir(v) do { ioc3->etpir = cpu_to_be32(v); } while (0)
-#define ioc3_r_emar_h() be32_to_cpu(ioc3->emar_h)
-#define ioc3_w_emar_h(v) do { ioc3->emar_h = cpu_to_be32(v); } while (0)
-#define ioc3_r_emar_l() be32_to_cpu(ioc3->emar_l)
-#define ioc3_w_emar_l(v) do { ioc3->emar_l = cpu_to_be32(v); } while (0)
-#define ioc3_r_ehar_h() be32_to_cpu(ioc3->ehar_h)
-#define ioc3_w_ehar_h(v) do { ioc3->ehar_h = cpu_to_be32(v); } while (0)
-#define ioc3_r_ehar_l() be32_to_cpu(ioc3->ehar_l)
-#define ioc3_w_ehar_l(v) do { ioc3->ehar_l = cpu_to_be32(v); } while (0)
-#define ioc3_r_micr() be32_to_cpu(ioc3->micr)
-#define ioc3_w_micr(v) do { ioc3->micr = cpu_to_be32(v); } while (0)
-#define ioc3_r_midr_r() be32_to_cpu(ioc3->midr_r)
-#define ioc3_w_midr_r(v) do { ioc3->midr_r = cpu_to_be32(v); } while (0)
-#define ioc3_r_midr_w() be32_to_cpu(ioc3->midr_w)
-#define ioc3_w_midr_w(v) do { ioc3->midr_w = cpu_to_be32(v); } while (0)
-
-static inline u32 mcr_pack(u32 pulse, u32 sample)
-{
- return (pulse << 10) | (sample << 2);
-}
-
-static int nic_wait(struct ioc3 *ioc3)
-{
- u32 mcr;
-
- do {
- mcr = ioc3_r_mcr();
- } while (!(mcr & 2));
-
- return mcr & 1;
-}
-
-static int nic_reset(struct ioc3 *ioc3)
-{
- int presence;
-
- ioc3_w_mcr(mcr_pack(500, 65));
- presence = nic_wait(ioc3);
-
- ioc3_w_mcr(mcr_pack(0, 500));
- nic_wait(ioc3);
-
- return presence;
-}
-
-static inline int nic_read_bit(struct ioc3 *ioc3)
-{
- int result;
-
- ioc3_w_mcr(mcr_pack(6, 13));
- result = nic_wait(ioc3);
- ioc3_w_mcr(mcr_pack(0, 100));
- nic_wait(ioc3);
-
- return result;
-}
-
-static inline void nic_write_bit(struct ioc3 *ioc3, int bit)
-{
- if (bit)
- ioc3_w_mcr(mcr_pack(6, 110));
- else
- ioc3_w_mcr(mcr_pack(80, 30));
-
- nic_wait(ioc3);
-}
-
-/*
- * Read a byte from an iButton device
- */
-static u32 nic_read_byte(struct ioc3 *ioc3)
+static void __ioc3_set_mac_address(struct net_device *dev,
+ struct ioc3_ethregs *regs)
{
- u32 result = 0;
- int i;
-
- for (i = 0; i < 8; i++)
- result = (result >> 1) | (nic_read_bit(ioc3) << 7);
-
- return result;
+ writel((dev->dev_addr[5] << 8) |
+ dev->dev_addr[4],
+ ®s->emar_h);
+ writel((dev->dev_addr[3] << 24) |
+ (dev->dev_addr[2] << 16) |
+ (dev->dev_addr[1] << 8) |
+ dev->dev_addr[0],
+ ®s->emar_l);
}
/*
- * Write a byte to an iButton device
+ * Caller must hold the ioc3_lock ever for MII readers. This is also
+ * used to protect the transmitter side but it's low contention.
*/
-static void nic_write_byte(struct ioc3 *ioc3, int byte)
+static int ioc3_mdio_read(struct net_device *dev, int phy, int reg)
{
- int i, bit;
+ struct ioc3_private *ip = netdev_priv(dev);
+ struct ioc3_ethregs *regs = ip->regs;
- for (i = 8; i; i--) {
- bit = byte & 1;
- byte >>= 1;
+ while (readl(®s->micr) & MICR_BUSY)
+ ;
+ writel((phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG,
+ ®s->micr);
+ while (readl(®s->micr) & MICR_BUSY)
+ ;
- nic_write_bit(ioc3, bit);
- }
+ return readl(®s->midr_r) & MIDR_DATA_MASK;
}
-static u64 nic_find(struct ioc3 *ioc3, int *last)
+static void ioc3_mdio_write(struct net_device *dev, int phy, int reg, int data)
{
- int a, b, index, disc;
- u64 address = 0;
-
- nic_reset(ioc3);
- /* Search ROM. */
- nic_write_byte(ioc3, 0xf0);
-
- /* Algorithm from ``Book of iButton Standards''. */
- for (index = 0, disc = 0; index < 64; index++) {
- a = nic_read_bit(ioc3);
- b = nic_read_bit(ioc3);
-
- if (a && b) {
- printk("NIC search failed (not fatal).\n");
- *last = 0;
- return 0;
- }
-
- if (!a && !b) {
- if (index == *last) {
- address |= 1UL << index;
- } else if (index > *last) {
- address &= ~(1UL << index);
- disc = index;
- } else if ((address & (1UL << index)) == 0)
- disc = index;
- nic_write_bit(ioc3, address & (1UL << index));
- continue;
- } else {
- if (a)
- address |= 1UL << index;
- else
- address &= ~(1UL << index);
- nic_write_bit(ioc3, a);
- continue;
- }
- }
-
- *last = disc;
-
- return address;
+ struct ioc3_private *ip = netdev_priv(dev);
+ struct ioc3_ethregs *regs = ip->regs;
+
+ while (readl(®s->micr) & MICR_BUSY)
+ ;
+ writel(data, ®s->midr_w);
+ writel((phy << MICR_PHYADDR_SHIFT) | reg, ®s->micr);
+ while (readl(®s->micr) & MICR_BUSY)
+ ;
}
-static int nic_init(struct ioc3 *ioc3)
+static void ioc3_stop(struct ioc3_private *ip)
{
- const char *unknown = "unknown";
- const char *type = unknown;
- u8 crc;
- u8 serial[6];
- int save = 0, i;
-
- while (1) {
- u64 reg;
- reg = nic_find(ioc3, &save);
-
- switch (reg & 0xff) {
- case 0x91:
- type = "DS1981U";
- break;
- default:
- if (save == 0) {
- /* Let the caller try again. */
- return -1;
- }
- continue;
- }
-
- nic_reset(ioc3);
-
- /* Match ROM. */
- nic_write_byte(ioc3, 0x55);
- for (i = 0; i < 8; i++)
- nic_write_byte(ioc3, (reg >> (i << 3)) & 0xff);
-
- reg >>= 8; /* Shift out type. */
- for (i = 0; i < 6; i++) {
- serial[i] = reg & 0xff;
- reg >>= 8;
- }
- crc = reg & 0xff;
- break;
- }
-
- printk("Found %s NIC", type);
- if (type != unknown)
- printk (" registration number %pM, CRC %02x", serial, crc);
- printk(".\n");
+ struct ioc3_ethregs *regs = ip->regs;
- return 0;
+ writel(0, ®s->emcr); /* Shutup */
+ writel(0, ®s->eier); /* Disable interrupts */
+ (void)readl(®s->eier); /* Flush */
}
/*
- * Read the NIC (Number-In-a-Can) device used to store the MAC address on
- * SN0 / SN00 nodeboards and PCI cards.
+ * Given a multicast ethernet address, this routine calculates the
+ * address's bit index in the logical address filter mask
*/
-static void ioc3_get_eaddr_nic(struct ioc3_private *ip)
+static u32 ioc3_hash(const u8 *addr)
{
- struct ioc3 *ioc3 = ip->regs;
- u8 nic[14];
- int tries = 2; /* There may be some problem with the battery? */
- int i;
-
- ioc3_w_gpcr_s(1 << 21);
+ u32 crc, temp = 0;
+ int bits;
- while (tries--) {
- if (!nic_init(ioc3))
- break;
- udelay(500);
- }
+ crc = ether_crc_le(ETH_ALEN, addr);
- if (tries < 0) {
- printk("Failed to read MAC address\n");
- return;
+ crc &= 0x3f; /* bit reverse lowest 6 bits for hash index */
+ for (bits = 6; --bits >= 0; ) {
+ temp <<= 1;
+ temp |= (crc & 0x1);
+ crc >>= 1;
}
- /* Read Memory. */
- nic_write_byte(ioc3, 0xf0);
- nic_write_byte(ioc3, 0x00);
- nic_write_byte(ioc3, 0x00);
-
- for (i = 13; i >= 0; i--)
- nic[i] = nic_read_byte(ioc3);
-
- for (i = 2; i < 8; i++)
- ip->dev->dev_addr[i - 2] = nic[i];
-}
-
-/*
- * Ok, this is hosed by design. It's necessary to know what machine the
- * NIC is in in order to know how to read the NIC address. We also have
- * to know if it's a PCI card or a NIC in on the node board ...
- */
-static void ioc3_get_eaddr(struct ioc3_private *ip)
-{
- ioc3_get_eaddr_nic(ip);
-
- printk("Ethernet address is %pM.\n", ip->dev->dev_addr);
-}
-
-static void __ioc3_set_mac_address(struct net_device *dev)
-{
- struct ioc3_private *ip = netdev_priv(dev);
- struct ioc3 *ioc3 = ip->regs;
-
- ioc3_w_emar_h((dev->dev_addr[5] << 8) | dev->dev_addr[4]);
- ioc3_w_emar_l((dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) |
- (dev->dev_addr[1] << 8) | dev->dev_addr[0]);
+ return temp;
}
-static int ioc3_set_mac_address(struct net_device *dev, void *addr)
+static void ioc3_set_multicast_list(struct net_device *dev)
{
+ struct netdev_hw_addr *ha;
struct ioc3_private *ip = netdev_priv(dev);
- struct sockaddr *sa = addr;
-
- memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+ struct ioc3_ethregs *regs = ip->regs;
+ u64 ehar = 0;
spin_lock_irq(&ip->ioc3_lock);
- __ioc3_set_mac_address(dev);
- spin_unlock_irq(&ip->ioc3_lock);
-
- return 0;
-}
-
-/*
- * Caller must hold the ioc3_lock ever for MII readers. This is also
- * used to protect the transmitter side but it's low contention.
- */
-static int ioc3_mdio_read(struct net_device *dev, int phy, int reg)
-{
- struct ioc3_private *ip = netdev_priv(dev);
- struct ioc3 *ioc3 = ip->regs;
-
- while (ioc3_r_micr() & MICR_BUSY);
- ioc3_w_micr((phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG);
- while (ioc3_r_micr() & MICR_BUSY);
-
- return ioc3_r_midr_r() & MIDR_DATA_MASK;
-}
-
-static void ioc3_mdio_write(struct net_device *dev, int phy, int reg, int data)
-{
- struct ioc3_private *ip = netdev_priv(dev);
- struct ioc3 *ioc3 = ip->regs;
-
- while (ioc3_r_micr() & MICR_BUSY);
- ioc3_w_midr_w(data);
- ioc3_w_micr((phy << MICR_PHYADDR_SHIFT) | reg);
- while (ioc3_r_micr() & MICR_BUSY);
-}
-
-static int ioc3_mii_init(struct ioc3_private *ip);
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ ip->emcr |= EMCR_PROMISC;
+ writel(ip->emcr, ®s->emcr);
+ (void)readl(®s->emcr);
+ } else {
+ ip->emcr &= ~EMCR_PROMISC;
+ writel(ip->emcr, ®s->emcr); /* Clear promiscuous. */
+ (void)readl(®s->emcr);
-static struct net_device_stats *ioc3_get_stats(struct net_device *dev)
-{
- struct ioc3_private *ip = netdev_priv(dev);
- struct ioc3 *ioc3 = ip->regs;
+ if ((dev->flags & IFF_ALLMULTI) ||
+ (netdev_mc_count(dev) > 64)) {
+ /* Too many for hashing to make sense or we want all
+ * multicast packets anyway, so skip computing all
+ * the hashes and just accept all packets.
+ */
+ ip->ehar_h = 0xffffffff;
+ ip->ehar_l = 0xffffffff;
+ } else {
+ netdev_for_each_mc_addr(ha, dev) {
+ ehar |= (1UL << ioc3_hash(ha->addr));
+ }
+ ip->ehar_h = ehar >> 32;
+ ip->ehar_l = ehar & 0xffffffff;
+ }
+ writel(ip->ehar_h, ®s->ehar_h);
+ writel(ip->ehar_l, ®s->ehar_l);
+ }
- dev->stats.collisions += (ioc3_r_etcdc() & ETCDC_COLLCNT_MASK);
- return &dev->stats;
+ spin_unlock_irq(&ip->ioc3_lock);
}
static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
{
struct ethhdr *eh = eth_hdr(skb);
- uint32_t csum, ehsum;
- unsigned int proto;
struct iphdr *ih;
- uint16_t *ew;
- unsigned char *cp;
+ u8 *cp;
+ u16 *ew;
+ u32 csum, ehsum, proto;
/*
* Did hardware handle the checksum at all? The cases we can handle
@@ -568,277 +308,95 @@ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
-static inline void ioc3_rx(struct net_device *dev)
-{
- struct ioc3_private *ip = netdev_priv(dev);
- struct sk_buff *skb, *new_skb;
- struct ioc3 *ioc3 = ip->regs;
- int rx_entry, n_entry, len;
- struct ioc3_erxbuf *rxb;
- unsigned long *rxr;
- u32 w0, err;
+#define ETCSR_FD ((17 << ETCSR_IPGR2_SHIFT) | (11 << ETCSR_IPGR1_SHIFT) | 21)
+#define ETCSR_HD ((21 << ETCSR_IPGR2_SHIFT) | (21 << ETCSR_IPGR1_SHIFT) | 21)
- rxr = ip->rxr; /* Ring base */
- rx_entry = ip->rx_ci; /* RX consume index */
- n_entry = ip->rx_pi;
+static void ioc3_setup_duplex(struct ioc3_private *ip)
+{
+ struct ioc3_ethregs *regs = ip->regs;
- skb = ip->rx_skbs[rx_entry];
- rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET);
- w0 = be32_to_cpu(rxb->w0);
+ if (ip->mii.full_duplex) {
+ writel(ETCSR_FD, ®s->etcsr);
+ ip->emcr |= EMCR_DUPLEX;
+ } else {
+ writel(ETCSR_HD, ®s->etcsr);
+ ip->emcr &= ~EMCR_DUPLEX;
+ }
+ writel(ip->emcr, ®s->emcr);
+ (void)readl(®s->emcr);
+}
- while (w0 & ERXBUF_V) {
- err = be32_to_cpu(rxb->err); /* It's valid ... */
- if (err & ERXBUF_GOODPKT) {
- len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4;
- skb_trim(skb, len);
- skb->protocol = eth_type_trans(skb, dev);
+static void ioc3_timer(struct timer_list *t)
+{
+ struct ioc3_private *ip = from_timer(ip, t, ioc3_timer);
- new_skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
- if (!new_skb) {
- /* Ouch, drop packet and just recycle packet
- to keep the ring filled. */
- dev->stats.rx_dropped++;
- new_skb = skb;
- goto next;
- }
+ /* Print the link status if it has changed */
+ mii_check_media(&ip->mii, 1, 0);
+ ioc3_setup_duplex(ip);
- if (likely(dev->features & NETIF_F_RXCSUM))
- ioc3_tcpudp_checksum(skb,
- w0 & ERXBUF_IPCKSUM_MASK, len);
+ ip->ioc3_timer.expires = jiffies + ((12 * HZ) / 10); /* 1.2s */
+ add_timer(&ip->ioc3_timer);
+}
- netif_rx(skb);
+/* Try to find a PHY. There is no apparent relation between the MII addresses
+ * in the SGI documentation and what we find in reality, so we simply probe
+ * for the PHY. It seems IOC3 PHYs usually live on address 31. One of my
+ * onboard IOC3s has the special oddity that probing doesn't seem to find it
+ * yet the interface seems to work fine, so if probing fails we for now will
+ * simply default to PHY 31 instead of bailing out.
+ */
+static int ioc3_mii_init(struct ioc3_private *ip)
+{
+ int i, found = 0, res = 0;
+ int ioc3_phy_workaround = 1;
+ u16 word;
- ip->rx_skbs[rx_entry] = NULL; /* Poison */
+ for (i = 0; i < 32; i++) {
+ word = ioc3_mdio_read(ip->mii.dev, i, MII_PHYSID1);
- /* Because we reserve afterwards. */
- skb_put(new_skb, (1664 + RX_OFFSET));
- rxb = (struct ioc3_erxbuf *) new_skb->data;
- skb_reserve(new_skb, RX_OFFSET);
+ if (word != 0xffff && word != 0x0000) {
+ found = 1;
+ break; /* Found a PHY */
+ }
+ }
- dev->stats.rx_packets++; /* Statistics */
- dev->stats.rx_bytes += len;
+ if (!found) {
+ if (ioc3_phy_workaround) {
+ i = 31;
} else {
- /* The frame is invalid and the skb never
- reached the network layer so we can just
- recycle it. */
- new_skb = skb;
- dev->stats.rx_errors++;
+ ip->mii.phy_id = -1;
+ res = -ENODEV;
+ goto out;
}
- if (err & ERXBUF_CRCERR) /* Statistics */
- dev->stats.rx_crc_errors++;
- if (err & ERXBUF_FRAMERR)
- dev->stats.rx_frame_errors++;
-next:
- ip->rx_skbs[n_entry] = new_skb;
- rxr[n_entry] = cpu_to_be64(ioc3_map(rxb, 1));
- rxb->w0 = 0; /* Clear valid flag */
- n_entry = (n_entry + 1) & 511; /* Update erpir */
-
- /* Now go on to the next ring entry. */
- rx_entry = (rx_entry + 1) & 511;
- skb = ip->rx_skbs[rx_entry];
- rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET);
- w0 = be32_to_cpu(rxb->w0);
}
- ioc3_w_erpir((n_entry << 3) | ERPIR_ARM);
- ip->rx_pi = n_entry;
- ip->rx_ci = rx_entry;
+
+ ip->mii.phy_id = i;
+
+out:
+ return res;
}
-static inline void ioc3_tx(struct net_device *dev)
+static void ioc3_mii_start(struct ioc3_private *ip)
+{
+ ip->ioc3_timer.expires = jiffies + (12 * HZ) / 10; /* 1.2 sec. */
+ add_timer(&ip->ioc3_timer);
+}
+
+static void ioc3_clean_rx_ring(struct ioc3_private *ip)
{
- struct ioc3_private *ip = netdev_priv(dev);
- unsigned long packets, bytes;
- struct ioc3 *ioc3 = ip->regs;
- int tx_entry, o_entry;
struct sk_buff *skb;
- u32 etcir;
+ struct ioc3_erxbuf *rxb;
+ int i;
- spin_lock(&ip->ioc3_lock);
- etcir = ioc3_r_etcir();
-
- tx_entry = (etcir >> 7) & 127;
- o_entry = ip->tx_ci;
- packets = 0;
- bytes = 0;
-
- while (o_entry != tx_entry) {
- packets++;
- skb = ip->tx_skbs[o_entry];
- bytes += skb->len;
- dev_consume_skb_irq(skb);
- ip->tx_skbs[o_entry] = NULL;
-
- o_entry = (o_entry + 1) & 127; /* Next */
-
- etcir = ioc3_r_etcir(); /* More pkts sent? */
- tx_entry = (etcir >> 7) & 127;
- }
-
- dev->stats.tx_packets += packets;
- dev->stats.tx_bytes += bytes;
- ip->txqlen -= packets;
-
- if (ip->txqlen < 128)
- netif_wake_queue(dev);
-
- ip->tx_ci = o_entry;
- spin_unlock(&ip->ioc3_lock);
-}
-
-/*
- * Deal with fatal IOC3 errors. This condition might be caused by a hard or
- * software problems, so we should try to recover
- * more gracefully if this ever happens. In theory we might be flooded
- * with such error interrupts if something really goes wrong, so we might
- * also consider to take the interface down.
- */
-static void ioc3_error(struct net_device *dev, u32 eisr)
-{
- struct ioc3_private *ip = netdev_priv(dev);
- unsigned char *iface = dev->name;
-
- spin_lock(&ip->ioc3_lock);
-
- if (eisr & EISR_RXOFLO)
- printk(KERN_ERR "%s: RX overflow.\n", iface);
- if (eisr & EISR_RXBUFOFLO)
- printk(KERN_ERR "%s: RX buffer overflow.\n", iface);
- if (eisr & EISR_RXMEMERR)
- printk(KERN_ERR "%s: RX PCI error.\n", iface);
- if (eisr & EISR_RXPARERR)
- printk(KERN_ERR "%s: RX SSRAM parity error.\n", iface);
- if (eisr & EISR_TXBUFUFLO)
- printk(KERN_ERR "%s: TX buffer underflow.\n", iface);
- if (eisr & EISR_TXMEMERR)
- printk(KERN_ERR "%s: TX PCI error.\n", iface);
-
- ioc3_stop(ip);
- ioc3_init(dev);
- ioc3_mii_init(ip);
-
- netif_wake_queue(dev);
-
- spin_unlock(&ip->ioc3_lock);
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
-static irqreturn_t ioc3_interrupt(int irq, void *_dev)
-{
- struct net_device *dev = (struct net_device *)_dev;
- struct ioc3_private *ip = netdev_priv(dev);
- struct ioc3 *ioc3 = ip->regs;
- const u32 enabled = EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO |
- EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO |
- EISR_TXEXPLICIT | EISR_TXMEMERR;
- u32 eisr;
-
- eisr = ioc3_r_eisr() & enabled;
-
- ioc3_w_eisr(eisr);
- (void) ioc3_r_eisr(); /* Flush */
-
- if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR |
- EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXMEMERR))
- ioc3_error(dev, eisr);
- if (eisr & EISR_RXTIMERINT)
- ioc3_rx(dev);
- if (eisr & EISR_TXEXPLICIT)
- ioc3_tx(dev);
-
- return IRQ_HANDLED;
-}
-
-static inline void ioc3_setup_duplex(struct ioc3_private *ip)
-{
- struct ioc3 *ioc3 = ip->regs;
-
- if (ip->mii.full_duplex) {
- ioc3_w_etcsr(ETCSR_FD);
- ip->emcr |= EMCR_DUPLEX;
- } else {
- ioc3_w_etcsr(ETCSR_HD);
- ip->emcr &= ~EMCR_DUPLEX;
- }
- ioc3_w_emcr(ip->emcr);
-}
-
-static void ioc3_timer(struct timer_list *t)
-{
- struct ioc3_private *ip = from_timer(ip, t, ioc3_timer);
-
- /* Print the link status if it has changed */
- mii_check_media(&ip->mii, 1, 0);
- ioc3_setup_duplex(ip);
-
- ip->ioc3_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2s */
- add_timer(&ip->ioc3_timer);
-}
-
-/*
- * Try to find a PHY. There is no apparent relation between the MII addresses
- * in the SGI documentation and what we find in reality, so we simply probe
- * for the PHY. It seems IOC3 PHYs usually live on address 31. One of my
- * onboard IOC3s has the special oddity that probing doesn't seem to find it
- * yet the interface seems to work fine, so if probing fails we for now will
- * simply default to PHY 31 instead of bailing out.
- */
-static int ioc3_mii_init(struct ioc3_private *ip)
-{
- int i, found = 0, res = 0;
- int ioc3_phy_workaround = 1;
- u16 word;
-
- for (i = 0; i < 32; i++) {
- word = ioc3_mdio_read(ip->dev, i, MII_PHYSID1);
-
- if (word != 0xffff && word != 0x0000) {
- found = 1;
- break; /* Found a PHY */
- }
- }
-
- if (!found) {
- if (ioc3_phy_workaround)
- i = 31;
- else {
- ip->mii.phy_id = -1;
- res = -ENODEV;
- goto out;
- }
- }
-
- ip->mii.phy_id = i;
-
-out:
- return res;
-}
-
-static void ioc3_mii_start(struct ioc3_private *ip)
-{
- ip->ioc3_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */
- add_timer(&ip->ioc3_timer);
-}
-
-static inline void ioc3_clean_rx_ring(struct ioc3_private *ip)
-{
- struct sk_buff *skb;
- int i;
-
- for (i = ip->rx_ci; i & 15; i++) {
- ip->rx_skbs[ip->rx_pi] = ip->rx_skbs[ip->rx_ci];
- ip->rxr[ip->rx_pi++] = ip->rxr[ip->rx_ci++];
- }
- ip->rx_pi &= 511;
- ip->rx_ci &= 511;
-
- for (i = ip->rx_ci; i != ip->rx_pi; i = (i+1) & 511) {
- struct ioc3_erxbuf *rxb;
+ for (i = 0; i < RX_BUFFS; i++) {
skb = ip->rx_skbs[i];
- rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET);
- rxb->w0 = 0;
+ if (skb) {
+ rxb = (struct ioc3_erxbuf *)(skb->data - RX_OFFSET);
+ rxb->w0 = 0;
+ }
}
+ ip->rx_ci = 0;
+ ip->rx_pi = RX_BUFFS - 16;
}
static inline void ioc3_clean_tx_ring(struct ioc3_private *ip)
@@ -846,7 +404,7 @@ static inline void ioc3_clean_tx_ring(struct ioc3_private *ip)
struct sk_buff *skb;
int i;
- for (i=0; i < 128; i++) {
+ for (i = 0; i < TX_BUFFS; i++) {
skb = ip->tx_skbs[i];
if (skb) {
ip->tx_skbs[i] = NULL;
@@ -861,7 +419,7 @@ static inline void ioc3_clean_tx_ring(struct ioc3_private *ip)
static void ioc3_free_rings(struct ioc3_private *ip)
{
struct sk_buff *skb;
- int rx_entry, n_entry;
+ int i;
if (ip->txr) {
ioc3_clean_tx_ring(ip);
@@ -870,15 +428,10 @@ static void ioc3_free_rings(struct ioc3_private *ip)
}
if (ip->rxr) {
- n_entry = ip->rx_ci;
- rx_entry = ip->rx_pi;
-
- while (n_entry != rx_entry) {
- skb = ip->rx_skbs[n_entry];
+ for (i = 0; i < RX_BUFFS; i++) {
+ skb = ip->rx_skbs[i];
if (skb)
dev_kfree_skb_any(skb);
-
- n_entry = (n_entry + 1) & 511;
}
free_page((unsigned long)ip->rxr);
ip->rxr = NULL;
@@ -897,15 +450,16 @@ static void ioc3_alloc_rings(struct net_device *dev)
ip->rxr = (unsigned long *) get_zeroed_page(GFP_ATOMIC);
rxr = ip->rxr;
if (!rxr)
- printk("ioc3_alloc_rings(): get_zeroed_page() failed!\n");
+ printk(KERN_ERR "ioc3_alloc_rings(): get_zeroed_page() failed!\n");
- /* Now the rx buffers. The RX ring may be larger but
- we only allocate 16 buffers for now. Need to tune
- this for performance and memory later. */
+ /* Now the rx buffers. The RX ring may be larger but we
+ * only allocate RX_BUFFS buffers for now. Need to tune
+ * this for performance and memory later.
+ */
for (i = 0; i < RX_BUFFS; i++) {
struct sk_buff *skb;
- skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
+ skb = ioc3_alloc_skb(dev);
if (!skb) {
show_free_areas(0, NULL);
continue;
@@ -914,141 +468,135 @@ static void ioc3_alloc_rings(struct net_device *dev)
ip->rx_skbs[i] = skb;
/* Because we reserve afterwards. */
- skb_put(skb, (1664 + RX_OFFSET));
+ skb_put(skb, (RX_BUF_SIZE + RX_OFFSET));
rxb = (struct ioc3_erxbuf *) skb->data;
- rxr[i] = cpu_to_be64(ioc3_map(rxb, 1));
+ rxr[i] = cpu_to_be64(ioc3_map(rxb, PCI64_ATTR_BAR));
skb_reserve(skb, RX_OFFSET);
}
- ip->rx_ci = 0;
- ip->rx_pi = RX_BUFFS;
}
if (ip->txr == NULL) {
/* Allocate and initialize tx rings. 16kb = 128 bufs. */
- ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2);
+ ip->txr = (struct ioc3_etxd *)__get_free_pages((GFP_ATOMIC |
+ __GFP_ZERO), 2);
if (!ip->txr)
- printk("ioc3_alloc_rings(): __get_free_pages() failed!\n");
- ip->tx_pi = 0;
- ip->tx_ci = 0;
+ printk(KERN_ERR "ioc3_alloc_rings(): __get_free_pages() failed!\n");
}
}
static void ioc3_init_rings(struct net_device *dev)
{
struct ioc3_private *ip = netdev_priv(dev);
- struct ioc3 *ioc3 = ip->regs;
+ struct ioc3_ethregs *regs = ip->regs;
unsigned long ring;
ioc3_free_rings(ip);
ioc3_alloc_rings(dev);
-
ioc3_clean_rx_ring(ip);
ioc3_clean_tx_ring(ip);
/* Now the rx ring base, consume & produce registers. */
- ring = ioc3_map(ip->rxr, 0);
- ioc3_w_erbr_h(ring >> 32);
- ioc3_w_erbr_l(ring & 0xffffffff);
- ioc3_w_ercir(ip->rx_ci << 3);
- ioc3_w_erpir((ip->rx_pi << 3) | ERPIR_ARM);
-
- ring = ioc3_map(ip->txr, 0);
-
- ip->txqlen = 0; /* nothing queued */
+ ring = ioc3_map(ip->rxr, PCI64_ATTR_VIRTUAL | PCI64_ATTR_PREC);
+ writel(ring >> 32, ®s->erbr_h);
+ writel(ring & 0xffffffff, ®s->erbr_l);
+ writel(ip->rx_ci << 3, ®s->ercir);
+ writel((ip->rx_pi << 3) | ERPIR_ARM, ®s->erpir);
/* Now the tx ring base, consume & produce registers. */
- ioc3_w_etbr_h(ring >> 32);
- ioc3_w_etbr_l(ring & 0xffffffff);
- ioc3_w_etpir(ip->tx_pi << 7);
- ioc3_w_etcir(ip->tx_ci << 7);
- (void) ioc3_r_etcir(); /* Flush */
+ ring = ioc3_map(ip->txr, PCI64_ATTR_VIRTUAL | PCI64_ATTR_PREC);
+ ip->txbfree = TX_BUFFS; /* nothing queued */
+ writel(ring >> 32, ®s->etbr_h);
+ writel(ring & 0xffffffff, ®s->etbr_l);
+ writel(ip->tx_pi << 7, ®s->etpir);
+ writel(ip->tx_ci << 7, ®s->etcir);
+ (void)readl(®s->etcir); /* Flush */
}
-static inline void ioc3_ssram_disc(struct ioc3_private *ip)
+static void ioc3_ssram_disc(struct ioc3_private *ip)
{
- struct ioc3 *ioc3 = ip->regs;
- volatile u32 *ssram0 = &ioc3->ssram[0x0000];
- volatile u32 *ssram1 = &ioc3->ssram[0x4000];
- unsigned int pattern = 0x5555;
+ struct ioc3_ethregs *regs = ip->regs;
+ u32 *emcr_p = ®s->emcr;
+ u32 *ssram0 = &ip->ssram[0x0000];
+ u32 *ssram1 = &ip->ssram[0x4000];
+ const u32 pattern0 = 0x5555;
+ const u32 pattern1 = ~pattern0 & IOC3_SSRAM_DM;
/* Assume the larger size SSRAM and enable parity checking */
- ioc3_w_emcr(ioc3_r_emcr() | (EMCR_BUFSIZ | EMCR_RAMPAR));
+ writel(readl(emcr_p) | EMCR_BUFSIZ | EMCR_RAMPAR, emcr_p);
+ (void)readl(emcr_p);
- *ssram0 = pattern;
- *ssram1 = ~pattern & IOC3_SSRAM_DM;
+ writel(pattern0, ssram0);
+ writel(pattern1, ssram1);
- if ((*ssram0 & IOC3_SSRAM_DM) != pattern ||
- (*ssram1 & IOC3_SSRAM_DM) != (~pattern & IOC3_SSRAM_DM)) {
+ if (((readl(ssram0) & IOC3_SSRAM_DM) != pattern0) ||
+ ((readl(ssram1) & IOC3_SSRAM_DM) != pattern1)) {
/* set ssram size to 64 KB */
- ip->emcr = EMCR_RAMPAR;
- ioc3_w_emcr(ioc3_r_emcr() & ~EMCR_BUFSIZ);
- } else
- ip->emcr = EMCR_BUFSIZ | EMCR_RAMPAR;
+ ip->emcr |= EMCR_RAMPAR;
+ writel(readl(emcr_p) & ~EMCR_BUFSIZ, emcr_p);
+ (void)readl(emcr_p);
+ } else {
+ ip->emcr |= EMCR_RAMPAR | EMCR_BUFSIZ;
+ }
}
static void ioc3_init(struct net_device *dev)
{
struct ioc3_private *ip = netdev_priv(dev);
- struct ioc3 *ioc3 = ip->regs;
+ struct ioc3_ethregs *regs = ip->regs;
del_timer_sync(&ip->ioc3_timer); /* Kill if running */
- ioc3_w_emcr(EMCR_RST); /* Reset */
- (void) ioc3_r_emcr(); /* Flush WB */
- udelay(4); /* Give it time ... */
- ioc3_w_emcr(0);
- (void) ioc3_r_emcr();
+ writel(EMCR_RST, ®s->emcr); /* Reset */
+ (void)readl(®s->emcr); /* Flush WB */
+ udelay(4); /* Give it time... */
+ writel(0, ®s->emcr);
+ (void)readl(®s->emcr);
/* Misc registers */
#ifdef CONFIG_SGI_IP27
- ioc3_w_erbar(PCI64_ATTR_BAR >> 32); /* Barrier on last store */
+ /* Barrier on last store */
+ writel(readl(®s->erbar) |
+ (ERBAR_BARRIER_BIT << ERBAR_RXBARR_SHIFT), ®s->erbar);
#else
- ioc3_w_erbar(0); /* Let PCI API get it right */
+ /* Let PCI API get it right */
+ writel(0, ®s->erbar);
#endif
- (void) ioc3_r_etcdc(); /* Clear on read */
- ioc3_w_ercsr(15); /* RX low watermark */
- ioc3_w_ertr(0); /* Interrupt immediately */
- __ioc3_set_mac_address(dev);
- ioc3_w_ehar_h(ip->ehar_h);
- ioc3_w_ehar_l(ip->ehar_l);
- ioc3_w_ersr(42); /* XXX should be random */
+ readl(®s->etcdc); /* Clear on read */
+ writel(15, ®s->ercsr); /* RX low watermark */
+ writel(1, ®s->ertr); /* Interrupt immediately */
+ __ioc3_set_mac_address(dev, regs);
+ writel(ip->ehar_h, ®s->ehar_h);
+ writel(ip->ehar_l, ®s->ehar_l);
+ writel(42, ®s->ersr); /* XXX Should be random */
ioc3_init_rings(dev);
- ip->emcr |= ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | EMCR_TXDMAEN |
- EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN | EMCR_PADEN;
- ioc3_w_emcr(ip->emcr);
- ioc3_w_eier(EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO |
- EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO |
- EISR_TXEXPLICIT | EISR_TXMEMERR);
- (void) ioc3_r_eier();
-}
-
-static inline void ioc3_stop(struct ioc3_private *ip)
-{
- struct ioc3 *ioc3 = ip->regs;
-
- ioc3_w_emcr(0); /* Shutup */
- ioc3_w_eier(0); /* Disable interrupts */
- (void) ioc3_r_eier(); /* Flush */
+ ip->emcr |= ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) |
+ EMCR_TXDMAEN | EMCR_TXEN |
+ EMCR_RXDMAEN | EMCR_RXEN |
+ EMCR_PADEN;
+ writel(ip->emcr, ®s->emcr);
+ readl(®s->emcr);
+ writel(EISR_RXTIMERINT | EISR_RXTHRESHINT |
+ EISR_RXOFLO | EISR_RXBUFOFLO |
+ EISR_RXMEMERR | EISR_RXPARERR |
+ EISR_TXEXDEF |
+ EISR_TXBUFUFLO |
+ EISR_TXMEMERR, ®s->eier);
+ readl(®s->eier);
}
static int ioc3_open(struct net_device *dev)
{
struct ioc3_private *ip = netdev_priv(dev);
- if (request_irq(dev->irq, ioc3_interrupt, IRQF_SHARED, ioc3_str, dev)) {
- printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq);
-
- return -EAGAIN;
- }
-
ip->ehar_h = 0;
ip->ehar_l = 0;
ioc3_init(dev);
+ ioc3_mii_init(ip);
ioc3_mii_start(ip);
-
netif_start_queue(dev);
+
return 0;
}
@@ -1061,444 +609,152 @@ static int ioc3_close(struct net_device *dev)
netif_stop_queue(dev);
ioc3_stop(ip);
- free_irq(dev->irq, dev);
+ ioc3_free_rings(ip);
ioc3_free_rings(ip);
return 0;
}
-/*
- * MENET cards have four IOC3 chips, which are attached to two sets of
- * PCI slot resources each: the primary connections are on slots
- * 0..3 and the secondaries are on 4..7
- *
- * All four ethernets are brought out to connectors; six serial ports
- * (a pair from each of the first three IOC3s) are brought out to
- * MiniDINs; all other subdevices are left swinging in the wind, leave
- * them disabled.
- */
-
-static int ioc3_adjacent_is_ioc3(struct pci_dev *pdev, int slot)
+static netdev_tx_t ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct pci_dev *dev = pci_get_slot(pdev->bus, PCI_DEVFN(slot, 0));
- int ret = 0;
-
- if (dev) {
- if (dev->vendor == PCI_VENDOR_ID_SGI &&
- dev->device == PCI_DEVICE_ID_SGI_IOC3)
- ret = 1;
- pci_dev_put(dev);
- }
-
- return ret;
-}
+ struct ioc3_private *ip = netdev_priv(dev);
+ struct ioc3_etxd *desc;
+ unsigned long data;
+ u32 len, w0 = 0;
+ int produce;
-static int ioc3_is_menet(struct pci_dev *pdev)
-{
- return pdev->bus->parent == NULL &&
- ioc3_adjacent_is_ioc3(pdev, 0) &&
- ioc3_adjacent_is_ioc3(pdev, 1) &&
- ioc3_adjacent_is_ioc3(pdev, 2);
-}
+ /* IOC3 has a fairly simple minded checksumming hardware which simply
+ * adds up the 1's complement checksum for the entire packet and
+ * inserts it at an offset which can be specified in the descriptor
+ * into the transmit packet. This means we have to compensate for the
+ * MAC header which should not be summed and the TCP/UDP pseudo headers
+ * manually.
+ */
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ struct iphdr *ih = ip_hdr(skb);
+ u32 proto = ntohs(ih->protocol);
+ u32 csoff, csum, ehsum;
+ u16 *eh;
-#ifdef CONFIG_SERIAL_8250
-/*
- * Note about serial ports and consoles:
- * For console output, everyone uses the IOC3 UARTA (offset 0x178)
- * connected to the master node (look in ip27_setup_console() and
- * ip27prom_console_write()).
- *
- * For serial (/dev/ttyS0 etc), we can not have hardcoded serial port
- * addresses on a partitioned machine. Since we currently use the ioc3
- * serial ports, we use dynamic serial port discovery that the serial.c
- * driver uses for pci/pnp ports (there is an entry for the SGI ioc3
- * boards in pci_boards[]). Unfortunately, UARTA's pio address is greater
- * than UARTB's, although UARTA on o200s has traditionally been known as
- * port 0. So, we just use one serial port from each ioc3 (since the
- * serial driver adds addresses to get to higher ports).
- *
- * The first one to do a register_console becomes the preferred console
- * (if there is no kernel command line console= directive). /dev/console
- * (ie 5, 1) is then "aliased" into the device number returned by the
- * "device" routine referred to in this console structure
- * (ip27prom_console_dev).
- *
- * Also look in ip27-pci.c:pci_fixup_ioc3() for some comments on working
- * around ioc3 oddities in this respect.
- *
- * The IOC3 serials use a 22MHz clock rate with an additional divider which
- * can be programmed in the SCR register if the DLAB bit is set.
- *
- * Register to interrupt zero because we share the interrupt with
- * the serial driver which we don't properly support yet.
- *
- * Can't use UPF_IOREMAP as the whole of IOC3 resources have already been
- * registered.
- */
-static void ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
-{
-#define COSMISC_CONSTANT 6
-
- struct uart_8250_port port = {
- .port = {
- .irq = 0,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 0,
- .uartclk = (22000000 << 1) / COSMISC_CONSTANT,
-
- .membase = (unsigned char __iomem *) uart,
- .mapbase = (unsigned long) uart,
- }
- };
- unsigned char lcr;
-
- lcr = uart->iu_lcr;
- uart->iu_lcr = lcr | UART_LCR_DLAB;
- uart->iu_scr = COSMISC_CONSTANT,
- uart->iu_lcr = lcr;
- uart->iu_lcr;
- serial8250_register_8250_port(&port);
-}
+ /* The MAC header. skb->mac seems the logical approach
+ * to find the MAC header. Except if it's a NULL pointer...
+ */
+ eh = (u16 *)skb->data;
-static void ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
-{
- /*
- * We need to recognice and treat the fourth MENET serial as it
- * does not have an SuperIO chip attached to it, therefore attempting
- * to access it will result in bus errors. We call something an
- * MENET if PCI slot 0, 1, 2 and 3 of a master PCI bus all have an IOC3
- * in it. This is paranoid but we want to avoid blowing up on a
- * showhorn PCI box that happens to have 4 IOC3 cards in it so it's
- * not paranoid enough ...
- */
- if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3)
- return;
+ /* Sum up dest addr, src addr and protocol */
+ ehsum = eh[0] + eh[1] + eh[2] + eh[3] + eh[4] + eh[5] + eh[6];
- /*
- * Switch IOC3 to PIO mode. It probably already was but let's be
- * paranoid
- */
- ioc3->gpcr_s = GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL;
- ioc3->gpcr_s;
- ioc3->gppr_6 = 0;
- ioc3->gppr_6;
- ioc3->gppr_7 = 0;
- ioc3->gppr_7;
- ioc3->sscr_a = ioc3->sscr_a & ~SSCR_DMA_EN;
- ioc3->sscr_a;
- ioc3->sscr_b = ioc3->sscr_b & ~SSCR_DMA_EN;
- ioc3->sscr_b;
- /* Disable all SA/B interrupts except for SA/B_INT in SIO_IEC. */
- ioc3->sio_iec &= ~ (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL |
- SIO_IR_SA_RX_HIGH | SIO_IR_SA_RX_TIMER |
- SIO_IR_SA_DELTA_DCD | SIO_IR_SA_DELTA_CTS |
- SIO_IR_SA_TX_EXPLICIT | SIO_IR_SA_MEMERR);
- ioc3->sio_iec |= SIO_IR_SA_INT;
- ioc3->sscr_a = 0;
- ioc3->sio_iec &= ~ (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL |
- SIO_IR_SB_RX_HIGH | SIO_IR_SB_RX_TIMER |
- SIO_IR_SB_DELTA_DCD | SIO_IR_SB_DELTA_CTS |
- SIO_IR_SB_TX_EXPLICIT | SIO_IR_SB_MEMERR);
- ioc3->sio_iec |= SIO_IR_SB_INT;
- ioc3->sscr_b = 0;
-
- ioc3_8250_register(&ioc3->sregs.uarta);
- ioc3_8250_register(&ioc3->sregs.uartb);
-}
-#endif
+ /* Skip IP header; it's sum is always zero and was already
+ * filled in by ip_output.c
+ */
+ csum = csum_tcpudp_nofold(ih->saddr, ih->daddr,
+ ih->tot_len - (ih->ihl << 2),
+ proto, csum_fold(ehsum));
-static const struct net_device_ops ioc3_netdev_ops = {
- .ndo_open = ioc3_open,
- .ndo_stop = ioc3_close,
- .ndo_start_xmit = ioc3_start_xmit,
- .ndo_tx_timeout = ioc3_timeout,
- .ndo_get_stats = ioc3_get_stats,
- .ndo_set_rx_mode = ioc3_set_multicast_list,
- .ndo_do_ioctl = ioc3_ioctl,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = ioc3_set_mac_address,
-};
+ csum = (csum & 0xffff) + (csum >> 16); /* Fold again */
+ csum = (csum & 0xffff) + (csum >> 16);
-static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- unsigned int sw_physid1, sw_physid2;
- struct net_device *dev = NULL;
- struct ioc3_private *ip;
- struct ioc3 *ioc3;
- unsigned long ioc3_base, ioc3_size;
- u32 vendor, model, rev;
- int err, pci_using_dac;
-
- /* Configure DMA attributes. */
- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
- if (!err) {
- pci_using_dac = 1;
- err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
- if (err < 0) {
- printk(KERN_ERR "%s: Unable to obtain 64 bit DMA "
- "for consistent allocations\n", pci_name(pdev));
- goto out;
+ csoff = ETH_HLEN + (ih->ihl << 2);
+ if (proto == IPPROTO_UDP) {
+ csoff += offsetof(struct udphdr, check);
+ udp_hdr(skb)->check = csum;
}
- } else {
- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (err) {
- printk(KERN_ERR "%s: No usable DMA configuration, "
- "aborting.\n", pci_name(pdev));
- goto out;
+ if (proto == IPPROTO_TCP) {
+ csoff += offsetof(struct tcphdr, check);
+ tcp_hdr(skb)->check = csum;
}
- pci_using_dac = 0;
+
+ w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT);
}
- if (pci_enable_device(pdev))
- return -ENODEV;
+ spin_lock_irq(&ip->ioc3_lock);
- dev = alloc_etherdev(sizeof(struct ioc3_private));
- if (!dev) {
- err = -ENOMEM;
- goto out_disable;
+ if (ip->txbfree <= 0) {
+ netif_stop_queue(dev);
+ spin_unlock_irq(&ip->ioc3_lock);
+ printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
+ dev->name);
+ return NETDEV_TX_BUSY;
}
- if (pci_using_dac)
- dev->features |= NETIF_F_HIGHDMA;
+ data = (unsigned long)skb->data;
+ len = skb->len;
- err = pci_request_regions(pdev, "ioc3");
- if (err)
- goto out_free;
+ produce = ip->tx_pi;
+ desc = &ip->txr[produce];
- SET_NETDEV_DEV(dev, &pdev->dev);
+ if (len <= 104) {
+ /* Short packet, let's copy it directly into the ring. */
+ skb_copy_from_linear_data(skb, desc->data, skb->len);
+ if (len < ETH_ZLEN) {
+ /* Very short packet, pad with zeros at the end. */
+ memset(desc->data + len, 0, ETH_ZLEN - len);
+ len = ETH_ZLEN;
+ }
+ desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_D0V | w0);
+ desc->bufcnt = cpu_to_be32(len);
+ } else if ((data ^ (data + len - 1)) & 0x4000) {
+ unsigned long b2 = (data | 0x3fffUL) + 1UL;
+ unsigned long s1 = b2 - data;
+ unsigned long s2 = data + len - b2;
- ip = netdev_priv(dev);
- ip->dev = dev;
-
- dev->irq = pdev->irq;
-
- ioc3_base = pci_resource_start(pdev, 0);
- ioc3_size = pci_resource_len(pdev, 0);
- ioc3 = (struct ioc3 *) ioremap(ioc3_base, ioc3_size);
- if (!ioc3) {
- printk(KERN_CRIT "ioc3eth(%s): ioremap failed, goodbye.\n",
- pci_name(pdev));
- err = -ENOMEM;
- goto out_res;
+ desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE |
+ ETXD_B1V | ETXD_B2V | w0);
+ desc->bufcnt = cpu_to_be32((s1 << ETXD_B1CNT_SHIFT) |
+ (s2 << ETXD_B2CNT_SHIFT));
+ desc->p1 = cpu_to_be64(ioc3_map(skb->data,
+ PCI64_ATTR_PREF));
+ desc->p2 = cpu_to_be64(ioc3_map((void *)b2,
+ PCI64_ATTR_PREF));
+ } else {
+ /* Normal sized packet that doesn't cross a page boundary. */
+ desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_B1V | w0);
+ desc->bufcnt = cpu_to_be32(len << ETXD_B1CNT_SHIFT);
+ desc->p1 = cpu_to_be64(ioc3_map(skb->data,
+ PCI64_ATTR_PREF));
}
- ip->regs = ioc3;
-#ifdef CONFIG_SERIAL_8250
- ioc3_serial_probe(pdev, ioc3);
-#endif
+ mb(); /* make sure all descriptor changes are visible */
- spin_lock_init(&ip->ioc3_lock);
- timer_setup(&ip->ioc3_timer, ioc3_timer, 0);
+ ip->tx_skbs[produce] = skb; /* Remember skb */
+ produce = (produce + 1) & TX_MASK;
+ ip->tx_pi = produce;
+ writel(produce << 7, &ip->regs->etpir); /* Fire! */
- ioc3_stop(ip);
- ioc3_init(dev);
-
- ip->pdev = pdev;
-
- ip->mii.phy_id_mask = 0x1f;
- ip->mii.reg_num_mask = 0x1f;
- ip->mii.dev = dev;
- ip->mii.mdio_read = ioc3_mdio_read;
- ip->mii.mdio_write = ioc3_mdio_write;
-
- ioc3_mii_init(ip);
-
- if (ip->mii.phy_id == -1) {
- printk(KERN_CRIT "ioc3-eth(%s): Didn't find a PHY, goodbye.\n",
- pci_name(pdev));
- err = -ENODEV;
- goto out_stop;
- }
-
- ioc3_mii_start(ip);
- ioc3_ssram_disc(ip);
- ioc3_get_eaddr(ip);
-
- /* The IOC3-specific entries in the device structure. */
- dev->watchdog_timeo = 5 * HZ;
- dev->netdev_ops = &ioc3_netdev_ops;
- dev->ethtool_ops = &ioc3_ethtool_ops;
- dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
- dev->features = NETIF_F_IP_CSUM;
-
- sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1);
- sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2);
-
- err = register_netdev(dev);
- if (err)
- goto out_stop;
-
- mii_check_media(&ip->mii, 1, 1);
- ioc3_setup_duplex(ip);
-
- vendor = (sw_physid1 << 12) | (sw_physid2 >> 4);
- model = (sw_physid2 >> 4) & 0x3f;
- rev = sw_physid2 & 0xf;
- printk(KERN_INFO "%s: Using PHY %d, vendor 0x%x, model %d, "
- "rev %d.\n", dev->name, ip->mii.phy_id, vendor, model, rev);
- printk(KERN_INFO "%s: IOC3 SSRAM has %d kbyte.\n", dev->name,
- ip->emcr & EMCR_BUFSIZ ? 128 : 64);
+ ip->txbfree--;
+ if (ip->txbfree == 0)
+ netif_stop_queue(dev);
- return 0;
+ spin_unlock_irq(&ip->ioc3_lock);
-out_stop:
- ioc3_stop(ip);
- del_timer_sync(&ip->ioc3_timer);
- ioc3_free_rings(ip);
-out_res:
- pci_release_regions(pdev);
-out_free:
- free_netdev(dev);
-out_disable:
- /*
- * We should call pci_disable_device(pdev); here if the IOC3 wasn't
- * such a weird device ...
- */
-out:
- return err;
+ return NETDEV_TX_OK;
}
-static void ioc3_remove_one(struct pci_dev *pdev)
+static int ioc3_set_mac_address(struct net_device *dev, void *addr)
{
- struct net_device *dev = pci_get_drvdata(pdev);
struct ioc3_private *ip = netdev_priv(dev);
- struct ioc3 *ioc3 = ip->regs;
-
- unregister_netdev(dev);
- del_timer_sync(&ip->ioc3_timer);
+ struct ioc3_ethregs *regs = ip->regs;
+ struct sockaddr *sa = addr;
- iounmap(ioc3);
- pci_release_regions(pdev);
- free_netdev(dev);
- /*
- * We should call pci_disable_device(pdev); here if the IOC3 wasn't
- * such a weird device ...
- */
-}
+ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
-static const struct pci_device_id ioc3_pci_tbl[] = {
- { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, ioc3_pci_tbl);
+ spin_lock_irq(&ip->ioc3_lock);
+ __ioc3_set_mac_address(dev, regs);
+ spin_unlock_irq(&ip->ioc3_lock);
-static struct pci_driver ioc3_driver = {
- .name = "ioc3-eth",
- .id_table = ioc3_pci_tbl,
- .probe = ioc3_probe,
- .remove = ioc3_remove_one,
-};
+ return 0;
+}
-static netdev_tx_t ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- unsigned long data;
struct ioc3_private *ip = netdev_priv(dev);
- struct ioc3 *ioc3 = ip->regs;
- unsigned int len;
- struct ioc3_etxd *desc;
- uint32_t w0 = 0;
- int produce;
-
- /*
- * IOC3 has a fairly simple minded checksumming hardware which simply
- * adds up the 1's complement checksum for the entire packet and
- * inserts it at an offset which can be specified in the descriptor
- * into the transmit packet. This means we have to compensate for the
- * MAC header which should not be summed and the TCP/UDP pseudo headers
- * manually.
- */
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- const struct iphdr *ih = ip_hdr(skb);
- const int proto = ntohs(ih->protocol);
- unsigned int csoff;
- uint32_t csum, ehsum;
- uint16_t *eh;
-
- /* The MAC header. skb->mac seem the logic approach
- to find the MAC header - except it's a NULL pointer ... */
- eh = (uint16_t *) skb->data;
-
- /* Sum up dest addr, src addr and protocol */
- ehsum = eh[0] + eh[1] + eh[2] + eh[3] + eh[4] + eh[5] + eh[6];
-
- /* Fold ehsum. can't use csum_fold which negates also ... */
- ehsum = (ehsum & 0xffff) + (ehsum >> 16);
- ehsum = (ehsum & 0xffff) + (ehsum >> 16);
-
- /* Skip IP header; it's sum is always zero and was
- already filled in by ip_output.c */
- csum = csum_tcpudp_nofold(ih->saddr, ih->daddr,
- ih->tot_len - (ih->ihl << 2),
- proto, 0xffff ^ ehsum);
-
- csum = (csum & 0xffff) + (csum >> 16); /* Fold again */
- csum = (csum & 0xffff) + (csum >> 16);
-
- csoff = ETH_HLEN + (ih->ihl << 2);
- if (proto == IPPROTO_UDP) {
- csoff += offsetof(struct udphdr, check);
- udp_hdr(skb)->check = csum;
- }
- if (proto == IPPROTO_TCP) {
- csoff += offsetof(struct tcphdr, check);
- tcp_hdr(skb)->check = csum;
- }
-
- w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT);
- }
+ int rc;
spin_lock_irq(&ip->ioc3_lock);
-
- data = (unsigned long) skb->data;
- len = skb->len;
-
- produce = ip->tx_pi;
- desc = &ip->txr[produce];
-
- if (len <= 104) {
- /* Short packet, let's copy it directly into the ring. */
- skb_copy_from_linear_data(skb, desc->data, skb->len);
- if (len < ETH_ZLEN) {
- /* Very short packet, pad with zeros at the end. */
- memset(desc->data + len, 0, ETH_ZLEN - len);
- len = ETH_ZLEN;
- }
- desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_D0V | w0);
- desc->bufcnt = cpu_to_be32(len);
- } else if ((data ^ (data + len - 1)) & 0x4000) {
- unsigned long b2 = (data | 0x3fffUL) + 1UL;
- unsigned long s1 = b2 - data;
- unsigned long s2 = data + len - b2;
-
- desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE |
- ETXD_B1V | ETXD_B2V | w0);
- desc->bufcnt = cpu_to_be32((s1 << ETXD_B1CNT_SHIFT) |
- (s2 << ETXD_B2CNT_SHIFT));
- desc->p1 = cpu_to_be64(ioc3_map(skb->data, 1));
- desc->p2 = cpu_to_be64(ioc3_map((void *) b2, 1));
- } else {
- /* Normal sized packet that doesn't cross a page boundary. */
- desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_B1V | w0);
- desc->bufcnt = cpu_to_be32(len << ETXD_B1CNT_SHIFT);
- desc->p1 = cpu_to_be64(ioc3_map(skb->data, 1));
- }
-
- BARRIER();
-
- ip->tx_skbs[produce] = skb; /* Remember skb */
- produce = (produce + 1) & 127;
- ip->tx_pi = produce;
- ioc3_w_etpir(produce << 7); /* Fire ... */
-
- ip->txqlen++;
-
- if (ip->txqlen >= 127)
- netif_stop_queue(dev);
-
+ rc = generic_mii_ioctl(&ip->mii, if_mii(rq), cmd, NULL);
spin_unlock_irq(&ip->ioc3_lock);
- return NETDEV_TX_OK;
+ return rc;
}
static void ioc3_timeout(struct net_device *dev)
@@ -1507,49 +763,42 @@ static void ioc3_timeout(struct net_device *dev)
printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
- spin_lock_irq(&ip->ioc3_lock);
-
ioc3_stop(ip);
ioc3_init(dev);
ioc3_mii_init(ip);
ioc3_mii_start(ip);
- spin_unlock_irq(&ip->ioc3_lock);
-
netif_wake_queue(dev);
}
-/*
- * Given a multicast ethernet address, this routine calculates the
- * address's bit index in the logical address filter mask
- */
-
-static inline unsigned int ioc3_hash(const unsigned char *addr)
+static struct net_device_stats *ioc3_get_stats(struct net_device *dev)
{
- unsigned int temp = 0;
- u32 crc;
- int bits;
-
- crc = ether_crc_le(ETH_ALEN, addr);
-
- crc &= 0x3f; /* bit reverse lowest 6 bits for hash index */
- for (bits = 6; --bits >= 0; ) {
- temp <<= 1;
- temp |= (crc & 0x1);
- crc >>= 1;
- }
+ struct ioc3_private *ip = netdev_priv(dev);
+ struct ioc3_ethregs *regs = ip->regs;
- return temp;
+ dev->stats.collisions += (readl(®s->etcdc) & ETCDC_COLLCNT_MASK);
+ return &dev->stats;
}
-static void ioc3_get_drvinfo (struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct ioc3_private *ip = netdev_priv(dev);
+static const struct net_device_ops ioc3_netdev_ops = {
+ .ndo_open = ioc3_open,
+ .ndo_stop = ioc3_close,
+ .ndo_start_xmit = ioc3_start_xmit,
+ .ndo_tx_timeout = ioc3_timeout,
+ .ndo_get_stats = ioc3_get_stats,
+ .ndo_set_rx_mode = ioc3_set_multicast_list,
+ .ndo_do_ioctl = ioc3_ioctl,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = ioc3_set_mac_address,
+};
+static void ioc3_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
strlcpy(info->driver, IOC3_NAME, sizeof(info->driver));
strlcpy(info->version, IOC3_VERSION, sizeof(info->version));
- strlcpy(info->bus_info, pci_name(ip->pdev), sizeof(info->bus_info));
+ strlcpy(info->bus_info, pci_name(to_pci_dev(dev->dev.parent)),
+ sizeof(info->bus_info));
}
static int ioc3_get_link_ksettings(struct net_device *dev,
@@ -1609,58 +858,359 @@ static const struct ethtool_ops ioc3_ethtool_ops = {
.set_link_ksettings = ioc3_set_link_ksettings,
};
-static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+/* Deal with fatal IOC3 errors. This condition might be caused by a hard or
+ * software problems, so we should try to recover
+ * more gracefully if this ever happens. In theory we might be flooded
+ * with such error interrupts if something really goes wrong, so we might
+ * also consider to take the interface down.
+ */
+static noinline void ioc3_error(struct ioc3_private *ip,
+ struct net_device *dev, u32 eisr)
{
- struct ioc3_private *ip = netdev_priv(dev);
- int rc;
+ u8 *iface = dev->name;
- spin_lock_irq(&ip->ioc3_lock);
- rc = generic_mii_ioctl(&ip->mii, if_mii(rq), cmd, NULL);
- spin_unlock_irq(&ip->ioc3_lock);
+ if (eisr & EISR_RXOFLO)
+ printk(KERN_ERR "%s: RX overflow.\n", iface);
+ if (eisr & EISR_RXBUFOFLO)
+ printk(KERN_ERR "%s: RX buffer overflow.\n", iface);
+ if (eisr & EISR_RXMEMERR)
+ printk(KERN_ERR "%s: RX PCI error.\n", iface);
+ if (eisr & EISR_RXPARERR)
+ printk(KERN_ERR "%s: RX SSRAM parity error.\n", iface);
+ if (eisr & EISR_TXBUFUFLO)
+ printk(KERN_ERR "%s: TX buffer underflow.\n", iface);
+ if (eisr & EISR_TXMEMERR)
+ printk(KERN_ERR "%s: TX PCI error.\n", iface);
- return rc;
+ ioc3_stop(ip);
+
+ /* This can trigger a BUG(): sleeping function called */
+ ioc3_init(dev);
+ ioc3_mii_init(ip);
+ ioc3_mii_start(ip);
+
+ netif_wake_queue(dev);
}
-static void ioc3_set_multicast_list(struct net_device *dev)
+static noinline void ioc3_rx(struct ioc3_private *ip, struct net_device *dev)
{
- struct netdev_hw_addr *ha;
- struct ioc3_private *ip = netdev_priv(dev);
- struct ioc3 *ioc3 = ip->regs;
- u64 ehar = 0;
+ struct sk_buff *skb, *new_skb;
+ struct ioc3_erxbuf *rxb;
+ int rx_entry, n_entry, len;
+ u32 w0, err;
- netif_stop_queue(dev); /* Lock out others. */
+ rx_entry = ip->rx_ci; /* RX consume index */
+ n_entry = ip->rx_pi;
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- ip->emcr |= EMCR_PROMISC;
- ioc3_w_emcr(ip->emcr);
- (void) ioc3_r_emcr();
- } else {
- ip->emcr &= ~EMCR_PROMISC;
- ioc3_w_emcr(ip->emcr); /* Clear promiscuous. */
- (void) ioc3_r_emcr();
+ skb = ip->rx_skbs[rx_entry];
+ rxb = (struct ioc3_erxbuf *)(skb->data - RX_OFFSET);
+ w0 = be32_to_cpu(rxb->w0);
- if ((dev->flags & IFF_ALLMULTI) ||
- (netdev_mc_count(dev) > 64)) {
- /* Too many for hashing to make sense or we want all
- multicast packets anyway, so skip computing all the
- hashes and just accept all packets. */
- ip->ehar_h = 0xffffffff;
- ip->ehar_l = 0xffffffff;
- } else {
- netdev_for_each_mc_addr(ha, dev) {
- ehar |= (1UL << ioc3_hash(ha->addr));
+ while (w0 & ERXBUF_V) {
+ err = be32_to_cpu(rxb->err); /* It's valid */
+ if (err & ERXBUF_GOODPKT) {
+ len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4;
+ skb_trim(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
+
+ new_skb = ioc3_alloc_skb(dev);
+ if (!new_skb) {
+ /* Ouch, drop packet and just recycle packet
+ * to keep the ring filled.
+ */
+ dev->stats.rx_dropped++;
+ new_skb = skb;
+ goto next;
}
- ip->ehar_h = ehar >> 32;
- ip->ehar_l = ehar & 0xffffffff;
+
+ if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS))
+ ioc3_tcpudp_checksum(skb,
+ (w0 & ERXBUF_IPCKSUM_MASK),
+ len);
+
+ netif_rx(skb);
+
+ ip->rx_skbs[rx_entry] = NULL; /* Poison */
+
+ /* Because we reserve afterwards. */
+ skb_put(new_skb, (RX_BUF_SIZE + RX_OFFSET));
+ rxb = (struct ioc3_erxbuf *)new_skb->data;
+ skb_reserve(new_skb, RX_OFFSET);
+
+ dev->stats.rx_packets++; /* Statistics */
+ dev->stats.rx_bytes += len;
+ } else {
+ /* The frame is invalid and the skb never reached the
+ * network layer so we can just recycle it.
+ */
+ new_skb = skb;
+ dev->stats.rx_errors++;
}
- ioc3_w_ehar_h(ip->ehar_h);
- ioc3_w_ehar_l(ip->ehar_l);
+
+ /* Statistics */
+ if (err & ERXBUF_CRCERR)
+ dev->stats.rx_crc_errors++;
+ if (err & ERXBUF_FRAMERR)
+ dev->stats.rx_frame_errors++;
+next:
+ ip->rx_skbs[rx_entry] = new_skb;
+ ip->rxr[rx_entry] = cpu_to_be64(ioc3_map(rxb, PCI64_ATTR_BAR));
+ rxb->w0 = 0; /* Clear valid flag */
+
+ /* Now go on to the next ring entry. */
+ n_entry++;
+ n_entry &= RX_MASK;
+ rx_entry++;
+ rx_entry &= RX_MASK;
+
+ skb = ip->rx_skbs[rx_entry];
+ rxb = (struct ioc3_erxbuf *)(skb->data - RX_OFFSET);
+ w0 = be32_to_cpu(rxb->w0);
}
+ ip->rx_ci = rx_entry;
+ ip->rx_pi = n_entry;
+ writel((n_entry << 3) | ERPIR_ARM, &ip->regs->erpir);
+}
+
+static noinline void ioc3_tx(struct ioc3_private *ip, struct net_device *dev)
+{
+ struct sk_buff *skb;
+ struct ioc3_ethregs *regs = ip->regs;
+ unsigned long packets = 0;
+ unsigned long bytes = 0;
+ int tx_entry, o_entry;
+ u32 etcir;
+
+ etcir = readl(®s->etcir);
+ tx_entry = (etcir >> 7) & TX_MASK;
+ o_entry = ip->tx_ci;
+
+ while (o_entry != tx_entry) {
+ packets++;
+ skb = ip->tx_skbs[o_entry];
+ bytes += skb->len;
+ dev_consume_skb_irq(skb);
+ ip->tx_skbs[o_entry] = NULL;
+
+ etcir = readl(®s->etcir); /* More pkts sent? */
+ tx_entry = (etcir >> 7) & TX_MASK;
+ o_entry = (o_entry + 1) & TX_MASK; /* Next */
+ }
+ ip->tx_ci = o_entry;
+
+ dev->stats.tx_bytes += bytes;
+ dev->stats.tx_packets += packets;
+ ip->txbfree += packets;
+
+ if (netif_queue_stopped(dev) && ip->txbfree > 0)
+ netif_wake_queue(dev);
+}
+
+/* The interrupt handler does all of the Rx thread work
+ * and cleans up after the Tx thread.
+ */
+static irqreturn_t ioc3eth_intr(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct ioc3_private *ip = netdev_priv(dev);
+ struct ioc3_ethregs *regs = ip->regs;
+ u32 eisr;
+
+ spin_lock(&ip->ioc3_lock);
+
+ eisr = readl(®s->eisr);
+
+ writel(eisr, ®s->eisr);
+ (void)readl(®s->eisr); /* Flush */
+
+ if (eisr & (EISR_RXTIMERINT | EISR_RXTHRESHINT))
+ ioc3_rx(ip, dev);
+
+ if (eisr & (EISR_TXEMPTY | EISR_TXEXDEF | EISR_TXEXPLICIT))
+ ioc3_tx(ip, dev);
+
+ if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO |
+ EISR_RXMEMERR | EISR_RXPARERR |
+ EISR_TXBUFUFLO | EISR_TXMEMERR))
+ ioc3_error(ip, dev, eisr);
+
+ spin_unlock(&ip->ioc3_lock);
- netif_wake_queue(dev); /* Let us get going again. */
+ return eisr ? IRQ_HANDLED : IRQ_NONE;
}
-module_pci_driver(ioc3_driver);
+static int ioc3eth_nvmem_match(struct device *dev, void *data)
+{
+ const char *name = dev_name(dev);
+ const char *prefix = data;
+ int prefix_len;
+
+ prefix_len = strlen(prefix);
+ if (strlen(name) < (prefix_len + 3))
+ return 0;
+
+ if (memcmp(prefix, name, prefix_len) != 0)
+ return 0;
+
+ /* found nvmem device which is attached to our ioc3
+ * now check for one wire family code 09, 89 and 91
+ */
+ if (memcmp(name + prefix_len, "09-", 3) == 0)
+ return 1;
+ if (memcmp(name + prefix_len, "89-", 3) == 0)
+ return 1;
+ if (memcmp(name + prefix_len, "91-", 3) == 0)
+ return 1;
+
+ return 0;
+}
+
+static int ioc3eth_get_mac_addr(struct resource *res, u8 mac_addr[6])
+{
+ struct nvmem_device *nvmem;
+ char prefix[24];
+ u8 prom[16];
+ int ret;
+ int i;
+
+ snprintf(prefix, sizeof(prefix), "ioc3-%012llx-",
+ res->start & ~0xffff);
+
+ nvmem = nvmem_device_find(prefix, ioc3eth_nvmem_match);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
+
+ ret = nvmem_device_read(nvmem, 0, 16, prom);
+ nvmem_device_put(nvmem);
+ if (ret < 0)
+ return ret;
+
+ /* check, if content is valid */
+ if (prom[0] != 0x0a ||
+ crc16(CRC16_INIT, prom, 13) != CRC16_VALID)
+ return -EINVAL;
+
+ for (i = 0; i < 6; i++)
+ mac_addr[i] = prom[10 - i];
+
+ return 0;
+}
+
+static int ioc3eth_probe(struct platform_device *pdev)
+{
+ u32 sw_physid1, sw_physid2, vendor, model, rev;
+ struct resource *regs, *sram;
+ struct ioc3_private *ip;
+ struct net_device *dev;
+ u8 mac_addr[6];
+ int err;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ /* get mac addr from one wire prom */
+ if (ioc3eth_get_mac_addr(regs, mac_addr))
+ return -EPROBE_DEFER; /* not available yet */
+
+ dev = alloc_etherdev(sizeof(struct ioc3_private));
+ if (!dev)
+ return -ENOMEM;
+
+ /* The IOC3-specific entries in the device structure. */
+ dev->watchdog_timeo = 5 * HZ;
+ dev->netdev_ops = &ioc3_netdev_ops;
+ dev->ethtool_ops = &ioc3_ethtool_ops;
+ dev->features = NETIF_F_IP_CSUM | NETIF_F_HIGHDMA;
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ ip = netdev_priv(dev);
+ ip->regs = ioremap(regs->start, resource_size(regs));
+ sram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ ip->ssram = ioremap(sram->start, resource_size(sram));
+
+ dev->irq = platform_get_irq(pdev, 0);
+ if (dev->irq < 0)
+ return dev->irq;
+
+ if (request_irq(dev->irq, ioc3eth_intr, IRQF_SHARED, "ioc3-eth", dev)) {
+ pr_err("%s: Can't get irq %d\n", dev->name, dev->irq);
+ return -ENODEV;
+ }
+
+ spin_lock_init(&ip->ioc3_lock);
+ timer_setup(&ip->ioc3_timer, ioc3_timer, 0);
+
+ ioc3_stop(ip);
+ ioc3_init(dev);
+
+ ip->mii.phy_id_mask = 0x1f;
+ ip->mii.reg_num_mask = 0x1f;
+ ip->mii.dev = dev;
+ ip->mii.mdio_read = ioc3_mdio_read;
+ ip->mii.mdio_write = ioc3_mdio_write;
+
+ ioc3_mii_init(ip);
+
+ if (ip->mii.phy_id == -1) {
+ printk(KERN_CRIT "ioc3-eth(%s): Didn't find a PHY, goodbye.\n",
+ dev->name);
+ err = -ENODEV;
+ goto out_stop;
+ }
+
+ ioc3_mii_start(ip);
+ ioc3_ssram_disc(ip);
+ memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
+
+ sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1);
+ sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2);
+
+ err = register_netdev(dev);
+ if (err)
+ goto out_stop;
+
+ mii_check_media(&ip->mii, 1, 1);
+ ioc3_setup_duplex(ip);
+
+ vendor = (sw_physid1 << 12) | (sw_physid2 >> 4);
+ model = (sw_physid2 >> 4) & 0x3f;
+ rev = sw_physid2 & 0xf;
+ printk(KERN_INFO "%s: Using PHY %d, vendor 0x%x, model %d, rev %d.\n",
+ dev->name, ip->mii.phy_id, vendor, model, rev);
+ printk(KERN_INFO "%s: IOC3 SSRAM has %d kbyte.\n", dev->name,
+ (ip->emcr & EMCR_BUFSIZ ? 128 : 64));
+
+ return 0;
+
+out_stop:
+ ioc3_stop(ip);
+ del_timer_sync(&ip->ioc3_timer);
+ ioc3_free_rings(ip);
+ free_netdev(dev);
+ return err;
+}
+
+static int ioc3eth_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct ioc3_private *ip = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ del_timer_sync(&ip->ioc3_timer);
+ ioc3_free_rings(ip);
+ free_netdev(dev);
+
+ return 0;
+}
+
+static struct platform_driver ioc3eth_driver = {
+ .probe = ioc3eth_probe,
+ .remove = ioc3eth_remove,
+ .driver = {
+ .name = "ioc3-eth",
+ }
+};
+
+module_platform_driver(ioc3eth_driver);
+
MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
MODULE_DESCRIPTION("SGI IOC3 Ethernet driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c
new file mode 100644
index 000000000000..2be6ed2967e0
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_ioc3.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SGI IOC3 8250 UART driver
+ *
+ * Copyright (C) 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de>
+ *
+ * based on code Copyright (C) 2005 Stanislaw Skowronek <skylark@unaligned.org>
+ * Copyright (C) 2014 Joshua Kinard <kumba@gentoo.org>
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include "8250.h"
+
+#define IOC3_UARTCLK (22000000 / 3)
+
+struct ioc3_8250_data {
+ int line;
+};
+
+static unsigned int ioc3_serial_in(struct uart_port *p, int offset)
+{
+ return readb(p->membase + offset);
+}
+
+static void ioc3_serial_out(struct uart_port *p, int offset, int value)
+{
+ writeb(value, p->membase + offset);
+}
+
+static int serial8250_ioc3_probe(struct platform_device *pdev)
+{
+ struct ioc3_8250_data *data;
+ struct uart_8250_port up;
+ struct resource *r;
+ void __iomem *membase;
+ int irq, line;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ membase = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r));
+ if (!membase)
+ return -ENOMEM;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ irq = 0; /* no interrupt -> use polling */
+
+ /* Register serial ports with 8250.c */
+ memset(&up, 0, sizeof(struct uart_8250_port));
+ up.port.iotype = UPIO_MEM;
+ up.port.uartclk = IOC3_UARTCLK;
+ up.port.type = PORT_16550A;
+ up.port.irq = irq;
+ up.port.flags = (UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ);
+ up.port.dev = &pdev->dev;
+ up.port.membase = membase;
+ up.port.mapbase = r->start;
+ up.port.serial_in = ioc3_serial_in;
+ up.port.serial_out = ioc3_serial_out;
+ line = serial8250_register_8250_port(&up);
+ if (line < 0)
+ return line;
+
+ platform_set_drvdata(pdev, data);
+ return 0;
+}
+
+static int serial8250_ioc3_remove(struct platform_device *pdev)
+{
+ struct ioc3_8250_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+ return 0;
+}
+
+static struct platform_driver serial8250_ioc3_driver = {
+ .probe = serial8250_ioc3_probe,
+ .remove = serial8250_ioc3_remove,
+ .driver = {
+ .name = "ioc3-serial8250",
+ }
+};
+
+module_platform_driver(serial8250_ioc3_driver);
+
+MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
+MODULE_DESCRIPTION("SGI IOC3 8250 UART driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 296115f6a4d8..c5e9d086e870 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -365,6 +365,17 @@ config SERIAL_8250_EM
port hardware found on the Emma Mobile line of processors.
If unsure, say N.
+config SERIAL_8250_IOC3
+ tristate "SGI IOC3 8250 UART support"
+ depends on SGI_MFD_IOC3 && SERIAL_8250
+ select SERIAL_8250_EXTENDED
+ select SERIAL_8250_SHARE_IRQ
+ help
+ Enable this if you have a SGI Origin or Octane machine. This module
+ provides basic serial support by directly driving the UART chip
+ behind the IOC3 device on those systems. Maximum baud speed is
+ 38400bps using this driver.
+
config SERIAL_8250_RT288X
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
depends on SERIAL_8250
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 18751bc63a84..79f74b4d57e5 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
+obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
--
2.13.7
^ permalink raw reply related
* [PATCH v3 4/7] MIPS: SGI-IP27: remove ioc3 ethernet init
From: Thomas Bogendoerfer @ 2019-06-13 17:06 UTC (permalink / raw)
To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
Lee Jones, David S. Miller, Srinivas Kandagatla, Alessandro Zummo,
Alexandre Belloni, Greg Kroah-Hartman, Jiri Slaby, linux-mips,
linux-kernel, linux-input, netdev, linux-rtc, linux-serial
In-Reply-To: <20190613170636.6647-1-tbogendoerfer@suse.de>
Removed not needed disabling of ethernet interrupts in IP27 platform code.
Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
arch/mips/sgi-ip27/ip27-init.c | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c
index 066b33f50bcc..59d5375c9021 100644
--- a/arch/mips/sgi-ip27/ip27-init.c
+++ b/arch/mips/sgi-ip27/ip27-init.c
@@ -130,17 +130,6 @@ cnodeid_t get_compact_nodeid(void)
return NASID_TO_COMPACT_NODEID(get_nasid());
}
-static inline void ioc3_eth_init(void)
-{
- struct ioc3 *ioc3;
- nasid_t nid;
-
- nid = get_nasid();
- ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;
-
- ioc3->eier = 0;
-}
-
extern void ip27_reboot_setup(void);
void __init plat_mem_setup(void)
@@ -182,8 +171,6 @@ void __init plat_mem_setup(void)
panic("Kernel compiled for N mode.");
#endif
- ioc3_eth_init();
-
ioport_resource.start = 0;
ioport_resource.end = ~0UL;
set_io_port_base(IO_BASE);
--
2.13.7
^ permalink raw reply related
* [PATCH v3 3/7] MIPS: PCI: use information from 1-wire PROM for IOC3 detection
From: Thomas Bogendoerfer @ 2019-06-13 17:06 UTC (permalink / raw)
To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
Lee Jones, David S. Miller, Srinivas Kandagatla, Alessandro Zummo,
Alexandre Belloni, Greg Kroah-Hartman, Jiri Slaby, linux-mips,
linux-kernel, linux-input, netdev, linux-rtc, linux-serial
In-Reply-To: <20190613170636.6647-1-tbogendoerfer@suse.de>
IOC3 chips in SGI system are conntected to a bridge ASIC, which has
a 1-wire prom attached with part number information. This changeset
uses this information to create PCI subsystem information, which
the MFD driver uses for further platform device setup.
Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
arch/mips/include/asm/pci/bridge.h | 1 +
arch/mips/include/asm/sn/ioc3.h | 9 +++
arch/mips/pci/pci-xtalk-bridge.c | 135 ++++++++++++++++++++++++++++++++++++-
arch/mips/sgi-ip27/ip27-xtalk.c | 38 +++++++++--
4 files changed, 175 insertions(+), 8 deletions(-)
diff --git a/arch/mips/include/asm/pci/bridge.h b/arch/mips/include/asm/pci/bridge.h
index a92cd30b48c9..3bc630ff9ad4 100644
--- a/arch/mips/include/asm/pci/bridge.h
+++ b/arch/mips/include/asm/pci/bridge.h
@@ -807,6 +807,7 @@ struct bridge_controller {
unsigned long intr_addr;
struct irq_domain *domain;
unsigned int pci_int[8];
+ u32 ioc3_sid[8];
nasid_t nasid;
};
diff --git a/arch/mips/include/asm/sn/ioc3.h b/arch/mips/include/asm/sn/ioc3.h
index 25c8dccab51f..5022b0ab2074 100644
--- a/arch/mips/include/asm/sn/ioc3.h
+++ b/arch/mips/include/asm/sn/ioc3.h
@@ -661,4 +661,13 @@ typedef enum ioc3_subdevs_e {
#define IOC3_INTA_SUBDEVS IOC3_SDB_ETHER
#define IOC3_INTB_SUBDEVS (IOC3_SDB_GENERIC|IOC3_SDB_KBMS|IOC3_SDB_SERIAL|IOC3_SDB_ECPP|IOC3_SDB_RT)
+/* subsystem IDs supplied by card detection in pci-xtalk-bridge */
+#define IOC3_SUBSYS_IP27_BASEIO6G 0xc300
+#define IOC3_SUBSYS_IP27_MIO 0xc301
+#define IOC3_SUBSYS_IP27_BASEIO 0xc302
+#define IOC3_SUBSYS_IP29_SYSBOARD 0xc303
+#define IOC3_SUBSYS_IP30_SYSBOARD 0xc304
+#define IOC3_SUBSYS_MENET 0xc305
+#define IOC3_SUBSYS_MENET4 0xc306
+
#endif /* _IOC3_H */
diff --git a/arch/mips/pci/pci-xtalk-bridge.c b/arch/mips/pci/pci-xtalk-bridge.c
index 7b4d40354ee7..df87c686b308 100644
--- a/arch/mips/pci/pci-xtalk-bridge.c
+++ b/arch/mips/pci/pci-xtalk-bridge.c
@@ -11,16 +11,22 @@
#include <linux/dma-direct.h>
#include <linux/platform_device.h>
#include <linux/platform_data/xtalk-bridge.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/crc16.h>
#include <asm/pci/bridge.h>
#include <asm/paccess.h>
#include <asm/sn/irq_alloc.h>
+#include <asm/sn/ioc3.h>
+
+#define CRC16_INIT 0
+#define CRC16_VALID 0xb001
/*
* Most of the IOC3 PCI config register aren't present
* we emulate what is needed for a normal PCI enumeration
*/
-static int ioc3_cfg_rd(void *addr, int where, int size, u32 *value)
+static int ioc3_cfg_rd(void *addr, int where, int size, u32 *value, u32 sid)
{
u32 cf, shift, mask;
@@ -30,6 +36,9 @@ static int ioc3_cfg_rd(void *addr, int where, int size, u32 *value)
if (get_dbe(cf, (u32 *)addr))
return PCIBIOS_DEVICE_NOT_FOUND;
break;
+ case 0x2c:
+ cf = sid;
+ break;
case 0x3c:
/* emulate sane interrupt pin value */
cf = 0x00000100;
@@ -111,7 +120,8 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
*/
if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) {
addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
- return ioc3_cfg_rd(addr, where, size, value);
+ return ioc3_cfg_rd(addr, where, size, value,
+ bc->ioc3_sid[slot]);
}
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
@@ -149,7 +159,8 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
*/
if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) {
addr = &bridge->b_type1_cfg.c[(fn << 8) | (where & ~3)];
- return ioc3_cfg_rd(addr, where, size, value);
+ return ioc3_cfg_rd(addr, where, size, value,
+ bc->ioc3_sid[slot]);
}
addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
@@ -426,6 +437,117 @@ static int bridge_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return irq;
}
+#define IOC3_SID(sid) (PCI_VENDOR_ID_SGI << 16 | (sid))
+
+static void bridge_setup_ip27_baseio6g(struct bridge_controller *bc)
+{
+ bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP27_BASEIO6G);
+ bc->ioc3_sid[6] = IOC3_SID(IOC3_SUBSYS_IP27_MIO);
+}
+
+static void bridge_setup_ip27_baseio(struct bridge_controller *bc)
+{
+ bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP27_BASEIO);
+}
+
+static void bridge_setup_ip29_baseio(struct bridge_controller *bc)
+{
+ bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP29_SYSBOARD);
+}
+
+static void bridge_setup_ip30_sysboard(struct bridge_controller *bc)
+{
+ bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_IP30_SYSBOARD);
+}
+
+static void bridge_setup_menet(struct bridge_controller *bc)
+{
+ bc->ioc3_sid[0] = IOC3_SID(IOC3_SUBSYS_MENET);
+ bc->ioc3_sid[1] = IOC3_SID(IOC3_SUBSYS_MENET);
+ bc->ioc3_sid[2] = IOC3_SID(IOC3_SUBSYS_MENET);
+ bc->ioc3_sid[3] = IOC3_SID(IOC3_SUBSYS_MENET4);
+}
+
+#define BRIDGE_BOARD_SETUP(_partno, _setup) \
+ { .match = _partno, .setup = _setup }
+
+static const struct {
+ char *match;
+ void (*setup)(struct bridge_controller *bc);
+} bridge_ioc3_devid[] = {
+ BRIDGE_BOARD_SETUP("030-0734-", bridge_setup_ip27_baseio6g),
+ BRIDGE_BOARD_SETUP("030-0880-", bridge_setup_ip27_baseio6g),
+ BRIDGE_BOARD_SETUP("030-1023-", bridge_setup_ip27_baseio),
+ BRIDGE_BOARD_SETUP("030-1124-", bridge_setup_ip27_baseio),
+ BRIDGE_BOARD_SETUP("030-1025-", bridge_setup_ip29_baseio),
+ BRIDGE_BOARD_SETUP("030-1244-", bridge_setup_ip29_baseio),
+ BRIDGE_BOARD_SETUP("030-1389-", bridge_setup_ip29_baseio),
+ BRIDGE_BOARD_SETUP("030-0887-", bridge_setup_ip30_sysboard),
+ BRIDGE_BOARD_SETUP("030-1467-", bridge_setup_ip30_sysboard),
+ BRIDGE_BOARD_SETUP("030-0873-", bridge_setup_menet),
+};
+
+static void bridge_setup_board(struct bridge_controller *bc, char *partnum)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bridge_ioc3_devid); i++)
+ if (!strncmp(partnum, bridge_ioc3_devid[i].match,
+ strlen(bridge_ioc3_devid[i].match))) {
+ bridge_ioc3_devid[i].setup(bc);
+ }
+}
+
+static int bridge_nvmem_match(struct device *dev, void *data)
+{
+ const char *name = dev_name(dev);
+ const char *prefix = data;
+
+ if (strlen(name) < strlen(prefix))
+ return 0;
+
+ return memcmp(prefix, dev_name(dev), strlen(prefix)) == 0;
+}
+
+static int bridge_get_partnum(u64 baddr, char *partnum)
+{
+ struct nvmem_device *nvmem;
+ char prefix[24];
+ u8 prom[64];
+ int i, j;
+ int ret;
+
+ snprintf(prefix, sizeof(prefix), "bridge-%012llx-0b-", baddr);
+
+ nvmem = nvmem_device_find(prefix, bridge_nvmem_match);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
+
+ ret = nvmem_device_read(nvmem, 0, 64, prom);
+ nvmem_device_put(nvmem);
+
+ if (ret != 64)
+ return ret;
+
+ if (crc16(CRC16_INIT, prom, 32) != CRC16_VALID ||
+ crc16(CRC16_INIT, prom + 32, 32) != CRC16_VALID)
+ return -EINVAL;
+
+ /* Assemble part number */
+ j = 0;
+ for (i = 0; i < 19; i++)
+ if (prom[i + 11] != ' ')
+ partnum[j++] = prom[i + 11];
+
+ for (i = 0; i < 6; i++)
+ if (prom[i + 32] != ' ')
+ partnum[j++] = prom[i + 32];
+
+ partnum[j] = 0;
+
+ return 0;
+}
+
static int bridge_probe(struct platform_device *pdev)
{
struct xtalk_bridge_platform_data *bd = dev_get_platdata(&pdev->dev);
@@ -434,9 +556,14 @@ static int bridge_probe(struct platform_device *pdev)
struct pci_host_bridge *host;
struct irq_domain *domain, *parent;
struct fwnode_handle *fn;
+ char partnum[26];
int slot;
int err;
+ /* get part number from one wire prom */
+ if (bridge_get_partnum(virt_to_phys((void *)bd->bridge_addr), partnum))
+ return -EPROBE_DEFER; /* not available yet */
+
parent = irq_get_default_host();
if (!parent)
return -ENODEV;
@@ -517,6 +644,8 @@ static int bridge_probe(struct platform_device *pdev)
}
bridge_read(bc, b_wid_tflush); /* wait until Bridge PIO complete */
+ bridge_setup_board(bc, partnum);
+
host->dev.parent = dev;
host->sysdata = bc;
host->busnr = 0;
diff --git a/arch/mips/sgi-ip27/ip27-xtalk.c b/arch/mips/sgi-ip27/ip27-xtalk.c
index 4a1f0b0c29e2..9b7524362a11 100644
--- a/arch/mips/sgi-ip27/ip27-xtalk.c
+++ b/arch/mips/sgi-ip27/ip27-xtalk.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/platform_device.h>
+#include <linux/platform_data/sgi-w1.h>
#include <linux/platform_data/xtalk-bridge.h>
#include <asm/sn/addrs.h>
#include <asm/sn/types.h>
@@ -26,9 +27,35 @@
static void bridge_platform_create(nasid_t nasid, int widget, int masterwid)
{
struct xtalk_bridge_platform_data *bd;
+ struct sgi_w1_platform_data *wd;
struct platform_device *pdev;
+ struct resource w1_res;
unsigned long offset;
+ offset = NODE_OFFSET(nasid);
+
+ wd = kzalloc(sizeof(*wd), GFP_KERNEL);
+ if (!wd)
+ goto no_mem;
+
+ snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
+ offset + (widget << SWIN_SIZE_BITS));
+
+ memset(&w1_res, 0, sizeof(w1_res));
+ w1_res.start = offset + (widget << SWIN_SIZE_BITS) +
+ offsetof(struct bridge_regs, b_nic);
+ w1_res.end = w1_res.start + 3;
+ w1_res.flags = IORESOURCE_MEM;
+
+ pdev = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
+ if (!pdev) {
+ kfree(wd);
+ goto no_mem;
+ }
+ platform_device_add_resources(pdev, &w1_res, 1);
+ platform_device_add_data(pdev, wd, sizeof(*wd));
+ platform_device_add(pdev);
+
bd = kzalloc(sizeof(*bd), GFP_KERNEL);
if (!bd)
goto no_mem;
@@ -38,7 +65,6 @@ static void bridge_platform_create(nasid_t nasid, int widget, int masterwid)
goto no_mem;
}
- offset = NODE_OFFSET(nasid);
bd->bridge_addr = RAW_NODE_SWIN_BASE(nasid, widget);
bd->intr_addr = BIT_ULL(47) + 0x01800000 + PI_INT_PEND_MOD;
@@ -46,14 +72,14 @@ static void bridge_platform_create(nasid_t nasid, int widget, int masterwid)
bd->masterwid = masterwid;
bd->mem.name = "Bridge PCI MEM";
- bd->mem.start = offset + (widget << SWIN_SIZE_BITS);
- bd->mem.end = bd->mem.start + SWIN_SIZE - 1;
+ bd->mem.start = offset + (widget << SWIN_SIZE_BITS) + BRIDGE_DEVIO0;
+ bd->mem.end = offset + (widget << SWIN_SIZE_BITS) + SWIN_SIZE - 1;
bd->mem.flags = IORESOURCE_MEM;
bd->mem_offset = offset;
bd->io.name = "Bridge PCI IO";
- bd->io.start = offset + (widget << SWIN_SIZE_BITS);
- bd->io.end = bd->io.start + SWIN_SIZE - 1;
+ bd->io.start = offset + (widget << SWIN_SIZE_BITS) + BRIDGE_DEVIO0;
+ bd->io.end = offset + (widget << SWIN_SIZE_BITS) + SWIN_SIZE - 1;
bd->io.flags = IORESOURCE_IO;
bd->io_offset = offset;
@@ -81,6 +107,8 @@ static int probe_one_port(nasid_t nasid, int widget, int masterwid)
bridge_platform_create(nasid, widget, masterwid);
break;
default:
+ pr_info("xtalk:n%d/%d unknown widget (0x%x)\n",
+ nasid, widget, partnum);
break;
}
--
2.13.7
^ permalink raw reply related
* [PATCH v3 2/7] MIPS: PCI: refactor ioc3 special handling
From: Thomas Bogendoerfer @ 2019-06-13 17:06 UTC (permalink / raw)
To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
Lee Jones, David S. Miller, Srinivas Kandagatla, Alessandro Zummo,
Alexandre Belloni, Greg Kroah-Hartman, Jiri Slaby, linux-mips,
linux-kernel, linux-input, netdev, linux-rtc, linux-serial
In-Reply-To: <20190613170636.6647-1-tbogendoerfer@suse.de>
Refactored code to only have one ioc3 special handling for read
access and one for write access.
Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
arch/mips/pci/pci-xtalk-bridge.c | 167 +++++++++++++++------------------------
1 file changed, 62 insertions(+), 105 deletions(-)
diff --git a/arch/mips/pci/pci-xtalk-bridge.c b/arch/mips/pci/pci-xtalk-bridge.c
index bcf7f559789a..7b4d40354ee7 100644
--- a/arch/mips/pci/pci-xtalk-bridge.c
+++ b/arch/mips/pci/pci-xtalk-bridge.c
@@ -20,16 +20,50 @@
* Most of the IOC3 PCI config register aren't present
* we emulate what is needed for a normal PCI enumeration
*/
-static u32 emulate_ioc3_cfg(int where, int size)
+static int ioc3_cfg_rd(void *addr, int where, int size, u32 *value)
{
- if (size == 1 && where == 0x3d)
- return 0x01;
- else if (size == 2 && where == 0x3c)
- return 0x0100;
- else if (size == 4 && where == 0x3c)
- return 0x00000100;
+ u32 cf, shift, mask;
- return 0;
+ switch (where & ~3) {
+ case 0x00 ... 0x10:
+ case 0x40 ... 0x44:
+ if (get_dbe(cf, (u32 *)addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ break;
+ case 0x3c:
+ /* emulate sane interrupt pin value */
+ cf = 0x00000100;
+ break;
+ default:
+ cf = 0;
+ break;
+ }
+ shift = (where & 3) << 3;
+ mask = 0xffffffffU >> ((4 - size) << 3);
+ *value = (cf >> shift) & mask;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int ioc3_cfg_wr(void *addr, int where, int size, u32 value)
+{
+ u32 cf, shift, mask, smask;
+
+ if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (get_dbe(cf, (u32 *)addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ shift = ((where & 3) << 3);
+ mask = (0xffffffffU >> ((4 - size) << 3));
+ smask = mask << shift;
+
+ cf = (cf & ~smask) | ((value & mask) << shift);
+ if (put_dbe(cf, (u32 *)addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
}
static void bridge_disable_swapping(struct pci_dev *dev)
@@ -64,7 +98,7 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn);
void *addr;
- u32 cf, shift, mask;
+ u32 cf;
int res;
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
@@ -75,8 +109,10 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
* IOC3 is broken beyond belief ... Don't even give the
* generic PCI code a chance to look at it for real ...
*/
- if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
- goto is_ioc3;
+ if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) {
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
+ return ioc3_cfg_rd(addr, where, size, value);
+ }
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
@@ -88,26 +124,6 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
res = get_dbe(*value, (u32 *)addr);
return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-
-is_ioc3:
-
- /*
- * IOC3 special handling
- */
- if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) {
- *value = emulate_ioc3_cfg(where, size);
- return PCIBIOS_SUCCESSFUL;
- }
-
- addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
- if (get_dbe(cf, (u32 *)addr))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- shift = ((where & 3) << 3);
- mask = (0xffffffffU >> ((4 - size) << 3));
- *value = (cf >> shift) & mask;
-
- return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
@@ -119,7 +135,7 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn);
void *addr;
- u32 cf, shift, mask;
+ u32 cf;
int res;
bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
@@ -131,8 +147,10 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
* IOC3 is broken beyond belief ... Don't even give the
* generic PCI code a chance to look at it for real ...
*/
- if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
- goto is_ioc3;
+ if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) {
+ addr = &bridge->b_type1_cfg.c[(fn << 8) | (where & ~3)];
+ return ioc3_cfg_rd(addr, where, size, value);
+ }
addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
@@ -144,26 +162,6 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,
res = get_dbe(*value, (u32 *)addr);
return res ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-
-is_ioc3:
-
- /*
- * IOC3 special handling
- */
- if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) {
- *value = emulate_ioc3_cfg(where, size);
- return PCIBIOS_SUCCESSFUL;
- }
-
- addr = &bridge->b_type1_cfg.c[(fn << 8) | where];
- if (get_dbe(cf, (u32 *)addr))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- shift = ((where & 3) << 3);
- mask = (0xffffffffU >> ((4 - size) << 3));
- *value = (cf >> shift) & mask;
-
- return PCIBIOS_SUCCESSFUL;
}
static int pci_read_config(struct pci_bus *bus, unsigned int devfn,
@@ -183,7 +181,7 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
int slot = PCI_SLOT(devfn);
int fn = PCI_FUNC(devfn);
void *addr;
- u32 cf, shift, mask, smask;
+ u32 cf;
int res;
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[PCI_VENDOR_ID];
@@ -194,8 +192,10 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
* IOC3 is broken beyond belief ... Don't even give the
* generic PCI code a chance to look at it for real ...
*/
- if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
- goto is_ioc3;
+ if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) {
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
+ return ioc3_cfg_wr(addr, where, size, value);
+ }
addr = &bridge->b_type0_cfg_dev[slot].f[fn].c[where ^ (4 - size)];
@@ -210,29 +210,6 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_DEVICE_NOT_FOUND;
return PCIBIOS_SUCCESSFUL;
-
-is_ioc3:
-
- /*
- * IOC3 special handling
- */
- if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
- return PCIBIOS_SUCCESSFUL;
-
- addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
-
- if (get_dbe(cf, (u32 *)addr))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- shift = ((where & 3) << 3);
- mask = (0xffffffffU >> ((4 - size) << 3));
- smask = mask << shift;
-
- cf = (cf & ~smask) | ((value & mask) << shift);
- if (put_dbe(cf, (u32 *)addr))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
@@ -244,7 +221,7 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
int fn = PCI_FUNC(devfn);
int busno = bus->number;
void *addr;
- u32 cf, shift, mask, smask;
+ u32 cf;
int res;
bridge_write(bc, b_pci_cfg, (busno << 16) | (slot << 11));
@@ -256,8 +233,10 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
* IOC3 is broken beyond belief ... Don't even give the
* generic PCI code a chance to look at it for real ...
*/
- if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16)))
- goto is_ioc3;
+ if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) {
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
+ return ioc3_cfg_wr(addr, where, size, value);
+ }
addr = &bridge->b_type1_cfg.c[(fn << 8) | (where ^ (4 - size))];
@@ -272,28 +251,6 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_DEVICE_NOT_FOUND;
return PCIBIOS_SUCCESSFUL;
-
-is_ioc3:
-
- /*
- * IOC3 special handling
- */
- if ((where >= 0x14 && where < 0x40) || (where >= 0x48))
- return PCIBIOS_SUCCESSFUL;
-
- addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2];
- if (get_dbe(cf, (u32 *)addr))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- shift = ((where & 3) << 3);
- mask = (0xffffffffU >> ((4 - size) << 3));
- smask = mask << shift;
-
- cf = (cf & ~smask) | ((value & mask) << shift);
- if (put_dbe(cf, (u32 *)addr))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- return PCIBIOS_SUCCESSFUL;
}
static int pci_write_config(struct pci_bus *bus, unsigned int devfn,
--
2.13.7
^ permalink raw reply related
* [PATCH v3 1/7] nvmem: core: add nvmem_device_find
From: Thomas Bogendoerfer @ 2019-06-13 17:06 UTC (permalink / raw)
To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
Lee Jones, David S. Miller, Srinivas Kandagatla, Alessandro Zummo,
Alexandre Belloni, Greg Kroah-Hartman, Jiri Slaby, linux-mips,
linux-kernel, linux-input, netdev, linux-rtc, linux-serial
In-Reply-To: <20190613170636.6647-1-tbogendoerfer@suse.de>
nvmem_device_find provides a way to search for nvmem devices with
the help of a match function simlair to bus_find_device.
Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
drivers/nvmem/core.c | 62 ++++++++++++++++++++++--------------------
include/linux/nvmem-consumer.h | 9 ++++++
2 files changed, 41 insertions(+), 30 deletions(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index c7892c3da91f..29a1c937b290 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -76,36 +76,18 @@ static struct bus_type nvmem_bus_type = {
.name = "nvmem",
};
+#if IS_ENABLED(CONFIG_OF)
static int of_nvmem_match(struct device *dev, void *nvmem_np)
{
return dev->of_node == nvmem_np;
}
+#endif
-static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
+static int nvmem_match_name(struct device *dev, void *data)
{
- struct device *d;
-
- if (!nvmem_np)
- return NULL;
-
- d = bus_find_device(&nvmem_bus_type, NULL, nvmem_np, of_nvmem_match);
-
- if (!d)
- return NULL;
+ const char *name = data;
- return to_nvmem_device(d);
-}
-
-static struct nvmem_device *nvmem_find(const char *name)
-{
- struct device *d;
-
- d = bus_find_device_by_name(&nvmem_bus_type, NULL, name);
-
- if (!d)
- return NULL;
-
- return to_nvmem_device(d);
+ return sysfs_streq(name, dev_name(dev));
}
static void nvmem_cell_drop(struct nvmem_cell *cell)
@@ -537,13 +519,16 @@ int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
}
EXPORT_SYMBOL(devm_nvmem_unregister);
-static struct nvmem_device *__nvmem_device_get(struct device_node *np,
- const char *nvmem_name)
+static struct nvmem_device *__nvmem_device_get(void *data,
+ int (*match)(struct device *dev, void *data))
{
struct nvmem_device *nvmem = NULL;
+ struct device *dev;
mutex_lock(&nvmem_mutex);
- nvmem = np ? of_nvmem_find(np) : nvmem_find(nvmem_name);
+ dev = bus_find_device(&nvmem_bus_type, NULL, data, match);
+ if (dev)
+ nvmem = to_nvmem_device(dev);
mutex_unlock(&nvmem_mutex);
if (!nvmem)
return ERR_PTR(-EPROBE_DEFER);
@@ -592,7 +577,7 @@ struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id)
if (!nvmem_np)
return ERR_PTR(-ENOENT);
- return __nvmem_device_get(nvmem_np, NULL);
+ return __nvmem_device_get(nvmem_np, of_nvmem_match);
}
EXPORT_SYMBOL_GPL(of_nvmem_device_get);
#endif
@@ -618,10 +603,26 @@ struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name)
}
- return __nvmem_device_get(NULL, dev_name);
+ return __nvmem_device_get((void *)dev_name, nvmem_match_name);
}
EXPORT_SYMBOL_GPL(nvmem_device_get);
+/**
+ * nvmem_device_find() - Find nvmem device with matching function
+ *
+ * @data: Data to pass to match function
+ * @match: Callback function to check device
+ *
+ * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
+ * on success.
+ */
+struct nvmem_device *nvmem_device_find(void *data,
+ int (*match)(struct device *dev, void *data))
+{
+ return __nvmem_device_get(data, match);
+}
+EXPORT_SYMBOL_GPL(nvmem_device_find);
+
static int devm_nvmem_device_match(struct device *dev, void *res, void *data)
{
struct nvmem_device **nvmem = res;
@@ -715,7 +716,8 @@ nvmem_cell_get_from_lookup(struct device *dev, const char *con_id)
if ((strcmp(lookup->dev_id, dev_id) == 0) &&
(strcmp(lookup->con_id, con_id) == 0)) {
/* This is the right entry. */
- nvmem = __nvmem_device_get(NULL, lookup->nvmem_name);
+ nvmem = __nvmem_device_get((void *)lookup->nvmem_name,
+ nvmem_match_name);
if (IS_ERR(nvmem)) {
/* Provider may not be registered yet. */
cell = ERR_CAST(nvmem);
@@ -785,7 +787,7 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
if (!nvmem_np)
return ERR_PTR(-EINVAL);
- nvmem = __nvmem_device_get(nvmem_np, NULL);
+ nvmem = __nvmem_device_get(nvmem_np, of_nvmem_match);
of_node_put(nvmem_np);
if (IS_ERR(nvmem))
return ERR_CAST(nvmem);
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
index 8f8be5b00060..a8249b2dcaf4 100644
--- a/include/linux/nvmem-consumer.h
+++ b/include/linux/nvmem-consumer.h
@@ -89,6 +89,9 @@ void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries,
int nvmem_register_notifier(struct notifier_block *nb);
int nvmem_unregister_notifier(struct notifier_block *nb);
+struct nvmem_device *nvmem_device_find(void *data,
+ int (*match)(struct device *dev, void *data));
+
#else
static inline struct nvmem_cell *nvmem_cell_get(struct device *dev,
@@ -204,6 +207,12 @@ static inline int nvmem_unregister_notifier(struct notifier_block *nb)
return -EOPNOTSUPP;
}
+static inline struct nvmem_device *nvmem_device_find(void *data,
+ int (*match)(struct device *dev, void *data))
+{
+ return NULL;
+}
+
#endif /* CONFIG_NVMEM */
#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)
--
2.13.7
^ permalink raw reply related
* [PATCH v3 0/7] Use MFD framework for SGI IOC3 drivers
From: Thomas Bogendoerfer @ 2019-06-13 17:06 UTC (permalink / raw)
To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
Lee Jones, David S. Miller, Srinivas Kandagatla, Alessandro Zummo,
Alexandre Belloni, Greg Kroah-Hartman, Jiri Slaby, linux-mips,
linux-kernel, linux-input, netdev, linux-rtc, linux-serial
SGI IOC3 ASIC includes support for ethernet, PS2 keyboard/mouse,
NIC (number in a can), GPIO and a byte bus. By attaching a
SuperIO chip to it, it also supports serial lines and a parallel
port. The chip is used on a variety of SGI systems with different
configurations. This patchset moves code out of the network driver,
which doesn't belong there, into its new place a MFD driver and
specific platform drivers for the different subfunctions.
Changes in v3:
- use 1-wire subsystem for handling proms
- pci-xtalk driver uses prom information to create PCI subsystem
ids for use in MFD driver
- changed MFD driver to only use static declared mfd_cells
- added IP30 system board setup to MFD driver
- mac address is now read from ioc3-eth driver with nvmem framework
Changes in v2:
- fixed issue in ioc3kbd.c reported by Dmitry Torokhov
- merged IP27 RTC removal and 8250 serial driver addition into
main MFD patch to keep patches bisectable
Thomas Bogendoerfer (7):
nvmem: core: add nvmem_device_find
MIPS: PCI: refactor ioc3 special handling
MIPS: PCI: use information from 1-wire PROM for IOC3 detection
MIPS: SGI-IP27: remove ioc3 ethernet init
mfd: ioc3: Add driver for SGI IOC3 chip
MIPS: SGI-IP27: fix readb/writeb addressing
Input: add IOC3 serio driver
arch/mips/include/asm/mach-ip27/mangle-port.h | 4 +-
arch/mips/include/asm/pci/bridge.h | 1 +
arch/mips/include/asm/sn/ioc3.h | 356 ++---
arch/mips/pci/pci-xtalk-bridge.c | 296 ++--
arch/mips/sgi-ip27/ip27-console.c | 5 +-
arch/mips/sgi-ip27/ip27-init.c | 13 -
arch/mips/sgi-ip27/ip27-timer.c | 20 -
arch/mips/sgi-ip27/ip27-xtalk.c | 38 +-
drivers/input/serio/Kconfig | 10 +
drivers/input/serio/Makefile | 1 +
drivers/input/serio/ioc3kbd.c | 158 ++
drivers/mfd/Kconfig | 13 +
drivers/mfd/Makefile | 1 +
drivers/mfd/ioc3.c | 683 +++++++++
drivers/net/ethernet/sgi/Kconfig | 4 +-
drivers/net/ethernet/sgi/ioc3-eth.c | 1932 ++++++++++---------------
drivers/nvmem/core.c | 62 +-
drivers/rtc/rtc-m48t35.c | 11 +
drivers/tty/serial/8250/8250_ioc3.c | 98 ++
drivers/tty/serial/8250/Kconfig | 11 +
drivers/tty/serial/8250/Makefile | 1 +
include/linux/nvmem-consumer.h | 9 +
22 files changed, 2152 insertions(+), 1575 deletions(-)
create mode 100644 drivers/input/serio/ioc3kbd.c
create mode 100644 drivers/mfd/ioc3.c
create mode 100644 drivers/tty/serial/8250/8250_ioc3.c
--
2.13.7
^ permalink raw reply
* Re: [PATCH v2] HID: input: fix a4tech horizontal wheel custom usage
From: Wolfgang Bauer @ 2019-06-13 11:48 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Nicolas Saenz Julienne, Jiri Kosina, Dmitry Torokhov,
open list:HID CORE LAYER, lkml
In-Reply-To: <CAO-hwJLAiC1o-kZ5epZHtO2GK+zc5x28pYbZH-XsY4yAuBmHWw@mail.gmail.com>
On Tuesday, 11. Juni 2019, 16:42:37 Benjamin Tissoires wrote:
> On Tue, Jun 11, 2019 at 2:13 PM Nicolas Saenz Julienne
>
> <nsaenzjulienne@suse.de> wrote:
> > NOTE: I CC'd Wolfgang as he's the one who can test this.
>
> I'll wait for Wolfram to confirm that the patch works before pushing then.
My name is Wolfgang, not Wolfram... ;-)
But never mind.
I tested the patch meanwhile on top of kernel 5.2.rc4, where the mouse wheel
actually worked.
As the patch didn't apply cleanly (it's obviously based upon
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=abf82e8f7e9af40a49e3d905187c662a43c96c8f , called "HID-
a4tech-fix-horizontal-scrolling.patch" below), I added that patch as well.
My results:
kernel 5.2.rc4 works
kernel 5.2.rc4 + HID-a4tech-fix-horizontal-scrolling.patch is broken
kernel 5.2.rc4 + HID-a4tech-fix-horizontal-scrolling.patch +
HID-input-fix-a4tech-horizontal-wheel-custom-usage.patch (i.e. this patch)
works again
kernel 5.2.rc4 + HID-input-fix-a4tech-horizontal-wheel-custom-usage.patch
works as well.
So AFAICT this patch seems to be fine.
For completeness, this is my mouse as listed by lsusb:
Bus 003 Device 002: ID 09da:000a A4Tech Co., Ltd. Optical Mouse Opto 510D /
OP-620D
Kind Regards,
Wolfgang
^ permalink raw reply
* Re: [PATCH v1 20/31] docs: hid: convert to ReST
From: Mauro Carvalho Chehab @ 2019-06-13 9:52 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Linux Doc Mailing List, Mauro Carvalho Chehab, lkml,
Jonathan Corbet, Jiri Kosina, Jonathan Cameron,
Srinivas Pandruvada, Dmitry Torokhov, open list:HID CORE LAYER,
linux-iio, Linux USB Mailing List
In-Reply-To: <CAO-hwJKo4GLJu=pfVQe=-aBj5HOng2L4KYDepNwLPSkL9v+EWw@mail.gmail.com>
Em Thu, 13 Jun 2019 10:08:34 +0200
Benjamin Tissoires <benjamin.tissoires@redhat.com> escreveu:
> On Wed, Jun 12, 2019 at 8:39 PM Mauro Carvalho Chehab
> <mchehab+samsung@kernel.org> wrote:
> >
> > Rename the HID documentation files to ReST, add an
> > index for them and adjust in order to produce a nice html
> > output via the Sphinx build system.
> >
> > While here, fix the sysfs example from hid-sensor.txt, that
> > has a lot of "?" instead of the proper UTF-8 characters that
> > are produced by the tree command.
> >
> > At its new index.rst, let's add a :orphan: while this is not linked to
> > the main index.rst file, in order to avoid build warnings.
> >
> > Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
> > ---
>
> Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>
> Do you need to take this patch through the doc tree or should we carry
> it in the HID one?
Each patch in this series is pretty much independent. So, feel
free to apply it via the HID tree.
>
> Cheers,
> Benjamin
>
> > .../hid/{hid-alps.txt => hid-alps.rst} | 85 ++-
> > .../hid/{hid-sensor.txt => hid-sensor.rst} | 192 +++----
> > .../{hid-transport.txt => hid-transport.rst} | 82 ++-
> > Documentation/hid/{hiddev.txt => hiddev.rst} | 154 ++++--
> > Documentation/hid/{hidraw.txt => hidraw.rst} | 53 +-
> > Documentation/hid/index.rst | 18 +
> > Documentation/hid/intel-ish-hid.rst | 485 ++++++++++++++++++
> > Documentation/hid/intel-ish-hid.txt | 454 ----------------
> > Documentation/hid/{uhid.txt => uhid.rst} | 46 +-
> > Documentation/input/input.rst | 2 +-
> > MAINTAINERS | 2 +-
> > 11 files changed, 897 insertions(+), 676 deletions(-)
> > rename Documentation/hid/{hid-alps.txt => hid-alps.rst} (64%)
> > rename Documentation/hid/{hid-sensor.txt => hid-sensor.rst} (61%)
> > rename Documentation/hid/{hid-transport.txt => hid-transport.rst} (93%)
> > rename Documentation/hid/{hiddev.txt => hiddev.rst} (77%)
> > rename Documentation/hid/{hidraw.txt => hidraw.rst} (89%)
> > create mode 100644 Documentation/hid/index.rst
> > create mode 100644 Documentation/hid/intel-ish-hid.rst
> > delete mode 100644 Documentation/hid/intel-ish-hid.txt
> > rename Documentation/hid/{uhid.txt => uhid.rst} (94%)
> >
> > diff --git a/Documentation/hid/hid-alps.txt b/Documentation/hid/hid-alps.rst
> > similarity index 64%
> > rename from Documentation/hid/hid-alps.txt
> > rename to Documentation/hid/hid-alps.rst
> > index 6b02a2447c77..e2f4c4c11e3f 100644
> > --- a/Documentation/hid/hid-alps.txt
> > +++ b/Documentation/hid/hid-alps.rst
> > @@ -1,19 +1,26 @@
> > +==========================
> > ALPS HID Touchpad Protocol
> > -----------------------
> > +==========================
> >
> > Introduction
> > ------------
> > Currently ALPS HID driver supports U1 Touchpad device.
> >
> > -U1 devuce basic information.
> > +U1 device basic information.
> > +
> > +========== ======
> > Vender ID 0x044E
> > Product ID 0x120B
> > Version ID 0x0121
> > +========== ======
> >
> >
> > HID Descriptor
> > -------------
> > +--------------
> > +
> > +======= ==================== ===== =======================================
> > Byte Field Value Notes
> > +======= ==================== ===== =======================================
> > 0 wHIDDescLength 001E Length of HID Descriptor : 30 bytes
> > 2 bcdVersion 0100 Compliant with Version 1.00
> > 4 wReportDescLength 00B2 Report Descriptor is 178 Bytes (0x00B2)
> > @@ -28,32 +35,42 @@ Byte Field Value Notes
> > 22 wProductID 120B Product ID 0x120B
> > 24 wVersionID 0121 Version 01.21
> > 26 RESERVED 0000 RESERVED
> > +======= ==================== ===== =======================================
> >
> >
> > Report ID
> > -------------
> > -ReportID-1 (Input Reports) (HIDUsage-Mouse) for TP&SP
> > -ReportID-2 (Input Reports) (HIDUsage-keyboard) for TP
> > -ReportID-3 (Input Reports) (Vendor Usage: Max 10 finger data) for TP
> > -ReportID-4 (Input Reports) (Vendor Usage: ON bit data) for GP
> > -ReportID-5 (Feature Reports) Feature Reports
> > -ReportID-6 (Input Reports) (Vendor Usage: StickPointer data) for SP
> > -ReportID-7 (Feature Reports) Flash update (Bootloader)
> > +---------
> > +
> > +========== ================= =========================================
> > +ReportID-1 (Input Reports) (HIDUsage-Mouse) for TP&SP
> > +ReportID-2 (Input Reports) (HIDUsage-keyboard) for TP
> > +ReportID-3 (Input Reports) (Vendor Usage: Max 10 finger data) for TP
> > +ReportID-4 (Input Reports) (Vendor Usage: ON bit data) for GP
> > +ReportID-5 (Feature Reports) Feature Reports
> > +ReportID-6 (Input Reports) (Vendor Usage: StickPointer data) for SP
> > +ReportID-7 (Feature Reports) Flash update (Bootloader)
> > +========== ================= =========================================
> >
> >
> > Data pattern
> > ------------
> > +
> > +===== ========== ===== =================
> > Case1 ReportID_1 TP/SP Relative/Relative
> > Case2 ReportID_3 TP Absolute
> > ReportID_6 SP Absolute
> > +===== ========== ===== =================
> >
> >
> > Command Read/Write
> > ------------------
> > To read/write to RAM, need to send a commands to the device.
> > +
> > The command format is as below.
> >
> > DataByte(SET_REPORT)
> > +
> > +===== ======================
> > Byte1 Command Byte
> > Byte2 Address - Byte 0 (LSB)
> > Byte3 Address - Byte 1
> > @@ -61,13 +78,19 @@ Byte4 Address - Byte 2
> > Byte5 Address - Byte 3 (MSB)
> > Byte6 Value Byte
> > Byte7 Checksum
> > +===== ======================
> >
> > Command Byte is read=0xD1/write=0xD2 .
> > +
> > Address is read/write RAM address.
> > +
> > Value Byte is writing data when you send the write commands.
> > +
> > When you read RAM, there is no meaning.
> >
> > DataByte(GET_REPORT)
> > +
> > +===== ======================
> > Byte1 Response Byte
> > Byte2 Address - Byte 0 (LSB)
> > Byte3 Address - Byte 1
> > @@ -75,6 +98,7 @@ Byte4 Address - Byte 2
> > Byte5 Address - Byte 3 (MSB)
> > Byte6 Value Byte
> > Byte7 Checksum
> > +===== ======================
> >
> > Read value is stored in Value Byte.
> >
> > @@ -82,7 +106,11 @@ Read value is stored in Value Byte.
> > Packet Format
> > Touchpad data byte
> > ------------------
> > - b7 b6 b5 b4 b3 b2 b1 b0
> > +
> > +
> > +======= ======= ======= ======= ======= ======= ======= ======= =====
> > +- b7 b6 b5 b4 b3 b2 b1 b0
> > +======= ======= ======= ======= ======= ======= ======= ======= =====
> > 1 0 0 SW6 SW5 SW4 SW3 SW2 SW1
> > 2 0 0 0 Fcv Fn3 Fn2 Fn1 Fn0
> > 3 Xa0_7 Xa0_6 Xa0_5 Xa0_4 Xa0_3 Xa0_2 Xa0_1 Xa0_0
> > @@ -114,17 +142,25 @@ Touchpad data byte
> > 25 Ya4_7 Ya4_6 Ya4_5 Ya4_4 Ya4_3 Ya4_2 Ya4_1 Ya4_0
> > 26 Ya4_15 Ya4_14 Ya4_13 Ya4_12 Ya4_11 Ya4_10 Ya4_9 Ya4_8
> > 27 LFB4 Zs4_6 Zs4_5 Zs4_4 Zs4_3 Zs4_2 Zs4_1 Zs4_0
> > +======= ======= ======= ======= ======= ======= ======= ======= =====
> >
> >
> > -SW1-SW6: SW ON/OFF status
> > -Xan_15-0(16bit):X Absolute data of the "n"th finger
> > -Yan_15-0(16bit):Y Absolute data of the "n"th finger
> > -Zsn_6-0(7bit): Operation area of the "n"th finger
> > +SW1-SW6:
> > + SW ON/OFF status
> > +Xan_15-0(16bit):
> > + X Absolute data of the "n"th finger
> > +Yan_15-0(16bit):
> > + Y Absolute data of the "n"th finger
> > +Zsn_6-0(7bit):
> > + Operation area of the "n"th finger
> >
> >
> > StickPointer data byte
> > -------------------
> > - b7 b6 b5 b4 b3 b2 b1 b0
> > +----------------------
> > +
> > +======= ======= ======= ======= ======= ======= ======= ======= =====
> > +- b7 b6 b5 b4 b3 b2 b1 b0
> > +======= ======= ======= ======= ======= ======= ======= ======= =====
> > Byte1 1 1 1 0 1 SW3 SW2 SW1
> > Byte2 X7 X6 X5 X4 X3 X2 X1 X0
> > Byte3 X15 X14 X13 X12 X11 X10 X9 X8
> > @@ -132,8 +168,13 @@ Byte4 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
> > Byte5 Y15 Y14 Y13 Y12 Y11 Y10 Y9 Y8
> > Byte6 Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0
> > Byte7 T&P Z14 Z13 Z12 Z11 Z10 Z9 Z8
> > +======= ======= ======= ======= ======= ======= ======= ======= =====
> >
> > -SW1-SW3: SW ON/OFF status
> > -Xn_15-0(16bit):X Absolute data
> > -Yn_15-0(16bit):Y Absolute data
> > -Zn_14-0(15bit):Z
> > +SW1-SW3:
> > + SW ON/OFF status
> > +Xn_15-0(16bit):
> > + X Absolute data
> > +Yn_15-0(16bit):
> > + Y Absolute data
> > +Zn_14-0(15bit):
> > + Z
> > diff --git a/Documentation/hid/hid-sensor.txt b/Documentation/hid/hid-sensor.rst
> > similarity index 61%
> > rename from Documentation/hid/hid-sensor.txt
> > rename to Documentation/hid/hid-sensor.rst
> > index b287752a31cd..758972e34971 100644
> > --- a/Documentation/hid/hid-sensor.txt
> > +++ b/Documentation/hid/hid-sensor.rst
> > @@ -1,6 +1,6 @@
> > -
> > +=====================
> > HID Sensors Framework
> > -======================
> > +=====================
> > HID sensor framework provides necessary interfaces to implement sensor drivers,
> > which are connected to a sensor hub. The sensor hub is a HID device and it provides
> > a report descriptor conforming to HID 1.12 sensor usage tables.
> > @@ -15,22 +15,22 @@ the drivers themselves."
> > This specification describes many usage IDs, which describe the type of sensor
> > and also the individual data fields. Each sensor can have variable number of
> > data fields. The length and order is specified in the report descriptor. For
> > -example a part of report descriptor can look like:
> > +example a part of report descriptor can look like::
> >
> > - INPUT(1)[INPUT]
> > - ..
> > - Field(2)
> > - Physical(0020.0073)
> > - Usage(1)
> > - 0020.045f
> > - Logical Minimum(-32767)
> > - Logical Maximum(32767)
> > - Report Size(8)
> > - Report Count(1)
> > - Report Offset(16)
> > - Flags(Variable Absolute)
> > -..
> > -..
> > + INPUT(1)[INPUT]
> > + ..
> > + Field(2)
> > + Physical(0020.0073)
> > + Usage(1)
> > + 0020.045f
> > + Logical Minimum(-32767)
> > + Logical Maximum(32767)
> > + Report Size(8)
> > + Report Count(1)
> > + Report Offset(16)
> > + Flags(Variable Absolute)
> > + ..
> > + ..
> >
> > The report is indicating "sensor page (0x20)" contains an accelerometer-3D (0x73).
> > This accelerometer-3D has some fields. Here for example field 2 is motion intensity
> > @@ -40,13 +40,14 @@ data will use this format.
> >
> >
> > Implementation
> > -=================
> > +==============
> >
> > This specification defines many different types of sensors with different sets of
> > data fields. It is difficult to have a common input event to user space applications,
> > for different sensors. For example an accelerometer can send X,Y and Z data, whereas
> > an ambient light sensor can send illumination data.
> > So the implementation has two parts:
> > +
> > - Core hid driver
> > - Individual sensor processing part (sensor drivers)
> >
> > @@ -55,8 +56,11 @@ Core driver
> > The core driver registers (hid-sensor-hub) registers as a HID driver. It parses
> > report descriptors and identifies all the sensors present. It adds an MFD device
> > with name HID-SENSOR-xxxx (where xxxx is usage id from the specification).
> > -For example
> > +
> > +For example:
> > +
> > HID-SENSOR-200073 is registered for an Accelerometer 3D driver.
> > +
> > So if any driver with this name is inserted, then the probe routine for that
> > function will be called. So an accelerometer processing driver can register
> > with this name and will be probed if there is an accelerometer-3D detected.
> > @@ -66,7 +70,8 @@ drivers to register and get events for that usage id. Also it provides parsing
> > functions, which get and set each input/feature/output report.
> >
> > Individual sensor processing part (sensor drivers)
> > ------------
> > +--------------------------------------------------
> > +
> > The processing driver will use an interface provided by the core driver to parse
> > the report and get the indexes of the fields and also can get events. This driver
> > can use IIO interface to use the standard ABI defined for a type of sensor.
> > @@ -75,31 +80,34 @@ can use IIO interface to use the standard ABI defined for a type of sensor.
> > Core driver Interface
> > =====================
> >
> > -Callback structure:
> > -Each processing driver can use this structure to set some callbacks.
> > +Callback structure::
> > +
> > + Each processing driver can use this structure to set some callbacks.
> > int (*suspend)(..): Callback when HID suspend is received
> > int (*resume)(..): Callback when HID resume is received
> > int (*capture_sample)(..): Capture a sample for one of its data fields
> > int (*send_event)(..): One complete event is received which can have
> > multiple data fields.
> >
> > -Registration functions:
> > -int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
> > +Registration functions::
> > +
> > + int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
> > u32 usage_id,
> > struct hid_sensor_hub_callbacks *usage_callback):
> >
> > Registers callbacks for an usage id. The callback functions are not allowed
> > -to sleep.
> > +to sleep::
> >
> >
> > -int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
> > + int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
> > u32 usage_id):
> >
> > Removes callbacks for an usage id.
> >
> >
> > -Parsing function:
> > -int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
> > +Parsing function::
> > +
> > + int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
> > u8 type,
> > u32 usage_id, u32 attr_usage_id,
> > struct hid_sensor_hub_attribute_info *info);
> > @@ -110,26 +118,27 @@ so that fields can be set or get individually.
> > These indexes avoid searching every time and getting field index to get or set.
> >
> >
> > -Set Feature report
> > -int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> > +Set Feature report::
> > +
> > + int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> > u32 field_index, s32 value);
> >
> > This interface is used to set a value for a field in feature report. For example
> > if there is a field report_interval, which is parsed by a call to
> > -sensor_hub_input_get_attribute_info before, then it can directly set that individual
> > -field.
> > +sensor_hub_input_get_attribute_info before, then it can directly set that
> > +individual field::
> >
> >
> > -int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> > + int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> > u32 field_index, s32 *value);
> >
> > This interface is used to get a value for a field in input report. For example
> > if there is a field report_interval, which is parsed by a call to
> > -sensor_hub_input_get_attribute_info before, then it can directly get that individual
> > -field value.
> > +sensor_hub_input_get_attribute_info before, then it can directly get that
> > +individual field value::
> >
> >
> > -int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
> > + int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
> > u32 usage_id,
> > u32 attr_usage_id, u32 report_id);
> >
> > @@ -143,6 +152,8 @@ registered callback function to process the sample.
> > ----------
> >
> > HID Custom and generic Sensors
> > +------------------------------
> > +
> >
> > HID Sensor specification defines two special sensor usage types. Since they
> > don't represent a standard sensor, it is not possible to define using Linux IIO
> > @@ -158,66 +169,73 @@ keyboard attached/detached or lid open/close.
> > To allow application to utilize these sensors, here they are exported uses sysfs
> > attribute groups, attributes and misc device interface.
> >
> > -An example of this representation on sysfs:
> > -/sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R
> > -.
> > -????????? enable_sensor
> > -????????? feature-0-200316
> > -??????? ????????? feature-0-200316-maximum
> > -??????? ????????? feature-0-200316-minimum
> > -??????? ????????? feature-0-200316-name
> > -??????? ????????? feature-0-200316-size
> > -??????? ????????? feature-0-200316-unit-expo
> > -??????? ????????? feature-0-200316-units
> > -??????? ????????? feature-0-200316-value
> > -????????? feature-1-200201
> > -??????? ????????? feature-1-200201-maximum
> > -??????? ????????? feature-1-200201-minimum
> > -??????? ????????? feature-1-200201-name
> > -??????? ????????? feature-1-200201-size
> > -??????? ????????? feature-1-200201-unit-expo
> > -??????? ????????? feature-1-200201-units
> > -??????? ????????? feature-1-200201-value
> > -????????? input-0-200201
> > -??????? ????????? input-0-200201-maximum
> > -??????? ????????? input-0-200201-minimum
> > -??????? ????????? input-0-200201-name
> > -??????? ????????? input-0-200201-size
> > -??????? ????????? input-0-200201-unit-expo
> > -??????? ????????? input-0-200201-units
> > -??????? ????????? input-0-200201-value
> > -????????? input-1-200202
> > -??????? ????????? input-1-200202-maximum
> > -??????? ????????? input-1-200202-minimum
> > -??????? ????????? input-1-200202-name
> > -??????? ????????? input-1-200202-size
> > -??????? ????????? input-1-200202-unit-expo
> > -??????? ????????? input-1-200202-units
> > -??????? ????????? input-1-200202-value
> > +An example of this representation on sysfs::
> > +
> > + /sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R
> > + .
> > + │ ├── enable_sensor
> > + │ │ ├── feature-0-200316
> > + │ │ │ ├── feature-0-200316-maximum
> > + │ │ │ ├── feature-0-200316-minimum
> > + │ │ │ ├── feature-0-200316-name
> > + │ │ │ ├── feature-0-200316-size
> > + │ │ │ ├── feature-0-200316-unit-expo
> > + │ │ │ ├── feature-0-200316-units
> > + │ │ │ ├── feature-0-200316-value
> > + │ │ ├── feature-1-200201
> > + │ │ │ ├── feature-1-200201-maximum
> > + │ │ │ ├── feature-1-200201-minimum
> > + │ │ │ ├── feature-1-200201-name
> > + │ │ │ ├── feature-1-200201-size
> > + │ │ │ ├── feature-1-200201-unit-expo
> > + │ │ │ ├── feature-1-200201-units
> > + │ │ │ ├── feature-1-200201-value
> > + │ │ ├── input-0-200201
> > + │ │ │ ├── input-0-200201-maximum
> > + │ │ │ ├── input-0-200201-minimum
> > + │ │ │ ├── input-0-200201-name
> > + │ │ │ ├── input-0-200201-size
> > + │ │ │ ├── input-0-200201-unit-expo
> > + │ │ │ ├── input-0-200201-units
> > + │ │ │ ├── input-0-200201-value
> > + │ │ ├── input-1-200202
> > + │ │ │ ├── input-1-200202-maximum
> > + │ │ │ ├── input-1-200202-minimum
> > + │ │ │ ├── input-1-200202-name
> > + │ │ │ ├── input-1-200202-size
> > + │ │ │ ├── input-1-200202-unit-expo
> > + │ │ │ ├── input-1-200202-units
> > + │ │ │ ├── input-1-200202-value
> >
> > Here there is a custom sensors with four fields, two feature and two inputs.
> > Each field is represented by a set of attributes. All fields except the "value"
> > are read only. The value field is a RW field.
> > -Example
> > -/sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
> > -feature-0-200316-maximum:6
> > -feature-0-200316-minimum:0
> > -feature-0-200316-name:property-reporting-state
> > -feature-0-200316-size:1
> > -feature-0-200316-unit-expo:0
> > -feature-0-200316-units:25
> > -feature-0-200316-value:1
> > +
> > +Example::
> > +
> > + /sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
> > + feature-0-200316-maximum:6
> > + feature-0-200316-minimum:0
> > + feature-0-200316-name:property-reporting-state
> > + feature-0-200316-size:1
> > + feature-0-200316-unit-expo:0
> > + feature-0-200316-units:25
> > + feature-0-200316-value:1
> >
> > How to enable such sensor?
> > +^^^^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > By default sensor can be power gated. To enable sysfs attribute "enable" can be
> > -used.
> > -$ echo 1 > enable_sensor
> > +used::
> > +
> > + $ echo 1 > enable_sensor
> >
> > Once enabled and powered on, sensor can report value using HID reports.
> > -These reports are pushed using misc device interface in a FIFO order.
> > -/dev$ tree | grep HID-SENSOR-2000e1.6.auto
> > -??????? ????????? 10:53 -> ../HID-SENSOR-2000e1.6.auto
> > -????????? HID-SENSOR-2000e1.6.auto
> > +These reports are pushed using misc device interface in a FIFO order::
> > +
> > + /dev$ tree | grep HID-SENSOR-2000e1.6.auto
> > + │ │ │ ├── 10:53 -> ../HID-SENSOR-2000e1.6.auto
> > + │ ├── HID-SENSOR-2000e1.6.auto
> >
> > Each reports can be of variable length preceded by a header. This header
> > consist of a 32 bit usage id, 64 bit time stamp and 32 bit length field of raw
> > diff --git a/Documentation/hid/hid-transport.txt b/Documentation/hid/hid-transport.rst
> > similarity index 93%
> > rename from Documentation/hid/hid-transport.txt
> > rename to Documentation/hid/hid-transport.rst
> > index 3dcba9fd4a3a..6f3aaa86ce7b 100644
> > --- a/Documentation/hid/hid-transport.txt
> > +++ b/Documentation/hid/hid-transport.rst
> > @@ -1,5 +1,6 @@
> > - HID I/O Transport Drivers
> > - ===========================
> > +=========================
> > +HID I/O Transport Drivers
> > +=========================
> >
> > The HID subsystem is independent of the underlying transport driver. Initially,
> > only USB was supported, but other specifications adopted the HID design and
> > @@ -16,6 +17,8 @@ transport and device setup/management. HID core is responsible of
> > report-parsing, report interpretation and the user-space API. Device specifics
> > and quirks are handled by all layers depending on the quirk.
> >
> > +::
> > +
> > +-----------+ +-----------+ +-----------+ +-----------+
> > | Device #1 | | Device #i | | Device #j | | Device #k |
> > +-----------+ +-----------+ +-----------+ +-----------+
> > @@ -42,8 +45,9 @@ and quirks are handled by all layers depending on the quirk.
> > +----------------+ +-----------+ +------------------+ +------------------+
> >
> > Example Drivers:
> > - I/O: USB, I2C, Bluetooth-l2cap
> > - Transport: USB-HID, I2C-HID, BT-HIDP
> > +
> > + - I/O: USB, I2C, Bluetooth-l2cap
> > + - Transport: USB-HID, I2C-HID, BT-HIDP
> >
> > Everything below "HID Core" is simplified in this graph as it is only of
> > interest to HID device drivers. Transport drivers do not need to know the
> > @@ -183,7 +187,7 @@ Other ctrl-channel requests are supported by USB-HID but are not available
> > -------------------
> >
> > Transport drivers normally use the following procedure to register a new device
> > -with HID core:
> > +with HID core::
> >
> > struct hid_device *hid;
> > int ret;
> > @@ -215,7 +219,7 @@ Once hid_add_device() is entered, HID core might use the callbacks provided in
> > "custom_ll_driver". Note that fields like "country" can be ignored by underlying
> > transport-drivers if not supported.
> >
> > -To unregister a device, use:
> > +To unregister a device, use::
> >
> > hid_destroy_device(hid);
> >
> > @@ -226,73 +230,110 @@ driver callbacks.
> > -----------------------------
> >
> > The available HID callbacks are:
> > - - int (*start) (struct hid_device *hdev)
> > +
> > + ::
> > +
> > + int (*start) (struct hid_device *hdev)
> > +
> > Called from HID device drivers once they want to use the device. Transport
> > drivers can choose to setup their device in this callback. However, normally
> > devices are already set up before transport drivers register them to HID core
> > so this is mostly only used by USB-HID.
> >
> > - - void (*stop) (struct hid_device *hdev)
> > + ::
> > +
> > + void (*stop) (struct hid_device *hdev)
> > +
> > Called from HID device drivers once they are done with a device. Transport
> > drivers can free any buffers and deinitialize the device. But note that
> > ->start() might be called again if another HID device driver is loaded on the
> > device.
> > +
> > Transport drivers are free to ignore it and deinitialize devices after they
> > destroyed them via hid_destroy_device().
> >
> > - - int (*open) (struct hid_device *hdev)
> > + ::
> > +
> > + int (*open) (struct hid_device *hdev)
> > +
> > Called from HID device drivers once they are interested in data reports.
> > Usually, while user-space didn't open any input API/etc., device drivers are
> > not interested in device data and transport drivers can put devices asleep.
> > However, once ->open() is called, transport drivers must be ready for I/O.
> > ->open() calls are nested for each client that opens the HID device.
> >
> > - - void (*close) (struct hid_device *hdev)
> > + ::
> > +
> > + void (*close) (struct hid_device *hdev)
> > +
> > Called from HID device drivers after ->open() was called but they are no
> > longer interested in device reports. (Usually if user-space closed any input
> > devices of the driver).
> > +
> > Transport drivers can put devices asleep and terminate any I/O of all
> > ->open() calls have been followed by a ->close() call. However, ->start() may
> > be called again if the device driver is interested in input reports again.
> >
> > - - int (*parse) (struct hid_device *hdev)
> > + ::
> > +
> > + int (*parse) (struct hid_device *hdev)
> > +
> > Called once during device setup after ->start() has been called. Transport
> > drivers must read the HID report-descriptor from the device and tell HID core
> > about it via hid_parse_report().
> >
> > - - int (*power) (struct hid_device *hdev, int level)
> > + ::
> > +
> > + int (*power) (struct hid_device *hdev, int level)
> > +
> > Called by HID core to give PM hints to transport drivers. Usually this is
> > analogical to the ->open() and ->close() hints and redundant.
> >
> > - - void (*request) (struct hid_device *hdev, struct hid_report *report,
> > - int reqtype)
> > + ::
> > +
> > + void (*request) (struct hid_device *hdev, struct hid_report *report,
> > + int reqtype)
> > +
> > Send an HID request on the ctrl channel. "report" contains the report that
> > should be sent and "reqtype" the request type. Request-type can be
> > HID_REQ_SET_REPORT or HID_REQ_GET_REPORT.
> > +
> > This callback is optional. If not provided, HID core will assemble a raw
> > report following the HID specs and send it via the ->raw_request() callback.
> > The transport driver is free to implement this asynchronously.
> >
> > - - int (*wait) (struct hid_device *hdev)
> > + ::
> > +
> > + int (*wait) (struct hid_device *hdev)
> > +
> > Used by HID core before calling ->request() again. A transport driver can use
> > it to wait for any pending requests to complete if only one request is
> > allowed at a time.
> >
> > - - int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
> > - __u8 *buf, size_t count, unsigned char rtype,
> > - int reqtype)
> > + ::
> > +
> > + int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
> > + __u8 *buf, size_t count, unsigned char rtype,
> > + int reqtype)
> > +
> > Same as ->request() but provides the report as raw buffer. This request shall
> > be synchronous. A transport driver must not use ->wait() to complete such
> > requests. This request is mandatory and hid core will reject the device if
> > it is missing.
> >
> > - - int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)
> > + ::
> > +
> > + int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)
> > +
> > Send raw output report via intr channel. Used by some HID device drivers
> > which require high throughput for outgoing requests on the intr channel. This
> > must not cause SET_REPORT calls! This must be implemented as asynchronous
> > output report on the intr channel!
> >
> > - - int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)
> > + ::
> > +
> > + int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)
> > +
> > Perform SET/GET_IDLE request. Only used by USB-HID, do not implement!
> >
> > 2.3) Data Path
> > @@ -314,4 +355,5 @@ transport driver and not passed to hid_input_report().
> > Acknowledgements to SET_REPORT requests are not of interest to HID core.
> >
> > ----------------------------------------------------
> > +
> > Written 2013, David Herrmann <dh.herrmann@gmail.com>
> > diff --git a/Documentation/hid/hiddev.txt b/Documentation/hid/hiddev.rst
> > similarity index 77%
> > rename from Documentation/hid/hiddev.txt
> > rename to Documentation/hid/hiddev.rst
> > index 638448707aa2..209e6ba4e019 100644
> > --- a/Documentation/hid/hiddev.txt
> > +++ b/Documentation/hid/hiddev.rst
> > @@ -1,6 +1,9 @@
> > +================================================
> > Care and feeding of your Human Interface Devices
> > +================================================
> >
> > -INTRODUCTION
> > +Introduction
> > +============
> >
> > In addition to the normal input type HID devices, USB also uses the
> > human interface device protocols for things that are not really human
> > @@ -16,38 +19,40 @@ normalised event interface - see Documentation/input/input.rst
> > * the hiddev interface, which provides fairly raw HID events
> >
> > The data flow for a HID event produced by a device is something like
> > -the following :
> > +the following::
> >
> > usb.c ---> hid-core.c ----> hid-input.c ----> [keyboard/mouse/joystick/event]
> > |
> > |
> > - --> hiddev.c ----> POWER / MONITOR CONTROL
> > + --> hiddev.c ----> POWER / MONITOR CONTROL
> >
> > In addition, other subsystems (apart from USB) can potentially feed
> > events into the input subsystem, but these have no effect on the hid
> > device interface.
> >
> > -USING THE HID DEVICE INTERFACE
> > +Using the HID Device Interface
> > +==============================
> >
> > The hiddev interface is a char interface using the normal USB major,
> > with the minor numbers starting at 96 and finishing at 111. Therefore,
> > -you need the following commands:
> > -mknod /dev/usb/hiddev0 c 180 96
> > -mknod /dev/usb/hiddev1 c 180 97
> > -mknod /dev/usb/hiddev2 c 180 98
> > -mknod /dev/usb/hiddev3 c 180 99
> > -mknod /dev/usb/hiddev4 c 180 100
> > -mknod /dev/usb/hiddev5 c 180 101
> > -mknod /dev/usb/hiddev6 c 180 102
> > -mknod /dev/usb/hiddev7 c 180 103
> > -mknod /dev/usb/hiddev8 c 180 104
> > -mknod /dev/usb/hiddev9 c 180 105
> > -mknod /dev/usb/hiddev10 c 180 106
> > -mknod /dev/usb/hiddev11 c 180 107
> > -mknod /dev/usb/hiddev12 c 180 108
> > -mknod /dev/usb/hiddev13 c 180 109
> > -mknod /dev/usb/hiddev14 c 180 110
> > -mknod /dev/usb/hiddev15 c 180 111
> > +you need the following commands::
> > +
> > + mknod /dev/usb/hiddev0 c 180 96
> > + mknod /dev/usb/hiddev1 c 180 97
> > + mknod /dev/usb/hiddev2 c 180 98
> > + mknod /dev/usb/hiddev3 c 180 99
> > + mknod /dev/usb/hiddev4 c 180 100
> > + mknod /dev/usb/hiddev5 c 180 101
> > + mknod /dev/usb/hiddev6 c 180 102
> > + mknod /dev/usb/hiddev7 c 180 103
> > + mknod /dev/usb/hiddev8 c 180 104
> > + mknod /dev/usb/hiddev9 c 180 105
> > + mknod /dev/usb/hiddev10 c 180 106
> > + mknod /dev/usb/hiddev11 c 180 107
> > + mknod /dev/usb/hiddev12 c 180 108
> > + mknod /dev/usb/hiddev13 c 180 109
> > + mknod /dev/usb/hiddev14 c 180 110
> > + mknod /dev/usb/hiddev15 c 180 111
> >
> > So you point your hiddev compliant user-space program at the correct
> > interface for your device, and it all just works.
> > @@ -56,7 +61,9 @@ Assuming that you have a hiddev compliant user-space program, of
> > course. If you need to write one, read on.
> >
> >
> > -THE HIDDEV API
> > +The HIDDEV API
> > +==============
> > +
> > This description should be read in conjunction with the HID
> > specification, freely available from http://www.usb.org, and
> > conveniently linked of http://www.linux-usb.org.
> > @@ -69,12 +76,14 @@ each of which can have one or more "usages". In the hid-core,
> > each one of these usages has a single signed 32 bit value.
> >
> > read():
> > +-------
> > +
> > This is the event interface. When the HID device's state changes,
> > it performs an interrupt transfer containing a report which contains
> > the changed value. The hid-core.c module parses the report, and
> > returns to hiddev.c the individual usages that have changed within
> > the report. In its basic mode, the hiddev will make these individual
> > -usage changes available to the reader using a struct hiddev_event:
> > +usage changes available to the reader using a struct hiddev_event::
> >
> > struct hiddev_event {
> > unsigned hid;
> > @@ -90,13 +99,19 @@ behavior of the read() function can be modified using the HIDIOCSFLAG
> > ioctl() described below.
> >
> >
> > -ioctl():
> > -This is the control interface. There are a number of controls:
> > +ioctl():
> > +--------
> >
> > -HIDIOCGVERSION - int (read)
> > -Gets the version code out of the hiddev driver.
> > +This is the control interface. There are a number of controls:
> > +
> > +HIDIOCGVERSION
> > + - int (read)
> > +
> > + Gets the version code out of the hiddev driver.
> > +
> > +HIDIOCAPPLICATION
> > + - (none)
> >
> > -HIDIOCAPPLICATION - (none)
> > This ioctl call returns the HID application usage associated with the
> > hid device. The third argument to ioctl() specifies which application
> > index to get. This is useful when the device has more than one
> > @@ -104,25 +119,33 @@ application collection. If the index is invalid (greater or equal to
> > the number of application collections this device has) the ioctl
> > returns -1. You can find out beforehand how many application
> > collections the device has from the num_applications field from the
> > -hiddev_devinfo structure.
> > +hiddev_devinfo structure.
> > +
> > +HIDIOCGCOLLECTIONINFO
> > + - struct hiddev_collection_info (read/write)
> >
> > -HIDIOCGCOLLECTIONINFO - struct hiddev_collection_info (read/write)
> > This returns a superset of the information above, providing not only
> > application collections, but all the collections the device has. It
> > also returns the level the collection lives in the hierarchy.
> > -The user passes in a hiddev_collection_info struct with the index
> > -field set to the index that should be returned. The ioctl fills in
> > -the other fields. If the index is larger than the last collection
> > +The user passes in a hiddev_collection_info struct with the index
> > +field set to the index that should be returned. The ioctl fills in
> > +the other fields. If the index is larger than the last collection
> > index, the ioctl returns -1 and sets errno to -EINVAL.
> >
> > -HIDIOCGDEVINFO - struct hiddev_devinfo (read)
> > +HIDIOCGDEVINFO
> > + - struct hiddev_devinfo (read)
> > +
> > Gets a hiddev_devinfo structure which describes the device.
> >
> > -HIDIOCGSTRING - struct hiddev_string_descriptor (read/write)
> > +HIDIOCGSTRING
> > + - struct hiddev_string_descriptor (read/write)
> > +
> > Gets a string descriptor from the device. The caller must fill in the
> > "index" field to indicate which descriptor should be returned.
> >
> > -HIDIOCINITREPORT - (none)
> > +HIDIOCINITREPORT
> > + - (none)
> > +
> > Instructs the kernel to retrieve all input and feature report values
> > from the device. At this point, all the usage structures will contain
> > current values for the device, and will maintain it as the device
> > @@ -130,21 +153,29 @@ changes. Note that the use of this ioctl is unnecessary in general,
> > since later kernels automatically initialize the reports from the
> > device at attach time.
> >
> > -HIDIOCGNAME - string (variable length)
> > +HIDIOCGNAME
> > + - string (variable length)
> > +
> > Gets the device name
> >
> > -HIDIOCGREPORT - struct hiddev_report_info (write)
> > +HIDIOCGREPORT
> > + - struct hiddev_report_info (write)
> > +
> > Instructs the kernel to get a feature or input report from the device,
> > in order to selectively update the usage structures (in contrast to
> > INITREPORT).
> >
> > -HIDIOCSREPORT - struct hiddev_report_info (write)
> > +HIDIOCSREPORT
> > + - struct hiddev_report_info (write)
> > +
> > Instructs the kernel to send a report to the device. This report can
> > be filled in by the user through HIDIOCSUSAGE calls (below) to fill in
> > individual usage values in the report before sending the report in full
> > -to the device.
> > +to the device.
> > +
> > +HIDIOCGREPORTINFO
> > + - struct hiddev_report_info (read/write)
> >
> > -HIDIOCGREPORTINFO - struct hiddev_report_info (read/write)
> > Fills in a hiddev_report_info structure for the user. The report is
> > looked up by type (input, output or feature) and id, so these fields
> > must be filled in by the user. The ID can be absolute -- the actual
> > @@ -154,52 +185,67 @@ report_id) for the next report after report_id. Without a-priori
> > information about report ids, the right way to use this ioctl is to
> > use the relative IDs above to enumerate the valid IDs. The ioctl
> > returns non-zero when there is no more next ID. The real report ID is
> > -filled into the returned hiddev_report_info structure.
> > +filled into the returned hiddev_report_info structure.
> > +
> > +HIDIOCGFIELDINFO
> > + - struct hiddev_field_info (read/write)
> >
> > -HIDIOCGFIELDINFO - struct hiddev_field_info (read/write)
> > Returns the field information associated with a report in a
> > hiddev_field_info structure. The user must fill in report_id and
> > report_type in this structure, as above. The field_index should also
> > be filled in, which should be a number from 0 and maxfield-1, as
> > -returned from a previous HIDIOCGREPORTINFO call.
> > +returned from a previous HIDIOCGREPORTINFO call.
> > +
> > +HIDIOCGUCODE
> > + - struct hiddev_usage_ref (read/write)
> >
> > -HIDIOCGUCODE - struct hiddev_usage_ref (read/write)
> > Returns the usage_code in a hiddev_usage_ref structure, given that
> > given its report type, report id, field index, and index within the
> > field have already been filled into the structure.
> >
> > -HIDIOCGUSAGE - struct hiddev_usage_ref (read/write)
> > +HIDIOCGUSAGE
> > + - struct hiddev_usage_ref (read/write)
> > +
> > Returns the value of a usage in a hiddev_usage_ref structure. The
> > usage to be retrieved can be specified as above, or the user can
> > choose to fill in the report_type field and specify the report_id as
> > HID_REPORT_ID_UNKNOWN. In this case, the hiddev_usage_ref will be
> > filled in with the report and field information associated with this
> > -usage if it is found.
> > +usage if it is found.
> > +
> > +HIDIOCSUSAGE
> > + - struct hiddev_usage_ref (write)
> >
> > -HIDIOCSUSAGE - struct hiddev_usage_ref (write)
> > Sets the value of a usage in an output report. The user fills in
> > the hiddev_usage_ref structure as above, but additionally fills in
> > the value field.
> >
> > -HIDIOGCOLLECTIONINDEX - struct hiddev_usage_ref (write)
> > +HIDIOGCOLLECTIONINDEX
> > + - struct hiddev_usage_ref (write)
> > +
> > Returns the collection index associated with this usage. This
> > indicates where in the collection hierarchy this usage sits.
> >
> > -HIDIOCGFLAG - int (read)
> > -HIDIOCSFLAG - int (write)
> > +HIDIOCGFLAG
> > + - int (read)
> > +HIDIOCSFLAG
> > + - int (write)
> > +
> > These operations respectively inspect and replace the mode flags
> > that influence the read() call above. The flags are as follows:
> >
> > - HIDDEV_FLAG_UREF - read() calls will now return
> > + HIDDEV_FLAG_UREF
> > + - read() calls will now return
> > struct hiddev_usage_ref instead of struct hiddev_event.
> > This is a larger structure, but in situations where the
> > device has more than one usage in its reports with the
> > same usage code, this mode serves to resolve such
> > ambiguity.
> >
> > - HIDDEV_FLAG_REPORT - This flag can only be used in conjunction
> > + HIDDEV_FLAG_REPORT
> > + - This flag can only be used in conjunction
> > with HIDDEV_FLAG_UREF. With this flag set, when the device
> > sends a report, a struct hiddev_usage_ref will be returned
> > - to read() filled in with the report_type and report_id, but
> > + to read() filled in with the report_type and report_id, but
> > with field_index set to FIELD_INDEX_NONE. This serves as
> > additional notification when the device has sent a report.
> > diff --git a/Documentation/hid/hidraw.txt b/Documentation/hid/hidraw.rst
> > similarity index 89%
> > rename from Documentation/hid/hidraw.txt
> > rename to Documentation/hid/hidraw.rst
> > index c8436e354f44..4a4a0ba1f362 100644
> > --- a/Documentation/hid/hidraw.txt
> > +++ b/Documentation/hid/hidraw.rst
> > @@ -1,5 +1,6 @@
> > - HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices
> > - ==================================================================
> > +================================================================
> > +HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices
> > +================================================================
> >
> > The hidraw driver provides a raw interface to USB and Bluetooth Human
> > Interface Devices (HIDs). It differs from hiddev in that reports sent and
> > @@ -31,6 +32,7 @@ directly under /dev (eg: /dev/hidraw0). As this location is distribution-
> > and udev rule-dependent, applications should use libudev to locate hidraw
> > devices attached to the system. There is a tutorial on libudev with a
> > working example at:
> > +
> > http://www.signal11.us/oss/udev/
> >
> > The HIDRAW API
> > @@ -51,7 +53,7 @@ byte. For devices which do not use numbered reports, the report data
> > will begin at the first byte.
> >
> > write()
> > ---------
> > +-------
> > The write() function will write a report to the device. For USB devices, if
> > the device has an INTERRUPT OUT endpoint, the report will be sent on that
> > endpoint. If it does not, the report will be sent over the control endpoint,
> > @@ -62,38 +64,52 @@ number. If the device does not use numbered reports, the first byte should
> > be set to 0. The report data itself should begin at the second byte.
> >
> > ioctl()
> > ---------
> > +-------
> > Hidraw supports the following ioctls:
> >
> > -HIDIOCGRDESCSIZE: Get Report Descriptor Size
> > +HIDIOCGRDESCSIZE:
> > + Get Report Descriptor Size
> > +
> > This ioctl will get the size of the device's report descriptor.
> >
> > -HIDIOCGRDESC: Get Report Descriptor
> > +HIDIOCGRDESC:
> > + Get Report Descriptor
> > +
> > This ioctl returns the device's report descriptor using a
> > hidraw_report_descriptor struct. Make sure to set the size field of the
> > hidraw_report_descriptor struct to the size returned from HIDIOCGRDESCSIZE.
> >
> > -HIDIOCGRAWINFO: Get Raw Info
> > +HIDIOCGRAWINFO:
> > + Get Raw Info
> > +
> > This ioctl will return a hidraw_devinfo struct containing the bus type, the
> > vendor ID (VID), and product ID (PID) of the device. The bus type can be one
> > -of:
> > - BUS_USB
> > - BUS_HIL
> > - BUS_BLUETOOTH
> > - BUS_VIRTUAL
> > +of::
> > +
> > + - BUS_USB
> > + - BUS_HIL
> > + - BUS_BLUETOOTH
> > + - BUS_VIRTUAL
> > +
> > which are defined in uapi/linux/input.h.
> >
> > -HIDIOCGRAWNAME(len): Get Raw Name
> > +HIDIOCGRAWNAME(len):
> > + Get Raw Name
> > +
> > This ioctl returns a string containing the vendor and product strings of
> > the device. The returned string is Unicode, UTF-8 encoded.
> >
> > -HIDIOCGRAWPHYS(len): Get Physical Address
> > +HIDIOCGRAWPHYS(len):
> > + Get Physical Address
> > +
> > This ioctl returns a string representing the physical address of the device.
> > For USB devices, the string contains the physical path to the device (the
> > USB controller, hubs, ports, etc). For Bluetooth devices, the string
> > contains the hardware (MAC) address of the device.
> >
> > -HIDIOCSFEATURE(len): Send a Feature Report
> > +HIDIOCSFEATURE(len):
> > + Send a Feature Report
> > +
> > This ioctl will send a feature report to the device. Per the HID
> > specification, feature reports are always sent using the control endpoint.
> > Set the first byte of the supplied buffer to the report number. For devices
> > @@ -101,7 +117,9 @@ which do not use numbered reports, set the first byte to 0. The report data
> > begins in the second byte. Make sure to set len accordingly, to one more
> > than the length of the report (to account for the report number).
> >
> > -HIDIOCGFEATURE(len): Get a Feature Report
> > +HIDIOCGFEATURE(len):
> > + Get a Feature Report
> > +
> > This ioctl will request a feature report from the device using the control
> > endpoint. The first byte of the supplied buffer should be set to the report
> > number of the requested report. For devices which do not use numbered
> > @@ -109,11 +127,12 @@ reports, set the first byte to 0. The report will be returned starting at
> > the first byte of the buffer (ie: the report number is not returned).
> >
> > Example
> > ----------
> > +-------
> > In samples/, find hid-example.c, which shows examples of read(), write(),
> > and all the ioctls for hidraw. The code may be used by anyone for any
> > purpose, and can serve as a starting point for developing applications using
> > hidraw.
> >
> > Document by:
> > +
> > Alan Ott <alan@signal11.us>, Signal 11 Software
> > diff --git a/Documentation/hid/index.rst b/Documentation/hid/index.rst
> > new file mode 100644
> > index 000000000000..af4324902622
> > --- /dev/null
> > +++ b/Documentation/hid/index.rst
> > @@ -0,0 +1,18 @@
> > +:orphan:
> > +
> > +=============================
> > +Human Interface Devices (HID)
> > +=============================
> > +
> > +.. toctree::
> > + :maxdepth: 1
> > +
> > + hiddev
> > + hidraw
> > + hid-sensor
> > + hid-transport
> > +
> > + uhid
> > +
> > + hid-alps
> > + intel-ish-hid
> > diff --git a/Documentation/hid/intel-ish-hid.rst b/Documentation/hid/intel-ish-hid.rst
> > new file mode 100644
> > index 000000000000..cccbf4be17d7
> > --- /dev/null
> > +++ b/Documentation/hid/intel-ish-hid.rst
> > @@ -0,0 +1,485 @@
> > +=================================
> > +Intel Integrated Sensor Hub (ISH)
> > +=================================
> > +
> > +A sensor hub enables the ability to offload sensor polling and algorithm
> > +processing to a dedicated low power co-processor. This allows the core
> > +processor to go into low power modes more often, resulting in the increased
> > +battery life.
> > +
> > +There are many vendors providing external sensor hubs confirming to HID
> > +Sensor usage tables, and used in several tablets, 2 in 1 convertible laptops
> > +and embedded products. Linux had this support since Linux 3.9.
> > +
> > +Intel® introduced integrated sensor hubs as a part of the SoC starting from
> > +Cherry Trail and now supported on multiple generations of CPU packages. There
> > +are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
> > +These ISH also comply to HID sensor specification, but the difference is the
> > +transport protocol used for communication. The current external sensor hubs
> > +mainly use HID over i2C or USB. But ISH doesn't use either i2c or USB.
> > +
> > +1. Overview
> > +===========
> > +
> > +Using a analogy with a usbhid implementation, the ISH follows a similar model
> > +for a very high speed communication::
> > +
> > + ----------------- ----------------------
> > + | USB HID | --> | ISH HID |
> > + ----------------- ----------------------
> > + ----------------- ----------------------
> > + | USB protocol | --> | ISH Transport |
> > + ----------------- ----------------------
> > + ----------------- ----------------------
> > + | EHCI/XHCI | --> | ISH IPC |
> > + ----------------- ----------------------
> > + PCI PCI
> > + ----------------- ----------------------
> > + |Host controller| --> | ISH processor |
> > + ----------------- ----------------------
> > + USB Link
> > + ----------------- ----------------------
> > + | USB End points| --> | ISH Clients |
> > + ----------------- ----------------------
> > +
> > +Like USB protocol provides a method for device enumeration, link management
> > +and user data encapsulation, the ISH also provides similar services. But it is
> > +very light weight tailored to manage and communicate with ISH client
> > +applications implemented in the firmware.
> > +
> > +The ISH allows multiple sensor management applications executing in the
> > +firmware. Like USB endpoints the messaging can be to/from a client. As part of
> > +enumeration process, these clients are identified. These clients can be simple
> > +HID sensor applications, sensor calibration application or senor firmware
> > +update application.
> > +
> > +The implementation model is similar, like USB bus, ISH transport is also
> > +implemented as a bus. Each client application executing in the ISH processor
> > +is registered as a device on this bus. The driver, which binds each device
> > +(ISH HID driver) identifies the device type and registers with the hid core.
> > +
> > +2. ISH Implementation: Block Diagram
> > +====================================
> > +
> > +::
> > +
> > + ---------------------------
> > + | User Space Applications |
> > + ---------------------------
> > +
> > + ----------------IIO ABI----------------
> > + --------------------------
> > + | IIO Sensor Drivers |
> > + --------------------------
> > + --------------------------
> > + | IIO core |
> > + --------------------------
> > + --------------------------
> > + | HID Sensor Hub MFD |
> > + --------------------------
> > + --------------------------
> > + | HID Core |
> > + --------------------------
> > + --------------------------
> > + | HID over ISH Client |
> > + --------------------------
> > + --------------------------
> > + | ISH Transport (ISHTP) |
> > + --------------------------
> > + --------------------------
> > + | IPC Drivers |
> > + --------------------------
> > + OS
> > + ---------------- PCI -----------------
> > + Hardware + Firmware
> > + ----------------------------
> > + | ISH Hardware/Firmware(FW) |
> > + ----------------------------
> > +
> > +3. High level processing in above blocks
> > +========================================
> > +
> > +3.1 Hardware Interface
> > +----------------------
> > +
> > +The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI
> > +product and vendor IDs are changed from different generations of processors. So
> > +the source code which enumerate drivers needs to update from generation to
> > +generation.
> > +
> > +3.2 Inter Processor Communication (IPC) driver
> > +----------------------------------------------
> > +
> > +Location: drivers/hid/intel-ish-hid/ipc
> > +
> > +The IPC message used memory mapped I/O. The registers are defined in
> > +hw-ish-regs.h.
> > +
> > +3.2.1 IPC/FW message types
> > +^^^^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +There are two types of messages, one for management of link and other messages
> > +are to and from transport layers.
> > +
> > +TX and RX of Transport messages
> > +...............................
> > +
> > +A set of memory mapped register offers support of multi byte messages TX and
> > +RX (E.g.IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
> > +internal queues to sequence messages and send them in order to the FW.
> > +Optionally the caller can register handler to get notification of completion.
> > +A door bell mechanism is used in messaging to trigger processing in host and
> > +client firmware side. When ISH interrupt handler is called, the ISH2HOST
> > +doorbell register is used by host drivers to determine that the interrupt
> > +is for ISH.
> > +
> > +Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
> > +register has the following format:
> > +Bits 0..6: fragment length (7 bits are used)
> > +Bits 10..13: encapsulated protocol
> > +Bits 16..19: management command (for IPC management protocol)
> > +Bit 31: doorbell trigger (signal H/W interrupt to the other side)
> > +Other bits are reserved, should be 0.
> > +
> > +3.2.2 Transport layer interface
> > +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +To abstract HW level IPC communication, a set of callbacks are registered.
> > +The transport layer uses them to send and receive messages.
> > +Refer to struct ishtp_hw_ops for callbacks.
> > +
> > +3.3 ISH Transport layer
> > +-----------------------
> > +
> > +Location: drivers/hid/intel-ish-hid/ishtp/
> > +
> > +3.3.1 A Generic Transport Layer
> > +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +The transport layer is a bi-directional protocol, which defines:
> > +- Set of commands to start, stop, connect, disconnect and flow control
> > +(ishtp/hbm.h) for details
> > +- A flow control mechanism to avoid buffer overflows
> > +
> > +This protocol resembles bus messages described in the following document:
> > +http://www.intel.com/content/dam/www/public/us/en/documents/technical-\
> > +specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"
> > +
> > +3.3.2 Connection and Flow Control Mechanism
> > +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +Each FW client and a protocol is identified by an UUID. In order to communicate
> > +to a FW client, a connection must be established using connect request and
> > +response bus messages. If successful, a pair (host_client_id and fw_client_id)
> > +will identify the connection.
> > +
> > +Once connection is established, peers send each other flow control bus messages
> > +independently. Every peer may send a message only if it has received a
> > +flow-control credit before. Once it sent a message, it may not send another one
> > +before receiving the next flow control credit.
> > +Either side can send disconnect request bus message to end communication. Also
> > +the link will be dropped if major FW reset occurs.
> > +
> > +3.3.3 Peer to Peer data transfer
> > +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +Peer to Peer data transfer can happen with or without using DMA. Depending on
> > +the sensor bandwidth requirement DMA can be enabled by using module parameter
> > +ishtp_use_dma under intel_ishtp.
> > +
> > +Each side (host and FW) manages its DMA transfer memory independently. When an
> > +ISHTP client from either host or FW side wants to send something, it decides
> > +whether to send over IPC or over DMA; for each transfer the decision is
> > +independent. The sending side sends DMA_XFER message when the message is in
> > +the respective host buffer (TX when host client sends, RX when FW client
> > +sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
> > +the sender that the memory region for that message may be reused.
> > +
> > +DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
> > +(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
> > +Additionally to DMA address communication, this sequence checks capabilities:
> > +if thw host doesn't support DMA, then it won't send DMA allocation, so FW can't
> > +send DMA; if FW doesn't support DMA then it won't respond with
> > +DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
> > +Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
> > +it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means
> > +that it already did DMA and the message resides at host. Thus, DMA_XFER
> > +and DMA_XFER_ACK act as ownership indicators.
> > +
> > +At initial state all outgoing memory belongs to the sender (TX to host, RX to
> > +FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
> > +the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
> > +needs not wait for previous DMA_XFER to be ack'ed, and may send another message
> > +as long as remaining continuous memory in its ownership is enough.
> > +In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once
> > +(up to IPC MTU), thus allowing for interrupt throttling.
> > +Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC
> > +fragments and via IPC otherwise.
> > +
> > +3.3.4 Ring Buffers
> > +^^^^^^^^^^^^^^^^^^
> > +
> > +When a client initiate a connection, a ring or RX and TX buffers are allocated.
> > +The size of ring can be specified by the client. HID client set 16 and 32 for
> > +TX and RX buffers respectively. On send request from client, the data to be
> > +sent is copied to one of the send ring buffer and scheduled to be sent using
> > +bus message protocol. These buffers are required because the FW may have not
> > +have processed the last message and may not have enough flow control credits
> > +to send. Same thing holds true on receive side and flow control is required.
> > +
> > +3.3.5 Host Enumeration
> > +^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +The host enumeration bus command allow discovery of clients present in the FW.
> > +There can be multiple sensor clients and clients for calibration function.
> > +
> > +To ease in implantation and allow independent driver handle each client
> > +this transport layer takes advantage of Linux Bus driver model. Each
> > +client is registered as device on the the transport bus (ishtp bus).
> > +
> > +Enumeration sequence of messages:
> > +
> > +- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.
> > +- FW responds with HOST_START_RES_CMD
> > +- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)
> > +- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW
> > + client IDs
> > +- For each FW ID found in that bitmap host sends
> > + HOST_CLIENT_PROPERTIES_REQ_CMD
> > +- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,
> > + max ISHTP message size, etc.
> > +- Once host received properties for that last discovered client, it considers
> > + ISHTP device fully functional (and allocates DMA buffers)
> > +
> > +3.4 HID over ISH Client
> > +-----------------------
> > +
> > +Location: drivers/hid/intel-ish-hid
> > +
> > +The ISHTP client driver is responsible for:
> > +
> > +- enumerate HID devices under FW ISH client
> > +- Get Report descriptor
> > +- Register with HID core as a LL driver
> > +- Process Get/Set feature request
> > +- Get input reports
> > +
> > +3.5 HID Sensor Hub MFD and IIO sensor drivers
> > +---------------------------------------------
> > +
> > +The functionality in these drivers is the same as an external sensor hub.
> > +Refer to
> > +Documentation/hid/hid-sensor.rst for HID sensor
> > +Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space
> > +
> > +3.6 End to End HID transport Sequence Diagram
> > +---------------------------------------------
> > +
> > +::
> > +
> > + HID-ISH-CLN ISHTP IPC HW
> > + | | | |
> > + | | |-----WAKE UP------------------>|
> > + | | | |
> > + | | |-----HOST READY--------------->|
> > + | | | |
> > + | | |<----MNG_RESET_NOTIFY_ACK----- |
> > + | | | |
> > + | |<----ISHTP_START------ | |
> > + | | | |
> > + | |<-----------------HOST_START_RES_CMD-------------------|
> > + | | | |
> > + | |------------------QUERY_SUBSCRIBER-------------------->|
> > + | | | |
> > + | |------------------HOST_ENUM_REQ_CMD------------------->|
> > + | | | |
> > + | |<-----------------HOST_ENUM_RES_CMD--------------------|
> > + | | | |
> > + | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
> > + | | | |
> > + | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
> > + | Create new device on in ishtp bus | |
> > + | | | |
> > + | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
> > + | | | |
> > + | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
> > + | Create new device on in ishtp bus | |
> > + | | | |
> > + | |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
> > + | | | |
> > + probed()
> > + |----ishtp_cl_connect--->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
> > + | | | |
> > + | |<----------------CLIENT_CONNECT_RES_CMD----------------|
> > + | | | |
> > + |register event callback | | |
> > + | | | |
> > + |ishtp_cl_send(
> > + HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW----- >|
> > + | | | |
> > + | | |<-----IRQ(IPC_PROTOCOL_ISHTP---|
> > + | | | |
> > + |<--ENUM_DEVICE RSP------| | |
> > + | | | |
> > + for each enumerated device
> > + |ishtp_cl_send(
> > + HOSTIF_GET_HID_DESCRIPTOR|----------fill ishtp_msg_hdr struct write to HW----- >|
> > + | | | |
> > + ...Response
> > + | | | |
> > + for each enumerated device
> > + |ishtp_cl_send(
> > + HOSTIF_GET_REPORT_DESCRIPTOR|--------------fill ishtp_msg_hdr struct write to HW-- >|
> > + | | | |
> > + | | | |
> > + hid_allocate_device
> > + | | | |
> > + hid_add_device | | |
> > + | | | |
> > +
> > +
> > +3.7 ISH Debugging
> > +-----------------
> > +
> > +To debug ISH, event tracing mechanism is used. To enable debug logs
> > +echo 1 > /sys/kernel/debug/tracing/events/intel_ish/enable
> > +cat sys/kernel/debug/tracing/trace
> > +
> > +3.8 ISH IIO sysfs Example on Lenovo thinkpad Yoga 260
> > +-----------------------------------------------------
> > +
> > +::
> > +
> > + root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
> > + /sys/bus/iio/devices/
> > + ├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
> > + │ ├── buffer
> > + │ │ ├── enable
> > + │ │ ├── length
> > + │ │ └── watermark
> > + ...
> > + │ ├── in_accel_hysteresis
> > + │ ├── in_accel_offset
> > + │ ├── in_accel_sampling_frequency
> > + │ ├── in_accel_scale
> > + │ ├── in_accel_x_raw
> > + │ ├── in_accel_y_raw
> > + │ ├── in_accel_z_raw
> > + │ ├── name
> > + │ ├── scan_elements
> > + │ │ ├── in_accel_x_en
> > + │ │ ├── in_accel_x_index
> > + │ │ ├── in_accel_x_type
> > + │ │ ├── in_accel_y_en
> > + │ │ ├── in_accel_y_index
> > + │ │ ├── in_accel_y_type
> > + │ │ ├── in_accel_z_en
> > + │ │ ├── in_accel_z_index
> > + │ │ └── in_accel_z_type
> > + ...
> > + │ │ ├── devices
> > + │ │ │ │ ├── buffer
> > + │ │ │ │ │ ├── enable
> > + │ │ │ │ │ ├── length
> > + │ │ │ │ │ └── watermark
> > + │ │ │ │ ├── dev
> > + │ │ │ │ ├── in_intensity_both_raw
> > + │ │ │ │ ├── in_intensity_hysteresis
> > + │ │ │ │ ├── in_intensity_offset
> > + │ │ │ │ ├── in_intensity_sampling_frequency
> > + │ │ │ │ ├── in_intensity_scale
> > + │ │ │ │ ├── name
> > + │ │ │ │ ├── scan_elements
> > + │ │ │ │ │ ├── in_intensity_both_en
> > + │ │ │ │ │ ├── in_intensity_both_index
> > + │ │ │ │ │ └── in_intensity_both_type
> > + │ │ │ │ ├── trigger
> > + │ │ │ │ │ └── current_trigger
> > + ...
> > + │ │ │ │ ├── buffer
> > + │ │ │ │ │ ├── enable
> > + │ │ │ │ │ ├── length
> > + │ │ │ │ │ └── watermark
> > + │ │ │ │ ├── dev
> > + │ │ │ │ ├── in_magn_hysteresis
> > + │ │ │ │ ├── in_magn_offset
> > + │ │ │ │ ├── in_magn_sampling_frequency
> > + │ │ │ │ ├── in_magn_scale
> > + │ │ │ │ ├── in_magn_x_raw
> > + │ │ │ │ ├── in_magn_y_raw
> > + │ │ │ │ ├── in_magn_z_raw
> > + │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_raw
> > + │ │ │ │ ├── in_rot_hysteresis
> > + │ │ │ │ ├── in_rot_offset
> > + │ │ │ │ ├── in_rot_sampling_frequency
> > + │ │ │ │ ├── in_rot_scale
> > + │ │ │ │ ├── name
> > + ...
> > + │ │ │ │ ├── scan_elements
> > + │ │ │ │ │ ├── in_magn_x_en
> > + │ │ │ │ │ ├── in_magn_x_index
> > + │ │ │ │ │ ├── in_magn_x_type
> > + │ │ │ │ │ ├── in_magn_y_en
> > + │ │ │ │ │ ├── in_magn_y_index
> > + │ │ │ │ │ ├── in_magn_y_type
> > + │ │ │ │ │ ├── in_magn_z_en
> > + │ │ │ │ │ ├── in_magn_z_index
> > + │ │ │ │ │ ├── in_magn_z_type
> > + │ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_en
> > + │ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_index
> > + │ │ │ │ │ └── in_rot_from_north_magnetic_tilt_comp_type
> > + │ │ │ │ ├── trigger
> > + │ │ │ │ │ └── current_trigger
> > + ...
> > + │ │ │ │ ├── buffer
> > + │ │ │ │ │ ├── enable
> > + │ │ │ │ │ ├── length
> > + │ │ │ │ │ └── watermark
> > + │ │ │ │ ├── dev
> > + │ │ │ │ ├── in_anglvel_hysteresis
> > + │ │ │ │ ├── in_anglvel_offset
> > + │ │ │ │ ├── in_anglvel_sampling_frequency
> > + │ │ │ │ ├── in_anglvel_scale
> > + │ │ │ │ ├── in_anglvel_x_raw
> > + │ │ │ │ ├── in_anglvel_y_raw
> > + │ │ │ │ ├── in_anglvel_z_raw
> > + │ │ │ │ ├── name
> > + │ │ │ │ ├── scan_elements
> > + │ │ │ │ │ ├── in_anglvel_x_en
> > + │ │ │ │ │ ├── in_anglvel_x_index
> > + │ │ │ │ │ ├── in_anglvel_x_type
> > + │ │ │ │ │ ├── in_anglvel_y_en
> > + │ │ │ │ │ ├── in_anglvel_y_index
> > + │ │ │ │ │ ├── in_anglvel_y_type
> > + │ │ │ │ │ ├── in_anglvel_z_en
> > + │ │ │ │ │ ├── in_anglvel_z_index
> > + │ │ │ │ │ └── in_anglvel_z_type
> > + │ │ │ │ ├── trigger
> > + │ │ │ │ │ └── current_trigger
> > + ...
> > + │ │ │ │ ├── buffer
> > + │ │ │ │ │ ├── enable
> > + │ │ │ │ │ ├── length
> > + │ │ │ │ │ └── watermark
> > + │ │ │ │ ├── dev
> > + │ │ │ │ ├── in_anglvel_hysteresis
> > + │ │ │ │ ├── in_anglvel_offset
> > + │ │ │ │ ├── in_anglvel_sampling_frequency
> > + │ │ │ │ ├── in_anglvel_scale
> > + │ │ │ │ ├── in_anglvel_x_raw
> > + │ │ │ │ ├── in_anglvel_y_raw
> > + │ │ │ │ ├── in_anglvel_z_raw
> > + │ │ │ │ ├── name
> > + │ │ │ │ ├── scan_elements
> > + │ │ │ │ │ ├── in_anglvel_x_en
> > + │ │ │ │ │ ├── in_anglvel_x_index
> > + │ │ │ │ │ ├── in_anglvel_x_type
> > + │ │ │ │ │ ├── in_anglvel_y_en
> > + │ │ │ │ │ ├── in_anglvel_y_index
> > + │ │ │ │ │ ├── in_anglvel_y_type
> > + │ │ │ │ │ ├── in_anglvel_z_en
> > + │ │ │ │ │ ├── in_anglvel_z_index
> > + │ │ │ │ │ └── in_anglvel_z_type
> > + │ │ │ │ ├── trigger
> > + │ │ │ │ │ └── current_trigger
> > + ...
> > diff --git a/Documentation/hid/intel-ish-hid.txt b/Documentation/hid/intel-ish-hid.txt
> > deleted file mode 100644
> > index d48b21c71ddd..000000000000
> > --- a/Documentation/hid/intel-ish-hid.txt
> > +++ /dev/null
> > @@ -1,454 +0,0 @@
> > -Intel Integrated Sensor Hub (ISH)
> > -===============================
> > -
> > -A sensor hub enables the ability to offload sensor polling and algorithm
> > -processing to a dedicated low power co-processor. This allows the core
> > -processor to go into low power modes more often, resulting in the increased
> > -battery life.
> > -
> > -There are many vendors providing external sensor hubs confirming to HID
> > -Sensor usage tables, and used in several tablets, 2 in 1 convertible laptops
> > -and embedded products. Linux had this support since Linux 3.9.
> > -
> > -Intel® introduced integrated sensor hubs as a part of the SoC starting from
> > -Cherry Trail and now supported on multiple generations of CPU packages. There
> > -are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
> > -These ISH also comply to HID sensor specification, but the difference is the
> > -transport protocol used for communication. The current external sensor hubs
> > -mainly use HID over i2C or USB. But ISH doesn't use either i2c or USB.
> > -
> > -1. Overview
> > -
> > -Using a analogy with a usbhid implementation, the ISH follows a similar model
> > -for a very high speed communication:
> > -
> > - ----------------- ----------------------
> > - | USB HID | --> | ISH HID |
> > - ----------------- ----------------------
> > - ----------------- ----------------------
> > - | USB protocol | --> | ISH Transport |
> > - ----------------- ----------------------
> > - ----------------- ----------------------
> > - | EHCI/XHCI | --> | ISH IPC |
> > - ----------------- ----------------------
> > - PCI PCI
> > - ----------------- ----------------------
> > - |Host controller| --> | ISH processor |
> > - ----------------- ----------------------
> > - USB Link
> > - ----------------- ----------------------
> > - | USB End points| --> | ISH Clients |
> > - ----------------- ----------------------
> > -
> > -Like USB protocol provides a method for device enumeration, link management
> > -and user data encapsulation, the ISH also provides similar services. But it is
> > -very light weight tailored to manage and communicate with ISH client
> > -applications implemented in the firmware.
> > -
> > -The ISH allows multiple sensor management applications executing in the
> > -firmware. Like USB endpoints the messaging can be to/from a client. As part of
> > -enumeration process, these clients are identified. These clients can be simple
> > -HID sensor applications, sensor calibration application or senor firmware
> > -update application.
> > -
> > -The implementation model is similar, like USB bus, ISH transport is also
> > -implemented as a bus. Each client application executing in the ISH processor
> > -is registered as a device on this bus. The driver, which binds each device
> > -(ISH HID driver) identifies the device type and registers with the hid core.
> > -
> > -2. ISH Implementation: Block Diagram
> > -
> > - ---------------------------
> > - | User Space Applications |
> > - ---------------------------
> > -
> > -----------------IIO ABI----------------
> > - --------------------------
> > - | IIO Sensor Drivers |
> > - --------------------------
> > - --------------------------
> > - | IIO core |
> > - --------------------------
> > - --------------------------
> > - | HID Sensor Hub MFD |
> > - --------------------------
> > - --------------------------
> > - | HID Core |
> > - --------------------------
> > - --------------------------
> > - | HID over ISH Client |
> > - --------------------------
> > - --------------------------
> > - | ISH Transport (ISHTP) |
> > - --------------------------
> > - --------------------------
> > - | IPC Drivers |
> > - --------------------------
> > -OS
> > ----------------- PCI -----------------
> > -Hardware + Firmware
> > - ----------------------------
> > - | ISH Hardware/Firmware(FW) |
> > - ----------------------------
> > -
> > -3. High level processing in above blocks
> > -
> > -3.1 Hardware Interface
> > -
> > -The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI
> > -product and vendor IDs are changed from different generations of processors. So
> > -the source code which enumerate drivers needs to update from generation to
> > -generation.
> > -
> > -3.2 Inter Processor Communication (IPC) driver
> > -Location: drivers/hid/intel-ish-hid/ipc
> > -
> > -The IPC message used memory mapped I/O. The registers are defined in
> > -hw-ish-regs.h.
> > -
> > -3.2.1 IPC/FW message types
> > -
> > -There are two types of messages, one for management of link and other messages
> > -are to and from transport layers.
> > -
> > -TX and RX of Transport messages
> > -
> > -A set of memory mapped register offers support of multi byte messages TX and
> > -RX (E.g.IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
> > -internal queues to sequence messages and send them in order to the FW.
> > -Optionally the caller can register handler to get notification of completion.
> > -A door bell mechanism is used in messaging to trigger processing in host and
> > -client firmware side. When ISH interrupt handler is called, the ISH2HOST
> > -doorbell register is used by host drivers to determine that the interrupt
> > -is for ISH.
> > -
> > -Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
> > -register has the following format:
> > -Bits 0..6: fragment length (7 bits are used)
> > -Bits 10..13: encapsulated protocol
> > -Bits 16..19: management command (for IPC management protocol)
> > -Bit 31: doorbell trigger (signal H/W interrupt to the other side)
> > -Other bits are reserved, should be 0.
> > -
> > -3.2.2 Transport layer interface
> > -
> > -To abstract HW level IPC communication, a set of callbacks are registered.
> > -The transport layer uses them to send and receive messages.
> > -Refer to struct ishtp_hw_ops for callbacks.
> > -
> > -3.3 ISH Transport layer
> > -Location: drivers/hid/intel-ish-hid/ishtp/
> > -
> > -3.3.1 A Generic Transport Layer
> > -
> > -The transport layer is a bi-directional protocol, which defines:
> > -- Set of commands to start, stop, connect, disconnect and flow control
> > -(ishtp/hbm.h) for details
> > -- A flow control mechanism to avoid buffer overflows
> > -
> > -This protocol resembles bus messages described in the following document:
> > -http://www.intel.com/content/dam/www/public/us/en/documents/technical-\
> > -specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"
> > -
> > -3.3.2 Connection and Flow Control Mechanism
> > -
> > -Each FW client and a protocol is identified by an UUID. In order to communicate
> > -to a FW client, a connection must be established using connect request and
> > -response bus messages. If successful, a pair (host_client_id and fw_client_id)
> > -will identify the connection.
> > -
> > -Once connection is established, peers send each other flow control bus messages
> > -independently. Every peer may send a message only if it has received a
> > -flow-control credit before. Once it sent a message, it may not send another one
> > -before receiving the next flow control credit.
> > -Either side can send disconnect request bus message to end communication. Also
> > -the link will be dropped if major FW reset occurs.
> > -
> > -3.3.3 Peer to Peer data transfer
> > -
> > -Peer to Peer data transfer can happen with or without using DMA. Depending on
> > -the sensor bandwidth requirement DMA can be enabled by using module parameter
> > -ishtp_use_dma under intel_ishtp.
> > -
> > -Each side (host and FW) manages its DMA transfer memory independently. When an
> > -ISHTP client from either host or FW side wants to send something, it decides
> > -whether to send over IPC or over DMA; for each transfer the decision is
> > -independent. The sending side sends DMA_XFER message when the message is in
> > -the respective host buffer (TX when host client sends, RX when FW client
> > -sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
> > -the sender that the memory region for that message may be reused.
> > -
> > -DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
> > -(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
> > -Additionally to DMA address communication, this sequence checks capabilities:
> > -if thw host doesn't support DMA, then it won't send DMA allocation, so FW can't
> > -send DMA; if FW doesn't support DMA then it won't respond with
> > -DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
> > -Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
> > -it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means
> > -that it already did DMA and the message resides at host. Thus, DMA_XFER
> > -and DMA_XFER_ACK act as ownership indicators.
> > -
> > -At initial state all outgoing memory belongs to the sender (TX to host, RX to
> > -FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
> > -the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
> > -needs not wait for previous DMA_XFER to be ack'ed, and may send another message
> > -as long as remaining continuous memory in its ownership is enough.
> > -In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once
> > -(up to IPC MTU), thus allowing for interrupt throttling.
> > -Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC
> > -fragments and via IPC otherwise.
> > -
> > -3.3.4 Ring Buffers
> > -
> > -When a client initiate a connection, a ring or RX and TX buffers are allocated.
> > -The size of ring can be specified by the client. HID client set 16 and 32 for
> > -TX and RX buffers respectively. On send request from client, the data to be
> > -sent is copied to one of the send ring buffer and scheduled to be sent using
> > -bus message protocol. These buffers are required because the FW may have not
> > -have processed the last message and may not have enough flow control credits
> > -to send. Same thing holds true on receive side and flow control is required.
> > -
> > -3.3.5 Host Enumeration
> > -
> > -The host enumeration bus command allow discovery of clients present in the FW.
> > -There can be multiple sensor clients and clients for calibration function.
> > -
> > -To ease in implantation and allow independent driver handle each client
> > -this transport layer takes advantage of Linux Bus driver model. Each
> > -client is registered as device on the the transport bus (ishtp bus).
> > -
> > -Enumeration sequence of messages:
> > -- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.
> > -- FW responds with HOST_START_RES_CMD
> > -- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)
> > -- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW
> > -client IDs
> > -- For each FW ID found in that bitmap host sends
> > -HOST_CLIENT_PROPERTIES_REQ_CMD
> > -- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,
> > -max ISHTP message size, etc.
> > -- Once host received properties for that last discovered client, it considers
> > -ISHTP device fully functional (and allocates DMA buffers)
> > -
> > -3.4 HID over ISH Client
> > -Location: drivers/hid/intel-ish-hid
> > -
> > -The ISHTP client driver is responsible for:
> > -- enumerate HID devices under FW ISH client
> > -- Get Report descriptor
> > -- Register with HID core as a LL driver
> > -- Process Get/Set feature request
> > -- Get input reports
> > -
> > -3.5 HID Sensor Hub MFD and IIO sensor drivers
> > -
> > -The functionality in these drivers is the same as an external sensor hub.
> > -Refer to
> > -Documentation/hid/hid-sensor.txt for HID sensor
> > -Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space
> > -
> > -3.6 End to End HID transport Sequence Diagram
> > -
> > -HID-ISH-CLN ISHTP IPC HW
> > - | | | |
> > - | | |-----WAKE UP------------------>|
> > - | | | |
> > - | | |-----HOST READY--------------->|
> > - | | | |
> > - | | |<----MNG_RESET_NOTIFY_ACK----- |
> > - | | | |
> > - | |<----ISHTP_START------ | |
> > - | | | |
> > - | |<-----------------HOST_START_RES_CMD-------------------|
> > - | | | |
> > - | |------------------QUERY_SUBSCRIBER-------------------->|
> > - | | | |
> > - | |------------------HOST_ENUM_REQ_CMD------------------->|
> > - | | | |
> > - | |<-----------------HOST_ENUM_RES_CMD--------------------|
> > - | | | |
> > - | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
> > - | | | |
> > - | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
> > - | Create new device on in ishtp bus | |
> > - | | | |
> > - | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
> > - | | | |
> > - | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
> > - | Create new device on in ishtp bus | |
> > - | | | |
> > - | |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
> > - | | | |
> > - probed()
> > - |----ishtp_cl_connect-->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
> > - | | | |
> > - | |<----------------CLIENT_CONNECT_RES_CMD----------------|
> > - | | | |
> > - |register event callback| | |
> > - | | | |
> > - |ishtp_cl_send(
> > - HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW----- >|
> > - | | | |
> > - | | |<-----IRQ(IPC_PROTOCOL_ISHTP---|
> > - | | | |
> > - |<--ENUM_DEVICE RSP-----| | |
> > - | | | |
> > -for each enumerated device
> > - |ishtp_cl_send(
> > - HOSTIF_GET_HID_DESCRIPTOR |----------fill ishtp_msg_hdr struct write to HW--- >|
> > - | | | |
> > - ...Response
> > - | | | |
> > -for each enumerated device
> > - |ishtp_cl_send(
> > - HOSTIF_GET_REPORT_DESCRIPTOR |----------fill ishtp_msg_hdr struct write to HW- >|
> > - | | | |
> > - | | | |
> > - hid_allocate_device
> > - | | | |
> > - hid_add_device | | |
> > - | | | |
> > -
> > -
> > -3.7 ISH Debugging
> > -
> > -To debug ISH, event tracing mechanism is used. To enable debug logs
> > -echo 1 > /sys/kernel/debug/tracing/events/intel_ish/enable
> > -cat sys/kernel/debug/tracing/trace
> > -
> > -3.8 ISH IIO sysfs Example on Lenovo thinkpad Yoga 260
> > -
> > -root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
> > -/sys/bus/iio/devices/
> > -├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
> > -│ ├── buffer
> > -│ │ ├── enable
> > -│ │ ├── length
> > -│ │ └── watermark
> > -...
> > -│ ├── in_accel_hysteresis
> > -│ ├── in_accel_offset
> > -│ ├── in_accel_sampling_frequency
> > -│ ├── in_accel_scale
> > -│ ├── in_accel_x_raw
> > -│ ├── in_accel_y_raw
> > -│ ├── in_accel_z_raw
> > -│ ├── name
> > -│ ├── scan_elements
> > -│ │ ├── in_accel_x_en
> > -│ │ ├── in_accel_x_index
> > -│ │ ├── in_accel_x_type
> > -│ │ ├── in_accel_y_en
> > -│ │ ├── in_accel_y_index
> > -│ │ ├── in_accel_y_type
> > -│ │ ├── in_accel_z_en
> > -│ │ ├── in_accel_z_index
> > -│ │ └── in_accel_z_type
> > -...
> > -│ │ ├── devices
> > -│ │ │ │ ├── buffer
> > -│ │ │ │ │ ├── enable
> > -│ │ │ │ │ ├── length
> > -│ │ │ │ │ └── watermark
> > -│ │ │ │ ├── dev
> > -│ │ │ │ ├── in_intensity_both_raw
> > -│ │ │ │ ├── in_intensity_hysteresis
> > -│ │ │ │ ├── in_intensity_offset
> > -│ │ │ │ ├── in_intensity_sampling_frequency
> > -│ │ │ │ ├── in_intensity_scale
> > -│ │ │ │ ├── name
> > -│ │ │ │ ├── scan_elements
> > -│ │ │ │ │ ├── in_intensity_both_en
> > -│ │ │ │ │ ├── in_intensity_both_index
> > -│ │ │ │ │ └── in_intensity_both_type
> > -│ │ │ │ ├── trigger
> > -│ │ │ │ │ └── current_trigger
> > -...
> > -│ │ │ │ ├── buffer
> > -│ │ │ │ │ ├── enable
> > -│ │ │ │ │ ├── length
> > -│ │ │ │ │ └── watermark
> > -│ │ │ │ ├── dev
> > -│ │ │ │ ├── in_magn_hysteresis
> > -│ │ │ │ ├── in_magn_offset
> > -│ │ │ │ ├── in_magn_sampling_frequency
> > -│ │ │ │ ├── in_magn_scale
> > -│ │ │ │ ├── in_magn_x_raw
> > -│ │ │ │ ├── in_magn_y_raw
> > -│ │ │ │ ├── in_magn_z_raw
> > -│ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_raw
> > -│ │ │ │ ├── in_rot_hysteresis
> > -│ │ │ │ ├── in_rot_offset
> > -│ │ │ │ ├── in_rot_sampling_frequency
> > -│ │ │ │ ├── in_rot_scale
> > -│ │ │ │ ├── name
> > -...
> > -│ │ │ │ ├── scan_elements
> > -│ │ │ │ │ ├── in_magn_x_en
> > -│ │ │ │ │ ├── in_magn_x_index
> > -│ │ │ │ │ ├── in_magn_x_type
> > -│ │ │ │ │ ├── in_magn_y_en
> > -│ │ │ │ │ ├── in_magn_y_index
> > -│ │ │ │ │ ├── in_magn_y_type
> > -│ │ │ │ │ ├── in_magn_z_en
> > -│ │ │ │ │ ├── in_magn_z_index
> > -│ │ │ │ │ ├── in_magn_z_type
> > -│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_en
> > -│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_index
> > -│ │ │ │ │ └── in_rot_from_north_magnetic_tilt_comp_type
> > -│ │ │ │ ├── trigger
> > -│ │ │ │ │ └── current_trigger
> > -...
> > -│ │ │ │ ├── buffer
> > -│ │ │ │ │ ├── enable
> > -│ │ │ │ │ ├── length
> > -│ │ │ │ │ └── watermark
> > -│ │ │ │ ├── dev
> > -│ │ │ │ ├── in_anglvel_hysteresis
> > -│ │ │ │ ├── in_anglvel_offset
> > -│ │ │ │ ├── in_anglvel_sampling_frequency
> > -│ │ │ │ ├── in_anglvel_scale
> > -│ │ │ │ ├── in_anglvel_x_raw
> > -│ │ │ │ ├── in_anglvel_y_raw
> > -│ │ │ │ ├── in_anglvel_z_raw
> > -│ │ │ │ ├── name
> > -│ │ │ │ ├── scan_elements
> > -│ │ │ │ │ ├── in_anglvel_x_en
> > -│ │ │ │ │ ├── in_anglvel_x_index
> > -│ │ │ │ │ ├── in_anglvel_x_type
> > -│ │ │ │ │ ├── in_anglvel_y_en
> > -│ │ │ │ │ ├── in_anglvel_y_index
> > -│ │ │ │ │ ├── in_anglvel_y_type
> > -│ │ │ │ │ ├── in_anglvel_z_en
> > -│ │ │ │ │ ├── in_anglvel_z_index
> > -│ │ │ │ │ └── in_anglvel_z_type
> > -│ │ │ │ ├── trigger
> > -│ │ │ │ │ └── current_trigger
> > -...
> > -│ │ │ │ ├── buffer
> > -│ │ │ │ │ ├── enable
> > -│ │ │ │ │ ├── length
> > -│ │ │ │ │ └── watermark
> > -│ │ │ │ ├── dev
> > -│ │ │ │ ├── in_anglvel_hysteresis
> > -│ │ │ │ ├── in_anglvel_offset
> > -│ │ │ │ ├── in_anglvel_sampling_frequency
> > -│ │ │ │ ├── in_anglvel_scale
> > -│ │ │ │ ├── in_anglvel_x_raw
> > -│ │ │ │ ├── in_anglvel_y_raw
> > -│ │ │ │ ├── in_anglvel_z_raw
> > -│ │ │ │ ├── name
> > -│ │ │ │ ├── scan_elements
> > -│ │ │ │ │ ├── in_anglvel_x_en
> > -│ │ │ │ │ ├── in_anglvel_x_index
> > -│ │ │ │ │ ├── in_anglvel_x_type
> > -│ │ │ │ │ ├── in_anglvel_y_en
> > -│ │ │ │ │ ├── in_anglvel_y_index
> > -│ │ │ │ │ ├── in_anglvel_y_type
> > -│ │ │ │ │ ├── in_anglvel_z_en
> > -│ │ │ │ │ ├── in_anglvel_z_index
> > -│ │ │ │ │ └── in_anglvel_z_type
> > -│ │ │ │ ├── trigger
> > -│ │ │ │ │ └── current_trigger
> > -...
> > diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.rst
> > similarity index 94%
> > rename from Documentation/hid/uhid.txt
> > rename to Documentation/hid/uhid.rst
> > index 958fff945304..b18cb96c885f 100644
> > --- a/Documentation/hid/uhid.txt
> > +++ b/Documentation/hid/uhid.rst
> > @@ -1,5 +1,6 @@
> > - UHID - User-space I/O driver support for HID subsystem
> > - ========================================================
> > +======================================================
> > +UHID - User-space I/O driver support for HID subsystem
> > +======================================================
> >
> > UHID allows user-space to implement HID transport drivers. Please see
> > hid-transport.txt for an introduction into HID transport drivers. This document
> > @@ -22,9 +23,9 @@ If a new device is detected by your HID I/O Driver and you want to register this
> > device with the HID subsystem, then you need to open /dev/uhid once for each
> > device you want to register. All further communication is done by read()'ing or
> > write()'ing "struct uhid_event" objects. Non-blocking operations are supported
> > -by setting O_NONBLOCK.
> > +by setting O_NONBLOCK::
> >
> > -struct uhid_event {
> > + struct uhid_event {
> > __u32 type;
> > union {
> > struct uhid_create2_req create2;
> > @@ -32,7 +33,7 @@ struct uhid_event {
> > struct uhid_input2_req input2;
> > ...
> > } u;
> > -};
> > + };
> >
> > The "type" field contains the ID of the event. Depending on the ID different
> > payloads are sent. You must not split a single event across multiple read()'s or
> > @@ -86,31 +87,31 @@ the request was handled successfully. O_NONBLOCK does not affect write() as
> > writes are always handled immediately in a non-blocking fashion. Future requests
> > might make use of O_NONBLOCK, though.
> >
> > - UHID_CREATE2:
> > +UHID_CREATE2:
> > This creates the internal HID device. No I/O is possible until you send this
> > event to the kernel. The payload is of type struct uhid_create2_req and
> > contains information about your device. You can start I/O now.
> >
> > - UHID_DESTROY:
> > +UHID_DESTROY:
> > This destroys the internal HID device. No further I/O will be accepted. There
> > may still be pending messages that you can receive with read() but no further
> > UHID_INPUT events can be sent to the kernel.
> > You can create a new device by sending UHID_CREATE2 again. There is no need to
> > reopen the character device.
> >
> > - UHID_INPUT2:
> > +UHID_INPUT2:
> > You must send UHID_CREATE2 before sending input to the kernel! This event
> > contains a data-payload. This is the raw data that you read from your device
> > on the interrupt channel. The kernel will parse the HID reports.
> >
> > - UHID_GET_REPORT_REPLY:
> > +UHID_GET_REPORT_REPLY:
> > If you receive a UHID_GET_REPORT request you must answer with this request.
> > You must copy the "id" field from the request into the answer. Set the "err"
> > field to 0 if no error occurred or to EIO if an I/O error occurred.
> > If "err" is 0 then you should fill the buffer of the answer with the results
> > of the GET_REPORT request and set "size" correspondingly.
> >
> > - UHID_SET_REPORT_REPLY:
> > +UHID_SET_REPORT_REPLY:
> > This is the SET_REPORT equivalent of UHID_GET_REPORT_REPLY. Unlike GET_REPORT,
> > SET_REPORT never returns a data buffer, therefore, it's sufficient to set the
> > "id" and "err" fields correctly.
> > @@ -120,16 +121,18 @@ read()
> > read() will return a queued output report. No reaction is required to any of
> > them but you should handle them according to your needs.
> >
> > - UHID_START:
> > +UHID_START:
> > This is sent when the HID device is started. Consider this as an answer to
> > UHID_CREATE2. This is always the first event that is sent. Note that this
> > event might not be available immediately after write(UHID_CREATE2) returns.
> > Device drivers might required delayed setups.
> > This event contains a payload of type uhid_start_req. The "dev_flags" field
> > describes special behaviors of a device. The following flags are defined:
> > - UHID_DEV_NUMBERED_FEATURE_REPORTS:
> > - UHID_DEV_NUMBERED_OUTPUT_REPORTS:
> > - UHID_DEV_NUMBERED_INPUT_REPORTS:
> > +
> > + - UHID_DEV_NUMBERED_FEATURE_REPORTS
> > + - UHID_DEV_NUMBERED_OUTPUT_REPORTS
> > + - UHID_DEV_NUMBERED_INPUT_REPORTS
> > +
> > Each of these flags defines whether a given report-type uses numbered
> > reports. If numbered reports are used for a type, all messages from
> > the kernel already have the report-number as prefix. Otherwise, no
> > @@ -137,33 +140,35 @@ them but you should handle them according to your needs.
> > For messages sent by user-space to the kernel, you must adjust the
> > prefixes according to these flags.
> >
> > - UHID_STOP:
> > +UHID_STOP:
> > This is sent when the HID device is stopped. Consider this as an answer to
> > UHID_DESTROY.
> > +
> > If you didn't destroy your device via UHID_DESTROY, but the kernel sends an
> > UHID_STOP event, this should usually be ignored. It means that the kernel
> > reloaded/changed the device driver loaded on your HID device (or some other
> > maintenance actions happened).
> > +
> > You can usually ignored any UHID_STOP events safely.
> >
> > - UHID_OPEN:
> > +UHID_OPEN:
> > This is sent when the HID device is opened. That is, the data that the HID
> > device provides is read by some other process. You may ignore this event but
> > it is useful for power-management. As long as you haven't received this event
> > there is actually no other process that reads your data so there is no need to
> > send UHID_INPUT2 events to the kernel.
> >
> > - UHID_CLOSE:
> > +UHID_CLOSE:
> > This is sent when there are no more processes which read the HID data. It is
> > the counterpart of UHID_OPEN and you may as well ignore this event.
> >
> > - UHID_OUTPUT:
> > +UHID_OUTPUT:
> > This is sent if the HID device driver wants to send raw data to the I/O
> > device on the interrupt channel. You should read the payload and forward it to
> > the device. The payload is of type "struct uhid_output_req".
> > This may be received even though you haven't received UHID_OPEN, yet.
> >
> > - UHID_GET_REPORT:
> > +UHID_GET_REPORT:
> > This event is sent if the kernel driver wants to perform a GET_REPORT request
> > on the control channeld as described in the HID specs. The report-type and
> > report-number are available in the payload.
> > @@ -177,11 +182,12 @@ them but you should handle them according to your needs.
> > timed out, the kernel will ignore the response silently. The "id" field is
> > never re-used, so conflicts cannot happen.
> >
> > - UHID_SET_REPORT:
> > +UHID_SET_REPORT:
> > This is the SET_REPORT equivalent of UHID_GET_REPORT. On receipt, you shall
> > send a SET_REPORT request to your hid device. Once it replies, you must tell
> > the kernel about it via UHID_SET_REPORT_REPLY.
> > The same restrictions as for UHID_GET_REPORT apply.
> >
> > ----------------------------------------------------
> > +
> > Written 2012, David Herrmann <dh.herrmann@gmail.com>
> > diff --git a/Documentation/input/input.rst b/Documentation/input/input.rst
> > index 47f86a4bf16c..0eb61e67a7b7 100644
> > --- a/Documentation/input/input.rst
> > +++ b/Documentation/input/input.rst
> > @@ -188,7 +188,7 @@ LCDs and many other purposes.
> >
> > The monitor and speaker controls should be easy to add to the hid/input
> > interface, but for the UPSs and LCDs it doesn't make much sense. For this,
> > -the hiddev interface was designed. See Documentation/hid/hiddev.txt
> > +the hiddev interface was designed. See Documentation/hid/hiddev.rst
> > for more information about it.
> >
> > The usage of the usbhid module is very simple, it takes no parameters,
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 8d39979e4091..969225e6bfce 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -16383,7 +16383,7 @@ M: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> > L: linux-usb@vger.kernel.org
> > T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
> > S: Maintained
> > -F: Documentation/hid/hiddev.txt
> > +F: Documentation/hid/hiddev.rst
> > F: drivers/hid/usbhid/
> >
> > USB INTEL XHCI ROLE MUX DRIVER
> > --
> > 2.21.0
> >
Thanks,
Mauro
^ permalink raw reply
* Re: Re: [PATCH v6 2/5] HID: quirks: Refactor ELAN 400 and 401 handling
From: Benjamin Tissoires @ 2019-06-13 8:55 UTC (permalink / raw)
To: Jeffrey Hugo
Cc: Dmitry Torokhov, Jeffrey Hugo, Jiri Kosina, Hans de Goede,
Bjorn Andersson, Andy Gross, Lee Jones, xnox, Rob Herring,
Mark Rutland, open list:HID CORE LAYER, DTML, MSM, lkml
In-Reply-To: <84e7d83f-e133-0281-612a-94d8c4319040@codeaurora.org>
On Thu, Jun 13, 2019 at 12:20 AM Jeffrey Hugo <jhugo@codeaurora.org> wrote:
>
> On 6/12/2019 3:46 PM, Dmitry Torokhov wrote:
> > On Wed, Jun 12, 2019 at 02:27:21PM -0700, Jeffrey Hugo wrote:
> >> There needs to be coordination between hid-quirks and the elan_i2c driver
> >> about which devices are handled by what drivers. Currently, both use
> >> whitelists, which results in valid devices being unhandled by default,
> >> when they should not be rejected by hid-quirks. This is quickly becoming
> >> an issue.
> >>
> >> Since elan_i2c has a maintained whitelist of what devices it will handle,
> >> which is now in a header file that hid-quirks can access, use that to
> >> implement a blacklist in hid-quirks so that only the devices that need to
> >> be handled by elan_i2c get rejected by hid-quirks, and everything else is
> >> handled by default.
> >>
> >> Suggested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> >> Signed-off-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com>
> >> ---
> >> drivers/hid/hid-quirks.c | 27 ++++++++++++++++-----------
> >> 1 file changed, 16 insertions(+), 11 deletions(-)
> >>
> >> diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
> >> index e5ca6fe2ca57..bd81bb090222 100644
> >> --- a/drivers/hid/hid-quirks.c
> >> +++ b/drivers/hid/hid-quirks.c
> >> @@ -16,6 +16,7 @@
> >> #include <linux/export.h>
> >> #include <linux/slab.h>
> >> #include <linux/mutex.h>
> >> +#include <linux/input/elan-i2c-ids.h>
> >>
> >> #include "hid-ids.h"
> >>
> >> @@ -914,6 +915,8 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
> >>
> >> bool hid_ignore(struct hid_device *hdev)
> >> {
> >> + int i;
> >> +
> >> if (hdev->quirks & HID_QUIRK_NO_IGNORE)
> >> return false;
> >> if (hdev->quirks & HID_QUIRK_IGNORE)
> >> @@ -978,18 +981,20 @@ bool hid_ignore(struct hid_device *hdev)
> >> break;
> >> case USB_VENDOR_ID_ELAN:
> >> /*
> >> - * Many Elan devices have a product id of 0x0401 and are handled
> >> - * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
> >> - * is not (and cannot be) handled by that driver ->
> >> - * Ignore all 0x0401 devs except for the ELAN0800 dev.
> >> + * Blacklist of everything that gets handled by the elan_i2c
> >> + * input driver. This avoids disabling valid touchpads and
> >> + * other ELAN devices.
> >> */
> >> - if (hdev->product == 0x0401 &&
> >> - strncmp(hdev->name, "ELAN0800", 8) != 0)
> >> - return true;
> >> - /* Same with product id 0x0400 */
> >> - if (hdev->product == 0x0400 &&
> >> - strncmp(hdev->name, "QTEC0001", 8) != 0)
> >> - return true;
> >> + if ((hdev->product == 0x0401 || hdev->product == 0x0400)) {
> >> + for (i = 0; strlen(elan_acpi_id[i].id); ++i)
> >> + if (!strncmp(hdev->name, elan_acpi_id[i].id,
> >> + strlen(elan_acpi_id[i].id)))
> >> + return true;
> >> + for (i = 0; strlen(elan_of_match[i].name); ++i)
> >> + if (!strncmp(hdev->name, elan_of_match[i].name,
> >> + strlen(elan_of_match[i].name)))
> >> + return true;
> >
> > Do we really need to blacklist the OF case here? I thought that in ACPI
> > case we have clashes as HID gets matched by elan_i2c and CID is matched
> > by i2c-hid, but I do not believe we'll run into the same situation on OF
> > systems.
>
> I think its the safer approach.
>
> On an OF system, such as patch 3 in the series, the "hid-over-i2c" will
> end up running through this (kind of the whole reason why this series
> exists). The vendor and product ids will still match, so we'll end up
> going through the lists to see if the hdev->name (the compatible string)
> will match the blacklist. "hid-over-i2c" won't match the blacklist, but
> if there is a more specific compatible, it might.
>
> In that case, not matching OF would work, however how it could break
> today is if both "hid-over-i2c" and "elan,ekth3000" were listed for the
> same device, and elan_i2c was not compiled. In that case, if we skip
> the OF part of the black list, hid-quirks will not reject the device,
> and you'll probably have some odd behavior instead of the obvious "the
> device doesn't work because the correct driver isn't present" behavior.
>
> While that scenario might be far fetched since having both
> "hid-over-i2c" and "elan,ekth3000" probably violates the OF bindings,
> its still safer to include the OF case in the blacklist against future
> scenarios.
>
>
Dmitry, if you are happy with Jeffrey's answer, feel free to take this
through your tree and add:
Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
I don't expect any major conflicts given on where the code is located.
Cheers,
Benjamin
^ permalink raw reply
* Re: [PATCH v1 20/31] docs: hid: convert to ReST
From: Benjamin Tissoires @ 2019-06-13 8:08 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Linux Doc Mailing List, Mauro Carvalho Chehab, lkml,
Jonathan Corbet, Jiri Kosina, Jonathan Cameron,
Srinivas Pandruvada, Dmitry Torokhov, open list:HID CORE LAYER,
linux-iio, Linux USB Mailing List
In-Reply-To: <f21a936a8a7ea5fdbcca16c91ec49265cd258acf.1560364494.git.mchehab+samsung@kernel.org>
On Wed, Jun 12, 2019 at 8:39 PM Mauro Carvalho Chehab
<mchehab+samsung@kernel.org> wrote:
>
> Rename the HID documentation files to ReST, add an
> index for them and adjust in order to produce a nice html
> output via the Sphinx build system.
>
> While here, fix the sysfs example from hid-sensor.txt, that
> has a lot of "?" instead of the proper UTF-8 characters that
> are produced by the tree command.
>
> At its new index.rst, let's add a :orphan: while this is not linked to
> the main index.rst file, in order to avoid build warnings.
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
> ---
Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Do you need to take this patch through the doc tree or should we carry
it in the HID one?
Cheers,
Benjamin
> .../hid/{hid-alps.txt => hid-alps.rst} | 85 ++-
> .../hid/{hid-sensor.txt => hid-sensor.rst} | 192 +++----
> .../{hid-transport.txt => hid-transport.rst} | 82 ++-
> Documentation/hid/{hiddev.txt => hiddev.rst} | 154 ++++--
> Documentation/hid/{hidraw.txt => hidraw.rst} | 53 +-
> Documentation/hid/index.rst | 18 +
> Documentation/hid/intel-ish-hid.rst | 485 ++++++++++++++++++
> Documentation/hid/intel-ish-hid.txt | 454 ----------------
> Documentation/hid/{uhid.txt => uhid.rst} | 46 +-
> Documentation/input/input.rst | 2 +-
> MAINTAINERS | 2 +-
> 11 files changed, 897 insertions(+), 676 deletions(-)
> rename Documentation/hid/{hid-alps.txt => hid-alps.rst} (64%)
> rename Documentation/hid/{hid-sensor.txt => hid-sensor.rst} (61%)
> rename Documentation/hid/{hid-transport.txt => hid-transport.rst} (93%)
> rename Documentation/hid/{hiddev.txt => hiddev.rst} (77%)
> rename Documentation/hid/{hidraw.txt => hidraw.rst} (89%)
> create mode 100644 Documentation/hid/index.rst
> create mode 100644 Documentation/hid/intel-ish-hid.rst
> delete mode 100644 Documentation/hid/intel-ish-hid.txt
> rename Documentation/hid/{uhid.txt => uhid.rst} (94%)
>
> diff --git a/Documentation/hid/hid-alps.txt b/Documentation/hid/hid-alps.rst
> similarity index 64%
> rename from Documentation/hid/hid-alps.txt
> rename to Documentation/hid/hid-alps.rst
> index 6b02a2447c77..e2f4c4c11e3f 100644
> --- a/Documentation/hid/hid-alps.txt
> +++ b/Documentation/hid/hid-alps.rst
> @@ -1,19 +1,26 @@
> +==========================
> ALPS HID Touchpad Protocol
> -----------------------
> +==========================
>
> Introduction
> ------------
> Currently ALPS HID driver supports U1 Touchpad device.
>
> -U1 devuce basic information.
> +U1 device basic information.
> +
> +========== ======
> Vender ID 0x044E
> Product ID 0x120B
> Version ID 0x0121
> +========== ======
>
>
> HID Descriptor
> -------------
> +--------------
> +
> +======= ==================== ===== =======================================
> Byte Field Value Notes
> +======= ==================== ===== =======================================
> 0 wHIDDescLength 001E Length of HID Descriptor : 30 bytes
> 2 bcdVersion 0100 Compliant with Version 1.00
> 4 wReportDescLength 00B2 Report Descriptor is 178 Bytes (0x00B2)
> @@ -28,32 +35,42 @@ Byte Field Value Notes
> 22 wProductID 120B Product ID 0x120B
> 24 wVersionID 0121 Version 01.21
> 26 RESERVED 0000 RESERVED
> +======= ==================== ===== =======================================
>
>
> Report ID
> -------------
> -ReportID-1 (Input Reports) (HIDUsage-Mouse) for TP&SP
> -ReportID-2 (Input Reports) (HIDUsage-keyboard) for TP
> -ReportID-3 (Input Reports) (Vendor Usage: Max 10 finger data) for TP
> -ReportID-4 (Input Reports) (Vendor Usage: ON bit data) for GP
> -ReportID-5 (Feature Reports) Feature Reports
> -ReportID-6 (Input Reports) (Vendor Usage: StickPointer data) for SP
> -ReportID-7 (Feature Reports) Flash update (Bootloader)
> +---------
> +
> +========== ================= =========================================
> +ReportID-1 (Input Reports) (HIDUsage-Mouse) for TP&SP
> +ReportID-2 (Input Reports) (HIDUsage-keyboard) for TP
> +ReportID-3 (Input Reports) (Vendor Usage: Max 10 finger data) for TP
> +ReportID-4 (Input Reports) (Vendor Usage: ON bit data) for GP
> +ReportID-5 (Feature Reports) Feature Reports
> +ReportID-6 (Input Reports) (Vendor Usage: StickPointer data) for SP
> +ReportID-7 (Feature Reports) Flash update (Bootloader)
> +========== ================= =========================================
>
>
> Data pattern
> ------------
> +
> +===== ========== ===== =================
> Case1 ReportID_1 TP/SP Relative/Relative
> Case2 ReportID_3 TP Absolute
> ReportID_6 SP Absolute
> +===== ========== ===== =================
>
>
> Command Read/Write
> ------------------
> To read/write to RAM, need to send a commands to the device.
> +
> The command format is as below.
>
> DataByte(SET_REPORT)
> +
> +===== ======================
> Byte1 Command Byte
> Byte2 Address - Byte 0 (LSB)
> Byte3 Address - Byte 1
> @@ -61,13 +78,19 @@ Byte4 Address - Byte 2
> Byte5 Address - Byte 3 (MSB)
> Byte6 Value Byte
> Byte7 Checksum
> +===== ======================
>
> Command Byte is read=0xD1/write=0xD2 .
> +
> Address is read/write RAM address.
> +
> Value Byte is writing data when you send the write commands.
> +
> When you read RAM, there is no meaning.
>
> DataByte(GET_REPORT)
> +
> +===== ======================
> Byte1 Response Byte
> Byte2 Address - Byte 0 (LSB)
> Byte3 Address - Byte 1
> @@ -75,6 +98,7 @@ Byte4 Address - Byte 2
> Byte5 Address - Byte 3 (MSB)
> Byte6 Value Byte
> Byte7 Checksum
> +===== ======================
>
> Read value is stored in Value Byte.
>
> @@ -82,7 +106,11 @@ Read value is stored in Value Byte.
> Packet Format
> Touchpad data byte
> ------------------
> - b7 b6 b5 b4 b3 b2 b1 b0
> +
> +
> +======= ======= ======= ======= ======= ======= ======= ======= =====
> +- b7 b6 b5 b4 b3 b2 b1 b0
> +======= ======= ======= ======= ======= ======= ======= ======= =====
> 1 0 0 SW6 SW5 SW4 SW3 SW2 SW1
> 2 0 0 0 Fcv Fn3 Fn2 Fn1 Fn0
> 3 Xa0_7 Xa0_6 Xa0_5 Xa0_4 Xa0_3 Xa0_2 Xa0_1 Xa0_0
> @@ -114,17 +142,25 @@ Touchpad data byte
> 25 Ya4_7 Ya4_6 Ya4_5 Ya4_4 Ya4_3 Ya4_2 Ya4_1 Ya4_0
> 26 Ya4_15 Ya4_14 Ya4_13 Ya4_12 Ya4_11 Ya4_10 Ya4_9 Ya4_8
> 27 LFB4 Zs4_6 Zs4_5 Zs4_4 Zs4_3 Zs4_2 Zs4_1 Zs4_0
> +======= ======= ======= ======= ======= ======= ======= ======= =====
>
>
> -SW1-SW6: SW ON/OFF status
> -Xan_15-0(16bit):X Absolute data of the "n"th finger
> -Yan_15-0(16bit):Y Absolute data of the "n"th finger
> -Zsn_6-0(7bit): Operation area of the "n"th finger
> +SW1-SW6:
> + SW ON/OFF status
> +Xan_15-0(16bit):
> + X Absolute data of the "n"th finger
> +Yan_15-0(16bit):
> + Y Absolute data of the "n"th finger
> +Zsn_6-0(7bit):
> + Operation area of the "n"th finger
>
>
> StickPointer data byte
> -------------------
> - b7 b6 b5 b4 b3 b2 b1 b0
> +----------------------
> +
> +======= ======= ======= ======= ======= ======= ======= ======= =====
> +- b7 b6 b5 b4 b3 b2 b1 b0
> +======= ======= ======= ======= ======= ======= ======= ======= =====
> Byte1 1 1 1 0 1 SW3 SW2 SW1
> Byte2 X7 X6 X5 X4 X3 X2 X1 X0
> Byte3 X15 X14 X13 X12 X11 X10 X9 X8
> @@ -132,8 +168,13 @@ Byte4 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
> Byte5 Y15 Y14 Y13 Y12 Y11 Y10 Y9 Y8
> Byte6 Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0
> Byte7 T&P Z14 Z13 Z12 Z11 Z10 Z9 Z8
> +======= ======= ======= ======= ======= ======= ======= ======= =====
>
> -SW1-SW3: SW ON/OFF status
> -Xn_15-0(16bit):X Absolute data
> -Yn_15-0(16bit):Y Absolute data
> -Zn_14-0(15bit):Z
> +SW1-SW3:
> + SW ON/OFF status
> +Xn_15-0(16bit):
> + X Absolute data
> +Yn_15-0(16bit):
> + Y Absolute data
> +Zn_14-0(15bit):
> + Z
> diff --git a/Documentation/hid/hid-sensor.txt b/Documentation/hid/hid-sensor.rst
> similarity index 61%
> rename from Documentation/hid/hid-sensor.txt
> rename to Documentation/hid/hid-sensor.rst
> index b287752a31cd..758972e34971 100644
> --- a/Documentation/hid/hid-sensor.txt
> +++ b/Documentation/hid/hid-sensor.rst
> @@ -1,6 +1,6 @@
> -
> +=====================
> HID Sensors Framework
> -======================
> +=====================
> HID sensor framework provides necessary interfaces to implement sensor drivers,
> which are connected to a sensor hub. The sensor hub is a HID device and it provides
> a report descriptor conforming to HID 1.12 sensor usage tables.
> @@ -15,22 +15,22 @@ the drivers themselves."
> This specification describes many usage IDs, which describe the type of sensor
> and also the individual data fields. Each sensor can have variable number of
> data fields. The length and order is specified in the report descriptor. For
> -example a part of report descriptor can look like:
> +example a part of report descriptor can look like::
>
> - INPUT(1)[INPUT]
> - ..
> - Field(2)
> - Physical(0020.0073)
> - Usage(1)
> - 0020.045f
> - Logical Minimum(-32767)
> - Logical Maximum(32767)
> - Report Size(8)
> - Report Count(1)
> - Report Offset(16)
> - Flags(Variable Absolute)
> -..
> -..
> + INPUT(1)[INPUT]
> + ..
> + Field(2)
> + Physical(0020.0073)
> + Usage(1)
> + 0020.045f
> + Logical Minimum(-32767)
> + Logical Maximum(32767)
> + Report Size(8)
> + Report Count(1)
> + Report Offset(16)
> + Flags(Variable Absolute)
> + ..
> + ..
>
> The report is indicating "sensor page (0x20)" contains an accelerometer-3D (0x73).
> This accelerometer-3D has some fields. Here for example field 2 is motion intensity
> @@ -40,13 +40,14 @@ data will use this format.
>
>
> Implementation
> -=================
> +==============
>
> This specification defines many different types of sensors with different sets of
> data fields. It is difficult to have a common input event to user space applications,
> for different sensors. For example an accelerometer can send X,Y and Z data, whereas
> an ambient light sensor can send illumination data.
> So the implementation has two parts:
> +
> - Core hid driver
> - Individual sensor processing part (sensor drivers)
>
> @@ -55,8 +56,11 @@ Core driver
> The core driver registers (hid-sensor-hub) registers as a HID driver. It parses
> report descriptors and identifies all the sensors present. It adds an MFD device
> with name HID-SENSOR-xxxx (where xxxx is usage id from the specification).
> -For example
> +
> +For example:
> +
> HID-SENSOR-200073 is registered for an Accelerometer 3D driver.
> +
> So if any driver with this name is inserted, then the probe routine for that
> function will be called. So an accelerometer processing driver can register
> with this name and will be probed if there is an accelerometer-3D detected.
> @@ -66,7 +70,8 @@ drivers to register and get events for that usage id. Also it provides parsing
> functions, which get and set each input/feature/output report.
>
> Individual sensor processing part (sensor drivers)
> ------------
> +--------------------------------------------------
> +
> The processing driver will use an interface provided by the core driver to parse
> the report and get the indexes of the fields and also can get events. This driver
> can use IIO interface to use the standard ABI defined for a type of sensor.
> @@ -75,31 +80,34 @@ can use IIO interface to use the standard ABI defined for a type of sensor.
> Core driver Interface
> =====================
>
> -Callback structure:
> -Each processing driver can use this structure to set some callbacks.
> +Callback structure::
> +
> + Each processing driver can use this structure to set some callbacks.
> int (*suspend)(..): Callback when HID suspend is received
> int (*resume)(..): Callback when HID resume is received
> int (*capture_sample)(..): Capture a sample for one of its data fields
> int (*send_event)(..): One complete event is received which can have
> multiple data fields.
>
> -Registration functions:
> -int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
> +Registration functions::
> +
> + int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
> u32 usage_id,
> struct hid_sensor_hub_callbacks *usage_callback):
>
> Registers callbacks for an usage id. The callback functions are not allowed
> -to sleep.
> +to sleep::
>
>
> -int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
> + int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
> u32 usage_id):
>
> Removes callbacks for an usage id.
>
>
> -Parsing function:
> -int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
> +Parsing function::
> +
> + int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
> u8 type,
> u32 usage_id, u32 attr_usage_id,
> struct hid_sensor_hub_attribute_info *info);
> @@ -110,26 +118,27 @@ so that fields can be set or get individually.
> These indexes avoid searching every time and getting field index to get or set.
>
>
> -Set Feature report
> -int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> +Set Feature report::
> +
> + int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> u32 field_index, s32 value);
>
> This interface is used to set a value for a field in feature report. For example
> if there is a field report_interval, which is parsed by a call to
> -sensor_hub_input_get_attribute_info before, then it can directly set that individual
> -field.
> +sensor_hub_input_get_attribute_info before, then it can directly set that
> +individual field::
>
>
> -int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> + int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> u32 field_index, s32 *value);
>
> This interface is used to get a value for a field in input report. For example
> if there is a field report_interval, which is parsed by a call to
> -sensor_hub_input_get_attribute_info before, then it can directly get that individual
> -field value.
> +sensor_hub_input_get_attribute_info before, then it can directly get that
> +individual field value::
>
>
> -int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
> + int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
> u32 usage_id,
> u32 attr_usage_id, u32 report_id);
>
> @@ -143,6 +152,8 @@ registered callback function to process the sample.
> ----------
>
> HID Custom and generic Sensors
> +------------------------------
> +
>
> HID Sensor specification defines two special sensor usage types. Since they
> don't represent a standard sensor, it is not possible to define using Linux IIO
> @@ -158,66 +169,73 @@ keyboard attached/detached or lid open/close.
> To allow application to utilize these sensors, here they are exported uses sysfs
> attribute groups, attributes and misc device interface.
>
> -An example of this representation on sysfs:
> -/sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R
> -.
> -????????? enable_sensor
> -????????? feature-0-200316
> -??????? ????????? feature-0-200316-maximum
> -??????? ????????? feature-0-200316-minimum
> -??????? ????????? feature-0-200316-name
> -??????? ????????? feature-0-200316-size
> -??????? ????????? feature-0-200316-unit-expo
> -??????? ????????? feature-0-200316-units
> -??????? ????????? feature-0-200316-value
> -????????? feature-1-200201
> -??????? ????????? feature-1-200201-maximum
> -??????? ????????? feature-1-200201-minimum
> -??????? ????????? feature-1-200201-name
> -??????? ????????? feature-1-200201-size
> -??????? ????????? feature-1-200201-unit-expo
> -??????? ????????? feature-1-200201-units
> -??????? ????????? feature-1-200201-value
> -????????? input-0-200201
> -??????? ????????? input-0-200201-maximum
> -??????? ????????? input-0-200201-minimum
> -??????? ????????? input-0-200201-name
> -??????? ????????? input-0-200201-size
> -??????? ????????? input-0-200201-unit-expo
> -??????? ????????? input-0-200201-units
> -??????? ????????? input-0-200201-value
> -????????? input-1-200202
> -??????? ????????? input-1-200202-maximum
> -??????? ????????? input-1-200202-minimum
> -??????? ????????? input-1-200202-name
> -??????? ????????? input-1-200202-size
> -??????? ????????? input-1-200202-unit-expo
> -??????? ????????? input-1-200202-units
> -??????? ????????? input-1-200202-value
> +An example of this representation on sysfs::
> +
> + /sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R
> + .
> + │ ├── enable_sensor
> + │ │ ├── feature-0-200316
> + │ │ │ ├── feature-0-200316-maximum
> + │ │ │ ├── feature-0-200316-minimum
> + │ │ │ ├── feature-0-200316-name
> + │ │ │ ├── feature-0-200316-size
> + │ │ │ ├── feature-0-200316-unit-expo
> + │ │ │ ├── feature-0-200316-units
> + │ │ │ ├── feature-0-200316-value
> + │ │ ├── feature-1-200201
> + │ │ │ ├── feature-1-200201-maximum
> + │ │ │ ├── feature-1-200201-minimum
> + │ │ │ ├── feature-1-200201-name
> + │ │ │ ├── feature-1-200201-size
> + │ │ │ ├── feature-1-200201-unit-expo
> + │ │ │ ├── feature-1-200201-units
> + │ │ │ ├── feature-1-200201-value
> + │ │ ├── input-0-200201
> + │ │ │ ├── input-0-200201-maximum
> + │ │ │ ├── input-0-200201-minimum
> + │ │ │ ├── input-0-200201-name
> + │ │ │ ├── input-0-200201-size
> + │ │ │ ├── input-0-200201-unit-expo
> + │ │ │ ├── input-0-200201-units
> + │ │ │ ├── input-0-200201-value
> + │ │ ├── input-1-200202
> + │ │ │ ├── input-1-200202-maximum
> + │ │ │ ├── input-1-200202-minimum
> + │ │ │ ├── input-1-200202-name
> + │ │ │ ├── input-1-200202-size
> + │ │ │ ├── input-1-200202-unit-expo
> + │ │ │ ├── input-1-200202-units
> + │ │ │ ├── input-1-200202-value
>
> Here there is a custom sensors with four fields, two feature and two inputs.
> Each field is represented by a set of attributes. All fields except the "value"
> are read only. The value field is a RW field.
> -Example
> -/sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
> -feature-0-200316-maximum:6
> -feature-0-200316-minimum:0
> -feature-0-200316-name:property-reporting-state
> -feature-0-200316-size:1
> -feature-0-200316-unit-expo:0
> -feature-0-200316-units:25
> -feature-0-200316-value:1
> +
> +Example::
> +
> + /sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
> + feature-0-200316-maximum:6
> + feature-0-200316-minimum:0
> + feature-0-200316-name:property-reporting-state
> + feature-0-200316-size:1
> + feature-0-200316-unit-expo:0
> + feature-0-200316-units:25
> + feature-0-200316-value:1
>
> How to enable such sensor?
> +^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> By default sensor can be power gated. To enable sysfs attribute "enable" can be
> -used.
> -$ echo 1 > enable_sensor
> +used::
> +
> + $ echo 1 > enable_sensor
>
> Once enabled and powered on, sensor can report value using HID reports.
> -These reports are pushed using misc device interface in a FIFO order.
> -/dev$ tree | grep HID-SENSOR-2000e1.6.auto
> -??????? ????????? 10:53 -> ../HID-SENSOR-2000e1.6.auto
> -????????? HID-SENSOR-2000e1.6.auto
> +These reports are pushed using misc device interface in a FIFO order::
> +
> + /dev$ tree | grep HID-SENSOR-2000e1.6.auto
> + │ │ │ ├── 10:53 -> ../HID-SENSOR-2000e1.6.auto
> + │ ├── HID-SENSOR-2000e1.6.auto
>
> Each reports can be of variable length preceded by a header. This header
> consist of a 32 bit usage id, 64 bit time stamp and 32 bit length field of raw
> diff --git a/Documentation/hid/hid-transport.txt b/Documentation/hid/hid-transport.rst
> similarity index 93%
> rename from Documentation/hid/hid-transport.txt
> rename to Documentation/hid/hid-transport.rst
> index 3dcba9fd4a3a..6f3aaa86ce7b 100644
> --- a/Documentation/hid/hid-transport.txt
> +++ b/Documentation/hid/hid-transport.rst
> @@ -1,5 +1,6 @@
> - HID I/O Transport Drivers
> - ===========================
> +=========================
> +HID I/O Transport Drivers
> +=========================
>
> The HID subsystem is independent of the underlying transport driver. Initially,
> only USB was supported, but other specifications adopted the HID design and
> @@ -16,6 +17,8 @@ transport and device setup/management. HID core is responsible of
> report-parsing, report interpretation and the user-space API. Device specifics
> and quirks are handled by all layers depending on the quirk.
>
> +::
> +
> +-----------+ +-----------+ +-----------+ +-----------+
> | Device #1 | | Device #i | | Device #j | | Device #k |
> +-----------+ +-----------+ +-----------+ +-----------+
> @@ -42,8 +45,9 @@ and quirks are handled by all layers depending on the quirk.
> +----------------+ +-----------+ +------------------+ +------------------+
>
> Example Drivers:
> - I/O: USB, I2C, Bluetooth-l2cap
> - Transport: USB-HID, I2C-HID, BT-HIDP
> +
> + - I/O: USB, I2C, Bluetooth-l2cap
> + - Transport: USB-HID, I2C-HID, BT-HIDP
>
> Everything below "HID Core" is simplified in this graph as it is only of
> interest to HID device drivers. Transport drivers do not need to know the
> @@ -183,7 +187,7 @@ Other ctrl-channel requests are supported by USB-HID but are not available
> -------------------
>
> Transport drivers normally use the following procedure to register a new device
> -with HID core:
> +with HID core::
>
> struct hid_device *hid;
> int ret;
> @@ -215,7 +219,7 @@ Once hid_add_device() is entered, HID core might use the callbacks provided in
> "custom_ll_driver". Note that fields like "country" can be ignored by underlying
> transport-drivers if not supported.
>
> -To unregister a device, use:
> +To unregister a device, use::
>
> hid_destroy_device(hid);
>
> @@ -226,73 +230,110 @@ driver callbacks.
> -----------------------------
>
> The available HID callbacks are:
> - - int (*start) (struct hid_device *hdev)
> +
> + ::
> +
> + int (*start) (struct hid_device *hdev)
> +
> Called from HID device drivers once they want to use the device. Transport
> drivers can choose to setup their device in this callback. However, normally
> devices are already set up before transport drivers register them to HID core
> so this is mostly only used by USB-HID.
>
> - - void (*stop) (struct hid_device *hdev)
> + ::
> +
> + void (*stop) (struct hid_device *hdev)
> +
> Called from HID device drivers once they are done with a device. Transport
> drivers can free any buffers and deinitialize the device. But note that
> ->start() might be called again if another HID device driver is loaded on the
> device.
> +
> Transport drivers are free to ignore it and deinitialize devices after they
> destroyed them via hid_destroy_device().
>
> - - int (*open) (struct hid_device *hdev)
> + ::
> +
> + int (*open) (struct hid_device *hdev)
> +
> Called from HID device drivers once they are interested in data reports.
> Usually, while user-space didn't open any input API/etc., device drivers are
> not interested in device data and transport drivers can put devices asleep.
> However, once ->open() is called, transport drivers must be ready for I/O.
> ->open() calls are nested for each client that opens the HID device.
>
> - - void (*close) (struct hid_device *hdev)
> + ::
> +
> + void (*close) (struct hid_device *hdev)
> +
> Called from HID device drivers after ->open() was called but they are no
> longer interested in device reports. (Usually if user-space closed any input
> devices of the driver).
> +
> Transport drivers can put devices asleep and terminate any I/O of all
> ->open() calls have been followed by a ->close() call. However, ->start() may
> be called again if the device driver is interested in input reports again.
>
> - - int (*parse) (struct hid_device *hdev)
> + ::
> +
> + int (*parse) (struct hid_device *hdev)
> +
> Called once during device setup after ->start() has been called. Transport
> drivers must read the HID report-descriptor from the device and tell HID core
> about it via hid_parse_report().
>
> - - int (*power) (struct hid_device *hdev, int level)
> + ::
> +
> + int (*power) (struct hid_device *hdev, int level)
> +
> Called by HID core to give PM hints to transport drivers. Usually this is
> analogical to the ->open() and ->close() hints and redundant.
>
> - - void (*request) (struct hid_device *hdev, struct hid_report *report,
> - int reqtype)
> + ::
> +
> + void (*request) (struct hid_device *hdev, struct hid_report *report,
> + int reqtype)
> +
> Send an HID request on the ctrl channel. "report" contains the report that
> should be sent and "reqtype" the request type. Request-type can be
> HID_REQ_SET_REPORT or HID_REQ_GET_REPORT.
> +
> This callback is optional. If not provided, HID core will assemble a raw
> report following the HID specs and send it via the ->raw_request() callback.
> The transport driver is free to implement this asynchronously.
>
> - - int (*wait) (struct hid_device *hdev)
> + ::
> +
> + int (*wait) (struct hid_device *hdev)
> +
> Used by HID core before calling ->request() again. A transport driver can use
> it to wait for any pending requests to complete if only one request is
> allowed at a time.
>
> - - int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
> - __u8 *buf, size_t count, unsigned char rtype,
> - int reqtype)
> + ::
> +
> + int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
> + __u8 *buf, size_t count, unsigned char rtype,
> + int reqtype)
> +
> Same as ->request() but provides the report as raw buffer. This request shall
> be synchronous. A transport driver must not use ->wait() to complete such
> requests. This request is mandatory and hid core will reject the device if
> it is missing.
>
> - - int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)
> + ::
> +
> + int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)
> +
> Send raw output report via intr channel. Used by some HID device drivers
> which require high throughput for outgoing requests on the intr channel. This
> must not cause SET_REPORT calls! This must be implemented as asynchronous
> output report on the intr channel!
>
> - - int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)
> + ::
> +
> + int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)
> +
> Perform SET/GET_IDLE request. Only used by USB-HID, do not implement!
>
> 2.3) Data Path
> @@ -314,4 +355,5 @@ transport driver and not passed to hid_input_report().
> Acknowledgements to SET_REPORT requests are not of interest to HID core.
>
> ----------------------------------------------------
> +
> Written 2013, David Herrmann <dh.herrmann@gmail.com>
> diff --git a/Documentation/hid/hiddev.txt b/Documentation/hid/hiddev.rst
> similarity index 77%
> rename from Documentation/hid/hiddev.txt
> rename to Documentation/hid/hiddev.rst
> index 638448707aa2..209e6ba4e019 100644
> --- a/Documentation/hid/hiddev.txt
> +++ b/Documentation/hid/hiddev.rst
> @@ -1,6 +1,9 @@
> +================================================
> Care and feeding of your Human Interface Devices
> +================================================
>
> -INTRODUCTION
> +Introduction
> +============
>
> In addition to the normal input type HID devices, USB also uses the
> human interface device protocols for things that are not really human
> @@ -16,38 +19,40 @@ normalised event interface - see Documentation/input/input.rst
> * the hiddev interface, which provides fairly raw HID events
>
> The data flow for a HID event produced by a device is something like
> -the following :
> +the following::
>
> usb.c ---> hid-core.c ----> hid-input.c ----> [keyboard/mouse/joystick/event]
> |
> |
> - --> hiddev.c ----> POWER / MONITOR CONTROL
> + --> hiddev.c ----> POWER / MONITOR CONTROL
>
> In addition, other subsystems (apart from USB) can potentially feed
> events into the input subsystem, but these have no effect on the hid
> device interface.
>
> -USING THE HID DEVICE INTERFACE
> +Using the HID Device Interface
> +==============================
>
> The hiddev interface is a char interface using the normal USB major,
> with the minor numbers starting at 96 and finishing at 111. Therefore,
> -you need the following commands:
> -mknod /dev/usb/hiddev0 c 180 96
> -mknod /dev/usb/hiddev1 c 180 97
> -mknod /dev/usb/hiddev2 c 180 98
> -mknod /dev/usb/hiddev3 c 180 99
> -mknod /dev/usb/hiddev4 c 180 100
> -mknod /dev/usb/hiddev5 c 180 101
> -mknod /dev/usb/hiddev6 c 180 102
> -mknod /dev/usb/hiddev7 c 180 103
> -mknod /dev/usb/hiddev8 c 180 104
> -mknod /dev/usb/hiddev9 c 180 105
> -mknod /dev/usb/hiddev10 c 180 106
> -mknod /dev/usb/hiddev11 c 180 107
> -mknod /dev/usb/hiddev12 c 180 108
> -mknod /dev/usb/hiddev13 c 180 109
> -mknod /dev/usb/hiddev14 c 180 110
> -mknod /dev/usb/hiddev15 c 180 111
> +you need the following commands::
> +
> + mknod /dev/usb/hiddev0 c 180 96
> + mknod /dev/usb/hiddev1 c 180 97
> + mknod /dev/usb/hiddev2 c 180 98
> + mknod /dev/usb/hiddev3 c 180 99
> + mknod /dev/usb/hiddev4 c 180 100
> + mknod /dev/usb/hiddev5 c 180 101
> + mknod /dev/usb/hiddev6 c 180 102
> + mknod /dev/usb/hiddev7 c 180 103
> + mknod /dev/usb/hiddev8 c 180 104
> + mknod /dev/usb/hiddev9 c 180 105
> + mknod /dev/usb/hiddev10 c 180 106
> + mknod /dev/usb/hiddev11 c 180 107
> + mknod /dev/usb/hiddev12 c 180 108
> + mknod /dev/usb/hiddev13 c 180 109
> + mknod /dev/usb/hiddev14 c 180 110
> + mknod /dev/usb/hiddev15 c 180 111
>
> So you point your hiddev compliant user-space program at the correct
> interface for your device, and it all just works.
> @@ -56,7 +61,9 @@ Assuming that you have a hiddev compliant user-space program, of
> course. If you need to write one, read on.
>
>
> -THE HIDDEV API
> +The HIDDEV API
> +==============
> +
> This description should be read in conjunction with the HID
> specification, freely available from http://www.usb.org, and
> conveniently linked of http://www.linux-usb.org.
> @@ -69,12 +76,14 @@ each of which can have one or more "usages". In the hid-core,
> each one of these usages has a single signed 32 bit value.
>
> read():
> +-------
> +
> This is the event interface. When the HID device's state changes,
> it performs an interrupt transfer containing a report which contains
> the changed value. The hid-core.c module parses the report, and
> returns to hiddev.c the individual usages that have changed within
> the report. In its basic mode, the hiddev will make these individual
> -usage changes available to the reader using a struct hiddev_event:
> +usage changes available to the reader using a struct hiddev_event::
>
> struct hiddev_event {
> unsigned hid;
> @@ -90,13 +99,19 @@ behavior of the read() function can be modified using the HIDIOCSFLAG
> ioctl() described below.
>
>
> -ioctl():
> -This is the control interface. There are a number of controls:
> +ioctl():
> +--------
>
> -HIDIOCGVERSION - int (read)
> -Gets the version code out of the hiddev driver.
> +This is the control interface. There are a number of controls:
> +
> +HIDIOCGVERSION
> + - int (read)
> +
> + Gets the version code out of the hiddev driver.
> +
> +HIDIOCAPPLICATION
> + - (none)
>
> -HIDIOCAPPLICATION - (none)
> This ioctl call returns the HID application usage associated with the
> hid device. The third argument to ioctl() specifies which application
> index to get. This is useful when the device has more than one
> @@ -104,25 +119,33 @@ application collection. If the index is invalid (greater or equal to
> the number of application collections this device has) the ioctl
> returns -1. You can find out beforehand how many application
> collections the device has from the num_applications field from the
> -hiddev_devinfo structure.
> +hiddev_devinfo structure.
> +
> +HIDIOCGCOLLECTIONINFO
> + - struct hiddev_collection_info (read/write)
>
> -HIDIOCGCOLLECTIONINFO - struct hiddev_collection_info (read/write)
> This returns a superset of the information above, providing not only
> application collections, but all the collections the device has. It
> also returns the level the collection lives in the hierarchy.
> -The user passes in a hiddev_collection_info struct with the index
> -field set to the index that should be returned. The ioctl fills in
> -the other fields. If the index is larger than the last collection
> +The user passes in a hiddev_collection_info struct with the index
> +field set to the index that should be returned. The ioctl fills in
> +the other fields. If the index is larger than the last collection
> index, the ioctl returns -1 and sets errno to -EINVAL.
>
> -HIDIOCGDEVINFO - struct hiddev_devinfo (read)
> +HIDIOCGDEVINFO
> + - struct hiddev_devinfo (read)
> +
> Gets a hiddev_devinfo structure which describes the device.
>
> -HIDIOCGSTRING - struct hiddev_string_descriptor (read/write)
> +HIDIOCGSTRING
> + - struct hiddev_string_descriptor (read/write)
> +
> Gets a string descriptor from the device. The caller must fill in the
> "index" field to indicate which descriptor should be returned.
>
> -HIDIOCINITREPORT - (none)
> +HIDIOCINITREPORT
> + - (none)
> +
> Instructs the kernel to retrieve all input and feature report values
> from the device. At this point, all the usage structures will contain
> current values for the device, and will maintain it as the device
> @@ -130,21 +153,29 @@ changes. Note that the use of this ioctl is unnecessary in general,
> since later kernels automatically initialize the reports from the
> device at attach time.
>
> -HIDIOCGNAME - string (variable length)
> +HIDIOCGNAME
> + - string (variable length)
> +
> Gets the device name
>
> -HIDIOCGREPORT - struct hiddev_report_info (write)
> +HIDIOCGREPORT
> + - struct hiddev_report_info (write)
> +
> Instructs the kernel to get a feature or input report from the device,
> in order to selectively update the usage structures (in contrast to
> INITREPORT).
>
> -HIDIOCSREPORT - struct hiddev_report_info (write)
> +HIDIOCSREPORT
> + - struct hiddev_report_info (write)
> +
> Instructs the kernel to send a report to the device. This report can
> be filled in by the user through HIDIOCSUSAGE calls (below) to fill in
> individual usage values in the report before sending the report in full
> -to the device.
> +to the device.
> +
> +HIDIOCGREPORTINFO
> + - struct hiddev_report_info (read/write)
>
> -HIDIOCGREPORTINFO - struct hiddev_report_info (read/write)
> Fills in a hiddev_report_info structure for the user. The report is
> looked up by type (input, output or feature) and id, so these fields
> must be filled in by the user. The ID can be absolute -- the actual
> @@ -154,52 +185,67 @@ report_id) for the next report after report_id. Without a-priori
> information about report ids, the right way to use this ioctl is to
> use the relative IDs above to enumerate the valid IDs. The ioctl
> returns non-zero when there is no more next ID. The real report ID is
> -filled into the returned hiddev_report_info structure.
> +filled into the returned hiddev_report_info structure.
> +
> +HIDIOCGFIELDINFO
> + - struct hiddev_field_info (read/write)
>
> -HIDIOCGFIELDINFO - struct hiddev_field_info (read/write)
> Returns the field information associated with a report in a
> hiddev_field_info structure. The user must fill in report_id and
> report_type in this structure, as above. The field_index should also
> be filled in, which should be a number from 0 and maxfield-1, as
> -returned from a previous HIDIOCGREPORTINFO call.
> +returned from a previous HIDIOCGREPORTINFO call.
> +
> +HIDIOCGUCODE
> + - struct hiddev_usage_ref (read/write)
>
> -HIDIOCGUCODE - struct hiddev_usage_ref (read/write)
> Returns the usage_code in a hiddev_usage_ref structure, given that
> given its report type, report id, field index, and index within the
> field have already been filled into the structure.
>
> -HIDIOCGUSAGE - struct hiddev_usage_ref (read/write)
> +HIDIOCGUSAGE
> + - struct hiddev_usage_ref (read/write)
> +
> Returns the value of a usage in a hiddev_usage_ref structure. The
> usage to be retrieved can be specified as above, or the user can
> choose to fill in the report_type field and specify the report_id as
> HID_REPORT_ID_UNKNOWN. In this case, the hiddev_usage_ref will be
> filled in with the report and field information associated with this
> -usage if it is found.
> +usage if it is found.
> +
> +HIDIOCSUSAGE
> + - struct hiddev_usage_ref (write)
>
> -HIDIOCSUSAGE - struct hiddev_usage_ref (write)
> Sets the value of a usage in an output report. The user fills in
> the hiddev_usage_ref structure as above, but additionally fills in
> the value field.
>
> -HIDIOGCOLLECTIONINDEX - struct hiddev_usage_ref (write)
> +HIDIOGCOLLECTIONINDEX
> + - struct hiddev_usage_ref (write)
> +
> Returns the collection index associated with this usage. This
> indicates where in the collection hierarchy this usage sits.
>
> -HIDIOCGFLAG - int (read)
> -HIDIOCSFLAG - int (write)
> +HIDIOCGFLAG
> + - int (read)
> +HIDIOCSFLAG
> + - int (write)
> +
> These operations respectively inspect and replace the mode flags
> that influence the read() call above. The flags are as follows:
>
> - HIDDEV_FLAG_UREF - read() calls will now return
> + HIDDEV_FLAG_UREF
> + - read() calls will now return
> struct hiddev_usage_ref instead of struct hiddev_event.
> This is a larger structure, but in situations where the
> device has more than one usage in its reports with the
> same usage code, this mode serves to resolve such
> ambiguity.
>
> - HIDDEV_FLAG_REPORT - This flag can only be used in conjunction
> + HIDDEV_FLAG_REPORT
> + - This flag can only be used in conjunction
> with HIDDEV_FLAG_UREF. With this flag set, when the device
> sends a report, a struct hiddev_usage_ref will be returned
> - to read() filled in with the report_type and report_id, but
> + to read() filled in with the report_type and report_id, but
> with field_index set to FIELD_INDEX_NONE. This serves as
> additional notification when the device has sent a report.
> diff --git a/Documentation/hid/hidraw.txt b/Documentation/hid/hidraw.rst
> similarity index 89%
> rename from Documentation/hid/hidraw.txt
> rename to Documentation/hid/hidraw.rst
> index c8436e354f44..4a4a0ba1f362 100644
> --- a/Documentation/hid/hidraw.txt
> +++ b/Documentation/hid/hidraw.rst
> @@ -1,5 +1,6 @@
> - HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices
> - ==================================================================
> +================================================================
> +HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices
> +================================================================
>
> The hidraw driver provides a raw interface to USB and Bluetooth Human
> Interface Devices (HIDs). It differs from hiddev in that reports sent and
> @@ -31,6 +32,7 @@ directly under /dev (eg: /dev/hidraw0). As this location is distribution-
> and udev rule-dependent, applications should use libudev to locate hidraw
> devices attached to the system. There is a tutorial on libudev with a
> working example at:
> +
> http://www.signal11.us/oss/udev/
>
> The HIDRAW API
> @@ -51,7 +53,7 @@ byte. For devices which do not use numbered reports, the report data
> will begin at the first byte.
>
> write()
> ---------
> +-------
> The write() function will write a report to the device. For USB devices, if
> the device has an INTERRUPT OUT endpoint, the report will be sent on that
> endpoint. If it does not, the report will be sent over the control endpoint,
> @@ -62,38 +64,52 @@ number. If the device does not use numbered reports, the first byte should
> be set to 0. The report data itself should begin at the second byte.
>
> ioctl()
> ---------
> +-------
> Hidraw supports the following ioctls:
>
> -HIDIOCGRDESCSIZE: Get Report Descriptor Size
> +HIDIOCGRDESCSIZE:
> + Get Report Descriptor Size
> +
> This ioctl will get the size of the device's report descriptor.
>
> -HIDIOCGRDESC: Get Report Descriptor
> +HIDIOCGRDESC:
> + Get Report Descriptor
> +
> This ioctl returns the device's report descriptor using a
> hidraw_report_descriptor struct. Make sure to set the size field of the
> hidraw_report_descriptor struct to the size returned from HIDIOCGRDESCSIZE.
>
> -HIDIOCGRAWINFO: Get Raw Info
> +HIDIOCGRAWINFO:
> + Get Raw Info
> +
> This ioctl will return a hidraw_devinfo struct containing the bus type, the
> vendor ID (VID), and product ID (PID) of the device. The bus type can be one
> -of:
> - BUS_USB
> - BUS_HIL
> - BUS_BLUETOOTH
> - BUS_VIRTUAL
> +of::
> +
> + - BUS_USB
> + - BUS_HIL
> + - BUS_BLUETOOTH
> + - BUS_VIRTUAL
> +
> which are defined in uapi/linux/input.h.
>
> -HIDIOCGRAWNAME(len): Get Raw Name
> +HIDIOCGRAWNAME(len):
> + Get Raw Name
> +
> This ioctl returns a string containing the vendor and product strings of
> the device. The returned string is Unicode, UTF-8 encoded.
>
> -HIDIOCGRAWPHYS(len): Get Physical Address
> +HIDIOCGRAWPHYS(len):
> + Get Physical Address
> +
> This ioctl returns a string representing the physical address of the device.
> For USB devices, the string contains the physical path to the device (the
> USB controller, hubs, ports, etc). For Bluetooth devices, the string
> contains the hardware (MAC) address of the device.
>
> -HIDIOCSFEATURE(len): Send a Feature Report
> +HIDIOCSFEATURE(len):
> + Send a Feature Report
> +
> This ioctl will send a feature report to the device. Per the HID
> specification, feature reports are always sent using the control endpoint.
> Set the first byte of the supplied buffer to the report number. For devices
> @@ -101,7 +117,9 @@ which do not use numbered reports, set the first byte to 0. The report data
> begins in the second byte. Make sure to set len accordingly, to one more
> than the length of the report (to account for the report number).
>
> -HIDIOCGFEATURE(len): Get a Feature Report
> +HIDIOCGFEATURE(len):
> + Get a Feature Report
> +
> This ioctl will request a feature report from the device using the control
> endpoint. The first byte of the supplied buffer should be set to the report
> number of the requested report. For devices which do not use numbered
> @@ -109,11 +127,12 @@ reports, set the first byte to 0. The report will be returned starting at
> the first byte of the buffer (ie: the report number is not returned).
>
> Example
> ----------
> +-------
> In samples/, find hid-example.c, which shows examples of read(), write(),
> and all the ioctls for hidraw. The code may be used by anyone for any
> purpose, and can serve as a starting point for developing applications using
> hidraw.
>
> Document by:
> +
> Alan Ott <alan@signal11.us>, Signal 11 Software
> diff --git a/Documentation/hid/index.rst b/Documentation/hid/index.rst
> new file mode 100644
> index 000000000000..af4324902622
> --- /dev/null
> +++ b/Documentation/hid/index.rst
> @@ -0,0 +1,18 @@
> +:orphan:
> +
> +=============================
> +Human Interface Devices (HID)
> +=============================
> +
> +.. toctree::
> + :maxdepth: 1
> +
> + hiddev
> + hidraw
> + hid-sensor
> + hid-transport
> +
> + uhid
> +
> + hid-alps
> + intel-ish-hid
> diff --git a/Documentation/hid/intel-ish-hid.rst b/Documentation/hid/intel-ish-hid.rst
> new file mode 100644
> index 000000000000..cccbf4be17d7
> --- /dev/null
> +++ b/Documentation/hid/intel-ish-hid.rst
> @@ -0,0 +1,485 @@
> +=================================
> +Intel Integrated Sensor Hub (ISH)
> +=================================
> +
> +A sensor hub enables the ability to offload sensor polling and algorithm
> +processing to a dedicated low power co-processor. This allows the core
> +processor to go into low power modes more often, resulting in the increased
> +battery life.
> +
> +There are many vendors providing external sensor hubs confirming to HID
> +Sensor usage tables, and used in several tablets, 2 in 1 convertible laptops
> +and embedded products. Linux had this support since Linux 3.9.
> +
> +Intel® introduced integrated sensor hubs as a part of the SoC starting from
> +Cherry Trail and now supported on multiple generations of CPU packages. There
> +are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
> +These ISH also comply to HID sensor specification, but the difference is the
> +transport protocol used for communication. The current external sensor hubs
> +mainly use HID over i2C or USB. But ISH doesn't use either i2c or USB.
> +
> +1. Overview
> +===========
> +
> +Using a analogy with a usbhid implementation, the ISH follows a similar model
> +for a very high speed communication::
> +
> + ----------------- ----------------------
> + | USB HID | --> | ISH HID |
> + ----------------- ----------------------
> + ----------------- ----------------------
> + | USB protocol | --> | ISH Transport |
> + ----------------- ----------------------
> + ----------------- ----------------------
> + | EHCI/XHCI | --> | ISH IPC |
> + ----------------- ----------------------
> + PCI PCI
> + ----------------- ----------------------
> + |Host controller| --> | ISH processor |
> + ----------------- ----------------------
> + USB Link
> + ----------------- ----------------------
> + | USB End points| --> | ISH Clients |
> + ----------------- ----------------------
> +
> +Like USB protocol provides a method for device enumeration, link management
> +and user data encapsulation, the ISH also provides similar services. But it is
> +very light weight tailored to manage and communicate with ISH client
> +applications implemented in the firmware.
> +
> +The ISH allows multiple sensor management applications executing in the
> +firmware. Like USB endpoints the messaging can be to/from a client. As part of
> +enumeration process, these clients are identified. These clients can be simple
> +HID sensor applications, sensor calibration application or senor firmware
> +update application.
> +
> +The implementation model is similar, like USB bus, ISH transport is also
> +implemented as a bus. Each client application executing in the ISH processor
> +is registered as a device on this bus. The driver, which binds each device
> +(ISH HID driver) identifies the device type and registers with the hid core.
> +
> +2. ISH Implementation: Block Diagram
> +====================================
> +
> +::
> +
> + ---------------------------
> + | User Space Applications |
> + ---------------------------
> +
> + ----------------IIO ABI----------------
> + --------------------------
> + | IIO Sensor Drivers |
> + --------------------------
> + --------------------------
> + | IIO core |
> + --------------------------
> + --------------------------
> + | HID Sensor Hub MFD |
> + --------------------------
> + --------------------------
> + | HID Core |
> + --------------------------
> + --------------------------
> + | HID over ISH Client |
> + --------------------------
> + --------------------------
> + | ISH Transport (ISHTP) |
> + --------------------------
> + --------------------------
> + | IPC Drivers |
> + --------------------------
> + OS
> + ---------------- PCI -----------------
> + Hardware + Firmware
> + ----------------------------
> + | ISH Hardware/Firmware(FW) |
> + ----------------------------
> +
> +3. High level processing in above blocks
> +========================================
> +
> +3.1 Hardware Interface
> +----------------------
> +
> +The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI
> +product and vendor IDs are changed from different generations of processors. So
> +the source code which enumerate drivers needs to update from generation to
> +generation.
> +
> +3.2 Inter Processor Communication (IPC) driver
> +----------------------------------------------
> +
> +Location: drivers/hid/intel-ish-hid/ipc
> +
> +The IPC message used memory mapped I/O. The registers are defined in
> +hw-ish-regs.h.
> +
> +3.2.1 IPC/FW message types
> +^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +There are two types of messages, one for management of link and other messages
> +are to and from transport layers.
> +
> +TX and RX of Transport messages
> +...............................
> +
> +A set of memory mapped register offers support of multi byte messages TX and
> +RX (E.g.IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
> +internal queues to sequence messages and send them in order to the FW.
> +Optionally the caller can register handler to get notification of completion.
> +A door bell mechanism is used in messaging to trigger processing in host and
> +client firmware side. When ISH interrupt handler is called, the ISH2HOST
> +doorbell register is used by host drivers to determine that the interrupt
> +is for ISH.
> +
> +Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
> +register has the following format:
> +Bits 0..6: fragment length (7 bits are used)
> +Bits 10..13: encapsulated protocol
> +Bits 16..19: management command (for IPC management protocol)
> +Bit 31: doorbell trigger (signal H/W interrupt to the other side)
> +Other bits are reserved, should be 0.
> +
> +3.2.2 Transport layer interface
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +To abstract HW level IPC communication, a set of callbacks are registered.
> +The transport layer uses them to send and receive messages.
> +Refer to struct ishtp_hw_ops for callbacks.
> +
> +3.3 ISH Transport layer
> +-----------------------
> +
> +Location: drivers/hid/intel-ish-hid/ishtp/
> +
> +3.3.1 A Generic Transport Layer
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +The transport layer is a bi-directional protocol, which defines:
> +- Set of commands to start, stop, connect, disconnect and flow control
> +(ishtp/hbm.h) for details
> +- A flow control mechanism to avoid buffer overflows
> +
> +This protocol resembles bus messages described in the following document:
> +http://www.intel.com/content/dam/www/public/us/en/documents/technical-\
> +specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"
> +
> +3.3.2 Connection and Flow Control Mechanism
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +Each FW client and a protocol is identified by an UUID. In order to communicate
> +to a FW client, a connection must be established using connect request and
> +response bus messages. If successful, a pair (host_client_id and fw_client_id)
> +will identify the connection.
> +
> +Once connection is established, peers send each other flow control bus messages
> +independently. Every peer may send a message only if it has received a
> +flow-control credit before. Once it sent a message, it may not send another one
> +before receiving the next flow control credit.
> +Either side can send disconnect request bus message to end communication. Also
> +the link will be dropped if major FW reset occurs.
> +
> +3.3.3 Peer to Peer data transfer
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +Peer to Peer data transfer can happen with or without using DMA. Depending on
> +the sensor bandwidth requirement DMA can be enabled by using module parameter
> +ishtp_use_dma under intel_ishtp.
> +
> +Each side (host and FW) manages its DMA transfer memory independently. When an
> +ISHTP client from either host or FW side wants to send something, it decides
> +whether to send over IPC or over DMA; for each transfer the decision is
> +independent. The sending side sends DMA_XFER message when the message is in
> +the respective host buffer (TX when host client sends, RX when FW client
> +sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
> +the sender that the memory region for that message may be reused.
> +
> +DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
> +(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
> +Additionally to DMA address communication, this sequence checks capabilities:
> +if thw host doesn't support DMA, then it won't send DMA allocation, so FW can't
> +send DMA; if FW doesn't support DMA then it won't respond with
> +DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
> +Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
> +it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means
> +that it already did DMA and the message resides at host. Thus, DMA_XFER
> +and DMA_XFER_ACK act as ownership indicators.
> +
> +At initial state all outgoing memory belongs to the sender (TX to host, RX to
> +FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
> +the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
> +needs not wait for previous DMA_XFER to be ack'ed, and may send another message
> +as long as remaining continuous memory in its ownership is enough.
> +In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once
> +(up to IPC MTU), thus allowing for interrupt throttling.
> +Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC
> +fragments and via IPC otherwise.
> +
> +3.3.4 Ring Buffers
> +^^^^^^^^^^^^^^^^^^
> +
> +When a client initiate a connection, a ring or RX and TX buffers are allocated.
> +The size of ring can be specified by the client. HID client set 16 and 32 for
> +TX and RX buffers respectively. On send request from client, the data to be
> +sent is copied to one of the send ring buffer and scheduled to be sent using
> +bus message protocol. These buffers are required because the FW may have not
> +have processed the last message and may not have enough flow control credits
> +to send. Same thing holds true on receive side and flow control is required.
> +
> +3.3.5 Host Enumeration
> +^^^^^^^^^^^^^^^^^^^^^^
> +
> +The host enumeration bus command allow discovery of clients present in the FW.
> +There can be multiple sensor clients and clients for calibration function.
> +
> +To ease in implantation and allow independent driver handle each client
> +this transport layer takes advantage of Linux Bus driver model. Each
> +client is registered as device on the the transport bus (ishtp bus).
> +
> +Enumeration sequence of messages:
> +
> +- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.
> +- FW responds with HOST_START_RES_CMD
> +- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)
> +- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW
> + client IDs
> +- For each FW ID found in that bitmap host sends
> + HOST_CLIENT_PROPERTIES_REQ_CMD
> +- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,
> + max ISHTP message size, etc.
> +- Once host received properties for that last discovered client, it considers
> + ISHTP device fully functional (and allocates DMA buffers)
> +
> +3.4 HID over ISH Client
> +-----------------------
> +
> +Location: drivers/hid/intel-ish-hid
> +
> +The ISHTP client driver is responsible for:
> +
> +- enumerate HID devices under FW ISH client
> +- Get Report descriptor
> +- Register with HID core as a LL driver
> +- Process Get/Set feature request
> +- Get input reports
> +
> +3.5 HID Sensor Hub MFD and IIO sensor drivers
> +---------------------------------------------
> +
> +The functionality in these drivers is the same as an external sensor hub.
> +Refer to
> +Documentation/hid/hid-sensor.rst for HID sensor
> +Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space
> +
> +3.6 End to End HID transport Sequence Diagram
> +---------------------------------------------
> +
> +::
> +
> + HID-ISH-CLN ISHTP IPC HW
> + | | | |
> + | | |-----WAKE UP------------------>|
> + | | | |
> + | | |-----HOST READY--------------->|
> + | | | |
> + | | |<----MNG_RESET_NOTIFY_ACK----- |
> + | | | |
> + | |<----ISHTP_START------ | |
> + | | | |
> + | |<-----------------HOST_START_RES_CMD-------------------|
> + | | | |
> + | |------------------QUERY_SUBSCRIBER-------------------->|
> + | | | |
> + | |------------------HOST_ENUM_REQ_CMD------------------->|
> + | | | |
> + | |<-----------------HOST_ENUM_RES_CMD--------------------|
> + | | | |
> + | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
> + | | | |
> + | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
> + | Create new device on in ishtp bus | |
> + | | | |
> + | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
> + | | | |
> + | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
> + | Create new device on in ishtp bus | |
> + | | | |
> + | |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
> + | | | |
> + probed()
> + |----ishtp_cl_connect--->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
> + | | | |
> + | |<----------------CLIENT_CONNECT_RES_CMD----------------|
> + | | | |
> + |register event callback | | |
> + | | | |
> + |ishtp_cl_send(
> + HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW----- >|
> + | | | |
> + | | |<-----IRQ(IPC_PROTOCOL_ISHTP---|
> + | | | |
> + |<--ENUM_DEVICE RSP------| | |
> + | | | |
> + for each enumerated device
> + |ishtp_cl_send(
> + HOSTIF_GET_HID_DESCRIPTOR|----------fill ishtp_msg_hdr struct write to HW----- >|
> + | | | |
> + ...Response
> + | | | |
> + for each enumerated device
> + |ishtp_cl_send(
> + HOSTIF_GET_REPORT_DESCRIPTOR|--------------fill ishtp_msg_hdr struct write to HW-- >|
> + | | | |
> + | | | |
> + hid_allocate_device
> + | | | |
> + hid_add_device | | |
> + | | | |
> +
> +
> +3.7 ISH Debugging
> +-----------------
> +
> +To debug ISH, event tracing mechanism is used. To enable debug logs
> +echo 1 > /sys/kernel/debug/tracing/events/intel_ish/enable
> +cat sys/kernel/debug/tracing/trace
> +
> +3.8 ISH IIO sysfs Example on Lenovo thinkpad Yoga 260
> +-----------------------------------------------------
> +
> +::
> +
> + root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
> + /sys/bus/iio/devices/
> + ├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
> + │ ├── buffer
> + │ │ ├── enable
> + │ │ ├── length
> + │ │ └── watermark
> + ...
> + │ ├── in_accel_hysteresis
> + │ ├── in_accel_offset
> + │ ├── in_accel_sampling_frequency
> + │ ├── in_accel_scale
> + │ ├── in_accel_x_raw
> + │ ├── in_accel_y_raw
> + │ ├── in_accel_z_raw
> + │ ├── name
> + │ ├── scan_elements
> + │ │ ├── in_accel_x_en
> + │ │ ├── in_accel_x_index
> + │ │ ├── in_accel_x_type
> + │ │ ├── in_accel_y_en
> + │ │ ├── in_accel_y_index
> + │ │ ├── in_accel_y_type
> + │ │ ├── in_accel_z_en
> + │ │ ├── in_accel_z_index
> + │ │ └── in_accel_z_type
> + ...
> + │ │ ├── devices
> + │ │ │ │ ├── buffer
> + │ │ │ │ │ ├── enable
> + │ │ │ │ │ ├── length
> + │ │ │ │ │ └── watermark
> + │ │ │ │ ├── dev
> + │ │ │ │ ├── in_intensity_both_raw
> + │ │ │ │ ├── in_intensity_hysteresis
> + │ │ │ │ ├── in_intensity_offset
> + │ │ │ │ ├── in_intensity_sampling_frequency
> + │ │ │ │ ├── in_intensity_scale
> + │ │ │ │ ├── name
> + │ │ │ │ ├── scan_elements
> + │ │ │ │ │ ├── in_intensity_both_en
> + │ │ │ │ │ ├── in_intensity_both_index
> + │ │ │ │ │ └── in_intensity_both_type
> + │ │ │ │ ├── trigger
> + │ │ │ │ │ └── current_trigger
> + ...
> + │ │ │ │ ├── buffer
> + │ │ │ │ │ ├── enable
> + │ │ │ │ │ ├── length
> + │ │ │ │ │ └── watermark
> + │ │ │ │ ├── dev
> + │ │ │ │ ├── in_magn_hysteresis
> + │ │ │ │ ├── in_magn_offset
> + │ │ │ │ ├── in_magn_sampling_frequency
> + │ │ │ │ ├── in_magn_scale
> + │ │ │ │ ├── in_magn_x_raw
> + │ │ │ │ ├── in_magn_y_raw
> + │ │ │ │ ├── in_magn_z_raw
> + │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_raw
> + │ │ │ │ ├── in_rot_hysteresis
> + │ │ │ │ ├── in_rot_offset
> + │ │ │ │ ├── in_rot_sampling_frequency
> + │ │ │ │ ├── in_rot_scale
> + │ │ │ │ ├── name
> + ...
> + │ │ │ │ ├── scan_elements
> + │ │ │ │ │ ├── in_magn_x_en
> + │ │ │ │ │ ├── in_magn_x_index
> + │ │ │ │ │ ├── in_magn_x_type
> + │ │ │ │ │ ├── in_magn_y_en
> + │ │ │ │ │ ├── in_magn_y_index
> + │ │ │ │ │ ├── in_magn_y_type
> + │ │ │ │ │ ├── in_magn_z_en
> + │ │ │ │ │ ├── in_magn_z_index
> + │ │ │ │ │ ├── in_magn_z_type
> + │ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_en
> + │ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_index
> + │ │ │ │ │ └── in_rot_from_north_magnetic_tilt_comp_type
> + │ │ │ │ ├── trigger
> + │ │ │ │ │ └── current_trigger
> + ...
> + │ │ │ │ ├── buffer
> + │ │ │ │ │ ├── enable
> + │ │ │ │ │ ├── length
> + │ │ │ │ │ └── watermark
> + │ │ │ │ ├── dev
> + │ │ │ │ ├── in_anglvel_hysteresis
> + │ │ │ │ ├── in_anglvel_offset
> + │ │ │ │ ├── in_anglvel_sampling_frequency
> + │ │ │ │ ├── in_anglvel_scale
> + │ │ │ │ ├── in_anglvel_x_raw
> + │ │ │ │ ├── in_anglvel_y_raw
> + │ │ │ │ ├── in_anglvel_z_raw
> + │ │ │ │ ├── name
> + │ │ │ │ ├── scan_elements
> + │ │ │ │ │ ├── in_anglvel_x_en
> + │ │ │ │ │ ├── in_anglvel_x_index
> + │ │ │ │ │ ├── in_anglvel_x_type
> + │ │ │ │ │ ├── in_anglvel_y_en
> + │ │ │ │ │ ├── in_anglvel_y_index
> + │ │ │ │ │ ├── in_anglvel_y_type
> + │ │ │ │ │ ├── in_anglvel_z_en
> + │ │ │ │ │ ├── in_anglvel_z_index
> + │ │ │ │ │ └── in_anglvel_z_type
> + │ │ │ │ ├── trigger
> + │ │ │ │ │ └── current_trigger
> + ...
> + │ │ │ │ ├── buffer
> + │ │ │ │ │ ├── enable
> + │ │ │ │ │ ├── length
> + │ │ │ │ │ └── watermark
> + │ │ │ │ ├── dev
> + │ │ │ │ ├── in_anglvel_hysteresis
> + │ │ │ │ ├── in_anglvel_offset
> + │ │ │ │ ├── in_anglvel_sampling_frequency
> + │ │ │ │ ├── in_anglvel_scale
> + │ │ │ │ ├── in_anglvel_x_raw
> + │ │ │ │ ├── in_anglvel_y_raw
> + │ │ │ │ ├── in_anglvel_z_raw
> + │ │ │ │ ├── name
> + │ │ │ │ ├── scan_elements
> + │ │ │ │ │ ├── in_anglvel_x_en
> + │ │ │ │ │ ├── in_anglvel_x_index
> + │ │ │ │ │ ├── in_anglvel_x_type
> + │ │ │ │ │ ├── in_anglvel_y_en
> + │ │ │ │ │ ├── in_anglvel_y_index
> + │ │ │ │ │ ├── in_anglvel_y_type
> + │ │ │ │ │ ├── in_anglvel_z_en
> + │ │ │ │ │ ├── in_anglvel_z_index
> + │ │ │ │ │ └── in_anglvel_z_type
> + │ │ │ │ ├── trigger
> + │ │ │ │ │ └── current_trigger
> + ...
> diff --git a/Documentation/hid/intel-ish-hid.txt b/Documentation/hid/intel-ish-hid.txt
> deleted file mode 100644
> index d48b21c71ddd..000000000000
> --- a/Documentation/hid/intel-ish-hid.txt
> +++ /dev/null
> @@ -1,454 +0,0 @@
> -Intel Integrated Sensor Hub (ISH)
> -===============================
> -
> -A sensor hub enables the ability to offload sensor polling and algorithm
> -processing to a dedicated low power co-processor. This allows the core
> -processor to go into low power modes more often, resulting in the increased
> -battery life.
> -
> -There are many vendors providing external sensor hubs confirming to HID
> -Sensor usage tables, and used in several tablets, 2 in 1 convertible laptops
> -and embedded products. Linux had this support since Linux 3.9.
> -
> -Intel® introduced integrated sensor hubs as a part of the SoC starting from
> -Cherry Trail and now supported on multiple generations of CPU packages. There
> -are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
> -These ISH also comply to HID sensor specification, but the difference is the
> -transport protocol used for communication. The current external sensor hubs
> -mainly use HID over i2C or USB. But ISH doesn't use either i2c or USB.
> -
> -1. Overview
> -
> -Using a analogy with a usbhid implementation, the ISH follows a similar model
> -for a very high speed communication:
> -
> - ----------------- ----------------------
> - | USB HID | --> | ISH HID |
> - ----------------- ----------------------
> - ----------------- ----------------------
> - | USB protocol | --> | ISH Transport |
> - ----------------- ----------------------
> - ----------------- ----------------------
> - | EHCI/XHCI | --> | ISH IPC |
> - ----------------- ----------------------
> - PCI PCI
> - ----------------- ----------------------
> - |Host controller| --> | ISH processor |
> - ----------------- ----------------------
> - USB Link
> - ----------------- ----------------------
> - | USB End points| --> | ISH Clients |
> - ----------------- ----------------------
> -
> -Like USB protocol provides a method for device enumeration, link management
> -and user data encapsulation, the ISH also provides similar services. But it is
> -very light weight tailored to manage and communicate with ISH client
> -applications implemented in the firmware.
> -
> -The ISH allows multiple sensor management applications executing in the
> -firmware. Like USB endpoints the messaging can be to/from a client. As part of
> -enumeration process, these clients are identified. These clients can be simple
> -HID sensor applications, sensor calibration application or senor firmware
> -update application.
> -
> -The implementation model is similar, like USB bus, ISH transport is also
> -implemented as a bus. Each client application executing in the ISH processor
> -is registered as a device on this bus. The driver, which binds each device
> -(ISH HID driver) identifies the device type and registers with the hid core.
> -
> -2. ISH Implementation: Block Diagram
> -
> - ---------------------------
> - | User Space Applications |
> - ---------------------------
> -
> -----------------IIO ABI----------------
> - --------------------------
> - | IIO Sensor Drivers |
> - --------------------------
> - --------------------------
> - | IIO core |
> - --------------------------
> - --------------------------
> - | HID Sensor Hub MFD |
> - --------------------------
> - --------------------------
> - | HID Core |
> - --------------------------
> - --------------------------
> - | HID over ISH Client |
> - --------------------------
> - --------------------------
> - | ISH Transport (ISHTP) |
> - --------------------------
> - --------------------------
> - | IPC Drivers |
> - --------------------------
> -OS
> ----------------- PCI -----------------
> -Hardware + Firmware
> - ----------------------------
> - | ISH Hardware/Firmware(FW) |
> - ----------------------------
> -
> -3. High level processing in above blocks
> -
> -3.1 Hardware Interface
> -
> -The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI
> -product and vendor IDs are changed from different generations of processors. So
> -the source code which enumerate drivers needs to update from generation to
> -generation.
> -
> -3.2 Inter Processor Communication (IPC) driver
> -Location: drivers/hid/intel-ish-hid/ipc
> -
> -The IPC message used memory mapped I/O. The registers are defined in
> -hw-ish-regs.h.
> -
> -3.2.1 IPC/FW message types
> -
> -There are two types of messages, one for management of link and other messages
> -are to and from transport layers.
> -
> -TX and RX of Transport messages
> -
> -A set of memory mapped register offers support of multi byte messages TX and
> -RX (E.g.IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
> -internal queues to sequence messages and send them in order to the FW.
> -Optionally the caller can register handler to get notification of completion.
> -A door bell mechanism is used in messaging to trigger processing in host and
> -client firmware side. When ISH interrupt handler is called, the ISH2HOST
> -doorbell register is used by host drivers to determine that the interrupt
> -is for ISH.
> -
> -Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
> -register has the following format:
> -Bits 0..6: fragment length (7 bits are used)
> -Bits 10..13: encapsulated protocol
> -Bits 16..19: management command (for IPC management protocol)
> -Bit 31: doorbell trigger (signal H/W interrupt to the other side)
> -Other bits are reserved, should be 0.
> -
> -3.2.2 Transport layer interface
> -
> -To abstract HW level IPC communication, a set of callbacks are registered.
> -The transport layer uses them to send and receive messages.
> -Refer to struct ishtp_hw_ops for callbacks.
> -
> -3.3 ISH Transport layer
> -Location: drivers/hid/intel-ish-hid/ishtp/
> -
> -3.3.1 A Generic Transport Layer
> -
> -The transport layer is a bi-directional protocol, which defines:
> -- Set of commands to start, stop, connect, disconnect and flow control
> -(ishtp/hbm.h) for details
> -- A flow control mechanism to avoid buffer overflows
> -
> -This protocol resembles bus messages described in the following document:
> -http://www.intel.com/content/dam/www/public/us/en/documents/technical-\
> -specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"
> -
> -3.3.2 Connection and Flow Control Mechanism
> -
> -Each FW client and a protocol is identified by an UUID. In order to communicate
> -to a FW client, a connection must be established using connect request and
> -response bus messages. If successful, a pair (host_client_id and fw_client_id)
> -will identify the connection.
> -
> -Once connection is established, peers send each other flow control bus messages
> -independently. Every peer may send a message only if it has received a
> -flow-control credit before. Once it sent a message, it may not send another one
> -before receiving the next flow control credit.
> -Either side can send disconnect request bus message to end communication. Also
> -the link will be dropped if major FW reset occurs.
> -
> -3.3.3 Peer to Peer data transfer
> -
> -Peer to Peer data transfer can happen with or without using DMA. Depending on
> -the sensor bandwidth requirement DMA can be enabled by using module parameter
> -ishtp_use_dma under intel_ishtp.
> -
> -Each side (host and FW) manages its DMA transfer memory independently. When an
> -ISHTP client from either host or FW side wants to send something, it decides
> -whether to send over IPC or over DMA; for each transfer the decision is
> -independent. The sending side sends DMA_XFER message when the message is in
> -the respective host buffer (TX when host client sends, RX when FW client
> -sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
> -the sender that the memory region for that message may be reused.
> -
> -DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
> -(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
> -Additionally to DMA address communication, this sequence checks capabilities:
> -if thw host doesn't support DMA, then it won't send DMA allocation, so FW can't
> -send DMA; if FW doesn't support DMA then it won't respond with
> -DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
> -Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
> -it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means
> -that it already did DMA and the message resides at host. Thus, DMA_XFER
> -and DMA_XFER_ACK act as ownership indicators.
> -
> -At initial state all outgoing memory belongs to the sender (TX to host, RX to
> -FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
> -the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
> -needs not wait for previous DMA_XFER to be ack'ed, and may send another message
> -as long as remaining continuous memory in its ownership is enough.
> -In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once
> -(up to IPC MTU), thus allowing for interrupt throttling.
> -Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC
> -fragments and via IPC otherwise.
> -
> -3.3.4 Ring Buffers
> -
> -When a client initiate a connection, a ring or RX and TX buffers are allocated.
> -The size of ring can be specified by the client. HID client set 16 and 32 for
> -TX and RX buffers respectively. On send request from client, the data to be
> -sent is copied to one of the send ring buffer and scheduled to be sent using
> -bus message protocol. These buffers are required because the FW may have not
> -have processed the last message and may not have enough flow control credits
> -to send. Same thing holds true on receive side and flow control is required.
> -
> -3.3.5 Host Enumeration
> -
> -The host enumeration bus command allow discovery of clients present in the FW.
> -There can be multiple sensor clients and clients for calibration function.
> -
> -To ease in implantation and allow independent driver handle each client
> -this transport layer takes advantage of Linux Bus driver model. Each
> -client is registered as device on the the transport bus (ishtp bus).
> -
> -Enumeration sequence of messages:
> -- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.
> -- FW responds with HOST_START_RES_CMD
> -- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)
> -- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW
> -client IDs
> -- For each FW ID found in that bitmap host sends
> -HOST_CLIENT_PROPERTIES_REQ_CMD
> -- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,
> -max ISHTP message size, etc.
> -- Once host received properties for that last discovered client, it considers
> -ISHTP device fully functional (and allocates DMA buffers)
> -
> -3.4 HID over ISH Client
> -Location: drivers/hid/intel-ish-hid
> -
> -The ISHTP client driver is responsible for:
> -- enumerate HID devices under FW ISH client
> -- Get Report descriptor
> -- Register with HID core as a LL driver
> -- Process Get/Set feature request
> -- Get input reports
> -
> -3.5 HID Sensor Hub MFD and IIO sensor drivers
> -
> -The functionality in these drivers is the same as an external sensor hub.
> -Refer to
> -Documentation/hid/hid-sensor.txt for HID sensor
> -Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space
> -
> -3.6 End to End HID transport Sequence Diagram
> -
> -HID-ISH-CLN ISHTP IPC HW
> - | | | |
> - | | |-----WAKE UP------------------>|
> - | | | |
> - | | |-----HOST READY--------------->|
> - | | | |
> - | | |<----MNG_RESET_NOTIFY_ACK----- |
> - | | | |
> - | |<----ISHTP_START------ | |
> - | | | |
> - | |<-----------------HOST_START_RES_CMD-------------------|
> - | | | |
> - | |------------------QUERY_SUBSCRIBER-------------------->|
> - | | | |
> - | |------------------HOST_ENUM_REQ_CMD------------------->|
> - | | | |
> - | |<-----------------HOST_ENUM_RES_CMD--------------------|
> - | | | |
> - | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
> - | | | |
> - | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
> - | Create new device on in ishtp bus | |
> - | | | |
> - | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
> - | | | |
> - | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
> - | Create new device on in ishtp bus | |
> - | | | |
> - | |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
> - | | | |
> - probed()
> - |----ishtp_cl_connect-->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
> - | | | |
> - | |<----------------CLIENT_CONNECT_RES_CMD----------------|
> - | | | |
> - |register event callback| | |
> - | | | |
> - |ishtp_cl_send(
> - HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW----- >|
> - | | | |
> - | | |<-----IRQ(IPC_PROTOCOL_ISHTP---|
> - | | | |
> - |<--ENUM_DEVICE RSP-----| | |
> - | | | |
> -for each enumerated device
> - |ishtp_cl_send(
> - HOSTIF_GET_HID_DESCRIPTOR |----------fill ishtp_msg_hdr struct write to HW--- >|
> - | | | |
> - ...Response
> - | | | |
> -for each enumerated device
> - |ishtp_cl_send(
> - HOSTIF_GET_REPORT_DESCRIPTOR |----------fill ishtp_msg_hdr struct write to HW- >|
> - | | | |
> - | | | |
> - hid_allocate_device
> - | | | |
> - hid_add_device | | |
> - | | | |
> -
> -
> -3.7 ISH Debugging
> -
> -To debug ISH, event tracing mechanism is used. To enable debug logs
> -echo 1 > /sys/kernel/debug/tracing/events/intel_ish/enable
> -cat sys/kernel/debug/tracing/trace
> -
> -3.8 ISH IIO sysfs Example on Lenovo thinkpad Yoga 260
> -
> -root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
> -/sys/bus/iio/devices/
> -├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
> -│ ├── buffer
> -│ │ ├── enable
> -│ │ ├── length
> -│ │ └── watermark
> -...
> -│ ├── in_accel_hysteresis
> -│ ├── in_accel_offset
> -│ ├── in_accel_sampling_frequency
> -│ ├── in_accel_scale
> -│ ├── in_accel_x_raw
> -│ ├── in_accel_y_raw
> -│ ├── in_accel_z_raw
> -│ ├── name
> -│ ├── scan_elements
> -│ │ ├── in_accel_x_en
> -│ │ ├── in_accel_x_index
> -│ │ ├── in_accel_x_type
> -│ │ ├── in_accel_y_en
> -│ │ ├── in_accel_y_index
> -│ │ ├── in_accel_y_type
> -│ │ ├── in_accel_z_en
> -│ │ ├── in_accel_z_index
> -│ │ └── in_accel_z_type
> -...
> -│ │ ├── devices
> -│ │ │ │ ├── buffer
> -│ │ │ │ │ ├── enable
> -│ │ │ │ │ ├── length
> -│ │ │ │ │ └── watermark
> -│ │ │ │ ├── dev
> -│ │ │ │ ├── in_intensity_both_raw
> -│ │ │ │ ├── in_intensity_hysteresis
> -│ │ │ │ ├── in_intensity_offset
> -│ │ │ │ ├── in_intensity_sampling_frequency
> -│ │ │ │ ├── in_intensity_scale
> -│ │ │ │ ├── name
> -│ │ │ │ ├── scan_elements
> -│ │ │ │ │ ├── in_intensity_both_en
> -│ │ │ │ │ ├── in_intensity_both_index
> -│ │ │ │ │ └── in_intensity_both_type
> -│ │ │ │ ├── trigger
> -│ │ │ │ │ └── current_trigger
> -...
> -│ │ │ │ ├── buffer
> -│ │ │ │ │ ├── enable
> -│ │ │ │ │ ├── length
> -│ │ │ │ │ └── watermark
> -│ │ │ │ ├── dev
> -│ │ │ │ ├── in_magn_hysteresis
> -│ │ │ │ ├── in_magn_offset
> -│ │ │ │ ├── in_magn_sampling_frequency
> -│ │ │ │ ├── in_magn_scale
> -│ │ │ │ ├── in_magn_x_raw
> -│ │ │ │ ├── in_magn_y_raw
> -│ │ │ │ ├── in_magn_z_raw
> -│ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_raw
> -│ │ │ │ ├── in_rot_hysteresis
> -│ │ │ │ ├── in_rot_offset
> -│ │ │ │ ├── in_rot_sampling_frequency
> -│ │ │ │ ├── in_rot_scale
> -│ │ │ │ ├── name
> -...
> -│ │ │ │ ├── scan_elements
> -│ │ │ │ │ ├── in_magn_x_en
> -│ │ │ │ │ ├── in_magn_x_index
> -│ │ │ │ │ ├── in_magn_x_type
> -│ │ │ │ │ ├── in_magn_y_en
> -│ │ │ │ │ ├── in_magn_y_index
> -│ │ │ │ │ ├── in_magn_y_type
> -│ │ │ │ │ ├── in_magn_z_en
> -│ │ │ │ │ ├── in_magn_z_index
> -│ │ │ │ │ ├── in_magn_z_type
> -│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_en
> -│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_index
> -│ │ │ │ │ └── in_rot_from_north_magnetic_tilt_comp_type
> -│ │ │ │ ├── trigger
> -│ │ │ │ │ └── current_trigger
> -...
> -│ │ │ │ ├── buffer
> -│ │ │ │ │ ├── enable
> -│ │ │ │ │ ├── length
> -│ │ │ │ │ └── watermark
> -│ │ │ │ ├── dev
> -│ │ │ │ ├── in_anglvel_hysteresis
> -│ │ │ │ ├── in_anglvel_offset
> -│ │ │ │ ├── in_anglvel_sampling_frequency
> -│ │ │ │ ├── in_anglvel_scale
> -│ │ │ │ ├── in_anglvel_x_raw
> -│ │ │ │ ├── in_anglvel_y_raw
> -│ │ │ │ ├── in_anglvel_z_raw
> -│ │ │ │ ├── name
> -│ │ │ │ ├── scan_elements
> -│ │ │ │ │ ├── in_anglvel_x_en
> -│ │ │ │ │ ├── in_anglvel_x_index
> -│ │ │ │ │ ├── in_anglvel_x_type
> -│ │ │ │ │ ├── in_anglvel_y_en
> -│ │ │ │ │ ├── in_anglvel_y_index
> -│ │ │ │ │ ├── in_anglvel_y_type
> -│ │ │ │ │ ├── in_anglvel_z_en
> -│ │ │ │ │ ├── in_anglvel_z_index
> -│ │ │ │ │ └── in_anglvel_z_type
> -│ │ │ │ ├── trigger
> -│ │ │ │ │ └── current_trigger
> -...
> -│ │ │ │ ├── buffer
> -│ │ │ │ │ ├── enable
> -│ │ │ │ │ ├── length
> -│ │ │ │ │ └── watermark
> -│ │ │ │ ├── dev
> -│ │ │ │ ├── in_anglvel_hysteresis
> -│ │ │ │ ├── in_anglvel_offset
> -│ │ │ │ ├── in_anglvel_sampling_frequency
> -│ │ │ │ ├── in_anglvel_scale
> -│ │ │ │ ├── in_anglvel_x_raw
> -│ │ │ │ ├── in_anglvel_y_raw
> -│ │ │ │ ├── in_anglvel_z_raw
> -│ │ │ │ ├── name
> -│ │ │ │ ├── scan_elements
> -│ │ │ │ │ ├── in_anglvel_x_en
> -│ │ │ │ │ ├── in_anglvel_x_index
> -│ │ │ │ │ ├── in_anglvel_x_type
> -│ │ │ │ │ ├── in_anglvel_y_en
> -│ │ │ │ │ ├── in_anglvel_y_index
> -│ │ │ │ │ ├── in_anglvel_y_type
> -│ │ │ │ │ ├── in_anglvel_z_en
> -│ │ │ │ │ ├── in_anglvel_z_index
> -│ │ │ │ │ └── in_anglvel_z_type
> -│ │ │ │ ├── trigger
> -│ │ │ │ │ └── current_trigger
> -...
> diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.rst
> similarity index 94%
> rename from Documentation/hid/uhid.txt
> rename to Documentation/hid/uhid.rst
> index 958fff945304..b18cb96c885f 100644
> --- a/Documentation/hid/uhid.txt
> +++ b/Documentation/hid/uhid.rst
> @@ -1,5 +1,6 @@
> - UHID - User-space I/O driver support for HID subsystem
> - ========================================================
> +======================================================
> +UHID - User-space I/O driver support for HID subsystem
> +======================================================
>
> UHID allows user-space to implement HID transport drivers. Please see
> hid-transport.txt for an introduction into HID transport drivers. This document
> @@ -22,9 +23,9 @@ If a new device is detected by your HID I/O Driver and you want to register this
> device with the HID subsystem, then you need to open /dev/uhid once for each
> device you want to register. All further communication is done by read()'ing or
> write()'ing "struct uhid_event" objects. Non-blocking operations are supported
> -by setting O_NONBLOCK.
> +by setting O_NONBLOCK::
>
> -struct uhid_event {
> + struct uhid_event {
> __u32 type;
> union {
> struct uhid_create2_req create2;
> @@ -32,7 +33,7 @@ struct uhid_event {
> struct uhid_input2_req input2;
> ...
> } u;
> -};
> + };
>
> The "type" field contains the ID of the event. Depending on the ID different
> payloads are sent. You must not split a single event across multiple read()'s or
> @@ -86,31 +87,31 @@ the request was handled successfully. O_NONBLOCK does not affect write() as
> writes are always handled immediately in a non-blocking fashion. Future requests
> might make use of O_NONBLOCK, though.
>
> - UHID_CREATE2:
> +UHID_CREATE2:
> This creates the internal HID device. No I/O is possible until you send this
> event to the kernel. The payload is of type struct uhid_create2_req and
> contains information about your device. You can start I/O now.
>
> - UHID_DESTROY:
> +UHID_DESTROY:
> This destroys the internal HID device. No further I/O will be accepted. There
> may still be pending messages that you can receive with read() but no further
> UHID_INPUT events can be sent to the kernel.
> You can create a new device by sending UHID_CREATE2 again. There is no need to
> reopen the character device.
>
> - UHID_INPUT2:
> +UHID_INPUT2:
> You must send UHID_CREATE2 before sending input to the kernel! This event
> contains a data-payload. This is the raw data that you read from your device
> on the interrupt channel. The kernel will parse the HID reports.
>
> - UHID_GET_REPORT_REPLY:
> +UHID_GET_REPORT_REPLY:
> If you receive a UHID_GET_REPORT request you must answer with this request.
> You must copy the "id" field from the request into the answer. Set the "err"
> field to 0 if no error occurred or to EIO if an I/O error occurred.
> If "err" is 0 then you should fill the buffer of the answer with the results
> of the GET_REPORT request and set "size" correspondingly.
>
> - UHID_SET_REPORT_REPLY:
> +UHID_SET_REPORT_REPLY:
> This is the SET_REPORT equivalent of UHID_GET_REPORT_REPLY. Unlike GET_REPORT,
> SET_REPORT never returns a data buffer, therefore, it's sufficient to set the
> "id" and "err" fields correctly.
> @@ -120,16 +121,18 @@ read()
> read() will return a queued output report. No reaction is required to any of
> them but you should handle them according to your needs.
>
> - UHID_START:
> +UHID_START:
> This is sent when the HID device is started. Consider this as an answer to
> UHID_CREATE2. This is always the first event that is sent. Note that this
> event might not be available immediately after write(UHID_CREATE2) returns.
> Device drivers might required delayed setups.
> This event contains a payload of type uhid_start_req. The "dev_flags" field
> describes special behaviors of a device. The following flags are defined:
> - UHID_DEV_NUMBERED_FEATURE_REPORTS:
> - UHID_DEV_NUMBERED_OUTPUT_REPORTS:
> - UHID_DEV_NUMBERED_INPUT_REPORTS:
> +
> + - UHID_DEV_NUMBERED_FEATURE_REPORTS
> + - UHID_DEV_NUMBERED_OUTPUT_REPORTS
> + - UHID_DEV_NUMBERED_INPUT_REPORTS
> +
> Each of these flags defines whether a given report-type uses numbered
> reports. If numbered reports are used for a type, all messages from
> the kernel already have the report-number as prefix. Otherwise, no
> @@ -137,33 +140,35 @@ them but you should handle them according to your needs.
> For messages sent by user-space to the kernel, you must adjust the
> prefixes according to these flags.
>
> - UHID_STOP:
> +UHID_STOP:
> This is sent when the HID device is stopped. Consider this as an answer to
> UHID_DESTROY.
> +
> If you didn't destroy your device via UHID_DESTROY, but the kernel sends an
> UHID_STOP event, this should usually be ignored. It means that the kernel
> reloaded/changed the device driver loaded on your HID device (or some other
> maintenance actions happened).
> +
> You can usually ignored any UHID_STOP events safely.
>
> - UHID_OPEN:
> +UHID_OPEN:
> This is sent when the HID device is opened. That is, the data that the HID
> device provides is read by some other process. You may ignore this event but
> it is useful for power-management. As long as you haven't received this event
> there is actually no other process that reads your data so there is no need to
> send UHID_INPUT2 events to the kernel.
>
> - UHID_CLOSE:
> +UHID_CLOSE:
> This is sent when there are no more processes which read the HID data. It is
> the counterpart of UHID_OPEN and you may as well ignore this event.
>
> - UHID_OUTPUT:
> +UHID_OUTPUT:
> This is sent if the HID device driver wants to send raw data to the I/O
> device on the interrupt channel. You should read the payload and forward it to
> the device. The payload is of type "struct uhid_output_req".
> This may be received even though you haven't received UHID_OPEN, yet.
>
> - UHID_GET_REPORT:
> +UHID_GET_REPORT:
> This event is sent if the kernel driver wants to perform a GET_REPORT request
> on the control channeld as described in the HID specs. The report-type and
> report-number are available in the payload.
> @@ -177,11 +182,12 @@ them but you should handle them according to your needs.
> timed out, the kernel will ignore the response silently. The "id" field is
> never re-used, so conflicts cannot happen.
>
> - UHID_SET_REPORT:
> +UHID_SET_REPORT:
> This is the SET_REPORT equivalent of UHID_GET_REPORT. On receipt, you shall
> send a SET_REPORT request to your hid device. Once it replies, you must tell
> the kernel about it via UHID_SET_REPORT_REPLY.
> The same restrictions as for UHID_GET_REPORT apply.
>
> ----------------------------------------------------
> +
> Written 2012, David Herrmann <dh.herrmann@gmail.com>
> diff --git a/Documentation/input/input.rst b/Documentation/input/input.rst
> index 47f86a4bf16c..0eb61e67a7b7 100644
> --- a/Documentation/input/input.rst
> +++ b/Documentation/input/input.rst
> @@ -188,7 +188,7 @@ LCDs and many other purposes.
>
> The monitor and speaker controls should be easy to add to the hid/input
> interface, but for the UPSs and LCDs it doesn't make much sense. For this,
> -the hiddev interface was designed. See Documentation/hid/hiddev.txt
> +the hiddev interface was designed. See Documentation/hid/hiddev.rst
> for more information about it.
>
> The usage of the usbhid module is very simple, it takes no parameters,
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8d39979e4091..969225e6bfce 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -16383,7 +16383,7 @@ M: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> L: linux-usb@vger.kernel.org
> T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
> S: Maintained
> -F: Documentation/hid/hiddev.txt
> +F: Documentation/hid/hiddev.rst
> F: drivers/hid/usbhid/
>
> USB INTEL XHCI ROLE MUX DRIVER
> --
> 2.21.0
>
^ permalink raw reply
* [PATCH] Input: atmel_mxt_ts - fix -Wunused-const-variable
From: Nathan Huckleberry @ 2019-06-12 23:58 UTC (permalink / raw)
To: nick, dmitry.torokhov
Cc: linux-input, linux-kernel, Nathan Huckleberry, clang-built-linux
Clang produces the following warning
drivers/input/touchscreen/atmel_mxt_ts.c:259:42: warning: unused
variable 'mxt_video_fops' [-Wunused-const-variable]
static const struct v4l2_file_operations mxt_video_fops = {
Since mxt_video_fops is only used inside an ifdef. It should
be moved inside the ifdef.
Cc: clang-built-linux@googlegroups.com
Link: https://github.com/ClangBuiltLinux/linux/issues/527
Signed-off-by: Nathan Huckleberry <nhuck@google.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 19378f200c63..48411c83320b 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -256,6 +256,7 @@ enum v4l_dbg_inputs {
MXT_V4L_INPUT_MAX,
};
+#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
static const struct v4l2_file_operations mxt_video_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
@@ -265,6 +266,7 @@ static const struct v4l2_file_operations mxt_video_fops = {
.mmap = vb2_fop_mmap,
.poll = vb2_fop_poll,
};
+#endif
enum mxt_suspend_mode {
MXT_SUSPEND_DEEP_SLEEP = 0,
--
2.22.0.rc2.383.gf4fbbf30c2-goog
^ permalink raw reply related
* Re: Re: [PATCH v6 2/5] HID: quirks: Refactor ELAN 400 and 401 handling
From: Jeffrey Hugo @ 2019-06-12 22:20 UTC (permalink / raw)
To: Dmitry Torokhov, Jeffrey Hugo
Cc: benjamin.tissoires, jikos, hdegoede, bjorn.andersson, agross,
lee.jones, xnox, robh+dt, mark.rutland, linux-input, devicetree,
linux-arm-msm, linux-kernel
In-Reply-To: <20190612214636.GA40779@dtor-ws>
On 6/12/2019 3:46 PM, Dmitry Torokhov wrote:
> On Wed, Jun 12, 2019 at 02:27:21PM -0700, Jeffrey Hugo wrote:
>> There needs to be coordination between hid-quirks and the elan_i2c driver
>> about which devices are handled by what drivers. Currently, both use
>> whitelists, which results in valid devices being unhandled by default,
>> when they should not be rejected by hid-quirks. This is quickly becoming
>> an issue.
>>
>> Since elan_i2c has a maintained whitelist of what devices it will handle,
>> which is now in a header file that hid-quirks can access, use that to
>> implement a blacklist in hid-quirks so that only the devices that need to
>> be handled by elan_i2c get rejected by hid-quirks, and everything else is
>> handled by default.
>>
>> Suggested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>> Signed-off-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com>
>> ---
>> drivers/hid/hid-quirks.c | 27 ++++++++++++++++-----------
>> 1 file changed, 16 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
>> index e5ca6fe2ca57..bd81bb090222 100644
>> --- a/drivers/hid/hid-quirks.c
>> +++ b/drivers/hid/hid-quirks.c
>> @@ -16,6 +16,7 @@
>> #include <linux/export.h>
>> #include <linux/slab.h>
>> #include <linux/mutex.h>
>> +#include <linux/input/elan-i2c-ids.h>
>>
>> #include "hid-ids.h"
>>
>> @@ -914,6 +915,8 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
>>
>> bool hid_ignore(struct hid_device *hdev)
>> {
>> + int i;
>> +
>> if (hdev->quirks & HID_QUIRK_NO_IGNORE)
>> return false;
>> if (hdev->quirks & HID_QUIRK_IGNORE)
>> @@ -978,18 +981,20 @@ bool hid_ignore(struct hid_device *hdev)
>> break;
>> case USB_VENDOR_ID_ELAN:
>> /*
>> - * Many Elan devices have a product id of 0x0401 and are handled
>> - * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
>> - * is not (and cannot be) handled by that driver ->
>> - * Ignore all 0x0401 devs except for the ELAN0800 dev.
>> + * Blacklist of everything that gets handled by the elan_i2c
>> + * input driver. This avoids disabling valid touchpads and
>> + * other ELAN devices.
>> */
>> - if (hdev->product == 0x0401 &&
>> - strncmp(hdev->name, "ELAN0800", 8) != 0)
>> - return true;
>> - /* Same with product id 0x0400 */
>> - if (hdev->product == 0x0400 &&
>> - strncmp(hdev->name, "QTEC0001", 8) != 0)
>> - return true;
>> + if ((hdev->product == 0x0401 || hdev->product == 0x0400)) {
>> + for (i = 0; strlen(elan_acpi_id[i].id); ++i)
>> + if (!strncmp(hdev->name, elan_acpi_id[i].id,
>> + strlen(elan_acpi_id[i].id)))
>> + return true;
>> + for (i = 0; strlen(elan_of_match[i].name); ++i)
>> + if (!strncmp(hdev->name, elan_of_match[i].name,
>> + strlen(elan_of_match[i].name)))
>> + return true;
>
> Do we really need to blacklist the OF case here? I thought that in ACPI
> case we have clashes as HID gets matched by elan_i2c and CID is matched
> by i2c-hid, but I do not believe we'll run into the same situation on OF
> systems.
I think its the safer approach.
On an OF system, such as patch 3 in the series, the "hid-over-i2c" will
end up running through this (kind of the whole reason why this series
exists). The vendor and product ids will still match, so we'll end up
going through the lists to see if the hdev->name (the compatible string)
will match the blacklist. "hid-over-i2c" won't match the blacklist, but
if there is a more specific compatible, it might.
In that case, not matching OF would work, however how it could break
today is if both "hid-over-i2c" and "elan,ekth3000" were listed for the
same device, and elan_i2c was not compiled. In that case, if we skip
the OF part of the black list, hid-quirks will not reject the device,
and you'll probably have some odd behavior instead of the obvious "the
device doesn't work because the correct driver isn't present" behavior.
While that scenario might be far fetched since having both
"hid-over-i2c" and "elan,ekth3000" probably violates the OF bindings,
its still safer to include the OF case in the blacklist against future
scenarios.
^ 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