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