diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
commit | 012bb3e61e5eced6c610f9e036372bf0c8def2d1 (patch) | |
tree | 87efc733f9b164e8c85c0336f92c8fb7eff6d183 /drivers/macintosh | |
parent | 625a1589d3d6464b5d90b8a0918789e3afffd220 (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/Makefile | 103 | ||||
-rw-r--r-- | drivers/macintosh/adb.c | 9 | ||||
-rw-r--r-- | drivers/macintosh/adbhid.c | 875 | ||||
-rw-r--r-- | drivers/macintosh/mac_hid.c | 492 | ||||
-rw-r--r-- | drivers/macintosh/mac_keyb.c | 80 | ||||
-rw-r--r-- | drivers/macintosh/macio-adb.c | 2 | ||||
-rw-r--r-- | drivers/macintosh/macserial.c | 14 | ||||
-rw-r--r-- | drivers/macintosh/mediabay.c | 11 | ||||
-rw-r--r-- | drivers/macintosh/nvram.c | 26 | ||||
-rw-r--r-- | drivers/macintosh/rtc.c | 157 | ||||
-rw-r--r-- | drivers/macintosh/via-cuda.c | 124 | ||||
-rw-r--r-- | drivers/macintosh/via-pmu.c | 563 |
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: |