📄 mcdx.c
字号:
(unsigned
char) ((stuffp->high_border - stuffp->pending) / 4);
xtrace(XFER, "[%2d]\n", cmd[6]);
stuffp->busy = 1;
/* Now really issue the request command */
outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
}
#ifdef AK2
if (stuffp->int_err) {
stuffp->valid = 0;
stuffp->int_err = 0;
return -1;
}
#endif /* AK2 */
stuffp->low_border = (stuffp->low_border +=
done) <
stuffp->high_border ? stuffp->low_border : stuffp->high_border;
return done;
}
/* Access to elements of the mcdx_drive_map members */
static char *port(int *ip)
{
return (char *) ip[0];
}
static int irq(int *ip)
{
return ip[1];
}
/* Misc number converters */
static unsigned int bcd2uint(unsigned char c)
{
return (c >> 4) * 10 + (c & 0x0f);
}
static unsigned int uint2bcd(unsigned int ival)
{
return ((ival / 10) << 4) | (ival % 10);
}
static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
{
l += CD_MSF_OFFSET;
pmsf->minute = uint2bcd(l / 4500), l %= 4500;
pmsf->second = uint2bcd(l / 75);
pmsf->frame = uint2bcd(l % 75);
}
static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
{
return bcd2uint(pmsf->frame)
+ bcd2uint(pmsf->second) * 75
+ bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
}
int mcdx_readtoc(struct s_drive_stuff *stuffp)
/* Read the toc entries from the CD,
* Return: -1 on failure, else 0 */
{
if (stuffp->toc) {
xtrace(READTOC, "ioctl() toc already read\n");
return 0;
}
xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
stuffp->di.n_last - stuffp->di.n_first + 1);
if (-1 == mcdx_hold(stuffp, 1))
return -1;
xtrace(READTOC, "ioctl() tocmode\n");
if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
return -EIO;
/* all seems to be ok so far ... malloc */
{
int size;
size =
sizeof(struct s_subqcode) * (stuffp->di.n_last -
stuffp->di.n_first + 2);
xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
stuffp->toc = kmalloc(size, GFP_KERNEL);
if (!stuffp->toc) {
xwarn("Cannot malloc %d bytes for toc\n", size);
mcdx_setdrivemode(stuffp, DATA, 1);
return -EIO;
}
}
/* now read actually the index */
{
int trk;
int retries;
for (trk = 0;
trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
trk++)
stuffp->toc[trk].index = 0;
for (retries = 300; retries; retries--) { /* why 300? */
struct s_subqcode q;
unsigned int idx;
if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
mcdx_setdrivemode(stuffp, DATA, 1);
return -EIO;
}
idx = bcd2uint(q.index);
if ((idx > 0)
&& (idx <= stuffp->di.n_last)
&& (q.tno == 0)
&& (stuffp->toc[idx - stuffp->di.n_first].
index == 0)) {
stuffp->toc[idx - stuffp->di.n_first] = q;
xtrace(READTOC,
"ioctl() toc idx %d (trk %d)\n",
idx, trk);
trk--;
}
if (trk == 0)
break;
}
memset(&stuffp->
toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
sizeof(stuffp->toc[0]));
stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1].dt = stuffp->di.msf_leadout;
}
/* unset toc mode */
xtrace(READTOC, "ioctl() undo toc mode\n");
if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
return -EIO;
#if MCDX_DEBUG && READTOC
{
int trk;
for (trk = 0;
trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
trk++)
xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
" %02x:%02x.%02x %02x:%02x.%02x\n",
trk + stuffp->di.n_first,
stuffp->toc[trk].control,
stuffp->toc[trk].tno,
stuffp->toc[trk].index,
stuffp->toc[trk].tt.minute,
stuffp->toc[trk].tt.second,
stuffp->toc[trk].tt.frame,
stuffp->toc[trk].dt.minute,
stuffp->toc[trk].dt.second,
stuffp->toc[trk].dt.frame);
}
#endif
return 0;
}
static int
mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
{
unsigned char cmd[7] = {
0, 0, 0, 0, 0, 0, 0
};
if (!stuffp->readcmd) {
xinfo("Can't play from missing disk.\n");
return -1;
}
cmd[0] = stuffp->playcmd;
cmd[1] = msf->cdmsf_min0;
cmd[2] = msf->cdmsf_sec0;
cmd[3] = msf->cdmsf_frame0;
cmd[4] = msf->cdmsf_min1;
cmd[5] = msf->cdmsf_sec1;
cmd[6] = msf->cdmsf_frame1;
xtrace(PLAYMSF, "ioctl(): play %x "
"%02x:%02x:%02x -- %02x:%02x:%02x\n",
cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
xwarn("playmsf() timeout\n");
return -1;
}
stuffp->audiostatus = CDROM_AUDIO_PLAY;
return 0;
}
static int
mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
{
struct s_subqcode *p;
struct cdrom_msf msf;
if (-1 == mcdx_readtoc(stuffp))
return -1;
if (ti)
p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
else
p = &stuffp->start;
msf.cdmsf_min0 = p->dt.minute;
msf.cdmsf_sec0 = p->dt.second;
msf.cdmsf_frame0 = p->dt.frame;
if (ti) {
p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
stuffp->stop = *p;
} else
p = &stuffp->stop;
msf.cdmsf_min1 = p->dt.minute;
msf.cdmsf_sec1 = p->dt.second;
msf.cdmsf_frame1 = p->dt.frame;
return mcdx_playmsf(stuffp, &msf);
}
/* Drive functions ************************************************/
static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
{
struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
if (!stuffp->present)
return -ENXIO;
if (!(stuffp->present & DOOR))
return -ENOSYS;
if (position) /* 1: eject */
return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
else /* 0: close */
return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
return 1;
}
static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
{
return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
}
static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
{
return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
}
static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
struct s_subqcode *sub, int tries)
{
char buf[11];
int ans;
if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
2 * HZ, tries)))
return -1;
sub->control = buf[1];
sub->tno = buf[2];
sub->index = buf[3];
sub->tt.minute = buf[4];
sub->tt.second = buf[5];
sub->tt.frame = buf[6];
sub->dt.minute = buf[8];
sub->dt.second = buf[9];
sub->dt.frame = buf[10];
return ans;
}
static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
struct s_multi *multi, int tries)
{
char buf[5];
int ans;
if (stuffp->present & MULTI) {
ans =
mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
tries);
multi->multi = buf[1];
multi->msf_last.minute = buf[2];
multi->msf_last.second = buf[3];
multi->msf_last.frame = buf[4];
return ans;
} else {
multi->multi = 0;
return 0;
}
}
static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
int tries)
{
char buf[9];
int ans;
ans =
mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
if (ans == -1) {
info->n_first = 0;
info->n_last = 0;
} else {
info->n_first = bcd2uint(buf[1]);
info->n_last = bcd2uint(buf[2]);
info->msf_leadout.minute = buf[3];
info->msf_leadout.second = buf[4];
info->msf_leadout.frame = buf[5];
info->msf_first.minute = buf[6];
info->msf_first.second = buf[7];
info->msf_first.frame = buf[8];
}
return ans;
}
static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
int tries)
{
char cmd[2];
int ans;
xtrace(HW, "setdrivemode() %d\n", mode);
if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
return -1;
switch (mode) {
case TOC:
cmd[1] |= 0x04;
break;
case DATA:
cmd[1] &= ~0x04;
break;
case RAW:
cmd[1] |= 0x40;
break;
case COOKED:
cmd[1] &= ~0x40;
break;
default:
break;
}
cmd[0] = 0x50;
return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
}
static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
int tries)
{
unsigned char cmd[2] = { 0xa0 };
xtrace(HW, "setdatamode() %d\n", mode);
switch (mode) {
case MODE0:
cmd[1] = 0x00;
break;
case MODE1:
cmd[1] = 0x01;
break;
case MODE2:
cmd[1] = 0x02;
break;
default:
return -EINVAL;
}
return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
}
static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
{
char cmd[4];
xtrace(HW, "config()\n");
cmd[0] = 0x90;
cmd[1] = 0x10; /* irq enable */
cmd[2] = 0x05; /* pre, err irq enable */
if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
return -1;
cmd[1] = 0x02; /* dma select */
cmd[2] = 0x00; /* no dma */
return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
}
static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
int tries)
{
char buf[3];
int ans;
if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1, buf, sizeof(buf), 2 * HZ, tries)))
return ans;
ver->code = buf[1];
ver->ver = buf[2];
return ans;
}
static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
{
if (mode == HARD) {
outb(0, (unsigned int) stuffp->wreg_chn); /* no dma, no irq -> hardware */
outb(0, (unsigned int) stuffp->wreg_reset); /* hw reset */
return 0;
} else
return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
}
static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
{
struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
char cmd[2] = { 0xfe };
if (!(stuffp->present & DOOR))
return -ENOSYS;
if (stuffp->present & DOOR) {
cmd[1] = lock ? 0x01 : 0x00;
return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
} else
return 0;
}
static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
{
return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
}
static int
mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
{
unsigned long timeout = to + jiffies;
char c;
if (!buf)
buf = &c;
while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
if (time_after(jiffies, timeout))
return -1;
mcdx_delay(stuffp, delay);
}
*buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff;
return 0;
}
static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
struct cdrom_volctrl *vol, int tries)
{
char cmd[5];
cmd[0] = 0xae;
cmd[1] = vol->channel0;
cmd[2] = 0;
cmd[3] = vol->channel1;
cmd[4] = 0;
return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
}
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -