hcj@lzaz.ATT.COM (HC Johnson) (01/08/89)
This is a shar of 5 files to add BMS200 support to the BMS100 clock driver I posted earlier. User programs: Makefile - to make bmsset and bmsrtc bmsset.c - set the BMS clock 100 to 200 from the current date bmsrtc.c - set the current date from the BMS 100 or 200 clock. kernel/ programs: bmsclock.c - clock driver for bms 100 and 200 bms200.s - support for driver Add bms200.s to the Makefile in kernel/ in the manner of stmpx.s. Add the command bmsrtc to the etc/rc script. In /dev make a Inode for bms, with minor 0 for bms100 and 1 for bms200. Howard Johnson ATT-BL lzaz!hcj ================shar follows================= echo x - Makefile gres '^X' '' > Makefile << '/' Xall: bmsrtc bmsset Xbmsrtc: bmsrtc.c X cc -O bmsrtc.c -o bmsrtc X chmem =2000 bmsrtc Xbmsset: bmsset.c X cc -O bmsset.c -o bmsset X chmem =2000 bmsset / echo x - bms200.s gres '^X' '' > bms200.s << '/' X .define _rd1byte X .define _wr1byte X X .sect .text X .sect .rom X .sect .data X .sect .bss X X .sect .text X Xdma_base = 0xff8604 Xdma_data = 0 Xdma_cont = 2 X Xselect = 0x10 Xsck_en = 0x08 X Xwrite = 0x80 X Xclk_dev = 6 Xclk_adr = clk_dev*32 X! X! moves the byte in d0 to the clock chip X! uses d1, a0 must point to the dma channel X! X X_wr1byte: X clr.w d0 X move.b 5(a7), d0 X lea dma_base, a0 X move.w #7, d1 X swap d0 X move.w #clk_adr+select+sck_en, d0 X Xwrloop: lsr.w #1, d0 X swap d0 X X roxl.b #1, d0 X swap d0 X roxl.w #1, d0 X move.w d0, dma_data(a0) X X dbra d1, wrloop X X rts X X! X! moves a byte into d0 from the clock chip X! uses d1, a0 must point to the dma channel X! X X_rd1byte: X lea dma_base, a0 X move.w #7, d1 X Xrdloop: swap d0 X X move.w #clk_adr+select+sck_en, dma_data(a0) X move.w dma_data(a0), d0 X X roxr.b #1, d0 X swap d0 X roxl.b #1, d0 X X dbra d1, rdloop X X rts X / echo x - bmsclock.c gres '^X' '' > bmsclock.c << '/' X#ifdef ATARI_ST X/* X * This file contains a bms-100 clock driver X * This file contains a bms-200 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 * device = 0: bms100 X * device = 1: bms200 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#define XFERSIZE 13 X X/*===========================================================================* X * bmsclock_task * X *===========================================================================*/ XPUBLIC bmsclock_task() X{ X register r, drive, 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 if (count > XFERSIZE) X count = XFERSIZE; 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, minor?1:0); 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 X/* defines for bms 100 */ X#define CLK_100 0x7 X#define CLK_ADR1 (CLK_100 * 32) X#define CLK_HOLD 0x1 X#define CLK_WRITE 0x2 X#define CLK_READ 0x4 X#define CLK_WREN 0x8 X/* defines for bms 200 */ X#define SELECT 0x10 X#define SCK_EN 0x08 X#define SCK_WRITE 0x80 X#define CLK_SCSI 0x6 X#define CLK_ADR (CLK_SCSI * 32) Xextern int wr1byte(); Xextern int rd1byte(); X XPRIVATE int do_xbms(address, count, rw, minor) Xphys_bytes address; Xint count; Xint rw; Xint minor; /* 0= bms100 1=bms200 */ X{ X X register r, s, wrbit; X register index; X register char *cp; X char lbuf[XFERSIZE]; 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 minor=%d cmd:%s\n", X address, count, minor, (rw==0)?"READ":"WRITE") X ); X IDISABLE(); X X dmagrab(BMSCLOCK, dmaint); X if (rw == DISK_READ && minor == 0) { X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR1+CLK_HOLD; X for(r=100;r>0;r--) ; /* pause */ X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR1+CLK_READ+CLK_HOLD; X for(index = 0; index<XFERSIZE; 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 = CLK_ADR1+0; X DMA->dma_mode = FDC ; X X for(index=0,cp=(char*)address; index<count; index++) X *cp++ = lbuf[index]; X r = 0; /* good return */ X X } else if (rw == DISK_READ && minor == 1) { X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR+SELECT; X wr1byte(0x20); X X for(index = 0; index<7; index++) { X lbuf[index] = rd1byte(); X } X DMA->dma_data = CLK_ADR+0; X DMA->dma_mode = FDC ; X X cp=(char*)address; X/* lbuf format: bcd H L */ X *cp++ = lbuf[0] & 0xf; X *cp++ = (lbuf[0] >> 4) & 0xf; X *cp++ = lbuf[1] & 0xf; X *cp++ = (lbuf[1] >> 4) & 0xf; X *cp++ = lbuf[2] & 0xf; X *cp++ = (lbuf[2] >> 4) & 0xf; X *cp++ = lbuf[3] & 0xf; X *cp++ = lbuf[4] & 0xf; X *cp++ = (lbuf[4] >> 4) & 0xf; X *cp++ = lbuf[5] & 0xf; X *cp++ = (lbuf[5] >> 4) & 0xf; X *cp++ = lbuf[6] & 0xf; X *cp++ = (lbuf[6] >> 4) & 0xf; X r = 0; /* good return */ X X } else if (rw == DISK_WRITE && minor == 0) { X X X for(index=0,cp=(char*)address; index<count; index++) X lbuf[index] = *cp++; X X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR1+CLK_WREN+CLK_HOLD; X for(r=100;r>0;r--) ; /* pause */ X for(index = 0; index<13; index++) { X DMA->dma_mode = FDC | HDC | A0; X DMA->dma_data = (index << 4) | (lbuf[index] & 0xf); X for(r=1;r>0;r--) ; /* pause */ X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR1+CLK_WREN+CLK_HOLD+CLK_WRITE; X for(r=3;r>0;r--) ; /* pause */ X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR1+CLK_WREN+CLK_HOLD; X } X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR1+CLK_HOLD; X for(r=100;r>0;r--) ; /* pause */ X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR1+CLK_READ+CLK_HOLD; X 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 s = (unsigned char)DMA->dma_data & 0xf; X if(s != lbuf[index]) { /* fail */ X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR1+0; X DMA->dma_mode = FDC ; X r = EIO; /* bad return */ X goto bms_exit; X } X } X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR1+0; X DMA->dma_mode = FDC ; X r = 0; /* good return */ X } else if (rw == DISK_WRITE && minor == 1) { X int l; X X cp=(char*)address; X l = *cp++ & 0xf; /* sec-L */ X lbuf[0] = (*cp++ << 4) | l; X l = *cp++ & 0xf; /* min-L */ X lbuf[1] = (*cp++ << 4) | l; X l = *cp++ & 0xf; /* hr-L */ X lbuf[2] = (*cp++ << 4) | l; X lbuf[2] &= 0x7f; /* strip the 24 hour bit */ X lbuf[3] = *cp++ & 0xf; X l = *cp++ & 0xf; /* day-L */ X lbuf[4] = (*cp++ << 4) | l; X l = *cp++ & 0xf; /* mon-L */ X lbuf[5] = (*cp++ << 4) | l; X l = *cp++ & 0xf; /* yr-L */ X lbuf[6] = (*cp++ << 4) | l; X X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR+SELECT; X wr1byte(SCK_WRITE+0x31); X wr1byte(0xb5); X wr1byte(0); X DMA->dma_data = CLK_ADR+0; X X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR+SELECT; X wr1byte(SCK_WRITE+0x20); X for(index = 0; index<7; index++) { X wr1byte(lbuf[index]); X } X DMA->dma_data = CLK_ADR+0; X X DMA->dma_mode = FDC | HDC; X DMA->dma_data = CLK_ADR+SELECT; X wr1byte(0x20); X X for(index = 0; index<7; index++) { X if(lbuf[index] != rd1byte()) { /* fail */ X DMA->dma_data = CLK_ADR+0; X DMA->dma_mode = FDC ; X r = EIO; /* bad return */ X goto bms_exit; X } X } X DMA->dma_data = CLK_ADR+0; X DMA->dma_mode = FDC ; X r = 0; /* good return */ X } else { X/* reserve for screen blanker */ X r = EIO; X goto bms_exit; X } Xbms_exit: X dmafree(BMSCLOCK); X IENABLE(); X X return(r); X} / echo x - bmsrtc.c gres '^X' '' > bmsrtc.c << '/' X#define DEBUG X X#define AD_RTC 0xFFFC20 X X#define SECL 0 X#define SECH 1 X#define MINL 2 X#define MINH 3 X#define HOURL 4 X#define HOURH 5 X X#define DAYL 7 X#define DAYH 8 X#define MONL 9 X#define MONH 10 X#define YEARL 11 X#define YEARH 12 X X#define N 13 X Xint fd; Xunsigned char a[N]; Xint m[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; X Xlong time(); Xchar *ctime(); X Xmain(argc, argv) Xchar **argv; X{ X register i, n, d, ok; X long ot, nt; X#ifdef DEBUG X int debug = argc != 1; X#endif X X fd = open("/dev/bms", 0); X if (fd < 0) X fatal("cannot open /dev/bms "); X for(n=0;n<3;n++) { X i = read(fd,a,N); X if(i <0) { X perror("read"); X printf("read returned %d\n",i); X exit(1); X } X if (a[SECL] == 15) X fatal("no RTC present"); X break; X } Xif(debug) X printf("bms: %x %x %x %x %x %x %x %x %x %x %x %x %x\n", X a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12]); X a[HOURH] &= 3; X nt = 0; X i = dd(YEARL, 0, 99); X if ((i & 3) == 0) X m[1]++; X i += 80; X while (--i >= 70) { X nt += 365; X if ((i & 3) == 0) X nt++; X } X i = dd(MONL, 1, 12)-1; X while (--i >= 0) X nt += m[i]; X nt += dd(DAYL, 1, 31) - 1; X nt *= 24; X nt += dd(HOURL, 0, 23); X nt *= 60; X nt += dd(MINL, 0, 59); X nt *= 60; X nt += dd(SECL, 0, 59); X time(&ot); X#ifdef DEBUG X if (debug) { X printf("old time = (%ld) %s\n", ot, ctime(&ot)); X printf("new time = (%ld) %s\n", nt, ctime(&nt)); X } X#endif X if (ot > nt) X fatal("cannot set time back\n"); X if (stime(&nt) < 0) X fatal("stime() failed"); X exit(0); X} X Xdd(i, min, max) X{ X register n; X X n = a[i] + 10 * a[i+1]; X if (n < min || n > max) X fatal("ASSERT(idx=%d %d >= %d && %d <= %d)", i, n, min, n, max); X return(n); X} X X Xfatal(s, a1, a2, a3, a4, a5) Xchar *s; X{ X printf("bmsrtc: "); X printf(s, a1, a2, a3, a4, a5); X printf(" (fatal)\n"); X exit(1); X} / echo x - bmsset.c gres '^X' '' > bmsset.c << '/' X/* bmsset - r set the date in bms Author: Howard Johnson X * taken from minix date, Author: Adri Koppes X */ X X X#define SECL 0 X#define SECH 1 X#define MINL 2 X#define MINH 3 X#define HOURL 4 X#define HOURH 5 X X#define DAYW 6 X X#define DAYL 7 X#define DAYH 8 X#define MONL 9 X#define MONH 10 X#define YEARL 11 X#define YEARH 12 X X#define N 13 X Xint fd; Xunsigned char a[N]; X Xint days_per_month[] = X { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; X Xstruct { X int year, month, day, hour, min, sec; X} tm; X Xlong s_p_min; Xlong s_p_hour; Xlong s_p_day; Xlong s_p_year; Xint leap = 0; X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X long t, time(); X int n,i; X X s_p_min = 60; X s_p_hour = 60 * s_p_min; X s_p_day = 24 * s_p_hour; X s_p_year = 365 * s_p_day; X X time(&t); X cv_time(t); X/* expected fmt XThu Nov 10 13:59:34 EST 1988 X.month 0-11 X.day 1-31 X.hour 0-23 X.minute 0-59 X.second 0-59 X.year 1970 - X*/ X tm.year -= 1980; X tm.month += 1; X X X a[SECL] = (tm.sec % 10) & 0xf; X a[SECH] = (tm.sec / 10) & 0xf; X a[SECL] = 0; X a[SECH] = 0; X a[MINL] = (tm.min % 10) & 0xf; X a[MINH] = (tm.min / 10) & 0xf; X a[HOURL] = (tm.hour % 10) & 0xf; X a[HOURH] = ((tm.hour / 10) & 0xf) | 0x8; /* 24 hr format */ X X a[DAYL] = (tm.day % 10) & 0xf; X a[DAYH] = ((tm.day / 10) & 0xf) | (leap?4:0); X a[MONL] = (tm.month % 10) & 0xf; X a[MONH] = (tm.month / 10) & 0xf; X a[YEARL] = (tm.year % 10) & 0xf; X a[YEARH] = (tm.year / 10) & 0xf; X X a[DAYW] = 0; X X fd = open("/dev/bms", 1); X if (fd < 0) X fatal("cannot open /dev/bms "); X for(n=0;n<3;n++) { X i = write(fd,a,N); X if(i == N) X exit(0); X } X perror("write"); X X exit(1); X} X Xcv_time(t) Xlong t; X{ X tm.year = 0; X tm.month = 0; X tm.day = 1; X tm.hour = 0; X tm.min = 0; X tm.sec = 0; X while (t >= s_p_year) { X if (((tm.year + 2) % 4) == 0) X t -= s_p_day; X tm.year += 1; X t -= s_p_year; X } X if (((tm.year + 2) % 4) == 0) { X days_per_month[1]++; X leap = 1; X } X tm.year += 1970; X while ( t >= (days_per_month[tm.month] * s_p_day)) X t -= days_per_month[tm.month++] * s_p_day; X while (t >= s_p_day) { X t -= s_p_day; X tm.day++; X } X while (t >= s_p_hour) { X t -= s_p_hour; X tm.hour++; X } X while (t >= s_p_min) { X t -= s_p_min; X tm.min++; X } X tm.sec = (int) t; X} X Xfatal(s, a1, a2, a3, a4, a5) Xchar *s; X{ X printf("bmsrtc: "); X printf(s, a1, a2, a3, a4, a5); X printf(" (fatal)\n"); X exit(1); X} /