This is cd_commands.c in view mode; [Download] [Up]
/*
* cd_commands.c: CD-ROM drive specific commands
*
* This is based on the file that NeXT included in
* /NextDeveloper/Examples/UNIX/SCSI_CD,
* done by James C. Lee at NeXT, Sep 1991.
* It has been changed "just a bit" by Garance Alistair Drosehn/March 1994.
*
*/
#define CD_DEBUG2
#import <libc.h>
#import <objc/objc.h>
#import <c.h>
#import "cd_commands.h"
#import "cd_cmdsint.h" /* structs internal to cd_commands */
#import "scsi_commands.h"
/**************************************************************************
* do_eject_1b
*
*/
int
do_eject_1b(int fd, struct timeval * tvp, struct esense_reply * erp)
{
struct scsi_req sr;
struct start_stop_1B_cmd *sscp;
int err;
bzero((char *)&sr, sizeof(sr));
sscp = (struct start_stop_1B_cmd *) & sr.sr_cdb;
sscp->ssc_opcode = C6OP_STARTSTOP;
sscp->ssc_imm = 0; /* status will be returned after the
* operation is completed */
sscp->ssc_loej = 1; /* eject when spin down (scc_start=0) */
sscp->ssc_start = 0; /* spin down */
sr.sr_addr = NULL;
sr.sr_dma_max = 0; /* don't really do I/O to memory */
sr.sr_ioto = 10; /* time out in 10 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
*tvp = sr.sr_exec_time;
if (sr.sr_dma_xfr != 0)
fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_spinup_1b
*
* same command as do_eject, except that sscp->ssc_start=1 and
* sscp->ssc_loej=0
*/
int
do_spinup_1b(int fd, struct timeval * tvp, struct esense_reply * erp)
{
struct scsi_req sr;
struct start_stop_1B_cmd *sscp;
int err;
bzero((char *)&sr, sizeof(sr));
sscp = (struct start_stop_1B_cmd *) & sr.sr_cdb;
sscp->ssc_opcode = C6OP_STARTSTOP;
sscp->ssc_imm = 0; /* status will be returned after the
* operation is completed */
sscp->ssc_loej = 0;
sscp->ssc_start = 1; /* spin up */
sr.sr_addr = NULL;
sr.sr_dma_max = 0; /* don't really do I/O to memory */
sr.sr_ioto = 10; /* time out in 10 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
*tvp = sr.sr_exec_time;
if (sr.sr_dma_xfr != 0)
fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_stopunit_1b
*
* same command as do_eject_1b, except that sscp->ssc_loej=0
* because the caddy should not be ejected.
*/
int
do_stopunit_1b(int fd, struct timeval * tvp, struct esense_reply * erp)
{
struct scsi_req sr;
struct start_stop_1B_cmd *sscp;
int err;
bzero((char *)&sr, sizeof(sr));
sscp = (struct start_stop_1B_cmd *) & sr.sr_cdb;
sscp->ssc_opcode = C6OP_STARTSTOP;
sscp->ssc_imm = 0; /* status will be returned after the
* operation is completed */
sscp->ssc_loej = 0; /* do not eject when spin down (scc_start=0) */
sscp->ssc_start = 0; /* spin down */
sr.sr_addr = NULL;
sr.sr_dma_max = 0; /* don't really do I/O to memory */
sr.sr_ioto = 10; /* time out in 10 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
*tvp = sr.sr_exec_time;
if (sr.sr_dma_xfr != 0)
fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_pauseaudio_4b
*/
int
do_pauseaudio_4b(int fd, int pause, struct esense_reply * erp)
{
struct scsi_req sr;
struct pause_4b_cmd *pp;
int err;
bzero((char *)&sr, sizeof(sr));
pp = (struct pause_4b_cmd *) & sr.sr_cdb;
pp->p_op_code = C10OP_PAUSE_4B;
pp->p_resume = !pause; /* resume = not(pause) */
sr.sr_addr = NULL;
sr.sr_dma_max = 0;
sr.sr_ioto = 5; /* time out in 5 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
if (sr.sr_dma_xfr != 0)
fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_pauseaudio_c5
*
* this command implements the same capability as do_pauseaudio_4b,
* but the x'c5' opcode is the the standardized one. This works on
* the CD-ROM drive that NeXT sold, but not on other CD-ROM drives.
*/
int
do_pauseaudio_c5(int fd, int pause, struct esense_reply * erp)
{
struct scsi_req sr;
struct pause_c5_cmd *pp;
int err;
bzero((char *)&sr, sizeof(sr));
pp = (struct pause_c5_cmd *) & sr.sr_cdb;
pp->p_op_code = C10OP_PAUSE_C5;
pp->p_pause = pause;
sr.sr_addr = NULL;
sr.sr_dma_max = 0;
sr.sr_ioto = 5; /* time out in 5 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
if (sr.sr_dma_xfr != 0)
fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_preventremoval_1e
*
* prevent (or allow) medium removal. ie, disable (enable) the
* button on the front of the CD-ROM drive.
*/
int
do_preventremoval_1e(int fd, int prevent, struct esense_reply * erp)
{
struct scsi_req sr;
struct prevent_removal_1e_cmd *pp;
int err;
bzero((char *)&sr, sizeof(sr));
pp = (struct prevent_removal_1e_cmd *) & sr.sr_cdb;
pp->par_op_code = C6OP_PREVENT_REMOVAL_1E;
pp->par_prevent = prevent; /* 0 = allow, 1 = prevent */
sr.sr_addr = NULL;
sr.sr_dma_max = 0;
sr.sr_ioto = 5; /* time out in 5 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
if (sr.sr_dma_xfr != 0)
fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_rezerounit_01
*/
int
do_rezerounit_01(int fd, struct esense_reply * erp)
{
struct scsi_req sr;
struct rezero_unit_01_cmd *rz;
int err;
bzero((char *)&sr, sizeof(sr));
rz = (struct rezero_unit_01_cmd *) & sr.sr_cdb;
rz->rzu_opcode = C6OP_REZEROUNIT_01;
sr.sr_addr = NULL;
sr.sr_dma_max = 0;
sr.sr_ioto = 5; /* time out in 5 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
if (sr.sr_dma_xfr != 0)
fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_playaudio_c8
*/
int
do_playaudio_c8(int fd, int lba, int length, struct esense_reply * erp)
{
struct scsi_req sr;
struct playaudio_c8_cmd *pap;
int err;
bzero((char *)&sr, sizeof(sr));
pap = (struct playaudio_c8_cmd *) & sr.sr_cdb;
pap->pa_op_code = C6OP_PLAYAUDIO_C8;
SET_4BYTE_UINT(pap->pa_lba, lba); /* block to play audio from */
SET_2BYTE_UINT(pap->pa_length, length); /* length to play */
sr.sr_addr = NULL;
sr.sr_dma_max = 0;
sr.sr_ioto = 10; /* time out in 10 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
if (sr.sr_dma_xfr != 0)
fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_playaudio_msf_47
*/
int
do_playaudio_msf_47(int fd, struct pa_msf startmsf, struct pa_msf endmsf,
struct esense_reply * erp)
{
struct scsi_req sr;
struct playaudio_msf_47_cmd *pap;
int err;
bzero((char *)&sr, sizeof(sr));
pap = (struct playaudio_msf_47_cmd *) & sr.sr_cdb;
pap->pam_op_code = C10OP_PLAYAUDIO_MSF_47;
pap->pam_start_min = startmsf.min;
pap->pam_start_sec = startmsf.sec;
pap->pam_start_frame = startmsf.frame;
pap->pam_end_min = endmsf.min;
pap->pam_end_sec = endmsf.sec;
pap->pam_end_frame = endmsf.frame;
sr.sr_addr = NULL;
sr.sr_dma_max = 0;
sr.sr_ioto = 10; /* time out in 10 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
if (sr.sr_dma_xfr != 0)
fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_readtoc_43
*
* read in the entire table-of-contents of an audio CD, and return
* to the user in a platform-independent format.
*/
int
do_readtoc_43(int fd, struct cd_toc * toc_all, struct esense_reply * erp)
{
struct scsi_req sr;
struct readtoc_43_cmd *rt10cp;
struct readtoc_43_reply tocr;
int err;
char *toc_reply; /* toc reply from scsi bus, need to
* be allocated */
u_int toc_data_length,
toc_temp_length,
lastsec,
currsec;
struct rtr_desc *desc; /* pointer to traverse through *toc_reply */
int nrecords, /* number of desc blocks info in toc */
nrectemp,
i,
track,
lasttrack;
/*
* First zero most everything in the cd_toc parameter, except the times.
* Note the time variables are really unsigned integers..
*/
bzero((char *)toc_all, sizeof(struct cd_toc));
for (i = 0; i <= 100; i++) {
toc_all->info[i].hour = -1;
toc_all->info[i].min = -1;
toc_all->info[i].sec = -1;
toc_all->info[i].frame = -1;
}
bzero((char *)&sr, sizeof(sr));
toc_reply = NULL;
rt10cp = (struct readtoc_43_cmd *) & sr.sr_cdb;
rt10cp->rt_op_code = C10OP_READTOC_43;
rt10cp->rt_msf = 0; /* don't use msf format */
rt10cp->rt_starttrack = 0;
/* read only info on track 0 to find out TOC data length */
toc_data_length = sizeof(struct readtoc_43_reply);
SET_2BYTE_UINT(rt10cp->rt_length, toc_data_length);
sr.sr_addr = (char *)&tocr;
sr.sr_dma_max = sizeof(tocr);
sr.sr_ioto = 5; /* time out in 5 seconds */
sr.sr_dma_dir = SR_DMA_RD; /* read &sr.sr_addr from device */
err = ioctl(fd, SDIOCSRQ, &sr);
*erp = sr.sr_esense;
if (err | sr.sr_io_status) {/* problem reading TOC, return */
return err | sr.sr_io_status;
}
/* record first & last track, and toc data length */
toc_all->firsttrack = tocr.h.rtr_firsttrack;
toc_all->lasttrack = tocr.h.rtr_lasttrack;
nrecords = tocr.h.rtr_lasttrack - tocr.h.rtr_firsttrack + 2;
toc_data_length = nrecords * sizeof(struct rtr_desc);
toc_temp_length = GET_2BYTE_UINT(tocr.h.rtr_datalen) - 2;
nrectemp = toc_data_length / sizeof(struct rtr_desc);
if (toc_temp_length > toc_data_length) {
#ifdef CD_DEBUG2
printf("mCD: first = %d, last = %d, nrec=%d, toc_dl = %d\n",
tocr.h.rtr_firsttrack, tocr.h.rtr_lasttrack,
nrecords, toc_data_length);
printf("mCD: switch to --> nrec=%d, rtr_dl-2 = %d\n",
nrectemp, toc_temp_length);
#endif CD_DEBUG2
toc_data_length = toc_temp_length;
nrecords = nrectemp;
} else if (toc_temp_length < toc_data_length) {
printf("mCD: first = %d, last = %d, nrec=%d, toc_dl = %d\n",
tocr.h.rtr_firsttrack, tocr.h.rtr_lasttrack,
nrecords, toc_data_length);
printf("mCD: but nrectemp=%d, rtr_dl-2 = %d !!\n",
nrectemp, toc_temp_length);
}
/* prepare for second read toc for the whole thing */
bzero((char *)&sr, sizeof(sr));
rt10cp = (struct readtoc_43_cmd *) & sr.sr_cdb;
rt10cp->rt_op_code = C10OP_READTOC_43;
rt10cp->rt_msf = 1; /* want msf format */
rt10cp->rt_starttrack = 0;
toc_data_length += sizeof(struct rtr_header);
SET_2BYTE_UINT(rt10cp->rt_length, toc_data_length);
toc_reply = (char *)malloc(toc_data_length);
bzero((char *)toc_reply, toc_data_length);
sr.sr_addr = toc_reply;
sr.sr_dma_max = toc_data_length;
sr.sr_ioto = 5; /* time out in 5 seconds */
sr.sr_dma_dir = SR_DMA_RD; /* read &sr.sr_addr from device */
err = ioctl(fd, SDIOCSRQ, &sr);
*erp = sr.sr_esense;
if (err | sr.sr_io_status) {/* problem reading TOC, return */
return err | sr.sr_io_status;
}
/* successfully read the whole thing, now process it. */
desc = (struct rtr_desc *) & (toc_reply[4]); /* skip the header */
lastsec = 0;
lasttrack = -1;
for (i = 0; i < nrecords; i++) {
track = desc->rtrd_track;
if (track == 0xaa)
track = 100; /* lead-out area */
if (desc->rtrd_control & DATA_TRACK)
toc_all->ndata++;
else if (track != 100)
toc_all->naudio++;
toc_all->info[track].control = desc->rtrd_control;
toc_all->info[track].lblock = (desc->rtrd_addr.msf.hour * 3600)
+ (desc->rtrd_addr.msf.min * 60)
+ desc->rtrd_addr.msf.sec;
toc_all->info[track].lblock = (toc_all->info[track].lblock * 75)
+ desc->rtrd_addr.msf.frame;
toc_all->info[track].hour = desc->rtrd_addr.msf.hour;
toc_all->info[track].min = desc->rtrd_addr.msf.min;
toc_all->info[track].sec = desc->rtrd_addr.msf.sec;
toc_all->info[track].frame = desc->rtrd_addr.msf.frame;
currsec = (desc->rtrd_addr.msf.hour * 3600)
+ (desc->rtrd_addr.msf.min * 60)
+ desc->rtrd_addr.msf.sec;
if (lasttrack > 0)
toc_all->info[lasttrack].elapsedSec = currsec - lastsec;
lasttrack = track;
lastsec = currsec;
desc++;
}
toc_all->info[100].elapsedSec = (toc_all->info[100].hour * 3600)
+ (toc_all->info[100].min * 60)
+ toc_all->info[100].sec;
#ifdef CD_DEBUG
/* print the table of contents to stderr */
printf("\n start time time elapsed\n");
for (i = toc_all->firsttrack; i <= toc_all->lasttrack; i++) {
printf("Track %2d: %d:%02d:%02d-%02d %c %02d:%02d\n", i,
toc_all->info[i].hour, toc_all->info[i].min,
toc_all->info[i].sec,
toc_all->info[i].frame,
toc_all->info[i].control & DATA_TRACK ? 'D' : 'A',
toc_all->info[i].elapsedSec / 60,
toc_all->info[i].elapsedSec % 60);
}
printf("Track LO: %d:%02d:%02d-%02d %c\n",
toc_all->info[100].hour, toc_all->info[100].min,
toc_all->info[100].sec,
toc_all->info[100].frame,
toc_all->info[100].control & DATA_TRACK ? 'D' : 'A');
#endif
if (toc_reply != NULL)
free(toc_reply);
return err | sr.sr_io_status;
}
/**************************************************************************
* do_readsubchannel_42
*
* This is only here for reference purposes. Almost all programs
* interested in the information from readsubchannel should be using
* routines like do_readcurrentposition_42 and do_readmediacatnum_42.
*/
int
do_readsubchannel_42(int fd, int msf, int subq, int page, int track,
struct sc_reply * scrp, struct esense_reply * erp)
{
struct scsi_req sr;
struct read_subchannel_42_cmd *rscp;
int err;
bzero((char *)&sr, sizeof(sr));
rscp = (struct read_subchannel_42_cmd *) & sr.sr_cdb;
rscp->rsc_op_code = C10OP_READSUBCHANNEL_42;
rscp->rsc_msf = msf;
rscp->rsc_subq = subq;
rscp->rsc_dformat = page;
rscp->rsc_track = track;
SET_2BYTE_UINT(rscp->rsc_length, sizeof(struct sc_reply));
sr.sr_addr = (char *)scrp;
sr.sr_dma_max = sizeof(struct sc_reply);
sr.sr_ioto = 5; /* time out in 5 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_readcurrentposition_42
*
* This is really the "read sub-channel data" command with a few of
* the fields automatically filled in.
*/
int
do_readcurrentposition_42(int fd, struct rsc_cur_pos_reply * curpos,
struct esense_reply * erp)
{
struct scsi_req sr;
struct sc_reply scrp;
struct read_subchannel_42_cmd *rscp;
u_int tempUint;
int err;
bzero((char *)&sr, sizeof(sr));
bzero((char *)&scrp, sizeof(scrp));
rscp = (struct read_subchannel_42_cmd *) & sr.sr_cdb;
rscp->rsc_op_code = C10OP_READSUBCHANNEL_42;
rscp->rsc_msf = 1; /* want MSF (not LBA) format for times */
rscp->rsc_subq = 1; /* want to get Q subchannel data */
rscp->rsc_dformat = 1; /* want page 1 of Q subchannel data */
rscp->rsc_track = 0; /* track is irrelevent for page 1 req */
SET_2BYTE_UINT(rscp->rsc_length, sizeof(struct sc_reply));
sr.sr_addr = (char *)&scrp;
sr.sr_dma_max = sizeof(struct sc_reply);
sr.sr_ioto = 5; /* time out in 5 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
*erp = sr.sr_esense;
curpos->track = scrp.u.u_scr_cur_pos.sc1_track;
curpos->index = scrp.u.u_scr_cur_pos.sc1_index;
curpos->rsc_control = scrp.u.u_scr_cur_pos.sc1_control;
curpos->rsc_audio_status = scrp.scr_header.sch_astatus;
if (rscp->rsc_msf == 1) { /* ie, msf formatted times */
curpos->abs_logical_block = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.sec
+ (scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.min * 60)
+ (scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.hour * 3600);
curpos->abs_logical_block = (curpos->abs_logical_block * 75)
+ scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.frame;
curpos->abs_hour = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.hour;
curpos->abs_min = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.min;
curpos->abs_sec = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.sec;
curpos->abs_frame = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.frame;
if (curpos->abs_min >= 60) {
curpos->abs_hour++;
curpos->abs_min -= 60;
}
curpos->rel_logical_block = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.sec
+ (scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.min * 60)
+ (scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.hour * 3600);
curpos->rel_logical_block = (curpos->rel_logical_block * 75)
+ scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.frame;
curpos->rel_hour = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.hour;
curpos->rel_min = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.min;
curpos->rel_sec = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.sec;
curpos->rel_frame = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.frame;
if (curpos->rel_min >= 60) {
curpos->rel_hour++;
curpos->rel_min -= 60;
}
} else { /* ie, lba formatted times */
tempUint = GET_4BYTE_UINT(scrp.u.u_scr_cur_pos.sc1_abs_addr.lba.lblock);
curpos->abs_logical_block = tempUint;
curpos->abs_frame = tempUint % 75;
curpos->abs_sec = tempUint / 75;
curpos->abs_min = curpos->abs_sec / 60;
curpos->abs_sec = curpos->abs_sec % 60;
if (curpos->abs_min >= 60) {
curpos->abs_hour++;
curpos->abs_min -= 60;
}
tempUint = GET_4BYTE_UINT(scrp.u.u_scr_cur_pos.sc1_rel_addr.lba.lblock);
curpos->rel_logical_block = tempUint;
curpos->rel_frame = tempUint % 75;
curpos->rel_sec = tempUint / 75;
curpos->rel_min = curpos->rel_sec / 60;
curpos->rel_sec = curpos->rel_sec % 60;
if (curpos->rel_min >= 60) {
curpos->rel_hour++;
curpos->rel_min -= 60;
}
}
return err | sr.sr_io_status;
}
/**************************************************************************
* do_readmediacatnum_42
*
* This is really the "read sub-channel data" command with a few of
* the fields automatically filled in.
*/
int
do_readmediacatnum_42(int fd, struct rsc_media_catnum_reply * catnum,
struct esense_reply * erp)
{
struct scsi_req sr;
struct sc_reply scrp;
struct read_subchannel_42_cmd *rscp;
int err;
bzero((char *)&sr, sizeof(sr));
bzero((char *)&scrp, sizeof(scrp));
rscp = (struct read_subchannel_42_cmd *) & sr.sr_cdb;
rscp->rsc_op_code = C10OP_READSUBCHANNEL_42;
rscp->rsc_msf = 0; /* MSF format is irrelevent for this */
rscp->rsc_subq = 1; /* want to get Q subchannel data */
rscp->rsc_dformat = 2; /* want page 2 of Q subchannel data */
rscp->rsc_track = 0; /* track is irrelevent for page 2 req */
SET_2BYTE_UINT(rscp->rsc_length, sizeof(struct sc_reply));
sr.sr_addr = (char *)&scrp;
sr.sr_dma_max = sizeof(struct sc_reply);
sr.sr_ioto = 10; /* time out in 10 seconds */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
*erp = sr.sr_esense;
catnum->catnum_isSet = scrp.u.u_scr_med_cat.sc2_mcval;
memcpy(catnum->media_catnum, scrp.u.u_scr_med_cat.sc2_med_cat, 15);
/*
* note that many CDs have mcval set on, but the media-cat# is zero... Also
* note that different drives return the media-cat# in different formats...
*/
bzero((char *)&scrp.u.u_scr_med_cat.sc2_med_cat, 15); /* = no catnum */
if (!memcmp(catnum->media_catnum, scrp.u.u_scr_med_cat.sc2_med_cat, 15))
catnum->catnum_isSet = 0;
if (!memcmp(catnum->media_catnum, "000000000000000", 15))
catnum->catnum_isSet = 0;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_playbackstatus_c4
*
* Find out the position and status (playing, paused, whatever) of
* the CD drive. Also picks up the current volume settings. Note
* that this is probably Sony-specific.
*/
int
do_playbackstatus_c4(int fd, struct pb_status_reply * pbstatus,
struct esense_reply * erp)
{
struct scsi_req sr;
struct playback_statuscontrol_cmd *pbcp;
struct playback_c4c9_data pbdata;
u_int tempUint;
int err;
bzero((char *)&sr, sizeof(sr));
pbcp = (struct playback_statuscontrol_cmd *) & sr.sr_cdb;
pbcp->pb_opcode = C10OP_PLAYBACKSTATUS_C4;
SET_2BYTE_UINT(pbcp->pb_length, sizeof(struct playback_c4c9_data));
bzero((char *)&pbdata, sizeof(pbdata));
sr.sr_addr = (char *)&pbdata;
sr.sr_dma_max = sizeof(struct playback_c4c9_data);
sr.sr_ioto = 1; /* time out in 1 second */
sr.sr_dma_dir = SR_DMA_RD;
err = ioctl(fd, SDIOCSRQ, &sr);
*erp = sr.sr_esense;
/*
* copy information from platform-specific (bigendian) layout to one that
* matches the current platform
*/
bzero((char *)pbstatus, sizeof(struct pb_status_reply));
pbstatus->pbs_audio_status = pbdata.pbd_audio_status;
pbstatus->pbs_ch0_sel = pbdata.pbd_ch0_sel;
pbstatus->pbs_ch0_vol = pbdata.pbd_ch0_vol;
pbstatus->pbs_ch1_sel = pbdata.pbd_ch1_sel;
pbstatus->pbs_ch1_vol = pbdata.pbd_ch1_vol;
pbstatus->pbs_ch2_sel = pbdata.pbd_ch2_sel;
pbstatus->pbs_ch2_vol = pbdata.pbd_ch2_vol;
pbstatus->pbs_ch3_sel = pbdata.pbd_ch3_sel;
pbstatus->pbs_ch3_vol = pbdata.pbd_ch3_vol;
/* the cd-address is returned in both addressing formats */
if (pbdata.pbd_lbamsf == 1) { /* ie, msf formatted times */
if (pbdata.pbd_cd_addr.msf.min == 255) {
/* if min = 255, then we're really before the */
/* start of the first track... */
pbdata.pbd_cd_addr.msf.min = 0;
pbdata.pbd_cd_addr.msf.sec = 0;
pbdata.pbd_cd_addr.msf.frame = 75 - pbdata.pbd_cd_addr.msf.frame;
}
pbstatus->pbs_logical_block = pbdata.pbd_cd_addr.msf.sec
+ (pbdata.pbd_cd_addr.msf.min * 60)
+ (pbdata.pbd_cd_addr.msf.hour * 3600);
pbstatus->pbs_logical_block = (pbstatus->pbs_logical_block * 75)
+ pbdata.pbd_cd_addr.msf.frame;
pbstatus->pbs_hour = pbdata.pbd_cd_addr.msf.hour;
pbstatus->pbs_min = pbdata.pbd_cd_addr.msf.min;
pbstatus->pbs_sec = pbdata.pbd_cd_addr.msf.sec;
pbstatus->pbs_frame = pbdata.pbd_cd_addr.msf.frame;
if (pbstatus->pbs_min >= 60) {
pbstatus->pbs_hour++;
pbstatus->pbs_min -= 60;
}
} else { /* ie, lba formatted times */
tempUint = GET_4BYTE_UINT(pbdata.pbd_cd_addr.lba.lblock);
pbstatus->pbs_logical_block = tempUint;
pbstatus->pbs_frame = tempUint % 75;
pbstatus->pbs_sec = tempUint / 75;
pbstatus->pbs_min = pbstatus->pbs_sec / 60;
pbstatus->pbs_sec = pbstatus->pbs_sec % 60;
if (pbstatus->pbs_min == 255) {
/* if min = 255, then we're really before the */
/* start of the first track... */
pbstatus->pbs_min = 0;
pbstatus->pbs_sec = 0;
pbstatus->pbs_frame = 75 - pbstatus->pbs_frame;
pbstatus->pbs_logical_block = pbstatus->pbs_frame;
}
if (pbstatus->pbs_min >= 60) {
pbstatus->pbs_hour++;
pbstatus->pbs_min -= 60;
}
}
return err | sr.sr_io_status;
}
/**************************************************************************
* do_playbackvolume_c9
*
* Change the current volume settings, using the playback control
* command (which is probably Sony-specific).
*/
int
do_playbackvolume_c9(int fd, int leftVolume, int rightVolume,
struct esense_reply * erp)
{
struct scsi_req sr;
struct playback_statuscontrol_cmd *pbcp;
struct playback_c4c9_data pbdata;
int err;
bzero((char *)&sr, sizeof(sr));
pbcp = (struct playback_statuscontrol_cmd *) & sr.sr_cdb;
pbcp->pb_opcode = C10OP_PLAYBACKCONTROL_C9;
SET_2BYTE_UINT(pbcp->pb_length, sizeof(struct playback_c4c9_data));
bzero((char *)&pbdata, sizeof(pbdata));
pbdata.pbd_ch0_sel = 1;
pbdata.pbd_ch0_vol = leftVolume;
pbdata.pbd_ch1_sel = 2;
pbdata.pbd_ch1_vol = rightVolume;
sr.sr_addr = (char *)&pbdata;
sr.sr_dma_max = sizeof(struct playback_c4c9_data);
sr.sr_ioto = 1; /* time out in 1 second */
sr.sr_dma_dir = SR_DMA_WR;
err = ioctl(fd, SDIOCSRQ, &sr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_modesense_pc_E
*
* This is just the do_modesense command from scsi_commands, except
* that it's setup to return page-code E in particular. Page-code E
* is the one for CD-ROM Audio Control parameters. Declarations of
* some structs are also redone (and in cd_cmdsint.h) to make them
* more platform-independent.
*/
int
do_modesense_pc_E(int fd, struct cd_volset_reply * volset, struct esense_reply * erp)
{
struct scsi_req sr;
struct mode_sense_select_cmd *mscp;
struct mode_sense_select_reply msrp;
int err;
bzero((char *)&sr, sizeof(sr));
bzero((char *)&msrp, sizeof(msrp));
mscp = (struct mode_sense_select_cmd *) & sr.sr_cdb;
mscp->msc_opcode = C6OP_MODESENSE;
mscp->msc_lun = 0;
mscp->msc_pcf = 0; /* report current values */
mscp->msc_page = 0x0E;
mscp->msc_len = sizeof(msrp);
sr.sr_addr = (char *)&msrp;
sr.sr_dma_max = sizeof(msrp);
sr.sr_ioto = 50; /* using an extended timeout */
sr.sr_dma_dir = SR_DMA_RD; /* read &sr.sr_addr from device */
err = ioctl(fd, SDIOCSRQ, &sr);
*erp = sr.sr_esense;
/*
* copy information from platform-specific (bigendian) layout to one that
* matches the current platform
*/
bzero((char *)volset, sizeof(struct cd_volset_reply));
volset->ch0_sel = msrp.u.u_msr_pcE.pce_ch0_sel;
volset->ch0_vol = msrp.u.u_msr_pcE.pce_ch0_vol;
volset->ch1_sel = msrp.u.u_msr_pcE.pce_ch1_sel;
volset->ch1_vol = msrp.u.u_msr_pcE.pce_ch1_vol;
volset->ch2_sel = msrp.u.u_msr_pcE.pce_ch2_sel;
volset->ch2_vol = msrp.u.u_msr_pcE.pce_ch2_vol;
volset->ch3_sel = msrp.u.u_msr_pcE.pce_ch3_sel;
volset->ch3_vol = msrp.u.u_msr_pcE.pce_ch3_vol;
return err | sr.sr_io_status;
}
/**************************************************************************
* do_modeselect_pc_E
*
* This is basically just the do_modesense_pc_E command reversed,
* such that CD volume settings are being set instead of sensed.
*/
int
do_modeselect_pc_E(int fd, int leftVolume, int rightVolume, struct esense_reply * erp)
{
struct scsi_req sr;
struct mode_sense_select_cmd *mscp;
struct mode_select_alt_reply msarp;
int err;
bzero((char *)&sr, sizeof(sr));
mscp = (struct mode_sense_select_cmd *) & sr.sr_cdb;
mscp->msc_opcode = C6OP_MODESELECT;
mscp->msc_lun = 0;
mscp->msc_len = sizeof(msarp);
mscp->msc_pf = 1;
sr.sr_addr = (char *)&msarp;
sr.sr_dma_max = sizeof(msarp);
sr.sr_ioto = 50; /* using an extended timeout */
sr.sr_dma_dir = SR_DMA_WR; /* write &sr.sr_addr to device */
bzero((char *)&msarp, sizeof(msarp));
msarp.msar_plh.plh_blkdesclen = 0; /* using alternate form, with no
* block descriptor */
msarp.u.u_msar_pcE.pce_pagecode = 0x0E;
msarp.u.u_msar_pcE.pce_parlen = 0x0E;
msarp.u.u_msar_pcE.pce_immd = YES;
msarp.u.u_msar_pcE.pce_ch0_sel = 1;
msarp.u.u_msar_pcE.pce_ch0_vol = leftVolume;
msarp.u.u_msar_pcE.pce_ch1_sel = 2;
msarp.u.u_msar_pcE.pce_ch1_vol = rightVolume;
err = ioctl(fd, SDIOCSRQ, &sr);
*erp = sr.sr_esense;
return err | sr.sr_io_status;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.