Linux Input/HID development
 help / color / mirror / Atom feed
* 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(&regs->sio_ir);
+	mask = readl(&regs->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(&regs->eth.eisr) & readl(&regs->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],
+		&regs->emar_h);
+	writel((dev->dev_addr[3] << 24) |
+		(dev->dev_addr[2] << 16) |
+		(dev->dev_addr[1] <<  8) |
+		dev->dev_addr[0],
+		&regs->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(&regs->micr) & MICR_BUSY)
+		;
+	writel((phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG,
+	       &regs->micr);
+	while (readl(&regs->micr) & MICR_BUSY)
+		;
 
-		nic_write_bit(ioc3, bit);
-	}
+	return readl(&regs->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(&regs->micr) & MICR_BUSY)
+		;
+	writel(data, &regs->midr_w);
+	writel((phy << MICR_PHYADDR_SHIFT) | reg, &regs->micr);
+	while (readl(&regs->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, &regs->emcr);		/* Shutup */
+	writel(0, &regs->eier);		/* Disable interrupts */
+	(void)readl(&regs->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, &regs->emcr);
+		(void)readl(&regs->emcr);
+	} else {
+		ip->emcr &= ~EMCR_PROMISC;
+		writel(ip->emcr, &regs->emcr);	/* Clear promiscuous. */
+		(void)readl(&regs->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, &regs->ehar_h);
+		writel(ip->ehar_l, &regs->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, &regs->etcsr);
+		ip->emcr |= EMCR_DUPLEX;
+	} else {
+		writel(ETCSR_HD, &regs->etcsr);
+		ip->emcr &= ~EMCR_DUPLEX;
+	}
+	writel(ip->emcr, &regs->emcr);
+	(void)readl(&regs->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, &regs->erbr_h);
+	writel(ring & 0xffffffff, &regs->erbr_l);
+	writel(ip->rx_ci << 3, &regs->ercir);
+	writel((ip->rx_pi << 3) | ERPIR_ARM, &regs->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, &regs->etbr_h);
+	writel(ring & 0xffffffff, &regs->etbr_l);
+	writel(ip->tx_pi << 7, &regs->etpir);
+	writel(ip->tx_ci << 7, &regs->etcir);
+	(void)readl(&regs->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 = &regs->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, &regs->emcr);		/* Reset */
+	(void)readl(&regs->emcr);		/* Flush WB */
+	udelay(4);				/* Give it time... */
+	writel(0, &regs->emcr);
+	(void)readl(&regs->emcr);
 
 	/* Misc registers  */
 #ifdef CONFIG_SGI_IP27
-	ioc3_w_erbar(PCI64_ATTR_BAR >> 32);	/* Barrier on last store */
+	/* Barrier on last store */
+	writel(readl(&regs->erbar) |
+		(ERBAR_BARRIER_BIT << ERBAR_RXBARR_SHIFT), &regs->erbar);
 #else
-	ioc3_w_erbar(0);			/* Let PCI API get it right */
+	/* Let PCI API get it right */
+	writel(0, &regs->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(&regs->etcdc);			/* Clear on read */
+	writel(15, &regs->ercsr);		/* RX low watermark  */
+	writel(1, &regs->ertr);			/* Interrupt immediately */
+	__ioc3_set_mac_address(dev, regs);
+	writel(ip->ehar_h, &regs->ehar_h);
+	writel(ip->ehar_l, &regs->ehar_l);
+	writel(42, &regs->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, &regs->emcr);
+	readl(&regs->emcr);
+	writel(EISR_RXTIMERINT | EISR_RXTHRESHINT |
+		EISR_RXOFLO | EISR_RXBUFOFLO |
+		EISR_RXMEMERR | EISR_RXPARERR |
+		EISR_TXEXDEF |
+		EISR_TXBUFUFLO |
+		EISR_TXMEMERR, &regs->eier);
+	readl(&regs->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(&regs->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(&regs->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(&regs->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(&regs->eisr);
+
+	writel(eisr, &regs->eisr);
+	(void)readl(&regs->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


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox