Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
[linux-2.6.git] / drivers / macintosh / adbhid.c
index 8f02c15..09d72bb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * drivers/input/adbhid.c
+ * drivers/macintosh/adbhid.c
  *
  * ADB HID driver for Power Macintosh computers.
  *
@@ -34,7 +34,6 @@
  * Move to syfs
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 
 #include <asm/machdep.h>
 #ifdef CONFIG_PPC_PMAC
-#include <asm/pmac_feature.h>
-#endif
-
-#ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
+#include <asm/pmac_feature.h>
 #endif
 
 MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
 
+static int restore_capslock_events;
+module_param(restore_capslock_events, int, 0644);
+MODULE_PARM_DESC(restore_capslock_events,
+       "Produce keypress events for capslock on both keyup and keydown.");
+
 #define KEYB_KEYREG    0       /* register # for key up/down data */
 #define KEYB_LEDREG    2       /* register # for leds on ADB keyboard */
 #define MOUSE_DATAREG  0       /* reg# for movement/button codes from mouse */
@@ -74,7 +75,7 @@ static struct notifier_block adbhid_adb_notifier = {
 #define ADB_KEY_POWER_OLD      0x7e
 #define ADB_KEY_POWER          0x7f
 
-u8 adb_to_linux_keycodes[128] = {
+static const u16 adb_to_linux_keycodes[128] = {
        /* 0x00 */ KEY_A,               /*  30 */
        /* 0x01 */ KEY_S,               /*  31 */
        /* 0x02 */ KEY_D,               /*  32 */
@@ -138,7 +139,7 @@ u8 adb_to_linux_keycodes[128] = {
        /* 0x3c */ KEY_RIGHT,           /* 106 */
        /* 0x3d */ KEY_DOWN,            /* 108 */
        /* 0x3e */ KEY_UP,              /* 103 */
-       /* 0x3f */ 0,
+       /* 0x3f */ KEY_FN,              /* 0x1d0 */
        /* 0x40 */ 0,
        /* 0x41 */ KEY_KPDOT,           /*  83 */
        /* 0x42 */ 0,
@@ -179,7 +180,7 @@ u8 adb_to_linux_keycodes[128] = {
        /* 0x65 */ KEY_F9,              /*  67 */
        /* 0x66 */ KEY_HANJA,           /* 123 */
        /* 0x67 */ KEY_F11,             /*  87 */
-       /* 0x68 */ KEY_HANGUEL,         /* 122 */
+       /* 0x68 */ KEY_HANGEUL,         /* 122 */
        /* 0x69 */ KEY_SYSRQ,           /*  99 */
        /* 0x6a */ 0,
        /* 0x6b */ KEY_SCROLLLOCK,      /*  70 */
@@ -212,21 +213,25 @@ struct adbhid {
        int original_handler_id;
        int current_handler_id;
        int mouse_kind;
-       unsigned char *keycode;
+       u16 *keycode;
        char name[64];
        char phys[32];
        int flags;
 };
 
-#define FLAG_FN_KEY_PRESSED    0x00000001
-#define FLAG_POWER_FROM_FN     0x00000002
-#define FLAG_EMU_FWDEL_DOWN    0x00000004
+#define FLAG_FN_KEY_PRESSED            0x00000001
+#define FLAG_POWER_FROM_FN             0x00000002
+#define FLAG_EMU_FWDEL_DOWN            0x00000004
+#define FLAG_CAPSLOCK_TRANSLATE                0x00000008
+#define FLAG_CAPSLOCK_DOWN             0x00000010
+#define FLAG_CAPSLOCK_IGNORE_NEXT      0x00000020
+#define FLAG_POWER_KEY_PRESSED         0x00000040
 
 static struct adbhid *adbhid[16];
 
 static void adbhid_probe(void);
 
-static void adbhid_input_keycode(int, int, int, struct pt_regs *);
+static void adbhid_input_keycode(int, int, int);
 
 static void init_trackpad(int id);
 static void init_trackball(int id);
@@ -238,11 +243,6 @@ static struct adb_ids keyboard_ids;
 static struct adb_ids mouse_ids;
 static struct adb_ids buttons_ids;
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-/* Exported to via-pmu.c */
-int disable_kernel_backlight = 0;
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
 /* Kind of keyboard, see Apple technote 1152  */
 #define ADB_KEYBOARD_UNKNOWN   0
 #define ADB_KEYBOARD_ANSI      0x0100
@@ -262,7 +262,7 @@ int disable_kernel_backlight = 0;
 #define ADBMOUSE_MACALLY2      9       /* MacAlly 2-button mouse */
 
 static void
-adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll)
+adbhid_keyboard_input(unsigned char *data, int nb, int apoll)
 {
        int id = (data[0] >> 4) & 0x0f;
 
@@ -275,27 +275,67 @@ adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apo
        /* first check this is from register 0 */
        if (nb != 3 || (data[0] & 3) != KEYB_KEYREG)
                return;         /* ignore it */
-       adbhid_input_keycode(id, data[1], 0, regs);
+       adbhid_input_keycode(id, data[1], 0);
        if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f)))
-               adbhid_input_keycode(id, data[2], 0, regs);
+               adbhid_input_keycode(id, data[2], 0);
 }
 
 static void
-adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
+adbhid_input_keycode(int id, int scancode, int repeat)
 {
        struct adbhid *ahid = adbhid[id];
-       int up_flag;
-
-       up_flag = (keycode & 0x80);
-       keycode &= 0x7f;
+       int keycode, up_flag, key;
+
+       keycode = scancode & 0x7f;
+       up_flag = scancode & 0x80;
+
+       if (restore_capslock_events) {
+               if (keycode == ADB_KEY_CAPSLOCK && !up_flag) {
+                       /* Key pressed, turning on the CapsLock LED.
+                        * The next 0xff will be interpreted as a release. */
+                       if (ahid->flags & FLAG_CAPSLOCK_IGNORE_NEXT) {
+                               /* Throw away this key event if it happens
+                                * just after resume. */
+                               ahid->flags &= ~FLAG_CAPSLOCK_IGNORE_NEXT;
+                               return;
+                       } else {
+                               ahid->flags |= FLAG_CAPSLOCK_TRANSLATE
+                                       | FLAG_CAPSLOCK_DOWN;
+                       }
+               } else if (scancode == 0xff &&
+                          !(ahid->flags & FLAG_POWER_KEY_PRESSED)) {
+                       /* Scancode 0xff usually signifies that the capslock
+                        * key was either pressed or released, or that the
+                        * power button was released. */
+                       if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) {
+                               keycode = ADB_KEY_CAPSLOCK;
+                               if (ahid->flags & FLAG_CAPSLOCK_DOWN) {
+                                       /* Key released */
+                                       up_flag = 1;
+                                       ahid->flags &= ~FLAG_CAPSLOCK_DOWN;
+                               } else {
+                                       /* Key pressed */
+                                       up_flag = 0;
+                                       ahid->flags &= ~FLAG_CAPSLOCK_TRANSLATE;
+                               }
+                       } else {
+                               printk(KERN_INFO "Spurious caps lock event "
+                                                "(scancode 0xff).\n");
+                       }
+               }
+       }
 
        switch (keycode) {
-       case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */
-               input_regs(ahid->input, regs);
-               input_report_key(ahid->input, KEY_CAPSLOCK, 1);
-               input_report_key(ahid->input, KEY_CAPSLOCK, 0);
-               input_sync(ahid->input);
-               return;
+       case ADB_KEY_CAPSLOCK:
+               if (!restore_capslock_events) {
+                       /* Generate down/up events for CapsLock every time. */
+                       input_report_key(ahid->input, KEY_CAPSLOCK, 1);
+                       input_sync(ahid->input);
+                       input_report_key(ahid->input, KEY_CAPSLOCK, 0);
+                       input_sync(ahid->input);
+                       return;
+               }
+               break;
 #ifdef CONFIG_PPC_PMAC
        case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */
                switch(pmac_call_feature(PMAC_FTR_GET_MB_INFO,
@@ -306,7 +346,13 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
                        keycode = ADB_KEY_POWER;
                }
                break;
-       case ADB_KEY_POWER: 
+       case ADB_KEY_POWER:
+               /* Keep track of the power key state */
+               if (up_flag)
+                       ahid->flags &= ~FLAG_POWER_KEY_PRESSED;
+               else
+                       ahid->flags |= FLAG_POWER_KEY_PRESSED;
+
                /* Fn + Command will produce a bogus "power" keycode */
                if (ahid->flags & FLAG_FN_KEY_PRESSED) {
                        keycode = ADB_KEY_CMD;
@@ -331,8 +377,7 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
                        }
                } else
                        ahid->flags |= FLAG_FN_KEY_PRESSED;
-               /* Swallow the key press */
-               return;
+               break;
        case ADB_KEY_DEL:
                /* Emulate Fn+delete = forward delete */
                if (ahid->flags & FLAG_FN_KEY_PRESSED) {
@@ -346,10 +391,9 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
 #endif /* CONFIG_PPC_PMAC */
        }
 
-       if (adbhid[id]->keycode[keycode]) {
-               input_regs(adbhid[id]->input, regs);
-               input_report_key(adbhid[id]->input,
-                                adbhid[id]->keycode[keycode], !up_flag);
+       key = adbhid[id]->keycode[keycode];
+       if (key) {
+               input_report_key(adbhid[id]->input, key, !up_flag);
                input_sync(adbhid[id]->input);
        } else
                printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode,
@@ -358,7 +402,7 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
 }
 
 static void
-adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+adbhid_mouse_input(unsigned char *data, int nb, int autopoll)
 {
        int id = (data[0] >> 4) & 0x0f;
 
@@ -441,8 +485,6 @@ adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopo
                 break;
        }
 
-       input_regs(adbhid[id]->input, regs);
-
        input_report_key(adbhid[id]->input, BTN_LEFT,   !((data[1] >> 7) & 1));
        input_report_key(adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1));
 
@@ -458,7 +500,7 @@ adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopo
 }
 
 static void
-adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+adbhid_buttons_input(unsigned char *data, int nb, int autopoll)
 {
        int id = (data[0] >> 4) & 0x0f;
 
@@ -467,8 +509,6 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
                return;
        }
 
-       input_regs(adbhid[id]->input, regs);
-
        switch (adbhid[id]->original_handler_id) {
        default:
        case 0x02: /* Adjustable keyboard button device */
@@ -503,9 +543,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
        case 0x1f: /* Powerbook button device */
          {
                int down = (data[1] == (data[1] & 0xf));
-#ifdef CONFIG_PMAC_BACKLIGHT
-               int backlight = get_backlight_level();
-#endif
+
                /*
                 * XXX: Where is the contrast control for the passive?
                 *  -- Cort
@@ -530,29 +568,17 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
 
                case 0xa:       /* brightness decrease */
 #ifdef CONFIG_PMAC_BACKLIGHT
-                       if (!disable_kernel_backlight) {
-                               if (down && backlight >= 0) {
-                                       if (backlight > BACKLIGHT_OFF)
-                                               set_backlight_level(backlight-1);
-                                       else
-                                               set_backlight_level(BACKLIGHT_OFF);
-                               }
-                       }
-#endif /* CONFIG_PMAC_BACKLIGHT */
+                       if (down)
+                               pmac_backlight_key_down();
+#endif
                        input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
                        break;
 
                case 0x9:       /* brightness increase */
 #ifdef CONFIG_PMAC_BACKLIGHT
-                       if (!disable_kernel_backlight) {
-                               if (down && backlight >= 0) {
-                                       if (backlight < BACKLIGHT_MAX)
-                                               set_backlight_level(backlight+1);
-                                       else 
-                                               set_backlight_level(BACKLIGHT_MAX);
-                               }
-                       }
-#endif /* CONFIG_PMAC_BACKLIGHT */
+                       if (down)
+                               pmac_backlight_key_up();
+#endif
                        input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
                        break;
 
@@ -603,8 +629,8 @@ static struct adb_request led_request;
 static int leds_pending[16];
 static int leds_req_pending;
 static int pending_devs[16];
-static int pending_led_start=0;
-static int pending_led_end=0;
+static int pending_led_start;
+static int pending_led_end;
 static DEFINE_SPINLOCK(leds_lock);
 
 static void leds_done(struct adb_request *req)
@@ -657,28 +683,43 @@ static void real_leds(unsigned char leds, int device)
  */
 static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-       struct adbhid *adbhid = dev->private;
+       struct adbhid *adbhid = input_get_drvdata(dev);
        unsigned char leds;
 
        switch (type) {
        case EV_LED:
-         leds = (test_bit(LED_SCROLLL, dev->led) ? 4 : 0)
-              | (test_bit(LED_NUML,    dev->led) ? 1 : 0)
-              | (test_bit(LED_CAPSL,   dev->led) ? 2 : 0);
-         real_leds(leds, adbhid->id);
-         return 0;
+               leds =  (test_bit(LED_SCROLLL, dev->led) ? 4 : 0) |
+                       (test_bit(LED_NUML,    dev->led) ? 1 : 0) |
+                       (test_bit(LED_CAPSL,   dev->led) ? 2 : 0);
+               real_leds(leds, adbhid->id);
+               return 0;
        }
 
        return -1;
 }
 
+static void
+adbhid_kbd_capslock_remember(void)
+{
+       struct adbhid *ahid;
+       int i;
+
+       for (i = 1; i < 16; i++) {
+               ahid = adbhid[i];
+
+               if (ahid && ahid->id == ADB_KEYBOARD)
+                       if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE)
+                               ahid->flags |= FLAG_CAPSLOCK_IGNORE_NEXT;
+       }
+}
+
 static int
 adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
 {
        switch (code) {
        case ADB_MSG_PRE_RESET:
        case ADB_MSG_POWERDOWN:
-               /* Stop the repeat timer. Autopoll is already off at this point */
+               /* Stop the repeat timer. Autopoll is already off at this point */
                {
                        int i;
                        for (i = 1; i < 16; i++) {
@@ -688,8 +729,17 @@ adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
                }
 
                /* Stop pending led requests */
-               while(leds_req_pending)
+               while (leds_req_pending)
                        adb_poll();
+
+               /* After resume, and if the capslock LED is on, the PMU will
+                * send a "capslock down" key event. This confuses the
+                * restore_capslock_events logic. Remember if the capslock
+                * LED was on before suspend so the unwanted key event can
+                * be ignored after resume. */
+               if (restore_capslock_events)
+                       adbhid_kbd_capslock_remember();
+
                break;
 
        case ADB_MSG_POST_RESET:
@@ -718,7 +768,6 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
        if (!hid || !input_dev) {
                err = -ENOMEM;
                goto fail;
-
        }
 
        sprintf(hid->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id);
@@ -729,7 +778,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
        hid->current_handler_id = current_handler_id;
        hid->mouse_kind = mouse_kind;
        hid->flags = 0;
-       input_dev->private = hid;
+       input_set_drvdata(input_dev, hid);
        input_dev->name = hid->name;
        input_dev->phys = hid->phys;
        input_dev->id.bustype = BUS_ADB;
@@ -784,26 +833,30 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
                        if (hid->keycode[i])
                                set_bit(hid->keycode[i], input_dev->keybit);
 
-               input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
-               input_dev->ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML);
+               input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
+                       BIT_MASK(EV_REP);
+               input_dev->ledbit[0] = BIT_MASK(LED_SCROLLL) |
+                       BIT_MASK(LED_CAPSL) | BIT_MASK(LED_NUML);
                input_dev->event = adbhid_kbd_event;
-               input_dev->keycodemax = 127;
-               input_dev->keycodesize = 1;
+               input_dev->keycodemax = KEY_FN;
+               input_dev->keycodesize = sizeof(hid->keycode[0]);
                break;
 
        case ADB_MOUSE:
                sprintf(hid->name, "ADB mouse");
 
-               input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-               input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
-               input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+               input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+               input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+                       BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+               input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
                break;
 
        case ADB_MISC:
                switch (original_handler_id) {
                case 0x02: /* Adjustable keyboard button device */
                        sprintf(hid->name, "ADB adjustable keyboard buttons");
-                       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+                       input_dev->evbit[0] = BIT_MASK(EV_KEY) |
+                               BIT_MASK(EV_REP);
                        set_bit(KEY_SOUND, input_dev->keybit);
                        set_bit(KEY_MUTE, input_dev->keybit);
                        set_bit(KEY_VOLUMEUP, input_dev->keybit);
@@ -811,7 +864,8 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
                        break;
                case 0x1f: /* Powerbook button device */
                        sprintf(hid->name, "ADB Powerbook buttons");
-                       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+                       input_dev->evbit[0] = BIT_MASK(EV_KEY) |
+                               BIT_MASK(EV_REP);
                        set_bit(KEY_MUTE, input_dev->keybit);
                        set_bit(KEY_VOLUMEUP, input_dev->keybit);
                        set_bit(KEY_VOLUMEDOWN, input_dev->keybit);
@@ -836,7 +890,9 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
 
        input_dev->keycode = hid->keycode;
 
-       input_register_device(input_dev);
+       err = input_register_device(input_dev);
+       if (err)
+               goto fail;
 
        if (default_id == ADB_KEYBOARD) {
                /* HACK WARNING!! This should go away as soon there is an utility
@@ -849,7 +905,10 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
        return 0;
 
  fail: input_free_device(input_dev);
-       kfree(hid);
+       if (hid) {
+               kfree(hid->keycode);
+               kfree(hid);
+       }
        adbhid[id] = NULL;
        return err;
 }
@@ -857,8 +916,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
 static void adbhid_input_unregister(int id)
 {
        input_unregister_device(adbhid[id]->input);
-       if (adbhid[id]->keycode)
-               kfree(adbhid[id]->keycode);
+       kfree(adbhid[id]->keycode);
        kfree(adbhid[id]);
        adbhid[id] = NULL;
 }
@@ -1207,15 +1265,16 @@ init_ms_a3(int id)
 static int __init adbhid_init(void)
 {
 #ifndef CONFIG_MAC
-       if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-           return 0;
+       if (!machine_is(chrp) && !machine_is(powermac))
+               return 0;
 #endif
 
        led_request.complete = 1;
 
        adbhid_probe();
 
-       notifier_chain_register(&adb_client_list, &adbhid_adb_notifier);
+       blocking_notifier_chain_register(&adb_client_list,
+                       &adbhid_adb_notifier);
 
        return 0;
 }