VERSION = 1
PATCHLEVEL = 1
-SUBLEVEL = 23
+SUBLEVEL = 24
all: Version zImage
! Number of modes is the number of chip-specific svga modes plus the extended
! modes available on any vga (currently 2)
-moati: .byte 0x04, 0x23, 0x33
+moati: .byte 0x06, 0x23, 0x33, 0x22, 0x21
moahead: .byte 0x07, 0x22, 0x23, 0x24, 0x2f, 0x34
mocandt: .byte 0x04, 0x60, 0x61
mocirrus: .byte 0x06, 0x1f, 0x20, 0x22, 0x31
! The first two modes are standard vga modes available on any vga.
! mode 0 is 80x50 and mode 1 is 80x28
-dscati: .word 0x5032, 0x501c, 0x8419, 0x842c
+dscati: .word 0x5032, 0x501c, 0x8419, 0x842c, 0x641e, 0x6419
dscahead: .word 0x5032, 0x501c, 0x842c, 0x8419, 0x841c, 0xa032, 0x5042
dsccandt: .word 0x5032, 0x501c, 0x8419, 0x8432
dsccirrus: .word 0x5032, 0x501c, 0x8419, 0x842c, 0x841e, 0x6425
-This README belongs to release 2.0 of the SoundBlaster Pro (Matsushita,
+This README belongs to release 2.1 of the SoundBlaster Pro (Matsushita,
Kotobuki, Panasonic, CreativeLabs) CD-ROM driver for Linux.
The driver is able to drive the whole family of IDE-style
With the "new" drive family CR-562 and CR-563, the reading of audio frames is
possible. This is currently implemented by an IOCTL function which reads only
-one frame of 2352 bytes at a time. The transfer rate is as slow as 32 kB/sec.
-This will get better, and the software interface may change. We have to
-standardize it the day the SCSI driver supports it too.
-
-MultiSession is supported (even my "old" CR-521 can handle it), "ManySession"
-(not recommended, see below) alternatively.
-Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's
-package to convert photo CD image files.
+up to 4 frames of 2352 bytes at once. Reading more than 1 frame at once gives
+very poor quality. Reading the same frame a second time gives different data;
+it seems that the drive is out-of-sync at the beginning. See the program
+example below. This lack has to get corrected by higher level software.
+The transfer rate with reading audio (1-frame-pieces) is as slow as 32 kB/sec.
+This could be better reading bigger chunks, but the out-of-sync parts occur at
+the beginning of each single frame.
+The software interface possibly may change a bit the day the SCSI driver
+supports it too.
+
+MultiSession is supported, "ManySession" (not recommended, see below)
+alternatively.
+Photo CDs work, too (even with my "old" CR-521).
+At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's package to convert
+photo CD image files.
The transfer rate will reach 150 kB/sec with "old" drives and 300 kB/sec with
double-speed drives. XA (PhotoCD) disks with "old" drives give only 50 kB/sec.
}
/*===================== end program ========================================*/
+At ftp.gwdg.de:/pub/linux/misc/cdda2wav-sbpcd.tar.gz is an adapted version of
+Heiko Eissfeldt's digital-audio to .WAV converter (the original is there, too).
+This is preliminary, as Heiko himself will care about it.
+
Known problems:
---------------
* to the desired drive, but it will probably not survive the sleep if
* several floppies are used at the same time: thus the loop.
*/
-int floppy_change(struct buffer_head * bh)
+static int floppy_change(struct buffer_head * bh)
{
unsigned int mask = 1 << (bh->b_dev & 0x03);
int drive;
int old_dev;
- if (floppy_grab_irq_and_dma()) {
- return -EBUSY;
- }
drive = inode->i_rdev & 3;
old_dev = fd_device[drive];
if (fd_ref[drive])
if (old_dev != inode->i_rdev)
return -EBUSY;
+ if (floppy_grab_irq_and_dma())
+ return -EBUSY;
fd_ref[drive]++;
fd_device[drive] = inode->i_rdev;
buffer_drive = buffer_track = -1;
static void floppy_release(struct inode * inode, struct file * filp)
{
- sync_dev(inode->i_rdev);
+ fsync_dev(inode->i_rdev);
if (!fd_ref[inode->i_rdev & 3]--) {
printk("floppy_release with fd_ref == 0");
fd_ref[inode->i_rdev & 3] = 0;
floppy_release_irq_and_dma();
}
+static int check_floppy_change(dev_t dev)
+{
+ int i;
+ struct buffer_head * bh;
+
+ if (!(bh = getblk(dev,0,1024)))
+ return 0;
+ i = floppy_change(bh);
+ brelse(bh);
+ return i;
+}
+
static struct file_operations floppy_fops = {
NULL, /* lseek - default */
block_read, /* read - general block-dev read */
NULL, /* mmap */
floppy_open, /* open */
floppy_release, /* release */
- block_fsync /* fsync */
+ block_fsync, /* fsync */
+ NULL, /* fasync */
+ check_floppy_change, /* media_change */
+ NULL /* revalidate */
};
-/*
- * The version command is not supposed to generate an interrupt, but
- * my FDC does, except when booting in SVGA screen mode.
- * When it does generate an interrupt, it doesn't return any status bytes.
- * It appears to have something to do with the version command...
- *
- * This should never be called, because of the reset after the version check.
- */
-static void ignore_interrupt(void)
-{
- printk(DEVICE_NAME ": weird interrupt ignored (%d)\n", result());
- reset = 1;
- CLEAR_INTR; /* ignore only once */
-}
-
-
static void floppy_interrupt(int unused)
{
void (*handler)(void) = DEVICE_INTR;
timer_active &= ~(1 << FLOPPY_TIMER);
config_types();
/* Try to determine the floppy controller type */
- DEVICE_INTR = ignore_interrupt; /* don't ask ... */
output_byte(FD_VERSION); /* get FDC version code */
if (result() != 1) {
printk(DEVICE_NAME ": FDC failed to return version byte\n");
}
}
+static int usage_count = 0;
+
static int floppy_grab_irq_and_dma(void)
{
+ if (usage_count++)
+ return 0;
if (irqaction(FLOPPY_IRQ,&floppy_sigaction)) {
printk("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ);
return -1;
static void floppy_release_irq_and_dma(void)
{
+ if (--usage_count)
+ return;
disable_dma(FLOPPY_DMA);
free_dma(FLOPPY_DMA);
disable_irq(FLOPPY_IRQ);
* and for "no-sound" interfaces like Lasermate and the
* Panasonic CI-101P.
*
- * NOTE: This is release 2.0.
+ * NOTE: This is release 2.1.
* It works with my SbPro & drive CR-521 V2.11 from 2/92
* and with the new CR-562-B V0.75 on a "naked" Panasonic
* CI-101P interface. And vice versa.
* reset the drive and do again. Needs lots of resets here and sometimes
* that does not cure, so this can't be the solution.
*
+ * 2.1 Found bug with multisession CDs (accessing frame 16).
+ * "read audio" works now with address type CDROM_MSF, too.
+ * Bigger audio frame buffer: allows reading max. 4 frames at time; but
+ * reading more than one frame at once gives poor quality.
+ *
+ *
+ * TODO
+ *
+ * disk change detection
+ * allow & synchronize multi-activity
+ * (data + audio + ioctl + disk change, multiple drives)
+ * implement multi-controller-support with a single driver
+ * implement "read all subchannel data" (96 bytes per frame)
+ *
+ *
* special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
* elaborated speed-up experiments (and the fabulous results!), for
* the "push" towards load-free wait loops, and for the extensive mail
#include "blk.h"
-#define VERSION "2.0 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "2.1 Eberhard Moenkeberg <emoenke@gwdg.de>"
#define SBPCD_DEBUG
#define XA_TEST2
#define TEST_UPC 0
-#define READ_AUDIO 1
#define SPEA_TEST 0
#define PRINTK_BUG 0
#define TEST_STI 0
{
CDROM_PORT, SBPRO, /* probe with user's setup first */
0x230, 1, /* Soundblaster Pro and 16 (default) */
- 0x300, 0, /* CI-101P (default), Galaxy (default), Reveal (one default) */
+ 0x300, 0, /* CI-101P (default), WDH-7001C (default),
+ Galaxy (default), Reveal (one default) */
0x250, 1, /* OmniCD default, Soundblaster Pro and 16 */
0x260, 1, /* OmniCD */
- 0x320, 0, /* Lasermate, CI-101P, Galaxy, Reveal (other default) */
+ 0x320, 0, /* Lasermate, CI-101P, WDH-7001C, Galaxy, Reveal (other default) */
0x340, 0, /* Lasermate, CI-101P */
0x360, 0, /* Lasermate, CI-101P */
0x270, 1, /* Soundblaster 16 */
0x350, 2, /* SPEA Media FX */
#if 0
/* some "hazardous" locations (ethernet cards) */
- 0x330, 0, /* Lasermate, CI-101P */
+ 0x330, 0, /* Lasermate, CI-101P, WDH-7001C */
0x350, 0, /* Lasermate, CI-101P */
0x370, 0, /* Lasermate, CI-101P */
0x290, 1, /* Soundblaster 16 */
- 0x310, 0, /* Lasermate, CI-101P */
+ 0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
/* excluded due to incomplete address decoding of the SbPro card */
0x630, 0, /* "sound card #9" (default) */
0x650, 0, /* "sound card #9" */
* the forward references:
*/
static void sbp_read_cmd(void);
-static int sbp_data(void);
+static int sbp_data(void);
static int cmd_out(void);
+static int DiskInfo(void);
/*==========================================================================*/
#else
static int sbpcd_debug = (1<<DBG_INF) |
(1<<DBG_TOC) |
- (1<<DBG_UPC) |
- (1<<DBG_TIM) |
- (1<<DBG_LCK) |
- (1<<DBG_CHK) |
- (1<<DBG_AUD) |
- (1<<DBG_IOX);
+ (1<<DBG_UPC);
#endif
#endif
static int sbpcd_ioaddr = CDROM_PORT; /* default I/O base address */
/*==========================================================================*/
-#define SBP_BUFFER_FRAMES 4 /* driver's own read_ahead */
+#define SBP_BUFFER_FRAMES 4 /* driver's own read_ahead, data mode */
+#define SBP_BUFFER_AUDIO_FRAMES 4 /* driver's own read_ahead, read audio mode */
/*==========================================================================*/
static u_char xa_head_buf[CD_XA_HEAD];
static u_char xa_tail_buf[CD_XA_TAIL];
+static u_char busy_data=0, busy_audio=0; /* true semaphores would be safer */
static u_char timed_out=0;
static u_int datarate= 1000000;
static u_int maxtim16=16000000;
int sbp_current; /* Frame being currently read */
u_char mode; /* read_mode: READ_M1, READ_M2, READ_SC, READ_AU */
-#if READ_AUDIO
u_char *aud_buf; /* Pointer to audio data buffer,
space allocated during sbpcd_init() */
-#endif READ_AUDIO
-
u_char drv_type;
u_char drv_options;
u_char status_byte;
return (i);
}
/*==========================================================================*/
+/*
+ * convert m-s-f_number (3 bytes only) to logical_block_address
+ */
+static int msf2lba(u_char *msf)
+{
+ int i;
+
+ i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_BLOCK_OFFSET;
+ if (i<0) return (0);
+ return (i);
+}
+/*==========================================================================*/
/* evaluate xx_ReadError code (still mysterious) */
static int sta2err(int sta)
{
if (sta<=2) return (sta);
- if (sta==0x05) return (-4);
- if (sta==0x06) return (-6);
- if (sta==0x0d) return (-6);
- if (sta==0x0e) return (-3);
- if (sta==0x14) return (-3);
- if (sta==0x0c) return (-11);
- if (sta==0x0f) return (-11);
- if (sta==0x10) return (-11);
- if (sta>=0x16) return (-12);
+ if (sta==0x05) return (-4); /* CRC error */
+ if (sta==0x06) return (-6); /* seek error */
+ if (sta==0x0d) return (-6); /* seek error */
+ if (sta==0x0e) return (-3); /* unknown command */
+ if (sta==0x14) return (-3); /* unknown command */
+ if (sta==0x0c) return (-11); /* read fault */
+ if (sta==0x0f) return (-11); /* read fault */
+ if (sta==0x10) return (-11); /* read fault */
+ if (sta>=0x16) return (-12); /* general failure */
DriveStruct[d].CD_changed=0xFF;
- if (sta==0x11) return (-15);
- return (-2);
+ if (sta==0x11) return (-15); /* invalid disk change */
+ return (-2); /* drive not ready */
}
/*==========================================================================*/
static void clr_cmdbuf(void)
response_count=0;
i=cmd_out();
}
+ sbp_sleep(100); /* wait a second */
flush_status();
i=GetStatus();
if (i>=0) return -1;
}
while (!st_diskok);
DriveStruct[d].CD_changed=1;
- i=SetSpeed();
+ i=DiskInfo();
if (i<0) return (-2);
return (0);
}
/*==========================================================================*/
#if FUTURE
static int yy_SubChanInfo(int frame, int count, u_char *buffer)
-/* "frame" is a RED BOOK address */
+/* "frame" is a RED BOOK (msf-bin) address */
{
int i;
- if (!new_drive) return (-3);
+ if (!new_drive) return (-ENOSYS); /* drive firmware lacks it */
#if 0
- if (DriveStruct[d].audio_state!=audio_playing) return (-2);
+ if (DriveStruct[d].audio_state!=audio_playing) return (-ENODATA);
#endif
clr_cmdbuf();
drvcmd[0]=0x11;
flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
cmd_type=READ_SC;
DriveStruct[d].frame_size=CD_FRAMESIZE_SUB;
- i=cmd_out(); /* read directly into user's buffer */
+ i=cmd_out(); /* which buffer to use? */
return (i);
}
#endif FUTURE
/* fake entry for LeadOut Track */
DriveStruct[d].TocBuffer[j].nixbyte=0;
DriveStruct[d].TocBuffer[j].ctl_adr=0;
- DriveStruct[d].TocBuffer[j].number=0;
+ DriveStruct[d].TocBuffer[j].number=CDROM_LEADOUT;
DriveStruct[d].TocBuffer[j].format=0;
DriveStruct[d].TocBuffer[j].address=DriveStruct[d].size_msf;
{
int i, j;
-#if READ_AUDIO
DriveStruct[d].mode=READ_M1;
-#endif READ_AUDIO
#undef LOOP_COUNT
#define LOOP_COUNT 20 /* needed for some "old" drives */
DriveStruct[d].mode=READ_M2;
return (0);
-#if READ_AUDIO
case CDROMREADAUDIO:
{ /* start of CDROMREADAUDIO */
int i=0, j=0, frame, block;
DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADAUDIO requested.\n"));
+#if 0
+ if (!new_drive) return (-EINVAL);
+#endif
+ if (DriveStruct[d].aud_buf==NULL) return (-EINVAL);
i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio));
if (i) return (i);
memcpy_fromfs(&read_audio, (void *) arg, sizeof(struct cdrom_read_audio));
- i=verify_area(VERIFY_WRITE, read_audio.buf, CD_FRAMESIZE_RAW);
+ if (read_audio.nframes>SBP_BUFFER_AUDIO_FRAMES) return (-EINVAL);
+ i=verify_area(VERIFY_WRITE, read_audio.buf,
+ read_audio.nframes*CD_FRAMESIZE_RAW);
if (i) return (i);
if (read_audio.addr_format==CDROM_MSF) /* MSF-bin specification of where to start */
- block=msf2blk(read_audio.addr.lba);
+ block=msf2lba(&read_audio.addr.msf.minute);
else if (read_audio.addr_format==CDROM_LBA) /* lba specification of where to start */
block=read_audio.addr.lba;
else return (-EINVAL);
- if (read_audio.nframes!=1) return (-EINVAL);
DPRINTF((DBG_AUD,"SBPCD: read_audio: lba: %d, msf: %06X\n",
block, blk2msf(block)));
DPRINTF((DBG_AUD,"SBPCD: read_audio: before xx_ReadStatus.\n"));
+
+ while (busy_data) sbp_sleep(10); /* wait a bit */
+ busy_audio=1;
+
for (data_tries=5; data_tries>0; data_tries--)
{
DPRINTF((DBG_AUD,"SBPCD: data_tries=%d ...\n", data_tries));
drvcmd[2]=(block>>8)&0x000000ff;
drvcmd[3]=block&0x000000ff;
drvcmd[4]=0;
- drvcmd[5]=1; /* # of frames */
+ drvcmd[5]=read_audio.nframes; /* # of frames */
drvcmd[6]=0;
}
else /* if new_drive */
error_flag=0;
p = DriveStruct[d].aud_buf;
if (sbpro_type==1) OUT(CDo_sel_d_i,0x01);
- READ_DATA(CDi_data, p, CD_FRAMESIZE_RAW);
+#if 0
+ cli();
+#endif
+ READ_DATA(CDi_data, p, read_audio.nframes*CD_FRAMESIZE_RAW);
+#if 0
+ sti();
+#endif
if (sbpro_type==1) OUT(CDo_sel_d_i,0x00);
data_retrying = 0;
}
continue;
}
memcpy_tofs((u_char *) read_audio.buf,
- (u_char *) DriveStruct[d].aud_buf, CD_FRAMESIZE_RAW);
+ (u_char *) DriveStruct[d].aud_buf,
+ read_audio.nframes*CD_FRAMESIZE_RAW);
DPRINTF((DBG_AUD,"SBPCD: read_audio: memcpy_tofs done.\n"));
break;
}
xx_ModeSelect(CD_FRAMESIZE);
xx_ModeSense();
DriveStruct[d].mode=READ_M1;
+ busy_audio=0;
if (data_tries == 0)
{
DPRINTF((DBG_AUD,"SBPCD: read_audio: failed after 5 tries.\n"));
DPRINTF((DBG_AUD,"SBPCD: read_audio: successful return.\n"));
return (0);
} /* end of CDROMREADAUDIO */
-#endif READ_AUDIO
case BLKRASET:
if(!suser()) return -EACCES;
sti();
- if ((CURRENT==NULL)||(CURRENT->dev<0)) return;
- if (CURRENT -> sector == -1) return;
+ if ((CURRENT==NULL)||(CURRENT->dev<0)) goto done;
+ if (CURRENT -> sector == -1) goto done;
dev = MINOR(CURRENT->dev);
if ( (dev<0) || (dev>=NR_SBPCD) )
{
printk("SBPCD: do_request: bad device: %d\n", dev);
- return;
+ goto done;
}
switch_drive(dev);
if (i!=0)
DPRINTF((DBG_INF,"SBPCD: \"prepare\" tells error %d -- ignored\n", i));
+ while (busy_audio) sbp_sleep(100); /* wait a bit */
+ busy_data=1;
+
if (!st_spinning) xx_SpinUp();
#ifdef XA_TEST1
end_request(0);
sbp_sleep(10); /* wait a bit, try again */
goto request_loop;
+
+done:
+ busy_data=0;
+ return;
}
/*==========================================================================*/
/*
DPRINTF((DBG_MUL,"SBPCD: read MSF %08X\n", blk2msf(block)));
if ( (DriveStruct[d].f_multisession) && (multisession_valid) )
{
- DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n",
+ DPRINTF((DBG_MUL,"SBPCD: ManySession: use %08X for %08X (msf)\n",
blk2msf(DriveStruct[d].lba_multi+block),
blk2msf(block)));
block=DriveStruct[d].lba_multi+block;
}
#else
- if ( (block==CD_BLOCK_OFFSET+16) && (DriveStruct[d].f_multisession) && (multisession_valid) )
+ if ( (block==16) && (DriveStruct[d].f_multisession) && (multisession_valid) )
{
DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n",
blk2msf(DriveStruct[d].lba_multi+16),
check_datarate();
DPRINTF((DBG_INI,"SBPCD: check_datarate done.\n"));
+ OUT(CDo_reset,0);
+ sbp_sleep(100);
+
for (j=0;j<NR_SBPCD;j++)
{
if (DriveStruct[j].drv_minor==-1) continue;
*/
DriveStruct[j].sbp_buf=(u_char *)mem_start;
mem_start += SBP_BUFFER_FRAMES*CD_FRAMESIZE;
-#if READ_AUDIO
- DriveStruct[j].aud_buf=(u_char *)mem_start;
- mem_start += CD_FRAMESIZE_RAW;
-#endif READ_AUDIO
+ if (new_drive)
+ {
+ DriveStruct[j].aud_buf=(u_char *)mem_start;
+ mem_start += SBP_BUFFER_AUDIO_FRAMES*CD_FRAMESIZE_RAW;
+ }
+ else DriveStruct[j].aud_buf=NULL;
/*
* set the block size
*/
#include <asm/segment.h>
#include <asm/io.h>
-#ifdef CONFIG_SCSI
-#ifdef CONFIG_BLK_DEV_SR
-extern int check_cdrom_media_change(int, int);
-#endif
-#ifdef CONFIG_BLK_DEV_SD
-extern int check_scsidisk_media_change(int, int);
-extern int revalidate_scsidisk(int, int);
-#endif
-#endif
-#ifdef CONFIG_CDU31A
-extern int check_cdu31a_media_change(int, int);
-#endif
-#ifdef CONFIG_MCD
-extern int check_mcd_media_change(int, int);
-#endif
-#ifdef CONFIG_SBPCD
-extern int check_sbpcd_media_change(int, int);
-#endif
-
#define NR_SIZES 4
static char buffersize_index[9] = {-1, 0, 1, -1, 2, -1, -1, -1, 3};
static short int bufferindex_size[NR_SIZES] = {512, 1024, 2048, 4096};
}
}
-/*
- * This routine checks whether a floppy has been changed, and
- * invalidates all buffer-cache-entries in that case. This
- * is a relatively slow routine, so we have to try to minimize using
- * it. Thus it is called only upon a 'mount' or 'open'. This
- * is the best way of combining speed and utility, I think.
- * People changing diskettes in the middle of an operation deserve
- * to loose :-)
- *
- * NOTE! Although currently this is only for floppies, the idea is
- * that any additional removable block-device will use this routine,
- * and that mount/open needn't know that floppies/whatever are
- * special.
- */
-void check_disk_change(dev_t dev)
-{
- int i;
- struct buffer_head * bh;
-
- switch(MAJOR(dev)){
- case FLOPPY_MAJOR:
- if (!(bh = getblk(dev,0,1024)))
- return;
- i = floppy_change(bh);
- brelse(bh);
- break;
-
-#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
- case SCSI_DISK_MAJOR:
- i = check_scsidisk_media_change(dev, 0);
- break;
-#endif
-
-#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI)
- case SCSI_CDROM_MAJOR:
- i = check_cdrom_media_change(dev, 0);
- break;
-#endif
-
-#if defined(CONFIG_CDU31A)
- case CDU31A_CDROM_MAJOR:
- i = check_cdu31a_media_change(dev, 0);
- break;
-#endif
-
-#if defined(CONFIG_MCD)
- case MITSUMI_CDROM_MAJOR:
- i = check_mcd_media_change(dev, 0);
- break;
-#endif
-
-#if defined(CONFIG_SBPCD)
- case MATSUSHITA_CDROM_MAJOR:
- i = check_sbpcd_media_change(dev, 0);
- break;
-#endif
-
- default:
- return;
- };
-
- if (!i) return;
-
- printk("VFS: Disk change detected on device %d/%d\n",
- MAJOR(dev), MINOR(dev));
- for (i=0 ; i<NR_SUPER ; i++)
- if (super_blocks[i].s_dev == dev)
- put_super(super_blocks[i].s_dev);
- invalidate_inodes(dev);
- invalidate_buffers(dev);
-
-#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
-/* This is trickier for a removable hardisk, because we have to invalidate
- all of the partitions that lie on the disk. */
- if (MAJOR(dev) == SCSI_DISK_MAJOR)
- revalidate_scsidisk(dev, 0);
-#endif
-}
-
#define _hashfn(dev,block) (((unsigned)(dev^block))%nr_hash)
#define hash(dev,block) hash_table[_hashfn(dev,block)]
#include <linux/fcntl.h>
#include <linux/errno.h>
+/*
+ * Ugly. We'll fix this once all the drivers use the f_ops->check_media_change()
+ * stuff instead..
+ */
+#ifdef CONFIG_SCSI
+#ifdef CONFIG_BLK_DEV_SR
+extern int check_cdrom_media_change(int, int);
+#endif
+#ifdef CONFIG_BLK_DEV_SD
+extern int check_scsidisk_media_change(int, int);
+extern int revalidate_scsidisk(int, int);
+#endif
+#endif
+#ifdef CONFIG_CDU31A
+extern int check_cdu31a_media_change(int, int);
+#endif
+#ifdef CONFIG_MCD
+extern int check_mcd_media_change(int, int);
+#endif
+#ifdef CONFIG_SBPCD
+extern int check_sbpcd_media_change(int, int);
+#endif
+
struct device_struct {
const char * name;
struct file_operations * fops;
return 0;
}
+/*
+ * This routine checks whether a removable media has been changed,
+ * and invalidates all buffer-cache-entries in that case. This
+ * is a relatively slow routine, so we have to try to minimize using
+ * it. Thus it is called only upon a 'mount' or 'open'. This
+ * is the best way of combining speed and utility, I think.
+ * People changing diskettes in the middle of an operation deserve
+ * to loose :-)
+ */
+void check_disk_change(dev_t dev)
+{
+ int i;
+ struct file_operations * fops;
+
+ i = MAJOR(dev);
+ if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
+ return;
+ if (fops->check_media_change != NULL) {
+ if (!fops->check_media_change(dev))
+ return;
+ }
+#if 1 /* this will go soon.. */
+ else switch(MAJOR(dev)){
+#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
+ case SCSI_DISK_MAJOR:
+ if (!check_scsidisk_media_change(dev, 0))
+ return;
+ break;
+#endif
+
+#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI)
+ case SCSI_CDROM_MAJOR:
+ if (!check_cdrom_media_change(dev, 0))
+ return;
+ break;
+#endif
+
+#if defined(CONFIG_CDU31A)
+ case CDU31A_CDROM_MAJOR:
+ if (!check_cdu31a_media_change(dev, 0))
+ return;
+ break;
+#endif
+
+#if defined(CONFIG_MCD)
+ case MITSUMI_CDROM_MAJOR:
+ if (!check_mcd_media_change(dev, 0))
+ return;
+ break;
+#endif
+
+#if defined(CONFIG_SBPCD)
+ case MATSUSHITA_CDROM_MAJOR:
+ if (!check_sbpcd_media_change(dev, 0))
+ return;
+ break;
+#endif
+
+ default:
+ return;
+ }
+#endif /* will go away */
+
+ printk("VFS: Disk change detected on device %d/%d\n",
+ MAJOR(dev), MINOR(dev));
+ for (i=0 ; i<NR_SUPER ; i++)
+ if (super_blocks[i].s_dev == dev)
+ put_super(super_blocks[i].s_dev);
+ invalidate_inodes(dev);
+ invalidate_buffers(dev);
+
+ if (fops->revalidate)
+ fops->revalidate(dev);
+
+#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
+/* This is trickier for a removable hardisk, because we have to invalidate
+ all of the partitions that lie on the disk. */
+ if (MAJOR(dev) == SCSI_DISK_MAJOR)
+ revalidate_scsidisk(dev, 0);
+#endif
+}
+
/*
* Called every time a block special file is opened
*/
/*
* some fix numbers
*/
-#define CD_MINS 75 /* minutes per CD */
+#define CD_MINS 74 /* max. minutes per CD */
#define CD_SECS 60 /* seconds per minute */
#define CD_FRAMES 75 /* frames per second */
#define CD_FRAMESIZE 2048 /* bytes per frame, cooked mode */
/*
* CD-ROM address types (cdrom_tocentry.cdte_format)
*/
-
-#define CDROM_LBA 0x01
-#define CDROM_MSF 0x02
+#define CDROM_LBA 0x01 /* "logical block": first frame is #0 */
+#define CDROM_MSF 0x02 /* "minute-second-frame": binary, not bcd here! */
/*
* bit to tell whether track is data or audio
int lba;
} addr; /* frame address */
u_char addr_format; /* CDROM_LBA or CDROM_MSF */
- int nframes; /* number of 2352-byte-frames to read at once, currently only 1 allowed */
+ int nframes; /* number of 2352-byte-frames to read at once, limited by the drivers */
u_char *buf; /* frame buffer (size: nframes*2352 bytes) */
};
/* vlume control */
#define CDROMSUBCHNL 0x530b /* (struct cdrom_subchnl) */
- /* read sub-channel data */
+ /* read Q sub-channel data */
#define CDROMREADMODE2 0x530c /* (struct cdrom_read) */
/* read type-2 data (not suppt) */
void (*release) (struct inode *, struct file *);
int (*fsync) (struct inode *, struct file *);
int (*fasync) (struct inode *, struct file *, int);
+ int (*check_media_change) (dev_t dev);
+ int (*revalidate) (dev_t dev);
};
struct inode_operations {
extern void check_disk_change(dev_t dev);
extern void invalidate_inodes(dev_t dev);
extern void invalidate_buffers(dev_t dev);
-extern int floppy_change(struct buffer_head * first_block);
extern void sync_inodes(dev_t dev);
extern void sync_dev(dev_t dev);
extern int fsync_dev(dev_t dev);
#define MCD_BASE_ADDR 0x300
/* *** change this to set the interrupt number */
-#define MCD_INTR_NR 11
+#define MCD_INTR_NR 10
/* Increase this if you get lots of timeouts */
#define MCD_STATUS_DELAY 100
* and specify the type of your interface in SBPRO.
*
* SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
- * LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ...
+ * LASERMATE (CI-101P, WDH-7001C) adresses typically are 0x0300, 0x0310, ...
* SPEA addresses are 0x320, 0x330, 0x340, 0x350
* there are some soundcards on the market with 0x0630, 0x0650, ...
*