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

📄 mfmhd.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Tell the user about the drive if we decided it exists. */static void mfm_geometry (int drive){	if (mfm_info[drive].cylinders)		printk ("mfm%c: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n", 'a' + drive,			mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 4096,			mfm_info[drive].cylinders, mfm_info[drive].heads, mfm_info[drive].sectors,			mfm_info[drive].lowcurrent, mfm_info[drive].precomp);}#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT/* * Attempt to detect a drive and find its geometry.  The drive has already been * specified... * * We first recalibrate the disk, then try to probe sectors, heads and then * cylinders.  NOTE! the cylinder probe may break drives.  The xd disk driver * does something along these lines, so I assume that most drives are up to * this mistreatment... */static int mfm_detectdrive (int drive){	unsigned int mingeo[3], maxgeo[3];	unsigned int attribute, need_recal = 1;	unsigned char cmdb[8];	memset (mingeo, 0, sizeof (mingeo));	maxgeo[0] = mfm_info[drive].sectors;	maxgeo[1] = mfm_info[drive].heads;	maxgeo[2] = mfm_info[drive].cylinders;	cmdb[0] = drive + 1;	cmdb[6] = 0;	cmdb[7] = 1;	for (attribute = 0; attribute < 3; attribute++) {		while (mingeo[attribute] != maxgeo[attribute]) {			unsigned int variable;			variable = (maxgeo[attribute] + mingeo[attribute]) >> 1;			cmdb[1] = cmdb[2] = cmdb[3] = cmdb[4] = cmdb[5] = 0;			if (need_recal) {				int tries = 5;				do {					issue_command (CMD_RCLB, cmdb, 2);					wait_for_completion ();					wait_for_command_end ();					if  (result[1] == 0x20)						break;				} while (result[1] && --tries);				if (result[1]) {					outw (CMD_RCAL, MFM_COMMAND);					return 0;				}				need_recal = 0;			}			switch (attribute) {			case 0:				cmdb[5] = variable;				issue_command (CMD_CMPD, cmdb, 8);				break;			case 1:				cmdb[1] = variable;				cmdb[4] = variable;				issue_command (CMD_CMPD, cmdb, 8);				break;			case 2:				cmdb[2] = variable >> 8;				cmdb[3] = variable;				issue_command (CMD_SEK, cmdb, 4);				break;			}			wait_for_completion ();			wait_for_command_end ();			switch (result[1]) {			case 0x00:			case 0x50:				mingeo[attribute] = variable + 1;				break;			case 0x20:				outw (CMD_RCAL, MFM_COMMAND);				return 0;			case 0x24:				need_recal = 1;			default:				maxgeo[attribute] = variable;				break;			}		}	}	mfm_info[drive].cylinders  = mingeo[2];	mfm_info[drive].lowcurrent = mingeo[2];	mfm_info[drive].precomp    = mingeo[2] / 2;	mfm_info[drive].heads 	   = mingeo[1];	mfm_info[drive].sectors	   = mingeo[0];	outw (CMD_RCAL, MFM_COMMAND);	return 1;}#endif/* * Initialise all drive information for this controller. */static int mfm_initdrives(void){	int drive;	if (number_mfm_drives > MFM_MAXDRIVES) {		number_mfm_drives = MFM_MAXDRIVES;		printk("No. of ADFS MFM drives is greater than MFM_MAXDRIVES - you can't have that many!\n");	}	for (drive = 0; drive < number_mfm_drives; drive++) {		mfm_info[drive].lowcurrent = 1;		mfm_info[drive].precomp    = 1;		mfm_info[drive].cylinder   = -1;		mfm_info[drive].errors.recal  = 0;		mfm_info[drive].errors.report = 0;		mfm_info[drive].errors.abort  = 4;#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT		mfm_info[drive].cylinders  = 1024;		mfm_info[drive].heads	   = 8;		mfm_info[drive].sectors	   = 64;		{			unsigned char cmdb[16];			mfm_setupspecify (drive, cmdb);			cmdb[1] &= ~0x81;			issue_command (CMD_SPC, cmdb, 16);			wait_for_completion ();			if (!mfm_detectdrive (drive)) {				mfm_info[drive].cylinders = 0;				mfm_info[drive].heads     = 0;				mfm_info[drive].sectors   = 0;			}			cmdb[0] = cmdb[1] = 0;			issue_command (CMD_CKV, cmdb, 2);		}#else		mfm_info[drive].cylinders  = 1;	/* its going to have to figure it out from the partition info */		mfm_info[drive].heads      = 4;		mfm_info[drive].sectors    = 32;#endif	}	return number_mfm_drives;}/* * The 'front' end of the mfm driver follows... */static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg){	struct hd_geometry *geo = (struct hd_geometry *) arg;	kdev_t dev;	int device, major, minor, err;	if (!inode || !(dev = inode->i_rdev))		return -EINVAL;	major = MAJOR(dev);	minor = MINOR(dev);	device = DEVICE_NR(MINOR(inode->i_rdev)), err;	if (device >= mfm_drives)		return -EINVAL;	switch (cmd) {	case HDIO_GETGEO:		if (!arg)			return -EINVAL;		if (put_user (mfm_info[device].heads, &geo->heads))			return -EFAULT;		if (put_user (mfm_info[device].sectors, &geo->sectors))			return -EFAULT;		if (put_user (mfm_info[device].cylinders, &geo->cylinders))			return -EFAULT;		if (put_user (mfm[minor].start_sect, &geo->start))			return -EFAULT;		return 0;	case BLKFRASET:		if (!capable(CAP_SYS_ADMIN))			return -EACCES;		max_readahead[major][minor] = arg;		return 0;	case BLKFRAGET:		return put_user(max_readahead[major][minor], (long *) arg);	case BLKSECTGET:		return put_user(max_sectors[major][minor], (long *) arg);	case BLKRRPART:		if (!capable(CAP_SYS_ADMIN))			return -EACCES;		return mfm_reread_partitions(dev);	case BLKGETSIZE:	case BLKGETSIZE64:	case BLKFLSBUF:	case BLKROSET:	case BLKROGET:	case BLKRASET:	case BLKRAGET:	case BLKPG:		return blk_ioctl(dev, cmd, arg);	default:		return -EINVAL;	}}static int mfm_open(struct inode *inode, struct file *file){	int dev = DEVICE_NR(MINOR(inode->i_rdev));	if (dev >= mfm_drives)		return -ENODEV;	while (mfm_info[dev].busy)		sleep_on (&mfm_wait_open);	mfm_info[dev].access_count++;	return 0;}/* * Releasing a block device means we sync() it, so that it can safely * be forgotten about... */static int mfm_release(struct inode *inode, struct file *file){	mfm_info[DEVICE_NR(MINOR(inode->i_rdev))].access_count--;	return 0;}/* * This is to handle various kernel command line parameters * specific to this driver. */void mfm_setup(char *str, int *ints){	return;}/* * Set the CHS from the ADFS boot block if it is present.  This is not ideal * since if there are any non-ADFS partitions on the disk, this won't work! * Hence, I want to get rid of this... */void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads,		     unsigned long discsize, unsigned int secsize){	int drive = MINOR(dev) >> 6;	if (mfm_info[drive].cylinders == 1) {		mfm_info[drive].sectors = secsptrack;		mfm_info[drive].heads = heads;		mfm_info[drive].cylinders = discsize / (secsptrack * heads * secsize);		if ((heads < 1) || (mfm_info[drive].cylinders > 1024)) {			printk("mfm%c: Insane disc shape! Setting to 512/4/32\n",'a' + (dev >> 6));			/* These values are fairly arbitary, but are there so that if your			 * lucky you can pick apart your disc to find out what is going on -			 * I reckon these figures won't hurt MOST drives			 */			mfm_info[drive].sectors = 32;			mfm_info[drive].heads = 4;			mfm_info[drive].cylinders = 512;		}		if (raw_cmd.dev == drive)			mfm_specify ();		mfm_geometry (drive);		mfm[drive << 6].start_sect = 0;		mfm[drive << 6].nr_sects = mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 2;	}}static struct gendisk mfm_gendisk = {	major:		MAJOR_NR,	major_name:	"mfm",	minor_shift:	6,	max_p:		1 << 6,	part:		mfm,	sizes:		mfm_sizes,	real_devices:	(void *)mfm_info,};static struct block_device_operations mfm_fops ={	owner:		THIS_MODULE,	open:		mfm_open,	release:	mfm_release,	ioctl:		mfm_ioctl,};static void mfm_geninit (void){	int i;	for (i = 0; i < (MFM_MAXDRIVES << 6); i++) {		/* Can't increase this - if you do all hell breaks loose */		mfm_blocksizes[i] = 1024;		mfm_sectsizes[i] = 512;	}	blksize_size[MAJOR_NR] = mfm_blocksizes;	hardsect_size[MAJOR_NR] = mfm_sectsizes;	mfm_drives = mfm_initdrives();	printk("mfm: detected %d hard drive%s\n", mfm_drives,				mfm_drives == 1 ? "" : "s");	mfm_gendisk.nr_real = mfm_drives;	if (request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL))		printk("mfm: unable to get IRQ%d\n", mfm_irq);	if (mfm_irqenable)		outw(0x80, mfm_irqenable);	/* Required to enable IRQs from MFM podule */	for (i = 0; i < mfm_drives; i++) {		mfm_geometry (i);		register_disk(&mfm_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6,				&mfm_fops,				mfm_info[i].cylinders * mfm_info[i].heads *				mfm_info[i].sectors / 2);	}}static struct expansion_card *ecs;/* * See if there is a controller at the address presently at mfm_addr * * We check to see if the controller is busy - if it is, we abort it first, * and check that the chip is no longer busy after at least 180 clock cycles. * We then issue a command and check that the BSY or CPR bits are set. */static int mfm_probecontroller (unsigned int mfm_addr){	if (inw (MFM_STATUS) & STAT_BSY) {		outw (CMD_ABT, MFM_COMMAND);		udelay (50);		if (inw (MFM_STATUS) & STAT_BSY)			return 0;	}	if (inw (MFM_STATUS) & STAT_CED)		outw (CMD_RCAL, MFM_COMMAND);	outw (CMD_SEK, MFM_COMMAND);	if (inw (MFM_STATUS) & (STAT_BSY | STAT_CPR)) {		unsigned int count = 2000;		while (inw (MFM_STATUS) & STAT_BSY) {			udelay (500);			if (!--count)				return 0;		}		outw (CMD_RCAL, MFM_COMMAND);	}	return 1;}/* * Look for a MFM controller - first check the motherboard, then the podules * The podules have an extra interrupt enable that needs to be played with * * The HDC is accessed at MEDIUM IOC speeds. */int mfm_init (void){	unsigned char irqmask;	if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) {		mfm_addr	= ONBOARD_MFM_ADDRESS;		mfm_IRQPollLoc	= IOC_IRQSTATB;		mfm_irqenable	= 0;		mfm_irq		= IRQ_HARDDISK;		irqmask		= 0x08;			/* IL3 pin */	} else {		ecs = ecard_find(0, mfm_cids);		if (!ecs) {			mfm_addr = 0;			return -1;		}		mfm_addr	= ecard_address(ecs, ECARD_IOC, ECARD_MEDIUM) + 0x800;		mfm_IRQPollLoc	= ioaddr(mfm_addr + 0x400);		mfm_irqenable	= mfm_IRQPollLoc;		mfm_irq		= ecs->irq;		irqmask		= 0x08;		ecard_claim(ecs);	}	printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);	if (!request_region (mfm_addr, 10, "mfm")) {		ecard_release(ecs);		return -1;	}	if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) {		printk("mfm_init: unable to get major number %d\n", MAJOR_NR);		ecard_release(ecs);		release_region(mfm_addr, 10);		return -1;	}	/* Stuff for the assembler routines to get to */	hdc63463_baseaddress	= ioaddr(mfm_addr);	hdc63463_irqpolladdress	= mfm_IRQPollLoc;	hdc63463_irqpollmask	= irqmask;	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);	read_ahead[MAJOR_NR] = 8;	/* 8 sector (4kB?) read ahread */	add_gendisk(&mfm_gendisk);	Busy = 0;	lastspecifieddrive = -1;	mfm_geninit();	return 0;}/* * This routine is called to flush all partitions and partition tables * for a changed MFM disk, and then re-read the new partition table. * If we are revalidating due to an ioctl, we have USAGE == 1. */static int mfm_reread_partitions(kdev_t dev){	unsigned int start, i, maxp, target = DEVICE_NR(MINOR(dev));	unsigned long flags;	save_flags_cli(flags);	if (mfm_info[target].busy || mfm_info[target].access_count > 1) {		restore_flags (flags);		return -EBUSY;	}	mfm_info[target].busy = 1;	restore_flags (flags);	maxp = mfm_gendisk.max_p;	start = target << mfm_gendisk.minor_shift;	for (i = maxp - 1; i >= 0; i--) {		int minor = start + i;		invalidate_device (MKDEV(MAJOR_NR, minor), 1);		mfm_gendisk.part[minor].start_sect = 0;		mfm_gendisk.part[minor].nr_sects = 0;	}	/* Divide by 2, since sectors are 2 times smaller than usual ;-) */	grok_partitions(&mfm_gendisk, target, 1<<6, mfm_info[target].heads *		    mfm_info[target].cylinders * mfm_info[target].sectors / 2);	mfm_info[target].busy = 0;	wake_up (&mfm_wait_open);	return 0;}#ifdef MODULEEXPORT_NO_SYMBOLS;MODULE_LICENSE("GPL");int init_module(void){	return mfm_init();}void cleanup_module(void){	if (ecs && mfm_irqenable)		outw (0, mfm_irqenable);	/* Required to enable IRQs from MFM podule */	free_irq(mfm_irq, NULL);	unregister_blkdev(MAJOR_NR, "mfm");	del_gendisk(&mfm_gendisk);	if (ecs)		ecard_release(ecs);	if (mfm_addr)		release_region(mfm_addr, 10);}#endif

⌨️ 快捷键说明

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