/* * Current Loop Interface Driver * */ #include "../h/local.h" #ifdef SCCS_ID static char SCCS_ID [] = "@(#)cli.c 3.1 17:30:23 - 81/11/18 "; #endif SCCS_ID #include "../h/param.h" #include "../h/conf.h" #include "../h/proc.h" #include "../h/tty.h" #include "../h/dir.h" #include "../h/user.h" extern int ncli; /* number of terminals */ extern char cliaddr[]; /* cli addresses */ extern struct tty cli[]; /* common tty structure */ #define WINIT WOPEN /* waiting to change mode read->write */ /* Current Loop Interface Command and Status Bits */ /* commands */ #define DISABLE 0200 #define ENABLE 0100 #define UNBLOCK 0040 #define BLOCK 0020 #define WRITE 0010 #define READ 0004 /* status */ #define OV 0200 #define BRK 0040 #define BSY 0010 #define EX 0004 #define DU 0001 /* * open routine: * called each time a process opens a terminal as a character file * * - if the terminal was previously inactive, set up the initial status * and arm interrupts */ cliopen(dev,flag) { register struct tty *tp; int clistart(); if (minor(dev) >= ncli) { /* minor device number too large ? */ u.u_error = ENXIO; /* yes, return error */ return; } tp = &cli[minor(dev)]; /* get tty struct for terminal */ if ((tp->t_state & ISOPEN) == 0) { tp->t_dev = dev; /* set device number in tty struct */ tp->t_state = ISOPEN | CARR_ON; if (tp->t_flags == 0) tp->t_flags = XTABS | LCASE | CRMOD | ECHO; ttychars(tp); tp->t_oproc = &clistart; cliparam(tp); /* enable read and set parms */ rd(cliaddr[minor(dev)]); } ttyopen(dev, tp); } /* * close routine: * - called only when last process using terminal releases it */ cliclose (dev) { register struct tty *tp; tp = &cli[minor(dev)]; /* find tty struct for terminal */ ttyclose(tp); oc(cliaddr[minor(dev)], DISABLE | READ | BLOCK); /* disable read */ } /* * read, write, ioctl routines: * - call standard tty routines */ cliread(dev) { ttread(&cli[minor(dev)]); } cliwrite(dev) { ttwrite(&cli[minor(dev)]); } cliioctl(dev, cmd, addr, flag) caddr_t addr; { register struct tty *tp; tp = &cli[minor(dev)]; if (ttioccom(cmd, tp, addr, dev) == 0) { u.u_error = ENOTTY; return; } if ( cmd == TIOCSETP && !(tp->t_state & BUSY)) /* if read and ECHO */ cliparam(tp); /* ... set hardware echo */ } /* * set device parameters * enable read; if ECHO, enable hardware echo. * */ cliparam(tp) struct tty *tp; { /*** oc(cliaddr[minor(tp->t_dev)], ENABLE | READ | ((tp->t_flag & ECHO) ? UNBLOCK : BLOCK)); ***/ oc(cliaddr[minor(tp->t_dev)], ENABLE | READ | BLOCK); return; } /* * * When the interface changes from read to write, an interrupt * is generated. This is where we enable the transmit side. * If busy is set , then a write is in progress and there is * nothing to do. * */ clistart(tp) register struct tty *tp; { if ( !(tp->t_state & (TIMEOUT|TTSTOP|BUSY))) { tp->t_state |= (WINIT | BUSY); /* set winit flag */ oc(cliaddr[minor(tp->t_dev)], ENABLE | WRITE | BLOCK ); /* enable write */ } } /* * second level output start routine * * This routine is called from cliint on write interrupt * to send a character. * */ clistrto(tp) register struct tty *tp; { int ttrstrt(); register c; /* get character to output */ c = getc(&tp->t_outq); if (c < 0) /* no more chars on outq, start reading */ { cliparam(tp); /* enable read */ return; } if (c > 0177) { /* timeout delay */ tp->t_state |= TIMEOUT; timeout(ttrstrt, tp, c&0177); } else { /* write character to device */ tp->t_state |= BUSY; wd(cliaddr[minor(tp->t_dev)], c); trace(0x1000, "wrt", ss(cliaddr[minor(tp->t_dev)])); } } /* interrupt handler */ cliint(dev,stat) int dev; int stat; { register int addr; register struct tty *tp; register c; tp = &cli[dev]; addr = cliaddr[dev]; if ( !(tp->t_state & ISOPEN)) /* return if device not open */ return; if (tp->t_state & BUSY) /* if write enable or write complete */ { if (stat & BRK) /* if BRK key hit */ { trace(0x1000,"brk :",0); c = CINTR; /* set character to del */ tp->t_state &= ~(BUSY | WINIT); /* reset flags */ cliparam(tp); /* reset to read mode */ ttyinput(c, tp); } else if (tp->t_state & WINIT) { /* if WINIT, interrupt was write enable */ trace(0x1000, "WINIT", stat); tp->t_state &= ~(BUSY | WINIT); clistrto(tp); } else { /* else interrupt was write complete */ trace(0x1000, "wint", stat); tp->t_state &= ~BUSY; clistrto(tp); #ifdef UCB_TTHIWAT if (tp->t_outq.c_cc <= TTLOWAT(tp) && (tp->t_state&ASLEEP)) #else UCB_TTHIWAT if (tp->t_outq.c_cc <= TTLOWAT && (tp->t_state&ASLEEP)) #endif UCB_TTHIWAT { tp->t_state &= ~ASLEEP; wakeup(&tp->t_outq); } } } else /* read complete interrupt */ { trace(0x1000, "rint", stat); c = rd(addr); trace(0x1000, "c = ", c); ttyinput(c, tp); } trace(0x1000,"int exit ss:",ss(addr)); trace(0x1000,"t_state",tp->t_state); trace(0x1000,"addr",addr); }