X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fide%2Fppc%2Fpmac.c;h=ffca8b63ee79af28a1363df86c359fbcde1e12ef;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=15b89e8a1e75832bcf6439e92ab8c3a30de9e11e;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 15b89e8a1..ffca8b63e 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -22,6 +22,7 @@ * big table * */ +#include #include #include #include @@ -419,6 +420,107 @@ static void pmac_ide_kauai_selectproc(ide_drive_t *drive); #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ +/* + * Below is the code for blinking the laptop LED along with hard + * disk activity. + */ + +#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK + +/* Set to 50ms minimum led-on time (also used to limit frequency + * of requests sent to the PMU + */ +#define PMU_HD_BLINK_TIME (HZ/50) + +static struct adb_request pmu_blink_on, pmu_blink_off; +static spinlock_t pmu_blink_lock; +static unsigned long pmu_blink_stoptime; +static int pmu_blink_ledstate; +static struct timer_list pmu_blink_timer; +static int pmu_ide_blink_enabled; + + +static void +pmu_hd_blink_timeout(unsigned long data) +{ + unsigned long flags; + + spin_lock_irqsave(&pmu_blink_lock, flags); + + /* We may have been triggered again in a racy way, check + * that we really want to switch it off + */ + if (time_after(pmu_blink_stoptime, jiffies)) + goto done; + + /* Previous req. not complete, try 100ms more */ + if (pmu_blink_off.complete == 0) + mod_timer(&pmu_blink_timer, jiffies + PMU_HD_BLINK_TIME); + else if (pmu_blink_ledstate) { + pmu_request(&pmu_blink_off, NULL, 4, 0xee, 4, 0, 0); + pmu_blink_ledstate = 0; + } +done: + spin_unlock_irqrestore(&pmu_blink_lock, flags); +} + +static void +pmu_hd_kick_blink(void *data, int rw) +{ + unsigned long flags; + + pmu_blink_stoptime = jiffies + PMU_HD_BLINK_TIME; + wmb(); + mod_timer(&pmu_blink_timer, pmu_blink_stoptime); + /* Fast path when LED is already ON */ + if (pmu_blink_ledstate == 1) + return; + spin_lock_irqsave(&pmu_blink_lock, flags); + if (pmu_blink_on.complete && !pmu_blink_ledstate) { + pmu_request(&pmu_blink_on, NULL, 4, 0xee, 4, 0, 1); + pmu_blink_ledstate = 1; + } + spin_unlock_irqrestore(&pmu_blink_lock, flags); +} + +static int +pmu_hd_blink_init(void) +{ + struct device_node *dt; + const char *model; + + /* Currently, I only enable this feature on KeyLargo based laptops, + * older laptops may support it (at least heathrow/paddington) but + * I don't feel like loading those venerable old machines with so + * much additional interrupt & PMU activity... + */ + if (pmu_get_model() != PMU_KEYLARGO_BASED) + return 0; + + dt = of_find_node_by_path("/"); + if (dt == NULL) + return 0; + model = (const char *)get_property(dt, "model", NULL); + if (model == NULL) + return 0; + if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 && + strncmp(model, "iBook", strlen("iBook")) != 0) { + of_node_put(dt); + return 0; + } + of_node_put(dt); + + pmu_blink_on.complete = 1; + pmu_blink_off.complete = 1; + spin_lock_init(&pmu_blink_lock); + init_timer(&pmu_blink_timer); + pmu_blink_timer.function = pmu_hd_blink_timeout; + + return 1; +} + +#endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */ + /* * N.B. this can't be an initfunc, because the media-bay task can * call ide_[un]register at any time. @@ -1090,6 +1192,23 @@ pmac_ide_do_suspend(ide_hwif_t *hwif) pmif->timings[0] = 0; pmif->timings[1] = 0; +#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK + /* Note: This code will be called for every hwif, thus we'll + * try several time to stop the LED blinker timer, but that + * should be harmless + */ + if (pmu_ide_blink_enabled) { + unsigned long flags; + + /* Make sure we don't hit the PMU blink */ + spin_lock_irqsave(&pmu_blink_lock, flags); + if (pmu_blink_ledstate) + del_timer(&pmu_blink_timer); + pmu_blink_ledstate = 0; + spin_unlock_irqrestore(&pmu_blink_lock, flags); + } +#endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */ + disable_irq(pmif->irq); /* The media bay will handle itself just fine */ @@ -1257,6 +1376,13 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->selectproc = pmac_ide_selectproc; hwif->speedproc = pmac_ide_tune_chipset; +#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK + pmu_ide_blink_enabled = pmu_hd_blink_init(); + + if (pmu_ide_blink_enabled) + hwif->led_act = pmu_hd_kick_blink; +#endif + printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n", hwif->index, model_name[pmif->kind], pmif->aapl_bus_id, pmif->mediabay ? " (mediabay)" : "", hwif->irq); @@ -1326,7 +1452,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) if (macio_irq_count(mdev) == 0) { printk(KERN_WARNING "ide%d: no intrs for device %s, using 13\n", i, mdev->ofdev.node->full_name); - irq = irq_create_mapping(NULL, 13); + irq = 13; } else irq = macio_irq(mdev, 0);