📄 mcdx.c
字号:
sub->cdsc_absaddr.msf.frame, sub->cdsc_reladdr.msf.minute, sub->cdsc_reladdr.msf.second, sub->cdsc_reladdr.msf.frame); return 0; } case CDROMREADTOCHDR: { struct cdrom_tochdr *toc=(struct cdrom_tochdr *) arg; xtrace(IOCTL, "ioctl() READTOCHDR\n"); toc->cdth_trk0 = stuffp->di.n_first; toc->cdth_trk1 = stuffp->di.n_last; xtrace(TOCHDR, "ioctl() track0 = %d, track1 = %d\n", stuffp->di.n_first, stuffp->di.n_last); return 0; } case CDROMPAUSE: { xtrace(IOCTL, "ioctl() PAUSE\n"); if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL; if (-1 == mcdx_stop(stuffp, 1)) return -EIO; stuffp->audiostatus = CDROM_AUDIO_PAUSED; if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1)) return -EIO; return 0; } case CDROMMULTISESSION: { struct cdrom_multisession *ms=(struct cdrom_multisession *) arg; xtrace(IOCTL, "ioctl() MULTISESSION\n"); /* Always return stuff in LBA, and let the Uniform cdrom driver worry about what the user actually wants */ ms->addr.lba = msf2log(&stuffp->multi.msf_last); ms->xa_flag = !!stuffp->multi.multi; xtrace(MS, "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n", ms->xa_flag, ms->addr.lba, stuffp->multi.msf_last.minute, stuffp->multi.msf_last.second,stuffp->multi.msf_last.frame); return 0; } case CDROMEJECT: { xtrace(IOCTL, "ioctl() EJECT\n"); if (stuffp->users > 1) return -EBUSY; return(mcdx_tray_move(cdi, 1)); } case CDROMCLOSETRAY: { xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n"); return(mcdx_tray_move(cdi, 0)); } case CDROMVOLCTRL: { struct cdrom_volctrl *volctrl=(struct cdrom_volctrl *)arg; xtrace(IOCTL, "ioctl() VOLCTRL\n");#if 0 /* not tested! */ /* adjust for the weirdness of workman (md) */ /* can't test it (hs) */ volctrl.channel2 = volctrl.channel1; volctrl.channel1 = volctrl.channel3 = 0x00;#endif return mcdx_setattentuator(stuffp, volctrl, 2); } default: xwarn("ioctl(): unknown request 0x%04x\n", cmd); return -EINVAL; }}void do_mcdx_request(){ int dev; struct s_drive_stuff *stuffp; again: if (CURRENT == NULL) { xtrace(REQUEST, "end_request(0): CURRENT == NULL\n"); return; } if (CURRENT->rq_status == RQ_INACTIVE) { xtrace(REQUEST, "end_request(0): rq_status == RQ_INACTIVE\n"); return; } INIT_REQUEST; dev = MINOR(CURRENT->rq_dev); stuffp = mcdx_stuffp[dev]; if ((dev < 0) || (dev >= MCDX_NDRIVES) || !stuffp || (!stuffp->present)) { xwarn("do_request(): bad device: %s\n", kdevname(CURRENT->rq_dev)); xtrace(REQUEST, "end_request(0): bad device\n"); end_request(0); return; } if (stuffp->audio) { xwarn("do_request() attempt to read from audio cd\n"); xtrace(REQUEST, "end_request(0): read from audio\n"); end_request(0); return; } xtrace(REQUEST, "do_request() (%lu + %lu)\n", CURRENT->sector, CURRENT->nr_sectors); switch (CURRENT->cmd) { case WRITE: xwarn("do_request(): attempt to write to cd!!\n"); xtrace(REQUEST, "end_request(0): write\n"); end_request(0); return; case READ: stuffp->status = 0; while (CURRENT->nr_sectors) { int i; i = mcdx_transfer(stuffp, CURRENT->buffer, CURRENT->sector, CURRENT->nr_sectors); if (i == -1) { end_request(0); goto again; } CURRENT->sector += i; CURRENT->nr_sectors -= i; CURRENT->buffer += (i * 512); } end_request(1); goto again; xtrace(REQUEST, "end_request(1)\n"); end_request(1); break; default: panic(MCDX "do_request: unknown command.\n"); break; } goto again;}static int mcdx_open(struct cdrom_device_info * cdi, int purpose){ struct s_drive_stuff *stuffp; xtrace(OPENCLOSE, "open()\n"); stuffp = mcdx_stuffp[MINOR(cdi->dev)]; if (!stuffp->present) return -ENXIO; /* Make the modules looking used ... (thanx bjorn). * But we shouldn't forget to decrement the module counter * on error return */ MOD_INC_USE_COUNT; /* this is only done to test if the drive talks with us */ if (-1 == mcdx_getstatus(stuffp, 1)) { MOD_DEC_USE_COUNT; return -EIO; } if (stuffp->xxx) { xtrace(OPENCLOSE, "open() media changed\n"); stuffp->audiostatus = CDROM_AUDIO_INVALID; stuffp->readcmd = 0; xtrace(OPENCLOSE, "open() Request multisession info\n"); if (-1 == mcdx_requestmultidiskinfo( stuffp, &stuffp->multi, 6)) xinfo("No multidiskinfo\n"); } else { /* multisession ? */ if (!stuffp->multi.multi) stuffp->multi.msf_last.second = 2; xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n", stuffp->multi.multi, stuffp->multi.msf_last.minute, stuffp->multi.msf_last.second, stuffp->multi.msf_last.frame); { ; } /* got multisession information */ /* request the disks table of contents (aka diskinfo) */ if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) { stuffp->lastsector = -1; } else { stuffp->lastsector = (CD_FRAMESIZE / 512) * msf2log(&stuffp->di.msf_leadout) - 1; xtrace(OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n", stuffp->di.n_first, stuffp->di.msf_first.minute, stuffp->di.msf_first.second, stuffp->di.msf_first.frame, msf2log(&stuffp->di.msf_first)); xtrace(OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n", stuffp->di.n_last, stuffp->di.msf_leadout.minute, stuffp->di.msf_leadout.second, stuffp->di.msf_leadout.frame, msf2log(&stuffp->di.msf_leadout)); } if (stuffp->toc) { xtrace(MALLOC, "open() free old toc @ %p\n", stuffp->toc); kfree(stuffp->toc); stuffp->toc = NULL; } xtrace(OPENCLOSE, "open() init irq generation\n"); if (-1 == mcdx_config(stuffp, 1)) { MOD_DEC_USE_COUNT; return -EIO; }#if FALLBACK /* Set the read speed */ xwarn("AAA %x AAA\n", stuffp->readcmd); if (stuffp->readerrs) stuffp->readcmd = READ1X; else stuffp->readcmd = stuffp->present | SINGLE ? READ1X : READ2X; xwarn("XXX %x XXX\n", stuffp->readcmd);#else stuffp->readcmd = stuffp->present | SINGLE ? READ1X : READ2X;#endif /* try to get the first sector, iff any ... */ if (stuffp->lastsector >= 0) { char buf[512]; int ans; int tries; stuffp->xa = 0; stuffp->audio = 0; for (tries = 6; tries; tries--) { stuffp->introk = 1; xtrace(OPENCLOSE, "open() try as %s\n", stuffp->xa ? "XA" : "normal"); /* set data mode */ if (-1 == (ans = mcdx_setdatamode(stuffp, stuffp->xa ? MODE2 : MODE1, 1))) { /* MOD_DEC_USE_COUNT, return -EIO; */ stuffp->xa = 0; break; } if ((stuffp->audio = e_audio(ans))) break; while (0 == (ans = mcdx_transfer(stuffp, buf, 0, 1))) ; if (ans == 1) break; stuffp->xa = !stuffp->xa; } } /* xa disks will be read in raw mode, others not */ if (-1 == mcdx_setdrivemode(stuffp, stuffp->xa ? RAW : COOKED, 1)) { MOD_DEC_USE_COUNT; return -EIO; } if (stuffp->audio) { xinfo("open() audio disk found\n"); } else if (stuffp->lastsector >= 0) { xinfo("open() %s%s disk found\n", stuffp->xa ? "XA / " : "", stuffp->multi.multi ? "Multi Session" : "Single Session"); } } stuffp->xxx = 0; stuffp->users++; return 0;}static void mcdx_close(struct cdrom_device_info * cdi){ struct s_drive_stuff *stuffp; xtrace(OPENCLOSE, "close()\n"); stuffp = mcdx_stuffp[MINOR(cdi->dev)]; --stuffp->users; MOD_DEC_USE_COUNT;}static int mcdx_media_changed(struct cdrom_device_info * cdi, int disc_nr) /* Return: 1 if media changed since last call to this function 0 otherwise */{ struct s_drive_stuff *stuffp; xinfo("mcdx_media_changed called for device %s\n", kdevname(cdi->dev)); stuffp = mcdx_stuffp[MINOR(cdi->dev)]; mcdx_getstatus(stuffp, 1); if (stuffp->yyy == 0) return 0; stuffp->yyy = 0; return 1;}__initfunc(void mcdx_setup(char *str, int *pi)){ if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1]; if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];}/* DIRTY PART ******************************************************/static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)/* This routine is used for sleeping. * A jifs value <0 means NO sleeping, * =0 means minimal sleeping (let the kernel * run for other processes) * >0 means at least sleep for that amount. * May be we could use a simple count loop w/ jumps to itself, but * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */{ if (jifs < 0) return; xtrace(SLEEP, "*** delay: sleepq\n"); interruptible_sleep_on_timeout(&stuff->sleepq, jifs); xtrace(SLEEP, "delay awoken\n"); if (signal_pending(current)) { xtrace(SLEEP, "got signal\n"); }}static voidmcdx_intr(int irq, void *dev_id, struct pt_regs* regs){ struct s_drive_stuff *stuffp; unsigned char b; stuffp = mcdx_irq_map[irq]; if (stuffp == NULL ) { xwarn("mcdx: no device for intr %d\n", irq); return; }#ifdef AK2 if ( !stuffp->busy && stuffp->pending ) stuffp->int_err = 1;#endif /* AK2 */ /* get the interrupt status */ b = inb((unsigned int) stuffp->rreg_status); stuffp->introk = ~b & MCDX_RBIT_DTEN; /* NOTE: We only should get interrupts if the data we * requested are ready to transfer. * But the drive seems to generate ``asynchronous'' interrupts * on several error conditions too. (Despite the err int enable * setting during initialisation) */ /* if not ok, read the next byte as the drives status */ if (!stuffp->introk) { xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b); if (~b & MCDX_RBIT_STEN) { xinfo( "intr() irq %d status 0x%02x\n", irq, inb((unsigned int) stuffp->rreg_data)); } else { xinfo( "intr() irq %d ambiguous hw status\n", irq); } } else { xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b); } stuffp->busy = 0; wake_up_interruptible(&stuffp->busyq);}static intmcdx_talk ( struct s_drive_stuff *stuffp, const unsigned char *cmd, size_t cmdlen, void *buffer, size_t size, unsigned int timeout, int tries)/* Send a command to the drive, wait for the result. * returns -1 on timeout, drive status otherwise * If buffer is not zero, the result (length size) is stored there. * If buffer is zero the size should be the number of bytes to read * from the drive. These bytes are discarded. */{ int st; char c; int discard; /* Somebody wants the data read? */ if ((discard = (buffer == NULL))) buffer = &c; while (stuffp->lock) { xtrace(SLEEP, "*** talk: lockq\n"); interruptible_sleep_on(&stuffp->lockq); xtrace(SLEEP, "talk: awoken\n"); } stuffp->lock = 1; /* An operation other then reading data destroys the * data already requested and remembered in stuffp->request, ... */ stuffp->valid = 0;#if MCDX_DEBUG & TALK { unsigned char i; xtrace(TALK, "talk() %d / %d tries, res.size %d, command 0x%02x", tries, timeout, size, (unsigned char) cmd[0]); for (i = 1; i < cmdlen; i++) xtrace(TALK, " 0x%02x", cmd[i]); xtrace(TALK, "\n"); }#endif /* give up if all tries are done (bad) or if the status * st != -1 (good) */ for (st = -1; st == -1 && tries; tries--) { char *bp = (char*) buffer; size_t sz = size; outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen); xtrace(TALK, "talk() command sent\n"); /* get the status byte */ if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) { xinfo("talk() %02x timed out (status), %d tr%s left\n", cmd[0], tries - 1, tries == 2 ? "y" : "ies"); continue; } st = *bp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -