/* * Standalone profile/widget driver * * (C) 1984 UniSoft Corp. of Berkeley CA * * UniPlus Source Code. This program is proprietary * with Unisoft Corporation and is not to be reproduced * or used in any manner except as authorized in * writing by Unisoft. */#include "sys/param.h"#include "sys/mmu.h"#include "sys/types.h"#include "sys/inode.h"#include "saio.h"#include "sys/pport.h"#include "sys/d_profile.h"#include "sys/profile.h"#include "sys/cops.h"#define min(a,b) ((a)<(b)?(a):(b))/* Bytes to disk blocks */#define	btod(x)	(((x)+(BSIZE-1))>>BSHIFT)#define MAXREAD 32768struct device_d *pro_da[NPPDEVS] = {		/* DEV	Description */	PPADDR,					/* 0x00	parallel port */	(struct device_d *)(STDIO+0x2000),	/* 0x10	FPC port 0 slot 1 */	(struct device_d *)(STDIO+0x2800),	/* 0x20	FPC port 1 slot 1 */	(struct device_d *)(STDIO+0x3000),	/* 0x30	FPC port 2 slot 1 */	(struct device_d *)(STDIO+0x6000),	/* 0x40	FPC port 0 slot 2 */	(struct device_d *)(STDIO+0x6800),	/* 0x50	FPC port 1 slot 2 */	(struct device_d *)(STDIO+0x7000),	/* 0x60	FPC port 2 slot 2 */	(struct device_d *)(STDIO+0xA000), 	/* 0x70	FPC port 0 slot 3 */	(struct device_d *)(STDIO+0xA800),	/* 0x80	FPC port 1 slot 3 */	(struct device_d *)(STDIO+0xB000)	/* 0x90	FPC port 2 slot 3 */};struct proheader ph;proopen(io)	register struct iob *io;{	if (io->i_unit < 0 || io->i_unit > NPPDEVS) {		printf("proopen(%d): invalid unit\n",io->i_unit);		return -1;	}	return proinit(pro_da[io->i_unit]);		/* initialize drive */}prostrategy(ip, func)	register struct iob *ip;{	register i, cc;	register daddr_t bn;	caddr_t addr;	int unit;	addr = ip->i_ma;	cc = ip->i_cc;	bn = ip->i_bn;	unit = ip->i_unit;	if (unit < 0 || unit > NPPDEVS) {		printf("prostrategy: i_unit=%d i_bn=%d i_cc=%d invalid unit\n",			unit, bn, cc);		return -1;	}			if (bn < 0 || bn + btod(cc) > MAXBLOCK) {		printf("prostrategy: i_bn=%d i_cc=%d, bad blkno\n",			bn, cc);		return -1;	}	while (cc > 0) {		if (cc > MAXREAD)			i = MAXREAD;		else			i = cc;		if (prorw(func, unit, addr, i, bn) != 0)			goto out;		cc -= i;		addr += i;		bn += btod(i);	}out:	if (cc != 0)		printf("prostrategy: bn=%d cc=%d resid=%d\n",			ip->i_bn, ip->i_cc, cc);	return ip->i_cc - cc;}proinit(devp)	register struct device_d *devp;{	devp->d_pcr = 0x6B;	/* set controller CA2 pulse mode strobe */	if (devp->d_pcr != 0x6B)		return -1;	devp->d_ddra = 0;	/* set port A bits to input **/	devp->d_ddrb = 0x1C;	devp->d_irb &= ~DEN;	/* set enable = true */	devp->d_irb |= CMD|DRW;	/* set direction = out, command = false */	devp->d_ier = 0;	devp->d_acr = 0;	return 0;}prorw(func, pun, addr, cnt, bn)	caddr_t addr;	daddr_t bn;{	register struct device_d *devp;	register int i;	register char zero;	int state;	register char *cp;	struct cmd pc;	int status;	int retrys = 5;	devp = pro_da[pun];		/* Build Command (ok to send extra bytes on write cmd) */	pc.p_cmd = (func&F_READ) ? PROREAD : PROWRITE;	pc.p_high = (bn >> 16) & 0xFF;	pc.p_mid = (bn >> 8) & 0xFF;	pc.p_low = bn & 0xFF;	pc.p_retry = 10;	pc.p_thold = 3;retry:	while (((i=devp->d_irb)&BSY)!=BSY) ;	/* wait for controller */			/* sync controller to cmd state */	if (prochk(devp,SCMD) && prochk(devp,SCMD)) {		printf("cant force disk into CMD state\n");		return -1;	}	cp = (char *)(&pc);		/* send command */	devp->d_ira = *cp++;	devp->d_ira = *cp++;	devp->d_ira = *cp++;	devp->d_ira = *cp++;	devp->d_ira = *cp++;	devp->d_ira = *cp;	state = (func&F_READ) ?SRDBLK :SWRTD;	if (prochk(devp,state)) {		printf("disk operation failed\n");		return -1;	}	if (state == SRDBLK) {fini:		i = 0;		devp->d_irb |= DRW;		/* set to read */		devp->d_ddra = i;		status = 0;		cp = (char *)(&status);		*cp++ = devp->d_ira;		/* get status of command */		*cp++ = devp->d_ira;		*cp++ = devp->d_ira;		*cp = devp->d_ira;		if (status & (GOAHEAD | FAIL | RESETP)) {			printf("dev %d: status=x%x\n",pun,status);			if (retrys-- > 0) goto retry;			return -1;		}		if (state == SRDBLK) {	/* Read successful so pickup data*/			i = HDRSIZE - 1;		/* sizeof header */			do zero = devp->d_ira;			while (--i != -1);	/* optimizes to DBRA */			cp = addr;			i = min(SECSIZE,cnt) - 1;			do *cp++ = devp->d_ira;			while (--i != -1);		}		return 0;	}	if (state == SWRTD) {		/* send data */		state = SFINI;		if (bn)			ph.ph_fileid = 0;		else			ph.ph_fileid = 0xAAAA;				devp->d_irb &= ~DRW;	/* set dir=out */		devp->d_ddra = 0xFF;	/* set port A bits to output */		i = HDRSIZE - 1;		cp = (char *)(&ph);		do devp->d_ira = *cp++;		while (--i != -1);		i = min(SECSIZE,cnt) - 1;		cp = (char *)addr;	/* place to get data from */		do devp->d_ira = *cp++;		while (--i != -1);		if (prochk(devp,SPERFORM)) {			printf("dev %d blk %d: write op failed\n",pun,bn);			return -1;		}		goto fini;	}	printf ("LOGIC ERR IN DISK DRIVER\n");	return -1;}/* * Get in sync with disk. * (subroutine FINDD2 & CHKRSP from 'profrom.text' document) * Expects enable==true and Direction==in at start. * If disk response is 'state' then returns 0 (success) * otherwise fails (returns -1 if timeout and cur state if bad state). */prochk(devp, state)	register struct device_d *devp;{	register zero = 0;	register i;	int resp;	if (devp->d_irb & OCD) {		/* cable disconnected ? */		printf("unit at x%x doesn't appear to be plugged in\n",devp);		return -1;	}	while ((devp->d_irb&BSY)==0) ;	devp->d_irb |= DRW;		/* set input mode */	devp->d_ddra = zero;		/* set port A bits to input */	devp->d_irb &= ~CMD;		/* set cmd and enable bufs */	i = RSPTIME;			/* about 1ms */	while (devp->d_irb&BSY && i--);	/* wait sig that resp byte is ready*/	resp = PIDL;			/* reply to use if resp byte wrong */	if (i > 0) {			/* didn't timeout */		i = devp->d_ira;	/* get response from disk */		if (i == state)		/* got correct state */			resp = PGO;	/* reply to use if resp byte correct*/		else			printf("> prochk: state %d instead of %d\n",i,state);		devp->d_irb &= ~(DRW|CMD);	/* set dir=out cmd=true */		devp->d_ddra = 0xFF;		/* set port A bits to output */		devp->d_ira = resp;		/* send reply (GO or RESET) */		devp->d_ier = FCA1;		devp->d_irb |= CMD;		/* sig disk to read resp */		while (!(devp->d_irb&BSY)) ;	/* wait, action is performed */		return (i == state) ?0 :i;	}	printf("EXCESSIVE DISK DELAY -- CHECK HARDWARE");	devp->d_ddra = zero;		/* set port A bits to input */	devp->d_irb |= CMD|DRW;		/* set dir=in, disable buffers */	return (-1);}