Commit 6a2900b6 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Linus Torvalds

[PATCH] kill cdrom ->dev_ioctl method

Since early 2.4.x all cdrom drivers implement the block_device methods
themselves, so they can handle additional ioctls directly instead of going
through the cdrom layer.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Acked-by: default avatarJens Axboe <axboe@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d2c5d4fc
......@@ -407,7 +407,6 @@ int register_cdrom(struct cdrom_device_info *cdi)
ENSURE(get_mcn, CDC_MCN);
ENSURE(reset, CDC_RESET);
ENSURE(audio_ioctl, CDC_PLAY_AUDIO);
ENSURE(dev_ioctl, CDC_IOCTLS);
ENSURE(generic_packet, CDC_GENERIC_PACKET);
cdi->mc_flags = 0;
cdo->n_minors = 0;
......@@ -2776,12 +2775,6 @@ int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
return cdrom_ioctl_audioctl(cdi, cmd);
}
/*
* Finally, do the device specific ioctls
*/
if (CDROM_CAN(CDC_IOCTLS))
return cdi->ops->dev_ioctl(cdi, cmd, arg);
return -ENOSYS;
}
......
......@@ -2668,7 +2668,7 @@ static int scd_audio_ioctl(struct cdrom_device_info *cdi,
return retval;
}
static int scd_dev_ioctl(struct cdrom_device_info *cdi,
static int scd_read_audio(struct cdrom_device_info *cdi,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
......@@ -2894,11 +2894,10 @@ static struct cdrom_device_ops scd_dops = {
.get_mcn = scd_get_mcn,
.reset = scd_reset,
.audio_ioctl = scd_audio_ioctl,
.dev_ioctl = scd_dev_ioctl,
.capability = CDC_OPEN_TRAY | CDC_CLOSE_TRAY | CDC_LOCK |
CDC_SELECT_SPEED | CDC_MULTI_SESSION |
CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO |
CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS,
CDC_RESET | CDC_DRIVE_STATUS,
.n_minors = 1,
};
......@@ -2936,6 +2935,9 @@ static int scd_block_ioctl(struct inode *inode, struct file *file,
case CDROMCLOSETRAY:
retval = scd_tray_move(&scd_info, 0);
break;
case CDROMREADAUDIO:
retval = scd_read_audio(&scd_info, CDROMREADAUDIO, arg);
break;
default:
retval = cdrom_ioctl(file, &scd_info, inode, cmd, arg);
}
......
......@@ -1157,32 +1157,6 @@ static int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
}
}
/* Ioctl. These ioctls are specific to the cm206 driver. I have made
some driver statistics accessible through ioctl calls.
*/
static int cm206_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
#ifdef STATISTICS
case CM206CTL_GET_STAT:
if (arg >= NR_STATS)
return -EINVAL;
else
return cd->stats[arg];
case CM206CTL_GET_LAST_STAT:
if (arg >= NR_STATS)
return -EINVAL;
else
return cd->last_stat[arg];
#endif
default:
debug(("Unknown ioctl call 0x%x\n", cmd));
return -EINVAL;
}
}
static int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr)
{
if (cd != NULL) {
......@@ -1321,11 +1295,10 @@ static struct cdrom_device_ops cm206_dops = {
.get_mcn = cm206_get_upc,
.reset = cm206_reset,
.audio_ioctl = cm206_audio_ioctl,
.dev_ioctl = cm206_ioctl,
.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |
CDC_MCN | CDC_PLAY_AUDIO | CDC_SELECT_SPEED |
CDC_IOCTLS | CDC_DRIVE_STATUS,
CDC_DRIVE_STATUS,
.n_minors = 1,
};
......@@ -1350,6 +1323,21 @@ static int cm206_block_release(struct inode *inode, struct file *file)
static int cm206_block_ioctl(struct inode *inode, struct file *file,
unsigned cmd, unsigned long arg)
{
switch (cmd) {
#ifdef STATISTICS
case CM206CTL_GET_STAT:
if (arg >= NR_STATS)
return -EINVAL;
return cd->stats[arg];
case CM206CTL_GET_LAST_STAT:
if (arg >= NR_STATS)
return -EINVAL;
return cd->last_stat[arg];
#endif
default:
break;
}
return cdrom_ioctl(file, &cm206_info, inode, cmd, arg);
}
......
......@@ -4160,18 +4160,13 @@ static int sbpcd_get_last_session(struct cdrom_device_info *cdi, struct cdrom_mu
return 0;
}
/*==========================================================================*/
/*==========================================================================*/
/*
* ioctl support
*/
static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd,
u_long arg)
static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd,
void * arg)
{
struct sbpcd_drive *p = cdi->handle;
int i;
int i, st, j;
msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08lX)\n", cdi->name, cmd, arg);
msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08p)\n", cdi->name, cmd, arg);
if (p->drv_id==-1) {
msg(DBG_INF, "ioctl: bad device: %s\n", cdi->name);
return (-ENXIO); /* no such drive */
......@@ -4183,484 +4178,163 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd,
msg(DBG_IO2,"ioctl: device %s, request %04X\n",cdi->name,cmd);
switch (cmd) /* Sun-compatible */
{
case DDIOCSDBG: /* DDI Debug */
if (!capable(CAP_SYS_ADMIN)) 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();
current_drive->audio_state=0;
RETURN_UP(i);
case CDROMREADMODE1:
msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n");
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 (current_drive->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);
current_drive->pos_audio_start=current_drive->SubQ_run_tot;
current_drive->audio_state=audio_pausing;
RETURN_UP(0);
case audio_pausing:
i=cc_Seek(current_drive->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 (current_drive->audio_state!=audio_pausing) RETURN_UP(-EINVAL);
if (famL_drive)
i=cc_PlayAudio(current_drive->pos_audio_start,
current_drive->pos_audio_end);
else i=cc_Pause_Resume(3);
if (i<0) RETURN_UP(-EIO);
current_drive->audio_state=audio_playing;
RETURN_UP(0);
case CDROMPLAYMSF:
msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n");
#ifdef SAFE_MIXED
if (current_drive->has_data>1) RETURN_UP(-EBUSY);
#endif /* SAFE_MIXED */
cc_ModeSelect(CD_FRAMESIZE);
cc_ModeSense();
current_drive->mode=READ_M1;
if (current_drive->audio_state==audio_playing)
{
i=cc_Pause_Resume(1);
if (i<0) RETURN_UP(-EIO);
i=cc_ReadSubQ();
if (i<0) RETURN_UP(-EIO);
current_drive->pos_audio_start=current_drive->SubQ_run_tot;
i=cc_Seek(current_drive->pos_audio_start,1);
}
memcpy(&msf, (void *) arg, sizeof(struct cdrom_msf));
/* values come as msf-bin */
current_drive->pos_audio_start = (msf.cdmsf_min0<<16) |
(msf.cdmsf_sec0<<8) |
msf.cdmsf_frame0;
current_drive->pos_audio_end = (msf.cdmsf_min1<<16) |
(msf.cdmsf_sec1<<8) |
msf.cdmsf_frame1;
msg(DBG_IOX,"ioctl: CDROMPLAYMSF %08X %08X\n",
current_drive->pos_audio_start,current_drive->pos_audio_end);
i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end);
if (i<0)
{
msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
DriveReset();
current_drive->audio_state=0;
RETURN_UP(-EIO);
}
current_drive->audio_state=audio_playing;
RETURN_UP(0);
case CDROMREADMODE2: /* not usable at the moment */
msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n");
case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n");
#ifdef SAFE_MIXED
if (current_drive->has_data>1) RETURN_UP(-EBUSY);
#endif /* SAFE_MIXED */
cc_ModeSelect(CD_FRAMESIZE_RAW1);
cc_ModeSense();
current_drive->mode=READ_M2;
if (current_drive->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<current_drive->n_first_track) RETURN_UP(-EINVAL);
if (ti.cdti_trk0>current_drive->n_last_track) RETURN_UP(-EINVAL);
if (ti.cdti_trk1<ti.cdti_trk0) ti.cdti_trk1=ti.cdti_trk0;
if (ti.cdti_trk1>current_drive->n_last_track) ti.cdti_trk1=current_drive->n_last_track;
current_drive->pos_audio_start=current_drive->TocBuffer[ti.cdti_trk0].address;
current_drive->pos_audio_end=current_drive->TocBuffer[ti.cdti_trk1+1].address;
i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end);
if (i<0)
{
msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
DriveReset();
current_drive->audio_state=0;
RETURN_UP(-EIO);
}
current_drive->audio_state=audio_playing;
RETURN_UP(0);
case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */
msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n");
if (current_drive->sbp_audsiz>0)
vfree(current_drive->aud_buf);
current_drive->aud_buf=NULL;
current_drive->sbp_audsiz=arg;
case CDROMREADTOCHDR: /* Read the table of contents header */
msg(DBG_IOC,"ioctl: CDROMREADTOCHDR entered.\n");
tochdr.cdth_trk0=current_drive->n_first_track;
tochdr.cdth_trk1=current_drive->n_last_track;
memcpy((void *) arg, &tochdr, sizeof(struct cdrom_tochdr));
RETURN_UP(0);
if (current_drive->sbp_audsiz>16)
{
current_drive->sbp_audsiz = 0;
RETURN_UP(current_drive->sbp_audsiz);
}
if (current_drive->sbp_audsiz>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=current_drive->n_last_track+1;
else if (i<current_drive->n_first_track||i>current_drive->n_last_track)
RETURN_UP(-EINVAL);
tocentry.cdte_adr=current_drive->TocBuffer[i].ctl_adr&0x0F;
tocentry.cdte_ctrl=(current_drive->TocBuffer[i].ctl_adr>>4)&0x0F;
tocentry.cdte_datamode=current_drive->TocBuffer[i].format;
if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */
{
current_drive->aud_buf=(u_char *) vmalloc(current_drive->sbp_audsiz*CD_FRAMESIZE_RAW);
if (current_drive->aud_buf==NULL)
{
msg(DBG_INF,"audio buffer (%d frames) not available.\n",current_drive->sbp_audsiz);
current_drive->sbp_audsiz=0;
}
else msg(DBG_INF,"audio buffer size: %d frames.\n",current_drive->sbp_audsiz);
tocentry.cdte_addr.msf.minute=(current_drive->TocBuffer[i].address>>16)&0x00FF;
tocentry.cdte_addr.msf.second=(current_drive->TocBuffer[i].address>>8)&0x00FF;
tocentry.cdte_addr.msf.frame=current_drive->TocBuffer[i].address&0x00FF;
}
RETURN_UP(current_drive->sbp_audsiz);
case CDROMREADAUDIO:
{ /* start of CDROMREADAUDIO */
int i=0, j=0, frame, block=0;
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;
else if (tocentry.cdte_format==CDROM_LBA) /* blk required */
tocentry.cdte_addr.lba=msf2blk(current_drive->TocBuffer[i].address);
else RETURN_UP(-EINVAL);
memcpy((void *) arg, &tocentry, sizeof(struct cdrom_tocentry));
RETURN_UP(0);
msg(DBG_IOC,"ioctl: CDROMREADAUDIO entered.\n");
if (fam0_drive) RETURN_UP(-EINVAL);
if (famL_drive) RETURN_UP(-EINVAL);
if (famV_drive) RETURN_UP(-EINVAL);
if (famT_drive) RETURN_UP(-EINVAL);
case CDROMSTOP: /* Spin down the drive */
msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n");
#ifdef SAFE_MIXED
if (current_drive->has_data>1) RETURN_UP(-EBUSY);
#endif /* SAFE_MIXED */
if (current_drive->aud_buf==NULL) RETURN_UP(-EINVAL);
if (copy_from_user(&read_audio, (void __user *)arg,
sizeof(struct cdrom_read_audio)))
RETURN_UP(-EFAULT);
if (read_audio.nframes < 0 || read_audio.nframes>current_drive->sbp_audsiz) RETURN_UP(-EINVAL);
if (!access_ok(VERIFY_WRITE, read_audio.buf,
read_audio.nframes*CD_FRAMESIZE_RAW))
RETURN_UP(-EFAULT);
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_UP(-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");
#if OLD_BUSY
while (busy_data) sbp_sleep(HZ/10); /* wait a bit */
busy_audio=1;
#endif /* OLD_BUSY */
error_flag=0;
for (data_tries=5; data_tries>0; data_tries--)
{
msg(DBG_AUD,"data_tries=%d ...\n", data_tries);
current_drive->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 in line %d.\n", __LINE__);
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 || time_after_eq(jiffies, timeout)) 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 = current_drive->aud_buf;
if (sbpro_type==1) OUT(CDo_sel_i_d,1);
if (do_16bit)
{
u_short *p2 = (u_short *) p;
for (; (u_char *) p2 < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;)
{
if ((inb_p(CDi_status)&s_not_data_ready)) continue;
/* get one sample */
*p2++ = inw_p(CDi_data);
*p2++ = inw_p(CDi_data);
}
} else {
for (; p < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;)
{
if ((inb_p(CDi_status)&s_not_data_ready)) continue;
/* get one sample */
*p++ = inb_p(CDi_data);
*p++ = inb_p(CDi_data);
*p++ = inb_p(CDi_data);
*p++ = inb_p(CDi_data);
}
}
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
continue;
}
if (fam0L_drive)
{
i=maxtim_data;
for (timeout=jiffies+9*HZ; time_before(jiffies, timeout); 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 || time_after_eq(jiffies, timeout)) 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",
current_drive->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;
}
if (copy_to_user(read_audio.buf,
current_drive->aud_buf,
read_audio.nframes * CD_FRAMESIZE_RAW))
RETURN_UP(-EFAULT);
msg(DBG_AUD,"read_audio: copy_to_user done.\n");
break;
}
cc_ModeSelect(CD_FRAMESIZE);
cc_ModeSense();
current_drive->mode=READ_M1;
#if OLD_BUSY
busy_audio=0;
#endif /* OLD_BUSY */
if (data_tries == 0)
{
msg(DBG_AUD,"read_audio: failed after 5 tries in line %d.\n", __LINE__);
RETURN_UP(-EIO);
}
msg(DBG_AUD,"read_audio: successful return.\n");
RETURN_UP(0);
} /* end of CDROMREADAUDIO */
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)
{
struct sbpcd_drive *p = cdi->handle;
int i, st, j;
msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08p)\n", cdi->name, cmd, arg);
if (p->drv_id==-1) {
msg(DBG_INF, "ioctl: bad device: %s\n", cdi->name);
return (-ENXIO); /* no such drive */
}
down(&ioctl_read_sem);
if (p != current_drive)
switch_drive(p);
msg(DBG_IO2,"ioctl: device %s, request %04X\n",cdi->name,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 (current_drive->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);
current_drive->pos_audio_start=current_drive->SubQ_run_tot;
current_drive->audio_state=audio_pausing;
RETURN_UP(0);
case audio_pausing:
i=cc_Seek(current_drive->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 (current_drive->audio_state!=audio_pausing) RETURN_UP(-EINVAL);
if (famL_drive)
i=cc_PlayAudio(current_drive->pos_audio_start,
current_drive->pos_audio_end);
else i=cc_Pause_Resume(3);
if (i<0) RETURN_UP(-EIO);
current_drive->audio_state=audio_playing;
RETURN_UP(0);
case CDROMPLAYMSF:
msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n");
#ifdef SAFE_MIXED
if (current_drive->has_data>1) RETURN_UP(-EBUSY);
#endif /* SAFE_MIXED */
if (current_drive->audio_state==audio_playing)
{
i=cc_Pause_Resume(1);
if (i<0) RETURN_UP(-EIO);
i=cc_ReadSubQ();
if (i<0) RETURN_UP(-EIO);
current_drive->pos_audio_start=current_drive->SubQ_run_tot;
i=cc_Seek(current_drive->pos_audio_start,1);
}
memcpy(&msf, (void *) arg, sizeof(struct cdrom_msf));
/* values come as msf-bin */
current_drive->pos_audio_start = (msf.cdmsf_min0<<16) |
(msf.cdmsf_sec0<<8) |
msf.cdmsf_frame0;
current_drive->pos_audio_end = (msf.cdmsf_min1<<16) |
(msf.cdmsf_sec1<<8) |
msf.cdmsf_frame1;
msg(DBG_IOX,"ioctl: CDROMPLAYMSF %08X %08X\n",
current_drive->pos_audio_start,current_drive->pos_audio_end);
i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end);
if (i<0)
{
msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
DriveReset();
current_drive->audio_state=0;
RETURN_UP(-EIO);
}
current_drive->audio_state=audio_playing;
RETURN_UP(0);
case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n");
#ifdef SAFE_MIXED
if (current_drive->has_data>1) RETURN_UP(-EBUSY);
#endif /* SAFE_MIXED */
if (current_drive->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<current_drive->n_first_track) RETURN_UP(-EINVAL);
if (ti.cdti_trk0>current_drive->n_last_track) RETURN_UP(-EINVAL);
if (ti.cdti_trk1<ti.cdti_trk0) ti.cdti_trk1=ti.cdti_trk0;
if (ti.cdti_trk1>current_drive->n_last_track) ti.cdti_trk1=current_drive->n_last_track;
current_drive->pos_audio_start=current_drive->TocBuffer[ti.cdti_trk0].address;
current_drive->pos_audio_end=current_drive->TocBuffer[ti.cdti_trk1+1].address;
i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end);
if (i<0)
{
msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i);
DriveReset();
current_drive->audio_state=0;
RETURN_UP(-EIO);
}
current_drive->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=current_drive->n_first_track;
tochdr.cdth_trk1=current_drive->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=current_drive->n_last_track+1;
else if (i<current_drive->n_first_track||i>current_drive->n_last_track)
RETURN_UP(-EINVAL);
tocentry.cdte_adr=current_drive->TocBuffer[i].ctl_adr&0x0F;
tocentry.cdte_ctrl=(current_drive->TocBuffer[i].ctl_adr>>4)&0x0F;
tocentry.cdte_datamode=current_drive->TocBuffer[i].format;
if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */
{
tocentry.cdte_addr.msf.minute=(current_drive->TocBuffer[i].address>>16)&0x00FF;
tocentry.cdte_addr.msf.second=(current_drive->TocBuffer[i].address>>8)&0x00FF;
tocentry.cdte_addr.msf.frame=current_drive->TocBuffer[i].address&0x00FF;
}
else if (tocentry.cdte_format==CDROM_LBA) /* blk required */
tocentry.cdte_addr.lba=msf2blk(current_drive->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");
#ifdef SAFE_MIXED
if (current_drive->has_data>1) RETURN_UP(-EBUSY);
#endif /* SAFE_MIXED */
i=cc_Pause_Resume(1);
current_drive->audio_state=0;
#if 0
cc_DriveReset();
i=cc_Pause_Resume(1);
current_drive->audio_state=0;
#if 0
cc_DriveReset();
#endif
RETURN_UP(i);
case CDROMSTART: /* Spin up the drive */
msg(DBG_IOC,"ioctl: CDROMSTART entered.\n");
cc_SpinUp();
current_drive->audio_state=0;
RETURN_UP(0);
case CDROMVOLCTRL: /* Volume control */
msg(DBG_IOC,"ioctl: CDROMVOLCTRL entered.\n");
memcpy(&volctrl,(char *) arg,sizeof(volctrl));
......@@ -4670,7 +4344,7 @@ static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd,
current_drive->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();
......@@ -4694,7 +4368,7 @@ static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd,
if (i<0) {
j=cc_ReadError(); /* clear out error status from drive */
current_drive->audio_state=CDROM_AUDIO_NO_STATUS;
/* get and set the disk state here,
/* get and set the disk state here,
probably not the right place, but who cares!
It makes it work properly! --AJK */
if (current_drive->CD_changed==0xFF) {
......@@ -4715,8 +4389,8 @@ static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd,
}
}
memcpy(&SC, (void *) arg, sizeof(struct cdrom_subchnl));
/*
This virtual crap is very bogus!
/*
This virtual crap is very bogus!
It doesn't detect when the cd is done playing audio!
Lets do this right with proper hardware register reading!
*/
......@@ -4775,7 +4449,7 @@ static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd,
SC.cdsc_trk,SC.cdsc_ind,
SC.cdsc_absaddr,SC.cdsc_reladdr);
RETURN_UP(0);
default:
msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd);
RETURN_UP(-EINVAL);
......@@ -4788,7 +4462,7 @@ static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd,
static void sbp_transfer(struct request *req)
{
long offs;
while ( (req->nr_sectors > 0) &&
(req->sector/4 >= current_drive->sbp_first_frame) &&
(req->sector/4 <= current_drive->sbp_last_frame) )
......@@ -4807,11 +4481,11 @@ static void sbp_transfer(struct request *req)
*
* This is a kludge so we don't need to modify end_request.
* We put the req we take out after INIT_REQUEST in the requests list,
* so that end_request will discard it.
* so that end_request will discard it.
*
* The bug could be present in other block devices, perhaps we
* should modify INIT_REQUEST and end_request instead, and
* change every block device..
* change every block device..
*
* Could be a race here?? Could e.g. a timer interrupt schedule() us?
* If so, we should copy end_request here, and do it right.. (or
......@@ -4831,546 +4505,865 @@ static void sbp_transfer(struct request *req)
/*==========================================================================*/
/*
* I/O request routine, called from Linux kernel.
* I/O request routine, called from Linux kernel.
*/
static void do_sbpcd_request(request_queue_t * q)
{
u_int block;
u_int nsect;
int status_tries, data_tries;
struct request *req;
struct sbpcd_drive *p;
#ifdef DEBUG_GTL
static int xx_nr=0;
int xnr;
#endif
request_loop:
#ifdef DEBUG_GTL
xnr=++xx_nr;
req = elv_next_request(q);
if (!req)
{
printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n",
xnr, current->pid, jiffies);
printk( "do_sbpcd_request[%do](NULL) end 0 (null), Time:%li\n",
xnr, jiffies);
return;
}
printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n",
xnr, req, req->sector, req->nr_sectors, current->pid, jiffies);
#endif
req = elv_next_request(q); /* take out our request so no other */
if (!req)
return;
if (req -> sector == -1)
end_request(req, 0);
spin_unlock_irq(q->queue_lock);
down(&ioctl_read_sem);
if (rq_data_dir(elv_next_request(q)) != READ)
{
msg(DBG_INF, "bad cmd %d\n", req->cmd[0]);
goto err_done;
}
p = req->rq_disk->private_data;
#if OLD_BUSY
while (busy_audio) sbp_sleep(HZ); /* wait a bit */
busy_data=1;
#endif /* OLD_BUSY */
if (p->audio_state==audio_playing) goto err_done;
if (p != current_drive)
switch_drive(p);
block = req->sector; /* always numbered as 512-byte-pieces */
nsect = req->nr_sectors; /* always counted as 512-byte-pieces */
msg(DBG_BSZ,"read sector %d (%d sectors)\n", block, nsect);
#if 0
msg(DBG_MUL,"read LBA %d\n", block/4);
#endif
sbp_transfer(req);
/* if we satisfied the request from the buffer, we're done. */
if (req->nr_sectors == 0)
{
#ifdef DEBUG_GTL
printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 2, Time:%li\n",
xnr, req, req->sector, req->nr_sectors, jiffies);
#endif
up(&ioctl_read_sem);
spin_lock_irq(q->queue_lock);
end_request(req, 1);
goto request_loop;
}
#ifdef FUTURE
i=prepare(0,0); /* at moment not really a hassle check, but ... */
if (i!=0)
msg(DBG_INF,"\"prepare\" tells error %d -- ignored\n", i);
#endif /* FUTURE */
if (!st_spinning) cc_SpinUp();
for (data_tries=n_retries; data_tries > 0; data_tries--)
{
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_INF,"sbp_status: failed after 3 tries in line %d\n", __LINE__);
break;
}
sbp_read_cmd(req);
sbp_sleep(0);
if (sbp_data(req) != 0)
{
#ifdef SAFE_MIXED
current_drive->has_data=2; /* is really a data disk */
#endif /* SAFE_MIXED */
#ifdef DEBUG_GTL
printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n",
xnr, req, req->sector, req->nr_sectors, jiffies);
#endif
up(&ioctl_read_sem);
spin_lock_irq(q->queue_lock);
end_request(req, 1);
goto request_loop;
}
}
err_done:
#if OLD_BUSY
busy_data=0;
#endif /* OLD_BUSY */
#ifdef DEBUG_GTL
printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n",
xnr, req, req->sector, req->nr_sectors, jiffies);
#endif
up(&ioctl_read_sem);
sbp_sleep(0); /* wait a bit, try again */
spin_lock_irq(q->queue_lock);
end_request(req, 0);
goto request_loop;
}
/*==========================================================================*/
/*
* build and send the READ command.
*/
static void sbp_read_cmd(struct request *req)
{
#undef OLD
int i;
int block;
current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1; /* purge buffer */
current_drive->sbp_current = 0;
block=req->sector/4;
if (block+current_drive->sbp_bufsiz <= current_drive->CDsize_frm)
current_drive->sbp_read_frames = current_drive->sbp_bufsiz;
else
{
current_drive->sbp_read_frames=current_drive->CDsize_frm-block;
/* avoid reading past end of data */
if (current_drive->sbp_read_frames < 1)
{
msg(DBG_INF,"requested frame %d, CD size %d ???\n",
block, current_drive->CDsize_frm);
current_drive->sbp_read_frames=1;
}
}
flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check;
clr_cmdbuf();
if (famV_drive)
{
drvcmd[0]=CMDV_READ;
lba2msf(block,&drvcmd[1]); /* msf-bcd format required */
bin2bcdx(&drvcmd[1]);
bin2bcdx(&drvcmd[2]);
bin2bcdx(&drvcmd[3]);
drvcmd[4]=current_drive->sbp_read_frames>>8;
drvcmd[5]=current_drive->sbp_read_frames&0xff;
drvcmd[6]=0x02; /* flag "msf-bcd" */
}
else if (fam0L_drive)
{
flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
if (current_drive->xa_byte==0x20)
{
cmd_type=READ_M2;
drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */
drvcmd[1]=(block>>16)&0x0ff;
drvcmd[2]=(block>>8)&0x0ff;
drvcmd[3]=block&0x0ff;
drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff;
drvcmd[5]=current_drive->sbp_read_frames&0x0ff;
}
else
{
drvcmd[0]=CMD0_READ; /* "read frames", old drives */
if (current_drive->drv_type>=drv_201)
{
lba2msf(block,&drvcmd[1]); /* msf-bcd format required */
bin2bcdx(&drvcmd[1]);
bin2bcdx(&drvcmd[2]);
bin2bcdx(&drvcmd[3]);
}
else
{
drvcmd[1]=(block>>16)&0x0ff;
drvcmd[2]=(block>>8)&0x0ff;
drvcmd[3]=block&0x0ff;
}
drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff;
drvcmd[5]=current_drive->sbp_read_frames&0x0ff;
drvcmd[6]=(current_drive->drv_type<drv_201)?0:2; /* flag "lba or msf-bcd format" */
}
}
else if (fam1_drive)
{
drvcmd[0]=CMD1_READ;
lba2msf(block,&drvcmd[1]); /* msf-bin format required */
drvcmd[5]=(current_drive->sbp_read_frames>>8)&0x0ff;
drvcmd[6]=current_drive->sbp_read_frames&0x0ff;
}
else if (fam2_drive)
{
drvcmd[0]=CMD2_READ;
lba2msf(block,&drvcmd[1]); /* msf-bin format required */
drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff;
drvcmd[5]=current_drive->sbp_read_frames&0x0ff;
drvcmd[6]=0x02;
}
else if (famT_drive)
{
drvcmd[0]=CMDT_READ;
drvcmd[2]=(block>>24)&0x0ff;
drvcmd[3]=(block>>16)&0x0ff;
drvcmd[4]=(block>>8)&0x0ff;
drvcmd[5]=block&0x0ff;
drvcmd[7]=(current_drive->sbp_read_frames>>8)&0x0ff;
drvcmd[8]=current_drive->sbp_read_frames&0x0ff;
}
flags_cmd_out=f_putcmd;
response_count=0;
i=cmd_out();
if (i<0) msg(DBG_INF,"error giving READ command: %0d\n", i);
return;
}
/*==========================================================================*/
/*
* Check the completion of the read-data command. On success, read
* the current_drive->sbp_bufsiz * 2048 bytes of data from the disk into buffer.
*/
static void do_sbpcd_request(request_queue_t * q)
static int sbp_data(struct request *req)
{
u_int block;
u_int nsect;
int status_tries, data_tries;
struct request *req;
struct sbpcd_drive *p;
#ifdef DEBUG_GTL
static int xx_nr=0;
int xnr;
#endif
request_loop:
#ifdef DEBUG_GTL
xnr=++xx_nr;
req = elv_next_request(q);
if (!req)
{
printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n",
xnr, current->pid, jiffies);
printk( "do_sbpcd_request[%do](NULL) end 0 (null), Time:%li\n",
xnr, jiffies);
return;
}
int i=0, j=0, l, frame;
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 error_flag;
int xa_count;
int max_latency;
int success;
int wait;
int duration;
printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n",
xnr, req, req->sector, req->nr_sectors, current->pid, jiffies);
error_flag=0;
success=0;
#if LONG_TIMING
max_latency=9*HZ;
#else
if (current_drive->f_multisession) max_latency=15*HZ;
else max_latency=5*HZ;
#endif
duration=jiffies;
for (frame=0;frame<current_drive->sbp_read_frames&&!error_flag; frame++)
{
SBPCD_CLI;
req = elv_next_request(q); /* take out our request so no other */
if (!req)
return;
del_timer(&data_timer);
data_timer.expires=jiffies+max_latency;
timed_out_data=0;
add_timer(&data_timer);
while (!timed_out_data)
{
if (current_drive->f_multisession) try=maxtim_data*4;
else try=maxtim_data;
msg(DBG_000,"sbp_data: CDi_status loop: try=%d.\n",try);
for ( ; try!=0;try--)
{
j=inb(CDi_status);
if (!(j&s_not_data_ready)) break;
if (!(j&s_not_result_ready)) break;
if (fam0LV_drive) if (j&s_attention) break;
}
if (!(j&s_not_data_ready)) goto data_ready;
if (try==0)
{
if (data_retrying == 0) data_waits++;
data_retrying = 1;
msg(DBG_000,"sbp_data: CDi_status loop: sleeping.\n");
sbp_sleep(1);
try = 1;
}
}
msg(DBG_INF,"sbp_data: CDi_status loop expired.\n");
data_ready:
del_timer(&data_timer);
if (req -> sector == -1)
end_request(req, 0);
spin_unlock_irq(q->queue_lock);
if (timed_out_data)
{
msg(DBG_INF,"sbp_data: CDi_status timeout (timed_out_data) (%02X).\n", j);
error_flag++;
}
if (try==0)
{
msg(DBG_INF,"sbp_data: CDi_status timeout (try=0) (%02X).\n", j);
error_flag++;
}
if (!(j&s_not_result_ready))
{
msg(DBG_INF, "sbp_data: RESULT_READY where DATA_READY awaited (%02X).\n", j);
response_count=20;
j=ResponseInfo();
j=inb(CDi_status);
}
if (j&s_not_data_ready)
{
if ((current_drive->ored_ctl_adr&0x40)==0)
msg(DBG_INF, "CD contains no data tracks.\n");
else msg(DBG_INF, "sbp_data: DATA_READY timeout (%02X).\n", j);
error_flag++;
}
SBPCD_STI;
if (error_flag) break;
down(&ioctl_read_sem);
if (rq_data_dir(elv_next_request(q)) != READ)
{
msg(DBG_INF, "bad cmd %d\n", req->cmd[0]);
goto err_done;
msg(DBG_000, "sbp_data: beginning to read.\n");
p = current_drive->sbp_buf + frame * CD_FRAMESIZE;
if (sbpro_type==1) OUT(CDo_sel_i_d,1);
if (cmd_type==READ_M2) {
if (do_16bit) insw(CDi_data, xa_head_buf, CD_XA_HEAD>>1);
else insb(CDi_data, xa_head_buf, CD_XA_HEAD);
}
if (do_16bit) insw(CDi_data, p, CD_FRAMESIZE>>1);
else insb(CDi_data, p, CD_FRAMESIZE);
if (cmd_type==READ_M2) {
if (do_16bit) insw(CDi_data, xa_tail_buf, CD_XA_TAIL>>1);
else insb(CDi_data, xa_tail_buf, CD_XA_TAIL);
}
current_drive->sbp_current++;
if (sbpro_type==1) OUT(CDo_sel_i_d,0);
if (cmd_type==READ_M2)
{
for (xa_count=0;xa_count<CD_XA_HEAD;xa_count++)
sprintf(&msgbuf[xa_count*3], " %02X", xa_head_buf[xa_count]);
msgbuf[xa_count*3]=0;
msg(DBG_XA1,"xa head:%s\n", msgbuf);
}
data_retrying = 0;
data_tries++;
if (data_tries >= 1000)
{
msg(DBG_INF,"sbp_data() statistics: %d waits in %d frames.\n", data_waits, data_tries);
data_waits = data_tries = 0;
}
}
p = req->rq_disk->private_data;
#if OLD_BUSY
while (busy_audio) sbp_sleep(HZ); /* wait a bit */
busy_data=1;
#endif /* OLD_BUSY */
if (p->audio_state==audio_playing) goto err_done;
if (p != current_drive)
switch_drive(p);
block = req->sector; /* always numbered as 512-byte-pieces */
nsect = req->nr_sectors; /* always counted as 512-byte-pieces */
msg(DBG_BSZ,"read sector %d (%d sectors)\n", block, nsect);
duration=jiffies-duration;
msg(DBG_TEA,"time to read %d frames: %d jiffies .\n",frame,duration);
if (famT_drive)
{
wait=8;
do
{
if (teac==2)
{
if ((i=CDi_stat_loop_T()) == -1) break;
}
else
{
sbp_sleep(1);
OUT(CDo_sel_i_d,0);
i=inb(CDi_status);
}
if (!(i&s_not_data_ready))
{
OUT(CDo_sel_i_d,1);
j=0;
do
{
if (do_16bit) i=inw(CDi_data);
else i=inb(CDi_data);
j++;
i=inb(CDi_status);
}
while (!(i&s_not_data_ready));
msg(DBG_TEA, "==========too much data (%d bytes/words)==============.\n", j);
}
if (!(i&s_not_result_ready))
{
OUT(CDo_sel_i_d,0);
l=0;
do
{
infobuf[l++]=inb(CDi_info);
i=inb(CDi_status);
}
while (!(i&s_not_result_ready));
if (infobuf[0]==0x00) success=1;
#if 1
for (j=0;j<l;j++) sprintf(&msgbuf[j*3], " %02X", infobuf[j]);
msgbuf[j*3]=0;
msg(DBG_TEA,"sbp_data info response:%s\n", msgbuf);
#endif
if (infobuf[0]==0x02)
{
error_flag++;
do
{
++recursion;
if (recursion>1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (sbp_data): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",recursion);
else msg(DBG_TEA,"sbp_data: CMDT_READ_ERR necessary.\n");
clr_cmdbuf();
drvcmd[0]=CMDT_READ_ERR;
j=cmd_out_T(); /* !!! recursive here !!! */
--recursion;
sbp_sleep(1);
}
while (j<0);
current_drive->error_state=infobuf[2];
current_drive->b3=infobuf[3];
current_drive->b4=infobuf[4];
}
break;
}
else
{
#if 0
msg(DBG_MUL,"read LBA %d\n", block/4);
msg(DBG_TEA, "============= waiting for result=================.\n");
sbp_sleep(1);
#endif
sbp_transfer(req);
/* if we satisfied the request from the buffer, we're done. */
if (req->nr_sectors == 0)
}
}
while (wait--);
}
if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
{
#ifdef DEBUG_GTL
printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 2, Time:%li\n",
xnr, req, req->sector, req->nr_sectors, jiffies);
msg(DBG_TEA, "================error flag: %d=================.\n", error_flag);
msg(DBG_INF,"sbp_data: read aborted by drive.\n");
#if 1
i=cc_DriveReset(); /* ugly fix to prevent a hang */
#else
i=cc_ReadError();
#endif
up(&ioctl_read_sem);
spin_lock_irq(q->queue_lock);
end_request(req, 1);
goto request_loop;
return (0);
}
#ifdef FUTURE
i=prepare(0,0); /* at moment not really a hassle check, but ... */
if (i!=0)
msg(DBG_INF,"\"prepare\" tells error %d -- ignored\n", i);
#endif /* FUTURE */
if (!st_spinning) cc_SpinUp();
for (data_tries=n_retries; data_tries > 0; data_tries--)
if (fam0LV_drive)
{
for (status_tries=3; status_tries > 0; status_tries--)
SBPCD_CLI;
i=maxtim_data;
for (timeout=jiffies+HZ; time_before(jiffies, timeout); timeout--)
{
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 */
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 || time_after_eq(jiffies, timeout)) break;
sbp_sleep(0);
i = 1;
}
if (status_tries == 0)
if (i==0) msg(DBG_INF,"status timeout after READ.\n");
if (!(j&s_attention))
{
msg(DBG_INF,"sbp_status: failed after 3 tries in line %d\n", __LINE__);
break;
msg(DBG_INF,"sbp_data: timeout waiting DRV_ATTN - retrying.\n");
i=cc_DriveReset(); /* ugly fix to prevent a hang */
SBPCD_STI;
return (0);
}
sbp_read_cmd(req);
sbp_sleep(0);
if (sbp_data(req) != 0)
SBPCD_STI;
}
#if 0
if (!success)
#endif
do
{
#ifdef SAFE_MIXED
current_drive->has_data=2; /* is really a data disk */
#endif /* SAFE_MIXED */
#ifdef DEBUG_GTL
printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n",
xnr, req, req->sector, req->nr_sectors, jiffies);
if (fam0LV_drive) cc_ReadStatus();
#if 1
if (famT_drive) msg(DBG_TEA, "================before ResponseStatus=================.\n", i);
#endif
up(&ioctl_read_sem);
spin_lock_irq(q->queue_lock);
end_request(req, 1);
goto request_loop;
i=ResponseStatus(); /* builds status_bits, returns orig. status (old) or faked p_success (new) */
#if 1
if (famT_drive) msg(DBG_TEA, "================ResponseStatus: %d=================.\n", i);
#endif
if (i<0)
{
msg(DBG_INF,"bad cc_ReadStatus after read: %02X\n", current_drive->status_bits);
return (0);
}
}
while ((fam0LV_drive)&&(!st_check)&&(!(i&p_success)));
if (st_check)
{
i=cc_ReadError();
msg(DBG_INF,"cc_ReadError was necessary after read: %d\n",i);
return (0);
}
if (fatal_err)
{
fatal_err=0;
current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1; /* purge buffer */
current_drive->sbp_current = 0;
msg(DBG_INF,"sbp_data: fatal_err - retrying.\n");
return (0);
}
err_done:
#if OLD_BUSY
busy_data=0;
#endif /* OLD_BUSY */
#ifdef DEBUG_GTL
printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n",
xnr, req, req->sector, req->nr_sectors, jiffies);
#endif
up(&ioctl_read_sem);
sbp_sleep(0); /* wait a bit, try again */
spin_lock_irq(q->queue_lock);
end_request(req, 0);
goto request_loop;
current_drive->sbp_first_frame = req -> sector / 4;
current_drive->sbp_last_frame = current_drive->sbp_first_frame + current_drive->sbp_read_frames - 1;
sbp_transfer(req);
return (1);
}
/*==========================================================================*/
/*
* build and send the READ command.
*/
static void sbp_read_cmd(struct request *req)
static int sbpcd_block_open(struct inode *inode, struct file *file)
{
#undef OLD
struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
return cdrom_open(p->sbpcd_infop, inode, file);
}
int i;
int block;
static int sbpcd_block_release(struct inode *inode, struct file *file)
{
struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
return cdrom_release(p->sbpcd_infop, file);
}
static int sbpcd_block_ioctl(struct inode *inode, struct file *file,
unsigned cmd, unsigned long arg)
{
struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
struct cdrom_device_info *cdi = p->sbpcd_infop;
int ret, i;
ret = cdrom_ioctl(file, p->sbpcd_infop, inode, cmd, arg);
if (ret != -ENOSYS)
return ret;
msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08lX)\n", cdi->name, cmd, arg);
if (p->drv_id==-1) {
msg(DBG_INF, "ioctl: bad device: %s\n", cdi->name);
return (-ENXIO); /* no such drive */
}
down(&ioctl_read_sem);
if (p != current_drive)
switch_drive(p);
current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1; /* purge buffer */
current_drive->sbp_current = 0;
block=req->sector/4;
if (block+current_drive->sbp_bufsiz <= current_drive->CDsize_frm)
current_drive->sbp_read_frames = current_drive->sbp_bufsiz;
else
msg(DBG_IO2,"ioctl: device %s, request %04X\n",cdi->name,cmd);
switch (cmd) /* Sun-compatible */
{
current_drive->sbp_read_frames=current_drive->CDsize_frm-block;
/* avoid reading past end of data */
if (current_drive->sbp_read_frames < 1)
case DDIOCSDBG: /* DDI Debug */
if (!capable(CAP_SYS_ADMIN)) 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();
current_drive->audio_state=0;
RETURN_UP(i);
case CDROMREADMODE1:
msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n");
#ifdef SAFE_MIXED
if (current_drive->has_data>1) RETURN_UP(-EBUSY);
#endif /* SAFE_MIXED */
cc_ModeSelect(CD_FRAMESIZE);
cc_ModeSense();
current_drive->mode=READ_M1;
RETURN_UP(0);
case CDROMREADMODE2: /* not usable at the moment */
msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n");
#ifdef SAFE_MIXED
if (current_drive->has_data>1) RETURN_UP(-EBUSY);
#endif /* SAFE_MIXED */
cc_ModeSelect(CD_FRAMESIZE_RAW1);
cc_ModeSense();
current_drive->mode=READ_M2;
RETURN_UP(0);
case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */
msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n");
if (current_drive->sbp_audsiz>0)
vfree(current_drive->aud_buf);
current_drive->aud_buf=NULL;
current_drive->sbp_audsiz=arg;
if (current_drive->sbp_audsiz>16)
{
msg(DBG_INF,"requested frame %d, CD size %d ???\n",
block, current_drive->CDsize_frm);
current_drive->sbp_read_frames=1;
current_drive->sbp_audsiz = 0;
RETURN_UP(current_drive->sbp_audsiz);
}
}
flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check;
clr_cmdbuf();
if (famV_drive)
{
drvcmd[0]=CMDV_READ;
lba2msf(block,&drvcmd[1]); /* msf-bcd format required */
bin2bcdx(&drvcmd[1]);
bin2bcdx(&drvcmd[2]);
bin2bcdx(&drvcmd[3]);
drvcmd[4]=current_drive->sbp_read_frames>>8;
drvcmd[5]=current_drive->sbp_read_frames&0xff;
drvcmd[6]=0x02; /* flag "msf-bcd" */
}
else if (fam0L_drive)
{
flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
if (current_drive->xa_byte==0x20)
if (current_drive->sbp_audsiz>0)
{
cmd_type=READ_M2;
drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */
drvcmd[1]=(block>>16)&0x0ff;
drvcmd[2]=(block>>8)&0x0ff;
drvcmd[3]=block&0x0ff;
drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff;
drvcmd[5]=current_drive->sbp_read_frames&0x0ff;
current_drive->aud_buf=(u_char *) vmalloc(current_drive->sbp_audsiz*CD_FRAMESIZE_RAW);
if (current_drive->aud_buf==NULL)
{
msg(DBG_INF,"audio buffer (%d frames) not available.\n",current_drive->sbp_audsiz);
current_drive->sbp_audsiz=0;
}
else msg(DBG_INF,"audio buffer size: %d frames.\n",current_drive->sbp_audsiz);
}
else
RETURN_UP(current_drive->sbp_audsiz);
case CDROMREADAUDIO:
{ /* start of CDROMREADAUDIO */
int i=0, j=0, frame, block=0;
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_UP(-EINVAL);
if (famL_drive) RETURN_UP(-EINVAL);
if (famV_drive) RETURN_UP(-EINVAL);
if (famT_drive) RETURN_UP(-EINVAL);
#ifdef SAFE_MIXED
if (current_drive->has_data>1) RETURN_UP(-EBUSY);
#endif /* SAFE_MIXED */
if (current_drive->aud_buf==NULL) RETURN_UP(-EINVAL);
if (copy_from_user(&read_audio, (void __user *)arg,
sizeof(struct cdrom_read_audio)))
RETURN_UP(-EFAULT);
if (read_audio.nframes < 0 || read_audio.nframes>current_drive->sbp_audsiz) RETURN_UP(-EINVAL);
if (!access_ok(VERIFY_WRITE, read_audio.buf,
read_audio.nframes*CD_FRAMESIZE_RAW))
RETURN_UP(-EFAULT);
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_UP(-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");
#if OLD_BUSY
while (busy_data) sbp_sleep(HZ/10); /* wait a bit */
busy_audio=1;
#endif /* OLD_BUSY */
error_flag=0;
for (data_tries=5; data_tries>0; data_tries--)
{
drvcmd[0]=CMD0_READ; /* "read frames", old drives */
if (current_drive->drv_type>=drv_201)
msg(DBG_AUD,"data_tries=%d ...\n", data_tries);
current_drive->mode=READ_AU;
cc_ModeSelect(CD_FRAMESIZE_RAW);
cc_ModeSense();
for (status_tries=3; status_tries > 0; status_tries--)
{
lba2msf(block,&drvcmd[1]); /* msf-bcd format required */
bin2bcdx(&drvcmd[1]);
bin2bcdx(&drvcmd[2]);
bin2bcdx(&drvcmd[3]);
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 */
}
else
if (status_tries == 0)
{
drvcmd[1]=(block>>16)&0x0ff;
drvcmd[2]=(block>>8)&0x0ff;
drvcmd[3]=block&0x0ff;
msg(DBG_AUD,"read_audio: sbp_status: failed after 3 tries in line %d.\n", __LINE__);
continue;
}
drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff;
drvcmd[5]=current_drive->sbp_read_frames&0x0ff;
drvcmd[6]=(current_drive->drv_type<drv_201)?0:2; /* flag "lba or msf-bcd format" */
}
}
else if (fam1_drive)
{
drvcmd[0]=CMD1_READ;
lba2msf(block,&drvcmd[1]); /* msf-bin format required */
drvcmd[5]=(current_drive->sbp_read_frames>>8)&0x0ff;
drvcmd[6]=current_drive->sbp_read_frames&0x0ff;
}
else if (fam2_drive)
{
drvcmd[0]=CMD2_READ;
lba2msf(block,&drvcmd[1]); /* msf-bin format required */
drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff;
drvcmd[5]=current_drive->sbp_read_frames&0x0ff;
drvcmd[6]=0x02;
}
else if (famT_drive)
{
drvcmd[0]=CMDT_READ;
drvcmd[2]=(block>>24)&0x0ff;
drvcmd[3]=(block>>16)&0x0ff;
drvcmd[4]=(block>>8)&0x0ff;
drvcmd[5]=block&0x0ff;
drvcmd[7]=(current_drive->sbp_read_frames>>8)&0x0ff;
drvcmd[8]=current_drive->sbp_read_frames&0x0ff;
}
flags_cmd_out=f_putcmd;
response_count=0;
i=cmd_out();
if (i<0) msg(DBG_INF,"error giving READ command: %0d\n", i);
return;
}
/*==========================================================================*/
/*
* Check the completion of the read-data command. On success, read
* the current_drive->sbp_bufsiz * 2048 bytes of data from the disk into buffer.
*/
static int sbp_data(struct request *req)
{
int i=0, j=0, l, frame;
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 error_flag;
int xa_count;
int max_latency;
int success;
int wait;
int duration;
error_flag=0;
success=0;
#if LONG_TIMING
max_latency=9*HZ;
#else
if (current_drive->f_multisession) max_latency=15*HZ;
else max_latency=5*HZ;
#endif
duration=jiffies;
for (frame=0;frame<current_drive->sbp_read_frames&&!error_flag; frame++)
{
SBPCD_CLI;
del_timer(&data_timer);
data_timer.expires=jiffies+max_latency;
timed_out_data=0;
add_timer(&data_timer);
while (!timed_out_data)
{
if (current_drive->f_multisession) try=maxtim_data*4;
else try=maxtim_data;
msg(DBG_000,"sbp_data: CDi_status loop: try=%d.\n",try);
for ( ; try!=0;try--)
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)
{
j=inb(CDi_status);
if (!(j&s_not_data_ready)) break;
if (!(j&s_not_result_ready)) break;
if (fam0LV_drive) if (j&s_attention) break;
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;
}
if (!(j&s_not_data_ready)) goto data_ready;
if (try==0)
else if (fam1_drive)
{
if (data_retrying == 0) data_waits++;
data_retrying = 1;
msg(DBG_000,"sbp_data: CDi_status loop: sleeping.\n");
sbp_sleep(1);
try = 1;
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 */
}
}
msg(DBG_INF,"sbp_data: CDi_status loop expired.\n");
data_ready:
del_timer(&data_timer);
if (timed_out_data)
{
msg(DBG_INF,"sbp_data: CDi_status timeout (timed_out_data) (%02X).\n", j);
error_flag++;
}
if (try==0)
{
msg(DBG_INF,"sbp_data: CDi_status timeout (try=0) (%02X).\n", j);
error_flag++;
}
if (!(j&s_not_result_ready))
{
msg(DBG_INF, "sbp_data: RESULT_READY where DATA_READY awaited (%02X).\n", j);
response_count=20;
j=ResponseInfo();
j=inb(CDi_status);
}
if (j&s_not_data_ready)
{
if ((current_drive->ored_ctl_adr&0x40)==0)
msg(DBG_INF, "CD contains no data tracks.\n");
else msg(DBG_INF, "sbp_data: DATA_READY timeout (%02X).\n", j);
error_flag++;
}
SBPCD_STI;
if (error_flag) break;
msg(DBG_000, "sbp_data: beginning to read.\n");
p = current_drive->sbp_buf + frame * CD_FRAMESIZE;
if (sbpro_type==1) OUT(CDo_sel_i_d,1);
if (cmd_type==READ_M2) {
if (do_16bit) insw(CDi_data, xa_head_buf, CD_XA_HEAD>>1);
else insb(CDi_data, xa_head_buf, CD_XA_HEAD);
}
if (do_16bit) insw(CDi_data, p, CD_FRAMESIZE>>1);
else insb(CDi_data, p, CD_FRAMESIZE);
if (cmd_type==READ_M2) {
if (do_16bit) insw(CDi_data, xa_tail_buf, CD_XA_TAIL>>1);
else insb(CDi_data, xa_tail_buf, CD_XA_TAIL);
}
current_drive->sbp_current++;
if (sbpro_type==1) OUT(CDo_sel_i_d,0);
if (cmd_type==READ_M2)
{
for (xa_count=0;xa_count<CD_XA_HEAD;xa_count++)
sprintf(&msgbuf[xa_count*3], " %02X", xa_head_buf[xa_count]);
msgbuf[xa_count*3]=0;
msg(DBG_XA1,"xa head:%s\n", msgbuf);
}
data_retrying = 0;
data_tries++;
if (data_tries >= 1000)
{
msg(DBG_INF,"sbp_data() statistics: %d waits in %d frames.\n", data_waits, data_tries);
data_waits = data_tries = 0;
}
}
duration=jiffies-duration;
msg(DBG_TEA,"time to read %d frames: %d jiffies .\n",frame,duration);
if (famT_drive)
{
wait=8;
do
{
if (teac==2)
{
if ((i=CDi_stat_loop_T()) == -1) break;
}
else
{
sbp_sleep(1);
OUT(CDo_sel_i_d,0);
i=inb(CDi_status);
}
if (!(i&s_not_data_ready))
else if (fam2_drive)
{
OUT(CDo_sel_i_d,1);
j=0;
do
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; ; )
{
if (do_16bit) i=inw(CDi_data);
else i=inb(CDi_data);
j++;
i=inb(CDi_status);
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 || time_after_eq(jiffies, timeout)) break;
if (data_retrying == 0) data_waits++;
data_retrying = 1;
sbp_sleep(1);
try = 1;
}
while (!(i&s_not_data_ready));
msg(DBG_TEA, "==========too much data (%d bytes/words)==============.\n", j);
}
if (!(i&s_not_result_ready))
{
OUT(CDo_sel_i_d,0);
l=0;
do
if (try==0)
{
infobuf[l++]=inb(CDi_info);
i=inb(CDi_status);
msg(DBG_INF,"read_audio: sbp_data: CDi_status timeout.\n");
error_flag++;
break;
}
while (!(i&s_not_result_ready));
if (infobuf[0]==0x00) success=1;
#if 1
for (j=0;j<l;j++) sprintf(&msgbuf[j*3], " %02X", infobuf[j]);
msgbuf[j*3]=0;
msg(DBG_TEA,"sbp_data info response:%s\n", msgbuf);
#endif
if (infobuf[0]==0x02)
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++;
do
{
++recursion;
if (recursion>1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (sbp_data): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",recursion);
else msg(DBG_TEA,"sbp_data: CMDT_READ_ERR necessary.\n");
clr_cmdbuf();
drvcmd[0]=CMDT_READ_ERR;
j=cmd_out_T(); /* !!! recursive here !!! */
--recursion;
sbp_sleep(1);
break;
}
msg(DBG_AUD,"read_audio: before reading data.\n");
error_flag=0;
p = current_drive->aud_buf;
if (sbpro_type==1) OUT(CDo_sel_i_d,1);
if (do_16bit)
{
u_short *p2 = (u_short *) p;
for (; (u_char *) p2 < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;)
{
if ((inb_p(CDi_status)&s_not_data_ready)) continue;
/* get one sample */
*p2++ = inw_p(CDi_data);
*p2++ = inw_p(CDi_data);
}
} else {
for (; p < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;)
{
if ((inb_p(CDi_status)&s_not_data_ready)) continue;
/* get one sample */
*p++ = inb_p(CDi_data);
*p++ = inb_p(CDi_data);
*p++ = inb_p(CDi_data);
*p++ = inb_p(CDi_data);
}
while (j<0);
current_drive->error_state=infobuf[2];
current_drive->b3=infobuf[3];
current_drive->b4=infobuf[4];
}
break;
if (sbpro_type==1) OUT(CDo_sel_i_d,0);
data_retrying = 0;
}
else
msg(DBG_AUD,"read_audio: after reading data.\n");
if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
{
#if 0
msg(DBG_TEA, "============= waiting for result=================.\n");
sbp_sleep(1);
#endif
}
}
while (wait--);
}
if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
{
msg(DBG_TEA, "================error flag: %d=================.\n", error_flag);
msg(DBG_INF,"sbp_data: read aborted by drive.\n");
#if 1
i=cc_DriveReset(); /* ugly fix to prevent a hang */
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();
i=cc_ReadError();
#endif
return (0);
}
if (fam0LV_drive)
{
SBPCD_CLI;
i=maxtim_data;
for (timeout=jiffies+HZ; time_before(jiffies, timeout); timeout--)
{
for ( ;i!=0;i--)
continue;
}
if (fam0L_drive)
{
j=inb(CDi_status);
if (!(j&s_not_data_ready)) break;
if (!(j&s_not_result_ready)) break;
if (j&s_attention) break;
i=maxtim_data;
for (timeout=jiffies+9*HZ; time_before(jiffies, timeout); 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 || time_after_eq(jiffies, timeout)) 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;
}
}
if (i != 0 || time_after_eq(jiffies, timeout)) break;
sbp_sleep(0);
i = 1;
}
if (i==0) msg(DBG_INF,"status timeout after READ.\n");
if (!(j&s_attention))
{
msg(DBG_INF,"sbp_data: timeout waiting DRV_ATTN - retrying.\n");
i=cc_DriveReset(); /* ugly fix to prevent a hang */
SBPCD_STI;
return (0);
}
SBPCD_STI;
}
#if 0
if (!success)
#endif
do
{
if (fam0LV_drive) cc_ReadStatus();
#if 1
if (famT_drive) msg(DBG_TEA, "================before ResponseStatus=================.\n", i);
#endif
i=ResponseStatus(); /* builds status_bits, returns orig. status (old) or faked p_success (new) */
#if 1
if (famT_drive) msg(DBG_TEA, "================ResponseStatus: %d=================.\n", i);
#endif
if (i<0)
do
{
msg(DBG_INF,"bad cc_ReadStatus after read: %02X\n", current_drive->status_bits);
return (0);
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",
current_drive->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;
}
if (copy_to_user(read_audio.buf,
current_drive->aud_buf,
read_audio.nframes * CD_FRAMESIZE_RAW))
RETURN_UP(-EFAULT);
msg(DBG_AUD,"read_audio: copy_to_user done.\n");
break;
}
while ((fam0LV_drive)&&(!st_check)&&(!(i&p_success)));
if (st_check)
{
i=cc_ReadError();
msg(DBG_INF,"cc_ReadError was necessary after read: %d\n",i);
return (0);
}
if (fatal_err)
{
fatal_err=0;
current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1; /* purge buffer */
current_drive->sbp_current = 0;
msg(DBG_INF,"sbp_data: fatal_err - retrying.\n");
return (0);
}
current_drive->sbp_first_frame = req -> sector / 4;
current_drive->sbp_last_frame = current_drive->sbp_first_frame + current_drive->sbp_read_frames - 1;
sbp_transfer(req);
return (1);
}
/*==========================================================================*/
static int sbpcd_block_open(struct inode *inode, struct file *file)
{
struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
return cdrom_open(p->sbpcd_infop, inode, file);
}
static int sbpcd_block_release(struct inode *inode, struct file *file)
{
struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
return cdrom_release(p->sbpcd_infop, file);
}
cc_ModeSelect(CD_FRAMESIZE);
cc_ModeSense();
current_drive->mode=READ_M1;
#if OLD_BUSY
busy_audio=0;
#endif /* OLD_BUSY */
if (data_tries == 0)
{
msg(DBG_AUD,"read_audio: failed after 5 tries in line %d.\n", __LINE__);
RETURN_UP(-EIO);
}
msg(DBG_AUD,"read_audio: successful return.\n");
RETURN_UP(0);
} /* end of CDROMREADAUDIO */
static int sbpcd_block_ioctl(struct inode *inode, struct file *file,
unsigned cmd, unsigned long arg)
{
struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data;
return cdrom_ioctl(file, p->sbpcd_infop, inode, cmd, arg);
default:
msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd);
RETURN_UP(-EINVAL);
} /* end switch(cmd) */
}
static int sbpcd_block_media_changed(struct gendisk *disk)
......@@ -5478,10 +5471,9 @@ static struct cdrom_device_ops sbpcd_dops = {
.get_mcn = sbpcd_get_mcn,
.reset = sbpcd_reset,
.audio_ioctl = sbpcd_audio_ioctl,
.dev_ioctl = sbpcd_dev_ioctl,
.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |
CDC_MCN | CDC_PLAY_AUDIO | CDC_IOCTLS,
CDC_MCN | CDC_PLAY_AUDIO,
.n_minors = 1,
};
......
......@@ -627,7 +627,7 @@ static struct cdrom_device_ops viocd_dops = {
.media_changed = viocd_media_changed,
.lock_door = viocd_lock_door,
.generic_packet = viocd_packet,
.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM
.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM
};
static int __init find_capability(const char *type)
......
......@@ -2470,52 +2470,6 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi,
return cgc->stat;
}
static
int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
unsigned int cmd, unsigned long arg)
{
struct packet_command cgc;
char buffer[16];
int stat;
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
/* These will be moved into the Uniform layer shortly... */
switch (cmd) {
case CDROMSETSPINDOWN: {
char spindown;
if (copy_from_user(&spindown, (void __user *) arg, sizeof(char)))
return -EFAULT;
if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
return stat;
buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
return cdrom_mode_select(cdi, &cgc);
}
case CDROMGETSPINDOWN: {
char spindown;
if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
return stat;
spindown = buffer[11] & 0x0f;
if (copy_to_user((void __user *) arg, &spindown, sizeof (char)))
return -EFAULT;
return 0;
}
default:
return -EINVAL;
}
}
static
int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
unsigned int cmd, void *arg)
......@@ -2852,12 +2806,11 @@ static struct cdrom_device_ops ide_cdrom_dops = {
.get_mcn = ide_cdrom_get_mcn,
.reset = ide_cdrom_reset,
.audio_ioctl = ide_cdrom_audio_ioctl,
.dev_ioctl = ide_cdrom_dev_ioctl,
.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
CDC_SELECT_SPEED | CDC_SELECT_DISC |
CDC_MULTI_SESSION | CDC_MCN |
CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET |
CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R |
CDC_DRIVE_STATUS | CDC_CD_R |
CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM |
CDC_GENERIC_PACKET | CDC_MO_DRIVE | CDC_MRW |
CDC_MRW_W | CDC_RAM,
......@@ -3367,6 +3320,45 @@ static int idecd_release(struct inode * inode, struct file * file)
return 0;
}
static int idecd_set_spindown(struct cdrom_device_info *cdi, unsigned long arg)
{
struct packet_command cgc;
char buffer[16];
int stat;
char spindown;
if (copy_from_user(&spindown, (void __user *)arg, sizeof(char)))
return -EFAULT;
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
if (stat)
return stat;
buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
return cdrom_mode_select(cdi, &cgc);
}
static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg)
{
struct packet_command cgc;
char buffer[16];
int stat;
char spindown;
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
if (stat)
return stat;
spindown = buffer[11] & 0x0f;
if (copy_to_user((void __user *)arg, &spindown, sizeof (char)))
return -EFAULT;
return 0;
}
static int idecd_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
......@@ -3374,7 +3366,16 @@ static int idecd_ioctl (struct inode *inode, struct file *file,
struct cdrom_info *info = ide_cd_g(bdev->bd_disk);
int err;
err = generic_ide_ioctl(info->drive, file, bdev, cmd, arg);
switch (cmd) {
case CDROMSETSPINDOWN:
return idecd_set_spindown(&info->devinfo, arg);
case CDROMGETSPINDOWN:
return idecd_get_spindown(&info->devinfo, arg);
default:
break;
}
err = generic_ide_ioctl(info->drive, file, bdev, cmd, arg);
if (err == -EINVAL)
err = cdrom_ioctl(file, &info->devinfo, inode, cmd, arg);
......
......@@ -71,7 +71,7 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR);
#define SR_CAPABILITIES \
(CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_SPEED| \
CDC_SELECT_DISC|CDC_MULTI_SESSION|CDC_MCN|CDC_MEDIA_CHANGED| \
CDC_PLAY_AUDIO|CDC_RESET|CDC_IOCTLS|CDC_DRIVE_STATUS| \
CDC_PLAY_AUDIO|CDC_RESET|CDC_DRIVE_STATUS| \
CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \
CDC_MRW|CDC_MRW_W|CDC_RAM)
......@@ -118,7 +118,6 @@ static struct cdrom_device_ops sr_dops = {
.get_mcn = sr_get_mcn,
.reset = sr_reset,
.audio_ioctl = sr_audio_ioctl,
.dev_ioctl = sr_dev_ioctl,
.capability = SR_CAPABILITIES,
.generic_packet = sr_packet,
};
......@@ -456,17 +455,33 @@ static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd,
{
struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
struct scsi_device *sdev = cd->device;
void __user *argp = (void __user *)arg;
int ret;
/*
* Send SCSI addressing ioctls directly to mid level, send other
* ioctls to cdrom/block level.
*/
switch (cmd) {
case SCSI_IOCTL_GET_IDLUN:
case SCSI_IOCTL_GET_BUS_NUMBER:
return scsi_ioctl(sdev, cmd, (void __user *)arg);
/*
* Send SCSI addressing ioctls directly to mid level, send other
* ioctls to cdrom/block level.
*/
switch (cmd) {
case SCSI_IOCTL_GET_IDLUN:
case SCSI_IOCTL_GET_BUS_NUMBER:
return scsi_ioctl(sdev, cmd, argp);
}
return cdrom_ioctl(file, &cd->cdi, inode, cmd, arg);
ret = cdrom_ioctl(file, &cd->cdi, inode, cmd, arg);
if (ret != ENOSYS)
return ret;
/*
* ENODEV means that we didn't recognise the ioctl, or that we
* cannot execute it in the current device state. In either
* case fall through to scsi_ioctl, which will return ENDOEV again
* if it doesn't recognise the ioctl
*/
ret = scsi_nonblockable_ioctl(sdev, cmd, argp, NULL);
if (ret != -ENODEV)
return ret;
return scsi_ioctl(sdev, cmd, argp);
}
static int sr_block_media_changed(struct gendisk *disk)
......
......@@ -55,7 +55,6 @@ int sr_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *);
int sr_reset(struct cdrom_device_info *);
int sr_select_speed(struct cdrom_device_info *cdi, int speed);
int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
int sr_dev_ioctl(struct cdrom_device_info *, unsigned int, unsigned long);
int sr_is_xa(Scsi_CD *);
......
......@@ -562,22 +562,3 @@ int sr_is_xa(Scsi_CD *cd)
#endif
return is_xa;
}
int sr_dev_ioctl(struct cdrom_device_info *cdi,
unsigned int cmd, unsigned long arg)
{
Scsi_CD *cd = cdi->handle;
int ret;
ret = scsi_nonblockable_ioctl(cd->device, cmd,
(void __user *)arg, NULL);
/*
* ENODEV means that we didn't recognise the ioctl, or that we
* cannot execute it in the current device state. In either
* case fall through to scsi_ioctl, which will return ENDOEV again
* if it doesn't recognise the ioctl
*/
if (ret != -ENODEV)
return ret;
return scsi_ioctl(cd->device, cmd, (void __user *)arg);
}
......@@ -378,7 +378,6 @@ struct cdrom_generic_command
#define CDC_MEDIA_CHANGED 0x80 /* media changed */
#define CDC_PLAY_AUDIO 0x100 /* audio functions */
#define CDC_RESET 0x200 /* hard reset device */
#define CDC_IOCTLS 0x400 /* driver has non-standard ioctls */
#define CDC_DRIVE_STATUS 0x800 /* driver implements drive status */
#define CDC_GENERIC_PACKET 0x1000 /* driver implements generic packets */
#define CDC_CD_R 0x2000 /* drive is a CD-R */
......@@ -974,9 +973,7 @@ struct cdrom_device_ops {
int (*reset) (struct cdrom_device_info *);
/* play stuff */
int (*audio_ioctl) (struct cdrom_device_info *,unsigned int, void *);
/* dev-specific */
int (*dev_ioctl) (struct cdrom_device_info *,
unsigned int, unsigned long);
/* driver specifications */
const int capability; /* capability flags */
int n_minors; /* number of active minor devices */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment