Ejemplo n.º 1
0
static int 
mcd_tray_move(struct cdrom_device_info * cdi, int position)
{
	int i;
	if (position) {
	/*  Eject */
       		/* all drives can at least stop! */
		if (audioStatus == CDROM_AUDIO_PLAY) {
	  	outb(MCMD_STOP, MCDPORT(0));
	  	i = getMcdStatus(MCD_STATUS_DELAY);
		}

                audioStatus = CDROM_AUDIO_NO_STATUS;

                outb(MCMD_EJECT, MCDPORT(0));
                /*
                 * the status (i) shows failure on all but the FX drives.
                 * But nothing we can do about that in software!
                 * So just read the status and forget it. - Jon.
                 */
                i = getMcdStatus(MCD_STATUS_DELAY);
                return 0;
	}
	else 
		return -EINVAL;
}
Ejemplo n.º 2
0
static int mcdStatus(void)
{
	int i;
	int st;

	st = inb(MCDPORT(1)) & MFL_STATUS;
	if (!st) {
		i = inb(MCDPORT(0)) & 0xFF;
		return i;
	} else
		return -1;
}
Ejemplo n.º 3
0
static void mcd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	int st;

	st = inb(MCDPORT(1)) & 0xFF;
	test1(printk("<int1-%02X>", st));
	if (!(st & MFL_STATUS)) {
		st = inb(MCDPORT(0)) & 0xFF;
		test1(printk("<int0-%02X>", st));
		if ((st & 0xFF) != 0xFF)
			mcd_error = st ? st & 0xFF : -1;
	}
}
Ejemplo n.º 4
0
int
GetQChannelInfo(struct mcd_Toc *qp)
{
	unsigned char notUsed;
	int retry;

	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
	{
		outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
			break;
	}

	if (retry >= MCD_RETRY_ATTEMPTS)
		return -1;

	if (getValue(&qp -> ctrl_addr) < 0) return -1;
	if (getValue(&qp -> track) < 0) return -1;
	if (getValue(&qp -> pointIndex) < 0) return -1;
	if (getValue(&qp -> trackTime.min) < 0) return -1;
	if (getValue(&qp -> trackTime.sec) < 0) return -1;
	if (getValue(&qp -> trackTime.frame) < 0) return -1;
	if (getValue(&notUsed) < 0) return -1;
	if (getValue(&qp -> diskTime.min) < 0) return -1;
	if (getValue(&qp -> diskTime.sec) < 0) return -1;
	if (getValue(&qp -> diskTime.frame) < 0) return -1;

	return 0;
}
Ejemplo n.º 5
0
static int
getMcdStatus(int timeout)
{
	int st;

	McdTimeout = timeout;
	SET_TIMER(mcdStatTimer, 1);
	sleep_on(&mcd_waitq);
	if (McdTimeout <= 0)
		return -1;

	st = inb(MCDPORT(0)) & 0xFF;
	if (st == 0xFF)
		return -1;

	if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
		/* XXX might be an error? look at q-channel? */
		audioStatus = CDROM_AUDIO_COMPLETED;

	if (st & MST_DSK_CHG)
	{
		mcdDiskChanged = 1;
		tocUpToDate = 0;
		audioStatus = CDROM_AUDIO_NO_STATUS;
	}

	return st;
}
Ejemplo n.º 6
0
static int getValue(unsigned char *result)
{
	int count;
	int s;

	for (count = 0; count < 2000; count++)
		if (!(inb(MCDPORT(1)) & MFL_STATUS))
			break;

	if (count >= 2000) {
		printk("mcd: getValue timeout\n");
		return -1;
	}

	s = inb(MCDPORT(0)) & 0xFF;
	*result = (unsigned char) s;
	return 0;
}
Ejemplo n.º 7
0
static void sendMcdCmd(int cmd, struct mcd_Play_msf *params)
{
	outb(cmd, MCDPORT(0));
	outb(params->start.min, MCDPORT(0));
	outb(params->start.sec, MCDPORT(0));
	outb(params->start.frame, MCDPORT(0));
	outb(params->end.min, MCDPORT(0));
	outb(params->end.sec, MCDPORT(0));
	outb(params->end.frame, MCDPORT(0));
}
Ejemplo n.º 8
0
static void mcdStatTimer(unsigned long dummy)
{
	if (!(inb(MCDPORT(1)) & MFL_STATUS)) {
		wake_up(&mcd_waitq);
		return;
	}

	McdTimeout--;
	if (McdTimeout <= 0) {
		wake_up(&mcd_waitq);
		return;
	}
	mcd_timer.function = mcdStatTimer;
	mod_timer(&mcd_timer, jiffies + 1);
}
Ejemplo n.º 9
0
static int statusCmd(void)
{
	int st = -1, retry;

	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
		/* send get-status cmd */
		outb(MCMD_GET_STATUS, MCDPORT(0));

		st = getMcdStatus(MCD_STATUS_DELAY);
		if (st != -1)
			break;
	}

	return st;
}
Ejemplo n.º 10
0
static int GetDiskInfo(void)
{
	int retry;

	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
		outb(MCMD_GET_DISK_INFO, MCDPORT(0));
		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
			break;
	}

	if (retry >= MCD_RETRY_ATTEMPTS)
		return -1;

	if (getValue(&DiskInfo.first) < 0)
		return -1;
	if (getValue(&DiskInfo.last) < 0)
		return -1;

	DiskInfo.first = bcd2bin(DiskInfo.first);
	DiskInfo.last = bcd2bin(DiskInfo.last);

#ifdef MCD_DEBUG
	printk
	    ("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
	     DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
	     DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
	     DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
	     DiskInfo.firstTrack.frame);
#endif

	if (getValue(&DiskInfo.diskLength.min) < 0)
		return -1;
	if (getValue(&DiskInfo.diskLength.sec) < 0)
		return -1;
	if (getValue(&DiskInfo.diskLength.frame) < 0)
		return -1;
	if (getValue(&DiskInfo.firstTrack.min) < 0)
		return -1;
	if (getValue(&DiskInfo.firstTrack.sec) < 0)
		return -1;
	if (getValue(&DiskInfo.firstTrack.frame) < 0)
		return -1;

	return 0;
}
Ejemplo n.º 11
0
static void
mcdStatTimer(void)
{
	if (!(inb(MCDPORT(1)) & MFL_STATUS))
	{
		wake_up(&mcd_waitq);
		return;
	}

	McdTimeout--;
	if (McdTimeout <= 0)
	{
		wake_up(&mcd_waitq);
		return;
	}

	SET_TIMER(mcdStatTimer, 1);
}
Ejemplo n.º 12
0
static int
GetToc()
{
	int i, px;
	int limit;
	int retry;
	struct mcd_Toc qInfo;

	for (i = 0; i < MAX_TRACKS; i++)
		Toc[i].pointIndex = 0;

	i = DiskInfo.last + 3;

	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
	{
		outb(MCMD_STOP, MCDPORT(0));
		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
			break;
	}

	if (retry >= MCD_RETRY_ATTEMPTS)
		return -1;

	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
	{
		outb(MCMD_SET_MODE, MCDPORT(0));
		outb(0x05, MCDPORT(0));			/* mode: toc */
		mcd_mode = 0x05;
		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
			break;
	}

	if (retry >= MCD_RETRY_ATTEMPTS)
		return -1;

	for (limit = 300; limit > 0; limit--)
	{
		if (GetQChannelInfo(&qInfo) < 0)
			break;

		px = bcd2bin(qInfo.pointIndex);
		if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
			if (Toc[px].pointIndex == 0)
			{
				Toc[px] = qInfo;
				i--;
			}

		if (i <= 0)
			break;
	}

	Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;

	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
	{
                outb(MCMD_SET_MODE, MCDPORT(0));
                outb(0x01, MCDPORT(0));
		mcd_mode = 1;
                if (getMcdStatus(MCD_STATUS_DELAY) != -1)
                        break;
	}

#ifdef MCD_DEBUG
for (i = 1; i <= DiskInfo.last; i++)
printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
for (i = 100; i < 103; i++)
printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
#endif

	return limit > 0 ? 0 : -1;
}
Ejemplo n.º 13
0
__initfunc(int mcd_init(void))
{
	int count;
	unsigned char result[3];
	char msg[80];

	if (mcd_port <= 0 || mcd_irq <= 0) {
	  printk("skip mcd_init\n");
          return -EIO;
	}

	if (register_blkdev(MAJOR_NR, "mcd", &cdrom_fops) != 0)
	{
		printk("Unable to get major %d for Mitsumi CD-ROM\n",
		       MAJOR_NR);
                return -EIO;
	}
        if (check_region(mcd_port, 4)) {
	  cleanup(1);
	  printk("Init failed, I/O port (%X) already in use\n",
		 mcd_port);
          return -EIO;
	}

	blksize_size[MAJOR_NR] = mcd_blocksizes;
	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
	read_ahead[MAJOR_NR] = 4;

	/* check for card */

	outb(0, MCDPORT(1));			/* send reset */
	for (count = 0; count < 2000000; count++)
		(void) inb(MCDPORT(1));		/* delay a bit */

	outb(0x40, MCDPORT(0));	                /* send get-stat cmd */
	for (count = 0; count < 2000000; count++)
		if (!(inb(MCDPORT(1)) & MFL_STATUS))
			break;

	if (count >= 2000000) {
		printk("Init failed. No mcd device at 0x%x irq %d\n",
		     mcd_port, mcd_irq);
		cleanup(1);
                return -EIO;
	}
	count = inb(MCDPORT(0));		/* pick up the status */
	
	outb(MCMD_GET_VERSION,MCDPORT(0));
	for(count=0;count<3;count++)
		if(getValue(result+count)) {
			printk("mitsumi get version failed at 0x%d\n",
			       mcd_port);
                        cleanup(1);
                        return -EIO;
		}	

	if (result[0] == result[1] && result[1] == result[2]) {
		cleanup(1);
                return -EIO;
	}

	mcdVersion=result[2];

	if (mcdVersion >=4)
		outb(4,MCDPORT(2)); 	/* magic happens */

	/* don't get the IRQ until we know for sure the drive is there */

	if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL))
	{
		printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
		cleanup(1);
                return -EIO;
	}

        if (result[1] == 'D') 
	{
		sprintf(msg, " mcd: Mitsumi Double Speed CD-ROM at port=0x%x,"
			     " irq=%d\n", mcd_port, mcd_irq);
		MCMD_DATA_READ = MCMD_2X_READ;

		mcd_info.speed = 2;
		/* Added flag to drop to 1x speed if too many errors */
		mcdDouble = 1;
        } else {
		sprintf(msg, " mcd: Mitsumi Single Speed CD-ROM at port=0x%x,"
			     " irq=%d\n", mcd_port, mcd_irq);
		mcd_info.speed = 2;
	}

	request_region(mcd_port, 4, "mcd");

	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
	outb(0x02,MCDPORT(0));
	outb(0x00,MCDPORT(0));
	getValue(result);

	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
	outb(0x10,MCDPORT(0));
	outb(0x04,MCDPORT(0));
	getValue(result);

	mcd_invalidate_buffers();
	mcdPresent = 1;

	mcd_info.dev = MKDEV(MAJOR_NR,0);

        if (register_cdrom(&mcd_info) != 0) {
              printk("Cannot register Mitsumi CD-ROM!\n");
              cleanup(3);
              return -EIO;
        }
        printk(msg);

	return 0;
}
Ejemplo n.º 14
0
int __init mcd_init(void)
{
	struct gendisk *disk = alloc_disk(1);
	int count;
	unsigned char result[3];
	char msg[80];

	if (!disk) {
		printk(KERN_INFO "mcd: can't allocated disk.\n");
		return -ENOMEM;
	}
	if (mcd_port <= 0 || mcd_irq <= 0) {
		printk(KERN_INFO "mcd: not probing.\n");
		put_disk(disk);
		return -EIO;
	}
	if (register_blkdev(MAJOR_NR, "mcd")) {
		put_disk(disk);
		return -EIO;
	}
	if (!request_region(mcd_port, 4, "mcd")) {
		printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port);
		goto out_region;
	}

	mcd_queue = blk_init_queue(do_mcd_request, &mcd_spinlock);
	if (!mcd_queue)
		goto out_queue;

	/* check for card */

	outb(0, MCDPORT(1));	/* send reset */
	for (count = 0; count < 2000000; count++)
		(void) inb(MCDPORT(1));	/* delay a bit */

	outb(0x40, MCDPORT(0));	/* send get-stat cmd */
	for (count = 0; count < 2000000; count++)
		if (!(inb(MCDPORT(1)) & MFL_STATUS))
			break;

	if (count >= 2000000) {
		printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n",
		       mcd_port, mcd_irq);
		goto out_probe;
	}
	count = inb(MCDPORT(0));	/* pick up the status */

	outb(MCMD_GET_VERSION, MCDPORT(0));
	for (count = 0; count < 3; count++)
		if (getValue(result + count)) {
			printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n",
			       mcd_port);
			goto out_probe;
		}

	if (result[0] == result[1] && result[1] == result[2])
		goto out_probe;

	mcdVersion = result[2];

	if (mcdVersion >= 4)
		outb(4, MCDPORT(2));	/* magic happens */

	/* don't get the IRQ until we know for sure the drive is there */

	if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
		printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
		goto out_probe;
	}

	if (result[1] == 'D') {
		MCMD_DATA_READ = MCMD_2X_READ;
		/* Added flag to drop to 1x speed if too many errors */
		mcdDouble = 1;
	} else
		mcd_info.speed = 1;
	sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
		" irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double",
		mcd_port, mcd_irq);

	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
	outb(0x02, MCDPORT(0));
	outb(0x00, MCDPORT(0));
	getValue(result);

	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
	outb(0x10, MCDPORT(0));
	outb(0x04, MCDPORT(0));
	getValue(result);

	mcd_invalidate_buffers();
	mcdPresent = 1;

	disk->major = MAJOR_NR;
	disk->first_minor = 0;
	sprintf(disk->disk_name, "mcd");
	disk->fops = &mcd_bdops;
	disk->flags = GENHD_FL_CD;
	mcd_gendisk = disk;

	if (register_cdrom(&mcd_info) != 0) {
		printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n");
		goto out_cdrom;
	}
	disk->queue = mcd_queue;
	add_disk(disk);
	printk(msg);
	return 0;

