Enscript Output

extractedLnx/linux/drivers/cdrom/sbpcd.c_sbpcd_ioctl.c

static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
		       u_long arg)
{
	int i, st;
	
	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);
	if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1))
	{
		msg(DBG_INF, "ioctl: bad device: %04X\n", inode->i_rdev);
		return (-ENXIO);             /* no such drive */
	}
	if (d!=i) switch_drive(i);
	
#if 0
	st=GetStatus();
	if (st<0) return (-EIO);
	
	if (!toc_valid)
	{
		i=DiskInfo();
		if (i<0) return (-EIO);	/* error reading TOC */
	}
#endif
	
	msg(DBG_IO2,"ioctl: device %d, request %04X\n",i,cmd);
	switch (cmd) 		/* Sun-compatible */
	{
	case DDIOCSDBG:		/* DDI Debug */
		if (!suser()) return (-EPERM);
		i=sbpcd_dbg_ioctl(arg,1);
		return (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 (-EIO);
			if (famL_drive) i=cc_Pause_Resume(1);
			else i=cc_ReadSubQ();
			if (i<0) return (-EIO);
			D_S[d].pos_audio_start=D_S[d].SubQ_run_tot;
			D_S[d].audio_state=audio_pausing;
			return (0);
		case audio_pausing:
			i=cc_Seek(D_S[d].pos_audio_start,1);
			if (i<0) return (-EIO);
			return (0);
		default:
			return (-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 (-EIO);
		D_S[d].audio_state=audio_playing;
		return (0);
		
	case CDROMPLAYMSF:
		msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n");
#if SAFE_MIXED
		if (D_S[d].has_data>1) return (-EBUSY);
#endif SAFE_MIXED
		if (D_S[d].audio_state==audio_playing)
		{
			i=cc_Pause_Resume(1);
			if (i<0) return (-EIO);
			i=cc_ReadSubQ();
			if (i<0) return (-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 (st);
		memcpy_fromfs(&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 (-EIO);
		}
		D_S[d].audio_state=audio_playing;
		return (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 (-EBUSY);
#endif SAFE_MIXED
		if (D_S[d].audio_state==audio_playing)
		{
			msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n");
			return (0);
			return (-EINVAL);
		}
		st=verify_area(VERIFY_READ,(void *) arg,sizeof(struct cdrom_ti));
		if (st<0)
		{
			msg(DBG_IOX,"CDROMPLAYTRKIND: verify_area error.\n");
			return (st);
		}
		memcpy_fromfs(&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 (-EINVAL);
		if (ti.cdti_trk0>D_S[d].n_last_track) return (-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 (-EIO);
		}
		D_S[d].audio_state=audio_playing;
		return (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 (st);
		memcpy_tofs((void *) arg, &tochdr, sizeof(struct cdrom_tochdr));
		return (0);
		
	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 (st);
		memcpy_fromfs(&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 (-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 (-EINVAL);
		memcpy_tofs((void *) arg, &tocentry, sizeof(struct cdrom_tocentry));
		return (0);
		
	case CDROMRESET:      /* hard reset the drive */
		msg(DBG_IOC,"ioctl: CDROMRESET entered.\n");
		i=DriveReset();
		D_S[d].audio_state=0;
		return (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 (-EBUSY);
#endif SAFE_MIXED
		i=cc_Pause_Resume(1);
		D_S[d].audio_state=0;
		return (i);
		
	case CDROMSTART:  /* Spin up the drive */
		msg(DBG_IOC,"ioctl: CDROMSTART entered.\n");
		cc_SpinUp();
		D_S[d].audio_state=0;
		return (0);
		
	case CDROMEJECT:
		msg(DBG_IOC,"ioctl: CDROMEJECT entered.\n");
		if (fam0_drive) return (0);
		if (D_S[d].open_count>1) return (-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 (-EIO);
		D_S[d].CD_changed=0xFF;
		D_S[d].diskstate_flags=0;
		D_S[d].audio_state=0;
		return (0);
		
	case CDROMEJECT_SW:
		msg(DBG_IOC,"ioctl: CDROMEJECT_SW entered.\n");
		if (fam0_drive) return (0);
		D_S[d].f_eject=arg;
		return (0);
		
	case CDROMVOLCTRL:   /* Volume control */
		msg(DBG_IOC,"ioctl: CDROMVOLCTRL entered.\n");
		st=verify_area(VERIFY_READ,(void *) arg,sizeof(volctrl));
		if (st) return (st);
		memcpy_fromfs(&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 (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 (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;
		memcpy_tofs((void *)arg,&volctrl,sizeof(volctrl));
		return (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 (-EIO);
					    }
		st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
		if (st)	return (st);
		memcpy_fromfs(&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_tofs((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 (0);
		
	case CDROMREADMODE1:
		msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n");
#if SAFE_MIXED
		if (D_S[d].has_data>1) return (-EBUSY);
#endif SAFE_MIXED
		cc_ModeSelect(CD_FRAMESIZE);
		cc_ModeSense();
		D_S[d].mode=READ_M1;
		return (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 (-EBUSY);
#endif SAFE_MIXED
		cc_ModeSelect(CD_FRAMESIZE_RAW1);
		cc_ModeSense();
		D_S[d].mode=READ_M2;
		return (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);
		}
		return (D_S[d].sbp_audsiz);

	case CDROMREADAUDIO:
	{ /* start of CDROMREADAUDIO */
		int i=0, j=0, frame, block;
		u_int try=0;
		u_long timeout;
		u_char *p;
		u_int data_tries = 0;
		u_int data_waits = 0;
		u_int data_retrying = 0;
		int status_tries;
		int error_flag;
		
		msg(DBG_IOC,"ioctl: CDROMREADAUDIO entered.\n");
		if (fam0_drive) return (-EINVAL);
		if (famL_drive) return (-EINVAL);
		if (famV_drive) return (-EINVAL);
		if (famT_drive) return (-EINVAL);
#if SAFE_MIXED
		if (D_S[d].has_data>1) return (-EBUSY);
#endif SAFE_MIXED
		if (D_S[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));
		if (read_audio.nframes>D_S[d].sbp_audsiz) 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=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 000
		i=cc_SetSpeed(speed_150,0,0);
		if (i) msg(DBG_AUD,"read_audio: SetSpeed error %d\n", i);
#endif
		msg(DBG_AUD,"read_audio: lba: %d, msf: %06X\n",
		    block, blk2msf(block));
		msg(DBG_AUD,"read_audio: before cc_ReadStatus.\n");
		while (busy_data) sbp_sleep(HZ/10); /* wait a bit */
		busy_audio=1;
		error_flag=0;
		for (data_tries=5; data_tries>0; data_tries--)
		{
			msg(DBG_AUD,"data_tries=%d ...\n", data_tries);
			D_S[d].mode=READ_AU;
			cc_ModeSelect(CD_FRAMESIZE_RAW);
			cc_ModeSense();
			for (status_tries=3; status_tries > 0; status_tries--)
			{
				flags_cmd_out |= f_respo3;
				cc_ReadStatus();
				if (sbp_status() != 0) break;
				if (st_check) cc_ReadError();
				sbp_sleep(1);    /* wait a bit, try again */
			}
			if (status_tries == 0)
			{
				msg(DBG_AUD,"read_audio: sbp_status: failed after 3 tries.\n");
				continue;
			}
			msg(DBG_AUD,"read_audio: sbp_status: ok.\n");
			
			flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check;
			if (fam0L_drive)
			{
				flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
				cmd_type=READ_M2;
				drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */
				drvcmd[1]=(block>>16)&0x000000ff;
				drvcmd[2]=(block>>8)&0x000000ff;
				drvcmd[3]=block&0x000000ff;
				drvcmd[4]=0;
				drvcmd[5]=read_audio.nframes; /* # of frames */
				drvcmd[6]=0;
			}
			else if (fam1_drive)
			{
				drvcmd[0]=CMD1_READ; /* "read frames", new drives */
				lba2msf(block,&drvcmd[1]); /* msf-bin format required */
				drvcmd[4]=0;
				drvcmd[5]=0;
				drvcmd[6]=read_audio.nframes; /* # of frames */
			}
			else if (fam2_drive)
			{
				drvcmd[0]=CMD2_READ_XA2;
				lba2msf(block,&drvcmd[1]); /* msf-bin format required */
				drvcmd[4]=0;
				drvcmd[5]=read_audio.nframes; /* # of frames */
				drvcmd[6]=0x11; /* raw mode */
			}
			else if (famT_drive) /* CD-55A: not tested yet */
			{
			}
			msg(DBG_AUD,"read_audio: before giving \"read\" command.\n");
			flags_cmd_out=f_putcmd;
			response_count=0;
			i=cmd_out();
			if (i<0) msg(DBG_INF,"error giving READ AUDIO command: %0d\n", i);
			sbp_sleep(0);
			msg(DBG_AUD,"read_audio: after giving \"read\" command.\n");
			for (frame=1;frame<2 && !error_flag; frame++)
			{
				try=maxtim_data;
				for (timeout=jiffies+9*HZ; ; )
				{
					for ( ; try!=0;try--)
					{
						j=inb(CDi_status);
						if (!(j&s_not_data_ready)) break;
						if (!(j&s_not_result_ready)) break;
						if (fam0L_drive) if (j&s_attention) break;
					}
					if (try != 0 || timeout <= jiffies) break;
					if (data_retrying == 0) data_waits++;
					data_retrying = 1;
					sbp_sleep(1);
					try = 1;
				}
				if (try==0)
				{
					msg(DBG_INF,"read_audio: sbp_data: CDi_status timeout.\n");
					error_flag++;
					break;
				}
				msg(DBG_AUD,"read_audio: sbp_data: CDi_status ok.\n");
				if (j&s_not_data_ready)
				{
					msg(DBG_INF, "read_audio: sbp_data: DATA_READY timeout.\n");
					error_flag++;
					break;
				}
				msg(DBG_AUD,"read_audio: before reading data.\n");
				error_flag=0;
				p = D_S[d].aud_buf;
				if (sbpro_type==1) OUT(CDo_sel_i_d,1);
				if (do_16bit) insw(CDi_data, p, read_audio.nframes*(CD_FRAMESIZE_RAW>>1));
				else insb(CDi_data, p, read_audio.nframes*CD_FRAMESIZE_RAW);
				if (sbpro_type==1) OUT(CDo_sel_i_d,0);
				data_retrying = 0;
			}
			msg(DBG_AUD,"read_audio: after reading data.\n");
			if (error_flag)    /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
			{
				msg(DBG_AUD,"read_audio: read aborted by drive\n");
#if 0000
				i=cc_DriveReset();                /* ugly fix to prevent a hang */
#else
				i=cc_ReadError();
#endif 0000
				continue;
			}
			if (fam0L_drive)
			{
				i=maxtim_data;
				for (timeout=jiffies+9*HZ; timeout > jiffies; timeout--)
				{
					for ( ;i!=0;i--)
					{
						j=inb(CDi_status);
						if (!(j&s_not_data_ready)) break;
						if (!(j&s_not_result_ready)) break;
						if (j&s_attention) break;
					}
					if (i != 0 || timeout <= jiffies) break;
					sbp_sleep(0);
					i = 1;
				}
				if (i==0) msg(DBG_AUD,"read_audio: STATUS TIMEOUT AFTER READ");
				if (!(j&s_attention))
				{
					msg(DBG_AUD,"read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n");
					i=cc_DriveReset();  /* ugly fix to prevent a hang */
					continue;
				}
			}
			do
			{
				if (fam0L_drive) cc_ReadStatus();
				i=ResponseStatus();  /* builds status_bits, returns orig. status (old) or faked p_success (new) */
				if (i<0) { msg(DBG_AUD,
					       "read_audio: cc_ReadStatus error after read: %02X\n",
					       D_S[d].status_bits);
					   continue; /* FIXME */
				   }
			}
			while ((fam0L_drive)&&(!st_check)&&(!(i&p_success)));
			if (st_check)
			{
				i=cc_ReadError();
				msg(DBG_AUD,"read_audio: cc_ReadError was necessary after read: %02X\n",i);
				continue;
			}
			memcpy_tofs((u_char *) read_audio.buf,
				    (u_char *) D_S[d].aud_buf,
				    read_audio.nframes*CD_FRAMESIZE_RAW);
			msg(DBG_AUD,"read_audio: memcpy_tofs done.\n");
			break;
		}
		cc_ModeSelect(CD_FRAMESIZE);
		cc_ModeSense();
		D_S[d].mode=READ_M1;
		busy_audio=0;
		if (data_tries == 0)
		{
			msg(DBG_AUD,"read_audio: failed after 5 tries.\n");
			return (-8);
		}
		msg(DBG_AUD,"read_audio: successful return.\n");
		return (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 (st);
		memcpy_fromfs(&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 (-EINVAL);
		if (D_S[d].f_multisession) ms_info.xa_flag=1; /* valid redirection address */
		else ms_info.xa_flag=0; /* invalid redirection address */
		memcpy_tofs((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 (0);
		
	case BLKRASET:
		if(!suser())  return -EACCES;
		if(!(inode->i_rdev)) return -EINVAL;
		if(arg > 0xff) return -EINVAL;
		read_ahead[MAJOR(inode->i_rdev)] = arg;
		return (0);
		
	default:
		msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd);
		return (-EINVAL);
	} /* end switch(cmd) */
}

Generated by GNU enscript 1.6.4.