📄 ide-probe.c
字号:
blk_queue_max_phys_segments(q, max_sg_entries); /* assign drive queue */ drive->queue = q; /* needs drive->queue to be set */ ide_toggle_bounce(drive, 1); return 0;}/* * This routine sets up the irq for an ide interface, and creates a new * hwgroup for the irq/hwif if none was previously assigned. * * Much of the code is for correctly detecting/handling irq sharing * and irq serialization situations. This is somewhat complex because * it handles static as well as dynamic (PCMCIA) IDE interfaces. * * The IRQF_DISABLED in sa_flags means ide_intr() is always entered with * interrupts completely disabled. This can be bad for interrupt latency, * but anything else has led to problems on some machines. We re-enable * interrupts as much as we can safely do in most places. */static int init_irq (ide_hwif_t *hwif){ unsigned int index; ide_hwgroup_t *hwgroup; ide_hwif_t *match = NULL; BUG_ON(in_interrupt()); BUG_ON(irqs_disabled()); BUG_ON(hwif == NULL); mutex_lock(&ide_cfg_mtx); hwif->hwgroup = NULL;#if MAX_HWIFS > 1 /* * Group up with any other hwifs that share our irq(s). */ for (index = 0; index < MAX_HWIFS; index++) { ide_hwif_t *h = &ide_hwifs[index]; if (h->hwgroup) { /* scan only initialized hwif's */ if (hwif->irq == h->irq) { hwif->sharing_irq = h->sharing_irq = 1; if (hwif->chipset != ide_pci || h->chipset != ide_pci) { save_match(hwif, h, &match); } } if (hwif->serialized) { if (hwif->mate && hwif->mate->irq == h->irq) save_match(hwif, h, &match); } if (h->serialized) { if (h->mate && hwif->irq == h->mate->irq) save_match(hwif, h, &match); } } }#endif /* MAX_HWIFS > 1 */ /* * If we are still without a hwgroup, then form a new one */ if (match) { hwgroup = match->hwgroup; hwif->hwgroup = hwgroup; /* * Link us into the hwgroup. * This must be done early, do ensure that unexpected_intr * can find the hwif and prevent irq storms. * No drives are attached to the new hwif, choose_drive * can't do anything stupid (yet). * Add ourself as the 2nd entry to the hwgroup->hwif * linked list, the first entry is the hwif that owns * hwgroup->handler - do not change that. */ spin_lock_irq(&ide_lock); hwif->next = hwgroup->hwif->next; hwgroup->hwif->next = hwif; spin_unlock_irq(&ide_lock); } else { hwgroup = kmalloc_node(sizeof(ide_hwgroup_t), GFP_KERNEL | __GFP_ZERO, hwif_to_node(hwif->drives[0].hwif)); if (!hwgroup) goto out_up; hwif->hwgroup = hwgroup; hwgroup->hwif = hwif->next = hwif; hwgroup->rq = NULL; hwgroup->handler = NULL; hwgroup->drive = NULL; hwgroup->busy = 0; init_timer(&hwgroup->timer); hwgroup->timer.function = &ide_timer_expiry; hwgroup->timer.data = (unsigned long) hwgroup; } /* * Allocate the irq, if not already obtained for another hwif */ if (!match || match->irq != hwif->irq) { int sa = IRQF_DISABLED;#if defined(__mc68000__) || defined(CONFIG_APUS) sa = IRQF_SHARED;#endif /* __mc68000__ || CONFIG_APUS */ if (IDE_CHIPSET_IS_PCI(hwif->chipset)) { sa = IRQF_SHARED;#ifndef CONFIG_IDEPCI_SHARE_IRQ sa |= IRQF_DISABLED;#endif /* CONFIG_IDEPCI_SHARE_IRQ */ } if (hwif->io_ports[IDE_CONTROL_OFFSET]) /* clear nIEN */ hwif->OUTB(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); if (request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup)) goto out_unlink; } /* * For any present drive: * - allocate the block device queue * - link drive into the hwgroup */ for (index = 0; index < MAX_DRIVES; ++index) { ide_drive_t *drive = &hwif->drives[index]; if (!drive->present) continue; if (ide_init_queue(drive)) { printk(KERN_ERR "ide: failed to init %s\n",drive->name); continue; } spin_lock_irq(&ide_lock); if (!hwgroup->drive) { /* first drive for hwgroup. */ drive->next = drive; hwgroup->drive = drive; hwgroup->hwif = HWIF(hwgroup->drive); } else { drive->next = hwgroup->drive->next; hwgroup->drive->next = drive; } spin_unlock_irq(&ide_lock); }#if !defined(__mc68000__) && !defined(CONFIG_APUS) printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name, hwif->io_ports[IDE_DATA_OFFSET], hwif->io_ports[IDE_DATA_OFFSET]+7, hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);#else printk("%s at 0x%08lx on irq %d", hwif->name, hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);#endif /* __mc68000__ && CONFIG_APUS */ if (match) printk(" (%sed with %s)", hwif->sharing_irq ? "shar" : "serializ", match->name); printk("\n"); mutex_unlock(&ide_cfg_mtx); return 0;out_unlink: spin_lock_irq(&ide_lock); if (hwif->next == hwif) { BUG_ON(match); BUG_ON(hwgroup->hwif != hwif); kfree(hwgroup); } else { ide_hwif_t *g; g = hwgroup->hwif; while (g->next != hwif) g = g->next; g->next = hwif->next; if (hwgroup->hwif == hwif) { /* Impossible. */ printk(KERN_ERR "Duh. Uninitialized hwif listed as active hwif.\n"); hwgroup->hwif = g; } BUG_ON(hwgroup->hwif == hwif); } spin_unlock_irq(&ide_lock);out_up: mutex_unlock(&ide_cfg_mtx); return 1;}static int ata_lock(dev_t dev, void *data){ /* FIXME: we want to pin hwif down */ return 0;}static struct kobject *ata_probe(dev_t dev, int *part, void *data){ ide_hwif_t *hwif = data; int unit = *part >> PARTN_BITS; ide_drive_t *drive = &hwif->drives[unit]; if (!drive->present) return NULL; if (drive->media == ide_disk) request_module("ide-disk"); if (drive->scsi) request_module("ide-scsi"); if (drive->media == ide_cdrom || drive->media == ide_optical) request_module("ide-cd"); if (drive->media == ide_tape) request_module("ide-tape"); if (drive->media == ide_floppy) request_module("ide-floppy"); return NULL;}static struct kobject *exact_match(dev_t dev, int *part, void *data){ struct gendisk *p = data; *part &= (1 << PARTN_BITS) - 1; return &p->kobj;}static int exact_lock(dev_t dev, void *data){ struct gendisk *p = data; if (!get_disk(p)) return -1; return 0;}void ide_register_region(struct gendisk *disk){ blk_register_region(MKDEV(disk->major, disk->first_minor), disk->minors, NULL, exact_match, exact_lock, disk);}EXPORT_SYMBOL_GPL(ide_register_region);void ide_unregister_region(struct gendisk *disk){ blk_unregister_region(MKDEV(disk->major, disk->first_minor), disk->minors);}EXPORT_SYMBOL_GPL(ide_unregister_region);void ide_init_disk(struct gendisk *disk, ide_drive_t *drive){ ide_hwif_t *hwif = drive->hwif; unsigned int unit = (drive->select.all >> 4) & 1; disk->major = hwif->major; disk->first_minor = unit << PARTN_BITS; sprintf(disk->disk_name, "hd%c", 'a' + hwif->index * MAX_DRIVES + unit); disk->queue = drive->queue;}EXPORT_SYMBOL_GPL(ide_init_disk);static void ide_remove_drive_from_hwgroup(ide_drive_t *drive){ ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; if (drive == drive->next) { /* special case: last drive from hwgroup. */ BUG_ON(hwgroup->drive != drive); hwgroup->drive = NULL; } else { ide_drive_t *walk; walk = hwgroup->drive; while (walk->next != drive) walk = walk->next; walk->next = drive->next; if (hwgroup->drive == drive) { hwgroup->drive = drive->next; hwgroup->hwif = hwgroup->drive->hwif; } } BUG_ON(hwgroup->drive == drive);}static void drive_release_dev (struct device *dev){ ide_drive_t *drive = container_of(dev, ide_drive_t, gendev); spin_lock_irq(&ide_lock); ide_remove_drive_from_hwgroup(drive); kfree(drive->id); drive->id = NULL; drive->present = 0; /* Messed up locking ... */ spin_unlock_irq(&ide_lock); blk_cleanup_queue(drive->queue); spin_lock_irq(&ide_lock); drive->queue = NULL; spin_unlock_irq(&ide_lock); complete(&drive->gendev_rel_comp);}/* * init_gendisk() (as opposed to ide_geninit) is called for each major device, * after probing for drives, to allocate partition tables and other data * structures needed for the routines in genhd.c. ide_geninit() gets called * somewhat later, during the partition check. */static void init_gendisk (ide_hwif_t *hwif){ unsigned int unit; for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t * drive = &hwif->drives[unit]; ide_add_generic_settings(drive); snprintf(drive->gendev.bus_id,BUS_ID_SIZE,"%u.%u", hwif->index,unit); drive->gendev.parent = &hwif->gendev; drive->gendev.bus = &ide_bus_type; drive->gendev.driver_data = drive; drive->gendev.release = drive_release_dev; } blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS, THIS_MODULE, ata_probe, ata_lock, hwif);}static int hwif_init(ide_hwif_t *hwif){ int old_irq; /* Return success if no device is connected */ if (!hwif->present) return 1; if (!hwif->irq) { if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) { printk("%s: DISABLED, NO IRQ\n", hwif->name); return (hwif->present = 0); } }#ifdef CONFIG_BLK_DEV_HD if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) { printk("%s: CANNOT SHARE IRQ WITH OLD " "HARDDISK DRIVER (hd.c)\n", hwif->name); return (hwif->present = 0); }#endif /* CONFIG_BLK_DEV_HD */ /* we set it back to 1 if all is ok below */ hwif->present = 0; if (register_blkdev(hwif->major, hwif->name)) return 0; if (!hwif->sg_max_nents) hwif->sg_max_nents = PRD_ENTRIES; hwif->sg_table = kmalloc(sizeof(struct scatterlist)*hwif->sg_max_nents, GFP_KERNEL); if (!hwif->sg_table) { printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name); goto out; } sg_init_table(hwif->sg_table, hwif->sg_max_nents); if (init_irq(hwif) == 0) goto done; old_irq = hwif->irq; /* * It failed to initialise. Find the default IRQ for * this port and try that. */ if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) { printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, old_irq); goto out; } if (init_irq(hwif)) { printk("%s: probed IRQ %d and default IRQ %d failed.\n", hwif->name, old_irq, hwif->irq); goto out; } printk("%s: probed IRQ %d failed, using default.\n", hwif->name, hwif->irq);done: init_gendisk(hwif); ide_acpi_init(hwif); hwif->present = 1; /* success */ return 1;out: unregister_blkdev(hwif->major, hwif->name); return 0;}static void hwif_register_devices(ide_hwif_t *hwif){ unsigned int i; for (i = 0; i < MAX_DRIVES; i++) { ide_drive_t *drive = &hwif->drives[i]; if (drive->present) { int ret = device_register(&drive->gendev); if (ret < 0) printk(KERN_WARNING "IDE: %s: " "device_register error: %d\n", __FUNCTION__, ret); } }}int ideprobe_init (void){ unsigned int index; int probe[MAX_HWIFS]; memset(probe, 0, MAX_HWIFS * sizeof(int)); for (index = 0; index < MAX_HWIFS; ++index) probe[index] = !ide_hwifs[index].present; for (index = 0; index < MAX_HWIFS; ++index) if (probe[index]) probe_hwif(&ide_hwifs[index]); for (index = 0; index < MAX_HWIFS; ++index) if (probe[index]) hwif_init(&ide_hwifs[index]); for (index = 0; index < MAX_HWIFS; ++index) { if (probe[index]) { ide_hwif_t *hwif = &ide_hwifs[index]; if (!hwif->present) continue; if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced) hwif->chipset = ide_generic; hwif_register_devices(hwif); } } for (index = 0; index < MAX_HWIFS; ++index) if (probe[index]) ide_proc_register_port(&ide_hwifs[index]); return 0;}EXPORT_SYMBOL_GPL(ideprobe_init);int ide_device_add(u8 idx[4]){ int i, rc = 0; for (i = 0; i < 4; i++) { if (idx[i] != 0xff) rc |= probe_hwif_init(&ide_hwifs[idx[i]]); } for (i = 0; i < 4; i++) { if (idx[i] != 0xff) ide_proc_register_port(&ide_hwifs[idx[i]]); } return rc;}EXPORT_SYMBOL_GPL(ide_device_add);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -