⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide.c

📁 《嵌入式系统设计与实例开发实验教材II:基于ARM9微处理器与Linux操作系统》IDE—CF卡模块读写实验
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (io_32bit) {#if SUPPORT_VLB_SYNC		if (io_32bit & 2) {			unsigned long flags;			__save_flags(flags);	/* local CPU only */			__cli();		/* local CPU only */			do_vlb_sync(IDE_NSECTOR_REG);			insl(IDE_DATA_REG, buffer, wcount);			__restore_flags(flags);	/* local CPU only */		} else#endif /* SUPPORT_VLB_SYNC */			insl(IDE_DATA_REG, buffer, wcount);	} else {#if SUPPORT_SLOW_DATA_PORTS		if (drive->slow) {			unsigned short *ptr = (unsigned short *) buffer;			while (wcount--) {				*ptr++ = inw_p(IDE_DATA_REG);				*ptr++ = inw_p(IDE_DATA_REG);			}		} else#endif /* SUPPORT_SLOW_DATA_PORTS */			insw(IDE_DATA_REG, buffer, wcount<<1);	}}/* * This is used for most PIO data transfers *to* the IDE interface */void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount){	byte io_32bit;	if(HWIF(drive)->ideproc) {		HWIF(drive)->ideproc(ideproc_ide_output_data,				     drive, buffer, wcount);		return;	}	io_32bit = drive->io_32bit;	if (io_32bit) {#if SUPPORT_VLB_SYNC		if (io_32bit & 2) {			unsigned long flags;			__save_flags(flags);	/* local CPU only */			__cli();		/* local CPU only */			do_vlb_sync(IDE_NSECTOR_REG);			outsl(IDE_DATA_REG, buffer, wcount);			__restore_flags(flags);	/* local CPU only */		} else#endif /* SUPPORT_VLB_SYNC */			outsl(IDE_DATA_REG, buffer, wcount);	} else {#if SUPPORT_SLOW_DATA_PORTS		if (drive->slow) {			unsigned short *ptr = (unsigned short *) buffer;			while (wcount--) {				outw_p(*ptr++, IDE_DATA_REG);				outw_p(*ptr++, IDE_DATA_REG);			}		} else#endif /* SUPPORT_SLOW_DATA_PORTS */			outsw(IDE_DATA_REG, buffer, wcount<<1);	}}/* * The following routines are mainly used by the ATAPI drivers. * * These routines will round up any request for an odd number of bytes, * so if an odd bytecount is specified, be sure that there's at least one * extra byte allocated for the buffer. */void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount){	if(HWIF(drive)->ideproc) {		HWIF(drive)->ideproc(ideproc_atapi_input_bytes,				     drive, buffer, bytecount);		return;	}	++bytecount;#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)	if (MACH_IS_ATARI || MACH_IS_Q40) {		/* Atari has a byte-swapped IDE interface */		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);		return;	}#endif /* CONFIG_ATARI */	ide_input_data (drive, buffer, bytecount / 4);	if ((bytecount & 0x03) >= 2)		insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);}void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount){	if(HWIF(drive)->ideproc) {		HWIF(drive)->ideproc(ideproc_atapi_output_bytes,				     drive, buffer, bytecount);		return;	}	++bytecount;#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)	if (MACH_IS_ATARI || MACH_IS_Q40) {		/* Atari has a byte-swapped IDE interface */		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);		return;	}#endif /* CONFIG_ATARI */	ide_output_data (drive, buffer, bytecount / 4);	if ((bytecount & 0x03) >= 2)		outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);}/* * Needed for PCI irq sharing */static inline int drive_is_ready (ide_drive_t *drive){	byte stat = 0;	if (drive->waiting_for_dma)		return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);#if 0	udelay(1);	/* need to guarantee 400ns since last command was issued */#endif#ifdef CONFIG_IDEPCI_SHARE_IRQ	/*	 * We do a passive status test under shared PCI interrupts on	 * cards that truly share the ATA side interrupt, but may also share	 * an interrupt with another pci card/device.  We make no assumptions	 * about possible isa-pnp and pci-pnp issues yet.	 */	if (IDE_CONTROL_REG)		stat = GET_ALTSTAT();	else#endif /* CONFIG_IDEPCI_SHARE_IRQ */	stat = GET_STAT();	/* Note: this may clear a pending IRQ!! */	if (stat & BUSY_STAT)		return 0;	/* drive busy:  definitely not interrupting */	return 1;		/* drive ready: *might* be interrupting */}/* * This is our end_request replacement function. */void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup){	struct request *rq;	unsigned long flags;	ide_drive_t *drive = hwgroup->drive;	spin_lock_irqsave(&io_request_lock, flags);	rq = hwgroup->rq;	/*	 * decide whether to reenable DMA -- 3 is a random magic for now,	 * if we DMA timeout more than 3 times, just stay in PIO	 */	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {		drive->state = 0;		hwgroup->hwif->dmaproc(ide_dma_on, drive);	}	if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) {		add_blkdev_randomness(MAJOR(rq->rq_dev));		blkdev_dequeue_request(rq);        	hwgroup->rq = NULL;		end_that_request_last(rq);	}	spin_unlock_irqrestore(&io_request_lock, flags);}/* * This should get invoked any time we exit the driver to * wait for an interrupt response from a drive.  handler() points * at the appropriate code to handle the next interrupt, and a * timer is started to prevent us from waiting forever in case * something goes wrong (see the ide_timer_expiry() handler later on). */void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,		      unsigned int timeout, ide_expiry_t *expiry){	unsigned long flags;	ide_hwgroup_t *hwgroup = HWGROUP(drive);	spin_lock_irqsave(&io_request_lock, flags);	if (hwgroup->handler != NULL) {		printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",			drive->name, hwgroup->handler, handler);	}	hwgroup->handler	= handler;	hwgroup->expiry		= expiry;	hwgroup->timer.expires	= jiffies + timeout;	add_timer(&hwgroup->timer);	spin_unlock_irqrestore(&io_request_lock, flags);}/* * current_capacity() returns the capacity (in sectors) of a drive * according to its current geometry/LBA settings. */unsigned long current_capacity (ide_drive_t *drive){	if (!drive->present)		return 0;	if (drive->driver != NULL)		return DRIVER(drive)->capacity(drive);	return 0;}extern struct block_device_operations ide_fops[];/* * ide_geninit() is called exactly *once* for each interface. */void ide_geninit (ide_hwif_t *hwif){	unsigned int unit;	struct gendisk *gd = hwif->gd;	for (unit = 0; unit < MAX_DRIVES; ++unit) {		ide_drive_t *drive = &hwif->drives[unit];		if (!drive->present)			continue;		if (drive->media!=ide_disk && drive->media!=ide_floppy)			continue;		register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),#ifdef CONFIG_BLK_DEV_ISAPNP			(drive->forced_geom && drive->noprobe) ? 1 :#endif /* CONFIG_BLK_DEV_ISAPNP */			1<<PARTN_BITS, ide_fops,			current_capacity(drive));	}}static ide_startstop_t do_reset1 (ide_drive_t *, int);		/* needed below *//* * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms * during an atapi drive reset operation. If the drive has not yet responded, * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. */static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive){	ide_hwgroup_t *hwgroup = HWGROUP(drive);	byte stat;	SELECT_DRIVE(HWIF(drive),drive);	udelay (10);	if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {		printk("%s: ATAPI reset complete\n", drive->name);	} else {		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);			return ide_started;	/* continue polling */		}		hwgroup->poll_timeout = 0;	/* end of polling */		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);		return do_reset1 (drive, 1);	/* do it the old fashioned way */	}	hwgroup->poll_timeout = 0;	/* done polling */	return ide_stopped;}/* * reset_pollfunc() gets invoked to poll the interface for completion every 50ms * during an ide reset operation. If the drives have not yet responded, * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. */static ide_startstop_t reset_pollfunc (ide_drive_t *drive){	ide_hwgroup_t *hwgroup = HWGROUP(drive);	ide_hwif_t *hwif = HWIF(drive);	byte tmp;	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {			ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);			return ide_started;	/* continue polling */		}		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);		drive->failures++;	} else  {		printk("%s: reset: ", hwif->name);		if ((tmp = GET_ERR()) == 1) {			printk("success\n");			drive->failures = 0;		} else {			drive->failures++;#if FANCY_STATUS_DUMPS			printk("master: ");			switch (tmp & 0x7f) {				case 1: printk("passed");					break;				case 2: printk("formatter device error");					break;				case 3: printk("sector buffer error");					break;				case 4: printk("ECC circuitry error");					break;				case 5: printk("controlling MPU error");					break;				default:printk("error (0x%02x?)", tmp);			}			if (tmp & 0x80)				printk("; slave: failed");			printk("\n");#else			printk("failed\n");#endif /* FANCY_STATUS_DUMPS */		}	}	hwgroup->poll_timeout = 0;	/* done polling */	return ide_stopped;}static void check_dma_crc (ide_drive_t *drive){	if (drive->crc_count) {		(void) HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);		if ((HWIF(drive)->speedproc) != NULL)			HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));		if (drive->current_speed >= XFER_SW_DMA_0)			(void) HWIF(drive)->dmaproc(ide_dma_on, drive);	} else {		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);	}}static void pre_reset (ide_drive_t *drive){	if (drive->driver != NULL)		DRIVER(drive)->pre_reset(drive);	if (!drive->keep_settings) {		if (drive->using_dma) {			check_dma_crc(drive);		} else {			drive->unmask = 0;			drive->io_32bit = 0;		}		return;	}	if (drive->using_dma)		check_dma_crc(drive);}/* * do_reset1() attempts to recover a confused drive by resetting it. * Unfortunately, resetting a disk drive actually resets all devices on * the same interface, so it can really be thought of as resetting the * interface rather than resetting the drive. * * ATAPI devices have their own reset mechanism which allows them to be * individually reset without clobbering other devices on the same interface. * * Unfortunately, the IDE interface does not generate an interrupt to let * us know when the reset operation has finished, so we must poll for this. * Equally poor, though, is the fact that this may a very long time to complete, * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it, * we set a timer to poll at 50ms intervals. */static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi){	unsigned int unit;	unsigned long flags;	ide_hwif_t *hwif = HWIF(drive);	ide_hwgroup_t *hwgroup = HWGROUP(drive);	__save_flags(flags);	/* local CPU only */	__cli();		/* local CPU only */	/* For an ATAPI device, first try an ATAPI SRST. */	if (drive->media != ide_disk && !do_not_try_atapi) {		pre_reset(drive);		SELECT_DRIVE(hwif,drive);		udelay (20);		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);		__restore_flags (flags);	/* local CPU only */		return ide_started;	}	/*	 * First, reset any device state data we were maintaining	 * for any of the drives on this interface.	 */	for (unit = 0; unit < MAX_DRIVES; ++unit)		pre_reset(&hwif->drives[unit]);#if OK_TO_RESET_CONTROLLER	if (!IDE_CONTROL_REG) {		__restore_flags(flags);		return ide_stopped;	}	/*	 * Note that we also set nIEN while resetting the device,	 * to mask unwanted interrupts from the interface during the reset.	 * However, due to the design of PC hardware, this will cause an	 * immediate interrupt due to the edge transition it produces.	 * This single interrupt gives us a "fast poll" for drives that	 * recover from reset very quickly, saving us the first 50ms wait time.	 */	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */	udelay(10);			/* more than enough time */	OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */	udelay(10);			/* more than enough time */	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;	ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);

⌨️ 快捷键说明

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