ide.c
来自「2410的硬盘块设备源码」· C语言 代码 · 共 2,013 行 · 第 1/4 页
C
2,013 行
*/ 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(&ide_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(&ide_lock, flags); } return val;}/** * 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);/** * 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(&ide_lock); return 0;}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){#ifdef CONFIG_BLK_DEV_IDEDMA if (!drive->id || !(drive->id->capability & 1)) return -EPERM; if (HWIF(drive)->ide_dma_check == NULL) return -EPERM; if (arg) { if (HWIF(drive)->ide_dma_check(drive)) return -EIO; if (HWIF(drive)->ide_dma_on(drive)) return -EIO; } else { if (__ide_dma_off(drive)) return -EIO; } return 0;#else return -EPERM;#endif}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); if (!err && arg) { ide_set_xfer_rate(drive, (u8) arg); ide_driveid_update(drive); } return err;}/** * ide_add_generic_settings - generic ide settings * @drive: drive being configured * * Add the generic parts of the system settings to the /proc files and * ioctls for this IDE device. The caller must not be holding the * ide_setting_sem. */void ide_add_generic_settings (ide_drive_t *drive){/* * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function */ __ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit, 0); __ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL, 0); __ide_add_setting(drive, "nice1", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL, 0); __ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode, 0); __ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL, 0); __ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma, 0); __ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL, 0); __ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate, 0); __ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL, 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 state){ ide_drive_t *drive = dev->driver_data; struct request rq; struct request_pm_state rqpm; ide_task_t args; memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); rq.flags = REQ_PM_SUSPEND; rq.special = &args; rq.pm = &rqpm; rqpm.pm_step = ide_pm_state_start_suspend; rqpm.pm_state = state.event; return ide_do_drive_cmd(drive, &rq, ide_wait);}static int generic_ide_resume(struct device *dev){ ide_drive_t *drive = dev->driver_data; struct request rq; struct request_pm_state rqpm; ide_task_t args; memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); rq.flags = REQ_PM_RESUME; rq.special = &args; rq.pm = &rqpm; rqpm.pm_step = ide_pm_state_start_resume; rqpm.pm_state = PM_EVENT_ON; return ide_do_drive_cmd(drive, &rq, ide_head_wait);}int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev, unsigned int cmd, unsigned long arg){ ide_settings_t *setting; ide_driver_t *drv; int err = 0; void __user *p = (void __user *)arg; down(&ide_setting_sem); if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) { if (cmd == setting->read_ioctl) { err = ide_read_setting(drive, setting); up(&ide_setting_sem); return err >= 0 ? put_user(err, (long __user *)arg) : err; } else { if (bdev != bdev->bd_contains) err = -EINVAL; else err = ide_write_setting(drive, setting, arg); up(&ide_setting_sem); return err; } } up(&ide_setting_sem); switch (cmd) { case HDIO_GETGEO: { struct hd_geometry geom; if (!p || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; geom.heads = drive->bios_head; geom.sectors = drive->bios_sect; geom.cylinders = (u16)drive->bios_cyl; /* truncate */ geom.start = get_start_sect(bdev); if (copy_to_user(p, &geom, sizeof(struct hd_geometry))) return -EFAULT; return 0; } case HDIO_OBSOLETE_IDENTITY: case HDIO_GET_IDENTITY: if (bdev != bdev->bd_contains) return -EINVAL; if (drive->id_read == 0) return -ENOMSG; if (copy_to_user(p, drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) return -EFAULT; return 0; case HDIO_GET_NICE: return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP | drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP | drive->nice0 << IDE_NICE_0 | drive->nice1 << IDE_NICE_1 | drive->nice2 << IDE_NICE_2, (long __user *) arg);#ifdef CONFIG_IDE_TASK_IOCTL case HDIO_DRIVE_TASKFILE: if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; switch(drive->media) { case ide_disk: return ide_taskfile_ioctl(drive, cmd, arg); default: return -ENOMSG; }#endif /* CONFIG_IDE_TASK_IOCTL */ case HDIO_DRIVE_CMD: if (!capable(CAP_SYS_RAWIO)) return -EACCES; return ide_cmd_ioctl(drive, cmd, arg); case HDIO_DRIVE_TASK: if (!capable(CAP_SYS_RAWIO)) return -EACCES; return ide_task_ioctl(drive, cmd, arg); case HDIO_SCAN_HWIF: { hw_regs_t hw; int args[3]; if (!capable(CAP_SYS_RAWIO)) return -EACCES; if (copy_from_user(args, p, 3 * sizeof(int))) return -EFAULT; memset(&hw, 0, sizeof(hw)); ide_init_hwif_ports(&hw, (unsigned long) args[0], (unsigned long) args[1], NULL); hw.irq = args[2]; if (ide_register_hw(&hw, NULL) == -1) return -EIO; return 0; } case HDIO_UNREGISTER_HWIF: if (!capable(CAP_SYS_RAWIO)) return -EACCES; /* (arg > MAX_HWIFS) checked in function */ ide_unregister(arg); return 0; case HDIO_SET_NICE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) return -EPERM; drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1; drv = *(ide_driver_t **)bdev->bd_disk->private_data; if (drive->dsc_overlap && !drv->supports_dsc_overlap) { drive->dsc_overlap = 0; return -EPERM; } drive->nice1 = (arg >> IDE_NICE_1) & 1; return 0; case HDIO_DRIVE_RESET: { unsigned long flags; if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* * Abort the current command on the * group if there is one, taking * care not to allow anything else * to be queued and to die on the * spot if we miss one somehow */ spin_lock_irqsave(&ide_lock, flags); ide_abort(drive, "drive reset"); if(HWGROUP(drive)->handler) BUG(); /* Ensure nothing gets queued after we drop the lock. Reset will clear the busy */ HWGROUP(drive)->busy = 1; spin_unlock_irqrestore(&ide_lock, flags); (void) ide_do_reset(drive); return 0; } case CDROMEJECT: case CDROMCLOSETRAY: return scsi_cmd_ioctl(file, bdev->bd_disk, cmd, p); case HDIO_GET_BUSSTATE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (put_user(HWIF(drive)->bus_state, (long __user *)arg)) return -EFAULT; return 0; case HDIO_SET_BUSSTATE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (HWIF(drive)->busproc) return HWIF(drive)->busproc(drive, (int)arg); return -EOPNOTSUPP; default: return -EINVAL; }}EXPORT_SYMBOL(generic_ide_ioctl);/* * stridx() returns the offset of c within s, * or -1 if c is '\0' or not found within s. */static int __init stridx (const char *s, char c){ char *i = strchr(s, c); return (i && c) ? i - s : -1;}/* * match_parm() does parsing for ide_setup(): * * 1. the first char of s must be '='. * 2. if the remainder matches one of the supplied keywords, * the index (1 based) of the keyword is negated and returned. * 3. if the remainder is a series of no more than max_vals numbers * separated by commas, the numbers are saved in vals[] and a * count of how many were saved is returned. Base10 is assumed, * and base16 is allowed when prefixed with "0x". * 4. otherwise, zero is returned. */static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals){ static const char *decimal = "0123456789"; static const char *hex = "0123456789abcdef"; int i, n; if (*s++ == '=') { /* * Try matching against the supplied keywords, * and return -(index+1) if we match one */ if (keywords != NULL) { for (i = 0; *keywords != NULL; ++i) { if (!strcmp(s, *keywords++)) return -(i+1); } } /* * Look for a series of no more than "max_vals" * numeric values separated by commas, in base10, * or base16 when prefixed with "0x". * Return a count of how many were found. */ for (n = 0; (i = stridx(decimal, *s)) >= 0;) { vals[n] = i; while ((i = stridx(decimal, *++s)) >= 0) vals[n] = (vals[n] * 10) + i; if (*s == 'x' && !vals[n]) { while ((i = stridx(hex, *++s)) >= 0) vals[n] = (vals[n] * 0x10) + i; } if (++n == max_vals) break; if (*s == ',' || *s == ';') ++s; } if (!*s) return n; } return 0; /* zero = nothing matched */}#ifdef CONFIG_BLK_DEV_ALI14XXstatic int __initdata probe_ali14xx;extern int ali14xx_init(void);#endif#ifdef CONFIG_BLK_DEV_UMC8672static int __initdata probe_umc8672;extern int umc8672_init(void);#endif#ifdef CONFIG_BLK_DEV_DTC2278static int __initdata probe_dtc2278;extern int dtc2278_init(void);#endif#ifdef CONFIG_BLK_DEV_HT6560Bstatic int __initdata probe_ht6560b;extern int ht6560b_init(void);#endif#ifdef CONFIG_BLK_DEV_QD65XXstatic int __initdata probe_qd65xx;extern int qd65xx_init(void);#endifstatic int __initdata is_chipset_set[MAX_HWIFS];/* * ide_setup() gets called VERY EARLY during initialization, * to handle kernel "command line" strings beginning with "hdx=" or "ide". * * Remember to update Documentation/ide.txt if you change something here.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?