📄 ide.c
字号:
#ifndef CONFIG_BLK_DEV_IDECS hwif->irq = tmp_hwif->irq;#endif hwif->dma_base = tmp_hwif->dma_base; hwif->dma_master = tmp_hwif->dma_master; hwif->dma_command = tmp_hwif->dma_command; hwif->dma_vendor1 = tmp_hwif->dma_vendor1; hwif->dma_status = tmp_hwif->dma_status; hwif->dma_vendor3 = tmp_hwif->dma_vendor3; hwif->dma_prdtable = tmp_hwif->dma_prdtable; hwif->config_data = tmp_hwif->config_data; hwif->select_data = tmp_hwif->select_data; hwif->extra_base = tmp_hwif->extra_base; hwif->extra_ports = tmp_hwif->extra_ports; hwif->hwif_data = tmp_hwif->hwif_data;}/** * ide_unregister - free an IDE interface * @index: index of interface (will change soon to a pointer) * * Perform the final unregister of an IDE interface. At the moment * we don't refcount interfaces so this will also get split up. * * Locking: * The caller must not hold the IDE locks * The drive present/vanishing is not yet properly locked * Take care with the callbacks. These have been split to avoid * deadlocking the IDE layer. The shutdown callback is called * before we take the lock and free resources. It is up to the * caller to be sure there is no pending I/O here, and that * the interface will not be reopened (present/vanishing locking * isn't yet done BTW). After we commit to the final kill we * call the cleanup callback with the ide locks held. * * Unregister restores the hwif structures to the default state. * This is raving bonkers. */void ide_unregister(unsigned int index){ ide_drive_t *drive; ide_hwif_t *hwif, *g; static ide_hwif_t tmp_hwif; /* protected by ide_cfg_mtx */ ide_hwgroup_t *hwgroup; int irq_count = 0, unit; BUG_ON(index >= MAX_HWIFS); BUG_ON(in_interrupt()); BUG_ON(irqs_disabled()); mutex_lock(&ide_cfg_mtx); spin_lock_irq(&ide_lock); hwif = &ide_hwifs[index]; if (!hwif->present) goto abort; for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; if (!drive->present) continue; spin_unlock_irq(&ide_lock); device_unregister(&drive->gendev); wait_for_completion(&drive->gendev_rel_comp); spin_lock_irq(&ide_lock); } hwif->present = 0; spin_unlock_irq(&ide_lock); ide_proc_unregister_port(hwif); hwgroup = hwif->hwgroup; /* * free the irq if we were the only hwif using it */ g = hwgroup->hwif; do { if (g->irq == hwif->irq) ++irq_count; g = g->next; } while (g != hwgroup->hwif); if (irq_count == 1) free_irq(hwif->irq, hwgroup); spin_lock_irq(&ide_lock); /* * Note that we only release the standard ports, * and do not even try to handle any extra ports * allocated for weird IDE interface chipsets. */ ide_hwif_release_regions(hwif); /* * Remove us from the hwgroup, and free * the hwgroup if we were the only member */ if (hwif->next == hwif) { BUG_ON(hwgroup->hwif != hwif); kfree(hwgroup); } else { /* There is another interface in hwgroup. * Unlink us, and set hwgroup->drive and ->hwif to * something sane. */ g = hwgroup->hwif; while (g->next != hwif) g = g->next; g->next = hwif->next; if (hwgroup->hwif == hwif) { /* Chose a random hwif for hwgroup->hwif. * It's guaranteed that there are no drives * left in the hwgroup. */ BUG_ON(hwgroup->drive != NULL); hwgroup->hwif = g; } BUG_ON(hwgroup->hwif == hwif); } /* More messed up locking ... */ spin_unlock_irq(&ide_lock); device_unregister(&hwif->gendev); wait_for_completion(&hwif->gendev_rel_comp); /* * Remove us from the kernel's knowledge */ blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS); kfree(hwif->sg_table); unregister_blkdev(hwif->major, hwif->name); spin_lock_irq(&ide_lock); if (hwif->dma_base) { (void) ide_release_dma(hwif); hwif->dma_base = 0; hwif->dma_master = 0; hwif->dma_command = 0; hwif->dma_vendor1 = 0; hwif->dma_status = 0; hwif->dma_vendor3 = 0; hwif->dma_prdtable = 0; hwif->extra_base = 0; hwif->extra_ports = 0; } /* copy original settings */ tmp_hwif = *hwif; /* restore hwif data to pristine status */ init_hwif_data(hwif, index); init_hwif_default(hwif, index); ide_hwif_restore(hwif, &tmp_hwif);abort: spin_unlock_irq(&ide_lock); mutex_unlock(&ide_cfg_mtx);}EXPORT_SYMBOL(ide_unregister);/** * ide_setup_ports - set up IDE interface ports * @hw: register descriptions * @base: base register * @offsets: table of register offsets * @ctrl: control register * @ack_irq: IRQ ack * @irq: interrupt lie * * Setup hw_regs_t structure described by parameters. You * may set up the hw structure yourself OR use this routine to * do it for you. This is basically a helper * */ void ide_setup_ports ( hw_regs_t *hw, unsigned long base, int *offsets, unsigned long ctrl, unsigned long intr, ide_ack_intr_t *ack_intr,/* * ide_io_ops_t *iops, */ int irq){ int i; memset(hw, 0, sizeof(hw_regs_t)); for (i = 0; i < IDE_NR_PORTS; i++) { if (offsets[i] == -1) { switch(i) { case IDE_CONTROL_OFFSET: hw->io_ports[i] = ctrl; break;#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) case IDE_IRQ_OFFSET: hw->io_ports[i] = intr; break;#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */ default: hw->io_ports[i] = 0; break; } } else { hw->io_ports[i] = base + offsets[i]; } } hw->irq = irq; hw->ack_intr = ack_intr;/* * hw->iops = iops; */}/** * ide_register_hw - register IDE interface * @hw: hardware registers * @fixup: fixup function * @initializing: set while initializing built-in drivers * @hwifp: pointer to returned hwif * * Register an IDE interface, specifying exactly the registers etc. * Set init=1 iff calling before probes have taken place. * * Returns -1 on error. */int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *), int initializing, ide_hwif_t **hwifp){ int index, retry = 1; ide_hwif_t *hwif; do { for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; if (hwif->io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET]) goto found; } for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; if (hwif->hold) continue; if ((!hwif->present && !hwif->mate && !initializing) || (!hwif->io_ports[IDE_DATA_OFFSET] && initializing)) goto found; } for (index = 0; index < MAX_HWIFS; index++) ide_unregister(index); } while (retry--); return -1;found: if (hwif->present) ide_unregister(index); else if (!hwif->hold) { init_hwif_data(hwif, index); init_hwif_default(hwif, index); } if (hwif->present) return -1; memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports)); hwif->irq = hw->irq; hwif->noprobe = 0; hwif->fixup = fixup; hwif->chipset = hw->chipset; hwif->gendev.parent = hw->dev; hwif->ack_intr = hw->ack_intr; if (initializing == 0) { u8 idx[4] = { index, 0xff, 0xff, 0xff }; ide_device_add(idx); } if (hwifp) *hwifp = hwif; return (initializing || hwif->present) ? index : -1;}EXPORT_SYMBOL(ide_register_hw);/* * Locks for IDE setting functionality */DEFINE_MUTEX(ide_setting_mtx);EXPORT_SYMBOL_GPL(ide_setting_mtx);/** * ide_spin_wait_hwgroup - wait for group * @drive: drive in the group * * Wait for an IDE device group to go non busy and then return * holding the ide_lock which guards the hwgroup->busy status * and right to use it. */int ide_spin_wait_hwgroup (ide_drive_t *drive){ ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned long timeout = jiffies + (3 * HZ); spin_lock_irq(&ide_lock); while (hwgroup->busy) { unsigned long lflags; spin_unlock_irq(&ide_lock); local_irq_set(lflags); if (time_after(jiffies, timeout)) { local_irq_restore(lflags); printk(KERN_ERR "%s: channel busy\n", drive->name); return -EBUSY; } local_irq_restore(lflags); spin_lock_irq(&ide_lock); } return 0;}EXPORT_SYMBOL(ide_spin_wait_hwgroup);int set_io_32bit(ide_drive_t *drive, int arg){ if (drive->no_io_32bit) return -EPERM; if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1)) return -EINVAL; if (ide_spin_wait_hwgroup(drive)) return -EBUSY; drive->io_32bit = arg;#ifdef CONFIG_BLK_DEV_DTC2278 if (HWIF(drive)->chipset == ide_dtc2278) HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;#endif /* CONFIG_BLK_DEV_DTC2278 */ spin_unlock_irq(&ide_lock); return 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;}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_on == 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}int set_pio_mode(ide_drive_t *drive, int arg){ struct request rq; if (arg < 0 || arg > 255) return -EINVAL; if (drive->hwif->set_pio_mode == NULL) return -ENOSYS; if (drive->special.b.set_tune) return -EBUSY; ide_init_drive_cmd(&rq); drive->tune_req = (u8) arg; drive->special.b.set_tune = 1; (void) ide_do_drive_cmd(drive, &rq, ide_wait); 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;}/** * system_bus_clock - clock guess * * External version of the bus clock guess used by very old IDE drivers * for things like VLB timings. Should not be used. */int system_bus_clock (void){ return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));}EXPORT_SYMBOL(system_bus_clock);static int generic_ide_suspend(struct device *dev, pm_message_t mesg){ ide_drive_t *drive = dev->driver_data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -