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#include <linux/config.h>
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52#ifdef CONFIG_QTRONIX_KEYBOARD
53
54#include <linux/module.h>
55#include <linux/types.h>
56#include <linux/pci.h>
57#include <linux/kernel.h>
58
59#include <asm/it8172/it8172.h>
60#include <asm/it8172/it8172_int.h>
61#include <asm/it8172/it8172_cir.h>
62
63#include <linux/spinlock.h>
64#include <linux/sched.h>
65#include <linux/interrupt.h>
66#include <linux/tty.h>
67#include <linux/mm.h>
68#include <linux/signal.h>
69#include <linux/init.h>
70#include <linux/kbd_ll.h>
71#include <linux/delay.h>
72#include <linux/random.h>
73#include <linux/poll.h>
74#include <linux/miscdevice.h>
75#include <linux/slab.h>
76#include <linux/kbd_kern.h>
77#include <linux/smp_lock.h>
78#include <asm/io.h>
79#include <linux/pc_keyb.h>
80
81#include <asm/keyboard.h>
82#include <asm/bitops.h>
83#include <asm/uaccess.h>
84#include <asm/irq.h>
85#include <asm/system.h>
86
87#define leading1 0
88#define leading2 0xF
89
90#define KBD_CIR_PORT 0
91#define AUX_RECONNECT 170
92
93static int data_index;
94struct cir_port *cir;
95static unsigned char kbdbytes[5];
96static unsigned char cir_data[32];
97
98static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs);
99static int handle_data(unsigned char *p_data);
100static inline void handle_mouse_event(unsigned char scancode);
101static inline void handle_keyboard_event(unsigned char scancode, int down);
102static int __init psaux_init(void);
103
104static struct aux_queue *queue;
105static int aux_count = 0;
106
107
108
109
110
111
112
113#define NUM_FN_KEYS 56
114static unsigned char fn_keys[NUM_FN_KEYS] = {
115 0,0,0,0,0,0,0,0,
116 8,9,10,93,0,0,0,0,
117 0,0,0,0,0,0,0,5,
118 6,7,91,0,0,0,0,0,
119 0,0,0,0,0,2,3,4,
120 92,0,0,0,0,0,0,0,
121 0,0,0,0,11,0,94,95
122
123};
124
125void __init init_qtronix_990P_kbd(void)
126{
127 int retval;
128
129 cir = (struct cir_port *)kmalloc(sizeof(struct cir_port), GFP_KERNEL);
130 if (!cir) {
131 printk("Unable to initialize Qtronix keyboard\n");
132 return;
133 }
134
135
136
137
138
139 cir->port = KBD_CIR_PORT;
140 cir->baud_rate = 0x1d;
141 cir->rdwos = 0;
142 cir->rxdcr = 0x3;
143 cir->hcfs = 0;
144 cir->fifo_tl = 0;
145 cir->cfq = 0x1d;
146 cir_port_init(cir);
147
148 retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler,
149 (unsigned long )(SA_INTERRUPT|SA_SHIRQ),
150 (const char *)"Qtronix IR Keyboard", (void *)cir);
151
152 if (retval) {
153 printk("unable to allocate cir %d irq %d\n",
154 cir->port, IT8172_CIR0_IRQ);
155 }
156#ifdef CONFIG_PSMOUSE
157 psaux_init();
158#endif
159}
160
161static inline unsigned char BitReverse(unsigned short key)
162{
163 unsigned char rkey = 0;
164 rkey |= (key & 0x1) << 7;
165 rkey |= (key & 0x2) << 5;
166 rkey |= (key & 0x4) << 3;
167 rkey |= (key & 0x8) << 1;
168 rkey |= (key & 0x10) >> 1;
169 rkey |= (key & 0x20) >> 3;
170 rkey |= (key & 0x40) >> 5;
171 rkey |= (key & 0x80) >> 7;
172 return rkey;
173
174}
175
176
177static inline u_int8_t UpperByte(u_int8_t data)
178{
179 return (data >> 4);
180}
181
182
183static inline u_int8_t LowerByte(u_int8_t data)
184{
185 return (data & 0xF);
186}
187
188
189int CheckSumOk(u_int8_t byte1, u_int8_t byte2,
190 u_int8_t byte3, u_int8_t byte4, u_int8_t byte5)
191{
192 u_int8_t CheckSum;
193
194 CheckSum = (byte1 & 0x0F) + byte2 + byte3 + byte4 + byte5;
195 if ( LowerByte(UpperByte(CheckSum) + LowerByte(CheckSum)) != UpperByte(byte1) )
196 return 0;
197 else
198 return 1;
199}
200
201
202static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs)
203{
204 struct cir_port *cir;
205 int j;
206 unsigned char int_status;
207
208 cir = (struct cir_port *)dev_id;
209 int_status = get_int_status(cir);;
210 if (int_status & 0x4) {
211 clear_fifo(cir);
212 return;
213 }
214
215 while (cir_get_rx_count(cir)) {
216
217 cir_data[data_index] = cir_read_data(cir);
218
219 if (data_index == 0) {
220 if (cir_data[data_index] != leading1) {
221
222 set_rx_active(cir);
223 clear_fifo(cir);
224 continue;
225 }
226 }
227 if (data_index == 1) {
228 if ((cir_data[data_index] & 0xf) != leading2) {
229 set_rx_active(cir);
230 data_index = 0;
231 clear_fifo(cir);
232 continue;
233 }
234 }
235
236 if ( (cir_data[data_index] == 0xff)) {
237
238 set_rx_active(cir);
239#if 0
240 for (j=0; j<=data_index; j++) {
241 printk("rx_data %d: %x\n", j, cir_data[j]);
242 }
243#endif
244 data_index = 0;
245 handle_data(cir_data);
246 return;
247 }
248 else if (data_index>16) {
249 set_rx_active(cir);
250#if 0
251 printk("warning: data_index %d\n", data_index);
252 for (j=0; j<=data_index; j++) {
253 printk("rx_data %d: %x\n", j, cir_data[j]);
254 }
255#endif
256 data_index = 0;
257 clear_fifo(cir);
258 return;
259 }
260 data_index++;
261 }
262}
263
264
265#define NUM_KBD_BYTES 5
266static int handle_data(unsigned char *p_data)
267{
268 u_int32_t bit_bucket;
269 u_int32_t i, j;
270 u_int32_t got_bits, next_byte;
271 int down = 0;
272
273
274 for (i=0; i<16; i++)
275 p_data[i] = BitReverse(~p_data[i]);
276
277
278
279
280
281
282
283
284 bit_bucket = p_data[1] << 12;
285 got_bits = 4;
286 next_byte = 2;
287
288
289
290
291 for (i=0; i<NUM_KBD_BYTES; i++) {
292
293 kbdbytes[i]=0;
294
295 for (j=0; j<8; j++)
296 {
297 if (got_bits < 4) {
298 bit_bucket |= (p_data[next_byte++] << (8 - got_bits));
299 got_bits += 8;
300 }
301
302 if ((bit_bucket & 0xF000) == 0x8000) {
303
304 kbdbytes[i] = 0x80 | (kbdbytes[i] >> 1);
305 got_bits -= 4;
306 bit_bucket = bit_bucket << 4;
307 }
308 else if ((bit_bucket & 0xC000) == 0x8000) {
309
310 kbdbytes[i] = kbdbytes[i] >> 1;
311 got_bits -= 2;
312 bit_bucket = bit_bucket << 2;
313 }
314 else {
315
316 return 1;
317 }
318
319 if (next_byte > 16) {
320
321 return 1;
322 }
323 }
324 }
325
326
327 if (!CheckSumOk(kbdbytes[0], kbdbytes[1],
328 kbdbytes[2], kbdbytes[3], kbdbytes[4])) {
329
330 return 1;
331 }
332
333 if (kbdbytes[1] & 0x08) {
334
335 handle_mouse_event(kbdbytes[1]);
336 handle_mouse_event(kbdbytes[2]);
337 handle_mouse_event(kbdbytes[3]);
338 }
339 else {
340 if (kbdbytes[2] == 0) down = 1;
341#if 0
342 if (down)
343 printk("down %d\n", kbdbytes[3]);
344 else
345 printk("up %d\n", kbdbytes[3]);
346#endif
347 handle_keyboard_event(kbdbytes[3], down);
348 }
349 return 0;
350}
351
352
353spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
354static unsigned char handle_kbd_event(void);
355
356
357int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
358{
359 printk("kbd_setkeycode scancode %x keycode %x\n", scancode, keycode);
360 return 0;
361}
362
363int kbd_getkeycode(unsigned int scancode)
364{
365 return scancode;
366}
367
368
369int kbd_translate(unsigned char scancode, unsigned char *keycode,
370 char raw_mode)
371{
372 static int prev_scancode = 0;
373
374 if (scancode == 0x00 || scancode == 0xff) {
375 prev_scancode = 0;
376 return 0;
377 }
378
379
380 if (!prev_scancode && scancode == 160) {
381
382 prev_scancode = 160;
383 return 0;
384 }
385 else if (prev_scancode && scancode == 160) {
386
387 prev_scancode = 0;
388 return 0;
389 }
390
391
392 if (prev_scancode == 160) {
393 if (scancode <= NUM_FN_KEYS) {
394 *keycode = fn_keys[scancode];
395
396 }
397 else
398 return 0;
399 }
400 else if (scancode <= 127) {
401 *keycode = scancode;
402 }
403 else
404 return 0;
405
406
407 return 1;
408}
409
410char kbd_unexpected_up(unsigned char keycode)
411{
412
413 return 0;
414}
415
416static unsigned char kbd_exists = 1;
417
418static inline void handle_keyboard_event(unsigned char scancode, int down)
419{
420 kbd_exists = 1;
421 handle_scancode(scancode, down);
422 tasklet_schedule(&keyboard_tasklet);
423}
424
425
426void kbd_leds(unsigned char leds)
427{
428}
429
430
431void kbd_init_hw(void)
432{
433}
434
435
436
437static inline void handle_mouse_event(unsigned char scancode)
438{
439 if(scancode == AUX_RECONNECT){
440 queue->head = queue->tail = 0;
441
442 return;
443 }
444
445 add_mouse_randomness(scancode);
446 if (aux_count) {
447 int head = queue->head;
448
449 queue->buf[head] = scancode;
450 head = (head + 1) & (AUX_BUF_SIZE-1);
451 if (head != queue->tail) {
452 queue->head = head;
453 kill_fasync(&queue->fasync, SIGIO, POLL_IN);
454 wake_up_interruptible(&queue->proc_list);
455 }
456 }
457}
458
459static unsigned char get_from_queue(void)
460{
461 unsigned char result;
462 unsigned long flags;
463
464 spin_lock_irqsave(&kbd_controller_lock, flags);
465 result = queue->buf[queue->tail];
466 queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
467 spin_unlock_irqrestore(&kbd_controller_lock, flags);
468 return result;
469}
470
471
472static inline int queue_empty(void)
473{
474 return queue->head == queue->tail;
475}
476
477static int fasync_aux(int fd, struct file *filp, int on)
478{
479 int retval;
480
481
482 retval = fasync_helper(fd, filp, on, &queue->fasync);
483 if (retval < 0)
484 return retval;
485 return 0;
486}
487
488
489
490
491
492#define AUX_DEV ((void *)queue)
493
494static int release_aux(struct inode * inode, struct file * file)
495{
496 lock_kernel();
497 fasync_aux(-1, file, 0);
498 aux_count--;
499 unlock_kernel();
500 return 0;
501}
502
503static int open_aux(struct inode * inode, struct file * file)
504{
505 if (aux_count++) {
506 return 0;
507 }
508 queue->head = queue->tail = 0;
509 return 0;
510}
511
512
513
514
515
516static ssize_t read_aux(struct file * file, char * buffer,
517 size_t count, loff_t *ppos)
518{
519 DECLARE_WAITQUEUE(wait, current);
520 ssize_t i = count;
521 unsigned char c;
522
523 if (queue_empty()) {
524 if (file->f_flags & O_NONBLOCK)
525 return -EAGAIN;
526 add_wait_queue(&queue->proc_list, &wait);
527repeat:
528 set_current_state(TASK_INTERRUPTIBLE);
529 if (queue_empty() && !signal_pending(current)) {
530 schedule();
531 goto repeat;
532 }
533 current->state = TASK_RUNNING;
534 remove_wait_queue(&queue->proc_list, &wait);
535 }
536 while (i > 0 && !queue_empty()) {
537 c = get_from_queue();
538 put_user(c, buffer++);
539 i--;
540 }
541 if (count-i) {
542 file->f_dentry->d_inode->i_atime = CURRENT_TIME;
543 return count-i;
544 }
545 if (signal_pending(current))
546 return -ERESTARTSYS;
547 return 0;
548}
549
550
551
552
553
554static ssize_t write_aux(struct file * file, const char * buffer,
555 size_t count, loff_t *ppos)
556{
557
558
559
560
561 return count;
562}
563
564static unsigned int aux_poll(struct file *file, poll_table * wait)
565{
566 poll_wait(file, &queue->proc_list, wait);
567 if (!queue_empty())
568 return POLLIN | POLLRDNORM;
569 return 0;
570}
571
572struct file_operations psaux_fops = {
573 read: read_aux,
574 write: write_aux,
575 poll: aux_poll,
576 open: open_aux,
577 release: release_aux,
578 fasync: fasync_aux,
579};
580
581
582
583
584static struct miscdevice psaux_mouse = {
585 PSMOUSE_MINOR, "psaux", &psaux_fops
586};
587
588static int __init psaux_init(void)
589{
590 int retval;
591
592 retval = misc_register(&psaux_mouse);
593 if(retval < 0)
594 return retval;
595
596 queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
597 memset(queue, 0, sizeof(*queue));
598 queue->head = queue->tail = 0;
599 init_waitqueue_head(&queue->proc_list);
600
601 return 0;
602}
603module_init(init_qtronix_990P_kbd);
604#endif
605