patch-1.3.36 linux/drivers/block/mcd.c
Next file: linux/drivers/block/mcdx.c
Previous file: linux/drivers/block/ll_rw_blk.c
Back to the patch index
Back to the overall index
- Lines: 1633
- Date:
Thu Jan 1 02:00:00 1970
- Orig file:
v1.3.35/linux/drivers/block/mcd.c
- Orig date:
Tue Oct 10 18:46:32 1995
diff -u --recursive --new-file v1.3.35/linux/drivers/block/mcd.c linux/drivers/block/mcd.c
@@ -1,1632 +0,0 @@
-/*
- linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
-
- Copyright (C) 1992 Martin Harriss
-
- martin@bdsi.com (no longer valid - where are you now, Martin?)
-
- 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
- (stud11@cc4.kuleuven.ac.be)
- 0.3.2 bug fixes to the ioctls and merged with ALPHA0.99-pl12
- (Jon Tombs <jon@robots.ox.ac.uk>)
- 0.3.3 Added more #defines and mcd_setup()
- (Jon Tombs <jon@gtex02.us.es>)
-
- October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH,
- Braunschweig, Germany: rework to speed up data read operation.
- Also enabled definition of irq and address from bootstrap, using the
- environment.
- November 93 added code for FX001 S,D (single & double speed).
- February 94 added code for broken M 5/6 series of 16-bit single speed.
-
-
- 0.4
- Added support for loadable MODULEs, so mcd can now also be loaded by
- insmod and removed by rmmod during runtime.
- Werner Zimmermann (zimmerma@rz.fht-esslingen.de), Mar. 26, 95
-
- 0.5
- I added code for FX001 D to drop from double speed to single speed
- when encountering errors... this helps with some "problematic" CD's
- that are supposedly "OUT OF TOLERANCE" (but are really shitty presses!)
- severly scratched, or possibly slightly warped! I have noticed that
- the Mitsumi 2x/4x drives are just less tolerant and the firmware is
- not smart enough to drop speed, so let's just kludge it with software!
- ****** THE 4X SPEED MITSUMI DRIVES HAVE THE SAME PROBLEM!!!!!! ******
- Anyone want to "DONATE" one to me?! ;) I hear sometimes they are
- even WORSE! ;)
- ** HINT... HINT... TAKE NOTES MITSUMI This could save some hassels with
- certain "large" CD's that have data on the outside edge in your
- DOS DRIVERS .... Accuracy counts... speed is secondary ;)
- 17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
- 07 July 1995 Modifications by Andrew J. Kroll
-
-*/
-
-#include <linux/config.h>
-
-#ifdef MODULE
-# include <linux/module.h>
-# include <linux/version.h>
-# ifndef CONFIG_MODVERSIONS
- char kernel_version[]= UTS_RELEASE;
-# endif
-#define mcd_init init_module
-#else
-# define MOD_INC_USE_COUNT
-# define MOD_DEC_USE_COUNT
-#endif
-
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-
-/* #define REALLY_SLOW_IO */
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/segment.h>
-
-#define MAJOR_NR MITSUMI_CDROM_MAJOR
-#include "blk.h"
-#define mcd_port mcd /* for compatible parameter passing with "insmod" */
-#include <linux/mcd.h>
-
-#if 0
-static int mcd_sizes[] = { 0 };
-#endif
-
-/* I know putting defines in this file is probably stupid, but it should be */
-/* the only place that they are really needed... I HOPE! :) */
-
-/* How many sectors to read at 1x when an error at 2x speed occurs. */
-/* You can change this to anything from 2 to 32767, but 30 seems to */
-/* work best for me. I have found that when the drive has problems */
-/* reading one sector, it will have troubles reading the next few. */
-#define SINGLE_HOLD_SECTORS 30
-
-#define MCMD_2X_READ 0xC1 /* Double Speed Read DON'T TOUCH! */
-
-/* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
-static int mcdDouble = 0;
-
-/* How many sectors to hold at 1x speed counter */
-static int mcd1xhold = 0;
-
-/* Is the drive connected properly and responding?? */
-static int mcdPresent = 0;
-
-#if 0
-#define TEST1 /* <int-..> */
-#define TEST2 /* do_mcd_req */
-#define TEST3 */ /* MCD_S_state */
-#define TEST4 /* QUICK_LOOP-counter */
-#define TEST5 */ /* port(1) state */
-#endif
-
-#if 1
-#define QUICK_LOOP_DELAY udelay(45) /* use udelay */
-#define QUICK_LOOP_COUNT 20
-#else
-#define QUICK_LOOP_DELAY
-#define QUICK_LOOP_COUNT 140 /* better wait constant time */
-#endif
-/* #define DOUBLE_QUICK_ONLY */
-
-#define CURRENT_VALID \
- (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
- && CURRENT -> sector != -1)
-#define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
-#define MCD_BUF_SIZ 16
-static volatile int mcd_transfer_is_active;
-static char mcd_buf[2048*MCD_BUF_SIZ]; /* buffer for block size conversion */
-static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
-static volatile int mcd_buf_in, mcd_buf_out = -1;
-static volatile int mcd_error;
-static int mcd_open_count;
-enum mcd_state_e {
- MCD_S_IDLE, /* 0 */
- MCD_S_START, /* 1 */
- MCD_S_MODE, /* 2 */
- MCD_S_READ, /* 3 */
- MCD_S_DATA, /* 4 */
- MCD_S_STOP, /* 5 */
- MCD_S_STOPPING /* 6 */
-};
-static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
-static int mcd_mode = -1;
-static int MCMD_DATA_READ= MCMD_PLAY_READ;
-#define READ_TIMEOUT 3000
-#define WORK_AROUND_MITSUMI_BUG_92
-#define WORK_AROUND_MITSUMI_BUG_93
-#ifdef WORK_AROUND_MITSUMI_BUG_93
-int mitsumi_bug_93_wait = 0;
-#endif /* WORK_AROUND_MITSUMI_BUG_93 */
-
-static short mcd_port = MCD_BASE_ADDR; /* used as "mcd" by "insmod" */
-static int mcd_irq = MCD_INTR_NR; /* must directly follow mcd_port */
-
-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_msf mcd_Play;
-
-static int audioStatus;
-static char mcdDiskChanged;
-static char tocUpToDate;
-static char mcdVersion;
-
-static void mcd_transfer(void);
-static void mcd_poll(void);
-static void mcd_invalidate_buffers(void);
-static void hsg2msf(long hsg, struct msf *msf);
-static void bin2bcd(unsigned char *p);
-static int bcd2bin(unsigned char bcd);
-static int mcdStatus(void);
-static void sendMcdCmd(int cmd, struct mcd_Play_msf *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(unsigned char *result);
-
-
-void mcd_setup(char *str, int *ints)
-{
- if (ints[0] > 0)
- mcd_port = ints[1];
- if (ints[0] > 1)
- mcd_irq = ints[2];
-#ifdef WORK_AROUND_MITSUMI_BUG_93
- if (ints[0] > 2)
- mitsumi_bug_93_wait = ints[3];
-#endif /* WORK_AROUND_MITSUMI_BUG_93 */
-}
-
-
-static int
-check_mcd_change(kdev_t full_dev)
-{
- int retval, target;
-
-
-#if 1 /* the below is not reliable */
- return 0;
-#endif
- target = MINOR(full_dev);
-
- if (target > 0) {
- printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
- return 0;
- }
-
- retval = mcdDiskChanged;
- mcdDiskChanged = 0;
-
- return retval;
-}
-
-
-/*
- * 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 < MCD_RETRY_ATTEMPTS; retry++)
- {
-
- outb(MCMD_GET_STATUS, MCDPORT(0)); /* send get-status cmd */
- st = getMcdStatus(MCD_STATUS_DELAY);
- 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_msf *arg)
-{
- int retry, st;
-
- for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
- {
- sendMcdCmd(MCMD_PLAY_READ, arg);
- st = getMcdStatus(2 * MCD_STATUS_DELAY);
- 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;
- struct cdrom_volctrl volctrl;
-
- 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(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;
- }
-}
-
-
-/*
- * Take care of the different block sizes between cdrom and Linux.
- * When Linux gets variable block sizes this will probably go away.
- */
-
-static void
-mcd_transfer(void)
-{
- if (CURRENT_VALID) {
- while (CURRENT -> nr_sectors) {
- int bn = CURRENT -> sector / 4;
- int i;
- for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i)
- ;
- if (i < MCD_BUF_SIZ) {
- int offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
- int nr_sectors = 4 - (CURRENT -> sector & 3);
- if (mcd_buf_out != i) {
- mcd_buf_out = i;
- if (mcd_buf_bn[i] != bn) {
- mcd_buf_out = -1;
- continue;
- }
- }
- if (nr_sectors > CURRENT -> nr_sectors)
- nr_sectors = CURRENT -> nr_sectors;
- memcpy(CURRENT -> buffer, mcd_buf + offs, nr_sectors * 512);
- CURRENT -> nr_sectors -= nr_sectors;
- CURRENT -> sector += nr_sectors;
- CURRENT -> buffer += nr_sectors * 512;
- } else {
- mcd_buf_out = -1;
- break;
- }
- }
- }
-}
-
-
-/*
- * We only seem to get interrupts after an error.
- * Just take the interrupt and clear out the status reg.
- */
-
-static void
-mcd_interrupt(int irq, struct pt_regs * regs)
-{
- int st;
-
- st = inb(MCDPORT(1)) & 0xFF;
-#ifdef TEST1
- printk("<int1-%02X>", st);
-#endif
- if (!(st & MFL_STATUS))
- {
- st = inb(MCDPORT(0)) & 0xFF;
-#ifdef TEST1
- printk("<int0-%02X>", st);
-#endif
- if ((st & 0xFF) != 0xFF)
- mcd_error = st ? st & 0xFF : -1;
- }
-}
-
-
-static void
-do_mcd_request(void)
-{
-#ifdef TEST2
- printk(" do_mcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors);
-#endif
- mcd_transfer_is_active = 1;
- while (CURRENT_VALID) {
- if (CURRENT->bh) {
- if (!CURRENT->bh->b_lock)
- panic(DEVICE_NAME ": block not locked");
- }
- mcd_transfer();
- if (CURRENT -> nr_sectors == 0) {
- end_request(1);
- } else {
- mcd_buf_out = -1; /* Want to read a block not in buffer */
- if (mcd_state == MCD_S_IDLE) {
- if (!tocUpToDate) {
- if (updateToc() < 0) {
- while (CURRENT_VALID)
- end_request(0);
- break;
- }
- }
- mcd_state = MCD_S_START;
- McdTries = 5;
- SET_TIMER(mcd_poll, 1);
- }
- break;
- }
- }
- mcd_transfer_is_active = 0;
-#ifdef TEST2
- printk(" do_mcd_request ends\n");
-#endif
-}
-
-
-
-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 Bevis! */
- 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);
-}
-
-
-
-static void
-mcd_invalidate_buffers(void)
-{
- int i;
- for (i = 0; i < MCD_BUF_SIZ; ++i)
- mcd_buf_bn[i] = -1;
- mcd_buf_out = -1;
-}
-
-
-/*
- * Open the device special file. Check that a disk is in.
- */
-
-int
-mcd_open(struct inode *ip, struct file *fp)
-{
- int st;
-
- if (mcdPresent == 0)
- return -ENXIO; /* no hardware */
-
- if (fp->f_mode & 2) /* write access? */
- return -EROFS;
-
- if (!mcd_open_count && mcd_state == MCD_S_IDLE) {
-
- mcd_invalidate_buffers();
-
- st = statusCmd(); /* check drive status */
- if (st == -1)
- return -EIO; /* drive doesn't respond */
-
- if ((st & MST_READY) == 0) /* no disk in drive */
- {
- printk("mcd: no disk in drive\n");
- return -EIO;
- }
-
- if (updateToc() < 0)
- return -EIO;
-
- }
- ++mcd_open_count;
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-
-/*
- * On close, we flush all mcd blocks from the buffer cache.
- */
-
-static void
-mcd_release(struct inode * inode, struct file * file)
-{ MOD_DEC_USE_COUNT;
- if (!--mcd_open_count) {
- mcd_invalidate_buffers();
- sync_dev(inode->i_rdev);
- invalidate_buffers(inode -> i_rdev);
- }
-}
-
-
-static struct file_operations mcd_fops = {
- NULL, /* lseek - default */
- block_read, /* read - general block-dev read */
- block_write, /* write - general block-dev write */
- NULL, /* readdir - bad */
- NULL, /* select */
- mcd_ioctl, /* ioctl */
- NULL, /* mmap */
- mcd_open, /* open */
- mcd_release, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
- check_mcd_change, /* media change */
- NULL /* revalidate */
-};
-
-
-/*
- * Test for presence of drive and initialize it. Called at boot time.
- */
-
-int
-mcd_init(void)
-{
- int count;
- unsigned char result[3];
-
- if (mcd_port <= 0 || mcd_irq <= 0) {
- printk("skip mcd_init\n");
- return -EIO;
- }
-
- printk("mcd=0x%x,%d: ", mcd_port, mcd_irq);
-
- if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0)
- {
- printk("Unable to get major %d for Mitsumi CD-ROM\n",
- MAJOR_NR);
- return -EIO;
- }
-
- if (check_region(mcd_port, 4)) {
- printk("Init failed, I/O port (%X) already in use\n",
- mcd_port);
- return -EIO;
- }
-
- 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);
- 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);
- return -EIO;
- }
-
- if (result[0] == result[1] && result[1] == result[2])
- return -EIO;
- printk("Mitsumi status, type and version : %02X %c %x ",
- result[0],result[1],result[2]);
-
- if (result[1] == 'D')
- {
- printk("Double Speed CD ROM\n");
- MCMD_DATA_READ = MCMD_2X_READ;
- mcdDouble = 1; /* Added flag to drop to 1x speed if too many errors */
- }
- else printk("Single Speed CD ROM\n");
-
- 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"))
- {
- printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
- return -EIO;
- }
- 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;
- return 0;
-}
-
-
-static void
-hsg2msf(long hsg, struct msf *msf)
-{
- hsg += 150;
- msf -> min = hsg / 4500;
- hsg %= 4500;
- msf -> sec = hsg / 75;
- msf -> frame = hsg % 75;
-
- bin2bcd(&msf -> min); /* convert to BCD */
- bin2bcd(&msf -> sec);
- bin2bcd(&msf -> frame);
-}
-
-
-static void
-bin2bcd(unsigned char *p)
-{
- int u, t;
-
- u = *p % 10;
- t = *p / 10;
- *p = u | (t << 4);
-}
-
-static int
-bcd2bin(unsigned char bcd)
-{
- return (bcd >> 4) * 10 + (bcd & 0xF);
-}
-
-
-/*
- * See if a status is ready from the drive and return it
- * if it is ready.
- */
-
-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;
-}
-
-
-/*
- * Send a play or read command to the drive
- */
-
-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));
-}
-
-
-/*
- * Timer interrupt routine to test for status ready from the drive.
- * (see the next routine)
- */
-
-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);
-}
-
-
-/*
- * Wait for a status to be returned from the drive. The actual test
- * (see routine above) is done by the timer interrupt to avoid
- * excessive rescheduling.
- */
-
-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;
-}
-
-
-/*
- * Read a value from the drive. Should return quickly, so a busy wait
- * is used to avoid excessive rescheduling.
- */
-
-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;
-}
-
-
-/*
- * Read the current Q-channel info. Also used for reading the
- * table of contents.
- */
-
-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(¬Used) < 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;
-}
-
-
-/*
- * Read the table of contents (TOC) and TOC header if necessary
- */
-
-static int
-updateToc()
-{
- if (tocUpToDate)
- return 0;
-
- if (GetDiskInfo() < 0)
- return -EIO;
-
- if (GetToc() < 0)
- return -EIO;
-
- tocUpToDate = 1;
- return 0;
-}
-
-
-/*
- * Read the table of contents header
- */
-
-static int
-GetDiskInfo()
-{
- 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);
-
- 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;
-
-#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
-
- return 0;
-}
-
-
-/*
- * Read the table of contents (TOC)
- */
-
-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;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{ if (MOD_IN_USE)
- { printk("mcd module in use - can't remove it.\n");
- return;
- }
- if ((unregister_blkdev(MAJOR_NR, "mcd") == -EINVAL))
- { printk("What's that: can't unregister mcd\n");
- return;
- }
- release_region(mcd_port,4);
- free_irq(mcd_irq);
- printk("mcd module released.\n");
-}
-#endif MODULE
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this