(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/ads7846.c

    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: 
   10: #include "hw.h"
   11: #include "devices.h"
   12: #include "console.h"
   13: 
   14: struct ads7846_state_s {
   15:     qemu_irq interrupt;
   16: 
   17:     int input[8];
   18:     int pressure;
   19:     int noise;
   20: 
   21:     int cycle;
   22:     int output;
   23: };
   24: 
   25: /* Control-byte bitfields */
   26: #define CB_PD0          (1 << 0)
   27: #define CB_PD1          (1 << 1)
   28: #define CB_SER          (1 << 2)
   29: #define CB_MODE         (1 << 3)
   30: #define CB_A0           (1 << 4)
   31: #define CB_A1           (1 << 5)
   32: #define CB_A2           (1 << 6)
   33: #define CB_START        (1 << 7)
   34: 
   35: #define X_AXIS_DMAX     3470
   36: #define X_AXIS_MIN      290
   37: #define Y_AXIS_DMAX     3450
   38: #define Y_AXIS_MIN      200
   39: 
   40: #define ADS_VBAT        2000
   41: #define ADS_VAUX        2000
   42: #define ADS_TEMP0       2000
   43: #define ADS_TEMP1       3000
   44: #define ADS_XPOS(x, y)  (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
   45: #define ADS_YPOS(x, y)  (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
   46: #define ADS_Z1POS(x, y) 600
   47: #define ADS_Z2POS(x, y) (600 + 6000 / ADS_XPOS(x, y))
   48: 
   49: static void ads7846_int_update(struct ads7846_state_s *s)
   50: {
   51:     if (s->interrupt)
   52:         qemu_set_irq(s->interrupt, s->pressure == 0);
   53: }
   54: 
   55: uint32_t ads7846_read(void *opaque)
   56: {
   57:     struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
   58: 
   59:     return s->output;
   60: }
   61: 
   62: void ads7846_write(void *opaque, uint32_t value)
   63: {
   64:     struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
   65: 
   66:     switch (s->cycle ++) {
   67:     case 0:
   68:         if (!(value & CB_START)) {
   69:             s->cycle = 0;
   70:             break;
   71:         }
   72: 
   73:         s->output = s->input[(value >> 4) & 7];
   74: 
   75:         /* Imitate the ADC noise, some drivers expect this.  */
   76:         s->noise = (s->noise + 3) & 7;
   77:         switch ((value >> 4) & 7) {
   78:         case 1: s->output += s->noise ^ 2; break;
   79:         case 3: s->output += s->noise ^ 0; break;
   80:         case 4: s->output += s->noise ^ 7; break;
   81:         case 5: s->output += s->noise ^ 5; break;
   82:         }
   83: 
   84:         if (value & CB_MODE)
   85:             s->output >>= 4;    /* 8 bits instead of 12 */
   86: 
   87:         break;
   88:     case 1:
   89:         s->cycle = 0;
   90:         break;
   91:     }
   92: }
   93: 
   94: static void ads7846_ts_event(void *opaque,
   95:                 int x, int y, int z, int buttons_state)
   96: {
   97:     struct ads7846_state_s *s = opaque;
   98: 
   99:     if (buttons_state) {
  100:         x = 0x7fff - x;
  101:         s->input[1] = ADS_XPOS(x, y);
  102:         s->input[3] = ADS_Z1POS(x, y);
  103:         s->input[4] = ADS_Z2POS(x, y);
  104:         s->input[5] = ADS_YPOS(x, y);
  105:     }
  106: 
  107:     if (s->pressure == !buttons_state) {
  108:         s->pressure = !!buttons_state;
  109: 
  110:         ads7846_int_update(s);
  111:     }
  112: }
  113: 
  114: static void ads7846_save(QEMUFile *f, void *opaque)
  115: {
  116:     struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
  117:     int i;
  118: 
  119:     for (i = 0; i < 8; i ++)
  120:         qemu_put_be32(f, s->input[i]);
  121:     qemu_put_be32(f, s->noise);
  122:     qemu_put_be32(f, s->cycle);
  123:     qemu_put_be32(f, s->output);
  124: }
  125: 
  126: static int ads7846_load(QEMUFile *f, void *opaque, int version_id)
  127: {
  128:     struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
  129:     int i;
  130: 
  131:     for (i = 0; i < 8; i ++)
  132:         s->input[i] = qemu_get_be32(f);
  133:     s->noise = qemu_get_be32(f);
  134:     s->cycle = qemu_get_be32(f);
  135:     s->output = qemu_get_be32(f);
  136: 
  137:     s->pressure = 0;
  138:     ads7846_int_update(s);
  139: 
  140:     return 0;
  141: }
  142: 
  143: static int ads7846_iid = 0;
  144: 
  145: struct ads7846_state_s *ads7846_init(qemu_irq penirq)
  146: {
  147:     struct ads7846_state_s *s;
  148:     s = (struct ads7846_state_s *)
  149:             qemu_mallocz(sizeof(struct ads7846_state_s));
  150:     memset(s, 0, sizeof(struct ads7846_state_s));
  151: 
  152:     s->interrupt = penirq;
  153: 
  154:     s->input[0] = ADS_TEMP0;    /* TEMP0 */
  155:     s->input[2] = ADS_VBAT;     /* VBAT */
  156:     s->input[6] = ADS_VAUX;     /* VAUX */
  157:     s->input[7] = ADS_TEMP1;    /* TEMP1 */
  158: 
  159:     /* We want absolute coordinates */
  160:     qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
  161:                     "QEMU ADS7846-driven Touchscreen");
  162: 
  163:     ads7846_int_update(s);
  164: 
  165:     register_savevm("ads7846", ads7846_iid ++, 0,
  166:                     ads7846_save, ads7846_load, s);
  167: 
  168:     return s;
  169: }
Syntax (Markdown)