linux-old/drivers/hil/hilkbd.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/hil/hilkbd.c
   3 *
   4 *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
   5 *  Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
   6 *  Copyright (C) 1999-2002 Helge Deller <deller@gmx.de>
   7 *
   8 *  Very basic HP Human Interface Loop (HIL) driver.
   9 *  This driver handles the keyboard on HP300 (m68k) and on some 
  10 *  HP700 (parisc) series machines.
  11 *
  12 * 
  13 * This file is subject to the terms and conditions of the GNU General Public
  14 * License version 2.  See the file COPYING in the main directory of this
  15 * archive for more details.
  16 */
  17
  18#include <linux/pci_ids.h>
  19#include <linux/ioport.h>
  20#include <linux/module.h>
  21#include <linux/config.h>
  22#include <linux/errno.h>
  23#include <linux/input.h>
  24#include <linux/init.h>
  25#include <linux/irq.h>
  26#include <linux/hil.h>
  27
  28
  29MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller");
  30MODULE_DESCRIPTION("HIL driver (basic functionality)");
  31MODULE_LICENSE("GPL");
  32EXPORT_NO_SYMBOLS;
  33
  34
  35#if defined(CONFIG_PARISC)
  36
  37 #include <asm/gsc.h>
  38 #include <asm/hardware.h>
  39 static unsigned long hil_base; /* HPA for the HIL device */
  40 static unsigned int hil_irq;
  41 #define HILBASE                hil_base /* HPPA (parisc) port address */
  42 #define HIL_DATA               0x800
  43 #define HIL_CMD                0x801
  44 #define HIL_IRQ                hil_irq
  45 #define hil_readb(p)           gsc_readb(p)
  46 #define hil_writeb(v,p)        gsc_writeb((v),(p))
  47
  48#elif defined(CONFIG_HP300)
  49
  50 #define HILBASE                0xf0428000 /* HP300 (m86k) port address */
  51 #define HIL_DATA               0x1
  52 #define HIL_CMD                0x3
  53 #define HIL_IRQ                2
  54 #define hil_readb(p)           readb(p)
  55 #define hil_writeb(v,p)        writeb((v),(p))
  56
  57#else
  58#error "HIL is not supported on this platform"
  59#endif
  60
  61
  62 
  63/* HIL helper functions */
  64 
  65#define hil_busy()              (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY)
  66#define hil_data_available()    (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
  67#define hil_status()            (hil_readb(HILBASE + HIL_CMD))
  68#define hil_command(x)          do { hil_writeb((x), HILBASE + HIL_CMD); } while (0)
  69#define hil_read_data()         (hil_readb(HILBASE + HIL_DATA))
  70#define hil_write_data(x)       do { hil_writeb((x), HILBASE + HIL_DATA); } while (0)
  71
  72/* HIL constants */
  73 
  74#define HIL_BUSY                0x02
  75#define HIL_DATA_RDY            0x01
  76
  77#define HIL_SETARD              0xA0            /* set auto-repeat delay */
  78#define HIL_SETARR              0xA2            /* set auto-repeat rate */
  79#define HIL_SETTONE             0xA3            /* set tone generator */
  80#define HIL_CNMT                0xB2            /* clear nmi */
  81#define HIL_INTON               0x5C            /* Turn on interrupts. */
  82#define HIL_INTOFF              0x5D            /* Turn off interrupts. */
  83#define HIL_TRIGGER             0xC5            /* trigger command */
  84#define HIL_STARTCMD            0xE0            /* start loop command */
  85#define HIL_TIMEOUT             0xFE            /* timeout */
  86#define HIL_READTIME            0x13            /* Read real time register */
  87
  88#define HIL_READBUSY            0x02            /* internal "busy" register */
  89#define HIL_READKBDLANG         0x12            /* read keyboard language code */
  90#define HIL_READKBDSADR         0xF9
  91#define HIL_WRITEKBDSADR        0xE9
  92#define HIL_READLPSTAT          0xFA
  93#define HIL_WRITELPSTAT         0xEA
  94#define HIL_READLPCTRL          0xFB
  95#define HIL_WRITELPCTRL         0xEB
  96
  97
  98static unsigned char hil_kbd_set1[128] = {
  99   KEY_5,               KEY_RESERVED,   KEY_RIGHTALT,   KEY_LEFTALT, 
 100   KEY_RIGHTSHIFT,      KEY_LEFTSHIFT,  KEY_LEFTCTRL,   KEY_SYSRQ,
 101   KEY_KP4,             KEY_KP8,        KEY_KP5,        KEY_KP9,
 102   KEY_KP6,             KEY_KP7,        KEY_KPCOMMA,    KEY_KPENTER,
 103   KEY_KP1,             KEY_KPSLASH,    KEY_KP2,        KEY_KPPLUS,
 104   KEY_KP3,             KEY_KPASTERISK, KEY_KP0,        KEY_KPMINUS,
 105   KEY_B,               KEY_V,          KEY_C,          KEY_X,
 106   KEY_Z,               KEY_UNKNOWN,    KEY_RESERVED,   KEY_ESC,
 107   KEY_6,               KEY_F10,        KEY_3,          KEY_F11,
 108   KEY_KPDOT,           KEY_F9,         KEY_TAB /*KP*/, KEY_F12,
 109   KEY_H,               KEY_G,          KEY_F,          KEY_D,
 110   KEY_S,               KEY_A,          KEY_RESERVED,   KEY_CAPSLOCK,
 111   KEY_U,               KEY_Y,          KEY_T,          KEY_R,
 112   KEY_E,               KEY_W,          KEY_Q,          KEY_TAB,
 113   KEY_7,               KEY_6,          KEY_5,          KEY_4,
 114   KEY_3,               KEY_2,          KEY_1,          KEY_GRAVE,
 115   KEY_INTL1,           KEY_INTL2,      KEY_INTL3,      KEY_INTL4, /*Buttons*/
 116   KEY_INTL5,           KEY_INTL6,      KEY_INTL7,      KEY_INTL8,
 117   KEY_MENU,            KEY_F4,         KEY_F3,         KEY_F2,
 118   KEY_F1,              KEY_VOLUMEUP,   KEY_STOP,       KEY_SENDFILE/*Enter/Print*/, 
 119   KEY_SYSRQ,           KEY_F5,         KEY_F6,         KEY_F7,
 120   KEY_F8,              KEY_VOLUMEDOWN, KEY_CUT /*CLEAR_LINE*/, KEY_REFRESH /*CLEAR_DISPLAY*/,
 121   KEY_8,               KEY_9,          KEY_0,          KEY_MINUS,
 122   KEY_EQUAL,           KEY_BACKSPACE,  KEY_INSERT/*KPINSERT_LINE*/, KEY_DELETE /*KPDELETE_LINE*/,
 123   KEY_I,               KEY_O,          KEY_P,          KEY_LEFTBRACE,
 124   KEY_RIGHTBRACE,      KEY_BACKSLASH,  KEY_INSERT,     KEY_DELETE,
 125   KEY_J,               KEY_K,          KEY_L,          KEY_SEMICOLON,
 126   KEY_APOSTROPHE,      KEY_ENTER,      KEY_HOME,       KEY_SCROLLUP,
 127   KEY_M,               KEY_COMMA,      KEY_DOT,        KEY_SLASH,
 128   KEY_RESERVED,        KEY_OPEN/*Select*/,KEY_RESERVED,KEY_SCROLLDOWN/*KPNEXT*/,
 129   KEY_N,               KEY_SPACE,      KEY_SCROLLDOWN/*Next*/, KEY_UNKNOWN,
 130   KEY_LEFT,            KEY_DOWN,       KEY_UP,         KEY_RIGHT
 131};
 132
 133
 134/* HIL structure */
 135static struct {
 136        struct input_dev dev;
 137
 138        unsigned int curdev;
 139        
 140        unsigned char s;
 141        unsigned char c;
 142        int valid;
 143        
 144        unsigned char data[16];
 145        unsigned int ptr;
 146
 147        void *dev_id;   /* native bus device */
 148} hil_dev;
 149
 150
 151static void poll_finished(void)
 152{
 153        int down;
 154        int key;
 155        unsigned char scode;
 156        
 157        switch (hil_dev.data[0]) {
 158        case 0x40:
 159                down = (hil_dev.data[1] & 1) == 0;
 160                scode = hil_dev.data[1] >> 1;
 161                key = hil_kbd_set1[scode & 0x7f];
 162                input_report_key(&hil_dev.dev, key, down);
 163                break;
 164        }
 165        hil_dev.curdev = 0;
 166}
 167
 168static inline void handle_status(unsigned char s, unsigned char c)
 169{
 170        if (c & 0x8) {
 171                /* End of block */
 172                if (c & 0x10)
 173                        poll_finished();
 174        } else {
 175                if (c & 0x10) {
 176                        if (hil_dev.curdev)
 177                                poll_finished();  /* just in case */
 178                        hil_dev.curdev = c & 7;
 179                        hil_dev.ptr = 0;
 180                }
 181        }
 182}
 183
 184static inline void handle_data(unsigned char s, unsigned char c)
 185{
 186        if (hil_dev.curdev) {
 187                hil_dev.data[hil_dev.ptr++] = c;
 188                hil_dev.ptr &= 15;
 189        }
 190}
 191
 192
 193/* 
 194 * Handle HIL interrupts.
 195 */
 196static void hil_interrupt(int irq, void *handle, struct pt_regs *regs)
 197{
 198        unsigned char s, c;
 199        
 200        s = hil_status();
 201        c = hil_read_data();
 202
 203        switch (s >> 4) {
 204        case 0x5:
 205                handle_status(s, c);
 206                break;
 207        case 0x6:
 208                handle_data(s, c);
 209                break;
 210        case 0x4:
 211                hil_dev.s = s;
 212                hil_dev.c = c;
 213                mb();
 214                hil_dev.valid = 1;
 215                break;
 216        }
 217}
 218
 219/*
 220 * Send a command to the HIL
 221 */
 222
 223static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
 224{
 225        unsigned long flags;
 226
 227        save_flags(flags);
 228        cli();
 229        while (hil_busy())
 230                /* wait */;
 231        hil_command(cmd);
 232        while (len--) {
 233                while (hil_busy())
 234                        /* wait */;
 235                hil_write_data(*(data++));
 236        }
 237        restore_flags(flags);
 238}
 239
 240
 241/*
 242 * Initialise HIL. 
 243 */
 244
 245static int __init
 246hil_keyb_init(void)
 247{
 248        unsigned char c;
 249        unsigned int i, kbid, n = 0;
 250
 251        if (hil_dev.dev.idbus) {
 252                printk("HIL: already initialized\n");
 253                return -ENODEV;
 254        }
 255        
 256#if defined(CONFIG_HP300)
 257        if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
 258                return -ENODEV;
 259        
 260        request_region(HILBASE+HIL_DATA, 2, "hil");
 261#endif
 262        
 263        request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
 264
 265        /* Turn on interrupts */
 266        hil_do(HIL_INTON, NULL, 0);
 267
 268        /* Look for keyboards */
 269        hil_dev.valid = 0;      /* clear any pending data */
 270        hil_do(HIL_READKBDSADR, NULL, 0);
 271        while (!hil_dev.valid) {
 272                if (n++ > 100000) {
 273                        printk(KERN_DEBUG "HIL: timed out, assuming no keyboard present.\n");
 274                        break;
 275                }
 276                mb();
 277        }
 278
 279        c = hil_dev.c; 
 280        hil_dev.valid = 0;
 281        if (c == 0) {
 282                kbid = -1;
 283                printk(KERN_WARNING "HIL: no keyboard present.\n");
 284        } else {
 285                kbid = ffz(~c);
 286                printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid);
 287        }
 288
 289        /* set it to raw mode */
 290        c = 0;
 291        hil_do(HIL_WRITEKBDSADR, &c, 1);
 292        
 293
 294        /* register input interface */
 295        hil_dev.dev.name        = "HIL keyboard";
 296        hil_dev.dev.idbus       = BUS_HIL;
 297        hil_dev.dev.idvendor    = PCI_VENDOR_ID_HP;
 298        hil_dev.dev.idproduct   = 0x0001;
 299        hil_dev.dev.idversion   = 0x0100;
 300
 301        hil_dev.dev.evbit[0] |= BIT(EV_KEY);
 302        for (i = 0; i < 128; i++)
 303                set_bit(hil_kbd_set1[i], hil_dev.dev.keybit);
 304        clear_bit(0, hil_dev.dev.keybit);
 305
 306#if 1
 307        /* XXX: HACK !!!
 308         * remove this call if hp_psaux.c/hp_keyb.c is converted
 309         * to the input layer... */
 310        register_ps2_keybfuncs();
 311#endif
 312        
 313        input_register_device(&hil_dev.dev);
 314        printk(KERN_INFO "input%d: %s on hil%d (id %d)\n",
 315                hil_dev.dev.number, hil_dev.dev.name, 0, kbid);
 316
 317        /* HIL keyboards don't have a numlock key,
 318         * simulate a up-down sequence of numlock to 
 319         * make the keypad work at expected. */
 320        input_report_key(&hil_dev.dev, KEY_NUMLOCK, 1);
 321
 322        return 0;
 323}
 324
 325#if defined(CONFIG_PARISC)
 326static int __init
 327hil_init_chip(struct parisc_device *dev)
 328{
 329        if (!dev->irq) {
 330                printk(KERN_WARNING "HIL: IRQ not found for HIL at 0x%lx\n", dev->hpa);
 331                return -ENODEV;
 332        }
 333
 334        hil_base = dev->hpa;
 335        hil_irq  = dev->irq;
 336        hil_dev.dev_id = dev;
 337        
 338        printk(KERN_INFO "Found HIL at 0x%lx, IRQ %d\n", hil_base, hil_irq);
 339
 340        return hil_keyb_init();
 341}
 342
 343static struct parisc_device_id hil_tbl[] = {
 344        { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 },
 345        { 0, }
 346};
 347
 348MODULE_DEVICE_TABLE(parisc, hil_tbl);
 349
 350static struct parisc_driver hil_driver = {
 351        .name =         "HIL",
 352        .id_table =     hil_tbl,
 353        .probe =        hil_init_chip,
 354};
 355#endif /* CONFIG_PARISC */
 356
 357
 358
 359
 360
 361static int __init hil_init(void)
 362{
 363#if defined(CONFIG_PARISC)
 364        return register_parisc_driver(&hil_driver);
 365#else
 366        return hil_keyb_init();
 367#endif
 368}
 369
 370
 371static void __exit hil_exit(void)
 372{
 373        if (HIL_IRQ) {
 374                disable_irq(HIL_IRQ);
 375                free_irq(HIL_IRQ, hil_dev.dev_id);
 376        }
 377
 378        input_unregister_device(&hil_dev.dev);
 379
 380#if defined(CONFIG_PARISC)
 381        unregister_parisc_driver(&hil_driver);
 382#else
 383        release_region(HILBASE+HIL_DATA, 2);
 384#endif
 385}
 386
 387module_init(hil_init);
 388module_exit(hil_exit);
 389
 390
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.