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

📄 floppy.c

📁 这是一个SIGMA方案的PMP播放器的UCLINUX程序,可播放DVD,VCD,CD MP3...有很好的参考价值.
💻 C
📖 第 1 页 / 共 5 页
字号:
		ready_date = DRS->spinup_date + DP->spinup;		/* If spinup will take a long time, rerun scandrives		 * again just before spinup completion. Beware that		 * after scandrives, we must again wait for selection.		 */		if ((signed) (ready_date - jiffies) > DP->select_delay){			ready_date -= DP->select_delay;			function = (timeout_fn) floppy_start;		} else			function = (timeout_fn) setup_rw_floppy;		/* wait until the floppy is spinning fast enough */		if (fd_wait_for_completion(ready_date,function))			return;	}	dflags = DRS->flags;	if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))		setup_DMA();	if (flags & FD_RAW_INTR)		SET_INTR(main_command_interrupt);	r=0;	for (i=0; i< raw_cmd->cmd_count; i++)		r|=output_byte(raw_cmd->cmd[i]);#ifdef DEBUGT	debugt("rw_command: ");#endif	if (r){		cont->error();		reset_fdc();		return;	}	if (!(flags & FD_RAW_INTR)){		inr = result();		cont->interrupt();	} else if (flags & FD_RAW_NEED_DISK)		fd_watchdog();}static int blind_seek;/* * This is the routine called after every seek (or recalibrate) interrupt * from the floppy controller. */static void seek_interrupt(void){#ifdef DEBUGT	debugt("seek interrupt:");#endif	if (inr != 2 || (ST0 & 0xF8) != 0x20) {		DPRINT("seek failed\n");		DRS->track = NEED_2_RECAL;		cont->error();		cont->redo();		return;	}	if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek){#ifdef DCL_DEBUG		if (DP->flags & FD_DEBUG){			DPRINT("clearing NEWCHANGE flag because of effective seek\n");			DPRINT("jiffies=%lu\n", jiffies);		}#endif		CLEARF(FD_DISK_NEWCHANGE); /* effective seek */		DRS->select_date = jiffies;	}	DRS->track = ST1;	floppy_ready();}static void check_wp(void){	if (TESTF(FD_VERIFY)) {		/* check write protection */		output_byte(FD_GETSTATUS);		output_byte(UNIT(current_drive));		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. Note that this can be called externally on the Sparc */void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs){	void (*handler)(void) = DEVICE_INTR;	int do_print;	unsigned long f;	lasthandler = handler;	interruptjiffies = jiffies;	f=claim_dma_lock();	fd_disable_dma();	release_dma_lock(f);		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) {		schedule_bh( (void *)(void *) 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){	unsigned long flags;		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).          */		flags=claim_dma_lock();	fd_disable_dma();	release_dma_lock(flags);	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);	}}static void show_floppy(void){	int i;	printk("\n");	printk("floppy driver state\n");	printk("-------------------\n");	printk("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",	       jiffies, interruptjiffies, 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 %lu\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 %lu\n", resultjiffies);	printk("last redo_fd_request at %lu\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=%lu\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 (timer_pending(&fd_timer))		printk("fd_timer.function=%p\n", fd_timer.function);	if (timer_pending(&fd_timeout)){		printk("timer_function=%p\n",fd_timeout.function);		printk("expires=%lu\n",fd_timeout.expires-jiffies);		printk("now=%lu\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){	unsigned long flags;		if (!initialising)		show_floppy();	cancel_activity();	floppy_enable_hlt();		flags=claim_dma_lock();	fd_disable_dma();	release_dma_lock(flags);		/* 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(fd_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 */#ifdef fd_chose_dma_mode	if ((raw_cmd->flags & FD_RAW_READ) || 	    (raw_cmd->flags & FD_RAW_WRITE))	{		unsigned long flags = claim_dma_lock();		fd_chose_dma_mode(raw_cmd->kernel_data,				  raw_cmd->length);		release_dma_lock(flags);	}#endif	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 {		if ((raw_cmd->flags & FD_RAW_READ) || 		    (raw_cmd->flags & FD_RAW_WRITE))			fdc_specify();		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();

⌨️ 快捷键说明

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