ide.c

来自「2410的硬盘块设备源码」· C语言 代码 · 共 2,013 行 · 第 1/4 页

C
2,013
字号
	hwif->ide_dma_check		= tmp_hwif->ide_dma_check;	hwif->ide_dma_on		= tmp_hwif->ide_dma_on;	hwif->ide_dma_off_quietly	= tmp_hwif->ide_dma_off_quietly;	hwif->ide_dma_test_irq		= tmp_hwif->ide_dma_test_irq;	hwif->ide_dma_host_on		= tmp_hwif->ide_dma_host_on;	hwif->ide_dma_host_off		= tmp_hwif->ide_dma_host_off;	hwif->ide_dma_lostirq		= tmp_hwif->ide_dma_lostirq;	hwif->ide_dma_timeout		= tmp_hwif->ide_dma_timeout;	hwif->OUTB			= tmp_hwif->OUTB;	hwif->OUTBSYNC			= tmp_hwif->OUTBSYNC;	hwif->OUTW			= tmp_hwif->OUTW;	hwif->OUTL			= tmp_hwif->OUTL;	hwif->OUTSW			= tmp_hwif->OUTSW;	hwif->OUTSL			= tmp_hwif->OUTSL;	hwif->INB			= tmp_hwif->INB;	hwif->INW			= tmp_hwif->INW;	hwif->INL			= tmp_hwif->INL;	hwif->INSW			= tmp_hwif->INSW;	hwif->INSL			= tmp_hwif->INSL;	hwif->sg_max_nents		= tmp_hwif->sg_max_nents;	hwif->mmio			= tmp_hwif->mmio;	hwif->rqsize			= tmp_hwif->rqsize;	hwif->no_lba48			= tmp_hwif->no_lba48;#ifndef CONFIG_BLK_DEV_IDECS	hwif->irq			= tmp_hwif->irq;#endif	hwif->dma_base			= tmp_hwif->dma_base;	hwif->dma_master		= tmp_hwif->dma_master;	hwif->dma_command		= tmp_hwif->dma_command;	hwif->dma_vendor1		= tmp_hwif->dma_vendor1;	hwif->dma_status		= tmp_hwif->dma_status;	hwif->dma_vendor3		= tmp_hwif->dma_vendor3;	hwif->dma_prdtable		= tmp_hwif->dma_prdtable;	hwif->dma_extra			= tmp_hwif->dma_extra;	hwif->config_data		= tmp_hwif->config_data;	hwif->select_data		= tmp_hwif->select_data;	hwif->autodma			= tmp_hwif->autodma;	hwif->udma_four			= tmp_hwif->udma_four;	hwif->no_dsc			= tmp_hwif->no_dsc;	hwif->hwif_data			= tmp_hwif->hwif_data;}/** *	ide_unregister		-	free an ide interface *	@index: index of interface (will change soon to a pointer) * *	Perform the final unregister of an IDE interface. At the moment *	we don't refcount interfaces so this will also get split up. * *	Locking: *	The caller must not hold the IDE locks *	The drive present/vanishing is not yet properly locked *	Take care with the callbacks. These have been split to avoid *	deadlocking the IDE layer. The shutdown callback is called *	before we take the lock and free resources. It is up to the *	caller to be sure there is no pending I/O here, and that *	the interfce will not be reopened (present/vanishing locking *	isnt yet done btw). After we commit to the final kill we *	call the cleanup callback with the ide locks held. * *	Unregister restores the hwif structures to the default state. *	This is raving bonkers. */void ide_unregister(unsigned int index){	ide_drive_t *drive;	ide_hwif_t *hwif, *g;	static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */	ide_hwgroup_t *hwgroup;	int irq_count = 0, unit;	BUG_ON(index >= MAX_HWIFS);	BUG_ON(in_interrupt());	BUG_ON(irqs_disabled());	down(&ide_cfg_sem);	spin_lock_irq(&ide_lock);	hwif = &ide_hwifs[index];	if (!hwif->present)		goto abort;	for (unit = 0; unit < MAX_DRIVES; ++unit) {		drive = &hwif->drives[unit];		if (!drive->present) {			if (drive->devfs_name[0] != '\0') {				devfs_remove(drive->devfs_name);				drive->devfs_name[0] = '\0';			}			continue;		}		spin_unlock_irq(&ide_lock);		device_unregister(&drive->gendev);		down(&drive->gendev_rel_sem);		spin_lock_irq(&ide_lock);	}	hwif->present = 0;	spin_unlock_irq(&ide_lock);	destroy_proc_ide_interface(hwif);	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);	spin_lock_irq(&ide_lock);	/*	 * 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_hwif_release_regions(hwif);	/*	 * Remove us from the hwgroup, and free	 * the hwgroup if we were the only member	 */	if (hwif->next == hwif) {		BUG_ON(hwgroup->hwif != hwif);		kfree(hwgroup);	} else {		/* There is another interface in hwgroup.		 * Unlink us, and set hwgroup->drive and ->hwif to		 * something sane.		 */		g = hwgroup->hwif;		while (g->next != hwif)			g = g->next;		g->next = hwif->next;		if (hwgroup->hwif == hwif) {			/* Chose a random hwif for hwgroup->hwif.			 * It's guaranteed that there are no drives			 * left in the hwgroup.			 */			BUG_ON(hwgroup->drive != NULL);			hwgroup->hwif = g;		}		BUG_ON(hwgroup->hwif == hwif);	}	/* More messed up locking ... */	spin_unlock_irq(&ide_lock);	device_unregister(&hwif->gendev);	down(&hwif->gendev_rel_sem);	/*	 * Remove us from the kernel's knowledge	 */	blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS);	kfree(hwif->sg_table);	unregister_blkdev(hwif->major, hwif->name);	spin_lock_irq(&ide_lock);	if (hwif->dma_base) {		(void) ide_release_dma(hwif);		hwif->dma_base = 0;		hwif->dma_master = 0;		hwif->dma_command = 0;		hwif->dma_vendor1 = 0;		hwif->dma_status = 0;		hwif->dma_vendor3 = 0;		hwif->dma_prdtable = 0;	}	/* copy original settings */	tmp_hwif = *hwif;	/* restore hwif data to pristine status */	init_hwif_data(hwif, index);	init_hwif_default(hwif, index);	ide_hwif_restore(hwif, &tmp_hwif);abort:	spin_unlock_irq(&ide_lock);	up(&ide_cfg_sem);}EXPORT_SYMBOL(ide_unregister);/** *	ide_setup_ports 	-	set up IDE interface ports *	@hw: register descriptions *	@base: base register *	@offsets: table of register offsets *	@ctrl: control register *	@ack_irq: IRQ ack *	@irq: interrupt lie * *	Setup hw_regs_t structure described by parameters.  You *	may set up the hw structure yourself OR use this routine to *	do it for you. This is basically a helper * */ void ide_setup_ports (	hw_regs_t *hw,			unsigned long base, int *offsets,			unsigned long ctrl, unsigned long intr,			ide_ack_intr_t *ack_intr,/* *			ide_io_ops_t *iops, */			int irq){	int i;	for (i = 0; i < IDE_NR_PORTS; i++) {		if (offsets[i] == -1) {			switch(i) {				case IDE_CONTROL_OFFSET:					hw->io_ports[i] = ctrl;					break;#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)				case IDE_IRQ_OFFSET:					hw->io_ports[i] = intr;					break;#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */				default:					hw->io_ports[i] = 0;					break;			}		} else {			hw->io_ports[i] = base + offsets[i];		}	}	hw->irq = irq;	hw->dma = NO_DMA;	hw->ack_intr = ack_intr;/* *	hw->iops = iops; */}/** *	ide_register_hw_with_fixup	-	register IDE interface *	@hw: hardware registers *	@hwifp: pointer to returned hwif *	@fixup: fixup function * *	Register an IDE interface, specifying exactly the registers etc. *	Set init=1 iff calling before probes have taken place. * *	Returns -1 on error. */int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif)){	int index, retry = 1;	ide_hwif_t *hwif;	do {		for (index = 0; index < MAX_HWIFS; ++index) {			hwif = &ide_hwifs[index];			if (hwif->hw.io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])				goto found;		}		for (index = 0; index < MAX_HWIFS; ++index) {			hwif = &ide_hwifs[index];			if (hwif->hold)				continue;			if ((!hwif->present && !hwif->mate && !initializing) ||			    (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))				goto found;		}		for (index = 0; index < MAX_HWIFS; index++)			ide_unregister(index);	} while (retry--);	return -1;found:	if (hwif->present)		ide_unregister(index);	else if (!hwif->hold) {		init_hwif_data(hwif, index);		init_hwif_default(hwif, index);	}	if (hwif->present)		return -1;	memcpy(&hwif->hw, hw, sizeof(*hw));	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));	hwif->irq = hw->irq;	hwif->noprobe = 0;	hwif->chipset = hw->chipset;	if (!initializing) {		probe_hwif_init_with_fixup(hwif, fixup);		create_proc_ide_interfaces();	}	if (hwifp)		*hwifp = hwif;	return (initializing || hwif->present) ? index : -1;}EXPORT_SYMBOL(ide_register_hw_with_fixup);int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp){	return ide_register_hw_with_fixup(hw, hwifp, NULL);}EXPORT_SYMBOL(ide_register_hw);/* *	Locks for IDE setting functionality */DECLARE_MUTEX(ide_setting_sem);/** *	__ide_add_setting	-	add an ide setting option *	@drive: drive to use *	@name: setting name *	@rw: true if the function is read write *	@read_ioctl: function to call on read *	@write_ioctl: function to call on write *	@data_type: type of data *	@min: range minimum *	@max: range maximum *	@mul_factor: multiplication scale *	@div_factor: divison scale *	@data: private data field *	@set: setting *	@auto_remove: setting auto removal flag * *	Removes the setting named from the device if it is present. *	The function takes the settings_lock to protect against  *	parallel changes. This function must not be called from IRQ *	context. Returns 0 on success or -1 on failure. * *	BUGS: This code is seriously over-engineered. There is also *	magic about how the driver specific features are setup. If *	a driver is attached we assume the driver settings are auto *	remove. */static int __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, int auto_remove){	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;	down(&ide_setting_sem);	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 (auto_remove)		setting->auto_remove = 1;	*p = setting;	up(&ide_setting_sem);	return 0;abort:	up(&ide_setting_sem);	if (setting)		kfree(setting);	return -1;}int 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){	return __ide_add_setting(drive, name, rw, read_ioctl, write_ioctl, data_type, min, max, mul_factor, div_factor, data, set, 1);}EXPORT_SYMBOL(ide_add_setting);/** *	__ide_remove_setting	-	remove an ide setting option *	@drive: drive to use *	@name: setting name * *	Removes the setting named from the device if it is present. *	The caller must hold the setting semaphore. */ static void __ide_remove_setting (ide_drive_t *drive, char *name){	ide_settings_t **p, *setting;	p = (ide_settings_t **) &drive->settings;	while ((*p) && strcmp((*p)->name, name))		p = &((*p)->next);	if ((setting = (*p)) == NULL)		return;	(*p) = setting->next;		kfree(setting->name);	kfree(setting);}/** *	ide_find_setting_by_ioctl	-	find a drive specific ioctl *	@drive: drive to scan *	@cmd: ioctl command to handle * *	Scan's the device setting table for a matching entry and returns *	this or NULL if no entry is found. The caller must hold the *	setting semaphore */ 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_find_setting_by_name	-	find a drive specific setting *	@drive: drive to scan *	@name: setting name * *	Scan's the device setting table for a matching entry and returns *	this or NULL if no entry is found. The caller must hold the *	setting semaphore */ 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;}/** *	auto_remove_settings	-	remove driver specific settings *	@drive: drive * *	Automatically remove all the driver specific settings for this *	drive. This function may sleep and must not be called from IRQ *	context. The caller must hold ide_setting_sem. */ 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;	}}/** *	ide_read_setting	-	read an IDE setting *	@drive: drive to read from *	@setting: drive setting * *	Read a drive setting and return the value. The caller *	must hold the ide_setting_sem when making this call. * *	BUGS: the data return and error are the same return value *	so an error -EINVAL and true return of the same value cannot *	be told apart

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?