summaryrefslogtreecommitdiffstats
path: root/drivers/macintosh/mediabay.c
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/mediabay.c
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/mediabay.c')
-rw-r--r--drivers/macintosh/mediabay.c236
1 files changed, 236 insertions, 0 deletions
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));
+}