📄 ide.c
字号:
if (!err && arg) { ide_set_xfer_rate(drive, (u8) arg); ide_driveid_update(drive); } return err;}int ide_atapi_to_scsi (ide_drive_t *drive, int arg){ if (drive->media == ide_disk) { drive->scsi = 0; return 0; } if (DRIVER(drive)->cleanup(drive)) { drive->scsi = 0; return 0; } drive->scsi = (u8) arg; ide_attach_drive(drive); return 0;}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); ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL); ide_add_setting(drive, "nice1", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL); ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode); ide_add_setting(drive, "slow", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->slow, NULL); 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); 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); ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL); ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate); ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL);#if 0 /* Experimental, but this needs the setting/register locking rewritten to be used */ if (drive->media != ide_disk) ide_add_setting(drive, "ide-scsi", SETTING_RW, -1, HDIO_SET_IDE_SCSI, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, ide_atapi_to_scsi);#endif }/* * Delay for *at least* 50ms. As we don't know how much time is left * until the next tick occurs, we wait an extra tick to be safe. * This is used only during the probing/polling for drives at boot time. * * However, its usefullness may be needed in other places, thus we export it now. * The future may change this to a millisecond setable delay. */void ide_delay_50ms (void){#ifndef CONFIG_BLK_DEV_IDECS mdelay(50);#else __set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1+HZ/20);#endif /* CONFIG_BLK_DEV_IDECS */}EXPORT_SYMBOL(ide_delay_50ms);int system_bus_clock (void){ return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));}EXPORT_SYMBOL(system_bus_clock);int ide_replace_subdriver (ide_drive_t *drive, const char *driver){ if (!drive->present || drive->busy || drive->usage || drive->dead) goto abort; if (DRIVER(drive)->cleanup(drive)) goto abort; strncpy(drive->driver_req, driver, 9); ide_driver_module(0); drive->driver_req[0] = 0; ide_driver_module(0); if (!strcmp(DRIVER(drive)->name, driver)) return 0;abort: return 1;}EXPORT_SYMBOL(ide_replace_subdriver);int ide_attach_drive (ide_drive_t *drive){ /* Someone unplugged the device on us */ if(drive->dead) return 1; #ifdef CONFIG_BLK_DEV_IDESCSI if (drive->scsi) { extern int idescsi_attach(ide_drive_t *drive); if (idescsi_attach(drive)) return 0; }#endif /* CONFIG_BLK_DEV_IDESCSI */ switch (drive->media) {#ifdef CONFIG_BLK_DEV_IDECD case ide_cdrom: { extern int ide_cdrom_attach(ide_drive_t *drive); if (ide_cdrom_attach(drive)) return 1; break; }#endif /* CONFIG_BLK_DEV_IDECD */#ifdef CONFIG_BLK_DEV_IDEDISK case ide_disk: { extern int idedisk_attach(ide_drive_t *drive); if (idedisk_attach(drive)) return 1; break; }#endif /* CONFIG_BLK_DEV_IDEDISK */#ifdef CONFIG_BLK_DEV_IDEFLOPPY case ide_floppy: { extern int idefloppy_attach(ide_drive_t *drive); if (idefloppy_attach(drive)) return 1; break; }#endif /* CONFIG_BLK_DEV_IDEFLOPPY */#ifdef CONFIG_BLK_DEV_IDETAPE case ide_tape: { extern int idetape_attach(ide_drive_t *drive); if (idetape_attach(drive)) return 1; break; }#endif /* CONFIG_BLK_DEV_IDETAPE */ default: { extern int idedefault_attach(ide_drive_t *drive); if(idedefault_attach(drive)) printk(KERN_CRIT "ide: failed to attach default driver.\n"); return 1; } } return 0;}EXPORT_SYMBOL(ide_attach_drive);static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int err = 0, major, minor; ide_drive_t *drive; struct request rq; kdev_t dev; ide_settings_t *setting; if (!inode || !(dev = inode->i_rdev)) return -EINVAL; major = MAJOR(dev); minor = MINOR(dev); if ((drive = get_info_ptr(inode->i_rdev)) == NULL) return -ENODEV; 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 *) arg) : err; } else { if ((MINOR(inode->i_rdev) & PARTN_MASK)) err = -EINVAL; else err = ide_write_setting(drive, setting, arg); up(&ide_setting_sem); return err; } } up(&ide_setting_sem); ide_init_drive_cmd (&rq); switch (cmd) { case HDIO_GETGEO: { struct hd_geometry *loc = (struct hd_geometry *) arg; u16 bios_cyl = drive->bios_cyl; /* truncate */ if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT; if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT; if (put_user(bios_cyl, (u16 *) &loc->cylinders)) return -EFAULT; if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } case HDIO_GETGEO_BIG: { struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT; if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT; if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT; if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } case HDIO_GETGEO_BIG_RAW: { struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; if (put_user(drive->head, (u8 *) &loc->heads)) return -EFAULT; if (put_user(drive->sect, (u8 *) &loc->sectors)) return -EFAULT; if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT; if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } case BLKGETSIZE: /* Return device size */ return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (unsigned long *) arg); case BLKGETSIZE64: return put_user((u64)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects << 9, (u64 *) arg); case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; return ide_revalidate_disk(inode->i_rdev); case HDIO_OBSOLETE_IDENTITY: case HDIO_GET_IDENTITY: if (MINOR(inode->i_rdev) & PARTN_MASK) return -EINVAL; if (drive->id_read == 0) return -ENOMSG; if (copy_to_user((char *)arg, (char *)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 *) 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, inode, file, cmd, arg);#ifdef CONFIG_PKT_TASK_IOCTL case ide_cdrom: case ide_tape: case ide_floppy: return pkt_taskfile_ioctl(drive, inode, file, cmd, arg);#endif /* CONFIG_PKT_TASK_IOCTL */ default: return -ENOMSG; }#endif /* CONFIG_IDE_TASK_IOCTL */ case HDIO_DRIVE_CMD: if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; return ide_cmd_ioctl(drive, inode, file, cmd, arg); case HDIO_DRIVE_TASK: if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; return ide_task_ioctl(drive, inode, file, cmd, arg); case HDIO_SCAN_HWIF: { int args[3]; if (!capable(CAP_SYS_RAWIO)) return -EACCES; if (copy_from_user(args, (void *)arg, 3 * sizeof(int))) return -EFAULT; if (ide_register(args[0], args[1], args[2]) == -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(&io_request_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(&io_request_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 ide_revalidate_disk(inode->i_rdev); } return 0; } case BLKROSET: case BLKROGET: case BLKFLSBUF: case BLKSSZGET: case BLKPG: case BLKELVGET: case BLKELVSET: case BLKBSZGET: case BLKBSZSET: return blk_ioctl(inode->i_rdev, cmd, arg); case HDIO_GET_BUSSTATE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (put_user(HWIF(drive)->bus_state, (long *)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 DRIVER(drive)->ioctl(drive, inode, file, cmd, arg); return -EPERM; }}static int ide_check_media_change (kdev_t i_rdev){ ide_drive_t *drive; if ((drive = get_info_ptr(i_rdev)) == NULL) return -ENODEV; return DRIVER(drive)->media_change(drive);}/* * 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 */}/* * ide_setup() gets called VERY EARLY during initialization, * to handle kernel "command line" strings beginning with "hdx=" * or "ide". Here is the complete set currently supported: * * "hdx=" is recognized for all "x" from "a" to "h", such as "hdc". * "idex=" is recognized for all "x" from "0" to "3", such as "ide1". * * "hdx=noprobe" : drive may be present, but do not probe for it * "hdx=none" : drive is NOT present, ignore cmos and do not probe * "hdx=nowerr" : ignore the WRERR_STAT bit on this drive * "hdx=cdrom" : drive is present, and is a cdrom drive * "hdx=cyl,head,sect" : disk drive is present, with specified geometry
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -