I wrote a simple code to capture the netdevice notifications and simply print their value out to the messages log file ... here's the code :
#include <linux/notifier.h>
#include <asm/kdebug.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
int my_dev_event_handler (struct notifier_block *self,unsigned long val, void *data)
{
printk (KERN_INFO "my_dev_event: Val=%ld, Interface=%s\n", val,((struct net_device *) data)->name);
return 0;
}
static struct notifier_block my_dev_notifier = {
.notifier_call = my_dev_event_handler,
};
static int __init
my_init (void)
{
printk(KERN_ALERT "***Module Loaded***\n");
register_netdevice_notifier (&my_dev_notifier);
return 0;
}
static void __exit my_end(void)
{
printk(KERN_ALERT "***Module Unloaded***\n");
}
module_init(my_init);
module_exit(my_end);
this code compiles and runs correctly, it prints out the "my_dev_event:..." line every time a device goes up/off ... but sometimes (not always) the entire system freezes when a device goes up\down ... now I have two questions here:
1- why is the system freezing? anything wrong with this code?
2- if there's a better way to notify my kernel module when a device goes connected/disconnected ...
The only problem I see is that my_end doesn't unregister the notifier.
This can cause crashes or freezes after you've unloaded your module. This is because a pointer to your code remains in Linux data structures, but your code is no longer there.
Regarding an alternative way - I think you're using the correct way to get these notifications.
Related
I have a smart card IC module, and I want to create a Linux device driver for it. This module is using SPI as the controlling line and has an interrupt line to indicate whether a card is ready. I know how to create a SPI device in Linux kernel and how to read data in the kernel when the interruption happens. But I have no idea on how to transfer the data to the user space (maybe need to create a device node for it), and how to give the user space a interruption to notify it. Does anyone have some suggestion?
One way you can go about this is by creating a devfs entry and then having the interested process open that device and receive asynchronous notification from the device driver using fasync.
Once you have the notification in user space you can notify other interested processes by any means you deem fit.
I am writing a small trimmed down example illustrating this feature.
On the driver side
/* Appropriate headers */
static int myfasync(int fd, struct file *fp, int on);
static struct fasync_struct *fasyncQueue;
static struct file_operations fops =
{
.open = charDriverOpen,
.release = charDriverClose,
.read = charDriverRead,
.write = charDriverWrite,
.unlocked_ioctl = charDriverCtrl,
// This will be called when the FASYNC flag is set
.fasync = myfasync,
};
static int __init charDriverEntry()
{
// Appropriate init for the driver
// Nothing specific needs to be done here with respect to
// fasync feature.
}
static int myfasync(int fd, struct file *fp, int on)
{
// Register the process pointed to by fp to the list
// of processes to be notified when any event occurs
return fasync_helper(fd, fp, 1, &fasyncQueue);
}
// Now to the part where we want to notify the processes listed
// in fasyncQueue when something happens. Here in this example I had
// implemented the timer. Not getting in to the details of timer func
// here
static void send_signal_timerfn(unsigned long data)
{
...
printk(KERN_INFO "timer expired \n");
kill_fasync(&fasyncQueue, SIGIO, POLL_OUT);
...
}
On the user land process side
void my_notifier(int signo, siginfo_t *sigInfo, void *data)
{
printf("Signal received from the driver expected %d got %d \n",SIGIO,signo);
}
int main()
{
struct sigaction signalInfo;
int flagInfo;
signalInfo.sa_sigaction = my_notifier;
signalInfo.sa_flags = SA_SIGINFO;
sigemptyset(&signalInfo.sa_mask);
sigaction(SIGIO, &signalInfo, NULL);
int fp,i;
fp = open("/dev/myCharDevice",O_RDWR);
if (fp<0)
printf("Failed to open\n");
/*New we will own the device so that we can get the signal from the device*/
// Own the process
fcntl(fp, F_SETOWN, getpid());
flagInfo = fcntl(fp, F_GETFL);
// Set the FASYNC flag this triggers the fasync fops
fcntl(fp, F_SETFL, flagInfo|FASYNC);
...
}
Hope this clears things up.
For more detailed reading I suggest you read this
I'm writing a command-line C++ program on Windows, that inevitably sometimes hits an error such as a stack overflow or access violation; in these cases, I would like it to print an informative error message before exiting. This is what I have at the moment:
AddVectoredExceptionHandler(0, handler);
and
LONG WINAPI handler(_EXCEPTION_POINTERS *ExceptionInfo) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode ==
EXCEPTION_STACK_OVERFLOW) {
puts("stack overflow");
ExitProcess(1);
}
printf("exception %X", ExceptionInfo->ExceptionRecord->ExceptionCode);
ExitProcess(1);
}
The special case for stack overflow is because I have found that puts works in that situation but printf doesn't. Is that because there is so little stack space left that only the simplest functions work, or because the stack is damaged in such a way that varargs doesn't work?
Right now, I'm getting exception C0000005. I look at the definitions in minwinbase.h and ntstatus.h and find this is STATUS_ACCESS_VIOLATION. Which is useful to know! It would be even better if I could get more details as well as doing the lookup automatically. I notice the accompanying comment in the header file says
// MessageText:
//
// The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.
A format string, which suggests this information could be automatically printed. What's the way to do this?
Minimal, complete and verifiable example, compile with cl main.cc:
#include <stdio.h>
#include <windows.h>
LONG WINAPI handler(_EXCEPTION_POINTERS *ExceptionInfo) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode ==
EXCEPTION_STACK_OVERFLOW) {
puts("stack overflow");
ExitProcess(1);
}
printf("exception %X\n", ExceptionInfo->ExceptionRecord->ExceptionCode);
ExitProcess(1);
}
void overflow() { overflow(); }
int main(int argc, const char **argv) {
AddVectoredExceptionHandler(0, handler);
// demonstrate access violation
*(int *)0 = 0;
// demonstrate stack overflow
overflow();
return 0;
}
Why this kernel module doesn't do anything when i load it?
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#define DEVICE_NAME "hello-1.00.a"
#define DRIVER_NAME "hello"
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(struct platform_device *pdev){
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static int hello_exit(struct platform_device *pdev){
printk(KERN_ALERT "Goodbye, cruel world\n");
return 0;
}
static const struct of_device_id myled_of_match[] =
{
{.compatible = DEVICE_NAME},
{},
};
MODULE_DEVICE_TABLE(of, myled_of_match);
static struct platform_driver hello_driver =
{
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = myled_of_match
},
.probe = hello_init,
.remove = hello_exit
};
module_platform_driver(hello_driver);
It musts print Hello, world\n, if i do lsmod the module appear to be loaded:
lsmod
hello_world 1538 0 - Live 0xbf000000 (O)
but nothing is printed neither in the console nor in dmesg.
If i use module_init and module_exit all works, but i need the pointer platform_device *pdev to the device, what can i do?
EDIT:
the original module looks like this:
#include <linux/init.h>
#include <linux/module.h>
static int hello_init(void){
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void){
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
In my device tree blob is present this entry:
hello {
compatible = "dglnt,hello-1.00.a";
reg = <0x41220000 0x10000>;
};
If i use module_init and module_exit all works
That short "original" code only consists of the module framework. The init routine is guaranteed to be called when the module is loaded, and the exit routine is called prior to unloading. That "original" code is not a driver.
The longer kernel module is a driver and getting loaded, but since it has the default init and exit code that does nothing (as generated by the expansion of the module_platform_driver() macro), there are no messages. The driver code in the loadable module is not guaranteed to be called when the kernel uses a Device Tree.
Why this kernel module doesn't do anything when i load it?
The probe function of the driver (which would output messages) is probably not getting called because there is nothing in your Device Tree that indicates that this device driver is needed.
The snippet of the board's Device Tree has
compatible = "dglnt,hello-1.00.a";
but the driver declares that it should specified as
#define DEVICE_NAME "hello-1.00.a"
...
{.compatible = DEVICE_NAME},
These strings should match so that the driver can bind with this referenced device in the Device Tree node.
Also the device node should be declared as
status = "okay";
to override any default status that could disable the device.
A properly configured node in the Device Tree should get the driver's probe function to be executed as expected.
I'm trying to get a fixed timer in a MicroBlaze MCS core to call a function to toggle some LEDs as a proof of concept.
Here is my code I have now
#include <xparameters.h>
#include <xiomodule.h>
#include <xiomodule_l.h>
XIOModule gpo1;
volatile u32 ct = 0;
void timerTick(void* ref){
ct++;
XIOModule_DiscreteWrite(&gpo1, 1, ct);
XIOModule_DiscreteWrite(&gpo1, 2, ct);
}
int main() {
XIOModule_Initialize(&gpo1, XPAR_IOMODULE_0_DEVICE_ID);
XIOModule_Start(&gpo1);
XIOModule_EnableIntr(XPAR_IOMODULE_0_BASEADDR, XIN_IOMODULE_FIT_1_INTERRUPT_INTR);
XIOModule_Connect(&gpo1, XIN_IOMODULE_FIT_1_INTERRUPT_INTR, timerTick, NULL);
while (1) {
}
}
The GPO stuff works. If I put it in the while loop I can get the LEDs to toggle as expected. However, as the code currently is, timerTick() never gets called. I am really confused on how to properly setup the interrupt and I haven't been able to find any documentation on this. The best I could find was http://www.xilinx.com/support/documentation/sw_manuals/xilinx14_4/pg048-microblaze-mcs.pdf which covers more about the hardware of the core and not how to program it.
What is the proper way to enable and connect an interrupt?
I found the solution thanks to this forum post http://forums.xilinx.com/t5/Embedded-Development-Tools/Can-not-fire-MicroBlaze-MCS-interrupt/td-p/256372
#include <xparameters.h>
#include <xiomodule.h>
#include <xiomodule_l.h>
XIOModule gpo1;
volatile u32 ct = 0;
void timerTick(void* ref) {
ct++;
XIOModule_DiscreteWrite(&gpo1, 1, ct);
XIOModule_DiscreteWrite(&gpo1, 2, ct);
}
int main() {
XIOModule_Initialize(&gpo1, XPAR_IOMODULE_0_DEVICE_ID);
microblaze_register_handler(XIOModule_DeviceInterruptHandler, XPAR_IOMODULE_0_DEVICE_ID);
XIOModule_Start(&gpo1);
XIOModule_Connect(&gpo1, XIN_IOMODULE_FIT_1_INTERRUPT_INTR, timerTick, NULL);
XIOModule_Enable(&gpo1,XIN_IOMODULE_FIT_1_INTERRUPT_INTR);
microblaze_enable_interrupts();
while (1) {
}
}
First, I don't know if this is the correct place to put this question. Would Serverfault or Apple be better?
I was running through a tutorial on making Mac Kernel Extensions. I loaded it, and when I did tail -1 /var/log/system.log, it didn't tell me "Hello World!", it said...
parentalcontrolsd[374]: -[ActivityTracker appDidLaunchOrBecomeFront:launched:] [1844:wolfram] -- Got an error when saving MOC: Error Domain=NSCocoaErrorDomain Code=134030 UserInfo=0x36ba10 "An error occurred while saving."
A few things... What does this mean? And am I looking at the right log file? I can pick out that it's the parentalcontrolsd telling me that the ActivityTracker found that some app launched for the user wolfram. Any help?
Here is my code...
#include <libkern/libkern.h>
#include <mach/mach_types.h>
kern_return_t MyKextStart(kmod_info_t *ki, void *d)
{
printf("Hello, World!\n");
return KERN_SUCCESS;
}
kern_return_t MyKextStop(kmod_info_t *ki, void *d)
{
printf("Goodbye, World!\n");
return KERN_SUCCESS;
}
extern kern_return_t _start(kmod_info_t *ki, void *data);
extern kern_return_t _stop(kmod_info_t *ki, void *data);
KMOD_EXPLICIT_DECL(edu.nerd.kext.MyKext, "1.0.0d1", _start, _stop)
__private_extern__ kmod_start_func_t *_realmain = MyKextStart;
__private_extern__ kmod_stop_func_t *_antimain = MyKextStop;
__private_extern__ int _kext_apple_cc = __APPLE_CC__;
I was looking in the wrong log file. The kernel log is /var/log/kernel.log.