aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/qtronix.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/char/qtronix.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/char/qtronix.c')
-rw-r--r--drivers/char/qtronix.c601
1 files changed, 601 insertions, 0 deletions
diff --git a/drivers/char/qtronix.c b/drivers/char/qtronix.c
new file mode 100644
index 000000000000..40a3cf62e1a8
--- /dev/null
+++ b/drivers/char/qtronix.c
@@ -0,0 +1,601 @@
1/*
2 *
3 * BRIEF MODULE DESCRIPTION
4 * Qtronix 990P infrared keyboard driver.
5 *
6 *
7 * Copyright 2001 MontaVista Software Inc.
8 * Author: MontaVista Software, Inc.
9 * ppopov@mvista.com or source@mvista.com
10 *
11 *
12 * The bottom portion of this driver was take from
13 * pc_keyb.c Please see that file for copyrights.
14 *
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the
17 * Free Software Foundation; either version 2 of the License, or (at your
18 * option) any later version.
19 *
20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
21 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
23 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * You should have received a copy of the GNU General Public License along
32 * with this program; if not, write to the Free Software Foundation, Inc.,
33 * 675 Mass Ave, Cambridge, MA 02139, USA.
34 */
35
36#include <linux/config.h>
37
38/*
39 * NOTE:
40 *
41 * This driver has only been tested with the Consumer IR
42 * port of the ITE 8172 system controller.
43 *
44 * You do not need this driver if you are using the ps/2 or
45 * USB adapter that the keyboard ships with. You only need
46 * this driver if your board has a IR port and the keyboard
47 * data is being sent directly to the IR. In that case,
48 * you also need some low-level IR support. See it8172_cir.c.
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/poll.h>
73#include <linux/miscdevice.h>
74#include <linux/slab.h>
75#include <linux/kbd_kern.h>
76#include <linux/smp_lock.h>
77#include <asm/io.h>
78#include <linux/pc_keyb.h>
79
80#include <asm/keyboard.h>
81#include <linux/bitops.h>
82#include <asm/uaccess.h>
83#include <asm/irq.h>
84#include <asm/system.h>
85
86#define leading1 0
87#define leading2 0xF
88
89#define KBD_CIR_PORT 0
90#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */
91
92static int data_index;
93struct cir_port *cir;
94static unsigned char kbdbytes[5];
95static unsigned char cir_data[32]; /* we only need 16 chars */
96
97static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs);
98static int handle_data(unsigned char *p_data);
99static inline void handle_mouse_event(unsigned char scancode);
100static inline void handle_keyboard_event(unsigned char scancode, int down);
101static int __init psaux_init(void);
102
103static struct aux_queue *queue; /* Mouse data buffer. */
104static int aux_count = 0;
105
106/*
107 * Keys accessed through the 'Fn' key
108 * The Fn key does not produce a key-up sequence. So, the first
109 * time the user presses it, it will be key-down event. The key
110 * stays down until the user presses it again.
111 */
112#define NUM_FN_KEYS 56
113static unsigned char fn_keys[NUM_FN_KEYS] = {
114 0,0,0,0,0,0,0,0, /* 0 7 */
115 8,9,10,93,0,0,0,0, /* 8 15 */
116 0,0,0,0,0,0,0,5, /* 16 23 */
117 6,7,91,0,0,0,0,0, /* 24 31 */
118 0,0,0,0,0,2,3,4, /* 32 39 */
119 92,0,0,0,0,0,0,0, /* 40 47 */
120 0,0,0,0,11,0,94,95 /* 48 55 */
121
122};
123
124void __init init_qtronix_990P_kbd(void)
125{
126 int retval;
127
128 cir = (struct cir_port *)kmalloc(sizeof(struct cir_port), GFP_KERNEL);
129 if (!cir) {
130 printk("Unable to initialize Qtronix keyboard\n");
131 return;
132 }
133
134 /*
135 * revisit
136 * this should be programmable, somehow by the, by the user.
137 */
138 cir->port = KBD_CIR_PORT;
139 cir->baud_rate = 0x1d;
140 cir->rdwos = 0;
141 cir->rxdcr = 0x3;
142 cir->hcfs = 0;
143 cir->fifo_tl = 0;
144 cir->cfq = 0x1d;
145 cir_port_init(cir);
146
147 retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler,
148 (unsigned long )(SA_INTERRUPT|SA_SHIRQ),
149 (const char *)"Qtronix IR Keyboard", (void *)cir);
150
151 if (retval) {
152 printk("unable to allocate cir %d irq %d\n",
153 cir->port, IT8172_CIR0_IRQ);
154 }
155#ifdef CONFIG_PSMOUSE
156 psaux_init();
157#endif
158}
159
160static inline unsigned char BitReverse(unsigned short key)
161{
162 unsigned char rkey = 0;
163 rkey |= (key & 0x1) << 7;
164 rkey |= (key & 0x2) << 5;
165 rkey |= (key & 0x4) << 3;
166 rkey |= (key & 0x8) << 1;
167 rkey |= (key & 0x10) >> 1;
168 rkey |= (key & 0x20) >> 3;
169 rkey |= (key & 0x40) >> 5;
170 rkey |= (key & 0x80) >> 7;
171 return rkey;
172
173}
174
175
176static inline u_int8_t UpperByte(u_int8_t data)
177{
178 return (data >> 4);
179}
180
181
182static inline u_int8_t LowerByte(u_int8_t data)
183{
184 return (data & 0xF);
185}
186
187
188int CheckSumOk(u_int8_t byte1, u_int8_t byte2,
189 u_int8_t byte3, u_int8_t byte4, u_int8_t byte5)
190{
191 u_int8_t CheckSum;
192
193 CheckSum = (byte1 & 0x0F) + byte2 + byte3 + byte4 + byte5;
194 if ( LowerByte(UpperByte(CheckSum) + LowerByte(CheckSum)) != UpperByte(byte1) )
195 return 0;
196 else
197 return 1;
198}
199
200
201static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs)
202{
203 struct cir_port *cir;
204 int j;
205 unsigned char int_status;
206
207 cir = (struct cir_port *)dev_id;
208 int_status = get_int_status(cir);
209 if (int_status & 0x4) {
210 clear_fifo(cir);
211 return;
212 }
213
214 while (cir_get_rx_count(cir)) {
215
216 cir_data[data_index] = cir_read_data(cir);
217
218 if (data_index == 0) {/* expecting first byte */
219 if (cir_data[data_index] != leading1) {
220 //printk("!leading byte %x\n", cir_data[data_index]);
221 set_rx_active(cir);
222 clear_fifo(cir);
223 continue;
224 }
225 }
226 if (data_index == 1) {
227 if ((cir_data[data_index] & 0xf) != leading2) {
228 set_rx_active(cir);
229 data_index = 0; /* start over */
230 clear_fifo(cir);
231 continue;
232 }
233 }
234
235 if ( (cir_data[data_index] == 0xff)) { /* last byte */
236 //printk("data_index %d\n", data_index);
237 set_rx_active(cir);
238#if 0
239 for (j=0; j<=data_index; j++) {
240 printk("rx_data %d: %x\n", j, cir_data[j]);
241 }
242#endif
243 data_index = 0;
244 handle_data(cir_data);
245 return;
246 }
247 else if (data_index>16) {
248 set_rx_active(cir);
249#if 0
250 printk("warning: data_index %d\n", data_index);
251 for (j=0; j<=data_index; j++) {
252 printk("rx_data %d: %x\n", j, cir_data[j]);
253 }
254#endif
255 data_index = 0;
256 clear_fifo(cir);
257 return;
258 }
259 data_index++;
260 }
261}
262
263
264#define NUM_KBD_BYTES 5
265static int handle_data(unsigned char *p_data)
266{
267 u_int32_t bit_bucket;
268 u_int32_t i, j;
269 u_int32_t got_bits, next_byte;
270 int down = 0;
271
272 /* Reorganize the bit stream */
273 for (i=0; i<16; i++)
274 p_data[i] = BitReverse(~p_data[i]);
275
276 /*
277 * We've already previously checked that p_data[0]
278 * is equal to leading1 and that (p_data[1] & 0xf)
279 * is equal to leading2. These twelve bits are the
280 * leader code. We can now throw them away (the 12
281 * bits) and continue parsing the stream.
282 */
283 bit_bucket = p_data[1] << 12;
284 got_bits = 4;
285 next_byte = 2;
286
287 /*
288 * Process four bits at a time
289 */
290 for (i=0; i<NUM_KBD_BYTES; i++) {
291
292 kbdbytes[i]=0;
293
294 for (j=0; j<8; j++) /* 8 bits per byte */
295 {
296 if (got_bits < 4) {
297 bit_bucket |= (p_data[next_byte++] << (8 - got_bits));
298 got_bits += 8;
299 }
300
301 if ((bit_bucket & 0xF000) == 0x8000) {
302 /* Convert 1000b to 1 */
303 kbdbytes[i] = 0x80 | (kbdbytes[i] >> 1);
304 got_bits -= 4;
305 bit_bucket = bit_bucket << 4;
306 }
307 else if ((bit_bucket & 0xC000) == 0x8000) {
308 /* Convert 10b to 0 */
309 kbdbytes[i] = kbdbytes[i] >> 1;
310 got_bits -= 2;
311 bit_bucket = bit_bucket << 2;
312 }
313 else {
314 /* bad serial stream */
315 return 1;
316 }
317
318 if (next_byte > 16) {
319 //printk("error: too many bytes\n");
320 return 1;
321 }
322 }
323 }
324
325
326 if (!CheckSumOk(kbdbytes[0], kbdbytes[1],
327 kbdbytes[2], kbdbytes[3], kbdbytes[4])) {
328 //printk("checksum failed\n");
329 return 1;
330 }
331
332 if (kbdbytes[1] & 0x08) {
333 //printk("m: %x %x %x\n", kbdbytes[1], kbdbytes[2], kbdbytes[3]);
334 handle_mouse_event(kbdbytes[1]);
335 handle_mouse_event(kbdbytes[2]);
336 handle_mouse_event(kbdbytes[3]);
337 }
338 else {
339 if (kbdbytes[2] == 0) down = 1;
340#if 0
341 if (down)
342 printk("down %d\n", kbdbytes[3]);
343 else
344 printk("up %d\n", kbdbytes[3]);
345#endif
346 handle_keyboard_event(kbdbytes[3], down);
347 }
348 return 0;
349}
350
351
352DEFINE_SPINLOCK(kbd_controller_lock);
353static unsigned char handle_kbd_event(void);
354
355
356int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
357{
358 printk("kbd_setkeycode scancode %x keycode %x\n", scancode, keycode);
359 return 0;
360}
361
362int kbd_getkeycode(unsigned int scancode)
363{
364 return scancode;
365}
366
367
368int kbd_translate(unsigned char scancode, unsigned char *keycode,
369 char raw_mode)
370{
371 static int prev_scancode = 0;
372
373 if (scancode == 0x00 || scancode == 0xff) {
374 prev_scancode = 0;
375 return 0;
376 }
377
378 /* todo */
379 if (!prev_scancode && scancode == 160) { /* Fn key down */
380 //printk("Fn key down\n");
381 prev_scancode = 160;
382 return 0;
383 }
384 else if (prev_scancode && scancode == 160) { /* Fn key up */
385 //printk("Fn key up\n");
386 prev_scancode = 0;
387 return 0;
388 }
389
390 /* todo */
391 if (prev_scancode == 160) {
392 if (scancode <= NUM_FN_KEYS) {
393 *keycode = fn_keys[scancode];
394 //printk("fn keycode %d\n", *keycode);
395 }
396 else
397 return 0;
398 }
399 else if (scancode <= 127) {
400 *keycode = scancode;
401 }
402 else
403 return 0;
404
405
406 return 1;
407}
408
409char kbd_unexpected_up(unsigned char keycode)
410{
411 //printk("kbd_unexpected_up\n");
412 return 0;
413}
414
415static unsigned char kbd_exists = 1;
416
417static inline void handle_keyboard_event(unsigned char scancode, int down)
418{
419 kbd_exists = 1;
420 handle_scancode(scancode, down);
421 tasklet_schedule(&keyboard_tasklet);
422}
423
424
425void kbd_leds(unsigned char leds)
426{
427}
428
429/* dummy */
430void kbd_init_hw(void)
431{
432}
433
434
435
436static inline void handle_mouse_event(unsigned char scancode)
437{
438 if(scancode == AUX_RECONNECT){
439 queue->head = queue->tail = 0; /* Flush input queue */
440 // __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */
441 return;
442 }
443
444 if (aux_count) {
445 int head = queue->head;
446
447 queue->buf[head] = scancode;
448 head = (head + 1) & (AUX_BUF_SIZE-1);
449 if (head != queue->tail) {
450 queue->head = head;
451 kill_fasync(&queue->fasync, SIGIO, POLL_IN);
452 wake_up_interruptible(&queue->proc_list);
453 }
454 }
455}
456
457static unsigned char get_from_queue(void)
458{
459 unsigned char result;
460 unsigned long flags;
461
462 spin_lock_irqsave(&kbd_controller_lock, flags);
463 result = queue->buf[queue->tail];
464 queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
465 spin_unlock_irqrestore(&kbd_controller_lock, flags);
466 return result;
467}
468
469
470static inline int queue_empty(void)
471{
472 return queue->head == queue->tail;
473}
474
475static int fasync_aux(int fd, struct file *filp, int on)
476{
477 int retval;
478
479 //printk("fasync_aux\n");
480 retval = fasync_helper(fd, filp, on, &queue->fasync);
481 if (retval < 0)
482 return retval;
483 return 0;
484}
485
486
487/*
488 * Random magic cookie for the aux device
489 */
490#define AUX_DEV ((void *)queue)
491
492static int release_aux(struct inode * inode, struct file * file)
493{
494 fasync_aux(-1, file, 0);
495 aux_count--;
496 return 0;
497}
498
499static int open_aux(struct inode * inode, struct file * file)
500{
501 if (aux_count++) {
502 return 0;
503 }
504 queue->head = queue->tail = 0; /* Flush input queue */
505 return 0;
506}
507
508/*
509 * Put bytes from input queue to buffer.
510 */
511
512static ssize_t read_aux(struct file * file, char * buffer,
513 size_t count, loff_t *ppos)
514{
515 DECLARE_WAITQUEUE(wait, current);
516 ssize_t i = count;
517 unsigned char c;
518
519 if (queue_empty()) {
520 if (file->f_flags & O_NONBLOCK)
521 return -EAGAIN;
522 add_wait_queue(&queue->proc_list, &wait);
523repeat:
524 set_current_state(TASK_INTERRUPTIBLE);
525 if (queue_empty() && !signal_pending(current)) {
526 schedule();
527 goto repeat;
528 }
529 current->state = TASK_RUNNING;
530 remove_wait_queue(&queue->proc_list, &wait);
531 }
532 while (i > 0 && !queue_empty()) {
533 c = get_from_queue();
534 put_user(c, buffer++);
535 i--;
536 }
537 if (count-i) {
538 struct inode *inode = file->f_dentry->d_inode;
539 inode->i_atime = current_fs_time(inode->i_sb);
540 return count-i;
541 }
542 if (signal_pending(current))
543 return -ERESTARTSYS;
544 return 0;
545}
546
547/*
548 * Write to the aux device.
549 */
550
551static ssize_t write_aux(struct file * file, const char * buffer,
552 size_t count, loff_t *ppos)
553{
554 /*
555 * The ITE boards this was tested on did not have the
556 * transmit wires connected.
557 */
558 return count;
559}
560
561static unsigned int aux_poll(struct file *file, poll_table * wait)
562{
563 poll_wait(file, &queue->proc_list, wait);
564 if (!queue_empty())
565 return POLLIN | POLLRDNORM;
566 return 0;
567}
568
569struct file_operations psaux_fops = {
570 .read = read_aux,
571 .write = write_aux,
572 .poll = aux_poll,
573 .open = open_aux,
574 .release = release_aux,
575 .fasync = fasync_aux,
576};
577
578/*
579 * Initialize driver.
580 */
581static struct miscdevice psaux_mouse = {
582 PSMOUSE_MINOR, "psaux", &psaux_fops
583};
584
585static int __init psaux_init(void)
586{
587 int retval;
588
589 retval = misc_register(&psaux_mouse);
590 if(retval < 0)
591 return retval;
592
593 queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
594 memset(queue, 0, sizeof(*queue));
595 queue->head = queue->tail = 0;
596 init_waitqueue_head(&queue->proc_list);
597
598 return 0;
599}
600module_init(init_qtronix_990P_kbd);
601#endif