📄 mcd.c
字号:
if (st == -1) return -EIO; /* 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) return -EIO; } ++mcd_open_count; MOD_INC_USE_COUNT; return 0;}/* * On close, we flush all mcd blocks from the buffer cache. */static void mcd_release(struct cdrom_device_info * cdi){ MOD_DEC_USE_COUNT; if (!--mcd_open_count) { mcd_invalidate_buffers(); }}/* This routine gets called during initialization if things go wrong, * and is used in cleanup_module as well. */static void cleanup(int level){ switch (level) { case 3: if (unregister_cdrom(&mcd_info)) { printk(KERN_WARNING "Can't unregister cdrom mcd\n"); return; } free_irq(mcd_irq, NULL); case 2: release_region(mcd_port,4); case 1: if (unregister_blkdev(MAJOR_NR, "mcd")) { printk(KERN_WARNING "Can't unregister major mcd\n"); return; } default: }}/* * Test for presence of drive and initialize it. Called at boot time. */__initfunc(int mcd_init(void)){ int count; unsigned char result[3]; char msg[80]; if (mcd_port <= 0 || mcd_irq <= 0) { printk("skip mcd_init\n"); return -EIO; } if (register_blkdev(MAJOR_NR, "mcd", &cdrom_fops) != 0) { printk("Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR); return -EIO; } if (check_region(mcd_port, 4)) { cleanup(1); printk("Init failed, I/O port (%X) already in use\n", mcd_port); return -EIO; } blksize_size[MAJOR_NR] = mcd_blocksizes; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; read_ahead[MAJOR_NR] = 4; /* check for card */ outb(0, MCDPORT(1)); /* send reset */ for (count = 0; count < 2000000; count++) (void) inb(MCDPORT(1)); /* delay a bit */ outb(0x40, MCDPORT(0)); /* send get-stat cmd */ for (count = 0; count < 2000000; count++) if (!(inb(MCDPORT(1)) & MFL_STATUS)) break; if (count >= 2000000) { printk("Init failed. No mcd device at 0x%x irq %d\n", mcd_port, mcd_irq); cleanup(1); return -EIO; } count = inb(MCDPORT(0)); /* pick up the status */ outb(MCMD_GET_VERSION,MCDPORT(0)); for(count=0;count<3;count++) if(getValue(result+count)) { printk("mitsumi get version failed at 0x%d\n", mcd_port); cleanup(1); return -EIO; } if (result[0] == result[1] && result[1] == result[2]) { cleanup(1); return -EIO; } mcdVersion=result[2]; if (mcdVersion >=4) outb(4,MCDPORT(2)); /* magic happens */ /* don't get the IRQ until we know for sure the drive is there */ if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) { printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq); cleanup(1); return -EIO; } if (result[1] == 'D') { sprintf(msg, " mcd: Mitsumi Double Speed CD-ROM at port=0x%x," " irq=%d\n", mcd_port, mcd_irq); MCMD_DATA_READ = MCMD_2X_READ; mcd_info.speed = 2; /* Added flag to drop to 1x speed if too many errors */ mcdDouble = 1; } else { sprintf(msg, " mcd: Mitsumi Single Speed CD-ROM at port=0x%x," " irq=%d\n", mcd_port, mcd_irq); mcd_info.speed = 2; } request_region(mcd_port, 4, "mcd"); outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); outb(0x02,MCDPORT(0)); outb(0x00,MCDPORT(0)); getValue(result); outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); outb(0x10,MCDPORT(0)); outb(0x04,MCDPORT(0)); getValue(result); mcd_invalidate_buffers(); mcdPresent = 1; mcd_info.dev = MKDEV(MAJOR_NR,0); if (register_cdrom(&mcd_info) != 0) { printk("Cannot register Mitsumi CD-ROM!\n"); cleanup(3); return -EIO; } printk(msg); return 0;}static voidhsg2msf(long hsg, struct msf *msf){ hsg += 150; msf -> min = hsg / 4500; hsg %= 4500; msf -> sec = hsg / 75; msf -> frame = hsg % 75; bin2bcd(&msf -> min); /* convert to BCD */ bin2bcd(&msf -> sec); bin2bcd(&msf -> frame);}static voidbin2bcd(unsigned char *p){ int u, t; u = *p % 10; t = *p / 10; *p = u | (t << 4);}static intbcd2bin(unsigned char bcd){ return (bcd >> 4) * 10 + (bcd & 0xF);}/* * See if a status is ready from the drive and return it * if it is ready. */static intmcdStatus(void){ int i; int st; st = inb(MCDPORT(1)) & MFL_STATUS; if (!st) { i = inb(MCDPORT(0)) & 0xFF; return i; } else return -1;}/* * Send a play or read command to the drive */static voidsendMcdCmd(int cmd, struct mcd_Play_msf *params){ outb(cmd, MCDPORT(0)); outb(params -> start.min, MCDPORT(0)); outb(params -> start.sec, MCDPORT(0)); outb(params -> start.frame, MCDPORT(0)); outb(params -> end.min, MCDPORT(0)); outb(params -> end.sec, MCDPORT(0)); outb(params -> end.frame, MCDPORT(0));}/* * Timer interrupt routine to test for status ready from the drive. * (see the next routine) */static voidmcdStatTimer(void){ if (!(inb(MCDPORT(1)) & MFL_STATUS)) { wake_up(&mcd_waitq); return; } McdTimeout--; if (McdTimeout <= 0) { wake_up(&mcd_waitq); return; } SET_TIMER(mcdStatTimer, 1);}/* * Wait for a status to be returned from the drive. The actual test * (see routine above) is done by the timer interrupt to avoid * excessive rescheduling. */static intgetMcdStatus(int timeout){ int st; McdTimeout = timeout; SET_TIMER(mcdStatTimer, 1); sleep_on(&mcd_waitq); if (McdTimeout <= 0) return -1; st = inb(MCDPORT(0)) & 0xFF; if (st == 0xFF) return -1; if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY) /* XXX might be an error? look at q-channel? */ audioStatus = CDROM_AUDIO_COMPLETED; if (st & MST_DSK_CHG) { mcdDiskChanged = 1; tocUpToDate = 0; audioStatus = CDROM_AUDIO_NO_STATUS; } return st;}/* gives current state of the drive This function is quite unreliable, and should probably be rewritten by someone, eventually... */int mcd_drive_status(struct cdrom_device_info * cdi, int slot_nr){ int st; st = statusCmd(); /* check drive status */ if (st == -1) return -EIO; /* drive doesn't respond */ if ((st & MST_READY)) return CDS_DISC_OK; if ((st & MST_DOOR_OPEN)) return CDS_TRAY_OPEN; if ((st & MST_DSK_CHG)) return CDS_NO_DISC; if ((st & MST_BUSY)) return CDS_DRIVE_NOT_READY; return -EIO;}/* * Read a value from the drive. */static intgetValue(unsigned char *result){ int count; int s; for (count = 0; count < 2000; count++) if (!(inb(MCDPORT(1)) & MFL_STATUS)) break; if (count >= 2000) { printk("mcd: getValue timeout\n"); return -1; } s = inb(MCDPORT(0)) & 0xFF; *result = (unsigned char) s; return 0;}/* * Read the current Q-channel info. Also used for reading the * table of contents. */intGetQChannelInfo(struct mcd_Toc *qp){ unsigned char notUsed; int retry; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { outb(MCMD_GET_Q_CHANNEL, MCDPORT(0)); if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; } if (retry >= MCD_RETRY_ATTEMPTS) return -1; if (getValue(&qp -> ctrl_addr) < 0) return -1; if (getValue(&qp -> track) < 0) return -1; if (getValue(&qp -> pointIndex) < 0) return -1; if (getValue(&qp -> trackTime.min) < 0) return -1; if (getValue(&qp -> trackTime.sec) < 0) return -1; if (getValue(&qp -> trackTime.frame) < 0) return -1; if (getValue(¬Used) < 0) return -1; if (getValue(&qp -> diskTime.min) < 0) return -1; if (getValue(&qp -> diskTime.sec) < 0) return -1; if (getValue(&qp -> diskTime.frame) < 0) return -1; return 0;}/* * Read the table of contents (TOC) and TOC header if necessary */static intupdateToc(){ if (tocUpToDate) return 0; if (GetDiskInfo() < 0) return -EIO; if (GetToc() < 0) return -EIO; tocUpToDate = 1; return 0;}/* * Read the table of contents header */static intGetDiskInfo(){ int retry; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { outb(MCMD_GET_DISK_INFO, MCDPORT(0)); if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; } if (retry >= MCD_RETRY_ATTEMPTS) return -1; if (getValue(&DiskInfo.first) < 0) return -1; if (getValue(&DiskInfo.last) < 0) return -1; DiskInfo.first = bcd2bin(DiskInfo.first); DiskInfo.last = bcd2bin(DiskInfo.last);#ifdef MCD_DEBUGprintk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n", DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min, DiskInfo.diskLength.sec, DiskInfo.diskLength.frame, DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec, DiskInfo.firstTrack.frame);#endif if (getValue(&DiskInfo.diskLength.min) < 0) return -1; if (getValue(&DiskInfo.diskLength.sec) < 0) return -1; if (getValue(&DiskInfo.diskLength.frame) < 0) return -1; if (getValue(&DiskInfo.firstTrack.min) < 0) return -1; if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1; if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1; return 0;}/* * Read the table of contents (TOC) */static intGetToc(){ int i, px; int limit; int retry; struct mcd_Toc qInfo; for (i = 0; i < MAX_TRACKS; i++) Toc[i].pointIndex = 0; i = DiskInfo.last + 3; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { outb(MCMD_STOP, MCDPORT(0)); if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; } if (retry >= MCD_RETRY_ATTEMPTS) return -1; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { outb(MCMD_SET_MODE, MCDPORT(0)); outb(0x05, MCDPORT(0)); /* mode: toc */ mcd_mode = 0x05; if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; } if (retry >= MCD_RETRY_ATTEMPTS) return -1; for (limit = 300; limit > 0; limit--) { if (GetQChannelInfo(&qInfo) < 0) break; px = bcd2bin(qInfo.pointIndex); if (px > 0 && px < MAX_TRACKS && qInfo.track == 0) if (Toc[px].pointIndex == 0) { Toc[px] = qInfo; i--; } if (i <= 0) break; } Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { outb(MCMD_SET_MODE, MCDPORT(0)); outb(0x01, MCDPORT(0)); mcd_mode = 1; if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; }#ifdef MCD_DEBUGfor (i = 1; i <= DiskInfo.last; i++)printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);for (i = 100; i < 103; i++)printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);#endif return limit > 0 ? 0 : -1;}#ifdef MODULEint init_module(void){ return mcd_init();}void cleanup_module(void){ cleanup(3);}#endif MODULE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -