summaryrefslogtreecommitdiff
path: root/emu/Hp
diff options
context:
space:
mode:
Diffstat (limited to 'emu/Hp')
-rw-r--r--emu/Hp/NOTE1
-rw-r--r--emu/Hp/asm-s800.s113
-rw-r--r--emu/Hp/cmd.c205
-rw-r--r--emu/Hp/devaudio.c506
-rw-r--r--emu/Hp/devfs.c1
-rw-r--r--emu/Hp/emu107
-rw-r--r--emu/Hp/mkfile50
-rw-r--r--emu/Hp/mkfile-Hp13
-rw-r--r--emu/Hp/os.c591
9 files changed, 1587 insertions, 0 deletions
diff --git a/emu/Hp/NOTE b/emu/Hp/NOTE
new file mode 100644
index 00000000..3f1041ea
--- /dev/null
+++ b/emu/Hp/NOTE
@@ -0,0 +1 @@
+this, like Irix, lacks deveia
diff --git a/emu/Hp/asm-s800.s b/emu/Hp/asm-s800.s
new file mode 100644
index 00000000..865c0b2b
--- /dev/null
+++ b/emu/Hp/asm-s800.s
@@ -0,0 +1,113 @@
+;
+; /*
+; * To get lock routine, compile this into a .s, then SUBSTITUTE
+; * a LOAD AND CLEAR WORD instruction for the load and store of
+; * l->key.
+; *
+; */
+; typedef struct Lock {
+; int key;
+; int pid;
+; } Lock;
+;
+; int
+; mutexlock(Lock *l)
+; {
+; int key;
+;
+; key = l->key;
+; l->key = 0;
+; return key != 0;
+; }
+
+ .LEVEL 1.1
+
+ .SPACE $TEXT$,SORT=8
+ .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=0x2c,CODE_ONLY,SORT=24
+mutexlock
+ .PROC
+ .CALLINFO FRAME=0,ARGS_SAVED
+ .ENTRY
+; SUBSTITUTED LDW 0(%r26),%r31
+; SUBSTITUTED STWS %r0,0(%r26)
+ LDCWS 0(%r26),%r31 ; SUBSTITUTED
+ COMICLR,= 0,%r31,%r28
+ LDI 1,%r28
+ .EXIT
+ BV,N %r0(%r2)
+ .PROCEND
+
+;
+; JIT help
+;
+ .SPACE $TEXT$,SORT=8
+ .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=0x2c,CODE_ONLY,SORT=24
+calldata
+ .PROC
+ .CALLINFO CALLER,FRAME=16,SAVE_RP
+ .ENTRY
+ STW %r2,-20(%r30)
+ LDO 64(%r30),%r30
+ ADDIL LR'dataptr-$global$,%r27
+ LDW RR'dataptr-$global$(%r1),%r31
+ BLE 0(%sr5,%r31)
+ COPY %r31,%r2
+ LDW -84(%r30),%r2
+ BV %r0(%r2)
+ .EXIT
+ LDO -64(%r30),%r30
+ .PROCEND
+
+ .SPACE $PRIVATE$
+ .SUBSPA $SHORTBSS$
+dataptr .COMM 4
+ .SUBSPA $SHORTDATA$,QUAD=1,ALIGN=8,ACCESS=0x1f,SORT=24
+dyncall
+ .WORD $$dyncall
+ .EXPORT calldata
+ .EXPORT dyncall
+ .IMPORT $$dyncall,MILLICODE
+
+ .SPACE $TEXT$
+ .SUBSPA $CODE$
+ .SPACE $PRIVATE$,SORT=16
+ .SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=0x1f,SORT=16
+ .SPACE $TEXT$
+ .SUBSPA $CODE$
+ .EXPORT mutexlock,ENTRY,PRIV_LEV=3,ARGW0=GR,RTNVAL=GR
+
+ .code
+; segflush(addr,len)
+ .proc
+ .callinfo
+ .export segflush,entry
+segflush
+ .enter
+ ldsid (0,%arg0),%r1
+ mtsp %r1,%sr0
+ ldo -1(%arg1),%arg1
+ copy %arg0,%arg2
+ copy %arg1,%arg3
+ fdc %arg1(0,%arg0)
+
+loop1
+ addib,>,n -16,%arg1,loop1
+ fdc %arg1(0,%arg0)
+ fdc 0(0,%arg0)
+ sync
+ fic %arg3(%sr0,%arg2)
+loop2
+ addib,>,n -16,%arg3,loop2
+ fic %arg3(%sr0,%arg2)
+ fic 0(%sr0,%arg2)
+ sync
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ .leave
+ .procend
+ .end
diff --git a/emu/Hp/cmd.c b/emu/Hp/cmd.c
new file mode 100644
index 00000000..97e303ac
--- /dev/null
+++ b/emu/Hp/cmd.c
@@ -0,0 +1,205 @@
+#include <sys/types.h>
+#include <signal.h>
+#include <pwd.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+
+enum
+{
+ Debug = 0
+};
+
+/*
+ * os-specific devcmd support.
+ * this version should be reasonably portable across Unix systems.
+ */
+typedef struct Targ Targ;
+struct Targ
+{
+ int fd[2]; /* fd[0] is standard input, fd[1] is standard output */
+ char** args;
+ char* dir;
+ int pid;
+ int wfd; /* child writes errors that occur after the fork or on exec */
+ int uid;
+ int gid;
+};
+
+extern int gidnobody;
+extern int uidnobody;
+
+static int
+childproc(Targ *t)
+{
+ int i, nfd;
+
+ if(Debug)
+ print("devcmd: '%s'", t->args[0]);
+
+ nfd = getdtablesize();
+ for(i = 0; i < nfd; i++)
+ if(i != t->fd[0] && i != t->fd[1] && i != t->wfd)
+ close(i);
+
+ dup2(t->fd[0], 0);
+ dup2(t->fd[1], 1);
+ dup2(t->fd[1], 2);
+ close(t->fd[0]);
+ close(t->fd[1]);
+
+ if(t->gid != -1){
+ if(setgid(t->gid) < 0 && getegid() == 0){
+ fprint(t->wfd, "can't set gid %d: %s", t->gid, strerror(errno));
+ _exit(1);
+ }
+ }
+
+ if(t->uid != -1){
+ if(setuid(t->uid) < 0 && geteuid() == 0){
+ fprint(t->wfd, "can't set uid %d: %s", t->uid, strerror(errno));
+ _exit(1);
+ }
+ }
+
+ if(t->dir != nil && chdir(t->dir) < 0){
+ fprint(t->wfd, "can't chdir to %s: %s", t->dir, strerror(errno));
+ _exit(1);
+ }
+
+ signal(SIGPIPE, SIG_DFL);
+
+ execvp(t->args[0], t->args);
+ if(Debug)
+ print("execvp: %s\n",strerror(errno));
+ fprint(t->wfd, "exec failed: %s", strerror(errno));
+
+ _exit(1);
+}
+
+void*
+oscmd(char **args, int nice, char *dir, int *rfd, int *sfd)
+{
+ Dir *d;
+ Targ *t;
+ int r, fd0[2], fd1[2], wfd[2], n, pid;
+
+ t = mallocz(sizeof(*t), 1);
+ if(t == nil)
+ return nil;
+
+ fd0[0] = fd0[1] = -1;
+ fd1[0] = fd1[1] = -1;
+ wfd[0] = wfd[1] = -1;
+ if(pipe(fd0) < 0 || pipe(fd1) < 0 || pipe(wfd) < 0)
+ goto Error;
+ if(fcntl(wfd[1], F_SETFD, FD_CLOEXEC) < 0) /* close on exec to give end of file on success */
+ goto Error;
+
+ t->fd[0] = fd0[0];
+ t->fd[1] = fd1[1];
+ t->wfd = wfd[1];
+ t->args = args;
+ t->dir = dir;
+ t->gid = up->env->gid;
+ if(t->gid == -1)
+ t->gid = gidnobody;
+ t->uid = up->env->uid;
+ if(t->uid == -1)
+ t->uid = uidnobody;
+
+ signal(SIGCHLD, SIG_DFL);
+ switch(pid = fork()) {
+ case -1:
+ goto Error;
+ case 0:
+ setpgrp();
+ if(nice)
+ oslopri();
+ childproc(t);
+ _exit(1);
+ default:
+ t->pid = pid;
+ if(Debug)
+ print("cmd pid %d\n", t->pid);
+ break;
+ }
+
+ close(fd0[0]);
+ close(fd1[1]);
+ close(wfd[1]);
+
+ n = read(wfd[0], up->genbuf, sizeof(up->genbuf)-1);
+ close(wfd[0]);
+ if(n > 0){
+ close(fd0[1]);
+ close(fd1[0]);
+ free(t);
+ up->genbuf[n] = 0;
+ if(Debug)
+ print("oscmd: bad exec: %q\n", up->genbuf);
+ error(up->genbuf);
+ return nil;
+ }
+
+ *sfd = fd0[1];
+ *rfd = fd1[0];
+ return t;
+
+Error:
+ r = errno;
+ if(Debug)
+ print("oscmd: %q\n",strerror(r));
+ close(fd0[0]);
+ close(fd0[1]);
+ close(fd1[0]);
+ close(fd1[1]);
+ close(wfd[0]);
+ close(wfd[1]);
+ error(strerror(r));
+ return nil;
+}
+
+int
+oscmdkill(void *a)
+{
+ Targ *t = a;
+
+ if(Debug)
+ print("kill: %d\n", t->pid);
+ return kill(-t->pid, SIGTERM);
+}
+
+int
+oscmdwait(void *a, char *buf, int n)
+{
+ Targ *t = a;
+ int s;
+
+ if(waitpid(t->pid, &s, 0) == -1){
+ if(Debug)
+ print("wait error: %d [in %d] %q\n", t->pid, getpid(), strerror(errno));
+ return -1;
+ }
+ if(WIFEXITED(s)){
+ if(WEXITSTATUS(s) == 0)
+ return snprint(buf, n, "%d 0 0 0 ''", t->pid);
+ return snprint(buf, n, "%d 0 0 0 'exit: %d'", t->pid, WEXITSTATUS(s));
+ }
+ if(WIFSIGNALED(s)){
+ if(WTERMSIG(s) == SIGTERM || WTERMSIG(s) == SIGKILL)
+ return snprint(buf, n, "%d 0 0 0 killed", t->pid);
+ return snprint(buf, n, "%d 0 0 0 'signal: %d'", t->pid, WTERMSIG(s));
+ }
+ return snprint(buf, n, "%d 0 0 0 'odd status: 0x%x'", t->pid, s);
+}
+
+void
+oscmdfree(void *a)
+{
+ free(a);
+}
diff --git a/emu/Hp/devaudio.c b/emu/Hp/devaudio.c
new file mode 100644
index 00000000..c26143e3
--- /dev/null
+++ b/emu/Hp/devaudio.c
@@ -0,0 +1,506 @@
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+
+#include <sys/audio.h>
+
+
+enum{
+ Qdir,
+ Qaudio,
+ Qaudioctl, /* deprecated */
+ Qvolume,
+
+ Fmono = 1,
+ Fin = 2,
+ Fout = 4,
+ Fhearn = 8,
+
+ Vaudio = 0,
+ Vsynth,
+ Vcd,
+ Vline,
+ Vmic,
+ Vspeaker,
+ Vtreb,
+ Vbass,
+ Vspeed,
+ Vbits,
+ Vchans,
+ Venc,
+ Nvol,
+
+ Epcm = 0,
+ Eulaw,
+ Ealaw,
+ Nenc,
+
+ Speed = 44100,
+ Ncmd = 50, /* max volume command words */
+};
+Dirtab audiotab[]={
+ "audio", {Qaudio, 0}, 0, 0666,
+ "audioctl", {Qaudioctl, 0}, 0, 0666,
+ "volume", {Qvolume, 0}, 0, 0666,
+};
+
+typedef struct Audiodev Audiodev;
+
+struct Audiodev {
+ int fd;
+ int swab;
+ int repl1;
+ int repl2;
+};
+
+static struct
+{
+ QLock; /* XXX maybe we should use this guy! */
+ int rivol[Nvol]; /* right/left input/output volumes */
+ int livol[Nvol];
+ int rovol[Nvol];
+ int lovol[Nvol];
+} audio;
+
+static struct
+{
+ char* name;
+ int flag;
+ int ilval; /* initial values */
+ int irval;
+} volumes[] =
+{
+/*[Vaudio]*/ "audio", Fout, 50, 50,
+/*[Vsynth]*/ "synth", Fin|Fout, 0, 0,
+/*[Vcd]*/ "cd", Fin|Fout, 0, 0,
+/*[Vline]*/ "line", Fin|Fout, 0, 0,
+/*[Vmic]*/ "mic", Fin|Fout|Fmono, 0, 0,
+/*[Vspeaker]*/ "speaker", Fout|Fmono, 0, 0,
+
+/*[Vtreb]*/ "treb", Fout, 50, 50,
+/*[Vbass]*/ "bass", Fout, 50, 50,
+
+/*[Vspeed]*/ "speed", Fin|Fout|Fmono, Speed, Speed,
+/*[Vbits]*/ "bits", Fin|Fout|Fmono|Fhearn, 16, 16,
+/*[Vchans]*/ "chans", Fin|Fout|Fmono|Fhearn, 2, 2,
+/*[Venc]*/ "enc", Fin|Fout|Fmono|Fhearn, Epcm, Epcm,
+ 0
+};
+
+static char *encname[] =
+{
+/*Epcm*/ "pcm",
+/*Eulaw*/ "ulaw",
+/*Ealaw*/ "alaw",
+};
+
+static char Evolume[] = "illegal volume specifier";
+
+static void
+resetlevel(void)
+{
+ int i;
+
+ for(i=0; volumes[i].name; i++) {
+ audio.lovol[i] = volumes[i].ilval;
+ audio.rovol[i] = volumes[i].irval;
+ audio.livol[i] = volumes[i].ilval;
+ audio.rivol[i] = volumes[i].irval;
+ }
+}
+
+/* Start OS-dependant code */
+static int
+doioctl(int fd, int whim, void *data, char *what)
+{
+ char ebuf[ERRMAX];
+ int r, n;
+
+ osenter();
+ r = ioctl(fd, whim, data);
+ osleave();
+ if (r < 0) {
+ n = snprint(ebuf, ERRMAX, "ioctl %s: ", what);
+ oserrstr(ebuf+n, sizeof ebuf-n);
+ error(ebuf);
+ }
+ return r;
+}
+
+static void
+setlevels(Audiodev *a)
+{
+ struct audio_describe au;
+ struct audio_gain gain;
+ int i, x;
+
+/* XXX todo: simulate it with a data conversion routine (could also do swab...) */
+ if (audio.lovol[Venc] == Epcm && audio.lovol[Vbits] != 16) {
+ audio.lovol[Vbits] = 16;
+ error("pcm must be 16 bits");
+ }
+ if (audio.lovol[Vchans] != 1 && audio.lovol[Vchans] != 2) {
+ audio.lovol[Vchans] = 1;
+ error("bad number of channels");
+ }
+
+ doioctl(a->fd, AUDIO_DESCRIBE, &au, "describe");
+ doioctl(a->fd, AUDIO_SET_SAMPLE_RATE, audio.lovol[Vspeed], "rate"); /* what if input != output??? */
+ doioctl(a->fd, AUDIO_SET_CHANNELS, audio.lovol[Vchans], "channels");
+
+ switch (audio.lovol[Venc]) {
+ default:
+ case Epcm:
+ x = AUDIO_FORMAT_LINEAR16BIT;
+ break;
+ case Eulaw:
+ x = AUDIO_FORMAT_ULAW;
+ break;
+ case Ealaw:
+ x = AUDIO_FORMAT_ALAW;
+ break;
+ }
+ doioctl(a->fd, AUDIO_SET_DATA_FORMAT, x, "set format");
+
+ x = 0;
+ if (audio.lovol[Vspeaker] != 0 || audio.rovol[Vspeaker] != 0)
+ x |= AUDIO_OUT_SPEAKER;
+ if (audio.lovol[Vaudio] != 0 || audio.rovol[Vaudio] != 0)
+ x |= AUDIO_OUT_HEADPHONE;
+ if (audio.lovol[Vline] != 0 || audio.rovol[Vline] != 0)
+ x |= AUDIO_OUT_LINE;
+ doioctl(a->fd, AUDIO_SET_OUTPUT, x, "set output");
+
+ x = 0;
+ if (audio.livol[Vline] != 0 || audio.rivol[Vline] != 0)
+ x |= AUDIO_IN_LINE;
+ if (audio.livol[Vmic] != 0 || audio.rivol[Vmic] != 0 || x == 0) /* must set at least one */
+ x |= AUDIO_IN_MIKE;
+ doioctl(a->fd, AUDIO_SET_INPUT, x, "set input");
+
+/* XXX todo: get the gains right. should scale 0-100 into min-max (as in struct audio_describe au) */
+/* doioctl(a->fd, AUDIO_GET_GAINS, &gain, "get gains"); */
+ gain.channel_mask = AUDIO_CHANNEL_LEFT|AUDIO_CHANNEL_RIGHT;
+ for (i = 0; i < 2; i++) {
+ gain.cgain[i].receive_gain = au.min_receive_gain;
+ gain.cgain[i].monitor_gain = au.min_monitor_gain;
+ gain.cgain[i].transmit_gain = au.max_transmit_gain;
+ }
+ doioctl(a->fd, AUDIO_SET_GAINS, &gain, "set gains");
+}
+
+static char *
+audiofname(int isctl)
+{
+ if (isctl)
+ return "/dev/audioCtl";
+ else
+ return "/dev/audio";
+}
+
+static void
+audioswab(uchar *p, int n)
+{
+ int x;
+
+ /* XXX slow; should check for 16bit mode; should be combined with format conversion; etc */
+ while (n >= 2) {
+ x = p[0];
+ p[0] = p[1];
+ p[1] = x;
+ p +=2;
+ n -=2;
+ }
+}
+/* End OS-dependant code */
+
+static void
+audioinit(void)
+{
+ resetlevel();
+}
+
+static Chan*
+audioattach(char* spec)
+{
+ return devattach('A', spec);
+}
+
+static int
+audiowalk(Chan* c, char* name)
+{
+ return devwalk(c, name, audiotab, nelem(audiotab), devgen);
+}
+
+static void
+audiostat(Chan* c, char* db)
+{
+ devstat(c, db, audiotab, nelem(audiotab), devgen);
+}
+
+static Chan*
+audioopen(Chan *c, int omode)
+{
+ Audiodev *a;
+ long path;
+ char ebuf[ERRMAX];
+
+ path = c->qid.path & ~CHDIR;
+ if (path != Qdir){
+/* XXX Irix portability? (multiple opens -- how to match ctl with data???) */
+ a = malloc(sizeof(Audiodev));
+ if(a == nil)
+ error(Enomem);
+ if (waserror()) {
+ free(a);
+ nexterror();
+ }
+ a->fd = open(audiofname(path != Qaudio), omode&7);
+ if(a->fd < 0)
+ oserror();
+ if (path == Qaudio)
+ setlevels(a);
+ c->aux = a;
+ poperror();
+ }
+ return devopen(c, omode, audiotab, nelem(audiotab), devgen);
+}
+
+static void
+audioclose(Chan* c)
+{
+ Audiodev *a;
+
+ a = c->aux;
+ if (a != nil) {
+ close(a->fd);
+ free(a);
+ }
+}
+
+static long
+audioread(Chan* c, void *ua, long n, vlong offset)
+{
+ Audiodev *a;
+ char buf[300], ebuf[ERRMAX];
+ int liv, riv, lov, rov;
+ int j, m;
+ long path;
+
+ a = c->aux;
+ path = (c->qid.path & ~CHDIR);
+ switch(path){
+ case Qdir:
+ return devdirread(c, a, n, audiotab, nelem(audiotab), devgen);
+ case Qaudio:
+ osenter();
+ n = read(a->fd, ua, n);
+ osleave();
+ if (n < 0)
+ oserror();
+ audioswab(ua, n); /* XXX what if n is odd? also, only if 16 bit... must fix portability */
+ break;
+ case Qaudioctl:
+ case Qvolume:
+ j = 0;
+ buf[0] = 0;
+ for(m=0; volumes[m].name; m++){
+ if ((volumes[m].flag & Fhearn) && path == Qvolume)
+ continue;
+ liv = audio.livol[m];
+ riv = audio.rivol[m];
+ lov = audio.lovol[m];
+ rov = audio.rovol[m];
+ j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
+ if(m == Venc)
+ j += snprint(buf+j, sizeof(buf)-j, " %s", encname[lov]);
+ else if((volumes[m].flag & Fmono) || liv==riv && lov==rov){
+ if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
+ j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
+ else{
+ if(volumes[m].flag & Fin)
+ j += snprint(buf+j, sizeof(buf)-j, " in %d", liv);
+ if(volumes[m].flag & Fout)
+ j += snprint(buf+j, sizeof(buf)-j, " out %d", lov);
+ }
+ }else{
+ if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov && riv==rov)
+ j += snprint(buf+j, sizeof(buf)-j, " left %d right %d",
+ liv, riv);
+ else{
+ if(volumes[m].flag & Fin)
+ j += snprint(buf+j, sizeof(buf)-j, " in left %d right %d",
+ liv, riv);
+ if(volumes[m].flag & Fout)
+ j += snprint(buf+j, sizeof(buf)-j, " out left %d right %d",
+ lov, rov);
+ }
+ }
+ j += snprint(buf+j, sizeof(buf)-j, "\n");
+ }
+ return readstr(offset, ua, n, buf);
+ default:
+ n=0;
+ break;
+ }
+ return n;
+}
+
+static long
+audiowrite(Chan* c, char *ua, long n, vlong offset)
+{
+ Audiodev *a;
+ long m, n0;
+ int i, nf, v, left, right, in, out;
+ char buf[255], *field[Ncmd], ebuf[ERRMAX], *p;
+
+ a = c->aux;
+ switch(c->qid.path & ~CHDIR){
+ case Qaudio:
+ n &= ~1;
+ audioswab(ua, n); /* XXX VERY BAD BUG; THIS CHANGES THE CALLER'S DATA */
+ osenter();
+ n = write(a->fd, ua, n);
+ osleave();
+ if (n < 0)
+ oserror();
+ break;
+ case Qaudioctl:
+ case Qvolume:
+ v = Vaudio;
+ left = 1;
+ right = 1;
+ in = 1;
+ out = 1;
+ if(n > sizeof(buf)-1)
+ n = sizeof(buf)-1;
+ memmove(buf, ua, n);
+ buf[n] = '\0';
+
+ nf = getfields(buf, field, Ncmd, 1, " \t\n");
+ for(i = 0; i < nf; i++){
+ /*
+ * a number is volume
+ */
+ if(field[i][0] >= '0' && field[i][0] <= '9') {
+ m = strtoul(field[i], &p, 10);
+ if (p != nil && *p == 'k')
+ m *= 1000;
+ if(left && out)
+ audio.lovol[v] = m;
+ if(left && in)
+ audio.livol[v] = m;
+ if(right && out)
+ audio.rovol[v] = m;
+ if(right && in)
+ audio.rivol[v] = m;
+ setlevels(a);
+ goto cont0;
+ }
+
+ for(m=0; volumes[m].name; m++) {
+ if(strcmp(field[i], volumes[m].name) == 0) {
+ v = m;
+ in = 1;
+ out = 1;
+ left = 1;
+ right = 1;
+ goto cont0;
+ }
+ }
+
+ if(strcmp(field[i], "reset") == 0) {
+ resetlevel();
+ setlevels(a);
+ goto cont0;
+ }
+ if(strcmp(field[i], "in") == 0) {
+ in = 1;
+ out = 0;
+ goto cont0;
+ }
+ if(strcmp(field[i], "out") == 0) {
+ in = 0;
+ out = 1;
+ goto cont0;
+ }
+ if(strcmp(field[i], "left") == 0) {
+ left = 1;
+ right = 0;
+ goto cont0;
+ }
+ if(strcmp(field[i], "right") == 0) {
+ left = 0;
+ right = 1;
+ goto cont0;
+ }
+ if(strcmp(field[i], "rate") == 0) {
+ v = Vspeed;
+ in = 1;
+ out = 1;
+ left = 1;
+ right = 1;
+ goto cont0;
+ }
+ if(strcmp(field[i], "chan") == 0) { /* XXX egregious backward compatibility hack */
+ v = Vchans;
+ in = 1;
+ out = 1;
+ left = 1;
+ right = 1;
+ goto cont0;
+ }
+ if(v == Venc) {
+ if (strcmp(field[i], "pcm") == 0) {
+ audio.lovol[v] = Epcm;
+ goto cont0;
+ }
+ if (strcmp(field[i], "ulaw") == 0) {
+ audio.lovol[v] = Eulaw;
+ goto cont0;
+ }
+ if (strcmp(field[i], "alaw") == 0) {
+ audio.lovol[v] = Ealaw;
+ goto cont0;
+ }
+ }
+ if(v == Vchans) {
+ if (strcmp(field[i], "mono") == 0) {
+ audio.lovol[v] = 1;
+ goto cont0;
+ }
+ if (strcmp(field[i], "stereo") == 0) {
+ audio.lovol[v] = 2;
+ goto cont0;
+ }
+ }
+ error(Evolume);
+ break;
+ cont0:;
+ }
+ break;
+ default:
+ error(Ebadusefd);
+ }
+ return n;
+}
+
+Dev audiodevtab = {
+ 'A',
+ "audio",
+
+ audioinit,
+ audioattach,
+ devclone,
+ audiowalk,
+ audiostat,
+ audioopen,
+ devcreate,
+ audioclose,
+ audioread,
+ devbread,
+ audiowrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
diff --git a/emu/Hp/devfs.c b/emu/Hp/devfs.c
new file mode 100644
index 00000000..9017c3fc
--- /dev/null
+++ b/emu/Hp/devfs.c
@@ -0,0 +1 @@
+#include "devfs-posix.c"
diff --git a/emu/Hp/emu b/emu/Hp/emu
new file mode 100644
index 00000000..88bb23e4
--- /dev/null
+++ b/emu/Hp/emu
@@ -0,0 +1,107 @@
+dev
+ root
+ cons
+ env
+ mnt
+ pipe
+ prog
+ prof
+ srv
+ dup
+ ssl
+ cap
+ fs
+ cmd cmd
+ indir
+
+ draw
+ pointer
+ snarf
+
+ ip ipif-posix ipaux
+# eia
+# audio audio
+ audio
+ mem
+
+lib
+ interp
+ tk
+ freetype
+ math
+ draw
+
+ memlayer
+ memdraw
+ keyring
+ sec
+ mp
+
+ 9
+
+link
+
+mod
+ sys
+ draw
+
+ tk
+ math
+ srv srv
+ keyring
+ loader
+ freetype
+
+port
+ alloc
+ cache
+ chan
+ dev
+ dial
+ dis
+ discall
+ env
+ error
+ errstr
+ exception
+ exportfs
+ inferno
+ latin1
+ main
+ parse
+ pgrp
+ print
+ proc
+ qio
+ random
+ sysfile
+ uqid
+
+code
+
+init
+ emuinit
+
+root
+ /dev /
+ /fd /
+ /prog /
+ /net /
+ /net.alt /
+ /chan /
+ /nvfs /
+ /env /
+# /chan
+# /dev
+# /dis
+# /env
+# /n
+# /net
+# /nvfs /
+# /prog
+# /icons
+# /osinit.dis
+# /dis/emuinit.dis
+# /dis/lib/auth.dis
+# /dis/lib/ssl.dis
+# /n/local /
diff --git a/emu/Hp/mkfile b/emu/Hp/mkfile
new file mode 100644
index 00000000..ef7c6db1
--- /dev/null
+++ b/emu/Hp/mkfile
@@ -0,0 +1,50 @@
+SYSTARG=Hp
+OBJTYPE=s800
+<../../mkconfig
+SYSTARG=Hp
+OBJTYPE=s800
+
+#Configurable parameters
+
+CONF=emu #default configuration
+CONFLIST=emu
+CLEANCONFLIST=
+
+INSTALLDIR=$ROOT/$SYSTARG/$OBJTYPE/bin #path of directory where kernel is installed
+
+#end configurable parameters
+
+<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE #set vars based on target system
+
+<| $SHELLNAME ../port/mkdevlist $CONF #sets $IP, $DEVS, $PORT, $LIBS
+
+OBJ=\
+ asm-$OBJTYPE.$O\
+ os.$O\
+ win-x11.$O\
+ $CONF.root.$O\
+ lock.$O\
+ $DEVS\
+ $PORT\
+
+HFILES=\
+
+CFLAGS='-DROOT="'$ROOT'"' -DEMU -I. -I../port -I$ROOT/$SYSTARG/$OBJTYPE/include -I$ROOT/include -I$ROOT/libinterp $CTHREADFLAGS $CFLAGS $EMUOPTIONS
+SYSLIBS= -lm -lX11 -lcma
+KERNDATE=`{$NDATE}
+
+default:V: $O.$CONF
+
+<../port/portmkfile
+
+$O.$CONF: $OBJ $CONF.c $CONF.root.h $LIBFILES
+ $CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c
+ $LD $LDFLAGS -o $target $OBJ $CONF.$O $LIBFILES $SYSLIBS
+
+install:V: $O.$CONF
+ cp $O.$CONF $INSTALLDIR/$CONF
+
+devaudio.$O: devaudio.c
+ $CC $CFLAGS devaudio.c
+
+devfs.$O: ../port/devfs-posix.c
diff --git a/emu/Hp/mkfile-Hp b/emu/Hp/mkfile-Hp
new file mode 100644
index 00000000..37c625db
--- /dev/null
+++ b/emu/Hp/mkfile-Hp
@@ -0,0 +1,13 @@
+#
+# architecture-dependent files for Hp
+#
+
+TARGFILES=asm-Hp-s800.$O\
+ devfs-posix.$O\
+ devip.$O\
+ ipif-posix.$O\
+ os-Hp.$O\
+ win-x11.$O\
+ devaudio-Hp.$O\
+ srv.$O\
+ lock.$O\
diff --git a/emu/Hp/os.c b/emu/Hp/os.c
new file mode 100644
index 00000000..a371ac50
--- /dev/null
+++ b/emu/Hp/os.c
@@ -0,0 +1,591 @@
+#include <pthread.h>
+#include <signal.h>
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+#include <sys/socket.h>
+#include <time.h>
+#include <sys/time.h>
+#include <termios.h>
+#include <pwd.h>
+#include <errno.h>
+
+enum
+{
+ BUNCHES = 5000,
+ DELETE = 0x7F
+};
+char *hosttype = "Hp";
+
+
+static pthread_key_t prdakey;
+
+extern int dflag;
+
+Lock mulock = {1, 0};
+
+ulong
+_tas(ulong *l)
+{
+ ulong v;
+
+ while(!(mutexlock(&mulock)))
+ pthread_yield();
+
+ v = *l;
+ if(v == 0)
+ *l = 1;
+ mulock.key = 1;
+ return v;
+}
+
+static ulong erendezvous(void*, ulong);
+
+
+void
+osblock(void)
+{
+ erendezvous(up, 0);
+}
+
+void
+osready(Proc *p)
+{
+ erendezvous(p, 0);
+}
+
+
+void
+pexit(char *msg, int t)
+{
+ Osenv *e;
+
+ lock(&procs.l);
+ if(up->prev)
+ up->prev->next = up->next;
+ else
+ procs.head = up->next;
+
+ if(up->next)
+ up->next->prev = up->prev;
+ else
+ procs.tail = up->prev;
+ unlock(&procs.l);
+
+ e = up->env;
+ if(e != nil) {
+ closefgrp(e->fgrp);
+ closepgrp(e->pgrp);
+ closeegrp(e->egrp);
+ closesigs(e->sigs);
+ }
+ free(up->prog);
+ free(up);
+ pthread_exit(0);
+}
+
+void
+trapBUS(int signo, siginfo_t *info, void *context)
+{
+ if(info)
+ print("trapBUS: signo: %d code: %d addr: %lx\n",
+ info->si_signo, info->si_code, info->si_addr);
+ else
+ print("trapBUS: no info\n");
+ disfault(nil, "Bus error");
+}
+
+void
+trapUSR1(void)
+{
+ int intwait;
+
+ intwait = up->intwait;
+ up->intwait = 0; /* clear it to let proc continue in osleave */
+
+ if(up->type != Interp) /* Used to unblock pending I/O */
+ return;
+
+ if(intwait == 0) /* Not posted so it's a sync error */
+ disfault(nil, Eintr); /* Should never happen */
+}
+
+void
+trapILL(void)
+{
+ disfault(nil, "Illegal instruction");
+}
+
+void
+trapSEGV(void)
+{
+ disfault(nil, "Segmentation violation");
+}
+
+sigset_t set;
+setsigs()
+{
+ struct sigaction act;
+
+ memset(&act, 0 , sizeof(act));
+ sigemptyset(&set);
+
+ act.sa_handler=SIG_IGN;
+ if(sigaction(SIGPIPE, &act, nil))
+ panic("can't ignore sig pipe");
+
+ if(sigaddset(&set,SIGUSR1)== -1)
+ panic("sigaddset SIGUSR1");
+
+ if(sigaddset(&set,SIGUSR2)== -1)
+ panic("sigaddset SIGUSR2");
+
+ /* For the correct functioning of devcmd in the
+ * face of exiting slaves
+ */
+ if(sflag == 0) {
+ act.sa_handler=trapBUS;
+ act.sa_flags|=SA_SIGINFO;
+ if(sigaction(SIGBUS, &act, nil))
+ panic("sigaction SIGBUS");
+ act.sa_handler=trapILL;
+ if(sigaction(SIGILL, &act, nil))
+ panic("sigaction SIGILL");
+ act.sa_handler=trapSEGV;
+ if(sigaction(SIGSEGV, &act, nil))
+ panic("sigaction SIGSEGV");
+ if(sigaddset(&set,SIGINT)== -1)
+ panic("sigaddset");
+ }
+ if(sigprocmask(SIG_BLOCK,&set,nil)!= 0)
+ panic("sigprocmask");
+}
+
+static void *
+tramp(void *v)
+{
+ struct Proc *Up;
+ pthread_t thread;
+ struct sigaction oldact;
+
+ setsigs();
+ if(sigaction(SIGBUS, nil, &oldact))
+ panic("sigaction failed");
+ if(oldact.sa_handler!=trapBUS && sflag==0)
+ panic("3rd old act sa_handler");
+
+ if(pthread_setspecific(prdakey,v)) {
+ print("set specific data failed in tramp\n");
+ pthread_exit(0);
+ }
+ Up = v;
+ thread = pthread_self();
+ Up->sigid = cma_thread_get_unique(&thread);
+ /* attempt to catch signals again */
+ setsigs();
+ Up->func(Up->arg);
+ pexit("", 0);
+}
+
+pthread_t active_threads[BUNCHES]; /* this should be more than enuf */
+
+int
+kproc(char *name, void (*func)(void*), void *arg, int flags)
+{
+ pthread_t thread;
+ pthread_attr_t attr;
+ int id;
+ Proc *p;
+ Pgrp *pg;
+ Fgrp *fg;
+ Egrp *eg;
+ struct sigaction oldact;
+
+ p = newproc();
+
+ if(flags & KPDUPPG) {
+ pg = up->env->pgrp;
+ incref(&pg->r);
+ p->env->pgrp = pg;
+ }
+ if(flags & KPDUPFDG) {
+ fg = up->env->fgrp;
+ incref(&fg->r);
+ p->env->fgrp = fg;
+ }
+ if(flags & KPDUPENVG) {
+ eg = up->env->egrp;
+ incref(&eg->r);
+ p->env->egrp = eg;
+ }
+
+ p->env->uid = up->env->uid;
+ p->env->gid = up->env->gid;
+ kstrdup(&p->env->user, up->env->user);
+;
+
+ strcpy(p->text, name);
+
+ p->func = func;
+ p->arg = arg;
+
+ lock(&procs.l);
+ if(procs.tail != nil) {
+ p->prev = procs.tail;
+ procs.tail->next = p;
+ }
+ else {
+ procs.head = p;
+ p->prev = nil;
+ }
+ procs.tail = p;
+ unlock(&procs.l);
+ if((pthread_attr_create(&attr))== -1)
+ panic("pthread_attr_create failed");
+
+ errno=0;
+ pthread_attr_setsched(&attr,SCHED_OTHER);
+ if(errno)
+ panic("pthread_attr_setsched failed");
+
+ if(pthread_create(&thread, attr, tramp, p))
+ panic("thr_create failed\n");
+ if(sigaction(SIGBUS, nil, &oldact))
+ panic("sigaction failed");
+ if(oldact.sa_handler!=trapBUS && sflag == 0)
+ panic("2nd old act sa_handler");
+
+ if((id=cma_thread_get_unique(&thread))>=BUNCHES)
+ panic("id too big");
+ active_threads[id]=thread;
+ return id;
+}
+
+void
+oshostintr(Proc *p)
+{
+ pthread_cancel(active_threads[p->sigid]);
+}
+
+void
+oslongjmp(void *regs, osjmpbuf env, int val)
+{
+ USED(regs);
+ siglongjmp(env, val);
+}
+
+struct termios tinit;
+
+static void
+termset(void)
+{
+ struct termios t;
+
+ tcgetattr(0, &t);
+ tinit = t;
+ t.c_lflag &= ~(ICANON|ECHO|ISIG);
+ t.c_cc[VMIN] = 1;
+ t.c_cc[VTIME] = 0;
+ tcsetattr(0, TCSANOW, &t);
+}
+
+static void
+termrestore(void)
+{
+ tcsetattr(0, TCSANOW, &tinit);
+}
+
+void
+cleanexit(int x)
+{
+ USED(x);
+
+ if(up->intwait) {
+ up->intwait = 0;
+ return;
+ }
+
+ if(dflag == 0)
+ termrestore();
+
+ kill(0, SIGKILL);
+ exit(0);
+}
+
+void
+osreboot(char *file, char **argv)
+{
+ if(dflag == 0)
+ termrestore();
+ execvp(file, argv);
+ panic("reboot failure");
+}
+
+int gidnobody= -1, uidnobody= -1;
+
+void
+getnobody()
+{
+ struct passwd *pwd;
+
+ if(pwd = getpwnam("nobody")) {
+ uidnobody = pwd->pw_uid;
+ gidnobody = pwd->pw_gid;
+ }
+}
+
+static pthread_mutex_t rendezvouslock;
+
+void
+libinit(char *imod)
+{
+ struct passwd *pw;
+ struct Proc *Up;
+ struct sigaction oldact;
+ int ii;
+ int retval;
+ int *pidptr;
+ char sys[64];
+
+ cma_init();
+ setsid();
+ /* mulock.key = 1; */ /* initialize to unlock */
+ if(pthread_mutex_init(&rendezvouslock,pthread_mutexattr_default))
+ panic("pthread_mutex_init");
+
+ gethostname(sys, sizeof(sys));
+ kstrdup(&ossysname, sys);
+ getnobody();
+
+ if(dflag == 0)
+ termset();
+
+ setsigs();
+ if(sigaction(SIGBUS, nil, &oldact)) {
+ panic("sigaction failed");
+ }
+ if(oldact.sa_handler!=trapBUS && sflag == 0)
+ panic("1st old act sa_handler");
+
+ if(pthread_keycreate(&prdakey,NULL))
+ print("keycreate failed\n");
+
+ Up = newproc();
+ if(pthread_setspecific(prdakey,Up))
+ panic("set specific thread data failed\n");
+
+ pw = getpwuid(getuid());
+ if(pw != nil)
+ kstrdup(&eve, pw->pw_name);
+ else
+ print("cannot getpwuid\n");
+
+ up->env->uid = getuid();
+ up->env->gid = getgid();
+ emuinit(imod);
+}
+
+int
+readkbd(void)
+{
+ int n;
+ char buf[1];
+
+ n = read(0, buf, sizeof(buf));
+ if(n != 1) {
+ print("keyboard close (n=%d, %s)\n", n, strerror(errno));
+ pexit("keyboard thread", 0);
+ }
+
+ switch(buf[0]) {
+ case '\r':
+ buf[0] = '\n';
+ break;
+ case DELETE:
+ cleanexit(0);
+ break;
+ }
+ return buf[0];
+}
+
+enum
+{
+ NHLOG = 7,
+ NHASH = (1<<NHLOG)
+};
+
+typedef struct Tag Tag;
+struct Tag
+{
+ void* tag;
+ ulong val;
+ int pid;
+ Tag* hash;
+ Tag* free;
+ pthread_cond_t cv;
+};
+
+static Tag* ht[NHASH];
+static Tag* ft;
+
+static ulong
+erendezvous(void *tag, ulong value)
+{
+ int h;
+ ulong rval;
+ Tag *t, *f, **l;
+ int ii=0;
+
+ h = (ulong)tag & (NHASH-1);
+
+ if(pthread_mutex_lock(&rendezvouslock))
+ panic("pthread_mutex_lock");
+
+ l = &ht[h];
+ for(t = *l; t; t = t->hash) {
+ if(t->tag == tag) {
+ rval = t->val;
+ t->val = value;
+ t->tag = 0;
+ if(pthread_mutex_unlock(&rendezvouslock))
+ panic("pthread_mutex_unlock");
+ if(pthread_cond_signal(&(t->cv)))
+ panic("pthread_cond_signal");
+ return rval;
+ }
+ }
+
+ t = ft;
+ if(t == 0) {
+ t = malloc(sizeof(Tag));
+ if(t == 0)
+ panic("rendezvous: no memory");
+ if(pthread_cond_init(&(t->cv),pthread_condattr_default)) {
+ print("pthread_cond_init (errno: %s) \n", strerror(errno));
+ panic("pthread_cond_init");
+ }
+ } else
+ ft = t->free;
+
+ t->tag = tag;
+ t->val = value;
+ t->hash = *l;
+ *l = t;
+
+ while(t->tag)
+ pthread_cond_wait(&(t->cv),&rendezvouslock);
+
+ rval = t->val;
+ for(f = *l; f; f = f->hash){
+ if(f == t) {
+ *l = f->hash;
+ break;
+ }
+ l = &f->hash;
+ }
+ t->free = ft;
+ ft = t;
+ if(pthread_mutex_unlock(&rendezvouslock))
+ panic("pthread_mutex_unlock");
+
+ return rval;
+}
+
+
+/*
+ * Return an abitrary millisecond clock time
+ */
+long
+osmillisec(void)
+{
+ static long sec0 = 0, usec0;
+ struct timeval t;
+
+ if(gettimeofday(&t,(struct timezone*)0)<0)
+ return(0);
+ if(sec0==0) {
+ sec0 = t.tv_sec;
+ usec0 = t.tv_usec;
+ }
+ return((t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000);
+}
+
+/*
+ * Return the time since the epoch in nanoseconds and microseconds
+ * The epoch is defined at 1 Jan 1970
+ */
+vlong
+osnsec(void)
+{
+ struct timeval t;
+
+ gettimeofday(&t, nil);
+ return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
+}
+
+vlong
+osusectime(void)
+{
+ struct timeval t;
+
+ gettimeofday(&t, nil);
+ return (vlong)t.tv_sec * 1000000 + t.tv_usec;
+}
+
+
+int
+osmillisleep(ulong milsec)
+{
+ struct timespec time;
+ time.tv_sec = milsec/1000;
+ time.tv_nsec= (milsec%1000)*1000000;
+ if(pthread_delay_np(&time)== -1)
+ ; /* might be interrupted */
+ return 0;
+}
+
+Proc *
+getup(void)
+{
+ void *vp;
+
+ vp=nil;
+ pthread_getspecific(prdakey,&vp);
+ return(vp);
+}
+
+ulong
+getcallerpc(void *arg)
+{
+ return 0 ;
+}
+
+void
+osyield(void)
+{
+ pthread_yield();
+}
+
+void
+ospause(void)
+{
+ int s;
+
+ for(;;) {
+ switch(s=sigwait(&set)) {
+ case SIGUSR1:
+ trapUSR1();
+ case SIGINT:
+ cleanexit(0);
+ default:
+ print("signal: %d %s\n",s, strerror(errno));
+ panic("sigwait");
+ }
+ }
+}
+
+void
+oslopri(void)
+{
+ /* TO DO */
+}