summaryrefslogtreecommitdiffstats
path: root/include/asm-mips/keyboard.h
blob: a99289d004d465bf689c011c1f225b0c76bdcbba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
/*
 * CPU specific parts of the keyboard driver
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#ifndef __ASM_MIPS_KEYBOARD_H
#define __ASM_MIPS_KEYBOARD_H

#include <linux/config.h>
#include <linux/delay.h>

/*
 * The default IO slowdown is doing 'inb()'s from 0x61, which should be
 * safe. But as that is the keyboard controller chip address, we do our
 * slowdowns here by doing short jumps: the keyboard controller should
 * be able to keep up
 */
#define REALLY_SLOW_IO
#define SLOW_IO_BY_JUMPING
#include <asm/io.h>

#ifdef CONFIG_SGI
#include <asm/segment.h>
#include <asm/sgihpc.h>
#endif
#include <asm/bootinfo.h>
#include <asm/jazz.h>

#ifdef CONFIG_SGI
#define KEYBOARD_IRQ 20
#else
/* Not true for Jazz machines, we cheat a bit for 'em. */
#define KEYBOARD_IRQ 1
#endif

#ifdef CONFIG_SGI
#define DISABLE_KBD_DURING_INTERRUPTS 1
#else
#define DISABLE_KBD_DURING_INTERRUPTS 0
#endif

#ifndef CONFIG_SGI
#define KBD_REPORT_ERR
#endif

static int initialize_kbd(void);

int (*kbd_inb_p)(unsigned short port);
int (*kbd_inb)(unsigned short port);
void (*kbd_outb_p)(unsigned char data, unsigned short port);
void (*kbd_outb)(unsigned char data, unsigned short port);

#if defined(CONFIG_MIPS_JAZZ) || defined(CONFIG_SGI)
/*
 * We want the full initialization for the keyboard controller.
 */

/* XXX Define both and ...  */
#ifdef CONFIG_MIPS_JAZZ
#define INIT_KBD	/* full initialization for the keyboard controller. */
static volatile keyboard_hardware *kh = (void *) JAZZ_KEYBOARD_ADDRESS;
#endif

#ifdef CONFIG_SGI
#define INIT_KBD	/* full initialization for the keyboard controller. */
volatile struct hpc_keyb *kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64);
#endif

static int
jazz_kbd_inb_p(unsigned short port)
{
	int result;

	if(port == KBD_DATA_REG)
		result = kh->data;
	else /* Must be KBD_STATUS_REG */
		result = kh->command;
#ifndef CONFIG_SGI
	inb(0x80);
#endif

	return result;
}

static int
jazz_kbd_inb(unsigned short port)
{
	int result;

	if(port == KBD_DATA_REG)
		result = kh->data;
	else /* Must be KBD_STATUS_REG */
		result = kh->command;

	return result;
}

static void
jazz_kbd_outb_p(unsigned char data, unsigned short port)
{
	if(port == KBD_DATA_REG)
		kh->data = data;
	else if(port == KBD_CNTL_REG)
		kh->command = data;
#ifndef CONFIG_SGI
	inb(0x80);
#endif
}

static void
jazz_kbd_outb(unsigned char data, unsigned short port)
{
	if(port == KBD_DATA_REG)
		kh->data = data;
	else if(port == KBD_CNTL_REG)
		kh->command = data;
}
#endif /* CONFIG_MIPS_JAZZ */

/*
 * Most other MIPS machines access the keyboard controller via
 * ordinary I/O ports.
 */
static int
port_kbd_inb_p(unsigned short port)
{
	return inb_p(port);
}

static int
port_kbd_inb(unsigned short port)
{
	return inb(port);
}

static void
port_kbd_outb_p(unsigned char data, unsigned short port)
{
	return outb_p(data, port);
}

static void
port_kbd_outb(unsigned char data, unsigned short port)
{
	return outb(data, port);
}

#ifdef INIT_KBD
static int
kbd_wait_for_input(void)
{
        int     n;
        int     status, data;

        n = TIMEOUT_CONST;
        do {
                status = kbd_inb(KBD_STATUS_REG);
                /*
                 * Wait for input data to become available.  This bit will
                 * then be cleared by the following read of the DATA
                 * register.
                 */

                if (!(status & KBD_OBF))
			continue;

		data = kbd_inb(KBD_DATA_REG);

                /*
                 * Check to see if a timeout error has occurred.  This means
                 * that transmission was started but did not complete in the
                 * normal time cycle.  PERR is set when a parity error occurred
                 * in the last transmission.
                 */
                if (status & (KBD_GTO | KBD_PERR)) {
			continue;
                }
		return (data & 0xff);
        } while (--n);
        return (-1);	/* timed-out if fell through to here... */
}

static void kbd_write(int address, int data)
{
	int status;

	do {
		status = kbd_inb(KBD_STATUS_REG);  /* spin until input buffer empty*/
	} while (status & KBD_IBF);
	kbd_outb(data, address);               /* write out the data*/
}

static int initialize_kbd(void)
{
	unsigned long flags;

	save_flags(flags); cli();

	/* Flush any pending input. */
	while (kbd_wait_for_input() != -1)
		continue;

	/*
	 * Test the keyboard interface.
	 * This seems to be the only way to get it going.
	 * If the test is successful a x55 is placed in the input buffer.
	 */
	kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
	if (kbd_wait_for_input() != 0x55) {
		printk(KERN_WARNING "initialize_kbd: "
		       "keyboard failed self test.\n");
		restore_flags(flags);
		return(-1);
	}

	/*
	 * Perform a keyboard interface test.  This causes the controller
	 * to test the keyboard clock and data lines.  The results of the
	 * test are placed in the input buffer.
	 */
	kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
	if (kbd_wait_for_input() != 0x00) {
		printk(KERN_WARNING "initialize_kbd: "
		       "keyboard failed self test 2.\n");
		restore_flags(flags);
		return(-1);
	}

	/* Enable the keyboard by allowing the keyboard clock to run. */
	kbd_write(KBD_CNTL_REG, KBD_CNTL_ENABLE);

	/*
	 * Reset keyboard. If the read times out
	 * then the assumption is that no keyboard is
	 * plugged into the machine.
	 * This defaults the keyboard to scan-code set 2.
	 */
	kbd_write(KBD_DATA_REG, KBD_RESET);
	if (kbd_wait_for_input() != KBD_ACK) {
		printk(KERN_WARNING "initialize_kbd: "
		       "reset kbd failed, no ACK.\n");
		restore_flags(flags);
		return(-1);
	}

	/*
	 * Give the keyboard some time to breathe ...
	 *   ... or it fucks up the floppy controller, too.  Wiered.
	 */
	udelay(20);

	if (kbd_wait_for_input() != KBD_POR) {
		printk(KERN_WARNING "initialize_kbd: "
		       "reset kbd failed, not POR.\n");
		restore_flags(flags);
		return(-1);
	}

	/*
	 * now do a DEFAULTS_DISABLE always
	 */
	kbd_write(KBD_DATA_REG, KBD_DISABLE);
	if (kbd_wait_for_input() != KBD_ACK) {
		printk(KERN_WARNING "initialize_kbd: "
		       "disable kbd failed, no ACK.\n");
		restore_flags(flags);
		return(-1);
	}

	/*
	 * Enable keyboard interrupt, operate in "sys" mode,
	 *  enable keyboard (by clearing the disable keyboard bit),
	 *  disable mouse, do conversion of keycodes.
	 */
	kbd_write(KBD_CNTL_REG, KBD_WRITE_MODE);
	kbd_write(KBD_DATA_REG, KBD_EKI|KBD_SYS|KBD_DMS|KBD_KCC);

	/*
	 * now ENABLE the keyboard to set it scanning...
	 */
	kbd_write(KBD_DATA_REG, KBD_ENABLE);
	if (kbd_wait_for_input() != KBD_ACK) {
		printk(KERN_WARNING "initialize_kbd: "
		       "keyboard enable failed.\n");
		restore_flags(flags);
		return(-1);
	}

	restore_flags(flags);

	return (1);
}
#endif

extern __inline__ void
keyboard_setup(void)
{
#ifdef CONFIG_MIPS_JAZZ
        if (mips_machgroup == MACH_GROUP_JAZZ) {
		kbd_inb_p = jazz_kbd_inb_p;
		kbd_inb = jazz_kbd_inb;
		kbd_outb_p = jazz_kbd_outb_p;
		kbd_outb = jazz_kbd_outb;
		/*
		 * Enable keyboard interrupts.
		 */
		*((volatile u16 *)JAZZ_IO_IRQ_ENABLE) |= JAZZ_IE_KEYBOARD;
		set_cp0_status(IE_IRQ1, IE_IRQ1);
		initialize_kbd();
	} else
#endif
	if (mips_machgroup == MACH_GROUP_ARC ||	/* this is for Deskstation */
	    (mips_machgroup == MACH_GROUP_SNI_RM
	     && mips_machtype == MACH_SNI_RM200_PCI)) {
		/*
		 * These machines address their keyboard via the normal
		 * port address range.
		 *
		 * Also enable Scan Mode 2.
		 */
		kbd_inb_p = port_kbd_inb_p;
		kbd_inb = port_kbd_inb;
		kbd_outb_p = port_kbd_outb_p;
		kbd_outb = port_kbd_outb;
		request_region(0x60,16,"keyboard");

		kb_wait();
		kbd_outb(0x60, 0x64); /* 60 == PS/2 MODE ??  */
		kb_wait();
		kbd_outb(0x41, 0x60); /* 4d:same as freebsd, 41:KCC+EKI */
		kb_wait();
		if (!send_data(0xf0) || !send_data(0x02))
			printk("Scanmode 2 change failed\n");
	}
}

#endif /* __ASM_MIPS_KEYBOARD_H */