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

📄 floppy.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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(current_reqD, "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 = NULL;	command_status += 2;	wake_up(&command_done);}static struct cont_t wakeup_cont = {	.interrupt	= empty,	.redo		= do_wakeup,	.error		= empty,	.done		= (done_f) empty};static struct cont_t intr_cont = {	.interrupt	= empty,	.redo		= process_fd_request,	.error		= empty,	.done		= (done_f) empty};static int wait_til_done(void (*handler) (void), int interruptible){	int ret;	schedule_bh(handler);	if (command_status < 2 && NO_SIGNAL) {		DECLARE_WAITQUEUE(wait, current);		add_wait_queue(&command_done, &wait);		for (;;) {			set_current_state(interruptible ?					  TASK_INTERRUPTIBLE :					  TASK_UNINTERRUPTIBLE);			if (command_status >= 2 || !NO_SIGNAL)				break;			is_alive("wait_til_done");			schedule();		}		set_current_state(TASK_RUNNING);		remove_wait_queue(&command_done, &wait);	}	if (command_status < 2) {		cancel_activity();		cont = &intr_cont;		reset_fdc();		return -EINTR;	}	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;	probed_format = DRS->probed_format;	while (1) {		if (probed_format >= 8 || !DP->autodetect[probed_format]) {			DRS->probed_format = 0;			return 1;		}		if (floppy_type[DP->autodetect[probed_format]].sect) {			DRS->probed_format = probed_format;			return 0;		}		probed_format++;	}}static void bad_flp_intr(void){	int err_count;	if (probing) {		DRS->probed_format++;		if (!next_valid_format())			return;	}	err_count = ++(*errors);	INFBOUND(DRWE->badness, err_count);	if (err_count > DP->max_errors.abort)		cont->done(0);	if (err_count > DP->max_errors.reset)		FDCS->reset = 1;	else if (err_count > DP->max_errors.recal)		DRS->track = NEED_2_RECAL;}static void set_floppy(int drive){	int type = ITYPE(UDRS->fd_device);	if (type)		_floppy = floppy_type + type;	else		_floppy = current_type[drive];}/* * formatting support. * =================== */static void format_interrupt(void){	switch (interpret_errors()) {	case 1:		cont->error();	case 2:		break;	case 0:		cont->done(1);	}	cont->redo();}#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)#define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80) >>1))#define CT(x) ((x) | 0xc0)static void setup_format_params(int track){	struct fparm {		unsigned char track, head, sect, size;	} *here = (struct fparm *)floppy_track_buffer;	int il, n;	int count, head_shift, track_shift;	raw_cmd = &default_raw_cmd;	raw_cmd->track = track;	raw_cmd->flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |	    FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;	raw_cmd->rate = _floppy->rate & 0x43;	raw_cmd->cmd_count = NR_F;	COMMAND = FM_MODE(_floppy, FD_FORMAT);	DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);	F_SIZECODE = FD_SIZECODE(_floppy);	F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;	F_GAP = _floppy->fmt_gap;	F_FILL = FD_FILL_BYTE;	raw_cmd->kernel_data = floppy_track_buffer;	raw_cmd->length = 4 * F_SECT_PER_TRACK;	/* allow for about 30ms for data transport per track */	head_shift = (F_SECT_PER_TRACK + 5) / 6;	/* a ``cylinder'' is two tracks plus a little stepping time */	track_shift = 2 * head_shift + 3;	/* position of logical sector 1 on this track */	n = (track_shift * format_req.track + head_shift * format_req.head)	    % F_SECT_PER_TRACK;	/* determine interleave */	il = 1;	if (_floppy->fmt_gap < 0x22)		il++;	/* initialize field */	for (count = 0; count < F_SECT_PER_TRACK; ++count) {		here[count].track = format_req.track;		here[count].head = format_req.head;		here[count].sect = 0;		here[count].size = F_SIZECODE;	}	/* place logical sectors */	for (count = 1; count <= F_SECT_PER_TRACK; ++count) {		here[n].sect = count;		n = (n + il) % F_SECT_PER_TRACK;		if (here[n].sect) {	/* sector busy, find next free sector */			++n;			if (n >= F_SECT_PER_TRACK) {				n -= F_SECT_PER_TRACK;				while (here[n].sect)					++n;			}		}	}	if (_floppy->stretch & FD_ZEROBASED) {		for (count = 0; count < F_SECT_PER_TRACK; count++)			here[count].sect--;	}}static void redo_format(void){	buffer_track = -1;	setup_format_params(format_req.track << STRETCH(_floppy));	floppy_start();	debugt("queue format request");}static struct cont_t format_cont = {	.interrupt	= format_interrupt,	.redo		= redo_format,	.error		= bad_flp_intr,	.done		= generic_done};static int do_format(int drive, struct format_descr *tmp_format_req){	int ret;	LOCK_FDC(drive, 1);	set_floppy(drive);	if (!_floppy ||	    _floppy->track > DP->tracks ||	    tmp_format_req->track >= _floppy->track ||	    tmp_format_req->head >= _floppy->head ||	    (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||	    !_floppy->fmt_gap) {		process_fd_request();		return -EINVAL;	}	format_req = *tmp_format_req;	format_errors = 0;	cont = &format_cont;	errors = &format_errors;	IWAIT(redo_format);	process_fd_request();	return ret;}/* * Buffer read/write and support * ============================= */static void floppy_end_request(struct request *req, int uptodate){	unsigned int nr_sectors = current_count_sectors;	/* current_count_sectors can be zero if transfer failed */	if (!uptodate)		nr_sectors = req->current_nr_sectors;	if (end_that_request_first(req, uptodate, nr_sectors))		return;	add_disk_randomness(req->rq_disk);	floppy_off((long)req->rq_disk->private_data);	blkdev_dequeue_request(req);	end_that_request_last(req);	/* We're done with the request */	current_req = NULL;}/* new request_done. Can handle physical sectors which are smaller than a * logical buffer */static void request_done(int uptodate){	struct request_queue *q = floppy_queue;	struct request *req = current_req;	unsigned long flags;	int block;	probing = 0;	reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate);	if (!req) {		printk("floppy.c: no request in request_done\n");		return;	}	if (uptodate) {		/* maintain values for invalidation on geometry		 * change */		block = current_count_sectors + req->sector;		INFBOUND(DRS->maxblock, block);		if (block > _floppy->sect)			DRS->maxtrack = 1;		/* unlock chained buffers */		spin_lock_irqsave(q->queue_lock, flags);		floppy_end_request(req, 1);		spin_unlock_irqrestore(q->queue_lock, flags);	} else {		if (rq_data_dir(req) == WRITE) {			/* record write error information */			DRWE->write_errors++;			if (DRWE->write_errors == 1) {				DRWE->first_error_sector = req->sector;				DRWE->first_error_generation = DRS->generation;			}			DRWE->last_error_sector = req->sector;			DRWE->last_error_generation = DRS->generation;		}		spin_lock_irqsave(q->queue_lock, flags);		floppy_end_request(req, 0);		spin_unlock_irqrestore(q->queue_lock, flags);	}}/* Interrupt handler evaluating the result of the r/w operation */static void rw_interrupt(void){	int nr_sectors, ssize, eoc, heads;	if (R_HEAD >= 2) {		/* some Toshiba floppy controllers occasionnally seem to		 * return bogus interrupts after read/write operations, which		 * can be recognized by a bad head number (>= 2) */		return;	}	if (!DRS->first_read_date)		DRS->first_read_date = jiffies;	nr_sectors = 0;	CODE2SIZE;	if (ST1 & ST1_EOC)		eoc = 1;	else		eoc = 0;	if (COMMAND & 0x80)		heads = 2;	else		heads = 1;	nr_sectors = (((R_TRACK - TRACK) * heads +		       R_HEAD - HEAD) * SECT_PER_TRACK +		      R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;#ifdef FLOPPY_SANITY_CHECK	if (nr_sectors / ssize >	    (in_sector_offset + current_count_sectors + ssize - 1) / ssize) {		DPRINT("long rw: %x instead of %lx\n",		       nr_sectors, current_count_sectors);		printk("rs=%d s=%d\n", R_SECTOR, SECTOR);		printk("rh=%d h=%d\n", R_HEAD, HEAD);		printk("rt=%d t=%d\n", R_TRACK, TRACK);		printk("heads=%d eoc=%d\n", heads, eoc);		printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK,		       fsector_t, ssize);		printk("in_sector_offset=%d\n", in_sector_offset);	}#endif	nr_sectors -= in_sector_offset;	INFBOUND(nr_sectors, 0);	SUPBOUND(current_count_sectors, nr_sectors);	switch (interpret_errors()) {	case 2:		cont->redo();		return;	case 1:		if (!current_count_sectors) {			cont->error();			cont->redo();			return;		}		break;	case 0:		if (!current_count_sectors) {			cont->redo();			return;		}		current_type[current_drive] = _floppy;		floppy_sizes[TOMINOR(current_drive)] = _floppy->size;		break;	}	if (probing) {		if (DP->flags & FTD_MSG)			DPRINT("Auto-detected floppy type %s in fd%d\n",			       _floppy->name, current_drive);		current_type[current_drive] = _floppy;		floppy_sizes[TOMINOR(current_drive)] = _floppy->size;		probing = 0;	}	if (CT(COMMAND) != FD_READ ||	    raw_cmd->kernel_data == current_req->buffer) {		/* transfer directly from buffer */		cont->done(1);	} else if (CT(COMMAND) == FD_READ) {		buffer_track = raw_cmd->track;		buffer_drive = current_drive;		INFBOUND(buffer_max, nr_sectors + fsector_t);	}	cont->redo();}/* Compute max

⌨️ 快捷键说明

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