📄 mcdx.c
字号:
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:
return -EINVAL;
}
}
void do_mcdx_request(request_queue_t * q)
{
int dev;
struct s_drive_stuff *stuffp;
again:
if (QUEUE_EMPTY) {
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 */
/* this is only done to test if the drive talks with us */
if (-1 == mcdx_getstatus(stuffp, 1))
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))
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))) {
/* 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))
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;
}
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;
}
#ifndef MODULE
static int __init mcdx_setup(char *str)
{
int pi[4];
(void) get_options(str, ARRAY_SIZE(pi), pi);
if (pi[0] > 0)
mcdx_drive_map[0][0] = pi[1];
if (pi[0] > 1)
mcdx_drive_map[0][1] = pi[2];
return 1;
}
__setup("mcdx=", mcdx_setup);
#endif
/* 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 void mcdx_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 int mcdx_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;
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -