Restore original interrupt handler in Linux - linux-kernel

I removed the existing interrupt handler for the keyboard and registered my interrupt handler and after removing my interrupt handler, I want to restore the original interrupt handler for the keyboard.
int init_module()
{
free_irq(1, NULL); // removing the existing interrupt handler
return request_irq(1, irq_handler, IRQF_SHARED, "test_keyboard_irq_handler", (void *)(irq_handler)); // registering my interrupt handler
}
void cleanup_module()
{
free_irq(1, NULL); // removing my interrupt handler
}
In the cleanup_module(), after removing my interrupt handler, I want to restore the original one.

Related

How to get GPIO interrupt from an IOexpander in Linux

I am developing a kernel module for an embedded device, The device core is Toradex iMX6DL.
So I have an IO-Expander of mcp23xxx series on this device and I can work with its GPIOs. I can set them as input/output and get/set their values.
I need to use one of them as an interrupt, this is the part of my code for setting interrupt:
static irqreturn_t r_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
{
printk(KERN_DEBUG "interrupt received (irq: %d)\n", irq);
//do some stuff here
return IRQ_HANDLED;
}
...
if(gpio_request(497, 0)==0)
{
int result;
gpio_direction_input(497);
gpio_set_debounce(497, 100);
gpio_export(497,false);
irqNumber =gpio_to_irq(497); // map your GPIO to an IRQ
printk("irq number : %d\r\n",irqNumber);
result = request_irq(irqNumber, // requested interrupt
(irq_handler_t) r_irq_handler, // pointer to handler function
IRQF_TRIGGER_RISING, // interrupt mode flag
"irqHandler", // used in /proc/interrupts
NULL); // the *dev_id shared interrupt lines, NULL is okay
printk("irq request for pin %d result:%d \r\n",497,result);
if(result == SUCCESS)
printk("irq request for pin %d succeeds\r\n",497);
}
The result of gpio_to_irq() is '-6' and the result of request_irq() is '-22', What should I do to get this GPIO's interrupt?

Cortex M0 doesn't enter sleep mode

Got a problem with the Atmel SAMB11 on an explained pro Devboard. I've loaded a quite simple example from Atmel, where a 32KHz Timer is initialized to wake up the µC from sleep and turn on a LED. Problem is, the controller doesn't sleep at all. It just activates the LED immediately and doesn't wait for an interrupt.
#include <asf.h>
// Callback Func to enable LED
static void aon_sleep_timer_callback(void)
{
gpio_pin_set_output_level(LED_0_PIN, LED_0_ACTIVE);
}
//Configure LED
static void configure_gpio_pins(void)
{
struct gpio_config config_gpio_pin;
gpio_get_config_defaults(&config_gpio_pin);
config_gpio_pin.direction = GPIO_PIN_DIR_OUTPUT;
gpio_pin_set_config(LED_0_PIN, &config_gpio_pin);
gpio_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE);
}
// Configure Timer with 10sec to overflow
static void configure_aon_sleep_timer(void)
{
struct aon_sleep_timer_config config_aon_sleep_timer;
aon_sleep_timer_get_config_defaults(&config_aon_sleep_timer);
config_aon_sleep_timer.counter = 320000; // Wait about 10sec
aon_sleep_timer_init(&config_aon_sleep_timer);
}
// Configure Callback and enable Interrupt
static void configure_aon_sleep_timer_callback(void)
{
aon_sleep_timer_register_callback(aon_sleep_timer_callback);
NVIC_EnableIRQ(AON_SLEEP_TIMER_IRQn);
}
int main(void)
{
// Setup Clock, LED and Timer
system_clock_config(CLOCK_RESOURCE_XO_26_MHZ, CLOCK_FREQ_26_MHZ);
configure_gpio_pins();
configure_aon_sleep_timer();
configure_aon_sleep_timer_callback();
// wait for timer to be active
while(!aon_sleep_timer_sleep_timer_active());
// Go to sleep
asm volatile ("wfi");
asm volatile ("nop");
// Enable LED immediately if sleep doesn't work
gpio_pin_set_output_level(LED_0_PIN, LED_0_ACTIVE);
while (true) {}
}
Code seems self-explanatory, but the WFI command doesn't work here. Anyone can help?
Just to add to the answer by Prestige Worldwide.
Make sure AO_GPIO0/1/2 are low (pulldown advised), and no AON Sleep Timer interrupt is occuring, as these will wakeup the SAMB11 from ULP.
Also note that the ULP mode does not seem to work as expected while running a debug session over SWD.
I had all kinds of weirds behaviour when running the debug and sleep/waking up, but no problems at all when running the same code while not debugging. Note this was using Atmel ICE. The Xplored board contains EDBG, and this debugger seems to work ok with ULP.
The resume callback has never fired for me, maybe a bug in the ASF. But I do not need it as I can setup all GPIO/devices after the platform wait.
The WFI call works, it just receives an interrupt almost immediately after it is called, which causes the WFI call to stop blocking and then execution continues to the next line.
You could safely remove everything below // Go to sleep which would allow the main function to return. The AON timer would still execute its callback. However, there are a couple of potential downsides to this approach:
This would not allow the SAMB11 to transition to a lower power mode.
This removes your while-loop at the end of main. In its current state, the while-loop isn't needed, but you might have plans to add code to it later.
Here is an example that configures the AON, configures the SAMB11 to use low power modes, and then loops waiting for platform and/or BLE events. Currently there are no events for the loop to receive. If you want the loop to receive events then you could modify the AON callback to post an event with the at_ble_event_user_defined_post function or modify main() to configure the BLE module before entering the loop.
Use the ASF Wizard to add any of the BLE modules to your project in order to compile this example.
#include <asf.h>
#include "platform.h"
// Configure LED
static void configure_gpio_pins(void)
{
struct gpio_config config_gpio_pin;
gpio_get_config_defaults(&config_gpio_pin);
config_gpio_pin.direction = GPIO_PIN_DIR_OUTPUT;
gpio_pin_set_config(LED_0_PIN, &config_gpio_pin);
gpio_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE);
}
// Callback Func to toggle LED
static bool led_is_on = false;
static void aon_sleep_timer_callback(void)
{
configure_gpio_pins();
if(led_is_on) {
gpio_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE);
led_is_on = false;
} else {
gpio_pin_set_output_level(LED_0_PIN, LED_0_ACTIVE);
led_is_on = true;
}
}
// Configure Timer to fire periodically
static void configure_aon_sleep_timer(void)
{
struct aon_sleep_timer_config config_aon_sleep_timer;
aon_sleep_timer_get_config_defaults(&config_aon_sleep_timer);
config_aon_sleep_timer.counter = 32000; // Wait about 1 sec
config_aon_sleep_timer.mode = AON_SLEEP_TIMER_RELOAD_MODE;
aon_sleep_timer_init(&config_aon_sleep_timer);
}
// Configure Callback and enable Interrupt
static void configure_aon_sleep_timer_callback(void)
{
aon_sleep_timer_register_callback(aon_sleep_timer_callback);
NVIC_EnableIRQ(AON_SLEEP_TIMER0_IRQn);
}
int main(void)
{
// Setup Clock
system_clock_config(CLOCK_RESOURCE_XO_26_MHZ, CLOCK_FREQ_26_MHZ);
plf_drv_status plf_status;
if((plf_status = platform_driver_init()) == STATUS_SUCCESS) {
// Setup LED and Timer
configure_gpio_pins();
configure_aon_sleep_timer();
configure_aon_sleep_timer_callback();
// wait for timer to be active
while(!aon_sleep_timer_sleep_timer_active());
// Go to sleep
release_sleep_lock();
while(true) {
// Replace platform_event_wait with at_ble_event_get if you would like to read the received event.
plf_status = platform_event_wait(0);
}
}
}
Regarding WFI, the following example shows how to turn off most of the interrupts and use WFI to block main(). The LED will toggle every time an interrupt is received. I don't recommend using this as I'm not sure why these interrupts are enabled initially. This is just intended to show how WFI can block on a SAMB11.
#include <asf.h>
#include "platform.h"
// Configure LED
static void configure_gpio_pins(void)
{
struct gpio_config config_gpio_pin;
gpio_get_config_defaults(&config_gpio_pin);
config_gpio_pin.direction = GPIO_PIN_DIR_OUTPUT;
gpio_pin_set_config(LED_0_PIN, &config_gpio_pin);
gpio_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE);
}
// Callback Func to toggle LED
static bool led_is_on = false;
static void toggle_led(void)
{
configure_gpio_pins();
if(led_is_on) {
gpio_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE);
led_is_on = false;
} else {
gpio_pin_set_output_level(LED_0_PIN, LED_0_ACTIVE);
led_is_on = true;
}
}
int main(void)
{
// Setup Clock
system_clock_config(CLOCK_RESOURCE_XO_26_MHZ, CLOCK_FREQ_26_MHZ);
// Clear all interrupts.
NVIC->ICER[0] = 0xFFFFFFFF;
// During testing, interrupts were received about once per second; stopped receiving interrupts (LED stopped flashing) after about 2 minutes.
int loop_count = 0;
while(true) {
__WFI();
toggle_led();
}
}

How to detect application terminate in kernel extension, Mac OS X

I am looking for an approach to detect application quit (e.g. cmd-q) in kernel space for processing in a network kernel extension.
More precisely:
While a process (e.g. terminal ping) is held in an IOLockSleep(... THREAD_ABORTSAFE), ctrl-c is able to release the lock.
Asking the proc_issignal(), it responses the sigmask(SIGINT).
Now I am looking for a way to detect another process quit, e.g. firefox (menu bar: Application quit (cmd-q)).
Here is what I tried:
#define FLAG(X) ((dispatch_source_get_data(src) & DISPATCH_PROC_##X) ? #X" " : "")
struct ProcessInfo {
int pid;
dispatch_source_t source;
};
// function called back on event
void process_termination_event(struct ProcessInfo* procinfo) {
dispatch_source_t src = procinfo->source;
printf("process_termination_event: %d \n", procinfo->pid);
printf("flags: %s%s\n", FLAG(EXIT), FLAG(SIGNAL));
dispatch_source_cancel(procinfo->source);
}
// function called back when the dispatch source is cancelled
void process_termination_finalize(struct ProcessInfo* procinfo) {
printf("process_termination_finalize: %d \n", procinfo->pid);
dispatch_release(procinfo->source);
}
// Monitor a process by pid, for termination
void MonitorTermination(int pid) {
struct ProcessInfo* procinfo = (struct ProcessInfo*)malloc(sizeof(struct ProcessInfo));
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t dsp = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT|DISPATCH_PROC_SIGNAL, queue);
procinfo->pid = pid;
procinfo->source = dsp;
dispatch_source_set_event_handler_f(procinfo->source, (dispatch_function_t)process_termination_event);
dispatch_source_set_cancel_handler_f(procinfo->source, (dispatch_function_t)process_termination_finalize);
dispatch_set_context(procinfo->source, procinfo);
dispatch_resume(procinfo->source);
}
int main(int argc, const char * argv[])
{
for (int i = 0; i < argc; ++i) {
pid_t pid = atoi(argv[i]);
printf("MonitorTermination: %d\n", pid);
fflush(stdout);
MonitorTermination(pid);
}
CFRunLoopRun();
return 0;
}
The process_termination_event will not invoke after cmd-q as explained above. Even after force quit.
The process itself is held in a loop within the network kernel extension function:
errno_t KEXT::data_out(void *cookie, socket_t so, const struct sockaddr *to, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags)
{
// at this point I would like to detect the app quit/termination signal.
while(PROCESS_IS_NOT_TEMINATING); // <-- pseudo code, actually held with IOLockSleep...
return 0;
}
I would really appreciate any help! Thanks in advance.
It may not be the way you've been thinking, but if you're in the kernel space, then I assume you're writing a kernel extension (kext). With a kernel extension, you can monitor Vnodes for executing applications. You may be able to use the File Scope instead.
In conjunction with a user-level application (daemon), the kext notifies the daemon that a process has begun execution and then monitors the termination of the launched application from the user-level daemon, using Grand Central Dispatch functions. If required, the user-application can notify the kext of the terminated app.
To monitor the termination from a user-level application, you can do something like this when you're notified of an application being executed: -
// pid and path provided from vNode scope kext...
void UserLevelApp::MonitorProcessTermination(int pid, const QString &path)
{
ProcessInfo* procinfo = new ProcessInfo;
procinfo->pid = pid;
procinfo->path = path;
procinfo->context = this;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t dsp = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, queue);
dispatch_source_set_event_handler_f(dsp, (dispatch_function_t)process_termination_event);
dispatch_source_set_cancel_handler_f(dsp, (dispatch_function_t)process_termination_finalize);
procinfo->source = dsp;
dispatch_set_context(dsp, procinfo);
dispatch_resume(dsp);
}
// app terminated call-back function
void UserLevelApp::process_termination_event(struct ProcessInfo* procinfo)
{
dispatch_source_cancel(procinfo->source);
// example of how to use the context to call a class function
procinfo->context->SomeClassFunction(procinfo->pid, procinfo->path);
qDebug("App Terminated: %d, %s\n", procinfo->pid, procinfo->path.toUtf8().data());
}
// finalize callback function
void UserLevelApp::process_termination_finalize(struct ProcessInfo* procinfo)
{
dispatch_release(procinfo->source);
delete procinfo;
}
So each launched application, notified by the kext, has an event handler associated with it and when the application terminates, you get called back in the registered functions process_termination_event and process_termination_finalize
Whilst this method requires an associated user-level daemon application with the kext, that's not such a bad thing from a security and stability point of view.

