From 01d152c0bfabadc6c93a39e465eb2f66f3f11527 Mon Sep 17 00:00:00 2001
From: Xinhao Zhang
Date: Wed, 4 Nov 2020 21:37:09 +0800
Subject: hw/xen: Don't use '#' flag of printf format

Fix code style. Don't use '#' flag of printf format ('%#') in
format strings, use '0x' prefix instead

Signed-off-by: Xinhao Zhang <zhangxinhao1@huawei.com>
Signed-off-by: Kai Deng <dengkai1@huawei.com>
Message-Id: <20201104133709.3326630-1-zhangxinhao1@huawei.com>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/xen/xen_pt.c             | 10 +++++-----
 hw/xen/xen_pt_config_init.c |  6 +++---
 hw/xen/xen_pt_msi.c         | 16 ++++++++--------
 3 files changed, 16 insertions(+), 16 deletions(-)

(limited to 'hw')

diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index 6d359ee486..a5f3dd590c 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -489,7 +489,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
         pci_register_bar(&s->dev, i, type, &s->bar[i]);
 
         XEN_PT_LOG(&s->dev, "IO region %i registered (size=0x%08"PRIx64
-                   " base_addr=0x%08"PRIx64" type: %#x)\n",
+                   " base_addr=0x%08"PRIx64" type: 0x%x)\n",
                    i, r->size, r->base_addr, type);
     }
 
@@ -578,7 +578,7 @@ static void xen_pt_check_bar_overlap(PCIBus *bus, PCIDevice *d, void *opaque)
         if (ranges_overlap(arg->addr, arg->size, r->addr, r->size)) {
             XEN_PT_WARN(&s->dev,
                         "Overlapped to device [%02x:%02x.%d] Region: %i"
-                        " (addr: %#"FMT_PCIBUS", len: %#"FMT_PCIBUS")\n",
+                        " (addr: 0x%"FMT_PCIBUS", len: 0x%"FMT_PCIBUS")\n",
                         pci_bus_num(bus), PCI_SLOT(d->devfn),
                         PCI_FUNC(d->devfn), i, r->addr, r->size);
             arg->rc = true;
@@ -618,8 +618,8 @@ static void xen_pt_region_update(XenPCIPassthroughState *s,
     pci_for_each_device(pci_get_bus(d), pci_dev_bus_num(d),
                         xen_pt_check_bar_overlap, &args);
     if (args.rc) {
-        XEN_PT_WARN(d, "Region: %d (addr: %#"FMT_PCIBUS
-                    ", len: %#"FMT_PCIBUS") is overlapped.\n",
+        XEN_PT_WARN(d, "Region: %d (addr: 0x%"FMT_PCIBUS
+                    ", len: 0x%"FMT_PCIBUS") is overlapped.\n",
                     bar, sec->offset_within_address_space,
                     int128_get64(sec->size));
     }
@@ -786,7 +786,7 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
 
     /* register real device */
     XEN_PT_LOG(d, "Assigning real physical device %02x:%02x.%d"
-               " to devfn %#x\n",
+               " to devfn 0x%x\n",
                s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function,
                s->dev.devfn);
 
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
index c8724cc7c8..c5c4e943a8 100644
--- a/hw/xen/xen_pt_config_init.c
+++ b/hw/xen/xen_pt_config_init.c
@@ -1622,7 +1622,7 @@ static int xen_pt_pcie_size_init(XenPCIPassthroughState *s,
         case PCI_EXP_TYPE_PCIE_BRIDGE:
         case PCI_EXP_TYPE_RC_EC:
         default:
-            XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
+            XEN_PT_ERR(d, "Unsupported device/port type 0x%x.\n", type);
             return -1;
         }
     }
@@ -1645,11 +1645,11 @@ static int xen_pt_pcie_size_init(XenPCIPassthroughState *s,
         case PCI_EXP_TYPE_PCIE_BRIDGE:
         case PCI_EXP_TYPE_RC_EC:
         default:
-            XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
+            XEN_PT_ERR(d, "Unsupported device/port type 0x%x.\n", type);
             return -1;
         }
     } else {
-        XEN_PT_ERR(d, "Unsupported capability version %#x.\n", version);
+        XEN_PT_ERR(d, "Unsupported capability version 0x%x.\n", version);
         return -1;
     }
 
diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c
index fb4b887b92..b71563f98a 100644
--- a/hw/xen/xen_pt_msi.c
+++ b/hw/xen/xen_pt_msi.c
@@ -123,7 +123,7 @@ static int msi_msix_setup(XenPCIPassthroughState *s,
             *ppirq = XEN_PT_UNASSIGNED_PIRQ;
         } else {
             XEN_PT_LOG(&s->dev, "requested pirq %d for MSI%s"
-                       " (vec: %#x, entry: %#x)\n",
+                       " (vec: 0x%x, entry: 0x%x)\n",
                        *ppirq, is_msix ? "-X" : "", gvec, msix_entry);
         }
     }
