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

📄 tpqic02.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
			if (stat & QIC02_STAT_READY) {		/* not ready */				tpqputs(TPQD_ALWAYS, "isr: ? Tape controller not ready");				r = 1;			}		flags=claim_dma_lock();				if ( (i = get_dma_residue(QIC02_TAPE_DMA)) != 0 ) {			printk(TPQIC02_NAME ": dma_residue == %x !!!\n", i);			r = 1;	/* big trouble, but can't do much about it... */		}				release_dma_lock(flags);		if (r) 			return;		/* finish DMA cycle */		/* no errors detected, continue */		dma_bytes_done += TAPE_BLKSIZE;		if (dma_bytes_done >= dma_bytes_todo) {			/* finished! Wakeup rw() */			dma_mode = 0;			status_expect_int = NO;			TPQPUTS("isr: dma_bytes_done");			wake_up(&qic02_tape_transfer);		} else {			/* start next transfer, account for track-switching time */			timer_table[QIC02_TAPE_TIMER].expires = jiffies + 6*HZ;			dma_transfer();		}	} else {		printk(TPQIC02_NAME ": Unexpected interrupt, stat == %x\n",		       inb(QIC02_STAT_PORT));	}} /* qic02_tape_interrupt */static long long qic02_tape_lseek(struct file * file, long long offset, int origin){	return -EINVAL;	/* not supported */} /* qic02_tape_lseek *//* read/write routines: * This code copies between a kernel buffer and a user buffer. The  * actual data transfer is done using DMA and interrupts. Time-outs * are also used. * * When a filemark is read, we return '0 bytes read' and continue with the * next file after that. * When EOM is read, we return '0 bytes read' twice. * When the EOT marker is detected on writes, '0 bytes read' should be * returned twice. If user program does a MTNOP after that, 2 additional * blocks may be written.	------- FIXME: Implement this correctly  ************************************************* * * Only read/writes in multiples of 512 bytes are accepted. * When no bytes are available, we sleep() until they are. The controller will * generate an interrupt, and we (should) get a wake_up() call. * * Simple buffering is used. User program should ensure that a large enough * buffer is used. Usually the drive does some buffering as well (something * like 4k or so). * * Scott S. Bertilson suggested to continue filling the user buffer, rather * than waste time on a context switch, when the kernel buffer fills up. *//* * Problem: tar(1) doesn't always read the entire file. Sometimes the entire file * has been read, but the EOF token is never returned to tar(1), simply because * tar(1) knows it has already read all of the data it needs. So we must use * open/release to reset the `reported_read_eof' flag. If we don't, the next read * request would return the EOF flag for the previous file. */static ssize_t qic02_tape_read(struct file * filp, char * buf, size_t count, loff_t *ppos){    int err;    kdev_t dev = filp->f_dentry->d_inode->i_rdev;    unsigned short flags = filp->f_flags;    unsigned long bytes_todo, bytes_done, total_bytes_done = 0;    int stat;    if (status_zombie==YES)    {	tpqputs(TPQD_ALWAYS, "configs not set");			return -ENXIO;    }    if (TP_DIAGS(current_tape_dev))      /* can't print a ``long long'' (for filp->f_pos), so chop it */      printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%lx"	                  ", pos=%lx, flags=%x\n",	     MINOR(dev), buf, (long) count,	     (unsigned long) filp->f_pos, flags);        if (count % TAPE_BLKSIZE)	/* Only allow mod 512 bytes at a time. */    {	tpqputs(TPQD_BLKSZ, "Wrong block size");	return -EINVAL;    }    /* Just assume everything is ok. Controller will scream if not. */    if (status_bytes_wr)	/* Once written, no more reads, 'till after WFM. */    {	return -EACCES;    }        /* This is rather ugly because it has to implement a finite state     * machine in order to handle the EOF situations properly.     */    while ((signed)count>=0)    {	bytes_done = 0;	/* see how much fits in the kernel buffer */	bytes_todo = TPQBUF_SIZE;	if (bytes_todo>count)	{	    bytes_todo = count;	}		/* Must ensure that user program sees exactly one EOF token (==0) */	if (return_read_eof==YES)	{	    if (TPQDBG(DEBUG))	    {		printk("read: return_read_eof==%d, reported_read_eof==%d, total_bytes_done==%lu\n", return_read_eof, reported_read_eof, total_bytes_done);	    }	    	    if (reported_read_eof==NO)	    {		/* have not yet returned EOF to user program */		if (total_bytes_done>0)		{		    return total_bytes_done; /* next time return EOF */		}		else		{		    reported_read_eof = YES; /* move on next time */		    return 0;		 /* return EOF */		}					    }	    else	    {		/* Application program has already received EOF		 * (above), now continue with next file on tape,		 * if possible.		 * When the FM is reached, EXCEPTION is set,		 * causing a sense(). Subsequent read/writes will		 * continue after the FM.		 */		/*********** ?????????? this should check for (EOD|NDT), not EOM, 'cause we can read past EW: ************/		if (status_eom_detected)		{		    /* If EOM, nothing left to read, so keep returning EOFs.		     *** should probably set some flag to avoid clearing		     *** status_eom_detected through ioctls or something		     */		    return 0;		}		else		{		    /* just eof, there may be more files ahead... */		    return_read_eof = NO;		    reported_read_eof = NO;		    status_eof_detected = NO; /* reset this too */		    /*fall through*/		}	    }	}		/*****************************/	if (bytes_todo==0)	{	    return total_bytes_done;	}		if (bytes_todo>0)	{	    /* start reading data */	    if (is_exception())	/****************************************/	    {		tpqputs(TPQD_DMAX, "is_exception() before start_dma()!");	    }	    /****************************************************************** ***** if start_dma() fails because the head is positioned 0 bytes ***** before the FM, (causing EXCEPTION to be set) return_read_eof should ***** be set to YES, and we should return total_bytes_done, rather than -ENXIO. ***** The app should recognize this as an EOF condition. ***************************************************************************/	    stat = start_dma(READ, bytes_todo);	    if (stat == TE_OK)	    {		/* Wait for transfer to complete, interrupt should wake us */		while (dma_mode != 0)		{		    sleep_on(&qic02_tape_transfer);		}		if (status_error)		{		    return_read_eof = YES;		}			    }	    else if (stat != TE_END)	    {		/* should do sense() on error here */#if 0		return -ENXIO;#else		printk("Trouble: stat==%02x\n", stat);		return_read_eof = YES;		/*************** check EOF/EOT handling!!!!!! **/#endif	    }	    end_dma(&bytes_done);	    if (bytes_done>bytes_todo)	    {		tpqputs(TPQD_ALWAYS, "read: Oops, read more bytes than requested");		return -EIO;	    }	    /* copy buffer to user-space in one go */	    if (bytes_done>0)	    {		err = copy_to_user( (void *) buf, (void *) bus_to_virt(buffaddr), bytes_done);		if (err)		{		    return -EFAULT;		}	    }#if 1	    /* Checks Ton's patch below */	    if ((return_read_eof == NO) && (status_eof_detected == YES))	    {		printk(TPQIC02_NAME ": read(): return_read_eof=%d, status_eof_detected=YES. return_read_eof:=YES\n", return_read_eof);	    }#endif	    if ((bytes_todo != bytes_done) || (status_eof_detected == YES))	    {		/* EOF or EOM detected. return EOF next time. */		return_read_eof = YES;	    }	    	} /* else: ignore read request for 0 bytes */	if (bytes_done>0)	{	    status_bytes_rd = YES;	    buf += bytes_done;	    *ppos += bytes_done;	    total_bytes_done += bytes_done;	    count -= bytes_done;	}    }    tpqputs(TPQD_ALWAYS, "read request for <0 bytes");    return -EINVAL;} /* qic02_tape_read *//* The drive detects near-EOT by means of the holes in the tape. * When the holes are detected, there is some space left. The drive * reports this as a TP_EOM exception. After clearing the exception, * the drive should accept two extra blocks. * * It seems there are some archiver programs that would like to use the * extra space for writing a continuation marker. The driver should return * end-of-file to the user program on writes, when the holes are detected. * If the user-program wants to use the extra space, it should use the * MTNOP ioctl() to get the generic status register and may then continue * writing (max 1kB).	----------- doesn't work yet............... * * EOF behaviour on writes: * If there is enough room, write all of the data. * If there is insufficient room, write as much as will fit and * return the amount written. If the requested amount differs from the * written amount, the application program should recognize that as the * end of file. Subsequent writes will return -ENOSPC. * Unless the minor bits specify a rewind-on-close, the tape will not * be rewound when it is full. The user-program should do that, if desired. * If the driver were to do that automatically, a user-program could be  * confused about the EOT/BOT condition after re-opening the tape device. * * Multiple volume support: Tar closes the tape device before prompting for * the next tape. The user may then insert a new tape and tar will open the * tape device again. The driver will detect an exception status in (No Cartridge) * and force a rewind. After that tar may continue writing. */static ssize_t qic02_tape_write( struct file * filp,  const char * buf, 		size_t count, loff_t *ppos){    int err;    kdev_t dev = filp->f_dentry->d_inode->i_rdev;    unsigned short flags = filp->f_flags;    unsigned long bytes_todo, bytes_done, total_bytes_done = 0;        if (status_zombie==YES)    {	tpqputs(TPQD_ALWAYS, "configs not set");			return -ENXIO;    }    if (TP_DIAGS(current_tape_dev))    {	/* can't print a ``long long'' (for filp->f_pos), so chop it */	printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p"	                    ", count=%lx, pos=%lx, flags=%x\n",	       MINOR(dev), buf,	       (long) count, (unsigned long) filp->f_pos, flags);    }        if (count % TAPE_BLKSIZE) 	/* only allow mod 512 bytes at a time */    {	tpqputs(TPQD_BLKSZ, "Wrong block size");	return -EINVAL;    }    if (mode_access==READ)    {	tpqputs(TPQD_ALWAYS, "Not in write mode");	return -EACCES;    }    /* open() does a sense() and we can assume the tape isn't changed     * between open() and release(), so the tperror.exs bits will still     * be valid.     */    if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP))    {	tpqputs(TPQD_ALWAYS, "Cartridge is write-protected.");	return -EACCES;	/* don't even try when write protected */    }          if (doing_read == YES)    {	terminate_read(0);    }        while ((signed)count>=0)    {	/* see how much fits in the kernel buffer */	bytes_done = 0;	bytes_todo = TPQBUF_SIZE;	if (bytes_todo>count)	{	    bytes_todo = count;	}		if (return_write_eof == YES)	{	    /* return_write_eof should be reset on reverse tape movements. */	    	    if (reported_write_eof==NO)	    {		if (bytes_todo>0)		{		    tpqputs(TPQD_ALWAYS, "partial write");		    /* partial write signals EOF to user program */		}		reported_write_eof = YES;		return total_bytes_done;	    }	    else	    {		return -ENOSPC;		 /* return error */	    }		}		/* Quit when done. */	if (bytes_todo==0)	{	    return total_bytes_done;	}		/* copy from user to DMA buffer and initiate transfer. */	if (bytes_todo>0)	{	    err = copy_from_user( (void *) bus_to_virt(buffaddr), (const void *) buf, bytes_todo);	    if (err)	    {		return -EFAULT;	    }/****************** similar problem with read() at FM could happen here at EOT. ******************//***** if at EOT, 0 bytes can be written. start_dma() will ***** fail and write() will return ENXIO error *****/	    if (start_dma(WRITE, bytes_todo) != TE_OK)	    {		tpqputs(TPQD_ALWAYS, "write: start_dma() failed");		/* should do sense() on error here */		return -ENXIO;	/*********** FIXTHIS **************/	    }	    /* Wait for write to complete, interrupt should wake us. */	    while ((status_error == 0) && (dma_mode != 0))	    {		sleep_on(&qic02_tape_transfer);	    }	    end_dma(&bytes_done);	    if (bytes_done>bytes_todo)	    {		tpqputs(TPQD_ALWAYS, "write: Oops, wrote more bytes than requested");		return -EIO;	    }	    /* If the dma-transfer was aborted because of an exception,	     * status_error will have been set in the interrupt handler.	     * Then end_dma() will do a sense().	     * If the exception was EXC_EOM, the EW-hole was encountered	     * and two more blocks could be written. For the time being we'll	     * just consider this to be the EOT.	     * Otherwise, something Bad happened, such as the maximum number	     * of block-rewrites was exceeded. [e.g. A very bad spot on tape was	     * encountered. Normally short 

⌨️ 快捷键说明

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