The Linux device driver interrupt handler

Register interrupt handler

The interrupt handler is part of managing hardware drivers; if the device is using interrupts, then the appropriate drivers to register an interrupt handler;

Driver () function is registered by the request_irq, and activate a given interrupt to handle the interrupt; the request_irq () function may sleep, and therefore, can not be allowed not interrupt context or other code blocking call this function, since the this function calls the procedure will be used kmalloc () to allocate memory, and the function kmalloc () is sleeping;

1 int __must_check
2 request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
3         const char *name, void *dev)

Irq parameter identifies the interrupt number to be assigned, for some devices, this value is determined in advance; whereas most other devices, this value is either grams of detection by acquiring or acquired dynamically through programming;

The actual parameter handler points to an interrupt handler for the interrupt, the operating system when the interrupt is received, the function is called;

1 typedef irqreturn_t (*irq_handler_t)(int, void *)

Parameters flag may be 0, the mask may also be one or more of the following flag bits;

IRQF_DISABLED- after the flag is set, meaning that the kernel during the processing of the interrupt handler itself, to disable all other interrupts; if not set, the interrupt handler can with any other except their own interruptions to run simultaneously; most will not interrupt handler this bit is set; this usage is left to hope lightweight rapid execution of interrupt;

IRQF_SAMPLE_RANDOM- device generates an interrupt to the kernel entropy pool contributes to the kernel entropy pool is responsible for providing true random number is derived from a variety of random events;

IRQF_TIMER- the flag is designed specifically for system timer interrupt processing and preparation;

IRQF_SHARED- the flag may indicate multiple shared interrupt among the interrupt handler; this flag must be specified in each handler registered with a given line; otherwise, in each line can only have one handler ;

Parameter name is associated with the interruption ascii;

Dev argument for shared interrupt when an interrupt handler needs to be released, dev will provide a unique flag information, in order to break from the share that a plurality of interrupt handler to remove the specified; if one does not share interrupts line, then the function assigned to NULL; but if the interrupt line is shared, then the unique information must pass; in practice often transmitted through the device driver structure it; it is only the pointer, and may to be used in the interrupt handler;

Release interrupt handler

When you uninstall the driver, you need to write-off related to the interrupt handler, and release the break, call the following function:

1 void *free_irq(unsigned int, void *)

If the specified interrupt line is not shared, then the function will prohibit this interrupt handler is deleted, if the break is shared, only the deletion processing program corresponding to the dev, which interrupt lines itself will only be disabled when you delete the last handler;

Write interrupt handlers
1 typedef irqreturn_t (*irq_handler_t)(int, void *)

The first parameter is the irq handler to respond to the interrupt number;

Dev second parameter is a generic pointer, it passes the parameters to the request_irq dev () must be consistent with the interrupt handler registration; for each device, only the device structure, but also may be used in the interrupt handler to, therefore, is often seen as a pointer device dev;

Interrupt handler returns a value of type irqreturn_t, facing the two different return values: IRQ_NONE and IRQ_HANDLED; detected when the interrupt handler generates an interrupt, the interrupt corresponding to the device but not during a registration handler specified source, return IRQ_NONE; when the interrupt handler is invoked right, and indeed it corresponds to the device generated the interrupt, return IRQ_HANDLED;

The interrupt handler is not required reentrant; when a given interrupt handler is executed, the corresponding interrupt lines on all processors will be blocked to prevent the same interrupt line further receives a new break; under normal circumstances, other interrupts are being opened, these different interrupt other interrupt can be processed online, but the current interrupt line is always prohibited;

Interrupt Control

Linux kernel provides the interrupt state machine for operating a set of interfaces; these interfaces can be prohibited it provides us the current processor interrupt information, or the ability of a masked interrupt line of the entire machine;

The control system causes interruption in the final analysis still need to provide synchronization; by disabling interrupts, ensure that touch interrupt handler does not preempt the current code; In addition, disabling interrupts may also prohibit kernel preemption; however, whether or disable interrupts prohibited kernel preemption, do not provide any protection mechanism that prevents concurrent access from other processors; Linux multi-processor support, therefore, the kernel code are generally required to obtain some sort of lock to prevent concurrent access to shared data from the premise processor; at the same time to obtain these income also accompanied by prohibiting local interrupt; locks provide protection mechanisms to prevent concurrent access from other processors, while disabling interrupts provide protection mechanism is to prevent concurrent access from other interrupt handler;

Prohibition and current local activation interrupts the processor as follows:

1 local_irq_disable()
2 local_irq_enable()

If before calling local_irq_disable () it has been banned interrupted, then the routine danger; the same corresponding local_irq_enable () are also at risk, they will activate unconditional interrupt, even though these may be interrupted at the start is closed;

The kernel provides a mechanism to interrupt restored to its previous state rather than a simple prohibition or activation;

1 local_irq_save(flags)
2 local_irq_restore(flags)

flags parameter must be defined as an unsigned long, therefore, change the parameter values ​​passed contains the data specific architecture, i.e. comprising a system interrupt status; for the at least one stack architecture combining information value, so the two call functions must be in the same function;

 

In some cases, do not need to ban all processor interrupts on the whole, the whole system is only prohibited a particular interrupt line is enough; this is called a masked interrupt line; Linux offers four interfaces:

1 void disable_irq(unsigned int irq)
2 void disable_irq_nosync(unsigned int irq)
3 void enable_irq(unsigned int irq)
4 void synchronize_irq(unsigned int irq)

The first two function disables interrupts on the specified interrupt controller, which prohibits a given interrupt delivery to all processors in the system; In addition, the function only after all processors currently executing program is completed, disable_irq () to return ; therefore, the caller not only to ensure that no new interrupt specify online delivery, while ensuring that all handlers have already started all out; disable_irq_nosync will not wait for the current interrupt handler is finished;

synchronize_irq wait for a specific interrupt handler exits; if the wind blew the program is being executed, then after the function must exit to return;

Call these functions can be nested, but in a specified interrupt line for each call disable_irq or disable_irq_nosync, should correspond enable_irq called once, only after the completion of enable_irq last call, in order to truly break activate ;

The owner of the three functions can be called from an interrupt or process context, and will not sleep;

A plurality of interrupt handler is prohibited in the shared disconnection is inappropriate, on the disabled interrupt disabled interrupts transmission of all devices on this line, the new device driver tends not to use these interfaces;

 

It is usually necessary to know the state of the interrupt system, such as interrupts are disabled or active, or is currently being executed in the interrupt context;

Linux provides two macros current context is used to check the kernel:

1 in_interrupt()
2 in_irq()

in_interrupt most useful, if the kernel is in the interrupt handling any type, he returns non-zero, indicating that the kernel interrupt handler is executing at the moment, or the lower half of the handler being executed;

in_irq only does the kernel is executing when the interrupt handler returns a non-zero;

Under normal circumstances, you need to check whether they are in process context, that is to say, want to make sure they're not interrupt context, this situation is very common, because the code to do some sleep this can only be done from process context thing; if in_inerrupt () returns 0, now in the process of the kernel context;

 

Guess you like

Origin www.cnblogs.com/wanpengcoder/p/11761743.html