ide.c
来自「2410的硬盘块设备源码」· C语言 代码 · 共 2,013 行 · 第 1/4 页
C
2,013 行
hwif->ide_dma_check = tmp_hwif->ide_dma_check; hwif->ide_dma_on = tmp_hwif->ide_dma_on; hwif->ide_dma_off_quietly = tmp_hwif->ide_dma_off_quietly; hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq; hwif->ide_dma_host_on = tmp_hwif->ide_dma_host_on; hwif->ide_dma_host_off = tmp_hwif->ide_dma_host_off; hwif->ide_dma_lostirq = tmp_hwif->ide_dma_lostirq; hwif->ide_dma_timeout = tmp_hwif->ide_dma_timeout; hwif->OUTB = tmp_hwif->OUTB; hwif->OUTBSYNC = tmp_hwif->OUTBSYNC; hwif->OUTW = tmp_hwif->OUTW; hwif->OUTL = tmp_hwif->OUTL; hwif->OUTSW = tmp_hwif->OUTSW; hwif->OUTSL = tmp_hwif->OUTSL; hwif->INB = tmp_hwif->INB; hwif->INW = tmp_hwif->INW; hwif->INL = tmp_hwif->INL; hwif->INSW = tmp_hwif->INSW; hwif->INSL = tmp_hwif->INSL; hwif->sg_max_nents = tmp_hwif->sg_max_nents; hwif->mmio = tmp_hwif->mmio; hwif->rqsize = tmp_hwif->rqsize; hwif->no_lba48 = tmp_hwif->no_lba48;#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->dma_extra = tmp_hwif->dma_extra; hwif->config_data = tmp_hwif->config_data; hwif->select_data = tmp_hwif->select_data; hwif->autodma = tmp_hwif->autodma; hwif->udma_four = tmp_hwif->udma_four; hwif->no_dsc = tmp_hwif->no_dsc; 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 interfce will not be reopened (present/vanishing locking * isnt 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_sem */ ide_hwgroup_t *hwgroup; int irq_count = 0, unit; BUG_ON(index >= MAX_HWIFS); BUG_ON(in_interrupt()); BUG_ON(irqs_disabled()); down(&ide_cfg_sem); 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) { if (drive->devfs_name[0] != '\0') { devfs_remove(drive->devfs_name); drive->devfs_name[0] = '\0'; } continue; } spin_unlock_irq(&ide_lock); device_unregister(&drive->gendev); down(&drive->gendev_rel_sem); spin_lock_irq(&ide_lock); } hwif->present = 0; spin_unlock_irq(&ide_lock); destroy_proc_ide_interface(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); down(&hwif->gendev_rel_sem); /* * 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; } /* 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); up(&ide_cfg_sem);}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; 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->dma = NO_DMA; hw->ack_intr = ack_intr;/* * hw->iops = iops; */}/** * ide_register_hw_with_fixup - register IDE interface * @hw: hardware registers * @hwifp: pointer to returned hwif * @fixup: fixup function * * 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_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif)){ int index, retry = 1; ide_hwif_t *hwif; do { for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; if (hwif->hw.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->hw.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->hw, hw, sizeof(*hw)); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); hwif->irq = hw->irq; hwif->noprobe = 0; hwif->chipset = hw->chipset; if (!initializing) { probe_hwif_init_with_fixup(hwif, fixup); create_proc_ide_interfaces(); } if (hwifp) *hwifp = hwif; return (initializing || hwif->present) ? index : -1;}EXPORT_SYMBOL(ide_register_hw_with_fixup);int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp){ return ide_register_hw_with_fixup(hw, hwifp, NULL);}EXPORT_SYMBOL(ide_register_hw);/* * Locks for IDE setting functionality */DECLARE_MUTEX(ide_setting_sem);/** * __ide_add_setting - add an ide setting option * @drive: drive to use * @name: setting name * @rw: true if the function is read write * @read_ioctl: function to call on read * @write_ioctl: function to call on write * @data_type: type of data * @min: range minimum * @max: range maximum * @mul_factor: multiplication scale * @div_factor: divison scale * @data: private data field * @set: setting * @auto_remove: setting auto removal flag * * Removes the setting named from the device if it is present. * The function takes the settings_lock to protect against * parallel changes. This function must not be called from IRQ * context. Returns 0 on success or -1 on failure. * * BUGS: This code is seriously over-engineered. There is also * magic about how the driver specific features are setup. If * a driver is attached we assume the driver settings are auto * remove. */static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove){ ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; down(&ide_setting_sem); while ((*p) && strcmp((*p)->name, name) < 0) p = &((*p)->next); if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL) goto abort; memset(setting, 0, sizeof(*setting)); if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL) goto abort; strcpy(setting->name, name); setting->rw = rw; setting->read_ioctl = read_ioctl; setting->write_ioctl = write_ioctl; setting->data_type = data_type; setting->min = min; setting->max = max; setting->mul_factor = mul_factor; setting->div_factor = div_factor; setting->data = data; setting->set = set; setting->next = *p; if (auto_remove) setting->auto_remove = 1; *p = setting; up(&ide_setting_sem); return 0;abort: up(&ide_setting_sem); if (setting) kfree(setting); return -1;}int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set){ return __ide_add_setting(drive, name, rw, read_ioctl, write_ioctl, data_type, min, max, mul_factor, div_factor, data, set, 1);}EXPORT_SYMBOL(ide_add_setting);/** * __ide_remove_setting - remove an ide setting option * @drive: drive to use * @name: setting name * * Removes the setting named from the device if it is present. * The caller must hold the setting semaphore. */ static void __ide_remove_setting (ide_drive_t *drive, char *name){ ide_settings_t **p, *setting; p = (ide_settings_t **) &drive->settings; while ((*p) && strcmp((*p)->name, name)) p = &((*p)->next); if ((setting = (*p)) == NULL) return; (*p) = setting->next; kfree(setting->name); kfree(setting);}/** * ide_find_setting_by_ioctl - find a drive specific ioctl * @drive: drive to scan * @cmd: ioctl command to handle * * Scan's the device setting table for a matching entry and returns * this or NULL if no entry is found. The caller must hold the * setting semaphore */ static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd){ ide_settings_t *setting = drive->settings; while (setting) { if (setting->read_ioctl == cmd || setting->write_ioctl == cmd) break; setting = setting->next; } return setting;}/** * ide_find_setting_by_name - find a drive specific setting * @drive: drive to scan * @name: setting name * * Scan's the device setting table for a matching entry and returns * this or NULL if no entry is found. The caller must hold the * setting semaphore */ ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name){ ide_settings_t *setting = drive->settings; while (setting) { if (strcmp(setting->name, name) == 0) break; setting = setting->next; } return setting;}/** * auto_remove_settings - remove driver specific settings * @drive: drive * * Automatically remove all the driver specific settings for this * drive. This function may sleep and must not be called from IRQ * context. The caller must hold ide_setting_sem. */ static void auto_remove_settings (ide_drive_t *drive){ ide_settings_t *setting;repeat: setting = drive->settings; while (setting) { if (setting->auto_remove) { __ide_remove_setting(drive, setting->name); goto repeat; } setting = setting->next; }}/** * ide_read_setting - read an IDE setting * @drive: drive to read from * @setting: drive setting * * Read a drive setting and return the value. The caller * must hold the ide_setting_sem when making this call. * * BUGS: the data return and error are the same return value * so an error -EINVAL and true return of the same value cannot * be told apart
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?