linux-old/drivers/char/hp_psaux.c
<<
>>
Prefs
   1/*
   2 *      LASI PS/2 keyboard/psaux driver for HP-PARISC workstations
   3 *      
   4 *      (c) Copyright 1999 The Puffin Group Inc.
   5 *      by Alex deVries <adevries@thepuffingroup.com>
   6 *      Copyright 1999, 2000 Philipp Rumpf <prumpf@tux.org>
   7 *
   8 *      2000/10/26      Debacker Xavier (debackex@esiee.fr)
   9 *      implemented the psaux and controlled the mouse scancode based on pc_keyb.c
  10 *                      Marteau Thomas (marteaut@esiee.fr)
  11 *      fixed leds control
  12 *
  13 *      2001/12/17      Marteau Thomas (marteaut@esiee.fr)
  14 *      get nice initialisation procedure
  15 */
  16
  17#include <linux/config.h>
  18
  19#include <linux/types.h>
  20#include <linux/ptrace.h>       /* interrupt.h wants struct pt_regs defined */
  21#include <linux/interrupt.h>
  22#include <linux/sched.h>        /* for request_irq/free_irq */
  23#include <linux/ioport.h>
  24#include <linux/kernel.h>
  25#include <linux/wait.h>
  26#include <linux/delay.h>
  27#include <linux/errno.h>
  28#include <linux/init.h>
  29#include <linux/module.h>
  30#include <linux/pc_keyb.h>
  31#include <linux/kbd_kern.h>
  32
  33/* mouse includes */
  34#include <linux/miscdevice.h>
  35#include <linux/slab.h>
  36#include <linux/random.h>
  37#include <linux/spinlock.h>
  38#include <linux/smp_lock.h>
  39#include <linux/poll.h>
  40
  41#include <asm/hardware.h>
  42#include <asm/keyboard.h>
  43#include <asm/gsc.h>
  44#include <asm/uaccess.h>
  45
  46/* HP specific LASI PS/2 keyboard and psaux constants */
  47#define AUX_REPLY_ACK   0xFA    /* Command byte ACK. */
  48#define AUX_RESEND      0xFE    /* Sent by the keyb. Asking for resending the last command. */
  49#define AUX_RECONNECT   0xAA    /* scancode when ps2 device is plugged (back) in */
  50
  51#define LASI_PSAUX_OFFSET 0x0100 /* offset from keyboard to psaux port */
  52
  53#define LASI_ID         0x00    /* ID and reset port offsets */
  54#define LASI_RESET      0x00
  55#define LASI_RCVDATA    0x04    /* receive and transmit port offsets */
  56#define LASI_XMTDATA    0x04
  57#define LASI_CONTROL    0x08    /* see: control register bits */
  58#define LASI_STATUS     0x0C    /* see: status register bits */
  59
  60/* control register bits */
  61#define LASI_CTRL_ENBL  0x01    /* enable interface */
  62#define LASI_CTRL_LPBXR 0x02    /* loopback operation */
  63#define LASI_CTRL_DIAG  0x20    /* directly control clock/data line */
  64#define LASI_CTRL_DATDIR 0x40   /* data line direct control */
  65#define LASI_CTRL_CLKDIR 0x80   /* clock line direct control */
  66
  67/* status register bits */
  68#define LASI_STAT_RBNE  0x01
  69#define LASI_STAT_TBNE  0x02
  70#define LASI_STAT_TERR  0x04
  71#define LASI_STAT_PERR  0x08
  72#define LASI_STAT_CMPINTR 0x10
  73#define LASI_STAT_DATSHD 0x40
  74#define LASI_STAT_CLKSHD 0x80
  75
  76static spinlock_t       kbd_controller_lock = SPIN_LOCK_UNLOCKED;
  77static unsigned long lasikbd_hpa;
  78
  79static volatile int cmd_status;
  80
  81static inline u8 read_input(unsigned long hpa)
  82{
  83        return gsc_readb(hpa+LASI_RCVDATA);
  84}
  85
  86static inline u8 read_control(unsigned long hpa)
  87{
  88        return gsc_readb(hpa+LASI_CONTROL);
  89}
  90
  91static inline void write_control(u8 val, unsigned long hpa)
  92{
  93        gsc_writeb(val, hpa+LASI_CONTROL);
  94}
  95
  96static inline u8 read_status(unsigned long hpa)
  97{
  98        return gsc_readb(hpa+LASI_STATUS);
  99}
 100
 101/* XXX should this grab the spinlock? */
 102
 103static int write_output(u8 val, unsigned long hpa)
 104{
 105        int wait = 250;
 106
 107        while (read_status(hpa) & LASI_STAT_TBNE) {
 108                if (!--wait) {
 109                        return 0;
 110                }
 111                mdelay(1);
 112        }
 113        gsc_writeb(val, hpa+LASI_XMTDATA);
 114
 115        return 1;
 116}
 117
 118/* XXX should this grab the spinlock? */
 119
 120static u8 wait_input(unsigned long hpa)
 121{
 122        int wait = 250;
 123
 124        while (!(read_status(hpa) & LASI_STAT_RBNE)) {
 125                if (!--wait) {
 126                        return 0;
 127                }
 128                mdelay(1);
 129        }
 130        return read_input(hpa);      
 131}
 132
 133/* This function is the PA-RISC adaptation of i386 source */
 134
 135static inline int aux_write_ack(u8 val)
 136{
 137      return write_output(val, lasikbd_hpa+LASI_PSAUX_OFFSET);
 138}
 139
 140/* This is wrong, should do something like the pc driver, which sends
 141 * the command up to 3 times at 1 second intervals, checking once
 142 * per millisecond for an acknowledge.
 143 */
 144
 145static void lasikbd_leds(unsigned char leds)
 146{
 147        int loop = 1000;
 148
 149        if (!lasikbd_hpa)
 150                return;
 151
 152        cmd_status=2;
 153        while (cmd_status!=0 && --loop > 0) {
 154                write_output(KBD_CMD_SET_LEDS, lasikbd_hpa);
 155                mdelay(5); 
 156        }
 157   
 158        cmd_status=2;
 159        while (cmd_status!=0 && --loop > 0) {
 160                write_output(leds, lasikbd_hpa);
 161                mdelay(5);
 162        }
 163
 164        cmd_status=2;
 165        while (cmd_status!=0 && --loop > 0) {
 166           write_output(KBD_CMD_ENABLE, lasikbd_hpa);   
 167           mdelay(5);
 168        }
 169        if (loop <= 0)
 170                printk("lasikbd_leds: timeout\n");
 171}
 172
 173#if 0
 174/* this might become useful again at some point.  not now  -prumpf */
 175int lasi_ps2_test(void *hpa)
 176{
 177        u8 control,c;
 178        int i, ret = 0;
 179
 180        control = read_control(hpa);
 181        write_control(control | LASI_CTRL_LPBXR | LASI_CTRL_ENBL, hpa);
 182
 183        for (i=0; i<256; i++) {
 184                write_output(i, hpa);
 185
 186                while (!(read_status(hpa) & LASI_STAT_RBNE))
 187                    /* just wait */;
 188                    
 189                c = read_input(hpa);
 190                if (c != i)
 191                        ret--;
 192        }
 193
 194        write_control(control, hpa);
 195
 196        return ret;
 197}
 198#endif 
 199
 200static int init_keyb(unsigned long hpa)
 201{
 202        int res = 0;
 203        unsigned long flags;
 204
 205        spin_lock_irqsave(&kbd_controller_lock, flags);
 206
 207        if (write_output(KBD_CMD_SET_LEDS, hpa) &&
 208                        wait_input(hpa) == AUX_REPLY_ACK &&
 209                        write_output(0, hpa) &&
 210                        wait_input(hpa) == AUX_REPLY_ACK &&
 211                        write_output(KBD_CMD_ENABLE, hpa) &&
 212                        wait_input(hpa) == AUX_REPLY_ACK)
 213                res = 1;
 214
 215        spin_unlock_irqrestore(&kbd_controller_lock, flags);
 216
 217        return res;
 218}
 219
 220
 221static void __init lasi_ps2_reset(unsigned long hpa)
 222{
 223        u8 control;
 224
 225        /* reset the interface */
 226        gsc_writeb(0xff, hpa+LASI_RESET);
 227        gsc_writeb(0x0 , hpa+LASI_RESET);               
 228
 229        /* enable it */
 230        control = read_control(hpa);
 231        write_control(control | LASI_CTRL_ENBL, hpa);
 232}
 233
 234/* Greatly inspired by pc_keyb.c */
 235
 236/*
 237 * Wait for keyboard controller input buffer to drain.
 238 *
 239 * Don't use 'jiffies' so that we don't depend on
 240 * interrupts..
 241 *
 242 * Quote from PS/2 System Reference Manual:
 243 *
 244 * "Address hex 0060 and address hex 0064 should be written only when
 245 * the input-buffer-full bit and output-buffer-full bit in the
 246 * Controller Status register are set 0."
 247 */
 248#ifdef CONFIG_PSMOUSE
 249
 250static struct aux_queue *queue;
 251static unsigned char    mouse_reply_expected;
 252static int              aux_count;
 253
 254static int fasync_aux(int fd, struct file *filp, int on)
 255{
 256        int retval;
 257        
 258        retval = fasync_helper(fd, filp, on, &queue->fasync);
 259        if (retval < 0)
 260                return retval;
 261        
 262        return 0;
 263}
 264
 265
 266
 267static inline void handle_mouse_scancode(unsigned char scancode)
 268{
 269        if (mouse_reply_expected) {
 270                if (scancode == AUX_REPLY_ACK) {
 271                        mouse_reply_expected--;
 272                        return;
 273                }
 274                mouse_reply_expected = 0;
 275        }
 276        else if (scancode == AUX_RECONNECT) {
 277                queue->head = queue->tail = 0;  /* Flush input queue */
 278                return;
 279        }
 280
 281        add_mouse_randomness(scancode);
 282        if (aux_count) {
 283                int head = queue->head;
 284                                
 285                queue->buf[head] = scancode;
 286                head = (head + 1) & (AUX_BUF_SIZE-1);
 287                
 288                if (head != queue->tail) {
 289                        queue->head = head;
 290                        kill_fasync(&queue->fasync, SIGIO, POLL_IN);
 291                        wake_up_interruptible(&queue->proc_list);
 292                }
 293        }
 294}
 295
 296static inline int queue_empty(void)
 297{
 298        return queue->head == queue->tail;
 299}
 300
 301static unsigned char get_from_queue(void)
 302{
 303        unsigned char result;
 304        unsigned long flags;
 305
 306        spin_lock_irqsave(&kbd_controller_lock, flags);
 307        result = queue->buf[queue->tail];
 308        queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
 309        spin_unlock_irqrestore(&kbd_controller_lock, flags);
 310
 311        return result;
 312}
 313
 314
 315/*
 316 * Write to the aux device.
 317 */
 318
 319static ssize_t write_aux(struct file * file, const char * buffer,
 320                         size_t count, loff_t *ppos)
 321{
 322        ssize_t retval = 0;
 323
 324        if (count) {
 325                ssize_t written = 0;
 326
 327                if (count > 32)
 328                        count = 32; /* Limit to 32 bytes. */
 329                do {
 330                        char c;
 331                        get_user(c, buffer++);
 332                        written++;
 333                } while (--count);
 334                retval = -EIO;
 335                if (written) {
 336                        retval = written;
 337                        file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
 338                }
 339        }
 340
 341        return retval;
 342}
 343
 344
 345
 346static ssize_t read_aux(struct file * file, char * buffer,
 347                        size_t count, loff_t *ppos)
 348{
 349        DECLARE_WAITQUEUE(wait, current);
 350        ssize_t i = count;
 351        unsigned char c;
 352
 353        if (queue_empty()) {
 354                if (file->f_flags & O_NONBLOCK)
 355                        return -EAGAIN;
 356                add_wait_queue(&queue->proc_list, &wait);
 357repeat:
 358                set_current_state(TASK_INTERRUPTIBLE);
 359                if (queue_empty() && !signal_pending(current)) {
 360                        schedule();
 361                        goto repeat;
 362                }
 363                current->state = TASK_RUNNING;
 364                remove_wait_queue(&queue->proc_list, &wait);
 365        }
 366        while (i > 0 && !queue_empty()) {
 367                c = get_from_queue();
 368                put_user(c, buffer++);
 369                i--;
 370        }
 371        if (count-i) {
 372                file->f_dentry->d_inode->i_atime = CURRENT_TIME;
 373                return count-i;
 374        }
 375        if (signal_pending(current))
 376                return -ERESTARTSYS;
 377        return 0;
 378}
 379
 380
 381static int open_aux(struct inode * inode, struct file * file)
 382{
 383        if (aux_count++) 
 384                return 0;
 385
 386        queue->head = queue->tail = 0;  /* Flush input queue */
 387        aux_count = 1;
 388        aux_write_ack(AUX_ENABLE_DEV);  /* Enable aux device */
 389        
 390        return 0;
 391}
 392
 393
 394/* No kernel lock held - fine */
 395static unsigned int aux_poll(struct file *file, poll_table * wait)
 396{
 397
 398        poll_wait(file, &queue->proc_list, wait);
 399        if (!queue_empty())
 400                return POLLIN | POLLRDNORM;
 401        return 0;
 402}
 403
 404
 405static int release_aux(struct inode * inode, struct file * file)
 406{
 407        lock_kernel();
 408        fasync_aux(-1, file, 0);
 409        if (--aux_count) {
 410                unlock_kernel();
 411                return 0;
 412        }
 413        unlock_kernel();
 414        return 0;
 415}
 416
 417static struct file_operations psaux_fops = {
 418        read:           read_aux,
 419        write:          write_aux,
 420        poll:           aux_poll,
 421        open:           open_aux,
 422        release:        release_aux,
 423        fasync:         fasync_aux,
 424};
 425
 426static struct miscdevice psaux_mouse = {
 427        minor:          PSMOUSE_MINOR,
 428        name:           "psaux",
 429        fops:           &psaux_fops,
 430};
 431
 432#endif /* CONFIG_PSMOUSE */
 433
 434
 435/* This function is looking at the PS2 controller and empty the two buffers */
 436
 437static u8 handle_lasikbd_event(unsigned long hpa)
 438{
 439        u8 status_keyb,status_mouse,scancode,id;
 440        extern void handle_at_scancode(int); /* in drivers/char/keyb_at.c */
 441        
 442        /* Mask to get the base address of the PS/2 controller */
 443        id = gsc_readb(hpa+LASI_ID) & 0x0f;
 444        
 445        if (id==1) 
 446                hpa -= LASI_PSAUX_OFFSET; 
 447        
 448        status_keyb = read_status(hpa);
 449        status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
 450
 451        while ((status_keyb|status_mouse) & LASI_STAT_RBNE){
 452           
 453                while (status_keyb & LASI_STAT_RBNE) {
 454              
 455                scancode = read_input(hpa);
 456
 457                /* XXX don't know if this is a valid fix, but filtering
 458                 * 0xfa avoids 'unknown scancode' errors on, eg, capslock
 459                 * on some keyboards.
 460                 */
 461                      
 462                if (scancode == AUX_REPLY_ACK) 
 463                        cmd_status=0;
 464                        
 465                else if (scancode == AUX_RESEND)
 466                        cmd_status=1;
 467                else 
 468                        handle_at_scancode(scancode); 
 469              
 470                status_keyb =read_status(hpa);
 471                }
 472           
 473#ifdef CONFIG_PSMOUSE
 474                while (status_mouse & LASI_STAT_RBNE) {
 475                        scancode = read_input(hpa+LASI_PSAUX_OFFSET);
 476                        handle_mouse_scancode(scancode);
 477                        status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
 478                }
 479                status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
 480#endif /* CONFIG_PSMOUSE */
 481                status_keyb = read_status(hpa);
 482        }
 483
 484        tasklet_schedule(&keyboard_tasklet);
 485        return (status_keyb|status_mouse);
 486}
 487        
 488extern struct pt_regs *kbd_pt_regs;
 489
 490static void lasikbd_interrupt(int irq, void *dev, struct pt_regs *regs)
 491{
 492        kbd_pt_regs = regs;
 493        handle_lasikbd_event((unsigned long) dev);
 494}
 495
 496extern int pckbd_translate(unsigned char, unsigned char *, char);
 497extern int pckbd_setkeycode(unsigned int, unsigned int);
 498extern int pckbd_getkeycode(unsigned int);
 499
 500static struct kbd_ops gsc_ps2_kbd_ops = {
 501        setkeycode:     pckbd_setkeycode,
 502        getkeycode:     pckbd_getkeycode,
 503        translate:      pckbd_translate,
 504        leds:           lasikbd_leds,
 505#ifdef CONFIG_MAGIC_SYSRQ
 506        sysrq_key:      0x54,
 507        sysrq_xlate:    hp_ps2kbd_sysrq_xlate,
 508#endif
 509};
 510
 511
 512
 513#if 1
 514/* XXX: HACK !!!
 515 * remove this function and the call in hil_kbd.c 
 516 * if hp_psaux.c/hp_keyb.c is converted to the input layer... */
 517int register_ps2_keybfuncs(void)
 518{
 519        gsc_ps2_kbd_ops.leds = NULL;
 520        register_kbd_ops(&gsc_ps2_kbd_ops);
 521}
 522EXPORT_SYMBOL(register_ps2_keybfuncs);
 523#endif
 524
 525
 526static int __init
 527lasi_ps2_register(struct parisc_device *dev)
 528{
 529        unsigned long hpa = dev->hpa;
 530        char *name;
 531        int device_found = 0;
 532        u8 id;
 533
 534        id = gsc_readb(hpa+LASI_ID) & 0x0f;
 535
 536        switch (id) {
 537        case 0:
 538                name = "keyboard";
 539                lasikbd_hpa = hpa;      /* save "hpa" for lasikbd_leds() */
 540                break;
 541        case 1:
 542                name = "psaux";
 543                break;
 544        default:
 545                printk(KERN_WARNING "%s: Unknown PS/2 port (id=%d) - ignored.\n",
 546                        __FUNCTION__, id );
 547                return 0;
 548        }
 549        
 550        /* reset the PS/2 port */
 551        lasi_ps2_reset(hpa);
 552
 553        switch (id) {
 554        case 0: 
 555                device_found = init_keyb(hpa);
 556                if (device_found) register_kbd_ops(&gsc_ps2_kbd_ops);
 557                break;
 558        case 1:
 559#ifdef CONFIG_PSMOUSE
 560                queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
 561                if (!queue)
 562                        return -ENOMEM;
 563
 564                memset(queue, 0, sizeof(*queue));
 565                queue->head = queue->tail = 0;
 566                init_waitqueue_head(&queue->proc_list);
 567                
 568                misc_register(&psaux_mouse);
 569
 570                aux_write_ack(AUX_ENABLE_DEV);
 571                /* try it a second time, this will give status if the device is
 572                 * available */
 573                device_found = aux_write_ack(AUX_ENABLE_DEV);
 574                break;
 575#else
 576                /* return without printing any unnecessary and misleading info */
 577                return 0;       
 578#endif
 579        } /* of case */
 580        
 581        if (device_found) {
 582        /* Here we claim only if we have a device attached */   
 583                /* allocate the irq and memory region for that device */
 584                if (!dev->irq)
 585                return -ENODEV;
 586           
 587                if (request_irq(dev->irq, lasikbd_interrupt, 0, name, (void *)hpa))
 588                return -ENODEV;
 589           
 590                if (!request_mem_region(hpa, LASI_STATUS + 4, name))
 591                return -ENODEV;
 592        }
 593        
 594        printk(KERN_INFO "PS/2 %s port at 0x%08lx (irq %d) found, "
 595                         "%sdevice attached.\n",
 596                        name, hpa, dev->irq, device_found ? "":"no ");
 597
 598        return 0;
 599}
 600
 601static struct parisc_device_id lasi_psaux_tbl[] = {
 602        { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 },
 603        { 0, } /* 0 terminated list */
 604};
 605
 606MODULE_DEVICE_TABLE(parisc, lasi_psaux_tbl);
 607
 608static struct parisc_driver lasi_psaux_driver = {
 609        name:           "Lasi psaux",
 610        id_table:       lasi_psaux_tbl,
 611        probe:          lasi_ps2_register,
 612};
 613
 614static int __init gsc_ps2_init(void) 
 615{
 616        return register_parisc_driver(&lasi_psaux_driver);
 617}
 618
 619module_init(gsc_ps2_init);
 620
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.