Annotation of qemu/hw/pxa2xx_keypad.c, revision 1.1.1.8

1.1       root        1: /*
                      2:  * Intel PXA27X Keypad Controller emulation.
                      3:  *
                      4:  * Copyright (c) 2007 MontaVista Software, Inc
                      5:  * Written by Armin Kuster <akuster@kama-aina.net>
                      6:  *              or  <Akuster@mvista.com>
                      7:  *
                      8:  * This code is licensed under the GPLv2.
                      9:  */
                     10: 
                     11: #include "hw.h"
                     12: #include "pxa.h"
                     13: #include "console.h"
                     14: 
                     15: /*
                     16:  * Keypad
                     17:  */
                     18: #define KPC         0x00    /* Keypad Interface Control register */
                     19: #define KPDK        0x08    /* Keypad Interface Direct Key register */
                     20: #define KPREC       0x10    /* Keypad Interface Rotary Encoder register */
                     21: #define KPMK        0x18    /* Keypad Interface Matrix Key register */
                     22: #define KPAS        0x20    /* Keypad Interface Automatic Scan register */
                     23: #define KPASMKP0    0x28    /* Keypad Interface Automatic Scan Multiple
                     24:                                 Key Presser register 0 */
                     25: #define KPASMKP1    0x30    /* Keypad Interface Automatic Scan Multiple
                     26:                                 Key Presser register 1 */
                     27: #define KPASMKP2    0x38    /* Keypad Interface Automatic Scan Multiple
                     28:                                 Key Presser register 2 */
                     29: #define KPASMKP3    0x40    /* Keypad Interface Automatic Scan Multiple
                     30:                                 Key Presser register 3 */
                     31: #define KPKDI       0x48    /* Keypad Interface Key Debounce Interval
                     32:                                 register */
                     33: 
                     34: /* Keypad defines */
                     35: #define KPC_AS          (0x1 << 30)  /* Automatic Scan bit */
                     36: #define KPC_ASACT       (0x1 << 29)  /* Automatic Scan on Activity */
                     37: #define KPC_MI          (0x1 << 22)  /* Matrix interrupt bit */
                     38: #define KPC_IMKP        (0x1 << 21)  /* Ignore Multiple Key Press */
                     39: #define KPC_MS7         (0x1 << 20)  /* Matrix scan line 7 */
                     40: #define KPC_MS6         (0x1 << 19)  /* Matrix scan line 6 */
                     41: #define KPC_MS5         (0x1 << 18)  /* Matrix scan line 5 */
                     42: #define KPC_MS4         (0x1 << 17)  /* Matrix scan line 4 */
                     43: #define KPC_MS3         (0x1 << 16)  /* Matrix scan line 3 */
                     44: #define KPC_MS2         (0x1 << 15)  /* Matrix scan line 2 */
                     45: #define KPC_MS1         (0x1 << 14)  /* Matrix scan line 1 */
                     46: #define KPC_MS0         (0x1 << 13)  /* Matrix scan line 0 */
                     47: #define KPC_ME          (0x1 << 12)  /* Matrix Keypad Enable */
                     48: #define KPC_MIE         (0x1 << 11)  /* Matrix Interrupt Enable */
                     49: #define KPC_DK_DEB_SEL  (0x1 <<  9)  /* Direct Keypad Debounce Select */
                     50: #define KPC_DI          (0x1 <<  5)  /* Direct key interrupt bit */
                     51: #define KPC_RE_ZERO_DEB (0x1 <<  4)  /* Rotary Encoder Zero Debounce */
                     52: #define KPC_REE1        (0x1 <<  3)  /* Rotary Encoder1 Enable */
                     53: #define KPC_REE0        (0x1 <<  2)  /* Rotary Encoder0 Enable */
                     54: #define KPC_DE          (0x1 <<  1)  /* Direct Keypad Enable */
                     55: #define KPC_DIE         (0x1 <<  0)  /* Direct Keypad interrupt Enable */
                     56: 
                     57: #define KPDK_DKP        (0x1 << 31)
                     58: #define KPDK_DK7        (0x1 <<  7)
                     59: #define KPDK_DK6        (0x1 <<  6)
                     60: #define KPDK_DK5        (0x1 <<  5)
                     61: #define KPDK_DK4        (0x1 <<  4)
                     62: #define KPDK_DK3        (0x1 <<  3)
                     63: #define KPDK_DK2        (0x1 <<  2)
                     64: #define KPDK_DK1        (0x1 <<  1)
                     65: #define KPDK_DK0        (0x1 <<  0)
                     66: 
                     67: #define KPREC_OF1       (0x1 << 31)
                     68: #define KPREC_UF1       (0x1 << 30)
                     69: #define KPREC_OF0       (0x1 << 15)
                     70: #define KPREC_UF0       (0x1 << 14)
                     71: 
                     72: #define KPMK_MKP        (0x1 << 31)
                     73: #define KPAS_SO         (0x1 << 31)
                     74: #define KPASMKPx_SO     (0x1 << 31)
                     75: 
                     76: 
                     77: #define KPASMKPx_MKC(row, col)  (1 << (row + 16 * (col % 2)))
                     78: 
                     79: #define PXAKBD_MAXROW   8
                     80: #define PXAKBD_MAXCOL   8
                     81: 
1.1.1.3   root       82: struct PXA2xxKeyPadState {
1.1       root       83:     qemu_irq    irq;
                     84:     struct  keymap *map;
1.1.1.7   root       85:     int         pressed_cnt;
                     86:     int         alt_code;
1.1       root       87: 
                     88:     uint32_t    kpc;
                     89:     uint32_t    kpdk;
                     90:     uint32_t    kprec;
                     91:     uint32_t    kpmk;
                     92:     uint32_t    kpas;
1.1.1.7   root       93:     uint32_t    kpasmkp[4];
1.1       root       94:     uint32_t    kpkdi;
                     95: };
                     96: 
1.1.1.7   root       97: static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col)
                     98: {
                     99:     int i;
                    100:     for (i = 0; i < 4; i++)
                    101:     {
                    102:         *col = i * 2;
                    103:         for (*row = 0; *row < 8; (*row)++) {
                    104:             if (kp->kpasmkp[i] & (1 << *row))
                    105:                 return;
                    106:         }
                    107:         *col = i * 2 + 1;
                    108:         for (*row = 0; *row < 8; (*row)++) {
                    109:             if (kp->kpasmkp[i] & (1 << (*row + 16)))
                    110:                 return;
                    111:         }
                    112:     }
                    113: }
                    114: 
1.1.1.3   root      115: static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
1.1       root      116: {
1.1.1.7   root      117:     int row, col, rel, assert_irq = 0;
                    118:     uint32_t val;
                    119: 
                    120:     if (keycode == 0xe0) {
                    121:         kp->alt_code = 1;
                    122:         return;
                    123:     }
1.1       root      124: 
                    125:     if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
                    126:         return;
                    127: 
                    128:     if(kp->kpc & KPC_AS || kp->kpc & KPC_ASACT) {
                    129:         if(kp->kpc & KPC_AS)
                    130:             kp->kpc &= ~(KPC_AS);
                    131: 
                    132:         rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */
                    133:         keycode &= ~(0x80); /* strip qemu key release bit */
1.1.1.7   root      134:         if (kp->alt_code) {
                    135:             keycode |= 0x80;
                    136:             kp->alt_code = 0;
                    137:         }
                    138: 
1.1       root      139:         row = kp->map[keycode].row;
                    140:         col = kp->map[keycode].column;
                    141:         if(row == -1 || col == -1)
                    142:             return;
1.1.1.7   root      143: 
                    144:         val = KPASMKPx_MKC(row, col);
                    145:         if (rel) {
                    146:             if (kp->kpasmkp[col / 2] & val) {
                    147:                 kp->kpasmkp[col / 2] &= ~val;
                    148:                 kp->pressed_cnt--;
                    149:                 assert_irq = 1;
                    150:             }
                    151:         } else {
                    152:             if (!(kp->kpasmkp[col / 2] & val)) {
                    153:                 kp->kpasmkp[col / 2] |= val;
                    154:                 kp->pressed_cnt++;
                    155:                 assert_irq = 1;
                    156:             }
                    157:         }
                    158:         kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf;
                    159:         if (kp->pressed_cnt == 1) {
                    160:             kp->kpas &= ~((0xf << 4) | 0xf);
                    161:             if (rel)
                    162:                 pxa27x_keypad_find_pressed_key(kp, &row, &col);
                    163:             kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
                    164:         }
1.1       root      165:         goto out;
                    166:     }
                    167:     return;
                    168: 
                    169: out:
1.1.1.7   root      170:     if (assert_irq && (kp->kpc & KPC_MIE)) {
1.1       root      171:         kp->kpc |= KPC_MI;
                    172:         qemu_irq_raise(kp->irq);
                    173:     }
                    174:     return;
                    175: }
                    176: 
                    177: static uint32_t pxa2xx_keypad_read(void *opaque, target_phys_addr_t offset)
                    178: {
1.1.1.3   root      179:     PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
1.1       root      180:     uint32_t tmp;
                    181: 
                    182:     switch (offset) {
                    183:     case KPC:
                    184:         tmp = s->kpc;
                    185:         if(tmp & KPC_MI)
                    186:             s->kpc &= ~(KPC_MI);
                    187:         if(tmp & KPC_DI)
                    188:             s->kpc &= ~(KPC_DI);
                    189:         qemu_irq_lower(s->irq);
                    190:         return tmp;
                    191:         break;
                    192:     case KPDK:
                    193:         return s->kpdk;
                    194:         break;
                    195:     case KPREC:
                    196:         tmp = s->kprec;
                    197:         if(tmp & KPREC_OF1)
                    198:             s->kprec &= ~(KPREC_OF1);
                    199:         if(tmp & KPREC_UF1)
                    200:             s->kprec &= ~(KPREC_UF1);
                    201:         if(tmp & KPREC_OF0)
                    202:             s->kprec &= ~(KPREC_OF0);
                    203:         if(tmp & KPREC_UF0)
                    204:             s->kprec &= ~(KPREC_UF0);
                    205:         return tmp;
                    206:         break;
                    207:     case KPMK:
                    208:         tmp = s->kpmk;
                    209:         if(tmp & KPMK_MKP)
                    210:             s->kpmk &= ~(KPMK_MKP);
                    211:         return tmp;
                    212:         break;
                    213:     case KPAS:
                    214:         return s->kpas;
                    215:         break;
                    216:     case KPASMKP0:
1.1.1.7   root      217:         return s->kpasmkp[0];
1.1       root      218:         break;
                    219:     case KPASMKP1:
1.1.1.7   root      220:         return s->kpasmkp[1];
1.1       root      221:         break;
                    222:     case KPASMKP2:
1.1.1.7   root      223:         return s->kpasmkp[2];
1.1       root      224:         break;
                    225:     case KPASMKP3:
1.1.1.7   root      226:         return s->kpasmkp[3];
1.1       root      227:         break;
                    228:     case KPKDI:
                    229:         return s->kpkdi;
                    230:         break;
                    231:     default:
1.1.1.3   root      232:         hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
1.1       root      233:     }
                    234: 
                    235:     return 0;
                    236: }
                    237: 
                    238: static void pxa2xx_keypad_write(void *opaque,
                    239:                 target_phys_addr_t offset, uint32_t value)
                    240: {
1.1.1.3   root      241:     PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
1.1       root      242: 
                    243:     switch (offset) {
                    244:     case KPC:
                    245:         s->kpc = value;
                    246:         break;
                    247:     case KPDK:
                    248:         s->kpdk = value;
                    249:         break;
                    250:     case KPREC:
                    251:         s->kprec = value;
                    252:         break;
                    253:     case KPMK:
                    254:         s->kpmk = value;
                    255:         break;
                    256:     case KPAS:
                    257:         s->kpas = value;
                    258:         break;
                    259:     case KPASMKP0:
1.1.1.7   root      260:         s->kpasmkp[0] = value;
1.1       root      261:         break;
                    262:     case KPASMKP1:
1.1.1.7   root      263:         s->kpasmkp[1] = value;
1.1       root      264:         break;
                    265:     case KPASMKP2:
1.1.1.7   root      266:         s->kpasmkp[2] = value;
1.1       root      267:         break;
                    268:     case KPASMKP3:
1.1.1.7   root      269:         s->kpasmkp[3] = value;
1.1       root      270:         break;
                    271:     case KPKDI:
                    272:         s->kpkdi = value;
                    273:         break;
                    274: 
                    275:     default:
1.1.1.3   root      276:         hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
1.1       root      277:     }
                    278: }
                    279: 
