--- zzzz-none-000/linux-2.4.17/drivers/macintosh/mediabay.c 2001-09-08 19:38:42.000000000 +0000 +++ sangam-fb-322/linux-2.4.17/drivers/macintosh/mediabay.c 2004-11-24 13:23:25.000000000 +0000 @@ -25,9 +25,13 @@ #include #include #include -#include +#include +#include #include #include +#include +#include +#include #include #include @@ -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; in_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; ipismo) - 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); @@ -635,3 +697,134 @@ } #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; iparent || 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); + } +} +