1/*
2 *	$Id: scan_keyb.c,v 1.1.1.1 2008/10/15 03:26:28 james26_jang Exp $
3 *	Copyright (C) 2000 YAEGASHI Takeshi
4 *	Generic scan keyboard driver
5 */
6
7#include <linux/spinlock.h>
8#include <linux/sched.h>
9#include <linux/interrupt.h>
10#include <linux/tty.h>
11#include <linux/mm.h>
12#include <linux/signal.h>
13#include <linux/init.h>
14#include <linux/kbd_ll.h>
15#include <linux/delay.h>
16#include <linux/random.h>
17#include <linux/poll.h>
18#include <linux/miscdevice.h>
19#include <linux/slab.h>
20#include <linux/kbd_kern.h>
21#include <linux/timer.h>
22
23#define SCANHZ	(HZ/20)
24
25struct scan_keyboard {
26	struct scan_keyboard *next;
27	int (*scan)(unsigned char *buffer);
28	const unsigned char *table;
29	unsigned char *s0, *s1;
30	int length;
31};
32
33static int scan_jiffies=0;
34static struct scan_keyboard *keyboards=NULL;
35struct timer_list scan_timer;
36
37static void check_kbd(const unsigned char *table,
38		      unsigned char *new, unsigned char *old, int length)
39{
40	int need_tasklet_schedule=0;
41	unsigned int xor, bit;
42
43	while(length-->0) {
44		if((xor=*new^*old)==0) {
45			table+=8;
46		}
47		else {
48			for(bit=0x01; bit<0x100; bit<<=1) {
49				if(xor&bit) {
50					handle_scancode(*table, !(*new&bit));
51					need_tasklet_schedule=1;
52				}
53				table++;
54			}
55		}
56		new++; old++;
57	}
58
59	if(need_tasklet_schedule)
60		tasklet_schedule(&keyboard_tasklet);
61}
62
63
64static void scan_kbd(unsigned long dummy)
65{
66	struct scan_keyboard *kbd;
67
68	scan_jiffies++;
69
70	for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) {
71		if(scan_jiffies&1) {
72			if(!kbd->scan(kbd->s0))
73				check_kbd(kbd->table,
74					  kbd->s0, kbd->s1, kbd->length);
75			else
76				memcpy(kbd->s0, kbd->s1, kbd->length);
77		}
78		else {
79			if(!kbd->scan(kbd->s1))
80				check_kbd(kbd->table,
81					  kbd->s1, kbd->s0, kbd->length);
82			else
83				memcpy(kbd->s1, kbd->s0, kbd->length);
84		}
85
86	}
87
88	init_timer(&scan_timer);
89	scan_timer.expires = jiffies + SCANHZ;
90	scan_timer.data = 0;
91	scan_timer.function = scan_kbd;
92	add_timer(&scan_timer);
93}
94
95
96int register_scan_keyboard(int (*scan)(unsigned char *buffer),
97			   const unsigned char *table,
98			   int length)
99{
100	struct scan_keyboard *kbd;
101
102	kbd = kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL);
103	if (kbd == NULL)
104		goto error_out;
105
106	kbd->scan=scan;
107	kbd->table=table;
108	kbd->length=length;
109
110	kbd->s0 = kmalloc(length, GFP_KERNEL);
111	if (kbd->s0 == NULL)
112		goto error_free_kbd;
113
114	kbd->s1 = kmalloc(length, GFP_KERNEL);
115	if (kbd->s1 == NULL)
116		goto error_free_s0;
117
118	memset(kbd->s0, -1, kbd->length);
119	memset(kbd->s1, -1, kbd->length);
120
121	kbd->next=keyboards;
122	keyboards=kbd;
123
124	return 0;
125
126 error_free_s0:
127	kfree(kbd->s0);
128
129 error_free_kbd:
130	kfree(kbd);
131
132 error_out:
133	return -ENOMEM;
134}
135
136
137void __init scan_kbd_init(void)
138{
139	init_timer(&scan_timer);
140	scan_timer.expires = jiffies + SCANHZ;
141	scan_timer.data = 0;
142	scan_timer.function = scan_kbd;
143	add_timer(&scan_timer);
144
145	printk(KERN_INFO "Generic scan keyboard driver initialized\n");
146}
147