📄 mcd.c
字号:
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 + -