patch-2.1.70 linux/drivers/cdrom/sbpcd.c

Next file: linux/drivers/cdrom/sbpcd.h
Previous file: linux/drivers/cdrom/optcd.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.69/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
@@ -13,7 +13,7 @@
  *             labelled E2550UA or MK4015 or 2800F).
  */
 
-#define VERSION "v4.6 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "v4.61 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 /*   Copyright (C) 1993, 1994, 1995  Eberhard Moenkeberg <emoenke@gwdg.de>
  *
@@ -300,6 +300,10 @@
  *       Experiments to speed up the CD-55A; again with help of Rob Riggs
  *       (to be true, he gave both, idea & code. ;-)
  *
+ *  4.61 Ported to Uniform CD-ROM driver by 
+ *       Heiko Eissfeldt <heiko@colossus.escape.de> with additional
+ *       changes by Erik Andersen <andersee@debian.org>
+ *
  *
  *  TODO
  *     implement "read all subchannel data" (96 bytes per frame)
@@ -334,8 +338,8 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <stdarg.h>
-#include <linux/sbpcd.h>
 #include <linux/config.h>
+#include "sbpcd.h"
 
 #if !(SBPCD_ISSUE-1)
 #define MAJOR_NR MATSUSHITA_CDROM_MAJOR
@@ -404,6 +408,7 @@
 	CDROM_PORT, SBPRO, /* probe with user's setup first */
 #if DISTRIBUTION
 	0x230, 1, /* Soundblaster Pro and 16 (default) */
+#if 0
 	0x300, 0, /* CI-101P (default), WDH-7001C (default),
 		     Galaxy (default), Reveal (one default) */
 	0x250, 1, /* OmniCD default, Soundblaster Pro and 16 */
@@ -438,6 +443,7 @@
 	0x290, 1, /* Soundblaster 16 */
 	0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
 #endif MODULE
+#endif
 #endif DISTRIBUTION
 };
 #else
@@ -523,7 +529,7 @@
 #if DISTRIBUTION
 static int sbpcd_debug = (1<<DBG_INF);
 #else
-static int sbpcd_debug = ((1<<DBG_INF) |
+static int sbpcd_debug = 0 & ((1<<DBG_INF) |
 			  (1<<DBG_TOC) |
 			  (1<<DBG_MUL) |
 			  (1<<DBG_UPC));
@@ -558,7 +564,7 @@
 static const char *str_ss_l = "soundscape";
 static const char *str_t16 = "Teac16bit";
 static const char *str_t16_l = "teac16bit";
-const char *type;
+static const char *type;
 
 #if !(SBPCD_ISSUE-1)
 static const char *major_name="sbpcd";
@@ -736,7 +742,8 @@
 	u_char mode_yb_7;
 	u_char mode_xb_8;
 	u_char delay;
-	
+	struct cdrom_device_info *sbpcd_infop;
+
 } D_S[NR_SBPCD];
 
 /*
@@ -1990,6 +1997,7 @@
 		if (D_S[d].error_byte!=aud_12) return -501;
 	return (0);
 }
+
 /*==========================================================================*/
 static int SetSpeed(void)
 {
@@ -2005,6 +2013,19 @@
 	i=cc_SetSpeed(speed,0,0);
 	return (i);
 }
+
+static void switch_drive(int i);
+
+static int sbpcd_select_speed(struct cdrom_device_info *cdi, int speed)
+{
+  int i = MINOR(cdi->dev);
+
+  if (i != d)
+    switch_drive(i);
+
+  return cc_SetSpeed(speed == 2 ? speed_300 : speed_150, 0, 0);
+}
+
 /*==========================================================================*/
 static int DriveReset(void)
 {
@@ -2030,6 +2051,17 @@
 	}
 	return (0);
 }
+
+static int sbpcd_reset(struct cdrom_device_info *cdi)
+{
+  int i = MINOR(cdi->dev);
+
+  if (i != d)
+    switch_drive(i);
+
+  return DriveReset();
+}
+
 /*==========================================================================*/
 static int cc_PlayAudio(int pos_audio_start,int pos_audio_end)
 {
@@ -2220,6 +2252,12 @@
 	}
 	return (i);
 }
+
+static int sbpcd_lock_door(struct cdrom_device_info *cdi, int lock)
+{
+  return lock ? LockDoor() : UnLockDoor();
+}
+
 /*==========================================================================*/
 static int cc_CloseTray(void)
 {
@@ -2261,6 +2299,12 @@
 	msg(DBG_LCS,"p_door_closed bit %d after\n", st_door_closed);
 	return (i);
 }
+
+static int sbpcd_tray_move(struct cdrom_device_info *cdi, int position)
+{
+  return position ? cc_CloseTray() : 0; 
+}
+
 /*==========================================================================*/
 static int cc_ReadSubQ(void)
 {
@@ -2956,6 +3000,79 @@
 	D_S[d].diskstate_flags |= upc_bit;
 	return (0);
 }
+
+static int sbpcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
+{
+	int i;
+	unsigned char *mcnp = mcn->medium_catalog_number;
+	unsigned char *resp;
+
+	D_S[d].diskstate_flags &= ~upc_bit;
+	clr_cmdbuf();
+	if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_READ_UPC;
+		response_count=8;
+		flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam0L_drive)
+	{
+		drvcmd[0]=CMD0_READ_UPC;
+		response_count=0;
+		flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
+	}
+	else if (fam2_drive)
+	{
+		return (-1);
+	}
+	else if (famT_drive)
+	{
+		return (-1);
+	}
+	i=cmd_out();
+	if (i<0)
+	{
+		msg(DBG_000,"cc_ReadUPC cmd_out: err %d\n", i);
+		return (i);
+	}
+	if (fam0L_drive)
+	{
+		response_count=16;
+		if (famL_drive) flags_cmd_out=f_putcmd;
+		i=cc_ReadPacket();
+		if (i<0)
+		{
+			msg(DBG_000,"cc_ReadUPC ReadPacket: err %d\n", i);
+			return (i);
+		}
+	}
+	D_S[d].UPC_ctl_adr=0;
+	if (fam1_drive) i=0;
+	else i=2;
+
+	resp = infobuf + i;
+	if (*resp++ == 0x80) {
+		/* packed bcd to single ASCII digits */
+		*mcnp++ = (*resp >> 4)     + '0';
+		*mcnp++ = (*resp++ & 0x0f) + '0';
+		*mcnp++ = (*resp >> 4)     + '0';
+		*mcnp++ = (*resp++ & 0x0f) + '0';
+		*mcnp++ = (*resp >> 4)     + '0';
+		*mcnp++ = (*resp++ & 0x0f) + '0';
+		*mcnp++ = (*resp >> 4)     + '0';
+		*mcnp++ = (*resp++ & 0x0f) + '0';
+		*mcnp++ = (*resp >> 4)     + '0';
+		*mcnp++ = (*resp++ & 0x0f) + '0';
+		*mcnp++ = (*resp >> 4)     + '0';
+		*mcnp++ = (*resp++ & 0x0f) + '0';
+		*mcnp++ = (*resp >> 4)     + '0';
+	}
+	*mcnp = '\0';
+
+	D_S[d].diskstate_flags |= upc_bit;
+	return (0);
+}
+
 /*==========================================================================*/
 static int cc_CheckMultiSession(void)
 {
@@ -3716,6 +3833,21 @@
 	int i, j;
 	D_S[d].diskstate_flags &= ~toc_bit;
 	D_S[d].ored_ctl_adr=0;
+	/* special handling of CD-I HE */
+	if ((D_S[d].n_first_track == 2 && D_S[d].n_last_track == 2) ||
+             D_S[d].xa_byte == 0x10)
+        {
+		D_S[d].TocBuffer[1].nixbyte=0;
+		D_S[d].TocBuffer[1].ctl_adr=0x40;
+		D_S[d].TocBuffer[1].number=1;
+		D_S[d].TocBuffer[1].format=0;
+		D_S[d].TocBuffer[1].address=blk2msf(0);
+		D_S[d].ored_ctl_adr |= 0x40;
+		D_S[d].n_first_track = 1;
+		D_S[d].n_last_track = 1;
+		D_S[d].xa_byte = 0x10;
+                j = 2;
+        } else
 	for (j=D_S[d].n_first_track;j<=D_S[d].n_last_track;j++)
 	{
 		i=cc_ReadTocEntry(j);
@@ -3801,7 +3933,7 @@
 	}
 	i=cc_ReadUPC();
 	if (i<0) msg(DBG_INF,"DiskInfo: cc_ReadUPC returns %d\n", i);
-	if ((fam0L_drive) && (D_S[d].xa_byte==0x20))
+	if ((fam0L_drive) && (D_S[d].xa_byte==0x20 || D_S[d].xa_byte == 0x10))
 	{
 		/* XA disk with old drive */
 		cc_ModeSelect(CD_FRAMESIZE_RAW1);
@@ -3811,6 +3943,18 @@
 	msg(DBG_000,"DiskInfo done.\n");
 	return (0);
 }
+
+static int sbpcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
+{
+  if (CDSL_CURRENT != slot_nr) {
+     /* we have no changer support */
+     return -EINVAL;
+  }
+
+  return D_S[d].status_bits & p1_disk_ok ? CDS_DISC_OK : CDS_DRIVE_NOT_READY;
+}
+
+
 /*==========================================================================*/
 #if FUTURE
 /*
@@ -3934,40 +4078,40 @@
 	return (1);
 }
 /*==========================================================================*/
+		
+static int sbpcd_get_last_session(struct cdrom_device_info *cdi, struct cdrom_multisession *ms_infp)
+{
+	ms_infp->addr_format = CDROM_LBA;
+	ms_infp->addr.lba    = D_S[d].lba_multi;
+	if (D_S[d].f_multisession)
+		ms_infp->xa_flag=1; /* valid redirection address */
+	else
+		ms_infp->xa_flag=0; /* invalid redirection address */
+
+	return  1;
+}
 
 /*==========================================================================*/
 /*==========================================================================*/
 /*
  * ioctl support
  */
-static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg)
+static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd,
+		      u_long arg)
 {
-	int i, st;
+	int i;
 	
 	msg(DBG_IO2,"ioctl(%d, 0x%08lX, 0x%08lX)\n",
-	    MINOR(inode->i_rdev), cmd, arg);
-	if (!inode) return (-EINVAL);
-	i=MINOR(inode->i_rdev);
+	    MINOR(cdi->dev), cmd, arg);
+	i=MINOR(cdi->dev);
 	if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1))
 	{
-		msg(DBG_INF, "ioctl: bad device: %04X\n", inode->i_rdev);
+		msg(DBG_INF, "ioctl: bad device: %04X\n", cdi->dev);
 		return (-ENXIO);             /* no such drive */
 	}
 	down(&ioctl_read_sem);
 	if (d!=i) switch_drive(i);
 	
-#if 0
-	st=GetStatus();
-	if (st<0) RETURN_UP(-EIO);
-	
-	if (!toc_valid)
-	{
-		i=DiskInfo();
-		if (i<0) RETURN_UP(-EIO);	/* error reading TOC */
-	}
-#endif
-	
 	msg(DBG_IO2,"ioctl: device %d, request %04X\n",i,cmd);
 	switch (cmd) 		/* Sun-compatible */
 	{
@@ -3975,305 +4119,47 @@
 		if (!suser()) RETURN_UP(-EPERM);
 		i=sbpcd_dbg_ioctl(arg,1);
 		RETURN_UP(i);
+	case CDROMRESET:      /* hard reset the drive */
+		msg(DBG_IOC,"ioctl: CDROMRESET entered.\n");
+		i=DriveReset();
+		D_S[d].audio_state=0;
+		RETURN_UP(i);
 		
-	case CDROMPAUSE:     /* Pause the drive */
-		msg(DBG_IOC,"ioctl: CDROMPAUSE entered.\n");
-		/* pause the drive unit when it is currently in PLAY mode,         */
-		/* or reset the starting and ending locations when in PAUSED mode. */
-		/* If applicable, at the next stopping point it reaches            */
-		/* the drive will discontinue playing.                             */
-		switch (D_S[d].audio_state)
-		{
-		case audio_playing:
-			if (famL_drive) i=cc_ReadSubQ();
-			else i=cc_Pause_Resume(1);
-			if (i<0) RETURN_UP(-EIO);
-			if (famL_drive) i=cc_Pause_Resume(1);
-			else i=cc_ReadSubQ();
-			if (i<0) RETURN_UP(-EIO);
-			D_S[d].pos_audio_start=D_S[d].SubQ_run_tot;
-			D_S[d].audio_state=audio_pausing;
-			RETURN_UP(0);
-		case audio_pausing:
-			i=cc_Seek(D_S[d].pos_audio_start,1);
-			if (i<0) RETURN_UP(-EIO);
-			RETURN_UP(0);
-		default:
-			RETURN_UP(-EINVAL);
-		}
-		
-	case CDROMRESUME: /* resume paused audio play */
-		msg(DBG_IOC,"ioctl: CDROMRESUME entered.\n");
-		/* resume playing audio tracks when a previous PLAY AUDIO call has  */
-		/* been paused with a PAUSE command.                                */
-		/* It will resume playing from the location saved in SubQ_run_tot.  */
-		if (D_S[d].audio_state!=audio_pausing) return -EINVAL;
-		if (famL_drive)
-			i=cc_PlayAudio(D_S[d].pos_audio_start,
-				       D_S[d].pos_audio_end);
-		else i=cc_Pause_Resume(3);
-		if (i<0) RETURN_UP(-EIO);
-		D_S[d].audio_state=audio_playing;
-		RETURN_UP(0);
-		
-	case CDROMPLAYMSF:
-		msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n");
+	case CDROMREADMODE1:
+		msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n");
 #if SAFE_MIXED
 		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
 #endif SAFE_MIXED
-		if (D_S[d].audio_state==audio_playing)
-		{
-			i=cc_Pause_Resume(1);
-			if (i<0) RETURN_UP(-EIO);
-			i=cc_ReadSubQ();
-			if (i<0) RETURN_UP(-EIO);
-			D_S[d].pos_audio_start=D_S[d].SubQ_run_tot;
-			i=cc_Seek(D_S[d].pos_audio_start,1);
-		}
-		st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_msf));
-		if (st) RETURN_UP(st);
-		copy_from_user(&msf, (void *) arg, sizeof(struct cdrom_msf));
-		/* values come as msf-bin */
-		D_S[d].pos_audio_start = (msf.cdmsf_min0<<16) |
-                        (msf.cdmsf_sec0<<8) |
-				msf.cdmsf_frame0;
-		D_S[d].pos_audio_end = (msf.cdmsf_min1<<16) |
-			(msf.cdmsf_sec1<<8) |
-				msf.cdmsf_frame1;
-		msg(DBG_IOX,"ioctl: CDROMPLAYMSF %08X %08X\n",
-		    D_S[d].pos_audio_start,D_S[d].pos_audio_end);
-		i=cc_PlayAudio(D_S[d].pos_audio_start,D_S[d].pos_audio_end);
-		if (i<0)
-		{
-			msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
-			DriveReset();
-			D_S[d].audio_state=0;
-			RETURN_UP(-EIO);
-		}
-		D_S[d].audio_state=audio_playing;
+		cc_ModeSelect(CD_FRAMESIZE);
+		cc_ModeSense();
+		D_S[d].mode=READ_M1;
 		RETURN_UP(0);
 		
-	case CDROMPLAYTRKIND: /* Play a track.  This currently ignores index. */
-		msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n");
+	case CDROMREADMODE2: /* not usable at the moment */
+		msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n");
 #if SAFE_MIXED
 		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
 #endif SAFE_MIXED
-		if (D_S[d].audio_state==audio_playing)
-		{
-			msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n");
-#if 1
-			RETURN_UP(0); /* just let us play on */
-#else
-			RETURN_UP(-EINVAL); /* play on, but say "error" */
-#endif
-		}
-		st=verify_area(VERIFY_READ,(void *) arg,sizeof(struct cdrom_ti));
-		if (st<0)
-		{
-			msg(DBG_IOX,"CDROMPLAYTRKIND: verify_area error.\n");
-			RETURN_UP(st);
-		}
-		copy_from_user(&ti,(void *) arg,sizeof(struct cdrom_ti));
-		msg(DBG_IOX,"ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d\n",
-		    ti.cdti_trk0,ti.cdti_ind0,ti.cdti_trk1,ti.cdti_ind1);
-		if (ti.cdti_trk0<D_S[d].n_first_track) RETURN_UP(-EINVAL);
-		if (ti.cdti_trk0>D_S[d].n_last_track) RETURN_UP(-EINVAL);
-		if (ti.cdti_trk1<ti.cdti_trk0) ti.cdti_trk1=ti.cdti_trk0;
-		if (ti.cdti_trk1>D_S[d].n_last_track) ti.cdti_trk1=D_S[d].n_last_track;
-		D_S[d].pos_audio_start=D_S[d].TocBuffer[ti.cdti_trk0].address;
-		D_S[d].pos_audio_end=D_S[d].TocBuffer[ti.cdti_trk1+1].address;
-		i=cc_PlayAudio(D_S[d].pos_audio_start,D_S[d].pos_audio_end);
-		if (i<0)
-		{
-			msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
-			DriveReset();
-			D_S[d].audio_state=0;
-			RETURN_UP(-EIO);
-		}
-		D_S[d].audio_state=audio_playing;
+		cc_ModeSelect(CD_FRAMESIZE_RAW1);
+		cc_ModeSense();
+		D_S[d].mode=READ_M2;
 		RETURN_UP(0);
 		
-	case CDROMREADTOCHDR:        /* Read the table of contents header */
-		msg(DBG_IOC,"ioctl: CDROMREADTOCHDR entered.\n");
-		tochdr.cdth_trk0=D_S[d].n_first_track;
-		tochdr.cdth_trk1=D_S[d].n_last_track;
-		st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_tochdr));
-		if (st) RETURN_UP(st);
-		copy_to_user((void *) arg, &tochdr, sizeof(struct cdrom_tochdr));
-		RETURN_UP(0);
+	case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */
+		msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n");
+		if (D_S[d].sbp_audsiz>0) vfree(D_S[d].aud_buf);
+		D_S[d].aud_buf=NULL;
+		D_S[d].sbp_audsiz=arg;
 		
-	case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
-		msg(DBG_IOC,"ioctl: CDROMREADTOCENTRY entered.\n");
-		st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_tocentry));
-		if (st) RETURN_UP(st);
-		copy_from_user(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry));
-		i=tocentry.cdte_track;
-		if (i==CDROM_LEADOUT) i=D_S[d].n_last_track+1;
-		else if (i<D_S[d].n_first_track||i>D_S[d].n_last_track)
-                  RETURN_UP(-EINVAL);
-		tocentry.cdte_adr=D_S[d].TocBuffer[i].ctl_adr&0x0F;
-		tocentry.cdte_ctrl=(D_S[d].TocBuffer[i].ctl_adr>>4)&0x0F;
-		tocentry.cdte_datamode=D_S[d].TocBuffer[i].format;
-		if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */
+		if (D_S[d].sbp_audsiz>0)
 		{
-			tocentry.cdte_addr.msf.minute=(D_S[d].TocBuffer[i].address>>16)&0x00FF;
-			tocentry.cdte_addr.msf.second=(D_S[d].TocBuffer[i].address>>8)&0x00FF;
-			tocentry.cdte_addr.msf.frame=D_S[d].TocBuffer[i].address&0x00FF;
-		}
-		else if (tocentry.cdte_format==CDROM_LBA) /* blk required */
-			tocentry.cdte_addr.lba=msf2blk(D_S[d].TocBuffer[i].address);
-		else RETURN_UP(-EINVAL);
-		copy_to_user((void *) arg, &tocentry, sizeof(struct cdrom_tocentry));
-		RETURN_UP(0);
-		
-	case CDROMRESET:      /* hard reset the drive */
-		msg(DBG_IOC,"ioctl: CDROMRESET entered.\n");
-		i=DriveReset();
-		D_S[d].audio_state=0;
-		RETURN_UP(i);
-		
-	case CDROMSTOP:      /* Spin down the drive */
-		msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n");
-#if SAFE_MIXED
-		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
-#endif SAFE_MIXED
-		i=cc_Pause_Resume(1);
-		D_S[d].audio_state=0;
-		RETURN_UP(i);
-		
-	case CDROMSTART:  /* Spin up the drive */
-		msg(DBG_IOC,"ioctl: CDROMSTART entered.\n");
-		cc_SpinUp();
-		D_S[d].audio_state=0;
-		RETURN_UP(0);
-		
-	case CDROMEJECT:
-		msg(DBG_IOC,"ioctl: CDROMEJECT entered.\n");
-		if (fam0_drive) return (0);
-		if (D_S[d].open_count>1) RETURN_UP(-EBUSY);
-		i=UnLockDoor();
-		D_S[d].open_count=-9; /* to get it locked next time again */
-		i=cc_SpinDown();
-		msg(DBG_IOX,"ioctl: cc_SpinDown returned %d.\n", i);
-		msg(DBG_TEA,"ioctl: cc_SpinDown returned %d.\n", i);
-		if (i<0) RETURN_UP(-EIO);
-		D_S[d].CD_changed=0xFF;
-		D_S[d].diskstate_flags=0;
-		D_S[d].audio_state=0;
-		RETURN_UP(0);
-		
-	case CDROMEJECT_SW:
-		msg(DBG_IOC,"ioctl: CDROMEJECT_SW entered.\n");
-		if (fam0_drive) RETURN_UP(0);
-		D_S[d].f_eject=arg;
-		RETURN_UP(0);
-		
-	case CDROMVOLCTRL:   /* Volume control */
-		msg(DBG_IOC,"ioctl: CDROMVOLCTRL entered.\n");
-		st=verify_area(VERIFY_READ,(void *) arg,sizeof(volctrl));
-		if (st) RETURN_UP(st);
-		copy_from_user(&volctrl,(char *) arg,sizeof(volctrl));
-		D_S[d].vol_chan0=0;
-		D_S[d].vol_ctrl0=volctrl.channel0;
-		D_S[d].vol_chan1=1;
-		D_S[d].vol_ctrl1=volctrl.channel1;
-		i=cc_SetVolume();
-		RETURN_UP(0);
-		
-	case CDROMVOLREAD:   /* read Volume settings from drive */
-		msg(DBG_IOC,"ioctl: CDROMVOLREAD entered.\n");
-		st=verify_area(VERIFY_WRITE,(void *)arg,sizeof(volctrl));
-		if (st) RETURN_UP(st);
-		st=cc_GetVolume();
-		if (st<0) return (st);
-		volctrl.channel0=D_S[d].vol_ctrl0;
-		volctrl.channel1=D_S[d].vol_ctrl1;
-		volctrl.channel2=0;
-		volctrl.channel2=0;
-		copy_to_user((void *)arg,&volctrl,sizeof(volctrl));
-		RETURN_UP(0);
-
-	case CDROMSUBCHNL:   /* Get subchannel info */
-		msg(DBG_IOS,"ioctl: CDROMSUBCHNL entered.\n");
-		if ((st_spinning)||(!subq_valid)) {
-			i=cc_ReadSubQ();
-			if (i<0) RETURN_UP(-EIO);
-		}
-		st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
-		if (st)	RETURN_UP(st);
-		copy_from_user(&SC, (void *) arg, sizeof(struct cdrom_subchnl));
-		switch (D_S[d].audio_state)
-		{
-		case audio_playing:
-			SC.cdsc_audiostatus=CDROM_AUDIO_PLAY;
-			break;
-		case audio_pausing:
-			SC.cdsc_audiostatus=CDROM_AUDIO_PAUSED;
-			break;
-		default:
-			SC.cdsc_audiostatus=CDROM_AUDIO_NO_STATUS;
-			break;
-		}
-		SC.cdsc_adr=D_S[d].SubQ_ctl_adr;
-		SC.cdsc_ctrl=D_S[d].SubQ_ctl_adr>>4;
-		SC.cdsc_trk=bcd2bin(D_S[d].SubQ_trk);
-		SC.cdsc_ind=bcd2bin(D_S[d].SubQ_pnt_idx);
-		if (SC.cdsc_format==CDROM_LBA)
-		{
-			SC.cdsc_absaddr.lba=msf2blk(D_S[d].SubQ_run_tot);
-			SC.cdsc_reladdr.lba=msf2blk(D_S[d].SubQ_run_trk);
-		}
-		else /* not only if (SC.cdsc_format==CDROM_MSF) */
-		{
-			SC.cdsc_absaddr.msf.minute=(D_S[d].SubQ_run_tot>>16)&0x00FF;
-			SC.cdsc_absaddr.msf.second=(D_S[d].SubQ_run_tot>>8)&0x00FF;
-			SC.cdsc_absaddr.msf.frame=D_S[d].SubQ_run_tot&0x00FF;
-			SC.cdsc_reladdr.msf.minute=(D_S[d].SubQ_run_trk>>16)&0x00FF;
-			SC.cdsc_reladdr.msf.second=(D_S[d].SubQ_run_trk>>8)&0x00FF;
-			SC.cdsc_reladdr.msf.frame=D_S[d].SubQ_run_trk&0x00FF;
-		}
-		copy_to_user((void *) arg, &SC, sizeof(struct cdrom_subchnl));
-		msg(DBG_IOS,"CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n",
-		    SC.cdsc_format,SC.cdsc_audiostatus,
-		    SC.cdsc_adr,SC.cdsc_ctrl,
-		    SC.cdsc_trk,SC.cdsc_ind,
-		    SC.cdsc_absaddr,SC.cdsc_reladdr);
-		RETURN_UP(0);
-		
-	case CDROMREADMODE1:
-		msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n");
-#if SAFE_MIXED
-		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
-#endif SAFE_MIXED
-		cc_ModeSelect(CD_FRAMESIZE);
-		cc_ModeSense();
-		D_S[d].mode=READ_M1;
-		RETURN_UP(0);
-		
-	case CDROMREADMODE2: /* not usable at the moment */
-		msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n");
-#if SAFE_MIXED
-		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
-#endif SAFE_MIXED
-		cc_ModeSelect(CD_FRAMESIZE_RAW1);
-		cc_ModeSense();
-		D_S[d].mode=READ_M2;
-		RETURN_UP(0);
-		
-	case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */
-		msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n");
-		if (D_S[d].sbp_audsiz>0) vfree(D_S[d].aud_buf);
-		D_S[d].aud_buf=NULL;
-		D_S[d].sbp_audsiz=arg;
-		if (D_S[d].sbp_audsiz>0)
-		{
-			D_S[d].aud_buf=(u_char *) vmalloc(D_S[d].sbp_audsiz*CD_FRAMESIZE_RAW);
-			if (D_S[d].aud_buf==NULL)
-			{
-				msg(DBG_INF,"audio buffer (%d frames) not available.\n",D_S[d].sbp_audsiz);
-				D_S[d].sbp_audsiz=0;
-			}
-			else msg(DBG_INF,"audio buffer size: %d frames.\n",D_S[d].sbp_audsiz);
+			D_S[d].aud_buf=(u_char *) vmalloc(D_S[d].sbp_audsiz*CD_FRAMESIZE_RAW);
+			if (D_S[d].aud_buf==NULL)
+			{
+				msg(DBG_INF,"audio buffer (%d frames) not available.\n",D_S[d].sbp_audsiz);
+				D_S[d].sbp_audsiz=0;
+			}
+			else msg(DBG_INF,"audio buffer size: %d frames.\n",D_S[d].sbp_audsiz);
 		}
 		RETURN_UP(D_S[d].sbp_audsiz);
 
@@ -4496,28 +4382,277 @@
 		RETURN_UP(0);
 	} /* end of CDROMREADAUDIO */
 		
-	case CDROMMULTISESSION: /* tell start-of-last-session */
-		msg(DBG_IOC,"ioctl: CDROMMULTISESSION entered.\n");
-		st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_multisession));
-		if (st) RETURN_UP(st);
-		copy_from_user(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
-		if (ms_info.addr_format==CDROM_MSF) /* MSF-bin requested */
-			lba2msf(D_S[d].lba_multi,&ms_info.addr.msf.minute);
-		else if (ms_info.addr_format==CDROM_LBA) /* lba requested */
-			ms_info.addr.lba=D_S[d].lba_multi;
-		else RETURN_UP(-EINVAL);
-		if (D_S[d].f_multisession) ms_info.xa_flag=1; /* valid redirection address */
-		else ms_info.xa_flag=0; /* invalid redirection address */
-		copy_to_user((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
-		msg(DBG_MUL,"ioctl: CDROMMULTISESSION done (%d, %08X).\n",
-		    ms_info.xa_flag, ms_info.addr.lba);
-		RETURN_UP(0);
-		
 	case BLKRASET:
 		if(!suser()) RETURN_UP(-EACCES);
-		if(!(inode->i_rdev)) RETURN_UP(-EINVAL);
+		if(!(cdi->dev)) RETURN_UP(-EINVAL);
 		if(arg > 0xff) RETURN_UP(-EINVAL);
-		read_ahead[MAJOR(inode->i_rdev)] = arg;
+		read_ahead[MAJOR(cdi->dev)] = arg;
+		RETURN_UP(0);
+#if 0
+	case CDROMEJECT:
+		msg(DBG_IOC,"ioctl: CDROMEJECT entered.\n");
+		if (fam0_drive) return (0);
+		if (D_S[d].open_count>1) RETURN_UP(-EBUSY);
+		i=UnLockDoor();
+		D_S[d].open_count=-9; /* to get it locked next time again */
+		i=cc_SpinDown();
+		msg(DBG_IOX,"ioctl: cc_SpinDown returned %d.\n", i);
+		msg(DBG_TEA,"ioctl: cc_SpinDown returned %d.\n", i);
+		if (i<0) RETURN_UP(-EIO);
+		D_S[d].CD_changed=0xFF;
+		D_S[d].diskstate_flags=0;
+		D_S[d].audio_state=0;
+		RETURN_UP(0);
+
+	case CDROMEJECT_SW:
+		msg(DBG_IOC,"ioctl: CDROMEJECT_SW entered.\n");
+		if (fam0_drive) RETURN_UP(0);
+		D_S[d].f_eject=arg;
+		RETURN_UP(0);
+#endif		
+	default:
+		msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd);
+		RETURN_UP(-EINVAL);
+	} /* end switch(cmd) */
+}
+
+static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd,
+		       void * arg)
+{
+	int i, st;
+	
+	msg(DBG_IO2,"ioctl(%d, 0x%08lX, 0x%08p)\n",
+	    MINOR(cdi->dev), cmd, arg);
+	i=MINOR(cdi->dev);
+	if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1))
+	{
+		msg(DBG_INF, "ioctl: bad device: %04X\n", cdi->dev);
+		return (-ENXIO);             /* no such drive */
+	}
+	down(&ioctl_read_sem);
+	if (d!=i) switch_drive(i);
+	
+	msg(DBG_IO2,"ioctl: device %d, request %04X\n",i,cmd);
+	switch (cmd) 		/* Sun-compatible */
+	{
+		
+	case CDROMPAUSE:     /* Pause the drive */
+		msg(DBG_IOC,"ioctl: CDROMPAUSE entered.\n");
+		/* pause the drive unit when it is currently in PLAY mode,         */
+		/* or reset the starting and ending locations when in PAUSED mode. */
+		/* If applicable, at the next stopping point it reaches            */
+		/* the drive will discontinue playing.                             */
+		switch (D_S[d].audio_state)
+		{
+		case audio_playing:
+			if (famL_drive) i=cc_ReadSubQ();
+			else i=cc_Pause_Resume(1);
+			if (i<0) RETURN_UP(-EIO);
+			if (famL_drive) i=cc_Pause_Resume(1);
+			else i=cc_ReadSubQ();
+			if (i<0) RETURN_UP(-EIO);
+			D_S[d].pos_audio_start=D_S[d].SubQ_run_tot;
+			D_S[d].audio_state=audio_pausing;
+			RETURN_UP(0);
+		case audio_pausing:
+			i=cc_Seek(D_S[d].pos_audio_start,1);
+			if (i<0) RETURN_UP(-EIO);
+			RETURN_UP(0);
+		default:
+			RETURN_UP(-EINVAL);
+		}
+		
+	case CDROMRESUME: /* resume paused audio play */
+		msg(DBG_IOC,"ioctl: CDROMRESUME entered.\n");
+		/* resume playing audio tracks when a previous PLAY AUDIO call has  */
+		/* been paused with a PAUSE command.                                */
+		/* It will resume playing from the location saved in SubQ_run_tot.  */
+		if (D_S[d].audio_state!=audio_pausing) return -EINVAL;
+		if (famL_drive)
+			i=cc_PlayAudio(D_S[d].pos_audio_start,
+				       D_S[d].pos_audio_end);
+		else i=cc_Pause_Resume(3);
+		if (i<0) RETURN_UP(-EIO);
+		D_S[d].audio_state=audio_playing;
+		RETURN_UP(0);
+		
+	case CDROMPLAYMSF:
+		msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n");
+#if SAFE_MIXED
+		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
+#endif SAFE_MIXED
+		if (D_S[d].audio_state==audio_playing)
+		{
+			i=cc_Pause_Resume(1);
+			if (i<0) RETURN_UP(-EIO);
+			i=cc_ReadSubQ();
+			if (i<0) RETURN_UP(-EIO);
+			D_S[d].pos_audio_start=D_S[d].SubQ_run_tot;
+			i=cc_Seek(D_S[d].pos_audio_start,1);
+		}
+		memcpy(&msf, (void *) arg, sizeof(struct cdrom_msf));
+		/* values come as msf-bin */
+		D_S[d].pos_audio_start = (msf.cdmsf_min0<<16) |
+                        (msf.cdmsf_sec0<<8) |
+				msf.cdmsf_frame0;
+		D_S[d].pos_audio_end = (msf.cdmsf_min1<<16) |
+			(msf.cdmsf_sec1<<8) |
+				msf.cdmsf_frame1;
+		msg(DBG_IOX,"ioctl: CDROMPLAYMSF %08X %08X\n",
+		    D_S[d].pos_audio_start,D_S[d].pos_audio_end);
+		i=cc_PlayAudio(D_S[d].pos_audio_start,D_S[d].pos_audio_end);
+		if (i<0)
+		{
+			msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
+			DriveReset();
+			D_S[d].audio_state=0;
+			RETURN_UP(-EIO);
+		}
+		D_S[d].audio_state=audio_playing;
+		RETURN_UP(0);
+		
+	case CDROMPLAYTRKIND: /* Play a track.  This currently ignores index. */
+		msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n");
+#if SAFE_MIXED
+		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
+#endif SAFE_MIXED
+		if (D_S[d].audio_state==audio_playing)
+		{
+			msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n");
+#if 1
+			RETURN_UP(0); /* just let us play on */
+#else
+			RETURN_UP(-EINVAL); /* play on, but say "error" */
+#endif
+		}
+		memcpy(&ti,(void *) arg,sizeof(struct cdrom_ti));
+		msg(DBG_IOX,"ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d\n",
+		    ti.cdti_trk0,ti.cdti_ind0,ti.cdti_trk1,ti.cdti_ind1);
+		if (ti.cdti_trk0<D_S[d].n_first_track) RETURN_UP(-EINVAL);
+		if (ti.cdti_trk0>D_S[d].n_last_track) RETURN_UP(-EINVAL);
+		if (ti.cdti_trk1<ti.cdti_trk0) ti.cdti_trk1=ti.cdti_trk0;
+		if (ti.cdti_trk1>D_S[d].n_last_track) ti.cdti_trk1=D_S[d].n_last_track;
+		D_S[d].pos_audio_start=D_S[d].TocBuffer[ti.cdti_trk0].address;
+		D_S[d].pos_audio_end=D_S[d].TocBuffer[ti.cdti_trk1+1].address;
+		i=cc_PlayAudio(D_S[d].pos_audio_start,D_S[d].pos_audio_end);
+		if (i<0)
+		{
+			msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
+			DriveReset();
+			D_S[d].audio_state=0;
+			RETURN_UP(-EIO);
+		}
+		D_S[d].audio_state=audio_playing;
+		RETURN_UP(0);
+		
+	case CDROMREADTOCHDR:        /* Read the table of contents header */
+		msg(DBG_IOC,"ioctl: CDROMREADTOCHDR entered.\n");
+		tochdr.cdth_trk0=D_S[d].n_first_track;
+		tochdr.cdth_trk1=D_S[d].n_last_track;
+		memcpy((void *) arg, &tochdr, sizeof(struct cdrom_tochdr));
+		RETURN_UP(0);
+		
+	case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
+		msg(DBG_IOC,"ioctl: CDROMREADTOCENTRY entered.\n");
+		memcpy(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry));
+		i=tocentry.cdte_track;
+		if (i==CDROM_LEADOUT) i=D_S[d].n_last_track+1;
+		else if (i<D_S[d].n_first_track||i>D_S[d].n_last_track)
+                  RETURN_UP(-EINVAL);
+		tocentry.cdte_adr=D_S[d].TocBuffer[i].ctl_adr&0x0F;
+		tocentry.cdte_ctrl=(D_S[d].TocBuffer[i].ctl_adr>>4)&0x0F;
+		tocentry.cdte_datamode=D_S[d].TocBuffer[i].format;
+		if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */
+		{
+			tocentry.cdte_addr.msf.minute=(D_S[d].TocBuffer[i].address>>16)&0x00FF;
+			tocentry.cdte_addr.msf.second=(D_S[d].TocBuffer[i].address>>8)&0x00FF;
+			tocentry.cdte_addr.msf.frame=D_S[d].TocBuffer[i].address&0x00FF;
+		}
+		else if (tocentry.cdte_format==CDROM_LBA) /* blk required */
+			tocentry.cdte_addr.lba=msf2blk(D_S[d].TocBuffer[i].address);
+		else RETURN_UP(-EINVAL);
+		memcpy((void *) arg, &tocentry, sizeof(struct cdrom_tocentry));
+		RETURN_UP(0);
+		
+	case CDROMSTOP:      /* Spin down the drive */
+		msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n");
+#if SAFE_MIXED
+		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
+#endif SAFE_MIXED
+		i=cc_Pause_Resume(1);
+		D_S[d].audio_state=0;
+		RETURN_UP(i);
+		
+	case CDROMSTART:  /* Spin up the drive */
+		msg(DBG_IOC,"ioctl: CDROMSTART entered.\n");
+		cc_SpinUp();
+		D_S[d].audio_state=0;
+		RETURN_UP(0);
+		
+	case CDROMVOLCTRL:   /* Volume control */
+		msg(DBG_IOC,"ioctl: CDROMVOLCTRL entered.\n");
+		memcpy(&volctrl,(char *) arg,sizeof(volctrl));
+		D_S[d].vol_chan0=0;
+		D_S[d].vol_ctrl0=volctrl.channel0;
+		D_S[d].vol_chan1=1;
+		D_S[d].vol_ctrl1=volctrl.channel1;
+		i=cc_SetVolume();
+		RETURN_UP(0);
+		
+	case CDROMVOLREAD:   /* read Volume settings from drive */
+		msg(DBG_IOC,"ioctl: CDROMVOLREAD entered.\n");
+		st=cc_GetVolume();
+		if (st<0) return (st);
+		volctrl.channel0=D_S[d].vol_ctrl0;
+		volctrl.channel1=D_S[d].vol_ctrl1;
+		volctrl.channel2=0;
+		volctrl.channel2=0;
+		memcpy((void *)arg,&volctrl,sizeof(volctrl));
+		RETURN_UP(0);
+
+	case CDROMSUBCHNL:   /* Get subchannel info */
+		msg(DBG_IOS,"ioctl: CDROMSUBCHNL entered.\n");
+		if ((st_spinning)||(!subq_valid)) {
+			i=cc_ReadSubQ();
+			if (i<0) RETURN_UP(-EIO);
+		}
+		memcpy(&SC, (void *) arg, sizeof(struct cdrom_subchnl));
+		switch (D_S[d].audio_state)
+		{
+		case audio_playing:
+			SC.cdsc_audiostatus=CDROM_AUDIO_PLAY;
+			break;
+		case audio_pausing:
+			SC.cdsc_audiostatus=CDROM_AUDIO_PAUSED;
+			break;
+		default:
+			SC.cdsc_audiostatus=CDROM_AUDIO_NO_STATUS;
+			break;
+		}
+		SC.cdsc_adr=D_S[d].SubQ_ctl_adr;
+		SC.cdsc_ctrl=D_S[d].SubQ_ctl_adr>>4;
+		SC.cdsc_trk=bcd2bin(D_S[d].SubQ_trk);
+		SC.cdsc_ind=bcd2bin(D_S[d].SubQ_pnt_idx);
+		if (SC.cdsc_format==CDROM_LBA)
+		{
+			SC.cdsc_absaddr.lba=msf2blk(D_S[d].SubQ_run_tot);
+			SC.cdsc_reladdr.lba=msf2blk(D_S[d].SubQ_run_trk);
+		}
+		else /* not only if (SC.cdsc_format==CDROM_MSF) */
+		{
+			SC.cdsc_absaddr.msf.minute=(D_S[d].SubQ_run_tot>>16)&0x00FF;
+			SC.cdsc_absaddr.msf.second=(D_S[d].SubQ_run_tot>>8)&0x00FF;
+			SC.cdsc_absaddr.msf.frame=D_S[d].SubQ_run_tot&0x00FF;
+			SC.cdsc_reladdr.msf.minute=(D_S[d].SubQ_run_trk>>16)&0x00FF;
+			SC.cdsc_reladdr.msf.second=(D_S[d].SubQ_run_trk>>8)&0x00FF;
+			SC.cdsc_reladdr.msf.frame=D_S[d].SubQ_run_trk&0x00FF;
+		}
+		memcpy((void *) arg, &SC, sizeof(struct cdrom_subchnl));
+		msg(DBG_IOS,"CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n",
+		    SC.cdsc_format,SC.cdsc_audiostatus,
+		    SC.cdsc_adr,SC.cdsc_ctrl,
+		    SC.cdsc_trk,SC.cdsc_ind,
+		    SC.cdsc_absaddr,SC.cdsc_reladdr);
 		RETURN_UP(0);
 		
 	default:
@@ -5104,19 +5239,18 @@
 /*
  *  Open the device special file.  Check that a disk is in. Read TOC.
  */
-static int sbpcd_open(struct inode *ip, struct file *fp)
+static int sbpcd_open(struct cdrom_device_info *cdi, int purpose)
 {
 	int i;
 	
-	i = MINOR(ip->i_rdev);
+	i = MINOR(cdi->dev);
 	if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1))
 	{
-		msg(DBG_INF, "open: bad device: %04X\n", ip->i_rdev);
+		msg(DBG_INF, "open: bad device: %04X\n", cdi->dev);
 		return (-ENXIO);             /* no such drive */
 	}
-	if (fp->f_mode & 2)
-		return -EROFS;
 	
+	MOD_INC_USE_COUNT;
 	down(&ioctl_read_sem);
 	switch_drive(i);
 	
@@ -5136,21 +5270,13 @@
 	if (i<0)
 	{
 		msg(DBG_INF,"sbpcd_open: ResponseStatus timed out (%d).\n",i);
+		MOD_DEC_USE_COUNT;
 		RETURN_UP(-EIO);                  /* drive doesn't respond */
 	}
 	if (famT_drive)	msg(DBG_TEA,"sbpcd_open: ResponseStatus=%02X\n", i);
-	if (!st_door_closed)
-	{
-		if (famT_drive)	msg(DBG_TEA,"sbpcd_open: !st_door_closed.\n");
-		cc_CloseTray();
-		flags_cmd_out |= f_respo2;
-		cc_ReadStatus();
-		i=ResponseStatus();
-	}
 	if (!(famT_drive))
 		if (!st_spinning)
 		{
-			if (famT_drive)	msg(DBG_TEA,"sbpcd_open: !st_spinning.\n");
 			cc_SpinUp();
 			flags_cmd_out |= f_respo2;
 			cc_ReadStatus();
@@ -5161,19 +5287,12 @@
 	{
 		msg(DBG_INF, "sbpcd_open: no disk in drive.\n");
 		D_S[d].open_count=0;
-#if JUKEBOX
-		if (!fam0_drive)
-		{
-			i=UnLockDoor();
-			cc_SpinDown(); /* eject tray */
-		}
-#endif
+		MOD_DEC_USE_COUNT;
 		RETURN_UP(-ENXIO);
 	}
 	/*
 	 * try to keep an "open" counter here and lock the door if 0->1.
 	 */
-	MOD_INC_USE_COUNT;
 	msg(DBG_LCK,"open_count: %d -> %d\n",
 	    D_S[d].open_count,D_S[d].open_count+1);
 	if (++D_S[d].open_count<=1)
@@ -5201,22 +5320,21 @@
 /*
  *  On close, we flush all sbp blocks from the buffer cache.
  */
-static int sbpcd_release(struct inode * ip, struct file * file)
+static void sbpcd_release(struct cdrom_device_info * cdi)
 {
 	int i;
 	
-	i = MINOR(ip->i_rdev);
+	i = MINOR(cdi->dev);
 	if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1))
 	{
-		msg(DBG_INF, "release: bad device: %04X\n", ip->i_rdev);
-		return 0;
+		msg(DBG_INF, "release: bad device: %04X\n", cdi->dev);
+		return ;
 	}
 	down(&ioctl_read_sem);
 	switch_drive(i);
 	/*
 	 * try to keep an "open" counter here and unlock the door if 1->0.
 	 */
-	MOD_DEC_USE_COUNT;
 	msg(DBG_LCK,"open_count: %d -> %d\n",
 	    D_S[d].open_count,D_S[d].open_count-1);
 	if (D_S[d].open_count>-2) /* CDROMEJECT may have been done */
@@ -5224,9 +5342,7 @@
 		if (--D_S[d].open_count<=0) 
 		{
 			D_S[d].sbp_first_frame=D_S[d].sbp_last_frame=-1;
-			sync_dev(ip->i_rdev); /* nonsense if read only device? */
-			invalidate_buffers(ip->i_rdev);
-			i=UnLockDoor();
+			invalidate_buffers(cdi->dev);
 			if (D_S[d].audio_state!=audio_playing)
 				if (D_S[d].f_eject) cc_SpinDown();
 			D_S[d].diskstate_flags &= ~cd_size_bit;
@@ -5237,12 +5353,14 @@
 		}
 	}
 	up(&ioctl_read_sem);
-	return 0;
+	MOD_DEC_USE_COUNT;
+	return ;
 }
 /*==========================================================================*/
 /*
  *
  */
+#if 0
 static struct file_operations sbpcd_fops =
 {
 	NULL,                   /* lseek - default */
@@ -5259,6 +5377,39 @@
 	sbpcd_chk_disk_change,  /* media_change */
 	NULL                    /* revalidate */
 };
+#endif
+static int sbpcd_media_changed( struct cdrom_device_info *cdi, int disc_nr);
+static struct cdrom_device_ops sbpcd_dops = {
+  sbpcd_open,                   /* open */
+  sbpcd_release,                /* release */
+  sbpcd_drive_status,           /* drive status */
+  sbpcd_media_changed,          /* media changed */
+  sbpcd_tray_move,              /* tray move */
+  sbpcd_lock_door,              /* lock door */
+  sbpcd_select_speed,           /* select speed */
+  NULL,                         /* select disc */
+  sbpcd_get_last_session,       /* get last session */
+  sbpcd_get_mcn,                /* get universal product code */
+  sbpcd_reset,                  /* hard reset */
+  sbpcd_audio_ioctl,            /* audio ioctl */
+  sbpcd_dev_ioctl,              /* device-specific ioctl */
+  CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_MULTI_SESSION |
+    CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO, /* capability */
+  1,                            /* number of minor devices */
+};
+
+static struct cdrom_device_info sbpcd_info = {
+  &sbpcd_dops,                /* device operations */
+  NULL,                       /* link */
+  NULL,                       /* handle */
+  MKDEV(MAJOR_NR,0),          /* dev */
+  0,                          /* mask */
+  2,                          /* maximum speed */
+  1,                          /* number of discs */
+  0,                          /* options, not owned */
+  0,                          /* mc_flags, not owned */
+  0                           /* use count, not owned */
+};
 /*==========================================================================*/
 /*
  * accept "kernel command line" parameters 
@@ -5495,15 +5646,15 @@
 		if (!famL_drive) cc_DriveReset();
 #endif 0
 		if (!st_spinning) cc_SpinUp();
-		D_S[d].sbp_first_frame = -1;  /* First frame in buffer */
-		D_S[d].sbp_last_frame = -1;   /* Last frame in buffer  */
-		D_S[d].sbp_read_frames = 0;   /* Number of frames being read to buffer */
-		D_S[d].sbp_current = 0;       /* Frame being currently read */
-		D_S[d].CD_changed=1;
-		D_S[d].frame_size=CD_FRAMESIZE;
-		D_S[d].f_eject=0;
+		D_S[j].sbp_first_frame = -1;  /* First frame in buffer */
+		D_S[j].sbp_last_frame = -1;   /* Last frame in buffer  */
+		D_S[j].sbp_read_frames = 0;   /* Number of frames being read to buffer */
+		D_S[j].sbp_current = 0;       /* Frame being currently read */
+		D_S[j].CD_changed=1;
+		D_S[j].frame_size=CD_FRAMESIZE;
+		D_S[j].f_eject=0;
 #if EJECT
-		if (!fam0_drive) D_S[d].f_eject=1;
+		if (!fam0_drive) D_S[j].f_eject=1;
 #endif EJECT
 		cc_ReadStatus();
 		i=ResponseStatus();  /* returns orig. status or p_busy_new */
@@ -5521,8 +5672,8 @@
 		}
 		msg(DBG_INI,"init: first GetStatus: %d\n",i);
 		msg(DBG_LCS,"init: first GetStatus: error_byte=%d\n",
-		    D_S[d].error_byte);
-		if (D_S[d].error_byte==aud_12)
+		    D_S[j].error_byte);
+		if (D_S[j].error_byte==aud_12)
 		{
 			timeout=jiffies+2*HZ;
 			do
@@ -5531,14 +5682,14 @@
 				msg(DBG_INI,"init: second GetStatus: %02X\n",i);
 				msg(DBG_LCS,
 				    "init: second GetStatus: error_byte=%d\n",
-				    D_S[d].error_byte);
+				    D_S[j].error_byte);
 				if (i<0) break;
 				if (!st_caddy_in) break;
 				}
 			while ((!st_diskok)||(timeout<jiffies));
 		}
 		i=SetSpeed();
-		if (i>=0) D_S[d].CD_changed=1;
+		if (i>=0) D_S[j].CD_changed=1;
 	}
 	
 	/*
@@ -5550,7 +5701,7 @@
 	OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */
 #endif SOUND_BASE
 	
-	if (register_blkdev(MAJOR_NR, major_name, &sbpcd_fops) != 0)
+	if (register_blkdev(MAJOR_NR, major_name, &cdrom_fops) != 0)
 	{
 		msg(DBG_INF, "Can't get MAJOR %d for Matsushita CDROM\n", MAJOR_NR);
 #ifdef MODULE
@@ -5566,6 +5717,8 @@
 	
 	for (j=0;j<NR_SBPCD;j++)
 	{
+		struct cdrom_device_info * sbpcd_infop;
+
 		if (D_S[j].drv_id==-1) continue;
 		switch_drive(j);
 #if SAFE_MIXED
@@ -5583,6 +5736,11 @@
 		if (D_S[j].sbp_buf==NULL)
 		{
 			msg(DBG_INF,"data buffer (%d frames) not available.\n",D_S[j].sbp_bufsiz);
+			if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL))
+			{
+				printk("Can't unregister %s\n", major_name);
+			}
+			release_region(CDo_command,4);
 			return -EIO;
 		}
 #ifdef MODULE
@@ -5594,13 +5752,29 @@
 			if (D_S[j].aud_buf==NULL) msg(DBG_INF,"audio buffer (%d frames) not available.\n",D_S[j].sbp_audsiz);
 			else msg(DBG_INF,"audio buffer size: %d frames.\n",D_S[j].sbp_audsiz);
 		}
+                sbpcd_infop = vmalloc(sizeof (struct cdrom_device_info));
+		if (sbpcd_infop == NULL)
+		{
+                        release_region(CDo_command,4);
+                        return -ENOMEM;
+		}
+		D_S[j].sbpcd_infop = sbpcd_infop;
+		memcpy (sbpcd_infop, &sbpcd_info, sizeof(struct cdrom_device_info));
+		sbpcd_infop->dev = MKDEV(MAJOR_NR, j);
+		strncpy(sbpcd_infop->name,major_name, sizeof(sbpcd_infop->name)); 
+
+		if (register_cdrom(sbpcd_infop))
+		{
+                	printk(" sbpcd: Unable to register with Uniform CD-ROm driver\n");
+		}
+
 		/*
 		 * set the block size
 		 */
 		sbpcd_blocksizes[j]=CD_FRAMESIZE;
 	}
 	blksize_size[MAJOR_NR]=sbpcd_blocksizes;
-	
+
 #ifndef MODULE
  init_done:
 #if !(SBPCD_ISSUE-1)
@@ -5635,6 +5809,12 @@
 		if (D_S[j].drv_id==-1) continue;
 		vfree(D_S[j].sbp_buf);
 		if (D_S[j].sbp_audsiz>0) vfree(D_S[j].aud_buf);
+		if ((unregister_cdrom(D_S[j].sbpcd_infop) == -EINVAL))
+		{
+			msg(DBG_INF, "What's that: can't unregister info %s.\n", major_name);
+			return;
+		}
+		vfree(D_S[j].sbpcd_infop);
 	}
 	msg(DBG_INF, "%s module released.\n", major_name);
 }
@@ -5664,6 +5844,11 @@
         }
         else
                 return (0);
+}
+
+static int sbpcd_media_changed( struct cdrom_device_info *cdi, int disc_nr)
+{
+   return sbpcd_chk_disk_change(cdi->dev);
 }
 /*==========================================================================*/
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov