summaryrefslogtreecommitdiffstats
path: root/drivers/macintosh/mediabay.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/macintosh/mediabay.c')
-rw-r--r--drivers/macintosh/mediabay.c308
1 files changed, 211 insertions, 97 deletions
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 53f7ab62e..13ce064f4 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -8,6 +8,8 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+#define __KERNEL_SYSCALLS__
+
#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -16,44 +18,54 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/hdreg.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
#include <asm/prom.h>
#include <asm/pgtable.h>
#include <asm/io.h>
-#include <asm/ohare.h>
+#include <asm/feature.h>
#include <asm/mediabay.h>
#include <asm/init.h>
+
+#undef MB_USE_INTERRUPTS
+
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;
+struct media_bay_info {
+ volatile struct media_bay_hw* addr;
+ int content_id;
+ int previous_id;
+ int ready;
+ int last_value;
+ int value_count;
+ int reset_timer;
+ struct device_node* dev_node;
+#ifdef CONFIG_BLK_DEV_IDE
+ unsigned long cd_base;
+ int cd_index;
+ int cd_irq;
+ int cd_timer;
+#endif
+};
-#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));
+#define MAX_BAYS 2
-static int media_bay_id = -1;
-static int mb_ready;
-static int mb_last_value;
-static int mb_value_count;
+static volatile struct media_bay_info media_bays[MAX_BAYS];
+int media_bay_count = 0;
-int media_bay_present;
+#define MB_CONTENTS(i) ((in_8(&media_bays[i].addr->contents) >> 4) & 7)
#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)
+#define MB_IDE_READY(i) ((in_8((volatile unsigned char *) \
+ (media_bays[i].cd_base + 0x70)) & 0x80) == 0)
#endif
/*
@@ -66,16 +78,17 @@ int mb_cd_irq;
* Hold the media-bay reset signal true for this many ticks
* after a device is inserted before releasing it.
*/
-#define MB_RESET_COUNT 10
+#define MB_RESET_COUNT 20
/*
* 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
+#define MB_IDE_WAIT 1000
-static void poll_media_bay(void);
-static void set_media_bay(int id);
+static void poll_media_bay(int which);
+static void set_media_bay(int which, int id);
+static int media_bay_task(void *);
/*
* It seems that the bit for the media-bay interrupt in the IRQ_LEVEL
@@ -92,29 +105,62 @@ void
media_bay_init(void)
{
struct device_node *np;
-
+ int n,i;
+
+ for (i=0; i<MAX_BAYS; i++)
+ {
+ memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info));
+ media_bays[i].content_id = -1;
+#ifdef CONFIG_BLK_DEV_IDE
+ media_bays[i].cd_index = -1;
+#endif
+ }
+
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));
+ n = 0;
+ while(np && (n<MAX_BAYS))
+ {
+ if (np->n_addrs == 0)
+ continue;
+ media_bays[n].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);
- }
+#ifdef MB_USE_INTERRUPTS
+ if (np->n_intrs == 0)
+ {
+ printk(KERN_ERR "media bay %d has no irq\n",n);
+ continue;
+ }
+
+ if (request_irq(np_intrs[0].line, media_bay_intr, 0, "Media bay", NULL))
+ {
+ printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", irq, n);
+ continue;
+ }
+#endif
+ media_bay_count++;
+
+ set_media_bay(n, MB_CONTENTS(n));
+ if (media_bays[n].content_id != MB_NO) {
+ feature_clear(media_bays[n].dev_node, FEATURE_Mediabay_reset);
+ udelay(500);
+ }
+ media_bays[n].ready = 1;
+ media_bays[n].previous_id = media_bays[n].content_id;
+ media_bays[n].reset_timer = 0;
+ media_bays[n].dev_node = np;
+#ifdef CONFIG_BLK_DEV_IDE
+ media_bays[n].cd_timer = 0;
#endif
+ n++;
+ np=np->next;
+ }
+
+ if (media_bay_count)
+ {
+ printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count);
- media_bay_present = 1;
- set_media_bay(MB_CONTENTS());
- if (media_bay_id != MB_NO) {
- SET_FEATURES(0, OH_BAY_RESET);
- mb_ready = 1;
+ kernel_thread(media_bay_task, NULL, 0);
}
}
@@ -130,9 +176,61 @@ media_bay_intr(int irq, void *devid, struct pt_regs *regs)
#endif
int
-check_media_bay(int what)
+check_media_bay(struct device_node *which_bay, int what)
+{
+#ifdef CONFIG_BLK_DEV_IDE
+ int i;
+
+ for (i=0; i<media_bay_count; i++)
+ if (which_bay == media_bays[i].dev_node)
+ {
+ if ((what == media_bays[i].content_id) && media_bays[i].ready)
+ return 0;
+ media_bays[i].cd_index = -1;
+ return -EINVAL;
+ }
+#endif /* CONFIG_BLK_DEV_IDE */
+ return -ENODEV;
+}
+
+int
+check_media_bay_by_base(unsigned long base, int what)
+{
+ int i;
+
+#ifdef CONFIG_BLK_DEV_IDE
+ for (i=0; i<media_bay_count; i++)
+ if (base == media_bays[i].cd_base)
+ {
+ if ((what == media_bays[i].content_id) && media_bays[i].ready)
+ return 0;
+ media_bays[i].cd_index = -1;
+ return -EINVAL;
+ }
+#endif
+
+ return -ENODEV;
+}
+
+int
+media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,
+ int irq, int index)
{
- return what == media_bay_id && mb_ready;
+ int i;
+
+#ifdef CONFIG_BLK_DEV_IDE
+ for (i=0; i<media_bay_count; i++)
+ if (which_bay == media_bays[i].dev_node)
+ {
+ media_bays[i].cd_base = base;
+ media_bays[i].cd_irq = irq;
+ media_bays[i].cd_index = index;
+ printk(KERN_DEBUG "Registered ide %d for media bay %d\n", index, i);
+ return 0;
+ }
+#endif
+
+ return -ENODEV;
}
/*
@@ -144,96 +242,112 @@ check_media_bay(int what)
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
-
+ volatile struct media_bay_info* bay;
+ int i = 0;
+
strcpy(current->comm, "media-bay");
- for (;;) {
- poll_media_bay();
- if (media_bay_id != prev) {
- reset_timer = (media_bay_id != MB_NO)?
+ for (;;)
+ {
+ bay = &media_bays[i];
+ poll_media_bay(i);
+ if (bay->content_id != bay->previous_id) {
+ bay->reset_timer = (bay->content_id != MB_NO) ?
MB_RESET_COUNT: 0;
- mb_ready = 0;
+ bay->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;
+ bay->cd_timer = 0;
+ if (bay->content_id != MB_CD && bay->cd_index >= 0) {
+ printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index);
+ ide_unregister(bay->cd_index);
+ bay->cd_index = -1;
}
#endif
- } else if (reset_timer) {
- if (--reset_timer == 0) {
- SET_FEATURES(0, OH_BAY_RESET);
- mb_ready = 1;
+ } else if (bay->reset_timer) {
+ if (--bay->reset_timer == 0) {
+ feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
+ bay->ready = 1;
#ifdef CONFIG_BLK_DEV_IDE
- if (media_bay_id == MB_CD && mb_cd_base != 0)
- cd_timer = MB_IDE_WAIT;
+ bay->cd_timer = 0;
+ if (bay->content_id == MB_CD && bay->cd_base != 0)
+ bay->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);
+ } else if (bay->cd_timer && (--bay->cd_timer == 0 || MB_IDE_READY(i))
+ && bay->cd_index < 0) {
+ bay->cd_timer = 0;
+ printk(KERN_DEBUG "Registering IDE, base:0x%08lx, irq:%d\n", bay->cd_base, bay->cd_irq);
+ printk("\n");
+ bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
+ if (bay->cd_index == -1)
+ printk("\nCD-ROM badly inserted. Remove it and try again !\n");
+ else
+ printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index);
#endif
}
- prev = media_bay_id;
+ bay->previous_id = bay->content_id;
current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + 1;
- schedule();
+ schedule_timeout(1);
if (signal_pending(current))
return 0;
+ i = (i+1)%media_bay_count;
}
}
void
-poll_media_bay(void)
+poll_media_bay(int which)
{
- int id = MB_CONTENTS();
+ int id = MB_CONTENTS(which);
- if (id == mb_last_value) {
- if (id != media_bay_id
- && ++mb_value_count >= MB_STABLE_COUNT)
- set_media_bay(id);
+ if (id == media_bays[which].last_value) {
+ if (id != media_bays[which].content_id
+ && ++media_bays[which].value_count >= MB_STABLE_COUNT)
+ set_media_bay(which, id);
} else {
- mb_last_value = id;
- mb_value_count = 0;
+ media_bays[which].last_value = id;
+ media_bays[which].value_count = 0;
}
}
static void
-set_media_bay(int id)
+set_media_bay(int which, int id)
{
- u32 clr, set;
+ volatile struct media_bay_info* bay;
- media_bay_id = id;
- mb_last_value = id;
- clr = OH_FLOPPY_ENABLE | OH_IDECD_POWER;
- set = 0;
+ bay = &media_bays[which];
+
+ bay->content_id = id;
+ bay->last_value = id;
+
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");
+ feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+ feature_set(bay->dev_node, FEATURE_Mediabay_enable);
+ feature_set(bay->dev_node, FEATURE_CD_power);
+ feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable);
+ printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
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");
+ feature_clear(bay->dev_node, FEATURE_CD_power);
+ feature_set(bay->dev_node, FEATURE_Mediabay_enable);
+ feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+ feature_set(bay->dev_node, FEATURE_SWIM3_enable);
+ printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which);
break;
case MB_NO:
- printk(KERN_INFO "media bay is empty\n");
+ feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+ feature_clear(bay->dev_node, FEATURE_CD_power);
+ printk(KERN_INFO "media bay %d is empty\n", which);
break;
default:
- set = OH_BAY_ENABLE;
- printk(KERN_INFO "media bay contains an unknown device (%d)\n",
- id);
+ feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+ feature_clear(bay->dev_node, FEATURE_CD_power);
+ feature_set(bay->dev_node, FEATURE_Mediabay_enable);
+ printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
+ which, id);
break;
}
-
- SET_FEATURES(set, clr);
- printk(KERN_DEBUG "feature reg now %x\n", in_le32(&mb_addr->feature));
+
+ udelay(500);
}