📄 ide.c
字号:
EXPORT_SYMBOL(system_bus_clock);/* * Locking is badly broken here - since way back. That sucker is * root-only, but that's not an excuse... The real question is what * exclusion rules do we want here. */int ide_replace_subdriver (ide_drive_t *drive, const char *driver){ if (!drive->present || drive->usage || drive->dead) goto abort; if (DRIVER(drive)->cleanup(drive)) goto abort; strlcpy(drive->driver_req, driver, sizeof(drive->driver_req)); if (ata_attach(drive)) { spin_lock(&drives_lock); list_del_init(&drive->list); spin_unlock(&drives_lock); drive->driver_req[0] = 0; ata_attach(drive); } else { drive->driver_req[0] = 0; } if (DRIVER(drive)!= &idedefault_driver && !strcmp(DRIVER(drive)->name, driver)) return 0;abort: return 1;}/** * ata_attach - attach an ATA/ATAPI device * @drive: drive to attach * * Takes a drive that is as yet not assigned to any midlayer IDE * driver (or is assigned to the default driver) and figures out * which driver would like to own it. If nobody claims the drive * then it is automatically attached to the default driver used for * unclaimed objects. * * A return of zero indicates attachment to a driver, of one * attachment to the default driver. * * Takes drivers_lock. */int ata_attach(ide_drive_t *drive){ struct list_head *p; spin_lock(&drivers_lock); list_for_each(p, &drivers) { ide_driver_t *driver = list_entry(p, ide_driver_t, drivers); if (!try_module_get(driver->owner)) continue; spin_unlock(&drivers_lock); if (driver->attach(drive) == 0) { module_put(driver->owner); drive->gendev.driver = &driver->gen_driver; return 0; } spin_lock(&drivers_lock); module_put(driver->owner); } drive->gendev.driver = &idedefault_driver.gen_driver; spin_unlock(&drivers_lock); if(idedefault_driver.attach(drive) != 0) panic("ide: default attach failed"); return 1;}static int generic_ide_suspend(struct device *dev, u32 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; 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 = 0; return ide_do_drive_cmd(drive, &rq, ide_head_wait);}int generic_ide_ioctl(struct file *file, struct block_device *bdev, unsigned int cmd, unsigned long arg){ ide_drive_t *drive = bdev->bd_disk->private_data; ide_settings_t *setting; 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; if (drive->dsc_overlap && !DRIVER(drive)->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); DRIVER(drive)->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); if (drive->suspend_reset) {/* * APM WAKE UP todo !! * int nogoodpower = 1; * while(nogoodpower) { * check_power1() or check_power2() * nogoodpower = 0; * } * HWIF(drive)->multiproc(drive); */ return ioctl_by_bdev(bdev, BLKRRPART, 0); } 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_PDC4030static int __initdata probe_pdc4030;#endif#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. */int __init ide_setup (char *s){ int i, vals[3]; ide_hwif_t *hwif; ide_drive_t *drive; unsigned int hw, unit; const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1); const char max_hwif = '0' + (MAX_HWIFS - 1); if (strncmp(s,"hd",2) == 0 && s[2] == '=') /* hd= is for hd.c */ return 0; /* driver and not us */ if (strncmp(s,"ide",3) && strncmp(s,"idebus",6) && strncmp(s,"hd",2)) return 0; printk(KERN_INFO "ide_setup: %s", s); init_ide_data ();#ifdef CONFIG_BLK_DEV_IDEDOUBLER if (!strcmp(s, "ide=doubler")) { extern int ide_doubler; printk(" : Enabled support for IDE doublers\n"); ide_doubler = 1; return 1; }#endif /* CONFIG_BLK_DEV_IDEDOUBLER */ if (!strcmp(s, "ide=nodma")) { printk("IDE: Prevented DMA\n"); noautodma = 1; return 1; }#ifdef CONFIG_BLK_DEV_IDEPCI if (!strcmp(s, "ide=reverse")) { ide_scan_direction = 1; printk(" : Enabled support for IDE inverse scan order.\n"); return 1; }#endif /* CONFIG_BLK_DEV_IDEPCI */ /* * Look for drive options: "hdx=" */ if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) { const char *hd_words[] = { "none", "noprobe", "nowerr", "cdrom", "serialize", "autotune", "noautotune", "stroke", "swapdata", "bswap", "minus11", "remap", "remap63", "scsi", NULL }; unit = s[2] - 'a'; hw = unit / MAX_DRIVES; unit = unit % MAX_DRIVES; hwif = &ide_hwifs[hw]; drive = &hwif->drives[unit]; if (strncmp(s + 4, "ide-", 4) == 0) { strlcpy(drive->driver_req, s + 4, sizeof(drive->driver_req)); goto done; } switch (match_parm(&s[3], hd_words, vals, 3)) { case -1: /* "none" */ case -2: /* "noprobe" */ drive->noprobe = 1; goto done; case -3: /* "nowerr" */ drive->bad_wstat = BAD_R_STAT; hwif->noprobe = 0; goto done; case -4: /* "cdrom" */ drive->present = 1; drive->media = ide_cdrom; hwif->noprobe = 0; goto done; case -5: /* "serialize" */ printk(" -- USE \"ide%d=serialize\" INSTEAD", hw); goto do_serialize; case -6: /* "autotune" */ drive->autotune = IDE_TUNE_AUTO; goto done; case -7: /* "noautotune" */ drive->autotune = IDE_TUNE_NOAUTO; goto done; case -8: /* stroke */ drive->stroke = 1; goto done; case -9: /* "swapdata" */ case -10: /* "bswap" */ drive->bswap = 1; goto done; case -12: /* "remap" */ drive->remap_0_to_1 = 1; goto done; case -13: /* "remap63" */ drive->sect0 = 63; goto done; case -14: /* "scsi" */ drive->scsi = 1; goto done;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -