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

📄 floppy.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 3 页
字号:
	output_byte(1);}static void floppy_ready(void){	if (inb(FD_DIR) & 0x80) {		changed_floppies |= 1<<current_drive;		buffer_track = -1;		if (keep_data[current_drive]) {			if (keep_data[current_drive] > 0)				keep_data[current_drive]--;		} else {			if (ftd_msg[current_drive] && current_type[current_drive] != NULL)				printk("Disk type is undefined after disk "				    "change in fd%d\n",current_drive);			current_type[current_drive] = NULL;			floppy_sizes[current_drive] = MAX_DISK_SIZE;		}/* Forcing the drive to seek makes the "media changed" condition go away. * There should be a cleaner solution for that ... */		if (!reset && !recalibrate) {			if (current_track && current_track != NO_TRACK)				do_floppy = shake_zero;			else				do_floppy = shake_one;			output_byte(FD_RECALIBRATE);			output_byte(head<<2 | current_drive);			return;		}	}	if (reset) {		reset_floppy();		return;	}	if (recalibrate) {		recalibrate_floppy();		return;	}	transfer();}static void setup_format_params(void){    unsigned char *here = (unsigned char *) tmp_floppy_area;    int count,head_shift,track_shift,total_shift;    /* allow for about 30ms for data transport per track */    head_shift  = floppy->sect / 6;    /* a ``cylinder'' is two tracks plus a little stepping time */    track_shift = 2 * head_shift + 1;     /* count backwards */    total_shift = floppy->sect - 	((track_shift * track + head_shift * head) % floppy->sect);    /* XXX: should do a check to see this fits in tmp_floppy_area!! */    for (count = 0; count < floppy->sect; count++) {	*here++ = track;	*here++ = head;	*here++ = 1 + (( count + total_shift ) % floppy->sect);	*here++ = 2; /* 512 bytes */    }}static void redo_fd_request(void){	unsigned int block;	char * buffer_area;	int device;	if (CURRENT && CURRENT->dev < 0) return;repeat:	if (format_status == FORMAT_WAIT)		format_status = FORMAT_BUSY;	if (format_status != FORMAT_BUSY) {		if (!CURRENT) {			if (!fdc_busy)				printk("FDC access conflict!");			fdc_busy = 0;			wake_up(&fdc_wait);			CLEAR_INTR;			return;		}		if (MAJOR(CURRENT->dev) != MAJOR_NR)			panic(DEVICE_NAME ": request list destroyed"); \		if (CURRENT->bh) {			if (!CURRENT->bh->b_lock)				panic(DEVICE_NAME ": block not locked");		}	}	seek = 0;	probing = 0;	device = MINOR(CURRENT_DEVICE);	if (device > 3)		floppy = (device >> 2) + floppy_type;	else { /* Auto-detection */		floppy = current_type[device & 3];		if (!floppy) {			probing = 1;			floppy = base_type[device & 3];			if (!floppy) {				request_done(0);				goto repeat;			}			if (CURRENT_ERRORS & 1)				floppy++;		}	}	if (format_status != FORMAT_BUSY) {		if (current_drive != CURRENT_DEV) {			current_track = NO_TRACK;			current_drive = CURRENT_DEV;		}		block = CURRENT->sector;		if (block+2 > floppy->size) {			request_done(0);			goto repeat;		}		sector = block % floppy->sect;		block /= floppy->sect;		head = block % floppy->head;		track = block / floppy->head;		seek_track = track << floppy->stretch;		if (CURRENT->cmd == READ)			command = FD_READ;		else if (CURRENT->cmd == WRITE)			command = FD_WRITE;		else {			printk("do_fd_request: unknown command\n");			request_done(0);			goto repeat;		}	} else {		if (current_drive != (format_req.device & 3))			current_track = NO_TRACK;		current_drive = format_req.device & 3;		if (((unsigned) format_req.track) >= floppy->track ||		    (format_req.head & 0xfffe) || probing) {			request_done(0);			goto repeat;		}		head = format_req.head;		track = format_req.track;		seek_track = track << floppy->stretch;		if (seek_track == buffer_track) buffer_track = -1;		command = FD_FORMAT;		setup_format_params();	}	timer_table[FLOPPY_TIMER].expires = jiffies+10*HZ;	timer_active |= 1 << FLOPPY_TIMER;	if ((seek_track == buffer_track) &&	 (current_drive == buffer_drive)) {		buffer_area = floppy_track_buffer +			((sector + head*floppy->sect)<<9);		if (command == FD_READ) {			copy_buffer(buffer_area,CURRENT->buffer);			request_done(1);			goto repeat;		} else if (command == FD_WRITE)			copy_buffer(CURRENT->buffer,buffer_area);	}	if (seek_track != current_track)		seek = 1;	sector++;	del_timer(motor_off_timer + current_drive);	floppy_on(current_drive);}void do_fd_request(void){	cli();	while (fdc_busy) sleep_on(&fdc_wait);	fdc_busy = 1;	sti();	redo_fd_request();}static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,    unsigned long param){	int i,drive,cnt,okay;	struct floppy_struct *this_floppy;	switch (cmd) {		RO_IOCTLS(inode->i_rdev,param);	}	drive = MINOR(inode->i_rdev);	switch (cmd) {		case FDFMTBEG:			if (!suser())				return -EPERM;			return 0;		case FDFMTEND:			if (!suser())				return -EPERM;			cli();			fake_change |= 1 << (drive & 3);			sti();			drive &= 3;			cmd = FDCLRPRM;			break;		case FDGETPRM:			if (drive > 3) this_floppy = &floppy_type[drive >> 2];			else if ((this_floppy = current_type[drive & 3]) == NULL)				    return -ENODEV;			i = verify_area(VERIFY_WRITE,(void *) param,sizeof(struct floppy_struct));			if (i)				return i;			for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)				put_fs_byte(((char *) this_floppy)[cnt],				    (char *) param+cnt);			return 0;		case FDFMTTRK:			if (!suser())				return -EPERM;			if (fd_ref[drive & 3] != 1)				return -EBUSY;			cli();			while (format_status != FORMAT_NONE)				sleep_on(&format_done);			for (cnt = 0; cnt < sizeof(struct format_descr); cnt++)				((char *) &format_req)[cnt] = get_fs_byte(				    (char *) param+cnt);			format_req.device = drive;			format_status = FORMAT_WAIT;			format_errors = 0;			while (format_status != FORMAT_OKAY && format_status !=			    FORMAT_ERROR) {				if (fdc_busy) sleep_on(&fdc_wait);				else {					fdc_busy = 1;					redo_fd_request();				}			}			while (format_status != FORMAT_OKAY && format_status !=			    FORMAT_ERROR)				sleep_on(&format_done);			sti();			okay = format_status == FORMAT_OKAY;			format_status = FORMAT_NONE;			floppy_off(drive & 3);			wake_up(&format_done);			return okay ? 0 : -EIO;		case FDFLUSH:			if (!permission(inode, 2))				return -EPERM;			cli();			fake_change |= 1 << (drive & 3);			sti();			check_disk_change(inode->i_rdev);			return 0; 	}	if (!suser())		return -EPERM;	if (drive < 0 || drive > 3)		return -EINVAL;	switch (cmd) {		case FDCLRPRM:			current_type[drive] = NULL;			floppy_sizes[drive] = MAX_DISK_SIZE;			keep_data[drive] = 0;			break;		case FDSETPRM:		case FDDEFPRM:			memcpy_fromfs(user_params+drive,				(void *) param,				sizeof(struct floppy_struct));			current_type[drive] = &user_params[drive];			floppy_sizes[drive] = user_params[drive].size >> 1;			if (cmd == FDDEFPRM)				keep_data[drive] = -1;			else {				cli();				while (fdc_busy) sleep_on(&fdc_wait);				fdc_busy = 1;				sti();				outb_p((current_DOR & 0xfc) | drive |				    (0x10 << drive),FD_DOR);				for (cnt = 0; cnt < 1000; cnt++) __asm__("nop");				if (inb(FD_DIR) & 0x80)					keep_data[drive] = 1;				else					keep_data[drive] = 0;				outb_p(current_DOR,FD_DOR);				fdc_busy = 0;				wake_up(&fdc_wait);			}			break;		case FDMSGON:			ftd_msg[drive] = 1;			break;		case FDMSGOFF:			ftd_msg[drive] = 0;			break;		case FDSETEMSGTRESH:			min_report_error_cnt[drive] = (unsigned short) (param & 0x0f);			break;		default:			return -EINVAL;	}	return 0;}#define CMOS_READ(addr) ({ \outb_p(addr,0x70); \inb_p(0x71); \})static struct floppy_struct *find_base(int drive,int code){	struct floppy_struct *base;	if (code > 0 && code < 5) {		base = &floppy_types[(code-1)*2];		printk("fd%d is %s",drive,base->name);		return base;	}	printk("fd%d is unknown type %d",drive,code);	return NULL;}static void config_types(void){	printk("Floppy drive(s): ");	base_type[0] = find_base(0,(CMOS_READ(0x10) >> 4) & 15);	if (((CMOS_READ(0x14) >> 6) & 1) == 0)		base_type[1] = NULL;	else {		printk(", ");		base_type[1] = find_base(1,CMOS_READ(0x10) & 15);	}	base_type[2] = base_type[3] = NULL;	printk("\n");}/* * floppy_open check for aliasing (/dev/fd0 can be the same as * /dev/PS0 etc), and disallows simultaneous access to the same * drive with different device numbers. */static int floppy_open(struct inode * inode, struct file * filp){	int drive;	int old_dev;	drive = inode->i_rdev & 3;	old_dev = fd_device[drive];	if (fd_ref[drive])		if (old_dev != inode->i_rdev)			return -EBUSY;	fd_ref[drive]++;	fd_device[drive] = inode->i_rdev;	buffer_drive = buffer_track = -1;	if (old_dev && old_dev != inode->i_rdev)		invalidate_buffers(old_dev);	if (filp && filp->f_mode)		check_disk_change(inode->i_rdev);	return 0;}static void floppy_release(struct inode * inode, struct file * filp){	sync_dev(inode->i_rdev);	if (!fd_ref[inode->i_rdev & 3]--) {		printk("floppy_release with fd_ref == 0");		fd_ref[inode->i_rdev & 3] = 0;	}}static struct file_operations floppy_fops = {	NULL,			/* lseek - default */	block_read,		/* read - general block-dev read */	block_write,		/* write - general block-dev write */	NULL,			/* readdir - bad */	NULL,			/* select */	fd_ioctl,		/* ioctl */	NULL,			/* mmap */	floppy_open,		/* open */	floppy_release,		/* release */	block_fsync		/* fsync */};/* * The version command is not supposed to generate an interrupt, but * my FDC does, except when booting in SVGA screen mode. * When it does generate an interrupt, it doesn't return any status bytes. * It appears to have something to do with the version command... * * This should never be called, because of the reset after the version check. */static void ignore_interrupt(void){	printk(DEVICE_NAME ": weird interrupt ignored (%d)\n", result());	reset = 1;	CLEAR_INTR;	/* ignore only once */}static void floppy_interrupt(int unused){	void (*handler)(void) = DEVICE_INTR;	DEVICE_INTR = NULL;	if (!handler)		handler = unexpected_floppy_interrupt;	handler();}/* * This is the floppy IRQ description. The SA_INTERRUPT in sa_flags * means we run the IRQ-handler with interrupts disabled. */static struct sigaction floppy_sigaction = {	floppy_interrupt,	0,	SA_INTERRUPT,	NULL};void floppy_init(void){	outb(current_DOR,FD_DOR);	if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {		printk("Unable to get major %d for floppy\n",MAJOR_NR);		return;	}	blk_size[MAJOR_NR] = floppy_sizes;	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;	timer_table[FLOPPY_TIMER].fn = floppy_shutdown;	timer_active &= ~(1 << FLOPPY_TIMER);	config_types();	if (irqaction(FLOPPY_IRQ,&floppy_sigaction))		printk("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ);	if (request_dma(FLOPPY_DMA))		printk("Unable to grab DMA%d for the floppy driver\n", FLOPPY_DMA);	/* Try to determine the floppy controller type */	DEVICE_INTR = ignore_interrupt;	/* don't ask ... */	output_byte(FD_VERSION);	/* get FDC version code */	if (result() != 1) {		printk(DEVICE_NAME ": FDC failed to return version byte\n");		fdc_version = FDC_TYPE_STD;	} else		fdc_version = reply_buffer[0];	if (fdc_version != FDC_TYPE_STD) 		printk(DEVICE_NAME ": FDC version 0x%x\n", fdc_version);#ifndef FDC_FIFO_UNTESTED	fdc_version = FDC_TYPE_STD;	/* force std fdc type; can't test other. */#endif	/* Not all FDCs seem to be able to handle the version command	 * properly, so force a reset for the standard FDC clones,	 * to avoid interrupt garbage.	 */	if (fdc_version == FDC_TYPE_STD) {		initial_reset_flag = 1;		reset_floppy();	}}

⌨️ 快捷键说明

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