OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [qtronix.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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/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 /* scancode when ps2 device is plugged (back) in */
92
 
93
static int data_index;
94
struct cir_port *cir;
95
static unsigned char kbdbytes[5];
96
static unsigned char cir_data[32]; /* we only need 16 chars */
97
 
98
static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs);
99
static int handle_data(unsigned char *p_data);
100
static inline void handle_mouse_event(unsigned char scancode);
101
static inline void handle_keyboard_event(unsigned char scancode, int down);
102
static int __init psaux_init(void);
103
 
104
static struct aux_queue *queue; /* Mouse data buffer. */
105
static int aux_count = 0;
106
 
107
/*
108
 * Keys accessed through the 'Fn' key
109
 * The Fn key does not produce a key-up sequence. So, the first
110
 * time the user presses it, it will be key-down event. The key
111
 * stays down until the user presses it again.
112
 */
113
#define NUM_FN_KEYS 56
114
static unsigned char fn_keys[NUM_FN_KEYS] = {
115
        0,0,0,0,0,0,0,0,        /* 0 7   */
116
        8,9,10,93,0,0,0,0,      /* 8 15  */
117
        0,0,0,0,0,0,0,5,        /* 16 23 */
118
        6,7,91,0,0,0,0,0,       /* 24 31 */
119
        0,0,0,0,0,2,3,4,        /* 32 39 */
120
        92,0,0,0,0,0,0,0,       /* 40 47 */
121
        0,0,0,0,11,0,94,95        /* 48 55 */
122
 
123
};
124
 
125
void __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
         * revisit
137
         * this should be programmable, somehow by the, by the user.
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
 
161
static 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
 
177
static inline u_int8_t UpperByte(u_int8_t data)
178
{
179
        return (data >> 4);
180
}
181
 
182
 
183
static inline u_int8_t LowerByte(u_int8_t data)
184
{
185
        return (data & 0xF);
186
}
187
 
188
 
189
int 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
 
202
static 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) {/* expecting first byte */
220
                        if (cir_data[data_index] != leading1) {
221
                                //printk("!leading byte %x\n", cir_data[data_index]);
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; /* start over */
231
                                clear_fifo(cir);
232
                                continue;
233
                        }
234
                }
235
 
236
                if ( (cir_data[data_index] == 0xff)) { /* last byte */
237
                        //printk("data_index %d\n", data_index);
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
266
static 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
        /* Reorganize the bit stream */
274
        for (i=0; i<16; i++)
275
                p_data[i] = BitReverse(~p_data[i]);
276
 
277
        /*
278
         * We've already previously checked that p_data[0]
279
         * is equal to leading1 and that (p_data[1] & 0xf)
280
         * is equal to leading2. These twelve bits are the
281
         * leader code.  We can now throw them away (the 12
282
         * bits) and continue parsing the stream.
283
         */
284
        bit_bucket = p_data[1] << 12;
285
        got_bits = 4;
286
        next_byte = 2;
287
 
288
        /*
289
         * Process four bits at a time
290
         */
291
        for (i=0; i<NUM_KBD_BYTES; i++) {
292
 
293
                kbdbytes[i]=0;
294
 
295
                for (j=0; j<8; j++) /* 8 bits per byte */
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
                                /* Convert 1000b to 1 */
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
                                /* Convert 10b to 0 */
310
                                kbdbytes[i] =  kbdbytes[i] >> 1;
311
                                got_bits -= 2;
312
                                bit_bucket = bit_bucket << 2;
313
                        }
314
                        else {
315
                                /* bad serial stream */
316
                                return 1;
317
                        }
318
 
319
                        if (next_byte > 16) {
320
                                //printk("error: too many bytes\n");
321
                                return 1;
322
                        }
323
                }
324
        }
325
 
326
 
327
        if (!CheckSumOk(kbdbytes[0], kbdbytes[1],
328
                                kbdbytes[2], kbdbytes[3], kbdbytes[4])) {
329
                //printk("checksum failed\n");
330
                return 1;
331
        }
332
 
333
        if (kbdbytes[1] & 0x08) {
334
                //printk("m: %x %x %x\n", kbdbytes[1], kbdbytes[2], kbdbytes[3]);
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
 
353
spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
354
static unsigned char handle_kbd_event(void);
355
 
356
 
357
int 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
 
363
int kbd_getkeycode(unsigned int scancode)
364
{
365
        return scancode;
366
}
367
 
368
 
369
int 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
        /* todo */
380
        if (!prev_scancode && scancode == 160) { /* Fn key down */
381
                //printk("Fn key down\n");
382
                prev_scancode = 160;
383
                return 0;
384
        }
385
        else if (prev_scancode && scancode == 160) { /* Fn key up */
386
                //printk("Fn key up\n");
387
                prev_scancode = 0;
388
                return 0;
389
        }
390
 
391
        /* todo */
392
        if (prev_scancode == 160) {
393
                if (scancode <= NUM_FN_KEYS) {
394
                        *keycode = fn_keys[scancode];
395
                        //printk("fn keycode %d\n", *keycode);
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
 
410
char kbd_unexpected_up(unsigned char keycode)
411
{
412
        //printk("kbd_unexpected_up\n");
413
        return 0;
414
}
415
 
416
static unsigned char kbd_exists = 1;
417
 
418
static 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
 
426
void kbd_leds(unsigned char leds)
427
{
428
}
429
 
430
/* dummy */
431
void kbd_init_hw(void)
432
{
433
}
434
 
435
 
436
 
437
static inline void handle_mouse_event(unsigned char scancode)
438
{
439
        if(scancode == AUX_RECONNECT){
440
                queue->head = queue->tail = 0;  /* Flush input queue */
441
        //      __aux_write_ack(AUX_ENABLE_DEV);  /* ping the mouse :) */
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
 
459
static 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
 
472
static inline int queue_empty(void)
473
{
474
        return queue->head == queue->tail;
475
}
476
 
477
static int fasync_aux(int fd, struct file *filp, int on)
478
{
479
        int retval;
480
 
481
        //printk("fasync_aux\n");
482
        retval = fasync_helper(fd, filp, on, &queue->fasync);
483
        if (retval < 0)
484
                return retval;
485
        return 0;
486
}
487
 
488
 
489
/*
490
 * Random magic cookie for the aux device
491
 */
492
#define AUX_DEV ((void *)queue)
493
 
494
static 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
 
503
static int open_aux(struct inode * inode, struct file * file)
504
{
505
        if (aux_count++) {
506
                return 0;
507
        }
508
        queue->head = queue->tail = 0;           /* Flush input queue */
509
        return 0;
510
}
511
 
512
/*
513
 * Put bytes from input queue to buffer.
514
 */
515
 
516
static 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);
527
repeat:
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
 * Write to the aux device.
552
 */
553
 
554
static ssize_t write_aux(struct file * file, const char * buffer,
555
                         size_t count, loff_t *ppos)
556
{
557
        /*
558
         * The ITE boards this was tested on did not have the
559
         * transmit wires connected.
560
         */
561
        return count;
562
}
563
 
564
static 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
 
572
struct 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
 * Initialize driver.
583
 */
584
static struct miscdevice psaux_mouse = {
585
        PSMOUSE_MINOR, "psaux", &psaux_fops
586
};
587
 
588
static 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
}
603
module_init(init_qtronix_990P_kbd);
604
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.