⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mcdx.c

📁 cdrom device drive for linux.
💻 C
📖 第 1 页 / 共 4 页
字号:
		    (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 + -