📄 mcd.c
字号:
SET_TIMER(mcd_status, 1); return; } if (st & MST_DSK_CHG) { mcdDiskChanged = 1; } if ((st & MST_READY) == 0) { printk("mcd: disk removed\n"); mcdDiskChanged = 1; end_request(0); do_mcd_request(); return; } outb(0x50, MCDPORT(0)); /* set mode */ outb(0x01, MCDPORT(0)); /* mode = cooked data */ McdTimeout = 100; SET_TIMER(mcd_read_cmd, 1);}/* * Check the result of the set-mode command. On success, send the * read-data command. */static voidmcd_read_cmd(){ int st; long block; struct mcd_Play_msf mcdcmd; McdTimeout--; st = mcdStatus(); if (st & MST_DSK_CHG) { mcdDiskChanged = 1; } if (st == -1) { if (McdTimeout == 0) { printk("mcd: set mode timed out\n"); SET_TIMER(mcd_start, 1); /* wait a bit, try again */ return; } SET_TIMER(mcd_read_cmd, 1); return; } mcd_bn = -1; /* purge our buffer */ block = CURRENT -> sector / 4; hsg2msf(block, &mcdcmd.start); /* cvt to msf format */ mcdcmd.end.min = 0; mcdcmd.end.sec = 0; mcdcmd.end.frame = 1; sendMcdCmd(MCMD_PLAY_READ, &mcdcmd); /* read command */ McdTimeout = 200; SET_TIMER(mcd_data, 1);}/* * Check the completion of the read-data command. On success, read * the 2048 bytes of data from the disk into our buffer. */static voidmcd_data(){ int i; McdTimeout--; cli(); i =inb(MCDPORT(1)) & (MFL_STATUS | MFL_DATA); if (i == MFL_DATA) { printk("mcd: read failed\n");#ifdef MCD_DEBUG printk("got 0xB %02X\n", inb(MCDPORT(0)) & 0xFF);#endif SET_TIMER(mcd_start, 1); sti(); return; } if (i == (MFL_STATUS | MFL_DATA)) { if (McdTimeout == 0) { printk("mcd: data timeout, retrying\n"); SET_TIMER(mcd_start, 1); } else SET_TIMER(mcd_data, 1); sti(); return; } CLEAR_TIMER; READ_DATA(MCDPORT(0), &mcd_buf[0], 2048); sti(); mcd_bn = CURRENT -> sector / 4; mcd_transfer(); end_request(1); SET_TIMER(do_mcd_request, 1);}/* * Open the device special file. Check that a disk is in. */intmcd_open(struct inode *ip, struct file *fp){ int st; if (mcdPresent == 0) return -ENXIO; /* no hardware */ st = statusCmd(); /* check drive status */ if (st == -1) return -EIO; /* drive doesn't respond */ if ((st & MST_READY) == 0) /* no disk in drive */ { printk("mcd: no disk in drive\n"); return -EIO; } if (updateToc() < 0) return -EIO; return 0;}/* * On close, we flush all mcd blocks from the buffer cache. */static voidmcd_release(struct inode * inode, struct file * file){ mcd_bn = -1; sync_dev(inode->i_rdev); invalidate_buffers(inode -> i_rdev);}static struct file_operations mcd_fops = { NULL, /* lseek - default */ block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ NULL, /* select */ mcd_ioctl, /* ioctl */ NULL, /* mmap */ mcd_open, /* open */ mcd_release /* release */};/* * MCD interrupt descriptor */static struct sigaction mcd_sigaction = { mcd_interrupt, 0, SA_INTERRUPT, NULL};/* * Test for presence of drive and initialize it. Called at boot time. */unsigned longmcd_init(unsigned long mem_start, unsigned long mem_end){ int count; unsigned char result[3]; if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0) { printk("mcd: Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR); return mem_start; } if (check_region(mcd_port, 4)) { printk("mcd: Init failed, I/O port (%X) already in use\n", mcd_port); return mem_start; } 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 < 1000000; count++) (void) inb(MCDPORT(1)); /* delay a bit */ outb(0x40, MCDPORT(0)); /* send get-stat cmd */ for (count = 0; count < 1000000; count++) if (!(inb(MCDPORT(1)) & MFL_STATUS)) break; if (count >= 1000000) { printk("mcd: Init failed. No mcd device at 0x%x irq %d\n", mcd_port, mcd_irq); return mem_start; } 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("mcd: mitsumi get version failed at 0x%d\n", mcd_port); return mem_start; } if (result[0] == result[1] && result[1] == result[2]) return mem_start; printk("mcd: Mitsumi version : %02X %c %x\n", result[0],result[1],result[2]); 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 (irqaction(MCD_INTR_NR, &mcd_sigaction)) { printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", MCD_INTR_NR); return mem_start; } snarf_region(mcd_port, 4); mcdPresent = 1; printk("mcd: Mitsumi CD-ROM Drive present at addr %x, irq %d\n", mcd_port, mcd_irq); return mem_start;}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;}/* * Read a value from the drive. Should return quickly, so a busy wait * is used to avoid excessive rescheduling. */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 neccessary */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); 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;#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 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 */ 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)); 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -