This is playcd.c in view mode; [Download] [Up]
/* -*-C-*-
*******************************************************************************
*
* File: play3401.c
* RCS: /usr/local/lib/cvs/play3401/play3401.c,v 1.3 1994/03/03 19:10:36 cedman Exp
* Description: Play Toshiba 3401
* Author: Carl Edman
* Created: Wed May 5 21:34:47 1993
* Modified: Thu Mar 3 13:48:25 1994 (Carl Edman) cedman@capitalist.princeton.edu
* Modified: Sat Apr 08 1995 (Juergen Sell) js@icem.de
+ support the NEC player (3Xi that is, if it matters)
+ force search for drive to begin at /dev/sd2 hardcoded
(this should become a paramter)
* Modified Sat Apr 08 1995 js
+ support -d<number> parameter to set start search device
to /dev/sd<number>
* Modified Wed Apr 12 1995 js
+ added -l option to produce frames-listing
+ incorporated toshiba and nec support in a single source
* Language: C
* Package: N/A
* Status: Alpha
*
* (C) Copyright 1993, but otherwise this file is perfect freeware.
*
*******************************************************************************
*/
/* define exactly one of the following */
#if (0) /* Toshiba 3401 */
#define TOSHIBA
#define NO_TRACK (0xaa)
#define OPCODE (0x28)
#define CONTROL (1<<6)
#define DEVICE "TOSHIBA CD-ROM XM-3401TA" /* or try "TOSHIBA CD-ROM XM-4101TA" */
#define LBA (BCD((rp+offset)/(75*60))<<24)+(BCD(((rp+offset)/75)%60)<<16)+(BCD((rp+offset)%75)<<8)
#else if (0) /* nec 3x */
#define NO_TRACK (0xA2)
#define OPCODE (0xD4)
#define CONTROL (0)
#define DEVICE "NEC CD-ROM DRIVE:500"
#define LBA (rp+offset)
#endif
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <libc.h>
#include <signal.h>
#include <errno.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <sound/sound.h>
#include <sound/sounddriver.h>
#include <sound/utilsound.h>
#include "scsicommands.h"
#define BCD(c) (((c)%10)+((((c)/10)%10)<<4))
#define BLOCKSIZE (2352)
#define BUFBLOCK (6*75)
#define READBLOCK (27)
#define TRACKNO (100)
#define GETNO() for(c=0;isascii(*d) && isdigit(*d);d++) c= (c*10)+(*d-'0')
struct Mode
{
u_int data_length:8,
medium_type:8,
dev_parameter:8,
bdescriptor_length:8;
u_int density:8,
nblocks:24;
u_int mbz1:8,
block_length:24;
};
struct Toc_track_descriptor
{
u_int mbz1:8,
adr:4,
control:4,
track_number:8,
mbz2:8;
u_int address;
};
struct Toc
{
u_int toc_data_length:16,
first:8,
last:8;
struct Toc_track_descriptor track[TRACKNO];
};
volatile int done,fillup;
volatile int readp,playp;
port_t devicePort,ownerPort,streamPort,replyPort;
condition_t sync_threads;
mutex_t position;
cthread_t play_t;
char *buf;
struct Toc toc;
int errflg=0,dontejectflg=0,recordflg=0,playflg=0;
extern int getopt(int ac,char *av[],char *opts);
extern int optind;
extern char *optarg;
int interpret_duration(const char *str,int *sf,int *ef)
{
int c,i;
const char *d;
for(i=0,d=str;*d;d++) if (*d=='-') i++;
if (i>1) return -1;
d=str;
if (*d=='#')
{
d++;
GETNO();
for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==c) break;
if (i>=TRACKNO) return -1;
*sf=toc.track[i].address;
if (*d=='+') d++;
}
else
{
*sf=toc.track[0].address;
}
if (*d && *d!='-')
{
GETNO();
if (*d==':')
{
d++;
*sf+=c*60*75;
GETNO();
if (c>=60) return -1;
*sf+=c*75;
if (*d==':')
{
d++;
GETNO(); if (c>=75) return -1;
*sf+=c;
}
}
else
{
*sf+=c;
}
}
if (!*d) d=str; else if (*d=='-') d++; else return -1;
if (*d=='#')
{
d++;
GETNO();
for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==c) break;
if (i>=TRACKNO) return -1;
if (*d=='+')
{
*ef=toc.track[i].address;
d++;
}
else
{
*ef=toc.track[i+1].address;
}
}
else if (*d=='\0')
{
for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==NO_TRACK) break;
if (i>=TRACKNO) return -1;
*ef=toc.track[i].address;
}
else
{
*ef=toc.track[0].address;
}
if (*d && *d!='-')
{
GETNO();
if (*d==':')
{
d++;
*ef+=c*60*75;
GETNO(); if (c>=60) return -1;
*ef+=c*75;
if (*d==':')
{
d++;
GETNO(); if (c>=75) return -1;
*ef+=c+1;
}
else
{
*ef+=75;
}
}
else
{
*ef+=c+1;
}
}
if (*d && *d!=-1) return -1;
if (*sf<toc.track[0].address) return -1;
for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==NO_TRACK) break;
if (i>=TRACKNO) return -1;
if (*ef>toc.track[i].address) return -1;
return (*sf<*ef);
}
void play_suspend(int sig)
{
snddriver_stream_control(streamPort,0,SNDDRIVER_PAUSE_STREAM);
signal(sig,SIG_DFL);
raise(sig);
}
void play_continue(int sig)
{
signal(SIGTSTP,play_suspend);
snddriver_stream_control(streamPort,0,SNDDRIVER_RESUME_STREAM);
}
void setdone(int sig)
{
snddriver_stream_control(streamPort,0,SNDDRIVER_ABORT_STREAM);
done=1;
}
void play_completed(void *arg,int tag)
{
playp=tag;
}
any_t play_thread(any_t arg)
{
int rp,pp,tp,ep;
unsigned short *p,*e,*r;
int protocol=0;
int err;
snddriver_handlers_t handlers = { 0,0,0,play_completed,0,0,0,0,0,0,0,0 };
msg_header_t *replyMsg = 0;
if (playflg)
{
replyMsg=malloc(MSG_SIZE_MAX);
port_allocate(task_self(),&replyPort);
SNDAcquire(SND_ACCESS_OUT,10,0,0,0,0,&devicePort,&ownerPort);
snddriver_stream_setup(devicePort,ownerPort,SNDDRIVER_STREAM_TO_SNDOUT_44,vm_page_size/2,2,176400,352800,&protocol,&streamPort);
}
mutex_lock(position);
tp=readp;
while(!done)
{
while (!done && ((fillup && (readp<playp+(BUFBLOCK*3)/4))||
(!fillup && (readp<=tp))))
condition_wait(sync_threads,position);
fillup=0;
rp=readp; pp=playp;
mutex_unlock(position);
ep=tp;
while (tp<rp)
{
ep=tp+75;
if (ep>rp) ep=rp;
if (tp%BUFBLOCK+(ep-tp)>BUFBLOCK) ep=tp+BUFBLOCK-(tp%BUFBLOCK);
p=(unsigned short *)(buf+((tp%BUFBLOCK)*BLOCKSIZE));
e=(unsigned short *)(buf+((((ep-1)%BUFBLOCK)+1)*BLOCKSIZE));
for(r=p;r<e;r++) *r=NXSwapShort(*r);
if (playflg)
err=snddriver_stream_start_writing(streamPort,
p,e-p,
ep,
0,0,
0,1,0,0,0,0,
replyPort);
if (recordflg) write(1,p,(e-p)*sizeof(*p));
tp=ep;
}
mutex_lock(position);
if (playflg)
{
replyMsg->msg_size=MSG_SIZE_MAX;
replyMsg->msg_local_port=replyPort;
while (msg_receive(replyMsg, RCV_TIMEOUT,0)==RCV_SUCCESS)
{
err=snddriver_reply_handler(replyMsg,&handlers);
if (playp>=tp) fillup=1;
condition_broadcast(sync_threads);
}
}
else
{
playp=ep;
condition_broadcast(sync_threads);
}
}
done=1;
mutex_unlock(position);
if (playflg)
{
free(replyMsg);
port_deallocate(task_self(),replyPort);
SNDRelease(SND_ACCESS_OUT,devicePort,ownerPort);
}
return arg;
}
int main(int ac,char *av[])
{
int c;
int startframe,endframe;
struct Mode page,opage;
int aDeviceId= 0;
int listFlag= 0;
while((c=getopt(ac,av,"leprd:"))!=EOF) switch(c)
{
case 'l':
listFlag++;
break;
case 'e':
dontejectflg++;
break;
case 'p':
playflg++;
break;
case 'r':
recordflg++;
break;
case 'd':
if (!sscanf( optarg, "%d", &aDeviceId) ) errflg++;
break;
case '?':
default:
errflg++;
}
if (geteuid())
{
fprintf(stderr,"%s was not installed SUID root.\n",av[0]);
exit(1);
}
if (errflg)
{
fprintf(stderr,"Usage: %s [-l] [-e] [-r] [-p] [-d<n>] duration ...\n",av[0]);
exit(2);
}
if (playflg==0 && recordflg==0)
playflg++;
position=mutex_alloc();
sync_threads=condition_alloc();
signal(SIGHUP ,setdone); signal(SIGINT ,setdone); signal(SIGQUIT,setdone);
signal(SIGILL ,setdone); signal(SIGTRAP,setdone); signal(SIGIOT ,setdone);
signal(SIGEMT ,setdone); signal(SIGFPE ,setdone); signal(SIGBUS ,setdone);
signal(SIGSEGV,setdone); signal(SIGSYS ,setdone); signal(SIGPIPE,setdone);
signal(SIGTERM,setdone); signal(SIGXCPU,setdone); signal(SIGXFSZ,setdone);
signal(SIGTSTP,play_suspend); signal(SIGCONT,play_continue);
scsisettimeout(10); //js origianl 10
if (scsigetdev(DEVICE, aDeviceId)==-1) //js, begin at /dev/sd2
{
fprintf(stderr,"Can't find CD player -- this version of %s is compiled for %s only.\n",av[0], DEVICE); //js
exit(3);
}
if (scsiread6s(&opage,sizeof(opage),0x1a,0,0,0,sizeof(opage),0))
{
fprintf(stderr,"Can't read mode page.\n");
exit(4);
}
opage.data_length=0;
page=opage;
page.density=0x82;
page.block_length=0x930;
#ifdef TOSHIBA
if (scsiwrite6s(&page,sizeof(page),0x15,0,0,0,sizeof(page),0))
{
fprintf(stderr,"Can't write mode page.\n");
exit(5);
}
#endif
buf=malloc(BUFBLOCK*BLOCKSIZE);
done=0;
fillup=1;
if (scsiread10(&toc,sizeof(toc),0x43,0,0,0,1,0,0,0,sizeof(toc),0))
{
fprintf(stderr,"Can't read CDs table of contents.\n");
goto end;
}
for(c=0;c<TRACKNO;c++)
{
int i=toc.track[c].address;
toc.track[c].address=(i&0xff)+75*((i>>8)&0xff)+75*60*((i>>16)&0xff);
if (listFlag /* > 0 */) {
if (toc.track[c].track_number != 0) fprintf(stderr, "[%d] %d\n", toc.track[c].track_number, toc.track[c].address/75);
}
}
setpriority(PRIO_PROCESS,0,-10);
playp=readp=0;
play_t=cthread_fork(play_thread,0);
if (recordflg)
{
SNDSoundStruct sndheader;
sndheader.magic=SND_MAGIC;
sndheader.dataLocation=28;
sndheader.dataSize=0; /* a lie, but /usr/bin/sndplay dosen't care */
sndheader.dataFormat=SND_FORMAT_LINEAR_16;
sndheader.samplingRate=SND_RATE_HIGH;
sndheader.channelCount=2;
sndheader.info[0]=0;
sndheader.info[1]=0;
sndheader.info[2]=0;
sndheader.info[3]=0;
write(1,&sndheader,28); /* write 28-byte header */
}
for(c=optind;(c<ac) && !done;c++)
{
int offset,rp,pp,ep;
if (!strcmp(av[c],"repeat"))
{
if (c==optind)
{
fprintf(stderr,"No durations before repeat\n");
continue;
}
c=optind;
}
if (interpret_duration(av[c],&startframe,&endframe)==-1)
{
fprintf(stderr,"Bad duration specificitation: %s\n",av[c]);
continue;
}
mutex_lock(position);
offset=startframe-readp;
startframe-=offset;
endframe-=offset;
while(!done && readp<endframe)
{
while ((playp+BUFBLOCK<=readp) && !done) condition_wait(sync_threads,position);
rp=readp; pp=playp;
ep=rp+READBLOCK;
if (ep>endframe) ep=endframe;
if (rp%BUFBLOCK+(ep-rp)>BUFBLOCK) ep=rp+BUFBLOCK-(rp%BUFBLOCK);
if (pp+BUFBLOCK<ep) ep=pp+BUFBLOCK;
if (ep>rp)
{
mutex_unlock(position);
if (scsiread10(buf+(rp%BUFBLOCK)*BLOCKSIZE,(ep-rp)*BLOCKSIZE,OPCODE,0,0,0,0,0,LBA,0,ep-rp,CONTROL)) goto end;
mutex_lock(position);
rp=readp=ep;
condition_broadcast(sync_threads);
}
}
mutex_unlock(position);
}
end:
done=1;
condition_broadcast(sync_threads);
cthread_join(play_t);
#ifdef TOSHIBA
if (scsiwrite6s(&opage,sizeof(opage),0x15,0,0,0,sizeof(opage),0))
{
fprintf(stderr,"Can't reset mode page.\n");
}
#endif
if (scsiclose(!dontejectflg))
{
fprintf(stderr,"Can't eject CD.\n");
}
exit(0);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.