summaryrefslogtreecommitdiffstats
path: root/drivers/macintosh
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
commitdcec8a13bf565e47942a1751a9cec21bec5648fe (patch)
tree548b69625b18cc2e88c3e68d0923be546c9ebb03 /drivers/macintosh
parent2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff)
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash. o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'drivers/macintosh')
-rw-r--r--drivers/macintosh/Makefile13
-rw-r--r--drivers/macintosh/adb.c325
-rw-r--r--drivers/macintosh/ati-gx.h81
-rw-r--r--drivers/macintosh/aty.c29
-rw-r--r--drivers/macintosh/chips.c43
-rw-r--r--drivers/macintosh/control.c22
-rw-r--r--drivers/macintosh/imstt.c759
-rw-r--r--drivers/macintosh/imstt.h7
-rw-r--r--drivers/macintosh/mac_keyb.c294
-rw-r--r--drivers/macintosh/macio-adb.c12
-rw-r--r--drivers/macintosh/macserial.c453
-rw-r--r--drivers/macintosh/mediabay.c236
-rw-r--r--drivers/macintosh/platinum.c20
-rw-r--r--drivers/macintosh/pmac-cons.c42
-rw-r--r--drivers/macintosh/valkyrie.c24
-rw-r--r--drivers/macintosh/via-cuda.c28
-rw-r--r--drivers/macintosh/via-pmu.c669
17 files changed, 2453 insertions, 604 deletions
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 2d280d4c8..116a1d98e 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -14,7 +14,10 @@ MOD_SUB_DIRS := $(SUB_DIRS)
L_TARGET := macintosh.a
M_OBJS :=
-L_OBJS := via-cuda.o adb.o nvram.o macio-adb.o
+
+ifndef CONFIG_MBX
+L_OBJS := via-cuda.o adb.o nvram.o macio-adb.o via-pmu.o mediabay.o
+endif
ifeq ($(CONFIG_SERIAL)$(CONFIG_PMAC),yy)
LX_OBJS += macserial.o
@@ -25,7 +28,7 @@ else
endif
ifdef CONFIG_MAC_KEYBOARD
-L_OBJS += mac_keyb.o mackeymap.o
+L_OBJS += mac_keyb.o
endif
ifdef CONFIG_VT
@@ -54,5 +57,7 @@ endif
include $(TOPDIR)/Rules.make
-mackeymap.c: mackeymap.map
- loadkeys --mktable mackeymap.map > mackeymap.c
+# 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 945c7d456..c20efde6b 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -10,18 +10,23 @@
#include <linux/malloc.h>
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/sched.h>
#include <asm/prom.h>
#include <asm/adb.h>
#include <asm/cuda.h>
+#include <asm/pmu.h>
#include <asm/uaccess.h>
#include <asm/hydra.h>
enum adb_hw adb_hardware;
int (*adb_send_request)(struct adb_request *req, int sync);
int (*adb_autopoll)(int on);
+static void adb_scan_bus(void);
static struct adb_handler {
void (*handler)(unsigned char *, int, struct pt_regs *, int);
+ int original_address;
+ int handler_id;
} adb_handler[16];
static int adb_nodev(void)
@@ -29,17 +34,123 @@ static int adb_nodev(void)
return -1;
}
+#if 0
+static void printADBreply(struct adb_request *req)
+{
+ int i;
+
+ printk("adb reply (%d)", req->reply_len);
+ for(i = 0; i < req->reply_len; i++)
+ printk(" %x", req->reply[i]);
+ printk("\n");
+
+}
+#endif
+
+static void adb_scan_bus(void)
+{
+ int i, highFree=0, noMovement;
+ struct adb_request req;
+
+ /* reset ADB bus */
+ /*adb_request(&req, NULL, ADBREQ_SYNC, 1, 0);*/
+
+ /* assumes adb_handler[] is all zeroes at this point */
+ for (i = 1; i < 16; i++) {
+ /* see if there is anything at address i */
+ adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+ (i << 4) | 0xf);
+ if (req.reply_len > 1)
+ /* one or more devices at this address */
+ adb_handler[i].original_address = i;
+ else if (i > highFree)
+ highFree = i;
+ }
+
+ /* Note we reset noMovement to 0 each time we move a device */
+ for (noMovement = 1; noMovement < 2 && highFree > 0; noMovement++) {
+ for (i = 1; i < 16; i++) {
+ if (adb_handler[i].original_address == 0)
+ continue;
+ /*
+ * Send a "talk register 3" command to address i
+ * to provoke a collision if there is more than
+ * one device at this address.
+ */
+ adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+ (i << 4) | 0xf);
+ /*
+ * Move the device(s) which didn't detect a
+ * collision to address `highFree'. Hopefully
+ * this only moves one device.
+ */
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ (i<< 4) | 0xb, (highFree | 0x60), 0xfe);
+ /*
+ * Test whether there are any device(s) left
+ * at address i.
+ */
+ adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+ (i << 4) | 0xf);
+ if (req.reply_len > 1) {
+ /*
+ * There are still one or more devices
+ * left at address i. Register the one(s)
+ * we moved to `highFree', and find a new
+ * value for highFree.
+ */
+ adb_handler[highFree].original_address =
+ adb_handler[i].original_address;
+ while (highFree > 0 &&
+ adb_handler[highFree].original_address)
+ highFree--;
+ if (highFree <= 0)
+ break;
+
+ noMovement = 0;
+ }
+ else {
+ /*
+ * No devices left at address i; move the
+ * one(s) we moved to `highFree' back to i.
+ */
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ (highFree << 4) | 0xb,
+ (i | 0x60), 0xfe);
+ }
+ }
+ }
+
+ /* Now fill in the handler_id field of the adb_handler entries. */
+ printk(KERN_DEBUG "adb devices:");
+ for (i = 1; i < 16; i++) {
+ if (adb_handler[i].original_address == 0)
+ continue;
+ adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+ (i << 4) | 0xf);
+ adb_handler[i].handler_id = req.reply[2];
+ printk(" [%d]: %d %x", i, adb_handler[i].original_address,
+ adb_handler[i].handler_id);
+ }
+ printk("\n");
+}
+
void adb_init(void)
{
adb_hardware = ADB_NONE;
adb_send_request = (void *) adb_nodev;
adb_autopoll = (void *) adb_nodev;
+ if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+ return;
via_cuda_init();
+ via_pmu_init();
macio_adb_init();
if (adb_hardware == ADB_NONE)
printk(KERN_WARNING "Warning: no ADB interface detected\n");
- else
+ else {
+ adb_scan_bus();
adb_autopoll(1);
+ }
}
int
@@ -67,12 +178,25 @@ adb_request(struct adb_request *req, void (*done)(struct adb_request *),
/* Ultimately this should return the number of devices with
the given default id. */
int
-adb_register(int default_id,
+adb_register(int default_id, int handler_id, struct adb_ids *ids,
void (*handler)(unsigned char *, int, struct pt_regs *, int))
{
- if (adb_handler[default_id].handler != 0)
- panic("Two handlers for ADB device %d\n", default_id);
- adb_handler[default_id].handler = handler;
+ int i;
+
+ ids->nids = 0;
+ for (i = 1; i < 16; i++) {
+ if ((adb_handler[i].original_address == default_id) ||
+ (adb_handler[i].handler_id == handler_id)) {
+ if (adb_handler[i].handler != 0) {
+ printk(KERN_ERR
+ "Two handlers for ADB device %d\n",
+ default_id);
+ return 0;
+ }
+ adb_handler[i].handler = handler;
+ ids->id[ids->nids++] = i;
+ }
+ }
return 1;
}
@@ -103,44 +227,40 @@ adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll)
extern void adbdev_init(void);
struct adbdev_state {
- struct adb_request req;
+ spinlock_t lock;
+ atomic_t n_pending;
+ struct adb_request *completed;
+ struct wait_queue *wait_queue;
+ int inuse;
};
-static struct wait_queue *adb_wait;
-
-static int adb_wait_reply(struct adbdev_state *state, struct file *file)
-{
- int ret = 0;
- struct wait_queue wait = { current, NULL };
-
- add_wait_queue(&adb_wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- while (!state->req.complete) {
- if (file->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- ret = -ERESTARTSYS;
- break;
- }
- schedule();
- }
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&adb_wait, &wait);
-
- return ret;
-}
-
static void adb_write_done(struct adb_request *req)
{
+ struct adbdev_state *state = (struct adbdev_state *) req->arg;
+ unsigned long flags;
+
if (!req->complete) {
req->reply_len = 0;
req->complete = 1;
}
- wake_up_interruptible(&adb_wait);
+ spin_lock_irqsave(&state->lock, flags);
+ atomic_dec(&state->n_pending);
+ if (!state->inuse) {
+ kfree(req);
+ if (atomic_read(&state->n_pending) == 0) {
+ spin_unlock_irqrestore(&state->lock, flags);
+ kfree(state);
+ return;
+ }
+ } else {
+ struct adb_request **ap = &state->completed;
+ while (*ap != NULL)
+ ap = &(*ap)->next;
+ req->next = NULL;
+ *ap = req;
+ wake_up_interruptible(&state->wait_queue);
+ }
+ spin_unlock_irqrestore(&state->lock, flags);
}
static int adb_open(struct inode *inode, struct file *file)
@@ -153,20 +273,31 @@ static int adb_open(struct inode *inode, struct file *file)
if (state == 0)
return -ENOMEM;
file->private_data = state;
- state->req.reply_expected = 0;
+ spin_lock_init(&state->lock);
+ atomic_set(&state->n_pending, 0);
+ state->completed = NULL;
+ state->wait_queue = NULL;
+ state->inuse = 1;
+
return 0;
}
static int adb_release(struct inode *inode, struct file *file)
{
struct adbdev_state *state = file->private_data;
+ unsigned long flags;
if (state) {
file->private_data = NULL;
- if (state->req.reply_expected && !state->req.complete)
- if (adb_wait_reply(state, file))
- return 0;
- kfree(state);
+ spin_lock_irqsave(&state->lock, flags);
+ if (atomic_read(&state->n_pending) == 0
+ && state->completed == NULL) {
+ spin_unlock_irqrestore(&state->lock, flags);
+ kfree(state);
+ } else {
+ state->inuse = 0;
+ spin_unlock_irqrestore(&state->lock, flags);
+ }
}
return 0;
}
@@ -181,27 +312,57 @@ static ssize_t adb_read(struct file *file, char *buf,
{
int ret;
struct adbdev_state *state = file->private_data;
+ struct adb_request *req;
+ struct wait_queue wait = { current, NULL };
+ unsigned long flags;
if (count < 2)
return -EINVAL;
- if (count > sizeof(state->req.reply))
- count = sizeof(state->req.reply);
+ if (count > sizeof(req->reply))
+ count = sizeof(req->reply);
ret = verify_area(VERIFY_WRITE, buf, count);
if (ret)
return ret;
- if (!state->req.reply_expected)
- return 0;
+ req = NULL;
+ add_wait_queue(&state->wait_queue, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+
+ for (;;) {
+ spin_lock_irqsave(&state->lock, flags);
+ req = state->completed;
+ if (req != NULL)
+ state->completed = req->next;
+ else if (atomic_read(&state->n_pending) == 0)
+ ret = -EIO;
+ spin_unlock_irqrestore(&state->lock, flags);
+ if (req != NULL || ret != 0)
+ break;
+
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&state->wait_queue, &wait);
- ret = adb_wait_reply(state, file);
if (ret)
return ret;
- state->req.reply_expected = 0;
- ret = state->req.reply_len;
- if (copy_to_user(buf, state->req.reply, ret))
- return -EFAULT;
+ ret = req->reply_len;
+ if (ret > count)
+ ret = count;
+ if (ret > 0 && copy_to_user(buf, req->reply, ret))
+ ret = -EFAULT;
+ kfree(req);
return ret;
}
@@ -210,46 +371,64 @@ static ssize_t adb_write(struct file *file, const char *buf,
{
int ret, i;
struct adbdev_state *state = file->private_data;
+ struct adb_request *req;
- if (count < 2 || count > sizeof(state->req.data))
+ if (count < 2 || count > sizeof(req->data))
return -EINVAL;
ret = verify_area(VERIFY_READ, buf, count);
if (ret)
return ret;
- if (state->req.reply_expected && !state->req.complete) {
- /* A previous request is still being processed.
- Wait for it to finish. */
- ret = adb_wait_reply(state, file);
- if (ret)
- return ret;
- }
+ req = (struct adb_request *) kmalloc(sizeof(struct adb_request),
+ GFP_KERNEL);
+ if (req == NULL)
+ return -ENOMEM;
- state->req.nbytes = count;
- state->req.done = adb_write_done;
- state->req.complete = 0;
- if (copy_from_user(state->req.data, buf, count))
- return -EFAULT;
+ req->nbytes = count;
+ req->done = adb_write_done;
+ req->arg = (void *) state;
+ req->complete = 0;
+ ret = -EFAULT;
+ if (copy_from_user(req->data, buf, count))
+ goto out;
+
+ atomic_inc(&state->n_pending);
switch (adb_hardware) {
case ADB_NONE:
- return -ENXIO;
+ ret = -ENXIO;
+ break;
case ADB_VIACUDA:
- state->req.reply_expected = 1;
- cuda_send_request(&state->req);
+ req->reply_expected = 1;
+ ret = cuda_send_request(req);
break;
+ case ADB_VIAPMU:
+ if (req->data[0] != ADB_PACKET) {
+ ret = pmu_send_request(req);
+ break;
+ }
+ /* else fall through */
default:
- if (state->req.data[0] != ADB_PACKET)
- return -EINVAL;
- for (i = 1; i < state->req.nbytes; ++i)
- state->req.data[i] = state->req.data[i+1];
- state->req.reply_expected =
- ((state->req.data[0] & 0xc) == 0xc);
- adb_send_request(&state->req, 0);
+ ret = -EINVAL;
+ if (req->data[0] != ADB_PACKET)
+ break;
+ for (i = 0; i < req->nbytes-1; ++i)
+ req->data[i] = req->data[i+1];
+ req->nbytes--;
+ req->reply_expected = ((req->data[0] & 0xc) == 0xc);
+ ret = adb_send_request(req, 0);
break;
}
+ if (ret != 0) {
+ atomic_dec(&state->n_pending);
+ goto out;
+ }
return count;
+
+out:
+ kfree(req);
+ return ret;
}
static struct file_operations adb_fops = {
@@ -266,6 +445,8 @@ static struct file_operations adb_fops = {
void adbdev_init()
{
+ if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+ return;
if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
}
diff --git a/drivers/macintosh/ati-gx.h b/drivers/macintosh/ati-gx.h
index b986cc38e..df48c1865 100644
--- a/drivers/macintosh/ati-gx.h
+++ b/drivers/macintosh/ati-gx.h
@@ -1,64 +1,37 @@
-#if 0 /* not filled inaty_gt_reg_init yet */
-/* Register values for 1280x1024, 75Hz mode (20) */
+/* Register values for 1280x1024, 75Hz (WAS 60) mode (20) */
static struct aty_regvals aty_gx_reg_init_20 = {
- { 0x10, 0x28, 0x3c },
- { },
- { } /* pixel clock = 134.61MHz for V=74.81Hz */
-};
+ { 0x200, 0x200, 0x200 },
-/* Register values for 1280x960, 75Hz mode (19) */
-static struct aty_regvals aty_gx_reg_init_19 = {
- { 0x10, 0x28, 0x3c },
- { },
- { } /* pixel clock = 126.01MHz for V=75.01 Hz */
-};
+ { 0x1200a5, 0x1200a3, 0x1200a3 },
+ { 0x30c0200, 0x30e0300, 0x30e0300 },
+ { 0x2, 0x3, 0x3 },
+
+ 0x9f00d2, 0x3ff0429, 0x30400, 0x28100040,
+ { 0xd4, 0x9 }
+};
/* Register values for 1152x870, 75Hz mode (18) */
static struct aty_regvals aty_gx_reg_init_18 = {
- { 0x10, 0x28, 0x50 },
- { },
- { } /* pixel clock = 100.33MHz for V=75.31Hz */
-};
+ { 0x200, 0x200, 0x200 },
-/* Register values for 1024x768, 75Hz mode (17) */
-static struct aty_regvals aty_gx_reg_init_17 = {
- { 0x10, 0x28, 0x50 },
- { },
- { } /* pixel clock = 79.55MHz for V=74.50Hz */
-};
+ { 0x300097, 0x300095, 0x300094 },
+ { 0x3090200, 0x30e0300, 0x30e0600 },
+ { 0x2, 0x3, 0x6 },
-/* Register values for 1024x768, 72Hz mode (15) */
-static struct aty_regvals aty_gx_reg_init_15 = {
- { 0x10, 0x28, 0x50 },
- { },
- { } /* pixel clock = 78.12MHz for V=72.12Hz */
+ 0x8f00b5, 0x3650392, 0x230368, 0x24100040,
+ { 0x53, 0x3 }
};
-#endif
-
-
-/* Register values for 1280x1024, 60Hz mode (20) */
-static struct aty_regvals aty_gx_reg_init_20 = {
- { 0, 0, 0 },
-
- { 0x310086, 0x310084, 0x310084 },
- { 0x3070200, 0x30e0300, 0x30e0300 },
- { 0x2002312, 0x3002312, 0x3002312 },
-
- 0x7f00a5, 0x2ff0325, 0x260302, 0x20100000,
- { 0x88, 0x7 }
-};
-
/* Register values for 1024x768, 75Hz mode (17) */
static struct aty_regvals aty_gx_reg_init_17 = {
- { 0, 0, 0 },
+ { 0x200, 0x200, 0x200 },
- { 0xc0085, 0xc0083, 0xc0083 },
- { 0x3070200, 0x30e0300, 0x30e0300 },
- { 0x2002312, 0x3002312, 0x3002312 },
+ { 0x2c0087, 0x2c0085, 0x2c0084 },
+ { 0x3070200, 0x30e0300, 0x30e0600 },
+ { 0x2, 0x3, 0x6 },
- 0x7f00a3, 0x2ff031f, 0x30300, 0x20100000,
- { 0x41, 0x3 }
+ 0x7f00a5, 0x2ff0323, 0x230302, 0x20100000,
+ { 0x42, 0x3 }
};
/* Register values for 1024x768, 72Hz mode (15) */
@@ -87,14 +60,14 @@ static struct aty_regvals aty_gx_reg_init_14 = {
/* Register values for 832x624, 75Hz mode (13) */
static struct aty_regvals aty_gx_reg_init_13 = {
- { 0x200, 0x200, 0x200 },
+ { 0x200, 0x200, 0x200 },
- { 0x28006f, 0x28006d, 0x28006c },
- { 0x3050200, 0x30b0300, 0x30e0600 },
- { 0x2002312, 0x3002312, 0x6002312 },
+ { 0x28006f, 0x28006d, 0x28006c },
+ { 0x3050200, 0x30b0300, 0x30e0600 },
+ { 0x2, 0x3, 0x6 },
- 0x67008f, 0x26f029a, 0x230270, 0x1a100040,
- { 0x4f, 0x05 }
+ 0x67008f, 0x26f029a, 0x230270, 0x1a100040,
+ { 0x4f, 0x5 }
};
#if 0 /* not filled in yet */
diff --git a/drivers/macintosh/aty.c b/drivers/macintosh/aty.c
index ec70b4a50..7bd48052b 100644
--- a/drivers/macintosh/aty.c
+++ b/drivers/macintosh/aty.c
@@ -18,12 +18,12 @@
#include <linux/string.h>
#include <linux/vc_ioctl.h>
#include <linux/pci.h>
-#include <linux/bios32.h>
#include <linux/nvram.h>
#include <linux/selection.h>
#include <linux/vt_kern.h>
#include <asm/prom.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
#include <asm/pci-bridge.h>
#include "pmac-cons.h"
#include "aty.h"
@@ -61,10 +61,12 @@ static int aty_vram_reqd(int vmode, int cmode);
static aty_regvals *get_aty_struct(void);
static unsigned char *frame_buffer;
+static unsigned long frame_buffer_phys;
static int total_vram; /* total amount of video memory, bytes */
static int chip_type; /* what chip type was detected */
static unsigned long ati_regbase;
+static unsigned long ati_regbase_phys;
static struct aty_cmap_regs *aty_cmap_regs;
#if 0
@@ -126,7 +128,8 @@ static struct aty_regvals *aty_gx_reg_init[20] = {
&aty_gx_reg_init_15,
NULL,
&aty_gx_reg_init_17,
- NULL, NULL,
+ &aty_gx_reg_init_18,
+ NULL,
&aty_gx_reg_init_20
};
@@ -323,7 +326,8 @@ map_aty_display(struct device_node *dp)
printk("Warning: expecting 1 or 3 addresses for ATY (got %d)",
dp->n_addrs);
- ati_regbase = (int) ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000);
+ ati_regbase_phys = 0x7ffc00 + dp->addrs[0].address;
+ ati_regbase = (int) ioremap(ati_regbase_phys, 0x1000);
aty_cmap_regs = (struct aty_cmap_regs *) (ati_regbase + 0xC0);
/* enable memory-space accesses using config-space command register */
@@ -384,12 +388,12 @@ map_aty_display(struct device_node *dp)
total_vram = 0x80000;
}
-#if 1
+#if 0
printk("aty_display_init: node = %p, addrs = ", dp->node);
printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size);
printk(", intrs =");
for (i = 0; i < dp->n_intrs; ++i)
- printk(" %x", dp->intrs[i]);
+ printk(" %x", dp->intrs[i].line);
printk("\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %x\n", (int) ati_regbase,
bus, devfn, total_vram, (int) aty_cmap_regs);
#endif
@@ -398,10 +402,11 @@ map_aty_display(struct device_node *dp)
/* use the big-endian aperture (??) */
addr += 0x800000;
- frame_buffer = ioremap(addr, 0x800000);
+ frame_buffer_phys = addr;
+ frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU);
sense = read_aty_sense();
- printk("monitor sense = %x\n", sense);
+ printk(KERN_INFO "monitor sense = %x\n", sense);
if (video_mode == VMODE_NVRAM) {
video_mode = nvram_read_byte(NV_VMODE);
init = get_aty_struct();
@@ -720,11 +725,11 @@ aty_init()
break;
}
display_info.fb_address = (chip_type != MACH64_GT_ID) ?
- (unsigned long) frame_buffer + init->offset[color_mode] :
- (unsigned long) frame_buffer;
- display_info.cmap_adr_address = (unsigned long) &aty_cmap_regs->windex;
- display_info.cmap_data_address = (unsigned long) &aty_cmap_regs->lut;
- display_info.disp_reg_address = ati_regbase;
+ frame_buffer_phys + init->offset[color_mode] :
+ frame_buffer_phys;
+ display_info.cmap_adr_address = ati_regbase_phys + 0xc0;
+ display_info.cmap_data_address = ati_regbase_phys + 0xc1;
+ display_info.disp_reg_address = ati_regbase_phys;
}
int
diff --git a/drivers/macintosh/chips.c b/drivers/macintosh/chips.c
index d959608cb..d60abe84f 100644
--- a/drivers/macintosh/chips.c
+++ b/drivers/macintosh/chips.c
@@ -14,10 +14,13 @@
#include <linux/string.h>
#include <linux/vc_ioctl.h>
#include <linux/pci.h>
-#include <linux/bios32.h>
#include <linux/selection.h>
#include <asm/prom.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/adb.h>
+#include <asm/cuda.h>
+#include <asm/pmu.h>
#include <asm/pci-bridge.h>
#include "pmac-cons.h"
#include "chips.h"
@@ -26,6 +29,8 @@
static unsigned char *frame_buffer;
static unsigned char *blitter_regs;
static unsigned char *io_space;
+static unsigned long chips_base_phys;
+static unsigned long chips_io_phys;
void
map_chips_display(struct device_node *dp)
@@ -35,17 +40,21 @@ map_chips_display(struct device_node *dp)
unsigned long addr;
addr = dp->addrs[0].address;
- frame_buffer = ioremap(addr + 0x800000, 0x100000);
+ chips_base_phys = addr;
+ frame_buffer = __ioremap(addr + 0x800000, 0x100000, _PAGE_WRITETHRU);
blitter_regs = ioremap(addr + 0xC00000, 4096);
- printk("Mapped chips65550 frame buffer at %p, blitter at %p\n", frame_buffer, blitter_regs);
+ printk("Mapped chips65550 frame buffer at %p, blitter at %p\n",
+ frame_buffer, blitter_regs);
if (pci_device_loc(dp, &bus, &devfn) == 0) {
pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
cmd |= 3; // enable memory and IO space
pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
- io_space = ioremap((unsigned long) pci_io_base(bus), 4096);
- printk("Mapped chips65550 IO space at %p\n", io_space);
+ io_space = (unsigned char *) pci_io_base(bus);
+ /* XXX really want the physical address here */
+ chips_io_phys = (unsigned long) pci_io_base(bus);
+ printk("Chips65550 IO space at %p\n", io_space);
}
video_mode = VMODE_800_600_60;
@@ -65,11 +74,15 @@ chips_init()
unsigned *p;
int i, hres;
- if (video_mode != VMODE_800_600_60)
- panic("chips65550: display mode %d not supported", video_mode);
+ if (video_mode != VMODE_800_600_60) {
+ printk(KERN_ERR "chips65550: display mode %d not supported", video_mode);
+ video_mode = VMODE_800_600_60;
+ }
- if (color_mode != CMODE_8 && color_mode != CMODE_16)
- panic("chips65550: color mode %d not supported", color_mode);
+ if (color_mode != CMODE_8 && color_mode != CMODE_16) {
+ printk(KERN_ERR "chips65550: color mode %d not supported", color_mode);
+ color_mode = CMODE_8;
+ }
n_scanlines = 600;
hres = 800;
@@ -106,15 +119,18 @@ chips_init()
display_info.pitch = line_pitch;
display_info.mode = video_mode;
strncpy(display_info.name, "chips65550", sizeof(display_info.name));
- display_info.fb_address = (unsigned long) frame_buffer;
- display_info.cmap_adr_address = 0;
- display_info.cmap_data_address = 0;
- display_info.disp_reg_address = 0;
+ display_info.fb_address = chips_base_phys + 0x800000;
+ display_info.cmap_adr_address = chips_io_phys + 0x3c8;
+ display_info.cmap_data_address = chips_io_phys + 0x3c9;
+ display_info.disp_reg_address = chips_base_phys + 0xC00000;
/* Clear screen */
p = (unsigned *) frame_buffer;
for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
*p++ = 0;
+
+ /* Turn on backlight */
+ pmu_enable_backlight(1);
}
int
@@ -164,4 +180,5 @@ chips_set_palette(unsigned char red[], unsigned char green[],
void
chips_set_blanking(int blank_mode)
{
+ pmu_enable_backlight(blank_mode == VESA_NO_BLANKING);
}
diff --git a/drivers/macintosh/control.c b/drivers/macintosh/control.c
index 4f6e6c84b..9db048a4a 100644
--- a/drivers/macintosh/control.c
+++ b/drivers/macintosh/control.c
@@ -18,6 +18,7 @@
#include <asm/io.h>
#include <asm/adb.h>
#include <asm/cuda.h>
+#include <asm/pgtable.h>
#include <linux/selection.h>
#include "pmac-cons.h"
#include "control.h"
@@ -88,6 +89,10 @@ static struct cmap_regs *cmap_regs;
static struct control_regs *disp_regs;
static int control_use_bank2;
+static unsigned long frame_buffer_phys;
+static unsigned long disp_regs_phys;
+static unsigned long cmap_regs_phys;
+
/*
* Register initialization tables for the control display.
*
@@ -317,7 +322,7 @@ map_control_display(struct device_node *dp)
printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size);
printk(", intrs =");
for (i = 0; i < dp->n_intrs; ++i)
- printk(" %x", dp->intrs[i]);
+ printk(" %x", dp->intrs[i].line);
printk("\n");
#endif
@@ -329,12 +334,15 @@ map_control_display(struct device_node *dp)
/* use the big-endian aperture (??) */
addr += 0x800000;
/* map at most 8MB for the frame buffer */
- frame_buffer = ioremap(addr, 0x800000);
+ frame_buffer_phys = addr;
+ frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU);
} else {
+ disp_regs_phys = addr;
disp_regs = ioremap(addr, size);
}
}
- cmap_regs = ioremap(0xf301b000, 0x1000); /* XXX not in prom? */
+ cmap_regs_phys = 0xf301b000; /* XXX not in prom? */
+ cmap_regs = ioremap(cmap_regs_phys, 0x1000);
/* Work out which banks of VRAM we have installed. */
frame_buffer[0] = 0x5a;
@@ -454,10 +462,10 @@ control_init()
display_info.pitch = line_pitch;
display_info.mode = video_mode;
strncpy(display_info.name, "control", sizeof(display_info.name));
- display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode];
- display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
- display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
- display_info.disp_reg_address = (unsigned long) &disp_regs;
+ display_info.fb_address = frame_buffer_phys + init->offset[color_mode];
+ display_info.cmap_adr_address = cmap_regs_phys;
+ display_info.cmap_data_address = cmap_regs_phys + 0x30;
+ display_info.disp_reg_address = disp_regs_phys;
}
int
diff --git a/drivers/macintosh/imstt.c b/drivers/macintosh/imstt.c
index 2f74a153c..0cf18edc7 100644
--- a/drivers/macintosh/imstt.c
+++ b/drivers/macintosh/imstt.c
@@ -2,28 +2,39 @@
* imstt.c: Console support for PowerMac "imstt" display adaptor.
*
* Copyright (C) 1997 Sigurdur Asgeirsson
+ * Modified by Danilo Beuche 1997
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/module.h>
+
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/vc_ioctl.h>
#include <linux/pci.h>
-#include <linux/bios32.h>
#include <linux/nvram.h>
#include <asm/prom.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
#include <asm/pci-bridge.h>
#include <linux/selection.h>
#include <linux/vt_kern.h>
#include "pmac-cons.h"
#include "imstt.h"
+
+enum {
+ IBMRAMDAC = 0x00,
+ TVPRAMDAC = 0x01
+};
+
+
+// IMS TWIN TURBO
enum
{
S1SA = 0, /* 0x00 */
@@ -79,6 +90,8 @@ enum
#endif
};
+
+// IBM RAMDAC
enum
{
PADDRW = 0x00,
@@ -97,12 +110,256 @@ enum
PC0 = 0x23
};
+// TI TVP 3030 RAMDAC Direct Registers
+enum
+{
+ TVPADDRW = 0x00, // 0 Palette/Cursor RAM Write Adress/Index
+ TVPPDATA = 0x04, // 1 Palette Data RAM Data
+ TVPPMASK = 0x08, // 2 Pixel Read-Mask
+ TVPPADRR = 0x0c, // 3 Palette/Cursor RAM Read Adress
+ TVPCADRW = 0x10, // 4 Cursor/Overscan Color Write Address
+ TVPCDATA = 0x14, // 5 Cursor/Overscan Color Data
+ // 6 reserved
+ TVPCADRR = 0x1c, // 7 Cursor/Overscan Color Read Address
+ // 8 reserved
+ TVPDCCTL = 0x24, // 9 Direct Cursor Control
+ TVPIDATA = 0x28, // 10 Index Data
+ TVPCRDAT = 0x2c, // 11 Cursor RAM Data
+ TVPCXPOL = 0x30, // 12 Cursor-Position X LSB
+ TVPCXPOH = 0x34, // 13 Cursor-Position X MSB
+ TVPCYPOL = 0x38, // 14 Cursor-Position Y LSB
+ TVPCYPOH = 0x3c, // 15 Cursor-Position Y MSB
+};
+
+// TI TVP 3030 RAMDAC Indirect Registers
+enum
+{
+ TVPIRREV = 0x01, // Silicon Revision [RO]
+ TVPIRICC = 0x06, // Indirect Cursor Control (0x00)
+ TVPIRBRC = 0x07, // Byte Router Control (0xe4)
+ TVPIRLAC = 0x0f, // Latch Control (0x06)
+ TVPIRTCC = 0x18, // True Color Control (0x80)
+ TVPIRMXC = 0x19, // Multiplex Control (0x98)
+ TVPIRCLS = 0x1a, // Clock Selection (0x07)
+ TVPIRPPG = 0x1c, // Palette Page (0x00)
+ TVPIRGEC = 0x1d, // General Control (0x00)
+ TVPIRMIC = 0x1e, // Miscellaneous Control (0x00)
+ TVPIRPLA = 0x2c, // PLL Address
+ TVPIRPPD = 0x2d, // Pixel Clock PLL Data
+ TVPIRMPD = 0x2e, // Memory Clock PLL Data
+ TVPIRLPD = 0x2f, // Loop Clock PLL Data
+ TVPIRCKL = 0x30, // Color-Key Overlay Low
+ TVPIRCKH = 0x31, // Color-Key Overlay High
+ TVPIRCRL = 0x32, // Color-Key Red Low
+ TVPIRCRH = 0x33, // Color-Key Red High
+ TVPIRCGL = 0x34, // Color-Key Green Low
+ TVPIRCGH = 0x35, // Color-Key Green High
+ TVPIRCBL = 0x36, // Color-Key Blue Low
+ TVPIRCBH = 0x37, // Color-Key Blue High
+ TVPIRCKC = 0x38, // Color-Key Control (0x00)
+ TVPIRMLC = 0x39, // MCLK/Loop Clock Control (0x18)
+ TVPIRSEN = 0x3a, // Sense Test (0x00)
+ TVPIRTMD = 0x3b, // Test Mode Data
+ TVPIRRML = 0x3c, // CRC Remainder LSB [RO]
+ TVPIRRMM = 0x3d, // CRC Remainder MSB [RO]
+ TVPIRRMS = 0x3e, // CRC Bit Select [WO]
+ TVPIRDID = 0x3f, // Device ID [RO] (0x30)
+ TVPIRRES = 0xff, // Software Reset [WO]
+
+};
+
struct initvalues
{
unsigned char addr, value;
};
-static struct initvalues initregs[] =
+
+
+// Values which only depend on resolution not on color mode
+struct tt_single_rmodevals
+{
+ unsigned short hes;
+ unsigned short heb;
+ unsigned short hsb;
+ unsigned short ht;
+ unsigned short ves;
+ unsigned short veb;
+ unsigned short vsb;
+ unsigned short vt;
+};
+
+struct tvp_single_rmodevals
+{
+ unsigned char pclk_n;
+ unsigned char pclk_m;
+ unsigned char pclk_p;
+};
+
+struct ibm_single_rmodevals
+{
+ unsigned char pclk_m;
+ unsigned char pclk_n;
+ unsigned char pclk_p;
+ unsigned char pclk_c;
+};
+
+// Values which only depend on color mode not on resolution
+struct tvp_single_cmodevals
+{
+ unsigned char tcc; // True Color control
+ unsigned char mxc; // Multiplexer control
+ unsigned char lckl_n; // N value of LCKL PLL
+};
+
+struct ibm_single_cmodevals
+{
+ unsigned char pformat; // pixel format
+};
+
+// Values of the tvp which change depending on colormode x resolution
+struct tvp_single_crmodevals
+{
+ unsigned char mlc; // Memory Loop Config 0x39
+ unsigned char lckl_p; // P value of LCKL PLL
+};
+
+struct ibm_single_crmodevals
+{
+ // oh nothing changes
+};
+
+// complete configuration for a resolution in all depths
+// 0 = 8 Bit, 15/16 bit = 1 , 32 Bit = 2
+struct ims_crmodevals
+{
+ int pitch;
+ struct tt_single_rmodevals tt[2]; // for each ramdac seperate tt config
+
+ struct tvp_single_rmodevals tvp_clock; // for each ramdac seperate clock config
+ struct tvp_single_crmodevals tvp[3]; // for each colormode
+
+ struct ibm_single_rmodevals ibm_clock; // for each ramdac seperate clock config
+// struct ibm_single_crmodevals ibm[3]; // for each color mode
+};
+
+struct ims_modevals
+{
+ int dac; // which dac do we have
+ int total_vram; // how much vram is on board
+ int sense; // what monitor
+ unsigned char* fb; // frame buffer address
+ unsigned char* fb_phys; // frame buffer address
+ unsigned char* cmap; // dac address
+ unsigned char* cmap_phys; // dac address
+ unsigned int* dc; // tt address
+ unsigned int* dc_phys; // tt address
+
+ struct initvalues* init[2]; // initial register settings for each ramdac
+
+ struct ims_crmodevals* mode[20]; // for each possible mode
+
+ struct tvp_single_cmodevals tvp[3]; // for each color mode
+
+ struct ibm_single_cmodevals ibm[3]; // for each color mode
+};
+
+
+struct ims_crmodevals imsmode_6 =
+{
+ 640,
+ {
+ { 0x08, 0x12, 0x62, 0x6C, 0x0003, 0x002A, 0x020A, 0x020C },
+ { 0x04, 0x0009, 0x0031, 0x0036, 0x0003, 0x002a, 0x020a, 0x020d },
+ },
+ { 0xef, 0x2e, 0xb2 },
+ {
+ { 0x39, 0xf3 },
+ { 0x39, 0xf3 },
+ { 0x38, 0xf3 }
+ },
+ // IBM CLOCK
+ { 0x78, 0x13, 0x02, 0x02 },
+};
+
+struct ims_crmodevals imsmode_13 =
+{
+ 832,
+ {
+ { 0x05, 0x20, 0x88, 0x90, 0x0003, 0x0028, 0x0298, 0x029B },
+ { 0x04, 0x0011, 0x0045, 0x0048, 0x0003, 0x002a, 0x029a, 0x029b},
+ },
+ { 0xfe, 0x3e, 0xf1 },
+ {
+ { 0x39, 0xf3 },
+ { 0x38, 0xf3 },
+ { 0x38, 0xf2 }
+ },
+ { 0x3E, 0x0A, 0x01, 0x02 }
+};
+struct ims_crmodevals imsmode_17 =
+{
+ 1024,
+ {
+ { 0x0A, 0x1C, 0x9C, 0xA6, 0x0003, 0x0020, 0x0320, 0x0323 } ,
+ { 0x06, 0x0210, 0x0250, 0x0053, 0x1003, 0x0021, 0x0321, 0x0324 },
+ },
+ { 0xfc, 0x3a, 0xf1 },
+ {
+ { 0x39, 0xf3 },
+ { 0x38, 0xf3 },
+ { 0x38, 0xf2 }
+ },
+ { 0x07, 0x00, 0x01, 0x02 }
+};
+struct ims_crmodevals imsmode_18 =
+{
+ 1152,
+ {
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x09, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a },
+ },
+ { 0xfd, 0x3a, 0xf1 },
+ {
+ { 0x39, 0xf3 },
+ { 0x38, 0xf3 },
+ { 0x38, 0xf2 }
+ },
+ { 0, 0, 0, 0 }
+};
+struct ims_crmodevals imsmode_19 =
+{
+ 1280,
+ {
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x09, 0x0016, 0x0066, 0x0069, 0x0003, 0x0027, 0x03e7, 0x03e8 },
+ },
+ { 0xf7, 0x36, 0xf0 },
+ {
+ { 0x38, 0xf3 },
+ { 0x38, 0xf2 },
+ { 0x38, 0xf1 }
+ },
+ { 0, 0, 0, 0 }
+};
+struct ims_crmodevals imsmode_20 =
+{
+ 1280,
+ {
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x09, 0x0018, 0x0068, 0x006a, 0x0003, 0x0029, 0x0429, 0x042a },
+ },
+ { 0xf0, 0x2d, 0xf0 },
+ {
+ { 0x38, 0xf3 },
+ { 0x38, 0xf2 },
+ { 0x38, 0xf1 }
+ },
+ { 0, 0, 0, 0 }
+};
+
+// IBM RAMDAC initial register values
+
+static struct initvalues ibm_initregs[] =
{
{ 0x02, 0x21 }, /* (0x01) Miscellaneous Clock Control */
{ 0x03, 0x00 }, /* (0x00) Sync Control */
@@ -129,64 +386,114 @@ static struct initvalues initregs[] =
{ 0x71, 0x45 }, /* (0x00) Miscellaneous Control 2 */
{ 0x72, 0x00 }, /* (0x00) Miscellaneous Control 3 */
{ 0x78, 0x00 }, /* (0x00) Key Control/DB Operation */
+ { 0x00, 0x00 }
};
-static void set_imstt_clock(unsigned char *params);
-static int read_imstt_sense(void);
-static int imstt_vram_reqd(int vmode, int cmode);
-static int total_vram = 2 * 1024 * 1024; /* total amount of video memory, bytes */
-static unsigned char *frame_buffer;
-static unsigned char *cmap_regs;
-static unsigned *dc_regs;
+static struct initvalues tvp_initregs[] =
+{
+{ 0x6, 0x00},
+{ 0x7, 0xe4},
+{ 0xf, 0x06},
+{ 0x18, 0x80},
+{ 0x19, 0x4d},
+{ 0x1a, 0x05},
+{ 0x1c, 0x00},
+{ 0x1d, 0x00},
+{ 0x1e, 0x08},
+{ 0x30, 0xff},
+{ 0x31, 0xff},
+{ 0x32, 0xff},
+{ 0x33, 0xff},
+{ 0x34, 0xff},
+{ 0x35, 0xff},
+{ 0x36, 0xff},
+{ 0x37, 0xff},
+{ 0x38, 0x00},
+{ TVPIRPLA, 0x00 },
+{ TVPIRPPD, 0xc0 },
+{ TVPIRPPD, 0xd5 },
+{ TVPIRPPD, 0xea },
+{ TVPIRPLA, 0x00 },
+{ TVPIRMPD, 0xb9 },
+{ TVPIRMPD, 0x3a },
+{ TVPIRMPD, 0xb1 },
+{ TVPIRPLA, 0x00 },
+{ TVPIRLPD, 0xc1 },
+{ TVPIRLPD, 0x3d },
+{ TVPIRLPD, 0xf3 },
+{ 0x00, 0x00 }
+};
-/*
- * Register initialization tables for the imstt display.
- *
- * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
- * where m = clk[0], n = clk[1], p = clk[2]
- * clk[3] is c, charge pump bias which depends on the VCO frequency
- */
-struct imstt_regvals {
- unsigned short cfg[8];
- unsigned char clk[4];
- unsigned long pitch[3];
-} imsttmode;
-
-/* Register values for 1024x768, 75Hz mode (17) */
-static struct imstt_regvals imstt_reg_init_17 = {
- { 0x0A, 0x1C, 0x9C, 0xA6, 0x0003, 0x0020, 0x0320, 0x0323 },
- { 0x07, 0x00, 0x01, 0x02 },
- { 0x0400, 0x0800, 0x1000 }
-};
+static struct ims_modevals ims_info =
+{
+ -1, // DAC
+ -1, // VRAM
+ -1, // Monitor;
+ 0, // Framebuffer
+ 0, // Framebuffer_phys
+ 0, // colormap
+ 0, // colormap_phys
+ 0, // dc
+ 0, // dc_phys
+ { ibm_initregs, tvp_initregs},
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &imsmode_6,
+ &imsmode_6,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &imsmode_13,
+ NULL,
+ NULL,
+ NULL,
+ &imsmode_17,
+ &imsmode_18,
+ &imsmode_19,
+ &imsmode_20
+ },
+ {
+ { 0x80, 0x4d, 0xc1 },
+ { 0x44, 0x55, 0xe1 },
+ { 0x46, 0x5d, 0xf1 }
+ },
+ {
+ { 0x03 },
+ { 0x04 },
+ { 0x06 }
+ }
+};
+
+
-/* Register values for 832x624, 75Hz mode (13) */
-static struct imstt_regvals imstt_reg_init_13 = {
- { 0x05, 0x20, 0x88, 0x90, 0x0003, 0x0028, 0x0298, 0x029B },
- { 0x3E, 0x0A, 0x01, 0x02 },
- { 832, 832 * 2, 832 * 4 }
-};
-/* Register values for 640x480, 67Hz mode (6) */
-static struct imstt_regvals imstt_reg_init_6 = {
- { 0x08, 0x12, 0x62, 0x6C, 0x0003, 0x002A, 0x020A, 0x020C },
- { 0x78, 0x13, 0x02, 0x02 },
- { 640, 640 * 2, 640 * 4 }
-};
+// static void set_imstt_clock(unsigned char *params);
+static void map_imstt_display(struct device_node *, int);
+static int read_imstt_sense(void);
+static int imstt_vram_reqd(int vmode, int cmode);
-static struct imstt_regvals *imstt_reg_init[20] = {
- NULL, NULL, NULL, NULL,
- &imstt_reg_init_6, // fake'm out
- &imstt_reg_init_6,
- NULL, NULL, NULL,
- NULL, NULL, NULL,
- &imstt_reg_init_13,
- NULL, NULL, NULL,
- &imstt_reg_init_17,
- NULL, NULL, NULL
-};
+#if 0
+static int get_tvp_ireg(int iaddr)
+{
+ ims_info.cmap[0] = iaddr & 0xff; eieio();
+ return ims_info.cmap[40];
+}
+#endif
+
+static void set_tvp_ireg(int iaddr,unsigned char value)
+{
+ ims_info.cmap[0] = iaddr & 0xff; eieio();
+ ims_info.cmap[40] = value; eieio();
+}
/*
* Get the monitor sense value.
* Note that this can be called before calibrate_delay,
@@ -199,28 +506,28 @@ read_imstt_sense()
int sense;
unsigned gio, gioe;
- gio = ld_le32(dc_regs + GIO) & ~0x0038;
+ gio = ld_le32(ims_info.dc + GIO) & ~0x0038;
gioe = ld_le32(dc_
- out_le32(dc_regs + GIOE, reg); /* drive all lines high */
+ out_le32(ims_info.dc + GIOE, reg); /* drive all lines high */
__delay(200);
- out_le32(dc_regs + GIOE, 077); /* turn off drivers */
+ out_le32(ims_info.dc + GIOE, 077); /* turn off drivers */
__delay(2000);
- sense = (in_le32(dc_regs + GIOE) & 0x1c0) << 2;
+ sense = (in_le32(ims_info.dc + GIOE) & 0x1c0) << 2;
/* drive each sense line low in turn and collect the other 2 */
- out_le32(dc_regs + GIOE, 033); /* drive A low */
+ out_le32(ims_info.dc + GIOE, 033); /* drive A low */
__delay(2000);
- sense |= (in_le32(dc_regs + GIOE) & 0xc0) >> 2;
- out_le32(dc_regs + GIOE, 055); /* drive B low */
+ sense |= (in_le32(ims_info.dc + GIOE) & 0xc0) >> 2;
+ out_le32(ims_info.dc + GIOE, 055); /* drive B low */
__delay(2000);
- sense |= ((in_le32(dc_regs + GIOE) & 0x100) >> 5)
- | ((in_le32(dc_regs + GIOE) & 0x40) >> 4);
- out_le32(dc_regs + GIOE, 066); /* drive C low */
+ sense |= ((in_le32(ims_info.dc + GIOE) & 0x100) >> 5)
+ | ((in_le32(ims_info.dc + GIOE) & 0x40) >> 4);
+ out_le32(ims_info.dc + GIOE, 066); /* drive C low */
__delay(2000);
- sense |= (in_le32(dc_regs + GIOE) & 0x180) >> 7;
+ sense |= (in_le32(ims_info.dc + GIOE) & 0x180) >> 7;
- out_le32(dc_regs + GIOE, 077); /* turn off drivers */
+ out_le32(ims_info.dc + GIOE, 077); /* turn off drivers */
return sense;
#else
return 0;
@@ -229,12 +536,24 @@ read_imstt_sense()
static inline int imstt_vram_reqd(int vmode, int cmode)
{
- return vmode_attrs[vmode-1].vres
- * imstt_reg_init[vmode-1]->pitch[cmode];
+ return vmode_attrs[vmode-1].vres *
+ (ims_info.mode[vmode-1])->pitch * ( 1 << cmode);
+}
+
+void
+map_imstt_display_tvp(struct device_node *dp)
+{
+ map_imstt_display(dp,1);
}
void
-map_imstt_display(struct device_node *dp)
+map_imstt_display_ibm(struct device_node *dp)
+{
+ map_imstt_display(dp,0);
+}
+
+static void
+map_imstt_display(struct device_node *dp, int which)
{
int i, sense;
unsigned long addr, size, tmp;
@@ -244,7 +563,7 @@ map_imstt_display(struct device_node *dp)
if (dp->next != 0)
printk("Warning: only using first imstt display device\n");
-#if 1
+#if 0
printk("pmac_display_init: node = %p, addrs =", dp->node);
for (i = 0; i < dp->n_addrs; ++i)
printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size);
@@ -259,12 +578,14 @@ map_imstt_display(struct device_node *dp)
addr = dp->addrs[i].address;
size = dp->addrs[i].size;
if (size >= 0x02000000) {
- frame_buffer = ioremap(addr, size);
- dc_regs = (unsigned*)(frame_buffer + 0x00800000);
- cmap_regs = (unsigned char*)(frame_buffer + 0x00840000);
-
- printk("mapped frame_buffer=%x(%x)", (unsigned)frame_buffer, (unsigned)size);
- printk(" dc_regs=%x, cmap_regs=%x\n", (unsigned)dc_regs, (unsigned)cmap_regs);
+ ims_info.fb = __ioremap(addr, size, _PAGE_NO_CACHE);
+ ims_info.fb_phys = (unsigned char*)addr;
+ ims_info.dc = (unsigned*)(ims_info.fb + 0x00800000);
+ ims_info.dc_phys = (unsigned*)(ims_info.fb_phys + 0x00800000);
+ ims_info.cmap = (unsigned char*)(ims_info.fb + 0x00840000);
+ ims_info.cmap_phys = (unsigned char*)(ims_info.fb_phys + 0x00840000);
+ printk("mapped ims_info.fb=%x(%x)", (unsigned)ims_info.fb, (unsigned)size);
+ printk(" ims_info.dc=%x, ims_info.cmap=%x\n", (unsigned)ims_info.dc, (unsigned)ims_info.cmap);
}
}
@@ -282,12 +603,28 @@ map_imstt_display(struct device_node *dp)
else
printk("unable to find pci device\n");
- tmp = in_le32(dc_regs + SSTATUS);
+ tmp = in_le32(ims_info.dc + SSTATUS);
printk("chip version %ld, ", (tmp & 0x0F00) >> 8);
- tmp = in_le32(dc_regs + PRC);
- total_vram = (tmp & 0x0004) ? 0x000400000L : 0x000200000L;
- printk("VRAM size %ldM\n", total_vram / 0x000100000L);
+ tmp = in_le32(ims_info.dc + PRC);
+
+ if (0 == which )
+ ims_info.total_vram = (tmp & 0x0004) ? 0x000400000L : 0x000200000L;
+ else
+ ims_info.total_vram = 0x000800000L;
+
+ printk("VRAM size %ldM\n", ims_info.total_vram / 0x000100000L);
+
+ if (ims_info.total_vram == 0x000800000L)
+ {
+ ims_info.dac = TVPRAMDAC;
+ printk("Selecting TVP 3030 RAMDAC\n");
+ }
+ else
+ {
+ ims_info.dac = IBMRAMDAC;
+ printk("Selecting IBM RAMDAC\n");
+ }
sense = read_imstt_sense();
printk("Monitor sense value = 0x%x, ", sense);
@@ -311,147 +648,232 @@ map_imstt_display(struct device_node *dp)
if (color_mode < CMODE_8 || color_mode > CMODE_32)
color_mode = CMODE_8;
while (color_mode > CMODE_8
- && imstt_vram_reqd(video_mode, color_mode) > total_vram)
+ && imstt_vram_reqd(video_mode, color_mode) > ims_info.total_vram)
--color_mode;
#endif
-
+ // Hack Hack Hack !!!
video_mode = VMODE_640_480_67;
color_mode = CMODE_8;
}
+/*
+ * We dont need it ( all is done in ims_init )
+static void
+set_imstt_clock_tvp(char* tvprv)
+{
+ int j;
+ for (j=0;j<3;j++)
+ {
+ set_tvp_ireg(TVPIRPLA,(j << 4) | (j << 2) | j); // Select same value for all plls
+ set_tvp_ireg(TVPIRPPD,tvprv[j]);
+ set_tvp_ireg(TVPIRMPD,tvprv[3+j]);
+ set_tvp_ireg(TVPIRLPD,tvprv[6+j]);
+ }
+}
+
static void
-set_imstt_clock(unsigned char *params)
+set_imstt_clock_ibm(unsigned char *params)
{
- cmap_regs[PIDXHI] = 0; eieio();
- cmap_regs[PIDXLO] = PM0; eieio();
- cmap_regs[PIDXDATA] = params[0]; eieio();
+ ims_info.cmap[PIDXHI] = 0; eieio();
+ ims_info.cmap[PIDXLO] = PM0; eieio();
+ ims_info.cmap[PIDXDATA] = params[0]; eieio();
- cmap_regs[PIDXLO] = PN0; eieio();
- cmap_regs[PIDXDATA] = params[1]; eieio();
+ ims_info.cmap[PIDXLO] = PN0; eieio();
+ ims_info.cmap[PIDXDATA] = params[1]; eieio();
- cmap_regs[PIDXLO] = PP0; eieio();
- cmap_regs[PIDXDATA] = params[2]; eieio();
+ ims_info.cmap[PIDXLO] = PP0; eieio();
+ ims_info.cmap[PIDXDATA] = params[2]; eieio();
- cmap_regs[PIDXLO] = PC0; eieio();
- cmap_regs[PIDXDATA] = params[3]; eieio();
+ ims_info.cmap[PIDXLO] = PC0; eieio();
+ ims_info.cmap[PIDXDATA] = params[3]; eieio();
}
+*/
void
imstt_init()
{
int i, yoff, hres;
- unsigned long ctl, pitch, tmp;
- unsigned char pformat;
- unsigned *p;
- struct imstt_regvals *init;
+ unsigned long ctl, pitch, tmp, scrCmode;
+ struct ims_crmodevals *init;
- if (video_mode <= 0 || video_mode > VMODE_MAX
- || (init = imstt_reg_init[video_mode-1]) == 0)
- panic("imstt: display mode %d not supported", video_mode);
+ if (video_mode <= 0 || video_mode > VMODE_MAX ) panic("imstt: display mode %d not supported(not in valid range)", video_mode);
+ if ((init = ims_info.mode[video_mode-1]) == 0) panic("imstt: display mode %d not supported(no mode definition)", video_mode);
+ if (init->tt[ims_info.dac].vt == 0) panic("imstt: display mode %d not supported (no timing definition)", video_mode);
+
n_scanlines = vmode_attrs[video_mode-1].vres;
hres = vmode_attrs[video_mode-1].hres;
pixel_size = 1 << color_mode;
- line_pitch = init->pitch[color_mode];
+ line_pitch = init->pitch * pixel_size;
row_pitch = line_pitch * 16;
/* initialize the card */
- tmp = in_le32(dc_regs + STGCTL);
- out_le32(dc_regs + STGCTL, tmp & ~0x1);
+ tmp = in_le32(ims_info.dc + STGCTL);
+ out_le32(ims_info.dc + STGCTL, tmp & ~0x1);
#if 0
- out_le32(dc_regs + SCR, 0);
+ out_le32(ims_info.dc + SCR, 0);
#endif
- cmap_regs[PPMASK] = 0xFF;
- /* set default values for DAC registers */
- cmap_regs[PIDXHI] = 0; eieio();
- for(i = 0; i < sizeof(initregs) / sizeof(*initregs); i++) {
- cmap_regs[PIDXLO] = initregs[i].addr; eieio();
- cmap_regs[PIDXDATA] = initregs[i].value; eieio();
+ switch(ims_info.dac)
+ {
+ case IBMRAMDAC:
+ ims_info.cmap[PPMASK] = 0xFF; eieio();
+ ims_info.cmap[PIDXHI] = 0x00; eieio();
+ for (i = 0; ims_info.init[IBMRAMDAC][i].addr != 0 && ims_info.init[IBMRAMDAC][i].value != 0 ;i++)
+ {
+ ims_info.cmap[PIDXLO] = ims_info.init[IBMRAMDAC][i].addr; eieio();
+ ims_info.cmap[PIDXDATA] = ims_info.init[IBMRAMDAC][i].value; eieio();
+ }
+
+ ims_info.cmap[PIDXHI] = 0; eieio();
+ ims_info.cmap[PIDXLO] = PM0; eieio();
+ ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_m; eieio();
+
+ ims_info.cmap[PIDXLO] = PN0; eieio();
+ ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_n; eieio();
+
+ ims_info.cmap[PIDXLO] = PP0; eieio();
+ ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_p; eieio();
+
+ ims_info.cmap[PIDXLO] = PC0; eieio();
+ ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_c; eieio();
+
+ ims_info.cmap[PIDXLO] = PPIXREP; eieio();
+ ims_info.cmap[PIDXDATA] = ims_info.ibm[color_mode].pformat; eieio();
+
+ break;
+ case TVPRAMDAC:
+ for (i = 0; ims_info.init[TVPRAMDAC][i].addr != 0 && ims_info.init[TVPRAMDAC][i].value != 0 ;i++)
+ {
+ set_tvp_ireg(ims_info.init[TVPRAMDAC][i].addr,ims_info.init[TVPRAMDAC][i].value);
+ }
+ set_tvp_ireg(TVPIRPLA,0x00);
+ set_tvp_ireg(TVPIRPPD,init->tvp_clock.pclk_n);
+ set_tvp_ireg(TVPIRPPD,init->tvp_clock.pclk_m);
+ set_tvp_ireg(TVPIRPPD,init->tvp_clock.pclk_p);
+
+ set_tvp_ireg(TVPIRTCC,ims_info.tvp[color_mode].tcc);
+ set_tvp_ireg(TVPIRMXC,ims_info.tvp[color_mode].mxc);
+
+ set_tvp_ireg(TVPIRPLA,0x00);
+ set_tvp_ireg(TVPIRLPD,ims_info.tvp[color_mode].lckl_n);
+
+ set_tvp_ireg(TVPIRPLA,0x15);
+ set_tvp_ireg(TVPIRMLC,(init->tvp[color_mode]).mlc);
+
+ set_tvp_ireg(TVPIRPLA,0x2a);
+ set_tvp_ireg(TVPIRLPD,init->tvp[color_mode].lckl_p);
+ break;
}
- set_imstt_clock(init->clk);
+
switch(color_mode) {
case CMODE_32:
- ctl = 0x17b5;
- pitch = init->pitch[2] / 4;
- pformat = 0x06;
+ ctl = 0x1785;
+ pitch = init->pitch;
+ scrCmode = 0x300;
break;
case CMODE_16:
- ctl = 0x17b3;
- pitch = init->pitch[1] / 4;
- pformat = 0x04;
+ ctl = 0x1783;
+ pitch = init->pitch / 2;
+ scrCmode = 0x100;
break;
case CMODE_8:
default:
- ctl = 0x17b1;
- pitch = init->pitch[0] / 4;
- pformat = 0x03;
+ ctl = 0x1781;
+ pitch = init->pitch / 4;
+ scrCmode = 0x000;
break;
}
- out_le32(&dc_regs[HES], init->cfg[0]);
- out_le32(&dc_regs[HEB], init->cfg[1]);
- out_le32(&dc_regs[HSB], init->cfg[2]);
- out_le32(&dc_regs[HT], init->cfg[3]);
- out_le32(&dc_regs[VES], init->cfg[4]);
- out_le32(&dc_regs[VEB], init->cfg[5]);
- out_le32(&dc_regs[VSB], init->cfg[6]);
- out_le32(&dc_regs[VT], init->cfg[7]);
- out_le32(&dc_regs[HCIV], 1);
- out_le32(&dc_regs[VCIV], 1);
- out_le32(&dc_regs[TCDR], 4);
- out_le32(&dc_regs[VIL], 0);
+ out_le32(&ims_info.dc[HES], init->tt[ims_info.dac].hes);
+ out_le32(&ims_info.dc[HEB], init->tt[ims_info.dac].heb);
+ out_le32(&ims_info.dc[HSB], init->tt[ims_info.dac].hsb);
+ out_le32(&ims_info.dc[HT], init->tt[ims_info.dac].ht);
+ out_le32(&ims_info.dc[VES], init->tt[ims_info.dac].ves);
+ out_le32(&ims_info.dc[VEB], init->tt[ims_info.dac].veb);
+ out_le32(&ims_info.dc[VSB], init->tt[ims_info.dac].vsb);
+ out_le32(&ims_info.dc[VT], init->tt[ims_info.dac].vt);
+ out_le32(&ims_info.dc[HCIV], 1);
+ out_le32(&ims_info.dc[VCIV], 1);
+ out_le32(&ims_info.dc[TCDR], 4);
+ out_le32(&ims_info.dc[VIL], 0);
- out_le32(&dc_regs[SSR], 0);
- out_le32(&dc_regs[HRIR], 0x0200);
- out_le32(&dc_regs[CMR], 0x01FF);
- out_le32(&dc_regs[SRGCTL], 0x0003);
- if(total_vram == 0x000200000)
- out_le32(&dc_regs[SCR], 0x0059D);
- else {
- pitch /= 2;
- out_le32(&dc_regs[SCR], 0x00D0DC);
+ out_le32(&ims_info.dc[SSR], 0);
+ out_le32(&ims_info.dc[HRIR], 0x0200);
+ out_le32(&ims_info.dc[CMR], 0x01FF);
+ out_le32(&ims_info.dc[SRGCTL], 0x0003);
+ switch(ims_info.total_vram)
+ {
+ case 0x000200000:
+ out_le32(&ims_info.dc[SCR], 0x0059D| scrCmode);
+ break;
+ case 0x000400000:
+ pitch /= 2;
+ out_le32(&ims_info.dc[SCR], 0x00D0DC | scrCmode);
+ break;
+ case 0x000800000:
+ pitch /= 2;
+ out_le32(&ims_info.dc[SCR], 0x0150DD | scrCmode);
+ break;
}
- out_le32(&dc_regs[SPR], pitch);
-
- cmap_regs[PIDXLO] = PPIXREP; eieio();
- cmap_regs[PIDXDATA] = pformat; eieio();
+ out_le32(&ims_info.dc[SPR], pitch);
+ if (ims_info.dac == IBMRAMDAC)
+ {
+
+ }
+
pmac_init_palette(); /* Initialize colormap */
- out_le32(&dc_regs[STGCTL], ctl);
+ out_le32(&ims_info.dc[STGCTL], ctl);
yoff = (n_scanlines % 16) / 2;
- fb_start = frame_buffer + yoff * line_pitch;
+ fb_start = ims_info.fb + yoff * line_pitch;
/* Clear screen */
- p = (unsigned *)frame_buffer;
- for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
- *p++ = 0;
+ {
+ unsigned long *p;
+ p = (unsigned long*)ims_info.fb;
+ for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+ *p++ = 0;
+ }
display_info.height = n_scanlines;
display_info.width = hres;
display_info.depth = pixel_size * 8;
display_info.pitch = line_pitch;
display_info.mode = video_mode;
- strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
- display_info.fb_address = (unsigned long) frame_buffer;
- display_info.cmap_adr_address = (unsigned long) &cmap_regs[PADDRW];
- display_info.cmap_data_address = (unsigned long) &cmap_regs[PDATA];
+
+ if (ims_info.dac == IBMRAMDAC )
+ strncpy(display_info.name, "IMS,tt128mb2/4", sizeof(display_info.name));
+ else
+ strncpy(display_info.name, "IMS,tt128mb8/8A", sizeof(display_info.name));
+
+ display_info.fb_address = (unsigned long) ims_info.fb_phys;
+ display_info.cmap_adr_address = (unsigned long) &ims_info.cmap_phys[PADDRW];
+ display_info.cmap_data_address = (unsigned long) &ims_info.cmap_phys[PDATA];
display_info.disp_reg_address = (unsigned long) NULL;
}
int
imstt_setmode(struct vc_mode *mode, int doit)
{
- int cmode;
+ int cmode;
+ struct ims_crmodevals *init;
+
+ if (video_mode <= 0 || video_mode > VMODE_MAX )
+ return -EINVAL;
+ if ((init = ims_info.mode[video_mode-1]) == 0)
+ return -EINVAL;
+ if (init->tt[ims_info.dac].vt == 0)
+ return -EINVAL;
if (mode->mode <= 0 || mode->mode > VMODE_MAX
- || imstt_reg_init[mode->mode-1] == 0)
+ || (ims_info.mode[mode->mode-1] == 0))
return -EINVAL;
switch (mode->depth) {
case 24:
@@ -468,7 +890,7 @@ imstt_setmode(struct vc_mode *mode, int doit)
default:
return -EINVAL;
}
- if (imstt_vram_reqd(mode->mode, cmode) > total_vram)
+ if (imstt_vram_reqd(mode->mode, cmode) > ims_info.total_vram)
return -EINVAL;
if (doit) {
video_mode = mode->mode;
@@ -478,17 +900,32 @@ imstt_setmode(struct vc_mode *mode, int doit)
return 0;
}
+// set palette for TI TVP3030 ramdac (used on 8MB version)
+void
+imstt_set_palette_tvp(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors)
+{
+ int i;
+ for (i = 0; i < ncolors; ++i) {
+ ims_info.cmap[TVPADDRW] = index + i; eieio();
+ ims_info.cmap[TVPPDATA] = red[i]; eieio();
+ ims_info.cmap[TVPPDATA] = green[i]; eieio();
+ ims_info.cmap[TVPPDATA] = blue[i]; eieio();
+ }
+}
+
+// set palette for IBM ramdac (used on 2MB/4MB version)
void
-imstt_set_palette(unsigned char red[], unsigned char green[],
+imstt_set_palette_ibm(unsigned char red[], unsigned char green[],
unsigned char blue[], int index, int ncolors)
{
int i;
for (i = 0; i < ncolors; ++i) {
- cmap_regs[PADDRW] = index + i; eieio();
- cmap_regs[PDATA] = red[i]; eieio();
- cmap_regs[PDATA] = green[i]; eieio();
- cmap_regs[PDATA] = blue[i]; eieio();
+ ims_info.cmap[PADDRW] = index + i; eieio();
+ ims_info.cmap[PDATA] = red[i]; eieio();
+ ims_info.cmap[PDATA] = green[i]; eieio();
+ ims_info.cmap[PDATA] = blue[i]; eieio();
}
}
@@ -497,10 +934,12 @@ imstt_set_blanking(int blank_mode)
{
long ctrl;
- ctrl = ld_le32(dc_regs + STGCTL) | 0x0030;
+ ctrl = ld_le32(ims_info.dc + STGCTL) | 0x0030;
if (blank_mode & VESA_VSYNC_SUSPEND)
ctrl &= ~0x0020;
if (blank_mode & VESA_HSYNC_SUSPEND)
ctrl &= ~0x0010;
- out_le32(dc_regs + STGCTL, ctrl);
+ out_le32(ims_info.dc + STGCTL, ctrl);
}
+
+
diff --git a/drivers/macintosh/imstt.h b/drivers/macintosh/imstt.h
index 853e8f00d..a7f635982 100644
--- a/drivers/macintosh/imstt.h
+++ b/drivers/macintosh/imstt.h
@@ -9,10 +9,13 @@
* 2 of the License, or (at your option) any later version.
*/
-extern void map_imstt_display(struct device_node *);
+extern void map_imstt_display_ibm(struct device_node *);
+extern void map_imstt_display_tvp(struct device_node *);
extern void imstt_init(void);
extern int imstt_setmode(struct vc_mode *mode, int doit);
-extern void imstt_set_palette(unsigned char red[], unsigned char green[],
+extern void imstt_set_palette_ibm(unsigned char red[], unsigned char green[],
+ unsigned char blue[], int index, int ncolors);
+extern void imstt_set_palette_tvp(unsigned char red[], unsigned char green[],
unsigned char blue[], int index, int ncolors);
extern void imstt_set_blanking(int blank_mode);
diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c
index 49dbd622b..190e5222a 100644
--- a/drivers/macintosh/mac_keyb.c
+++ b/drivers/macintosh/mac_keyb.c
@@ -15,8 +15,8 @@
#include <linux/mm.h>
#include <linux/signal.h>
#include <linux/ioport.h>
+#include <linux/init.h>
-#include <asm/keyboard.h>
#include <asm/bitops.h>
#include <asm/adb.h>
#include <asm/cuda.h>
@@ -28,6 +28,140 @@
#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */
#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */
+static u_short macplain_map[NR_KEYS] = __initdata {
+ 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] __initdata = {
+ 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] __initdata = {
+ 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] __initdata = {
+ 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] __initdata = {
+ 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] __initdata = {
+ 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] __initdata = {
+ 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 void kbd_repeat(unsigned long);
static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
static int last_keycode;
@@ -38,8 +172,7 @@ static void leds_done(struct adb_request *);
/* XXX: Hook for mouse driver */
void (*adb_mouse_interrupt_hook) (char *, int);
-int adb_emulate_button2;
-int adb_emulate_button3;
+static int adb_emulate_buttons = 0;
extern int console_loglevel;
extern struct kbd_struct kbd_table[];
@@ -47,6 +180,9 @@ extern struct kbd_struct kbd_table[];
extern void handle_scancode(unsigned char);
extern void put_queue(int);
+static struct adb_ids keyboard_ids;
+static struct adb_ids mouse_ids;
+
/* this map indicates which keys shouldn't autorepeat. */
static unsigned char dont_repeat[128] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -118,6 +254,10 @@ input_keycode(int keycode, int repeat)
up_flag = (keycode & 0x80);
keycode &= 0x7f;
+ /* on the powerbook 3400, the power key gives code 0x7e */
+ if (keycode == 0x7e)
+ keycode = 0x7f;
+
if (!repeat)
del_timer(&repeat_timer);
@@ -130,7 +270,8 @@ input_keycode(int keycode, int repeat)
* Might also want to know how many buttons need to be emulated.
* -> hide this as function in arch/m68k/mac ?
*/
- if (adb_mouse_interrupt_hook || console_loglevel == 10) {
+ if ( (adb_emulate_buttons) &&
+ (adb_mouse_interrupt_hook || console_loglevel == 10) ) {
unsigned char button, button2, button3, fake_event;
static unsigned char button2state=0, button3state=0; /* up */
/* faked ADB packet */
@@ -140,19 +281,19 @@ input_keycode(int keycode, int repeat)
fake_event = 0;
switch (keycode) { /* which 'button' ? */
case 0x7c: /* R-option */
- button2 = (!up_flag); /* new state */
- if (button2 != button2state) /* change ? */
- button = 2;
- button2state = button2; /* save state */
- fake_event = 2;
- break;
- case 0x7d: /* R-control */
button3 = (!up_flag); /* new state */
if (button3 != button3state) /* change ? */
button = 3;
button3state = button3; /* save state */
fake_event = 3;
break;
+ case 0x7d: /* R-control */
+ button2 = (!up_flag); /* new state */
+ if (button2 != button2state) /* change ? */
+ button = 2;
+ button2state = button2; /* save state */
+ fake_event = 2;
+ break;
}
if (fake_event && console_loglevel >= 8)
printk("fake event: button2 %d button3 %d button %d\n",
@@ -365,57 +506,134 @@ static unsigned char mac_ledmap[8] = {
};
static struct adb_request led_request;
-static int leds_pending;
+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_mackbd_leds(unsigned char leds, int device)
+{
+
+ if (led_request.complete) {
+ adb_request(&led_request, leds_done, 0, 3,
+ ADB_WRITEREG(device, KEYB_LEDREG), 0xff,
+ ~mac_ledmap[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;
+ }
+}
void mackbd_leds(unsigned char leds)
{
- if (led_request.complete) {
- adb_request(&led_request, leds_done, 0, 3,
- ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG),
- 0xff, ~mac_ledmap[leds]);
- } else
- leds_pending = leds | 0x100;
+ int i;
+
+ for(i = 0; i < keyboard_ids.nids; i++)
+ real_mackbd_leds(leds,keyboard_ids.id[i]);
}
static void leds_done(struct adb_request *req)
{
- int leds;
+ 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_mackbd_leds(leds,device);
+ }
- if (leds_pending) {
- leds = leds_pending & 0xff;
- leds_pending = 0;
- mackbd_leds(leds);
- }
}
-void mackbd_init_hw(void)
+__initfunc(void mackbd_init_hw(void))
{
struct adb_request req;
+ int i;
+
+ if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+ return;
+
+ /* setup key map */
+ memcpy(plain_map, macplain_map, sizeof(plain_map));
+ memcpy(shift_map, macshift_map, sizeof(shift_map));
+ memcpy(altgr_map, macaltgr_map, sizeof(altgr_map));
+ memcpy(ctrl_map, macctrl_map, sizeof(ctrl_map));
+ memcpy(shift_ctrl_map, macshift_ctrl_map, sizeof(shift_ctrl_map));
+ memcpy(alt_map, macalt_map, sizeof(alt_map));
+ memcpy(ctrl_alt_map, macctrl_alt_map, sizeof(ctrl_alt_map));
/* initialize mouse interrupt hook */
adb_mouse_interrupt_hook = NULL;
- /* assume broken mouse :-) - should be adjusted based on
- * result of the mouse setup !! (or passed as kernel option) */
- adb_emulate_button2 = 1;
- adb_emulate_button3 = 1;
- adb_register(ADB_KEYBOARD, keyboard_input);
- adb_register(ADB_MOUSE, mouse_input);
+ adb_register(ADB_KEYBOARD, 5, &keyboard_ids, keyboard_input);
+ adb_register(ADB_MOUSE, 1, &mouse_ids, mouse_input);
- /* turn off all leds */
- adb_request(&req, NULL, ADBREQ_SYNC, 3,
- ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, 0xff);
+ for(i = 0; i < keyboard_ids.nids; i++) {
+ /* turn off all leds */
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(keyboard_ids.id[i], KEYB_LEDREG), 0xff, 0xff);
+ }
/* get the keyboard to send separate codes for
left and right shift, control, option keys. */
- adb_request(&req, NULL, ADBREQ_SYNC, 3,
- ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3);
+ for(i = 0;i < keyboard_ids.nids; i++) {
+ /* get the keyboard to send separate codes for
+ left and right shift, control, option keys. */
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(keyboard_ids.id[i], 3), 0, 3);
+ }
led_request.complete = 1;
/* Try to switch the mouse (id 3) to handler 4, for three-button
mode. (0x20 is Service Request Enable, 0x03 is Device ID). */
- adb_request(&req, NULL, ADBREQ_SYNC, 3,
- ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 );
+ for(i = 0; i < mouse_ids.nids; i++) {
+ adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+ ADB_READREG(mouse_ids.id[i], 1));
+
+ if ((req.reply_len) &&
+ (req.reply[1] == 0x9a) && (req.reply[2] == 0x21)) {
+
+ printk("aha, trackball found at %d\n", mouse_ids.id[i]);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(mouse_ids.id[i], 3), 0x63, 4 );
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(mouse_ids.id[i],1), 00,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(mouse_ids.id[i],1), 01,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(mouse_ids.id[i],1), 02,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(mouse_ids.id[i],1), 03,0x38);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(mouse_ids.id[i],1), 00,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(mouse_ids.id[i],1), 01,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(mouse_ids.id[i],1), 02,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(mouse_ids.id[i],1), 03,0x38);
+ }
+ }
}
+void adb_setup_mouse( char *s, int *ints )
+{
+ if (ints[0] >= 1)
+ adb_emulate_buttons = ints[1];
+}
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index 65048b0da..a826daea6 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -10,6 +10,7 @@
#include <asm/prom.h>
#include <asm/adb.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
#include <asm/hydra.h>
#include <asm/irq.h>
#include <asm/system.h>
@@ -71,7 +72,7 @@ void macio_adb_init(void)
if (adbs == 0)
return;
-#if 1
+#if 0
{ int i;
printk("macio_adb_init: node = %p, addrs =", adbs->node);
@@ -79,16 +80,17 @@ void macio_adb_init(void)
printk(" %x(%x)", adbs->addrs[i].address, adbs->addrs[i].size);
printk(", intrs =");
for (i = 0; i < adbs->n_intrs; ++i)
- printk(" %x", adbs->intrs[i]);
+ printk(" %x", adbs->intrs[i].line);
printk("\n"); }
#endif
- adb = (volatile struct adb_regs *) adbs->addrs->address;
+ adb = (volatile struct adb_regs *)
+ ioremap(adbs->addrs->address, sizeof(struct adb_regs));
- if (request_irq(openpic_to_irq(adbs->intrs[0]), macio_adb_interrupt,
+ if (request_irq(adbs->intrs[0].line, macio_adb_interrupt,
0, "ADB", (void *)0)) {
printk(KERN_ERR "ADB: can't get irq %d\n",
- openpic_to_irq(adbs->intrs[0]));
+ adbs->intrs[0].line);
return;
}
diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
index 3a99b07b2..4232f5953 100644
--- a/drivers/macintosh/macserial.c
+++ b/drivers/macintosh/macserial.c
@@ -7,6 +7,7 @@
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -20,13 +21,21 @@
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/delay.h>
+#include <linux/init.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
#include <asm/io.h>
+#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/bitops.h>
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
#include "macserial.h"
@@ -43,7 +52,6 @@
in the order we want. */
#define RECOVERY_DELAY eieio()
-struct mac_zschannel *zs_kgdbchan;
struct mac_zschannel zs_channels[NUM_CHANNELS];
struct mac_serial zs_soft[NUM_CHANNELS];
@@ -51,31 +59,24 @@ int zs_channels_found;
struct mac_serial *zs_chain; /* list of all channels */
struct tty_struct zs_ttys[NUM_CHANNELS];
-/** struct tty_struct *zs_constty; **/
-/* Console hooks... */
-static int zs_cons_chan = 0;
-struct mac_serial *zs_consinfo = 0;
-struct mac_zschannel *zs_conschan;
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console sercons;
+#endif
-/*
- * Initialization values for when a channel is used for
- * kernel gdb support.
- */
-static unsigned char kgdb_regs[16] = {
- 0, 0, 0, /* write 0, 1, 2 */
- (Rx8 | RxENABLE), /* write 3 */
- (X16CLK | SB1), /* write 4 */
- (Tx8 | TxENAB | RTS), /* write 5 */
- 0, 0, 0, /* write 6, 7, 8 */
- (NV), /* write 9 */
- (NRZ), /* write 10 */
- (TCBR | RCBR), /* write 11 */
- 1, 0, /* 38400 baud divisor, write 12 + 13 */
- (BRENABL), /* write 14 */
- (DCDIE) /* write 15 */
+#ifdef CONFIG_KGDB
+struct mac_zschannel *zs_kgdbchan;
+static unsigned char scc_inittab[] = {
+ 9, 0x80, /* reset A side (CHRA) */
+ 13, 0, /* set baud rate divisor */
+ 12, 1,
+ 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */
+ 11, 0x50, /* clocks = br gen (RCBR | TCBR) */
+ 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
+ 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/
+ 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/
};
-
+#endif
#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */
DECLARE_TASK_QUEUE(tq_serial);
@@ -90,8 +91,8 @@ static int serial_refcount;
/* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256
-/* Debugging... DEBUG_INTR is bad to use when one of the zs
- * lines is your console ;(
+/*
+ * Debugging.
*/
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_OPEN
@@ -233,23 +234,6 @@ static inline void zs_rtsdtr(struct mac_serial *ss, int set)
return;
}
-static inline void kgdb_chaninit(struct mac_serial *ss, int intson, int bps)
-{
- int brg;
-
- if (intson) {
- kgdb_regs[R1] = INT_ALL_Rx;
- kgdb_regs[R9] |= MIE;
- } else {
- kgdb_regs[R1] = 0;
- kgdb_regs[R9] &= ~MIE;
- }
- brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
- kgdb_regs[R12] = brg;
- kgdb_regs[R13] = brg >> 8;
- load_zsregs(ss->zs_channel, kgdb_regs);
-}
-
/* Utility routines for the Zilog */
static inline int get_zsbaud(struct mac_serial *ss)
{
@@ -300,8 +284,6 @@ static _INLINE_ void rs_sched_event(struct mac_serial *info,
mark_bh(SERIAL_BH);
}
-extern void breakpoint(void); /* For the KGDB frame character */
-
static _INLINE_ void receive_chars(struct mac_serial *info,
struct pt_regs *regs)
{
@@ -313,17 +295,13 @@ static _INLINE_ void receive_chars(struct mac_serial *info,
stat = read_zsreg(info->zs_channel, R1);
ch = read_zsdata(info->zs_channel);
-#if 0 /* KGDB not yet supported */
- /* Look for kgdb 'stop' character, consult the gdb documentation
- * for remote target debugging and arch/sparc/kernel/sparc-stub.c
- * to see how all this works.
- */
- if ((info->kgdb_channel) && (ch =='\003')) {
- breakpoint();
- continue;
+#ifdef CONFIG_KGDB
+ if (info->kgdb_channel) {
+ if (ch == 0x03 || ch == '$')
+ breakpoint();
+ return;
}
#endif
-
if (!tty)
continue;
tty_flip_buffer_push(tty);
@@ -767,93 +745,6 @@ static void change_speed(struct mac_serial *info)
restore_flags(flags);
}
-/* This is for console output over ttya/ttyb */
-static void rs_put_char(char ch)
-{
- struct mac_zschannel *chan = zs_conschan;
- int loops = 0;
- unsigned long flags;
-
- if(!chan)
- return;
-
- save_flags(flags); cli();
- while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
- if (++loops >= 1000000)
- break;
- write_zsdata(chan, ch);
- restore_flags(flags);
-}
-
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
-
- while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
- udelay(5);
- write_zsdata(chan, kgdb_char);
-}
-
-char getDebugChar(void)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
-
- while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
- udelay(5);
- return read_zsdata(chan);
-}
-
-/*
- * Fair output driver allows a process to speak.
- */
-static void rs_fair_output(void)
-{
- int left; /* Output no more than that */
- unsigned long flags;
- struct mac_serial *info = zs_consinfo;
- char c;
-
- if (info == 0) return;
- if (info->xmit_buf == 0) return;
-
- save_flags(flags); cli();
- left = info->xmit_cnt;
- while (left != 0) {
- c = info->xmit_buf[info->xmit_tail];
- info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- restore_flags(flags);
-
- rs_put_char(c);
-
- save_flags(flags); cli();
- left = MIN(info->xmit_cnt, left-1);
- }
-
- restore_flags(flags);
- return;
-}
-
-/*
- * zs_console_print is registered for printk.
- */
-static void zs_console_print(const char *p)
-{
- char c;
-
- while ((c = *(p++)) != 0) {
- if (c == '\n')
- rs_put_char('\r');
- rs_put_char(c);
- }
-
- /* Comment this if you want to have a strict interrupt-driven output */
- rs_fair_output();
-}
-
static void rs_flush_chars(struct tty_struct *tty)
{
struct mac_serial *info = (struct mac_serial *)tty->driver_data;
@@ -1204,6 +1095,10 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
int error;
struct mac_serial * info = (struct mac_serial *)tty->driver_data;
+#ifdef CONFIG_KGDB
+ if (info->kgdb_channel)
+ return -ENODEV;
+#endif
if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
return -ENODEV;
@@ -1340,7 +1235,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
* At this point we stop accepting input. To do this, we
* disable the receiver and receive interrupts.
*/
- /** if (!info->iscons) ... **/
info->curregs[3] &= ~RxENABLE;
info->pendregs[3] = info->curregs[3];
write_zsreg(info->zs_channel, 3, info->curregs[3]);
@@ -1580,9 +1474,10 @@ int rs_open(struct tty_struct *tty, struct file * filp)
return -ENODEV;
info = zs_soft + line;
- /* Is the kgdb running over this line? */
+#ifdef CONFIG_KGDB
if (info->kgdb_channel)
return -ENODEV;
+#endif
if (serial_paranoia_check(info, tty->device, "rs_open"))
return -ENODEV;
#ifdef SERIAL_DEBUG_OPEN
@@ -1632,6 +1527,13 @@ int rs_open(struct tty_struct *tty, struct file * filp)
*tty->termios = info->callout_termios;
change_speed(info);
}
+#ifdef CONFIG_SERIAL_CONSOLE
+ if (sercons.cflag && sercons.index == line) {
+ tty->termios->c_cflag = sercons.cflag;
+ sercons.cflag = 0;
+ change_speed(info);
+ }
+#endif
info->session = current->session;
info->pgrp = current->pgrp;
@@ -1672,15 +1574,15 @@ probe_sccs()
continue;
}
zs_channels[n].control = (volatile unsigned char *)
- ch->addrs[0].address;
+ ioremap(ch->addrs[0].address, 0x1000);
zs_channels[n].data = zs_channels[n].control
+ ch->addrs[0].size / 2;
zs_soft[n].zs_channel = &zs_channels[n];
- zs_soft[n].irq = ch->intrs[0];
- if (request_irq(ch->intrs[0], rs_interrupt, 0,
+ zs_soft[n].irq = ch->intrs[0].line;
+ if (request_irq(ch->intrs[0].line, rs_interrupt, 0,
"SCC", &zs_soft[n]))
- panic("macserial: can't get irq %d",
- ch->intrs[0]);
+ printk(KERN_ERR "macserial: can't get irq %d\n",
+ ch->intrs[0].line);
/* XXX this assumes the prom puts chan A before B */
if (n & 1)
zs_soft[n].zs_chan_a = &zs_channels[n-1];
@@ -1769,6 +1671,11 @@ int rs_init(void)
save_flags(flags); cli();
for (channel = 0; channel < zs_channels_found; ++channel) {
+#ifdef CONFIG_KGDB
+ if (zs_soft[channel].kgdb_channel) {
+ continue;
+ }
+#endif
zs_soft[channel].clk_divisor = 16;
zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
@@ -1779,17 +1686,15 @@ int rs_init(void)
write_zsreg(zs_soft[channel].zs_channel, R9,
(NV | MIE));
}
- /* If this is the kgdb line, enable interrupts because we
- * now want to receive the 'control-c' character from the
- * client attached to us asynchronously.
- */
- if (zs_soft[channel].kgdb_channel)
- kgdb_chaninit(&zs_soft[channel], 1,
- zs_soft[channel].zs_baud);
}
for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
{
+#ifdef CONFIG_KGDB
+ if (info->kgdb_channel) {
+ continue;
+ }
+#endif
info->magic = SERIAL_MAGIC;
info->port = (int) info->zs_channel->control;
info->line = i;
@@ -1832,84 +1737,212 @@ void unregister_serial(int line)
return;
}
-extern void register_console(void (*proc)(const char *));
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
/*
- * Initialization values for when a channel is used for
- * a serial console.
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
*/
-static unsigned char cons_init_regs[16] = {
- 0, 0, 0, /* write 0, 1, 2 */
- (Rx8 | RxENABLE), /* write 3 */
- (X16CLK | SB1), /* write 4 */
- (Tx8 | TxENAB | RTS), /* write 5 */
- 0, 0, 0, /* write 6, 7, 8 */
- 0, /* write 9 */
- (NRZ), /* write 10 */
- (TCBR | RCBR), /* write 11 */
- 1, 0, /* 38400 baud divisor, write 12 + 13 */
- (BRENABL), /* write 14 */
- 0 /* write 15 */
-};
+static void serial_console_write(struct console *co, const char *s,
+ unsigned count)
+{
+}
/*
- * Hooks for running a serial console. con_init() calls this if the
- * console is being run over one of the serial ports.
- * 'channel' is decoded as 1=modem, 2=printer.
+ * Receive character from the serial port
*/
-void
-rs_cons_hook(int chip, int out, int channel)
+static int serial_console_wait_key(struct console *co)
{
- int brg;
+ return 0;
+}
- if (!out)
- return;
- if (zs_consinfo != 0) {
- printk("rs_cons_hook called twice?\n");
- return;
+static kdev_t serial_console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ * Setup initial baud/bits/parity. We do two things here:
+ * - construct a cflag setting for the first rs_open()
+ * - initialize the serial port
+ * Return non-zero if we didn't find a serial port.
+ */
+__initfunc(static int serial_console_setup(struct console *co, char *options))
+{
+ struct serial_state *ser;
+ unsigned cval;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int cflag = CREAD | HUPCL | CLOCAL;
+ int quot = 0;
+ char *s;
+
+ if (options) {
+ baud = simple_strtoul(options, NULL, 10);
+ s = options;
+ while(*s >= '0' && *s <= '9')
+ s++;
+ if (*s)
+ parity = *s++;
+ if (*s)
+ bits = *s - '0';
}
- if (zs_chain == 0)
- probe_sccs();
- --channel;
- if (channel < 0 || channel >= zs_channels_found) {
- printk("rs_cons_hook: channel = %d?\n", channel);
- return;
+
+ /*
+ * Now construct a cflag setting.
+ */
+ switch(baud) {
+ case 1200:
+ cflag |= B1200;
+ break;
+ case 2400:
+ cflag |= B2400;
+ break;
+ case 4800:
+ cflag |= B4800;
+ break;
+ case 19200:
+ cflag |= B19200;
+ break;
+ case 38400:
+ cflag |= B38400;
+ break;
+ case 57600:
+ cflag |= B57600;
+ break;
+ case 115200:
+ cflag |= B115200;
+ break;
+ case 9600:
+ default:
+ cflag |= B9600;
+ break;
+ }
+ switch(bits) {
+ case 7:
+ cflag |= CS7;
+ break;
+ default:
+ case 8:
+ cflag |= CS8;
+ break;
+ }
+ switch(parity) {
+ case 'o': case 'O':
+ cflag |= PARODD;
+ break;
+ case 'e': case 'E':
+ cflag |= PARENB;
+ break;
}
+ co->cflag = cflag;
- zs_cons_chan = channel;
- zs_consinfo = &zs_soft[channel];
- zs_conschan = zs_consinfo->zs_channel;
- zs_consinfo->clk_divisor = 16;
- zs_consinfo->zs_baud = 38400;
- zs_consinfo->is_cons = 1;
-
- memcpy(zs_consinfo->curregs, cons_init_regs, sizeof(cons_init_regs));
- brg = BPS_TO_BRG(zs_consinfo->zs_baud, ZS_CLOCK/16);
- zs_consinfo->curregs[R12] = brg;
- zs_consinfo->curregs[R13] = brg >> 8;
- load_zsregs(zs_conschan, zs_consinfo->curregs);
-
- register_console(zs_console_print);
- printk("zs%d: console I/O\n", channel);
+ return 0;
}
+static struct console sercons = {
+ "ttyS",
+ serial_console_write,
+ NULL,
+ serial_console_device,
+ serial_console_wait_key,
+ NULL,
+ serial_console_setup,
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+
+/*
+ * Register console.
+ */
+__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+{
+ register_console(&sercons);
+ return kmem_start;
+}
+#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+#ifdef CONFIG_KGDB
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+ while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+ udelay(5);
+ write_zsdata(chan, kgdb_char);
+}
+char getDebugChar(void)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+ while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+ eieio(); /*barrier();*/
+ return read_zsdata(chan);
+}
+void kgdb_interruptible(int yes)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+ int one, nine;
+ nine = read_zsreg(chan, 9);
+ if (yes == 1) {
+ one = EXT_INT_ENAB|INT_ALL_Rx;
+ nine |= MIE;
+ printk("turning serial ints on\n");
+ } else {
+ one = RxINT_DISAB;
+ nine &= ~MIE;
+ printk("turning serial ints off\n");
+ }
+ write_zsreg(chan, 1, one);
+ write_zsreg(chan, 9, nine);
+}
+/* This sets up the serial port we're using, and turns on
+ * interrupts for that channel, so kgdb is usable once we're done.
+ */
+static inline void kgdb_chaninit(struct mac_zschannel *ms, int intson, int bps)
+{
+ int brg;
+ int i, x;
+ volatile char *sccc = ms->control;
+ brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+ printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
+ for (i = 20000; i != 0; --i) {
+ x = *sccc; eieio();
+ }
+ for (i = 0; i < sizeof(scc_inittab); ++i) {
+ write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
+ i++;
+ }
+}
/* This is called at boot time to prime the kgdb serial debugging
- * serial line. The 'tty_num' argument is 0 for /dev/ttyS0 and 1
- * for /dev/ttyS1 which is determined in setup_arch() from the
+ * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1
+ * for /dev/ttyb which is determined in setup_arch() from the
* boot command line flags.
*/
-void
-rs_kgdb_hook(int tty_num)
+__initfunc(void zs_kgdb_hook(int tty_num))
{
+ /* Find out how many Z8530 SCCs we have */
if (zs_chain == 0)
probe_sccs();
+ zs_soft[tty_num].zs_channel = &zs_channels[tty_num];
zs_kgdbchan = zs_soft[tty_num].zs_channel;
+ zs_soft[tty_num].change_needed = 0;
zs_soft[tty_num].clk_divisor = 16;
- zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]);
+ zs_soft[tty_num].zs_baud = 38400;
zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */
zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
/* Turn on transmitter/receiver at 8-bits/char */
- kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
- ZS_CLEARERR(zs_kgdbchan);
- ZS_CLEARFIFO(zs_kgdbchan);
+ kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
+ printk("KGDB: on channel %d initialized\n", tty_num);
+ set_debug_traps(); /* init stub */
}
+#endif /* ifdef CONFIG_KGDB */
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
new file mode 100644
index 000000000..6e39367e0
--- /dev/null
+++ b/drivers/macintosh/mediabay.c
@@ -0,0 +1,236 @@
+/*
+ * Driver for the media bay on the PowerBook 3400 and 2400.
+ *
+ * Copyright (C) 1998 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/hdreg.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/ohare.h>
+#include <asm/mediabay.h>
+
+struct media_bay_hw {
+ unsigned char b0;
+ unsigned char contents;
+ unsigned char b2;
+ unsigned char b3;
+ unsigned feature;
+};
+
+static volatile struct media_bay_hw *mb_addr;
+
+#define MB_CONTENTS() ((in_8(&mb_addr->contents) >> 4) & 7)
+#define SET_FEATURES(set, clr) \
+ out_le32(&mb_addr->feature, \
+ (in_le32(&mb_addr->feature) & ~(clr)) | (set));
+
+static int media_bay_id = -1;
+static int mb_ready;
+static int mb_last_value;
+static int mb_value_count;
+
+int media_bay_present;
+
+#ifdef CONFIG_BLK_DEV_IDE
+unsigned long mb_cd_base;
+int mb_cd_index = -1;
+int mb_cd_irq;
+
+/* check the busy bit in the media-bay ide interface
+ (assumes the media-bay contains an ide device) */
+#define MB_IDE_READY() ((in_8((volatile unsigned char *) \
+ (mb_cd_base + 0x70)) & 0x80) == 0)
+#endif
+
+/*
+ * Consider the media-bay ID value stable if it is the same for
+ * this many consecutive samples (at intervals of 1/HZ seconds).
+ */
+#define MB_STABLE_COUNT 4
+
+/*
+ * Hold the media-bay reset signal true for this many ticks
+ * after a device is inserted before releasing it.
+ */
+#define MB_RESET_COUNT 10
+
+/*
+ * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted
+ * (or until the device is ready) before registering the IDE interface.
+ */
+#define MB_IDE_WAIT 500
+
+static void poll_media_bay(void);
+static void set_media_bay(int id);
+
+/*
+ * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL
+ * register is always set when there is something in the media bay.
+ * This causes problems for the interrupt code if we attach an interrupt
+ * handler to the media-bay interrupt, because it tends to go into
+ * an infinite loop calling the media bay interrupt handler.
+ * Therefore we do it all by polling the media bay once each tick.
+ */
+
+void
+media_bay_init(void)
+{
+ struct device_node *np;
+
+ np = find_devices("media-bay");
+ if (np == NULL || np->n_addrs == 0)
+ return;
+ mb_addr = (volatile struct media_bay_hw *)
+ ioremap(np->addrs[0].address, sizeof(struct media_bay_hw));
+
+#if 0
+ if (np->n_intrs == 0) {
+ printk(KERN_WARNING "No interrupt for media bay?\n");
+ } else {
+ if (request_irq(np->intrs[0].line, media_bay_intr, 0,
+ "Media bay", NULL))
+ printk(KERN_WARNING "Couldn't get IRQ %d for "
+ "media bay\n", np->intrs[0].line);
+ }
+#endif
+
+ media_bay_present = 1;
+ set_media_bay(MB_CONTENTS());
+ if (media_bay_id != MB_NO) {
+ SET_FEATURES(0, OH_BAY_RESET);
+ mb_ready = 1;
+ }
+}
+
+#if 0
+static void
+media_bay_intr(int irq, void *devid, struct pt_regs *regs)
+{
+ int id = MB_CONTENTS();
+
+ if (id == MB_NO)
+ set_media_bay(id);
+}
+#endif
+
+int
+check_media_bay(int what)
+{
+ return what == media_bay_id && mb_ready;
+}
+
+/*
+ * This procedure runs as a kernel thread to poll the media bay
+ * once each tick and register and unregister the IDE interface
+ * with the IDE driver. It needs to be a thread because
+ * ide_register can't be called from interrupt context.
+ */
+int
+media_bay_task(void *x)
+{
+ int prev = media_bay_id;
+ int reset_timer = 0;
+#ifdef CONFIG_BLK_DEV_IDE
+ int cd_timer = 0;
+#endif
+
+ strcpy(current->comm, "media-bay");
+ for (;;) {
+ poll_media_bay();
+ if (media_bay_id != prev) {
+ reset_timer = (media_bay_id != MB_NO)?
+ MB_RESET_COUNT: 0;
+ mb_ready = 0;
+#ifdef CONFIG_BLK_DEV_IDE
+ cd_timer = 0;
+ if (media_bay_id != MB_CD && mb_cd_index >= 0) {
+ printk(KERN_DEBUG "Unregistering mb ide\n");
+ ide_unregister(mb_cd_index);
+ mb_cd_index = -1;
+ }
+#endif
+ } else if (reset_timer) {
+ if (--reset_timer == 0) {
+ SET_FEATURES(0, OH_BAY_RESET);
+ mb_ready = 1;
+#ifdef CONFIG_BLK_DEV_IDE
+ if (media_bay_id == MB_CD && mb_cd_base != 0)
+ cd_timer = MB_IDE_WAIT;
+#endif
+ }
+#ifdef CONFIG_BLK_DEV_IDE
+ } else if (cd_timer && (--cd_timer == 0 || MB_IDE_READY())
+ && mb_cd_index < 0) {
+ mb_cd_index = ide_register(mb_cd_base, 0, mb_cd_irq);
+ printk(KERN_DEBUG "media-bay is ide %d\n", mb_cd_index);
+#endif
+ }
+
+ prev = media_bay_id;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ if (signal_pending(current))
+ return 0;
+ }
+}
+
+void
+poll_media_bay(void)
+{
+ int id = MB_CONTENTS();
+
+ if (id == mb_last_value) {
+ if (id != media_bay_id
+ && ++mb_value_count >= MB_STABLE_COUNT)
+ set_media_bay(id);
+ } else {
+ mb_last_value = id;
+ mb_value_count = 0;
+ }
+}
+
+static void
+set_media_bay(int id)
+{
+ u32 clr, set;
+
+ media_bay_id = id;
+ mb_last_value = id;
+ clr = OH_FLOPPY_ENABLE | OH_IDECD_POWER;
+ set = 0;
+ switch (id) {
+ case MB_CD:
+ set = OH_BAY_ENABLE | OH_IDECD_POWER | OH_BAY_IDE_ENABLE;
+ printk(KERN_INFO "media bay contains a CD-ROM drive\n");
+ break;
+ case MB_FD:
+ set = OH_BAY_ENABLE | OH_BAY_FLOPPY_ENABLE | OH_FLOPPY_ENABLE;
+ printk(KERN_INFO "media bay contains a floppy disk drive\n");
+ break;
+ case MB_NO:
+ printk(KERN_INFO "media bay is empty\n");
+ break;
+ default:
+ set = OH_BAY_ENABLE;
+ printk(KERN_INFO "media bay contains an unknown device (%d)\n",
+ id);
+ break;
+ }
+
+ SET_FEATURES(set, clr);
+ printk(KERN_DEBUG "feature reg now %x\n", in_le32(&mb_addr->feature));
+}
diff --git a/drivers/macintosh/platinum.c b/drivers/macintosh/platinum.c
index 34f314df7..d35961d79 100644
--- a/drivers/macintosh/platinum.c
+++ b/drivers/macintosh/platinum.c
@@ -16,6 +16,7 @@
#include <linux/nvram.h>
#include <asm/prom.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
#include <linux/selection.h>
#include "pmac-cons.h"
#include "platinum.h"
@@ -58,6 +59,10 @@ static unsigned char *base_frame_buffer;
static struct cmap_regs *cmap_regs;
static volatile struct platinum_regs *plat_regs;
+static unsigned long frame_buffer_phys;
+static unsigned long cmap_regs_phys;
+static unsigned long plat_regs_phys;
+
/*
* Register initialization tables for the platinum display.
*
@@ -403,14 +408,17 @@ map_platinum(struct device_node *dp)
size = dp->addrs[i].size;
if (size >= 0x400000) {
/* frame buffer - map only 4MB */
- frame_buffer = ioremap(addr, 0x400000);
+ frame_buffer_phys = addr;
+ frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU);
base_frame_buffer = frame_buffer;
} else {
/* registers */
+ plat_regs_phys = addr;
plat_regs = ioremap(addr, size);
}
}
- cmap_regs = ioremap(0xf301b000, 0x1000); /* XXX not in prom? */
+ cmap_regs_phys = 0xf301b000; /* XXX not in prom? */
+ cmap_regs = ioremap(cmap_regs_phys, 0x1000);
/* Grok total video ram */
plat_regs->reg[16].r = (unsigned)frame_buffer;
@@ -560,10 +568,10 @@ platinum_init()
display_info.pitch = line_pitch;
display_info.mode = video_mode;
strncpy(display_info.name, "platinum", sizeof(display_info.name));
- display_info.fb_address = (unsigned long) frame_buffer + 0x10;
- display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
- display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
- display_info.disp_reg_address = (unsigned long) &plat_regs;
+ display_info.fb_address = frame_buffer_phys + init->fb_offset + 0x10;
+ display_info.cmap_adr_address = cmap_regs_phys;
+ display_info.cmap_data_address = cmap_regs_phys + 0x30;
+ display_info.disp_reg_address = plat_regs_phys;
}
int
diff --git a/drivers/macintosh/pmac-cons.c b/drivers/macintosh/pmac-cons.c
index 8c199e94f..731d19fe2 100644
--- a/drivers/macintosh/pmac-cons.c
+++ b/drivers/macintosh/pmac-cons.c
@@ -26,6 +26,7 @@
#include <linux/selection.h>
#include <linux/console_struct.h>
#include <linux/vt_kern.h>
+#include "../char/console_macros.h"
#include "pmac-cons.h"
#include "control.h"
#include "platinum.h"
@@ -95,6 +96,7 @@ struct mon_map {
{0x72d, VMODE_832_624_75}, /* 16" RGB (Goldfish) */
{0x730, VMODE_768_576_50I}, /* PAL (Alternate) */
{0x73a, VMODE_1152_870_75}, /* 3rd party 19" */
+ {0x73f, VMODE_640_480_67}, /* no sense lines connected at all */
{-1, VMODE_640_480_60}, /* catch-all, must be last */
};
@@ -183,12 +185,22 @@ struct display_interface {
aty_setmode, aty_set_palette, aty_set_blanking },
{ "ATY,XCLAIMVR", map_aty_display, aty_init,
aty_setmode, aty_set_palette, aty_set_blanking },
- { "ATY,RAGEII_M", map_aty_display, aty_init, // untested!!
+#if 0 /* problematic */
+ { "ATY,RAGEII_M", map_aty_display, aty_init,
+ aty_setmode, aty_set_palette, aty_set_blanking },
+#endif
+ { "ATY,XCLAIMVRPro", map_aty_display, aty_init,
+ aty_setmode, aty_set_palette, aty_set_blanking },
+ { "ATY,mach64_3DU", map_aty_display, aty_init,
aty_setmode, aty_set_palette, aty_set_blanking },
#endif
#ifdef CONFIG_IMSTT_VIDEO
- { "IMS,tt128mb", map_imstt_display, imstt_init,
- imstt_setmode, imstt_set_palette, imstt_set_blanking },
+ { "IMS,tt128mb", map_imstt_display_ibm, imstt_init,
+ imstt_setmode, imstt_set_palette_ibm, imstt_set_blanking },
+ { "IMS,tt128mb8", map_imstt_display_tvp, imstt_init,
+ imstt_setmode, imstt_set_palette_tvp, imstt_set_blanking },
+ { "IMS,tt128mb8A", map_imstt_display_tvp, imstt_init,
+ imstt_setmode, imstt_set_palette_tvp, imstt_set_blanking },
#endif
{ NULL }
};
@@ -593,6 +605,16 @@ console_setmode(struct vc_mode *mode, int doit)
}
int
+console_setcmap(int n_entries, unsigned char *red,
+ unsigned char *green, unsigned char *blue)
+{
+ if (current_display == NULL || current_display->set_palette == NULL)
+ return -EOPNOTSUPP;
+ (*current_display->set_palette)(red, green, blue, 0, n_entries);
+ return 0;
+}
+
+int
console_powermode(int mode)
{
if (mode == VC_POWERMODE_INQUIRY)
@@ -600,7 +622,7 @@ console_powermode(int mode)
if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
return -EINVAL;
if (current_display == NULL || current_display->set_blanking == NULL)
- return -ENXIO;
+ return mode == VESA_NO_BLANKING? 0: -ENXIO;
(*current_display->set_blanking)(mode);
vesa_blanked = mode;
return 0;
@@ -890,6 +912,7 @@ static int unknown_modes[] = {
static unsigned char *frame_buffer;
static unsigned char *unknown_cmap_adr;
static volatile unsigned char *unknown_cmap_data;
+static unsigned long frame_buffer_phys;
static int map_unknown(struct device_node *dp)
{
@@ -938,7 +961,8 @@ static int map_unknown(struct device_node *dp)
address = dp->addrs[i].address;
}
printk(KERN_INFO "%s: using address %x\n", dp->full_name, address);
- frame_buffer = ioremap(address, len);
+ frame_buffer_phys = address;
+ frame_buffer = __ioremap(frame_buffer_phys, len, _PAGE_WRITETHRU);
video_mode = 0;
color_mode = CMODE_8;
@@ -961,15 +985,15 @@ static int map_unknown(struct device_node *dp)
display_info.pitch = line_pitch;
display_info.mode = video_mode;
strncpy(display_info.name, dp->name, sizeof(display_info.name));
- display_info.fb_address = (unsigned long) frame_buffer;
+ display_info.fb_address = frame_buffer_phys;
display_info.cmap_adr_address = 0;
display_info.cmap_data_address = 0;
unknown_cmap_adr = 0;
/* XXX kludge for ati */
if (strncmp(dp->name, "ATY,", 4) == 0) {
- display_info.disp_reg_address = address + 0x7ffc00;
- display_info.cmap_adr_address = address + 0x7ffcc0;
- display_info.cmap_data_address = address + 0x7ffcc1;
+ display_info.disp_reg_address = frame_buffer_phys + 0x7ffc00;
+ display_info.cmap_adr_address = frame_buffer_phys + 0x7ffcc0;
+ display_info.cmap_data_address = frame_buffer_phys + 0x7ffcc1;
unknown_cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0;
unknown_cmap_data = unknown_cmap_adr + 1;
}
diff --git a/drivers/macintosh/valkyrie.c b/drivers/macintosh/valkyrie.c
index 63c8fe074..02b81ea72 100644
--- a/drivers/macintosh/valkyrie.c
+++ b/drivers/macintosh/valkyrie.c
@@ -18,6 +18,7 @@
#include <asm/io.h>
#include <asm/adb.h>
#include <asm/cuda.h>
+#include <asm/pgtable.h>
#include <linux/selection.h>
#include "pmac-cons.h"
#include "valkyrie.h"
@@ -62,6 +63,10 @@ static unsigned char *frame_buffer;
static struct cmap_regs *cmap_regs;
static struct valkyrie_regs *disp_regs;
+static unsigned long frame_buffer_phys;
+static unsigned long disp_regs_phys;
+static unsigned long cmap_regs_phys;
+
/*
* Register initialization tables for the valkyrie display.
*
@@ -161,7 +166,7 @@ read_valkyrie_sense()
__delay(20000);
sense |= (in_8(&disp_regs->msense) & 0x60) >> 5;
- out_8(&disp_regs->msense, 7);
+ out_8(&disp_regs->msense, 0);
return sense;
}
@@ -178,9 +183,12 @@ map_valkyrie_display(struct device_node *dp)
/* Map in frame buffer and registers */
addr = dp->addrs[0].address;
- frame_buffer = ioremap(addr, 0x100000);
- disp_regs = ioremap(addr + 0x30a000, 4096);
- cmap_regs = ioremap(addr + 0x304000, 4096);
+ frame_buffer_phys = addr;
+ frame_buffer = __ioremap(addr, 0x100000, _PAGE_WRITETHRU);
+ disp_regs_phys = addr + 0x30a000;
+ disp_regs = ioremap(disp_regs_phys, 4096);
+ cmap_regs_phys = addr + 0x304000;
+ cmap_regs = ioremap(cmap_regs_phys, 4096);
/* Read the monitor sense value and choose the video mode */
sense = read_valkyrie_sense();
@@ -266,10 +274,10 @@ valkyrie_init()
display_info.pitch = line_pitch;
display_info.mode = video_mode;
strncpy(display_info.name, "valkyrie", sizeof(display_info.name));
- display_info.fb_address = (unsigned long) frame_buffer + 0x1000;
- display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
- display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
- display_info.disp_reg_address = (unsigned long) &disp_regs;
+ display_info.fb_address = frame_buffer_phys + 0x1000;
+ display_info.cmap_adr_address = cmap_regs_phys;
+ display_info.cmap_data_address = cmap_regs_phys + 8;
+ display_info.disp_reg_address = disp_regs_phys;
}
int
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 6185e16c5..55fd8ea92 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -18,6 +18,7 @@
#include <asm/adb.h>
#include <asm/cuda.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
#include <asm/system.h>
static volatile unsigned char *via;
@@ -98,7 +99,7 @@ via_cuda_init()
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]);
+ printk(" %x", vias->intrs[i].line);
printk("\n"); }
#endif
@@ -108,7 +109,7 @@ via_cuda_init()
if (vias->n_addrs < 1 || vias->n_intrs < 1)
return;
}
- via = (volatile unsigned char *) vias->addrs->address;
+ via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
if (!init_via()) {
printk(KERN_ERR "init_via failed\n");
@@ -117,8 +118,8 @@ via_cuda_init()
cuda_state = idle;
- if (request_irq(vias->intrs[0], via_interrupt, 0, "VIA", (void *)0)) {
- printk(KERN_ERR "VIA: can't get irq %d\n", vias->intrs[0]);
+ if (request_irq(vias->intrs[0].line, via_interrupt, 0, "VIA", (void *)0)) {
+ printk(KERN_ERR "VIA: can't get irq %d\n", vias->intrs[0].line);
return;
}
@@ -238,6 +239,14 @@ cuda_send_request(struct adb_request *req)
{
unsigned long flags;
+ if (via == NULL) {
+ req->complete = 1;
+ return -ENXIO;
+ }
+ if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) {
+ req->complete = 1;
+ return -EINVAL;
+ }
req->next = 0;
req->sent = 0;
req->complete = 0;
@@ -388,6 +397,17 @@ via_interrupt(int irq, void *arg, struct pt_regs *regs)
if (reading_reply) {
req = current_req;
req->reply_len = reply_ptr - req->reply;
+ if (req->data[0] == ADB_PACKET) {
+ /* Have to adjust the reply from ADB commands */
+ if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) {
+ /* the 0x2 bit indicates no response */
+ req->reply_len = 0;
+ } else {
+ /* leave just the command and result bytes in the reply */
+ req->reply_len -= 2;
+ memmove(req->reply, req->reply + 2, req->reply_len);
+ }
+ }
req->complete = 1;
current_req = req->next;
if (req->done)
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
new file mode 100644
index 000000000..922aed06b
--- /dev/null
+++ b/drivers/macintosh/via-pmu.c
@@ -0,0 +1,669 @@
+/*
+ * Device driver for the via-pmu on Apple Powermacs.
+ *
+ * The VIA (versatile interface adapter) interfaces to the PMU,
+ * a 6805 microprocessor core whose primary function is to control
+ * battery charging and system power on the PowerBook 3400 and 2400.
+ * The PMU also controls the ADB (Apple Desktop Bus) which connects
+ * to the keyboard and mouse, as well as the non-volatile RAM
+ * and the RTC (real time clock) chip.
+ *
+ * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
+ */
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/prom.h>
+#include <asm/adb.h>
+#include <asm/pmu.h>
+#include <asm/cuda.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+static volatile unsigned char *via;
+
+/* VIA registers - spaced 0x200 bytes apart */
+#define RS 0x200 /* skip between registers */
+#define B 0 /* B-side data */
+#define A RS /* A-side data */
+#define DIRB (2*RS) /* B-side direction (1=output) */
+#define DIRA (3*RS) /* A-side direction (1=output) */
+#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
+#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
+#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
+#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
+#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
+#define SR (10*RS) /* Shift register */
+#define ACR (11*RS) /* Auxiliary control register */
+#define PCR (12*RS) /* Peripheral control register */
+#define IFR (13*RS) /* Interrupt flag register */
+#define IER (14*RS) /* Interrupt enable register */
+#define ANH (15*RS) /* A-side data, no handshake */
+
+/* Bits in B data register: both active low */
+#define TACK 0x08 /* Transfer acknowledge (input) */
+#define TREQ 0x10 /* Transfer request (output) */
+
+/* Bits in ACR */
+#define SR_CTRL 0x1c /* Shift register control bits */
+#define SR_EXT 0x0c /* Shift on external clock */
+#define SR_OUT 0x10 /* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET 0x80 /* set bits in IER */
+#define IER_CLR 0 /* clear bits in IER */
+#define SR_INT 0x04 /* Shift register full/empty */
+#define CB1_INT 0x10 /* transition on CB1 input */
+
+static enum pmu_state {
+ idle,
+ sending,
+ intack,
+ reading,
+ reading_intr,
+} 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 *reply_ptr;
+static int data_index;
+static int data_len;
+static int adb_int_pending;
+static int pmu_adb_flags;
+static int adb_dev_map = 0;
+static struct adb_request bright_req_1, bright_req_2;
+
+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_adb_send_request(struct adb_request *req, int sync);
+static int pmu_adb_autopoll(int on);
+static void send_byte(int x);
+static void recv_byte(void);
+static void pmu_sr_intr(struct pt_regs *regs);
+static void pmu_done(struct adb_request *req);
+static void pmu_handle_data(unsigned char *data, int len,
+ struct pt_regs *regs);
+static void set_brightness(int level);
+static void set_volume(int level);
+
+/*
+ * This table indicates for each PMU opcode:
+ * - the number of data bytes to be sent with the command, or -1
+ * if a length byte should be sent,
+ * - the number of response bytes which the PMU will return, or
+ * -1 if it will send a length byte.
+ */
+static s8 pmu_data_len[256][2] = {
+/* 0 1 2 3 4 5 6 7 */
+/*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*10*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*18*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},
+/*20*/ {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*28*/ { 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*30*/ { 4, 0},{20, 0},{ 2, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*38*/ { 0, 4},{ 0,20},{ 1, 1},{ 2, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*40*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*48*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
+/*50*/ { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},
+/*58*/ { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},
+/*60*/ { 2, 0},{-1, 0},{ 2, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*68*/ { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},
+/*70*/ { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 4, 1},{ 4, 1},
+/*80*/ { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*88*/ { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*90*/ { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*98*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*a0*/ { 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},
+/*a8*/ { 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*b0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*b8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*c0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*c8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*d0*/ { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*d8*/ { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},
+/*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*e8*/ { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},
+/*f0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+};
+
+void
+via_pmu_init()
+{
+ struct device_node *vias;
+
+ vias = find_devices("via-pmu");
+ if (vias == 0)
+ return;
+ if (vias->next != 0)
+ printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
+
+#if 0
+ { int i;
+
+ printk("via_pmu_init: 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",
+ vias->n_addrs, vias->n_intrs);
+ if (vias->n_addrs < 1 || vias->n_intrs < 1)
+ return;
+ }
+ via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
+
+ out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
+
+ pmu_state = idle;
+
+ if (!init_pmu())
+ return;
+
+ if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
+ (void *)0)) {
+ printk(KERN_ERR "VIA-PMU: can't get irq %d\n",
+ vias->intrs[0].line);
+ return;
+ }
+
+ /* Enable interrupts */
+ out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
+
+ /* Set function pointers */
+ adb_hardware = ADB_VIAPMU;
+ adb_send_request = pmu_adb_send_request;
+ adb_autopoll = pmu_adb_autopoll;
+
+ bright_req_1.complete = 1;
+ bright_req_2.complete = 1;
+}
+
+static int
+init_pmu()
+{
+ int timeout;
+ struct adb_request req;
+
+ 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);
+ timeout = 100000;
+ while (!req.complete) {
+ if (--timeout < 0) {
+ printk(KERN_ERR "init_pmu: no response from PMU\n");
+ return 0;
+ }
+ udelay(10);
+ pmu_poll();
+ }
+
+ /* ack all pending interrupts */
+ timeout = 100000;
+ interrupt_data[0] = 1;
+ while (interrupt_data[0] || pmu_state != idle) {
+ if (--timeout < 0) {
+ printk(KERN_ERR "init_pmu: timed out acking intrs\n");
+ return 0;
+ }
+ if (pmu_state == idle)
+ adb_int_pending = 1;
+ via_pmu_interrupt(0, 0, 0);
+ udelay(10);
+ }
+
+ return 1;
+}
+
+/* Send an ADB command */
+static int
+pmu_adb_send_request(struct adb_request *req, int sync)
+{
+ int i;
+
+ for (i = req->nbytes - 1; i > 0; --i)
+ req->data[i+3] = req->data[i];
+ req->data[3] = req->nbytes - 1;
+ req->data[2] = pmu_adb_flags;
+ req->data[1] = req->data[0];
+ req->data[0] = PMU_ADB_CMD;
+ req->nbytes += 3;
+ req->reply_expected = 1;
+ req->reply_len = 0;
+ i = pmu_queue_request(req);
+ if (i)
+ return i;
+ if (sync) {
+ while (!req->complete)
+ pmu_poll();
+ }
+ return 0;
+}
+
+/* Enable/disable autopolling */
+static int
+pmu_adb_autopoll(int on)
+{
+ struct adb_request req;
+
+ if (on) {
+ pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,
+ adb_dev_map >> 8, adb_dev_map);
+ pmu_adb_flags = 2;
+ } else {
+ pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF);
+ pmu_adb_flags = 0;
+ }
+ while (!req.complete)
+ pmu_poll();
+ return 0;
+}
+
+/* Construct and send a pmu request */
+int
+pmu_request(struct adb_request *req, void (*done)(struct adb_request *),
+ int nbytes, ...)
+{
+ va_list list;
+ int i;
+
+ if (nbytes < 0 || nbytes > 32) {
+ printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes);
+ req->complete = 1;
+ return -EINVAL;
+ }
+ req->nbytes = nbytes;
+ req->done = done;
+ va_start(list, nbytes);
+ for (i = 0; i < nbytes; ++i)
+ req->data[i] = va_arg(list, int);
+ va_end(list);
+ if (pmu_data_len[req->data[0]][1] != 0) {
+ req->reply[0] = ADB_RET_OK;
+ req->reply_len = 1;
+ } else
+ req->reply_len = 0;
+ req->reply_expected = 0;
+ return pmu_queue_request(req);
+}
+
+/*
+ * This procedure handles requests written to /dev/adb where the
+ * first byte is CUDA_PACKET or PMU_PACKET. For CUDA_PACKET, we
+ * emulate a few CUDA requests.
+ */
+int
+pmu_send_request(struct adb_request *req)
+{
+ int i;
+
+ switch (req->data[0]) {
+ case PMU_PACKET:
+ for (i = 0; i < req->nbytes - 1; ++i)
+ req->data[i] = req->data[i+1];
+ --req->nbytes;
+ if (pmu_data_len[req->data[0]][1] != 0) {
+ req->reply[0] = ADB_RET_OK;
+ req->reply_len = 1;
+ } else
+ req->reply_len = 0;
+ return pmu_queue_request(req);
+ case CUDA_PACKET:
+ switch (req->data[1]) {
+ case CUDA_GET_TIME:
+ if (req->nbytes != 2)
+ break;
+ req->data[0] = PMU_READ_RTC;
+ req->nbytes = 1;
+ req->reply_len = 3;
+ req->reply[0] = CUDA_PACKET;
+ req->reply[1] = 0;
+ req->reply[2] = CUDA_GET_TIME;
+ return pmu_queue_request(req);
+ case CUDA_SET_TIME:
+ if (req->nbytes != 6)
+ break;
+ req->data[0] = PMU_SET_RTC;
+ req->nbytes = 5;
+ for (i = 1; i <= 4; ++i)
+ req->data[i] = req->data[i+1];
+ req->reply_len = 0;
+ return pmu_queue_request(req);
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+int
+pmu_queue_request(struct adb_request *req)
+{
+ unsigned long flags;
+ int nsend;
+
+ if (via == NULL) {
+ req->complete = 1;
+ return -ENXIO;
+ }
+ if (req->nbytes <= 0) {
+ req->complete = 1;
+ return 0;
+ }
+ nsend = pmu_data_len[req->data[0]][0];
+ if (nsend >= 0 && req->nbytes != nsend + 1) {
+ req->complete = 1;
+ return -EINVAL;
+ }
+
+ req->next = 0;
+ req->sent = 0;
+ req->complete = 0;
+ save_flags(flags); cli();
+
+ if (current_req != 0) {
+ last_req->next = req;
+ last_req = req;
+ } else {
+ current_req = req;
+ last_req = req;
+ if (pmu_state == idle)
+ pmu_start();
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+static void
+send_byte(int x)
+{
+ out_8(&via[ACR], 0x1c);
+ out_8(&via[SR], x);
+ out_8(&via[B], via[B] & ~0x10); /* assert TREQ */
+}
+
+static void
+recv_byte()
+{
+ out_8(&via[ACR], 0x0c);
+ in_8(&via[SR]); /* resets SR */
+ out_8(&via[B], via[B] & ~0x10);
+}
+
+static void
+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;
+
+ pmu_state = sending;
+ data_index = 1;
+ data_len = pmu_data_len[req->data[0]][0];
+
+ /* set the shift register to shift out and send a byte */
+ send_byte(req->data[0]);
+
+out:
+ restore_flags(flags);
+}
+
+void
+pmu_poll()
+{
+ int ie;
+
+ ie = _disable_interrupts();
+ if (via[IFR] & (SR_INT | CB1_INT))
+ via_pmu_interrupt(0, 0, 0);
+ _enable_interrupts(ie);
+}
+
+static void
+via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+ int intr;
+ int nloop = 0;
+
+ while ((intr = (in_8(&via[IFR]) & (SR_INT | CB1_INT))) != 0) {
+ if (++nloop > 1000) {
+ printk(KERN_DEBUG "PMU: stuck in intr loop, "
+ "intr=%x pmu_state=%d\n", intr, pmu_state);
+ break;
+ }
+ if (intr & SR_INT)
+ pmu_sr_intr(regs);
+ else if (intr & CB1_INT) {
+ adb_int_pending = 1;
+ out_8(&via[IFR], CB1_INT);
+ }
+ }
+ if (pmu_state == idle) {
+ if (adb_int_pending) {
+ pmu_state = intack;
+ send_byte(PMU_INT_ACK);
+ adb_int_pending = 0;
+ } else if (current_req) {
+ pmu_start();
+ }
+ }
+}
+
+static void
+pmu_sr_intr(struct pt_regs *regs)
+{
+ struct adb_request *req;
+ int bite, timeout;
+
+ if (via[B] & TACK)
+ printk(KERN_DEBUG "PMU: sr_intr but ack still high! (%x)\n",
+ via[B]);
+
+ /* if reading grab the byte, and reset the interrupt */
+ if ((via[ACR] & SR_OUT) == 0)
+ bite = in_8(&via[SR]);
+ out_8(&via[IFR], SR_INT);
+
+ /* reset TREQ and wait for TACK to go high */
+ out_8(&via[B], 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);
+ }
+
+ switch (pmu_state) {
+ case sending:
+ req = current_req;
+ if (data_len < 0) {
+ data_len = req->nbytes - 1;
+ send_byte(data_len);
+ break;
+ }
+ if (data_index <= data_len) {
+ send_byte(req->data[data_index++]);
+ break;
+ }
+ req->sent = 1;
+ data_len = pmu_data_len[req->data[0]][1];
+ if (data_len == 0) {
+ pmu_state = idle;
+ current_req = req->next;
+ if (req->reply_expected)
+ req_awaiting_reply = req;
+ else
+ pmu_done(req);
+ } else {
+ pmu_state = reading;
+ data_index = 0;
+ reply_ptr = req->reply + req->reply_len;
+ recv_byte();
+ }
+ break;
+
+ case intack:
+ data_index = 0;
+ data_len = -1;
+ pmu_state = reading_intr;
+ reply_ptr = interrupt_data;
+ recv_byte();
+ break;
+
+ case reading:
+ case reading_intr:
+ if (data_len == -1) {
+ data_len = bite;
+ if (bite > 32)
+ printk(KERN_ERR "PMU: bad reply len %d\n",
+ bite);
+ } else {
+ reply_ptr[data_index++] = bite;
+ }
+ if (data_index < data_len) {
+ recv_byte();
+ break;
+ }
+
+ if (pmu_state == reading_intr) {
+ pmu_handle_data(interrupt_data, data_index, regs);
+ } else {
+ req = current_req;
+ current_req = req->next;
+ req->reply_len += data_index;
+ pmu_done(req);
+ }
+ pmu_state = idle;
+
+ break;
+
+ default:
+ printk(KERN_ERR "via_pmu_interrupt: unknown state %d?\n",
+ pmu_state);
+ }
+}
+
+static void
+pmu_done(struct adb_request *req)
+{
+ req->complete = 1;
+ if (req->done)
+ (*req->done)(req);
+}
+
+/* Interrupt data could be the result data from an ADB cmd */
+static void
+pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
+{
+ static int show_pmu_ints = 1;
+
+ if (len < 1) {
+ adb_int_pending = 0;
+ return;
+ }
+ if (data[0] & PMU_INT_ADB) {
+ if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
+ struct adb_request *req = req_awaiting_reply;
+ if (req == 0) {
+ printk(KERN_ERR "PMU: extra ADB reply\n");
+ return;
+ }
+ req_awaiting_reply = 0;
+ if (len <= 2)
+ req->reply_len = 0;
+ else {
+ memcpy(req->reply, data + 1, len - 1);
+ req->reply_len = len - 1;
+ }
+ pmu_done(req);
+ } else {
+ adb_input(data+1, len-1, regs, 1);
+ }
+ } else {
+ if (data[0] == 0x08 && len == 3) {
+ /* sound/brightness buttons pressed */
+ set_brightness(data[1]);
+ set_volume(data[2]);
+ } else if (show_pmu_ints
+ && !(data[0] == PMU_INT_TICK && len == 1)) {
+ int i;
+ printk(KERN_DEBUG "pmu intr");
+ for (i = 0; i < len; ++i)
+ printk(" %.2x", data[i]);
+ printk("\n");
+ }
+ }
+}
+
+int backlight_bright = -1;
+int backlight_enabled = 0;
+
+#define LEVEL_TO_BRIGHT(lev) ((lev) < 8? 0x7f: 0x4a - ((lev) >> 2))
+
+void
+pmu_enable_backlight(int on)
+{
+ struct adb_request req;
+
+ if (on) {
+ if (backlight_bright < 0) {
+ pmu_request(&req, NULL, 2, 0xd9, 0);
+ while (!req.complete)
+ pmu_poll();
+ backlight_bright = LEVEL_TO_BRIGHT(req.reply[1]);
+ }
+ pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+ backlight_bright);
+ while (!req.complete)
+ pmu_poll();
+ }
+ pmu_request(&req, NULL, 2, PMU_BACKLIGHT_CTRL, on? 0x81: 1);
+ while (!req.complete)
+ pmu_poll();
+ backlight_enabled = on;
+}
+
+static void
+set_brightness(int level)
+{
+ backlight_bright = LEVEL_TO_BRIGHT(level);
+ if (bright_req_1.complete)
+ pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+ backlight_bright);
+ if (bright_req_2.complete) {
+ backlight_enabled = backlight_bright < 0x7f;
+ pmu_request(&bright_req_2, NULL, 2, PMU_BACKLIGHT_CTRL,
+ backlight_enabled? 0x81: 1);
+ }
+}
+
+static void
+set_volume(int level)
+{
+}