📄 mcdx.c
字号:
sz--; if (!discard) bp++; xtrace(TALK, "talk() got status 0x%02x\n", st); /* command error? */ if (e_cmderr(st)) { xwarn("command error cmd = %02x %s \n", cmd[0], cmdlen > 1 ? "..." : ""); st = -1; continue; } /* audio status? */ if (stuffp->audiostatus == CDROM_AUDIO_INVALID) stuffp->audiostatus = e_audiobusy(st) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS; else if (stuffp->audiostatus == CDROM_AUDIO_PLAY && e_audiobusy(st) == 0) stuffp->audiostatus = CDROM_AUDIO_COMPLETED; /* media change? */ if (e_changed(st)) { xinfo("talk() media changed\n"); stuffp->xxx = stuffp->yyy = 1; } /* now actually get the data */ while (sz--) { if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) { xinfo("talk() %02x timed out (data), %d tr%s left\n", cmd[0], tries - 1, tries == 2 ? "y" : "ies"); st = -1; break; } if (!discard) bp++; xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1)); } }#if !MCDX_QUIET if (!tries && st == -1) xinfo("talk() giving up\n");#endif stuffp->lock = 0; wake_up_interruptible(&stuffp->lockq); xtrace(TALK, "talk() done with 0x%02x\n", st); return st;}/* MODULE STUFF ***********************************************************/#ifdef MODULEEXPORT_NO_SYMBOLS;int init_module(void){ int i; int drives = 0; mcdx_init(); for (i = 0; i < MCDX_NDRIVES; i++) { if (mcdx_stuffp[i]) { xtrace(INIT, "init_module() drive %d stuff @ %p\n", i, mcdx_stuffp[i]); drives++; } } if (!drives) return -EIO; return 0;}void cleanup_module(void){ int i; xinfo("cleanup_module called\n"); for (i = 0; i < MCDX_NDRIVES; i++) { struct s_drive_stuff *stuffp; if (unregister_cdrom(&mcdx_info)) { printk(KERN_WARNING "Can't unregister cdrom mcdx\n"); return; } stuffp = mcdx_stuffp[i]; if (!stuffp) continue; release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE); free_irq(stuffp->irq, NULL); if (stuffp->toc) { xtrace(MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc); kfree(stuffp->toc); } xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp); mcdx_stuffp[i] = NULL; kfree(stuffp); } if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) { xwarn("cleanup() unregister_blkdev() failed\n"); }#if !MCDX_QUIET else xinfo("cleanup() succeeded\n");#endif}#endif MODULE/* Support functions ************************************************/__initfunc(int mcdx_init_drive(int drive)){ struct s_version version; struct s_drive_stuff* stuffp; int size = sizeof(*stuffp); char msg[80]; mcdx_blocksizes[drive] = 0; xtrace(INIT, "init() try drive %d\n", drive); xtrace(INIT, "kmalloc space for stuffpt's\n"); xtrace(MALLOC, "init() malloc %d bytes\n", size); if (!(stuffp = kmalloc(size, GFP_KERNEL))) { xwarn("init() malloc failed\n"); return 1; } xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp); /* set default values */ memset(stuffp, 0, sizeof(*stuffp)); stuffp->present = 0; /* this should be 0 already */ stuffp->toc = NULL; /* this should be NULL already */ /* setup our irq and i/o addresses */ stuffp->irq = irq(mcdx_drive_map[drive]); stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; stuffp->wreg_hcon = stuffp->wreg_reset + 1; stuffp->wreg_chn = stuffp->wreg_hcon + 1; /* check if i/o addresses are available */ if (check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) { xwarn("0x%3p,%d: Init failed. " "I/O ports (0x%3p..0x%3p) already in use.\n", stuffp->wreg_data, stuffp->irq, stuffp->wreg_data, stuffp->wreg_data + MCDX_IO_SIZE - 1); xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); kfree(stuffp); xtrace(INIT, "init() continue at next drive\n"); return 0; /* next drive */ } xtrace(INIT, "init() i/o port is available at 0x%3p\n", stuffp->wreg_data); xtrace(INIT, "init() hardware reset\n"); mcdx_reset(stuffp, HARD, 1); xtrace(INIT, "init() get version\n"); if (-1 == mcdx_requestversion(stuffp, &version, 4)) { /* failed, next drive */ xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n", MCDX, stuffp->wreg_data, stuffp->irq); xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); kfree(stuffp); xtrace(INIT, "init() continue at next drive\n"); return 0; } switch (version.code) { case 'D': stuffp->readcmd = READ2X; stuffp->present = DOUBLE | DOOR | MULTI; break; case 'F': stuffp->readcmd = READ1X; stuffp->present = SINGLE | DOOR | MULTI; break; case 'M': stuffp->readcmd = READ1X; stuffp->present = SINGLE; break; default: stuffp->present = 0; break; } stuffp->playcmd = READ1X; if (!stuffp->present) { xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n", MCDX, stuffp->wreg_data, stuffp->irq); kfree(stuffp); return 0; /* next drive */ } xtrace(INIT, "init() register blkdev\n"); if (register_blkdev(MAJOR_NR, "mcdx", &cdrom_fops) != 0) { xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n", MCDX, stuffp->wreg_data, stuffp->irq, MAJOR_NR); kfree(stuffp); return 1; } blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; read_ahead[MAJOR_NR] = READ_AHEAD; blksize_size[MAJOR_NR] = mcdx_blocksizes; xtrace(INIT, "init() subscribe irq and i/o\n"); mcdx_irq_map[stuffp->irq] = stuffp; if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) { xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n", MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq); stuffp->irq = 0; kfree(stuffp); return 0; } request_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE, "mcdx"); xtrace(INIT, "init() get garbage\n"); { int i; mcdx_delay(stuffp, HZ/2); for (i = 100; i; i--) (void) inb((unsigned int) stuffp->rreg_status); }#if WE_KNOW_WHY /* irq 11 -> channel register */ outb(0x50, (unsigned int) stuffp->wreg_chn);#endif xtrace(INIT, "init() set non dma but irq mode\n"); mcdx_config(stuffp, 1); stuffp->minor = drive; sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d." " (Firmware version %c %x)\n", stuffp->wreg_data, stuffp->irq, version.code, version.ver); mcdx_stuffp[drive] = stuffp; xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); mcdx_info.dev = MKDEV(MAJOR_NR,0); if (register_cdrom(&mcdx_info) != 0) { printk("Cannot register Mitsumi CD-ROM!\n"); release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE); free_irq(stuffp->irq, NULL); kfree(stuffp); if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) xwarn("cleanup() unregister_blkdev() failed\n"); return 2; } printk(msg); return 0;}__initfunc(int mcdx_init(void)){ int drive;#ifdef MODULE xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");#else xwarn("Version 2.14(hs) \n");#endif xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n"); /* zero the pointer array */ for (drive = 0; drive < MCDX_NDRIVES; drive++) mcdx_stuffp[drive] = NULL; /* do the initialisation */ for (drive = 0; drive < MCDX_NDRIVES; drive++) { switch(mcdx_init_drive(drive)) { case 2: return -EIO; case 1: break; } } return 0;}static intmcdx_transfer(struct s_drive_stuff *stuffp, char *p, int sector, int nr_sectors)/* This seems to do the actually transfer. But it does more. It keeps track of errors occurred and will (if possible) fall back to single speed on error. Return: -1 on timeout or other error else status byte (as in stuff->st) */{ int ans; ans = mcdx_xfer(stuffp, p, sector, nr_sectors); return ans;#if FALLBACK if (-1 == ans) stuffp->readerrs++; else return ans; if (stuffp->readerrs && stuffp->readcmd == READ1X) { xwarn("XXX Already reading 1x -- no chance\n"); return -1; } xwarn("XXX Fallback to 1x\n"); stuffp->readcmd = READ1X; return mcdx_transfer(stuffp, p, sector, nr_sectors);#endif}static int mcdx_xfer(struct s_drive_stuff *stuffp, char *p, int sector, int nr_sectors)/* This does actually the transfer from the drive. Return: -1 on timeout or other error else status byte (as in stuff->st) */{ int border; int done = 0; long timeout; if (stuffp->audio) { xwarn("Attempt to read from audio CD.\n"); return -1; } if (!stuffp->readcmd) { xinfo("Can't transfer from missing disk.\n"); return -1; } while (stuffp->lock) { interruptible_sleep_on(&stuffp->lockq); } if (stuffp->valid && (sector >= stuffp->pending) && (sector < stuffp->low_border)) { /* All (or at least a part of the sectors requested) seems * to be already requested, so we don't need to bother the * drive with new requests ... * Wait for the drive become idle, but first * check for possible occurred errors --- the drive * seems to report them asynchronously */ border = stuffp->high_border < (border = sector + nr_sectors) ? stuffp->high_border : border; stuffp->lock = current->pid; do { while (stuffp->busy) { timeout = interruptible_sleep_on_timeout(&stuffp->busyq, 5*HZ); if (!stuffp->introk) { xtrace(XFER, "error via interrupt\n"); } else if (!timeout) { xtrace(XFER, "timeout\n"); } else if (signal_pending(current)) { xtrace(XFER, "signal\n"); } else continue; stuffp->lock = 0; stuffp->busy = 0; stuffp->valid = 0; wake_up_interruptible(&stuffp->lockq); xtrace(XFER, "transfer() done (-1)\n"); return -1; } /* check if we need to set the busy flag (as we * expect an interrupt */ stuffp->busy = (3 == (stuffp->pending & 3)); /* Test if it's the first sector of a block, * there we have to skip some bytes as we read raw data */ if (stuffp->xa && (0 == (stuffp->pending & 3))) { const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE; insb((unsigned int) stuffp->rreg_data, p, HEAD); } /* now actually read the data */ insb((unsigned int) stuffp->rreg_data, p, 512); /* test if it's the last sector of a block, * if so, we have to handle XA special */ if ((3 == (stuffp->pending & 3)) && stuffp->xa) { char dummy[CD_XA_TAIL]; insb((unsigned int) stuffp->rreg_data, &dummy[0], CD_XA_TAIL); } if (stuffp->pending == sector) { p += 512; done++; sector++; } } while (++(stuffp->pending) < border); stuffp->lock = 0; wake_up_interruptible(&stuffp->lockq); } else { /* The requested sector(s) is/are out of the * already requested range, so we have to bother the drive * with a new request. */ static unsigned char cmd[] = { 0, 0, 0, 0, 0, 0, 0 }; cmd[0] = stuffp->readcmd; /* The numbers held in ->pending, ..., should be valid */ stuffp->valid = 1; stuffp->pending = sector & ~3; /* do some sanity checks */ if (stuffp->pending > stuffp->lastsector) { xwarn("transfer() sector %d from nirvana requested.\n", stuffp->pending); stuffp->status = MCDX_ST_EOM; stuffp->valid = 0; xtrace(XFER, "transfer() done (-1)\n"); return -1; } if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE) > stuffp->lastsector + 1) { xtrace(XFER, "cut low_border\n"); stuffp->low_border = stuffp->lastsector + 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -