                     <*> USI (User Space Interrupts?) <*>

N.B. the ? in the header is explained at the end of this text.

If you are deeply concerned about any computational overhead this is not for 
you. Neither I would have used such a way of working on my favourite Z80.

Instead if you are using any PC that kids use nowdays to play their favourite 
video games it can be of some interest. On such machines task switching times 
are far less than the worst latency you'll encounter in getting to the first 
line of code in your interrupt handler, even if it seats in kernel space. 
If you do not believe it try the interrupt latency check available in the 
calibration program for a few minutes, under intense Linux peripheral 
activities. 

So if your concern is mostly on the worst case and some added overhead does
not impede meeting your deadlines you might find it not so bad and what 
found here might be usefull. In any case it can be a helper for preliminary
development and easy proof of concept verifications of interrupt handlers code.

RTAI already contains some examples hinting at managing interrupts in user
tasks, e.g: various resumefromintr in showroom (kernel/user space), steelworks
etc., but all of them require installing a proper handler in kernel space to 
wake up a hard real time task, in whatever space you like. 

USI does much the same but adds something that permits you to avoid writing 
anything in kernel space.

In fact it contains a few support functions allowing to write interrupt
handlers directly in user space, without installing anything in the kernel. 
The related APIs are much the same as those available from RTAI for kernel 
space, so there is not much else to be saidi, from the conceptual point of
view. 
You should just care of getting ioperm/iopl in order to gain the often 
needed access to IO space.

The only point worth clarifying is how you can write your handler. For that 
you must use rt_request_irq_task in place of rt_request_irq, its prototype is:
int rt_request_irq_task(unsigned irq, void *handler, int type, int affine2task))
with:
- irq: the irq number,
- handler: the pointer to the handler task/tasklet,
- type: RT_IRQ_TASK if the handler is a task; RT_IRQ_TASKLET if the handler 
  is a tasklet,
- affine2task: 1 if the handler must be kept on the CPU of the requestor, 
  0 otherwise; not used UP wise.

The related function to be called when the work is done is:
void rt_release_irq_task(unsigned irq).

The handler task/tasklet must then sit in an never ending loop that calls
any of the available rt_irq_wait functions, i.e.:
int rt_irq_wait(unsigned long irq);
int rt_irq_wait_if(unsigned long irq);
int rt_irq_wait_until(unsigned long irq, RTIME until);
int rt_irq_wait_timed(unsigned long irq, RTIME delay);
The value returned by the above functions can be checked for possible interrupt
overruns. Their number  will be signalled by a value > 0. The special value 
RT_IRQ_TASK_ERR indicates an irregular end of the handler. It can be either 
an unexpected error or related to the handler cancellation by another task.
Since you coded it you should know why it appears.

The function:
void rt_irq_signal(unsigned irq), 
can be used to trigger the interrupt from a program. It allows to emulate
a true interrupt and can be useful in the early handler development phase.

The "user/i386/usi" directory contains a couple of simple examples using the 
above approaches.

At the moment USI contains also the essential functions needed to support the 
interrupt handling job, i.e. interrupt flags and PIC processing. Nothing 
forbid expanding it if needed.

USI makes available basic locking primitives. So it should now be 
possible to do quick protection of shared data by disabling/enabling 
interrupts and using spinlocks from user space. For somebody it might 
be a frightening possibility but real time must not be slave to anything. 
It should be remarked that on an x86, apart from the PIC handling services, 
all the hard interrupt flags manipulating functions can be coded, directly 
and more effectively, with inlined asm in user space also. So one needs not 
use what found in rtai_usi.h for those services. Nonetheless thay can be 
useful for those that could find it easier coding without minding of too 
many details.

All the available APIs can be easily understood if you master RTAI usage 
already, in fact it makes little sense using them if you do not. So have a 
quick look at rtai_usi.h, they should be self explaining.

There is a notable difference between using a task and a standard kernel 
handler to manage interrupts. The task handler runs with interrupt enabled 
while the kernel handler is entered with interrupt disabled. If one needs to
recover the behaviour of the kernel handler to a task handler (s)he has just
to call "rtai_cli()" before entering the irq handling loop, caring of calling
"rtai_sti()" when the loop is exited.
In the tasklets case the irq handling loop is not available directly to
the user, since it is embedded and hidden in the core tasklet service. To
have a tasklet handler operate with interrupt disabled it is then enough to
include something like: 
        static int first;
        if (!first) {
                first = 1;
                rtai_cli();
        }
at the very beginning of the tasklet function, so that interrupts will be kept
disabled till the function ends.
There is no need to worry for enabling interrupts again, tasklets are aware that
can be used for interrupt handling and call "rtai_sti()" always when exiting.

Once more nothing new, there are other OSes that allow doing the same thing 
and UML should allow it also under plain Linux. On the RTAI side there is the 
added advantage of having it in hard real time.

After having illustrated USI as its acronym implies, i.e.: 
User Space Interrupts, 
we must now recall that RTAI allows simmetry of usage of any of its services
in kernel space alike. That means you can use all what has been explained here
for managing interrupts in kernel space using RTAI kernel tasks. Nothing changes
but the fact that you do not need include any rtai_usi.h in your application.
More specifically there is no added code or module to be used for USI anymore.
It is just the extension of some native RTAI services to user space.

Then the name USI is retained because all what explained here was born as such,
but now it is nothing but interrupts specific tasks, symmetrically usable in 
kernel/user space. This should explain the reason of the question mark in the 
header of this README.

Paolo Mantegazza.
