patch-2.2.17 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

diff -u --recursive --new-file v2.2.16/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 1998 Paul Mackerras.
  *
+ * Various evolutions by Benjamin Herrenschmidt & Henry Worth
+ *
  *  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
@@ -38,6 +40,14 @@
 #endif
 
 #undef MB_USE_INTERRUPTS
+#undef MB_DEBUG
+#define MB_IGNORE_SIGNALS
+
+#ifdef MB_DEBUG
+#define MBDBG(fmt, arg...)	printk(KERN_INFO fmt , ## arg)
+#else
+#define MBDBG(fmt, arg...)	do { } while (0)
+#endif
 
 struct media_bay_hw {
 	unsigned char	b0;
@@ -48,18 +58,20 @@
 
 struct media_bay_info {
 	volatile struct media_bay_hw*	addr;
+	volatile u8*			extint_gpio;
 	int				content_id;
-	int				previous_id;
-	int				ready;
+	int				state;
 	int				last_value;
 	int				value_count;
-	int				reset_timer;
+	int				timer;
 	struct device_node*		dev_node;
+	int				pismo;	/* New PowerBook3,1 */
+	int				gpio_cache;
 #ifdef CONFIG_BLK_DEV_IDE
 	unsigned long			cd_base;
 	int 				cd_index;
 	int				cd_irq;
-	int				cd_timer;
+	int				cd_retry;
 #endif
 };
 
@@ -68,42 +80,102 @@
 static volatile struct media_bay_info media_bays[MAX_BAYS];
 int media_bay_count = 0;
 
-#define MB_CONTENTS(i)	((in_8(&media_bays[i].addr->contents) >> 4) & 7)
+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
 
+/* Note: All delays are not in milliseconds and converted to HZ relative
+ * values by the macro below
+ */
+#define MS_TO_HZ(ms)	((ms * HZ) / 1000)
+
 /*
  * Consider the media-bay ID value stable if it is the same for
- * this many consecutive samples (at intervals of 1/HZ seconds).
+ * this number of milliseconds
+ */
+#define MB_STABLE_DELAY	40
+
+/* Wait after powering up the media bay this delay in ms
+ * timeout bumped for some powerbooks
  */
-#define MB_STABLE_COUNT	4
+#define MB_POWER_DELAY	200
 
 /*
  * Hold the media-bay reset signal true for this many ticks
  * after a device is inserted before releasing it.
  */
-#define MB_RESET_COUNT	40
+#define MB_RESET_DELAY	40
+
+/*
+ * Wait this long after the reset signal is released and before doing
+ * further operations. After this delay, the IDE reset signal is released
+ * too for an IDE device
+ */
+#define MB_SETUP_DELAY	100
 
 /*
  * 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.
+ * (or until the device is ready) before waiting for busy bit to disappear
+ */
+#define MB_IDE_WAIT	1000
+
+/*
+ * Timeout waiting for busy bit of an IDE device to go down
  */
-#define MB_IDE_WAIT	1500
+#define MB_IDE_TIMEOUT	5000
 
 /*
- * Wait at least this many ticks after resetting an IDE device before
- * believing its ready bit.
+ * Max retries of the full power up/down sequence for an IDE device
  */
-#define MB_IDE_MINWAIT	250
+#define MAX_CD_RETRIES	3
+
+/*
+ * States of a media bay
+ */
+enum {
+	mb_empty = 0,		/* Idle */
+	mb_powering_up,		/* power bit set, waiting MB_POWER_DELAY */
+	mb_enabling_bay,	/* enable bits set, waiting MB_RESET_DELAY */
+	mb_resetting,		/* reset bit unset, waiting MB_SETUP_DELAY */
+	mb_ide_resetting,	/* IDE reset bit unser, waiting MB_IDE_WAIT */
+	mb_ide_waiting,		/* Waiting for BUSY bit to go away until MB_IDE_TIMEOUT */
+	mb_up,			/* Media bay full */
+	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 *);
 
+#ifdef MB_USE_INTERRUPTS
+static void media_bay_intr(int irq, void *devid, struct pt_regs *regs);
+#endif
+
 /*
  * 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.
@@ -120,56 +192,69 @@
 {
 	struct device_node *np;
 	int		n,i;
-	
-	for (i=0; i<MAX_BAYS; 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))
-	{
+	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));
 
+		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);
+		}
+
 #ifdef MB_USE_INTERRUPTS
-		if (np->n_intrs == 0)
-		{
+		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);
+
+		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	
+#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
+
+		/* 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));
+
 		n++;
 		np=np->next;
 	}
-	
+
 	if (media_bay_count)
 	{
 		printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count);
@@ -178,21 +263,83 @@
 		pmu_register_sleep_notifier(&mb_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 
-		kernel_thread(media_bay_task, NULL, 0);
+		kernel_thread(media_bay_task, NULL,
+			      CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	}
 }
 
-#if 0
+#ifdef MB_USE_INTERRUPTS
 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
 
+static void
+set_mb_power(int which, int onoff)
+{
+	volatile struct media_bay_info*	mb = &media_bays[which];
+
+	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);
+	}
+	mb->timer = MS_TO_HZ(MB_POWER_DELAY);
+}
+
+static void
+set_media_bay(int which, int id)
+{
+	volatile struct media_bay_info* 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);
+		}
+		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;
+	}
+}
+
 int
 check_media_bay(struct device_node *which_bay, int what)
 {
@@ -202,7 +349,7 @@
 	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)
+			if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up)
 				return 0;
 			media_bays[i].cd_index = -1;
 			return -EINVAL;
@@ -220,13 +367,13 @@
 	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)
+			if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up)
 				return 0;
 			media_bays[i].cd_index = -1;
 			return -EINVAL;
 		} 
 #endif
-	
+
 	return -ENODEV;
 }
 
@@ -240,17 +387,138 @@
 	for (i=0; i<media_bay_count; i++)
 		if (which_bay == media_bays[i].dev_node)
 		{
+			int timeout = 5000;
+
  			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;
+
+			if ((MB_CD != media_bays[i].content_id) || media_bays[i].state != mb_up)
+				return 0;
+
+			printk(KERN_DEBUG "Registered ide %d for media bay %d\n", index, i);
+			do {
+				if (MB_IDE_READY(i)) {
+					media_bays[i].cd_index	= index;
+					return 0;
+				}
+				mdelay(1);
+			} while(--timeout);
+			printk(KERN_DEBUG "Timeount waiting IDE in bay %d\n", i);
+			return -ENODEV;
 		} 
 #endif
-	
+
 	return -ENODEV;
 }
 
+static void
+media_bay_step(int i)
+{
+	volatile 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);
+
+	/* If timer expired or polling IDE busy, run state machine */
+	if ((bay->state != mb_ide_waiting) && (bay->timer != 0) && ((--bay->timer) != 0))
+	    return;
+
+	switch(bay->state) {
+	case mb_powering_up:
+	    	set_media_bay(i, bay->last_value);
+	    	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->timer = MS_TO_HZ(MB_SETUP_DELAY);
+	    	bay->state = mb_resetting;
+		MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id);
+	    	break;
+	    
+	case mb_resetting:
+		if (bay->content_id != MB_CD) {
+			MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id);
+			bay->state = mb_up;
+			break;
+	    	}
+#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->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
+	    	break;
+	    
+#ifdef CONFIG_BLK_DEV_IDE
+	case mb_ide_resetting:
+	    	bay->timer = MS_TO_HZ(MB_IDE_TIMEOUT);
+	    	bay->state = mb_ide_waiting;
+		MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id);
+	    	break;
+	    
+	case mb_ide_waiting:
+	    	if (bay->cd_base == 0) {
+			bay->timer = 0;
+			bay->state = mb_up;
+			MBDBG("mediabay%d: up before IDE init\n", i);
+			break;
+	    	} else if (MB_IDE_READY(i)) {
+			bay->timer = 0;
+			bay->state = mb_up;
+			if (bay->cd_index < 0)
+				bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
+			if (bay->cd_index == -1) {
+				/* We eventually do a retry */
+				bay->cd_retry++;
+				printk("IDE register error\n");
+				set_mb_power(i, 0);
+			} else {
+				printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index);
+				MBDBG("mediabay %d IDE ready\n", i);
+			}
+			break;
+	    	}
+	    	if (bay->timer == 0) {
+			printk("\nIDE Timeout in bay %d !\n", i);
+			MBDBG("mediabay%d: nIDE Timeout !\n", i);
+			set_mb_power(i, 0);
+	    	}
+		break;
+#endif // #ifdef CONFIG_BLK_DEV_IDE
+
+	case mb_powering_down:
+	    	bay->state = mb_empty;
+#ifdef CONFIG_BLK_DEV_IDE
+    	        if (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;
+		}
+	    	if (bay->cd_retry) {
+			if (bay->cd_retry > MAX_CD_RETRIES) {
+				/* Should add an error sound (sort of beep in dmasound) */
+				printk("\nmedia-bay %d, IDE device badly inserted or unrecognised\n", i);
+			} else {
+				/* Force a new power down/up sequence */
+				bay->content_id = MB_NO;
+			}
+	    	}
+#endif	    
+		MBDBG("mediabay%d: end of power down\n", i);
+	    	break;
+	}
+}
+
 /*
  * This procedure runs as a kernel thread to poll the media bay
  * once each tick and register and unregister the IDE interface
@@ -260,128 +528,57 @@
 int
 media_bay_task(void *x)
 {
-	volatile struct media_bay_info* bay;
 	int	i = 0;
-	
+
 	strcpy(current->comm, "media-bay");
-	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;
-			bay->ready = 0;
-#ifdef CONFIG_BLK_DEV_IDE
-			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 (bay->reset_timer) {
-			if (--bay->reset_timer == 0) {
- 				feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
-				bay->ready = 1;
-#ifdef CONFIG_BLK_DEV_IDE
-				bay->cd_timer = 0;
-				if (bay->content_id == MB_CD && bay->cd_base != 0)
-					bay->cd_timer = MB_IDE_WAIT;
+#ifdef MB_IGNORE_SIGNALS
+	sigfillset(&current->blocked);
 #endif
-			}
-#ifdef CONFIG_BLK_DEV_IDE
-		} else if (bay->cd_timer
-			   && (--bay->cd_timer == 0
-			       || (bay->cd_timer < MB_IDE_WAIT - MB_IDE_MINWAIT
-				   && 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
-		}
 
-		bay->previous_id = bay->content_id;
-		if (++i >= media_bay_count) {
-			i = 0;
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(1);
-			if (signal_pending(current))
-				return 0;
-		}
+	for (;;) {
+	    media_bay_step(i);
+
+	    if (++i >= media_bay_count) {
+		i = 0;
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+		if (signal_pending(current))
+		    return 0;
+	    }
 	}
 }
 
 void
 poll_media_bay(int which)
 {
-	int id = MB_CONTENTS(which);
+	volatile struct media_bay_info* bay = &media_bays[which];
+	int id = mb_content(bay);
 
-	if (id == media_bays[which].last_value) {
-	    if (id != media_bays[which].content_id
-	        && ++media_bays[which].value_count >= MB_STABLE_COUNT) {
+	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) && (media_bays[which].content_id != MB_NO)) {
-		    set_media_bay(which, MB_NO);
-		    udelay(500);
+	        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);
 		}
- 		set_media_bay(which, id);
  	    }
 	} else {
-		media_bays[which].last_value = id;
-		media_bays[which].value_count = 0;
+		bay->last_value = id;
+		bay->value_count = 0;
 	}
 }
 
-static void
-set_media_bay(int which, int id)
-{
-	volatile struct media_bay_info* bay;
-
-	bay = &media_bays[which];
-	
-	bay->content_id = id;
-	bay->last_value = id;
-	
-	switch (id) {
-	case MB_CD:
-		feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-		feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable);
-		udelay(500);
-		feature_set(bay->dev_node, FEATURE_CD_power);
-		printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
-		break;
-	case MB_FD:
-		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:
-		feature_clear(bay->dev_node, FEATURE_CD_power);
-		feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
-		feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
-		feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
-		feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
-		feature_set(bay->dev_node, FEATURE_Mediabay_reset);
-		printk(KERN_INFO "media bay %d is empty\n", which);
-		break;
-	default:
-		feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-		printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
-		       which, id);
-		break;
-	}
-	
-	udelay(500);
-}
 
 #ifdef CONFIG_PMAC_PBOOK
 /*
@@ -392,51 +589,44 @@
 {
 	volatile struct media_bay_info* bay;
 	int i;
-	
+
 	switch (when) {
 	case PBOOK_SLEEP_REQUEST:
 	case PBOOK_SLEEP_REJECT:
 		break;
-		
+
 	case PBOOK_SLEEP_NOW:
 		for (i=0; i<media_bay_count; i++) {
 			bay = &media_bays[i];
-			feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
-			feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
-			feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
-			feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
-			feature_set(bay->dev_node, FEATURE_Mediabay_reset);
-			feature_clear(bay->dev_node, FEATURE_CD_power);
-			out_8(&media_bays[i].addr->contents, 0x70);
+			set_mb_power(i, 0);
+			mdelay(10);
+			feature_clear(bay->dev_node, FEATURE_IOBUS_enable);
 		}
 		break;
 	case PBOOK_WAKE:
 		for (i=0; i<media_bay_count; i++) {
 			bay = &media_bays[i];
-			feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-			/* I suppose this is enough delay to stabilize MB_CONTENT ... */
-			mdelay(10);
 			/* We re-enable the bay using it's previous content
-			   only if it did not change */
-			if (MB_CONTENTS(i) != bay->content_id)
-				continue;
-			set_media_bay(i, bay->content_id);
-			if (bay->content_id == MB_NO)
+			   only if it did not change. Note those bozo timings,
+			   they seem to help the 3400 get it right.
+			 */
+			feature_set(bay->dev_node, FEATURE_IOBUS_enable);
+			mdelay(MB_STABLE_DELAY);
+			if (!bay->pismo)
+				out_8(&bay->addr->contents, 0x70);
+			mdelay(MB_STABLE_DELAY);
+			if (mb_content(bay) != bay->content_id)
 				continue;
-			mdelay(400);
-			/* Clear the bay reset */
-			feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
-			/* This small delay makes sure the device has time
-			   to assert the BUSY bit (used by IDE sleep) */
-			udelay(100);
-			/* We reset the state machine timers in case we were
-			   in the middle of a wait loop */
-			if (bay->reset_timer)
-				bay->reset_timer = MB_RESET_COUNT;
-#ifdef CONFIG_BLK_DEV_IDE
-			if (bay->cd_timer)
-				bay->cd_timer = MB_IDE_WAIT;
-#endif
+			set_mb_power(i, 1);
+			bay->last_value = bay->content_id;
+			bay->value_count = MS_TO_HZ(MB_STABLE_DELAY);
+			bay->timer = MS_TO_HZ(MB_POWER_DELAY);
+			bay->cd_retry = 0;
+			do {
+				mdelay(1000/HZ);
+				media_bay_step(i);
+			} while((media_bays[i].state != mb_empty) &&
+				(media_bays[i].state != mb_up));
 		}
 		break;
 	}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)