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

📄 ide-taskfile.c

📁 at91rm9200处理器ide接口驱动程序源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * linux/drivers/ide/ide-taskfile.c	Version 0.20	Oct 11, 2000 * *  Copyright (C) 2000		Michael Cornwell <cornwell@acm.org> *  Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org> * *  May be copied or modified under the terms of the GNU General Public License * * IDE_DEBUG(__LINE__); */#include <linux/config.h>#define __NO_VERSION__#include <linux/module.h>#include <linux/types.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/major.h>#include <linux/errno.h>#include <linux/genhd.h>#include <linux/blkpg.h>#include <linux/slab.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/hdreg.h>#include <linux/ide.h>#include <asm/byteorder.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/bitops.h>#ifdef CONFIG_IDE_TASKFILE_IO#  define __TASKFILE__IO#else /* CONFIG_IDE_TASKFILE_IO */#  undef __TASKFILE__IO#endif /* CONFIG_IDE_TASKFILE_IO */#define DEBUG_TASKFILE	0	/* unset when fixed */#if DEBUG_TASKFILE#define DTF(x...) printk(##x)#else#define DTF(x...)#endifinline u32 task_read_24 (ide_drive_t *drive){	return	(IN_BYTE(IDE_HCYL_REG)<<16) |		(IN_BYTE(IDE_LCYL_REG)<<8) |		 IN_BYTE(IDE_SECTOR_REG);}static void ata_bswap_data (void *buffer, int wcount){	u16 *p = buffer;	while (wcount--) {		*p = *p << 8 | *p >> 8; p++;		*p = *p << 8 | *p >> 8; p++;	}}#if SUPPORT_VLB_SYNC/* * Some localbus EIDE interfaces require a special access sequence * when using 32-bit I/O instructions to transfer data.  We call this * the "vlb_sync" sequence, which consists of three successive reads * of the sector count register location, with interrupts disabled * to ensure that the reads all happen together. */static inline void task_vlb_sync (ide_ioreg_t port) {	(void) inb (port);	(void) inb (port);	(void) inb (port);}#endif /* SUPPORT_VLB_SYNC *//* * This is used for most PIO data transfers *from* the IDE interface */void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount){	byte 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 */			task_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 ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount){	byte 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 */			task_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);	}}static inline void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount){	ata_input_data(drive, buffer, wcount);	if (drive->bswap)		ata_bswap_data(buffer, wcount);}static inline void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount){	if (drive->bswap) {		ata_bswap_data(buffer, wcount);		ata_output_data(drive, buffer, wcount);		ata_bswap_data(buffer, wcount);	} else {		ata_output_data(drive, buffer, wcount);	}}ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task){	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;	struct hd_driveid *id = drive->id;	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;	/* (ks/hs): Moved to start, do not use for multiple out commands */	if (task->handler != task_mulout_intr) {		if (IDE_CONTROL_REG)			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */		SELECT_MASK(HWIF(drive), drive, 0);	}	if ((id->command_set_2 & 0x0400) &&	    (id->cfs_enable_2 & 0x0400) &&	    (drive->addressing == 1)) {		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);	}	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);	/* refers to number of sectors to transfer */	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);	/* refers to sector offset or start sector */	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);	if (task->handler != NULL) {#if 0		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);		/*		 * warning check for race between handler and prehandler for		 * writing first block of data.  however since we are well		 * inside the boundaries of the seek, we should be okay.		 */		if (task->prehandler != NULL) {			return task->prehandler(drive, task->rq);		}#else		ide_startstop_t startstop;		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {			printk(KERN_ERR "%s: no DRQ after issuing %s\n",				drive->name,				drive->mult_count ? "MULTWRITE" : "WRITE");			return startstop;		}		/* (ks/hs): Fixed Multi Write */		if ((taskfile->command != WIN_MULTWRITE) &&		    (taskfile->command != WIN_MULTWRITE_EXT)) {			struct request *rq = HWGROUP(drive)->rq;		/* For Write_sectors we need to stuff the first sector */			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);			rq->current_nr_sectors--;		} else {		/* Stuff first sector(s) by implicitly calling the handler */			if (!(drive_is_ready(drive))) {			/* FIXME: Replace hard-coded 100, error handling? */				int i;				for (i=0; i<100; i++) {					if (drive_is_ready(drive))						break;				}			}			return task->handler(drive);		}#endif	} else {		/* for dma commands we down set the handler */		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));	}	return ide_started;}void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler){	struct hd_driveid *id = drive->id;	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;	/* (ks/hs): Moved to start, do not use for multiple out commands */	if (*handler != task_mulout_intr) {		if (IDE_CONTROL_REG)			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */		SELECT_MASK(HWIF(drive), drive, 0);	}	if ((id->command_set_2 & 0x0400) &&	    (id->cfs_enable_2 & 0x0400) &&	    (drive->addressing == 1)) {		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);	}	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);	/* refers to number of sectors to transfer */	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);	/* refers to sector offset or start sector */	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);	if (handler != NULL) {		ide_set_handler (drive, handler, WAIT_CMD, NULL);		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);	} else {		/* for dma commands we down set the handler */		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));	}}#if 0ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task){	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;	struct hd_driveid *id = drive->id;	/*	 * (KS) Check taskfile in/out flags.	 * If set, then execute as it is defined.	 * If not set, then define default settings.	 * The default values are:	 *	write and read all taskfile registers (except data) 	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)	 */	if (task->tf_out_flags.all == 0) {		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;		if ((id->command_set_2 & 0x0400) &&		    (id->cfs_enable_2 & 0x0400) &&		    (drive->addressing == 1)) {			task->tf_out_flags.all != (IDE_HOB_STD_OUT_FLAGS << 8);		}        }	if (task->tf_in_flags.all == 0) {		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;		if ((id->command_set_2 & 0x0400) &&		    (id->cfs_enable_2 & 0x0400) &&		    (drive->addressing == 1)) {			task->tf_in_flags.all  != (IDE_HOB_STD_IN_FLAGS  << 8);		}        }	if (IDE_CONTROL_REG)		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */	SELECT_MASK(HWIF(drive), drive, 0);	if (task->tf_out_flags.b.data) {		unsigned short data =  taskfile->data + (hobfile->data << 8);		OUT_WORD (data, IDE_DATA_REG);	}	/* (KS) send hob registers first */	if (task->tf_out_flags.b.nsector_hob)		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);	if (task->tf_out_flags.b.sector_hob)		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);	if (task->tf_out_flags.b.lcyl_hob)		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);	if (task->tf_out_flags.b.hcyl_hob)		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);	/* (KS) Send now the standard registers */	if (task->tf_out_flags.b.error_feature)		OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);	/* refers to number of sectors to transfer */	if (task->tf_out_flags.b.nsector)		OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);	/* refers to sector offset or start sector */	if (task->tf_out_flags.b.sector)		OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);	if (task->tf_out_flags.b.lcyl)		OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);	if (task->tf_out_flags.b.hcyl)		OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);        /*	 * (KS) Do not modify the specified taskfile. We want to have a	 * universal pass through, so we must execute ALL specified values.	 *	 * (KS) The drive head register is mandatory.	 * Don't care about the out flags !	 */	OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);	if (task->handler != NULL) {#if 0		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);		/*		 * warning check for race between handler and prehandler for		 * writing first block of data.  however since we are well		 * inside the boundaries of the seek, we should be okay.		 */		if (task->prehandler != NULL) {			return task->prehandler(drive, task->rq);		}#else		ide_startstop_t startstop;		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);		/*		 * (KS) The drive command register is also mandatory.		 * Don't care about the out flags !		 */		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {			printk(KERN_ERR "%s: no DRQ after issuing %s\n",				drive->name,				drive->mult_count ? "MULTWRITE" : "WRITE");			return startstop;		}		/* (ks/hs): Fixed Multi Write */		if ((taskfile->command != WIN_MULTWRITE) &&		    (taskfile->command != WIN_MULTWRITE_EXT)) {			struct request *rq = HWGROUP(drive)->rq;		/* For Write_sectors we need to stuff the first sector */			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);			rq->current_nr_sectors--;		} else {		/* Stuff first sector(s) by implicitly calling the handler */			if (!(drive_is_ready(drive))) {			/* FIXME: Replace hard-coded 100, error handling? */				int i;				for (i=0; i<100; i++) {					if (drive_is_ready(drive))						break;				}			}			return task->handler(drive);		}#endif	} else {		/* for dma commands we down set the handler */		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));	}	return ide_started;}#endif#if 0/* * Error reporting, in human readable form (luxurious, but a memory hog). */byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat){

⌨️ 快捷键说明

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