This commit is contained in:
gferg 2005-05-27 17:04:12 +00:00
parent f06bcd9b6e
commit 77ba6298b3
41 changed files with 622 additions and 493 deletions

View File

@ -34,29 +34,6 @@
</sect1>
<!--
This is in the Chinese translation:
<sect1><title>Note From the Chinese Translator</title>
<para>I am Jerry Tian, the translator of the simplified Chinese edition of this guide, and now a university student in
Beijing. I became a GNU/Linux enthusiast when I first encountered it as a senior high school; I like the spirit of
freedom in open source software.</para>
<para>This guide is the most updated document in Linux kernel module programming. I have also translated the former 2.4
branch of LKMPG into simplified Chinese, but based on HTML files, so it's inconvenient to convert it to other formats. Thanks
to Peter's advice and encouragement, the translation of 2.6 branch is based on DOCBOOK files, and it's very easy to convert it
to other formats like HTML, PDF, etc. Most of its content is from the translation of 2.4 branch, but some translation
mistakes in 2.4 branch are corrected. Since I hardly have enough time to go through the 2.4 branch of translation again and
correct the mistakes in the HTML files, I suggest if you need to read the simplified translation of 2.4 branch of LKMPG, do
refer to the translation of 2.6 branch. Please contact me if you have any ideas on how to improve the simplified Chinese
translation of LKMPG or want to help me maintain it.</para>
<para>My email address is jerrytianbupt@163.com. Learning and sharing the learning is the motive of my translation. I hope
you enjoy it! </para>
</sect1>
-->
<!--

View File

