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

📄 mcdx.c

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