x86, AMD IOMMU: replace DEVID macro with a function
[sfrench/cifs-2.6.git] / arch / ppc / boot / lib / kbd.c
1 #include <linux/keyboard.h>
2
3 #include "defkeymap.c"  /* yeah I know it's bad -- Cort */
4
5
6 unsigned char shfts, ctls, alts, caps;
7
8 #define KBDATAP         0x60    /* kbd data port */
9 #define KBSTATUSPORT    0x61    /* kbd status */
10 #define KBSTATP         0x64    /* kbd status port */
11 #define KBINRDY         0x01
12 #define KBOUTRDY        0x02
13
14 extern unsigned char inb(int port);
15 extern void outb(int port, char val);
16 extern void puts(const char *);
17 extern void puthex(unsigned long val);
18 extern void udelay(long x);
19
20 static int kbd(int noblock)
21 {
22         unsigned char dt, brk, val;
23         unsigned code;
24 loop:
25         if (noblock) {
26             if ((inb(KBSTATP) & KBINRDY) == 0)
27                 return (-1);
28         } else while((inb(KBSTATP) & KBINRDY) == 0) ;
29
30         dt = inb(KBDATAP);
31
32         brk = dt & 0x80;        /* brk == 1 on key release */
33         dt = dt & 0x7f;         /* keycode */
34
35         if (shfts)
36             code = shift_map[dt];
37         else if (ctls)
38             code = ctrl_map[dt];
39         else
40             code = plain_map[dt];
41
42         val = KVAL(code);
43         switch (KTYP(code) & 0x0f) {
44             case KT_LATIN:
45                 if (brk)
46                     break;
47                 if (alts)
48                     val |= 0x80;
49                 if (val == 0x7f)        /* map delete to backspace */
50                     val = '\b';
51                 return val;
52
53             case KT_LETTER:
54                 if (brk)
55                     break;
56                 if (caps)
57                     val -= 'a'-'A';
58                 return val;
59
60             case KT_SPEC:
61                 if (brk)
62                     break;
63                 if (val == KVAL(K_CAPS))
64                     caps = !caps;
65                 else if (val == KVAL(K_ENTER)) {
66 enter:              /* Wait for key up */
67                     while (1) {
68                         while((inb(KBSTATP) & KBINRDY) == 0) ;
69                         dt = inb(KBDATAP);
70                         if (dt & 0x80) /* key up */ break;
71                     }
72                     return 10;
73                 }
74                 break;
75
76             case KT_PAD:
77                 if (brk)
78                     break;
79                 if (val < 10)
80                     return val;
81                 if (val == KVAL(K_PENTER))
82                     goto enter;
83                 break;
84
85             case KT_SHIFT:
86                 switch (val) {
87                     case KG_SHIFT:
88                     case KG_SHIFTL:
89                     case KG_SHIFTR:
90                         shfts = brk ? 0 : 1;
91                         break;
92                     case KG_ALT:
93                     case KG_ALTGR:
94                         alts = brk ? 0 : 1;
95                         break;
96                     case KG_CTRL:
97                     case KG_CTRLL:
98                     case KG_CTRLR:
99                         ctls = brk ? 0 : 1;
100                         break;
101                 }
102                 break;
103
104             case KT_LOCK:
105                 switch (val) {
106                     case KG_SHIFT:
107                     case KG_SHIFTL:
108                     case KG_SHIFTR:
109                         if (brk)
110                             shfts = !shfts;
111                         break;
112                     case KG_ALT:
113                     case KG_ALTGR:
114                         if (brk)
115                             alts = !alts;
116                         break;
117                     case KG_CTRL:
118                     case KG_CTRLL:
119                     case KG_CTRLR:
120                         if (brk)
121                             ctls = !ctls;
122                         break;
123                 }
124                 break;
125         }
126         if (brk) return (-1);  /* Ignore initial 'key up' codes */
127         goto loop;
128 }
129
130 static int __kbdreset(void)
131 {
132         unsigned char c;
133         int i, t;
134
135         /* flush input queue */
136         t = 2000;
137         while ((inb(KBSTATP) & KBINRDY))
138         {
139                 (void)inb(KBDATAP);
140                 if (--t == 0)
141                         return 1;
142         }
143         /* Send self-test */
144         t = 20000;
145         while (inb(KBSTATP) & KBOUTRDY)
146                 if (--t == 0)
147                         return 2;
148         outb(KBSTATP,0xAA);
149         t = 200000;
150         while ((inb(KBSTATP) & KBINRDY) == 0)   /* wait input ready */
151                 if (--t == 0)
152                         return 3;
153         if ((c = inb(KBDATAP)) != 0x55)
154         {
155                 puts("Keyboard self test failed - result:");
156                 puthex(c);
157                 puts("\n");
158         }
159         /* Enable interrupts and keyboard controller */
160         t = 20000;
161         while (inb(KBSTATP) & KBOUTRDY)
162                 if (--t == 0) return 4;
163         outb(KBSTATP,0x60);
164         t = 20000;
165         while (inb(KBSTATP) & KBOUTRDY)
166                 if (--t == 0) return 5;
167         outb(KBDATAP,0x45);
168         for (i = 0;  i < 10000;  i++) udelay(1);
169
170         t = 20000;
171         while (inb(KBSTATP) & KBOUTRDY)
172                 if (--t == 0) return 6;
173         outb(KBSTATP,0x20);
174         t = 200000;
175         while ((inb(KBSTATP) & KBINRDY) == 0)   /* wait input ready */
176                 if (--t == 0) return 7;
177         if (! (inb(KBDATAP) & 0x40)) {
178                 /*
179                  * Quote from PS/2 System Reference Manual:
180                  *
181                  * "Address hex 0060 and address hex 0064 should be
182                  * written only when the input-buffer-full bit and
183                  * output-buffer-full bit in the Controller Status
184                  * register are set 0." (KBINRDY and KBOUTRDY)
185                  */
186                 t = 200000;
187                 while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
188                         if (--t == 0) return 8;
189                 outb(KBDATAP,0xF0);
190                 t = 200000;
191                 while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
192                         if (--t == 0) return 9;
193                 outb(KBDATAP,0x01);
194         }
195         t = 20000;
196         while (inb(KBSTATP) & KBOUTRDY)
197                 if (--t == 0) return 10;
198         outb(KBSTATP,0xAE);
199         return 0;
200 }
201
202 static void kbdreset(void)
203 {
204         int ret = __kbdreset();
205
206         if (ret) {
207                 puts("__kbdreset failed: ");
208                 puthex(ret);
209                 puts("\n");
210         }
211 }
212
213 /* We have to actually read the keyboard when CRT_tstc is called,
214  * since the pending data might be a key release code, and therefore
215  * not valid data.  In this case, kbd() will return -1, even though there's
216  * data to be read.  Of course, we might actually read a valid key press,
217  * in which case it gets queued into key_pending for use by CRT_getc.
218  */
219
220 static int kbd_reset = 0;
221
222 static int key_pending = -1;
223
224 int CRT_getc(void)
225 {
226         int c;
227         if (!kbd_reset) {kbdreset(); kbd_reset++; }
228
229         if (key_pending != -1) {
230                 c = key_pending;
231                 key_pending = -1;
232                 return c;
233         } else {
234         while ((c = kbd(0)) == 0) ;
235                 return c;
236         }
237 }
238
239 int CRT_tstc(void)
240 {
241         if (!kbd_reset) {kbdreset(); kbd_reset++; }
242
243         while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) {
244                 key_pending = kbd(1);
245         }
246
247         return (key_pending != -1);
248 }