linux-old/drivers/char/qtronix.c
<<
>>
Prefs
   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/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
  93static int data_index;
  94struct cir_port *cir;
  95static unsigned char kbdbytes[5];
  96static unsigned char cir_data[32]; /* we only need 16 chars */
  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; /* Mouse data buffer. */
 105static 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
 114static 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
 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         * 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
 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) {/* 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
 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        /* 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
 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        /* 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
 410char kbd_unexpected_up(unsigned char keycode)
 411{
 412        //printk("kbd_unexpected_up\n");
 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/* dummy */
 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;  /* 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
 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        //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
 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;          /* Flush input queue */
 509        return 0;
 510}
 511
 512/*
 513 * Put bytes from input queue to buffer.
 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 * Write to the aux device.
 552 */
 553
 554static 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
 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 * Initialize driver.
 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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.