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

📄 floppy.c

📁 这是一个SIGMA方案的PMP播放器的UCLINUX程序,可播放DVD,VCD,CD MP3...有很好的参考价值.
💻 C
📖 第 1 页 / 共 5 页
字号:
#define ECALL(x) if ((ret = (x))) return ret;#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))#define WAIT(x) _WAIT((x),interruptible)#define IWAIT(x) _WAIT((x),1)/* Errors during formatting are counted here. */static int format_errors;/* Format request descriptor. */static struct format_descr format_req;/* * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), * H is head unload time (1=16ms, 2=32ms, etc) *//* * Track buffer * Because these are written to by the DMA controller, they must * not contain a 64k byte boundary crossing, or data will be * corrupted/lost. */static char *floppy_track_buffer;static int max_buffer_sectors;static int *errors;typedef void (*done_f)(int);static struct cont_t {	void (*interrupt)(void); /* this is called after the interrupt of the				  * main command */	void (*redo)(void); /* this is called to retry the operation */	void (*error)(void); /* this is called to tally an error */	done_f done; /* this is called to say if the operation has 		      * succeeded/failed */} *cont;static void floppy_ready(void);static void floppy_start(void);static void process_fd_request(void);static void recalibrate_floppy(void);static void floppy_shutdown(void);static int floppy_grab_irq_and_dma(void);static void floppy_release_irq_and_dma(void);/* * The "reset" variable should be tested whenever an interrupt is scheduled, * after the commands have been sent. This is to ensure that the driver doesn't * get wedged when the interrupt doesn't come because of a failed command. * reset doesn't need to be tested before sending commands, because * output_byte is automatically disabled when reset is set. */#define CHECK_RESET { if (FDCS->reset){ reset_fdc(); return; } }static void reset_fdc(void);/* * These are global variables, as that's the easiest way to give * information to interrupts. They are the data used for the current * request. */#define NO_TRACK -1#define NEED_1_RECAL -2#define NEED_2_RECAL -3static int usage_count;/* buffer related variables */static int buffer_track = -1;static int buffer_drive = -1;static int buffer_min = -1;static int buffer_max = -1;/* fdc related variables, should end up in a struct */static struct floppy_fdc_state fdc_state[N_FDC];static int fdc; /* current fdc */static struct floppy_struct *_floppy = floppy_type;static unsigned char current_drive;static long current_count_sectors;static unsigned char sector_t; /* sector in track */static unsigned char in_sector_offset;	/* offset within physical sector,					 * expressed in units of 512 bytes */#ifndef fd_eject#define fd_eject(x) -EINVAL#endif#ifdef DEBUGTstatic long unsigned debugtimer;#endif/* * Debugging * ========= */static inline void set_debugt(void){#ifdef DEBUGT	debugtimer = jiffies;#endif}static inline void debugt(const char *message){#ifdef DEBUGT	if (DP->flags & DEBUGT)		printk("%s dtime=%lu\n", message, jiffies-debugtimer);#endif}typedef void (*timeout_fn)(unsigned long);static struct timer_list fd_timeout ={ function: (timeout_fn) floppy_shutdown };static const char *timeout_message;#ifdef FLOPPY_SANITY_CHECKstatic void is_alive(const char *message){	/* this routine checks whether the floppy driver is "alive" */	if (fdc_busy && command_status < 2 && !timer_pending(&fd_timeout)){		DPRINT("timeout handler died: %s\n",message);	}}#endif#ifdef FLOPPY_SANITY_CHECK#define OLOGSIZE 20static void (*lasthandler)(void);static unsigned long interruptjiffies;static unsigned long resultjiffies;static int resultsize;static unsigned long lastredo;static struct output_log {	unsigned char data;	unsigned char status;	unsigned long jiffies;} output_log[OLOGSIZE];static int output_log_pos;#endif#define CURRENTD -1#define MAXTIMEOUT -2static void reschedule_timeout(int drive, const char *message, int marg){	if (drive == CURRENTD)		drive = current_drive;	del_timer(&fd_timeout);	if (drive < 0 || drive > N_DRIVE) {		fd_timeout.expires = jiffies + 20UL*HZ;		drive=0;	} else		fd_timeout.expires = jiffies + UDP->timeout;	add_timer(&fd_timeout);	if (UDP->flags & FD_DEBUG){		DPRINT("reschedule timeout ");		printk(message, marg);		printk("\n");	}	timeout_message = message;}static int maximum(int a, int b){	if (a > b)		return a;	else		return b;}#define INFBOUND(a,b) (a)=maximum((a),(b));static int minimum(int a, int b){	if (a < b)		return a;	else		return b;}#define SUPBOUND(a,b) (a)=minimum((a),(b));/* * Bottom half floppy driver. * ========================== * * This part of the file contains the code talking directly to the hardware, * and also the main service loop (seek-configure-spinup-command) *//* * disk change. * This routine is responsible for maintaining the FD_DISK_CHANGE flag, * and the last_checked date. * * last_checked is the date of the last check which showed 'no disk change' * FD_DISK_CHANGE is set under two conditions: * 1. The floppy has been changed after some i/o to that floppy already *    took place. * 2. No floppy disk is in the drive. This is done in order to ensure that *    requests are quickly flushed in case there is no disk in the drive. It *    follows that FD_DISK_CHANGE can only be cleared if there is a disk in *    the drive. * * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet. * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on *  each seek. If a disk is present, the disk change line should also be *  cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk *  change line is set, this means either that no disk is in the drive, or *  that it has been removed since the last seek. * * This means that we really have a third possibility too: *  The floppy has been changed after the last seek. */static int disk_change(int drive){	int fdc=FDC(drive);#ifdef FLOPPY_SANITY_CHECK	if (jiffies - UDRS->select_date < UDP->select_delay)		DPRINT("WARNING disk change called early\n");	if (!(FDCS->dor & (0x10 << UNIT(drive))) ||	    (FDCS->dor & 3) != UNIT(drive) ||	    fdc != FDC(drive)){		DPRINT("probing disk change on unselected drive\n");		DPRINT("drive=%d fdc=%d dor=%x\n",drive, FDC(drive),			(unsigned int)FDCS->dor);	}#endif#ifdef DCL_DEBUG	if (UDP->flags & FD_DEBUG){		DPRINT("checking disk change line for drive %d\n",drive);		DPRINT("jiffies=%lu\n", jiffies);		DPRINT("disk change line=%x\n",fd_inb(FD_DIR)&0x80);		DPRINT("flags=%lx\n",UDRS->flags);	}#endif	if (UDP->flags & FD_BROKEN_DCL)		return UTESTF(FD_DISK_CHANGED);	if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80){		USETF(FD_VERIFY); /* verify write protection */		if (UDRS->maxblock){			/* mark it changed */			USETF(FD_DISK_CHANGED);		}		/* invalidate its geometry */		if (UDRS->keep_data >= 0) {			if ((UDP->flags & FTD_MSG) &&			    current_type[drive] != NULL)				DPRINT("Disk type is undefined after "				       "disk change\n");			current_type[drive] = NULL;			floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE;		}		/*USETF(FD_DISK_NEWCHANGE);*/		return 1;	} else {		UDRS->last_checked=jiffies;		UCLEARF(FD_DISK_NEWCHANGE);	}	return 0;}static inline int is_selected(int dor, int unit){	return ((dor  & (0x10 << unit)) && (dor &3) == unit);}static int set_dor(int fdc, char mask, char data){	register unsigned char drive, unit, newdor,olddor;	if (FDCS->address == -1)		return -1;	olddor = FDCS->dor;	newdor =  (olddor & mask) | data;	if (newdor != olddor){		unit = olddor & 0x3;		if (is_selected(olddor, unit) && !is_selected(newdor,unit)){			drive = REVDRIVE(fdc,unit);#ifdef DCL_DEBUG			if (UDP->flags & FD_DEBUG){				DPRINT("calling disk change from set_dor\n");			}#endif			disk_change(drive);		}		FDCS->dor = newdor;		fd_outb(newdor, FD_DOR);		unit = newdor & 0x3;		if (!is_selected(olddor, unit) && is_selected(newdor,unit)){			drive = REVDRIVE(fdc,unit);			UDRS->select_date = jiffies;		}	}	/*	 *	We should propogate failures to grab the resources back	 *	nicely from here. Actually we ought to rewrite the fd	 *	driver some day too.	 */	if (newdor & FLOPPY_MOTOR_MASK)		floppy_grab_irq_and_dma();	if (olddor & FLOPPY_MOTOR_MASK)		floppy_release_irq_and_dma();	return olddor;}static void twaddle(void){	if (DP->select_delay)		return;	fd_outb(FDCS->dor & ~(0x10<<UNIT(current_drive)), FD_DOR);	fd_outb(FDCS->dor, FD_DOR);	DRS->select_date = jiffies;}/* reset all driver information about the current fdc. This is needed after * a reset, and after a raw command. */static void reset_fdc_info(int mode){	int drive;	FDCS->spec1 = FDCS->spec2 = -1;	FDCS->need_configure = 1;	FDCS->perp_mode = 1;	FDCS->rawcmd = 0;	for (drive = 0; drive < N_DRIVE; drive++)		if (FDC(drive) == fdc &&		    (mode || UDRS->track != NEED_1_RECAL))			UDRS->track = NEED_2_RECAL;}/* selects the fdc and drive, and enables the fdc's input/dma. */static void set_fdc(int drive){	if (drive >= 0 && drive < N_DRIVE){		fdc = FDC(drive);		current_drive = drive;	}	if (fdc != 1 && fdc != 0) {		printk("bad fdc value\n");		return;	}	set_dor(fdc,~0,8);#if N_FDC > 1	set_dor(1-fdc, ~8, 0);#endif	if (FDCS->rawcmd == 2)		reset_fdc_info(1);	if (fd_inb(FD_STATUS) != STATUS_READY)		FDCS->reset = 1;}/* locks the driver */static int _lock_fdc(int drive, int interruptible, int line){	if (!usage_count){		printk(KERN_ERR "Trying to lock fdc while usage count=0 at line %d\n", line);		return -1;	}	if(floppy_grab_irq_and_dma()==-1)		return -EBUSY;	if (test_and_set_bit(0, &fdc_busy)) {		DECLARE_WAITQUEUE(wait, current);		add_wait_queue(&fdc_wait, &wait);		for (;;) {			set_current_state(TASK_INTERRUPTIBLE);			if (!test_and_set_bit(0, &fdc_busy))				break;			schedule();			if (!NO_SIGNAL) {				remove_wait_queue(&fdc_wait, &wait);				return -EINTR;			}		}		set_current_state(TASK_RUNNING);		remove_wait_queue(&fdc_wait, &wait);	}	command_status = FD_COMMAND_NONE;	reschedule_timeout(drive, "lock fdc", 0);	set_fdc(drive);	return 0;}#define lock_fdc(drive,interruptible) _lock_fdc(drive,interruptible, __LINE__)#define LOCK_FDC(drive,interruptible) \if (lock_fdc(drive,interruptible)) return -EINTR;/* unlocks the driver */static inline void unlock_fdc(void){	raw_cmd = 0;	if (!fdc_busy)		DPRINT("FDC access conflict!\n");	if (DEVICE_INTR)		DPRINT("device interrupt still active at FDC release: %p!\n",			DEVICE_INTR);	command_status = FD_COMMAND_NONE;	del_timer(&fd_timeout);	cont = NULL;	clear_bit(0, &fdc_busy);	floppy_release_irq_and_dma();	wake_up(&fdc_wait);}/* switches the motor off after a given timeout */static void motor_off_callback(unsigned long nr){	unsigned char mask = ~(0x10 << UNIT(nr));	set_dor(FDC(nr), mask, 0);}/* schedules motor off */static void floppy_off(unsigned int drive){	unsigned long volatile delta;	register int fdc=FDC(drive);	if (!(FDCS->dor & (0x10 << UNIT(drive))))		return;	del_timer(motor_off_timer+drive);	/* make spindle stop in a position which minimizes spinup time	 * next time */	if (UDP->rps){		delta = jiffies - UDRS->first_read_date + HZ -			UDP->spindown_offset;		delta = ((delta * UDP->rps) % HZ) / UDP->rps;		motor_off_timer[drive].expires = jiffies + UDP->spindown - delta;	}	add_timer(motor_off_timer+drive);}/* * cycle through all N_DRIVE floppy drives, for disk change testing. * stopping at current drive. This is done before any long operation, to * be sure to have up to date disk change information. */static void scandrives(void){	int i, drive, saved_drive;	if (DP->select_delay)		return;	saved_drive = current_drive;	for (i=0; i < N_DRIVE; i++){		drive = (saved_drive + i + 1) % N_DRIVE;		if (UDRS->fd_ref == 0 || UDP->select_delay != 0)			continue; /* skip closed drives */		set_fdc(drive);		if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &		      (0x10 << UNIT(drive))))			/* switch the motor off again, if it was off to			 * begin with */			set_dor(fdc, ~(0x10 << UNIT(drive)), 0);	}	set_fdc(saved_drive);}static void empty(void){}static struct tq_struct floppy_tq;static void schedule_bh( void (*handler)(void*) ){	floppy_tq.routine = (void *)(void *) handler;	queue_task(&floppy_tq, &tq_immediate);	mark_bh(IMMEDIATE_BH);}static struct timer_list fd_timer;static void cancel_activity(void){

⌨️ 快捷键说明

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