h6. [[Programmer's Reference Manuals]] h6(. » Interrupts When a hardware device sends a signal to the ARM processor indicating that it needs attention, this is called an _interrupt_. The process of sending an interrupt is known as an _interrupt request_. Devices handled by interrupts include the keyboard, printer, mouse, serial port, disc drives and expansion cards, as well as built-in timers. When an interrupt is received, RISC OS temporarily halts the active task, and enters an _interrupt routine_. The routine deals with the interrupting device very quickly so it can continue with the previous task as quickly as possible. Often, interrupts are handled so quickly that users never realise their task was temporarily halted. Interrupts are an efficient method of dealing with hardware devices, as the devices inform the system that it needs attention, rather than the system regularly checking all the devices. Because external hardware, such as expansion cards, can generate new interrupts, it is possible to install new routines to deal with them. Each device that can generate interrupts has a _device number_. There are corresponding _device vectors_, similar to [[Software Vectors]] and [[Hardware Vectors]]. Installed on each vector is a default _device driver_ that receives only interrupts from that device. h3(#types). Interrupt types There are two different types of interrupt requests: IRQs (interrupt requests) and FIQs (fast interrupt requests). As the name suggests, FIQs are generated by devices that require their request be serviced more quickly than the normal IRQ request. The ARM processor has a separate mode, its own hardware vector and range of device numbers for dealing with FIQs. h3(#numbers). System Device Numbers Different RISC OS computers use different interrupt generating hardware. The very early Archimedes range used a variety of different peripheral control chips, whereas later versions used the 82C710 or 82C711 chip. Because different controllers have been used, device numbers differ between models of RISC OS computers. A list of current RISC OS system device numbers is [[System Device Numbers|here]]. h3(#vectors). Device Vectors It is possible to claim device vectors and call a routine of your choosing, instead of the default one. With the exception of the Expansion Card interrupts (8 and 13), all device vectors call the most recent routine that claimed the vector. Previous routines that claimed the vector remain on the vector chain, unless they are released. If the most recent routine is released, then the previous owner of the vector is re-installed as the routine that is called. To claim and release vectors, two SWI calls are used: * Claim a vector by calling [[OS_ClaimDeviceVector]] * Release a vector by calling [[OS_ReleaseDeviceVector]] When a routine claims a vector, RISC OS first checks the vector chain to see if there are any earlier instances of the same routine claiming this vector. If found, it removes them from the chain before claiming the vector. When releasing a device vector, RISC OS checks the vector chain for any earlier claimants of the vector. If none are found, it will automatically disable interrupts from the corresponding device. No attempt to manually disable interrupts should be made. h3(#interrupt). Interrupt handling routines As mentioned earlier, the routine dealing with the interrupting device must do so quickly. If a routine cannot deal with a device quickly, it should re-enable interrupts (as they are disabled automatically when entering a routine). Any routine that re-enables interrupts must be able to cope with further interrupts if they occur, and hence the routine being entered for the second time. This is called _re-entrancy_. h3(#error). Error Handling Routines that handle interrupts must *only* call the error-returning SWI calls (that is, SWI calls that have their X-bit set). If an error is returned to the routine, appropriate action must be taken within the routine. It may be useful to store an error indicator within the routine, so that the next call to an appropriate SWI (one in the module that provides the routine) will generate an error. h3(#swi). SWI re-entrancy Some SWIs are defined as being re-entrant: that is, they can safely be called even though they are currently in the process of being used already. Some SWIs are deemed to be not re-entrant (i.e. they cannot handle more than one simultaneous call). As a result of this, non re-entrant SWIs should _not_ be called from within an interrupt handling routine. An example of why this is the case is shown below: # A non re-entrant SWI is called from within a task. It stores some values in its own private workspace # An interrupt occurs. The interrupt routine calls the same non re-entrant SWI # The previous values in the workspace is overwritten # When the interrupt has been serviced and control is returned to the original task, the SWI workspace is corrupt and so the routine does not work as expected h3(#clearing). Clearing interrupt conditions Once the routine has serviced the interrupt, it must also clear the interrupt so that it does continue to generate the same interrupt. The interrupt is cleared by accessing the hardware that is generating the interrupt. h3(#fiq). FIQ specifics Devices that issue FIQs require them to be handled more quickly, and unlike IRQs no SWI can be called within the handler routine. The default owner of the FIQ vector is the [[Econet]] module (which is a proprietary network), and only one owner of the FIQ is supported, so any task that wishes to claim the FIQ vector must follow the process below: # Claim the FIQ using [[OS_ServiceCall]], with one of the following service calls: #* To claim from the foreground: A service number of 12 (&0C) ([[Service_ClaimFIQ]]). This call will always be successful, but may involve a wait if any current background FIQ process must be completed first #* To claim from the background: A service number of 71 (&47) ([[Service_ClaimFIQinBackground]]). This routine may fail, but does not signify that this was due to an error; it may be because the FIQs could not be claimed. The following should steps should then be taken: #** You _must_ leave your routine to allow the foreground routine to release the FIQs #** Schedule another attempt at claiming the FIQ # The fast interrupt mask register should be set to &00. This will prevent fast interrupts while changing to the FIQ code # Poke your FIQ routine into addresses &1C to &100 # Enable FIQ generation from the device # Set the bit corresponding to the device in the fast interrupt mask register # Start your own FIQ operation # Upon the FIQ operation completing, it must set the interrupt mask register to zero # Disable FIQ generation from the device # Release FIQs using [[OS_ServiceCall]] with the service number of 11 (&0B) ([[Service_ReleaseFIQ]]) h3(#disabling). Disabling interrupts When an interrupt routine is called, interrupts are by default disabled until the routine completes. However, there may be other times when it is desirable to manually disable interrupts (i.e. IRQs). Because interrupts are an important to the integrity of a system it is important to minimise the amount of time interrupts are disabled. Perhaps the easiest method of enabling and disabling interrupts from user mode is to use the [[OS_IntOn]] and [[OS_IntOff]] SWIs. h3. Disabling devices or fast interrupts Unlike the method of disabling IRQs, you must be in a privileged mode to disable FIQs or specific devices. To disable specific devices, all interrupts must first have been disabled, before clearing the relevant bits of the interrupt mask registers. h4. See also * [[OS_ClaimDeviceVector]] * [[OS_IntOff]] * [[OS_IntOn]] * [[OS_ReleaseDeviceVector]] * [[OS_ServiceCall]] * [[Service_ClaimFIQinBackground]] * [[Service_ClaimFIQ]] * [[Service_ReleaseFIQ]] * [[System Device Numbers]]