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->firstCDtrack = tocr.h.rtr_firsttrack; toc_all->lastCDtrack = 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; toc_all->firstAtrack = 255; toc_all->lastAtrack = 0; 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++; if (toc_all->firstAtrack > track) toc_all->firstAtrack = track; toc_all->lastAtrack = track; } 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.