예제 #1
0
파일: ide-proc.c 프로젝트: 274914765/C
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;
}
예제 #2
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 */
}
예제 #3
0
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;
}
예제 #4
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;
}
예제 #5
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
}
예제 #6
0
/* 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;
}