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

📄 mfmhd.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
				cont->redo();			};			return;		};		DBG("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr);		hdc63463_readdma();	};			/* Read */	if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) {		/* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */		/* Ah - well looking at the status its just when we get command end; so no problem */		/*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n",		   hdc63463_dataptr,Copy_buffer+256);		   print_status(); */	} else {		Sectors256LeftInCurrent--;		Copy_buffer += 256;		Copy_Sector++;		/* We have come to the end of this request */		if (!Sectors256LeftInCurrent) {			DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n",				       CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors);			CURRENT->nr_sectors -= CURRENT->current_nr_sectors;			CURRENT->sector += CURRENT->current_nr_sectors;			SectorsLeftInRequest -= CURRENT->current_nr_sectors;			end_request(CURRENT, 1);			if (SectorsLeftInRequest) {				hdc63463_dataptr = (unsigned int) CURRENT->buffer;				Copy_buffer = CURRENT->buffer;				Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;				errors = &(CURRENT->errors);				/* These should match the present calculations of the next logical sector				   on the device				   Copy_Sector=CURRENT->sector*2; */				if (Copy_Sector != CURRENT->sector * 2)#ifdef DEBUG					/*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n",					Copy_Sector, CURRENT->sector * 2);#else					printk("mfm: Copy_Sector mismatch! Eek!\n");#endif			};	/* CURRENT */		};	/* Sectors256LeftInCurrent */	};	old_status = mfm_status;	mfm_status = inw(MFM_STATUS);	if (mfm_status & (STAT_DER | STAT_ABN)) {		/* Something has gone wrong - let's try that again */		if (cont) {			DBG("mfm_rw_intr: DER/ABN error\n");			cont->error();			cont->redo();		};		return;	};	/* If this code wasn't entered due to command_end but there is	   now a command end we must read the command results out. If it was	   entered like this then mfm_interrupt_handler would have done the	   job. */	if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) &&	    ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) {		int len = 0;		while (len < 16) {			int in;			in = inw(MFM_DATAIN);			result[len++] = in >> 8;			result[len++] = in;		};	};			/* Result read */	/*console_printf ("mfm_rw_intr nearexit [%02X]\n", __raw_readb(mfm_IRQPollLoc)); */	/* If end of command move on */	if (mfm_status & (STAT_CED)) {		outw(CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */		/* End of command - trigger the next command */		if (cont) {			cont->done(1);		}		DBG("mfm_rw_intr: returned from cont->done\n");	} else {		/* Its going to generate another interrupt */		do_mfm = mfm_rw_intr;	};}static void mfm_setup_rw(void){	DBG("setting up for rw...\n");	do_mfm = mfm_rw_intr;	issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);}static void mfm_recal_intr(void){#ifdef DEBUG	console_printf("recal intr - status = ");	print_status();#endif	outw(CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */	if (mfm_status & (STAT_DER | STAT_ABN)) {		printk("recal failed\n");		MFM_DRV_INFO.cylinder = NEED_2_RECAL;		if (cont) {			cont->error();			cont->redo();		}		return;	}	/* Thats seek end - we are finished */	if (mfm_status & STAT_SED) {		issue_command(CMD_POD, NULL, 0);		MFM_DRV_INFO.cylinder = 0;		mfm_seek();		return;	}	/* Command end without seek end (see data sheet p.20) for parallel seek	   - we have to send a POL command to wait for the seek */	if (mfm_status & STAT_CED) {		do_mfm = mfm_recal_intr;		issue_command(CMD_POL, NULL, 0);		return;	}	printk("recal: unknown status\n");}static void mfm_seek_intr(void){#ifdef DEBUG	console_printf("seek intr - status = ");	print_status();#endif	outw(CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */	if (mfm_status & (STAT_DER | STAT_ABN)) {		printk("seek failed\n");		MFM_DRV_INFO.cylinder = NEED_2_RECAL;		if (cont) {			cont->error();			cont->redo();		}		return;	}	if (mfm_status & STAT_SED) {		issue_command(CMD_POD, NULL, 0);		MFM_DRV_INFO.cylinder = raw_cmd.cylinder;		mfm_seek();		return;	}	if (mfm_status & STAT_CED) {		do_mfm = mfm_seek_intr;		issue_command(CMD_POL, NULL, 0);		return;	}	printk("seek: unknown status\n");}/* IDEA2 seems to work better - its what RiscOS sets my * disc to - on its SECOND call to specify! */#define IDEA2#ifndef IDEA2#define SPEC_SL 0x16#define SPEC_SH 0xa9		/* Step pulse high=21, Record Length=001 (256 bytes) */#else#define SPEC_SL 0x00		/* OM2 - SL - step pulse low */#define SPEC_SH 0x21		/* Step pulse high=4, Record Length=001 (256 bytes) */#endifstatic void mfm_setupspecify (int drive, unsigned char *cmdb){	cmdb[0]  = 0x1f;		/* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */	cmdb[1]  = 0xc3;		/* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */	cmdb[2]  = SPEC_SL;		/* OM2 - SL - step pulse low */	cmdb[3]  = (number_mfm_drives == 1) ? 0x02 : 0x06;	/* 1 or 2 drives */	cmdb[4]  = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */	cmdb[5]  = mfm_info[drive].cylinders - 1;		/* low part of number of cylinders */	cmdb[6]  = mfm_info[drive].heads - 1;			/* Number of heads */	cmdb[7]  = mfm_info[drive].sectors - 1;			/* Number of sectors */	cmdb[8]  = SPEC_SH;	cmdb[9]  = 0x0a;		/* gap length 1 */	cmdb[10] = 0x0d;		/* gap length 2 */	cmdb[11] = 0x0c;		/* gap length 3 */	cmdb[12] = (mfm_info[drive].precomp - 1) >> 8;	/* pre comp cylinder */	cmdb[13] = mfm_info[drive].precomp - 1;	cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8;	/* Low current cylinder */	cmdb[15] = mfm_info[drive].lowcurrent - 1;}static void mfm_specify (void){	unsigned char cmdb[16];	DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive);	mfm_setupspecify (raw_cmd.dev, cmdb);	issue_command (CMD_SPC, cmdb, 16);	/* Ensure that we will do another specify if we move to the other drive */	lastspecifieddrive = raw_cmd.dev;	wait_for_completion();}static void mfm_seek(void){	unsigned char cmdb[4];	DBG("seeking...\n");	if (MFM_DRV_INFO.cylinder < 0) {		do_mfm = mfm_recal_intr;		DBG("mfm_seek: about to call specify\n");		mfm_specify ();	/* DAG added this */		cmdb[0] = raw_cmd.dev + 1;		cmdb[1] = 0;		issue_command(CMD_RCLB, cmdb, 2);		return;	}	if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) {		cmdb[0] = raw_cmd.dev + 1;		cmdb[1] = 0;	/* raw_cmd.head; DAG: My data sheet says this should be 0 */		cmdb[2] = raw_cmd.cylinder >> 8;		cmdb[3] = raw_cmd.cylinder;		do_mfm = mfm_seek_intr;		issue_command(CMD_SEK, cmdb, 4);	} else		mfm_setup_rw();}static void mfm_initialise(void){	DBG("init...\n");	mfm_seek();}static void request_done(int uptodate){	DBG("mfm:request_done\n");	if (uptodate) {		unsigned char block[2] = {0, 0};		/* Apparently worked - let's check bytes left to DMA */		if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) {			printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256);			end_request(CURRENT, 0);			Busy = 0;		};		/* Potentially this means that we've done; but we might be doing		   a partial access, (over two cylinders) or we may have a number		   of fragments in an image file.  First let's deal with partial accesss		 */		if (PartFragRead) {			/* Yep - a partial access */			/* and issue the remainder */			issue_request(PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT);			return;		}		/* ah well - perhaps there is another fragment to go */		/* Increment pointers/counts to start of next fragment */		if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n");		/* No - its the end of the line */		/* end_request's should have happened at the end of sector DMAs */		/* Turns Drive LEDs off - may slow it down? */		if (!elv_next_request(QUEUE))			issue_command(CMD_CKV, block, 2);		Busy = 0;		DBG("request_done: About to mfm_request\n");		/* Next one please */		mfm_request();	/* Moved from mfm_rw_intr */		DBG("request_done: returned from mfm_request\n");	} else {		printk("mfm:request_done: update=0\n");		end_request(CURRENT, 0);		Busy = 0;	}}static void error_handler(void){	printk("error detected... status = ");	print_status();	(*errors)++;	if (*errors > MFM_DRV_INFO.errors.abort)		cont->done(0);	if (*errors > MFM_DRV_INFO.errors.recal)		MFM_DRV_INFO.cylinder = NEED_2_RECAL;}static void rw_interrupt(void){	printk("rw_interrupt\n");}static struct cont rw_cont ={	rw_interrupt,	error_handler,	mfm_rerequest,	request_done};/* * Actually gets round to issuing the request - note everything at this * point is in 256 byte sectors not Linux 512 byte blocks */static void issue_request(unsigned int block, unsigned int nsect,			  struct request *req){	struct gendisk *disk = req->rq_disk;	struct mfm_info *p = disk->private_data;	int track, start_head, start_sector;	int sectors_to_next_cyl;	dev = p - mfm_info;	track = block / p->sectors;	start_sector = block % p->sectors;	start_head = track % p->heads;	/* First get the number of whole tracks which are free before the next	   track */	sectors_to_next_cyl = (p->heads - (start_head + 1)) * p->sectors;	/* Then add in the number of sectors left on this track */	sectors_to_next_cyl += (p->sectors - start_sector);	DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", p->sectors, track);	raw_cmd.dev = dev;	raw_cmd.sector = start_sector;	raw_cmd.head = start_head;	raw_cmd.cylinder = track / p->heads;	raw_cmd.cmdtype = CURRENT->cmd;	raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD;	raw_cmd.cmddata[0] = dev + 1;	/* DAG: +1 to get US */	raw_cmd.cmddata[1] = raw_cmd.head;	raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8;	raw_cmd.cmddata[3] = raw_cmd.cylinder;	raw_cmd.cmddata[4] = raw_cmd.head;	raw_cmd.cmddata[5] = raw_cmd.sector;	/* Was == and worked - how the heck??? */	if (lastspecifieddrive != raw_cmd.dev)		mfm_specify ();	if (nsect <= sectors_to_next_cyl) {		raw_cmd.cmddata[6] = nsect >> 8;		raw_cmd.cmddata[7] = nsect;		PartFragRead = 0;	/* All in one */		PartFragRead_SectorsLeft = 0;	/* Must set this - used in DMA calcs */	} else {		raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8;		raw_cmd.cmddata[7] = sectors_to_next_cyl;		PartFragRead = sectors_to_next_cyl;	/* only do this many this time */		PartFragRead_RestartBlock = block + sectors_to_next_cyl;	/* Where to restart from */		PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl;	}	raw_cmd.cmdlen = 8;	/* Setup DMA pointers */	hdc63463_dataptr = (unsigned int) Copy_buffer;	hdc63463_dataleft = nsect * 256;	/* Better way? */	DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",	     raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ",		       raw_cmd.cylinder,		       raw_cmd.head,	    raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT);	cont = &rw_cont;	errors = &(CURRENT->errors);#if 0	mfm_tq.routine = (void (*)(void *)) mfm_initialise;	queue_task(&mfm_tq, &tq_immediate);	mark_bh(IMMEDIATE_BH);#else	mfm_initialise();#endif}				/* issue_request *//* * Called when an error has just happened - need to trick mfm_request * into thinking we weren't busy * * Turn off ints - mfm_request expects them this way */static void mfm_rerequest(void){	DBG("mfm_rerequest\n");	cli();	Busy = 0;	mfm_request();}static struct gendisk *mfm_gendisk[2];static void mfm_request(void){	DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy);	/* If we are still processing then return; we will get called again */	if (Busy) {		/* Again seems to be common in 1.3.45 */		/*DBG*/printk("mfm_request: Exiting due to busy\n");		return;	}	Busy = 1;	while (1) {		unsigned int block, nsect;		struct gendisk *disk;		DBG("mfm_request: loop start\n");		sti();		DBG("mfm_request: before !CURRENT\n");		if (!CURRENT) {			printk("mfm_request: Exiting due to empty queue (pre)\n");			do_mfm = NULL;			Busy = 0;			return;		}		DBG("mfm_request:                 before arg extraction\n");		disk = CURRENT->rq_disk;		block = CURRENT->sector;		nsect = CURRENT->nr_sectors;		if (block >= get_capacity(disk) ||		    block+nsect > get_capacity(disk)) {			printk("%s: bad access: block=%d, count=%d, nr_sects=%ld\n",			       disk->disk_name, block, nsect, get_capacity(disk));			printk("mfm: continue 1\n");			end_request(CURRENT, 0);			Busy = 0;			continue;		}		/* DAG: Linux doesn't cope with this - even though it has an array telling		   it the hardware block size - silly */		block <<= 1;	/* Now in 256 byte sectors */		nsect <<= 1;	/* Ditto */		SectorsLeftInRequest = nsect >> 1;		Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;		Copy_buffer = CURRENT->buffer;		Copy_Sector = CURRENT->sector << 1;		DBG("mfm_request: block after offset=%d\n", block);		if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) {			printk("unknown mfm-command %d\n", CURRENT->cmd);			end_request(CURRENT, 0);			Busy = 0;			printk("mfm: continue 4\n");			continue;		}		issue_request(block, nsect, CURRENT);		break;	}	DBG("mfm_request: Dropping out bottom\n");

⌨️ 快捷键说明

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