|
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 - metrics - download
Length: 11949 (0x2ead) Types: TextFile Notes: UNIX file Names: »bio.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦2d53db1df⟧ UNIX Filesystem └─⟦this⟧ »sys/coh/bio.c«
/* (-lgl * The information contained herein is a trade secret of Mark Williams * Company, and is confidential information. It is provided under a * license agreement, and may be copied or disclosed only under the * terms of that agreement. Any reproduction or disclosure of this * material without the express written authorization of Mark Williams * Company or persuant to the license agreement is unlawful. * * COHERENT Version 0.7.3 * Copyright (c) 1982, 1983, 1984. * An unpublished work by Mark Williams Company, Chicago. * All rights reserved. -lgl) */ /* * Coherent. * Buffered I/O. */ #include <coherent.h> #include <buf.h> #include <con.h> #include <errno.h> #include <io.h> #include <proc.h> #include <sched.h> #include <seg.h> #include <stat.h> #include <uproc.h> /* * Initialise buffer headers. */ bufinit() { register BUF *bp; register paddr_t p; register int i; p = blockp; bufl = kalloc(NBUF * sizeof(BUF)); if (bufl == NULL) panic("bufinit: no space for BUF's"); for (i=0; i<NBUF; i++) { bp = &bufl[i]; bp->b_dev = NODEV; bp->b_vaddr = bvirt(bconv(p)); bp->b_paddr = p; p += BSIZE; } } /* * Synchronise the buffer cache. */ bsync() { register BUF *bp; for (bp=bufl; bp<&bufl[NBUF]; bp++) { if ((bp->b_flag&BFMOD) == 0) continue; lock(bp->b_gate); if ((bp->b_flag&BFMOD) != 0) bwrite(bp, 1); unlock(bp->b_gate); } } /* * Synchronise all block for a particular device in the buffer cache * and invalidate all references. */ bflush(dev) register dev_t dev; { register BUF *bp; for (bp=bufl; bp<&bufl[NBUF]; bp++) { if (bp->b_dev != dev) continue; lock(bp->b_gate); if (bp->b_dev == dev) { if ((bp->b_flag&BFMOD) != 0) bwrite(bp, 1); bp->b_dev = NODEV; } unlock(bp->b_gate); } } /* * Return a buffer containing the given block from the given device. * If `f' is not set, the read is asynchronous and no buffer is returned. */ BUF * bread(dev, bno, f) dev_t dev; daddr_t bno; register int f; { register BUF *bp; register int s; bp = bclaim(dev, bno); if ((bp->b_flag&BFNTP) != 0) { if (f != 0) bp->b_flag &= ~BFASY; else { bp->b_flag |= BFASY; bumap(bp); } bp->b_req = BREAD; bp->b_count = BSIZE; s = sphi(); dblock(dev, bp); if (f == 0) { spl(s); return (NULL); } #if READAHEAD > 0 spl(s); bread(dev, bno+1, 0); #endif #if READAHEAD > 1 bread(dev, bno+2, 0); #endif #if READAHEAD > 2 bread(dev, bno+3, 0); #endif #if READAHEAD > 3 bread(dev, bno+4, 0); #endif #if READAHEAD > 0 sphi(); #endif while ((bp->b_flag&BFNTP) != 0) sleep((char *)bp, CVBLKIO, IVBLKIO, SVBLKIO); spl(s); if ((bp->b_flag&BFERR) != 0) { u.u_error = bp->b_err ? bp->b_err : EIO; brelease(bp); return (NULL); } if (bp->b_resid == BSIZE) { brelease(bp); return (NULL); } } if (f == 0) { brelease(bp); return (NULL); } u.u_block++; return (bp); } /* * If the requested buffer is in the buffer cache, return a pointer to * it. If not, pick an empty buffer, set it up and return it. */ BUF * bclaim(dev, bno) dev_t dev; daddr_t bno; { register BUF *bp; register BUF *bp1; register unsigned seqn; register int s; again: bp1 = NULL; seqn = 0; for (bp=bufl; bp<&bufl[NBUF]; bp++) { if (bp->b_dev==dev && bp->b_bno==bno) { lock(bp->b_gate); if (bp->b_dev!=dev || bp->b_bno!=bno) { unlock(bp->b_gate); goto again; } if ((bp->b_flag&BFERR) != 0) bp->b_flag |= BFNTP; bsmap(bp); return (bp); } if (locked(bp->b_gate) == 0) { if (bufseqn-bp->b_seqn >= seqn) { bp1 = bp; seqn = bufseqn - bp->b_seqn; } } } if (bp1 == NULL) { s = sphi(); for (bp=bufl; bp<&bufl[NBUF]; bp++) { if (locked(bp->b_gate) == 0) { if (bufseqn-bp->b_seqn >= seqn) { bp1 = bp; seqn = bufseqn - bp->b_seqn; } } } if (bp1 == NULL) { bufneed = 1; sleep((char *)&bufneed, CVBLKIO, IVBLKIO, SVBLKIO); spl(s); goto again; } spl(s); } bp = bp1; lock(bp->b_gate); if ((bp->b_flag&BFMOD) != 0) { bwrite(bp, 0); goto again; } bp->b_flag = BFNTP; bp->b_dev = dev; bp->b_bno = bno; bsmap(bp); return (bp); } /* * Write the given buffer out. If `f' is set, the write is synchronous, * otherwise asynchronous. This routine must be called with the buffer * gate locked. */ bwrite(bp, f) register BUF *bp; { register int s; if (f != 0) bp->b_flag &= ~BFASY; else { bp->b_flag |= BFASY; bumap(bp); } bp->b_flag |= BFNTP; bp->b_req = BWRITE; bp->b_count = BSIZE; s = sphi(); dblock(bp->b_dev, bp); if (f == 0) { spl(s); return; } while ((bp->b_flag&BFNTP) != 0) sleep((char *)bp, CVBLKIO, IVBLKIO, SVBLKIO); spl(s); } /* * This is called by the driver when I/O has completed on a buffer. */ bdone(bp) register BUF *bp; { if (bp->b_req == BWRITE) bp->b_flag &= ~BFMOD; if (bp->b_req == BREAD) { if ((bp->b_flag&BFERR) != 0) bp->b_dev = NODEV; } if ((bp->b_flag&BFASY) != 0) { bp->b_flag &= ~BFASY; brelease(bp); } bp->b_flag &= ~BFNTP; wakeup((char *)bp); } /* * Release the given buffer. */ brelease(bp) register BUF *bp; { if ((bp->b_flag&BFERR) == 0) bp->b_seqn = bufseqn++; else { bp->b_flag &= ~BFERR; bp->b_dev = NODEV; } bp->b_flag &= ~BFNTP; bumap(bp); unlock(bp->b_gate); if (bufneed != 0) { bufneed = 0; wakeup((char *)&bufneed); } } /* * Map the given buffer. */ bsmap(bp) register BUF *bp; { bsave(bp->b_map); bp->b_flag |= BFMAP; bmapv(bconv(bp->b_paddr)); } /* * Unmap the given buffer. */ bumap(bp) register BUF *bp; { if ((bp->b_flag&BFMAP) == 0) return; bp->b_flag &= ~BFMAP; brest(bp->b_map); } /* * Read data from the I/O segment into kernel space. */ ioread(iop, v, n) register IO *iop; register char *v; register unsigned n; { switch (iop->io_seg) { case IOSYS: iop->io_base += kkcopy(iop->io_base, v, n); break; case IOUSR: iop->io_base += ukcopy(iop->io_base, v, n); break; case IOPHY: iop->io_phys += pkcopy(iop->io_phys, v, n); break; } iop->io_ioc -= n; } /* * Write data from kernel space to the I/O segment. */ iowrite(iop, v, n) register IO *iop; register char *v; register unsigned n; { switch (iop->io_seg) { case IOSYS: iop->io_base += kkcopy(v, iop->io_base, n); break; case IOUSR: iop->io_base += kucopy(v, iop->io_base, n); break; case IOPHY: iop->io_phys += kpcopy(v, iop->io_phys, n); break; } iop->io_ioc -= n; } /* * Get a character from the I/O segment. */ iogetc(iop) register IO *iop; { register int c; if (iop->io_ioc == 0) return (-1); --iop->io_ioc; if (iop->io_seg == IOSYS) c = *iop->io_base++ & 0377; else { c = getubd(iop->io_base++); if (u.u_error) return (-1); } return (c); } /* * Put a character using the I/O segment. */ ioputc(c, iop) register IO *iop; { if (iop->io_ioc == 0) return (-1); --iop->io_ioc; if (iop->io_seg == IOSYS) *iop->io_base++ = c; else { putubd(iop->io_base++, c); if (u.u_error) return (-1); } return (c); } /* * Given a buffer pointer, an I/O structure, a device, request type, and * a flags word, check the I/O structure and perform the I/O request. */ ioreq(bp, iop, dev, req, f) register BUF *bp; register IO *iop; dev_t dev; { register SEG *sp; register int n; register int s; register CON *cp; dold_t dold; if ((cp=drvmap(dev, &dold)) == NULL) return; lock(bp->b_gate); n = cp->c_flag; /* n should do something with that flag */ drest(dold); sp = NULL; if (iop != NULL) { if ((f&BFBLK) != 0) { if (blocko(iop->io_seek) != 0) { u.u_error = EIO; goto out; } } if ((f&BFIOC) != 0) { if ((sp=iomapvp(iop, bp)) == NULL) { u.u_error = EIO; goto out; } } } bp->b_flag = f|BFNTP; bp->b_req = req; bp->b_dev = dev; if (iop != NULL) { bp->b_bno = blockn(iop->io_seek); bp->b_count = iop->io_ioc; } if (sp != NULL) sp->s_lrefc++; s = sphi(); dblock(dev, bp); while ((bp->b_flag&BFNTP) != 0) sleep((char *)bp, CVBLKIO, IVBLKIO, SVBLKIO); spl(s); if (sp != NULL) --sp->s_lrefc; wakeup((char *)&stimer); if ((bp->b_flag&BFERR) != 0) { u.u_error = bp->b_err ? bp->b_err : EIO; goto out; } if (iop != NULL) { n = iop->io_ioc - bp->b_resid; iop->io_seek += n; iop->io_ioc -= n; } out: unlock(bp->b_gate); } /* * Given an I/O structure and a buffer header, see if the addresses * in the I/O structure are valid and set up the buffer header. */ SEG * iomapvp(iop, bp) register IO *iop; register BUF *bp; { register SR *srp; register SEG *sp; register vaddr_t b; if (iop->io_seg != IOUSR) panic("Raw I/O from non user"); for (srp=u.u_segl; srp<&u.u_segl[NUSEG]; srp++) { if ((sp=srp->sr_segp) == NULL) continue; if ((srp->sr_flag&SRFDATA) == 0) continue; /* Yet another bug in the 8000 C compiler if ((long)(b=iop->io_base) < (long)srp->sr_base) */ if ((b=iop->io_base) < srp->sr_base) continue; if ((long)b+iop->io_ioc > (long)srp->sr_base+ctob(sp->s_size)) continue; bp->b_paddr = ctob((paddr_t)sp->s_mbase) + vtop(b) - vtop(srp->sr_base); return (sp); } return (NULL); } /* * Initialise devices. */ devinit() { register DRV *dp; register DRV *dpe; for (dp=drvl, dpe=&dp[drvn]; dp<dpe; dp++) if (dp->d_conp != NULL) (*dp->d_conp->c_load)(); } /* * Open a device. */ dopen(dev, m, f) register dev_t dev; { register CON *cp; dold_t dold; if ((cp=drvmap(dev, &dold)) == NULL) return; if ((cp->c_flag&f) == 0) { u.u_error = ENXIO; return; } (*cp->c_open)(dev, m); drest(dold); } /* * Close a device. */ dclose(dev) register dev_t dev; { register CON *cp; dold_t dold; if ((cp=drvmap(dev, &dold)) == NULL) return; (*cp->c_close)(dev); drest(dold); } /* * Call the block entry point of a device. */ dblock(dev, bp) dev_t dev; BUF *bp; { register CON *cp; dold_t dold; if ((cp=drvmap(dev, &dold)) == NULL) return; (*cp->c_block)(bp); drest(dold); } /* * Read from a device. */ dread(dev, iop) register dev_t dev; register IO *iop; { register CON *cp; dold_t dold; if ((cp=drvmap(dev, &dold)) == NULL) return; (*cp->c_read)(dev, iop); drest(dold); } /* * Write to a device. */ dwrite(dev, iop) register dev_t dev; register IO *iop; { register CON *cp; dold_t dold; if ((cp=drvmap(dev, &dold)) == NULL) return; (*cp->c_write)(dev, iop); drest(dold); } /* * Call the ioctl function for a device. */ dioctl(dev, com, vec) register dev_t dev; union ioctl *vec; { register CON *cp; dold_t dold; if ((cp=drvmap(dev, &dold)) == NULL) return; (*cp->c_ioctl)(dev, com, vec); drest(dold); } /* * Call the powerfail entry point of a device. */ dpower(dev) register dev_t dev; { register CON *cp; dold_t dold; if ((cp=drvmap(dev, &dold)) == NULL) return; (*cp->c_power)(dev); drest(dold); } /* * Call the timeout entry point of a device. */ dtime(dev) register dev_t dev; { register CON *cp; dold_t dold; if ((cp=drvmap(dev, &dold)) == NULL) return; (*cp->c_timer)(dev); drest(dold); } /* * Given a device, return the flags word. */ dflag(dev) dev_t dev; { register CON *cp; register int f; dold_t dold; if ((cp=drvmap(dev, &dold)) == NULL) return (DFERR); f = cp->c_flag; drest(dold); return (f); } /* * Given a device, and a pointer to a driver map save area, save the * current map in the driver map save area and map in the new device, * returning a pointer to the configuration entry for that device. */ CON * drvmap(dev, doldp) dev_t dev; dold_t *doldp; { register DRV *dp; register unsigned m; if ((m=major(dev)) >= drvn) { u.u_error = ENXIO; return (NULL); } dp = &drvl[m]; if (locked(dp->d_gate)) { u.u_error = ENXIO; return (NULL); } if (dp->d_conp == NULL) { u.u_error = ENXIO; return (NULL); } dsave(*doldp); if (dp->d_map != 0) dmapv(dp->d_map); return (dp->d_conp); } /* * Non existant device. */ nonedev() { u.u_error = ENXIO; } /* * Null device. */ nulldev() { }