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

📄 ftape-io.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *      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. $Source: /usr/local/cvsroot/AplioTRIO/linux/drivers/char/ftape/ftape-io.c,v $ $Author: vadim $ * $Revision: 1.1.1.1 $ $Date: 1999/11/15 13:41:57 $ $State: Exp $ * *      This file contains the general control functions *      for the QIC-40/80 floppy-tape driver for Linux. */#include <linux/errno.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/ftape.h>#include <asm/segment.h>#include <asm/system.h>#include <linux/ioctl.h>#include <linux/mtio.h>#include "tracing.h"#include "fdc-io.h"#include "qic117.h"#include "ftape-io.h"#include "ftape-ctl.h"#include "ftape-rw.h"#include "ftape-write.h"#include "ftape-read.h"#include "ftape-eof.h"#include "kernel-interface.h"#include "calibr.h"/*      Global vars. *//* NOTE: sectors start numbering at 1, all others at 0 ! */timeout_table timeout;vendor_struct drive_type;int qic_std;int tape_len;volatile int current_command;const struct qic117_command_table qic117_cmds[] = QIC117_COMMANDS;int might_be_off_track;/*      Local vars. */static int command_parameter = 0;/*      command-restrictions is a table according *      to the QIC-117 specs specifying the state *      the drive status should be in at command execution. */static const ftape_error ftape_errors[] = QIC117_ERRORS;static int ftape_udelay_count;static int ftape_udelay_time;static const struct {	char *text;	int fdc_code;	byte drive_code;	int precomp;} rates[4] = {#if defined(FDC_82078SL)	{		"2 M", -1 /* unsupported */ , QIC_CONFIG_RATE_2000, 0	},#else	{		"2 M", fdc_data_rate_2000, QIC_CONFIG_RATE_2000, 0	},#endif	{		"1 M", fdc_data_rate_1000, QIC_CONFIG_RATE_1000, 42	},	{		"500 K", fdc_data_rate_500, QIC_CONFIG_RATE_500, 125	},	{		"250 K", fdc_data_rate_250, QIC_CONFIG_RATE_250, 250	},};typedef enum {	prehistoric, pre_qic117c, post_qic117b, post_qic117d} qic_model;void udelay(int usecs){	volatile int count = (1 + (usecs * ftape_udelay_count - 1) /			      ftape_udelay_time);	volatile int i;	while (count-- > 0) {		for (i = 0; i < 20; ++i);	}}int udelay_calibrate(void){	return calibrate("udelay", udelay, &ftape_udelay_count, &ftape_udelay_time);}/*      Delay (msec) routine. */void ftape_sleep(unsigned int time){	TRACE_FUN(8, "ftape_sleep");	unsigned long flags;	int ticks = 1 + (time + MSPT - 1) / MSPT;	/*    error in range [0..1] MSPT	 */	if (time < MSPT) {		/*  Time too small for scheduler, do a busy wait ! */		udelay(1000 * time);	} else {		TRACEx2(8, "%d msec, %d ticks", time, ticks);		current->timeout = jiffies + ticks;		current->state = TASK_INTERRUPTIBLE;		save_flags(flags);		sti();		do {			while (current->state != TASK_RUNNING) {				schedule();			}			if (current->signal & ~current->blocked) {				TRACE(1, "awoken by non-blocked signal :-(");				break;	/* exit on signal */			}		} while (current->timeout > 0);		restore_flags(flags);	}	TRACE_EXIT;}/* forward */ int ftape_report_raw_drive_status(int *status);/*      Issue a tape command: *      Generate command # of step pulses. */int ftape_command(int command){	TRACE_FUN(8, "ftape_command");	int result = 0;	int track;	int old_tracing = tracing;	static int level = 0;	int status = -1;	if (++level > 5) {		/*  This is a bug we'll want to know about.		 */		TRACEx1(1, "bug - recursion for command: %d", command);		result = -EIO;	} else if (command_parameter) {		/*  Don't check restrictions for parameters.		 */		TRACEx1(5, "called with parameter = %d", command - 2);	} else if (command <= 0 || command > NR_ITEMS(qic117_cmds)) {		/*  This is a bug we'll want to know about too.		 */		TRACEx1(-1, "bug - bad command: %d", command);		result = -EIO;	} else {		/*  disable logging and restriction check for some commands,		 *  check all other commands that have a prescribed starting status.		 */		if (command == QIC_REPORT_DRIVE_STATUS) {			TRACE(8, "report drive status called");			tracing = 0;		} else if (command == QIC_REPORT_NEXT_BIT) {			tracing = 0;		} else {			TRACEx1(5, "%s", qic117_cmds[command].name);			/*  A new motion command during an uninterruptible (motion)			 *  command requires a ready status before the new command			 *  can be issued. Otherwise a new motion command needs to			 *  be checked against required status.			 */			if (qic117_cmds[command].cmd_type == motion &&			    qic117_cmds[current_command].non_intr) {				ftape_report_raw_drive_status(&status);				if ((status & QIC_STATUS_READY) == 0) {					TRACEx2(4, "motion cmd (%d) during non-intr cmd (%d)",						command, current_command);					TRACE(4, "waiting until drive gets ready");					ftape_ready_wait(timeout.seek, &status);				}			}			if (qic117_cmds[command].mask != 0) {				byte difference;				/*  Some commands do require a certain status:				 */				if (status == -1) {	/* not yet set */					ftape_report_raw_drive_status(&status);				}				difference = ((status ^ qic117_cmds[command].state) &					      qic117_cmds[command].mask);				/*  Wait until the drive gets ready. This may last forever				 *  if the drive never gets ready...				 */				while ((difference & QIC_STATUS_READY) != 0) {					TRACEx1(4, "command %d issued while not ready", command);					TRACE(4, "waiting until drive gets ready");					ftape_ready_wait(timeout.seek, &status);					difference = ((status ^ qic117_cmds[command].state) &					      qic117_cmds[command].mask);					/*  Bail out on signal !					 */					if (current->signal & _DONT_BLOCK) {						result = -EINTR;						break;					}				}				while (result == 0 && (difference & QIC_STATUS_ERROR) != 0) {					int err;					int cmd;					TRACEx1(4, "command %d issued while error pending", command);					TRACE(4, "clearing error status");					ftape_report_error(&err, &cmd, 1);					ftape_report_raw_drive_status(&status);					difference = ((status ^ qic117_cmds[command].state) &					      qic117_cmds[command].mask);					/*  Bail out on fatal signal !					 */					if (current->signal & _DONT_BLOCK) {						result = -EINTR;						break;					}				}				if (result == 0 && difference) {					/*  Any remaining difference can't be solved here.					 */					if (difference & (QIC_STATUS_CARTRIDGE_PRESENT |					       QIC_STATUS_NEW_CARTRIDGE |						QIC_STATUS_REFERENCED)) {						TRACE(1, "Fatal: tape removed or reinserted !");						ftape_failure = 1;					} else {						TRACEx2(1, "wrong state: 0x%02x should be: 0x%02x",							status & qic117_cmds[command].mask,							qic117_cmds[command].state);					}					result = -EIO;				}				if (~status & QIC_STATUS_READY & qic117_cmds[command].mask) {					TRACE(1, "Bad: still busy!");					result = -EBUSY;				}			}		}	}	tracing = old_tracing;	/*  Now all conditions are met or result is < 0.	 */	if (result >= 0) {		/*  Always wait for a command_timeout period to separate		 *  individuals commands and/or parameters.		 */		ftape_sleep(3 * MILLISECOND);		/*  Keep cylinder nr within range, step towards home if possible.		 */		if (current_cylinder >= command) {			track = current_cylinder - command;		} else {			track = current_cylinder + command;		}		result = fdc_seek(track);		/*  position is no longer valid after any of these commands		 *  have completed.		 */		if (qic117_cmds[command].cmd_type == motion &&		    command != QIC_LOGICAL_FORWARD && command != QIC_STOP_TAPE) {			location.known = 0;		}		command_parameter = 0;	/* always turned off for next command */		current_command = command;	}	--level;	TRACE_EXIT;	return result;}/*      Send a tape command parameter: *      Generates command # of step pulses. *      Skips tape-status call ! */int ftape_parameter(int command){	command_parameter = 1;	return ftape_command(command + 2);}/*      Wait for the drive to get ready. *      timeout time in milli-seconds *      Returned status is valid if result != -EIO */int ftape_ready_wait(int timeout, int *status){	TRACE_FUN(8, "ftape_ready_wait");	int result;	unsigned long t0;	const int poll_delay = 100 * MILLISECOND;	for (;;) {		t0 = jiffies;		result = ftape_report_raw_drive_status(status);		if (result < 0) {			TRACE(1, "ftape_report_raw_drive_status failed");			result = -EIO;			break;		}		if (*status & QIC_STATUS_READY) {			result = 0;			break;		}		if (timeout >= 0) {			/* this will fail when jiffies wraps around about			 * once every year :-)			 */			timeout -= ((jiffies - t0) * SECOND) / HZ;			if (timeout <= 0) {				TRACE(1, "timeout");				result = -ETIME;				break;			}			ftape_sleep(poll_delay);			timeout -= poll_delay;		} else {			ftape_sleep(poll_delay);		}		if (current->signal & _NEVER_BLOCK) {			TRACE(1, "interrupted by fatal signal");			result = -EINTR;			break;	/* exit on signal */		}	}	TRACE_EXIT;	return result;}/*      Issue command and wait up to timeout seconds for drive ready */int ftape_command_wait(int command, int timeout, int *status){	TRACE_FUN(8, "ftape_command_wait");	int result;	/* Drive should be ready, issue command	 */	result = ftape_command(command);	if (result >= 0) {		result = ftape_ready_wait(timeout, status);	}	TRACE_EXIT;	return result;}int ftape_parameter_wait(int command, int timeout, int *status){	TRACE_FUN(8, "ftape_parameter_wait");	int result;	/* Drive should be ready, issue command	 */	result = ftape_parameter(command);	if (result >= 0) {		result = ftape_ready_wait(timeout, status);	}	TRACE_EXIT;	return result;}/*-------------------------------------------------------------------------- *      Report operations *//* Query the drive about its status.  The command is sent and   result_length bits of status are returned (2 extra bits are read   for start and stop). */static int ftape_report_operation(int *status, int command, int result_length){	TRACE_FUN(8, "ftape_report_operation");	int i, st3;	int result;	unsigned int t0, t1, dt;	result = ftape_command(command);	if (result < 0) {		TRACE(1, "ftape_command failed");		TRACE_EXIT;		return result;	}	t0 = timestamp();	dt = 0;	i = 0;	do {		++i;		ftape_sleep(3 * MILLISECOND);	/* see remark below */		result = fdc_sense_drive_status(&st3);		if (result < 0) {			TRACE(1, "fdc_sense_drive_status failed");			TRACE_EXIT;			return result;		}		/*  Calculate time difference every iteration because timer may		 *  wrap around (but only one !) and timediff will account for this.		 *  Note that the sleep above must be < 1/HZ or we'll lose ticks !		 */		t1 = timestamp();		dt += timediff(t0, t1);		t0 = t1;		/*  Ack should be asserted within Ttimout + Tack = 6 msec.		 *  Looks like some drives fail to do this so extend this		 *  period to 300 msec.		 */	} while (!(st3 & ST3_TRACK_0) && dt < 300000);	if (st3 & ST3_TRACK_0) {		/*  dt may be larger than expected because of other tasks		 *  scheduled while we were sleeping.		 */		if (i > 1 && dt > 6000) {			TRACEx2(1, "Acknowledge after %u msec. (%i iter)", dt / 1000, i);		}	} else {		TRACEx2(1, "No acknowledge after %u msec. (%i iter)", dt / 1000, i);		TRACE(1, "timeout on Acknowledge");		TRACE_EXIT;		return -EIO;	}	*status = 0;	for (i = 0; i < result_length + 1; i++) {		result = ftape_command(QIC_REPORT_NEXT_BIT);		if (result < 0) {			TRACE(1, "report next bit failed");			TRACE_EXIT;			return result;		}#if 1		/*  fdc_seek does interrupt wait, so why should we ?		 *  (it will only fail causing fdc to be reset...)		 *  It's only purpose may be the delay, we'll have to find out!		 */#else		fdc_interrupt_wait(25 * MILLISECOND);	/* fails only if hw fails */#endif		result = fdc_sense_drive_status(&st3);		if (result < 0) {			TRACE(1, "fdc_sense_drive_status (2) failed");			TRACE_EXIT;			return result;		}		if (i < result_length) {			*status |= ((st3 & ST3_TRACK_0) ? 1 : 0) << i;		} else {			if ((st3 & ST3_TRACK_0) == 0) {				TRACE(1, "missing status stop bit");				TRACE_EXIT;				return -EIO;			}		}	}	/* this command will put track zero and index back into normal state */	result = ftape_command(QIC_REPORT_NEXT_BIT);	TRACE_EXIT;	return 0;}/* Report the current drive status. */int ftape_report_raw_drive_status(int *status){	TRACE_FUN(8, "ftape_report_raw_drive_status");	int result;	int count = 0;	do {		result = ftape_report_operation(status, QIC_REPORT_DRIVE_STATUS, 8);	} while (result < 0 && ++count <= 3);	if (result < 0) {		TRACE(1, "report_operation failed");		result = -EIO;	} else if (*status & QIC_STATUS_READY) {		current_command = 0;	/* completed */	}	TRACE_EXIT;	return result;}int ftape_report_drive_status(int *status){	TRACE_FUN(8, "ftape_report_drive_status");	int result;	result = ftape_report_raw_drive_status(status);	if (result < 0) {		TRACE(1, "ftape_report_raw_drive_status failed");		TRACE_EXIT;		return result;	}	if (*status & QIC_STATUS_NEW_CARTRIDGE ||	    !(*status & QIC_STATUS_CARTRIDGE_PRESENT)) {		ftape_failure = 1;	/* will inhibit further operations */		TRACE_EXIT;		return -EIO;	}	if (*status & QIC_STATUS_READY && *status & QIC_STATUS_ERROR) {		/*  Let caller handle all errors */

⌨️ 快捷键说明

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