extractedLnx/linux/drivers/block/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 (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);
msg(DBG_IOC,"ioctl: cc_PlayAudio returns %d\n",i);
#if 0
if (i<0) return (-EIO);
#endif 0
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 (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 0
if (i<0) return (-EIO);
#endif 0
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_READ, (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);
st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_tocentry));
if (st) return (st);
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");
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);
st=verify_area(VERIFY_READ, (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");
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");
cc_ModeSelect(CD_FRAMESIZE_XA);
cc_ModeSense();
D_S[d].mode=READ_M2;
return (0);
case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */
msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n");
#ifdef MODULE
if (D_S[d].sbp_audsiz>0)
vfree(D_S[d].aud_buf);
#endif MODULE
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 (fam2_drive) return (-EINVAL);
if (famT_drive) return (-EINVAL);
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);
i=cc_SetSpeed(speed_150,0,0);
if (i) msg(DBG_AUD,"read_audio: SetSpeed error %d\n", i);
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(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;
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) /* CD200: not tested yet */
{
}
else if (famT_drive) /* CD-55A: not tested yet */
{
}
msg(DBG_AUD,"read_audio: before giving \"read\" command.\n");
for (i=0;i<7;i++) OUT(CDo_command,drvcmd[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+900; ; )
{
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);
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+900; 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_READ, (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 */
st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_multisession));
if (st) return (st);
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.