📄 ide.c
字号:
*/void ide_intr (int irq, void *dev_id, struct pt_regs *regs){ unsigned long flags; ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id; ide_hwif_t *hwif; ide_drive_t *drive; ide_handler_t *handler; ide_startstop_t startstop; spin_lock_irqsave(&io_request_lock, flags); hwif = hwgroup->hwif; if (!ide_ack_intr(hwif)) { spin_unlock_irqrestore(&io_request_lock, flags); return; } if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) { /* * Not expecting an interrupt from this drive. * That means this could be: * (1) an interrupt from another PCI device * sharing the same PCI INT# as us. * or (2) a drive just entered sleep or standby mode, * and is interrupting to let us know. * or (3) a spurious interrupt of unknown origin. * * For PCI, we cannot tell the difference, * so in that case we just ignore it and hope it goes away. */#ifdef CONFIG_BLK_DEV_IDEPCI if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))#endif /* CONFIG_BLK_DEV_IDEPCI */ { /* * Probably not a shared PCI interrupt, * so we can safely try to do something about it: */ unexpected_intr(irq, hwgroup);#ifdef CONFIG_BLK_DEV_IDEPCI } else { /* * Whack the status register, just in case we have a leftover pending IRQ. */ (void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);#endif /* CONFIG_BLK_DEV_IDEPCI */ } spin_unlock_irqrestore(&io_request_lock, flags); return; } drive = hwgroup->drive; if (!drive) { /* * This should NEVER happen, and there isn't much we could do about it here. */ spin_unlock_irqrestore(&io_request_lock, flags); return; } if (!drive_is_ready(drive)) { /* * This happens regularly when we share a PCI IRQ with another device. * Unfortunately, it can also happen with some buggy drives that trigger * the IRQ before their status register is up to date. Hopefully we have * enough advance overhead that the latter isn't a problem. */ spin_unlock_irqrestore(&io_request_lock, flags); return; } if (!hwgroup->busy) { hwgroup->busy = 1; /* paranoia */ printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name); } hwgroup->handler = NULL; del_timer(&hwgroup->timer); spin_unlock(&io_request_lock); if (drive->unmask) ide__sti(); /* local CPU only */ startstop = handler(drive); /* service this interrupt, may set handler for next interrupt */ spin_lock_irq(&io_request_lock); /* * Note that handler() may have set things up for another * interrupt to occur soon, but it cannot happen until * we exit from this routine, because it will be the * same irq as is currently being serviced here, and Linux * won't allow another of the same (on any CPU) until we return. */ set_recovery_timer(HWIF(drive)); drive->service_time = jiffies - drive->service_start; if (startstop == ide_stopped) { if (hwgroup->handler == NULL) { /* paranoia */ hwgroup->busy = 0; ide_do_request(hwgroup, hwif->irq); } else { printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name); } } spin_unlock_irqrestore(&io_request_lock, flags);}/* * get_info_ptr() returns the (ide_drive_t *) for a given device number. * It returns NULL if the given device number does not match any present drives. */ide_drive_t *get_info_ptr (kdev_t i_rdev){ int major = MAJOR(i_rdev);#if 0 int minor = MINOR(i_rdev) & PARTN_MASK;#endif unsigned int h; for (h = 0; h < MAX_HWIFS; ++h) { ide_hwif_t *hwif = &ide_hwifs[h]; if (hwif->present && major == hwif->major) { unsigned unit = DEVICE_NR(i_rdev); if (unit < MAX_DRIVES) { ide_drive_t *drive = &hwif->drives[unit];#if 0 if ((drive->present) && (drive->part[minor].nr_sects))#else if (drive->present)#endif return drive; } break; } } return NULL;}/* * This function is intended to be used prior to invoking ide_do_drive_cmd(). */void ide_init_drive_cmd (struct request *rq){ memset(rq, 0, sizeof(*rq)); rq->cmd = IDE_DRIVE_CMD;}/* * This function issues a special IDE device request * onto the request queue. * * If action is ide_wait, then the rq is queued at the end of the * request queue, and the function sleeps until it has been processed. * This is for use when invoked from an ioctl handler. * * If action is ide_preempt, then the rq is queued at the head of * the request queue, displacing the currently-being-processed * request and this function returns immediately without waiting * for the new rq to be completed. This is VERY DANGEROUS, and is * intended for careful use by the ATAPI tape/cdrom driver code. * * If action is ide_next, then the rq is queued immediately after * the currently-being-processed-request (if any), and the function * returns without waiting for the new rq to be completed. As above, * This is VERY DANGEROUS, and is intended for careful use by the * ATAPI tape/cdrom driver code. * * If action is ide_end, then the rq is queued at the end of the * request queue, and the function returns immediately without waiting * for the new rq to be completed. This is again intended for careful * use by the ATAPI tape/cdrom driver code. */int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action){ unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned int major = HWIF(drive)->major; struct list_head *queue_head = &drive->queue.queue_head; DECLARE_COMPLETION(wait);#ifdef CONFIG_BLK_DEV_PDC4030 if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL) return -ENOSYS; /* special drive cmds not supported */#endif rq->errors = 0; rq->rq_status = RQ_ACTIVE; rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS); if (action == ide_wait) rq->waiting = &wait; spin_lock_irqsave(&io_request_lock, flags); if (list_empty(queue_head) || action == ide_preempt) { if (action == ide_preempt) hwgroup->rq = NULL; } else { if (action == ide_wait || action == ide_end) { queue_head = queue_head->prev; } else queue_head = queue_head->next; } list_add(&rq->queue, queue_head); ide_do_request(hwgroup, 0); spin_unlock_irqrestore(&io_request_lock, flags); if (action == ide_wait) { wait_for_completion(&wait); /* wait for it to be serviced */ return rq->errors ? -EIO : 0; /* return -EIO if errors */ } return 0;}/* * This routine is called to flush all partitions and partition tables * for a changed disk, and then re-read the new partition table. * If we are revalidating a disk because of a media change, then we * enter with usage == 0. If we are using an ioctl, we automatically have * usage == 1 (we need an open channel to use an ioctl :-), so this * is our limit. */int ide_revalidate_disk (kdev_t i_rdev){ ide_drive_t *drive; ide_hwgroup_t *hwgroup; unsigned int p, major, minor; long flags; if ((drive = get_info_ptr(i_rdev)) == NULL) return -ENODEV; major = MAJOR(i_rdev); minor = drive->select.b.unit << PARTN_BITS; hwgroup = HWGROUP(drive); spin_lock_irqsave(&io_request_lock, flags); if (drive->busy || (drive->usage > 1)) { spin_unlock_irqrestore(&io_request_lock, flags); return -EBUSY; }; drive->busy = 1; MOD_INC_USE_COUNT; spin_unlock_irqrestore(&io_request_lock, flags); for (p = 0; p < (1<<PARTN_BITS); ++p) { if (drive->part[p].nr_sects > 0) { kdev_t devp = MKDEV(major, minor+p); invalidate_device(devp, 1); } drive->part[p].start_sect = 0; drive->part[p].nr_sects = 0; }; if (DRIVER(drive)->revalidate) DRIVER(drive)->revalidate(drive); drive->busy = 0; wake_up(&drive->wqueue); MOD_DEC_USE_COUNT; return 0;}static void revalidate_drives (void){ ide_hwif_t *hwif; ide_drive_t *drive; int index, unit; for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &ide_hwifs[index].drives[unit]; if (drive->revalidate) { drive->revalidate = 0; if (!initializing) (void) ide_revalidate_disk(MKDEV(hwif->major, unit<<PARTN_BITS)); } } }}static void ide_probe_module (void){ if (!ide_probe) {#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE) (void) request_module("ide-probe-mod");#endif /* (CONFIG_KMOD) && (CONFIG_BLK_DEV_IDE_MODULE) */ } else { (void) ide_probe->init(); } revalidate_drives();}static void ide_driver_module (void){ int index; ide_module_t *module = ide_modules; for (index = 0; index < MAX_HWIFS; ++index) if (ide_hwifs[index].present) goto search; ide_probe_module();search: while (module) { (void) module->init(); module = module->next; } revalidate_drives();}static int ide_open (struct inode * inode, struct file * filp){ ide_drive_t *drive; if ((drive = get_info_ptr(inode->i_rdev)) == NULL) return -ENXIO; if (drive->driver == NULL) ide_driver_module();#ifdef CONFIG_KMOD if (drive->driver == NULL) { if (drive->media == ide_disk) (void) request_module("ide-disk"); if (drive->media == ide_cdrom) (void) request_module("ide-cd"); if (drive->media == ide_tape) (void) request_module("ide-tape"); if (drive->media == ide_floppy) (void) request_module("ide-floppy"); }#endif /* CONFIG_KMOD */ while (drive->busy) sleep_on(&drive->wqueue); drive->usage++; if (drive->driver != NULL) return DRIVER(drive)->open(inode, filp, drive); printk ("%s: driver not present\n", drive->name); drive->usage--; return -ENXIO;}/* * Releasing a block device means we sync() it, so that it can safely * be forgotten about... */static int ide_release (struct inode * inode, struct file * file){ ide_drive_t *drive; if ((drive = get_info_ptr(inode->i_rdev)) != NULL) { drive->usage--; if (drive->driver != NULL) DRIVER(drive)->release(inode, file, drive); } return 0;}int ide_replace_subdriver (ide_drive_t *drive, const char *driver){ if (!drive->present || drive->busy || drive->usage) goto abort; if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) goto abort; strncpy(drive->driver_req, driver, 9); ide_driver_module(); drive->driver_req[0] = 0; ide_driver_module(); if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver)) return 0;abort: return 1;}#ifdef CONFIG_PROC_FSide_proc_entry_t generic_subdriver_entries[] = { { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL }, { NULL, 0, NULL, NULL }};#endif/* * Note that we only release the standard ports, * and do not even try to handle any extra ports * allocated for weird IDE interface chipsets. */void hwif_unregister (ide_hwif_t *hwif){ if (hwif->straight8) { ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8); goto jump_eight; } if (hwif->io_ports[IDE_DATA_OFFSET]) ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1); if (hwif->io_ports[IDE_ERROR_OFFSET]) ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1); if (hwif->io_ports[IDE_NSECTOR_OFFSET]) ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1); if (hwif->io_ports[IDE_SECTOR_OFFSET]) ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1); if (hwif->io_ports[IDE_LCYL_OFFSET]) ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1); if (hwif->io_ports[IDE_HCYL_OFFSET]) ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1); if (hwif->io_ports[IDE_SELECT_OFFSET]) ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1); if (hwif->io_ports[IDE_STATUS_OFFSET]) ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);jump_eight: if (hwif->io_ports[IDE_CONTROL_OFFSET]) ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) if (hwif->io_ports[IDE_IRQ_OFFSET]) ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */}void ide_unregister (unsigned int index){ struct gendisk *gd; ide_drive_t *drive, *d; ide_hwif_t *hwif, *g; ide_hwgroup_t *hwgroup; int irq_count = 0, unit, i; unsigned long flags; unsigned int p, minor; ide_hwif_t old_hwif; if (index >= MAX_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -