patch-2.4.18 linux/drivers/macintosh/mediabay.c
Next file: linux/drivers/macintosh/rtc.c
Previous file: linux/drivers/macintosh/macserial.h
Back to the patch index
Back to the overall index
- Lines: 828
- Date:
Wed Dec 26 16:32:31 2001
- Orig file:
linux.orig/drivers/macintosh/mediabay.c
- Orig date:
Mon Feb 18 20:18:39 2002
diff -Naur -X /home/marcelo/lib/dontdiff linux.orig/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c
@@ -25,9 +25,13 @@
#include <asm/prom.h>
#include <asm/pgtable.h>
#include <asm/io.h>
-#include <asm/feature.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
#include <asm/mediabay.h>
#include <asm/sections.h>
+#include <asm/ohare.h>
+#include <asm/heathrow.h>
+#include <asm/keylargo.h>
#include <linux/adb.h>
#include <linux/pmu.h>
@@ -40,7 +44,7 @@
#endif
#undef MB_USE_INTERRUPTS
-#undef MB_DEBUG
+#define MB_DEBUG
#define MB_IGNORE_SIGNALS
#ifdef MB_DEBUG
@@ -49,24 +53,46 @@
#define MBDBG(fmt, arg...) do { } while (0)
#endif
-struct media_bay_hw {
- unsigned char b0;
- unsigned char contents;
- unsigned char b2;
- unsigned char b3;
+/* Type of media bay */
+enum {
+ mb_ohare,
+ mb_heathrow,
+ mb_keylargo
+};
+
+#define MB_FCR32(bay, r) ((bay)->base + ((r) >> 2))
+#define MB_FCR8(bay, r) (((volatile u8*)((bay)->base)) + (r))
+
+#define MB_IN32(bay,r) (in_le32(MB_FCR32(bay,r)))
+#define MB_OUT32(bay,r,v) (out_le32(MB_FCR32(bay,r), (v)))
+#define MB_BIS(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) | (v)))
+#define MB_BIC(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) & ~(v)))
+#define MB_IN8(bay,r) (in_8(MB_FCR8(bay,r)))
+#define MB_OUT8(bay,r,v) (out_8(MB_FCR8(bay,r), (v)))
+
+struct media_bay_info;
+
+struct mb_ops {
+ char* name;
+ u8 (*content)(struct media_bay_info* bay);
+ void (*power)(struct media_bay_info* bay, int on_off);
+ int (*setup_bus)(struct media_bay_info* bay, u8 device_id);
+ void (*un_reset)(struct media_bay_info* bay);
+ void (*un_reset_ide)(struct media_bay_info* bay);
};
struct media_bay_info {
- volatile struct media_bay_hw* addr;
- volatile u8* extint_gpio;
+ volatile u32* base;
int content_id;
int state;
int last_value;
int value_count;
int timer;
struct device_node* dev_node;
- int pismo; /* New PowerBook3,1 */
- int gpio_cache;
+ int mb_type;
+ struct mb_ops* ops;
+ int index;
+ int cached_gpio;
#ifdef CONFIG_BLK_DEV_IDE
unsigned long cd_base;
int cd_index;
@@ -77,33 +103,12 @@
#define MAX_BAYS 2
-static volatile struct media_bay_info media_bays[MAX_BAYS];
+static struct media_bay_info media_bays[MAX_BAYS];
int media_bay_count = 0;
-inline int mb_content(volatile struct media_bay_info *bay)
-{
- if (bay->pismo) {
- unsigned char new_gpio = in_8(bay->extint_gpio + 0xe) & 2;
- if (new_gpio) {
- bay->gpio_cache = new_gpio;
- return MB_NO;
- } else if (bay->gpio_cache != new_gpio) {
- /* make sure content bits are set */
- feature_set(bay->dev_node, FEATURE_Mediabay_content);
- udelay(5);
- bay->gpio_cache = new_gpio;
- }
- return (in_le32((unsigned*)bay->addr) >> 4) & 0xf;
- } else {
- int cont = (in_8(&bay->addr->contents) >> 4) & 7;
- return (cont == 7) ? MB_NO : cont;
- }
-}
-
#ifdef CONFIG_BLK_DEV_IDE
/* check the busy bit in the media-bay ide interface
(assumes the media-bay contains an ide device) */
-//#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0xc0) == 0x40)
#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0x80) == 0)
#endif
@@ -116,7 +121,7 @@
* Consider the media-bay ID value stable if it is the same for
* this number of milliseconds
*/
-#define MB_STABLE_DELAY 40
+#define MB_STABLE_DELAY 100
/* Wait after powering up the media bay this delay in ms
* timeout bumped for some powerbooks
@@ -166,175 +171,259 @@
mb_powering_down /* Powering down (avoid too fast down/up) */
};
-static void poll_media_bay(int which);
-static void set_media_bay(int which, int id);
-static void set_mb_power(int which, int onoff);
-static void media_bay_step(int i);
-static int media_bay_task(void *);
+#define MB_POWER_SOUND 0x08
+#define MB_POWER_FLOPPY 0x04
+#define MB_POWER_ATA 0x02
+#define MB_POWER_PCI 0x01
+#define MB_POWER_OFF 0x00
-#ifdef MB_USE_INTERRUPTS
-static void media_bay_intr(int irq, void *devid, struct pt_regs *regs);
-#endif
+/*
+ * Functions for polling content of media bay
+ */
+
+static u8 __pmac
+ohare_mb_content(struct media_bay_info *bay)
+{
+ return (MB_IN32(bay, OHARE_MBCR) >> 12) & 7;
+}
+
+static u8 __pmac
+heathrow_mb_content(struct media_bay_info *bay)
+{
+ return (MB_IN32(bay, HEATHROW_MBCR) >> 12) & 7;
+}
+
+static u8 __pmac
+keylargo_mb_content(struct media_bay_info *bay)
+{
+ int new_gpio;
+
+ new_gpio = MB_IN8(bay, KL_GPIO_MEDIABAY_IRQ) & KEYLARGO_GPIO_INPUT_DATA;
+ if (new_gpio) {
+ bay->cached_gpio = new_gpio;
+ return MB_NO;
+ } else if (bay->cached_gpio != new_gpio) {
+ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE);
+ (void)MB_IN32(bay, KEYLARGO_MBCR);
+ udelay(5);
+ MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F);
+ (void)MB_IN32(bay, KEYLARGO_MBCR);
+ udelay(5);
+ bay->cached_gpio = new_gpio;
+ }
+ return (MB_IN32(bay, KEYLARGO_MBCR) >> 4) & 7;
+}
/*
- * 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.
+ * Functions for powering up/down the bay, puts the bay device
+ * into reset state as well
*/
-void __pmac
-media_bay_init(void)
+static void __pmac
+ohare_mb_power(struct media_bay_info* bay, int on_off)
{
- 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
+ if (on_off) {
+ /* Power up device, assert it's reset line */
+ MB_BIC(bay, OHARE_FCR, OH_BAY_RESET_N);
+ MB_BIC(bay, OHARE_FCR, OH_BAY_POWER_N);
+ } else {
+ /* Disable all devices */
+ MB_BIC(bay, OHARE_FCR, OH_BAY_DEV_MASK);
+ MB_BIC(bay, OHARE_FCR, OH_FLOPPY_ENABLE);
+ /* Cut power from bay, release reset line */
+ MB_BIS(bay, OHARE_FCR, OH_BAY_POWER_N);
+ MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N);
+ MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N);
}
-
- np = find_devices("media-bay");
- 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));
+ MB_BIC(bay, OHARE_MBCR, 0x00000F00);
+}
- media_bays[n].pismo = device_is_compatible(np, "keylargo-media-bay");
- if (media_bays[n].pismo) {
- if (!np->parent || strcmp(np->parent->name, "mac-io")) {
- printk(KERN_ERR "Pismo media-bay has no mac-io parent !\n");
- continue;
- }
- media_bays[n].extint_gpio = ioremap(np->parent->addrs[0].address
- + 0x58, 0x10);
- }
+static void __pmac
+heathrow_mb_power(struct media_bay_info* bay, int on_off)
+{
+ if (on_off) {
+ /* Power up device, assert it's reset line */
+ MB_BIC(bay, HEATHROW_FCR, HRW_BAY_RESET_N);
+ MB_BIC(bay, HEATHROW_FCR, HRW_BAY_POWER_N);
+ } else {
+ /* Disable all devices */
+ MB_BIC(bay, HEATHROW_FCR, HRW_BAY_DEV_MASK);
+ MB_BIC(bay, HEATHROW_FCR, HRW_SWIM_ENABLE);
+ /* Cut power from bay, release reset line */
+ MB_BIS(bay, HEATHROW_FCR, HRW_BAY_POWER_N);
+ MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N);
+ MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N);
+ }
+ MB_BIC(bay, HEATHROW_MBCR, 0x00000F00);
+}
-#ifdef MB_USE_INTERRUPTS
- if (np->n_intrs == 0) {
- printk(KERN_ERR "media bay %d has no irq\n",n);
- continue;
- }
+static void __pmac
+keylargo_mb_power(struct media_bay_info* bay, int on_off)
+{
+ if (on_off) {
+ /* Power up device, assert it's reset line */
+ MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET);
+ MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER);
+ } else {
+ /* Disable all devices */
+ MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
+ MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE);
+ /* Cut power from bay, release reset line */
+ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER);
+ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET);
+ MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N);
+ }
+ MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F);
+}
- if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) {
- printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n",
- np->intrs[0].line, n);
- continue;
- }
-#endif
- media_bay_count++;
-
- media_bays[n].dev_node = np;
+/*
+ * Functions for configuring the media bay for a given type of device,
+ * enable the related busses
+ */
- /* Force an immediate detect */
- set_mb_power(n,0);
- mdelay(MB_POWER_DELAY);
- if(!media_bays[n].pismo)
- out_8(&media_bays[n].addr->contents, 0x70);
- mdelay(MB_STABLE_DELAY);
- media_bays[n].content_id = MB_NO;
- media_bays[n].last_value = mb_content(&media_bays[n]);
- media_bays[n].value_count = MS_TO_HZ(MB_STABLE_DELAY);
- media_bays[n].state = mb_empty;
- do {
- mdelay(1000/HZ);
- media_bay_step(n);
- } while((media_bays[n].state != mb_empty) &&
- (media_bays[n].state != mb_up));
+static int __pmac
+ohare_mb_setup_bus(struct media_bay_info* bay, u8 device_id)
+{
+ switch(device_id) {
+ case MB_FD:
+ case MB_FD1:
+ MB_BIS(bay, OHARE_FCR, OH_BAY_FLOPPY_ENABLE);
+ MB_BIS(bay, OHARE_FCR, OH_FLOPPY_ENABLE);
+ return 0;
+ case MB_CD:
+ MB_BIC(bay, OHARE_FCR, OH_IDE1_RESET_N);
+ MB_BIS(bay, OHARE_FCR, OH_BAY_IDE_ENABLE);
+ return 0;
+ case MB_PCI:
+ MB_BIS(bay, OHARE_FCR, OH_BAY_PCI_ENABLE);
+ return 0;
+ }
+ return -ENODEV;
+}
- n++;
- np=np->next;
+static int __pmac
+heathrow_mb_setup_bus(struct media_bay_info* bay, u8 device_id)
+{
+ switch(device_id) {
+ case MB_FD:
+ case MB_FD1:
+ MB_BIS(bay, HEATHROW_FCR, HRW_BAY_FLOPPY_ENABLE);
+ MB_BIS(bay, HEATHROW_FCR, HRW_SWIM_ENABLE);
+ return 0;
+ case MB_CD:
+ MB_BIC(bay, HEATHROW_FCR, HRW_IDE1_RESET_N);
+ MB_BIS(bay, HEATHROW_FCR, HRW_BAY_IDE_ENABLE);
+ return 0;
+ case MB_PCI:
+ MB_BIS(bay, HEATHROW_FCR, HRW_BAY_PCI_ENABLE);
+ return 0;
}
+ return -ENODEV;
+}
- if (media_bay_count)
- {
- printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count);
+static int __pmac
+keylargo_mb_setup_bus(struct media_bay_info* bay, u8 device_id)
+{
+ switch(device_id) {
+ case MB_CD:
+ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE);
+ MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N);
+ MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE);
+ return 0;
+ case MB_PCI:
+ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_PCI_ENABLE);
+ return 0;
+ case MB_SOUND:
+ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_SOUND_ENABLE);
+ return 0;
+ }
+ return -ENODEV;
+}
-#ifdef CONFIG_PMAC_PBOOK
- pmu_register_sleep_notifier(&mb_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+/*
+ * Functions for tweaking resets
+ */
- kernel_thread(media_bay_task, NULL,
- CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
- }
+static void __pmac
+ohare_mb_un_reset(struct media_bay_info* bay)
+{
+ MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N);
}
-#ifdef MB_USE_INTERRUPTS
static void __pmac
-media_bay_intr(int irq, void *devid, struct pt_regs *regs)
+heathrow_mb_un_reset(struct media_bay_info* bay)
{
+ MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N);
+}
+
+static void __pmac
+keylargo_mb_un_reset(struct media_bay_info* bay)
+{
+ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET);
+}
+
+static void __pmac
+ohare_mb_un_reset_ide(struct media_bay_info* bay)
+{
+ MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N);
+}
+
+static void __pmac
+heathrow_mb_un_reset_ide(struct media_bay_info* bay)
+{
+ MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N);
}
-#endif
static void __pmac
-set_mb_power(int which, int onoff)
+keylargo_mb_un_reset_ide(struct media_bay_info* bay)
{
- volatile struct media_bay_info* mb = &media_bays[which];
+ MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N);
+}
+static inline void __pmac
+set_mb_power(struct media_bay_info* bay, int onoff)
+{
+ /* Power up up and assert the bay reset line */
if (onoff) {
- feature_set(mb->dev_node, FEATURE_Mediabay_power);
- udelay(10);
- feature_set(mb->dev_node, FEATURE_Mediabay_reset);
- udelay(10);
- mb->state = mb_powering_up;
- MBDBG("mediabay%d: powering up\n", which);
- } else {
- feature_clear(mb->dev_node, FEATURE_Mediabay_floppy_enable);
- if (mb->pismo)
- feature_clear(mb->dev_node, FEATURE_IDE0_enable);
- else
- feature_clear(mb->dev_node, FEATURE_IDE1_enable);
- feature_clear(mb->dev_node, FEATURE_Mediabay_IDE_switch);
- feature_clear(mb->dev_node, FEATURE_Mediabay_PCI_enable);
- feature_clear(mb->dev_node, FEATURE_SWIM3_enable);
- feature_clear(mb->dev_node, FEATURE_Mediabay_power);
- mb->state = mb_powering_down;
- MBDBG("mediabay%d: powering down\n", which);
+ bay->ops->power(bay, 1);
+ bay->state = mb_powering_up;
+ MBDBG("mediabay%d: powering up\n", bay->index);
+ } else {
+ /* Make sure everything is powered down & disabled */
+ bay->ops->power(bay, 0);
+ bay->state = mb_powering_down;
+ MBDBG("mediabay%d: powering down\n", bay->index);
}
- mb->timer = MS_TO_HZ(MB_POWER_DELAY);
+ bay->timer = MS_TO_HZ(MB_POWER_DELAY);
}
static void __pmac
-set_media_bay(int which, int id)
+poll_media_bay(struct media_bay_info* bay)
{
- volatile struct media_bay_info* bay;
+ int id = bay->ops->content(bay);
- bay = &media_bays[which];
-
- switch (id) {
- case MB_CD:
- if (bay->pismo) {
- feature_set(bay->dev_node, FEATURE_Mediabay_IDE_switch);
- udelay(10);
- feature_set(bay->dev_node, FEATURE_IDE0_enable);
- udelay(10);
- feature_set(bay->dev_node, FEATURE_IDE0_reset);
- } else {
- feature_set(bay->dev_node, FEATURE_IDE1_enable);
- udelay(10);
- feature_set(bay->dev_node, FEATURE_IDE1_reset);
+ if (id == bay->last_value) {
+ if (id != bay->content_id
+ && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) {
+ /* If the device type changes without going thru "MB_NO", we force
+ a pass by "MB_NO" to make sure things are properly reset */
+ if ((id != MB_NO) && (bay->content_id != MB_NO)) {
+ id = MB_NO;
+ MBDBG("mediabay%d: forcing MB_NO\n", bay->index);
}
- printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
- break;
- case MB_FD:
- case MB_FD1:
- 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:
- break;
- default:
- printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
- which, id);
- break;
+ MBDBG("mediabay%d: switching to %d\n", bay->index, id);
+ set_mb_power(bay, id != MB_NO);
+ bay->content_id = id;
+ if (id == MB_NO) {
+#ifdef CONFIG_BLK_DEV_IDE
+ bay->cd_retry = 0;
+#endif
+ printk(KERN_INFO "media bay %d is empty\n", bay->index);
+ }
+ }
+ } else {
+ bay->last_value = id;
+ bay->value_count = 0;
}
}
@@ -412,11 +501,11 @@
static void __pmac
media_bay_step(int i)
{
- volatile struct media_bay_info* bay = &media_bays[i];
+ struct media_bay_info* bay = &media_bays[i];
/* We don't poll when powering down */
if (bay->state != mb_powering_down)
- poll_media_bay(i);
+ poll_media_bay(bay);
/* If timer expired or polling IDE busy, run state machine */
if ((bay->state != mb_ide_waiting) && (bay->timer != 0) && ((--bay->timer) != 0))
@@ -424,13 +513,17 @@
switch(bay->state) {
case mb_powering_up:
- set_media_bay(i, bay->last_value);
+ if (bay->ops->setup_bus(bay, bay->last_value) < 0) {
+ MBDBG("mediabay%d: device not supported (kind:%d)\n", i, bay->content_id);
+ set_mb_power(bay, 0);
+ break;
+ }
bay->timer = MS_TO_HZ(MB_RESET_DELAY);
bay->state = mb_enabling_bay;
MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id);
break;
case mb_enabling_bay:
- feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
+ bay->ops->un_reset(bay);
bay->timer = MS_TO_HZ(MB_SETUP_DELAY);
bay->state = mb_resetting;
MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id);
@@ -444,16 +537,13 @@
}
#ifdef CONFIG_BLK_DEV_IDE
MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id);
- if (bay->pismo)
- feature_clear(bay->dev_node, FEATURE_IDE0_reset);
- else
- feature_clear(bay->dev_node, FEATURE_IDE1_reset);
+ bay->ops->un_reset_ide(bay);
bay->timer = MS_TO_HZ(MB_IDE_WAIT);
bay->state = mb_ide_resetting;
#else
printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i);
- set_mb_power(i, 0);
-#endif // #ifdef CONFIG_BLK_DEV_IDE
+ set_mb_power(bay, 0);
+#endif /* CONFIG_BLK_DEV_IDE */
break;
#ifdef CONFIG_BLK_DEV_IDE
@@ -481,7 +571,7 @@
/* We eventually do a retry */
bay->cd_retry++;
printk("IDE register error\n");
- set_mb_power(i, 0);
+ set_mb_power(bay, 0);
} else {
printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index);
MBDBG("mediabay %d IDE ready\n", i);
@@ -491,10 +581,10 @@
if (bay->timer == 0) {
printk("\nIDE Timeout in bay %d !\n", i);
MBDBG("mediabay%d: nIDE Timeout !\n", i);
- set_mb_power(i, 0);
+ set_mb_power(bay, 0);
}
break;
-#endif // #ifdef CONFIG_BLK_DEV_IDE
+#endif /* CONFIG_BLK_DEV_IDE */
case mb_powering_down:
bay->state = mb_empty;
@@ -514,7 +604,7 @@
bay->content_id = MB_NO;
}
}
-#endif
+#endif /* CONFIG_BLK_DEV_IDE */
MBDBG("mediabay%d: end of power down\n", i);
break;
}
@@ -526,7 +616,7 @@
* with the IDE driver. It needs to be a thread because
* ide_register can't be called from interrupt context.
*/
-int __pmac
+static int __pmac
media_bay_task(void *x)
{
int i;
@@ -547,37 +637,12 @@
}
}
-void __pmac
-poll_media_bay(int which)
+#ifdef MB_USE_INTERRUPTS
+static void __pmac
+media_bay_intr(int irq, void *devid, struct pt_regs *regs)
{
- volatile struct media_bay_info* bay = &media_bays[which];
- int id = mb_content(bay);
-
- if (id == bay->last_value) {
- if (id != bay->content_id
- && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) {
- /* If the device type changes without going thru "MB_NO", we force
- a pass by "MB_NO" to make sure things are properly reset */
- if ((id != MB_NO) && (bay->content_id != MB_NO)) {
- id = MB_NO;
- MBDBG("mediabay%d: forcing MB_NO\n", which);
- }
- MBDBG("mediabay%d: switching to %d\n", which, id);
- set_mb_power(which, id != MB_NO);
- bay->content_id = id;
- if (id == MB_NO) {
-#ifdef CONFIG_BLK_DEV_IDE
- bay->cd_retry = 0;
-#endif
- printk(KERN_INFO "media bay %d is empty\n", which);
- }
- }
- } else {
- bay->last_value = id;
- bay->value_count = 0;
- }
}
-
+#endif
#ifdef CONFIG_PMAC_PBOOK
/*
@@ -586,7 +651,7 @@
int __pmac
mb_notify_sleep(struct pmu_sleep_notifier *self, int when)
{
- volatile struct media_bay_info* bay;
+ struct media_bay_info* bay;
int i;
switch (when) {
@@ -597,7 +662,7 @@
case PBOOK_SLEEP_NOW:
for (i=0; i<media_bay_count; i++) {
bay = &media_bays[i];
- set_mb_power(i, 0);
+ set_mb_power(bay, 0);
mdelay(10);
}
break;
@@ -609,14 +674,11 @@
they seem to help the 3400 get it right.
*/
/* Force MB power to 0 */
- set_mb_power(i, 0);
+ set_mb_power(bay, 0);
mdelay(MB_POWER_DELAY);
- if (!bay->pismo)
- out_8(&bay->addr->contents, 0x70);
- mdelay(MB_STABLE_DELAY);
- if (mb_content(bay) != bay->content_id)
+ if (bay->ops->content(bay) != bay->content_id)
continue;
- set_mb_power(i, 1);
+ set_mb_power(bay, 1);
bay->last_value = bay->content_id;
bay->value_count = MS_TO_HZ(MB_STABLE_DELAY);
bay->timer = MS_TO_HZ(MB_POWER_DELAY);
@@ -634,4 +696,135 @@
return PBOOK_SLEEP_OK;
}
#endif /* CONFIG_PMAC_PBOOK */
+
+
+/* Definitions of "ops" structures.
+ */
+static struct mb_ops ohare_mb_ops __pmacdata = {
+ name: "Ohare",
+ content: ohare_mb_content,
+ power: ohare_mb_power,
+ setup_bus: ohare_mb_setup_bus,
+ un_reset: ohare_mb_un_reset,
+ un_reset_ide: ohare_mb_un_reset_ide,
+};
+
+static struct mb_ops heathrow_mb_ops __pmacdata = {
+ name: "Heathrow",
+ content: heathrow_mb_content,
+ power: heathrow_mb_power,
+ setup_bus: heathrow_mb_setup_bus,
+ un_reset: heathrow_mb_un_reset,
+ un_reset_ide: heathrow_mb_un_reset_ide,
+};
+
+static struct mb_ops keylargo_mb_ops __pmacdata = {
+ name: "KeyLargo",
+ content: keylargo_mb_content,
+ power: keylargo_mb_power,
+ setup_bus: keylargo_mb_setup_bus,
+ un_reset: keylargo_mb_un_reset,
+ un_reset_ide: keylargo_mb_un_reset_ide,
+};
+
+/*
+ * 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 __pmac
+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");
+ n = 0;
+ while(np && (n<MAX_BAYS)) {
+ struct media_bay_info* bay = &media_bays[n];
+ if (!np->parent || np->n_addrs == 0 || !request_OF_resource(np, 0, NULL)) {
+ np = np->next;
+ printk(KERN_ERR "media-bay: Can't request IO resource !\n");
+ continue;
+ }
+ bay->mb_type = mb_ohare;
+
+ if (device_is_compatible(np, "keylargo-media-bay")) {
+ bay->mb_type = mb_keylargo;
+ bay->ops = &keylargo_mb_ops;
+ } else if (device_is_compatible(np, "heathrow-media-bay")) {
+ bay->mb_type = mb_heathrow;
+ bay->ops = &heathrow_mb_ops;
+ } else if (device_is_compatible(np, "ohare-media-bay")) {
+ bay->mb_type = mb_ohare;
+ bay->ops = &ohare_mb_ops;
+ } else {
+ printk(KERN_ERR "mediabay: Unknown bay type !\n");
+ np = np->next;
+ continue;
+ }
+ bay->base = (volatile u32*)ioremap(np->parent->addrs[0].address, 0x1000);
+
+ /* Enable probe logic on keylargo */
+ if (bay->mb_type == mb_keylargo)
+ MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE);
+#ifdef MB_USE_INTERRUPTS
+ if (np->n_intrs == 0) {
+ printk(KERN_ERR "media bay %d has no irq\n",n);
+ np = np->next;
+ continue;
+ }
+
+ if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) {
+ printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n",
+ np->intrs[0].line, n);
+ np = np->next;
+ continue;
+ }
+#endif
+ media_bay_count++;
+
+ printk(KERN_INFO "mediabay%d: Registered %s media-bay\n", n, bay->ops->name);
+ bay->dev_node = np;
+ bay->index = n;
+
+ /* Force an immediate detect */
+ set_mb_power(bay, 0);
+ mdelay(MB_POWER_DELAY);
+ bay->content_id = MB_NO;
+ bay->last_value = bay->ops->content(bay);
+ bay->value_count = MS_TO_HZ(MB_STABLE_DELAY);
+ bay->state = mb_empty;
+ do {
+ mdelay(1000/HZ);
+ media_bay_step(n);
+ } while((bay->state != mb_empty) &&
+ (bay->state != mb_up));
+
+ n++;
+ np=np->next;
+ }
+
+ if (media_bay_count)
+ {
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_register_sleep_notifier(&mb_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
+ kernel_thread(media_bay_task, NULL,
+ CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ }
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)