|
|
Subscribe / Log in / New account

Driver porting: hello world

This article is part of the LWN Porting Drivers to 2.6 series.
Your editor is currently in the middle of porting the example source from Linux Device Drivers, Second Edition to the 2.5 kernel. This work is, of course, just the beginning of the rather larger job of updating the whole book. This article is the first in what will, hopefully, be a series describing what is required to make this code work again. The series will thus, with luck, be useful as a guide to how to port drivers to the new kernel API.

The obvious place to start in this sort of exercise, of course, is the classic "hello world" program, which, in this context, is implemented as a kernel module. The 2.4 version of this module looked like:

    #define MODULE
    #include <linux/module.h>
    #include <linux/kernel.h>

    int init_module(void)      
    { 
	printk(KERN_INFO "Hello, world\n"); 
	return 0; 
    }

    void cleanup_module(void)  
    { 
	printk(KERN_INFO "Goodbye cruel world\n"); 
    }

One would not expect that something this simple and useless would require much in the way of changes, but, in fact, this module will not quite work in a 2.5 kernel. So what do we have to do to fix it up?

The first change is relatively insignificant; the first line:

    #define MODULE
is no longer necessary, since the kernel build system (which you really should use now, see the next article) defines it for you.

The biggest problem with this module, however, is that you have to explicitly declare your initialization and cleanup functions with module_init and module_exit, which are found in <linux/init.h>. You really should have done that for 2.4 as well, but you could get away without it as long as you used the names init_module and cleanup_module. You can still sort of get away with it (though you may have to ignore some compiler warnings), but the new module code broke this way of doing things once, and could do so again. It's really time to bite the bullet and do things right.

With these changes, "hello world" now looks like:

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.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);

This module will now work - the "Hello, world" message shows up in the system log file. What also shows up there, however, is a message reading "hello: module license 'unspecified' taints kernel." "Tainting" of the kernel is (usually) a way of indicating that a proprietary module has been inserted, which is not really the case here. What's missing is a declaration of the license used by the module:

    MODULE_LICENSE("Dual BSD/GPL");
MODULE_LICENSE is not exactly new; it was added to the 2.4.10 kernel. Some older code may still lack MODULE_LICENSE calls, however. They are worth adding; in addition to avoiding the "taints kernel" message, a license declaration gives your module access to GPL-only kernel symbols. Assuming, of course, that the module is GPL-licensed.

With these changes, "hello world" works as desired. At least, once you have succeeded in building it properly; that is the subject of the next article.


to post comments

Driver porting: hello world

Posted Feb 14, 2003 5:19 UTC (Fri) by rusty (guest, #26) [Link]

Hi Jon,

I appeciate the series in modernizing modules, but just FYI, I don't think the old-style init_module/cleanup_module stuff will break any time soon: there are still a large number of drivers which use it, and there's not much point making such changes.

However, this "new" scheme (introduced by Linus in 2.3 IIRC) has the advantage that your module will work correctly when built into the kernel: you want that initialization routine called, even then.

So I hope that clarifies,
Rusty.

Driver porting: hello world

Posted Jul 14, 2004 6:59 UTC (Wed) by hemal (guest, #23037) [Link] (6 responses)

Hello every1,
I am new to Linux and just installed Fedora Core 2. I tried adding a simple hello world module but I have been getting problems.
This is my hello.c program:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static int hello_init(void)
{
printk("<1> Hello, world\n");
return 0;
}

static void hello_exit(void)
{
printk("<1> Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);


The Makefile for this is:

ifneq ($(KERNELRELEASE),)
obj-m:= hello.o

else
KDIR:= /lib/modules/$(shell uname -r)/build
PWD:= $(shell pwd)

default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif

so the problem is once I type the command "make" at the shell prompt it gives the following message :

$ make: Nothing to be done for 'default'

I dont know whats the problem. Can any1 please help me out here. Your help will be appreciated.


Driver porting: hello world

Posted Jul 15, 2004 11:34 UTC (Thu) by littertiger (guest, #22470) [Link]

My makefile is simple:

obj-m += hello.o
default:
make -C /lib/modules/$(shell uname -r)/build/ SUBDIRS=$(PWD) modules

Driver porting: hello world

Posted Jul 17, 2004 1:14 UTC (Sat) by bhaskie (guest, #23099) [Link] (3 responses)

Towards the end of the Makefile:
----------
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif
----------
add a tab before the $(MAKE)

copy-pasting code results in such errors. read the man pages.
check http://lwn.net/Articles/21823/ , the Makefile has a tab space there.

Driver porting: hello world

Posted May 24, 2006 9:15 UTC (Wed) by Jackie (guest, #37933) [Link] (2 responses)

I am a newer and my makefile is :

ifneq ($(KERNELRELEASE),)
obj-m:=hello.o

else
KDIR:=/lib/modules/$(shell uname -r)
PWD:=$(shell pwd)

default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) hello
endif

When I type 'make' on the command line, it says:
make[1]: Entering directory `/lib/modules/2.6.12-10-386'
make[1]: *** No rule to make target `mytest'. Stop.
make[1]: Leaving directory `/lib/modules/2.6.12-10-386'
make: *** [default] Error 2

"2.6.12-10-386" is my kernel version.I don't know why and any answer is appreciated.

Driver porting: hello world

Posted May 24, 2006 9:18 UTC (Wed) by Jackie (guest, #37933) [Link]

I am a newer and my makefile is :

ifneq ($(KERNELRELEASE),)
obj-m:=hello.o

else
KDIR:=/lib/modules/$(shell uname -r)
PWD:=$(shell pwd)

default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) hello
endif

When I type 'make' on the command line, it says:
make[1]: Entering directory `/lib/modules/2.6.12-10-386'
make[1]: *** No rule to make target `hello'. Stop.
make[1]: Leaving directory `/lib/modules/2.6.12-10-386'
make: *** [default] Error 2

"2.6.12-10-386" is my kernel version.I don't know why and any answer is appreciated.

Driver porting: hello world

Posted Jul 17, 2006 13:12 UTC (Mon) by jameswin (guest, #39125) [Link]

Hello!I got the same problem like you.
Could you guide me how to solve the problem.
Thank you in advance.
jameswin

Driver porting: hello world

Posted Jun 21, 2006 9:00 UTC (Wed) by robin48gx (guest, #38475) [Link]

I added a little to this driver, and implemented the read and write
parts.

I put it on the gumstix tikiwiki http://www.gumstix.org/tikiwiki/tiki-index.php?page=kerne...

Driver porting: hello world

Posted Jul 15, 2004 11:37 UTC (Thu) by littertiger (guest, #22470) [Link] (1 responses)

I don't know what the "KERN_INFO" means in the example.
if write like that, there are compiling errors.

Driver porting: hello world

Posted Jul 28, 2004 9:28 UTC (Wed) by PsychoJamin (guest, #23518) [Link]

KERN_INFO is part of a macro defined in <linux/kernel.h>

It replaces the need for <0> .. <7> in printk messages which specifies the priority of the message. Where 0 is the highest priority and 7 is the lowest.

As these are macros there is no need for a ',' between it ans the rest of the printk parameter. ie printk(KERN_INFO "Hello\n"); not printk(KERN_INFO, "Hello\n");

The definietions are as follows:

#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant condition */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages */

Driver porting: hello world

Posted Sep 23, 2004 20:47 UTC (Thu) by Droep (guest, #24946) [Link] (1 responses)

Hi,

I'm new to "Linux Device Drivers". When I try to compile the given example as shown above, I get the following error messages. The only difference is that I named the file "hello-driver2.c".
Anyone who knows what I did wrong?

*/usr/include/linux/jiffies.h:16: error: parse error before "jiffies_64"
*/usr/include/linux/jiffies.h:20: error: parse error before "get_jiffies_64"
*/usr/include/asm/mmu.h:13: error: field `sem' has incomplete type
*/usr/include/linux/list.h:604:2: warning: #warning "don't include kernel headers in userspace"
*/usr/include/asm-generic/siginfo.h:53: error: size of array `_pad' is too large
*/usr/include/linux/fs_struct.h:9: error: parse error before "rwlock_t"
*/usr/include/linux/fs_struct.h:13: error: parse error before '}' token
*/usr/include/linux/completion.h:15: error: parse error before "wait_queue_head_t"
*/usr/include/linux/completion.h:26: error: dereferencing pointer to incomplete type
*/usr/include/linux/completion.h:27: error: dereferencing pointer to incomplete type
*/usr/include/linux/pid.h:18: error: field `task_list' has incomplete type
*/usr/include/linux/pid.h:19: error: field `hash_chain' has incomplete type
*/usr/include/linux/pid.h:24: error: field `pid_chain' has incomplete type
*/usr/include/linux/sched.h:93: error: parse error before "process_counts"
*/usr/include/linux/timer.h:10: error: field `entry' has incomplete type
*hello-driver2.c:6: error: `KERN_ALERT' undeclared (first use in this function)
*hello-driver2.c:6: error: parse error before string constant
*hello-driver2.c:11: error: `KERN_ALERT' undeclared (first use in this function)
*hello-driver2.c:11: error: parse error before string constant
*hello-driver2.c:14: error: parse error before "__attribute_used__"
*hello-driver2.c:14: warning: initialization makes integer from pointer without a cast
*hello-driver2.c:14: warning: data definition has no type or storage class
*hello-driver2.c:15: error: parse error before "__attribute_used__"
*hello-driver2.c:15: error: redefinition of `__attribute_used__'
*hello-driver2.c:14: error: `__attribute_used__' previously defined here
*hello-driver2.c:15: warning: initialization makes integer from pointer without a cast
*hello-driver2.c:15: warning: data definition has no type or storage class
**** Beƫindigd met status: 2 ***

Driver porting: hello world

Posted Jun 13, 2006 13:44 UTC (Tue) by tuxonnst (guest, #33869) [Link]

Dear Mr.X,

Is this the start of your error message or is it preceeded by a hell lot of other messages ?

Just try out this thing

go to the Linux source directory
go to include/linux/asm/ directory in the source directory
check if it is having a link arch to the architecture you are using

If no, be free to use 'ln' command for making the link arch for required architecture

Hope this will solve the probs

Rgds
Aeolus Jacob

Driver porting: hello world

Posted Nov 9, 2004 12:32 UTC (Tue) by madhavi_srinivas (guest, #25933) [Link]

Dear all,

Here is the small hello.c program.
----------------------------------

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
printk("Hello World!\n");
return 0;
}

static void hello_exit(void)
{
printk("Good bye!\n");
}

module_init(hello_init);
module_exit(hello_exit);

Here is the Makefile.
---------------------

#
# Makefile for hello.c file
#
KDIR:=/lib/modules/$(shell uname -r)/build

obj-m:=hello.o

default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
$(RM) .*.cmd *.mod.c *.o *.ko -r .tmp*

#####################################################

It got compiled and inserted with out any errors, but dmesg says "unsupported module, tainting kernel".

System Configuration: x86, SuSE 9.1 with 2.6.5-7.71 kernel version.

What can I do to get rid of that message?

Thanks for any hints.

Regards,
Srinivas G

Driver porting: hello world

Posted Nov 22, 2004 4:33 UTC (Mon) by prakash07 (guest, #26172) [Link] (4 responses)

i am getting error while compiling make file in kernel 2.6.8.1
make: -C/lib/modules/2.6.8.1/build/SUBDIRS=/rootmodules
make:*** /lib/modules/2.6.8.1/build/SUBDIRS=/rootmodules: No Such file or directory. stop
make: ***[default]error 2
can any one give me the solutions

Driver porting: hello world

Posted Dec 18, 2004 5:22 UTC (Sat) by sockie (guest, #26758) [Link] (3 responses)

I am getting the following errors when trying to compile the above example on Kernel 2.6.9

**************************************************************************
make -C /lib/modules/2.6.9-1.667smp/build SUBDIRS=/root/ppm/client modules
make[1]: Entering directory `/lib/modules/2.6.9-1.667smp/build'
CC [M] /root/ppm/client/test.o
In file included from include/asm/smp.h:18,
from include/linux/smp.h:17,
from include/linux/sched.h:23,
from include/linux/module.h:10,
from /root/ppm/client/test.c:2:
include/asm/mpspec.h:6:38: mach-generic/mach_mpspec.h: No such file or directory
In file included from include/asm/smp.h:18,
from include/linux/smp.h:17,
from include/linux/sched.h:23,
from include/linux/module.h:10,
from /root/ppm/client/test.c:2:
include/asm/mpspec.h:8: error: `MAX_MP_BUSSES' undeclared here (not in a function)
include/asm/mpspec.h:22: error: `MAX_IRQ_SOURCES' undeclared here (not in a function)
make[2]: *** [/root/ppm/client/test.o] Error 1
make[1]: *** [_module_/root/ppm/client] Error 2
make[1]: Leaving directory `/lib/modules/2.6.9-1.667smp/build'
make: *** [default] Error 2

**************************************************************************

Any help is appreciated.

Y.W.

Driver porting: hello world

Posted Aug 26, 2005 20:24 UTC (Fri) by vleo (guest, #32027) [Link] (2 responses)

Everybody new to driver development - RTFM - Read Rubini's book.

Most people having problem with hello_world driver don't understand that you should have Linux kernel sources installed and configured, 'make menuconfig' is your friend. Only after that you can start building your own drivers.

Good place to put sources into is for example /usr/src/linux-2.6.12 (for kernel 2.6.12). If you untar kernel souce into /usr/src you would be pretty close to that.

Then make sure you have following among gcc flags in your Makefile:

-I /usr/src/linux-2.6.12/include

If you do not have that, #includes like <linux/types.h> would get file /usr/include/linux/types.h, which is certainly not what you want to be included as opposed to /usr/src/linux-2.6.12/include/linux/types.h

Driver porting: hello world

Posted Sep 20, 2005 15:17 UTC (Tue) by jeanwelly (guest, #29199) [Link] (1 responses)

I use "insmod hello.ko " to use the module, It's OK when I check the kernel message. But when I want to remove the module, error found:

[root@localhost kernel-dev]# rmmod -f hello.ko
ERROR: Removing 'hello': Device or resource busy

Does any one know why?
Thanks!

Driver porting: hello world

Posted Jan 13, 2008 5:51 UTC (Sun) by manish_badarkhe (guest, #49929) [Link]

I think your device is in some other mode(read or write) while you are removing the device

Driver porting: hello world

Posted Feb 11, 2006 12:26 UTC (Sat) by vikasvasud (guest, #35870) [Link] (1 responses)

Hi
I am new to kernel programming. I am using Fedora Core. kernel version 2.6.5-1.358.

My code is
>>>>>
#include<linux/module.h>
#include<linux/kernel.h>
int init_module()
{printk("welcome to the world of kernel programming");
return 0;
}
void init_module()
{printk("removing from kernel space");
}

MODULE_LICENCE("GPL");
>>>>>>
i have named this source file as hello.c

Now the problem is i dont know how to insert this module in the kernel space. I have tried gcc -c hello.c to generate hello.o. And then i tried insmod hello.o but to my luck no go . i know this method works with kernel 2.4. But with 2.6 i am not much sure
So i tried modprobe hello.o and i got the message module format not supported.

Finally i tried gcc -I/usr/src/linux-2.6.5-1.358/include -c hello.o
But first it gave me some linker error
then i tried gcc -c hello.0 hello.c
and i got the following errors.

************
/usr/lib/gcc-lib/i386-redhat-linux/3.3.3/../../../crt1.o(.text+0x18): In function `_start':
: undefined reference to `main'
/tmp/cckOZLS5.o(.text+0xf): In function `init_module':
: undefined reference to `printk'
/tmp/cckOZLS5.o(.text+0x2c): In function `cleanup_module':
: undefined reference to `printk'
collect2: ld returned 1 exit status
************

I really dont know what i am doing wrong please suggest me as it is really very important for me.

Thank you in advance
Regards
Vikas Vasudev


Driver porting: hello world

Posted Oct 28, 2007 10:05 UTC (Sun) by ravidubey (guest, #32563) [Link]

in the code snippet, you dont have a cleanup_module (both are init_module functions) and in
the compilation log, you are getting cleanup_module...Seems you have not copied the correct
code...

Ferrari

Driver porting: hello world

Posted Apr 25, 2006 11:48 UTC (Tue) by SAturn (guest, #37343) [Link]

Hi. I'm trying to make a module under kernel 2.6.11.4 with the source:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static int hello_init(void)
{
printk( "<1>Hello World 1.\n" );

return 0;
}

static void hello_exit(void)
{
printk( KERN_ALERT "Goodbye 1.\n" );
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("Dual BSD/GPL");
// end of source

the Makefile is

ifneq ($ (KERNELRELEASE), )
obj-m := mod1.o

else
KDIR := /lib/modules/$( shell uname -r)/build
PwD := $(shell pwd )

default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

endif

# end of Makefile

And executing a command like:

make -C /usr/src/linux SUBDIRS=$PWD modules

I get a response:

make: Entering directory `/usr/src/linux-2.6.11.4-20a'

WARNING: Symbol version dump /usr/src/linux-2.6.11.4-20a/Module.symvers is missing; modules will have no modversions.

Building modules, stage 2.
MODPOST
/bin/sh: scripts/mod/modpost: No such file or directory
make[1]: *** [__modpost] Error 127
make: *** [modules] Error 2
make: Leaving directory `/usr/src/linux-2.6.11.4-20a'

What's the problem? And what should I do? Help me please.

Driver porting: hello world

Posted Jul 9, 2006 21:35 UTC (Sun) by dkandula (guest, #37125) [Link]

The outputs are given below along with the program. Please help me out.

[root@localhost dp-c]# insmod modul.ko
insmod: error inserting 'modul.ko': -1 Invalid module format
[root@localhost dp-c]#

[root@localhost dp-c]# uname -a
Linux localhost.localdomain 2.6.16.20 #1 Sun Jun 25 23:05:31 EDT 2006 i686
i686 i386 GNU/Linux

The program is given below and the Makefile

obj-m += modul.o

Program

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init (void) {
printk("Hello World!\n");
return 0;
}

static void hello_exit(void) {
printk("Bye world\n");
}

module_init(hello_init);
module_exit(hello_exit);

Please help me out. I want to be a device driver. None of the online help
regarding invalid format helps.

Driver porting: hello world

Posted Aug 13, 2007 0:23 UTC (Mon) by apc20 (guest, #46735) [Link] (1 responses)

Does anyone know how to link in the C math libraries (math.h)? I've had no luck getting a device driver to compile by linking in math.h ( -lm in the old Makefile).

Thanks,

Alex

Driver porting: hello world

Posted Aug 13, 2007 16:31 UTC (Mon) by zlynx (guest, #2285) [Link]

The kernel does not have the Standard C libraries. It's a free-standing program, like some embedded code. The only libraries you are allowed to use are the ones declared in the Linux source include directories.

Math libraries are generally for floating point. The Linux kernel does not support floating point inside the kernel. Floating point adds a rather large and slow set of registers to save and restore. Not doing the save/restore means context switch in and out of the kernel is much faster.

You *can* do floating point in kernel if you *really* want to, but you'd better know exactly what you're doing. If your calculations are not precison critical, it'd be faster to use fractional integer math and small lookup tables to estimate things like sqrt and trig functions.

Driver porting: hello world

Posted Oct 16, 2007 4:36 UTC (Tue) by gprabodha (guest, #48431) [Link] (1 responses)

I'm new to fedora core 5 and using it. I tried to compile a very simple memory driver and got
the error message 
"memory: module license 'unspecified' taints kernel." when I check log file with dmesg
command.
But I already put 
"MODULE_LICENSE("Dual BSD/GPL");"
on my memory.c code.
Can someone pls expain me why I got that message.

Driver porting: hello world

Posted Oct 16, 2007 6:15 UTC (Tue) by gprabodha (guest, #48431) [Link]

It's ok.Found the bug.It is on my makefile.


Copyright © 2003, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds