patch-pre2.0.7 linux/drivers/cdrom/mcdx.c
Next file: linux/drivers/char/amigamouse.c
Previous file: linux/drivers/cdrom/aztcd.c
Back to the patch index
Back to the overall index
- Lines: 1049
- Date:
Tue May 21 11:49:03 1996
- Orig file:
pre2.0.6/linux/drivers/cdrom/mcdx.c
- Orig date:
Mon May 20 08:20:59 1996
diff -u --recursive --new-file pre2.0.6/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
@@ -1,7 +1,12 @@
/*
* The Mitsumi CDROM interface
+ *
+ * (H) Hackright 1996 by Marcin Dalecki <dalecki@namu03.gwdg.de>
+ *
+ * Based on previous work (as of version 1.9) done by:
* Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 2.3
+ *
+ * VERSION: 2.5
*
* 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
@@ -36,28 +41,31 @@
* Mostly fixes to some silly bugs in the previous release :-).
* (Hi Michael Thimm! Thank's for lending me Your's double speed drive.)
* 2.3 1996/05/15 Marcin Dalecki <dalecki@namu03.gwdg.de>
- * Fixed stereo support.
+ * Fixed stereo support.
+ * 2.5 1996/05/19 Marcin Dalecki <dalecki@namu03.gwdg.de>
+ * Overall performance increased by a factor of 1.25 :-).
+ * I hope Heiko doesn't mind the Hackright change, but there isn't much of
+ * code left from his version 1.9 anymore.
+ * Start speedup for Work(Man|Bone).
+ *
* NOTE:
- * There will be probably a 3.0 adhering to the new generic non ATAPI
- * cdrom interface in the unforeseen future.
+ * There will be probably a 3.0 adhering to the new generic non ATAPI
+ * CDROM interface in the unforeseen future.
*/
-#define VERSION "2.3"
+#define VERSION "2.5"
#include <linux/version.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/sched.h>
-#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/cdrom.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/malloc.h>
-#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
#include <linux/major.h>
#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
@@ -69,8 +77,7 @@
#define mcdx_drive_map mcdx
#include <linux/mcdx.h>
-#define REQUEST_SIZE 200
-#define DIRECT_SIZE 200
+#define REQUEST_SIZE 400
enum drivemodes {
TOC, DATA, RAW, COOKED
@@ -110,11 +117,12 @@
/*
* Per drive/controller stuff.
*/
-
struct s_drive_stuff {
struct wait_queue *busyq;
-
+
/* flags */
+ u_char used:1; /* locks on open, we allow only
+ exclusive usage of the drive */
u_char introk:1; /* status of last irq operation */
u_char busy:1; /* drive performs an operation */
u_char eject_sw:1; /* 1 - eject on last close (default 0) */
@@ -126,12 +134,12 @@
/* drives capabilities */
u_char door:1; /* can close/lock tray */
- u_char multi_cap:1; /* multisession capable */
+ u_char multi_cap:1; /* multi-session capable */
u_char double_speed:1; /* double speed drive */
/* cd infos */
- unsigned int n_first;
- unsigned int n_last;
+ u_int first;
+ u_int last;
struct cdrom_msf0 msf_leadout;
struct s_multi multi;
@@ -141,26 +149,30 @@
int audiostatus;
/* `buffer' control */
- unsigned int valid:1;
+ u_char valid:1;
int pending;
- int off_direct;
- int off_requested;
+ int border; /* the last sector in sequence we will read,
+ without reissuing a read command */
+ u_int base; /* base for all registers of the drive */
int irq; /* irq used by this drive */
- unsigned int base; /* base for all registers of the drive */
- int users; /* keeps track of open/close */
- int lastsector; /* last accessible blocks */
+ int lastsector; /* last accessible block */
};
/*
* Macros for accessing interface registers
*/
-
#define DATA_REG (stuffp->base)
#define RESET_REG (stuffp->base+1)
#define STAT_REG (stuffp->base+1)
#define CHAN_REG (stuffp->base+3)
+/*
+ * Access to elements of the mcdx_drive_map members
+ */
+#define PORT 0
+#define IRQ 1
+
/*
* declared in blk.h
*/
@@ -175,7 +187,7 @@
/*
* Indirect exported functions. These functions are exported by their
* addresses, such as mcdx_open and mcdx_close in the
- * structure fops.
+ * structure fops.
*/
/*
@@ -184,7 +196,7 @@
static void mcdx_intr(int, void *, struct pt_regs *);
/*
- * exported by file_ops
+ * exported by file_ops
*/
static int mcdx_open(struct inode *, struct file *);
static void mcdx_close(struct inode *, struct file *);
@@ -192,8 +204,7 @@
unsigned int, unsigned long);
static int mcdx_media_change(kdev_t);
-
-static int mcdx_blocksizes[MCDX_NDRIVES];
+static int mcdx_blksize_size[MCDX_NDRIVES];
static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
static struct s_drive_stuff *mcdx_irq_map[16] =
@@ -221,7 +232,7 @@
* Misc number converters
*/
-static unsigned int bcd2uint(unsigned char c)
+static unsigned int bcd2uint(unsigned int c)
{
return (c >> 4) * 10 + (c & 0x0f);
}
@@ -239,20 +250,6 @@
- CD_BLOCK_OFFSET;
}
-/*
- * Access to elements of the mcdx_drive_map members
- */
-static inline unsigned int port(int *ip)
-{
- return (unsigned int) ip[0];
-}
-
-static inline int irq(int *ip)
-{
- return ip[1];
-}
-
-
/*
* Low level hardware related functions.
*/
@@ -287,6 +284,14 @@
return (inb(DATA_REG) & 0xff);
}
+static void release_toc(struct s_drive_stuff *stuffp)
+{
+ if (stuffp->toc) {
+ kfree(stuffp->toc);
+ stuffp->toc = 0;
+ }
+}
+
/* 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.
@@ -301,10 +306,6 @@
{
int st;
- while (stuffp->busy) {
- interruptible_sleep_on(&stuffp->busyq);
- }
- stuffp->busy = 1;
stuffp->valid = 0;
outb(command, DATA_REG);
if (parslen)
@@ -321,19 +322,15 @@
/* audio status? */
if (stuffp->audiostatus == CDROM_AUDIO_INVALID) {
stuffp->audiostatus =
- (st & MCDX_RBIT_AUDIOBS) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
+ (st & MCDX_RBIT_AUDIOBS) ?
+ CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
} else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
&& !(st & MCDX_RBIT_AUDIOBS)) {
stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
}
/* media change? */
- if (st & MCDX_RBIT_CHANGED) {
+ if (st & MCDX_RBIT_CHANGED)
stuffp->xxx = 1;
- if (stuffp->toc) {
- kfree(stuffp->toc);
- stuffp->toc = 0;
- }
- }
/* now actually get the data */
while (size--) {
if (-1 == (st = get_status(stuffp, timeout))) {
@@ -342,11 +339,9 @@
*((char *) buffer) = st;
buffer++;
}
-
+ /* The goto's make GCC generate better code.
+ */
end_talk:
- stuffp->busy = 0;
- wake_up_interruptible(&stuffp->busyq);
-
return st;
}
@@ -387,11 +382,11 @@
ans = get_command(stuffp, MCDX_CMD_GET_TOC, buf, sizeof(buf), 2 * HZ);
if (ans == -1) {
- stuffp->n_first = 0;
- stuffp->n_last = 0;
+ stuffp->first = 0;
+ stuffp->last = 0;
} else {
- stuffp->n_first = bcd2uint(buf[0]);
- stuffp->n_last = bcd2uint(buf[1]);
+ stuffp->first = bcd2uint(buf[0]);
+ stuffp->last = bcd2uint(buf[1]);
memcpy(&(stuffp->msf_leadout), buf + 2, 3);
}
return ans;
@@ -445,7 +440,7 @@
int read_toc(struct s_drive_stuff *stuffp)
{
int trk;
- int retries;
+ int i;
if (stuffp->toc)
return 0;
@@ -454,21 +449,16 @@
if (-1 == set_drive_mode(stuffp, TOC))
return -EIO;
- /* all seems to be ok so far ... malloc */
+ /* All seems to be OK so far ... malloc. When this fails all bets
+ * are off anyway, so we don't check for it.
+ */
stuffp->toc = kmalloc(sizeof(struct s_subqcode) *
- (stuffp->n_last - stuffp->n_first + 2), GFP_KERNEL);
- if (!stuffp->toc) {
- printk(KERN_ERR MCDX ": malloc for toc failed\n");
- set_drive_mode(stuffp, DATA);
- return -EIO;
- }
+ (stuffp->last - stuffp->first + 1), GFP_KERNEL);
/* now read actually the index tracks */
- for (trk = 0;
- trk < (stuffp->n_last - stuffp->n_first + 1);
- trk++)
+ for (trk = 0; trk < stuffp->last - stuffp->first + 1; trk++)
stuffp->toc[trk].index = 0;
- for (retries = 300; retries; retries--) { /* why 300? */
+ for (i = 300; i; --i) { /* why 300? */
struct s_subqcode q;
unsigned int idx;
@@ -478,20 +468,17 @@
}
idx = bcd2uint(q.index);
- if ((idx > 0)
- && (idx <= stuffp->n_last)
- && (q.tno == 0)
- && (stuffp->toc[idx - stuffp->n_first].index == 0)) {
- stuffp->toc[idx - stuffp->n_first] = q;
+ if (idx > 0 && idx <= stuffp->last && q.tno == 0
+ && stuffp->toc[idx - stuffp->first].index == 0) {
+ stuffp->toc[idx - stuffp->first] = q;
trk--;
}
if (trk == 0)
break;
}
- memset(&stuffp->toc[stuffp->n_last - stuffp->n_first + 1],
- 0, sizeof(stuffp->toc[0]));
- stuffp->toc[stuffp->n_last - stuffp->n_first + 1].dt
- = stuffp->msf_leadout;
+ i = stuffp->last - stuffp->first + 1;
+ memset(&stuffp->toc[i], 0, sizeof(stuffp->toc[0]));
+ stuffp->toc[i].dt = stuffp->msf_leadout;
/* unset toc mode */
if (-1 == set_drive_mode(stuffp, DATA))
@@ -512,9 +499,9 @@
stuffp->audiostatus = CDROM_AUDIO_ERROR;
return -EIO;
}
- times.start = stuffp->toc[ti->cdti_trk0 - stuffp->n_first].dt;
+ times.start = stuffp->toc[ti->cdti_trk0 - stuffp->first].dt;
times.stop = stuffp->resume.stop =
- stuffp->toc[ti->cdti_trk1 - stuffp->n_first + 1].dt;
+ stuffp->toc[ti->cdti_trk1 - stuffp->first + 1].dt;
} else {
times = stuffp->resume;
}
@@ -535,9 +522,12 @@
return set_command(stuffp, MCDX_CMD_LOCK_DOOR,
&lock, sizeof(lock), 5 * HZ);
return 0;
-} /*
- * KERNEL INTERFACE FUNCTIONS
- */
+}
+
+/*
+ * KERNEL INTERFACE FUNCTIONS
+ */
+
static int mcdx_ioctl(struct inode *ip, struct file *fp,
unsigned int command, unsigned long arg)
{
@@ -560,19 +550,6 @@
if (!ip)
return -EINVAL;
- /*
- * Update disk information, when necessary.
- * This part will only work, when the new disk is of the same type as
- * the one which was previously there, esp. also for audio disks.
- * This doesn't hurt us, since otherwise the mounting/unmounting scheme
- * will ensure correct operation.
- */
- if (stuffp->xxx) { /* disk changed */
- if ((-1 == request_toc_data(stuffp)) ||
- (-1 == read_toc(stuffp)))
- return -EIO;
- stuffp->xxx = 0;
- }
switch (command) {
case CDROMSTART: /* spin up the drive */
MCDX_TRACE_IOCTL(("CDROMSTART\n"));
@@ -595,12 +572,12 @@
if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(ti))))
return ans;
memcpy_fromfs(&ti, (void *) arg, sizeof(ti));
- if ((ti.cdti_trk0 < stuffp->n_first)
- || (ti.cdti_trk0 > stuffp->n_last)
- || (ti.cdti_trk1 < stuffp->n_first))
+ if (ti.cdti_trk0 < stuffp->first
+ || ti.cdti_trk0 > stuffp->last
+ || ti.cdti_trk1 < stuffp->first)
return -EINVAL;
- if (ti.cdti_trk1 > stuffp->n_last)
- ti.cdti_trk1 = stuffp->n_last;
+ if (ti.cdti_trk1 > stuffp->last)
+ ti.cdti_trk1 = stuffp->last;
return play_track(stuffp, &ti);
case CDROMPLAYMSF:
@@ -613,12 +590,12 @@
msf.cdmsf_min0 = uint2bcd(msf.cdmsf_min0);
msf.cdmsf_sec0 = uint2bcd(msf.cdmsf_sec0);
msf.cdmsf_frame0 = uint2bcd(msf.cdmsf_frame0);
- msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1);
- msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
- msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
- stuffp->resume.stop.minute = msf.cdmsf_min1;
- stuffp->resume.stop.second = msf.cdmsf_sec1;
- stuffp->resume.stop.frame = msf.cdmsf_frame1;
+ stuffp->resume.stop.minute =
+ msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1);
+ stuffp->resume.stop.second =
+ msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
+ stuffp->resume.stop.frame =
+ msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
if (-1 == set_command(stuffp, MCDX_CMD_PLAY,
&msf, sizeof(msf), 3 * HZ)) {
return -1;
@@ -658,15 +635,12 @@
memcpy_fromfs(&entry, (void *) arg, sizeof(entry));
if (entry.cdte_track == CDROM_LEADOUT)
- tp = &stuffp->toc[stuffp->n_last - stuffp->n_first + 1];
- else if (entry.cdte_track > stuffp->n_last
- || entry.cdte_track < stuffp->n_first)
+ tp = &stuffp->toc[stuffp->last - stuffp->first + 1];
+ else if (entry.cdte_track > stuffp->last
+ || entry.cdte_track < stuffp->first)
return -EINVAL;
else
- tp = &stuffp->toc[entry.cdte_track - stuffp->n_first];
-
- if (NULL == tp)
- printk(KERN_ERR MCDX ": FATAL.\n");
+ tp = &stuffp->toc[entry.cdte_track - stuffp->first];
entry.cdte_adr = tp->adr;
entry.cdte_ctrl = tp->ctrl;
@@ -717,8 +691,7 @@
} else
return -EINVAL;
- if ((ans = verify_area(VERIFY_WRITE,
- (void *) arg, sizeof(sub))))
+ if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof(sub))))
return ans;
memcpy_tofs((void *) arg, &sub, sizeof(sub));
@@ -729,16 +702,22 @@
if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof toc)))
return ans;
+ /*
+ * Make sure, we really read it!
+ */
+ release_toc(stuffp);
+ if (-1 == request_toc_data(stuffp))
+ return -EIO;
- toc.cdth_trk0 = stuffp->n_first;
- toc.cdth_trk1 = stuffp->n_last;
+ toc.cdth_trk0 = stuffp->first;
+ toc.cdth_trk1 = stuffp->last;
memcpy_tofs((void *) arg, &toc, sizeof toc);
return 0;
case CDROMMULTISESSION:
MCDX_TRACE_IOCTL(("CDROMMULTISESSION\n"));
- if (0 != (ans = verify_area(VERIFY_READ, (void *) arg,
+ if ((ans = verify_area(VERIFY_READ, (void *) arg,
sizeof(struct cdrom_multisession))))
return ans;
@@ -757,7 +736,7 @@
return -EINVAL;
ms.xa_flag = !!stuffp->multi.multi;
- if (0 != (ans = verify_area(VERIFY_WRITE, (void *) arg,
+ if ((ans = verify_area(VERIFY_WRITE, (void *) arg,
sizeof(struct cdrom_multisession))))
return ans;
@@ -767,8 +746,6 @@
case CDROMEJECT:
MCDX_TRACE_IOCTL(("CDROMEJECT\n"));
- if (stuffp->users > 1)
- return -EBUSY;
if (stuffp->door) {
if (-1 == issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ))
return -EIO;
@@ -776,10 +753,8 @@
/*
* Force rereading of toc next time the disk gets accessed!
*/
- if (stuffp->toc) {
- kfree(stuffp->toc);
- stuffp->toc = 0;
- }
+ release_toc(stuffp);
+
return 0;
case CDROMEJECT_SW:
@@ -814,9 +789,6 @@
/*
* This does actually the transfer from the drive.
* Return: -1 on timeout or other error
- * else status byte (as in stuff->st)
- * FIXME: the excessive jumping through wait queues degrades the
- * performance significantly.
*/
static int transfer_data(struct s_drive_stuff *stuffp,
char *p, int sector, int nr_sectors)
@@ -824,65 +796,10 @@
int off;
int done = 0;
- if (stuffp->valid
- && (sector >= stuffp->pending)
- && (sector < stuffp->off_direct)) {
- off = stuffp->off_requested < (off = sector + nr_sectors)
- ? stuffp->off_requested : off;
-
- do {
- /* wait for the drive become idle, but first
- * check for possible occurred errors --- the drive
- * seems to report them asynchronously
- */
- current->timeout = jiffies + 5 * HZ;
- while (stuffp->introk && stuffp->busy
- && current->timeout) {
- interruptible_sleep_on(&stuffp->busyq);
- }
-
- /* test for possible errors */
- if (current->timeout == 0 || !stuffp->introk) {
- if (current->timeout == 0) {
- printk(KERN_ERR MCDX ": transfer timeout\n");
- } else if (!stuffp->introk) {
- printk(KERN_ERR MCDX
- ": error via irq in transfer reported\n");
- }
-
- stuffp->busy = 0;
- stuffp->valid = 0;
- stuffp->introk = 1;
- return -1;
- }
- /* test if it's the first sector of a block,
- * there we have to skip some bytes as we read raw data
- */
- if (stuffp->xa && (0 == (stuffp->pending & 3))) {
- insb(DATA_REG, p,
- CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE);
- }
- /* now actually read the data */
- insb(DATA_REG, p, 512);
-
- /* test if it's the last sector of a block,
- * if so, we have to expect an interrupt and to skip
- * some data too
- */
- if ((stuffp->busy = (3 == (stuffp->pending & 3)))
- && stuffp->xa) {
- int i;
- for (i = 0; i < CD_XA_TAIL; ++i)
- inb(DATA_REG);
- }
- if (stuffp->pending == sector) {
- p += 512;
- done++;
- sector++;
- }
- } while (++(stuffp->pending) < off);
- } else {
+ if (!stuffp->valid || sector < stuffp->pending
+ || sector > stuffp->border) {
unsigned char cmd[6];
+
stuffp->valid = 1;
stuffp->pending = sector & ~3;
@@ -895,18 +812,14 @@
stuffp->valid = 0;
return -1;
}
- if ((stuffp->off_direct = stuffp->pending + DIRECT_SIZE)
- > stuffp->lastsector + 1)
- stuffp->off_direct = stuffp->lastsector + 1;
- if ((stuffp->off_requested = stuffp->pending + REQUEST_SIZE)
- > stuffp->lastsector + 1)
- stuffp->off_requested = stuffp->lastsector + 1;
+ if ((stuffp->border = stuffp->pending + REQUEST_SIZE)
+ > stuffp->lastsector)
+ stuffp->border = stuffp->lastsector;
{
unsigned int l = (stuffp->pending / 4)
+ CD_BLOCK_OFFSET;
- cmd[0] = uint2bcd(l / 4500), l %= 4500;
- /* minute */
+ cmd[0] = uint2bcd(l / 4500), l %= 4500; /* minute */
cmd[1] = uint2bcd(l / 75); /* second */
cmd[2] = uint2bcd(l % 75); /* frame */
}
@@ -915,19 +828,66 @@
/*
* FIXME: What about the ominous frame length?!
*/
- cmd[3] = ~0;
- cmd[4] = ~0;
- cmd[5] = ~0;
+ cmd[5] = cmd[4] = cmd[3] = ~0;
outb(stuffp->double_speed ? MCDX_CMD_PLAY_2X : MCDX_CMD_PLAY,
DATA_REG);
outsb(DATA_REG, cmd, 6);
}
+ off = sector + nr_sectors;
+ if (stuffp->border < off)
+ off = stuffp->border;
+ do {
+ /* wait for the drive become idle, but first
+ * check for possible occurred errors --- the drive
+ * seems to report them asynchronously
+ */
+ current->timeout = jiffies + 5 * HZ;
+ while (stuffp->introk && stuffp->busy
+ && current->timeout) {
+ interruptible_sleep_on(&stuffp->busyq);
+ }
- stuffp->off_direct =
- (stuffp->off_direct += done) < stuffp->off_requested
- ? stuffp->off_direct
- : stuffp->off_requested;
+ /* test for possible errors */
+ if (current->timeout == 0 || !stuffp->introk) {
+ if (current->timeout == 0) {
+ printk(KERN_ERR MCDX ": transfer timeout.\n");
+ }
+ /*
+ * We don't report about !stuffp->introk, sice this is
+ * allready done in the interrupt routine.
+ */
+ stuffp->busy = 0;
+ stuffp->valid = 0;
+ stuffp->introk = 1;
+ return -1;
+ }
+ /* test if it's the first sector of a block,
+ * there we have to skip some bytes as we read raw data
+ */
+ if (stuffp->xa && (0 == (stuffp->pending & 3))) {
+ insb(DATA_REG, p,
+ CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE);
+ }
+ /* now actually read the data */
+ insb(DATA_REG, p, 512);
+
+ /* test if it's the last sector of a block,
+ * if so, we have to expect an interrupt and to skip
+ * some data too
+ */
+ if ((stuffp->busy = (3 == (stuffp->pending & 3)))
+ && stuffp->xa) {
+ int i;
+ for (i = 0; i < CD_XA_TAIL; ++i)
+ inb(DATA_REG);
+ }
+ if (stuffp->pending == sector) {
+ p += 512;
+ done++;
+ sector++;
+ }
+ } while (++(stuffp->pending) < off);
return done;
}
@@ -946,21 +906,12 @@
INIT_REQUEST;
dev = MINOR(CURRENT->rq_dev);
-
- if ((dev < 0) || (dev >= MCDX_NDRIVES) || (!stuffp)) {
- printk(KERN_WARNING MCDX ": bad device requested: %s\n",
- kdevname(CURRENT->rq_dev));
- end_request(0);
- goto again;
- }
- if (stuffp->audio) {
- printk(KERN_WARNING MCDX ": attempt to read from audio cd\n");
+ if (dev < 0 || dev >= MCDX_NDRIVES || !stuffp || stuffp->audio) {
end_request(0);
goto again;
}
switch (CURRENT->cmd) {
case WRITE:
- printk(KERN_ERR MCDX ": attempt to write to cd!!\n");
end_request(0);
break;
@@ -969,18 +920,14 @@
while (CURRENT->nr_sectors) {
int i;
- if (-1 == (i = transfer_data(stuffp,
- CURRENT->buffer,
- CURRENT->sector,
- CURRENT->nr_sectors))) {
+ i = transfer_data(stuffp, CURRENT->buffer,
+ CURRENT->sector, CURRENT->nr_sectors);
+ if (i == -1) {
if (stuffp->eom) {
CURRENT->sector += CURRENT->nr_sectors;
CURRENT->nr_sectors = 0;
- } else {
- /*
- * FIXME: TRY SOME ERROR RECOVERY HERE!
- */
- }
+ } else
+ break; /* FIXME: drop down speed ??? */
end_request(0);
goto again;
}
@@ -1002,6 +949,7 @@
/*
* actions done on open:
* 1) get the drives status
+ * 2) handle disk changes
*/
static int mcdx_open(struct inode *ip, struct file *fp)
{
@@ -1014,23 +962,31 @@
if (!stuffp)
return -ENXIO;
+ /* We don't allow multiple users of a drive. In case of data CD's they
+ * will be only used by mounting, which ensures anyway exclusive usage.
+ * In case of sound CD's it's anyway meaningless to try playing two
+ * different tracks at once! This saves us A LOT of trouble.
+ */
+ if (stuffp->used)
+ return -EBUSY;
+
/* close the door, if necessary (get the door information
* from the hardware status register).
* If we can't read the CD after an autoclose
- * no further autocloses will be tried
+ * no further auto-closes will be tried
*/
if (inb(STAT_REG) & MCDX_RBIT_DOOR) {
if (stuffp->autoclose && (stuffp->door))
- issue_command(stuffp, MCDX_CMD_CLOSE_DOOR, 10 * HZ);
+ issue_command(stuffp, MCDX_CMD_CLOSE_DOOR, 5 * HZ);
else
return -EIO;
}
/*
* Check if a disk is in.
- */
- bang = jiffies + 10 * HZ;
+ */
+ bang = jiffies + 5 * HZ;
while (jiffies < bang) {
- st = issue_command(stuffp, MCDX_CMD_GET_STATUS, 5 * HZ);
+ st = issue_command(stuffp, MCDX_CMD_GET_STATUS, 1 * HZ);
if (st != -1 && (st & MCDX_RBIT_DISKSET))
break;
current->state = TASK_INTERRUPTIBLE;
@@ -1057,75 +1013,62 @@
if (stuffp->multi_cap) {
int i = 6; /* number of retries */
- while (i && (-1 == get_command(stuffp,
- MCDX_CMD_GET_MDISK_INFO,
- &stuffp->multi, sizeof(struct s_multi), 2 * HZ)))
- --i;
+
+ while (i--)
+ if (-1 != get_command(stuffp, MCDX_CMD_GET_MDISK_INFO,
+ &stuffp->multi,
+ sizeof(struct s_multi),
+ 2 * HZ))
+ break;
+
if (!i) {
- stuffp->autoclose = 0;
- /*
- * No multidisk info
- */
+ stuffp->autoclose = 0; /* don't try it again on next open */
+ if (stuffp->door)
+ issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ);
+ return -EIO;
}
} else
stuffp->multi.multi = 0;
- if (stuffp->autoclose) {
- /* we succeeded, so on next open(2) we could try
- * auto close again
- */
-
- /* multisession ? */
- if (!stuffp->multi.multi)
- stuffp->multi.msf_last.second = 2;
- } /* got multisession information */
- /* request the disks table of contents (aka diskinfo) */
- if (-1 == request_toc_data(stuffp)) {
+ if (!stuffp->multi.multi)
+ stuffp->multi.msf_last.second = 2;
+ release_toc(stuffp); /* force rereading */
+ if (-1 == request_toc_data(stuffp))
stuffp->lastsector = -1;
- } else {
+ else {
stuffp->lastsector = (CD_FRAMESIZE / 512)
* msf2log(&stuffp->msf_leadout) - 1;
}
-
- if (stuffp->toc) {
- kfree(stuffp->toc);
- stuffp->toc = 0;
- }
if (-1 == config_drive(stuffp))
return -EIO;
/* 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--) {
+ char buf[512];
+ int st;
unsigned char c;
stuffp->introk = 1;
/* set data mode */
c = stuffp->xa ? MODE2 : MODE1;
- ans = set_command(stuffp,
- MCDX_CMD_SET_DATA_MODE,
- &c, sizeof(c), 5 * HZ);
-
- if (-1 == ans) {
- /* return -EIO; */
+ st = set_command(stuffp,
+ MCDX_CMD_SET_DATA_MODE,
+ &c, sizeof(c), 5 * HZ);
+ if (-1 == st) {
stuffp->xa = 0;
- break;
- } else if (ans & MCDX_RBIT_AUDIOTR) {
+ continue;
+ } else if (st & MCDX_RBIT_AUDIOTR) {
stuffp->audio = 1;
break;
}
-
- while (0 == (ans = transfer_data(stuffp, buf,
- 0, 1)));
-
- if (ans == 1)
+ while (0 == (st = transfer_data(stuffp, buf,
+ 0, 1)));
+ if (st == 1)
break;
stuffp->xa = !stuffp->xa;
}
@@ -1137,10 +1080,10 @@
stuffp->xxx = 0;
}
/* lock the door if not already done */
- if (0 == stuffp->users && (-1 == lock_door(stuffp, DOOR_LOCK)))
+ if (!stuffp->used && (-1 == lock_door(stuffp, DOOR_LOCK)))
return -EIO;
- stuffp->users++;
+ stuffp->used = 1;
MOD_INC_USE_COUNT;
return 0;
}
@@ -1151,26 +1094,22 @@
MCDX_TRACE(("mcdx_close()\n"));
- if (0 == --stuffp->users) {
- sync_dev(ip->i_rdev); /* needed for r/o device? */
+ sync_dev(ip->i_rdev); /* needed for r/o device? */
- /* invalidate_inodes(ip->i_rdev); */
- invalidate_buffers(ip->i_rdev);
- lock_door(stuffp, DOOR_UNLOCK);
-
- /* eject if wished and possible */
- if (stuffp->eject_sw && (stuffp->door)) {
- issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ);
- }
+ /* invalidate_inodes(ip->i_rdev); */
+ invalidate_buffers(ip->i_rdev);
+ lock_door(stuffp, DOOR_UNLOCK);
+
+ /* eject if wished and possible */
+ if (stuffp->eject_sw && (stuffp->door)) {
+ issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ);
}
+ stuffp->used = 0;
MOD_DEC_USE_COUNT;
-
- return;
}
/*
- * Return: 1 if media changed since last call to this function
- * 0 otherwise
+ * Return: 1 if media changed since last call to this function, 0 otherwise.
*/
static int mcdx_media_change(kdev_t full_dev)
{
@@ -1199,32 +1138,30 @@
if (!(stuffp = mcdx_irq_map[irq])) {
return; /* huh? */
}
-
/* NOTE: We only should get interrupts if data were requested.
* But the drive seems to generate ``asynchronous'' interrupts
* on several error conditions too. (Despite the err int enable
- * setting during initialisation)
+ * setting during initialization)
*/
-
- /* get the interrupt status */
- b = inb(STAT_REG);
- if (!(b & MCDX_RBIT_DTEN)) {
+ b = inb(STAT_REG);
+ if (!(b & MCDX_RBIT_DTEN))
stuffp->introk = 1;
- } else {
+ else {
stuffp->introk = 0;
if (!(b & MCDX_RBIT_STEN)) {
- printk(KERN_DEBUG MCDX ": irq %d status 0x%02x\n",
- irq, inb(DATA_REG));
- } else {
+ b = inb(DATA_REG);
+ if (stuffp->used)
+ printk(KERN_DEBUG MCDX
+ ": irq %d status 0x%02x\n", irq, b);
+ } else
MCDX_TRACE(("irq %d ambiguous hw status\n", irq));
- }
}
stuffp->busy = 0;
wake_up_interruptible(&stuffp->busyq);
}
/*
- * FIXME!
+ * FIXME:
* This seems to hang badly, when the driver is loaded with inappropriate
* port/irq settings!
*/
@@ -1233,10 +1170,10 @@
int drive;
#ifdef MODULE
- printk(KERN_INFO "Mitsumi driver version " VERSION " for %s\n",
+ printk(KERN_INFO "Mitsumi driver V" VERSION " for %s\n",
kernel_version);
#else
- printk(KERN_INFO "Mitsumi driver version " VERSION "\n");
+ printk(KERN_INFO "Mitsumi driver V" VERSION "\n");
#endif
for (drive = 0; drive < MCDX_NDRIVES; drive++) {
struct {
@@ -1247,21 +1184,20 @@
struct s_drive_stuff *stuffp;
int size;
- mcdx_blocksizes[drive] = 0;
+ mcdx_blksize_size[drive] = 0;
mcdx_stuffp[drive] = 0;
size = sizeof(*stuffp);
- if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
- printk(KERN_ERR MCDX
- ": malloc of drives data failed!\n");
+ if (!(stuffp = kmalloc(size, GFP_KERNEL)))
break;
- }
- /* set default values */ memset(stuffp, 0, sizeof(*stuffp));
+
+ /* set default values */
+ memset(stuffp, 0, sizeof(*stuffp));
stuffp->autoclose = 1; /* close the door on open(2) */
- stuffp->irq = irq(mcdx_drive_map[drive]);
- stuffp->base = port(mcdx_drive_map[drive]);
+ stuffp->base = mcdx_drive_map[drive][PORT];
+ stuffp->irq = mcdx_drive_map[drive][IRQ];
/* check if i/o addresses are available */
if (check_region(stuffp->base, MCDX_IO_SIZE)) {
@@ -1311,10 +1247,13 @@
kfree(stuffp);
continue; /* next drive */
}
+ /*
+ * CD-ROM's are an example of non 1024 devices
+ */
+ mcdx_blksize_size[drive] = 1024;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = READ_AHEAD;
-
- blksize_size[MAJOR_NR] = mcdx_blocksizes;
+ blksize_size[MAJOR_NR] = mcdx_blksize_size;
mcdx_irq_map[stuffp->irq] = stuffp;
if (request_irq(stuffp->irq, mcdx_intr,
@@ -1339,7 +1278,8 @@
config_drive(stuffp);
- printk(KERN_INFO MCDX "%d: at 0x%3x, irq %d, firmware: %c %x\n",
+ printk(KERN_INFO MCDX
+ "%d: at 0x%3x, irq %d, type: %c, firmware: %x\n",
drive, stuffp->base, stuffp->irq,
firmware.code, firmware.version);
mcdx_stuffp[drive] = stuffp;
@@ -1377,9 +1317,7 @@
continue;
release_region(stuffp->base, MCDX_IO_SIZE);
free_irq(stuffp->irq, NULL);
- if (stuffp->toc) {
- kfree(stuffp->toc);
- }
+ release_toc(stuffp);
mcdx_stuffp[i] = NULL;
kfree(stuffp);
}
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