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