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

📄 acsi.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, int enable){	unsigned long	flags, paddr;	int				i;#ifdef NO_WRITE	if (rwflag || *cmd == 0x0a) {		printk( "ACSI: Write commands disabled!\n" );		return( 0 );	}#endif		rwflag = rwflag ? 0x100 : 0;	paddr = virt_to_phys( buffer );	acsi_delay_end(COMMAND_DELAY);	DISABLE_IRQ();	save_flags(flags);  	cli();	/* Low on A1 */	dma_wd.dma_mode_status = 0x88 | rwflag;	MFPDELAY();	/* set DMA address */	dma_wd.dma_lo = (unsigned char)paddr;	paddr >>= 8;	MFPDELAY();	dma_wd.dma_md = (unsigned char)paddr;	paddr >>= 8;	MFPDELAY();	if (ATARIHW_PRESENT(EXTD_DMA))		st_dma_ext_dmahi = (unsigned short)paddr;	else		dma_wd.dma_hi = (unsigned char)paddr;	MFPDELAY();	restore_flags(flags);	/* send the command bytes except the last */	for( i = 0; i < 5; ++i ) {		DMA_LONG_WRITE( *cmd++, 0x8a | rwflag );		udelay(20);		if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */	}	/* Clear FIFO and switch DMA to correct direction */  	dma_wd.dma_mode_status = 0x92 | (rwflag ^ 0x100);  	MFPDELAY();	dma_wd.dma_mode_status = 0x92 | rwflag;	MFPDELAY();	/* How many sectors for DMA */	dma_wd.fdc_acces_seccount = blocks;	MFPDELAY();		/* send last command byte */	dma_wd.dma_mode_status = 0x8a | rwflag;	MFPDELAY();	DMA_LONG_WRITE( *cmd++, 0x0a | rwflag );	if (enable)		ENABLE_IRQ();	udelay(80);	return( 1 );}/* * acsicmd_nodma() sends an ACSI command that requires no DMA. */int acsicmd_nodma( const char *cmd, int enable){	int	i;	acsi_delay_end(COMMAND_DELAY);	DISABLE_IRQ();	/* send first command byte */	dma_wd.dma_mode_status = 0x88;	MFPDELAY();	DMA_LONG_WRITE( *cmd++, 0x8a );	udelay(20);	if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */	/* send the intermediate command bytes */	for( i = 0; i < 4; ++i ) {		DMA_LONG_WRITE( *cmd++, 0x8a );		udelay(20);		if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */	}	/* send last command byte */	DMA_LONG_WRITE( *cmd++, 0x0a );	if (enable)		ENABLE_IRQ();	udelay(80);		return( 1 );	/* Note that the ACSI interrupt is still disabled after this	 * function. If you want to get the IRQ delivered, enable it manually!	 */}static int acsi_reqsense( char *buffer, int targ, int lun){	CMDSET_TARG_LUN( reqsense_cmd, targ, lun);	if (!acsicmd_dma( reqsense_cmd, buffer, 1, 0, 0 )) return( 0 );	if (!acsi_wait_for_IRQ( 10 )) return( 0 );	acsi_getstatus();	if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 );	if (!acsi_wait_for_IRQ( 10 )) return( 0 );	acsi_getstatus();	if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 );	if (!acsi_wait_for_IRQ( 10 )) return( 0 );	acsi_getstatus();	if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 );	if (!acsi_wait_for_IRQ( 10 )) return( 0 );	acsi_getstatus();	dma_cache_maintenance( virt_to_phys(buffer), 16, 0 );		return( 1 );}	/* * ACSI status phase: get the status byte from the bus * * I've seen several times that a 0xff status is read, propably due to * a timing error. In this case, the procedure is repeated after the * next _IRQ edge. */int acsi_getstatus( void ){	int	status;	DISABLE_IRQ();	for(;;) {		if (!acsi_wait_for_IRQ( 100 )) {			acsi_delay_start();			return( -1 );		}		dma_wd.dma_mode_status = 0x8a;		MFPDELAY();		status = dma_wd.fdc_acces_seccount;		if (status != 0xff) break;#ifdef DEBUG		printk("ACSI: skipping 0xff status byte\n" );#endif		udelay(40);		acsi_wait_for_noIRQ( 20 );	}	dma_wd.dma_mode_status = 0x80;	udelay(40);	acsi_wait_for_noIRQ( 20 );	acsi_delay_start();	return( status & 0x1f ); /* mask of the device# */}#if (defined(CONFIG_ATARI_SLM) || defined(CONFIG_ATARI_SLM_MODULE))/* Receive data in an extended status phase. Needed by SLM printer. */int acsi_extstatus( char *buffer, int cnt ){	int	status;	DISABLE_IRQ();	udelay(80);	while( cnt-- > 0 ) {		if (!acsi_wait_for_IRQ( 40 )) return( 0 );		dma_wd.dma_mode_status = 0x8a;		MFPDELAY();		status = dma_wd.fdc_acces_seccount;		MFPDELAY();		*buffer++ = status & 0xff;		udelay(40);	}	return( 1 );}/* Finish an extended status phase */void acsi_end_extstatus( void ){	dma_wd.dma_mode_status = 0x80;	udelay(40);	acsi_wait_for_noIRQ( 20 );	acsi_delay_start();}/* Send data in an extended command phase */int acsi_extcmd( unsigned char *buffer, int cnt ){	while( cnt-- > 0 ) {		DMA_LONG_WRITE( *buffer++, 0x8a );		udelay(20);		if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */	}	return( 1 );}#endifstatic void acsi_print_error( const unsigned char *errblk, int dev  ){	int atari_err, i, errcode;	struct acsi_error *arr;	atari_err = acsi_info[dev].old_atari_disk;	if (atari_err)		errcode = errblk[0] & 0x7f;	else		if ((errblk[0] & 0x70) == 0x70)			errcode = errblk[2] & 0x0f;		else			errcode = errblk[0] & 0x0f;		printk( KERN_ERR "ACSI error 0x%02x", errcode );	if (errblk[0] & 0x80)		printk( " for sector %d",				((errblk[1] & 0x1f) << 16) |				(errblk[2] << 8) | errblk[0] );	arr = atari_err ? atari_acsi_errors : scsi_acsi_errors;	i = atari_err ? sizeof(atari_acsi_errors)/sizeof(*atari_acsi_errors) :		            sizeof(scsi_acsi_errors)/sizeof(*scsi_acsi_errors);		for( --i; i >= 0; --i )		if (arr[i].code == errcode) break;	if (i >= 0)		printk( ": %s\n", arr[i].text );}/******************************************************************* * * ACSI interrupt routine *   Test, if this is a ACSI interrupt and call the irq handler *   Otherwise ignore this interrupt. * *******************************************************************/static void acsi_interrupt(int irq, void *data, struct pt_regs *fp ){	void (*acsi_irq_handler)(void) = DEVICE_INTR;	DEVICE_INTR = NULL;	CLEAR_TIMER();	if (!acsi_irq_handler)		acsi_irq_handler = unexpected_acsi_interrupt;	acsi_irq_handler();}/****************************************************************** * * The Interrupt handlers * *******************************************************************/static void unexpected_acsi_interrupt( void ){	printk( KERN_WARNING "Unexpected ACSI interrupt\n" );}/* This function is called in case of errors. Because we cannot reset * the ACSI bus or a single device, there is no other choice than * retrying several times :-( */static void bad_rw_intr( void ){	if (QUEUE_EMPTY)		return;	if (++CURRENT->errors >= MAX_ERRORS)		end_request(0);	/* Otherwise just retry */}static void read_intr( void ){	int		status;		status = acsi_getstatus();	if (status != 0) {		int dev = DEVICE_NR(MINOR(CURRENT->rq_dev));		printk( KERN_ERR "ad%c: ", dev+'a' );		if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target, 					acsi_info[dev].lun))			printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status );		else {			acsi_print_error( acsi_buffer, dev );			if (CARTRCH_STAT( dev, acsi_buffer ))				acsi_info[dev].changed = 1;		}		ENABLE_IRQ();		bad_rw_intr();		redo_acsi_request();		return;	}	dma_cache_maintenance( virt_to_phys(CurrentBuffer), CurrentNSect*512, 0 );	if (CurrentBuffer == acsi_buffer)		copy_from_acsibuffer();	do_end_requests();	redo_acsi_request();}static void write_intr(void){	int	status;	status = acsi_getstatus();	if (status != 0) {		int	dev = DEVICE_NR(MINOR(CURRENT->rq_dev));		printk( KERN_ERR "ad%c: ", dev+'a' );		if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target,					acsi_info[dev].lun))			printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status );		else {			acsi_print_error( acsi_buffer, dev );			if (CARTRCH_STAT( dev, acsi_buffer ))				acsi_info[dev].changed = 1;		}		bad_rw_intr();		redo_acsi_request();		return;	}	do_end_requests();	redo_acsi_request();}static void acsi_times_out( unsigned long dummy ){	DISABLE_IRQ();	if (!DEVICE_INTR) return;	DEVICE_INTR = NULL;	printk( KERN_ERR "ACSI timeout\n" );	if (QUEUE_EMPTY) return;	if (++CURRENT->errors >= MAX_ERRORS) {#ifdef DEBUG		printk( KERN_ERR "ACSI: too many errors.\n" );#endif		end_request(0);	}	redo_acsi_request();}/*********************************************************************** * *  Scatter-gather utility functions * ***********************************************************************/static void copy_to_acsibuffer( void ){	int					i;	char				*src, *dst;	struct buffer_head	*bh;		src = CURRENT->buffer;	dst = acsi_buffer;	bh = CURRENT->bh;	if (!bh)		memcpy( dst, src, CurrentNSect*512 );	else		for( i = 0; i < CurrentNReq; ++i ) {			memcpy( dst, src, bh->b_size );			dst += bh->b_size;			if ((bh = bh->b_reqnext))				src = bh->b_data;		}}static void copy_from_acsibuffer( void ){	int					i;	char				*src, *dst;	struct buffer_head	*bh;		dst = CURRENT->buffer;	src = acsi_buffer;	bh = CURRENT->bh;	if (!bh)		memcpy( dst, src, CurrentNSect*512 );	else		for( i = 0; i < CurrentNReq; ++i ) {			memcpy( dst, src, bh->b_size );			src += bh->b_size;			if ((bh = bh->b_reqnext))				dst = bh->b_data;		}}static void do_end_requests( void ){	int		i, n;	if (!CURRENT->bh) {		CURRENT->nr_sectors -= CurrentNSect;		CURRENT->current_nr_sectors -= CurrentNSect;		CURRENT->sector += CurrentNSect;		if (CURRENT->nr_sectors == 0)			end_request(1);	}	else {		for( i = 0; i < CurrentNReq; ++i ) {			n = CURRENT->bh->b_size >> 9;			CURRENT->nr_sectors -= n;			CURRENT->current_nr_sectors -= n;			CURRENT->sector += n;			end_request(1);		}	}}/*********************************************************************** * *  do_acsi_request and friends * ***********************************************************************/static void do_acsi_request( request_queue_t * q ){	stdma_lock( acsi_interrupt, NULL );	redo_acsi_request();}static void redo_acsi_request( void ){	unsigned			block, dev, target, lun, nsect;	char 				*buffer;	unsigned long		pbuffer;	struct buffer_head	*bh;		if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) {		if (!DEVICE_INTR) {			ENABLE_IRQ();			stdma_release();		}		return;	}

⌨️ 快捷键说明

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