out_cdrom:
	free_irq(mcd_irq, NULL);
out_queue:
	release_region(mcd_port, 4);
out_probe:
	blk_cleanup_queue(mcd_queue);
out_region:
	unregister_blkdev(MAJOR_NR, "mcd");
	put_disk(disk);
	return -EIO;
}
Ejemplo n.º 15
0
static int
mcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
          unsigned long arg)
{
    int i, st;
    struct mcd_Toc qInfo;
    struct cdrom_ti ti;
    struct cdrom_tochdr tocHdr;
    struct cdrom_msf msf;
    struct cdrom_tocentry entry;
    struct mcd_Toc *tocPtr;
    struct cdrom_subchnl subchnl;
    struct cdrom_volctrl volctrl;

    if (!ip)
        return -EINVAL;

    st = statusCmd();
    if (st < 0)
        return -EIO;

    if (!tocUpToDate)
    {
        i = updateToc();
        if (i < 0)
            /* [email protected]:
            We _can_ open the door even without a CD */
            if (cmd != CDROMEJECT)
                return i;	/* error reading TOC */
    }

    switch (cmd)
    {
    case CDROMSTART:     /* Spin up the drive */
        /* Don't think we can do this.  Even if we could,
         * I think the drive times out and stops after a while
         * anyway.  For now, ignore it.
         */

        return 0;

    case CDROMSTOP:      /* Spin down the drive */
        outb(MCMD_STOP, MCDPORT(0));
        i = getMcdStatus(MCD_STATUS_DELAY);

        /* should we do anything if it fails? */

        audioStatus = CDROM_AUDIO_NO_STATUS;
        return 0;

    case CDROMPAUSE:     /* Pause the drive */
        if (audioStatus != CDROM_AUDIO_PLAY)
            return -EINVAL;

        outb(MCMD_STOP, MCDPORT(0));
        i = getMcdStatus(MCD_STATUS_DELAY);

        if (GetQChannelInfo(&qInfo) < 0)
        {
            /* didn't get q channel info */

            audioStatus = CDROM_AUDIO_NO_STATUS;
            return 0;
        }

        mcd_Play.start = qInfo.diskTime;	/* remember restart point */

        audioStatus = CDROM_AUDIO_PAUSED;
        return 0;

    case CDROMRESUME:    /* Play it again, Sam */
        if (audioStatus != CDROM_AUDIO_PAUSED)
            return -EINVAL;

        /* restart the drive at the saved position. */

        i = mcdPlay(&mcd_Play);
        if (i < 0)
        {
            audioStatus = CDROM_AUDIO_ERROR;
            return -EIO;
        }

        audioStatus = CDROM_AUDIO_PLAY;
        return 0;

    case CDROMPLAYTRKIND:     /* Play a track.  This currently ignores index. */

        st = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
        if (st)
            return st;

        memcpy_fromfs(&ti, (void *) arg, sizeof ti);

        if (ti.cdti_trk0 < DiskInfo.first
                || ti.cdti_trk0 > DiskInfo.last
                || ti.cdti_trk1 < ti.cdti_trk0)
        {
            return -EINVAL;
        }

        if (ti.cdti_trk1 > DiskInfo.last)
            ti. cdti_trk1 = DiskInfo.last;

        mcd_Play.start = Toc[ti.cdti_trk0].diskTime;
        mcd_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;

#ifdef MCD_DEBUG
        printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
               mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
               mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
#endif

        i = mcdPlay(&mcd_Play);
        if (i < 0)
        {
            audioStatus = CDROM_AUDIO_ERROR;
            return -EIO;
        }

        audioStatus = CDROM_AUDIO_PLAY;
        return 0;

    case CDROMPLAYMSF:   /* Play starting at the given MSF address. */

        if (audioStatus == CDROM_AUDIO_PLAY) {
            outb(MCMD_STOP, MCDPORT(0));
            i = getMcdStatus(MCD_STATUS_DELAY);
            audioStatus = CDROM_AUDIO_NO_STATUS;
        }

        st = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
        if (st)
            return st;

        memcpy_fromfs(&msf, (void *) arg, sizeof msf);

        /* convert to bcd */

        bin2bcd(&msf.cdmsf_min0);
        bin2bcd(&msf.cdmsf_sec0);
        bin2bcd(&msf.cdmsf_frame0);
        bin2bcd(&msf.cdmsf_min1);
        bin2bcd(&msf.cdmsf_sec1);
        bin2bcd(&msf.cdmsf_frame1);

        mcd_Play.start.min = msf.cdmsf_min0;
        mcd_Play.start.sec = msf.cdmsf_sec0;
        mcd_Play.start.frame = msf.cdmsf_frame0;
        mcd_Play.end.min = msf.cdmsf_min1;
        mcd_Play.end.sec = msf.cdmsf_sec1;
        mcd_Play.end.frame = msf.cdmsf_frame1;

#ifdef MCD_DEBUG
        printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
               mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
               mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
#endif

        i = mcdPlay(&mcd_Play);
        if (i < 0)
        {
            audioStatus = CDROM_AUDIO_ERROR;
            return -EIO;
        }

        audioStatus = CDROM_AUDIO_PLAY;
        return 0;

    case CDROMREADTOCHDR:        /* Read the table of contents header */
        st = verify_area(VERIFY_WRITE, (void *) arg, sizeof tocHdr);
        if (st)
            return st;

        tocHdr.cdth_trk0 = DiskInfo.first;
        tocHdr.cdth_trk1 = DiskInfo.last;
        memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
        return 0;

    case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */

        st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
        if (st)
            return st;

        memcpy_fromfs(&entry, (void *) arg, sizeof entry);
        if (entry.cdte_track == CDROM_LEADOUT)
            /* XXX */
            tocPtr = &Toc[DiskInfo.last + 1];

        else if (entry.cdte_track > DiskInfo.last
                 || entry.cdte_track < DiskInfo.first)
            return -EINVAL;

        else
            tocPtr = &Toc[entry.cdte_track];

        entry.cdte_adr = tocPtr -> ctrl_addr;
        entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;

        if (entry.cdte_format == CDROM_LBA)
            entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);

        else if (entry.cdte_format == CDROM_MSF)
        {
            entry.cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min);
            entry.cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec);
            entry.cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame);
        }

        else
            return -EINVAL;

        memcpy_tofs((void *) arg, &entry, sizeof entry);
        return 0;

    case CDROMSUBCHNL:   /* Get subchannel info */

        st = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
        if (st)
            return st;

        memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);

        if (GetQChannelInfo(&qInfo) < 0)
            return -EIO;

        subchnl.cdsc_audiostatus = audioStatus;
        subchnl.cdsc_adr = qInfo.ctrl_addr;
        subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
        subchnl.cdsc_trk = bcd2bin(qInfo.track);
        subchnl.cdsc_ind = bcd2bin(qInfo.pointIndex);

        if (subchnl.cdsc_format == CDROM_LBA)
        {
            subchnl.cdsc_absaddr.lba = msf2hsg(&qInfo.diskTime);
            subchnl.cdsc_reladdr.lba = msf2hsg(&qInfo.trackTime);
        }

        else if (subchnl.cdsc_format == CDROM_MSF)
        {
            subchnl.cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
            subchnl.cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
            subchnl.cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);

            subchnl.cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
            subchnl.cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
            subchnl.cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
        }

        else
            return -EINVAL;

        memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
        return 0;

    case CDROMVOLCTRL:   /* Volume control */
        st = verify_area(VERIFY_READ, (void *) arg, sizeof(volctrl));
        if (st)
            return st;

        memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
        outb(MCMD_SET_VOLUME, MCDPORT(0));
        outb(volctrl.channel0, MCDPORT(0));
        outb(255, MCDPORT(0));
        outb(volctrl.channel1, MCDPORT(0));
        outb(255, MCDPORT(0));

        i = getMcdStatus(MCD_STATUS_DELAY);
        if (i < 0)
            return -EIO;

        {
            char a, b, c, d;

            getValue(&a);
            getValue(&b);
            getValue(&c);
            getValue(&d);
        }

        return 0;

    case CDROMEJECT:
        /* all drives can at least stop! */
        if (audioStatus == CDROM_AUDIO_PLAY) {
            outb(MCMD_STOP, MCDPORT(0));
            i = getMcdStatus(MCD_STATUS_DELAY);
        }

        audioStatus = CDROM_AUDIO_NO_STATUS;

        outb(MCMD_EJECT, MCDPORT(0));
        /*
         * the status (i) shows failure on all but the FX drives.
         * But nothing we can do about that in software!
         * So just read the status and forget it. - Jon.
         */
        i = getMcdStatus(MCD_STATUS_DELAY);
        return 0;
    default:
        return -EINVAL;
    }
}
Ejemplo n.º 16
0
int mcd_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,
                      void * arg)
{
	int i, st;
	struct mcd_Toc qInfo;
	struct cdrom_ti *ti;
	struct cdrom_tochdr *tocHdr;
	struct cdrom_msf *msf;
	struct cdrom_subchnl *subchnl;
	struct cdrom_tocentry *entry;
	struct mcd_Toc *tocPtr;
	struct cdrom_volctrl *volctrl;

	st = statusCmd();
	if (st < 0)
		return -EIO;

	if (!tocUpToDate)
	{
		i = updateToc();
		if (i < 0) 
			return i;	/* error reading TOC */
	}

	switch (cmd)
	{
	case CDROMSTART:     /* Spin up the drive */
		/* Don't think we can do this.  Even if we could,
 		 * I think the drive times out and stops after a while
		 * anyway.  For now, ignore it.
		 */

		return 0;

	case CDROMSTOP:      /* Spin down the drive */
		outb(MCMD_STOP, MCDPORT(0));
		i = getMcdStatus(MCD_STATUS_DELAY);

		/* should we do anything if it fails? */

		audioStatus = CDROM_AUDIO_NO_STATUS;
		return 0;

	case CDROMPAUSE:     /* Pause the drive */
		if (audioStatus != CDROM_AUDIO_PLAY)
			return -EINVAL;

		outb(MCMD_STOP, MCDPORT(0));
		i = getMcdStatus(MCD_STATUS_DELAY);

		if (GetQChannelInfo(&qInfo) < 0)
		{
			/* didn't get q channel info */

			audioStatus = CDROM_AUDIO_NO_STATUS;
			return 0;
		}

		mcd_Play.start = qInfo.diskTime;	/* remember restart point */

		audioStatus = CDROM_AUDIO_PAUSED;
		return 0;

	case CDROMRESUME:    /* Play it again, Sam */
		if (audioStatus != CDROM_AUDIO_PAUSED)
			return -EINVAL;

		/* restart the drive at the saved position. */

		i = mcdPlay(&mcd_Play);
		if (i < 0)
		{
			audioStatus = CDROM_AUDIO_ERROR;
			return -EIO;
		}

		audioStatus = CDROM_AUDIO_PLAY;
		return 0;

	case CDROMPLAYTRKIND:     /* Play a track.  This currently ignores index. */

		ti=(struct cdrom_ti *) arg;

		if (ti->cdti_trk0 < DiskInfo.first
			|| ti->cdti_trk0 > DiskInfo.last
			|| ti->cdti_trk1 < ti->cdti_trk0)
		{
			return -EINVAL;
		}

		if (ti->cdti_trk1 > DiskInfo.last)
			ti->cdti_trk1 = DiskInfo.last;

		mcd_Play.start = Toc[ti->cdti_trk0].diskTime;
		mcd_Play.end = Toc[ti->cdti_trk1 + 1].diskTime;

#ifdef MCD_DEBUG
printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
	mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
	mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
#endif

		i = mcdPlay(&mcd_Play);
		if (i < 0)
		{
			audioStatus = CDROM_AUDIO_ERROR;
			return -EIO;
		}

		audioStatus = CDROM_AUDIO_PLAY;
		return 0;

	case CDROMPLAYMSF:   /* Play starting at the given MSF address. */

		if (audioStatus == CDROM_AUDIO_PLAY) {
		  outb(MCMD_STOP, MCDPORT(0));
		  i = getMcdStatus(MCD_STATUS_DELAY);
		  audioStatus = CDROM_AUDIO_NO_STATUS;
		}

		msf=(struct cdrom_msf *) arg;

		/* convert to bcd */

		bin2bcd(&msf->cdmsf_min0);
		bin2bcd(&msf->cdmsf_sec0);
		bin2bcd(&msf->cdmsf_frame0);
		bin2bcd(&msf->cdmsf_min1);
		bin2bcd(&msf->cdmsf_sec1);
		bin2bcd(&msf->cdmsf_frame1);

		mcd_Play.start.min = msf->cdmsf_min0;
		mcd_Play.start.sec = msf->cdmsf_sec0;
		mcd_Play.start.frame = msf->cdmsf_frame0;
		mcd_Play.end.min = msf->cdmsf_min1;
		mcd_Play.end.sec = msf->cdmsf_sec1;
		mcd_Play.end.frame = msf->cdmsf_frame1;

#ifdef MCD_DEBUG
printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
#endif

		i = mcdPlay(&mcd_Play);
		if (i < 0)
		{
			audioStatus = CDROM_AUDIO_ERROR;
			return -EIO;
		}

		audioStatus = CDROM_AUDIO_PLAY;
		return 0;

	case CDROMREADTOCHDR:        /* Read the table of contents header */
	        tocHdr=(struct cdrom_tochdr *) arg; 
		tocHdr->cdth_trk0 = DiskInfo.first;
		tocHdr->cdth_trk1 = DiskInfo.last;
		return 0;

	case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
		entry=(struct cdrom_tocentry *) arg;
		if (entry->cdte_track == CDROM_LEADOUT)
			tocPtr = &Toc[DiskInfo.last - DiskInfo.first + 1];

		else if (entry->cdte_track > DiskInfo.last
				|| entry->cdte_track < DiskInfo.first)
			return -EINVAL;

		else
			tocPtr = &Toc[entry->cdte_track];

		entry->cdte_adr = tocPtr -> ctrl_addr;
		entry->cdte_ctrl = tocPtr -> ctrl_addr >> 4;

		if (entry->cdte_format == CDROM_LBA)
			entry->cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);

		else if (entry->cdte_format == CDROM_MSF)
		{
			entry->cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min);
			entry->cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec);
			entry->cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame);
		}

		else
			return -EINVAL;

		return 0;

	case CDROMSUBCHNL:   /* Get subchannel info */

                subchnl=(struct cdrom_subchnl *) arg;
		if (GetQChannelInfo(&qInfo) < 0)
			return -EIO;

		subchnl->cdsc_audiostatus = audioStatus;
		subchnl->cdsc_adr = qInfo.ctrl_addr;
		subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
		subchnl->cdsc_trk = bcd2bin(qInfo.track);
		subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
		subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
		subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
		subchnl->cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);
		subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
		subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
		subchnl->cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
		return(0);

	case CDROMVOLCTRL:   /* Volume control */
		volctrl=(struct cdrom_volctrl *) arg;
		outb(MCMD_SET_VOLUME, MCDPORT(0));
		outb(volctrl->channel0, MCDPORT(0));
		outb(255, MCDPORT(0));
		outb(volctrl->channel1, MCDPORT(0));
		outb(255, MCDPORT(0));

		i = getMcdStatus(MCD_STATUS_DELAY);
		if (i < 0)
			return -EIO;

		{
			char a, b, c, d;

			getValue(&a);
			getValue(&b);
			getValue(&c);
			getValue(&d);
		}

		return 0;

	default:
		return -EINVAL;
	}
}
Ejemplo n.º 17
0
static void
mcd_poll(void)
{
  int st;


  if (mcd_error) 
  {
    if (mcd_error & 0xA5) 
    {
      printk("mcd: I/O error 0x%02x", mcd_error);
      if (mcd_error & 0x80)
	printk(" (Door open)");
      if (mcd_error & 0x20)
	printk(" (Disk changed)");
      if (mcd_error & 0x04)
	{
	printk(" (Read error)"); /* Bitch about the problem. */
	
	/* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
	/* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
	/* But I find that rather HANDY!!! */
	/* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
	/* AJK [06/17/95] */
	
	/* Slap the CD down to single speed! */
	if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_2X_READ) 
		{
		MCMD_DATA_READ = MCMD_PLAY_READ; /* Uhhh, Ummmm, muhuh-huh! */
		mcd1xhold = SINGLE_HOLD_SECTORS; /* Hey Beavis! */
		printk(" Speed now 1x");	 /* Pull my finger! */
		}
	}
      printk("\n");
      mcd_invalidate_buffers();
#ifdef WARN_IF_READ_FAILURE
      if (McdTries == MCD_RETRY_ATTEMPTS)
	printk("mcd: read of block %d failed\n", mcd_next_bn);
#endif
      if (!McdTries--) 
        {
	/* Nuts! This cd is ready for recycling! */
	/* When WAS the last time YOU cleaned it CORRECTLY?! */
	printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
	if (mcd_transfer_is_active) 
	{
	  McdTries = 0;
	  goto ret;
	}
	if (CURRENT_VALID)
	  end_request(0);
	McdTries = MCD_RETRY_ATTEMPTS;
      }
    }
    mcd_error = 0;
    mcd_state = MCD_S_STOP;
  }
	/* Switch back to Double speed if enough GOOD sectors were read! */
	
	/* Are we a double speed with a crappy CD?! */
    if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_PLAY_READ)
    	{
	/* We ARE a double speed and we ARE bitching! */
	if (mcd1xhold == 0) /* Okay, Like are we STILL at single speed? */
		{ /* We need to switch back to double speed now... */
		MCMD_DATA_READ = MCMD_2X_READ; /* Uhhh... BACK You GO! */
		printk("mcd: Switching back to 2X speed!\n"); /* Tell 'em! */
		}
	else mcd1xhold--; /* No?! Count down the good reads some more... */
				/* and try, try again! */
    	}



 immediately:
  switch (mcd_state) {



  case MCD_S_IDLE:
#ifdef TEST3
    printk("MCD_S_IDLE\n");
#endif
    return;



  case MCD_S_START:
#ifdef TEST3
    printk("MCD_S_START\n");
#endif

    outb(MCMD_GET_STATUS, MCDPORT(0));
    mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
    McdTimeout = 3000;
    break;



  case MCD_S_MODE:
#ifdef TEST3
    printk("MCD_S_MODE\n");
#endif

    if ((st = mcdStatus()) != -1) {

      if (st & MST_DSK_CHG) {
	mcdDiskChanged = 1;
	tocUpToDate = 0;
	mcd_invalidate_buffers();
      }

    set_mode_immediately:

      if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
	mcdDiskChanged = 1;
	tocUpToDate = 0;
	if (mcd_transfer_is_active) {
	  mcd_state = MCD_S_START;
	  goto immediately;
	}
	printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
	mcd_state = MCD_S_IDLE;
	while (CURRENT_VALID)
	  end_request(0);
	return;
      }

      outb(MCMD_SET_MODE, MCDPORT(0));
      outb(1, MCDPORT(0));
      mcd_mode = 1;
      mcd_state = MCD_S_READ;
      McdTimeout = 3000;

    }
    break;



  case MCD_S_READ:
#ifdef TEST3
    printk("MCD_S_READ\n");
#endif

    if ((st = mcdStatus()) != -1) {

      if (st & MST_DSK_CHG) {
	mcdDiskChanged = 1;
	tocUpToDate = 0;
	mcd_invalidate_buffers();
      }

    read_immediately:

      if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
	mcdDiskChanged = 1;
	tocUpToDate = 0;
	if (mcd_transfer_is_active) {
	  mcd_state = MCD_S_START;
	  goto immediately;
	}
	printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
	mcd_state = MCD_S_IDLE;
	while (CURRENT_VALID)
	  end_request(0);
	return;
      }

      if (CURRENT_VALID) {
	struct mcd_Play_msf msf;
	mcd_next_bn = CURRENT -> sector / 4;
	hsg2msf(mcd_next_bn, &msf.start);
	msf.end.min = ~0;
	msf.end.sec = ~0;
	msf.end.frame = ~0;
	sendMcdCmd(MCMD_DATA_READ, &msf);
	mcd_state = MCD_S_DATA;
	McdTimeout = READ_TIMEOUT;
      } else {
	mcd_state = MCD_S_STOP;
	goto immediately;
      }

    }
    break;


  case MCD_S_DATA:
#ifdef TEST3
    printk("MCD_S_DATA\n");
#endif

    st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
  data_immediately:
#ifdef TEST5
    printk("Status %02x\n",st);
#endif
    switch (st) {

    case MFL_DATA:
#ifdef WARN_IF_READ_FAILURE
      if (McdTries == 5)
	printk("mcd: read of block %d failed\n", mcd_next_bn);
#endif
      if (!McdTries--) {
	printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
	if (mcd_transfer_is_active) {
	  McdTries = 0;
	  break;
	}
	if (CURRENT_VALID)
	  end_request(0);
	McdTries = 5;
      }
      mcd_state = MCD_S_START;
      McdTimeout = READ_TIMEOUT;
      goto immediately;

    case MFL_STATUSorDATA:
      break;

    default:
      McdTries = 5;
      if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) {
	mcd_state = MCD_S_STOP;
	goto immediately;
      }
      mcd_buf_bn[mcd_buf_in] = -1;
      READ_DATA(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in, 2048);
      mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
      if (mcd_buf_out == -1)
	mcd_buf_out = mcd_buf_in;
      mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
      if (!mcd_transfer_is_active) {
	while (CURRENT_VALID) {
	  mcd_transfer();
	  if (CURRENT -> nr_sectors == 0)
	    end_request(1);
	  else
	    break;
	}
      }

      if (CURRENT_VALID
	  && (CURRENT -> sector / 4 < mcd_next_bn || 
	      CURRENT -> sector / 4 > mcd_next_bn + 16)) {
	mcd_state = MCD_S_STOP;
	goto immediately;
      }
      McdTimeout = READ_TIMEOUT;
