[comp.os.minix] MINIX/ST driver to read the BMS100 clock

hcj@lzaz.ATT.COM (HC Johnson) (11/09/88)

---------------------------------------------------------
The enclosed file, driver.diff allows installing a driver
in Minix.  This allows reading the clock in the BMS-100 hard
disk controller.  It turns out that the 13 bytes read are identical
to those read on a MEGA.  They must use the same chip.
Interfacing the SUPRA clock is likely just as simple.
-------------------------------cut here------------------
echo x - driver.diff
gres '^X' '' > driver.diff << '/'
Xkernel/Makefile
X9a10
X> 	  bmsclock.o \
X======================================================================
Xkernel/table.c
X36,39c36,40
X<            winchester_task(), tty_task(), printer_task();
X< 
X< /* The startup routine of each task is given below, from -NR_TASKS upwards.
X<  * The order of the names here MUST agree with the numerical values assigned to
X---
X>            winchester_task(), tty_task(), printer_task(), bmsclock_task();
X> 
X> /* The startup routine of each task is given below, from -NR_TASKS upwards.
X>  * The order of the 
X> names here MUST agree with the numerical values assigned to
X42a44
X>  bmsclock_task,
X======================================================================
Xkernel/stdmp.c
X124c124
X< char *nayme[]= {"PRINTR", "TTY   ", "WINCHE", "FLOPPY", "RAMDSK", "CLOCK ", 
X---
X> char *nayme[]= {"BMSCLK", "PRINTR", "TTY   ", "WINCHE", "FLOPPY", "RAMDSK", "CLOCK ", 
X======================================================================
Xfs/table
Xh/com.h
X54a55,60
X> #define BMSCLOCK	   -9	/* clock on BMS 100 */
X> #	define BMS_READ	    3
X> #	define BMS_WRITE    4
X> 
X> #define SERIAL		   -10	/* serial port */
X> 	
X======================================================================
Xh/const.h
X25,26c25,26
X< #define NR_TASKS           8	/* number of tasks in the transfer vector */
X< #define NR_PROCS          16	/* number of slots in proc table */
X---
X> #define NR_TASKS           9	/* number of tasks in the transfer vector */
X> #define NR_PROCS          17	/* number of slots in proc table */
X127,130c127,134
X<     no_call,   rw_dev,      no_call,    PRINTER      /* 6 = /dev/lp   */
X< };
X< 
X< int max_major = sizeof(dmap)/sizeof(struct dmap);
X---
X>     no_call,   rw_dev,      no_call,    PRINTER,     /* 6 = /dev/lp   */
X>     no_call,   rw_dev,      no_call,    BMSCLOCK,    /* 7 = /dev/bms   */
X> #ifdef NOTYET
X>     no_call,   rw_dev,      no_call,    SERIAL,      /* 8 = /dev/ser   */
X> #endif
X> };
X> 
X> int max_major = sizeof(dmap)/sizeof(struct dmap);
X======================================================================
Xkernel/bmsclock.c
X#ifdef ATARI_ST
X/*
X * This file contains a bms-100 clock driver
X * on the Atari ST.
X *
X * The driver supports two operations: read a bytes and write a bytes.
X * It accepts two messages, one for reading and one for writing,
X * both using message format m2 and with the same parameters:
X *
X *    m_type      DEVICE    PROC_NR     COUNT    POSITION  ADRRESS
X * ----------------------------------------------------------------
X * |  BMS_READ | device  | proc nr |  bytes  |  offset | buf ptr |
X * |------------+---------+---------+---------+---------+---------|
X * | BMS_WRITE | device  | proc nr |  bytes  |  offset | buf ptr |
X * ----------------------------------------------------------------
X *
X * The file contains one entry point:
X *
X *	bmsclock_task: main entry when system is brought up
X *
X *
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/callnr.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "const.h"
X#include "type.h"
X#include "proc.h"
X
X#include "staddr.h"
X#include "stmfp.h"
X#include "stdma.h"
X#define MAX_ERRORS 3
X
X#define TRACE(x)	/* x */
X#define DEBUG(x)	x
X
X/* dis/enable interrupts */
X#define IENABLE()	MFP->mf_ierb |= IB_DINT
X#define IDISABLE()	MFP->mf_ierb &= ~IB_DINT
X
X/* timing constants */
X
XPRIVATE message mess;		/* message buffer for in and out */
X
X
X/*===========================================================================*
X *				bmsclock_task				     *
X *===========================================================================*/
XPUBLIC bmsclock_task()
X{
X  register	r, drive, minor, caller, procno;
X
X
X  /*
X   * The main loop of the bms clock task.
X   * It waits for a message, carries it out, and sends a reply.
X   */
X  while (TRUE) {
X	receive(ANY, &mess);
X	if (mess.m_source < 0)
X		panic("bms clock task got message from ", mess.m_source);
X	TRACE(printf("bms: received %d from %d\n",mess.m_type,mess.m_source));
X	caller = mess.m_source;
X	procno = mess.PROC_NR;
X
X	/* Now carry out the work. */
X	switch (mess.m_type) {
X	    case BMS_READ:
X	    case BMS_WRITE:	r = do_bms(&mess);	break;
X	    default:		r = EINVAL;		break;
X	}
X
X	/* Finally, prepare and send the reply message. */
X	mess.m_type = TASK_REPLY;	
X	mess.REP_PROC_NR = procno;
X	mess.REP_STATUS = r;	/* # of bytes transferred or error code */
X	send(caller, &mess);	/* send reply to caller */
X  }
X}
X
X
X
X/*===========================================================================*
X *				do_bms  				     *
X *===========================================================================*/
XPRIVATE int do_bms(mp)
Xregister message *mp;
X{
X  register struct proc	*rp;
X  register		r, errors, count, rw, drive, minor;
X  register long		secnum;
X  register phys_bytes	address;
X  extern phys_bytes	umap();
X
X  rw = mp->m_type;
X
X  minor = mp->DEVICE;
X  count = mp->COUNT;
X  if (count <= 0)
X	return(EOF);
X  rp = proc_addr(mp->PROC_NR);
X  address = umap(rp, D, (vir_bytes) mp->ADDRESS, (vir_bytes) count);
X  if (address == 0)
X	return(EINVAL);
X  TRACE(printf("hd%d: %s: sec=%D; cnt=%d\n",
X	minor, rw == DISK_READ ? "read" : "write", secnum, count));
X  rp->p_physio = 1;		/* disable (un)shadowing */
X  /* This loop allows a failed operation to be repeated. */
X  for (errors = 0; errors < MAX_ERRORS; errors++) {
X	r = do_xbms(address, count, rw);
X	if (r == OK)
X		break;		/* if successful, exit loop */
X  }
X  rp->p_physio = 0;		/* enable (un)shadowing */
X  if (r != OK)
X	return(EIO);
X  return(count );
X}
X
X/*===========================================================================*
X *				do_xbms  				     *
X *===========================================================================*/
X
XPRIVATE int do_xbms(address, count, rw)
Xphys_bytes 	address;
Xint		count;
Xint		rw;
X{
X
X  register	r, s, wrbit;
X  register	index;
X  register	char *cp;
X  char	lbuf[13];
X  extern void	dmaint();
X
X
X  /*
X   * Carry out the transfer. All parameters have been checked and
X   * are set up properly.
X   *
X   * Every single byte written to the hdc will cause an interrupt.
X   * Thus disable interrupts while communicating with hdc. Ready test
X   * will be done by busy waiting. Only for real hard disk operations
X   * interrupts will be enabled.
X   */
X  TRACE(printf("hd address:0x%X count=%d cmd:%s\n",
X	address, count, (rw==0)?"READ":"WRITE")
X  );
X  IDISABLE();
X
X  dmagrab(BMSCLOCK, dmaint);
X  if (rw == DISK_READ) {
X	DMA->dma_mode = FDC | HDC;
X	DMA->dma_data = 0xe1;
X	for(r=100;r>0;r--) ; /* pause */
X	DMA->dma_mode = FDC | HDC;
X	DMA->dma_data = 0xe5;
X	for(index = 0; index<13; index++) {
X		DMA->dma_mode = FDC | HDC | A0;
X		DMA->dma_data = (index << 4);
X		for(r=3;r>0;r--) ; /* pause */
X		lbuf[index] =  DMA->dma_data & 0xf;
X	}
X	DMA->dma_mode = FDC | HDC;
X	DMA->dma_data = 0xe0;
X	DMA->dma_mode = FDC ;
X
X	for(index=0,cp=(char*)address; index<count; index++)
X		*cp++ = lbuf[index];
X/* reaccess */
X	DMA->dma_mode = FDC | HDC;
X	DMA->dma_data = 0xe1;
X	for(r=100;r>0;r--) ; /* pause */
X	DMA->dma_mode = FDC | HDC;
X	DMA->dma_data = 0xe5;
X	for(index = 7; index<12; index++) {
X		DMA->dma_mode = FDC | HDC | A0;
X		DMA->dma_data = (index << 4);
X		for(r=3;r>0;r--) ; /* pause */
X		lbuf[index] =  DMA->dma_data & 0xf;
X	}
X	DMA->dma_mode = FDC | HDC;
X	DMA->dma_data = 0xe1;
X
X	s = (lbuf[10] * 10 + lbuf[9]) ;
X	r = s + lbuf[12] *  10 + lbuf[11];
X	if (s > 2)
X		lbuf[8] &= 3;
X	if(r != 20) {
X		if ((r &= 3) == 0)
X			lbuf[8] |= 4;
X	}
X	DMA->dma_mode = FDC | HDC;
X	DMA->dma_data = 0xe9;
X	for(r=100;r>0;r--) ; /* pause */
X	DMA->dma_mode = FDC | HDC | A0;
X	index = 8;
X	r = (lbuf[index] & 0xf) + (index<<4);
X	DMA->dma_data = r;
X	for(r=1;r>0;r--) ; /* pause */
X	DMA->dma_mode = FDC | HDC;
X	DMA->dma_data = 0xeb;
X	for(r=1;r>0;r--) ; /* pause */
X	DMA->dma_mode = FDC | HDC;
X	DMA->dma_data = 0xe9;
X	for(r=1;r>0;r--) ; /* pause */
X	DMA->dma_mode = FDC | HDC;
X	DMA->dma_data = 0xe0;
X	DMA->dma_mode = FDC ;
X
X  } else if (rw = DISK_WRITE) {
X/* reserve for setting clock */
X	return(EINVAL);
X  } else {
X/* reserve for screen blanker */
X	return(EINVAL);
X  }
X  dmafree(BMSCLOCK);
X    IENABLE();
X  
X  return(r=0);
X}
X
/
-----------------------end here-----------------------

Howard Johnson
ATT Bell Labs
... lzaz!hcj

meulenbr@cst.UUCP (Frans Meulenbroeks) (11/13/88)

nice! thanks! I needed this, but didn't have the proper info to write
the code myself.
I noticed one problem though. It is explained below.
Note: I removed lots of stuff from the original article, just saving
enough context so one can repair.

In article <264@lzaz.ATT.COM> hcj@lzaz.ATT.COM (HC Johnson) writes:
>X> char *nayme[]= {"BMSCLK", "PRINTR", "TTY   ", "WINCHE", "FLOPPY", "RAMDSK", "CLOCK ", 
>X======================================================================
>Xfs/table
>Xh/com.h

This line should not be here! remove it.

>X54a55,60
>X> #define BMSCLOCK	   -9	/* clock on BMS 100 */
>X> #	define BMS_READ	    3
>X> #	define BMS_WRITE    4
>X> 
>X> #define SERIAL		   -10	/* serial port */
>X> 	
>X======================================================================
>Xh/const.h
>X25,26c25,26
>X< #define NR_TASKS           8	/* number of tasks in the transfer vector */
>X< #define NR_PROCS          16	/* number of slots in proc table */
>X---
>X> #define NR_TASKS           9	/* number of tasks in the transfer vector */
>X> #define NR_PROCS          17	/* number of slots in proc table */

You'll need a line
Xfs/table.c
here. This is a patch in this file. 
(By the way: patch crashed on this point on an uncorrected file)

>X127,130c127,134
>X<     no_call,   rw_dev,      no_call,    PRINTER      /* 6 = /dev/lp   */
>X< };
>X< 

What I missed after having this installed was a program to set the minix
clock. I changed megartc.c to cope with both the mega and the bms clock.
However, since I do not own a mega, and my BMS clock shows sometimes
weird behaviour (I think it needs a new power pill), I am looking for
one or a few persons who will test my changes.
Both one or two mega and BMS testers are needed.

Any volunteers??

-- 
Frans Meulenbroeks        (meulenbr@cst.prl.philips.nl)
	Centre for Software Technology
	( or try: ...!mcvax!philmds!prle!cst!meulenbr)