📄 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 + -