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

📄 mcd.c

📁 cdrom device drive for linux.
💻 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 + -