static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) { if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (setting->set) return setting->set(drive, val); if (!(setting->rw & SETTING_WRITE)) return -EPERM; if (val < setting->min || val > setting->max) return -EINVAL; if (ide_spin_wait_hwgroup(drive)) return -EBUSY; switch (setting->data_type) { case TYPE_BYTE: *((u8 *) setting->data) = val; break; case TYPE_SHORT: *((u16 *) setting->data) = val; break; case TYPE_INT: *((u32 *) setting->data) = val; break; } spin_unlock_irq(&ide_lock); return 0; }
static void idepmac_wake_device(ide_drive_t *drive, int used_dma) { /* We force the IDE subdriver to check for a media change * This must be done first or we may lost the condition * * Problem: This can schedule. I moved the block device * wakeup almost late by priority because of that. */ if (DRIVER(drive) && DRIVER(drive)->media_change) DRIVER(drive)->media_change(drive); /* We kick the VFS too (see fix in ide.c revalidate) */ check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS)); #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC /* We re-enable DMA on the drive if it was active. */ /* This doesn't work with the CD-ROM in the media-bay, probably * because of a pending unit attention. The problem if that if I * clear the error, the filesystem dies. */ if (used_dma && !ide_spin_wait_hwgroup(drive)) { /* Lock HW group */ HWGROUP(drive)->busy = 1; pmac_ide_check_dma(drive); HWGROUP(drive)->busy = 0; spin_unlock_irq(&io_request_lock); } #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ }
static int set_ksettings(ide_drive_t *drive, int arg) { if (arg < 0 || arg > 1) return -EINVAL; if (ide_spin_wait_hwgroup(drive)) return -EBUSY; drive->keep_settings = arg; spin_unlock_irq(&ide_lock); return 0; }
static int set_unmaskirq(ide_drive_t *drive, int arg) { if (drive->no_unmask) return -EPERM; if (arg < 0 || arg > 1) return -EINVAL; if (ide_spin_wait_hwgroup(drive)) return -EBUSY; drive->unmask = arg; spin_unlock_irq(&ide_lock); return 0; }
int set_using_dma(ide_drive_t *drive, int arg) { #ifdef CONFIG_BLK_DEV_IDEDMA ide_hwif_t *hwif = drive->hwif; int err = -EPERM; if (arg < 0 || arg > 1) return -EINVAL; if (!drive->id || !(drive->id->capability & 1)) goto out; if (hwif->ide_dma_check == NULL) goto out; err = -EBUSY; if (ide_spin_wait_hwgroup(drive)) goto out; /* * set ->busy flag, unlock and let it ride */ hwif->hwgroup->busy = 1; spin_unlock_irq(&ide_lock); err = 0; if (arg) { hwif->dma_off_quietly(drive); if (ide_set_dma(drive) || hwif->ide_dma_on(drive)) err = -EIO; } else ide_dma_off(drive); /* * lock, clear ->busy flag and unlock before leaving */ spin_lock_irq(&ide_lock); hwif->hwgroup->busy = 0; spin_unlock_irq(&ide_lock); out: return err; #else if (arg < 0 || arg > 1) return -EINVAL; return -EPERM; #endif }
/* Note: We support only master drives for now. This will have to be * improved if we want to handle sleep on the iMacDV where the CD-ROM * is a slave */ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) { int i, ret; unsigned long base; unsigned long flags; int big_delay; switch (when) { case PBOOK_SLEEP_REQUEST: break; case PBOOK_SLEEP_REJECT: break; case PBOOK_SLEEP_NOW: for (i = 0; i < pmac_ide_count; ++i) { ide_hwif_t *hwif; ide_drive_t *drive; int unlock = 0; if ((base = pmac_ide[i].regbase) == 0) continue; hwif = &ide_hwifs[i]; drive = &hwif->drives[0]; if (drive->present) { /* Wait for HW group to complete operations */ if (ide_spin_wait_hwgroup(drive)) { // What can we do here ? Wake drive we had already // put to sleep and return an error ? } else { unlock = 1; /* Lock HW group */ HWGROUP(drive)->busy = 1; /* Stop the device */ idepmac_sleep_device(drive, i, base); } } /* Disable irq during sleep */ disable_irq(pmac_ide[i].irq); if (unlock) spin_unlock_irq(&io_request_lock); /* Check if this is a media bay with an IDE device or not * a media bay. */ ret = check_media_bay_by_base(base, MB_CD); if ((ret == 0) || (ret == -ENODEV)) idepmac_sleep_interface(i, base, (ret == 0)); } break; case PBOOK_WAKE: big_delay = 0; for (i = 0; i < pmac_ide_count; ++i) { if ((base = pmac_ide[i].regbase) == 0) continue; /* Check if this is a media bay with an IDE device or not * a media bay */ ret = check_media_bay_by_base(base, MB_CD); if ((ret == 0) || (ret == -ENODEV)) { idepmac_wake_interface(i, base, (ret == 0)); big_delay = 1; } } /* Let hardware get up to speed */ if (big_delay) mdelay(IDE_WAKEUP_DELAY_MS); for (i = 0; i < pmac_ide_count; ++i) { ide_hwif_t *hwif; ide_drive_t *drive; int j, used_dma; if ((base = pmac_ide[i].regbase) == 0) continue; hwif = &ide_hwifs[i]; drive = &hwif->drives[0]; /* Wait for the drive to come up and set it's DMA */ if (drive->present) { /* Wait up to 20 seconds */ for (j = 0; j < 200; j++) { int status; mdelay(100); status = inb(base + 0x70); if (!(status & BUSY_STAT)) break; } } /* We don't have re-configured DMA yet */ used_dma = drive->using_dma; drive->using_dma = 0; /* We resume processing on the HW group */ spin_lock_irqsave(&io_request_lock, flags); enable_irq(pmac_ide[i].irq); if (drive->present) HWGROUP(drive)->busy = 0; spin_unlock_irqrestore(&io_request_lock, flags); /* Wake the device * We could handle the slave here */ if (drive->present) idepmac_wake_device(drive, used_dma); } break; } return PBOOK_SLEEP_OK; }