@@ -142,7 +142,7 @@ static int msi_msix_setup(XenPCIPassthroughState *s,
                                      msix_entry, table_base);
         if (rc) {
             XEN_PT_ERR(&s->dev,
-                       "Mapping of MSI%s (err: %i, vec: %#x, entry %#x)\n",
+                       "Mapping of MSI%s (err: %i, vec: 0x%x, entry 0x%x)\n",
                        is_msix ? "-X" : "", errno, gvec, msix_entry);
             return rc;
         }
@@ -165,8 +165,8 @@ static int msi_msix_update(XenPCIPassthroughState *s,
     int rc = 0;
     uint64_t table_addr = 0;
 
-    XEN_PT_LOG(d, "Updating MSI%s with pirq %d gvec %#x gflags %#x"
-               " (entry: %#x)\n",
+    XEN_PT_LOG(d, "Updating MSI%s with pirq %d gvec 0x%x gflags 0x%x"
+               " (entry: 0x%x)\n",
                is_msix ? "-X" : "", pirq, gvec, gflags, msix_entry);
 
     if (is_msix) {
@@ -208,11 +208,11 @@ static int msi_msix_disable(XenPCIPassthroughState *s,
     }
 
     if (is_binded) {
-        XEN_PT_LOG(d, "Unbind MSI%s with pirq %d, gvec %#x\n",
+        XEN_PT_LOG(d, "Unbind MSI%s with pirq %d, gvec 0x%x\n",
                    is_msix ? "-X" : "", pirq, gvec);
         rc = xc_domain_unbind_msi_irq(xen_xc, xen_domid, gvec, pirq, gflags);
         if (rc) {
-            XEN_PT_ERR(d, "Unbinding of MSI%s failed. (err: %d, pirq: %d, gvec: %#x)\n",
+            XEN_PT_ERR(d, "Unbinding of MSI%s failed. (err: %d, pirq: %d, gvec: 0x%x)\n",
                        is_msix ? "-X" : "", errno, pirq, gvec);
             return rc;
         }
@@ -539,7 +539,7 @@ int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)
     }
 
     if (id != PCI_CAP_ID_MSIX) {
-        XEN_PT_ERR(d, "Invalid id %#x base %#x\n", id, base);
+        XEN_PT_ERR(d, "Invalid id 0x%x base 0x%x\n", id, base);
         return -1;
     }
 
@@ -582,7 +582,7 @@ int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)
         XEN_PT_ERR(d, "Can't open /dev/mem: %s\n", strerror(errno));
         goto error_out;
     }
-    XEN_PT_LOG(d, "table_off = %#x, total_entries = %d\n",
+    XEN_PT_LOG(d, "table_off = 0x%x, total_entries = %d\n",
                table_off, total_entries);
     msix->table_offset_adjust = table_off & 0x0fff;
     msix->phys_iomem_base =
-- 
cgit v1.2.3-55-g7522


From f6a3c86ebd39aaedf1ebf89629ec91b5d44b670d Mon Sep 17 00:00:00 2001
From: Philippe Mathieu-Daudé
Date: Wed, 2 Dec 2020 14:20:38 +0100
Subject: hw/pci-host/pam: Replace magic number by PAM_REGIONS_COUNT definition

While this change helps triskaidekaphobic developers, it
is a good practice to avoid magic values and using constant
definitions instead.

Introduce the PAM_REGIONS_COUNT and use it. No logical change.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Julia Suvorova <jusual@redhat.com>
Message-Id: <20201202132038.1276404-1-philmd@redhat.com>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/pci-host/pam.c            | 2 +-
 hw/pci-host/q35.c            | 2 +-
 include/hw/pci-host/i440fx.h | 2 +-
 include/hw/pci-host/pam.h    | 2 ++
 include/hw/pci-host/q35.h    | 2 +-
 5 files changed, 6 insertions(+), 4 deletions(-)

(limited to 'hw')

diff --git a/hw/pci-host/pam.c b/hw/pci-host/pam.c
index a496205783..454dd120db 100644
--- a/hw/pci-host/pam.c
+++ b/hw/pci-host/pam.c
@@ -62,7 +62,7 @@ void init_pam(DeviceState *dev, MemoryRegion *ram_memory,
 
 void pam_update(PAMMemoryRegion *pam, int idx, uint8_t val)
 {
-    assert(0 <= idx && idx <= 12);
+    assert(0 <= idx && idx < PAM_REGIONS_COUNT);
 
     memory_region_set_enabled(&pam->alias[pam->current], false);
     pam->current = (val >> ((!(idx & 1)) * 4)) & PAM_ATTR_MASK;
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index b67cb9c29f..2eb729dff5 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -641,7 +641,7 @@ static void mch_realize(PCIDevice *d, Error **errp)
     init_pam(DEVICE(mch), mch->ram_memory, mch->system_memory,
              mch->pci_address_space, &mch->pam_regions[0],
              PAM_BIOS_BASE, PAM_BIOS_SIZE);
-    for (i = 0; i < 12; ++i) {
+    for (i = 0; i < ARRAY_SIZE(mch->pam_regions) - 1; ++i) {
         init_pam(DEVICE(mch), mch->ram_memory, mch->system_memory,
                  mch->pci_address_space, &mch->pam_regions[i+1],
                  PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
diff --git a/include/hw/pci-host/i440fx.h b/include/hw/pci-host/i440fx.h
index 6c16eaf876..24fd53942c 100644
--- a/include/hw/pci-host/i440fx.h
+++ b/include/hw/pci-host/i440fx.h
@@ -29,7 +29,7 @@ struct PCII440FXState {
     MemoryRegion *system_memory;
     MemoryRegion *pci_address_space;
     MemoryRegion *ram_memory;
-    PAMMemoryRegion pam_regions[13];
+    PAMMemoryRegion pam_regions[PAM_REGIONS_COUNT];
     MemoryRegion smram_region;
     MemoryRegion smram, low_smram;
 };
diff --git a/include/hw/pci-host/pam.h b/include/hw/pci-host/pam.h
index fec5cd35d6..c1fd06ba2a 100644
--- a/include/hw/pci-host/pam.h
+++ b/include/hw/pci-host/pam.h
@@ -80,6 +80,8 @@
 #define SMRAM_C_BASE_SEG_MASK  ((uint8_t)0x7)
 #define SMRAM_C_BASE_SEG       ((uint8_t)0x2)  /* hardwired to b010 */
 
+#define PAM_REGIONS_COUNT       13
+
 typedef struct PAMMemoryRegion {
     MemoryRegion alias[4];  /* index = PAM value */
     unsigned current;
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
index bbb9581765..ab989698ef 100644
--- a/include/hw/pci-host/q35.h
+++ b/include/hw/pci-host/q35.h
@@ -44,7 +44,7 @@ struct MCHPCIState {
     MemoryRegion *pci_address_space;
     MemoryRegion *system_memory;
     MemoryRegion *address_space_io;
-    PAMMemoryRegion pam_regions[13];
+    PAMMemoryRegion pam_regions[PAM_REGIONS_COUNT];
     MemoryRegion smram_region, open_high_smram;
     MemoryRegion smram, low_smram, high_smram;
     MemoryRegion tseg_blackhole, tseg_window;
-- 
cgit v1.2.3-55-g7522


From f12985f14a05181b34b3cfb935b4136a05726423 Mon Sep 17 00:00:00 2001
From: Gan Qixin
Date: Sun, 15 Nov 2020 20:35:03 +0800
Subject: ads7846: moves from the hw/display folder to the hw/input folder.

ads7846 is a touch-screen controller that is an input device rather
than a display device, so move it to the hw/input folder.

Signed-off-by: Gan Qixin <ganqixin@huawei.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-Id: <20201115123503.1110665-1-ganqixin@huawei.com>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/arm/Kconfig         |   2 +-
 hw/display/Kconfig     |   3 -
 hw/display/ads7846.c   | 186 -------------------------------------------------
 hw/display/meson.build |   1 -
 hw/input/Kconfig       |   3 +
 hw/input/ads7846.c     | 186 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/input/meson.build   |   1 +
 7 files changed, 191 insertions(+), 191 deletions(-)
 delete mode 100644 hw/display/ads7846.c
 create mode 100644 hw/input/ads7846.c

(limited to 'hw')

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index eb8a8844cf..0a242e4c5d 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -156,7 +156,7 @@ config TOSA
 
 config SPITZ
     bool
-    select ADS7846 # display
+    select ADS7846 # touch-screen controller
     select MAX111X # A/D converter
     select WM8750  # audio codec
     select MAX7310 # GPIO expander
diff --git a/hw/display/Kconfig b/hw/display/Kconfig
index 15d59e10dc..ca46b5830e 100644
--- a/hw/display/Kconfig
+++ b/hw/display/Kconfig
@@ -9,9 +9,6 @@ config EDID
 config FW_CFG_DMA
     bool
 
-config ADS7846
-    bool
-
 config VGA_CIRRUS
     bool
     default y if PCI_DEVICES
diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c
deleted file mode 100644
index 1d4e04a2dc..0000000000
--- a/hw/display/ads7846.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * TI ADS7846 / TSC2046 chip emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/ssi/ssi.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "ui/console.h"
-#include "qom/object.h"
-
-struct ADS7846State {
-    SSIPeripheral ssidev;
-    qemu_irq interrupt;
-
-    int input[8];
-    int pressure;
-    int noise;
-
-    int cycle;
-    int output;
-};
-
-#define TYPE_ADS7846 "ads7846"
-OBJECT_DECLARE_SIMPLE_TYPE(ADS7846State, ADS7846)
-
-/* Control-byte bitfields */
-#define CB_PD0		(1 << 0)
-#define CB_PD1		(1 << 1)
-#define CB_SER		(1 << 2)
-#define CB_MODE		(1 << 3)
-#define CB_A0		(1 << 4)
-#define CB_A1		(1 << 5)
-#define CB_A2		(1 << 6)
-#define CB_START	(1 << 7)
-
-#define X_AXIS_DMAX	3470
-#define X_AXIS_MIN	290
-#define Y_AXIS_DMAX	3450
-#define Y_AXIS_MIN	200
-
-#define ADS_VBAT	2000
-#define ADS_VAUX	2000
-#define ADS_TEMP0	2000
-#define ADS_TEMP1	3000
-#define ADS_XPOS(x, y)	(X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
-#define ADS_YPOS(x, y)	(Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
-#define ADS_Z1POS(x, y)	600
-#define ADS_Z2POS(x, y)	(600 + 6000 / ADS_XPOS(x, y))
-
-static void ads7846_int_update(ADS7846State *s)
-{
-    if (s->interrupt)
-        qemu_set_irq(s->interrupt, s->pressure == 0);
-}
-
-static uint32_t ads7846_transfer(SSIPeripheral *dev, uint32_t value)
-{
-    ADS7846State *s = ADS7846(dev);
-
-    switch (s->cycle ++) {
-    case 0:
-        if (!(value & CB_START)) {
-            s->cycle = 0;
-            break;
-        }
-
-        s->output = s->input[(value >> 4) & 7];
-
-        /* Imitate the ADC noise, some drivers expect this.  */
-        s->noise = (s->noise + 3) & 7;
-        switch ((value >> 4) & 7) {
-        case 1: s->output += s->noise ^ 2; break;
-        case 3: s->output += s->noise ^ 0; break;
-        case 4: s->output += s->noise ^ 7; break;
-        case 5: s->output += s->noise ^ 5; break;
-        }
-
-        if (value & CB_MODE)
-            s->output >>= 4;	/* 8 bits instead of 12 */
-
-        break;
-    case 1:
-        s->cycle = 0;
-        break;
-    }
-    return s->output;
-}
-
-static void ads7846_ts_event(void *opaque,
-                int x, int y, int z, int buttons_state)
-{
-    ADS7846State *s = opaque;
-
-    if (buttons_state) {
-        x = 0x7fff - x;
-        s->input[1] = ADS_XPOS(x, y);
-        s->input[3] = ADS_Z1POS(x, y);
-        s->input[4] = ADS_Z2POS(x, y);
-        s->input[5] = ADS_YPOS(x, y);
-    }
-
-    if (s->pressure == !buttons_state) {
-        s->pressure = !!buttons_state;
-
-        ads7846_int_update(s);
-    }
-}
-
-static int ads7856_post_load(void *opaque, int version_id)
-{
-    ADS7846State *s = opaque;
-
-    s->pressure = 0;
-    ads7846_int_update(s);
-    return 0;
-}
-
-static const VMStateDescription vmstate_ads7846 = {
-    .name = "ads7846",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .post_load = ads7856_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_SSI_PERIPHERAL(ssidev, ADS7846State),
-        VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
-        VMSTATE_INT32(noise, ADS7846State),
-        VMSTATE_INT32(cycle, ADS7846State),
-        VMSTATE_INT32(output, ADS7846State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void ads7846_realize(SSIPeripheral *d, Error **errp)
-{
-    DeviceState *dev = DEVICE(d);
-    ADS7846State *s = ADS7846(d);
-
-    qdev_init_gpio_out(dev, &s->interrupt, 1);
-
-    s->input[0] = ADS_TEMP0;	/* TEMP0 */
-    s->input[2] = ADS_VBAT;	/* VBAT */
-    s->input[6] = ADS_VAUX;	/* VAUX */
-    s->input[7] = ADS_TEMP1;	/* TEMP1 */
-
-    /* We want absolute coordinates */
-    qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
-                    "QEMU ADS7846-driven Touchscreen");
-
-    ads7846_int_update(s);
-
-    vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_ads7846, s);
-}
-
-static void ads7846_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
-
-    k->realize = ads7846_realize;
-    k->transfer = ads7846_transfer;
-    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo ads7846_info = {
-    .name          = TYPE_ADS7846,
-    .parent        = TYPE_SSI_PERIPHERAL,
-    .instance_size = sizeof(ADS7846State),
-    .class_init    = ads7846_class_init,
-};
-
-static void ads7846_register_types(void)
-{
-    type_register_static(&ads7846_info);
-}
-
-type_init(ads7846_register_types)
diff --git a/hw/display/meson.build b/hw/display/meson.build
index dad3bd2b41..9d79e3951d 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -6,7 +6,6 @@ softmmu_ss.add(when: 'CONFIG_EDID', if_true: files('edid-generate.c', 'edid-regi
 softmmu_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('ramfb.c'))
 softmmu_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('ramfb-standalone.c'))
 
-softmmu_ss.add(when: 'CONFIG_ADS7846', if_true: files('ads7846.c'))
 softmmu_ss.add(when: 'CONFIG_VGA_CIRRUS', if_true: files('cirrus_vga.c'))
 softmmu_ss.add(when: ['CONFIG_VGA_CIRRUS', 'CONFIG_VGA_ISA'], if_true: files('cirrus_vga_isa.c'))
 softmmu_ss.add(when: 'CONFIG_G364FB', if_true: files('g364fb.c'))
diff --git a/hw/input/Kconfig b/hw/input/Kconfig
index 64f14daabf..55865bb386 100644
--- a/hw/input/Kconfig
+++ b/hw/input/Kconfig
@@ -1,6 +1,9 @@
 config ADB
     bool
 
+config ADS7846
+    bool
+
 config LM832X
     bool
     depends on I2C
diff --git a/hw/input/ads7846.c b/hw/input/ads7846.c
new file mode 100644
index 0000000000..1d4e04a2dc
--- /dev/null
+++ b/hw/input/ads7846.c
@@ -0,0 +1,186 @@
+/*
+ * TI ADS7846 / TSC2046 chip emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/irq.h"
+#include "hw/ssi/ssi.h"
+#include "migration/vmstate.h"
+#include "qemu/module.h"
+#include "ui/console.h"
+#include "qom/object.h"
+
+struct ADS7846State {
+    SSIPeripheral ssidev;
+    qemu_irq interrupt;
+
+    int input[8];
+    int pressure;
+    int noise;
+
+    int cycle;
+    int output;
+};
+
+#define TYPE_ADS7846 "ads7846"
+OBJECT_DECLARE_SIMPLE_TYPE(ADS7846State, ADS7846)
+
+/* Control-byte bitfields */
+#define CB_PD0		(1 << 0)
+#define CB_PD1		(1 << 1)
+#define CB_SER		(1 << 2)
+#define CB_MODE		(1 << 3)
+#define CB_A0		(1 << 4)
+#define CB_A1		(1 << 5)
+#define CB_A2		(1 << 6)
+#define CB_START	(1 << 7)
+
+#define X_AXIS_DMAX	3470
+#define X_AXIS_MIN	290
+#define Y_AXIS_DMAX	3450
+#define Y_AXIS_MIN	200
+
+#define ADS_VBAT	2000
+#define ADS_VAUX	2000
+#define ADS_TEMP0	2000
+#define ADS_TEMP1	3000
+#define ADS_XPOS(x, y)	(X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
+#define ADS_YPOS(x, y)	(Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
+#define ADS_Z1POS(x, y)	600
+#define ADS_Z2POS(x, y)	(600 + 6000 / ADS_XPOS(x, y))
+
+static void ads7846_int_update(ADS7846State *s)
+{
+    if (s->interrupt)
+        qemu_set_irq(s->interrupt, s->pressure == 0);
+}
+
+static uint32_t ads7846_transfer(SSIPeripheral *dev, uint32_t value)
+{
+    ADS7846State *s = ADS7846(dev);
+
+    switch (s->cycle ++) {
+    case 0:
+        if (!(value & CB_START)) {
+            s->cycle = 0;
+            break;
+        }
+
+        s->output = s->input[(value >> 4) & 7];
+
+        /* Imitate the ADC noise, some drivers expect this.  */
+        s->noise = (s->noise + 3) & 7;
+        switch ((value >> 4) & 7) {
+        case 1: s->output += s->noise ^ 2; break;
+        case 3: s->output += s->noise ^ 0; break;
+        case 4: s->output += s->noise ^ 7; break;
+        case 5: s->output += s->noise ^ 5; break;
+        }
+
+        if (value & CB_MODE)
+            s->output >>= 4;	/* 8 bits instead of 12 */
+
+        break;
+    case 1:
+        s->cycle = 0;
+        break;
+    }
+    return s->output;
+}
+
+static void ads7846_ts_event(void *opaque,
+                int x, int y, int z, int buttons_state)
+{
+    ADS7846State *s = opaque;
+
+    if (buttons_state) {
+        x = 0x7fff - x;
+        s->input[1] = ADS_XPOS(x, y);
+        s->input[3] = ADS_Z1POS(x, y);
+        s->input[4] = ADS_Z2POS(x, y);
+        s->input[5] = ADS_YPOS(x, y);
+    }
+
+    if (s->pressure == !buttons_state) {
+        s->pressure = !!buttons_state;
+
+        ads7846_int_update(s);
+    }
+}
+
+static int ads7856_post_load(void *opaque, int version_id)
+{
+    ADS7846State *s = opaque;
+
+    s->pressure = 0;
+    ads7846_int_update(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_ads7846 = {
+    .name = "ads7846",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = ads7856_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_SSI_PERIPHERAL(ssidev, ADS7846State),
+        VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
+        VMSTATE_INT32(noise, ADS7846State),
+        VMSTATE_INT32(cycle, ADS7846State),
+        VMSTATE_INT32(output, ADS7846State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ads7846_realize(SSIPeripheral *d, Error **errp)
+{
+    DeviceState *dev = DEVICE(d);
+    ADS7846State *s = ADS7846(d);
+
+    qdev_init_gpio_out(dev, &s->interrupt, 1);
+
+    s->input[0] = ADS_TEMP0;	/* TEMP0 */
+    s->input[2] = ADS_VBAT;	/* VBAT */
+    s->input[6] = ADS_VAUX;	/* VAUX */
+    s->input[7] = ADS_TEMP1;	/* TEMP1 */
+
+    /* We want absolute coordinates */
+    qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
+                    "QEMU ADS7846-driven Touchscreen");
+
+    ads7846_int_update(s);
+
+    vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_ads7846, s);
+}
+
+static void ads7846_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
+
+    k->realize = ads7846_realize;
+    k->transfer = ads7846_transfer;
+    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+}
+
+static const TypeInfo ads7846_info = {
+    .name          = TYPE_ADS7846,
+    .parent        = TYPE_SSI_PERIPHERAL,
+    .instance_size = sizeof(ADS7846State),
+    .class_init    = ads7846_class_init,
+};
+
+static void ads7846_register_types(void)
+{
+    type_register_static(&ads7846_info);
+}
+
+type_init(ads7846_register_types)
diff --git a/hw/input/meson.build b/hw/input/meson.build
index e7285b15ae..0042c3f0dc 100644
--- a/hw/input/meson.build
+++ b/hw/input/meson.build
@@ -1,5 +1,6 @@
 softmmu_ss.add(files('hid.c'))
 softmmu_ss.add(when: 'CONFIG_ADB', if_true: files('adb.c', 'adb-mouse.c', 'adb-kbd.c'))
+softmmu_ss.add(when: 'CONFIG_ADS7846', if_true: files('ads7846.c'))
 softmmu_ss.add(when: 'CONFIG_LM832X', if_true: files('lm832x.c'))
 softmmu_ss.add(when: 'CONFIG_PCKBD', if_true: files('pckbd.c'))
 softmmu_ss.add(when: 'CONFIG_PL050', if_true: files('pl050.c'))
-- 
cgit v1.2.3-55-g7522