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

📄 mcd.c

📁 还有没有人研究过cdrom 的驱动源码啊
💻 C
📖 第 1 页 / 共 3 页
字号:
		subchnl->cdsc_adr = qInfo.ctrl_addr;		subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;		subchnl->cdsc_trk = bcd2bin(qInfo.track);		subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);		subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);		subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);		subchnl->cdsc_absaddr.msf.frame  = bcd2bin(qInfo.diskTime.frame);		subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);		subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);		subchnl->cdsc_reladdr.msf.frame  = bcd2bin(qInfo.trackTime.frame);		return (0);	case CDROMVOLCTRL:	/* Volume control */		volctrl = (struct cdrom_volctrl *) arg;		outb(MCMD_SET_VOLUME, MCDPORT(0));		outb(volctrl->channel0, MCDPORT(0));		outb(255, MCDPORT(0));		outb(volctrl->channel1, MCDPORT(0));		outb(255, MCDPORT(0));		i = getMcdStatus(MCD_STATUS_DELAY);		if (i < 0)			return -EIO;		{			char a, b, c, d;			getValue(&a);			getValue(&b);			getValue(&c);			getValue(&d);		}		return 0;	default:		return -EINVAL;	}}/* * Take care of the different block sizes between cdrom and Linux. * When Linux gets variable block sizes this will probably go away. */static void mcd_transfer(void){	if (CURRENT_VALID) {		while (CURRENT->nr_sectors) {			int bn = CURRENT->sector / 4;			int i;			for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn;			     ++i);			if (i < MCD_BUF_SIZ) {				int offs =(i * 4 + (CURRENT->sector & 3)) * 512;				int nr_sectors = 4 - (CURRENT->sector & 3);				if (mcd_buf_out != i) {					mcd_buf_out = i;					if (mcd_buf_bn[i] != bn) {						mcd_buf_out = -1;						continue;					}				}				if (nr_sectors > CURRENT->nr_sectors)					nr_sectors = CURRENT->nr_sectors;				memcpy(CURRENT->buffer, mcd_buf + offs,				       nr_sectors * 512);				CURRENT->nr_sectors -= nr_sectors;				CURRENT->sector += nr_sectors;				CURRENT->buffer += nr_sectors * 512;			} else {				mcd_buf_out = -1;				break;			}		}	}}/* * We only seem to get interrupts after an error. * Just take the interrupt and clear out the status reg. */static void mcd_interrupt(int irq, void *dev_id, struct pt_regs *regs){	int st;	st = inb(MCDPORT(1)) & 0xFF;	test1(printk("<int1-%02X>", st));	if (!(st & MFL_STATUS)) {		st = inb(MCDPORT(0)) & 0xFF;		test1(printk("<int0-%02X>", st));		if ((st & 0xFF) != 0xFF)			mcd_error = st ? st & 0xFF : -1;	}}static void do_mcd_request(request_queue_t * q){	test2(printk(" do_mcd_request(%ld+%ld)\n", CURRENT->sector,	       CURRENT->nr_sectors));		mcd_transfer_is_active = 1;	while (CURRENT_VALID) {		if (CURRENT->bh) {			if (!buffer_locked(CURRENT->bh))				panic(DEVICE_NAME ": block not locked");		}		mcd_transfer();		if (CURRENT->nr_sectors == 0) {			end_request(1);		} else {			mcd_buf_out = -1;	/* Want to read a block not in buffer */			if (mcd_state == MCD_S_IDLE) {				if (!tocUpToDate) {					if (updateToc() < 0) {						while (CURRENT_VALID)							end_request(0);						break;					}				}				mcd_state = MCD_S_START;				McdTries = 5;				mcd_timer.function = mcd_poll;				mod_timer(&mcd_timer, jiffies + 1);			}			break;		}	}	mcd_transfer_is_active = 0;	test2(printk(" do_mcd_request ends\n"));}static void mcd_poll(unsigned long dummy){	int st;	if (mcd_error) {		if (mcd_error & 0xA5) {			printk(KERN_ERR "mcd: I/O error 0x%02x", mcd_error);			if (mcd_error & 0x80)				printk(" (Door open)");			if (mcd_error & 0x20)				printk(" (Disk changed)");			if (mcd_error & 0x04) {				printk(" (Read error)");	/* Bitch about the problem. */				/* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */				/* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */				/* But I find that rather HANDY!!! */				/* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */				/* AJK [06/17/95] */				/* Slap the CD down to single speed! */				if (mcdDouble == 1				    && McdTries == MCD_RETRY_ATTEMPTS				    && MCMD_DATA_READ == MCMD_2X_READ) {					MCMD_DATA_READ = MCMD_PLAY_READ;	/* Uhhh, Ummmm, muhuh-huh! */					mcd1xhold = SINGLE_HOLD_SECTORS;	/* Hey Beavis! */					printk(" Speed now 1x");	/* Pull my finger! */				}			}			printk("\n");			mcd_invalidate_buffers();#ifdef WARN_IF_READ_FAILURE			if (McdTries == MCD_RETRY_ATTEMPTS)				printk(KERN_ERR "mcd: read of block %d failed\n",				       mcd_next_bn);#endif			if (!McdTries--) {				/* Nuts! This cd is ready for recycling! */				/* When WAS the last time YOU cleaned it CORRECTLY?! */				printk(KERN_ERR "mcd: read of block %d failed, giving up\n",				     mcd_next_bn);				if (mcd_transfer_is_active) {					McdTries = 0;					goto ret;				}				if (CURRENT_VALID)					end_request(0);				McdTries = MCD_RETRY_ATTEMPTS;			}		}		mcd_error = 0;		mcd_state = MCD_S_STOP;	}	/* Switch back to Double speed if enough GOOD sectors were read! */	/* Are we a double speed with a crappy CD?! */	if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS	    && MCMD_DATA_READ == MCMD_PLAY_READ) {		/* We ARE a double speed and we ARE bitching! */		if (mcd1xhold == 0) {	/* Okay, Like are we STILL at single speed? *//* We need to switch back to double speed now... */			MCMD_DATA_READ = MCMD_2X_READ;	/* Uhhh... BACK You GO! */			printk(KERN_INFO "mcd: Switching back to 2X speed!\n");	/* Tell 'em! */		} else			mcd1xhold--;	/* No?! Count down the good reads some more... */		/* and try, try again! */	}immediately:	switch (mcd_state) {	case MCD_S_IDLE:		test3(printk("MCD_S_IDLE\n"));		goto out;	case MCD_S_START:		test3(printk("MCD_S_START\n"));		outb(MCMD_GET_STATUS, MCDPORT(0));		mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;		McdTimeout = 3000;		break;	case MCD_S_MODE:		test3(printk("MCD_S_MODE\n"));		if ((st = mcdStatus()) != -1) {			if (st & MST_DSK_CHG) {				mcdDiskChanged = 1;				tocUpToDate = 0;				mcd_invalidate_buffers();			}set_mode_immediately:			if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {				mcdDiskChanged = 1;				tocUpToDate = 0;				if (mcd_transfer_is_active) {					mcd_state = MCD_S_START;					goto immediately;				}				printk(KERN_INFO);				printk((st & MST_DOOR_OPEN) ?				       "mcd: door open\n" :				       "mcd: disk removed\n");				mcd_state = MCD_S_IDLE;				while (CURRENT_VALID)					end_request(0);				goto out;			}			outb(MCMD_SET_MODE, MCDPORT(0));			outb(1, MCDPORT(0));			mcd_mode = 1;			mcd_state = MCD_S_READ;			McdTimeout = 3000;		}		break;	case MCD_S_READ:		test3(printk("MCD_S_READ\n"));		if ((st = mcdStatus()) != -1) {			if (st & MST_DSK_CHG) {				mcdDiskChanged = 1;				tocUpToDate = 0;				mcd_invalidate_buffers();			}read_immediately:			if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {				mcdDiskChanged = 1;				tocUpToDate = 0;				if (mcd_transfer_is_active) {					mcd_state = MCD_S_START;					goto immediately;				}				printk(KERN_INFO);				printk((st & MST_DOOR_OPEN) ?				       "mcd: door open\n" :				       "mcd: disk removed\n");				mcd_state = MCD_S_IDLE;				while (CURRENT_VALID)					end_request(0);				goto out;			}			if (CURRENT_VALID) {				struct mcd_Play_msf msf;				mcd_next_bn = CURRENT->sector / 4;				hsg2msf(mcd_next_bn, &msf.start);				msf.end.min = ~0;				msf.end.sec = ~0;				msf.end.frame = ~0;				sendMcdCmd(MCMD_DATA_READ, &msf);				mcd_state = MCD_S_DATA;				McdTimeout = READ_TIMEOUT;			} else {				mcd_state = MCD_S_STOP;				goto immediately;			}		}		break;	case MCD_S_DATA:		test3(printk("MCD_S_DATA\n"));		st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);data_immediately:		test5(printk("Status %02x\n", st))		switch (st) {		case MFL_DATA:#ifdef WARN_IF_READ_FAILURE			if (McdTries == 5)				printk(KERN_WARNING "mcd: read of block %d failed\n",				       mcd_next_bn);#endif			if (!McdTries--) {				printk(KERN_ERR "mcd: read of block %d failed, giving up\n", mcd_next_bn);				if (mcd_transfer_is_active) {					McdTries = 0;					break;				}				if (CURRENT_VALID)					end_request(0);				McdTries = 5;			}			mcd_state = MCD_S_START;			McdTimeout = READ_TIMEOUT;			goto immediately;		case MFL_STATUSorDATA:			break;		default:			McdTries = 5;			if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) {				mcd_state = MCD_S_STOP;				goto immediately;			}			mcd_buf_bn[mcd_buf_in] = -1;			insb(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in,				  2048);			mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;			if (mcd_buf_out == -1)				mcd_buf_out = mcd_buf_in;			mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;			if (!mcd_transfer_is_active) {				while (CURRENT_VALID) {					mcd_transfer();					if (CURRENT->nr_sectors == 0)						end_request(1);					else						break;				}			}			if (CURRENT_VALID			    && (CURRENT->sector / 4 < mcd_next_bn ||				CURRENT->sector / 4 > mcd_next_bn + 16)) {				mcd_state = MCD_S_STOP;				goto immediately;			}			McdTimeout = READ_TIMEOUT;			{				int count = QUICK_LOOP_COUNT;				while (count--) {					QUICK_LOOP_DELAY;					if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {						test4(printk(" %d ", QUICK_LOOP_COUNT - count));						goto data_immediately;					}				}				test4(printk("ended "));			}			break;		}		break;	case MCD_S_STOP:		test3(printk("MCD_S_STOP\n"));		if (!mitsumi_bug_93_wait)			goto do_not_work_around_mitsumi_bug_93_1;		McdTimeout = mitsumi_bug_93_wait;		mcd_state = 9 + 3 + 1;		break;	case 9 + 3 + 1:		if (McdTimeout)			break;do_not_work_around_mitsumi_bug_93_1:		outb(MCMD_STOP, MCDPORT(0));		if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {			int i = 4096;			do {				inb(MCDPORT(0));			} while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);			outb(MCMD_STOP, MCDPORT(0));			if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {				i = 4096;				do {					inb(MCDPORT(0));				} while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);				outb(MCMD_STOP, MCDPORT(0));			}		}		mcd_state = MCD_S_STOPPING;		McdTimeout = 1000;		break;	case MCD_S_STOPPING:		test3(printk("MCD_S_STOPPING\n"));		if ((st = mcdStatus()) == -1 && McdTimeout)			break;		if ((st != -1) && (st & MST_DSK_CHG)) {			mcdDiskChanged = 1;			tocUpToDate = 0;			mcd_invalidate_buffers();		}		if (!mitsumi_bug_93_wait)			goto do_not_work_around_mitsumi_bug_93_2;		McdTimeout = mitsumi_bug_93_wait;		mcd_state = 9 + 3 + 2;		break;	case 9 + 3 + 2:		if (McdTimeout)			break;		st = -1;do_not_work_around_mitsumi_bug_93_2:		test3(printk("CURRENT_VALID %d mcd_mode %d\n", CURRENT_VALID, mcd_mode));		if (CURRENT_VALID) {			if (st != -1) {				if (mcd_mode == 1)					goto read_immediately;				else					goto set_mode_immediately;			} else {				mcd_state = MCD_S_START;				McdTimeout = 1;			}		} else {			mcd_state = MCD_S_IDLE;			goto out;		}		break;	default:		printk(KERN_ERR "mcd: invalid state %d\n", mcd_state);		goto out;	}ret:	if (!McdTimeout--) {		printk(KERN_WARNING "mcd: timeout in state %d\n", mcd_state);		mcd_state = MCD_S_STOP;	}	mcd_timer.function = mcd_poll;	mod_timer(&mcd_timer, jiffies + 1);out:	return;}static void mcd_invalidate_buffers(void){	int i;	for (i = 0; i < MCD_BUF_SIZ; ++i)		mcd_buf_bn[i] = -1;	mcd_buf_out = -1;}/* * Open the device special file.  Check that a disk is in. */static int mcd_open(struct cdrom_device_info *cdi, int purpose){	int st, count = 0;	if (mcdPresent == 0)		return -ENXIO;	/* no hardware */	if (mcd_open_count || mcd_state != MCD_S_IDLE)		goto bump_count;	mcd_invalidate_buffers();	do {		st = statusCmd();	/* check drive status */		if (st == -1)			goto err_out;	/* drive doesn't respond */		if ((st & MST_READY) == 0) {	/* no disk? wait a sec... */			current->state = TASK_INTERRUPTIBLE;			schedule_timeout(HZ);		}	} while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);	if (updateToc() < 0)		goto err_out;bump_count:	++mcd_open_count;	return 0;err_out:	return -EIO;}/* * On close, we flush all mcd blocks from the buffer cache. */static void mcd_release(struct cdrom_device_info *cdi){	if (!--mcd_open_count) {		mcd_invalidate_buffers();	}}

⌨️ 快捷键说明

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