cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

ads7846.c (4626B)


      1/*
      2 * TI ADS7846 / TSC2046 chip emulation.
      3 *
      4 * Copyright (c) 2006 Openedhand Ltd.
      5 * Written by Andrzej Zaborowski <balrog@zabor.org>
      6 *
      7 * This code is licensed under the GNU GPL v2.
      8 *
      9 * Contributions after 2012-01-13 are licensed under the terms of the
     10 * GNU GPL, version 2 or (at your option) any later version.
     11 */
     12
     13#include "qemu/osdep.h"
     14#include "hw/irq.h"
     15#include "hw/ssi/ssi.h"
     16#include "migration/vmstate.h"
     17#include "qemu/module.h"
     18#include "ui/console.h"
     19#include "qom/object.h"
     20
     21struct ADS7846State {
     22    SSIPeripheral ssidev;
     23    qemu_irq interrupt;
     24
     25    int input[8];
     26    int pressure;
     27    int noise;
     28
     29    int cycle;
     30    int output;
     31};
     32
     33#define TYPE_ADS7846 "ads7846"
     34OBJECT_DECLARE_SIMPLE_TYPE(ADS7846State, ADS7846)
     35
     36/* Control-byte bitfields */
     37#define CB_PD0		(1 << 0)
     38#define CB_PD1		(1 << 1)
     39#define CB_SER		(1 << 2)
     40#define CB_MODE		(1 << 3)
     41#define CB_A0		(1 << 4)
     42#define CB_A1		(1 << 5)
     43#define CB_A2		(1 << 6)
     44#define CB_START	(1 << 7)
     45
     46#define X_AXIS_DMAX	3470
     47#define X_AXIS_MIN	290
     48#define Y_AXIS_DMAX	3450
     49#define Y_AXIS_MIN	200
     50
     51#define ADS_VBAT	2000
     52#define ADS_VAUX	2000
     53#define ADS_TEMP0	2000
     54#define ADS_TEMP1	3000
     55#define ADS_XPOS(x, y)	(X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
     56#define ADS_YPOS(x, y)	(Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
     57#define ADS_Z1POS(x, y)	600
     58#define ADS_Z2POS(x, y)	(600 + 6000 / ADS_XPOS(x, y))
     59
     60static void ads7846_int_update(ADS7846State *s)
     61{
     62    if (s->interrupt)
     63        qemu_set_irq(s->interrupt, s->pressure == 0);
     64}
     65
     66static uint32_t ads7846_transfer(SSIPeripheral *dev, uint32_t value)
     67{
     68    ADS7846State *s = ADS7846(dev);
     69
     70    switch (s->cycle ++) {
     71    case 0:
     72        if (!(value & CB_START)) {
     73            s->cycle = 0;
     74            break;
     75        }
     76
     77        s->output = s->input[(value >> 4) & 7];
     78
     79        /* Imitate the ADC noise, some drivers expect this.  */
     80        s->noise = (s->noise + 3) & 7;
     81        switch ((value >> 4) & 7) {
     82        case 1: s->output += s->noise ^ 2; break;
     83        case 3: s->output += s->noise ^ 0; break;
     84        case 4: s->output += s->noise ^ 7; break;
     85        case 5: s->output += s->noise ^ 5; break;
     86        }
     87
     88        if (value & CB_MODE)
     89            s->output >>= 4;	/* 8 bits instead of 12 */
     90
     91        break;
     92    case 1:
     93        s->cycle = 0;
     94        break;
     95    }
     96    return s->output;
     97}
     98
     99static void ads7846_ts_event(void *opaque,
    100                int x, int y, int z, int buttons_state)
    101{
    102    ADS7846State *s = opaque;
    103
    104    if (buttons_state) {
    105        x = 0x7fff - x;
    106        s->input[1] = ADS_XPOS(x, y);
    107        s->input[3] = ADS_Z1POS(x, y);
    108        s->input[4] = ADS_Z2POS(x, y);
    109        s->input[5] = ADS_YPOS(x, y);
    110    }
    111
    112    if (s->pressure == !buttons_state) {
    113        s->pressure = !!buttons_state;
    114
    115        ads7846_int_update(s);
    116    }
    117}
    118
    119static int ads7856_post_load(void *opaque, int version_id)
    120{
    121    ADS7846State *s = opaque;
    122
    123    s->pressure = 0;
    124    ads7846_int_update(s);
    125    return 0;
    126}
    127
    128static const VMStateDescription vmstate_ads7846 = {
    129    .name = "ads7846",
    130    .version_id = 1,
    131    .minimum_version_id = 1,
    132    .post_load = ads7856_post_load,
    133    .fields = (VMStateField[]) {
    134        VMSTATE_SSI_PERIPHERAL(ssidev, ADS7846State),
    135        VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
    136        VMSTATE_INT32(noise, ADS7846State),
    137        VMSTATE_INT32(cycle, ADS7846State),
    138        VMSTATE_INT32(output, ADS7846State),
    139        VMSTATE_END_OF_LIST()
    140    }
    141};
    142
    143static void ads7846_realize(SSIPeripheral *d, Error **errp)
    144{
    145    DeviceState *dev = DEVICE(d);
    146    ADS7846State *s = ADS7846(d);
    147
    148    qdev_init_gpio_out(dev, &s->interrupt, 1);
    149
    150    s->input[0] = ADS_TEMP0;	/* TEMP0 */
    151    s->input[2] = ADS_VBAT;	/* VBAT */
    152    s->input[6] = ADS_VAUX;	/* VAUX */
    153    s->input[7] = ADS_TEMP1;	/* TEMP1 */
    154
    155    /* We want absolute coordinates */
    156    qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
    157                    "QEMU ADS7846-driven Touchscreen");
    158
    159    ads7846_int_update(s);
    160
    161    vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_ads7846, s);
    162}
    163
    164static void ads7846_class_init(ObjectClass *klass, void *data)
    165{
    166    DeviceClass *dc = DEVICE_CLASS(klass);
    167    SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
    168
    169    k->realize = ads7846_realize;
    170    k->transfer = ads7846_transfer;
    171    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
    172}
    173
    174static const TypeInfo ads7846_info = {
    175    .name          = TYPE_ADS7846,
    176    .parent        = TYPE_SSI_PERIPHERAL,
    177    .instance_size = sizeof(ADS7846State),
    178    .class_init    = ads7846_class_init,
    179};
    180
    181static void ads7846_register_types(void)
    182{
    183    type_register_static(&ads7846_info);
    184}
    185
    186type_init(ads7846_register_types)