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

📄 fdc-io.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Yo, Emacs! we're -*- Linux-C -*- * *      Copyright (C) 1993-1995 Bas Laarhoven. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING.  If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * *      This file contains the low-level floppy disk interface code *      for the QIC-40/80 tape streamer device driver. */#include <linux/errno.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/ftape.h>#include <asm/system.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/irq.h>#include "tracing.h"#include "fdc-io.h"#include "fdc-isr.h"#include "ftape-io.h"#include "ftape-rw.h"#include "calibr.h"#include "fc-10.h"#include "qic117.h"/*      Global vars. */int ftape_unit = -1;int ftape_motor = 0;int current_cylinder = -1;fdc_mode_enum fdc_mode = fdc_idle;fdc_config_info fdc = {0};/*      Local vars. */static int fdc_calibr_count;static int fdc_calibr_time;static int fdc_confused = 0;static int fdc_status;volatile byte fdc_head;		/* FDC head */volatile byte fdc_cyl;		/* FDC track */volatile byte fdc_sect;		/* FDC sector */static int fdc_data_rate = 0;	/* default rate = 500 Kbps */static int fdc_seek_rate = 14;	/* default rate = 2 msec @ 500 Kbps */static void (*do_ftape) (void);static int fdc_fifo_state;	/* original fifo setting - fifo enabled */static int fdc_fifo_thr;	/* original fifo setting - threshold */static int fdc_lock_state;	/* original lock setting - locked */static int fdc_fifo_locked = 0;	/* has fifo && lock set ? */static byte fdc_precomp = 0;	/* sets fdc to default precomp. value */static byte fdc_drv_spec[4];	/* drive specification bytes for i82078 */static int perpend_mode;	/* true if fdc is in perpendicular mode */static char ftape_id[] = "ftape"; /* used by request irq and free irq */void fdc_catch_stray_interrupts(unsigned count){	unsigned long flags;	save_flags(flags);	cli();	if (count == 0) {		expected_stray_interrupts = 0;	} else {		expected_stray_interrupts += count;	}	restore_flags(flags);}/*  Wait during a timeout period for a given FDC status. *  If usecs == 0 then just test status, else wait at least for usecs. *  Returns -ETIME on timeout. Function must be calibrated first ! */int fdc_wait(int usecs, byte mask, byte state){	int count_1 = (fdc_calibr_count * usecs - 1) / fdc_calibr_time;	do {		fdc_status = inb_p(fdc.msr);		if ((fdc_status & mask) == state) {			return 0;		}	} while (count_1-- >= 0);	return -ETIME;}int fdc_ready_wait(int usecs){	return fdc_wait(usecs, FDC_DATA_READY, FDC_DATA_READY);}static void fdc_usec_wait(int usecs){	fdc_wait(usecs, 0, 1);	/* will always timeout ! */}int fdc_ready_out_wait(int usecs){	fdc_usec_wait(RQM_DELAY);	/* wait for valid RQM status */	return fdc_wait(usecs, FDC_DATA_OUT_READY, FDC_DATA_OUT_READY);}int fdc_ready_in_wait(int usecs){	fdc_usec_wait(RQM_DELAY);	/* wait for valid RQM status */	return fdc_wait(usecs, FDC_DATA_OUT_READY, FDC_DATA_IN_READY);}int fdc_wait_calibrate(void){	return calibrate("fdc_wait",		     fdc_usec_wait, &fdc_calibr_count, &fdc_calibr_time);}/*  Wait for a (short) while for the FDC to become ready *  and transfer the next command byte. *  Return -ETIME on timeout on getting ready (depends on hardware!). */int fdc_write(byte data){	fdc_usec_wait(RQM_DELAY);	/* wait for valid RQM status */	if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_IN_READY) < 0) {		return -ETIME;	} else {		outb(data, fdc.fifo);		return 0;	}}/*  Wait for a (short) while for the FDC to become ready *  and transfer the next result byte. *  Return -ETIME if timeout on getting ready (depends on hardware!). */int fdc_read(byte * data){	fdc_usec_wait(RQM_DELAY);	/* wait for valid RQM status */	if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_OUT_READY) < 0) {		return -ETIME;	} else {		*data = inb(fdc.fifo);		return 0;	}}/*  Output a cmd_len long command string to the FDC. *  The FDC should be ready to receive a new command or *  an error (EBUSY) will occur. */int fdc_command(byte * cmd_data, int cmd_len){	TRACE_FUN(8, "fdc_command");	int result = 0;	unsigned long flags;	int count = cmd_len;	fdc_usec_wait(RQM_DELAY);	/* wait for valid RQM status */	save_flags(flags);	cli();	fdc_status = inb(fdc.msr);	if ((fdc_status & FDC_DATA_READY_MASK) == FDC_DATA_IN_READY) {		int retry = 0;		fdc_mode = *cmd_data;	/* used by isr */		interrupt_seen = 0;		while (count) {			result = fdc_write(*cmd_data);			if (result < 0) {				TRACEx3(6, "fdc_mode = %02x, status = %02x at index %d",					(int) fdc_mode, (int) fdc_status, cmd_len - count);				if (++retry <= 3) {					TRACE(2, "fdc_write timeout, retry");				} else {					TRACE(1, "fdc_write timeout, fatal");					fdc_confused = 1;					/* recover ??? */					break;				}			} else {				--count;				++cmd_data;			}		}	} else {		TRACE(1, "fdc not ready");		result = -EBUSY;	}	restore_flags(flags);	TRACE_EXIT;	return result;}/*  Input a res_len long result string from the FDC. *  The FDC should be ready to send the result or an error *  (EBUSY) will occur. */int fdc_result(byte * res_data, int res_len){	TRACE_FUN(8, "fdc_result");	int result = 0;	unsigned long flags;	int count = res_len;	save_flags(flags);	cli();	fdc_status = inb(fdc.msr);	if ((fdc_status & FDC_DATA_READY_MASK) == FDC_DATA_OUT_READY) {		int retry = 0;		while (count) {			if (!(fdc_status & FDC_BUSY)) {				TRACE(1, "premature end of result phase");			}			result = fdc_read(res_data);			if (result < 0) {				TRACEx3(6, "fdc_mode = %02x, status = %02x at index %d",					(int) fdc_mode, (int) fdc_status, res_len - count);				if (++retry <= 3) {					TRACE(2, "fdc_read timeout, retry");				} else {					TRACE(1, "fdc_read timeout, fatal");					fdc_confused = 1;					/* recover ??? */					break;				}			} else {				--count;				++res_data;			}		}	} else {		TRACE(1, "fdc not ready");		result = -EBUSY;	}	restore_flags(flags);	fdc_usec_wait(RQM_DELAY);	/* allow FDC to negate BSY */	TRACE_EXIT;	return result;}/*      Handle command and result phases for *      commands without data phase. */int fdc_issue_command(byte * out_data, int out_count,		      byte * in_data, int in_count){	TRACE_FUN(8, "fdc_issue_command");	int result;	int t0, t1;	if (out_count > 0) {		result = fdc_command(out_data, out_count);		if (result < 0) {			TRACE(1, "fdc_command failed");			TRACE_EXIT;			return result;		}	}	/* will take 24 - 30 usec for fdc_sense_drive_status and	 * fdc_sense_interrupt_status commands.	 *    35 fails sometimes (5/9/93 SJL)	 * On a loaded system it incidentally takes longer than	 * this for the fdc to get ready ! ?????? WHY ??????	 * So until we know what's going on use a very long timeout.	 */	t0 = timestamp();	result = fdc_ready_out_wait(500 /* usec */ );	t1 = timestamp();	if (result < 0) {		TRACEi(1, "fdc_ready_out_wait failed after:", timediff(t0, t1));		TRACE_EXIT;		return result;	}	if (in_count > 0) {		result = fdc_result(in_data, in_count);		if (result < 0) {			TRACE(1, "result phase aborted");			TRACE_EXIT;			return result;		}	}	TRACE_EXIT;	return 0;}/*      Wait for FDC interrupt with timeout. *      Signals are blocked so the wait will not be aborted. *      Note: interrupts must be enabled ! (23/05/93 SJL) */int fdc_interrupt_wait(int time){	TRACE_FUN(8, "fdc_interrupt_wait");	struct wait_queue wait =	{current, NULL};	int result = -ETIME;	int need_cleanup = 0;	int current_blocked = current->blocked;	static int resetting = 0;	if (waitqueue_active(&wait_intr)) {		TRACE(1, "error: nested call");		return -EIO;	/* return error... */	}	if (interrupt_seen == 0) {		/* timeout time will be between 0 and MSPT milliseconds too long !		 */		current->timeout = jiffies + 1 + (time + MSPT - 1) / MSPT;		current->state = TASK_INTERRUPTIBLE;		current->blocked = _BLOCK_ALL;		add_wait_queue(&wait_intr, &wait);		do {			schedule();	/* sets TASK_RUNNING on timeout */		} while (!interrupt_seen && current->state != TASK_RUNNING);		current->blocked = current_blocked;	/* restore */		remove_wait_queue(&wait_intr, &wait);		if (interrupt_seen) {			current->timeout = 0;	/* interrupt hasn't cleared this */			result = 0;		} else {#if 1/*** remove me when sure this doesn't happen ***/			if (current->timeout > 0) {				TRACE(-1, "*** BUG: unexpected schedule exit ***");				if (current->signal & ~current->blocked) {					TRACE(4, "caused by signal ?");				}			}#endif			if (current->signal & ~current->blocked) {				result = -EINTR;			} else {				result = -ETIME;			}			need_cleanup = 1;	/* missing interrupt, reset fdc. */		}	} else {		result = 0;	}	/*  In first instance, next statement seems unnecessary since	 *  it will be cleared in fdc_command. However, a small part of	 *  the software seems to rely on this being cleared here	 *  (ftape_close might fail) so stick to it until things get fixed !	 */	interrupt_seen = 0;	/* clear for next call */	if (need_cleanup & !resetting) {		resetting = 1;	/* break infinite recursion if reset fails */		TRACE(8, "cleanup reset");		fdc_reset();		resetting = 0;	}	TRACE_EXIT;	return result;}/*      Start/stop drive motor. Enable DMA mode. */void fdc_motor(int motor){	TRACE_FUN(8, "fdc_motor");	int unit = FTAPE_UNIT;	int data = unit | FDC_RESET_NOT | FDC_DMA_MODE;	ftape_motor = motor;	if (ftape_motor) {		data |= FDC_MOTOR_0 << unit;		TRACEx1(4, "turning motor %d on", unit);	} else {		TRACEx1(4, "turning motor %d off", unit);	}#ifdef MACH2	outb_p(data, fdc.dor2);#else	outb_p(data, fdc.dor);#endif	ftape_sleep(10 * MILLISECOND);	TRACE_EXIT;}static void fdc_update_dsr(void){	TRACE_FUN(8, "fdc_update_dsr");	TRACEx2(5, "rate = %d, precomp = %d", fdc_data_rate, fdc_precomp);	if (fdc.type >= i82077) {		outb_p((fdc_data_rate & 0x03) | fdc_precomp, fdc.dsr);	} else {		outb_p(fdc_data_rate, fdc.ccr);	}	TRACE_EXIT;}void fdc_set_write_precomp(int precomp){	/*  write precompensation can be set in multiples of 41.67 nsec.	 *  round the parameter to the nearest multiple and convert it	 *  into a fdc setting. Note that 0 means default to the fdc,	 *  7 is used instead of that.	 */	fdc_precomp = ((precomp + 21) / 42) << 2;	if (fdc_precomp == 0) {		fdc_precomp = 7 << 2;	}	fdc_update_dsr();}/* Read back the Drive Specification regs on a i82078, so that we * are able to restore them later */void fdc_save_drive_specs(void){	byte cmd1[] =	{FDC_DRIVE_SPEC, 0x80};	byte cmd2[] =	{FDC_DRIVE_SPEC, 0x00, 0x00, 0x00, 0x00, 0xc0};	int result;	TRACE_FUN(8, "fdc_save_drive_specs");	if (fdc.type >= i82078_1) {		result = fdc_issue_command(cmd1, NR_ITEMS(cmd1), fdc_drv_spec, 4);

⌨️ 快捷键说明

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