#ifdef DOUBLE_QUICK_ONLY
      if (MCMD_DATA_READ != MCMD_PLAY_READ)
#endif
      {
	int count= QUICK_LOOP_COUNT;
	while (count--) {
          QUICK_LOOP_DELAY;
	  if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
#   ifdef TEST4
/*	    printk("Quickloop success at %d\n",QUICK_LOOP_COUNT-count); */
	    printk(" %d ",QUICK_LOOP_COUNT-count);
#   endif
	    goto data_immediately;
	  }
	}
#   ifdef TEST4
/*      printk("Quickloop ended at %d\n",QUICK_LOOP_COUNT); */
	printk("ended ");
#   endif
      }
      break;
    }
    break;



  case MCD_S_STOP:
#ifdef TEST3
    printk("MCD_S_STOP\n");
#endif

#ifdef WORK_AROUND_MITSUMI_BUG_93
    if (!mitsumi_bug_93_wait)
      goto do_not_work_around_mitsumi_bug_93_1;

    McdTimeout = mitsumi_bug_93_wait;
    mcd_state = 9+3+1;
    break;

  case 9+3+1:
    if (McdTimeout)
      break;

  do_not_work_around_mitsumi_bug_93_1:
#endif /* WORK_AROUND_MITSUMI_BUG_93 */

    outb(MCMD_STOP, MCDPORT(0));

#ifdef WORK_AROUND_MITSUMI_BUG_92
    if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
      int i = 4096;
      do {
	inb(MCDPORT(0));
      } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
      outb(MCMD_STOP, MCDPORT(0));
      if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
	i = 4096;
	do {
	  inb(MCDPORT(0));
	} while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
	outb(MCMD_STOP, MCDPORT(0));
      }
    }
#endif /* WORK_AROUND_MITSUMI_BUG_92 */

    mcd_state = MCD_S_STOPPING;
    McdTimeout = 1000;
    break;

  case MCD_S_STOPPING:
#ifdef TEST3
    printk("MCD_S_STOPPING\n");
#endif

    if ((st = mcdStatus()) == -1 && McdTimeout)
      break;

    if ((st != -1) && (st & MST_DSK_CHG)) {
      mcdDiskChanged = 1;
      tocUpToDate = 0;
      mcd_invalidate_buffers();
    }

#ifdef WORK_AROUND_MITSUMI_BUG_93
    if (!mitsumi_bug_93_wait)
      goto do_not_work_around_mitsumi_bug_93_2;

    McdTimeout = mitsumi_bug_93_wait;
    mcd_state = 9+3+2;
    break;

  case 9+3+2:
    if (McdTimeout)
      break;

    st = -1;

  do_not_work_around_mitsumi_bug_93_2:
#endif /* WORK_AROUND_MITSUMI_BUG_93 */

#ifdef TEST3
    printk("CURRENT_VALID %d mcd_mode %d\n",
	   CURRENT_VALID, mcd_mode);
#endif

    if (CURRENT_VALID) {
      if (st != -1) {
	if (mcd_mode == 1)
	  goto read_immediately;
	else
	  goto set_mode_immediately;
      } else {
	mcd_state = MCD_S_START;
	McdTimeout = 1;
      }
    } else {
      mcd_state = MCD_S_IDLE;
      return;
    }
    break;

  default:
    printk("mcd: invalid state %d\n", mcd_state);
    return;
  }

 ret:
  if (!McdTimeout--) {
    printk("mcd: timeout in state %d\n", mcd_state);
    mcd_state = MCD_S_STOP;
  }

  SET_TIMER(mcd_poll, 1);
}
Ejemplo n.º 18
0
int __init mcd_init(void)
{
	int count;
	unsigned char result[3];
	char msg[80];

	if (mcd_port <= 0 || mcd_irq <= 0) {
		printk(KERN_INFO "mcd: not probing.\n");
		return -EIO;
	}

	if (devfs_register_blkdev(MAJOR_NR, "mcd", &mcd_bdops) != 0) {
		printk(KERN_ERR "mcd: Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR);
		return -EIO;
	}
	if (check_region(mcd_port, 4)) {
		cleanup(1);
		printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port);
		return -EIO;
	}

	blksize_size[MAJOR_NR] = mcd_blocksizes;
	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST,
		       &mcd_spinlock);
	read_ahead[MAJOR_NR] = 4;

	/* check for card */

	outb(0, MCDPORT(1));	/* send reset */
	for (count = 0; count < 2000000; count++)
		(void) inb(MCDPORT(1));	/* delay a bit */

	outb(0x40, MCDPORT(0));	/* send get-stat cmd */
	for (count = 0; count < 2000000; count++)
		if (!(inb(MCDPORT(1)) & MFL_STATUS))
			break;

	if (count >= 2000000) {
		printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n",
		       mcd_port, mcd_irq);
		cleanup(1);
		return -EIO;
	}
	count = inb(MCDPORT(0));	/* pick up the status */

	outb(MCMD_GET_VERSION, MCDPORT(0));
	for (count = 0; count < 3; count++)
		if (getValue(result + count)) {
			printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n",
			       mcd_port);
			cleanup(1);
			return -EIO;
		}

	if (result[0] == result[1] && result[1] == result[2]) {
		cleanup(1);
		return -EIO;
	}

	mcdVersion = result[2];

	if (mcdVersion >= 4)
		outb(4, MCDPORT(2));	/* magic happens */

	/* don't get the IRQ until we know for sure the drive is there */

	if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
		printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
		cleanup(1);
		return -EIO;
	}

	if (result[1] == 'D') {
		MCMD_DATA_READ = MCMD_2X_READ;
		/* Added flag to drop to 1x speed if too many errors */
		mcdDouble = 1;
	} else
		mcd_info.speed = 1;
	sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
		" irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double",
		mcd_port, mcd_irq);

	request_region(mcd_port, 4, "mcd");

	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
	outb(0x02, MCDPORT(0));
	outb(0x00, MCDPORT(0));
	getValue(result);

	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
	outb(0x10, MCDPORT(0));
	outb(0x04, MCDPORT(0));
	getValue(result);

	mcd_invalidate_buffers();
	mcdPresent = 1;

	mcd_info.dev = mk_kdev(MAJOR_NR, 0);

	if (register_cdrom(&mcd_info) != 0) {
		printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n");
		cleanup(3);
		return -EIO;
	}
	devfs_plain_cdrom(&mcd_info, &mcd_bdops);
	printk(msg);

	return 0;
}