📄 ide.c
字号:
for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; if (!drive->present) continue; if (drive->busy || drive->usage) goto abort; if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) goto abort; } hwif->present = 0; /* * All clear? Then blow away the buffer cache */ sti(); for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; if (!drive->present) continue; minor = drive->select.b.unit << PARTN_BITS; for (p = 0; p < (1<<PARTN_BITS); ++p) { if (drive->part[p].nr_sects > 0) { kdev_t devp = MKDEV(hwif->major, minor+p); struct super_block * sb = get_super(devp); if (sb) invalidate_inodes(sb); invalidate_buffers (devp); } } } cli(); 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); /* * 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_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8); ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); /* * Remove us from the hwgroup, and free * the hwgroup if we were the only member */ d = hwgroup->drive; for (i = 0; i < MAX_DRIVES; ++i) { drive = &hwif->drives[i]; if (!drive->present) continue; while (hwgroup->drive->next != drive) hwgroup->drive = hwgroup->drive->next; hwgroup->drive->next = drive->next; if (hwgroup->drive == drive) hwgroup->drive = NULL; if (drive->id != NULL) { kfree(drive->id); drive->id = NULL; } drive->present = 0; } if (d->present) hwgroup->drive = d; while (hwgroup->hwif->next != hwif) hwgroup->hwif = hwgroup->hwif->next; hwgroup->hwif->next = hwif->next; if (hwgroup->hwif == hwif) kfree(hwgroup); else hwgroup->hwif = HWIF(hwgroup->drive);#ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) (void) ide_release_dma(hwif);#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * Remove us from the kernel's knowledge */ unregister_blkdev(hwif->major, hwif->name); kfree(blksize_size[hwif->major]); kfree(max_sectors[hwif->major]); kfree(max_readahead[hwif->major]); blk_dev[hwif->major].request_fn = NULL; blk_dev[hwif->major].data = NULL; blk_dev[hwif->major].queue = NULL; blksize_size[hwif->major] = NULL; for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) if (*gdp == hwif->gd) break; if (*gdp == NULL) printk("gd not in disk chain!\n"); else { gd = *gdp; *gdp = gd->next; kfree(gd->sizes); kfree(gd->part); kfree(gd); } init_hwif_data (index); /* restore hwif data to pristine status */abort: restore_flags(flags); /* all CPUs */#endif}int ide_register (int arg1, int arg2, int irq){ int index, retry = 1; ide_hwif_t *hwif; ide_ioreg_t data_port = (ide_ioreg_t) arg1, ctl_port = (ide_ioreg_t) arg2; do { for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; if (hwif->io_ports[IDE_DATA_OFFSET] == data_port) goto found; } for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; if (!hwif->present) goto found; } for (index = 0; index < MAX_HWIFS; index++) ide_unregister(index); } while (retry--); return -1;found: if (hwif->present) ide_unregister(index); if (hwif->present) return -1; ide_init_hwif_ports(hwif->io_ports, data_port, &hwif->irq); if (ctl_port) hwif->io_ports[IDE_CONTROL_OFFSET] = ctl_port; hwif->irq = irq; hwif->noprobe = 0; ide_init_module(IDE_PROBE_MODULE); ide_init_module(IDE_DRIVER_MODULE); return hwif->present ? index : -1;}void 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; 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) setting->auto_remove = 1; *p = setting; return;abort: if (setting) kfree(setting);}void ide_remove_setting(ide_drive_t *drive, char *name){ ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting; while ((*p) && strcmp((*p)->name, name)) p = &((*p)->next); if ((setting = (*p)) == NULL) return; (*p) = setting->next; kfree(setting->name); kfree(setting);}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_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;}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; }}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(&HWGROUP(drive)->spinlock, 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(&HWGROUP(drive)->spinlock, flags); } return val;}int ide_spin_wait_hwgroup (ide_drive_t *drive, unsigned long *flags){ ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned long timeout = jiffies + (3 * HZ); spin_lock_irqsave(&hwgroup->spinlock, *flags); while (hwgroup->busy) { spin_unlock_irqrestore(&hwgroup->spinlock, *flags); __sti(); /* local CPU only; needed for jiffies */ if (0 < (signed long)(jiffies - timeout)) { printk("%s: channel busy\n", drive->name); return -EBUSY; } spin_lock_irqsave(&hwgroup->spinlock, *flags); } return 0;}int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val){ unsigned long flags; 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, &flags)) 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_irqrestore(&HWGROUP(drive)->spinlock, flags); 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){ if (!drive->driver || !DRIVER(drive)->supports_dma) return -EPERM; if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc) return -EPERM; if (HWIF(drive)->dmaproc(arg ? ide_dma_on : 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 = (byte) arg; drive->special.b.set_tune = 1; (void) ide_do_drive_cmd (drive, &rq, ide_wait); 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);}int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf){ struct request rq; byte buffer[4]; if (!buf) buf = buffer; memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors); ide_init_drive_cmd(&rq); rq.buffer = buf; *buf++ = cmd; *buf++ = nsect; *buf++ = feature; *buf++ = sectors; return ide_do_drive_cmd(drive, &rq, ide_wait);}static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int err, 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; if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) { if (cmd == setting->read_ioctl) { err = ide_read_setting(drive, setting); return err >= 0 ? put_user(err, (long *) arg) : err; } else { if ((MINOR(inode->i_rdev) & PARTN_MASK)) return -EINVAL; return ide_write_setting(drive, setting, arg); } } ide_init_drive_cmd (&rq); switch (cmd) { case HDIO_GETGEO: { struct hd_geometry *loc = (struct hd_geometry *) arg; if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT; if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT; if (put_user(drive->bios_cyl, (unsigned short *) &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 BLKSSZGET: /* Block size of media */ return put_user(blksize_size[HWIF(drive)->major] [minor&PARTN_MASK], (int *)arg); case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case BLKGETSIZE: /* Return device size */ return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg); case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_A
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -