summaryrefslogtreecommitdiffstats
path: root/drivers/macintosh
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-10-05 01:18:40 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-10-05 01:18:40 +0000
commit012bb3e61e5eced6c610f9e036372bf0c8def2d1 (patch)
tree87efc733f9b164e8c85c0336f92c8fb7eff6d183 /drivers/macintosh
parent625a1589d3d6464b5d90b8a0918789e3afffd220 (diff)
Merge with Linux 2.4.0-test9. Please check DECstation, I had a number
of rejects to fixup while integrating Linus patches. I also found that this kernel will only boot SMP on Origin; the UP kernel freeze soon after bootup with SCSI timeout messages. I commit this anyway since I found that the last CVS versions had the same problem.
Diffstat (limited to 'drivers/macintosh')
-rw-r--r--drivers/macintosh/Makefile103
-rw-r--r--drivers/macintosh/adb.c9
-rw-r--r--drivers/macintosh/adbhid.c875
-rw-r--r--drivers/macintosh/mac_hid.c492
-rw-r--r--drivers/macintosh/mac_keyb.c80
-rw-r--r--drivers/macintosh/macio-adb.c2
-rw-r--r--drivers/macintosh/macserial.c14
-rw-r--r--drivers/macintosh/mediabay.c11
-rw-r--r--drivers/macintosh/nvram.c26
-rw-r--r--drivers/macintosh/rtc.c157
-rw-r--r--drivers/macintosh/via-cuda.c124
-rw-r--r--drivers/macintosh/via-pmu.c563
12 files changed, 2127 insertions, 329 deletions
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index ac096db95..6edf9ff5e 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -9,76 +9,67 @@
# parent makes..
#
-SUB_DIRS :=
-MOD_SUB_DIRS := $(SUB_DIRS)
+# Subdirs.
-O_TARGET := macintosh.o
-O_OBJS :=
-M_OBJS :=
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+MOD_IN_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
-ifeq ($(CONFIG_PMAC_PBOOK),y)
- O_OBJS += mediabay.o
-else
- ifeq ($(CONFIG_MAC_FLOPPY),y)
- O_OBJS += mediabay.o
- endif
-endif
+# The target object and module list name.
-ifeq ($(CONFIG_MAC_SERIAL),y)
- O_OBJS += macserial.o
-else
- ifeq ($(CONFIG_MAC_SERIAL),m)
- M_OBJS += macserial.o
- endif
-endif
+O_TARGET := macintosh.o
+M_OBJS :=
+O_OBJS :=
+MOD_LIST_NAME := MACINTOSH_MODULES
-ifeq ($(CONFIG_NVRAM),y)
- O_OBJS += nvram.o
-else
- ifeq ($(CONFIG_NVRAM),m)
- M_OBJS += nvram.o
- endif
-endif
+# Objects that export symbols.
-ifdef CONFIG_ADB
- OX_OBJS := adb.o
-endif
+export-objs := adb.o rtc.o mac_hid.o
-ifdef CONFIG_ADB_KEYBOARD
- O_OBJS += mac_keyb.o
-endif
+# Object file lists.
-ifdef CONFIG_ADB_MACII
- O_OBJS += via-macii.o
-endif
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
-ifdef CONFIG_ADB_MACIISI
- O_OBJS += via-maciisi.o
-endif
+# Each configuration option enables a list of files.
-ifdef CONFIG_ADB_CUDA
- O_OBJS += via-cuda.o
+ifeq ($(CONFIG_PMAC_PBOOK),y)
+ obj-y += mediabay.o
endif
-ifdef CONFIG_ADB_IOP
- O_OBJS += adb-iop.o
-endif
+obj-$(CONFIG_MAC_SERIAL) += macserial.o
+obj-$(CONFIG_NVRAM) += nvram.o
+obj-$(CONFIG_MAC_HID) += mac_hid.o
+obj-$(CONFIG_INPUT_ADBHID) += adbhid.o
+obj-$(CONFIG_PPC_RTC) += rtc.o
-ifdef CONFIG_ADB_PMU
- O_OBJS += via-pmu.o
-endif
+obj-$(CONFIG_ADB_PMU) += via-pmu.o
+obj-$(CONFIG_ADB_CUDA) += via-cuda.o
-ifdef CONFIG_ADB_PMU68K
- O_OBJS += via-pmu68k.o
-endif
+obj-$(CONFIG_ADB) += adb.o
+obj-$(CONFIG_ADB_KEYBOARD) += mac_keyb.o
+obj-$(CONFIG_ADB_MACII) += via-macii.o
+obj-$(CONFIG_ADB_MACIISI) += via-maciisi.o
+obj-$(CONFIG_ADB_IOP) += adb-iop.o
+obj-$(CONFIG_ADB_PMU68K) += via-pmu68k.o
+obj-$(CONFIG_ADB_MACIO) += macio-adb.o
-ifdef CONFIG_ADB_MACIO
- O_OBJS += macio-adb.o
-endif
+# Files that are both resident and modular: remove from modular.
+
+obj-m := $(filter-out $(obj-y), $(obj-m))
+int-m := $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
+OX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
+
+# The global Rules.make.
include $(TOPDIR)/Rules.make
-# Integrated in mac_keyb.c
-# mackeymap.map is retained for historical reasons
-#mackeymap.c: mackeymap.map
-# loadkeys --mktable mackeymap.map > mackeymap.c
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 10421b00d..d17382f4f 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -393,6 +393,15 @@ adb_register(int default_id, int handler_id, struct adb_ids *ids,
return ids->nids;
}
+int
+adb_unregister(int index)
+{
+ if (!adb_handler[index].handler)
+ return -ENODEV;
+ adb_handler[index].handler = 0;
+ return 0;
+}
+
void
adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll)
{
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
new file mode 100644
index 000000000..8ac4f37d4
--- /dev/null
+++ b/drivers/macintosh/adbhid.c
@@ -0,0 +1,875 @@
+/*
+ * drivers/input/adbhid.c
+ *
+ * ADB HID driver for Power Macintosh computers.
+ *
+ * Adapted from drivers/macintosh/mac_keyb.c by Franz Sirl
+ * (see that file for its authors and contributors).
+ *
+ * Copyright (C) 2000 Franz Sirl.
+ *
+ * Adapted to ADB changes and support for more devices by
+ * Benjamin Herrenschmidt. Adapted from code in MkLinux
+ * and reworked.
+ *
+ * Supported devices:
+ *
+ * - Standard 1 button mouse
+ * - All standard Apple Extended protocol (handler ID 4)
+ * - mouseman and trackman mice & trackballs
+ * - PowerBook Trackpad (default setup: enable tapping)
+ * - MicroSpeed mouse & trackball (needs testing)
+ * - CH Products Trackball Pro (needs testing)
+ * - Contour Design (Contour Mouse)
+ * - Hunter digital (NoHandsMouse)
+ * - Kensignton TurboMouse 5 (needs testing)
+ * - Mouse Systems A3 mice and trackballs <aidan@kublai.com>
+ * - MacAlly 2-buttons mouse (needs testing) <pochini@denise.shiny.it>
+ *
+ * To do:
+ *
+ * Improve Kensington support.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/input.h>
+#include <linux/kbd_ll.h>
+
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
+
+#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 */
+
+static int adb_message_handler(struct notifier_block *, unsigned long, void *);
+static struct notifier_block adbhid_adb_notifier = {
+ notifier_call: adb_message_handler,
+};
+
+unsigned char adb_to_linux_keycodes[128] = {
+ 30, 31, 32, 33, 35, 34, 44, 45, 46, 47, 86, 48, 16, 17, 18, 19,
+ 21, 20, 2, 3, 4, 5, 7, 6, 13, 10, 8, 12, 9, 11, 27, 24,
+ 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 51, 53, 49, 50, 52,
+ 15, 57, 41, 14, 96, 1, 29,125, 42, 58, 56,105,106,108,103, 0,
+ 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 98, 96, 0, 74, 0,
+ 0,117, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73,183,181,124,
+ 63, 64, 65, 61, 66, 67,191, 87,190, 99, 0, 70, 0, 68,101, 88,
+ 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,116,116
+};
+
+struct adbhid {
+ struct input_dev input;
+ int id;
+ int default_id;
+ int original_handler_id;
+ int current_handler_id;
+ int mouse_kind;
+ unsigned char *keycode;
+ char name[64];
+};
+
+static struct adbhid *adbhid[16] = { 0 };
+
+static void adbhid_probe(void);
+
+static void adbhid_input_keycode(int, int, int);
+static void leds_done(struct adb_request *);
+
+static void init_trackpad(int id);
+static void init_trackball(int id);
+static void init_turbomouse(int id);
+static void init_microspeed(int id);
+static void init_ms_a3(int id);
+
+static struct adb_ids keyboard_ids;
+static struct adb_ids mouse_ids;
+static struct adb_ids buttons_ids;
+
+/* Kind of keyboard, see Apple technote 1152 */
+#define ADB_KEYBOARD_UNKNOWN 0
+#define ADB_KEYBOARD_ANSI 0x0100
+#define ADB_KEYBOARD_ISO 0x0200
+#define ADB_KEYBOARD_JIS 0x0300
+
+/* Kind of mouse */
+#define ADBMOUSE_STANDARD_100 0 /* Standard 100cpi mouse (handler 1) */
+#define ADBMOUSE_STANDARD_200 1 /* Standard 200cpi mouse (handler 2) */
+#define ADBMOUSE_EXTENDED 2 /* Apple Extended mouse (handler 4) */
+#define ADBMOUSE_TRACKBALL 3 /* TrackBall (handler 4) */
+#define ADBMOUSE_TRACKPAD 4 /* Apple's PowerBook trackpad (handler 4) */
+#define ADBMOUSE_TURBOMOUSE5 5 /* Turbomouse 5 (previously req. mousehack) */
+#define ADBMOUSE_MICROSPEED 6 /* Microspeed mouse (&trackball ?), MacPoint */
+#define ADBMOUSE_TRACKBALLPRO 7 /* Trackball Pro (special buttons) */
+#define ADBMOUSE_MS_A3 8 /* Mouse systems A3 trackball (handler 3) */
+#define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */
+
+static void
+adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll)
+{
+ int id = (data[0] >> 4) & 0x0f;
+
+ if (!adbhid[id]) {
+ printk(KERN_ERR "ADB HID on ID %d not yet registered, packet %#02x, %#02x, %#02x, %#02x\n",
+ id, data[0], data[1], data[2], data[3]);
+ return;
+ }
+
+ /* first check this is from register 0 */
+ if (nb != 3 || (data[0] & 3) != KEYB_KEYREG)
+ return; /* ignore it */
+ kbd_pt_regs = 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);
+}
+
+static void
+adbhid_input_keycode(int id, int keycode, int repeat)
+{
+ int up_flag;
+
+ up_flag = (keycode & 0x80);
+ keycode &= 0x7f;
+
+ switch (keycode) {
+ case 0x39: /* Generate down/up events for CapsLock everytime. */
+ input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 1);
+ input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 0);
+ return;
+ case 0x3f: /* ignore Powerbook Fn key */
+ return;
+ }
+
+ if (adbhid[id]->keycode[keycode])
+ input_report_key(&adbhid[id]->input,
+ adbhid[id]->keycode[keycode], !up_flag);
+ else
+ printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode,
+ up_flag ? "released" : "pressed");
+}
+
+static void
+adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+{
+ int id = (data[0] >> 4) & 0x0f;
+
+ if (!adbhid[id]) {
+ printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id);
+ return;
+ }
+
+ /*
+ Handler 1 -- 100cpi original Apple mouse protocol.
+ Handler 2 -- 200cpi original Apple mouse protocol.
+
+ For Apple's standard one-button mouse protocol the data array will
+ contain the following values:
+
+ BITS COMMENTS
+ data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+ data[1] = bxxx xxxx First button and x-axis motion.
+ data[2] = byyy yyyy Second button and y-axis motion.
+
+ Handler 4 -- Apple Extended mouse protocol.
+
+ For Apple's 3-button mouse protocol the data array will contain the
+ following values:
+
+ BITS COMMENTS
+ data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+ data[1] = bxxx xxxx Left button and x-axis motion.
+ data[2] = byyy yyyy Second button and y-axis motion.
+ data[3] = byyy bxxx Third button and fourth button. Y is additional
+ high bits of y-axis motion. XY is additional
+ high bits of x-axis motion.
+
+ MacAlly 2-button mouse protocol.
+
+ For MacAlly 2-button mouse protocol the data array will contain the
+ following values:
+
+ BITS COMMENTS
+ data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+ data[1] = bxxx xxxx Left button and x-axis motion.
+ data[2] = byyy yyyy Right button and y-axis motion.
+ data[3] = ???? ???? unknown
+ data[4] = ???? ???? unknown
+
+ */
+
+ /* If it's a trackpad, we alias the second button to the first.
+ NOTE: Apple sends an ADB flush command to the trackpad when
+ the first (the real) button is released. We could do
+ this here using async flush requests.
+ */
+ switch (adbhid[id]->mouse_kind)
+ {
+ case ADBMOUSE_TRACKPAD:
+ data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80);
+ data[2] = data[2] | 0x80;
+ break;
+ case ADBMOUSE_MICROSPEED:
+ data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
+ data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
+ data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5)
+ | (data[3] & 0x08);
+ break;
+ case ADBMOUSE_TRACKBALLPRO:
+ data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5)
+ & ((data[3] & 0x08) << 4));
+ data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7);
+ data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6);
+ break;
+ case ADBMOUSE_MS_A3:
+ data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
+ data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
+ data[3] = ((data[3] & 0x04) << 5);
+ break;
+ case ADBMOUSE_MACALLY2:
+ data[3] = (data[2] & 0x80) ? 0x80 : 0x00;
+ data[2] |= 0x80; /* Right button is mapped as button 3 */
+ nb=4;
+ break;
+ }
+
+ input_report_key(&adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1));
+ input_report_key(&adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1));
+
+ if (nb >= 4)
+ input_report_key(&adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1));
+
+ input_report_rel(&adbhid[id]->input, REL_X,
+ ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 ));
+ input_report_rel(&adbhid[id]->input, REL_Y,
+ ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 ));
+}
+
+static void
+adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+{
+ int id = (data[0] >> 4) & 0x0f;
+
+ if (!adbhid[id]) {
+ printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id);
+ return;
+ }
+
+ switch (adbhid[id]->original_handler_id) {
+ default:
+ case 0x02: /* Adjustable keyboard button device */
+ printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
+ data[0], data[1], data[2], data[3]);
+ break;
+ case 0x1f: /* Powerbook button device */
+ {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ int backlight = get_backlight_level();
+
+ /*
+ * XXX: Where is the contrast control for the passive?
+ * -- Cort
+ */
+
+ switch (data[1]) {
+ case 0x8: /* mute */
+ break;
+
+ case 0x7: /* contrast decrease */
+ break;
+
+ case 0x6: /* contrast increase */
+ break;
+
+ case 0xa: /* brightness decrease */
+ if (backlight < 0)
+ break;
+ if (backlight > BACKLIGHT_OFF)
+ set_backlight_level(backlight-1);
+ else
+ set_backlight_level(BACKLIGHT_OFF);
+ break;
+
+ case 0x9: /* brightness increase */
+ if (backlight < 0)
+ break;
+ if (backlight < BACKLIGHT_MAX)
+ set_backlight_level(backlight+1);
+ else
+ set_backlight_level(BACKLIGHT_MAX);
+ break;
+ }
+#endif /* CONFIG_PMAC_BACKLIGHT */
+ }
+ break;
+ }
+}
+
+static struct adb_request led_request;
+static int leds_pending[16];
+static int pending_devs[16];
+static int pending_led_start=0;
+static int pending_led_end=0;
+
+static void real_leds(unsigned char leds, int device)
+{
+ if (led_request.complete) {
+ adb_request(&led_request, leds_done, 0, 3,
+ ADB_WRITEREG(device, KEYB_LEDREG), 0xff,
+ ~leds);
+ } else {
+ if (!(leds_pending[device] & 0x100)) {
+ pending_devs[pending_led_end] = device;
+ pending_led_end++;
+ pending_led_end = (pending_led_end < 16) ? pending_led_end : 0;
+ }
+ leds_pending[device] = leds | 0x100;
+ }
+}
+
+/*
+ * Event callback from the input module. Events that change the state of
+ * the hardware are processed here.
+ */
+static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+ struct adbhid *adbhid = dev->private;
+ 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;
+ }
+
+ return -1;
+}
+
+static void leds_done(struct adb_request *req)
+{
+ int leds,device;
+
+ if (pending_led_start != pending_led_end) {
+ device = pending_devs[pending_led_start];
+ leds = leds_pending[device] & 0xff;
+ leds_pending[device] = 0;
+ pending_led_start++;
+ pending_led_start = (pending_led_start < 16) ? pending_led_start : 0;
+ real_leds(leds,device);
+ }
+
+}
+
+static int
+adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
+{
+ unsigned long flags;
+
+ switch (code) {
+ case ADB_MSG_PRE_RESET:
+ case ADB_MSG_POWERDOWN:
+ /* Stop the repeat timer. Autopoll is already off at this point */
+ save_flags(flags);
+ cli();
+ {
+ int i;
+ for (i = 1; i < 16; i++) {
+ if (adbhid[i])
+ del_timer(&adbhid[i]->input.timer);
+ }
+ }
+ restore_flags(flags);
+
+ /* Stop pending led requests */
+ while(!led_request.complete)
+ adb_poll();
+ break;
+
+ case ADB_MSG_POST_RESET:
+ adbhid_probe();
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static void
+adbhid_input_register(int id, int default_id, int original_handler_id,
+ int current_handler_id, int mouse_kind)
+{
+ int i;
+
+ if (adbhid[id]) {
+ printk(KERN_ERR "Trying to reregister ADB HID on ID %d\n", id);
+ return;
+ }
+
+ if (!(adbhid[id] = kmalloc(sizeof(struct adbhid), GFP_KERNEL)))
+ return;
+
+ memset(adbhid[id], 0, sizeof(struct adbhid));
+
+ adbhid[id]->id = default_id;
+ adbhid[id]->original_handler_id = original_handler_id;
+ adbhid[id]->current_handler_id = current_handler_id;
+ adbhid[id]->mouse_kind = mouse_kind;
+ adbhid[id]->input.private = adbhid[id];
+ adbhid[id]->input.name = adbhid[id]->name;
+ adbhid[id]->input.idbus = BUS_ADB;
+ adbhid[id]->input.idvendor = 0x0001;
+ adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id;
+ adbhid[id]->input.idversion = 0x0100;
+
+ switch (default_id) {
+ case ADB_KEYBOARD:
+ if (!(adbhid[id]->keycode = kmalloc(sizeof(adb_to_linux_keycodes), GFP_KERNEL))) {
+ kfree(adbhid[id]);
+ return;
+ }
+
+ sprintf(adbhid[id]->name, "ADB keyboard on ID %d:%d.%02x",
+ id, default_id, original_handler_id);
+
+ memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes));
+
+ printk(KERN_INFO "Detected ADB keyboard, type ");
+ switch (original_handler_id) {
+ default:
+ printk("<unknown>.\n");
+ adbhid[id]->input.idversion = ADB_KEYBOARD_UNKNOWN;
+ break;
+
+ case 0x01: case 0x02: case 0x03: case 0x06: case 0x08:
+ case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C:
+ case 0xC0: case 0xC3: case 0xC6:
+ printk("ANSI.\n");
+ adbhid[id]->input.idversion = ADB_KEYBOARD_ANSI;
+ break;
+
+ case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D:
+ case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1:
+ case 0xC4: case 0xC7:
+ printk("ISO, swapping keys.\n");
+ adbhid[id]->input.idversion = ADB_KEYBOARD_ISO;
+ i = adbhid[id]->keycode[10];
+ adbhid[id]->keycode[10] = adbhid[id]->keycode[50];
+ adbhid[id]->keycode[50] = i;
+ break;
+
+ case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A:
+ case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9:
+ printk("JIS.\n");
+ adbhid[id]->input.idversion = ADB_KEYBOARD_JIS;
+ break;
+ }
+
+ for (i = 0; i < 128; i++)
+ if (adbhid[id]->keycode[i])
+ set_bit(adbhid[id]->keycode[i], adbhid[id]->input.keybit);
+
+ adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+ adbhid[id]->input.ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML);
+ adbhid[id]->input.event = adbhid_kbd_event;
+ adbhid[id]->input.keycodemax = 127;
+ adbhid[id]->input.keycodesize = 1;
+ break;
+
+ case ADB_MOUSE:
+ sprintf(adbhid[id]->name, "ADB mouse on ID %d:%d.%02x",
+ id, default_id, original_handler_id);
+
+ adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ adbhid[id]->input.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ break;
+
+ case ADB_MISC:
+ switch (original_handler_id) {
+ case 0x02: /* Adjustable keyboard button device */
+ sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons on ID %d:%d.%02x",
+ id, default_id, original_handler_id);
+ break;
+ case 0x1f: /* Powerbook button device */
+ sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x",
+ id, default_id, original_handler_id);
+ break;
+ }
+ if (adbhid[id]->name[0])
+ break;
+ /* else fall through */
+
+ default:
+ printk(KERN_INFO "Trying to register unknown ADB device to input layer.\n");
+ kfree(adbhid[id]);
+ return;
+ }
+
+ adbhid[id]->input.keycode = adbhid[id]->keycode;
+
+ input_register_device(&adbhid[id]->input);
+
+ printk(KERN_INFO "input%d: ADB HID on ID %d:%d.%02x\n",
+ adbhid[id]->input.number, id, default_id, original_handler_id);
+
+ if (default_id == ADB_KEYBOARD) {
+ /* HACK WARNING!! This should go away as soon there is an utility
+ * to control that for event devices.
+ */
+ adbhid[id]->input.rep[REP_DELAY] = HZ/2; /* input layer default: HZ/4 */
+ adbhid[id]->input.rep[REP_PERIOD] = HZ/15; /* input layer default: HZ/33 */
+ }
+}
+
+static void adbhid_input_unregister(int id)
+{
+ input_unregister_device(&adbhid[id]->input);
+ if (adbhid[id]->keycode)
+ kfree(adbhid[id]->keycode);
+ kfree(adbhid[id]);
+ adbhid[id] = 0;
+}
+
+
+static void
+adbhid_probe(void)
+{
+ struct adb_request req;
+ int i, default_id, org_handler_id, cur_handler_id;
+
+ for (i = 1; i < 16; i++) {
+ if (adbhid[i])
+ adbhid_input_unregister(i);
+ }
+
+ adb_register(ADB_MOUSE, 0, &mouse_ids, adbhid_mouse_input);
+ adb_register(ADB_KEYBOARD, 0, &keyboard_ids, adbhid_keyboard_input);
+ adb_register(ADB_MISC, 0, &buttons_ids, adbhid_buttons_input);
+
+ for (i = 0; i < keyboard_ids.nids; i++) {
+ int id = keyboard_ids.id[i];
+
+ adb_get_infos(id, &default_id, &org_handler_id);
+
+ /* turn off all leds */
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff);
+
+ /* Enable full feature set of the keyboard
+ ->get it to send separate codes for left and right shift,
+ control, option keys */
+#if 0 /* handler 5 doesn't send separate codes for R modifiers */
+ if (adb_try_handler_change(id, 5))
+ printk("ADB keyboard at %d, handler set to 5\n", id);
+ else
+#endif
+ if (adb_try_handler_change(id, 3))
+ printk("ADB keyboard at %d, handler set to 3\n", id);
+ else
+ printk("ADB keyboard at %d, handler 1\n", id);
+
+ adb_get_infos(id, &default_id, &cur_handler_id);
+ adbhid_input_register(id, default_id, org_handler_id, cur_handler_id, 0);
+ }
+
+ for (i = 0; i < buttons_ids.nids; i++) {
+ int id = buttons_ids.id[i];
+
+ adb_get_infos(id, &default_id, &org_handler_id);
+ adbhid_input_register(id, default_id, org_handler_id, org_handler_id, 0);
+ }
+
+ /* Try to switch all mice to handler 4, or 2 for three-button
+ mode and full resolution. */
+ for (i = 0; i < mouse_ids.nids; i++) {
+ int id = mouse_ids.id[i];
+ int mouse_kind;
+
+ adb_get_infos(id, &default_id, &org_handler_id);
+
+ if (adb_try_handler_change(id, 4)) {
+ printk("ADB mouse at %d, handler set to 4", id);
+ mouse_kind = ADBMOUSE_EXTENDED;
+ }
+ else if (adb_try_handler_change(id, 0x2F)) {
+ printk("ADB mouse at %d, handler set to 0x2F", id);
+ mouse_kind = ADBMOUSE_MICROSPEED;
+ }
+ else if (adb_try_handler_change(id, 0x42)) {
+ printk("ADB mouse at %d, handler set to 0x42", id);
+ mouse_kind = ADBMOUSE_TRACKBALLPRO;
+ }
+ else if (adb_try_handler_change(id, 0x66)) {
+ printk("ADB mouse at %d, handler set to 0x66", id);
+ mouse_kind = ADBMOUSE_MICROSPEED;
+ }
+ else if (adb_try_handler_change(id, 0x5F)) {
+ printk("ADB mouse at %d, handler set to 0x5F", id);
+ mouse_kind = ADBMOUSE_MICROSPEED;
+ }
+ else if (adb_try_handler_change(id, 3)) {
+ printk("ADB mouse at %d, handler set to 3", id);
+ mouse_kind = ADBMOUSE_MS_A3;
+ }
+ else if (adb_try_handler_change(id, 2)) {
+ printk("ADB mouse at %d, handler set to 2", id);
+ mouse_kind = ADBMOUSE_STANDARD_200;
+ }
+ else {
+ printk("ADB mouse at %d, handler 1", id);
+ mouse_kind = ADBMOUSE_STANDARD_100;
+ }
+
+ if ((mouse_kind == ADBMOUSE_TRACKBALLPRO)
+ || (mouse_kind == ADBMOUSE_MICROSPEED)) {
+ init_microspeed(id);
+ } else if (mouse_kind == ADBMOUSE_MS_A3) {
+ init_ms_a3(id);
+ } else if (mouse_kind == ADBMOUSE_EXTENDED) {
+ /*
+ * Register 1 is usually used for device
+ * identification. Here, we try to identify
+ * a known device and call the appropriate
+ * init function.
+ */
+ adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+ ADB_READREG(id, 1));
+
+ if ((req.reply_len) &&
+ (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21)
+ || (req.reply[2] == 0x20))) {
+ mouse_kind = ADBMOUSE_TRACKBALL;
+ init_trackball(id);
+ }
+ else if ((req.reply_len >= 4) &&
+ (req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
+ (req.reply[3] == 0x61) && (req.reply[4] == 0x64)) {
+ mouse_kind = ADBMOUSE_TRACKPAD;
+ init_trackpad(id);
+ }
+ else if ((req.reply_len >= 4) &&
+ (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
+ (req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) {
+ mouse_kind = ADBMOUSE_TURBOMOUSE5;
+ init_turbomouse(id);
+ }
+ else if ((req.reply_len == 9) &&
+ (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) &&
+ (req.reply[3] == 0x49) && (req.reply[4] == 0x54)) {
+ if (adb_try_handler_change(id, 0x42)) {
+ printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id);
+ mouse_kind = ADBMOUSE_MACALLY2;
+ }
+ }
+ }
+ printk("\n");
+
+ adb_get_infos(id, &default_id, &cur_handler_id);
+ adbhid_input_register(id, default_id, org_handler_id,
+ cur_handler_id, mouse_kind);
+ }
+}
+
+static void
+init_trackpad(int id)
+{
+ struct adb_request req;
+ unsigned char r1_buffer[8];
+
+ printk(" (trackpad)");
+
+ adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+ ADB_READREG(id,1));
+ if (req.reply_len < 8)
+ printk("bad length for reg. 1\n");
+ else
+ {
+ memcpy(r1_buffer, &req.reply[1], 8);
+ adb_request(&req, NULL, ADBREQ_SYNC, 9,
+ ADB_WRITEREG(id,1),
+ r1_buffer[0],
+ r1_buffer[1],
+ r1_buffer[2],
+ r1_buffer[3],
+ r1_buffer[4],
+ r1_buffer[5],
+ 0x0d, /*r1_buffer[6],*/
+ r1_buffer[7]);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 9,
+ ADB_WRITEREG(id,2),
+ 0x99,
+ 0x94,
+ 0x19,
+ 0xff,
+ 0xb2,
+ 0x8a,
+ 0x1b,
+ 0x50);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 9,
+ ADB_WRITEREG(id,1),
+ r1_buffer[0],
+ r1_buffer[1],
+ r1_buffer[2],
+ r1_buffer[3],
+ r1_buffer[4],
+ r1_buffer[5],
+ 0x03, /*r1_buffer[6],*/
+ r1_buffer[7]);
+ }
+}
+
+static void
+init_trackball(int id)
+{
+ struct adb_request req;
+
+ printk(" (trackman/mouseman)");
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 00,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 01,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 02,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 03,0x38);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 00,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 01,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 02,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 03,0x38);
+}
+
+static void
+init_turbomouse(int id)
+{
+ struct adb_request req;
+
+ printk(" (TurboMouse 5)");
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 9,
+ ADB_WRITEREG(3,2),
+ 0xe7,
+ 0x8c,
+ 0,
+ 0,
+ 0,
+ 0xff,
+ 0xff,
+ 0x94);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 9,
+ ADB_WRITEREG(3,2),
+ 0xa5,
+ 0x14,
+ 0,
+ 0,
+ 0x69,
+ 0xff,
+ 0xff,
+ 0x27);
+}
+
+static void
+init_microspeed(int id)
+{
+ struct adb_request req;
+
+ printk(" (Microspeed/MacPoint or compatible)");
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+ /* This will initialize mice using the Microspeed, MacPoint and
+ other compatible firmware. Bit 12 enables extended protocol.
+
+ Register 1 Listen (4 Bytes)
+ 0 - 3 Button is mouse (set also for double clicking!!!)
+ 4 - 7 Button is locking (affects change speed also)
+ 8 - 11 Button changes speed
+ 12 1 = Extended mouse mode, 0 = normal mouse mode
+ 13 - 15 unused 0
+ 16 - 23 normal speed
+ 24 - 31 changed speed
+
+ Register 1 talk holds version and product identification information.
+ Register 1 Talk (4 Bytes):
+ 0 - 7 Product code
+ 8 - 23 undefined, reserved
+ 24 - 31 Version number
+
+ Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max.
+ */
+ adb_request(&req, NULL, ADBREQ_SYNC, 5,
+ ADB_WRITEREG(id,1),
+ 0x20, /* alt speed = 0x20 (rather slow) */
+ 0x00, /* norm speed = 0x00 (fastest) */
+ 0x10, /* extended protocol, no speed change */
+ 0x07); /* all buttons enabled as mouse buttons, no locking */
+
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+}
+
+static void
+init_ms_a3(int id)
+{
+ struct adb_request req;
+
+ printk(" (Mouse Systems A3 Mouse, or compatible)");
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id, 0x2),
+ 0x00,
+ 0x07);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+}
+
+static int __init adbhid_init(void)
+{
+ if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+ return 0;
+
+ led_request.complete = 1;
+
+ adbhid_probe();
+
+ notifier_chain_register(&adb_client_list, &adbhid_adb_notifier);
+
+ return 0;
+}
+
+static void __exit adbhid_exit(void)
+{
+}
+
+module_init(adbhid_init);
+module_exit(adbhid_exit);
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
new file mode 100644
index 000000000..d97a1f6fb
--- /dev/null
+++ b/drivers/macintosh/mac_hid.c
@@ -0,0 +1,492 @@
+/*
+ * drivers/macintosh/mac_hid.c
+ *
+ * HID support stuff for Macintosh computers.
+ *
+ * Copyright (C) 2000 Franz Sirl.
+ *
+ * Stuff inside CONFIG_MAC_ADBKEYCODES should go away during 2.5 when all
+ * major distributions are using the Linux keycodes.
+ * Stuff inside CONFIG_MAC_EMUMOUSEBTN should really be moved to userspace.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/input.h>
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+#include <linux/keyboard.h>
+#include <asm/keyboard.h>
+#include <asm/machdep.h>
+#endif
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char mac_hid_kbd_sysrq_xlate[128] =
+ "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
+ "yt123465=97-80o]" /* 0x10 - 0x1f */
+ "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
+ "\t `\177\000\033\000\000\000\000\000\000\000\000\000\000"
+ /* 0x30 - 0x3f */
+ "\000\000\000*\000+\000\000\000\000\000/\r\000-\000"
+ /* 0x40 - 0x4f */
+ "\000\0000123456789\000\000\000" /* 0x50 - 0x5f */
+ "\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214";
+ /* 0x60 - 0x6f */
+extern unsigned char pckbd_sysrq_xlate[128];
+#endif
+
+static u_short macplain_map[NR_KEYS] = {
+ 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+ 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72,
+ 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035,
+ 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f,
+ 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027,
+ 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e,
+ 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+ 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macshift_map[NR_KEYS] = {
+ 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58,
+ 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52,
+ 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025,
+ 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f,
+ 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022,
+ 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e,
+ 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117,
+ 0xf10b, 0xf20a, 0xf10a, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macaltgr_map[NR_KEYS] = {
+ 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+ 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72,
+ 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+ 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f,
+ 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200,
+ 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f,
+ 0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200,
+ 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516,
+ 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117,
+ 0xf50d, 0xf119, 0xf50c, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macctrl_map[NR_KEYS] = {
+ 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+ 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+ 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d,
+ 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f,
+ 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007,
+ 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e,
+ 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+ 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macshift_ctrl_map[NR_KEYS] = {
+ 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+ 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+ 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f,
+ 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200,
+ 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117,
+ 0xf200, 0xf119, 0xf200, 0xf700, 0xf701, 0xf702, 0xf200, 0xf20c,
+};
+
+static u_short macalt_map[NR_KEYS] = {
+ 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878,
+ 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872,
+ 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835,
+ 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f,
+ 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827,
+ 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e,
+ 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905,
+ 0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200,
+ 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+ 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+ 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macctrl_alt_map[NR_KEYS] = {
+ 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818,
+ 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812,
+ 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f,
+ 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200,
+ 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+ 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+ 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static unsigned short *mac_key_maps_save[MAX_NR_KEYMAPS] = {
+ macplain_map, macshift_map, macaltgr_map, 0,
+ macctrl_map, macshift_ctrl_map, 0, 0,
+ macalt_map, 0, 0, 0,
+ macctrl_alt_map, 0
+};
+
+static unsigned short *pc_key_maps_save[MAX_NR_KEYMAPS];
+
+int mac_hid_kbd_translate(unsigned char keycode, unsigned char *keycodep,
+ char raw_mode);
+static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
+ void *buffer, size_t *lenp);
+char mac_hid_kbd_unexpected_up(unsigned char keycode);
+
+static int keyboard_lock_keycodes = 0;
+int keyboard_sends_linux_keycodes = 0;
+#else
+int keyboard_sends_linux_keycodes = 1;
+#endif
+
+
+static unsigned char e0_keys[128] = {
+ 0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0, /* 0x00-0x07 */
+ 0, 0, 0, 0, KEY_LANG1, KEY_LANG2, 0, 0, /* 0x08-0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
+ 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18-0x1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
+ 0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ, /* 0x30-0x37 */
+ KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */
+ 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40-0x47 */
+ KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */
+ KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */
+ 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, 0, 0, /* 0x58-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, 0, 0, KEY_MACRO, /* 0x68-0x6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
+};
+
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+static struct input_dev emumousebtn;
+static void emumousebtn_input_register(void);
+static int mouse_emulate_buttons = 0;
+static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */
+static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */
+static int mouse_last_keycode = 0;
+#endif
+
+extern void pckbd_init_hw(void);
+
+#if defined CONFIG_SYSCTL && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
+/* file(s) in /proc/sys/dev/mac_hid */
+ctl_table mac_hid_files[] =
+{
+#ifdef CONFIG_MAC_ADBKEYCODES
+ {
+ DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES,
+ "keyboard_sends_linux_keycodes", &keyboard_sends_linux_keycodes, sizeof(int),
+ 0644, NULL, &mac_hid_sysctl_keycodes
+ },
+ {
+ DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES,
+ "keyboard_lock_keycodes", &keyboard_lock_keycodes, sizeof(int),
+ 0644, NULL, &proc_dointvec
+ },
+#endif
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+ {
+ DEV_MAC_HID_MOUSE_BUTTON_EMULATION,
+ "mouse_button_emulation", &mouse_emulate_buttons, sizeof(int),
+ 0644, NULL, &proc_dointvec
+ },
+ {
+ DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE,
+ "mouse_button2_keycode", &mouse_button2_keycode, sizeof(int),
+ 0644, NULL, &proc_dointvec
+ },
+ {
+ DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE,
+ "mouse_button3_keycode", &mouse_button3_keycode, sizeof(int),
+ 0644, NULL, &proc_dointvec
+ },
+#endif
+ { 0 }
+};
+
+/* dir in /proc/sys/dev */
+ctl_table mac_hid_dir[] =
+{
+ { DEV_MAC_HID, "mac_hid", NULL, 0, 0555, mac_hid_files },
+ { 0 }
+};
+
+/* /proc/sys/dev itself, in case that is not there yet */
+ctl_table mac_hid_root_dir[] =
+{
+ { CTL_DEV, "dev", NULL, 0, 0555, mac_hid_dir },
+ { 0 }
+};
+
+static struct ctl_table_header *mac_hid_sysctl_header;
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+static
+int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
+ void *buffer, size_t *lenp)
+{
+ int val = keyboard_sends_linux_keycodes;
+ int ret = 0;
+
+ if (!write
+ || (write && !keyboard_lock_keycodes))
+ ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+
+ if (write
+ && keyboard_sends_linux_keycodes != val) {
+ if (!keyboard_sends_linux_keycodes) {
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
+ SYSRQ_KEY = 0x69;
+#endif
+ memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
+ memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
+ } else {
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
+ SYSRQ_KEY = 0x54;
+#endif
+ memcpy(mac_key_maps_save, key_maps, sizeof(key_maps));
+ memcpy(key_maps, pc_key_maps_save, sizeof(key_maps));
+ }
+ }
+
+ return ret;
+}
+#endif
+#endif /* endif CONFIG_SYSCTL */
+
+int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode)
+{
+#ifdef CONFIG_MAC_ADBKEYCODES
+ if (!keyboard_sends_linux_keycodes) {
+ if (!raw_mode) {
+ /*
+ * Convert R-shift/control/option to L version.
+ */
+ switch (scancode) {
+ case 0x7b: scancode = 0x38; break; /* R-shift */
+ case 0x7c: scancode = 0x3a; break; /* R-option */
+ case 0x7d: scancode = 0x36; break; /* R-control */
+ }
+ }
+ *keycode = scancode;
+ return 1;
+ } else
+#endif
+ {
+ /* This code was copied from char/pc_keyb.c and will be
+ * superflous when the input layer is fully integrated.
+ * We don't need the high_keys handling, so this part
+ * has been removed.
+ */
+ static int prev_scancode = 0;
+
+ /* special prefix scancodes.. */
+ if (scancode == 0xe0 || scancode == 0xe1) {
+ prev_scancode = scancode;
+ return 0;
+ }
+
+ scancode &= 0x7f;
+
+ if (prev_scancode) {
+ if (prev_scancode != 0xe0) {
+ if (prev_scancode == 0xe1 && scancode == 0x1d) {
+ prev_scancode = 0x100;
+ return 0;
+ } else if (prev_scancode == 0x100 && scancode == 0x45) {
+ *keycode = KEY_PAUSE;
+ prev_scancode = 0;
+ } else {
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
+ prev_scancode = 0;
+ return 0;
+ }
+ } else {
+ prev_scancode = 0;
+ if (scancode == 0x2a || scancode == 0x36)
+ return 0;
+ }
+ if (e0_keys[scancode])
+ *keycode = e0_keys[scancode];
+ else {
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+ scancode);
+ return 0;
+ }
+ } else {
+ switch (scancode) {
+ case 91: scancode = KEY_LINEFEED; break;
+ case 92: scancode = KEY_KPEQUAL; break;
+ case 125: scancode = KEY_INTL1; break;
+ }
+ *keycode = scancode;
+ }
+ return 1;
+ }
+}
+
+char mac_hid_kbd_unexpected_up(unsigned char keycode)
+{
+ if (keyboard_sends_linux_keycodes && keycode == KEY_F13)
+ return 0;
+ else
+ return 0x80;
+}
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+int mac_hid_keyboard_sends_linux_keycodes(void)
+{
+ return keyboard_sends_linux_keycodes;
+}
+
+static int __init mac_hid_setup(char *str)
+{
+ int ints[2];
+
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+ if (ints[0] == 1) {
+ keyboard_sends_linux_keycodes = ints[1] != 0;
+ keyboard_lock_keycodes = 1;
+ }
+ return 1;
+}
+
+__setup("keyboard_sends_linux_keycodes=", mac_hid_setup);
+
+#endif
+
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
+{
+ switch (caller) {
+ case 1:
+ /* Called from keybdev.c */
+ if (mouse_emulate_buttons
+ && (keycode == mouse_button2_keycode
+ || keycode == mouse_button3_keycode)) {
+ if (mouse_emulate_buttons == 1) {
+ input_report_key(&emumousebtn,
+ keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT,
+ down);
+ return 1;
+ }
+ mouse_last_keycode = down ? keycode : 0;
+ }
+ break;
+ case 2:
+ /* Called from mousedev.c */
+ if (mouse_emulate_buttons == 2 && keycode == 0) {
+ if (mouse_last_keycode == mouse_button2_keycode)
+ return 1; /* map to middle button */
+ if (mouse_last_keycode == mouse_button3_keycode)
+ return 2; /* map to right button */
+ }
+ return keycode; /* keep button */
+ }
+ return 0;
+}
+
+static void emumousebtn_input_register(void)
+{
+ emumousebtn.name = "Macintosh mouse button emulation";
+
+ emumousebtn.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ emumousebtn.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ emumousebtn.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+ emumousebtn.idbus = BUS_ADB;
+ emumousebtn.idvendor = 0x0001;
+ emumousebtn.idproduct = 0x0001;
+ emumousebtn.idversion = 0x0100;
+
+ input_register_device(&emumousebtn);
+
+ printk(KERN_INFO "input%d: Macintosh mouse button emulation\n", emumousebtn.number);
+}
+#endif
+
+void __init mac_hid_init_hw(void)
+{
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+ memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
+
+ if (!keyboard_sends_linux_keycodes)
+ memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
+#endif
+
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+ emumousebtn_input_register();
+#endif
+
+#if CONFIG_PPC
+ if (_machine != _MACH_Pmac)
+ pckbd_init_hw();
+#endif
+
+#if defined(CONFIG_SYSCTL) && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
+ mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1);
+#endif /* CONFIG_SYSCTL */
+}
diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c
index 7e9ec4751..662f4a7f5 100644
--- a/drivers/macintosh/mac_keyb.c
+++ b/drivers/macintosh/mac_keyb.c
@@ -51,6 +51,10 @@
#include <linux/kbd_kern.h>
#include <linux/kbd_ll.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
#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 */
@@ -585,68 +589,50 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
}
#endif /* CONFIG_ADBMOUSE */
-/* XXX Needs to get rid of this, see comments in pmu.c */
-extern int backlight_level;
-
static void
buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
{
-#ifdef CONFIG_ADB_PMU
+#ifdef CONFIG_PMAC_BACKLIGHT
+ int backlight = get_backlight_level();
+
/*
* XXX: Where is the contrast control for the passive?
* -- Cort
*/
/* Ignore data from register other than 0 */
-#if 0
- if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2))
-#else
if ((data[0] & 0x3) || (nb < 2))
-#endif
return;
- switch (data[1]&0xf )
- {
- /* mute */
- case 0x8:
- /* down event */
- if ( data[1] == (data[1]&0xf) ) {
- }
- break;
- /* contrast decrease */
- case 0x7:
- /* down event */
- if ( data[1] == (data[1]&0xf) ) {
- }
- break;
- /* contrast increase */
- case 0x6:
- /* down event */
- if ( data[1] == (data[1]&0xf) ) {
- }
- break;
- /* brightness decrease */
- case 0xa:
- /* down event */
- if ( data[1] == (data[1]&0xf) ) {
- if (backlight_level > 2)
- pmu_set_brightness(backlight_level-2);
- else
- pmu_set_brightness(0);
- }
+ switch (data[1]) {
+ case 0x8: /* mute */
+ break;
+
+ case 0x7: /* contrast decrease */
+ break;
+
+ case 0x6: /* contrast increase */
+ break;
+
+ case 0xa: /* brightness decrease */
+ if (backlight < 0)
break;
- /* brightness increase */
- case 0x9:
- /* down event */
- if ( data[1] == (data[1]&0xf) ) {
- if (backlight_level < 0x1e)
- pmu_set_brightness(backlight_level+2);
- else
- pmu_set_brightness(0x1f);
- }
+ if (backlight > BACKLIGHT_OFF)
+ set_backlight_level(backlight-1);
+ else
+ set_backlight_level(BACKLIGHT_OFF);
+ break;
+
+ case 0x9: /* brightness increase */
+ if (backlight < 0)
break;
+ if (backlight < BACKLIGHT_MAX)
+ set_backlight_level(backlight+1);
+ else
+ set_backlight_level(BACKLIGHT_MAX);
+ break;
}
-#endif /* CONFIG_ADB_PMU */
+#endif /* CONFIG_PMAC_BACKLIGHT */
}
/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index 52fc92198..abf570853 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -122,6 +122,8 @@ int macio_init(void)
out_8(&adb->autopoll.r, APE);
out_8(&adb->intr_enb.r, DFB | TAG);
+ printk("adb: mac-io driver 1.0 for unified ADB\n");
+
return 0;
}
diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
index 8e0528cba..55cf255b9 100644
--- a/drivers/macintosh/macserial.c
+++ b/drivers/macintosh/macserial.c
@@ -2291,7 +2291,7 @@ chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
zss->irq = ch->intrs[0].line;
zss->has_dma = 0;
#if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA)
- if (ch->n_addrs == 3 && ch->n_intrs == 3)
+ if (ch->n_addrs >= 3 && ch->n_intrs == 3)
zss->has_dma = 1;
#endif
zss->dma_initted = 0;
@@ -2643,9 +2643,6 @@ void unregister_serial(int line)
* ------------------------------------------------------------
*/
#ifdef CONFIG_SERIAL_CONSOLE
-#ifdef CONFIG_SERIAL
-#error Cannot build serial console with macserial and serial drivers
-#endif
/*
* Print a string to the serial port trying not to disturb
@@ -2719,7 +2716,7 @@ static kdev_t serial_console_device(struct console *c)
*/
static int __init serial_console_setup(struct console *co, char *options)
{
- struct mac_serial *info = zs_soft + co->index;
+ struct mac_serial *info;
int baud = 38400;
int bits = 8;
int parity = 'n';
@@ -2735,6 +2732,11 @@ static int __init serial_console_setup(struct console *co, char *options)
if (zs_chain == 0)
return -1;
+ /* Do we have the device asked for? */
+ if (co->index >= zs_channels_found)
+ return -1;
+ info = zs_soft + co->index;
+
set_scc_power(info, 1);
/* Reset the channel */
@@ -2904,7 +2906,7 @@ static struct console sercons = {
/*
* Register console.
*/
-void __init serial_console_init(void)
+void __init mac_scc_console_init(void)
{
register_console(&sercons);
}
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 6002870b4..1bc1608d7 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -472,8 +472,11 @@ media_bay_step(int i)
} else if (MB_IDE_READY(i)) {
bay->timer = 0;
bay->state = mb_up;
- if (bay->cd_index < 0)
+ if (bay->cd_index < 0) {
+ pmu_suspend();
bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
+ pmu_resume();
+ }
if (bay->cd_index == -1) {
/* We eventually do a retry */
bay->cd_retry++;
@@ -605,7 +608,9 @@ mb_notify_sleep(struct pmu_sleep_notifier *self, int when)
only if it did not change. Note those bozo timings,
they seem to help the 3400 get it right.
*/
- mdelay(MB_STABLE_DELAY);
+ /* Force MB power to 0 */
+ set_mb_power(i, 0);
+ mdelay(MB_POWER_DELAY);
if (!bay->pismo)
out_8(&bay->addr->contents, 0x70);
mdelay(MB_STABLE_DELAY);
@@ -615,7 +620,9 @@ mb_notify_sleep(struct pmu_sleep_notifier *self, int when)
bay->last_value = bay->content_id;
bay->value_count = MS_TO_HZ(MB_STABLE_DELAY);
bay->timer = MS_TO_HZ(MB_POWER_DELAY);
+#ifdef CONFIG_BLK_DEV_IDE
bay->cd_retry = 0;
+#endif
do {
mdelay(1000/HZ);
media_bay_step(i);
diff --git a/drivers/macintosh/nvram.c b/drivers/macintosh/nvram.c
index 69d3f2d72..3536c85cf 100644
--- a/drivers/macintosh/nvram.c
+++ b/drivers/macintosh/nvram.c
@@ -14,6 +14,7 @@
#include <linux/nvram.h>
#include <linux/init.h>
#include <asm/uaccess.h>
+#include <asm/nvram.h>
#define NVRAM_SIZE 8192
@@ -70,11 +71,36 @@ static ssize_t write_nvram(struct file *file, const char *buf,
return p - buf;
}
+static int nvram_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ switch(cmd) {
+ case PMAC_NVRAM_GET_OFFSET:
+ {
+ int part, offset;
+ if (copy_from_user(&part,(void*)arg,sizeof(part))!=0)
+ return -EFAULT;
+ if (part < pmac_nvram_OF || part > pmac_nvram_NR)
+ return -EINVAL;
+ offset = pmac_get_partition(part);
+ if (copy_to_user((void*)arg,&offset,sizeof(offset))!=0)
+ return -EFAULT;
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
struct file_operations nvram_fops = {
owner: THIS_MODULE,
llseek: nvram_llseek,
read: read_nvram,
write: write_nvram,
+ ioctl: nvram_ioctl,
};
static struct miscdevice nvram_dev = {
diff --git a/drivers/macintosh/rtc.c b/drivers/macintosh/rtc.c
new file mode 100644
index 000000000..3e1435a6c
--- /dev/null
+++ b/drivers/macintosh/rtc.c
@@ -0,0 +1,157 @@
+/*
+ * Linux/PowerPC Real Time Clock Driver
+ *
+ * heavily based on:
+ * Linux/SPARC Real Time Clock Driver
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ *
+ * This is a little driver that lets a user-level program access
+ * the PPC clocks chip. It is no use unless you
+ * use the modified clock utility.
+ *
+ * Get the modified clock utility from:
+ * ftp://vger.rutgers.edu/pub/linux/Sparc/userland/clock.c
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/mc146818rtc.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+
+#include <asm/time.h>
+
+static int rtc_busy = 0;
+
+/* Retrieve the current date and time from the real time clock. */
+void get_rtc_time(struct rtc_time *t)
+{
+ unsigned long nowtime;
+
+ nowtime = (ppc_md.get_rtc_time)();
+
+ to_tm(nowtime, t);
+
+ t->tm_year -= 1900;
+ t->tm_mon -= 1;
+ t->tm_wday -= 1;
+}
+
+/* Set the current date and time in the real time clock. */
+void set_rtc_time(struct rtc_time *t)
+{
+ unsigned long nowtime;
+
+ printk(KERN_INFO "rtc.c:set_rtc_time: %04d-%02d-%02d %02d:%02d:%02d.\n", t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+
+ nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+
+ printk(KERN_INFO "rtc.c:set_rtc_time: set rtc time to %ld seconds.\n", nowtime);
+
+ (ppc_md.set_rtc_time)(nowtime);
+}
+
+static loff_t rtc_lseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct rtc_time rtc_tm;
+
+ switch (cmd)
+ {
+ case RTC_RD_TIME:
+ if (ppc_md.get_rtc_time)
+ {
+ get_rtc_time(&rtc_tm);
+
+ if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
+ return -EFAULT;
+
+ return 0;
+ }
+ else
+ return -EINVAL;
+
+ case RTC_SET_TIME:
+ if (!capable(CAP_SYS_TIME))
+ return -EPERM;
+
+ if (ppc_md.set_rtc_time)
+ {
+ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
+ return -EFAULT;
+
+ set_rtc_time(&rtc_tm);
+
+ return 0;
+ }
+ else
+ return -EINVAL;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+ if (rtc_busy)
+ return -EBUSY;
+
+ rtc_busy = 1;
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+ MOD_DEC_USE_COUNT;
+ rtc_busy = 0;
+ return 0;
+}
+
+static struct file_operations rtc_fops = {
+ owner: THIS_MODULE,
+ llseek: rtc_lseek,
+ ioctl: rtc_ioctl,
+ open: rtc_open,
+ release: rtc_release
+};
+
+static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops };
+
+EXPORT_NO_SYMBOLS;
+
+static int __init rtc_init(void)
+{
+ int error;
+
+ error = misc_register(&rtc_dev);
+ if (error) {
+ printk(KERN_ERR "rtc: unable to get misc minor\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static void __exit rtc_exit(void)
+{
+ misc_deregister(&rtc_dev);
+}
+
+module_init(rtc_init);
+module_exit(rtc_exit);
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 1d1179b03..fe2ce318b 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -94,39 +94,48 @@ static struct device_node *vias;
#endif
static int cuda_fully_inited = 0;
+#ifdef CONFIG_ADB
static int cuda_probe(void);
static int cuda_init(void);
+static int cuda_send_request(struct adb_request *req, int sync);
+static int cuda_adb_autopoll(int devs);
+static int cuda_reset_adb_bus(void);
+#endif /* CONFIG_ADB */
+
static int cuda_init_via(void);
static void cuda_start(void);
static void cuda_interrupt(int irq, void *arg, struct pt_regs *regs);
static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs);
-static int cuda_send_request(struct adb_request *req, int sync);
-static int cuda_adb_autopoll(int devs);
void cuda_poll(void);
-static int cuda_reset_adb_bus(void);
static int cuda_write(struct adb_request *req);
int cuda_request(struct adb_request *req,
void (*done)(struct adb_request *), int nbytes, ...);
+#ifdef CONFIG_ADB
struct adb_driver via_cuda_driver = {
"CUDA",
cuda_probe,
cuda_init,
cuda_send_request,
- /*cuda_write,*/
cuda_adb_autopoll,
cuda_poll,
cuda_reset_adb_bus
};
+#endif /* CONFIG_ADB */
#ifdef CONFIG_PPC
-void
-find_via_cuda()
+int
+find_via_cuda(void)
{
+ int err;
+ struct adb_request req;
+
+ if (vias != 0)
+ return 1;
vias = find_devices("via-cuda");
if (vias == 0)
- return;
+ return 0;
if (vias->next != 0)
printk(KERN_WARNING "Warning: only using 1st via-cuda\n");
@@ -146,15 +155,54 @@ find_via_cuda()
printk(KERN_ERR "via-cuda: expecting 1 address (%d) and 1 interrupt (%d)\n",
vias->n_addrs, vias->n_intrs);
if (vias->n_addrs < 1 || vias->n_intrs < 1)
- return;
+ return 0;
}
via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
cuda_state = idle;
sys_ctrler = SYS_CTRLER_CUDA;
+
+ err = cuda_init_via();
+ if (err) {
+ printk(KERN_ERR "cuda_init_via() failed\n");
+ via = NULL;
+ return 0;
+ }
+
+ /* Clear and enable interrupts, but only on PPC. On 68K it's done */
+ /* for us by the the main VIA driver in arch/m68k/mac/via.c */
+
+#ifndef CONFIG_MAC
+ via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */
+ via[IER] = IER_SET|SR_INT; eieio(); /* enable interrupt from SR */
+#endif
+
+ /* enable autopoll */
+ cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
+ while (!req.complete)
+ cuda_poll();
+
+ return 1;
}
#endif /* CONFIG_PPC */
+int via_cuda_start(void)
+{
+ if (via == NULL)
+ return -ENODEV;
+
+ if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
+ printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ);
+ return -EAGAIN;
+ }
+
+ printk("Macintosh CUDA driver v0.5 for Unified ADB.\n");
+
+ cuda_fully_inited = 1;
+ return 0;
+}
+
+#ifdef CONFIG_ADB
static int
cuda_probe()
{
@@ -172,46 +220,24 @@ cuda_probe()
static int
cuda_init(void)
{
- int err;
-
if (via == NULL)
return -ENODEV;
-
- err = cuda_init_via();
- if (err) {
- printk(KERN_ERR "cuda_probe: init_via() failed\n");
- via = NULL;
- return err;
- }
-
- /* Clear and enable interrupts, but only on PPC. On 68K it's done */
- /* for us by the the main VIA driver in arch/m68k/mac/via.c */
-
-#ifndef CONFIG_MAC
- via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */
- via[IER] = IER_SET|SR_INT; eieio(); /* enable interrupt from SR */
+#ifndef CONFIG_PPC
+ return via_cuda_start();
#endif
-
- if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
- printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ);
- return -EAGAIN;
- }
-
- printk("adb: CUDA driver v0.5 for Unified ADB.\n");
-
- cuda_fully_inited = 1;
return 0;
}
-
-#define WAIT_FOR(cond, what) \
- do { \
- for (x = 1000; !(cond); --x) { \
- if (x == 0) { \
- printk("Timeout waiting for " what); \
- return -ENXIO; \
- } \
+#endif /* CONFIG_ADB */
+
+#define WAIT_FOR(cond, what) \
+ do { \
+ for (x = 1000; !(cond); --x) { \
+ if (x == 0) { \
+ printk("Timeout waiting for " what "\n"); \
+ return -ENXIO; \
+ } \
udelay(100); \
- } \
+ } \
} while (0)
static int
@@ -255,6 +281,7 @@ cuda_init_via()
return 0;
}
+#ifdef CONFIG_ADB
/* Send an ADB command */
static int
cuda_send_request(struct adb_request *req, int sync)
@@ -309,7 +336,7 @@ cuda_reset_adb_bus(void)
cuda_poll();
return 0;
}
-
+#endif /* CONFIG_ADB */
/* Construct and send a cuda request */
int
cuda_request(struct adb_request *req, void (*done)(struct adb_request *),
@@ -534,7 +561,18 @@ cuda_input(unsigned char *buf, int nb, struct pt_regs *regs)
switch (buf[0]) {
case ADB_PACKET:
+#ifdef CONFIG_XMON
+ if (nb == 5 && buf[2] == 0x2c) {
+ extern int xmon_wants_key, xmon_adb_keycode;
+ if (xmon_wants_key) {
+ xmon_adb_keycode = buf[3];
+ return;
+ }
+ }
+#endif /* CONFIG_XMON */
+#ifdef CONFIG_ADB
adb_input(buf+2, nb-2, regs, buf[1] & 0x40);
+#endif /* CONFIG_ADB */
break;
default:
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index efec54db0..9712ddbae 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -32,6 +32,7 @@
#include <linux/pmu.h>
#include <linux/cuda.h>
#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
@@ -39,10 +40,16 @@
#include <asm/system.h>
#include <asm/init.h>
#include <asm/irq.h>
+#include <asm/hardirq.h>
#include <asm/feature.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
-#include <asm/heathrow.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+/* Some compile options */
+#undef SUSPEND_USES_PMU
/* Misc minor number allocated for /dev/pmu */
#define PMU_MINOR 154
@@ -84,7 +91,7 @@ static volatile unsigned char *via;
#define CB2_INT 0x08
#define CB1_INT 0x10 /* transition on CB1 input */
-static enum pmu_state {
+static volatile enum pmu_state {
idle,
sending,
intack,
@@ -95,7 +102,7 @@ static enum pmu_state {
static struct adb_request *current_req;
static struct adb_request *last_req;
static struct adb_request *req_awaiting_reply;
-static unsigned char interrupt_data[32];
+static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */
static unsigned char *reply_ptr;
static int data_index;
static int data_len;
@@ -106,22 +113,27 @@ static struct adb_request bright_req_1, bright_req_2, bright_req_3;
static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited = 0;
-static int pmu_has_adb, pmu_has_backlight;
+static int pmu_has_adb;
static unsigned char *gpio_reg = NULL;
-static int gpio_irq;
+static int gpio_irq = -1;
+static volatile int pmu_suspended = 0;
+static spinlock_t pmu_lock;
int asleep;
struct notifier_block *sleep_notifier_list;
+#ifdef CONFIG_ADB
static int pmu_probe(void);
static int pmu_init(void);
+static int pmu_send_request(struct adb_request *req, int sync);
+static int pmu_adb_autopoll(int devs);
+static int pmu_adb_reset_bus(void);
+#endif /* CONFIG_ADB */
+
static int init_pmu(void);
static int pmu_queue_request(struct adb_request *req);
static void pmu_start(void);
static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
-static int pmu_send_request(struct adb_request *req, int sync);
-static int pmu_adb_autopoll(int devs);
-static int pmu_adb_reset_bus(void);
static void send_byte(int x);
static void recv_byte(void);
static void pmu_sr_intr(struct pt_regs *regs);
@@ -130,20 +142,25 @@ static void pmu_handle_data(unsigned char *data, int len,
struct pt_regs *regs);
static void set_volume(int level);
static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int pmu_set_backlight_level(int level, void* data);
+static int pmu_set_backlight_enable(int on, int level, void* data);
+#endif /* CONFIG_PMAC_BACKLIGHT */
#ifdef CONFIG_PMAC_PBOOK
static void pmu_pass_intr(unsigned char *data, int len);
#endif
+#ifdef CONFIG_ADB
struct adb_driver via_pmu_driver = {
"PMU",
pmu_probe,
pmu_init,
pmu_send_request,
- /*pmu_queue_request,*/
pmu_adb_autopoll,
pmu_poll,
pmu_adb_reset_bus
};
+#endif /* CONFIG_ADB */
extern void low_sleep_handler(void);
extern void sleep_save_intrs(int);
@@ -206,6 +223,13 @@ static char *pbook_type[] = {
"Core99"
};
+#ifdef CONFIG_PMAC_BACKLIGHT
+static struct backlight_controller pmu_backlight_controller = {
+ pmu_set_backlight_enable,
+ pmu_set_backlight_level
+};
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
int __openfirmware
find_via_pmu()
{
@@ -216,17 +240,6 @@ find_via_pmu()
return 0;
if (vias->next != 0)
printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
-#if 0
- { int i;
-
- printk("find_via_pmu: node = %p, addrs =", vias->node);
- for (i = 0; i < vias->n_addrs; ++i)
- printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
- printk(", intrs =");
- for (i = 0; i < vias->n_intrs; ++i)
- printk(" %x", vias->intrs[i].line);
- printk("\n"); }
-#endif
if (vias->n_addrs < 1 || vias->n_intrs < 1) {
printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",
@@ -235,8 +248,9 @@ find_via_pmu()
return 0;
}
+ spin_lock_init(&pmu_lock);
+
pmu_has_adb = 1;
- pmu_has_backlight = 1;
if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
|| device_is_compatible(vias->parent, "ohare")))
@@ -246,9 +260,18 @@ find_via_pmu()
else if (device_is_compatible(vias->parent, "heathrow"))
pmu_kind = PMU_HEATHROW_BASED;
else if (device_is_compatible(vias->parent, "Keylargo")) {
+ struct device_node *gpio, *gpiop;
+
pmu_kind = PMU_KEYLARGO_BASED;
pmu_has_adb = (find_type_devices("adb") != NULL);
- pmu_has_backlight = (find_type_devices("backlight") != NULL);
+
+ gpiop = find_devices("gpio");
+ if (gpiop && gpiop->n_addrs) {
+ gpio_reg = ioremap(gpiop->addrs->address, 0x10);
+ gpio = find_devices("extint-gpio1");
+ if (gpio && gpio->parent == gpiop && gpio->n_intrs)
+ gpio_irq = gpio->intrs[0].line;
+ }
} else
pmu_kind = PMU_UNKNOWN;
@@ -266,10 +289,13 @@ find_via_pmu()
printk(KERN_INFO "PMU driver initialized for %s\n",
pbook_type[pmu_kind]);
+
sys_ctrler = SYS_CTRLER_PMU;
+
return 1;
}
+#ifdef CONFIG_ADB
static int __openfirmware
pmu_probe()
{
@@ -280,9 +306,10 @@ static int __openfirmware
pmu_init(void)
{
if (vias == NULL)
- return -ENXIO;
+ return -ENODEV;
return 0;
}
+#endif /* CONFIG_ADB */
/*
* We can't wait until pmu_init gets called, that happens too late.
@@ -291,10 +318,10 @@ pmu_init(void)
* turned us off.
* This is called from arch/ppc/kernel/pmac_setup.c:pmac_init2().
*/
-void via_pmu_start(void)
+int via_pmu_start(void)
{
if (vias == NULL)
- return;
+ return -ENODEV;
bright_req_1.complete = 1;
bright_req_2.complete = 1;
@@ -304,24 +331,12 @@ void via_pmu_start(void)
(void *)0)) {
printk(KERN_ERR "VIA-PMU: can't get irq %d\n",
vias->intrs[0].line);
- return;
+ return -EAGAIN;
}
- if (pmu_kind == PMU_KEYLARGO_BASED) {
- struct device_node *gpio, *gpiop;
-
- gpiop = find_devices("gpio");
- if (gpiop && gpiop->n_addrs) {
- gpio_reg = ioremap(gpiop->addrs->address, 0x10);
- gpio = find_devices("extint-gpio1");
- if (gpio && gpio->parent == gpiop && gpio->n_intrs) {
- gpio_irq = gpio->intrs[0].line;
- if (request_irq(gpio_irq, gpio1_interrupt, 0,
- "GPIO1/ADB", (void *)0))
- printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n",
- gpio->intrs[0].line);
- }
- }
+ if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) {
+ if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1/ADB", (void *)0))
+ printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq);
}
/* Enable interrupts */
@@ -329,8 +344,24 @@ void via_pmu_start(void)
pmu_fully_inited = 1;
+#ifdef CONFIG_PMAC_BACKLIGHT
/* Enable backlight */
- pmu_enable_backlight(1);
+ register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+ /* Make sure PMU settle down before continuing. This is _very_ important
+ * since the IDE probe may shut interrupts down for quite a bit of time. If
+ * a PMU communication is pending while this happens, the PMU may timeout
+ * Not that on Core99 machines, the PMU keeps sending us environement
+ * messages, we should find a way to either fix IDE or make it call
+ * pmu_suspend() before masking interrupts. This can also happens while
+ * scolling with some fbdevs.
+ */
+ do {
+ pmu_poll();
+ } while (pmu_state != idle);
+
+ return 0;
}
static int __openfirmware
@@ -342,7 +373,7 @@ init_pmu()
out_8(&via[B], via[B] | TREQ); /* negate TREQ */
out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */
- pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xff);
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
timeout = 100000;
while (!req.complete) {
if (--timeout < 0) {
@@ -367,6 +398,13 @@ init_pmu()
udelay(10);
}
+ /* Tell PMU we are ready. Which PMU support this ? */
+ if (pmu_kind == PMU_KEYLARGO_BASED) {
+ pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
+ while (!req.complete)
+ pmu_poll();
+ }
+
return 1;
}
@@ -376,6 +414,7 @@ pmu_get_model(void)
return pmu_kind;
}
+#ifdef CONFIG_ADB
/* Send an ADB command */
static int __openfirmware
pmu_send_request(struct adb_request *req, int sync)
@@ -513,6 +552,7 @@ pmu_adb_reset_bus(void)
return 0;
}
+#endif /* CONFIG_ADB */
/* Construct and send a pmu request */
int __openfirmware
@@ -568,8 +608,8 @@ pmu_queue_request(struct adb_request *req)
req->next = 0;
req->sent = 0;
req->complete = 0;
- save_flags(flags); cli();
+ spin_lock_irqsave(&pmu_lock, flags);
if (current_req != 0) {
last_req->next = req;
last_req = req;
@@ -579,11 +619,27 @@ pmu_queue_request(struct adb_request *req)
if (pmu_state == idle)
pmu_start();
}
+ spin_unlock_irqrestore(&pmu_lock, flags);
- restore_flags(flags);
return 0;
}
+static void __openfirmware
+wait_for_ack(void)
+{
+ /* Sightly increased the delay, I had one occurence of the message
+ * reported
+ */
+ int timeout = 4000;
+ while ((in_8(&via[B]) & TACK) == 0) {
+ if (--timeout < 0) {
+ printk(KERN_ERR "PMU not responding (!ack)\n");
+ return;
+ }
+ udelay(10);
+ }
+}
+
/* New PMU seems to be very sensitive to those timings, so we make sure
* PCI is flushed immediately */
static void __openfirmware
@@ -613,57 +669,126 @@ static volatile int disable_poll;
static void __openfirmware
pmu_start()
{
- unsigned long flags;
struct adb_request *req;
/* assert pmu_state == idle */
/* get the packet to send */
- save_flags(flags); cli();
req = current_req;
if (req == 0 || pmu_state != idle
- || (req->reply_expected && req_awaiting_reply))
- goto out;
+ || (/*req->reply_expected && */req_awaiting_reply))
+ return;
pmu_state = sending;
data_index = 1;
data_len = pmu_data_len[req->data[0]][0];
+ /* Sounds safer to make sure ACK is high before writing. This helped
+ * kill a problem with ADB and some iBooks
+ */
+ wait_for_ack();
/* set the shift register to shift out and send a byte */
- ++disable_poll;
send_byte(req->data[0]);
- --disable_poll;
-
-out:
- restore_flags(flags);
}
void __openfirmware
pmu_poll()
{
- unsigned long flags;
-
+ if (!via)
+ return;
if (disable_poll)
return;
- save_flags(flags);
- cli();
- if ((via[IFR] & (SR_INT | CB1_INT)) ||
- (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0))
+ /* Kicks ADB read when PMU is suspended */
+ if (pmu_suspended)
+ adb_int_pending = 1;
+ do {
via_pmu_interrupt(0, 0, 0);
- restore_flags(flags);
+ } while (pmu_suspended && (adb_int_pending || pmu_state != idle
+ || req_awaiting_reply));
+}
+
+/* This function loops until the PMU is idle and prevents it from
+ * anwsering to ADB interrupts. pmu_request can still be called.
+ * This is done to avoid spurrious shutdowns when we know we'll have
+ * interrupts switched off for a long time
+ */
+void __openfirmware
+pmu_suspend(void)
+{
+ unsigned long flags;
+#ifdef SUSPEND_USES_PMU
+ struct adb_request *req;
+#endif
+ if (!via)
+ return;
+
+ spin_lock_irqsave(&pmu_lock, flags);
+ pmu_suspended++;
+ if (pmu_suspended > 1) {
+ spin_unlock_irqrestore(&pmu_lock, flags);
+ return;
+ }
+
+ do {
+ spin_unlock(&pmu_lock);
+ via_pmu_interrupt(0, 0, 0);
+ spin_lock(&pmu_lock);
+ if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
+#ifdef SUSPEND_USES_PMU
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
+ spin_unlock_irqrestore(&pmu_lock, flags);
+ while(!req.complete)
+ pmu_poll();
+#else /* SUSPEND_USES_PMU */
+ if (gpio_irq >= 0)
+ disable_irq(gpio_irq);
+ out_8(&via[IER], CB1_INT | IER_CLR);
+ spin_unlock_irqrestore(&pmu_lock, flags);
+#endif /* SUSPEND_USES_PMU */
+ break;
+ }
+ } while (1);
+}
+
+void __openfirmware
+pmu_resume(void)
+{
+ unsigned long flags;
+
+ if (!via || (pmu_suspended < 1))
+ return;
+
+ spin_lock_irqsave(&pmu_lock, flags);
+ pmu_suspended--;
+ if (pmu_suspended > 0) {
+ spin_unlock_irqrestore(&pmu_lock, flags);
+ return;
+ }
+ adb_int_pending = 1;
+#ifdef SUSPEND_USES_PMU
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
+ spin_unlock_irqrestore(&pmu_lock, flags);
+ while(!req.complete)
+ pmu_poll();
+#else /* SUSPEND_USES_PMU */
+ if (gpio_irq >= 0)
+ enable_irq(gpio_irq);
+ out_8(&via[IER], CB1_INT | IER_SET);
+ spin_unlock_irqrestore(&pmu_lock, flags);
+ pmu_poll();
+#endif /* SUSPEND_USES_PMU */
}
static void __openfirmware
via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
{
+ unsigned long flags;
int intr;
int nloop = 0;
- unsigned long flags;
- /* Currently, we use brute-force cli() for syncing with GPIO
- * interrupt. I'll make this smarter later, along with some
- * spinlocks for SMP */
- save_flags(flags);cli();
+ /* This is a bit brutal, we can probably do better */
+ spin_lock_irqsave(&pmu_lock, flags);
++disable_poll;
+
while ((intr = in_8(&via[IFR])) != 0) {
if (++nloop > 1000) {
printk(KERN_DEBUG "PMU: stuck in intr loop, "
@@ -681,25 +806,38 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
out_8(&via[IFR], intr);
}
}
- if (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)
+ /* This is not necessary except if synchronous ADB requests are done
+ * with interrupts off, which should not happen. Since I'm not sure
+ * this "wiring" will remain, I'm commenting it out for now. Please do
+ * not remove. -- BenH.
+ */
+#if 0
+ if (gpio_reg && !pmu_suspended && (in_8(gpio_reg + 0x9) & 0x02) == 0)
adb_int_pending = 1;
+#endif
if (pmu_state == idle) {
if (adb_int_pending) {
pmu_state = intack;
+ /* Sounds safer to make sure ACK is high before writing.
+ * This helped kill a problem with ADB and some iBooks
+ */
+ wait_for_ack();
send_byte(PMU_INT_ACK);
adb_int_pending = 0;
} else if (current_req) {
pmu_start();
}
}
+
--disable_poll;
- restore_flags(flags);
+ spin_unlock_irqrestore(&pmu_lock, flags);
}
static void __openfirmware
gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
{
+ adb_int_pending = 1;
via_pmu_interrupt(0, 0, 0);
}
@@ -707,7 +845,7 @@ static void __openfirmware
pmu_sr_intr(struct pt_regs *regs)
{
struct adb_request *req;
- int bite, timeout;
+ int bite;
if (via[B] & TREQ) {
printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]);
@@ -720,26 +858,16 @@ pmu_sr_intr(struct pt_regs *regs)
if (via[B] & TACK) {
while ((in_8(&via[B]) & TACK) != 0)
;
-#if 0
- printk(KERN_ERR "PMU: sr_intr but ack still high! (%x)\n",
- via[B]);
-#endif
}
/* reset TREQ and wait for TACK to go high */
out_8(&via[B], in_8(&via[B]) | TREQ);
- timeout = 3200;
- while ((in_8(&via[B]) & TACK) == 0) {
- if (--timeout < 0) {
- printk(KERN_ERR "PMU not responding (!ack)\n");
- return;
- }
- udelay(10);
- }
+ wait_for_ack();
/* if reading grab the byte, and reset the interrupt */
if (pmu_state == reading || pmu_state == reading_intr)
bite = in_8(&via[SR]);
+
out_8(&via[IFR], SR_INT);
switch (pmu_state) {
@@ -761,8 +889,11 @@ pmu_sr_intr(struct pt_regs *regs)
current_req = req->next;
if (req->reply_expected)
req_awaiting_reply = req;
- else
+ else {
+ spin_unlock(&pmu_lock);
pmu_done(req);
+ spin_lock(&pmu_lock);
+ }
} else {
pmu_state = reading;
data_index = 0;
@@ -795,12 +926,16 @@ pmu_sr_intr(struct pt_regs *regs)
}
if (pmu_state == reading_intr) {
+ spin_unlock(&pmu_lock);
pmu_handle_data(interrupt_data, data_index, regs);
+ spin_lock(&pmu_lock);
} else {
req = current_req;
current_req = req->next;
req->reply_len += data_index;
+ spin_unlock(&pmu_lock);
pmu_done(req);
+ spin_lock(&pmu_lock);
}
pmu_state = idle;
@@ -826,6 +961,7 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
{
asleep = 0;
if (len < 1) {
+// xmon_printk("empty ADB\n");
adb_int_pending = 0;
return;
}
@@ -854,6 +990,7 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
}
}
#endif /* CONFIG_XMON */
+#ifdef CONFIG_ADB
/*
* XXX On the [23]400 the PMU gives us an up
* event for keycodes 0x74 or 0x75 when the PC
@@ -864,10 +1001,13 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
&& data[1] == 0x2c && data[3] == 0xff
&& (data[2] & ~1) == 0xf4))
adb_input(data+1, len-1, regs, 1);
+#endif /* CONFIG_ADB */
}
} else if (data[0] == 0x08 && len == 3) {
/* sound/brightness buttons pressed */
- pmu_set_brightness(data[1] >> 3);
+#ifdef CONFIG_PMAC_BACKLIGHT
+ set_backlight_level(data[1] >> 4);
+#endif
set_volume(data[2]);
} else {
#ifdef CONFIG_PMAC_PBOOK
@@ -876,53 +1016,23 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
}
}
-int backlight_level = -1;
-int backlight_enabled = 0;
-
-#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1))
-
-void __openfirmware
-pmu_enable_backlight(int on)
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight_to_bright[] = {
+ 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e,
+ 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e
+};
+
+static int __openfirmware
+pmu_set_backlight_enable(int on, int level, void* data)
{
struct adb_request req;
+
+ if (vias == NULL)
+ return -ENODEV;
- if ((vias == NULL) || !pmu_has_backlight)
- return;
-
- /* first call: get current backlight value */
- if (on && backlight_level < 0) {
- switch (pmu_kind) {
- case PMU_OHARE_BASED:
- pmu_request(&req, NULL, 2, 0xd9, 0);
- while (!req.complete)
- pmu_poll();
- backlight_level = req.reply[1] >> 3;
- break;
- case PMU_HEATHROW_BASED:
- /* We cannot use nvram_read_byte here (not yet initialized) */
- pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe);
- while (!req.complete)
- pmu_poll();
- backlight_level = req.reply[1];
- printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level);
- break;
- case PMU_PADDINGTON_BASED:
- case PMU_KEYLARGO_BASED:
- /* the G3 PB 1999 has a backlight node
- and chrp-structured nvram */
- /* XXX should read macos's "blkt" property in nvram
- for this node. For now this ensures that the
- backlight doesn't go off as soon as linux boots. */
- backlight_level = 20;
- break;
- default:
- backlight_enabled = 0;
- return;
- }
- }
if (on) {
pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- LEVEL_TO_BRIGHT(backlight_level));
+ backlight_to_bright[level]);
while (!req.complete)
pmu_poll();
}
@@ -930,35 +1040,28 @@ pmu_enable_backlight(int on)
PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
while (!req.complete)
pmu_poll();
- backlight_enabled = on;
+
+ return 0;
}
-void __openfirmware
-pmu_set_brightness(int level)
+static int __openfirmware
+pmu_set_backlight_level(int level, void* data)
{
- int bright;
+ if (vias == NULL)
+ return -ENODEV;
- if ((vias == NULL) || !pmu_has_backlight)
- return ;
+ if (!bright_req_1.complete)
+ return -EAGAIN;
+ pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+ backlight_to_bright[level]);
+ if (!bright_req_2.complete)
+ return -EAGAIN;
+ pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT
+ | (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF));
- backlight_level = level;
- bright = LEVEL_TO_BRIGHT(level);
- if (!backlight_enabled)
- return;
- if (bright_req_1.complete)
- pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- bright);
- if (bright_req_2.complete)
- pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF));
-
- /* XXX nvram address is hard-coded and looks ok on wallstreet, please
- test on your machine. Note that newer MacOS system software may break
- the nvram layout. */
- if ((pmu_kind == PMU_HEATHROW_BASED) && bright_req_3.complete)
- pmu_request(&bright_req_3, NULL, 4, PMU_WRITE_NVRAM,
- 0x14, 0xe, level);
+ return 0;
}
+#endif /* CONFIG_PMAC_BACKLIGHT */
void __openfirmware
pmu_enable_irled(int on)
@@ -967,6 +1070,8 @@ pmu_enable_irled(int on)
if (vias == NULL)
return ;
+ if (pmu_kind == PMU_KEYLARGO_BASED)
+ return ;
pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED |
(on ? PMU_POW_ON : PMU_POW_OFF));
@@ -1201,17 +1306,9 @@ int __openfirmware powerbook_sleep_G3(void)
{
int ret;
unsigned long save_l2cr;
- unsigned long save_fcr;
unsigned long wait;
unsigned short pmcr1;
- struct adb_request sleep_req;
- struct device_node *macio;
- unsigned long macio_base = 0;
-
- macio = find_devices("mac-io");
- if (macio != 0 && macio->n_addrs > 0)
- macio_base = (unsigned long)
- ioremap(macio->addrs[0].address, 0x40);
+ struct adb_request req;
/* Notify device drivers */
ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
@@ -1245,14 +1342,13 @@ int __openfirmware powerbook_sleep_G3(void)
/* Make sure the decrementer won't interrupt us */
asm volatile("mtdec %0" : : "r" (0x7fffffff));
+ feature_prepare_for_sleep();
+
/* For 750, save backside cache setting and disable it */
save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */
if (save_l2cr)
_set_L2CR(0);
- if (macio_base != 0)
- save_fcr = in_le32(FEATURE_CTRL(macio_base));
-
if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)
giveup_fpu(current);
@@ -1263,17 +1359,14 @@ int __openfirmware powerbook_sleep_G3(void)
grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
/* Ask the PMU to put us to sleep */
- pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
- while (!sleep_req.complete)
+ pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+ while (!req.complete)
pmu_poll();
cli();
while (pmu_state != idle)
pmu_poll();
- /* clear IOBUS enable */
- out_le32(FEATURE_CTRL(macio_base), save_fcr & ~HRW_IOBUS_ENABLE);
-
/* Call low-level ASM sleep handler */
low_sleep_handler();
@@ -1282,15 +1375,14 @@ int __openfirmware powerbook_sleep_G3(void)
pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP);
grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
- /* reenable IOBUS */
- out_le32(FEATURE_CTRL(macio_base), save_fcr | HRW_IOBUS_ENABLE);
-
/* Make sure the PMU is idle */
while (pmu_state != idle)
pmu_poll();
sti();
+ feature_wake_up();
+
/* The PGD is only a placeholder until Dan finds a way to make
* this work properly on the 8xx processors. It is only used on
* 8xx processors, it is ignored here.
@@ -1304,6 +1396,116 @@ int __openfirmware powerbook_sleep_G3(void)
/* reenable interrupts */
sleep_restore_intrs();
+ /* Tell PMU we are ready */
+ pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
+ while (!req.complete)
+ pmu_poll();
+
+ /* Notify drivers */
+ mdelay(10);
+ broadcast_wake();
+
+ return 0;
+}
+
+/* Not finished yet */
+int __openfirmware powerbook_sleep_Core99(void)
+{
+ int ret;
+ unsigned long save_l2cr;
+ unsigned long wait;
+ struct adb_request req;
+
+ /* Notify device drivers */
+ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
+ if (ret != PBOOK_SLEEP_OK) {
+ printk("pmu: sleep rejected\n");
+ return -EBUSY;
+ }
+
+ /* Sync the disks. */
+ /* XXX It would be nice to have some way to ensure that
+ * nobody is dirtying any new buffers while we wait.
+ * BenH: Moved to _after_ sleep request and changed video
+ * drivers to vmalloc() during sleep request. This way, all
+ * vmalloc's are done before actual sleep of block drivers */
+ fsync_dev(0);
+
+ /* Sleep can fail now. May not be very robust but useful for debugging */
+ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
+ if (ret != PBOOK_SLEEP_OK) {
+ printk("pmu: sleep failed\n");
+ return -EBUSY;
+ }
+
+ /* Give the disks a little time to actually finish writing */
+ for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
+ mb();
+
+ /* Tell PMU what events will wake us up */
+ pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
+ 0xff, 0xff);
+ while (!req.complete)
+ pmu_poll();
+ pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS,
+ 0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN);
+ while (!req.complete)
+ pmu_poll();
+
+ /* Disable all interrupts except pmu */
+ sleep_save_intrs(vias->intrs[0].line);
+
+ /* Make sure the decrementer won't interrupt us */
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+
+ /* Save the state of PCI config space for some slots */
+ pbook_pci_save();
+
+ feature_prepare_for_sleep();
+
+ /* For 750, save backside cache setting and disable it */
+ save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */
+ if (save_l2cr)
+ _set_L2CR(0);
+
+ if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)
+ giveup_fpu(current);
+
+ /* Ask the PMU to put us to sleep */
+ pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+ while (!req.complete)
+ mb();
+
+ cli();
+ while (pmu_state != idle)
+ pmu_poll();
+
+ /* Call low-level ASM sleep handler */
+ low_sleep_handler();
+
+ /* Make sure the PMU is idle */
+ while (pmu_state != idle)
+ pmu_poll();
+
+ sti();
+
+ feature_wake_up();
+ pbook_pci_restore();
+
+ set_context(current->mm->context, current->mm->pgd);
+
+ /* Restore L2 cache */
+ if (save_l2cr)
+ _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */
+
+ /* reenable interrupts */
+ sleep_restore_intrs();
+
+ /* Tell PMU we are ready */
+ pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
+ while (!req.complete)
+ pmu_poll();
+
/* Notify drivers */
mdelay(10);
broadcast_wake();
@@ -1557,7 +1759,6 @@ static int pmu_ioctl(struct inode * inode, struct file *filp,
u_int cmd, u_long arg)
{
int error;
- __u32 value;
switch (cmd) {
case PMU_IOC_SLEEP:
@@ -1569,21 +1770,33 @@ static int pmu_ioctl(struct inode * inode, struct file *filp,
case PMU_PADDINGTON_BASED:
error = powerbook_sleep_G3();
break;
+#if 0 /* Not ready yet */
+ case PMU_KEYLARGO_BASED:
+ error = powerbook_sleep_Core99();
+ break;
+#endif
default:
error = -ENOSYS;
}
return error;
+#ifdef CONFIG_PMAC_BACKLIGHT
+ /* Backlight should have its own device or go via
+ * the fbdev
+ */
case PMU_IOC_GET_BACKLIGHT:
- if (!pmu_has_backlight)
- return -ENOSYS;
- return put_user(backlight_level, (__u32 *)arg);
+ error = get_backlight_level();
+ if (error < 0)
+ return error;
+ return put_user(error, (__u32 *)arg);
case PMU_IOC_SET_BACKLIGHT:
- if (!pmu_has_backlight)
- return -ENOSYS;
+ {
+ __u32 value;
error = get_user(value, (__u32 *)arg);
if (!error)
- pmu_set_brightness(value);
+ error = set_backlight_level(value);
return error;
+ }
+#endif /* CONFIG_PMAC_BACKLIGHT */
case PMU_IOC_GET_MODEL:
return put_user(pmu_kind, (__u32 *)arg);
case PMU_IOC_HAS_ADB: