|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 17892 (0x45e4) Types: TextFile Notes: UNIX file Names: »hr.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦2d53db1df⟧ UNIX Filesystem └─ ⟦this⟧ »hr/src/driver/hr.c«
/* * Commodore Z8000-HR console */ #include <coherent.h> #include <con.h> #include <io.h> #include <uproc.h> #include <errno.h> #include <sched.h> #include <sgtty.h> #include <signal.h> #include <stat.h> #include <rico.h> #include "hr.h" /* ** ZCIO1 base address */ #define ZCIO1 0x0000 #define PKBD 0x0205 /* keyboard enable port */ #define KBDEN 0x02 /* keyboard enable bit */ #define PC2 0x04 #define PC3 0x08 /* * Control register addresses */ #define MICR 0x01 /* master interrupt */ #define MCCR 0x03 /* master configuration */ /* * Register addresses for Port A */ #define PACAS 0x11 /* port a command and status */ #define PAMS 0x41 /* port a mode specification */ #define PAHS 0x43 /* port a handshake spec */ #define PADPP 0x45 /* port a data path polarity */ #define PADD 0x47 /* port a data direction */ #define PASIOC 0x49 /* port a special io control */ #define PAPP 0x4b /* port a pattern palarity */ #define PAPT 0x4d /* port a pattern transition */ #define PAPM 0x4f /* port a patterm mask */ #define PAIV 0x05 /* port a interrupt vector */ #define PADATA 0x1b /* port a data */ /* * Register addresses for Port C */ #define PCDD 0x0d /* port c data direction */ #define PCSIOC 0x0f /* port c special io control */ #define PCDPP 0x0b /* port c data path polarity */ #define PCDATA 0x1f /* port c data */ /* * Misc hardware flags and values */ #define MIE 0x80 /* master interrupt enable */ #define PAE 0x04 /* port a enable */ #define C_IPIUS 0x20 /* clear IP&IUS command */ #define IRF 0x04 /* input register full */ #define HRVECTOR 8 /* port a interrupt vector */ #define MAJOR 7 /* major device # of the console */ #define NMBUF 100 /* # message buffers */ #define MDELAY 10 /* delay (ticks) between mouse pos reports */ #define NOEVMGR (-1) /* indicates no event manager set */ #define MOUSEWI 16 /* mouse cursor bit width */ #define MOUSEHI 16 /* mouse cursor bit height */ /* flags */ #define WRITING 0x0001 /* appl. is blocked in hrwrite */ #define READING 0x0002 /* appl. is blocked in hrread */ #define WANTMB 0x0004 /* mbuf wanted */ #define NEEDDAT 0x0008 /* appl. waiting for simple data*/ #define GETDAT 0x0010 /* appl. blocked in getting data*/ #define NEEDMSG 0x0020 /* device blocked for message */ #define EXCL 0x0040 /* device is exclusive use */ #define BUSY 0x0080 /* previous send failed (EDBUSY)*/ /* * Index into client's sleeping array for event types */ #define SLP_WRIT (0) #define SLP_READ (1) #define SLP_MBUF (2) #define SLP_NDAT (3) #define SLP_GETD (4) #define SLP_MSG (5) #define SLP_MAX (5) struct cdata { int i; struct sgttyb tty; }; struct client { uint flags, wtype, /* window manager (WINDOW only) */ pid, /* window managers only */ group; /* process group */ int ocount; /* open count */ struct mbuf *head, /* messages waiting to be read */ *tail; /* last message in queue */ char *sleeping[SLP_MAX+1]; /* event awaited, many types */ int datc; /* read character data */ struct cdata data; /* misc client data */ }; struct mbuf { struct mbuf *mb_next; struct message mb_m; }; /* states of the xfer mechanism */ #define XIDLE 0 #define XFILL 1 #define XDRAIN 2 #define XERROR 3 /* event manager list */ struct evmgr { uint edev; /* device */ int emsen; struct evmgr *enext; }; /* mouse cursor buffer */ struct mouse { ulong ms_buf[16]; /* mouse pattern buffer */ int ms_x, /* last x position drawn */ ms_y, /* last y position drawn */ ms_bit, /* bit alignment of pat in buf */ ms_en; /* cursor drawing enabled flag */ }; struct mouse mousebuf = { { 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L, 0xffff0000L }, 0, 0, 7, 0 }; uint xstate, /* state of the xfer mechanism */ xbufn; /* # chars waiting in `xbuf' */ char xbuf[100]; /* kernel buffer for xfer mechanism */ struct mbuf mbuf[NMBUF], /* message buffers */ *mbufp, /* head of the free message buffers */ *mshead, /* head of mouse button msg list */ *mstail; /* end of mouse button msg list */ struct client client[DESTMAX]; /* message clients */ struct evmgr evmgr[WINDOW], /* room for all managers */ *evmfree, /* free evmgr list */ *evmlist; /* in-use evmgr entry */ struct xfer x; /* user args for xfer operation */ uint hrsmgr, /* who is event mgr */ hrislocked; /* is SMGR blocked? */ hrticks; /* time indicator for mouse and keys */ struct message mouse; /* mouse position report for SMGR */ struct message tiomsg; /* misc TIO function data */ TIM timebuf; /* to call hrmouse( ) every tick */ saddr_t kbpamap; /* original kbd OS segment mapping */ int (*kbpaivect)(); /* original keyboard ivector routine */ uint kbpaiv; /* original keyboard ivector */ uint kbpamccr; /* original keyboard MCCR register */ int hropen( ), hrclose( ), hrread( ), hrwrite( ), hrioctl( ), hrload( ), hruload( ), nulldev(); struct mbuf *hralloc(); CON hrcon = { DFCHR, MAJOR, hropen, hrclose, nulldev, hrread, hrwrite, hrioctl, nulldev, nulldev, hrload, hruload }; hrload( ) { register struct mbuf *p; register struct client *cp; register struct evmgr *ev; int s; extern void hrkey(); extern int (*vecs[])(); extern saddr_t vmaps[]; /* * Initialize clients, free lists, etc. */ hrsmgr = NOEVMGR; mbufp = mbuf; for (p=mbuf; p<endof( mbuf)-1; ++p) p->mb_next = p + 1; for (cp=client; cp< &client[WINDOW + 8]; ++cp) cp->wtype = WMGR + 1; for ( ; cp < &client[WINDOW + 10] ; ++cp ) cp->wtype = WMGR + 3; for (; cp< endof(client); ++cp) cp->wtype = WMGR + 2; for ( ev=evmgr ; ev<endof( evmgr)-1; ev++) ev->enext = ev + 1; evmfree = evmgr; evmlist = NULL; mouse.m_src = DRIVER; mouse.m_msg[0] = not SM_MOUSE; /* * Old Keyboard Status */ kbpaiv = inb(ZCIO1+PAIV); kbpamccr = inb(ZCIO1+MCCR); kbpaivect = vecs[kbpaiv >> 1]; kbpamap = vmaps[kbpaiv >> 1]; /* * Keyboard Load */ s = sphi(); if ( kbpamccr & PAE ) clrivec(kbpaiv); setivec(HRVECTOR, hrkey); outb(ZCIO1+PAMS, 0x1a); outb(ZCIO1+PAHS, 0x00); outb(ZCIO1+PADPP, 0x00); outb(ZCIO1+PADD, 0xff); outb(ZCIO1+PASIOC,0x00); outb(ZCIO1+PAPP, 0x80); outb(ZCIO1+PAPT, 0x00); outb(ZCIO1+PAPM, 0x80); outb(ZCIO1+PAIV, HRVECTOR); outb(ZCIO1+PACAS, 0xc0); outb(ZCIO1+MICR, inb(ZCIO1+MICR)|MIE); outb(ZCIO1+MCCR, inb(ZCIO1+MCCR)|PAE); outb(PKBD, KBDEN); outb(ZCIO1+PCDATA, 0); /* toggle pc3 */ outb(ZCIO1+PCDATA, PC3); spl(s); } hruload() { int s; extern saddr_t vmaps[]; mousebuf.ms_en = 0; timeout( &timebuf, 0, NULL, 0); s = sphi(); outb(ZCIO1+MCCR, kbpamccr); clrivec(HRVECTOR); if ( kbpamccr & PAE ) { setivec(kbpaiv, kbpaivect); vmaps[kbpaiv >> 1] = kbpamap; } spl(s); } hropen( dev, mode) dev_t dev; { register struct client *cp; register PROC *pp; register uint d; struct mbuf *p; d = minor( dev); if (d >= DESTMAX) { u.u_error = ENXIO; return; } cp = &client[d]; pp = SELF; if ( cp->flags & EXCL ) { u.u_error = EDBUSY; return; } if ( d<WINDOW ) { cp->flags = EXCL; cp->pid = pp->p_pid; cp->group = pp->p_group; cp->ocount++; if (pp->p_ttdev == NODEV) pp->p_ttdev = dev; #ifdef DEBUG printf("HROPEN: dev %d, pid %d, group %d\n", d, pp->p_pid, pp->p_group); #endif return; } else { if ( cp->ocount ) goto setgroup; hrlock(d, NEEDDAT); if ( cp->ocount ) { cp->flags &= ~NEEDDAT; goto setgroup; } p = hralloc(d); p->mb_m.m_src = d; p->mb_m.m_msg[0] = WM_OPEN; hrlink(cp->wtype, p); if ( hrwait(d, SLP_NDAT) == FALSE ) return; if ( cp->data.i ) { u.u_error = ENXIO; return; } setgroup: cp->ocount++; if ( pp->p_group == client[DMGR].group ) { if ( not cp->group ) cp->group = pp->p_pid; pp->p_group = cp->group; } if (pp->p_ttdev == NODEV) pp->p_ttdev = dev; #ifdef DEBUG printf("HROPEN: dev %d, pid %d, pgroup %d, cgroup %d\n", d, pp->p_pid, pp->p_group, cp->group); #endif } } hrclose( dev) dev_t dev; { register struct client *cp; register struct mbufp *p; uint self; self = minor( dev); cp = &client[self]; if ( --cp->ocount == 0 ) { if ( self >= WINDOW ) { hrlock(self, NEEDDAT); p = hralloc( self ); p->mb_m.m_src = self; p->mb_m.m_msg[0] = WM_CLOSE; hrlink(cp->wtype, p); hrwait(self, SLP_NDAT); } else hruevmgr(self); cp->flags = 0; cp->pid = 0; cp->group = 0; } } hrread( dev, iop) dev_t dev; IO *iop; { register struct mbuf *p; register struct client *cp; register uint self; if (not iop->io_ioc) return; self = minor( dev); cp = &client[self]; hrlock(self, READING); p = hralloc(self); p->mb_m.m_src = self; p->mb_m.m_msg[0] = WM_GETC; hrlink(cp->wtype, p); if ( hrwait(self, SLP_READ) == FALSE ) return; if ( cp->datc >= 0 ) ioputc( cp->datc, iop); } hrwrite( dev, iop) dev_t dev; register IO *iop; { register struct mbuf *p; register struct client *cp; register uint self; bool xcheck( ); if (not iop->io_ioc) return; self = minor( dev); cp = &client[self]; hrlock(self, WRITING); p = hralloc(self); p->mb_m.m_src = self; p->mb_m.m_msg[0] = WM_PUTD; p->mb_m.m_msg[1] = iop->io_ioc; p->mb_m.m_msg[2] = hiword( iop->io_base); p->mb_m.m_msg[3] = loword( iop->io_base); hrlink(cp->wtype, p); while (not xcheck( self)) { cp->sleeping[SLP_WRIT] = cp; sleep( cp, CVNOSIG, 0, 0); cp->sleeping[SLP_WRIT] = 0; } cp->flags &= ~WRITING; wakeup( &cp->flags); if (xstate == XERROR) u.u_error = EIO; else iop->io_ioc = 0; } hrioctl( dev, com, args) dev_t dev; int *args; { register struct mbuf *p; register struct client *cp; register uint self, d; uint *ip; ulong *lp; static uint mousepat[MOUSEHI]; self = minor( dev); switch (com) { case CIOFLUSH: hrflush(self); return; case CIOSENDM: xcheck(self); d = sphi(); if (not ismbfree() ) { client[self].flags |= BUSY; u.u_error = EDBUSY; spl(d); return; } p = mbufp; mbufp = p->mb_next; spl(d); ukcopy( args, &p->mb_m, sizeof p->mb_m); if (u.u_error) { hrunalloc(p); return; } d = p->mb_m.m_dst; if (d >= DESTMAX) baddest( ); p->mb_m.m_src = self; hrlink(d, p); return; case CIOGETM: cp = &client[self]; if (self==hrsmgr && !mstail && mouse.m_msg[0]==SM_MOUSE) { kucopy( &mouse, args, sizeof( struct message)); mouse.m_msg[0] = not SM_MOUSE; return; } hrlock(self, NEEDMSG); while (not cp->head) { if (cp->flags&BUSY && ismbfree() ) { cp->flags &= ~(BUSY+NEEDMSG); u.u_error = EDATTN; return; } hrsleep( &cp->head, self, SLP_MSG); if ( SELF->p_ssig && nondsig() ) { u.u_error = EINTR; cp->flags &= ~(BUSY+NEEDMSG); wakeup(&cp->flags); return; } if (self==hrsmgr && !mstail && mouse.m_msg[0]==SM_MOUSE) { kucopy( &mouse, args, sizeof( struct message)); mouse.m_msg[0] = not SM_MOUSE; cp->flags &= ~NEEDMSG; return; } } cp->flags &= ~NEEDMSG; kucopy( &cp->head->mb_m, args, sizeof( struct message)); if (u.u_error) return; #ifdef DEBUG if ( self == cp->head->mb_m.m_src ) { struct mbuf *p2; printf("\007CIOGETM: msg to self %d\n", self); for ( p2=client[SMGR].head; p2 ; p2=p2->mb_next ) if ( p2 == cp->head ) { printf("\tIN SMGR LIST, TOO\n"); return; } } #endif hrfree(self); return; case CIOGETD: while (xstate != XIDLE) hrsleep( &x, self, SLP_GETD); ukcopy( args, &x, sizeof x); if (u.u_error) return; if (x.x_src >= DESTMAX) baddest( ); cp = &client[x.x_src]; loop switch (xstate) { case XIDLE: if (not x.x_count) { wakeup( &x); return; } xstate = XFILL; for (d=0 ; d <= SLP_MAX ; d++) if (cp->sleeping[d]) { wakeup( cp->sleeping[d]); break; } break; case XFILL: sleep( &xstate, CVCLIST, IVCLIST, SVCLIST); break; case XDRAIN: kucopy( xbuf, x.x_dstp, xbufn); if (u.u_error) { xstate = XIDLE; wakeup( &x); return; } x.x_srcp += xbufn; x.x_dstp += xbufn; x.x_count -= xbufn; xstate = XIDLE; break; case XERROR: panic( "CIOGETD"); } case CIOSIG: if ( self < WINDOW ) hrsignal( hiword( args), loword( args)); return; case CIOEVMGR: if ( self < WINDOW && self != hrsmgr ) { struct evmgr *ev; for ( ev=evmlist ; ev ; ev=ev->enext ) if ( ev->edev == self ) return; while ( hrislocked ) sleep(&hrislocked, 0, 0, 0); if ( hrsmgr != NOEVMGR ) { ev = evmfree; evmfree = evmfree->enext; ev->edev = hrsmgr; ev->emsen = mousebuf.ms_en; ev->enext = evmlist; evmlist = ev; } hrevmgr(self); } return; case CIOUEVMGR: if ( self < WINDOW ) hruevmgr(self); return; case CIOHOLD: if ( self == hrsmgr && self != SMGR && !hrislocked ) { hrislocked++; hrsignal(SMGR, SIGALRM); } return; case CIOUHOLD: if ( self == hrsmgr ) { hrislocked = 0; wakeup(&hrislocked); } return; case CIOWAIT: if ( self == SMGR ) while ( hrislocked ) sleep( &hrislocked, 0, 0, 0); return; case CIOMSEON: if ( self == hrsmgr ) hrmseon(); return; case CIOMSEOFF: if ( self == hrsmgr ) hrmseoff(); return; case CIOMOUSE: if ( self != hrsmgr ) return; if ( mousebuf.ms_en ) hrudraw(); ukcopy(args, mousepat, sizeof(mousepat)); if ( !u.u_error ) { mousebuf.ms_bit = 7; ip = endof(mousepat) - 1; lp = endof(mousebuf.ms_buf) - 1; while ( ip >= mousepat ) *lp-- = ((ulong) *ip--) << 16; } if ( mousebuf.ms_en ) hrdraw(mouse.m_msg[2], mouse.m_msg[3]); return; case CIODATA: cp = &client[ hiword( args)]; cp->datc = loword( args ); cp->flags &= ~READING; wakeup( &cp->datc ); return; case CIOACK: cp = &client[ hiword( args)]; cp->data.i = loword( args ); cp->flags &= ~NEEDDAT; wakeup( &cp->data ); return; case CIOSGTTY: case CIOTCHRS: ukcopy( args, &tiomsg, sizeof( struct message )); if ( u.u_error ) return; cp = &client[tiomsg.m_dst]; cp->data.tty = * (struct sgttyb *) &tiomsg.m_msg[1]; cp->flags &= ~NEEDDAT; wakeup(&cp->data); return; case TIOCSETP: case TIOCSETC: case TIOCSETN: if ( self < WINDOW ) return; p = hralloc(self); p->mb_m.m_src = self; p->mb_m.m_msg[0] = ( com == TIOCSETP ? WM_TIOSETP : ( com == TIOCSETN ? WM_TIOSETN: WM_TIOSETC)); if ( sizeof(struct sgttyb) > sizeof(p->mb_m.m_msg) - sizeof(p->mb_m.m_msg[0]) ) { hrunalloc(p); panic("xxx tiocset"); } ukcopy( args, &p->mb_m.m_msg[1], sizeof ( struct sgttyb ) ); if ( u.u_error ) { hrunalloc(p); return; } hrlink(client[self].wtype, p); return; case TIOCGETP: case TIOCGETC: if ( self < WINDOW ) return; cp = &client[self]; hrlock(self, NEEDDAT); p = hralloc(self); p->mb_m.m_src = self; p->mb_m.m_msg[0] = ( com == TIOCGETP ? WM_TIOGETP : WM_TIOGETC); if ( sizeof(struct sgttyb) > sizeof(p->mb_m.m_msg) - sizeof(p->mb_m.m_msg[0]) ) { hrunalloc(p); panic("xxx tiocget"); } hrlink(cp->wtype, p); if ( hrwait(self, SLP_NDAT) == FALSE ) return; kucopy( &cp->data.tty, args, sizeof(struct sgttyb) ); return; case TIOCEXCL: client[self].flags |= EXCL; return; case TIOCNXCL: if ( self >= WINDOW ) client[self].flags &= ~EXCL; return; case TIOCFLUSH: if ( self < WINDOW ) return; p = hralloc(self); p->mb_m.m_src = self; p->mb_m.m_msg[0] = WM_TIOFLSH; hrlink(client[self].wtype, p); return; } } hrsleep( e, self, stype) char *e; uint self; uint stype; { register struct client *cp; if ( stype > SLP_MAX ) panic("bad sleep type"); xcheck( self); cp = &client[self]; cp->sleeping[stype] = e; sleep( e, CVNOSIG, 0, 0); cp->sleeping[stype] = 0; } bool xcheck( self) uint self; { if (xstate!=XFILL || x.x_src!=self) return (FALSE); xbufn = sizeof xbuf; if (x.x_count < sizeof xbuf) xbufn = x.x_count; ukcopy( x.x_srcp, xbuf, xbufn); if (u.u_error) { xstate = XERROR; u.u_error = 0; wakeup( &xstate); return (TRUE); } xstate = XDRAIN; wakeup( &xstate); return (xbufn == x.x_count); } #include "hr2.c" /* ** make this client the event manager. */ hrevmgr(self) register uint self; { register struct mbuf *p; register struct client *cp; int s; s = sphi(); if ( mstail ) { cp = &client[hrsmgr]; p = cp->head; cp->head = mstail->mb_next; cp = &client[self]; if ( not (mstail->mb_next = cp->head) ) { cp->tail = mstail; wakeup(&cp->head); } cp->head = p; #ifdef DEBUG for ( p=cp->head; p->mb_next ; p=p->mb_next ) if ( p == mstail ) printf("HREVMGR: good mstail\n"); if ( p != cp->tail) printf("HREVMGR: bad tail %d\n", self); #endif } else if ( mouse.m_msg[0] == SM_MOUSE ) wakeup(&client[self].head); hrsmgr = self; spl(s); } /* ** If the client is in the event mgr list, eliminate it. ** If it is the current event mgr, change to the next one if any. ** If there is no next mgr, eliminate all mouse msgs and disable. */ hruevmgr(self) uint self; { register struct evmgr *ep, *ep2; int s; if ( self == hrsmgr ) { if ( not (ep = evmlist) ) { s = sphi(); mouse.m_msg[0] = not SM_MOUSE; hrmseoff(); while ( mstail ) hrfree(self); hrsmgr = NOEVMGR; spl(s); } else { evmlist = ep->enext; ep->enext = evmfree; evmfree = ep; hrevmgr(ep->edev); if ( ep->emsen ) hrmseon(); else hrmseoff(); } if ( hrislocked ) { hrislocked = 0; wakeup(&hrislocked); } return; } ep2 = NULL; ep = evmlist; while ( ep ) { if ( ep->edev == self ) { if ( ep2 ) ep2->enext = ep->enext; else evmlist = ep->enext; ep->enext = evmfree; evmfree = ep; return; } ep2 = ep; ep = ep->enext; } }