Unix driver for a hitachi optical disc.
Joe Davida
jd at stmvax.UUCP
Sat Mar 8 02:29:40 AEST 1986
I am posting this for a friend.
Here is a driver for a hitachi optical disc "juke box" with
a GPIB interface. It was written for a WICAT uniplus unix
(a system 3?). Please refer all questions to mr. Jungbo Yang
at ttihwe, email
<ametek|group3|cadovax|ghsvax|scgvaxd|oberon>!stmvax!ttihwe!jy
------------------------------CUT HERE-----------------------------------------
: Run this file as a shell script to extract contents.
: This file contains files hita.c hita.h hitachi.h opt_fs.h
echo x - hita.c
cat << '//E*O*F hita.c' > hita.c
/* Hitachi optical disk and jukebox device driver for wicat */
/* IEEE-488 (GPIB) / multibus interface board from */
/* National Instruments is used to interface to the disk */
/* Author: Jungbo Yang */
#include <sys/param.h>
#include <sys/text.h>
#include <sys/tty.h>
#include <sys/mx.h>
#include <sys/ino.h>
#include <sys/inode.h>
#include <sys/filsys.h>
#include <sys/file.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/dir.h>
#include <sys/conf.h>
#include <sys/user.h>
#include <signal.h>
#include "hitachi.h"
#include "hita.h"
#include "opt_fs.h"
/* #define HITADEBUG Uncomment to turn driver debugging on */
#undef DEBUG
#ifdef HITADEBUG
#define DEBUG(args) printf args
#else
# define DEBUG(args)
#endif
#define TRUE 1
#define FALSE 0
#define odd(n) ((int)(n) & 01)
#define UNIT(devnum) (minor(devnum))
#ifndef void
#define void int
#endif
#define wlowbyte(x) (0xff & x)
#define whibyte(x) (0xff & (x >> 8))
/* GPIB 796 registers */
typedef struct { /* bytes are swaped. you know why. */
char imr1; /* +1 interrupt mask register 1 */
char cdor; /* +0 byte out register */
char spmr; /* +3 serial poll mode register */
char imr2; /* +2 interrupt mask register 2 */
char auxmr; /* +5 auxiliary mode register */
char admr; /* +4 address mode register */
char eosr; /* +7 end of string register */
char adr; /* +6 address register 0/1 */
char bcr1; /* +9 byte count register 1 */
char bcr0; /* +8 byte count register 0 */
char ccfr; /* +11 carry cycle function register */
char cr0; /* +10 control register 0 */
char acr1; /* +13 address count register 1 */
char acr0; /* +12 address count register 0 */
char cr1; /* +15 control register 1 */
char acr2; /* +14 address count register 2 */
} ibregs ;
/*
* one 488 interface board with 2 optical disk drives
*/
ibregs *ib = ((ibregs *) 0xf00600); /* only one board */
#define NHITA 1 /* one OFC */
#define NODD 2
static HITA_t hita[NODD]; /* two ODDs */
static HGPIB_t gpib;
#define HFMSSIZE 512 /* fms */
#define HNMINOR 8 /* max number of minor device */
static char fms[HNMINOR][HFMSSIZE];
#define HSTATSS 0xe0 /* status tables */
#define HSTATDEVID 0xe9
#define HSTATCELL 0x68
#define HSTATODDS 0xec
#define HSTATSECT 0x61
static char ss_stat[HSTAT_L_SS+2];
static char devid_stat[HSTAT_L_DEVID+2];
static char cell_stat[HSTAT_L_CELL+2];
static char odd_stat[HSTAT_L_ODDS+2];
static char sect_stat[HSTAT_L_SECT+2];
static char codd = -1; /* current ODD */
/* proc sync */
static int sleep_cnt = 0;
static int sleep_out = 0;
static int sleep_in = 0;
/* PSleeP should be done before the critical section */
#define PSleeP { \
if (hita[UNIT(dev)].h_state & HBUSY) { \
if (++sleep_cnt >= HMAXOPEN) { \
--sleep_cnt; \
u.u_error = EBUSY; \
return; \
} \
if (++sleep_in >= HMAXOPEN) \
sleep_in = 0; \
sleep( (caddr_t) ss_stat + sleep_in, HITAPRI); \
} \
hita[(UNIT(dev))].h_state |= HBUSY; \
}
/* done at the end but inside of the critical section */
#define PWakeuP { \
if (sleep_cnt) { \
if (++sleep_out >= HMAXOPEN) \
sleep_out = 0; \
wakeup( (caddr_t) ss_stat + sleep_out); \
sleep_cnt--; \
} else { \
hita[UNIT(dev)].h_state &= ~(HBUSY); \
} \
}
/*
* hita structure bit definitions
*/
#define HOPEN 0x1 /* state */
#define HREAD 0x1 /* state */
#define HWRITE 0x2 /* state */
#define HITASLEEP 0x4 /* state, process called sleep() */
#define HITAPHYS 0x8 /* state, user buffer is the hidden memory */
#define HEXCLUSIVE 0x10 /* state */
#define HBUSY 0x20 /* state */
#define DUAL 0x1 /* opop dual write on */
#define DCI 0x2 /* opop delete block check inhibit */
/*
* CRC checksum (this should really be done in hardware)
*/
#define POLY 0x8408
crc (start, end, crc1, crc2)
register char *start, *end, *crc1, *crc2;
{
register c;
register counter, data = 0xffff; /* data will start from all one's */
register polynom = POLY;
while (start < end) {
c = *start++ & 0xFF;
if (start < end)
c |= (0xff00 & (*start++ << 8));
data ^= c;
counter = 17;
while (--counter) { /* loop for 16 shifts */
if (data & 1) {
data >>= 1;
data ^= polynom;
} else
data >>= 1;
}
}
*crc1 = (char) ~(data & 0xff);
*crc2 = (char) ~(data >> 8) & 0xff;
/* DEBUG(("crc1= %x, crc2= %x\n",0xff&(*crc1),0xff&(*crc2))); */
}
/*
* Programmed I/O (busy wait)
* readone(), cmdone() and dataone()
*/
char readone()
{
register char t;
do {
t = ib->isr1;
gpib.h_isr1 |= t;
} while ((t & HR_DI) == 0);
return(ib->dir);
}
cmdone(cmd)
char cmd;
{
register char t;
ib->cdor = cmd;
do {
t = ib->isr2;
gpib.h_isr2 |= t;
} while ((t & HR_CO) == 0); /* busy wait until set */
}
dataone(dat)
char dat;
{
register char t;
ib->cdor = dat;
do {
t = ib->isr1;
gpib.h_isr2 |= t;
} while ((t & HR_DO) == 0); /* busy wait until set */
}
/*
* wait for SRQ routine (busy wait)
*/
srq() {
register char t;
DEBUG(("waiting for SRQ..."));
ib->imr2 = HR_SRQIE;
do {
t = ib->isr2;
gpib.h_isr2 |= t;
} while ((t & HR_SRQI) == 0); /* busy wait until set */
ib->imr2 &= ~HR_SRQIE;
}
/* short delay (busy wait) */
ibdelay(n) {
int j,i,t;
for (j=0; j<n; j++)
for (t=i=0; i<1000; i++)
t++;
return(t);
}
/*
* initialize the Interface board
*/
init(tl)
char tl;
{
char t;
/* DEBUG(("init(%c).\n",tl)); */
ib->cr0 = HR_LMR; /* set local master reset */
ib->cr0 = 0; /* clear it */
ib->cr1 = 0; /* clear it */
ib->auxmr = 2; /* chip reset */
t = ib->cptr; /* clear stat by reading */
t = ib->isr1;
t = ib->isr2;
ib->imr1 = ib->imr2 = ib->spmr = 0; /* disable all interrupt */
ib->adr = 0; /* set MTA=0100 and MLA=040 */
ib->adr = HR_ARS | HR_DT | HR_DL;
ib->admr = HR_TRM1 | HR_TRM0 | HR_ADM0;
if (tl == 't')
ib->admr = HR_TON;
else
ib->admr = HR_LON;
ib->auxmr = ICR | 5;
ib->auxmr = PPR | HR_PPU;
ib->auxmr = AUXRA | 0;
ib->auxmr = AUXRB | HR_INV;
ib->auxmr = AUXRE | 0;
ib->cr1 = HR_MIE | HR_SC; /* main interrupt switch on */
ib->auxmr = AUX_PON; /* power on */
}
/*
* GPIB ACTIVE state
*/
active(tl)
char tl;
{
/* DEBUG(("active(%c).\n",tl)); */
/* become active controller */
ib->cr1 = HR_SC; /* prepare for IFC and REN */
if (tl == 't')
ib->admr = HR_TON;
else
ib->admr = HR_LON;
ib->auxmr = AUX_PON; /* power on */
ib->auxmr = AUX_SIFC; /* set IFC */
ibdelay(1); /* > 100 micro seconds delay */
ib->auxmr = AUX_CIFC; /* clear IFC */
/* now, check to see I am active or not ***************
if (ib->adsr & HR_CIC) {
if (tl == 't')
if (ib->adsr & HR_TA)
DEBUG(("Active talker. ok.\n"));
else
DEBUG(("Active talker. NOT ok.\n"));
else
if (ib->adsr & HR_LA)
DEBUG(("Active listenner. ok.\n"));
else
DEBUG(("Active listenner. NOT ok.\n"));
}
***************** */
}
/* LISTEN and STANDBY for data in */
listen_sb() {
/* DEBUG(("listen and standby for data in\n")); */
ib->auxmr = LISTEN;
ib->auxmr = SB;
}
/* EOI with the final data out */
eoi() {
/* DEBUG(("eoi().\n")); */
ib->auxmr = AUX_SEOI;
}
/*
* POWER ON to reset some parameters, such as talker/listenner
* Also, this causes the state to shift from ACTIVE to PASSIVE
*/
pon() {
/* DEBUG(("pon().\n")); */
ib->auxmr = AUX_PON;
}
/*
* DMA i/o with interrrupt
*/
int dma(dev,rw,addr,cnt)
dev_t dev;
int cnt;
char rw;
char *addr;
{
register HITA_t *g = &hita[UNIT(dev)];
int ret;
char t;
register int i,fcnt;
register char *faddr;
/* state should be the active in standby mode */
fcnt = cnt;
faddr = addr;
/* set the byte count and address*/
cnt = -cnt;
DEBUG(("dma: %s cnt = %d\n",rw=='r'?"read":"write",cnt));
ib->bcr0 = (char) (0xff & cnt);
ib->bcr1 = (char) (0xff & (cnt >> 8));
ib->acr0 = lobyte(addr); /* physical memory addr */
ib->acr1 = midbyte(addr);
ib->acr2 = hibyte(addr);
if (rw == 'r') {
t = ib->isr1; /* clear it */
ib->auxmr = AUX_FH;
ib->auxmr = AUXRA; /* normal handshake */
ib->ccfr = 0;
ib->imr1 = HR_ENDIE; /* set for reading */
ib->imr2 = HR_DMAI;
/* DEBUG(("dma: read: sleeping...")); */
g->h_state |= HITASLEEP;
ib->cr1 = HR_MIE|HR_SC;
ib->cr0 = HR_DMAE|HR_FINIE;
ib->cr0 = HR_DMAE|HR_FINIE|HR_GO;
sleep( (caddr_t) g, HITAPRI);
/* DEBUG(("dma: read: woken up.\n")); */
} else { /* WRITE */
t = ib->sr; /* clear to start */
ib->imr1 = 0;
ib->imr2 = HR_DMAO;
/* DEBUG(("dma: write: sleeping...")); */
g->h_state |= HITASLEEP;
if (rw == 'l') { /* the last write. send EOI */
ib->ccfr = AUX_SEOI; /* send EOI with the last byte */
ib->cr1 = HR_MIE|HR_SC;
ib->cr0 = HR_MEMRD|HR_ECC|HR_DMAE|HR_FINIE;
ib->cr0 = HR_MEMRD|HR_ECC|HR_DMAE|HR_FINIE|HR_GO;
} else {
ib->ccfr = 0;
ib->cr1 = HR_MIE|HR_SC;
ib->cr0 = HR_MEMRD|HR_DMAE|HR_FINIE;
ib->cr0 = HR_MEMRD|HR_DMAE|HR_FINIE|HR_GO;
}
sleep( (caddr_t) g, HITAPRI);
/* DEBUG(("dma: write: woken up.\n")); */
}
ib->cr0 = 0; /* clear DMA */
/* g->h_state &= ~(HITASLEEP); done in hitaintr() */
gpib.h_sr &= ~(HR_NGPIBIR|HR_NFIN|HR_DONE);
ret = (ib->bcr1 << 8) + (unsigned char) ib->bcr0;
DEBUG(("dma: byte leftover = %d\n",-ret));
return(ret-cnt);
}
getstat(dev)
dev_t dev;
{
register int i;
char t,ret;
register HITA_t *g = &hita[UNIT(dev)];
/* catch the SQR */
gpib.h_isr2 &= ~(HR_SRQI);
/* set the ib to active Listenner */
active('l');
/* wait for SRQ */
if ((gpib.h_isr2 & HR_SRQI) == 0)
srq();
cmdone(UNL);
cmdone(UNT);
cmdone(SPE);
cmdone(g->h_mta);
/* aux listen and standby command */
listen_sb();
/* read one byte status */
ret = 0xff & readone();
DEBUG(("getstat: %x\n",ret));
/* set the ib back to active mode for sending commands */
active('t');
cmdone(SPD);
cmdone(UNT);
cmdone(UNL);
/* save the status, when they are available, here */
if (ret==0x80 || ret==0x40 || ret==0x10) {
return(0);
} else {
active('l');
cmdone(UNT);
cmdone(UNL);
cmdone(g->h_mta);
listen_sb();
gpib.h_isr1 &= ~(HR_END);
for (i=0; i<6; i++) /* through away the header */
readone();
i=0;
switch(0xff & ret) {
case HSTATSS:
while(1) {
ss_stat[i++] = readone();
if ((gpib.h_isr1 & HR_END) || i>HSTAT_L_SS+2)
break;
}
break;
case HSTATDEVID:
while(1) {
devid_stat[i++] = readone();
if ((gpib.h_isr1 & HR_END) || i>HSTAT_L_DEVID+2)
break;
}
break;
case HSTATCELL:
while(1) {
cell_stat[i++] = readone();
if ((gpib.h_isr1 & HR_END) || i>HSTAT_L_CELL+2)
break;
}
break;
case HSTATODDS:
while(1) {
odd_stat[i++] = readone();
if ((gpib.h_isr1 & HR_END) || i>HSTAT_L_ODDS+2)
break;
}
break;
case HSTATSECT:
while(1) {
sect_stat[i++] = readone();
if ((gpib.h_isr1 & HR_END) || i>HSTAT_L_SECT+2)
break;
}
break;
default:
while(1) {
readone();
if (gpib.h_isr1 & HR_END) /* unknown stat. dump it */
break;
}
break;
}
return(0xff & ret);
}
}
hitainit(u)
register short u;
{
register HITA_t *g;
int i;
DEBUG(("hitainit called:\n"));
g = &hita[u];
g -> h_state = 0;
g -> h_opfd = 0;
g -> h_opop = 0;
g -> h_pbn = -1; /* not initialized */
g -> h_woff = 0; /* empty */
g -> h_roff = 512;
g -> h_mta = MTA + u;
g -> h_mla = MLA + u;
sleep_cnt = sleep_in = sleep_out = 0;
}
/*
Fd is available in u.
fd.f_flag 1==read(FREAD) and 2==write(FWRITE)
rwflag =1 for FREAD and 2 for FWRITE and 0 for exclusive?
Allow only one WRITE open (mode 1,2 or 3)
is hita.state HWRITE?
Check the max number of open
is opfd < HMAXOPEN?
Increment opfd
Set hita.stat=HWRITE
*/
hitaopen(dev,rwflag)
dev_t dev;
short rwflag;
{
register HITA_t *g;
register struct a {
char *fname;
int fmode;
} *uap;
int i,x;
HFMS_t *pfms;
uap = (struct a *) u.u_ap;
DEBUG (("HITA OPEN called, dev = %d/%d, rwflag=%x, h.state=%x, mode=%x\n",
major(dev), UNIT(dev),rwflag,hita[UNIT(dev)].h_state,uap->fmode));
if (codd < 0) { /* first open */
for (i=0; i<NODD; i++) {
hitainit(i);
/* init fms states */
for (i=0; i<HNMINOR; i++) {
pfms = (HFMS_t *) &fms[i][0];
pfms->fms_state = FMS_NOT_MOUNTED;
pfms->fms_vol[0] = 0;
}
}
gpib.h_isr1 = gpib.h_isr2 = gpib.h_sr = codd = 0;
init('t');
active('t');
cmdone(DCL);
cmdone(UNT);
cmdone(UNL);
}
PSleeP
x = spl7();
g = &hita[UNIT(dev)];
if (g->h_opfd <= 0) /* IMPORTANT you do it first */
hitainit(UNIT(dev));
if ((UNIT(dev)) >= NODD || g->h_opfd > HMAXOPEN) {
u.u_error = EMFILE; /* too many open */
goto op_ret;
}
/* NOTE
* WICAT unix passes 0 for read and 2 for write.
most of unix pass 1 for read, 2 for write and 3 for both
* therefore there is no way to know it is opening for mode 1 or 2
*
* So, i have to get the mode from u structure!
*/
rwflag = uap->fmode;
/*
* EXCLUSIVE open is done. no open is allowd
*/
if ( (g->h_state & HEXCLUSIVE) ||
/*
* EXCLUSIVE open failes, when any open is already done
*/
(((rwflag&(HREAD|HWRITE))==(HREAD|HWRITE)) && g->h_opfd) ||
/*
* only one open for WRITE
*/
((rwflag&HWRITE) && (g->h_state & HWRITE)) )
{
u.u_error = ENXIO; /* Open fails */
goto op_ret;
}
g->h_opfd += 1;
g -> h_state |= (HOPEN | (rwflag & (HREAD|HWRITE)));
if ( (rwflag & (HREAD|HWRITE))==(HREAD|HWRITE))
g -> h_state |= HEXCLUSIVE;
op_ret:
PWakeuP
splx(x);
DEBUG(("OPEN end: h.state=%x\n",g->h_state));
}
hitaclose(dev,flag)
dev_t dev;
int flag;
{
register HITA_t *g;
int x;
DEBUG (("HITA CLOSE called, dev = %d/%d opfd=%d, flag=%x, h.state=%x\n",
major(dev), UNIT(dev),g->h_opfd,flag,hita[UNIT(dev)].h_state));
PSleeP
x = spl7();
g = &hita[UNIT(dev)];
/* ! fd is already closed before it gets here */
/* close is only called at the last close on a unit */
g->h_state = 0;
g->h_opfd = 0;
PWakeuP
splx(x);
DEBUG(("CLOSE end: h.state=%x\n",g->h_state));
}
/*
* ** NOTE **
* The WICAT UNIX system does not pass the UNIT device number to the
* interrupt handler as most UNIX systems do. So we must treat one
* interrupt as an interrupt from each.
*/
hitaintr()
{
register int i;
DEBUG (("HITA INTERRUPT called\n"));
gpib.h_sr |= ib -> sr; /* clears FIN in sr */
gpib.h_isr1 |= ib -> isr1; /* clear the interrupt by reading */
gpib.h_isr2 |= ib -> isr2;
/* is this my interrupt? */
if ( gpib.h_isr2 & HR_INTR ) {
for (i=0; i<NODD; i++) {
if (hita[i].h_state & HITASLEEP) {
hita[i].h_state &= ~(HITASLEEP);
DEBUG (("intr: waking up\n"));
wakeup( (caddr_t) (&hita[i]));
}
}
}
}
/*
* The Recent versions of UNIX (recent being later than V7)
* have an additional parameter to physio: physio(..., minphy).
* Although not used in the Xenix kernel, I've included it
* here in case this driver is ported to a newer release.
*/
hitaminphys()
{
/* No minimum i/o */
}
/*
* Setup wbuf,rbuf and woff,roff according to the given offset
* Should be called to verify the current buffer is in sync
* at the beginning of read() and write()
*/
int set_offset(dev,offset, rwflag)
dev_t dev;
off_t offset;
char rwflag;
{
register HITA_t *g = &hita[UNIT(dev)];
off_t tpbn;
int toff;
tpbn = offset/HBLOCKSIZE;
toff = offset%HBLOCKSIZE;
/* DEBUG(("set_offset: pbn=%d, off=%d, g->pbn=%d\n",tpbn,toff,g->h_pbn)); */
if (rwflag == B_READ) {
if (g->h_pbn != tpbn)
if ((g->h_pbn = rfill(dev,0,tpbn,0,0)) < 0) {
g->h_pbn = -1;
return(-1);
}
g->h_roff = toff;
} else { /* WRITE */
if (g->h_pbn != tpbn) {
if (g->h_woff)
if (wflush(dev,0,g->h_pbn,0,0) < 0) {
g->h_pbn = -1;
return(-1);
}
g->h_pbn = tpbn;
}
g->h_woff = toff;
}
return(0);
}
hitarw(dev, offset, count, flags)
dev_t dev;
off_t offset;
unsigned int count;
char flags;
{
register HITA_t *g = &hita[UNIT(dev)];
register struct file *fp;
register struct a {
int fdes;
char *cbuf;
unsigned count;
} *uap;
DEBUG (("HITArw %s offset=%d, count=%d\n",
flags & B_READ ? "READ":"WRITE", offset, count));
if (count == 0)
return;
if ((UNIT(dev)) >= NODD)
{
u.u_error = ENXIO;
return;
}
uap = (struct a *)u.u_ap;
GETF(fp, uap->fdes);
DEBUG (("HITA XFER: %d bytes\n", count));
/*
* IMPORTATANT! only one exit from this routine after this point
*/
/*
* adjust the device buffer and offset
*/
if (set_offset(dev,offset,flags) < 0)
goto error_ret;
/*
* count = how many more to read.
* offset = offset from the beginning of the file
*/
if (flags == B_READ) {
register int t;
if (count >= (t = HBUFSIZE-(g->h_roff))) {
if (t) {
iomove(&g->h_rbuf[g->h_roff],t,B_READ); /* empty the buffer */
count -= t;
}
for(; count>=HBUFSIZE; count -= HBUFSIZE) {
if (rfill(dev,0,++g->h_pbn,0,0) < 0) {
g->h_pbn = -1;
goto ok_ret;
}
iomove(g->h_rbuf,HBUFSIZE,B_READ);
}
if (rfill(dev,0,++g->h_pbn,0,0) < 0) {
g->h_pbn = -1;
goto ok_ret;
}
}
if (count) {
iomove(&g->h_rbuf[g->h_roff],count,B_READ); /* read from rbuf */
g->h_roff +=count;
}
} else { /* WRITE */
register int t;
if (count >= (t = HBUFSIZE-(g->h_woff))) {
if (t) {
iomove(&g->h_wbuf[g->h_woff],t,B_WRITE); /* fill it up */
count -= t;
}
for(; count>=HBUFSIZE; count -= HBUFSIZE) {
if (wflush(dev,0,g->h_pbn,0,0) < 0) {
g->h_woff = 0;
goto error_ret;
}
g->h_pbn += 1;
iomove(g->h_wbuf,HBUFSIZE,B_WRITE);
}
if (wflush(dev,0,g->h_pbn,0,0) < 0) {
g->h_woff = 0;
goto error_ret;
}
g->h_pbn += 1;
}
if (count) {
iomove(&g->h_wbuf[g->h_woff],count,B_WRITE);
g->h_woff +=count;
}
}
goto ok_ret;
error_ret:
u.u_error = EIO;
g->h_pbn = -1;
ok_ret:
return;
}
hitaread(dev)
dev_t dev;
{
int x;
/* DEBUG (("HITA READ called, dev = %d/%d\n", major(dev), UNIT(dev))); */
PSleeP
x = spl7();
hitarw(dev,(int) u.u_offset, u.u_count, B_READ);
PWakeuP
splx (x);
}
hitawrite(dev)
dev_t dev;
{
int x;
/* DEBUG(("HITA WRITE: dev=%d/%d, count=%d\n",
major(dev),UNIT(dev),u.u_count)); */
PSleeP
x = spl7();
hitarw(dev,(int) u.u_offset, u.u_count, B_WRITE);
PWakeuP
splx (x);
}
ss(dev,cmd,paddr,lmta,lmla)
dev_t dev;
int cmd;
char lmta,lmla;
caddr_t paddr;
{
register int i;
char ret,t,crc1,crc2;
char dd[24];
char s[300];
register HITA_t *g = &hita[UNIT(dev)];
DEBUG(("SS(%d,mta=%d,mla=%d) called\n",cmd,lmta,lmla));
/* init the ib and set it to active taker */
active('t'); /* active */
cmdone(UNT);
cmdone(UNL);
cmdone(lmla);
pon();
/* send the LOCK (hitachi) command as data */
dataone(CONTROL_OP);
dataone(SS_OR);
switch(cmd) {
case 's':
/* DEBUG(("Read secondary status\n")); */
dataone(READSS);
break;
case 't':
/* DEBUG(("Sector status\n")); */
dataone(SECTOR);
break;
case 'c':
/* DEBUG(("Cell status\n")); */
dataone(CELLSTAT);
break;
case 'o':
/* DEBUG(("OD status\n")); */
dataone(ODSTAT);
break;
case 'd':
/* DEBUG(("Device ID status\n")); */
dataone(DEVID);
break;
}
dataone(~(CONTROL_OP));
dataone(~(SS_OR));
switch(cmd) {
case 's':
dataone(~(READSS));
break;
case 't':
dataone(~(SECTOR));
break;
case 'c':
dataone(~(CELLSTAT));
break;
case 'o':
dataone(~(ODSTAT));
break;
case 'd':
dataone(~(DEVID));
break;
}
dd[0] = SS_POP;
for (i=1; i<18; i++)
dd[i] = 0;
crc(dd,&dd[17],&crc1,&crc2);
for (i=0; i<18; i++)
dataone(dd[i]);
dataone(crc1);
/* send EOI */
eoi();
dataone(crc2);
if (getstat(dev)) {
switch(cmd) {
case 's':
/* copyout(ss_stat,paddr,HSTAT_L_SS); just save it */
break;
case 't':
copyout(sect_stat,paddr,HSTAT_L_SECT);
break;
case 'c':
copyout(cell_stat,paddr,HSTAT_L_CELL);
break;
case 'o':
copyout(odd_stat,paddr,HSTAT_L_ODDS);
break;
case 'd':
copyout(devid_stat,paddr,HSTAT_L_DEVID);
break;
}
return(0);
}
return(EFAULT);
}
control(dev,cmd,paddr,lmta,lmla)
dev_t dev;
int cmd;
char lmta,lmla;
caddr_t paddr;
{
register int i;
char side = 0;
int cell;
char crc1,crc2,dd[24];
char s[32];
DEBUG (("CONTROL(cmd=%c,paddr=%x,mta=%d,mla=%d) called\n",cmd,paddr,lmta,lmla));
/* init the ib and set it to active taker */
active('t'); /* active */
/* init the hitachi */
cmdone(UNT);
cmdone(UNL);
cmdone(lmla);
pon();
/* send the LOCK (hitachi) command as data */
dataone(CONTROL_OP);
dataone(CONTROL_OR);
switch(cmd) {
case 'm':
DEBUG(("Mount/Lock\n"));
cell = whibyte( ((int) paddr) );
if (cell < 0 || cell > 31) {
DEBUG(("Invalid cell number (%d)\n",cell));
return(HERR_BADCELL);
}
side = wlowbyte( ((int) paddr) );
if (side != 'a' && side != 'b') {
DEBUG(("Invalid side (%x)\n",side));
return(HERR_BADSIDE);
}
dataone(MOUNT);
break;
case 'd':
DEBUG(("Demount/Unlock\n"));
cell = whibyte( ((int) paddr) );
if (cell < 0 || cell > 31) {
DEBUG(("Invalid cell number (%d)\n",cell));
return(HERR_BADCELL);
}
side = 'a';
dataone(DEMOUNT);
break;
case 'l':
/* DEBUG(("Lock\n")); */
dataone(MOUNT);
break;
case 'u':
/* DEBUG(("Unlock\n")); */
dataone(DEMOUNT);
break;
case 'c':
/* DEBUG(("Change\n")); */
dataone(CHANGE);
break;
case 'e':
/* DEBUG(("Eject\n")); */
cell = whibyte( ((int) paddr) );
if (cell < 0 || cell > 31) {
DEBUG(("Invalid cell number (%d)\n",cell));
return(HERR_BADCELL);
}
side = wlowbyte( ((int) paddr) );
if (side != 'i' && side != 'o') {
DEBUG(("Invalid side (%x)\n",side));
return(HERR_BADSIDE);
}
dataone(EJECT);
break;
case 'r':
/* DEBUG(("Rezero\n")); */
dataone(REZERO);
break;
case 'n':
/* DEBUG(("Noop\n")); */
dataone(NOP);
break;
}
dataone(~(CONTROL_OP));
dataone(~(CONTROL_OR));
switch(cmd) {
case 'm':
dataone(~(MOUNT));
break;
case 'd':
dataone(~(DEMOUNT));
break;
case 'l':
dataone(~(MOUNT));
break;
case 'u':
dataone(~(DEMOUNT));
break;
case 'c':
dataone(~(CHANGE));
break;
case 'e':
dataone(~(EJECT));
break;
case 'r':
dataone(~(REZERO));
break;
case 'n':
dataone(~(NOP));
break;
}
if (side) { /* mount or demount, send cell format (2 bytes) */
dd[0] = 0;
dd[1] = 0;
dd[2] = 0;
switch(side) {
case 'a':
dd[3] = 0x40; /* de/mount side a */
break;
case 'b':
dd[3] = 0xc0; /* de/mount side b */
break;
case 'i':
dd[3] = 0; /* eject. store only */
break;
case 'o':
dd[3] = 0x40; /* eject. eject out and store in */
}
dd[4] = cell;
for (i=5; i<18; i++)
dd[i] = 0;
crc(dd,dd+17,&crc1,&crc2);
for (i=0; i<18; i++)
dataone(dd[i]);
dataone(crc1);
eoi();
dataone(crc2);
} else {
for (i=0; i<18; i++) /* need to put Cell number for mount/demount */
dd[i] = 0;
crc(dd,dd+17,&crc1,&crc2);
for (i=0; i<18; i++) /* need to put Cell number for mount/demount */
dataone(dd[i]);
dataone(crc1);
eoi();
dataone(crc2);
}
return(getstat(dev)); /* FIX it to return a correct error code */
}
/*
* Seek (in a character device!?)
* Hitachi character dev is special.
* An extra entry in the file struct. I think its needed it, anyway.
*/
hseek(dev,paddr)
caddr_t paddr;
{
register HITA_t *g = &hita[UNIT(dev)];
register struct file *fp;
register struct a {
int fdes;
int cmd;
caddr_t cmarg;
} *uap;
/* flush the read buffer whenever SEEK is done */
g->h_roff = HBLOCKSIZE;
uap = (struct a *)u.u_ap;
GETF(fp, uap->fdes);
/*
* If it is writing and the wbuffer is not empty, it's flushed.
*/
if (fp->f_flag&FWRITE && g->h_woff)
if (wflush(dev,0,g->h_pbn,0,0) < 0) {
u.u_error = EIO;
return;
}
g->h_woff = 0;
fp->f_un.f_offset = (long)paddr * HBLOCKSIZE;
/* DEBUG(("hseek: offset=%d, paddr=%d\n",
fp->f_un.f_offset, (long)paddr)); */
}
/*
* flush the wbuf to the disk (actual i/o happens here)
* woff = 0
* init wbuf with 0
* returns pbn to where the block is written or -1 on error
*/
off_t wflush(dev,fg,pbn,pbcnt,pphys)
dev_t dev;
char fg;
off_t pbn;
int pbcnt;
caddr_t pphys;
{
register HITA_t *g = &hita[UNIT(dev)];
register int j,i;
int cell;
char ret,crc1,crc2,dd[24];
long offs;
int fd,bcnt;
DEBUG(("wflush: pbn=%d\n",pbn));
if (!fg) {
pbcnt = 1;
pphys = 0;
}
/* init the ib and set it to active taker */
active('t'); /* active */
/* ready to talk to hitachi */
/* init the hitachi */
cmdone(UNT);
cmdone(UNL);
cmdone(g->h_mla);
pon();
/* send the LOCK (hitachi) command as data
* Write/alt track
*/
dataone(CONTROL_OP);
dataone(0x1);
dataone(0xe0);
dataone(~(CONTROL_OP));
dataone(~(0x1));
dataone(~(0xe0));
dd[0] = 0xc0; /* POP for data transfer with no CRC */
dd[1] = dd[2] = 0;
dd[3] = 0xff & (pbn >> 24); /* pbn */
dd[4] = 0xff & (pbn >> 16);
dd[5] = 0xff & (pbn >> 8);
dd[6] = 0xff & pbn;
dd[7] = 0xff & (pbcnt >> 8); /* block count, hibyte */
dd[8] = 0xff & pbcnt; /* lowbyte */
dd[9]=dd[10]=dd[11]=dd[12] = 0; /* offset for dual write */
for (i=13; i<18; i++)
dd[i] = 0;
crc(dd,&dd[17],&crc1,&crc2);
for (i=0; i<18; i++) { /* send the command */
dataone(dd[i]);
}
dataone(crc1);
eoi();
dataone(crc2);
if (getstat(dev) == 0) {
/* this is done in getstat()
active('t');
cmdone(UNT);
cmdone(UNL);
*/
cmdone(g->h_mla);
pon();
dataone(0xc0); /* data trx again, must match with POP */
dataone(0);
dataone(0);
dataone(~(0xc0));
dataone(0xff);
dataone(0xff);
if (fg) {
for(; pbcnt>=63; pbcnt -= 63, pphys += 32256) {
if (pbcnt == 63)
break;
if (dma(dev,'w',pphys,32256) != 32256) { /* 63*512 */
pbn = -1;
pbcnt = 0;
break;
}
}
if (pbcnt) {
if (dma(dev,'l',pphys,pbcnt*512) != (pbcnt*512))
pbn = -1;
}
if (getstat(dev))
pbn = -1;
} else {
if ( ((dma(dev,'l',g->h_wbuf,HBUFSIZE)) != HBUFSIZE) ||
getstat(dev) )
pbn = -1;
}
} else {
pbn = -1;
}
/* done in getstat()
active('t');
cmdone(UNT);
cmdone(UNL);
*/
g->h_woff = 0;
for (i=0; i<HBUFSIZE; i++)
g->h_wbuf[i] = 0;
return(pbn);
}
/*
* fill the rbuf
* set hita.roff = 0
* returns pbn from where the data is read or -1 on error
*/
off_t rfill(dev,fg,pbn,pbcnt,pphys)
dev_t dev;
char fg;
off_t pbn;
int pbcnt;
caddr_t pphys;
{
register int i,j;
register HITA_t *g = &hita[UNIT(dev)];
char ret,crc1,crc2,dd[24],con[12];
DEBUG(("rfill: pbn=%d\n",pbn));
if (!fg) {
pbcnt = 1;
pphys = 0;
}
/* init the ib and set it to active taker */
active('t'); /* active */
/* init the hitachi */
cmdone(UNT);
cmdone(UNL);
cmdone(g->h_mla);
pon();
/* send the LOCK (hitachi) command as data */
dataone(CONTROL_OP);
/* Logical Read */
dataone(RD_OR);
dataone(RDL_NO);
dataone( ~(CONTROL_OP));
dataone( ~(RD_OR));
dataone( ~(RDL_NO));
dd[0] = 0xc0; /* POP for data transfer with no CRC */
dd[1] = dd[2] = 0;
dd[3] = 0xff & (pbn >> 24);
dd[4] = 0xff & (pbn >> 16);
dd[5] = 0xff & (pbn >> 8);
dd[6] = 0xff & pbn;
dd[7] = 0xff & (pbcnt >> 8);
dd[8] = 0xff & pbcnt;
dd[9]=dd[10]=dd[11]=dd[12] = 0; /* offset */
for (i=13; i<18; i++)
dd[i] = 0;
for (i=0; i<18; i++)
dataone(dd[i]);
crc(dd,dd+17,&crc1,&crc2);
dataone(crc1);
eoi();
dataone(crc2);
if (getstat(dev) == 0) {
active('l');
cmdone(UNT);
cmdone(UNL);
cmdone(g->h_mta);
listen_sb();
/* read and print */
gpib.h_isr1 &= ~(HR_END);
for (i=0; i<6; i++) /* through away the header for now */
readone(dev);
if (fg) { /* fast read */
for(; pbcnt>=63; pbcnt -= 63, pphys += 32256) {
if (dma(dev,'r',pphys,32256) != 32256) { /* 63*512 */
pbn = -1;
pbcnt = 0;
break;
}
}
if (pbcnt) {
if (dma(dev,'r',pphys,pbcnt*512) != (pbcnt*512))
pbn = -1;
}
if (getstat(dev))
pbn = -1;
} else {
if( ((i=dma(dev,'r',g->h_rbuf,HBUFSIZE)) != HBUFSIZE) ||
getstat(dev) )
pbn = -1;
}
} else {
pbn = -1;
}
/* done in getstat()
active('t');
cmdone(UNT);
cmdone(UNL);
*/
if (!fg)
g->h_roff = 0;
return(pbn);
}
hflush(dev)
{
register HITA_t *g = &hita[UNIT(dev)];
register struct file *fp;
register struct a {
int fdes;
int cmd;
caddr_t cmarg;
} *uap;
uap = (struct a *)u.u_ap;
GETF(fp, uap->fdes);
if (fp->f_flag&FWRITE && g->h_woff)
if (wflush(dev,0,g->h_pbn,0,0) < 0) {
u.u_error = EIO;
return;
}
++g->h_pbn;
g->h_woff = 0;
}
hsrchunwtn(dev,paddr)
dev_t dev;
caddr_t paddr;
{
register HITA_t *g = &hita[UNIT(dev)];
register int i,j;
char ret,crc1,crc2,dd[300];
HIOCTL_t io;
off_t pbn;
active('t'); /* active */
cmdone(UNT);
cmdone(UNL);
cmdone(g->h_mla);
pon();
/* Search Unwritten block */
dataone(CONTROL_OP);
dataone(RD_OR);
dataone(RD_SU);
dataone(~(CONTROL_OP));
dataone(~(RD_OR));
dataone(~(RD_SU));
dd[0] = 0; /* search unwritten command */
dd[1] = dd[2] = 0;
copyin( paddr, &io, sizeof(HIOCTL_t));
/* DEBUG(("HSRCHUNWTN: pbn=%d, bcnt=%d\n",io.h_start_pbn,io.h_bcnt)); */
dd[3] = 0xff & (io.h_start_pbn >> 24);
dd[4] = 0xff & (io.h_start_pbn >> 16);
dd[5] = 0xff & (io.h_start_pbn >> 8);
dd[6] = 0xff & io.h_start_pbn;
dd[7] = 0xff & (io.h_bcnt >> 8);
dd[8] = 0xff & io.h_bcnt;
for (i=9; i<18; i++)
dd[i] = 0;
for (i=0; i<18; i++)
dataone(dd[i]);
crc(dd,dd+17,&crc1,&crc2);
dataone(crc1);
eoi();
dataone(crc2);
/* get the sector status to find the result */
if (getstat(dev) == 0x61) {
if (sect_stat[4] == 0 && sect_stat[5] == 0) {
/* DEBUG(("HSRCHUNWTN: failed.\n")); */
u.u_error = EFAULT;
} else {
pbn = 0xff & sect_stat[0];
pbn = (pbn << 8) + (0xff & sect_stat[1]);
pbn = (pbn << 8) + (0xff & sect_stat[2]);
pbn = (pbn << 8) + (0xff & sect_stat[3]);
/* DEBUG(("HSRCHUNWTN: unwritten pbn = %d\n",pbn)); */
io.h_start_pbn = pbn;
copyout(&io, paddr, sizeof(HIOCTL_t));
}
} else {
u.u_error = EFAULT;
}
active('t');
cmdone(UNT);
cmdone(UNL);
}
hdelete(dev,paddr)
dev_t dev;
caddr_t paddr;
{
register HITA_t *g = &hita[UNIT(dev)];
register int i,j;
HIOCTL_t io;
char ret,crc1,crc2,dd[24];
active('t'); /* active */
cmdone(UNT);
cmdone(UNL);
cmdone(g->h_mla);
pon();
/* Delete */
dataone(CONTROL_OP);
dataone(0x11);
dataone(0x80);
dataone(~(CONTROL_OP));
dataone(~(0x11));
dataone(~(0x80));
dd[0] = 0; /* search unwritten command */
dd[1] = dd[2] = 0;
copyin( paddr, &io, sizeof(HIOCTL_t)); /* hope bytes are in right order */
/* DEBUG(("HDELETE: start_pbn=%d, bcnt=%d\n", io.h_start_pbn,io.h_bcnt)); */
dd[3] = 0xff & (io.h_start_pbn >> 24);
dd[4] = 0xff & (io.h_start_pbn >> 16);
dd[5] = 0xff & (io.h_start_pbn >> 8);
dd[6] = 0xff & io.h_start_pbn;
dd[7] = 0xff & (io.h_bcnt >> 8); /* block count */
dd[8] = 0xff & io.h_bcnt;
for (i=9; i<18; i++)
dd[i] = 0;
for (i=0; i<18; i++)
dataone(dd[i]);
crc(dd,dd+17,&crc1,&crc2);
dataone(crc1);
eoi();
dataone(crc2);
/* get the sector status to find the result */
if(getstat(dev))
u.u_error = EIO;
}
/*
* fast i/o
* does not change the standard I/O buffer
*/
hfast(dev,paddr)
dev_t dev;
caddr_t paddr;
{
register off_t fpbn;
register int fbcnt;
register caddr_t fpaddr;
HIOCTL_t io;
copyin( paddr, &io, sizeof(HIOCTL_t)); /* hope bytes are in right order */
/* DEBUG(("HFAST: rw=%c,start_pbn=%d, bcnt=%d, phys_addr=%d\n",
io.h_rw,io.h_start_pbn,io.h_bcnt,io.h_phys_addr)); */
if ((fbcnt = io.h_bcnt) < 0 || (fpbn = io.h_start_pbn) < 0 ||
(fpaddr = io.h_phys_addr) < 0) {
u.u_error = EIO;
return;
}
DEBUG(("HFAST: pbn=%d, bcnt=%d, phys_addr=%d\n",fpbn,fbcnt,fpaddr));
if (io.h_rw == 'r') { /* read */
if (rfill(dev,1,fpbn,fbcnt,fpaddr) < 0)
u.u_error = EIO;
} else {
if (wflush(dev,1,fpbn,fbcnt,fpaddr) < 0)
u.u_error = EIO;
}
}
hitaioctl(dev, cmd, paddr)
dev_t dev;
int cmd;
caddr_t paddr;
{
register HITA_t *g;
int x;
register struct file *fp;
register struct a {
int fdes;
int cmd;
caddr_t cmarg;
} *uap;
HFMS_t *lfms;
DEBUG(("IOCTL: dev=%d/%d, cmd=%d, addr=%o\n",major(dev),UNIT(dev),cmd));
PSleeP
x = spl7();
uap = (struct a *)u.u_ap;
GETF(fp, uap->fdes);
if ((UNIT(dev)) >= NODD)
{
u.u_error = ENXIO;
goto ctl_ret;
}
g = &hita[UNIT(dev)];
switch (cmd)
{
case HCLOSEWRITE:
if (fp->f_flag & HWRITE)
g->h_state &= ~(HWRITE|HEXCLUSIVE);
break;
case HFAST:
hfast(dev,paddr);
break;
case HLGETFMS:
lfms = (HFMS_t *) &fms[UNIT(dev)][0];
lfms->fms_state |= FMS_LOCK;
copyout((caddr_t) &fms[UNIT(dev)][0],paddr,sizeof(HFMS_t));
break;
case HULFMS:
lfms = (HFMS_t *) &fms[UNIT(dev)][0];
lfms->fms_state &= ~FMS_LOCK;
break;
case HGETFMS:
copyout((caddr_t) &fms[UNIT(dev)][0],paddr,sizeof(HFMS_t));
break;
case HPUTFMS:
copyin(paddr,(caddr_t) &fms[UNIT(dev)][0],sizeof(HFMS_t));
break;
case HDELETE:
hdelete(dev,paddr);
break;
case HSRCHUNWTN:
hsrchunwtn(dev,paddr);
break;
case HFLUSH:
hflush(dev);
break;
case HSEEK:
hseek(dev,paddr);
break;
case HREZERO:
u.u_error = control(dev,'r', paddr, g->h_mta, g->h_mla);
break;
case HMOUNT:
u.u_error = control(dev,'m', paddr, g->h_mta, g->h_mla );
break;
case HDMOUNT:
lfms = (HFMS_t *) &fms[UNIT(dev)][0];
lfms->fms_state = FMS_NOT_MOUNTED;
lfms->fms_ocnt = 0;
u.u_error = control(dev,'d', paddr, g->h_mta, g->h_mla );
break;
case HLIBOPEN:
u.u_error = control(dev,'e', paddr, g->h_mta, g->h_mla );
break;
case HFLIP:
u.u_error = control(dev,'c', paddr, g->h_mta, g->h_mla );
break;
case HNOOP:
u.u_error = control(dev,'n', paddr, g->h_mta, g->h_mla );
break;
case HSS:
copyout(ss_stat,paddr,HSTAT_L_SS);
u.u_error = ss(dev,'s', paddr, g->h_mta, g->h_mla );
break;
case HSECTS:
copyout(sect_stat,paddr,HSTAT_L_SECT);
break;
case HODDS:
u.u_error = ss(dev,'o', paddr, g->h_mta, g->h_mla );
break;
case HCELLS:
u.u_error = ss(dev,'c', paddr, g->h_mta, g->h_mla );
break;
case HDEVID:
u.u_error = ss(dev,'d', paddr, g->h_mta, g->h_mla );
break;
default:
u.u_error = EINVAL;
break;
}
ctl_ret:
PWakeuP
splx(x);
}
//E*O*F hita.c
echo x - hita.h
cat << '//E*O*F hita.h' > hita.h
/* hita.h 1.0 85/04/23 */
/* Hitachi optical disk driver ioctrl commands */
/* Author: Jungbo Yang 4/23/85 */
#define HREZERO 1 /* home the optical head */
#define HMOUNT 2 /* mount/lock */
#define HDMOUNT 3 /* demount/unlock */
#define HLIBOPEN 4 /* eject */
#define HFLIP 5 /* change */
#define HNOOP 6 /* noop */
#define HSS 7 /* read second status */
#define HODDS 8 /* read OD status */
#define HCELLS 9 /* read Cell status */
#define HDEVID 10 /* read Device ID */
#define HSEEK 11 /* seek */
#define HFLUSH 12 /* flush */
#define HSRCHUNWTN 13 /* search unwritten blocks(62) */
#define HDELETE 14 /* delete */
#define HGETFMS 15 /* get FM Structure */
#define HPUTFMS 16 /* put FM Structure */
#define HFAST 17 /* fast I/O */
#define HSECTS 18 /* sector status */
#define HEXCL 19 /* exclusive use request */
#define HCLOSEWRITE 20 /* close write ********* */
#define HLGETFMS 21 /* getfms with locking fms */
#define HULFMS 22 /* unlock fms */
/* NOTE
* this is because close() is called only at the last close call
* no way to know when the write operation did close()
* close() is redefined to do this automatically
*/
int close();
static int (*hclose)() = close;
#define close(x) { \
ioctl(x,HCLOSEWRITE,0); \
(*hclose)(x); \
}
#define gethk_cell(x,y) hk_cell(1,x,y)
#define puthk_cell(x,y) hk_cell(0,x,y)
#define RD_OR 0x2 /* read commands */
#define RD_DCI 0x1 /* bit location. OR it */
#define RD_DUAL 0x40 /* bit location */
#define RDL_NO 0x10 /* logical read */
#define RDP_NO 0x20 /* physical read */
#define RD_SU 0x40 /* search unwritten */
#define RD_SD 0x80 /* skip deleted blocks */
/*
* status data length
*/
#define HSTAT_L_SS 24
#define HSTAT_L_DEVID 6
#define HSTAT_L_ODDS 24
#define HSTAT_L_CELL 256
#define HSTAT_L_SECT 254
/* error codes */
#define HERR_BADCELL 1
#define HERR_BADSIDE 2
/* from vax750 */
#define GETF(fp, fd) { \
if ((unsigned)(fd) >= NOFILE || ((fp) = u.u_ofile[fd]) == NULL) { \
u.u_error = EBADF; \
return; \
} \
}
#define HBLOCKSIZE 512 /* hitachi block size */
#define HBUFSIZE 512 /* kernel buffer size */
#define HMAXOPEN 20 /* max number of open per device */
#define HITAPRI PRIBIO+1 /* priority for sleep() just slower than fs */
typedef struct
{
short h_state; /* drive status */
/* OPEN, WRITE */
short h_opfd; /* number of open */
char h_mta; /* IEEE488 MTA */
char h_mla; /* IEEE488 MLA */
short h_opop; /* operation options */
/* Dual write */
/* Delete check inhibit */
off_t h_pbn; /* current pbn */
/* location of the next read or write */
short h_woff; /* write buffer pointer */
short h_roff; /* read buffer pointer */
char h_rbuf[HBUFSIZE]; /* read buffer */
char h_wbuf[HBUFSIZE]; /* write buffer */
} HITA_t;
typedef struct {
char h_isr1; /* interrupt status */
char h_isr2; /* interrupt status */
char h_sr; /* interface board status */
} HGPIB_t;
typedef struct {
char h_rw;
off_t h_start_pbn;
short h_bcnt;
caddr_t h_phys_addr;
} HIOCTL_t;
//E*O*F hita.h
echo x - hitachi.h
cat << '//E*O*F hitachi.h' > hitachi.h
/* hitachi.h 4/23/85 */
/*
Test program for GPIB 796 and Hitachi (OFC)
Sends LOCK and UNLOCK commands to OFC
*/
/* Author: Jungbo Yang 4/23/85 */
/* read only register and write only registers */
#define dir cdor
#define isr1 imr1
#define isr2 imr2
#define spsr spmr
#define adsr admr
#define cptr auxmr
#define adr0 adr
#define adr1 eosr
#define sr cr0
/* Control masks for hidden registers (auxmr) */
#define LISTEN 0x13
#define SB 0x10
#define ICR 0040
#define PPR 0140
#define AUXRA 0200
#define AUXRB 0240
#define AUXRE 0300
/* Hardware register bit definitions */
/* Name Bit(s) register */
#define HR_DI (1<<0) /* isr1 */
#define HR_DO (1<<1) /* isr1 */
#define HR_END (1<<4) /* isr1 */
#define HR_DOIE (1<<1) /* imr1 */
#define HR_ENDIE (1<<4) /* imr1 */
#define HR_CO (1<<3) /* isr2 */
#define HR_SRQI (1<<6) /* isr2 */
#define HR_INTR (1<<7) /* isr2 */
#define HR_COIE (1<<3) /* imr2 */
#define HR_DMAI (1<<4) /* imr2 */
#define HR_DMAO (1<<5) /* imr2 */
#define HR_SRQIE (1<<6) /* imr2 */
#define HR_ADM0 (1<<0) /* admr */
#define HR_TRM0 (1<<4) /* admr */
#define HR_TRM1 (1<<5) /* admr */
#define HR_TON (1<<7) /* admr */
#define HR_LON (1<<6) /* admr */
#define HR_DL (1<<5) /* adr */
#define HR_DT (1<<6) /* adr */
#define HR_ARS (1<<7) /* adr */
#define HR_GO (1<<0) /* cr0 */
#define HR_DMAE (1<<1) /* cr0 */
#define HR_LMR (1<<2) /* cr0 */
#define HR_FINIE (1<<3) /* cr0 */
#define HR_MEMRD (1<<4) /* cr0 */
#define HR_ECC (1<<6) /* cr0 */
#define HR_NSRQ (1<<0) /* sr , this bit not used! */
#define HR_NFIN (1<<5) /* sr */
#define HR_NGPIBIR (1<<6) /* sr */
#define HR_DONE (1<<7) /* sr */
#define HR_CBRQ (1<<5) /* cr1 */
#define HR_SC (1<<3) /* cr1 */
#define HR_MIE (1<<7) /* cr1 */
#define HR_BURST (1<<6) /* cr1 */
#define HR_BTIME (7) /* cr1 */
#define HR_HLDA (1<<0) /* auxra */
#define HR_HLDE (1<<1) /* auxra */
#define HR_INV (1<<3) /* auxrb */
#define HR_PPU (1<<4) /* ppr */
#define HR_CIC (1<<7) /* adsr */
#define HR_TA (1<<1) /* adsr */
#define HR_LA (1<<2) /* adsr */
/* 7210 Auxiliary Commands */
#define AUX_PON 000 /* Immediate Execute pon */
#define AUX_FH 003 /* Finish handshake */
#define AUX_SEOI 006 /* Send EOI */
#define AUX_TCA 021 /* Take Control Asynchronously */
#define AUX_GTS 020 /* Go To Standby */
#define AUX_EPP 035 /* Execute Parallel Poll */
#define AUX_SIFC 036 /* Set IFC */
#define AUX_CIFC 026 /* Clear IFC */
#define AUX_SREN 037 /* Set REN */
#define AUX_CREN 027 /* Clear REN */
/* ieep 488 codes */
#define UNT '_'
#define UNL '?'
#define SPE '\030'
#define SPD '\031'
#define DCL '\024' /* device clear */
/* define talker and listers addresses */
#define MTA 0100
#define MLA 040
/* define hitachi commands */
/* control operations */
#define CONTROL_OP 0x89
#define CONTROL_OR 0x3
#define REZERO 0x0 /* rezero */
#define MOUNT 0x1 /* mount/lock */
#define DEMOUNT 0x2 /* demount/unlock */
#define EJECT 0x3 /* eject */
#define CHANGE 0x4 /* change */
#define NOP 0xf /* nop */
#define CRC1 0x5d /* default. all zero data */
#define CRC2 0x2a
/* send status operations */
#define SS_OP 0x49 /* no CRC? . use CONTROL_SS */
#define SS_OR 0x4
#define READSS 0x0
#define SECTOR 0x1
#define ODSTAT 0xc
#define CELLSTAT 0x8
#define DEVID 0x9
#define SS_POP 0x69 /** no CRC */
/*
* For converting addresses (long)
*/
#define lobyte(x) ((long)(x) & 0377)
#define midbyte(x) (((long)(x) >> 8) & 0377)
#define hibyte(x) (((long)(x) >> 16) & 0377)
//E*O*F hitachi.h
echo x - opt_fs.h
cat << '//E*O*F opt_fs.h' > opt_fs.h
/* opt_fs.h 4/23/85 */
/* Hitachi Optical Disk Filesystem */
/* Author: Jungbo Yang 7/8/85 */
/* error codes */
#define E_OK 0 /* no error. successful return */
#define E_VOLUME -1 /* invalid volume */
#define E_OPEN -2 /* open error */
#define E_READ -3 /* read error */
#define E_BADMODE -4 /* bad open mode */
#define E_NOT_MOUNTED -5 /* volume not mounted */
#define E_FIXFMS -6 /* cannot fix FMS */
#define E_FDESC -7 /* no more free desc block */
#define E_FREE -8 /* no more free file block */
#define E_WR_DESC -9 /* write_desc error */
#define E_FREAD -10 /* fast read error */
#define E_FWRITE -11 /* fast write error */
#define E_NOVID -12 /* no more volume block */
#define E_SEEK -13 /* hseek error */
#define E_SRCHUNWTN -14 /* srchunwtn error */
#define E_WRITE -15 /* write error */
#define E_BADFMS -16 /* bad FMS */
#define E_IOCTL -17 /* ioctl error return */
#define E_BADPBN -18 /* bad pbn */
#define E_FULL -19 /* disk full */
#define E_BADVD -20 /* bad volume descriptor */
#define E_BADFD -21 /* bad file descriptor */
#define E_FDMANY -22 /* too many open files */
#define E_BUSY -23 /* resource busy */
#define E_EMPTY -24 /* fs empty */
#define E_BADDRV -25 /* bad drive number */
#define E_BADVID -26 /* bad volume id */
#define E_BADVTYPE -27 /* bad volume type */
#define E_BADFS -28 /* bad fs layout */
#define E_BADSIDE -29 /* bad fs layout */
#define E_BADVLAB -30 /* bad volume label */
#define E_OUTSWAP -31 /* out swap error */
#define E_NOT_IN_JUKEBOX -32 /* volume not found in jukebox */
#define E_DOOR -33 /* open/close door operation error */
#define E_LOAD -34 /* platter loading error */
#define E_UNLOAD -35 /* platter unloading error */
#define E_HK_FILE -36 /* housekeeping file error */
#define E_FMHK -37 /* housekeeping file error */
#define E_HK_CELL -38 /* bad cell entry in hk file */
#define E_DOOR_OPEN -39 /* jukebox door is open */
#define E_LAST -39 /* last error code */
/* FMS */
#define VIDLEN 16 /* size of volume id in bytes */
#define FNAMELEN 16
#define VNAMELEN 32
#define FMS_VLEN (2*62) /* number of volume block */
#define FMS_NCELL 32 /* number of cells in jukebox */
#define FMS_OK 0 /* fms_dstat, fms_fstat */
#define FMS_DIRTY 1 /* fms_dstat, fms_fstat */
#define FMS_NOT_MOUNTED 0 /* fms_state */
#define FMS_MOUNTED 1 /* fms_state */
#define FMS_WRITE 2 /* fms_state */
#define FMS_EXCLUSIVE 4 /* fms_state */
#define FMS_OPENED 8 /* fms_state */
#define FMS_EMPTY 0x10 /* fms_state */
#define FMS_BADISK 0x20 /* fms_state */
#define FMS_LOCK 0x8000 /* fms_state */
#define FMS_0DRIVE "/dev/hitaa" /* drive 0 */
#define FMS_1DRIVE "/dev/hitab" /* drive 1 */
#define TYPE_IMAGE 0 /* fs type */
#define TYPE_BACKUP 1 /* fs type */
#define SIDE_A 0 /* platter side a */
#define SIDE_B 1 /* platter side b */
#define FMHK_NAME "fmhousekeeping"
#define NCELL 64 /* number of platters in jukebox */
extern int hk_file(),hk_cell();
#define lockhk_file() hk_file(1)
#define relhk_file() hk_file(0)
#define gethk_cell(a,b) hk_cell(1,a,b)
#define puthk_cell(a,b) hk_cell(0,a,b)
#include <time.h>
typedef struct { /* FM Structure definition */
short fms_state; /* file system status */
char fms_vol[VIDLEN]; /* volume ID */
long fms_dfree; /* next free PBN in descriptor area */
short fms_dstat; /* descriptor area status */
/* status values, such as */
/* OK - normal */
/* DIRTY - d_free is wrong */
long fms_ffree; /* next free PBN in file are */
short fms_fstat; /* file area status */
/* status values, such as */
/* OK - normal */
/* DIRTY - f_free is wrong */
long fms_vstart; /* volume area */
long fms_dstart; /* desc area */
long fms_fstart; /* file area */
long fms_sstart; /* spare area */
short fms_ocnt; /* open proc count. should be 0 when fms_state
is not FMS_OPENED */
short fms_cell; /* keeps jukebox cell number here */
} HFMS_t;
/* File descriptor structure */
typedef struct {
char f_name[16]; /* file verification area */
short f_version; /* format version number */
struct tm f_time; /* time */
long f_type; /* file type */
long f_pbn; /* starting physical block number */
long f_dpbn; /* desc physical block number */
long f_bcnt; /* length of file in bytes */
char f_acc[16]; /* account number (null terminated) */
char f_ff[16]; /* file folder number (null terminated) */
long f_doc; /* document number */
long f_page; /* page number */
long f_image; /* image number */
long f_doctype; /* document type */
long f_xpos; /* x position */
long f_ypos; /* y position */
long f_dispmode; /* display mode */
long f_itype; /* image type */
} Opt_file_t;
/* Volume block structure */
typedef struct {
char v_name[32]; /* volume label verification region */
short v_version; /* label version number */
char v_id[VIDLEN]; /* volume ID */
short v_vtype; /* volume type */
short v_side; /* platter side */
struct tm v_time; /* time */
long v_dfirst; /* first desc block */
long v_ffirst; /* first data block */
long v_sfirst; /* first spare block */
char v_project[32]; /* project name */
char v_institution[128]; /* institution description */
} Opt_volume_t;
#define FMS_CLOSE 0
#define FMS_BWRITE 1
#define FMS_BREAD 2
#define FMS_FWRITE 4
#define FMS_FREAD 8
#define FMS_EWRITE 0x10
#define FMS_EREAD 0x20
#define FMS_MAX_FILE 8 /* max # of file can be opened at once */
#define FMS_NDRIVE 2 /* number of optical drives on line */
#define FMS_VD 0x1234 /* magic number for volume desc */
#define FMS_VOPEN 0xf000 /* _vstat volume open bit */
/* globals */
/* optical file struct */
typedef struct {
int start_stat;
int opt_fd;
long start_dpbn;
long start_fpbn;
long start_cnt;
Opt_file_t desc;
} _Opt_t;
/* optical volume struct */
typedef struct {
int vs_stat;
int vs_fd;
long vs_vol[VIDLEN];
long vs_vstart; /* volume area */
long vs_dstart; /* desc area */
long vs_fstart; /* file area */
long vs_sstart; /* spare area */
_Opt_t vs_opt[FMS_MAX_FILE];
} _Vol_t;
//E*O*F opt_fs.h
echo The following shows errors detected by using 'wc':
cat <<! >/tmp/sar$$
1606 4914 36917 hita.c
105 514 3312 hita.h
128 605 4759 hitachi.h
178 1006 6317 opt_fs.h
2017 7039 51305 total
!
wc hita.c hita.h hitachi.h opt_fs.h | diff -b /tmp/sar$$ -
rm /tmp/sar$$
More information about the Comp.sources.unix
mailing list