@ -35,73 +35,56 @@
</itemizedlist>
<para>If modprobe is handed a generic identifier, it first looks for that string in the file
<filename>/etc/modules.conf</filename>. If it finds an alias line like:</para>
<filename>/etc/modprobe.conf</filename>.<footnote><para>If such a file exists. Note that the acual behavoir might be
distribution dependant. If you're interested in the details,read the man pages that came with module-init-tools,
and see for yourself what's really going on. You could use something like <command> strace modprobe dummy </command>
to find out how dummy.ko gets loaded. FYI: The dummy.ko I'm talking about here is part of the mainline kernel
and can be found in the networking section. It needs to be compiled as a module (and installed, of course) for this to
work. </para></footnote>
If it finds an alias line like:</para>
<screen>
alias char-major-10-30 softdog
</screen>
<para>it knows that the generic identifier refers to the module <filename>softdog.o</filename>.</para>
<para>it knows that the generic identifier refers to the module <filename>softdog.ko</filename>.</para>
<para>Next, modprobe looks through the file <filename>/lib/modules/version/modules.dep</filename>, to see if other modules
must be loaded before the requested module may be loaded. This file is created by <command>depmod -a</command> and contains
module dependencies. For example, <filename>msdos.o</filename> requires the <filename>fat.o</filename> module to be already
loaded into the kernel. The requested module has a dependancy on another module if the other module defines symbols
(variables or functions) that the requested module uses.</para>
must be loaded before the requested module may be loaded. This file is created by <command>depmod -a</command> and
contains module dependencies. For example, <filename>msdos.ko</filename> requires the <filename>fat.ko</filename> module
to be already loaded into the kernel. The requested module has a dependancy on another module if the other module defines
symbols (variables or functions) that the requested module uses.</para>
<para>Lastly, modprobe uses insmod to first load any prerequisite modules into the kernel, and then the requested module.
modprobe directs insmod to <filename role="directory">/lib/modules/version/</filename><footnote><para>If you are modifying the
kernel, to avoid overwriting your existing modules you may want to use the <varname>EXTRAVERSION</varname> variable in the
kernel Makefile to create a seperate directory.</para></footnote>, the standard directory for modules. insmod is intended to
be fairly dumb about the location of modules, whereas modprobe is aware of the default location of modules. So for example,
if you wanted to load the msdos module, you'd have to either run:</para>
modprobe directs insmod to <filename role="directory">/lib/modules/version/</filename><footnote><para>If you are modifying
the kernel, to avoid overwriting your existing modules you may want to use the <varname>EXTRAVERSION</varname> variable in
the kernel Makefile to create a seperate directory.</para></footnote>, the standard directory for modules. insmod is
intended to be fairly dumb about the location of modules, whereas modprobe is aware of the default location of modules,
knows how to figure out the dependancies and load the modules in the right order.
So for example, if you wanted to load the msdos module, you'd have to either run:</para>
<screen>
insmod /lib/modules/2.5.1/kernel/fs/fat/fat.o
insmod /lib/modules/2.5.1/kernel/fs/msdos/msdos.o
insmod /lib/modules/2.6.11/kernel/fs/fat/fat.ko
insmod /lib/modules/2.6.11/kernel/fs/msdos/msdos.ko
</screen>
<para>or just run "<command>modprobe -a msdos</command>".</para>
<indexterm><primary>modules.conf</primary><secondary>keep</secondary></indexterm>
<indexterm><primary>modules.conf</primary><secondary>comment</secondary></indexterm>
<indexterm><primary>modules.conf</primary><secondary>alias</secondary></indexterm>
<indexterm><primary>modules.conf</primary><secondary>options</secondary></indexterm>
<indexterm><primary>modules.conf</primary><secondary>path</secondary></indexterm>
<para>Linux distros provide modprobe, insmod and depmod as a package called modutils or mod-utils.</para>
<para>Before finishing this chapter, let's take a quick look at a piece of <filename>/etc/modules.conf</filename>:</para>
<para> or: </para>
<screen>
#This file is automatically generated by update-modules
path[misc]=/lib/modules/2.4.?/local
keep
path[net]=~p/mymodules
options mydriver irq=10
alias eth0 eepro
modprobe msdos
</screen>
<para>Lines beginning with a '#' are comments. Blank lines are ignored.</para>
<para> What we've seen here is: <command> insmod </command> requires you to pass it full pathname and to insert the modules
in the right order, while <command> modprobe </command> just takes the name, without any extension, and figures out
all it needs to know by parsing <filename>/lib/modules/version/modules.dep</filename>.
<para>The <literal>path[misc]</literal> line tells modprobe to replace the search path for misc modules with the directory
<filename role="directory">/lib/modules/2.4.?/local</filename>. As you can see, shell meta characters are honored.</para>
<para>The <literal>path[net]</literal> line tells modprobe to look for net modules in the directory <filename
role="directory">~p/mymodules</filename>, however, the "keep" directive preceding the <literal>path[net]</literal> directive
tells modprobe to add this directory to the standard search path of net modules as opposed to replacing the standard search
path, as we did for the misc modules.</para>
<para>The alias line says to load in <filename>eepro.o</filename> whenever kmod requests that the generic identifier `eth0' be
loaded.</para>
<para>You won't see lines like "alias block-major-2 floppy" in <filename>/etc/modules.conf</filename> because modprobe already
knows about the standard drivers which will be used on most systems.</para>
<para>Linux distros provide modprobe, insmod and depmod as a package called module-init-tools. In previous versions
that package was called modutils. Some distros also set up some wrappers that allow both packages to be installed
parallel and do the right thing in order to be able to deal with 2.4 and 2.6 kernels. Users should not need to care
about the details, as long as they're running recent versions of that tools.</para>
<para>Now you know how modules get into the kernel. There's a bit more to the story if you want to write your own modules
which depend on other modules (we calling this `stacking modules'). But this will have to wait for a future chapter. We have
a lot to cover before addressing this relatively high-level issue.</para>
which depend on other modules (we calling this `stacking modules'). But this will have to wait for a future chapter.
We have a lot to cover before addressing this relatively high-level issue.</para>

View File

@ -72,51 +72,91 @@
<indexterm><primary>insmod</primary></indexterm>
<para>Kernel modules need to be compiled with certain gcc options to make them work. In addition, they also need to be
compiled with certain symbols defined. Former kernel versions required us to care much about these settings,
which are usually stored in Makefiles. Although hierarchically organized, many redundant settings accumulated in
sublevel Makefiles and made them large and rather difficult to maintain.
<para>Kernel modules need to be compiled a bit different than regular userspace apps. Former kernel versions required us
to care much about these settings, which are usually stored in Makefiles. Although hierarchically organized, many redundant
settings accumulated in sublevel Makefiles and made them large and rather difficult to maintain.
Fortunately, there is a new way of doing these things, called kbuild, and the build process for external loadable modules is now
fully integrated into the standard kernel build mechanism. To learn more on how to compile modules which are not part of the
official kernel (as ours), see file <filename>linux/Documentation/kbuild/modules.txt</filename>.</para>
Fortunately, there is a new way of doing these things, called kbuild, and the build process for external loadable modules
is now fully integrated into the standard kernel build mechanism. To learn more on how to compile modules which are not
part of the official kernel (such as all the examples you'll find in this guide), see file
<filename>linux/Documentation/kbuild/modules.txt</filename>.</para>
<para>So, let's look at a simple Makefile for compiling a module named <filename>hello-1.c</filename>:</para>
<example><title>Makefile for a basic kernel module</title><programlisting><inlinegraphic fileref="lkmpg-examples/02-HelloWorld/Makefile.1" format="linespecific"/></inlinegraphic></programlisting></example>
<para>Now you can compile the module by issuing the command <command> make -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules </command>.
<para>From a technical point of view just the first line is really necessary,
the "all" and "clean" targets were added for pure convenience.</para>
<para>Now you can compile the module by issuing the command <command> make </command>.
You should obtain an output which resembles the following:</para>
<screen>
[root@pcsenonsrv test_module]# make -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules
make: Entering directory `/usr/src/linux-2.6.x
CC [M] /root/test_module/hello-1.o
Building modules, stage 2.
hostname:~/lkmpg-examples/02-HelloWorld# make
make -C /lib/modules/2.6.11/build M=/root/lkmpg-examples/02-HelloWorld modules
make[1]: Entering directory `/usr/src/linux-2.6.11'
CC [M] /root/lkmpg-examples/02-HelloWorld/hello-1.o
Building modules, stage 2.
MODPOST
CC /root/test_module/hello-1.mod.o
LD [M] /root/test_module/hello-1.ko
make: Leaving directory `/usr/src/linux-2.6.x
CC /root/lkmpg-examples/02-HelloWorld/hello-1.mod.o
LD [M] /root/lkmpg-examples/02-HelloWorld/hello-1.ko
make[1]: Leaving directory `/usr/src/linux-2.6.11'
hostname:~/lkmpg-examples/02-HelloWorld#
</screen>
<para>Please note that kernel 2.6 introduces a new file naming convention: kernel modules now have a <filename>.ko</filename>
extension (in place of the old <filename>.o</filename> extension) which easily distinguishes them from conventional object files.
Additional details about Makefiles for kernel modules are available in <filename>linux/Documentation/kbuild/makefiles.txt</filename>.
Be sure to read this and the related files before starting to dig into Makefiles.</para>
<para>Note that kernel 2.6 introduces a new file naming convention: kernel modules now have a <filename>.ko</filename>
extension (in place of the old <filename>.o</filename> extension) which easily distinguishes them from conventional object
files. The reason for this is that they contain an additional .modinfo section that where additional information about the
module is kept. We'll soon see what this information is good for. </para>
<para> Use <command> modinfo hello-*.ko </command> to see what kind of information it is. </para>
<screen>
hostname:~/lkmpg-examples/02-HelloWorld# modinfo hello-1.ko
filename: hello-1.ko
vermagic: 2.6.11 preempt PENTIUMII 4KSTACKS gcc-3.3
depends:
</screen>
<para> Nothing spectacular, so far. That changes once we're using modinfo on one of our the later examples,
<filename> hello-5.ko </filename>. </para>
<screen>
hostname:~/lkmpg-examples/02-HelloWorld# modinfo hello-5.ko
filename: hello-5.ko
license: GPL
author: Peter Jay Salzman
vermagic: 2.6.11 preempt PENTIUMII 4KSTACKS gcc-3.3
depends:
parm: myintArray:An array of integers (array of int)
parm: mystring:A character string (charp)
parm: mylong:A long integer (long)
parm: myint:An integer (int)
parm: myshort:A short integer (short)
hostname:~/lkmpg-examples/02-HelloWorld#
</screen>
<para> Lot's of useful information to see here. An author string for bugreports,
license information, even a short description of the parameters it accepts. </para>
<para> Additional details about Makefiles for kernel modules are available in
<filename>linux/Documentation/kbuild/makefiles.txt</filename>.
Be sure to read this and the related files before starting to hacking Makefiles.
It'll probably save you lots of work. </para>
<para>Now it is time to insert your freshly-compiled module it into the kernel with <command>insmod ./hello-1.ko</command>
(ignore anything you see about tainted kernels; we'll cover that shortly).</para>
<para>
All modules
loaded into the kernel are listed in <filename>/proc/modules</filename>. Go ahead and cat that file to see that your module
is really a part of the kernel. Congratulations, you are now the author of Linux kernel code! When the novelty wares off,
All modules loaded into the kernel are listed in <filename>/proc/modules</filename>.
Go ahead and cat that file to see that your module is really a part of the kernel.
Congratulations, you are now the author of Linux kernel code! When the novelty wares off,
remove your module from the kernel by using <command>rmmod hello-1</command>. Take a look at
<filename>/var/log/messages</filename> just to see that it got logged to your system logfile.</para>
<para>Here's another exercise to the reader. See that comment above the return statement in
<function>init_module()</function>? Change the return value to something non-zero, recompile and load the module again. What
happens?</para>
<function>init_module()</function>? Change the return value to something non-zero, recompile and load the module again.
What happens?</para>
</sect1>
@ -129,8 +169,8 @@ make: Leaving directory `/usr/src/linux-2.6.x
<para>As of Linux 2.4, you can rename the init and cleanup functions of your modules; they no longer have to be called
<function>init_module()</function> and <function>cleanup_module()</function> respectively. This is done with the
<function>module_init()</function> and <function>module_exit()</function> macros. These macros are defined in <filename
role="header">linux/init.h</filename>. The only caveat is that your init and cleanup functions must be defined before calling
the macros, otherwise you'll get compilation errors. Here's an example of this technique:</para>
role="header">linux/init.h</filename>. The only caveat is that your init and cleanup functions must be defined before
calling the macros, otherwise you'll get compilation errors. Here's an example of this technique:</para>
<indexterm><primary>source file</primary><secondary>hello-2.c</secondary></indexterm>
@ -191,23 +231,21 @@ make: Leaving directory `/usr/src/linux-2.6.x
<sect1><title>Hello World (part 4): Licensing and Module Documentation</title>
<para>If you're running kernel 2.4 or later, you might have noticed something like this when you loaded the previous example
modules:</para>
<para>If you're running kernel 2.4 or later, you might have noticed something like this when you loaded proprietary modules:</para>
<screen>
# insmod hello-3.o
Warning: loading hello-3.o will taint the kernel: no license
# insmod xxxxxx.o
Warning: loading xxxxxx.ko will taint the kernel: no license
See http://www.tux.org/lkml/#export-tainted for information about tainted modules
Hello, world 3
Module hello-3 loaded, with warnings
Module xxxxxx loaded, with warnings
</screen>
<indexterm><primary><function>MODULE_LICENSE()</function></primary></indexterm>
<para>In kernel 2.4 and later, a mechanism was devised to identify code licensed under the GPL (and friends) so people can be
warned that the code is non open-source. This is accomplished by the <function>MODULE_LICENSE()</function> macro which is
demonstrated in the next piece of code. By setting the license to GPL, you can keep the warning from being printed. This
license mechanism is defined and documented in <filename role="headerfile">linux/module.h</filename>:
<para>In kernel 2.4 and later, a mechanism was devised to identify code licensed under the GPL (and friends) so people can
be warned that the code is non open-source. This is accomplished by the <function>MODULE_LICENSE()</function> macro which
is demonstrated in the next piece of code. By setting the license to GPL, you can keep the warning from being printed.
This license mechanism is defined and documented in <filename role="headerfile">linux/module.h</filename>:
<screen>
/*
@ -248,10 +286,20 @@ Module hello-3 loaded, with warnings
declares what types of devices the module supports.</para>
<para>These macros are all defined in <filename role="headerfile">linux/module.h</filename> and aren't used by the kernel
itself. They're simply for documentation and can be viewed by a tool like <application>objdump</application>. As an exercise
to the reader, try grepping through <filename role="directory">linux/drivers</filename> to see how module authors use these
macros to document their modules.</para>
itself. They're simply for documentation and can be viewed by a tool like <application>objdump</application>.
As an exercise to the reader, try and search for this macros in <filename role="directory">linux/drivers</filename>
to see how module authors use these macros to document their modules.</para>
<para> I'd recommend to use something like <command> grep -inr MODULE_AUTHOR * </command> in
<filename> /usr/src/linux-2.6.x/ </filename>. People unfamiliar with command line tools will probably like
some web base solution, search for sites that offer kernel trees that got indexed with LXR. (or setup it up on your
local machine).</para>
<para> Users of traditional Unix editors, like <command> emacs </command> or <command> vi </command> will also find
tag files useful. They can be generated by <command> make tags </command> or <command> make TAGS </command> in
<filename> /usr/src/linux-2.6.x/ </filename>. Once you've got such a tagfile in your kerneltree you can put the cursor
on some function call and use some key combination to directly jump to the definition function. </para>
<indexterm><primary>source file</primary><secondary>hello-4.c</secondary></indexterm>
@ -271,9 +319,9 @@ Module hello-3 loaded, with warnings
<para>To allow arguments to be passed to your module, declare the variables that will take the values of the command line
arguments as global and then use the <functioN>MODULE_PARM()</function> macro, (defined in <filename
role="headerfile">linux/module.h</filename>) to set the mechanism up. At runtime, insmod will fill the variables with any
command line arguments that are given, like <command>./insmod mymodule.o myvariable=5</command>. The variable declarations
and macros should be placed at the beginning of the module for clarity. The example code should clear up my admittedly lousy
explanation.</para>
command line arguments that are given, like <command>./insmod mymodule.ko myvariable=5</command>. The variable
declarations and macros should be placed at the beginning of the module for clarity. The example code should clear up my
admittedly lousy explanation.</para>
<para>The <function>MODULE_PARM()</function> macro takes 2 arguments: the name of the variable and its type. The supported
variable types are "<literal>b</literal>": single byte, "<literal>h</literal>": short int, "<literal>i</literal>": integer,
@ -314,7 +362,7 @@ MODULE_PARM (myintArray, "3-9i");
<para>I would recommend playing around with this code:</para>
<screen>
satan# insmod hello-5.o mystring="bebop" mybyte=255 myintArray=-1
satan# insmod hello-5.ko mystring="bebop" mybyte=255 myintArray=-1
mybyte is an 8 bit integer: 255
myshort is a short integer: 1
myint is an integer: 20
@ -325,7 +373,7 @@ myintArray is -1 and 420
satan# rmmod hello-5
Goodbye, world 5
satan# insmod hello-5.o mystring="supercalifragilisticexpialidocious" \
satan# insmod hello-5.ko mystring="supercalifragilisticexpialidocious" \
> mybyte=256 myintArray=-1,-1
mybyte is an 8 bit integer: 0
myshort is a short integer: 1
@ -337,7 +385,7 @@ myintArray is -1 and -1
satan# rmmod hello-5
Goodbye, world 5
satan# insmod hello-5.o mylong=hello
satan# insmod hello-5.ko mylong=hello
hello-5.o: invalid argument syntax for mylong: 'h'
</screen>
@ -350,31 +398,8 @@ hello-5.o: invalid argument syntax for mylong: 'h'
<sect1><title>Modules Spanning Multiple Files</title>
<indexterm><primary>source files</primary><secondary>multiple</secondary></indexterm>
<indexterm><primary>__NO_VERSION__</primary></indexterm>
<indexterm><primary>module.h</primary></indexterm>
<indexterm><primary>version.h</primary></indexterm>
<indexterm><primary>kernel\_version</primary></indexterm>
<indexterm><primary>ld</primary></indexterm>
<indexterm><primary>elf_i386</primary></indexterm>
<para>Sometimes it makes sense to divide a kernel module between several source files. In this case, you need to:</para>
<orderedlist>
<listitem><para>In all the source files but one, add the line <command>#define __NO_VERSION__</command>. This is important
because <filename role="headerfile">module.h</filename> normally includes the definition of
<varname>kernel_version</varname>, a global variable with the kernel version the module is compiled for. If you need
<filename role="headerfile">version.h</filename>, you need to include it yourself, because <filename
role="headerfile">module.h</filename> won't do it for you with <varname>__NO_VERSION__</varname>.</para></listitem>
<listitem><para>Compile all the source files as usual.</para></listitem>
<listitem><para>Combine all the object files into a single one. Under x86, use <command>ld -m elf_i386 -r -o &lt;module
name.o&gt; &lt;1st src file.o&gt; &lt;2nd src file.o&gt;</command>.</para></listitem>
</orderedlist>
<para>The makefile will, once again, save us from having to get our hands dirty with compiling and linking the object files.</para>
<para>Sometimes it makes sense to divide a kernel module between several source files.</para>
<para>Here's an example of such a kernel module.</para>
@ -393,6 +418,10 @@ hello-5.o: invalid argument syntax for mylong: 'h'
<example><title>Makefile</title><programlisting><inlinegraphic fileref="lkmpg-examples/02-HelloWorld/Makefile" format="linespecific"/></inlinegraphic></programlisting></example>
<para>This is the complete makefile for all the examples we've seen so far. The first five lines are nothing special,
but for the last example we'll need two lines. First we invent an object name for our combined module, second we tell
<command> make </command> what object files are part of that module. </para>
</sect1>
<sect1><title>Building modules for a precompiled kernel</title>
@ -518,3 +547,4 @@ CC scripts/empty.o
<!--
vim: tw=128
-->

View File

@ -240,6 +240,14 @@ int register_chrdev(unsigned int major, const char *name, struct file_operations
use LKMPG version 2.4.x for kernels 2.4.x, use LKMPG version 2.6.x for kernels 2.6.x and so on.
Also make sure that you always use current, up to date versions of both, kernel and guide.
</para>
<para> Update: What we've said above was true for kernels up to and including 2.6.10. You might already
have noticed that recent kernels look different. In case you haven't they look like 2.6.x.y now.
The meaning of the first three items basically stays the same, but a subpatchlevel has been added and will
indicate security fixes till the next stable patchlevel is out. So people can choose between a stable
tree with security updates <emphasis> and </emphasis> use the latest kernel as developer tree.
Search the kernel mailing list archives if you're interested in the full story.
</para>
</sect2>

View File

@ -3,23 +3,25 @@
<indexterm><primary><filename role=directory>/proc</filename> filesystem</primary></indexterm>
<indexterm><primary>filesystem</primary><secondary><filename role=directory>/proc</filename></secondary></indexterm>
<para>In Linux there is an additional mechanism for the kernel and kernel modules to send information to processes --- the
<para>
In Linux, there is an additional mechanism for the kernel and kernel modules to send information to processes --- the
<filename role="directory">/proc</filename> file system. Originally designed to allow easy access to information about
processes (hence the name), it is now used by every bit of the kernel which has something interesting to report, such as
<filename>/proc/modules</filename> which has the list of modules and <filename>/proc/meminfo</filename> which has memory usage
statistics.</para>
<filename>/proc/modules</filename> which provides the list of modules and <filename>/proc/meminfo</filename>
which stats memory usage statistics.
</para>
<indexterm><primary><filename>/proc/modules</filename></primary></indexterm>
<indexterm><primary><filename>/proc/meminfo</filename></primary></indexterm>
<para>The method to use the proc file system is very similar to the one used with device drivers --- you create a structure
<para>The method to use the proc file system is very similar to the one used with device drivers --- a structure is created
with all the information needed for the <filename role="directory">/proc</filename> file, including pointers to any handler
functions (in our case there is only one, the one called when somebody attempts to read from the <filename
role="directory">/proc</filename> file). Then, <function>init_module</function> registers the structure with the kernel and
<function>cleanup_module</function> unregisters it.</para>
<para>The reason we use <function>proc_register_dynamic</function><footnote><para>In version 2.0, in version 2.2 this is done
for us automatically if we set the inode to zero.</para></footnote> is because we don't want to determine the inode number
automatically if we set the inode to zero.</para></footnote> is because we don't want to determine the inode number
used for our file in advance, but to allow the kernel to determine it to prevent clashes. Normal file systems are located on a
disk, rather than just in memory (which is where <filename role="directory">/proc</filename> is), and in that case the inode
number is a pointer to a disk location where the file's index-node (inode for short) is located. The inode contains
@ -30,19 +32,160 @@
<indexterm><primary><function>proc_register</function></primary></indexterm>
<indexterm><primary>inode</primary></indexterm>
<para>Because we don't get called when the file is opened or closed, there's no where for us to put
<varname>try_module_get</varname> and <varname>try_module_put</varname> in this module, and if the file is opened and
then the module is removed, there's no way to avoid the consequences. In the next chapter we'll see a harder to implement, but
more flexible, way of dealing with <filename role="directory">/proc</filename> files which will allow us to protect against
this problem as well.</para>
<para>
Because we don't get called when the file is opened or closed, there's nowhere for us to put
<varname>try_module_get</varname> and <varname>try_module_put</varname> in this module, and if
the file is opened and then the module is removed, there's no way to avoid the consequences.
</para>
<para>
Here a simple example showing how to use a /proc file. This is the HelloWorld for the /proc filesystem.
There are three parts: create the file <filename>/proc/helloworld</filename> in the function <function>init_module</function>,
return a value (and a buffer) when the file <filename>/proc/helloworld</filename> is read in the callback
function <function>procfs_read</function>, and delete the file <filename>/proc/helloworld</filename>
in the function <function>cleanup_module</function>.
</para>
<para>
The <filename>/proc/helloworld</filename> is created when the module is loaded with the function
<function>create_proc_entry</function>. The return value is a 'struct proc_dir_entry *', and it
will be used to configure the file <filename>/proc/helloworld</filename> (for example, the owner of this file).
A null return value means that the creation has failed.
</para>
<para>
Each time, everytime the file <filename>/proc/helloworld</filename> is read, the function
<function>procfs_read</function> is called.
Two parameters of this function are very important: the buffer (the first parameter) and the offset (the third one).
The content of the buffer will be returned to the application which read it (for example the cat command). The offset
is the current position in the file. If the return value of the function isn't null, then this function is
called again. So be careful with this function, if it never returns zero, the read function is called endlessly.
</para>
<screen>
% cat /proc/helloworld
HelloWorld!
</screen>
<example><title>procfs.c</title><programlisting><inlinegraphic fileref="lkmpg-examples/05-TheProcFileSystem/procfs.c" format="linespecific"/></inlinegraphic></programlisting></example>
<example>
<title>procfs1.c</title>
<programlisting>
<inlinegraphic fileref="lkmpg-examples/05-TheProcFileSystem/procfs1.c" format="linespecific"/></inlinegraphic>
</programlisting>
</example>
</sect1>
<sect1><title>Read and Write a /proc File</title>
<para>
We have seen a very simple example for a /proc file where we only read the file <filename>/proc/helloworld</filename>.
It's also possible to write in a /proc file. It works the same way as read, a function is called when the /proc
file is written. But there is a little difference with read, data comes from user, so you have to import data from
user space to kernel space (with <function>copy_from_user</function> or <function>get_user</function>)
</para>
<indexterm><primary><function>get_user</function></primary></indexterm>
<indexterm><primary><function>put_user</function></primary></indexterm>
<indexterm><primary><function>copy_from_user</function></primary></indexterm>
<indexterm><primary><function>copy_to_user</function></primary></indexterm>
<indexterm><primary>memory segments</primary></indexterm>
<indexterm><primary>segment</primary><secondary>memory</secondary></indexterm>
<para>
The reason for <function>copy_from_user</function> or <function>get_user</function> is that Linux memory (on Intel
architecture, it may be different under some other processors) is segmented. This means that a pointer, by itself,
does not reference a unique location in memory, only a location in a memory segment, and you need to know which
memory segment it is to be able to use it. There is one memory segment for the kernel, and one for each of the processes.
</para>
<para>
The only memory segment accessible to a process is its own, so when writing regular programs to run as processes,
there's no need to worry about segments. When you write a kernel module, normally you want to access the kernel memory
segment, which is handled automatically by the system. However, when the content of a memory buffer needs to be passed between
the currently running process and the kernel, the kernel function receives a pointer to the memory buffer which is in the
process segment. The <function>put_user</function> and <function>get_user</function> macros allow you to access that
memory. These functions handle only one caracter, you can handle several caracters with <function>copy_to_user</function> and
<function>copy_from_user</function>. As the buffer (in read or write function) is in kernel space, for write function
you need to import data because it comes from user space, but not for the read function because data is already
in kernel space.
</para>
<indexterm><primary>read</primary><secondary>in the kernel</secondary></indexterm>
<indexterm><primary>write</primary><secondary>in the kernel</secondary></indexterm>
<example>
<title>procfs2.c</title>
<programlisting>
<inlinegraphic fileref="lkmpg-examples/05-TheProcFileSystem/procfs2.c" format="linespecific"/></inlinegraphic>
</programlisting>
</example>
</sect1>
<sect1><title>Manage /proc file with standard filesystem</title>
<para>
We have seen how to read and write a /proc file with the /proc interface. But it's also possible
to manage /proc file with inodes. The main interest is to use advanced function, like permissions.
</para>
<para>
In Linux, there is a standard mechanism for file system registration. Since every file system has to have its own
functions to handle inode and file operations<footnote><para>The difference between the two is that file operations deal with
the file itself, and inode operations deal with ways of referencing the file, such as creating links to it.</para></footnote>,
there is a special structure to hold pointers to all those functions, <varname>struct inode_operations</varname>, which
includes a pointer to <varname>struct file_operations</varname>. In /proc, whenever we register a new file, we're allowed to
specify which <varname>struct inode_operations</varname> will be used to access to it. This is the mechanism we use, a
<varname>struct inode_operations</varname> which includes a pointer to a <varname>struct file_operations</varname> which
includes pointers to our <function>procfs_read</function> and <function>procfs_write</function> functions.
</para>
<indexterm><primary>filesystem</primary><secondary>registration</secondary></indexterm>
<indexterm><primary>filesystem registration</primary></indexterm>
<indexterm><primary><varname>struct inode_operations</varname></primary></indexterm>
<indexterm><primary><varname>inode_operations</varname> structure</primary></indexterm>
<indexterm><primary><varname>struct file_operations</varname></primary></indexterm>
<indexterm><primary><varname>file_operations</varname> structure</primary></indexterm>
<para>
Another interesting point here is the <function>module_permission</function> function. This function is called whenever
a process tries to do something with the <filename role="directory">/proc</filename> file, and it can decide whether to allow
access or not. Right now it is only based on the operation and the uid of the current user (as available in
<varname>current</varname>, a pointer to a structure which includes information on the currently running process), but it
could be based on anything we like, such as what other processes are doing with the same file, the time of day, or the last
input we received.</para>
<indexterm><primary>pointer</primary><secondary>current</secondary></indexterm>
<indexterm><primary>permission</primary></indexterm>
<indexterm><primary><varname>module_permissions</varname></primary></indexterm>
<para>
It's important to note that the standard roles of read and write are reversed in the kernel. Read functions are used for
output, whereas write functions are used for input. The reason for that is that read and write refer to the user's point of
view --- if a process reads something from the kernel, then the kernel needs to output it, and if a process writes something
to the kernel, then the kernel receives it as input.
</para>
<example>
<title>procfs3.c</title>
<programlisting>
<inlinegraphic fileref="lkmpg-examples/05-TheProcFileSystem/procfs3.c" format="linespecific"/></inlinegraphic>
</programlisting>
</example>
<para>
Still hungry for procfs examples? Well, first of all keep in mind, there are rumors around, claiming
that procfs is on it's way out, consider using sysfs instead. Second, if you really can't get enough,
there's a highly recommendable bonus level for procfs below <filename> linux/Documentation/DocBook/ </filename>.
Use <command> make help </command> in your toplevel kernel directory for instructions about how to convert it into
your favourite format. Example: <command> make htmldocs </command>. Consider using this mechanism,
in case you want to document something kernel related yourself.
</para>
</sect1>
<!--
vim:textwidth=128

View File

@ -1,82 +1,10 @@
<sect1><title>Using /proc For Input</title>
<indexterm><primary>input</primary><secondary>using /proc for</secondary></indexterm>
<indexterm><primary>proc</primary><secondary>using for input</secondary></indexterm>
<para>So far we have two ways to generate output from kernel modules: we can register a device driver and
<command>mknod</command> a device file, or we can create a <filename role="directory">/proc</filename> file. This allows the
kernel module to tell us anything it likes. The only problem is that there is no way for us to talk back. The first way we'll
send input to kernel modules will be by writing back to the <filename role="directory">/proc</filename> file.</para>
<para>Because the proc filesystem was written mainly to allow the kernel to report its situation to processes, there are no
special provisions for input. The <varname>struct proc_dir_entry</varname> doesn't include a pointer to an input function,
the way it includes a pointer to an output function. Instead, to write into a <filename role="directory">/proc</filename>
file, we need to use the standard filesystem mechanism.</para>
<indexterm><primary><varname>proc_dir_entry</varname></primary></indexterm>
<para>In Linux there is a standard mechanism for file system registration. Since every file system has to have its own
functions to handle inode and file operations<footnote><para>The difference between the two is that file operations deal with
the file itself, and inode operations deal with ways of referencing the file, such as creating links to it.</para></footnote>,
there is a special structure to hold pointers to all those functions, <varname>struct inode_operations</varname>, which
includes a pointer to <varname>struct file_operations</varname>. In /proc, whenever we register a new file, we're allowed to
specify which <varname>struct inode_operations</varname> will be used for access to it. This is the mechanism we use, a
<varname>struct inode_operations</varname> which includes a pointer to a <varname>struct file_operations</varname> which
includes pointers to our <function>module_input</function> and <function>module_output</function> functions.</para>
<indexterm><primary>filesystem</primary><secondary>registration</secondary></indexterm>
<indexterm><primary>filesystem registration</primary></indexterm>
<indexterm><primary><varname>struct inode_operations</varname></primary></indexterm>
<indexterm><primary><varname>inode_operations</varname> structure</primary></indexterm>
<indexterm><primary><varname>struct file_operations</varname></primary></indexterm>
<indexterm><primary><varname>file_operations</varname> structure</primary></indexterm>
<para>It's important to note that the standard roles of read and write are reversed in the kernel. Read functions are used for
output, whereas write functions are used for input. The reason for that is that read and write refer to the user's point of
view --- if a process reads something from the kernel, then the kernel needs to output it, and if a process writes something
to the kernel, then the kernel receives it as input.</para>
<indexterm><primary>read</primary><secondary>in the kernel</secondary></indexterm>
<indexterm><primary>write</primary><secondary>in the kernel</secondary></indexterm>
<para>Another interesting point here is the <function>module_permission</function> function. This function is called whenever
a process tries to do something with the <filename role="directory">/proc</filename> file, and it can decide whether to allow
access or not. Right now it is only based on the operation and the uid of the current user (as available in
<varname>current</varname>, a pointer to a structure which includes information on the currently running process), but it
could be based on anything we like, such as what other processes are doing with the same file, the time of day, or the last
input we received.</para>
<indexterm><primary>pointer</primary><secondary>current</secondary></indexterm>
<indexterm><primary>permission</primary></indexterm>
<indexterm><primary><varname>module_permissions</varname></primary></indexterm>
<para>The reason for <function>put_user</function> and <function>get_user</function> is that Linux memory (under Intel
architecture, it may be different under some other processors) is segmented. This means that a pointer, by itself, does not
reference a unique location in memory, only a location in a memory segment, and you need to know which memory segment it is to
be able to use it. There is one memory segment for the kernel, and one of each of the processes.</para>
<indexterm><primary><function>put_user</function></primary></indexterm>
<indexterm><primary><function>get_user</function></primary></indexterm>
<indexterm><primary>memory segments</primary></indexterm>
<indexterm><primary>segment</primary><secondary>memory</secondary></indexterm>
<para>The only memory segment accessible to a process is its own, so when writing regular programs to run as processes,
there's no need to worry about segments. When you write a kernel module, normally you want to access the kernel memory
segment, which is handled automatically by the system. However, when the content of a memory buffer needs to be passed between
the currently running process and the kernel, the kernel function receives a pointer to the memory buffer which is in the
process segment. The <function>put_user</function> and <function>get_user</function> macros allow you to access that
memory.</para>
<example><title>procfs.c</title><programlisting><inlinegraphic fileref="lkmpg-examples/06-UsingProcForInput/procfs.c" format="linespecific"/></inlinegraphic></programlisting></example>
<para> Still hungry for procfs examples? Well, first of all keep in mind, there are rumors around, claiming
that procfs is on it's way out, consider using sysfs instead. Second, if you really can't get enough,
there's a highly recommendable bonus level for procfs below <filename> linux/Documentation/DocBook/ </filename>.
Use <command> make help </command> in your toplevel kernel directory for instructions about how to convert it into
your favourite format. Example: <command> make htmldocs </command>. Consider using this mechanism,
in case you want to document something kernel related yourself.</para>
<sect1><title>TODO: Write a chapter about sysfs</title>
<para> This is just a placeholder for now. Finally I'd like to see a
(yet to be written) chapter about sysfs instead here. If you are familiar
with sysfs and would like to take part in writing this chapter, feel free to
contact us (the LKMPG maintainers) for further details.
</para>
</sect1>
<!--

View File

@ -1,4 +1,4 @@
<sect1><title>Talking to Device Files (writes and IOCTLs)}</title>
<sect1><title>Talking to Device Files (writes and IOCTLs)</title>
<indexterm><primary>ioctl</primary></indexterm>
<indexterm><primary>device files</primary><secondary>input to</secondary></indexterm>

View File

@ -84,12 +84,15 @@
<para>Note that all the related problems make syscall stealing unfeasiable for production use. In order to keep people from
doing potential harmful things sys_call_table is no longer exported. This means, if you want to do something more than a mere
dry run of this example, you will have to patch your current kernel in order to have sys_call_table exported. In the example
directory you will find a README and the patch. As you can imagine, such modifications are not to be taken lightly. Do not try
this on valueable systems (ie systems that you do not own - or cannot restore easily). It should go O.K., but kernel people,
choose to not support hacks like this in 2.6. and I'm sure they've had their reasons for that. For more details, see the
README. If in doubt, saying N here and skipping this example is the safe choice.</para>
doing potential harmful things sys_call_table is no longer exported. This means, if you want to do something more than a
mere dry run of this example, you will have to patch your current kernel in order to have sys_call_table exported.
In the example directory you will find a README and the patch. As you can imagine, such modifications are not to be
taken lightly. Do not try this on valueable systems (ie systems that you do not own - or cannot restore easily).
You'll need to get the complete sourcecode of this guide as a tarball in order to get the patch and the README.
Depending on your kernel version, you might even need to hand apply the patch. Still here? Well, so is this chapter.
If Wyle E. Coyote was a kernel hacker, this would be the first thing he'd try. ;)
</para>
<indexterm><primary>try_module_get</primary></indexterm>

View File

@ -3,10 +3,6 @@
<indexterm><primary>blocking processes</primary></indexterm>
<indexterm><primary>processes</primary><secondary>blocking</secondary></indexterm>
<sect2><title>Enter Sandman</title>
<para>What do you do when somebody asks you for something you can't do right away? If you're a human being and you're
bothered by a human being, the only thing you can say is: <quote>Not right now, I'm busy. <emphasis>Go
away!</emphasis></quote>. But if you're a kernel module and you're bothered by a process, you have another possibility.
@ -46,6 +42,11 @@
processes that the file is still open and go on with its life. When the other processes get a piece of the CPU, they'll
see that global variable and go back to sleep.</para>
<para> So we'll use <command> tail -f </command> to keep the file open in the background, while
trying to access it with another process (again in the background, so that we need not switch to
a different vt). As soon as the first background process is killed with <command> kill %1 </command>,
the second is woken up, is able to access the file and finally terminates. </para>
<indexterm><primary>signal</primary></indexterm>
<indexterm><primary>SIGINT</primary></indexterm>
<indexterm><primary>module_wake_up</primary></indexterm>
@ -75,13 +76,36 @@
<command>cat_noblock</command>, available in the source directory for this chapter, can be used to open a file with
<parameter>O_NONBLOCK</parameter>.</para>
<screen>
hostname:~/lkmpg-examples/09-BlockingProcesses# insmod sleep.ko
hostname:~/lkmpg-examples/09-BlockingProcesses# cat_noblock /proc/sleep
Last input:
hostname:~/lkmpg-examples/09-BlockingProcesses# tail -f /proc/sleep &
Last input:
Last input:
Last input:
Last input:
Last input:
Last input:
Last input:
tail: /proc/sleep: file truncated
[1] 6540
hostname:~/lkmpg-examples/09-BlockingProcesses# cat_noblock /proc/sleep
Open would block
hostname:~/lkmpg-examples/09-BlockingProcesses# kill %1
[1]+ Terminated tail -f /proc/sleep
hostname:~/lkmpg-examples/09-BlockingProcesses# cat_noblock /proc/sleep
Last input:
hostname:~/lkmpg-examples/09-BlockingProcesses#
</screen>
<indexterm><primary>source file</primary><secondary>sleep.c</secondary></indexterm>
<example><title>sleep.c</title><programlisting><inlinegraphic fileref="lkmpg-examples/09-BlockingProcesses/sleep.c" format="linespecific"/></inlinegraphic></programlisting></example>
<example><title>cat_noblock.c</title><programlisting><inlinegraphic fileref="lkmpg-examples/09-BlockingProcesses/cat_noblock.c" format="linespecific"/></inlinegraphic></programlisting></example>
</sect2>
</sect1>
@ -90,3 +114,4 @@
<!--
vim: tw=128
-->

View File

@ -29,10 +29,10 @@
<sect1><title>Flashing keyboard LEDs</title>
<indexterm><primary>keyboard LEDs</primary><secondary>flashing</secondary></indexterm>
<para>In certain conditions, you may desire for your module a simpler and more direct way to communicate to the external world that he's running.
<para>In certain conditions, you may desire a simpler and more direct way to communicate to the external world.
Flashing keyboard LEDs can be such a solution: It is an immediate way to attract attention or to display a status condition.
Keyboard LEDs are present on every hardware, they are always visible, they do not need any setup, and their use is rather simple and
non-intrusive, if compared to writing to a tty or a file.</para>
non-intrusive, compared to writing to a tty or a file.</para>
<para>
The following source code illustrates a minimal kernel module which, when loaded, starts blinking the keyboard LEDs until it is unloaded.
@ -45,14 +45,14 @@ The following source code illustrates a minimal kernel module which, when loaded
CONFIG_LL_DEBUG in <command> make menuconfig </command> is good for? If you activate that you get low level access to the serial port.
While this might not sound very powerful by itself, you can patch <filename>kernel/printk.c</filename> or any other
essential syscall to use printascii, thus makeing it possible to trace virtually everything what your code does over a
serial line. If your architecture does not support this and is equipped with a serial port, this might be one of the
first things that should be implemented. Logging over a netconsole might also be worth a try.
serial line. If you find yourself porting the kernel to some new and former unsupported architecture this is usually
amongst the first things that should be implemented. Logging over a netconsole might also be worth a try.
</para>
<para>
While you have seen lots of stuff that can be used to aid debugging here, there are some things to be aware of.
Debugging is almost always intrusive. Adding debug code can change the situation enough to make the bug seem to dissappear.
Thus you should try to keep debug code to a minimum and make shure it does not show up in production code.
Thus you should try to keep debug code to a minimum and make sure it does not show up in production code.
</para>
</sect1>

View File

@ -13,15 +13,14 @@
kernel module which is in memory anyway.</para>
<indexterm><primary>task</primary></indexterm>
<indexterm><primary>tq_struct</primary></indexterm>
<indexterm><primary>queue_task</primary></indexterm>
<indexterm><primary>tq_timer</primary></indexterm>
<indexterm><primary>workqueue_struct</primary></indexterm>
<indexterm><primary>queue_delayed_work</primary></indexterm>
<para>Instead of doing that, we can create a function that will be called once for every timer interrupt. The way we do this
is we create a task, held in a <structname>tq_struct</structname> structure, which will hold a pointer to the function. Then,
we use <function>queue_task</function> to put that task on a task list called <structname>tq_timer</structname>, which is the
list of tasks to be executed on the next timer interrupt. Because we want the function to keep on being executed, we need to
put it back on <structname>tq_timer</structname> whenever it is called, for the next timer interrupt.</para>
is we create a task, held in a <structname>workqueue_struct</structname> structure, which will hold a pointer to the function. Then,
we use <function>queue_delayed_work</function> to put that task on a task list called <structname>my_workqueue</structname>,
which is the list of tasks to be executed on the next timer interrupt. Because we want the function to keep on being executed,
we need to put it back on <structname>my_workqueue</structname> whenever it is called, for the next timer interrupt.</para>
<indexterm><primary>rmmod</primary></indexterm>
<indexterm><primary>reference count</primary></indexterm>
@ -29,22 +28,8 @@
<para>There's one more point we need to remember here. When a module is removed by <command>rmmod</command>, first its
reference count is checked. If it is zero, <function>module_cleanup</function> is called. Then, the module is removed from
memory with all its functions. Nobody checks to see if the timer's task list happens to contain a pointer to one of those
functions, which will no longer be available. Ages later (from the computer's perspective, from a human perspective it's
nothing, less than a hundredth of a second), the kernel has a timer interrupt and tries to call the function on the task list.
Unfortunately, the function is no longer there. In most cases, the memory page where it sat is unused, and you get an ugly
error message. But if some other code is now sitting at the same memory location, things could get <emphasis>very</emphasis>
ugly. Unfortunately, we don't have an easy way to unregister a task from a task list.</para>
<indexterm><primary>sleep_on</primary></indexterm>
<indexterm><primary>module_sleep_on</primary></indexterm>
<para>Since <function>cleanup_module</function> can't return with an error code (it's a void function), the solution is to not
let it return at all. Instead, it calls <function>sleep_on</function> or
<function>module_sleep_on</function><footnote><para>They're really the same.</para></footnote> to put the
<command>rmmod</command> process to sleep. Before that, it informs the function called on the timer interrupt to stop
attaching itself by setting a global variable. Then, on the next timer interrupt, the <command>rmmod</command> process will
be woken up, when our function is no longer in the queue and it's safe to remove the module.</para>
memory with all its functions. Things need to be shut down properly, or bad things will happen. See the code below how
this can be done in a safe way. </para>
<indexterm><primary>source file</primary><secondary>sched.c</secondary></indexterm>

View File

@ -42,32 +42,35 @@
<indexterm><primary>SA_INTERRUPT</primary></indexterm>
<indexterm><primary>SA_SHIRQ</primary></indexterm>
<para>The way to implement this is to call <function>request_irq()</function> to get your interrupt handler called when
the relevant IRQ is received (there are 15 of them, plus 1 which is used to cascade the interrupt controllers, on Intel
platforms). This function receives the IRQ number, the name of the function, flags, a name for
<filename>/proc/interrupts</filename> and a parameter to pass to the interrupt handler. The flags can include
<parameter>SA_SHIRQ</parameter> to indicate you're willing to share the IRQ with other interrupt handlers (usually because
a number of hardware devices sit on the same IRQ) and <parameter>SA_INTERRUPT</parameter> to indicate this is a fast
interrupt. This function will only succeed if there isn't already a handler on this IRQ, or if you're both willing to
share.</para>
<para>The way to implement this is to call <function>request_irq()</function> to get your interrupt handler called
when the relevant IRQ is received.
<indexterm><primary>queue_task_irq</primary></indexterm>
<indexterm><primary>tq_immediate</primary></indexterm>
<indexterm><primary>mark_bh</primary></indexterm>
<indexterm><primary>BH_IMMEDIATE</primary></indexterm>
<footnote><para>
In practice IRQ handling can be a bit more complex. Hardware is often designed in a way that chains two interrupt
controllers, so that all the IRQs from interrupt controller B are cascaded to a certain IRQ from
interrupt controller A. Of course that requires that the kernel finds out which IRQ it really was
afterwards and that adds overhead. Other architectures offer some special, very low overhead,
so called "fast IRQ" or FIQs. To take advantage of them requires handlers to be written in assembler,
so they do not really fit into the kernel. They can be made to work similar to the others, but after
that procedure, they're no longer any faster than "common" IRQs. SMP enabled kernels running on systems
with more than one processor need to solve another truckload of problems. It's not enough to know if a certain IRQs
has happend, it's also important for what CPU(s) it was for. People still interested in more details,
might want to do a web search for "APIC" now ;)
</para></footnote>
This function receives the IRQ number, the name of the function, flags, a name for
<filename>/proc/interrupts</filename> and a parameter to pass to the interrupt handler.
Usually there is a certain number of IRQs available. How many IRQs there are is hardware dependant.
The flags can include <parameter>SA_SHIRQ</parameter> to indicate you're willing to share the IRQ with other
interrupt handlers (usually because a number of hardware devices sit on the same IRQ) and
<parameter>SA_INTERRUPT</parameter> to indicate this is a fast interrupt. This function will only succeed if
there isn't already a handler on this IRQ, or if you're both willing to share.</para>
<indexterm><primary>queue_work</primary></indexterm>
<para>Then, from within the interrupt handler, we communicate with the hardware and then use
<function>queue_task_irq()</function> with <function>tq_immediate()</function> and
<function>mark_bh(BH_IMMEDIATE)</function> to schedule the bottom half. The reason we can't use the standard
<function>queue_task</function> <indexterm><primary>queue_task</primary></indexterm> in version 2.0 is that the interrupt
might happen right in the middle of somebody else's
<function>queue_task</function><footnote><para><function>queue_task_irq</function> is protected from this by a global lock
-- in 2.2 there is no <function>queue_task_irq</function> and <function>queue_task</function> is protected by a
lock.</para></footnote>. We need <function>mark_bh</function> because earlier versions of Linux only had an array of 32
bottom halves, and now one of them (<parameter>BH_IMMEDIATE</parameter>) is used for the linked list of bottom halves for
drivers which didn't get a bottom half entry assigned to them.</para>
</sect2>
<function>queue_work()</function> <function>mark_bh(BH_IMMEDIATE)</function> to schedule the bottom half.
</sect2>

View File

@ -1,91 +1,20 @@
<sect1><title>Changes between 2.0 and 2.2</title>
<sect1><title>Changes between 2.4 and 2.6</title>
<indexterm><primary>2.2 changes</primary></indexterm>
<indexterm><primary>2.6 changes</primary></indexterm>
<indexterm><primary>kernel</primary><secondary>versions</secondary></indexterm>
<sect2><title>Changes between 2.4 and 2.6</title>
<sect2><title>Changes between 2.0 and 2.2</title>
<para>I don't know the entire kernel well enough do document all of the changes. In the course of converting the examples
(or actually, adapting Emmanuel Papirakis's changes) I came across the following differences. I listed all of them here
together to help module programmers, especially those who learned from previous versions of this book and are most
familiar with the techniques I use, convert to the new version.</para>
<para>An additional resource for people who wish to convert to 2.2 is located on <ulink
url="http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.2.html"> Richard Gooch's site </ulink>.</para>
<indexterm><primary>asm/uaccess.h</primary></indexterm>
<indexterm><primary>asm</primary><secondary>uaccess.h</secondary></indexterm>
<indexterm><primary>put_user</primary></indexterm>
<indexterm><primary>get_user</primary></indexterm>
<indexterm><primary>structure</primary><secondary>file_operations</secondary></indexterm>
<indexterm><primary>flush</primary></indexterm>
<indexterm><primary>close</primary></indexterm>
<indexterm><primary>read</primary></indexterm>
<indexterm><primary>write</primary></indexterm>
<indexterm><primary>ssize_t</primary></indexterm>
<indexterm><primary>proc_register_dynamic</primary></indexterm>
<indexterm><primary>signals</primary></indexterm>
<indexterm><primary>queue_task_irq</primary></indexterm>
<indexterm><primary>queue_task</primary></indexterm>
<indexterm><primary>interrupts</primary></indexterm>
<indexterm><primary>irqs</primary></indexterm>
<indexterm><primary>module</primary><secondary>parameters</secondary></indexterm>
<indexterm><primary>module parameters</primary></indexterm>
<indexterm><primary>MODULE_PARM</primary></indexterm>
<indexterm><primary>Symmetrical Multi-Processing</primary></indexterm>
<indexterm><primary>SMP</primary></indexterm>
<variablelist>
<varlistentry><term><filename class="headerfile">asm/uaccess.h</filename></term>
<listitem><para>If you need <function>put_user</function> or <function>get_user</function> you have to
<userinput>#include</userinput> it.</para></listitem></varlistentry>
<varlistentry><term><function>get_user</function></term>
<listitem><para>In version 2.2, <function>get_user</function> receives both the pointer into user memory and the
variable in kernel memory to fill with the information. The reason for this is that <function>get_user</function> can
now read two or four bytes at a time if the variable we read is two or four bytes long.</para></listitem></varlistentry>
<varlistentry><term><structname>file_operations</structname></term>
<listitem><para>This structure now has a flush function between the <function>open</function> and
<function>close</function> functions. </para> </listitem> </varlistentry>
<varlistentry><term><function>close</function> in <structname>file_operations</structname></term>
<listitem><para>In version 2.2, the <function>close</function> function returns an integer, so it's allowed to
fail.</para></listitem></varlistentry>
<varlistentry><term><function>read</function>,<function>write</function> in <structname>file_operations</structname></term>
<listitem><para>The headers for these functions changed. They now return <userinput>ssize_t</userinput> instead of an
integer, and their parameter list is different. The inode is no longer a parameter, and on the other hand the offset
into the file is.</para></listitem></varlistentry>
<varlistentry><term><function>proc_register_dynamic</function></term>
<listitem><para>This function no longer exists. Instead, you call the regular <function>proc_register</function>
<indexterm><primary>proc_register</primary></indexterm> and put zero in the inode field of the
structure.</para></listitem></varlistentry>
<varlistentry><term>Signals</term>
<listitem><para>The signals in the task structure are no longer a 32 bit integer, but an array of
<parameter>_NSIG_WORDS</parameter> <indexterm><primary>_NSIG_WORDS</primary></indexterm>
integers.</para></listitem></varlistentry>
<varlistentry><term><function>queue_task_irq</function></term>
<listitem><para>Even if you want to scheduale a task to happen from inside an interrupt handler, you use
<function>queue_task</function>, not <function>queue_task_irq</function>.</para></listitem></varlistentry>
<varlistentry><term>Module Parameters</term>
<listitem><para>You no longer just declare module parameters as global variables. In 2.2 you have to also use
<parameter>MODULE_PARM</parameter> to declare their type. This is a big improvement, because it allows the module to
receive string parameters which start with a digits, for example, without getting
confused.</para></listitem></varlistentry>
<varlistentry><term>Symmetrical Multi-Processing</term>
<listitem><para>The kernel is no longer inside one huge spinlock, which means that kernel modules have to be aware of
<acronym>SMP</acronym>.</para></listitem></varlistentry>
</variablelist>
<para>I don't know the entire kernel well enough to document all of the changes.
Some hints for porting can be found by comparing this version of the LKMPG with it's counterpart for
kernel 2.4. Apart from that, anybody who needs to port drivers from 2.4 to 2.6 kernels might want to visit
<ulink url="http://lwn.net/Articles/driver-porting/"> http://lwn.net/Articles/driver-porting/ </ulink>.
If you still can't find an example that exactly meets your needs there, find a driver that's similar to your driver
and present in both kernel versions. File comparison tools like <command> xxdiff </command> or
<command> meld </command> can be a great help then. Also check if your driver is covered by docs in
<filename> linux/Documentation/ </filename>. Before starting with porting and in case you're stuck it's
a good idea to find an appropiate mailinglist and ask people there for pointers.
</para>
</sect2>

View File

@ -17,6 +17,9 @@
<para>I hope I have helped you in your quest to become a better programmer, or at least to have fun through technology. And,
if you do write useful kernel modules, I hope you publish them under the GPL, so I can use them too.</para>
<para>If you'd like to contribute to this guide, please contact one the maintainers for details. As you've
already seen, there's a placeholder chapter now, waiting to be filled with examples for sysfs. </para>
</sect1>

View File

@ -5,3 +5,9 @@ obj-m += hello-4.o
obj-m += hello-5.o
obj-m += startstop.o
startstop-objs := start.o stop.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

View File

@ -1,2 +1,7 @@
obj-m += hello-1.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

View File

@ -1,2 +1,8 @@
obj-m += hello-1.o
obj-m += hello-2.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

View File

@ -2,11 +2,11 @@
* hello-1.c - The simplest kernel module.
*/
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_ALERT */
#include <linux/kernel.h> /* Needed for KERN_INFO */
int init_module(void)
{
printk("<1>Hello world 1.\n");
printk(KERN_INFO "Hello world 1.\n");
/*
* A non 0 return means init_module failed; module can't be loaded.
@ -16,5 +16,5 @@ int init_module(void)
void cleanup_module(void)
{
printk(KERN_ALERT "Goodbye world 1.\n");
printk(KERN_INFO "Goodbye world 1.\n");
}

View File

@ -3,18 +3,18 @@
* This is preferred over using init_module() and cleanup_module().
*/
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_ALERT */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
static int __init hello_2_init(void)
{
printk(KERN_ALERT "Hello, world 2\n");
printk(KERN_INFO "Hello, world 2\n");
return 0;
}
static void __exit hello_2_exit(void)
{
printk(KERN_ALERT "Goodbye, world 2\n");
printk(KERN_INFO "Goodbye, world 2\n");
}
module_init(hello_2_init);

View File

@ -2,20 +2,20 @@
* hello-3.c - Illustrating the __init, __initdata and __exit macros.
*/
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_ALERT */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
static int hello3_data __initdata = 3;
static int __init hello_3_init(void)
{
printk(KERN_ALERT "Hello, world %d\n", hello3_data);
printk(KERN_INFO "Hello, world %d\n", hello3_data);
return 0;
}
static void __exit hello_3_exit(void)
{
printk(KERN_ALERT "Goodbye, world 3\n");
printk(KERN_INFO "Goodbye, world 3\n");
}
module_init(hello_3_init);

View File

@ -1,21 +1,21 @@
/*
* hello-4.c - Demonstrates module documentation.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#define DRIVER_AUTHOR "Peter Jay Salzman <p@dirac.org>"
#define DRIVER_DESC "A sample driver"
static int __init init_hello_4(void)
{
printk(KERN_ALERT "Hello, world 4\n");
printk(KERN_INFO "Hello, world 4\n");
return 0;
}
static void __exit cleanup_hello_4(void)
{
printk(KERN_ALERT "Goodbye, world 4\n");
printk(KERN_INFO "Goodbye, world 4\n");
}
module_init(init_hello_4);

View File

@ -14,6 +14,8 @@ static short int myshort = 1;
static int myint = 420;
static long int mylong = 9999;
static char *mystring = "blah";
static int myintArray[2] = { -1, -1 };
static int arr_argc = 0;
/*
* module_param(foo, int, 0000)
@ -32,19 +34,36 @@ MODULE_PARM_DESC(mylong, "A long integer");
module_param(mystring, charp, 0000);
MODULE_PARM_DESC(mystring, "A character string");
/*
* module_param_array(name, type, num, perm);
* The first param is the parameter's (in this case the array's) name
* The second param is the data type of the elements of the array
* The third argument is a pointer to the variable that will store the number
* of elements of the array initialized by the user at module loading time
* The fourth argument is the permission bits
*/
module_param_array(myintArray, int, &arr_argc, 0000);
MODULE_PARM_DESC(myintArray, "An array of integers");
static int __init hello_5_init(void)
{
printk(KERN_ALERT "Hello, world 5\n=============\n");
printk(KERN_ALERT "myshort is a short integer: %hd\n", myshort);
printk(KERN_ALERT "myint is an integer: %d\n", myint);
printk(KERN_ALERT "mylong is a long integer: %ld\n", mylong);
printk(KERN_ALERT "mystring is a string: %s\n", mystring);
int i;
printk(KERN_INFO "Hello, world 5\n=============\n");
printk(KERN_INFO "myshort is a short integer: %hd\n", myshort);
printk(KERN_INFO "myint is an integer: %d\n", myint);
printk(KERN_INFO "mylong is a long integer: %ld\n", mylong);
printk(KERN_INFO "mystring is a string: %s\n", mystring);
for (i = 0; i < (sizeof myintArray / sizeof (int)); i++)
{
printk(KERN_INFO "myintArray[%d] = %d\n", i, myintArray[i]);
}
printk(KERN_INFO "got %d arguments for myintArray.\n", arr_argc);
return 0;
}
static void __exit hello_5_exit(void)
{
printk(KERN_ALERT "Goodbye, world 5\n");
printk(KERN_INFO "Goodbye, world 5\n");
}
module_init(hello_5_init);

View File

@ -7,6 +7,6 @@
int init_module(void)
{
printk("Hello, world - this is the kernel speaking\n");
printk(KERN_INFO "Hello, world - this is the kernel speaking\n");
return 0;
}

View File

@ -7,5 +7,5 @@
void cleanup_module()
{
printk("<1>Short is the life of a kernel module\n");
printk(KERN_INFO "Short is the life of a kernel module\n");
}

View File

@ -1 +1,12 @@
#
# This is a sort a recursive Makefile
# This Makefile is used to compile the module
#
obj-m += chardev.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

View File

@ -40,29 +40,30 @@ static struct file_operations fops = {
};
/*
* Functions
* This function is called when the module is loaded
*/
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk("Registering the character device failed with %d\n",
Major);
return Major;
printk(KERN_ALERT "Registering char device failed with %d\n", Major);
return Major;
}
printk("<1>I was assigned major number %d. To talk to\n", Major);
printk("<1>the driver, create a dev file with\n");
printk("'mknod /dev/hello c %d 0'.\n", Major);
printk("<1>Try various minor numbers. Try to cat and echo to\n");
printk("the device file.\n");
printk("<1>Remove the device file and module when done.\n");
printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
printk(KERN_INFO "the driver, create a dev file with\n");
printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
printk(KERN_INFO "the device file.\n");
printk(KERN_INFO "Remove the device file and module when done.\n");
return 0;
return SUCCESS;
}
/*
* This function is called when the module is unloaded
*/
void cleanup_module(void)
{
/*
@ -70,7 +71,7 @@ void cleanup_module(void)
*/
int ret = unregister_chrdev(Major, DEVICE_NAME);
if (ret < 0)
printk("Error in unregister_chrdev: %d\n", ret);
printk(KERN_ALERT "Error in unregister_chrdev: %d\n", ret);
}
/*
@ -84,8 +85,10 @@ void cleanup_module(void)
static int device_open(struct inode *inode, struct file *file)
{
static int counter = 0;
if (Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
@ -160,6 +163,6 @@ static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
static ssize_t
device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk("<1>Sorry, this operation isn't supported.\n");
printk(KERN_ALERT "Sorry, this operation isn't supported.\n");
return -EINVAL;
}

View File

@ -1 +1,7 @@
obj-m += procfs.o
obj-m += procfs1.o procfs2.o procfs3.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

View File

@ -1 +1,7 @@
obj-m += procfs.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

View File

@ -165,10 +165,12 @@ int init_module()
Our_Proc_File->gid = 0;
Our_Proc_File->size = 80;
printk(KERN_INFO "/proc/rw_test created\n");
return 0; /* success */
}
void cleanup_module()
{
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
printk(KERN_INFO "/proc/rw_test removed\n");
}

View File

@ -1 +1,13 @@
obj-m += chardev.o
all: ioctl module
module:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
install:
mknod /proc/char_dev c 100 0
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
rm -f ioctl

View File

@ -36,7 +36,7 @@ static char *Message_Ptr;
static int device_open(struct inode *inode, struct file *file)
{
#ifdef DEBUG
printk("device_open(%p)\n", file);
printk(KERN_INFO "device_open(%p)\n", file);
#endif
/*
@ -57,7 +57,7 @@ static int device_open(struct inode *inode, struct file *file)
static int device_release(struct inode *inode, struct file *file)
{
#ifdef DEBUG
printk("device_release(%p,%p)\n", inode, file);
printk(KERN_INFO "device_release(%p,%p)\n", inode, file);
#endif
/*
@ -85,7 +85,7 @@ static ssize_t device_read(struct file *file, /* see include/linux/fs.h */
int bytes_read = 0;
#ifdef DEBUG
printk("device_read(%p,%p,%d)\n", file, buffer, length);
printk(KERN_INFO "device_read(%p,%p,%d)\n", file, buffer, length);
#endif
/*
@ -113,7 +113,7 @@ static ssize_t device_read(struct file *file, /* see include/linux/fs.h */
}
#ifdef DEBUG
printk("Read %d bytes, %d left\n", bytes_read, length);
printk(KERN_INFO "Read %d bytes, %d left\n", bytes_read, length);
#endif
/*
@ -134,7 +134,7 @@ device_write(struct file *file,
int i;
#ifdef DEBUG
printk("device_write(%p,%s,%d)", file, buffer, length);
printk(KERN_INFO "device_write(%p,%s,%d)", file, buffer, length);
#endif
for (i = 0; i < length && i < BUF_LEN; i++)
@ -247,20 +247,20 @@ int init_module()
* Negative values signify an error
*/
if (ret_val < 0) {
printk("%s failed with %d\n",
printk(KERN_ALERT "%s failed with %d\n",
"Sorry, registering the character device ", ret_val);
return ret_val;
}
printk("%s The major device number is %d.\n",
printk(KERN_INFO "%s The major device number is %d.\n",
"Registeration is a success", MAJOR_NUM);
printk("If you want to talk to the device driver,\n");
printk("you'll have to create a device file. \n");
printk("We suggest you use:\n");
printk("mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
printk("The device file name is important, because\n");
printk("the ioctl program assumes that's the\n");
printk("file you'll use.\n");
printk(KERN_INFO "If you want to talk to the device driver,\n");
printk(KERN_INFO "you'll have to create a device file. \n");
printk(KERN_INFO "We suggest you use:\n");
printk(KERN_INFO "mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
printk(KERN_INFO "The device file name is important, because\n");
printk(KERN_INFO "the ioctl program assumes that's the\n");
printk(KERN_INFO "file you'll use.\n");
return 0;
}
@ -281,5 +281,5 @@ void cleanup_module()
* If there's an error, report it
*/
if (ret < 0)
printk("Error in module_unregister_chrdev: %d\n", ret);
printk(KERN_ALERT "Error: unregister_chrdev: %d\n", ret);
}

View File

@ -1 +1,7 @@
obj-m += syscall.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

View File

@ -112,13 +112,13 @@ int init_module()
* Warning - too late for it now, but maybe for
* next time...
*/
printk("I'm dangerous. I hope you did a ");
printk("sync before you insmod'ed me.\n");
printk("My counterpart, cleanup_module(), is even");
printk("more dangerous. If\n");
printk("you value your file system, it will ");
printk("be \"sync; rmmod\" \n");
printk("when you remove this module.\n");
printk(KERN_ALERT "I'm dangerous. I hope you did a ");
printk(KERN_ALERT "sync before you insmod'ed me.\n");
printk(KERN_ALERT "My counterpart, cleanup_module(), is even");
printk(KERN_ALERT "more dangerous. If\n");
printk(KERN_ALERT "you value your file system, it will ");
printk(KERN_ALERT "be \"sync; rmmod\" \n");
printk(KERN_ALERT "when you remove this module.\n");
/*
* Keep a pointer to the original function in
@ -133,7 +133,7 @@ int init_module()
* call foo, go to sys_call_table[__NR_foo].
*/
printk("Spying on UID:%d\n", uid);
printk(KERN_INFO "Spying on UID:%d\n", uid);
return 0;
}
@ -147,10 +147,10 @@ void cleanup_module()
* Return the system call back to normal
*/
if (sys_call_table[__NR_open] != our_sys_open) {
printk("Somebody else also played with the ");
printk("open system call\n");
printk("The system may be left in ");
printk("an unstable state.\n");
printk(KERN_ALERT "Somebody else also played with the ");
printk(KERN_ALERT "open system call\n");
printk(KERN_ALERT "The system may be left in ");
printk(KERN_ALERT "an unstable state.\n");
}
sys_call_table[__NR_open] = original_call;

View File

@ -1 +1,10 @@
obj-m += sleep.o
all: cat_noblock module
module:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
rm -f cat_noblock

View File

@ -276,8 +276,15 @@ static struct inode_operations Inode_Ops_4_Our_Proc_File = {
int init_module()
{
int rv = 0;
Our_Proc_File = create_proc_entry(PROC_ENTRY_FILENAME, 0644, NULL);
if (Our_Proc_File == NULL) {
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
printk(KERN_ALERT "Error: Could not initialize /proc/test\n");
return -ENOMEM;
}
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->proc_iops = &Inode_Ops_4_Our_Proc_File;
Our_Proc_File->proc_fops = &File_Ops_4_Our_Proc_File;
@ -285,14 +292,10 @@ int init_module()
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 80;
if (Our_Proc_File == NULL) {
rv = -ENOMEM;
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
printk(KERN_INFO "Error: Could not initialize /proc/test\n");
}
return rv;
printk(KERN_INFO "/proc/test created\n");
return 0;
}
/*
@ -304,4 +307,6 @@ int init_module()
void cleanup_module()
{
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
printk(KERN_INFO "/proc/test removed\n");
}

View File

@ -1,2 +1,8 @@
obj-m += print_string.o
obj-m += kbleds.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

View File

@ -1 +1,7 @@
obj-m += sched.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

View File

@ -76,10 +76,8 @@ procfile_read(char *buffer,
*/
static char my_buffer[80];
static int count = 1;
/*
* We give all of our information in one go, so if the anybody asks us
* We give all of our information in one go, so if anybody asks us
* if we have more information the answer should always be no.
*/
if (offset > 0)
@ -89,7 +87,6 @@ procfile_read(char *buffer,
* Fill the buffer and get its length
*/
len = sprintf(my_buffer, "Timer called %d times so far\n", TimerIntrpt);
count++;
/*
* Tell the function which called us where the buffer is
@ -107,23 +104,18 @@ procfile_read(char *buffer,
*/
int __init init_module()
{
int rv = 0;
/*
* Put the task in the work_timer task queue, so it will be executed at
* next timer interrupt
/*
* Create our /proc file
*/
my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME);
queue_delayed_work(my_workqueue, &Task, 100);
Our_Proc_File = create_proc_entry(PROC_ENTRY_FILENAME, 0644, NULL);
if (Our_Proc_File == NULL) {
rv = -ENOMEM;
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
printk(KERN_INFO "Error: Could not initialize /proc/%s\n",
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
PROC_ENTRY_FILENAME);
return -ENOMEM;
}
Our_Proc_File->read_proc = procfile_read;
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->mode = S_IFREG | S_IRUGO;
@ -131,7 +123,17 @@ int __init init_module()
Our_Proc_File->gid = 0;
Our_Proc_File->size = 80;
return rv;
/*
* Put the task in the work_timer task queue, so it will be executed at
* next timer interrupt
*/
my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME);
queue_delayed_work(my_workqueue, &Task, 100);
printk(KERN_INFO "/proc/%s created\n", PROC_ENTRY_FILENAME);
return 0;
}
/*

View File

@ -1 +1,7 @@
obj-m += intrpt.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

View File

@ -28,7 +28,7 @@ static struct workqueue_struct *my_workqueue;
*/
static void got_char(void *scancode)
{
printk("Scan Code %x %s.\n",
printk(KERN_INFO "Scan Code %x %s.\n",
(int)*((char *)scancode) & 0x7F,
*((char *)scancode) & 0x80 ? "Released" : "Pressed");
}

View File

@ -29,7 +29,7 @@
</authorgroup>
<!-- year-month-day -->
<pubdate>2005-01-23 ver 2.6.1</pubdate>
<pubdate>2005-05-26 ver 2.6.1</pubdate>
<copyright>
@ -38,33 +38,29 @@
</copyright>
<legalnotice>
<para>The Linux Kernel Module Programming Guide is a free book; you may reproduce and/or
modify it under the terms of the Open Software License, version 1.1. You can obtain a copy of
this license at <ulink
<para>The Linux Kernel Module Programming Guide is a free book; you may reproduce and/or modify it under the terms of the
Open Software License, version 1.1. You can obtain a copy of this license at <ulink
url="http://opensource.org/licenses/osl.php">http://opensource.org/licenses/osl.php</ulink>.</para>
<para>This book is distributed in the hope it will be useful, but without any warranty,
without even the implied warranty of merchantability or fitness for a particular
purpose.</para>
<para>This book is distributed in the hope it will be useful, but without any warranty, without even the implied warranty
of merchantability or fitness for a particular purpose.</para>
<para>The author encourages wide distribution of this book for personal or commercial use,
provided the above copyright notice remains intact and the method adheres to the provisions of
the Open Software License. In summary, you may copy and distribute this book free of charge
or for a profit. No explicit permission is required from the author for reproduction of this
book in any medium, physical or electronic.</para>
<para>The author encourages wide distribution of this book for personal or commercial use, provided the above copyright
notice remains intact and the method adheres to the provisions of the Open Software License. In summary, you may copy and
distribute this book free of charge or for a profit. No explicit permission is required from the author for reproduction
of this book in any medium, physical or electronic.</para>
<para>Derivative works and translations of this document must be placed under the Open
Software License, and the original copyright notice must remain intact. If you have
contributed new material to this book, you must make the material and source code available
for your revisions. Please make revisions and updates available directly to the document
maintainer, Peter Jay Salzman <email>p@dirac.org</email>. This will allow for the merging of
updates and provide consistent revisions to the Linux community.</para>
<para>Derivative works and translations of this document must be placed under the Open Software License, and the original
copyright notice must remain intact. If you have contributed new material to this book, you must make the material and
source code available for your revisions. Please make revisions and updates available directly to the document
maintainer, Peter Jay Salzman <email>p@dirac.org</email>. This will allow for the merging of updates and provide
consistent revisions to the Linux community.</para>
<para>If you publish or distribute this book commercially, donations, royalties, and/or
printed copies are greatly appreciated by the author and the <ulink
url="http://www.tldp.org">Linux Documentation Project</ulink> (LDP). Contributing in this way
shows your support for free software and the LDP. If you have questions or comments, please
contact the address above.</para> </legalnotice>
<para>If you publish or distribute this book commercially, donations, royalties, and/or printed copies are greatly
appreciated by the author and the <ulink url="http://www.tldp.org">Linux Documentation Project</ulink> (LDP).
Contributing in this way shows your support for free software and the LDP. If you have questions or comments, please
contact the address above.</para>
</legalnotice>
</bookinfo>
@ -91,5 +87,5 @@
<!--
vim: tw=100
vim: tw=128
-->