📄 mcd.c
字号:
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 voidmcd_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 voidmcd_interrupt(int irq, void *dev_id, struct pt_regs * regs){ int st; st = inb(MCDPORT(1)) & 0xFF;#ifdef TEST1 printk("<int1-%02X>", st);#endif if (!(st & MFL_STATUS)) { st = inb(MCDPORT(0)) & 0xFF;#ifdef TEST1 printk("<int0-%02X>", st);#endif if ((st & 0xFF) != 0xFF) mcd_error = st ? st & 0xFF : -1; }}static voiddo_mcd_request(void){#ifdef TEST2 printk(" do_mcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors);#endif 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; SET_TIMER(mcd_poll, 1); } break; } } mcd_transfer_is_active = 0;#ifdef TEST2 printk(" do_mcd_request ends\n");#endif}static voidmcd_poll(void){ int st; if (mcd_error) { if (mcd_error & 0xA5) { printk("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("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("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("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:#ifdef TEST3 printk("MCD_S_IDLE\n");#endif return; case MCD_S_START:#ifdef TEST3 printk("MCD_S_START\n");#endif outb(MCMD_GET_STATUS, MCDPORT(0)); mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE; McdTimeout = 3000; break; case MCD_S_MODE:#ifdef TEST3 printk("MCD_S_MODE\n");#endif 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((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n"); mcd_state = MCD_S_IDLE; while (CURRENT_VALID) end_request(0); return; } 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:#ifdef TEST3 printk("MCD_S_READ\n");#endif 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((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n"); mcd_state = MCD_S_IDLE; while (CURRENT_VALID) end_request(0); return; } 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:#ifdef TEST3 printk("MCD_S_DATA\n");#endif st = inb(MCDPORT(1)) & (MFL_STATUSorDATA); data_immediately:#ifdef TEST5 printk("Status %02x\n",st);#endif switch (st) { case MFL_DATA:#ifdef WARN_IF_READ_FAILURE if (McdTries == 5) printk("mcd: read of block %d failed\n", mcd_next_bn);#endif if (!McdTries--) { printk("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; READ_DATA(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;#ifdef DOUBLE_QUICK_ONLY if (MCMD_DATA_READ != MCMD_PLAY_READ)#endif { int count= QUICK_LOOP_COUNT; while (count--) { QUICK_LOOP_DELAY; if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {# ifdef TEST4/* printk("Quickloop success at %d\n",QUICK_LOOP_COUNT-count); */ printk(" %d ",QUICK_LOOP_COUNT-count);# endif goto data_immediately; } }# ifdef TEST4/* printk("Quickloop ended at %d\n",QUICK_LOOP_COUNT); */ printk("ended ");# endif } break; } break; case MCD_S_STOP:#ifdef TEST3 printk("MCD_S_STOP\n");#endif#ifdef WORK_AROUND_MITSUMI_BUG_93 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:#endif /* WORK_AROUND_MITSUMI_BUG_93 */ outb(MCMD_STOP, MCDPORT(0));#ifdef WORK_AROUND_MITSUMI_BUG_92 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)); } }#endif /* WORK_AROUND_MITSUMI_BUG_92 */ mcd_state = MCD_S_STOPPING; McdTimeout = 1000; break; case MCD_S_STOPPING:#ifdef TEST3 printk("MCD_S_STOPPING\n");#endif if ((st = mcdStatus()) == -1 && McdTimeout) break; if ((st != -1) && (st & MST_DSK_CHG)) { mcdDiskChanged = 1; tocUpToDate = 0; mcd_invalidate_buffers(); }#ifdef WORK_AROUND_MITSUMI_BUG_93 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:#endif /* WORK_AROUND_MITSUMI_BUG_93 */#ifdef TEST3 printk("CURRENT_VALID %d mcd_mode %d\n", CURRENT_VALID, mcd_mode);#endif 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; return; } break; default: printk("mcd: invalid state %d\n", mcd_state); return; } ret: if (!McdTimeout--) { printk("mcd: timeout in state %d\n", mcd_state); mcd_state = MCD_S_STOP; } SET_TIMER(mcd_poll, 1);}static voidmcd_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) { mcd_invalidate_buffers(); do { st = statusCmd(); /* check drive status */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -