From: gero@gkminix.han.de (Gero Kuhlmann)
Subject: Re: internal modem and serial device driver
Organization: gkminix, Hannover, Germany
Date: Tue, 22 Dec 92 02:09:50 GMT

rchen@fraser.sfu.ca (Robert Chen) writes:
> Now for the problem.  I have a 9600bps mouse on /dev/ttys0.  While
> getty_ps is running (and hence accessing ttys2), my X cursor is jumpy
> when I move the mouse.  Since ttys0 and ttys2 share IRQ3, I assume
> that this has something to do with the serial driver (and the fact
> that my modem on ttys2 is not recognised at bootup).
> 
> What I would like to be able to do is access all three com ports
> simultaneously.  I would rather not move the 2400 baud modem to
> another IRQ (not 5 anyway) because I have an ethernet board using that
> IRQ (and it shouldn't be neccessary since at 2400bps, sharing an IRQ
> shouldn't be a problem).
> 
> Can anybody point me to a solution?  Is anybody successfully using
> COM1 and COM3 simultaneously?  Why is my internal modem not
> recognised?  

Well, this seems to become a FAQ, so I try to give an answer here.

The problem with the PC hardware is that it uses an active high interrupt
system with three-state outputs on the serial cards. That means that normally
the interrupt line is pulled down to zero by the output transistor
(if the interrupt is enabled on the serial card with OUT2). Now if two
cards share the same interrupt line, suppose only one line is trying to
send an interrupt. It then shuts off it's low-driving transistor and enables
it's high driving transistor. Unfortunately the low fan out of the standard
LS-TTL's is 8mA while the high fan out is only -400microA. You can think of
the low driving transistor being about twenty times stronger than the high
pulling one. So the single card trying to send out an interrupt doesn't
have any chance to bring the interrupt line up above the minimum high level
of approx. 2V because there is the low output of the other card. But that
low-to-high-transition is required by the interrupt controller.

There is one way to solve that problem. The goal is to combine both output
interrupt lines with a logical OR function. That means, wether one line or
the other is going high, the interrupt controller sees the necessary level
transition. To do this you can either use a 7432 or just a couple of diodes
and resistors. The first solution is not very easy to implement since you
need a lot of wiring. The latter is pretty easy to implement if you know
a bit about digital electronics.
In order to prevent the stronger low-driving transistors on each serial card
to drive the IRQ line to low, it is necessary to insert a diode into each
of the interrupt output lines in the reverse direction of the low current.
Besides, this is the basic logical OR combination:


        I1 -------->|--------+
                             |
        I2 -------->|--------+----------- O

I1 and I2 are the interrupt outputs of the serial cards and O is the output
of the OR function which goes into the interrupt controller.
This logic prevents the IRQ line from going to low. But if no interrupt is
active, it must become low. So we have to simulate the strong pulldown-
transistors of the output drivers by a weaker resistor:

        I1 -------->|--------+
                             |
        I2 -------->|--------+----------- O
                             |
                             R
                             |
                            GND

This resistor just has to be added onto one of the serial cards because it is
only needed to compensate for the internal pullup-resistor of the interrupt
controller and is thus only required once per IRQ line.

How to implement this all? Well on most serial cards and internal modems there
is a jumper field to select the desired interrupt. Normally the output of the
interrupt driver goes onto one side of that jumper, and the other side then
goes directly to the system io bus. Instead of placing a real jumper there
you have to solder in the diode. On one of the serial cards you have to find
GND using a multimeter and then connect a resistor between that ground point
and the output side of the jumper pins.
As diodes I used 1N4148 which worked fine. But they have a pretty high voltage
decrease, so if you have any troubles better use some shottky-diodes. For the
resistors I used 470 ohm types.
Still a problem might be if you don't have a jumper configuration as mentioned
above. My old 2400Baud internal modem had a PAL driving the interrupt directly.
I inserted the diodes between the PAL output and the IC socket. Some newer
serial cards use SMD's. I think it's almost impossible to change anything on
those.

Nevertheless there is still a software problem with the linux driver. At least
my pl1 driver had those problems and I think they are still in the pl5 kernel.
I don't know if there are any changes in version 0.99. Well, the problem is
that the driver has to detect, which one of the serial cards issued the inter-
rupt on the IRQ line. To do that it has to look up each serial controller's
interrupt status in sequence. Suppose the driver didn't find anything on the
first controller, it steps over to the second one. There it reads the ISR and
finds exactly one interrupt pending. The serial controller only releases it's
interrupt output AFTER the interrupt source (for example the input channel)
has been processed. The driver finds the receiving interrupt and steps over to
read the input buffer. At this time the first serial card gets a character and
issues an interrupt. After reading the second controller's buffer, that one
sets the IRQ to low, but in the meantime controller 1 pulls IRQ high and so
the line stays active high (remember the logical OR combination). The interrupt
gets only recognized if the line transitions from low to high, but there is no
such transition. After checking out the second serial card the driver termi-
nates and never gets called again for that interrupt: the hardware has blocked.
I wrote a patch for this problem but never made it public because I think
using two serial cards on one interrupt is not a common problem. Obviously
I'm wrong :-) The patch is still for my pl1-kernel, but it should be possible
to adapt it to the new serial driver (if it isn't in there already - but then
it doesn't come from me :-). Send me a mail if you are interested.

Not to mention that the above configuration (with the kernel patch) worked
perfectly well on my system. Unfortunately the patch adds some extra code to
the serial driver which makes it a bit slower. I didn't use it at 14.4kBaud
but it should be possible to use 9600Baud and 2400Baud at the same time. As
far as I know the new driver is a bit faster so there shouldn't be any problem
with your mentioned configuration.

gero.
-- 
Gero Kuhlmann			Zerberus:  G.KUHLMANN@A-LINK-H.ZER
Donarweg 4			SubNet:    gero@gkminix.sub.org
D-3000 Hannover 51              IN:        gero@gkminix.han.de
Newsgroups: comp.os.linux