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

📄 floppy.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (result() != 1){			FDCS->reset = 1;			return;		}		CLEARF(FD_VERIFY);		CLEARF(FD_NEED_TWADDLE);#ifdef DCL_DEBUG		if (DP->flags & FD_DEBUG){			DPRINT("checking whether disk is write protected\n");			DPRINT("wp=%x\n",ST3 & 0x40);		}#endif		if (!(ST3  & 0x40))			SETF(FD_DISK_WRITABLE);		else			CLEARF(FD_DISK_WRITABLE);	}}static void seek_floppy(void){	int track;	blind_seek=0;#ifdef DCL_DEBUG	if (DP->flags & FD_DEBUG){		DPRINT("calling disk change from seek\n");	}#endif	if (!TESTF(FD_DISK_NEWCHANGE) &&	    disk_change(current_drive) &&	    (raw_cmd->flags & FD_RAW_NEED_DISK)){		/* the media changed flag should be cleared after the seek.		 * If it isn't, this means that there is really no disk in		 * the drive.		 */		SETF(FD_DISK_CHANGED);		cont->done(0);		cont->redo();		return;	}	if (DRS->track <= NEED_1_RECAL){		recalibrate_floppy();		return;	} else if (TESTF(FD_DISK_NEWCHANGE) &&		   (raw_cmd->flags & FD_RAW_NEED_DISK) &&		   (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {		/* we seek to clear the media-changed condition. Does anybody		 * know a more elegant way, which works on all drives? */		if (raw_cmd->track)			track = raw_cmd->track - 1;		else {			if (DP->flags & FD_SILENT_DCL_CLEAR){				set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);				blind_seek = 1;				raw_cmd->flags |= FD_RAW_NEED_SEEK;			}			track = 1;		}	} else {		check_wp();		if (raw_cmd->track != DRS->track &&		    (raw_cmd->flags & FD_RAW_NEED_SEEK))			track = raw_cmd->track;		else {			setup_rw_floppy();			return;		}	}	SET_INTR(seek_interrupt);	output_byte(FD_SEEK);	output_byte(UNIT(current_drive));	LAST_OUT(track);#ifdef DEBUGT	debugt("seek command:");#endif}static void recal_interrupt(void){#ifdef DEBUGT	debugt("recal interrupt:");#endif	if (inr !=2)		FDCS->reset = 1;	else if (ST0 & ST0_ECE) {	       	switch(DRS->track){			case NEED_1_RECAL:#ifdef DEBUGT				debugt("recal interrupt need 1 recal:");#endif				/* after a second recalibrate, we still haven't				 * reached track 0. Probably no drive. Raise an				 * error, as failing immediately might upset				 * computers possessed by the Devil :-) */				cont->error();				cont->redo();				return;			case NEED_2_RECAL:#ifdef DEBUGT				debugt("recal interrupt need 2 recal:");#endif				/* If we already did a recalibrate,				 * and we are not at track 0, this				 * means we have moved. (The only way				 * not to move at recalibration is to				 * be already at track 0.) Clear the				 * new change flag */#ifdef DCL_DEBUG				if (DP->flags & FD_DEBUG){					DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");				}#endif				CLEARF(FD_DISK_NEWCHANGE);				DRS->select_date = jiffies;				/* fall through */			default:#ifdef DEBUGT				debugt("recal interrupt default:");#endif				/* Recalibrate moves the head by at				 * most 80 steps. If after one				 * recalibrate we don't have reached				 * track 0, this might mean that we				 * started beyond track 80.  Try				 * again.  */				DRS->track = NEED_1_RECAL;				break;		}	} else		DRS->track = ST1;	floppy_ready();}static void print_result(char *message, int inr){	int i;	DPRINT("%s ", message);	if (inr >= 0)		for (i=0; i<inr; i++)			printk("repl[%d]=%x ", i, reply_buffer[i]);	printk("\n");}/* interrupt handler */void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs){	void (*handler)(void) = DEVICE_INTR;	int do_print;	lasthandler = handler;	interruptjiffies = jiffies;	fd_disable_dma();	floppy_enable_hlt();	CLEAR_INTR;	if (fdc >= N_FDC || FDCS->address == -1){		/* we don't even know which FDC is the culprit */		printk("DOR0=%x\n", fdc_state[0].dor);		printk("floppy interrupt on bizarre fdc %d\n",fdc);		printk("handler=%p\n", handler);		is_alive("bizarre fdc");		return;	}	FDCS->reset = 0;	/* We have to clear the reset flag here, because apparently on boxes	 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to	 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the	 * emission of the SENSEI's.	 * It is OK to emit floppy commands because we are in an interrupt	 * handler here, and thus we have to fear no interference of other	 * activity.	 */	do_print = !handler && print_unex && !initialising;	inr = result();	if(do_print)		print_result("unexpected interrupt", inr);	if (inr == 0){		int max_sensei = 4;		do {			output_byte(FD_SENSEI);			inr = result();			if(do_print)				print_result("sensei", inr);			max_sensei--;		} while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2 && max_sensei);	}	if (handler) {		if(intr_count >= 2) {			/* expected interrupt */			floppy_tq.routine = (void *)(void *) handler;			queue_task_irq(&floppy_tq, &tq_immediate);			mark_bh(IMMEDIATE_BH);		} else			handler();	} else		FDCS->reset = 1;	is_alive("normal interrupt end");}static void recalibrate_floppy(void){#ifdef DEBUGT	debugt("recalibrate floppy:");#endif	SET_INTR(recal_interrupt);	output_byte(FD_RECALIBRATE);	LAST_OUT(UNIT(current_drive));}/* * Must do 4 FD_SENSEIs after reset because of ``drive polling''. */static void reset_interrupt(void){#ifdef DEBUGT	debugt("reset interrupt:");#endif	result();		/* get the status ready for set_fdc */	if (FDCS->reset) {		printk("reset set in interrupt, calling %p\n", cont->error);		cont->error(); /* a reset just after a reset. BAD! */	}	cont->redo();}/* * reset is done by pulling bit 2 of DOR low for a while (old FDCs), * or by setting the self clearing bit 7 of STATUS (newer FDCs) */static void reset_fdc(void){	SET_INTR(reset_interrupt);	FDCS->reset = 0;	reset_fdc_info(0);	/* Pseudo-DMA may intercept 'reset finished' interrupt.  */	/* Irrelevant for systems with true DMA (i386).          */	fd_disable_dma();	if (FDCS->version >= FDC_82072A)		fd_outb(0x80 | (FDCS->dtr &3), FD_STATUS);	else {		fd_outb(FDCS->dor & ~0x04, FD_DOR);		udelay(FD_RESET_DELAY);		fd_outb(FDCS->dor, FD_DOR);	}}void show_floppy(void){	int i;	printk("\n");	printk("floppy driver state\n");	printk("-------------------\n");	printk("now=%ld last interrupt=%d last called handler=%p\n",	       jiffies, interruptjiffies, lasthandler);#ifdef FLOPPY_SANITY_CHECK	printk("timeout_message=%s\n", timeout_message);	printk("last output bytes:\n");	for (i=0; i < OLOGSIZE; i++)		printk("%2x %2x %ld\n",		       output_log[(i+output_log_pos) % OLOGSIZE].data,		       output_log[(i+output_log_pos) % OLOGSIZE].status,		       output_log[(i+output_log_pos) % OLOGSIZE].jiffies);	printk("last result at %d\n", resultjiffies);	printk("last redo_fd_request at %d\n", lastredo);	for (i=0; i<resultsize; i++){		printk("%2x ", reply_buffer[i]);	}	printk("\n");#endif	printk("status=%x\n", fd_inb(FD_STATUS));	printk("fdc_busy=%d\n", fdc_busy);	if (DEVICE_INTR)		printk("DEVICE_INTR=%p\n", DEVICE_INTR);	if (floppy_tq.sync)		printk("floppy_tq.routine=%p\n", floppy_tq.routine);	if (fd_timer.prev)		printk("fd_timer.function=%p\n", fd_timer.function);	if (fd_timeout.prev){		printk("timer_table=%p\n",fd_timeout.function);		printk("expires=%ld\n",fd_timeout.expires-jiffies);		printk("now=%ld\n",jiffies);	}	printk("cont=%p\n", cont);	printk("CURRENT=%p\n", CURRENT);	printk("command_status=%d\n", command_status);	printk("\n");}static void floppy_shutdown(void){	if (!initialising)		show_floppy();	cancel_activity();	sti();	floppy_enable_hlt();	fd_disable_dma();	/* avoid dma going to a random drive after shutdown */	if (!initialising)		DPRINT("floppy timeout called\n");	FDCS->reset = 1;	if (cont){		cont->done(0);		cont->redo(); /* this will recall reset when needed */	} else {		printk("no cont in shutdown!\n");		process_fd_request();	}	is_alive("floppy shutdown");}/*typedef void (*timeout_fn)(unsigned long);*//* start motor, check media-changed condition and write protection */static int start_motor(void (*function)(void) ){	int mask, data;	mask = 0xfc;	data = UNIT(current_drive);	if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)){		if (!(FDCS->dor & (0x10 << UNIT(current_drive)))){			set_debugt();			/* no read since this drive is running */			DRS->first_read_date = 0;			/* note motor start time if motor is not yet running */			DRS->spinup_date = jiffies;			data |= (0x10 << UNIT(current_drive));		}	} else		if (FDCS->dor & (0x10 << UNIT(current_drive)))			mask &= ~(0x10 << UNIT(current_drive));	/* starts motor and selects floppy */	del_timer(motor_off_timer + current_drive);	set_dor(fdc, mask, data);	/* wait_for_completion also schedules reset if needed. */	return(wait_for_completion(DRS->select_date+DP->select_delay,				   (timeout_fn) function));}static void floppy_ready(void){	CHECK_RESET;	if (start_motor(floppy_ready)) return;	if (fdc_dtr()) return;#ifdef DCL_DEBUG	if (DP->flags & FD_DEBUG){		DPRINT("calling disk change from floppy_ready\n");	}#endif	if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&	   disk_change(current_drive) &&	   !DP->select_delay)		twaddle(); /* this clears the dcl on certain drive/controller			    * combinations */	if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)){		perpendicular_mode();		fdc_specify(); /* must be done here because of hut, hlt ... */		seek_floppy();	} else		setup_rw_floppy();}static void floppy_start(void){	reschedule_timeout(CURRENTD, "floppy start", 0);	scandrives();#ifdef DCL_DEBUG	if (DP->flags & FD_DEBUG){		DPRINT("setting NEWCHANGE in floppy_start\n");	}#endif	SETF(FD_DISK_NEWCHANGE);	floppy_ready();}/* * ======================================================================== * here ends the bottom half. Exported routines are: * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc, * start_motor, reset_fdc, reset_fdc_info, interpret_errors. * Initialization also uses output_byte, result, set_dor, floppy_interrupt * and set_dor. * ======================================================================== *//* * General purpose continuations. * ============================== */static void do_wakeup(void){	reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);	cont = 0;	command_status += 2;	wake_up(&command_done);}static struct cont_t wakeup_cont={	empty,	do_wakeup,	empty,	(done_f)empty};static struct cont_t intr_cont={	empty,	process_fd_request,	empty,	(done_f) empty};static int wait_til_done(void (*handler)(void), int interruptible){	int ret;	unsigned long flags;	floppy_tq.routine = (void *)(void *) handler;	queue_task(&floppy_tq, &tq_immediate); 	mark_bh(IMMEDIATE_BH);	INT_OFF;	while(command_status < 2 && NO_SIGNAL){		is_alive("wait_til_done");		if (interruptible)			interruptible_sleep_on(&command_done);		else			sleep_on(&command_done);	}	if (command_status < 2){		cancel_activity();		cont = &intr_cont;		reset_fdc();		INT_ON;		return -EINTR;	}	INT_ON;	if (FDCS->reset)		command_status = FD_COMMAND_ERROR;	if (command_status == FD_COMMAND_OKAY)		ret=0;	else		ret=-EIO;	command_status = FD_COMMAND_NONE;	return ret;}static void generic_done(int result){	command_status = result;	cont = &wakeup_cont;}static void generic_success(void){	cont->done(1);}static void generic_failure(void){	cont->done(0);}static void success_and_wakeup(void){	generic_success();	cont->redo();}/* * formatting and rw support. * ========================== */static int next_valid_format(void){	int probed_format;

⌨️ 快捷键说明

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