1.1.1.4   root      280: static CPUReadMemoryFunc * const pxa2xx_keypad_readfn[] = {
1.1       root      281:     pxa2xx_keypad_read,
                    282:     pxa2xx_keypad_read,
                    283:     pxa2xx_keypad_read
                    284: };
                    285: 
1.1.1.4   root      286: static CPUWriteMemoryFunc * const pxa2xx_keypad_writefn[] = {
1.1       root      287:     pxa2xx_keypad_write,
                    288:     pxa2xx_keypad_write,
                    289:     pxa2xx_keypad_write
                    290: };
                    291: 
1.1.1.7   root      292: static const VMStateDescription vmstate_pxa2xx_keypad = {
                    293:     .name = "pxa2xx_keypad",
                    294:     .version_id = 0,
                    295:     .minimum_version_id = 0,
                    296:     .minimum_version_id_old = 0,
                    297:     .fields      = (VMStateField[]) {
                    298:         VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
                    299:         VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
                    300:         VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
                    301:         VMSTATE_UINT32(kpmk, PXA2xxKeyPadState),
                    302:         VMSTATE_UINT32(kpas, PXA2xxKeyPadState),
                    303:         VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4),
                    304:         VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState),
                    305:         VMSTATE_END_OF_LIST()
                    306:     }
                    307: };
1.1       root      308: 
1.1.1.3   root      309: PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base,
1.1       root      310:         qemu_irq irq)
                    311: {
                    312:     int iomemtype;
1.1.1.3   root      313:     PXA2xxKeyPadState *s;
1.1       root      314: 
1.1.1.8 ! root      315:     s = (PXA2xxKeyPadState *) g_malloc0(sizeof(PXA2xxKeyPadState));
1.1       root      316:     s->irq = irq;
                    317: 
1.1.1.3   root      318:     iomemtype = cpu_register_io_memory(pxa2xx_keypad_readfn,
1.1.1.6   root      319:                     pxa2xx_keypad_writefn, s, DEVICE_NATIVE_ENDIAN);
1.1       root      320:     cpu_register_physical_memory(base, 0x00100000, iomemtype);
                    321: 
1.1.1.7   root      322:     vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s);
1.1       root      323: 
                    324:     return s;
                    325: }
                    326: 
1.1.1.3   root      327: void pxa27x_register_keypad(PXA2xxKeyPadState *kp, struct keymap *map,
1.1       root      328:         int size)
                    329: {
                    330:     if(!map || size < 0x80) {
                    331:         fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__);
                    332:         exit(-1);
                    333:     }
                    334: 
                    335:     kp->map = map;
                    336:     qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp);
                    337: }

unix.superglobalmegacorp.com