diff options
Diffstat (limited to 'drivers/macintosh/mediabay.c')
-rw-r--r-- | drivers/macintosh/mediabay.c | 308 |
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); } |