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

📄 tpqic02.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
			return -EACCES;		return -ENXIO;	case MTEOM:		/* This should leave the tape ready for appending		 * another file to the end, such that it would append		 * after the last FM on tape.		 */		tpqputs(TPQD_IOCTLS, "MTEOM search for End Of recorded Media");		if ((mode_access == WRITE) && status_bytes_wr)			return -EACCES;		if (TP_HAVE_EOD) {			/* Use faster seeking when possible.			 * This requires the absence of data beyond the EOM.			 * It seems that my drive does not always perform the			 * SEEK_EOD correctly, unless it is preceded by a			 * rewind command.			 */# if 0			status_eom_detected = status_eof_detected = NO;# endif			stat = do_qic_cmd(QCMD_REWIND, TIM_R);			if (stat)				return stat;			stat = do_qic_cmd(QCMD_SEEK_EOD, TIM_F);			/* After a successful seek, TP_EOR should be returned */		} else {			/* else just seek until the drive returns exception "No Data" */			stat = 0;			while ((stat == 0) && (!status_eom_detected)) {				stat = do_qic_cmd(QCMD_RD_FM, TIM_F);	      /***** should use MTFSFM here???? ******/			}			if (tperror.exs & TP_NDT)				return 0;		}		return stat;	case MTERASE:		tpqputs(TPQD_IOCTLS, "MTERASE -- ERASE TAPE !");		if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP)) {			tpqputs(TPQD_ALWAYS, "Cartridge is write-protected.");			return -EACCES;		} else {			time_t t = jiffies;			/* Plain GNU mt(1) 2.2 erases a tape in O_RDONLY. :-( */			if (mode_access == READ)				return -EACCES;			/* FIXME */			/* give user a few seconds to pull out tape */			while (jiffies - t < 4 * HZ)				schedule();		}		/* don't bother writing filemark first */		status_eom_detected = status_eof_detected = NO;		return do_qic_cmd(QCMD_ERASE, TIM_R);	case MTRAS1:		if (TP_HAVE_RAS1) {			tpqputs(TPQD_IOCTLS, "MTRAS1: non-destructive self test");			stat = do_qic_cmd(QCMD_SELF_TST1, TIM_R);			if (stat != 0) {				tpqputs(TPQD_ALWAYS, "RAS1 failed");				return stat;			}			return (tp_sense(0) == TE_OK) ? 0 : -EIO;	/* get_ext_status3(); */		}		tpqputs(TPQD_IOCTLS, "RAS1 not supported");		return -ENXIO;	case MTRAS2:		if (TP_HAVE_RAS2) {			tpqputs(TPQD_IOCTLS, "MTRAS2: destructive self test");			stat = do_qic_cmd(QCMD_SELF_TST2, TIM_R);			if (stat != 0) {				tpqputs(TPQD_ALWAYS, "RAS2 failed");				return stat;			}			return (tp_sense(0) == TE_OK) ? 0 : -EIO;	/* get_ext_status3(); */		}		tpqputs(TPQD_IOCTLS, "RAS2 not supported");		return -ENXIO;	case MTSEEK:		if (TP_HAVE_SEEK && (QIC02_TAPE_IFC == ARCHIVE)) {			tpqputs(TPQD_IOCTLS, "MTSEEK seeking block");			if ((mode_access == WRITE) && status_bytes_wr)				return -EACCES;			/* NOTE: address (24 bits) is in seek_addr_buf[] */			return do_qic_cmd(AR_QCMDV_SEEK_BLK, TIM_F);		} else			return -ENOTTY;	default:		return -ENOTTY;	}}				/* do_ioctl_cmd *//* dma_transfer(): This routine is called for every 512 bytes to be read * from/written to the tape controller. Speed is important here! * (There must be enough time left for the hd controller!) * When other devices use DMA they must ensure they use un-interruptible * double byte accesses to the DMA controller. Floppy.c is ok. * Must have interrupts disabled when this function is invoked, * otherwise, the double-byte transfers to the DMA controller will not * be atomic. That could lead to nasty problems when they are interrupted * by other DMA interrupt-routines. * * This routine merely does the least possible to keep * the transfers going: *	- set the DMA count register for the next 512 bytes *	- adjust the DMA address and page registers *	- adjust the timeout *	- tell the tape controller to start transferring * We assume the dma address and mode are, and remain, valid. */static inline void dma_transfer(void){	unsigned long flags;	if (QIC02_TAPE_IFC == WANGTEK)	/* or EVEREX */		outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT);	/* back to normal */	else if (QIC02_TAPE_IFC == ARCHIVE)		outb_p(0, AR_RESET_DMA_PORT);	else			/* QIC02_TAPE_IFC == MOUNTAIN */		outb_p(ctlbits, QIC02_CTL_PORT);	flags = claim_dma_lock();	clear_dma_ff(QIC02_TAPE_DMA);	set_dma_mode(QIC02_TAPE_DMA, dma_mode);	set_dma_addr(QIC02_TAPE_DMA,		     virt_to_bus(buffaddr) + dma_bytes_done);	set_dma_count(QIC02_TAPE_DMA, TAPE_BLKSIZE);	/* start tape DMA controller */	if (QIC02_TAPE_IFC == WANGTEK)	/* or EVEREX */		outb_p(WT_CTL_DMA | WT_CTL_ONLINE, QIC02_CTL_PORT);	/* trigger DMA transfer */	else if (QIC02_TAPE_IFC == ARCHIVE) {		outb_p(AR_CTL_IEN | AR_CTL_DNIEN, QIC02_CTL_PORT);	/* enable interrupts again */		outb_p(0, AR_START_DMA_PORT);	/* start DMA transfer */		/* In dma_end() AR_RESET_DMA_PORT is written too. */	} else {		/* QIC02_TAPE_IFC == MOUNTAIN */		inb(MTN_R_DESELECT_DMA_PORT);		outb_p(ctlbits | (MTN_CTL_EXC_IEN | MTN_CTL_DNIEN),		       QIC02_CTL_PORT);		outb_p(0, MTN_W_SELECT_DMA_PORT);	/* start DMA transfer */		if (dma_mode == DMA_MODE_WRITE)			outb_p(0, MTN_W_DMA_WRITE_PORT);	/* start DMA transfer */	}	/* start computer DMA controller */	enable_dma(QIC02_TAPE_DMA);	release_dma_lock(flags);	/* block transfer should start now, jumping to the 	 * interrupt routine when done or an exception was detected.	 */}				/* dma_transfer *//* start_dma() sets a DMA transfer up between the tape controller and * the kernel qic02_tape_buf buffer. * Normally bytes_todo==dma_bytes_done at the end of a DMA transfer. If not, * a filemark was read, or an attempt to write beyond the End Of Tape  * was made. [Or some other bad thing happened.] * Must do a sense() before returning error. */static int start_dma(short mode, unsigned long bytes_todo)/* assume 'bytes_todo'>0 */{	int stat;	unsigned long flags;	tpqputs(TPQD_DEBUG, "start_dma() enter");	TPQDEB( {printk(TPQIC02_NAME ": doing_read==%d, doing_write==%d\n",		      doing_read, doing_write);})	    dma_bytes_done = 0;	dma_bytes_todo = bytes_todo;	status_error = NO;	/* dma_mode!=0 indicates that the dma controller is in use */	dma_mode = (mode == WRITE) ? DMA_MODE_WRITE : DMA_MODE_READ;	/* Only give READ/WRITE DATA command to tape drive if we haven't	 * done that already. Otherwise the drive will rewind to the beginning	 * of the current file on tape. Any QIC command given other than	 * R/W FM will break the read/write transfer cycle.	 * do_qic_cmd() will terminate doing_{read,write}	 */	if ((doing_read == NO) && (doing_write == NO)) {		/* First, we have to clear the status -- maybe remove TP_FIL???		 */#if 0		/* Next dummy get status is to make sure CNI is valid,		   since we're only just starting a read/write it doesn't		   matter some exceptions are cleared by reading the status;		   we're only interested in CNI and WRP. -Eddy */		get_status(&tperror);#else		/* TP_CNI should now be handled in open(). -Hennus */#endif		stat =		    tp_sense(((mode ==			       WRITE) ? 0 : TP_WRP) | TP_BOM | TP_FIL);		if (stat != TE_OK)			return stat;#if OBSOLETE		/************* not needed iff rd_status() would wait for ready!!!!!! **********/		if (wait_for_ready(TIM_S) != TE_OK) {	/*** not sure this is needed ***/			tpqputs(TPQD_ALWAYS,				"wait_for_ready failed in start_dma");			return -EIO;		}#endif		if (QIC02_TAPE_IFC == MOUNTAIN) {			/* Set control bits to select ONLINE during command */			ctlbits |= MTN_QIC02_CTL_ONLINE;		}		/* Tell the controller the data direction */		/* r/w, timeout medium, check exceptions, sets status_cmd_pending. */		stat = send_qic02_cmd((mode == WRITE) 					? QCMD_WRT_DATA : QCMD_RD_DATA, TIM_M, 0);		if (stat != TE_OK) {			printk(TPQIC02_NAME ": start_dma: init %s failed\n",			       (mode == WRITE) ? "write" : "read");			(void) tp_sense(0);			return stat;		}		/* Do this last, because sense() will clear the doing_{read,write}		 * flags, causing trouble next time around.		 */		if (wait_for_ready(TIM_M) != TE_OK)			return -EIO;		switch (mode) {		case READ:			doing_read = YES;			break;		case WRITE:			doing_write = YES;			break;		default:			printk(TPQIC02_NAME			       ": requested unknown mode %d\n", mode);			panic(TPQIC02_NAME			      ": invalid mode in start_dma()");		}	} else if (is_exception()) {		/* This is for Archive drives, to handle reads with 0 bytes		 * left for the last read request.		 *		 * ******** this also affects EOF/EOT handling! ************		 */		tpqputs(TPQD_ALWAYS,			"detected exception in start_dma() while transfer in progress");		status_error = YES;		return TE_END;	}	status_expect_int = YES;	/* This assumes tape is already positioned, but these	 * semi-'intelligent' drives are unpredictable...	 */	TIMERON(TIM_M * 2);	/* initiate first data block read from/write to the tape controller */	save_flags(flags);	cli();	dma_transfer();	restore_flags(flags);	TPQPUTS("start_dma() end");	return TE_OK;}				/* start_dma *//* This cleans up after the dma transfer has completed * (or failed). If an exception occurred, a sense() * must be done. If the exception was caused by a FM, * sense() will set `status_eof_detected' and * `status_eom_detected', as required. */static void end_dma(unsigned long *bytes_done){	int stat = TE_OK;	unsigned long flags;	TIMEROFF;	TPQPUTS("end_dma() enter");	flags = claim_dma_lock();	disable_dma(QIC02_TAPE_DMA);	clear_dma_ff(QIC02_TAPE_DMA);	release_dma_lock(flags);	if (QIC02_TAPE_IFC == WANGTEK)	/* or EVEREX */		outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT);	/* back to normal */	else if (QIC02_TAPE_IFC == ARCHIVE)		outb_p(0, AR_RESET_DMA_PORT);	else {			/* QIC02_TAPE_IFC == MOUNTAIN */		/* Clear control bits, de-select ONLINE during tp_sense */		ctlbits &= ~MTN_QIC02_CTL_ONLINE;	}	stat = wait_for_ready(TIM_M);	if (status_error || (stat != TE_OK)) {		tpqputs(TPQD_DMAX, "DMA transfer exception");		stat = tp_sense((dma_mode == READ) ? TP_WRP : 0);		/* no return here -- got to clean up first! */	} else {		/* if (QIC02_TAPE_IFC == MOUNTAIN) */		outb_p(ctlbits, QIC02_CTL_PORT);	}	if (QIC02_TAPE_IFC == MOUNTAIN)		inb(MTN_R_DESELECT_DMA_PORT);	/* take the tape controller offline */	/* finish off DMA stuff */	dma_mode = 0;	/* Note: The drive is left on-line, ready for the next	 * data transfer.	 * If the next command to the drive does not continue	 * the pending cycle, it must do 2 sense()s first.	 */	*bytes_done = dma_bytes_done;	status_expect_int = NO;	ioctl_status.mt_blkno += (dma_bytes_done / TAPE_BLKSIZE);	TPQPUTS("end_dma() exit");	/*** could return stat here ***/}				/* end_dma *//*********** Below are the (public) OS-interface procedures ***********//* qic02_tape_times_out() is called when a DMA transfer doesn't complete * quickly enough. Usually this means there is something seriously wrong * with the hardware/software, but it could just be that the controller * has decided to do a long rewind, just when I didn't expect it. * Just try again. */static void qic02_tape_times_out(unsigned long dummy){	printk("time-out in %s driver\n", TPQIC02_NAME);	if ((status_cmd_pending > 0) || dma_mode) {		/* takes tooo long, shut it down */		status_dead = YES;		status_cmd_pending = 0;		status_timer_on = NO;		status_expect_int = NO;		status_error = YES;		if (dma_mode) {			dma_mode = 0;	/* signal end to read/write routine */			wake_up(&qic02_tape_transfer);		}	}}				/* qic02_tape_times_out *//* * Interrupt handling: * * 1) Interrupt is generated iff at the end of  *    a 512-DMA-block transfer. * 2) EXCEPTION is not raised unless something  *    is wrong or EOT/FM is detected. * 3) FM EXCEPTION is set *after* the last byte has *    been transferred by DMA. By the time the interrupt *    is handled, the EXCEPTION may already be set. * * So, * 1) On EXCEPTION, assume data has been transferred, so *    continue as usual, but set a flag to indicate the *    exception was detected. *    Do a sense status when the flag is found set. * 2) Do not attempt to continue a transfer after an exception. *    [??? What about marginal blocks???????] *//* qic02_tape_interrupt() is called when the tape controller completes  * a DMA transfer. * We are not allowed to sleep here!  * * Check if the transfer was successful, check if we need to transfer * more. If the buffer contains enough data/is empty enough, signal the * read/write() thread to copy to/from user space. * When we are finished, set flags to indicate end, disable timer. * NOTE: This *must* be fast!  */static void qic02_tape_interrupt(int irq, void *dev_id,				 struct pt_regs *regs){	int stat, r, i;	unsigned long flags;	TIMEROFF;	if (status_expect_int) {

⌨️ 快捷键说明

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