PostMessage with WM_USER doesn't seem to arrive when MsgWaitForMultipleObjectsEx is used to check for it

I have a program with a few thread loops that you can post tasks to. One of these thread loops is the UI thread loop. It has to handle window messages as well as the posted tasks, so I send WM_USER messages to wake the thread in the dispatch loop.
The problem is that sometimes (specifically when there's lot of other window messages like WM_PAINT or WM_RESIZE) my WM_USER message doesn't wake the thread. It seems that the PostMessage function doesn't wake the thread from the MsgWaitForMultipleObjectsEx call, though I can't figure out why.
This is what it looks like (some paraphrasing for simplicity):
#define HaveWorkMessage (WM_USER + 100)
class ThreadLoopUI {
public:
ThreadLoopUI()
: myHaveWork(0) {}
void PostTask(Task& aTask) {
{
ScopedLock lock(myMutex);
myTaskQueue.push_back(aTask);
}
ScheduleWork();
}
void ScheduleWork() {
if (InterlockedExchange(&myHaveWork, 1)) {
// No need to spam the message queue
return;
}
if (!PostMessage(myHWnd, HaveWorkMessage, reinterpret_cast<WPARAM>(this), 0)) {
std::cerr << "Oh noes! Could not post!" << std::endl;
}
}
void Run() {
for (;;) {
// SIMPLIFICATION, SEE EDIT BELOW
DWORD waitResult = MsgWaitForMultipleObjectsEx(0, NULL, (DWORD)INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
if (waitResult == WAIT_FAILED) {
std::cerr << "Well, that was unexpected..." << std::endl;
continue;
}
bool doWork = false;
MSG message;
if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
if (message == HaveWorkMessage) {
doWork = true;
InterlockedExchange(&myHaveWork, 0);
}
// Send the message on to the window procedure
TranslateMessage(&message);
DispatchMessage(&message);
}
if (doWork) {
// Process all tasks in work queue
}
}
}
private:
HWND myHwnd;
Mutex myMutex;
std::vector<Task> myTaskQueue;
LONG volatile myHaveWork;
}
Edit: The direct call to MsgWaitForMultipleObjectsEx above was a simplification. I actually call a function that looks like this:
void WaitForMessages() {
DWORD waitResult = MsgWaitForMultipleObjectsEx(0, NULL, (DWORD)INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
if (waitResult == WAIT_OBJECT_O) {
// Comment from the Chromium source:
// A WM_* message is available.
// If a parent child relationship exists between windows across threads
// then their thread inputs are implicitly attached.
// This causes the MsgWaitForMultipleObjectsEx API to return indicating
// that messages are ready for processing (Specifically, mouse messages
// intended for the child window may appear if the child window has
// capture).
// The subsequent PeekMessages call may fail to return any messages thus
// causing us to enter a tight loop at times.
// The WaitMessage call below is a workaround to give the child window
// some time to process its input messages.
MSG message = {0};
DWORD queueStatus = GetQueueStatus(QS_MOUSE);
if (HIWORD(queueStatus) & QS_MOUSE &&
!PeekMessage(&message, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE))
{
WaitMessage();
}
}
}
When MsgWaitForMultipleObjects[Ex] says that it returned due to one or more messages, you must go into a loop processing all of them. Your code processes only one message, which means that the second message remains unprocessed. That's why you never get your WM_USER message: You gave up before you got a chance to see it.
Not sure if it is the culprit in your case, but you should organize the code so the PostMessage() is guaranteed to be used after the target thread already has its message loop.
New threads do not initially have any message queue, and it is only created after a first call attempting to get a message from it. I am not sure if MsgWaitForMultipleObjectsEx() counts here, so I would recommend to begin the thread with a call to PeekMessage(), just in order to create the queue.
Your app should guarantee that it never posts/sends messages to the thread before the PeekMessage() returns, or the message can simply get lost.
I have found the culprit now, and it seems that in some cases messages are dispatched from the queue by Windows outside of the message loop (i.e. they are sent to WindowProcedure automatically). To solve this I changed my WindowProcedureto be like this:
LRESULT CALLBACK
ThreadLoopUI::WindowProcedure(
HWND aWindowHandle,
UINT aMessage,
WPARAM aWParam,
LPARAM aLParam )
{
switch (aMessage)
{
case HaveWorkMessage:
// This might happen if windows decides to start dispatch messages from our queue
ThreadLoopUI* threadLoop = reinterpret_cast<ThreadLoopUI*>(aWParam);
InterlockedExchange(&threadLoop->myHaveWork, 0);
// Read the next WM_ message from the queue and dispatch it
threadLoop->PrivProcessNextWindowMessage();
if (threadLoop->DoWork())
{
threadLoop->ScheduleWork();
}
break;
}
return DefWindowProc(aWindowHandle, aMessage, aWParam, aLParam);
Thanks everyone for your help and suggestions!

Why does this window subclassing code crash?

I am trying to subclass the window that currently has focus. I do this by monitoring for HCBT_ACTIVATE events using a CBT hook, and set and unset the WndProc of the focused and previously focused windows.
The problem is that it only works whenever I have a breakpoint set somewhere in the code.
If there is no breakpoint, once my application exits, all the windows that I have subclassed crashes in order, even though I have removed the subclassing and restored the original WndProc.
I have verified that Unsubclass() is called whenever my application shuts down.
// code extracts
HINSTANCE hInst;
HHOOK hHook;
#pragma data_seg(".shared")
HWND hWndSubclass = 0;
FARPROC lpfnOldWndProc = NULL;
#pragma data_seg()
#pragma comment(linker, "/section:.shared,rws")
void Unsubclass()
{
// if the window still exists
if (hWndSubclass != 0 && IsWindow(hWndSubclass))
{
SetWindowLongPtr(hWndSubclass, GWLP_WNDPROC, (LPARAM)lpfnOldWndProc);
hWndSubclass = 0;
}
}
static LRESULT CALLBACK SubClassFunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_MOVING)
{
// this is just test code so I can see it works (it does)
RECT* r = (RECT*)lParam;
r->right = r->left + 500;
r->bottom = r->top + 500;
return TRUE;
}
else if (message == WM_DESTROY)
{
Unsubclass();
}
return CallWindowProc((WNDPROC)lpfnOldWndProc, hWndSubclass, message, wParam, lParam);
}
void SubclassWindow(HWND hWnd)
{
// remove the subclassing for the old window
Unsubclass();
// subclass the new window
lpfnOldWndProc = (FARPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LPARAM)SubClassFunc);
hWndSubclass = hWnd;
}
static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_ACTIVATE)
{
SubclassWindow((HWND)wParam);
}
return 0;
}
// ... code that initializes the CBT proc
__declspec(dllexport) BOOL Setup()
{
hHook = SetWindowsHookEx(WH_CBT, CBTProc, hInst, 0);
}
__declspec(dllexport) BOOL Teardown()
{
UnhookWindowsHookEx(hHook);
Unsubclass();
}
BOOL APIENTRY DllMain( HINSTANCE hInstance,
DWORD Reason,
LPVOID Reserved
)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
hInst = hInstance;
return TRUE;
case DLL_PROCESS_DETACH:
Unsubclass();
return TRUE;
}
return TRUE;
}
Your problems hinge on several fronts:
UnHookWindowsHook does not unload injected dlls, all it does is remove the hook proc. If the dlls need to be unloaded its up to them to invent some kind of unloading mechanism.
SetWindowLongPtr typically fails when called from a process other than the process that owns the window.
The nett result of this is, its very difficult to safely remove windows hooks. First thing, your OldWindowProc pointer should not be stored in the shared data area. Next, in order to remove the subclass, you need to be able to co-erce the (currently) subclassed process to perform the un-subclassing.
What you could do is, first, register a new unique message id and place it in your shared area using RegisterWindowMessage. WM_REMOVE_HOOK.
UINT idWM_REMOVE_HOOK = RegisterWindowMessage("WM_REMOVE_HOOK");
Now, whenever you need to remove a hook,
SendMessage(hWndSubClass,idWM_REMOVE_HOOK,0,0);
In your subclass proc:
if(uMsg == WM_DESTROY || uMsg == idWM_REMOVE_HOOK)
{
Unsubclass(hwnd);
}
Remove the call to UnSubClass in DLL_PROCESS_DETATCH. Its a dangerous race condition thats going to cause your dll being unloaded in some random process to trash the hook data of a potentially valid hook in another process.
lpfnOldWndProc and hWndSubclass are global pointers. Seems like you've got only one per process. What if a process creates more than one window?
Then you will unsubclass only the last one.
EDIT: Also, why do you tear down in Process DETACH?
You are creating a global system-wide hook in a DLL. You need to store the HHOOK handle and your subclassing information in a block of shared memory so all instances of your DLL in all running processes can have access to them. Your variables are declared global in code, but each individual instance of the DLL will have its own local copy of them, and thus they will not be not initialized in all but 1 of your DLL instances (the one that calls Setup()). They need to be shared globally within the entire system instead.
You also should not be calling TearDown() in DLL_PROCESS_DETACH, either. Every instance of the DLL is going to call TearDown() when their respective processes terminate, but only the single instance that actually called Setup() should be the one to call Teardown().
If the debugger will cause the process to succeed by adding a breakpoint then most likely, this is a timing issue.
What possibly happens is that your main application is closing itself and freeing resources just before the subclassed windows get the messages they need to remove the subclass again. You might want to give them a few processing cycles to handle their own messages between the unhooking and the unsubclassing. (In Delphi you could do this by calling Application.ProcessMessages but in your C++ version? Don't know the answer to that.

Resources