📄 ide.c
字号:
*/void ide_setup_ports ( hw_regs_t *hw, ide_ioreg_t base, int *offsets, ide_ioreg_t ctrl, ide_ioreg_t 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; */}EXPORT_SYMBOL(ide_setup_ports);/* * Register an IDE interface, specifing exactly the registers etc * Set init=1 iff calling before probes have taken place. */int ide_register_hw (hw_regs_t *hw, 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->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 && ((!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(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) { ide_probe_module(1);#ifdef CONFIG_PROC_FS create_proc_ide_interfaces();#endif ide_driver_module(1); } if (hwifp) *hwifp = hwif; return (initializing || hwif->present) ? index : -1;}EXPORT_SYMBOL(ide_register_hw);/* * Compatability function with existing drivers. If you want * something different, use the function above. */int ide_register (int arg1, int arg2, int irq){ hw_regs_t hw; ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL); hw.irq = irq; return ide_register_hw(&hw, NULL);}EXPORT_SYMBOL(ide_register);/* * Locks for IDE setting functionality */DECLARE_MUTEX(ide_setting_sem);EXPORT_SYMBOL(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 * * 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. */ 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){ 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 (drive->driver != &idedefault_driver) setting->auto_remove = 1; *p = setting; up(&ide_setting_sem); return 0;abort: up(&ide_setting_sem); if (setting) kfree(setting); return -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_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 function takes the settings_lock to protect against * parallel changes. This function must not be called from IRQ * context. */ void ide_remove_setting (ide_drive_t *drive, char *name){ down(&ide_setting_sem); __ide_remove_setting(drive, name); up(&ide_setting_sem);}EXPORT_SYMBOL(ide_remove_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. Caller must hold the setting lock. */ 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 */ int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting){ int val = -EINVAL; unsigned long flags; if ((setting->rw & SETTING_READ)) { spin_lock_irqsave(&io_request_lock, flags); switch(setting->data_type) { case TYPE_BYTE: val = *((u8 *) setting->data); break; case TYPE_SHORT: val = *((u16 *) setting->data); break; case TYPE_INT: case TYPE_INTA: val = *((u32 *) setting->data); break; } spin_unlock_irqrestore(&io_request_lock, flags); } return val;}int ide_spin_wait_hwgroup (ide_drive_t *drive){ ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned long timeout = jiffies + (3 * HZ); spin_lock_irq(&io_request_lock); while (hwgroup->busy) { unsigned long lflags; spin_unlock_irq(&io_request_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(&io_request_lock); } return 0;}EXPORT_SYMBOL(ide_spin_wait_hwgroup);/** * ide_write_setting - read an IDE setting * @drive: drive to read from * @setting: drive setting * @val: value * * Write a drive setting if it is possible. 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 * * FIXME: This should be changed to enqueue a special request * to the driver to change settings, and then wait on a sema for completion. * The current scheme of polling is kludgy, though safe enough. */int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val){ int i; u32 *p; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!(setting->rw & SETTING_WRITE)) return -EPERM; if (val < setting->min || val > setting->max) return -EINVAL; if (setting->set) return setting->set(drive, val); 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; case TYPE_INTA: p = (u32 *) setting->data; for (i = 0; i < 1 << PARTN_BITS; i++, p++) *p = val; break; } spin_unlock_irq(&io_request_lock); return 0;}EXPORT_SYMBOL(ide_write_setting);static int set_io_32bit(ide_drive_t *drive, int arg){ 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 */ return 0;}static int set_using_dma (ide_drive_t *drive, int arg){ if (!DRIVER(drive)->supports_dma) return -EPERM; if (!(drive->id->capability & 1)) return -EPERM; if (HWIF(drive)->ide_dma_check == NULL) return -EPERM; if (HWIF(drive)->ide_dma_check(drive) != 0) return -EIO; if (arg) { if (HWIF(drive)->ide_dma_check(drive) != 0) return -EIO; if (HWIF(drive)->ide_dma_on(drive)) return -EIO; } else { if (HWIF(drive)->ide_dma_off(drive)) return -EIO; } return 0;}static int set_pio_mode (ide_drive_t *drive, int arg){ struct request rq; if (!HWIF(drive)->tuneproc) 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_xfer_rate (ide_drive_t *drive, int arg){ int err = ide_wait_cmd(drive, WIN_SETFEATURES, (u8) arg, SETFEATURES_XFER, 0, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -