MITSUMI CD-ROM LU005S march version : patch for linux driver.

MITSUMI CD-ROM LU005S march version : patch for linux driver.

Post by Lode Vande San » Tue, 10 Aug 1993 23:42:32



Hi,

I have developed a patch for the Linux Mitsumi CD-ROM driver. Basically only
some unused status bits changed in the march version. So i think my patch
should continue to work with the other drivers. I don't have verified this
however. The patch was developed for linux 0.99pl11.
------------------------------------------------------------------------
/*
        linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver

        Copyright (C) 1992  Martin Harriss

        mar...@bdsi.com

        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2, or (at your option)
        any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

        HISTORY

        0.1     First attempt - internal use only
        0.2     Cleaned up delays and use of timer - alpha release
        0.3     Audio support added
        0.3.1 Changes for mitsumi CRMC LU005S march version
                   (stu...@cc4.kuleuven.ac.be)
*/

#include <linux/config.h>
#ifdef CONFIG_BLK_DEV_MCD

#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/cdrom.h>

/* #define REALLY_SLOW_IO  */
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>

#define MAJOR_NR 23
#include "blk.h"

/* *** change this to set the I/O port address */
#define MCDPORT(x)              (0x300 + (x))

/* *** change this to set the interrupt number */
#define MCD_INTR_NR             10

/* status bits */

#define MST_CMD_CHECK           0x01                    /* command error */
#define MST_BUSY                                0x02                    /* now playing */
#define MST_READ_ERR                    0x04               /* read error */
#define MST_DSK_TYPE                    0x08
#define MST_SERVO_CHECK         0x10
#define MST_DSK_CHG                     0x20                    /* disk removed or changed */
#define MST_READY                               0x40                    /* disk in the drive */
#define MST_DOOR_OPEN           0x80                    /* door is open */

/* flag bits */

#define MFL_DATA                                0x02                    /* data available */
#define MFL_STATUS                      0x04                    /* status available */

/* commands */

#define MCMD_GET_DISK_INFO      0x10                    /* read info from disk */
#define MCMD_GET_Q_CHANNEL      0x20                    /* read info from q channel */
#define MCMD_GET_STATUS         0x40
#define MCMD_SET_MODE           0x50
#define MCMD_SOFT_RESET         0x60
#define MCMD_STOP                               0x70                    /* stop play */
#define MCMD_CONFIG_DRIVE       0x90
#define MCMD_SET_VOLUME         0xAE                    /* set audio level */
#define MCMD_PLAY_READ          0xC0                    /* play or read data */
#define MCMD_GET_VERSION        0xDC

/* borrowed from hd.c */

#define READ_DATA(port, buf, nr) \
__asm__("cld;rep;insb"::"d" (port),"D" (buf),"c" (nr):"cx","di")

#define SET_TIMER(func, jifs) \
        ((timer_table[MCD_TIMER].expires = jiffies + jifs), \
        (timer_table[MCD_TIMER].fn = func), \
        (timer_active |= 1<<MCD_TIMER))

#define CLEAR_TIMER             timer_active &= ~(1<<MCD_TIMER)

#define MAX_TRACKS              104

struct msf {
        unsigned char   min;
        unsigned char   sec;
        unsigned char   frame;

};

struct mcd_Play {
        struct msf      start;
        struct msf      end;

};

struct mcd_DiskInfo {
        unsigned char   first;
        unsigned char   last;
        struct msf      diskLength;
        struct msf      firstTrack;

};

struct mcd_Toc {
        unsigned char   ctrl_addr;
        unsigned char   track;
        unsigned char   pointIndex;
        struct msf      trackTime;
        struct msf      diskTime;

};

#if 0
static int mcd_sizes[] = { 0 };
#endif

static int mcdPresent = 0;

static char mcd_buf[2048];      /* buffer for block size conversion */
static int mcd_bn = -1;

static int McdTimeout, McdTries;
static struct wait_queue *mcd_waitq = NULL;

static struct mcd_DiskInfo DiskInfo;
static struct mcd_Toc Toc[MAX_TRACKS];
static struct mcd_Play mcd_Play;
static int audioStatus;
static char diskChanged;
static char tocUpToDate;
static char mcdVersion;

static void mcd_transfer(void);
static void mcd_start(void);
static void mcd_status(void);
static void mcd_read_cmd(void);
static void mcd_data(void);
static void do_mcd_request(void);
static void hsg2msf(long hsg, struct msf *msf);
static void bin2bcd(char *p);
static int bcd2bin(unsigned char bcd);
static int mcdStatus(void);
static void sendMcdCmd(int cmd, struct mcd_Play *params);
static int getMcdStatus(int timeout);
static int GetQChannelInfo(struct mcd_Toc *qp);
static int updateToc(void);
static int GetDiskInfo(void);
static int GetToc(void);
static int getValue(char *result);

/*
 * Do a 'get status' command and get the result.  Only use from the top half
 * because it calls 'getMcdStatus' which sleeps.
 */

static int
statusCmd(void)
{
        int st, retry;

        for (retry = 0; retry < 3; retry++)
        {
                outb(MCMD_GET_STATUS, MCDPORT(0));      /* send get-status cmd */
                st = getMcdStatus(100);
                if (st != -1)
                        break;
        }

        return st;

}

/*
 * Send a 'Play' command and get the status.  Use only from the top half.
 */

static int
mcdPlay(struct mcd_Play *arg)
{
        int retry, st;

        for (retry = 0; retry < 3; retry++)
        {
                sendMcdCmd(MCMD_PLAY_READ, arg);
                st = getMcdStatus(200);
                if (st != -1)
                        break;
        }

        return st;

}

long
msf2hsg(struct msf *mp)
{
        return bcd2bin(mp -> frame)
                + bcd2bin(mp -> sec) * 75
                + bcd2bin(mp -> min) * 4500
                - 150;

}

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;
#if 0
        struct cdrom_volctrl volctrl;
#endif

        if (!ip)
                return -EINVAL;

        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(100);

                /* 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(100);

                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)
                        return -EINVAL;

                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_sec0);
                bin2bcd(&msf.cdmsf_frame0);

                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);
...

read more »

 
 
 

MITSUMI CD-ROM LU005S march version : patch for linux driver.

Post by Jon Tom » Sat, 14 Aug 1993 05:50:00



[ lots of patch deleted ]

Quote:>            bin2bcd(&msf.cdmsf_min0);
>            bin2bcd(&msf.cdmsf_sec0);
>            bin2bcd(&msf.cdmsf_frame0);
>            bin2bcd(&msf.cdmsf_min1);
>            bin2bcd(&msf.cdmsf_sec0);
>            bin2bcd(&msf.cdmsf_frame0);

[ even more deleted ]

If you look at the above code you will spot an obvious typo, which makes the
playing of CDs difficult!

The correct code is below (look closely at the last two lines). I've sent this
to the author a long time ago, but as no official patch has shown up, here it
is.

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

Jon.