Path: utzoo!mnetor!uunet!munnari!otc!metro!ipso!runx!brucee From: brucee@runx.ips.oz (Bruce Evans) Newsgroups: comp.os.minix Subject: Re: Problems with Jim Paradis' tty driver Message-ID: <1341@runx.ips.oz> Date: 18 Jan 88 19:00:52 GMT References: <1828@botter.cs.vu.nl> Reply-To: brucee@runx.OZ (Bruce Evans) Organization: RUNX Un*x Timeshare. Sydney, Australia. Lines: 277 Here are some patches to help get Jim Paradis' tty driver running on Minix. I am running Minix on a standard PC with a Hercules graphics card and a nonstandard cross-development environment, and this setup exposed a few problems. (1) tty.c uses the wrong syntax to call pointers to functions. This was a minor problem since my Xenix compiler complained immediately. Apparently the Minix compiler generates the correct code from the wrong syntax. It probably needs fixing. The patches to tty.c cover this in great detail (there are lots of pointers). (2) console.c doesn't use SEG_MASK in all cases. Apparently it doesn't matter on a CGA or EGA, but I have an HGA. Hmmm, recent postings say the EGA doesn't really work. Hope this is the only problem. I hate to say this, but Minix should start using the BIOS to handle screen initialisation. There are too many hardware variations. (3) ser_putc and ser_bufin need to lock out interrupts. This was a real problem to debug since it is time-dependent. Must be rare on an AT. What happened was the output ready flag would be FALSE when read at the start of ser_putc but an output interrupt would set it to TRUE and ser_putc would then put a character in the buffer. Then ser_oflush would loop forever. I didn't actually see any problems from ser_bufin but the same lock seems necessary. See patches to rs232.c. I also tried implementing DTR/RTS flow control on input, shown in the diffs. Didn't help at all, because my PC is swamped on single-character input. Output flow control should work, except there seems to be no good way to wait for an external device in Minix (fs tends to block. Comments, Andy?). (4) The new drivers pushed my kernel over 64K, mainly because of a debugger already in it, so I had to use separate I & D. That (the 64K) broke build. Worse, the get_tot_mem routine scribbles on the memory above 128K, including (now) part of init. I am posting a rewrite of get_tot_mem separately. After this exercise I'm not very impressed with having all drivers linked directly to the kernel. It would be nice to keep the old ones around until the new ones are debugged. Also, I slightly prefer the old console driver. Now the arrow keys don't produce ANSI escape sequences. Actually, I hate the ANSI protocol, but it seems to be necessary as a standard. I've been thinking about a scheme where every non-control, non-shift (etc) key returns itself (together with usual control/shift encoding) plus an extra flags byte containing ALL special keys. Much like the standard PC scheme except the flags byte is dynamic and the scan code is not avaiable (but various 1's on the keyboard would be distinguished by the flags byte). A fancy combination like CTRL-ALT-RIGHTSHIFT ESC - would just return ESC (even PC BIOS doesn't return) and the application could decide what to with the control flags. Would need another fancy ioctl ... General ideas the speed problem. I only run Minix on a standard slow PC. It doesn't get close to keeping up even at 2400 Baud (when Xenix sends "\n$ " for a prompt, the " " is consistently missed). I traced the output interrupt routine in detail. It takes about 218 instructions, compared with a similar routine I wrote for a PC terminal program, all in assembler, which took 47. It is unnecessary to call save and restore for the output interrupt, could just push the registers C uses. That would save 50 or so instructions. However, the input interrupt is the real problem. It must be taking over 1000 instructions, mainly message passing. The only thing I can think of is to accumulate input in timed chunks. Actually 1000 is not so many. I also traced the instructions to write 1 character to the (old) console and was underwhelmed when the count was over 4700 or 20 msec (The exact count depends on the compiler. I don't know what it is for standard Minix.) Beep needs rewriting as Jim says. Suggest starting the beep as now but leaving interrupts on and stopping it with an alarm. Ser_oflush really shouldn't do a busy wait, it should give up control if the queue is large (though with external flow control, even 1 character could take a long time to flush). Ser_doint can't get by forever with the clever trick of waiting around a while for the next character to arrive. Interrupts are disabled in it, so interrupts on other serial lines will be missed for sure. Sending a message to wait would be no use since messages take about the same time as the delay between the interrupts. # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by brucee on Mon Jan 18 00:49:13 GMT+11:00 1988 # Contents: console.c.diff rs232.diff tty.c.diff echo x - console.c.diff sed 's/^@//' > "console.c.diff" <<'@//E*O*F console.c.diff//' 45a46 > #undef CHEAP_CGA /* otherwise MONO uses some slow CHEAP_CGA code */ 410c411 < --- > int vidoff; 530,531c531,532 < oque[oque_last].address = cur_start + < ( ((crow * NCOLS) + ccol) << 1); --- > oque[oque_last].address = (cur_start + > (((crow * NCOLS) + ccol)) << 1) & SEG_MASK; 541,546c542,544 < put_byte(VIDEO_SEG, < (int)(cur_start + (((crow * NCOLS) + ccol) << 1)), < (int)ch); < put_byte(VIDEO_SEG, < (int)(cur_start + (((crow * NCOLS) + ccol) << 1)) + 1, < (int)attrib); --- > vidoff = (cur_start + (((crow * NCOLS) + ccol) << 1)) & SEG_MASK; > put_byte(VIDEO_SEG, vidoff, (int)ch); > put_byte(VIDEO_SEG, vidoff + 1, (int)attrib); @//E*O*F console.c.diff// chmod u=rw,g=,o= console.c.diff echo x - rs232.diff sed 's/^@//' > "rs232.diff" <<'@//E*O*F rs232.diff//' 243a244 > lock(); 256c257 < --- > restore(); 457a459 > int nchars; 476a479,484 > nchars = rs->rs_ilast - rs->rs_ifirst; > if(nchars < 0) nchars += CIBUFSZ; > if(nchars == (3 * CIBUFSZ) / 4) > /* high water 3/4 full, drop RTS & DTR */ > port_out(MOD_CTL_REG(rs->rs_line), MC_OUT2); > 562,563c570 < < --- > lock(); 567,568c574,577 < if(maxchars < nchars) nchars = maxchars; < --- > if(nchars >= CIBUFSZ/4 && nchars - maxchars < CIBUFSZ/4) > /* low water 1/4 full, ready for more */ > port_out(MOD_CTL_REG(rs->rs_line), MC_OUT2 | MC_RTS | MC_DTR); > if(maxchars < nchars) nchars = maxchars; 575,578c584,586 < return(nchars); < } < < --- > restore(); > return(nchars); > } @//E*O*F rs232.diff// chmod u=rw,g=,o= rs232.diff echo x - tty.c.diff sed 's/^@//' > "tty.c.diff" <<'@//E*O*F tty.c.diff//' 202,205c202,205 < (tty_list[0].tt_dev_init)(0, 0); < < for(i = 1; i <= NUM_SERIAL_DEV; i++) { < (tty_list[1].tt_dev_init)(i, i - 1); --- > (*tty_list[0].tt_dev_init)(0, 0); > > for(i = 1; i <= NUM_SERIAL_DEV; i++) { > (*tty_list[1].tt_dev_init)(i, i - 1); 236c236 < nchars = (tp->tt_dev_bufin)(tp->tt_minor, cbuf, 132); --- > nchars = (*tp->tt_dev_bufin)(tp->tt_minor, cbuf, 132); 252c252 < (tp->tt_dev_oflush)(tp->tt_minor); --- > (*tp->tt_dev_oflush)(tp->tt_minor); 276c276 < (tp->tt_dev_oflush)(tp->tt_minor); --- > (*tp->tt_dev_oflush)(tp->tt_minor); 298c298 < (tp->tt_dev_oflush)(tp->tt_minor); --- > (*tp->tt_dev_oflush)(tp->tt_minor); 315c315 < (tp->tt_dev_oflush)(tp->tt_minor); --- > (*tp->tt_dev_oflush)(tp->tt_minor); 346c346 < (tp->tt_dev_oflush)(tp->tt_minor); --- > (*tp->tt_dev_oflush)(tp->tt_minor); 388,389c388,389 < (tp->tt_dev_putc)(tp->tt_minor, '\r'); < (tp->tt_dev_putc)(tp->tt_minor, '\n'); --- > (*tp->tt_dev_putc)(tp->tt_minor, '\r'); > (*tp->tt_dev_putc)(tp->tt_minor, '\n'); 394,395c394,395 < (tp->tt_dev_putc)(tp->tt_minor, '\r'); < (tp->tt_dev_putc)(tp->tt_minor, '\n'); --- > (*tp->tt_dev_putc)(tp->tt_minor, '\r'); > (*tp->tt_dev_putc)(tp->tt_minor, '\n'); 402c402 < (tp->tt_dev_oflush)(tp->tt_minor); --- > (*tp->tt_dev_oflush)(tp->tt_minor); 415,417c415,417 < (tp->tt_dev_putc)(tp->tt_minor, '\r'); < (tp->tt_dev_putc)(tp->tt_minor, '\n'); < (tp->tt_dev_oflush)(tp->tt_minor); --- > (*tp->tt_dev_putc)(tp->tt_minor, '\r'); > (*tp->tt_dev_putc)(tp->tt_minor, '\n'); > (*tp->tt_dev_oflush)(tp->tt_minor); 423,424c423,424 < (tp->tt_dev_putc)(tp->tt_minor, ch); < (tp->tt_dev_oflush)(tp->tt_minor); --- > (*tp->tt_dev_putc)(tp->tt_minor, ch); > (*tp->tt_dev_oflush)(tp->tt_minor); 434c434 < (tp->tt_dev_oflush)(tp->tt_minor); --- > (*tp->tt_dev_oflush)(tp->tt_minor); 442c442 < (tp->tt_dev_oflush)(tp->tt_minor); --- > (*tp->tt_dev_oflush)(tp->tt_minor); 515,517c515,517 < (tp->tt_dev_putc)(tp->tt_minor, 8); < (tp->tt_dev_putc)(tp->tt_minor, ' '); < (tp->tt_dev_putc)(tp->tt_minor, 8); --- > (*tp->tt_dev_putc)(tp->tt_minor, 8); > (*tp->tt_dev_putc)(tp->tt_minor, ' '); > (*tp->tt_dev_putc)(tp->tt_minor, 8); 748c748 < (tp->tt_dev_oflush)(tp->tt_minor); --- > (*tp->tt_dev_oflush)(tp->tt_minor); 801,803c801,803 < (tp->tt_dev_putc)(tp->tt_minor, '\r'); < } < (tp->tt_dev_putc)(tp->tt_minor, tty_sbuf[i]); --- > (*tp->tt_dev_putc)(tp->tt_minor, '\r'); > } > (*tp->tt_dev_putc)(tp->tt_minor, tty_sbuf[i]); 1080c1080 < tp->tt_dev_fcon(tp->tt_minor); --- > (*tp->tt_dev_fcon)(tp->tt_minor); 1130c1130 < tp->tt_dev_fcoff(tp->tt_minor); --- > (*tp->tt_dev_fcoff)(tp->tt_minor); 1180c1180 < tp->tt_dev_fcoff(tp->tt_minor); --- > (*tp->tt_dev_fcoff)(tp->tt_minor); 1205,1209c1205,1209 < (tp->tt_dev_putc)(tp->tt_minor, ch); < } < else { < (tp->tt_dev_putc)(tp->tt_minor, '^'); < (tp->tt_dev_putc)(tp->tt_minor, ch + '@'); --- > (*tp->tt_dev_putc)(tp->tt_minor, ch); > } > else { > (*tp->tt_dev_putc)(tp->tt_minor, '^'); > (*tp->tt_dev_putc)(tp->tt_minor, ch + '@'); @//E*O*F tty.c.diff// chmod u=rw,g=,o= tty.c.diff exit 0 Bruce Evans (brucee@runx.ips.oz)