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

📄 tpqic02.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
				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;				/* 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, buffaddr+dma_bytes_done);	/* full address */	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(void){	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) {#ifdef WANT_EXTRA_FULL_DEBUGGING		if (TP_DIAGS(current_tape_dev))			printk("@");#endif		stat = inb(QIC02_STAT_PORT);	/* Knock, knock */		if (QIC02_TAPE_IFC == ARCHIVE) {	/* "Who's there?" */			if (((stat & (AR_STAT_DMADONE)) == 0) &&        	              ((stat & (QIC02_STAT_EXCEPTION)) != 0)) {				TIMERCONT;				return;			/* "Linux with IRQ sharing" */			}		}		if ((stat & QIC02_STAT_EXCEPTION) == 0) {	/* exception occurred */			/* Possible causes for an exception during a transfer:			 * 	- during a write-cycle: end of tape (EW) hole detected.			 *	- during a read-cycle: filemark or EOD detected.			 *	- something went wrong			 * So don't continue with the next block.			 */			tpqputs(TPQD_ALWAYS, "isr: exception on tape controller");			printk("      status %02x\n", stat);			status_error = TE_EX;			dma_bytes_done += TAPE_BLKSIZE;			dma_mode = 0;	/* wake up rw() */			status_expect_int = NO;			wake_up(&qic02_tape_transfer);			return;		}		/* return if tape controller not ready, or		 * if dma channel hasn't finished last byte yet.		 */		r = 0;	    /* Skip next ready check for Archive controller because	     * it may be busy reading ahead. Weird. --hhb	     */		if (QIC02_TAPE_IFC == WANGTEK)	/* I think this is a drive-dependency, not IFC -- hhb */

⌨️ 快捷键说明

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