dbraun@cadavr.intel.com (Doug Braun ~) (11/29/88)
UZI, Part 3 of 5: #!/bin/sh # #Run this file through sh to get: # filesys.c # devtty.c echo -n 'Extracting filesys.c ... ' sed 's/^X//' > filesys.c << 'EOF_filesys.c' X/************************************************** XUZI (Unix Z80 Implementation) Kernel: filesys.c X***************************************************/ X X X#include "unix.h" X#include "extern.h" X X Xchar *bread(); X X X/* N_open is given a string containing a path name, X and returns a inode table pointer. If it returns NULL, X the file did not exist. If the parent existed, X and parent is not null, parent will be filled in with X the parents inoptr. Otherwise, parent will be set to NULL. */ X Xinoptr Xn_open(name,parent) Xregister char *name; Xregister inoptr *parent; X{ X X register inoptr wd; /* the directory we are currently searching. */ X register inoptr ninode; X register inoptr temp; X inoptr srch_dir(); X inoptr srch_mt(); X X if (*name == '/') X wd = root; X else X wd = udata.u_cwd; X X i_ref(ninode = wd); X i_ref(ninode); X X for(;;) X { X if (ninode) X magic(ninode); X X /* See if we are at a mount point */ X if (ninode) X ninode = srch_mt(ninode); X X while (*name == '/') /* Skip (possibly repeated) slashes */ X ++name; X ifnot (*name) /* No more components of path? */ X break; X ifnot (ninode) X { X udata.u_error = ENOENT; X goto nodir; X } X i_deref(wd); X wd = ninode; X if (getmode(wd) != F_DIR) X { X udata.u_error = ENOTDIR; X goto nodir; X } X ifnot (getperm(wd) & OTH_EX) X { X udata.u_error = EPERM; X goto nodir; X } X X /* See if we are going up through a mount point */ X if ( wd->c_num == ROOTINODE && wd->c_dev != ROOTDEV && name[1] == '.') X { X temp = fs_tab[wd->c_dev].s_mntpt; X ++temp->c_refs; X i_deref(wd); X wd = temp; X } X X ninode = srch_dir(wd,name); X X while (*name != '/' && *name ) X ++name; X } X X if (parent) X *parent = wd; X else X i_deref(wd); X ifnot (parent || ninode) X udata.u_error = ENOENT; X return (ninode); X Xnodir: X if (parent) X *parent = NULLINODE; X i_deref(wd); X return(NULLINODE); X X} X X X X/* Srch_dir is given a inode pointer of an open directory Xand a string containing a filename, and searches the directory Xfor the file. If it exists, it opens it and returns the inode pointer, Xotherwise NULL. This depends on the fact that ba_read will return unallocated Xblocks as zero-filled, and a partially allocated block will be padded with Xzeroes. */ X Xinoptr Xsrch_dir(wd,compname) Xregister inoptr wd; Xregister char *compname; X{ X register int curentry; X register blkno_t curblock; X register struct direct *buf; X register int nblocks; X unsigned inum; X inoptr i_open(); X blkno_t bmap(); X X nblocks = wd->c_node.i_size.o_blkno; X if (wd->c_node.i_size.o_offset) X ++nblocks; X X for (curblock=0; curblock < nblocks; ++curblock) X { X buf = (struct direct *)bread( wd->c_dev, bmap(wd, curblock, 1), 0); X for (curentry = 0; curentry < 32; ++curentry) X { X if (namecomp(compname,buf[curentry].d_name)) X { X inum = buf[curentry&0x1f].d_ino; X brelse(buf); X return(i_open(wd->c_dev, inum)); X } X } X brelse(buf); X } X return(NULLINODE); X} X X X X/* Srch_mt sees if the given inode is a mount point. If Xso it dereferences it, and references and returns a pointer Xto the root of the mounted filesystem. */ X Xinoptr Xsrch_mt(ino) Xregister inoptr ino; X{ X register int j; X inoptr i_open(); X X for (j=0; j < NDEVS; ++j) X if (fs_tab[j].s_mounted == SMOUNTED && fs_tab[j].s_mntpt == ino) X { X i_deref(ino); X return(i_open(j,ROOTINODE)); X } X X return(ino); X} X X X/* I_open is given an inode number and a device number, Xand makes an entry in the inode table for them, or Xincreases it reference count if it is already there. XAn inode # of zero means a newly allocated inode */ X Xinoptr Xi_open(dev,ino) Xregister int dev; Xregister unsigned ino; X{ X X struct dinode *buf; X register inoptr nindex; X int i; X register inoptr j; X int new; X static nexti = i_tab; X unsigned i_alloc(); X X if (dev<0 || dev>=NDEVS) X panic("i_open: Bad dev"); X X new = 0; X ifnot (ino) /* Want a new one */ X { X new = 1; X ifnot (ino = i_alloc(dev)) X { X udata.u_error = ENOSPC; X return (NULLINODE); X } X } X X if (ino < ROOTINODE || ino >= (fs_tab[dev].s_isize-2)*8) X { X warning("i_open: bad inode number"); X return (NULLINODE); X } X X X nindex = NULLINODE; X j = nexti; X for (i=0; i < ITABSIZE; ++i) X { X nexti =j; X if (++j >= i_tab+ITABSIZE) X j = i_tab; X X ifnot (j->c_refs) X nindex = j; X X if (j->c_dev == dev && j->c_num == ino) X { X nindex = j; X goto found; X } X } X X /* Not already in table. */ X X ifnot (nindex) /* No unrefed slots in inode table */ X { X udata.u_error = ENFILE; X return(NULLINODE); X } X X buf = (struct dinode *)bread(dev, (ino>>3)+2, 0); X bcopy((char *)&(buf[ino & 0x07]), (char *)&(nindex->c_node), 64); X brelse(buf); X X nindex->c_dev = dev; X nindex->c_num = ino; X nindex->c_magic = CMAGIC; X Xfound: X if (new) X { X if (nindex->c_node.i_nlink || nindex->c_node.i_mode & F_MASK) X goto badino; X } X else X { X ifnot (nindex->c_node.i_nlink && nindex->c_node.i_mode & F_MASK) X goto badino; X } X X ++nindex->c_refs; X return(nindex); X Xbadino: X warning("i_open: bad disk inode"); X return (NULLINODE); X} X X X X/* Ch_link modifies or makes a new entry in the directory for the name Xand inode pointer given. The directory is searched for oldname. XWhen found, it is changed to newname, and it inode # is that of X*nindex. A oldname of "" matches a unused slot, and a nindex Xof NULLINODE means an inode # of 0. A return status of 0 means there Xwas no space left in the filesystem, or a non-empty oldname was not found, Xor the user did not have write permission. */ X Xch_link(wd,oldname,newname,nindex) Xregister inoptr wd; Xchar *oldname; Xchar *newname; Xinoptr nindex; X{ X struct direct curentry; X X ifnot (getperm(wd) & OTH_WR) X { X udata.u_error = EPERM; X return (0); X } X X /* Search the directory for the desired slot. */ X X udata.u_offset.o_blkno = 0; X udata.u_offset.o_offset = 0; X X for (;;) X { X udata.u_count = 16; X udata.u_base = (char *)&curentry; X readi(wd); X X /* Read until EOF or name is found */ X /* readi() advances udata.u_offset */ X if (udata.u_count == 0 || namecomp(oldname, curentry.d_name)) X break; X } X X if (udata.u_count == 0 && *oldname) X return (0); /* Entry not found */ X X bcopy(newname, curentry.d_name, 14); X if (nindex) X curentry.d_ino = nindex->c_num; X else X curentry.d_ino = 0; X X /* If an existing slot is being used, we must back up the file offset */ X if (udata.u_count) X { X ifnot (udata.u_offset.o_offset) X { X --udata.u_offset.o_blkno; X udata.u_offset.o_offset = 512; X } X udata.u_offset.o_offset -= 16; X } X X udata.u_count = 16; X udata.u_base = (char *)&curentry; X writei(wd); X X if (udata.u_error) X return (0); X X setftime(wd, A_TIME|M_TIME|C_TIME); /* Sets c_dirty */ X X /* Update file length to next block */ X if (wd->c_node.i_size.o_offset) X { X wd->c_node.i_size.o_offset = 0; X ++wd->c_node.i_size.o_blkno; X } X X return (1); X} X X X X/* Filename is given a path name, and returns a pointer Xto the final component of it. */ X Xchar * Xfilename(path) Xchar *path; X{ X register char *ptr; X X ptr = path; X while (*ptr) X ++ptr; X while (*ptr != '/' && ptr-- > path) X ; X return (ptr+1); X} X X X/* Namecomp compares two strings to see if they are the same file name. XIt stops at 14 chars or a null or a slash. It returns 0 for difference. */ X Xnamecomp(n1,n2) Xregister char *n1; Xregister char *n2; X{ X register int n; X X n = 14; X while (*n1 && *n1 != '/') X { X if (*n1++ != *n2++) X return(0); X ifnot (--n) X return(-1); X } X return(*n2 == '\0' || *n2 == '/'); X} X X X X/* Newfile is given a pointer to a directory and a name, and X creates an entry in the directory for the name, dereferences X the parent, and returns a pointer to the new inode. X It allocates an inode number, X and creates a new entry in the inode table for the new file, X and initializes the inode table entry for the new file. The new file X will have one reference, and 0 links to it. X Better make sure there isn't already an entry with the same name. */ X Xinoptr Xnewfile(pino, name) Xregister inoptr pino; Xregister char *name; X{ X X register inoptr nindex; X register int j; X inoptr i_open(); X X ifnot (nindex = i_open(pino->c_dev, 0)) X goto nogood; X X nindex->c_node.i_mode = F_REG; /* For the time being */ X nindex->c_node.i_nlink = 1; X nindex->c_node.i_size.o_offset = 0; X nindex->c_node.i_size.o_blkno = 0; X for (j=0; j <20; j++) X nindex->c_node.i_addr[j] = 0; X wr_inode(nindex); X X ifnot (ch_link(pino,"",filename(name),nindex)) X { X i_deref(nindex); X goto nogood; X } X X i_deref (pino); X return(nindex); X Xnogood: X i_deref (pino); X return (NULLINODE); X} X X X X/* Check the given device number, and return its address in the mount table. XAlso time-stamp the superblock of dev, and mark it modified. XUsed when freeing and allocating blocks and inodes. */ X Xfsptr Xgetdev(devno) Xregister int devno; X{ X register fsptr dev; X X dev = fs_tab + devno; X if (devno < 0 || devno >= NDEVS || !dev->s_mounted) X panic("getdev: bad dev"); X rdtime(&(dev->s_time)); X dev->s_fmod = 1; X return (dev); X} X X X/* Returns true if the magic number of a superblock is corrupt */ X Xbaddev(dev) Xfsptr dev; X{ X return (dev->s_mounted != SMOUNTED); X} X X X/* I_alloc finds an unused inode number, and returns it, Xor 0 if there are no more inodes available. */ X Xunsigned Xi_alloc(devno) Xint devno; X{ X fsptr dev; X blkno_t blk; X struct dinode *buf; X register int j; X register int k; X unsigned ino; X X if (baddev(dev = getdev(devno))) X goto corrupt; X Xtryagain: X if (dev->s_ninode) X { X ifnot (dev->s_tinode) X goto corrupt; X ino = dev->s_inode[--dev->s_ninode]; X if (ino < 2 || ino >= (dev->s_isize-2)*8) X goto corrupt; X --dev->s_tinode; X return(ino); X } X X /* We must scan the inodes, and fill up the table */ X X _sync(); /* Make on-disk inodes consistent */ X k = 0; X for (blk = 2; blk < dev->s_isize; blk++) X { X buf = (struct dinode *)bread(devno, blk, 0); X for (j=0; j < 8; j++) X { X ifnot (buf[j].i_mode || buf[j].i_nlink) X dev->s_inode[k++] = 8*(blk-2) + j; X if (k==50) X { X brelse(buf); X goto done; X } X } X brelse(buf); X } X Xdone: X ifnot (k) X { X if (dev->s_tinode) X goto corrupt; X udata.u_error = ENOSPC; X return(0); X } X X dev->s_ninode = k; X goto tryagain; X Xcorrupt: X warning("i_alloc: corrupt superblock"); X dev->s_mounted = 1; X udata.u_error = ENOSPC; X return(0); X} X X X/* I_free is given a device and inode number, Xand frees the inode. It is assumed that there Xare no references to the inode in the inode table or Xin the filesystem. */ X Xi_free(devno, ino) Xregister int devno; Xregister unsigned ino; X{ X register fsptr dev; X X if (baddev(dev = getdev(devno))) X return; X X if (ino < 2 || ino >= (dev->s_isize-2)*8) X panic("i_free: bad ino"); X X ++dev->s_tinode; X if (dev->s_ninode < 50) X dev->s_inode[dev->s_ninode++] = ino; X} X X X/* Blk_alloc is given a device number, and allocates an unused block Xfrom it. A returned block number of zero means no more blocks. */ X Xblkno_t Xblk_alloc(devno) Xregister int devno; X{ X X register fsptr dev; X register blkno_t newno; X blkno_t *buf; X register int j; X X if (baddev(dev = getdev(devno))) X goto corrupt2; X X if (dev->s_nfree <= 0 || dev->s_nfree > 50) X goto corrupt; X X newno = dev->s_free[--dev->s_nfree]; X ifnot (newno) X { X if (dev->s_tfree != 0) X goto corrupt; X udata.u_error = ENOSPC; X ++dev->s_nfree; X return(0); X } X X /* See if we must refill the s_free array */ X X ifnot (dev->s_nfree) X { X buf = (blkno_t *)bread(devno,newno, 0); X dev->s_nfree = buf[0]; X for (j=0; j < 50; j++) X { X dev->s_free[j] = buf[j+1]; X } X brelse((char *)buf); X } X X validblk(devno, newno); X X ifnot (dev->s_tfree) X goto corrupt; X --dev->s_tfree; X X /* Zero out the new block */ X buf = bread(devno, newno, 2); X bzero(buf, 512); X bawrite(buf); X return(newno); X Xcorrupt: X warning("blk_alloc: corrupt"); X dev->s_mounted = 1; Xcorrupt2: X udata.u_error = ENOSPC; X return(0); X} X X X/* Blk_free is given a device number and a block number, Xand frees the block. */ X Xblk_free(devno,blk) Xregister int devno; Xregister blkno_t blk; X{ X register fsptr dev; X register char *buf; X X ifnot (blk) X return; X X if (baddev(dev = getdev(devno))) X return; X X validblk(devno, blk); X X if (dev->s_nfree == 50) X { X buf = bread(devno, blk, 1); X bcopy((char *)&(dev->s_nfree), buf, 512); X bawrite(buf); X dev->s_nfree = 0; X } X X ++dev->s_tfree; X dev->s_free[(dev->s_nfree)++] = blk; X X} X X X X X/* Oft_alloc and oft_deref allocate and dereference (and possibly free) Xentries in the open file table. */ X Xoft_alloc() X{ X register int j; X X for (j=0; j < OFTSIZE ; ++j) X { X ifnot (of_tab[j].o_refs) X { X of_tab[j].o_refs = 1; X of_tab[j].o_inode = NULLINODE; X return (j); X } X } X udata.u_error = ENFILE; X return(-1); X} X Xoft_deref(of) Xregister int of; X{ X register struct oft *ofptr; X X ofptr = of_tab + of; X X if (!(--ofptr->o_refs) && ofptr->o_inode) X { X i_deref(ofptr->o_inode); X ofptr->o_inode = NULLINODE; X } X} X X X X/* Uf_alloc finds an unused slot in the user file table. */ X Xuf_alloc() X{ X register int j; X X for (j=0; j < UFTSIZE ; ++j) X { X if (udata.u_files[j] & 0x80) /* Portable, unlike == -1 */ X { X return (j); X } X } X udata.u_error = ENFILE; X return(-1); X} X X X X/* I_ref increases the reference count of the given inode table entry. */ X Xi_ref(ino) Xinoptr ino; X{ X if (++(ino->c_refs) == 2*ITABSIZE) /* Arbitrary limit. */ X panic("too many i-refs"); X} X X X/* I_deref decreases the reference count of an inode, and frees it Xfrom the table if there are no more references to it. If it also Xhas no links, the inode itself and its blocks (if not a device) is freed. */ X Xi_deref(ino) Xregister inoptr ino; X{ X magic(ino); X X ifnot (ino->c_refs) X panic("inode freed."); X X if ((ino->c_node.i_mode & F_MASK) == F_PIPE) X wakeup((char *)ino); X X /* If the inode has no links and no refs, it must have X its blocks freed. */ X X ifnot (--ino->c_refs || ino->c_node.i_nlink) X f_trunc(ino); X X /* If the inode was modified, we must write it to disk. */ X if (!(ino->c_refs) && ino->c_dirty) X { X ifnot (ino->c_node.i_nlink) X { X ino->c_node.i_mode = 0; X i_free(ino->c_dev, ino->c_num); X } X wr_inode(ino); X } X} X X X/* Wr_inode writes out the given inode in the inode table out to disk, Xand resets its dirty bit. */ X Xwr_inode(ino) Xregister inoptr ino; X{ X struct dinode *buf; X register blkno_t blkno; X X magic(ino); X X blkno = (ino->c_num >> 3) + 2; X buf = (struct dinode *)bread(ino->c_dev, blkno,0); X bcopy((char *)(&ino->c_node), X (char *)((char **)&buf[ino->c_num & 0x07]), 64); X bfree(buf, 2); X ino->c_dirty = 0; X} X X X/* isdevice(ino) returns true if ino points to a device */ Xisdevice(ino) Xinoptr ino; X{ X return (ino->c_node.i_mode & 020000); X} X X X/* This returns the device number of an inode representing a device */ Xdevnum(ino) Xinoptr ino; X{ X return (*(ino->c_node.i_addr)); X} X X X/* F_trunc frees all the blocks associated with the file, Xif it is a disk file. */ X Xf_trunc(ino) Xregister inoptr ino; X{ X int dev; X int j; X X dev = ino->c_dev; X X /* First deallocate the double indirect blocks */ X freeblk(dev, ino->c_node.i_addr[19], 2); X X /* Also deallocate the indirect blocks */ X freeblk(dev, ino->c_node.i_addr[18], 1); X X /* Finally, free the direct blocks */ X for (j=17; j >= 0; --j) X freeblk(dev, ino->c_node.i_addr[j], 0); X X bzero((char *)ino->c_node.i_addr, sizeof(ino->c_node.i_addr)); X X ino->c_dirty = 1; X ino->c_node.i_size.o_blkno = 0; X ino->c_node.i_size.o_offset = 0; X} X X X/* Companion function to f_trunc(). */ Xfreeblk(dev, blk, level) Xint dev; Xblkno_t blk; Xint level; X{ X blkno_t *buf; X int j; X X ifnot (blk) X return; X X if (level) X { X buf = (blkno_t *)bread(dev, blk, 0); X for (j=255; j >= 0; --j) X freeblk(dev, buf[j], level-1); X brelse((char *)buf); X } X X blk_free(dev,blk); X} X X X X/* Changes: blk_alloc zeroes block it allocates */ X X/* X * Bmap defines the structure of file system storage X * by returning the physical block number on a device given the X * inode and the logical block number in a file. X * The block is zeroed if created. X */ Xblkno_t Xbmap(ip, bn, rwflg) Xinoptr ip; Xregister blkno_t bn; Xint rwflg; X{ X register int i; X register bufptr bp; X register int j; X register blkno_t nb; X int sh; X int dev; X X blkno_t blk_alloc(); X X if (getmode(ip) == F_BDEV) X return (bn); X X dev = ip->c_dev; X X /* X * blocks 0..17 are direct blocks X */ X if(bn < 18) { X nb = ip->c_node.i_addr[bn]; X if(nb == 0) { X if(rwflg || (nb = blk_alloc(dev))==0) X return(NULLBLK); X ip->c_node.i_addr[bn] = nb; X ip->c_dirty = 1; X } X return(nb); X } X X /* X * addresses 18 and 19 X * have single and double indirect blocks. X * the first step is to determine X * how many levels of indirection. X */ X bn -= 18; X sh = 0; X j = 2; X if (bn & 0xff00) /* bn > 255 so double indirect */ X { X sh = 8; X bn -= 256; X j = 1; X } X X /* X * fetch the address from the inode X * Create the first indirect block if needed. X */ X ifnot (nb = ip->c_node.i_addr[20-j]) X { X if(rwflg || !(nb = blk_alloc(dev))) X return(NULLBLK); X ip->c_node.i_addr[20-j] = nb; X ip->c_dirty = 1; X } X X /* X * fetch through the indirect blocks X */ X for(; j<=2; j++) { X bp = (bufptr)bread(dev, nb, 0); X /****** X if(bp->bf_error) { X brelse(bp); X return((blkno_t)0); X } X ******/ X i = (bn>>sh) & 0xff; X if (nb = ((blkno_t *)bp)[i]) X brelse(bp); X else X { X if(rwflg || !(nb = blk_alloc(dev))) { X brelse(bp); X return(NULLBLK); X } X ((blkno_t *)bp)[i] = nb; X bawrite(bp); X } X sh -= 8; X } X X return(nb); X} X X X X/* Validblk panics if the given block number is not a valid data block Xfor the given device. */ X Xvalidblk(dev, num) Xint dev; Xblkno_t num; X{ X register fsptr devptr; X X devptr = fs_tab + dev; X X if (devptr->s_mounted == 0) X panic("validblk: not mounted"); X X if (num < devptr->s_isize || num >= devptr->s_fsize) X panic("validblk: invalid blk"); X} X X X X/* This returns the inode pointer associated with a user's Xfile descriptor, checking for valid data structures */ X Xinoptr Xgetinode(uindex) Xregister int uindex; X{ X register int oftindex; X register inoptr inoindex; X X if (uindex < 0 || uindex >= UFTSIZE || udata.u_files[uindex] & 0x80 ) X { X udata.u_error = EBADF; X return (NULLINODE); X } X X if ((oftindex = udata.u_files[uindex]) < 0 || oftindex >= OFTSIZE) X panic("Getinode: bad desc table"); X X if ((inoindex = of_tab[oftindex].o_inode) < i_tab || X inoindex >= i_tab+ITABSIZE) X panic("Getinode: bad OFT"); X X magic(inoindex); X X return(inoindex); X} X X/* Super returns true if we are the superuser */ Xsuper() X{ X return(udata.u_euid == 0); X} X X/* Getperm looks at the given inode and the effective user/group ids, and Xreturns the effective permissions in the low-order 3 bits. */ X Xgetperm(ino) Xinoptr ino; X{ X int mode; X X if (super()) X return(07); X X mode = ino->c_node.i_mode; X if (ino->c_node.i_uid == udata.u_euid) X mode >>= 6; X else if (ino->c_node.i_gid == udata.u_egid) X mode >>= 3; X X return(mode & 07); X} X X X/* This sets the times of the given inode, according to the flags */ X Xsetftime(ino, flag) Xregister inoptr ino; Xregister int flag; X{ X ino->c_dirty = 1; X X if (flag & A_TIME) X rdtime(&(ino->c_node.i_atime)); X if (flag & M_TIME) X rdtime(&(ino->c_node.i_mtime)); X if (flag & C_TIME) X rdtime(&(ino->c_node.i_ctime)); X} X X Xgetmode(ino) Xinoptr ino; X{ X return( ino->c_node.i_mode & F_MASK); X} X X X/* Fmount places the given device in the mount table with Xmount point ino */ X Xfmount(dev,ino) Xregister int dev; Xregister inoptr ino; X{ X char *buf; X register struct filesys *fp; X X if (d_open(dev) != 0) X panic("fmount: Cant open filesystem"); X /* Dev 0 blk 1 */ X fp = fs_tab + dev; X buf = bread(dev, 1, 0); X bcopy(buf, (char *)fp, sizeof(struct filesys)); X brelse(buf); X X /* See if there really is a filesystem on the device */ X if (fp->s_mounted != SMOUNTED || X fp->s_isize >= fp->s_fsize) X return (-1); X X fp->s_mntpt = ino; X if (ino) X ++ino->c_refs; X X return (0); X} X X Xmagic(ino) Xinoptr ino; X{ X if (ino->c_magic != CMAGIC) X panic("Corrupt inode"); X} X EOF_filesys.c echo 'Done' echo -n 'Extracting devtty.c ... ' sed 's/^X//' > devtty.c << 'EOF_devtty.c' X/************************************************** XUZI (Unix Z80 Implementation) Kernel: devtty.c X***************************************************/ X X X#include "unix.h" Xextern struct u_data udata; X X#define TTYSIZ 132 X Xchar ttyinbuf[TTYSIZ]; X Xstruct s_queue ttyinq = { X ttyinbuf, X ttyinbuf, X ttyinbuf, X TTYSIZ, X 0, X TTYSIZ/2 X}; X Xint stopflag; /* Flag for ^S/^Q */ Xint flshflag; /* Flag for ^O */ X Xtty_read(minor, rawflag) Xint16 minor; Xint16 rawflag; X{ X int nread; X X nread = 0; X while (nread < udata.u_count) X { X for (;;) X { X di(); X if (remq(&ttyinq,udata.u_base)) X break; X psleep(&ttyinq); X if (udata.u_cursig || udata.u_ptab->p_pending) /* messy */ X { X udata.u_error = EINTR; X return(-1); X } X } X ei(); X X if (nread++ == 0 && *udata.u_base == '\004') /* ^D */ X return(0); X X if (*udata.u_base == '\n') X break; X ++udata.u_base; X } X return(nread); X} X X X Xtty_write(minor, rawflag) Xint16 minor; Xint16 rawflag; X{ X int towrite; X X towrite = udata.u_count; X X while (udata.u_count-- != 0) X { X for (;;) /* Wait on the ^S/^Q flag */ X { X di(); X ifnot (stopflag) X break; X psleep(&stopflag); X if (udata.u_cursig || udata.u_ptab->p_pending) /* messy */ X { X udata.u_error = EINTR; X return(-1); X } X } X ei(); X X ifnot (flshflag) X { X if (*udata.u_base == '\n') X _putc('\r'); X _putc(*udata.u_base); X } X ++udata.u_base; X } X return(towrite); X} X X X Xtty_open(minor) Xint minor; X{ X return(0); X} X X Xtty_close(minor) Xint minor; X{ X return(0); X} X X Xtty_ioctl(minor) Xint minor; X{ X return(-1); X} X X X X/* This tty interrupt routine checks to see if the uart receiver actually Xcaused the interrupt. If so it adds the character to the tty input Xqueue, echoing and processing backspace and carriage return. If the queue Xcontains a full line, it wakes up anything waiting on it. If it is totally Xfull, it beeps at the user. */ X Xtty_int() X{ X register char c; X register found; X char oc; X X found = 0; X Xagain: X if( (in(0x72)&0x81) != 0x81 ) X return (found); X c = in(0x73) & 0x7f; X X if (c==0x1a) /* ^Z */ X idump(); /* For debugging */ X X if (c == '\003') /* ^C */ X sendsig(NULL, SIGINT); X else if (c == '\017') /* ^O */ X flshflag = !flshflag; X else if (c == '\023') /* ^S */ X stopflag = 1; X else if (c == '\021') /* ^Q */ X { X stopflag = 0; X wakeup(&stopflag); X } X else if (c == '\b') X { X if (uninsq(&ttyinq,&oc)) X { X if (oc == '\n') X insq(&ttyinq,oc); /* Don't erase past newline */ X else X { X _putc('\b'); X _putc(' '); X _putc('\b'); X } X } X } X else X { X if (c == '\r' || c == '\n') X { X c = '\n'; X _putc('\r'); X } X X if (insq(&ttyinq,c)) X _putc(c); X else X _putc('\007'); /* Beep if no more room */ X } X X if (c == '\n' || c == '\004') /* ^D */ X wakeup(&ttyinq); X X found = 1; X goto again; /* Loop until the uart has no data ready */ X} X X#ifdef vax X X_putc(c) Xchar c; X{ X write(1,&c,1); X} X X#else X X_putc(c) Xchar c; X{ X while(!(in(0x72)&02)) X ; X out(c,0x73); X} X X#endif X X EOF_devtty.c echo 'Done' exit 0 Doug Braun Intel Corp CAD 408 765-4279 / decwrl \ | hplabs | -| oliveb |- !intelca!mipos3!cadev4!dbraun | amd | \ qantel /