📄 mcdx.c
字号:
if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE) > stuffp->lastsector + 1) { xtrace(XFER, "cut high_border\n"); stuffp->high_border = stuffp->lastsector + 1; } { /* Convert the sector to be requested to MSF format */ struct cdrom_msf0 pending; log2msf(stuffp->pending / 4, &pending); cmd[1] = pending.minute; cmd[2] = pending.second; cmd[3] = pending.frame; } cmd[6] = (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 intmcdx_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 intmcdx_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 intmcdx_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 intmcdx_stop(struct s_drive_stuff *stuffp, int tries){ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); }static intmcdx_hold(struct s_drive_stuff *stuffp, int tries){ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); }static intmcdx_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 intmcdx_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 intmcdx_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 intmcdx_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 intmcdx_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 intmcdx_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 intmcdx_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 intmcdx_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 intmcdx_getstatus(struct s_drive_stuff *stuffp, int tries){ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); }static intmcdx_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 intmcdx_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);}/* ex:set ts=4 sw=4 ai si: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -