wheels@mks.UUCP (Gerry Wheeler) (12/07/88)
I have been working on the BMS clock driver that was posted a couple of weeks ago, with help from Frans Meulenbrook (mcvax!cst.prl.philips.nl!meulenbr). I made some changes to the original driver. Some were cosmetic, but I also removed definitions of variables that were never used. Probably the biggest change is that it now returns a count that reflects the number of bytes it actually provides. Previously it would return as many bytes as the caller asked for, most of which were junk. There was also a section of code near the end of the driver that did a lot of bit twiddling with the hardware, but which had no effect on what was given to the caller. I deleted it with no harmful side effects. Once that was running, Frans gave me a program based on the clock program for the Mega ST which had been modified to read the data from the BMS driver (/dev/bms) and used it to set the system time. However, it seemed to have a lot of stuff in it, like converting yymmddhhmmss to seconds since Jan. 1970, and it had to know about leap years and all that ugly stuff. Most of that stuff is already in the date command, so I wrote another version which simply reads from /dev/bms and prints the data in a format acceptable to date. Now my /etc/rc simply has a line like this: date `bmsrtc` Since the information on how to put this driver into MINIX has already been posted, I won't cover that again. However, if someone needs the info, I have a copy of that posting here I can forward. ------------------------------ bmsclock.c ------------------------------ #ifdef atari_st /* * this file contains a bms-100 clock driver * on the atari st. * * the driver supports two operations: read a bytes and write a bytes. * it accepts two messages, one for reading and one for writing, * both using message format m2 and with the same parameters: * * m_type device proc_nr count position adrress * --------------------------------------------------------------- * | bms_read | device | proc nr | bytes | offset | buf ptr | * |-----------+---------+---------+---------+---------+---------| * | bms_write | device | proc nr | bytes | offset | buf ptr | * --------------------------------------------------------------- * * the file contains one entry point: * * bmsclock_task: main entry when system is brought up * * */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/com.h" #include "../h/error.h" #include "const.h" #include "type.h" #include "proc.h" #include "staddr.h" #include "stmfp.h" #include "stdma.h" #define max_errors 3 #define bms_count 13 /* number of bytes to transfer */ #define trace(x) /* x */ #define debug(x) x /* dis/enable interrupts */ #define ienable() mfp->mf_ierb |= ib_dint #define idisable() mfp->mf_ierb &= ~ib_dint private message mess; /* message buffer for in and out */ /*===================================================================* * bmsclock_task * *===================================================================*/ public bmsclock_task() { register r, caller, procno; /* * the main loop of the bms clock task. * it waits for a message, carries it out, and sends a reply. */ while (true) { receive(any, &mess); if (mess.m_source < 0) panic("bms clock task got message from ", mess.m_source); trace(printf("bms: received %d from %d\n", mess.m_type,mess.m_source)); caller = mess.m_source; procno = mess.proc_nr; /* now carry out the work. */ switch (mess.m_type) { case bms_read: case bms_write: r = do_bms(&mess); break; default: r = einval; break; } /* finally, prepare and send the reply message. */ mess.m_type = task_reply; mess.rep_proc_nr = procno; mess.rep_status = r; /* # of bytes or error code */ send(caller, &mess); /* send reply to caller */ } } /*===================================================================* * do_bms * *===================================================================*/ private int do_bms(mp) register message *mp; { register struct proc *rp; register r, errors, count, rw, minor; register phys_bytes address; extern phys_bytes umap(); rw = mp->m_type; minor = mp->device; count = mp->count; if (count <= 0) return(eof); rp = proc_addr(mp->proc_nr); address = umap(rp, d, (vir_bytes) mp->address, (vir_bytes) count); if (address == 0) return(einval); trace(printf("bms%d: %s: cnt=%d\n", minor, rw == disk_read ? "read" : "write", count)); rp->p_physio = 1; /* disable (un)shadowing */ /* this loop allows a failed operation to be repeated. */ for (errors = 0; errors < max_errors; errors++) { r = do_xbms(address, count, rw); if (r >= 0) break; /* if successful, exit loop */ } rp->p_physio = 0; /* enable (un)shadowing */ return(r); } /*===================================================================* * do_xbms * *===================================================================*/ private int do_xbms(address, count, rw) phys_bytes address; int count; int rw; { register int r; extern void dmaint(); /* * carry out the transfer. all parameters have been checked and * are set up properly. called with address, count (may be changed * when reading), and rw flag. returns count of bytes transferrred * (maximum of bms_count for reading) or an error. * * every single byte written to the hdc will cause an interrupt. * Thus disable interrupts while communicating with hdc. Ready test * will be done by busy waiting. Only for real hard disk operations * interrupts will be enabled. */ TRACE(printf("bms address:0x%X count=%d cmd:%s\n", address, count, (rw==DISK_READ)?"READ":"WRITE")); IDISABLE(); dmagrab(BMSCLOCK, dmaint); if (rw == DISK_READ) { r = read_clock(address, count); } else if (rw = DISK_WRITE) { /* reserve for setting clock */ r = EINVAL; } else { /* reserve for screen blanker */ r = EINVAL; } dmafree(BMSCLOCK); IENABLE(); return r; } #define DAYH 8 #define HOURH 5 PRIVATE int read_clock(address, count) phys_bytes address; int count; { char lbuf[BMS_COUNT]; register int r, s, index; register char *cp; if (count > BMS_COUNT) count = BMS_COUNT; DMA->dma_mode = FDC | HDC; DMA->dma_data = 0xe1; for(r = 100; r > 0; r--) /* pause */; DMA->dma_mode = FDC | HDC; DMA->dma_data = 0xe5; /* * Read the data into the local buffer. */ for(index = 0; index < count; index++) { DMA->dma_mode = FDC | HDC | A0; DMA->dma_data = (index << 4); for(r = 3; r > 0; r--) /* pause */; lbuf[index] = DMA->dma_data & 0xf; } DMA->dma_mode = FDC | HDC; DMA->dma_data = 0xe0; DMA->dma_mode = FDC; /* * Some digits contain flag bits as well as time; mask * out the extra bits. */ lbuf[HOURH] &= 0x03; lbuf[DAYH] &= 0x03; /* * Transfer the local buffer to the final address. */ for(index = 0, cp = (char*)address; index < count; index++) *cp++ = lbuf[index]; return count; } #endif /* ATARI_ST */ ------------------------------ bmsrtc.c ------------------------------ /* * A program to read /dev/bms and print the results to stdout. * The format of the output is the same as the input to the * date command, so one can use a command like * * date `bmsrtc` * * in /etc/rc to set the date. * * This program can later be extended to accept input and write * to /dev/bms to set the time. Its input might be made compatible * with the output of date, so one could use a command like * * bmsrtc `date` * * to copy the system date into the bms clock. */ #include <stdio.h> #define SECL 0 #define SECH 1 #define MINL 2 #define MINH 3 #define HOURL 4 #define HOURH 5 #define WDAY 6 #define DAYL 7 #define DAYH 8 #define MONL 9 #define MONH 10 #define YEARL 11 #define YEARH 12 #define BUFSIZE 13 main(argc, argv) int argc; char *argv[]; { register int fd, count, year; char buf[BUFSIZE]; fd = open("/dev/bms", 0); if (fd < 0) { fprintf(stderr, "%s: cannot open /dev/bms", argv[0]); exit(1); } count = read(fd, buf, BUFSIZE); close(fd); if (count != BUFSIZE) { fprintf(stderr, "%s: cannot read /dev/bms", argv[0]); exit(1); } /* * The year digits from the clock are 80 less than they * should be. Add a correction. */ year = buf[YEARH] * 10 + buf[YEARL] + 80; printf("%d%d%d%d%02d%d%d%d%d%d%d\n", buf[MONH], buf[MONL], buf[DAYH], buf[DAYL], year, buf[HOURH], buf[HOURL], buf[MINH], buf[MINL], buf[SECH], buf[SECL]); exit(0); } -- Gerry Wheeler Phone: (519)884-2251 Mortice Kern Systems Inc. UUCP: uunet!watmath!mks!wheels 35 King St. North BIX: join mks Waterloo, Ontario N2J 2W9 CompuServe: 73260,1043