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

📄 mfmhd.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
}static void do_mfm_request(request_queue_t *q){	DBG("do_mfm_request: about to mfm_request\n");	mfm_request();}static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs){	void (*handler) (void) = do_mfm;	do_mfm = NULL;	DBG("mfm_interrupt_handler (handler=0x%p)\n", handler);	mfm_status = inw(MFM_STATUS);	/* If CPR (Command Parameter Reject) and not busy it means that the command	   has some return message to give us */	if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) {		int len = 0;		while (len < 16) {			int in;			in = inw(MFM_DATAIN);			result[len++] = in >> 8;			result[len++] = in;		}	}	if (handler) {		handler();		return;	}	outw (CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */	printk ("mfm: unexpected interrupt - status = ");	print_status ();	while (1);}/* * Tell the user about the drive if we decided it exists. */static void mfm_geometry(int drive){	struct mfm_info *p = mfm_info + drive;	struct gendisk *disk = mfm_gendisk[drive];	disk->private_data = p;	if (p->cylinders)		printk ("%s: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n",			disk->disk_name,			p->cylinders * p->heads * p->sectors / 4096,			p->cylinders, p->heads, p->sectors,			p->lowcurrent, p->precomp);	set_capacity(disk, p->cylinders * p->heads * p->sectors / 2);}#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 mfm_info *p = inode->i_bdev->bd_disk->private_data;	struct hd_geometry *geo = (struct hd_geometry *) arg;	if (cmd != HDIO_GETGEO)		return -EINVAL;	if (!arg)		return -EINVAL;	if (put_user (p->heads, &geo->heads))		return -EFAULT;	if (put_user (p->sectors, &geo->sectors))		return -EFAULT;	if (put_user (p->cylinders, &geo->cylinders))		return -EFAULT;	if (put_user (get_start_sect(inode->i_bdev), &geo->start))		return -EFAULT;	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(struct block_device *bdev, unsigned char secsptrack,			unsigned char heads, unsigned int secsize){	struct mfm_info *p = bdev->bd_disk->private_data;	int drive = p - mfm_info;	unsigned long disksize = bdev->bd_inode->i_size;	if (p->cylinders == 1) {		p->sectors = secsptrack;		p->heads = heads;		p->cylinders = discsize / (secsptrack * heads * secsize);		if ((heads < 1) || (p->cylinders > 1024)) {			printk("%s: Insane disc shape! Setting to 512/4/32\n",				bdev->bd_disk->disk_name);			/* 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			 */			p->sectors = 32;			p->heads = 4;			p->cylinders = 512;		}		if (raw_cmd.dev == drive)			mfm_specify ();		mfm_geometry (drive);	}}static struct block_device_operations mfm_fops ={	.owner		= THIS_MODULE,	.ioctl		= mfm_ioctl,};/* * 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;}static int mfm_do_init(unsigned char irqmask){	int i, ret;	printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);	ret = -EBUSY;	if (!request_region (mfm_addr, 10, "mfm"))		goto out1;	ret = register_blkdev(MAJOR_NR, "mfm");	if (ret)		goto out2;	/* Stuff for the assembler routines to get to */	hdc63463_baseaddress	= ioaddr(mfm_addr);	hdc63463_irqpolladdress	= mfm_IRQPollLoc;	hdc63463_irqpollmask	= irqmask;	mfm_queue = blk_init_queue(do_mfm_request, &mfm_lock);	if (!mfm_queue)		goto out2a;	Busy = 0;	lastspecifieddrive = -1;	mfm_drives = mfm_initdrives();	if (!mfm_drives) {		ret = -ENODEV;		goto out3;	}		for (i = 0; i < mfm_drives; i++) {		struct gendisk *disk = alloc_disk(64);		if (!disk)			goto Enomem;		disk->major = MAJOR_NR;		disk->first_minor = i << 6;		disk->fops = &mfm_fops;		sprintf(disk->disk_name, "mfm%c", 'a'+i);		mfm_gendisk[i] = disk;	}	printk("mfm: detected %d hard drive%s\n", mfm_drives,				mfm_drives == 1 ? "" : "s");	ret = request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL);	if (ret) {		printk("mfm: unable to get IRQ%d\n", mfm_irq);		goto out4;	}	if (mfm_irqenable)		outw(0x80, mfm_irqenable);	/* Required to enable IRQs from MFM podule */	for (i = 0; i < mfm_drives; i++) {		mfm_geometry(i);		mfm_gendisk[i]->queue = mfm_queue;		add_disk(mfm_gendisk[i]);	}	return 0;out4:	for (i = 0; i < mfm_drives; i++)		put_disk(mfm_gendisk[i]);out3:	blk_cleanup_queue(mfm_queue);out2a:	unregister_blkdev(MAJOR_NR, "mfm");out2:	release_region(mfm_addr, 10);out1:	return ret;Enomem:	while (i--)		put_disk(mfm_gendisk[i]);	goto out3;}static void mfm_do_exit(void){	int i;	free_irq(mfm_irq, NULL);	for (i = 0; i < mfm_drives; i++) {		del_gendisk(mfm_gendisk[i]);		put_disk(mfm_gendisk[i]);	}	blk_cleanup_queue(mfm_queue);	unregister_blkdev(MAJOR_NR, "mfm");	if (mfm_addr)		release_region(mfm_addr, 10);}static int __devinit mfm_probe(struct expansion_card *ec, struct ecard_id *id){	if (mfm_addr)		return -EBUSY;	mfm_addr	= ecard_address(ec, ECARD_IOC, ECARD_MEDIUM) + 0x800;	mfm_IRQPollLoc	= ioaddr(mfm_addr + 0x400);	mfm_irqenable	= mfm_IRQPollLoc;	mfm_irq		= ec->irq;	return mfm_do_init(0x08);}static void __devexit mfm_remove(struct expansion_card *ec){	outw (0, mfm_irqenable);	/* Required to enable IRQs from MFM podule */	mfm_do_exit();}static const struct ecard_id mfm_cids[] = {	{ MANU_ACORN, PROD_ACORN_MFM },	{ 0xffff, 0xffff },};static struct ecard_driver mfm_driver = {	.probe		= mfm_probe,	.remove		= __devexit(mfm_remove),	.id_table	= mfm_cids,	.drv = {		.name	= "mfm",	},};/* * 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. */static int __init 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;		return mfm_do_init(0x08);	/* IL3 pin */	} else {		return ecard_register_driver(&mfm_driver);	}}static void __exit mfm_exit(void){	if (mfm_addr == ONBOARD_MFM_ADDRESS)		mfm_do_exit();	else		ecard_unregister_driver(&mfm_driver);}module_init(mfm_init)module_exit(mfm_exit)MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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