This commit is contained in:
gferg 2005-12-31 21:50:45 +00:00
parent 62a07332a5
commit 2a7e9da23b
16 changed files with 1495 additions and 120 deletions

View File

@ -29,7 +29,7 @@
<sect1><title>Acknowledgements</title>
<para>The following people have contributed corrections or good suggestions: Ignacio Martin, David Porter, Daniele Paolo
Scarpazza, Dimo Velev and Francois Audeon </para>
Scarpazza, Dimo Velev, Francois Audeon and Horst Schirmeier. </para>
</sect1>

View File

@ -30,8 +30,8 @@
kerneld.</para></footnote> execs modprobe to load the module in. modprobe is passed a string in one of two forms:</para>
<itemizedlist>
<listitem><para>A module name like <filename>softdog</filename> or <filename>ppp</filename>.</listitem>
<listitem><para>A more generic identifier like <varname>char-major-10-30</varname>.</listitem>
<listitem><para>A module name like <filename>softdog</filename> or <filename>ppp</filename>.</para></listitem>
<listitem><para>A more generic identifier like <varname>char-major-10-30</varname>.</para></listitem>
</itemizedlist>
<para>If modprobe is handed a generic identifier, it first looks for that string in the file
@ -75,7 +75,7 @@ modprobe msdos
<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>.
all it needs to know by parsing <filename>/lib/modules/version/modules.dep</filename>.</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

View File

@ -155,7 +155,7 @@ hostname:~/lkmpg-examples/02-HelloWorld#
<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.
<function>init_module()</function>? Change the return value to something negative, recompile and load the module again.
What happens?</para>
</sect1>
@ -317,33 +317,34 @@ Module xxxxxx loaded, with warnings
used to.</para>
<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
arguments as global and then use the <functioN>module_param()</function> macro, (defined in <filename
role="headerfile">linux/moduleparam.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.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,
"<literal>l</literal>": long int and "<literal>s</literal>": string, and the integer types can be signed as usual or unsigned.
Strings should be declared as "<type>char *</type>" and insmod will allocate memory for them. You should always try to give
the variables an initial default value. This is kernel code, and you should program defensively. For example:</para>
<para>The <function>module_param()</function> macro takes 3 arguments: the name of the variable, its type and
permissions for the corresponding file in sysfs. Integer types can be signed as usual or unsigned.
If you'd like to use arrays of integers or strings see <function>module_param_array()</function> and
<function>module_param_string()</function>.
<screen>
int myint = 3;
char *mystr;
MODULE_PARM(myint, "i");
MODULE_PARM(mystr, "s");
module_param(myint, int, 0);
</screen>
<para>Arrays are supported too. An integer value preceding the type in MODULE_PARM will indicate an array of some maximum
length. Two numbers separated by a '-' will give the minimum and maximum number of values. For example, an array of shorts
with at least 2 and no more than 4 values could be declared as:</para>
<para>Arrays are supported too, but things are a bit different now than they were in the 2.4. days. To keep track of the
number of parameters you need to pass a pointer to a count variable as third parameter. At your option, you could also
ignore the count and pass NULL instead. We show both possibilities here:</para>
<screen>
int myshortArray[4];
MODULE_PARM (myintArray, "3-9i");
int myintarray[2];
module_param_array(myintarray, int, NULL, 0); /* not interested in count */
int myshortarray[4];
int count;
module_parm_array(myshortarray, short, &amp count, 0); /* put count into "count" variable */
</screen>
<para>A good use for this is to have the module variable's default values set, like an port or IO address. If the variables

View File

@ -139,7 +139,7 @@ int main(void)
point to memory locations. Not real ones, anyway. When a process is created, the kernel sets aside a portion of real
physical memory and hands it to the process to use for its executing code, variables, stack, heap and other things which a
computer scientist would know about<footnote><para>I'm a physicist, not a computer scientist, Jim!</para></footnote>.
This memory begins with $0$ and extends up to whatever it needs to be. Since the memory space for any two processes don't
This memory begins with 0x00000000 and extends up to whatever it needs to be. Since the memory space for any two processes don't
overlap, every process that can access a memory address, say <literal>0xbffff978</literal>, would be accessing a different
location in real physical memory! The processes would be accessing an index named <literal>0xbffff978</literal> which
points to some kind of offset into the region of memory set aside for that particular process. For the most part, a
@ -149,7 +149,7 @@ int main(void)
<para>The kernel has its own space of memory as well. Since a module is code which can be dynamically inserted and
removed in the kernel (as opposed to a semi-autonomous object), it shares the kernel's codespace rather than having its
own. Therefore, if your module segfaults, the kernel segfaults. And if you start writing over data because of an
off-by-one error, then you're trampling on kernel code. This is even worse than it sounds, so try your best to be
off-by-one error, then you're trampling on kernel data (or code). This is even worse than it sounds, so try your best to be
careful.</para>
<para>By the way, I would like to point out that the above discussion is true for any operating system which uses a

View File

@ -68,7 +68,7 @@ struct file_operations fops = {
</screen>
<para>However, there's also a C99 way of assigning to elements of a structure, and this is definitely preferred over using
the GNU extension. The version of gcc I'm currently using, <literal>2.95</literal>, supports the new C99 syntax. You
the GNU extension. The version of gcc the author used when writing this, <literal>2.95</literal>, supports the new C99 syntax. You
should use this syntax in case someone wants to port your driver. It will help with compatibility:</para>
<screen>
@ -83,7 +83,8 @@ struct file_operations fops = {
<para>The meaning is clear, and you should be aware that any member of the structure which you don't explicitly assign
will be initialized to <varname>NULL</varname> by gcc.</para>
<para>A pointer to a <type>struct file_operations</type> is commonly named <varname>fops</varname>.</para>
<para>An instance of <type>struct file_operations</type> containing pointers to functions that are used to implement
read, write, open, ... syscalls is commonly named <varname>fops</varname>.</para>
</sect2>
@ -100,7 +101,7 @@ struct file_operations fops = {
kernel space function. Also, its name is a bit misleading; it represents an abstract open `file', not a file on a disk,
which is represented by a structure named <type>inode</type>.</para>
<para>A pointer to a <varname>struct file</varname> is commonly named <function>filp</function>. You'll also see it
<para>An instance of <varname>struct file</varname> is commonly named <function>filp</function>. You'll also see it
refered to as <varname>struct file file</varname>. Resist the temptation.</para>
<para>Go ahead and look at the definition of <function>file</function>. Most of the entries you see, like
@ -135,7 +136,7 @@ int register_chrdev(unsigned int major, const char *name, struct file_operations
<para>where <varname>unsigned int major</varname> is the major number you want to request, <varname>const char
*name</varname> is the name of the device as it'll appear in <filename>/proc/devices</filename> and <varname>struct
file_operations *fops</varname> is a pointer to the <varname>file_operations</varname> table for your driver. A negative
return value means the registertration failed. Note that we didn't pass the minor number to
return value means the registration failed. Note that we didn't pass the minor number to
<function>register_chrdev</function>. That's because the kernel doesn't care about the minor number; only our driver uses
it.</para>
@ -175,11 +176,11 @@ int register_chrdev(unsigned int major, const char *name, struct file_operations
will fail. Note that you don't have to check the counter from within <function>cleanup_module</function> because the
check will be performed for you by the system call <function>sys_delete_module</function>, defined in
<filename>linux/module.c</filename>. You shouldn't use this counter directly, but there are functions defined in <filename
role="headerfile">linux/modules.h</filename> which let you increase, decrease and display this counter:</para>
role="headerfile">linux/module.h</filename> which let you increase, decrease and display this counter:</para>
<itemizedlist>
<listitem><para><varname>try_module_get(THIS_MODULE)</varname>: Increment the use count.</para></listitem>
<listitem><para><varname>try_module_put(THIS_MODULE)</varname>: Decrement the use count.</para></listitem>
<listitem><para><varname>module_put(THIS_MODULE)</varname>: Decrement the use count.</para></listitem>
</itemizedlist>
<para>It's important to keep the counter accurate; if you ever do lose track of the correct usage count, you'll never be

View File

@ -187,6 +187,64 @@ HelloWorld!
</sect1>
<sect1><title>Manage /proc file with seq_file</title>
<indexterm><primary>seq_file</primary></indexterm>
<para>
As we have seen, writing a /proc file may be quite "complex". So to help people writting
/proc file, there is an API named seq_file that helps formating a /proc file for output.
It's based on sequence, which is composed of 3 functions: start(), next(), and stop().
The seq_file API starts a sequence when a user read the /proc file.
</para>
<para>
A sequence begins with the call of the function start(). If the return is a non NULL value,
the function next() is called. This function is an iterator, the goal is to go thought
all the data. Each time next() is called, the function show() is also called. It writes
data values in the buffer read by the user. The function next() is called until it returns
NULL. The sequence ends when next() returns NULL, then the function stop() is called.
</para>
<para>
BE CARREFUL: when a sequence is finished, another one starts. That means that at the end
of function stop(), the function start() is called again. This loop finishes when the
function start() returns NULL. You can see a scheme of this in the figure "How seq_file works".
</para>
<figure>
<title>How seq_file works</title>
<graphic fileref="figures/seq_file.png"></graphic>
</figure>
<para>
Seq_file provides basic functions for file_operations, as seq_read, seq_lseek, and some others.
But nothing to write in the /proc file. Of course, you can still use the same way as in the
previous example.
</para>
<example>
<title>procfs4.c</title>
<programlisting>
<inlinegraphic fileref="lkmpg-examples/05-TheProcFileSystem/procfs4.c" format="linespecific"/></inlinegraphic>
</programlisting>
</example>
<para>
If you want more information, you can read this web page:
</para>
<itemizedlist>
<listitem><para><ulink url="http://lwn.net/Articles/22355/"></ulink></para></listitem>
<listitem><para><ulink url="http://www.kernelnewbies.org/documents/seq_file_howto.txt"></ulink></para></listitem>
</itemizedlist>
<para>
You can also read the code of fs/seq_file.c in the linux kernel.
</para>
</sect1>
<!--
vim:textwidth=128
-->

View File

@ -11,7 +11,7 @@
<function>open()</function> system call. This meant I couldn't open any files, I couldn't run any programs, and I couldn't
<command>shutdown</command> the computer. I had to pull the power switch. Luckily, no files died. To ensure you won't lose
any files either, please run <command>sync</command> right before you do the <command>insmod</command> and the
<command>rmmod</command>.
<command>rmmod</command>.</para>
<indexterm><primary>sync</primary></indexterm>
<indexterm><primary>insmod</primary></indexterm>

View File

@ -3,115 +3,128 @@
<indexterm><primary>interrupt handlers</primary></indexterm>
<indexterm><primary>handlers</primary><secondary>interrupt</secondary></indexterm>
<sect2><title>Interrupt Handlers</title>
<para>
Except for the last chapter, everything we did in the kernel so far we've done as a response to a process
asking for it, either by dealing with a special file, sending an <function>ioctl()</function>, or issuing
a system call. But the job of the kernel isn't just to respond to process requests. Another job, which
is every bit as important, is to speak to the hardware connected to the machine.
</para>
<para>There are two types of interaction between the CPU and the rest of the computer's hardware.
The first type is when the CPU gives orders to the hardware, the other is when the hardware needs to tell
the CPU something. The second, called interrupts, is much harder to implement because it has to be dealt
with when convenient for the hardware, not the CPU. Hardware devices typically have a very small amount of
RAM, and if you don't read their information when available, it is lost.
</para>
<sect2><title>Interrupt Handlers</title>
<para>
Under Linux, hardware interrupts are called IRQ's (<emphasis>I</emphasis>nterrupt<emphasis>R</emphasis>e
<emphasis>q</emphasis>uests)<footnote><para>This is standard nomencalture on the Intel architecture where
Linux originated.</para></footnote>. There are two types of IRQ's, short and long. A short IRQ is one which
is expected to take a <emphasis>very</emphasis> short period of time, during which the rest of the machine
will be blocked and no other interrupts will be handled. A long IRQ is one which can take longer, and during
which other interrupts may occur (but not interrupts from the same device). If at all possible, it's better
to declare an interrupt handler to be long.
</para>
<para>Except for the last chapter, everything we did in the kernel so far we've done as a response to a process asking for
it, either by dealing with a special file, sending an <function>ioctl()</function>, or issuing a system call. But the job
of the kernel isn't just to respond to process requests. Another job, which is every bit as important, is to speak to the
hardware connected to the machine.</para>
<indexterm><primary>bottom half</primary></indexterm>
<para>There are two types of interaction between the CPU and the rest of the computer's hardware. The first type is when
the CPU gives orders to the hardware, the other is when the hardware needs to tell the CPU something. The second, called
interrupts, is much harder to implement because it has to be dealt with when convenient for the hardware, not the CPU.
Hardware devices typically have a very small amount of RAM, and if you don't read their information when available, it is
lost.</para>
<para>
When the CPU receives an interrupt, it stops whatever it's doing (unless it's processing a more important
interrupt, in which case it will deal with this one only when the more important one is done), saves certain
parameters on the stack and calls the interrupt handler. This means that certain things are not allowed
in the interrupt handler itself, because the system is in an unknown state. The solution to this problem
is for the interrupt handler to do what needs to be done immediately, usually read something from the hardware
or send something to the hardware, and then schedule the handling of the new information at a later time
(this is called the <quote>bottom half</quote>) and return. The kernel is then guaranteed to call the bottom
half as soon as possible -- and when it does, everything allowed in kernel modules will be allowed.
</para>
<para>Under Linux, hardware interrupts are called IRQ's (<emphasis>I</emphasis>nterrupt
<emphasis>R</emphasis>e<emphasis>q</emphasis>uests)<footnote><para>This is standard nomencalture on the Intel architecture
where Linux originated.<para></footnote>. There are two types of IRQ's, short and long. A short IRQ is one which is
expected to take a <emphasis>very</emphasis> short period of time, during which the rest of the machine will be blocked
and no other interrupts will be handled. A long IRQ is one which can take longer, and during which other interrupts may
occur (but not interrupts from the same device). If at all possible, it's better to declare an interrupt handler to be
long.</para>
<indexterm><primary>request_irq()</primary></indexterm>
<indexterm><primary>/proc/interrupts</primary></indexterm>
<indexterm><primary>SA_INTERRUPT</primary></indexterm>
<indexterm><primary>SA_SHIRQ</primary></indexterm>
<indexterm><primary>bottom half</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. <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>
<para>When the CPU receives an interrupt, it stops whatever it's doing (unless it's processing a more important interrupt,
in which case it will deal with this one only when the more important one is done), saves certain parameters on the stack
and calls the interrupt handler. This means that certain things are not allowed in the interrupt handler itself, because
the system is in an unknown state. The solution to this problem is for the interrupt handler to do what needs to be done
immediately, usually read something from the hardware or send something to the hardware, and then schedule the handling of
the new information at a later time (this is called the <quote>bottom half</quote>) and return. The kernel is then
guaranteed to call the bottom half as soon as possible -- and when it does, everything allowed in kernel modules will be
allowed.</para>
<indexterm><primary>queue_work</primary></indexterm>
<indexterm><primary>request_irq()</primary></indexterm>
<indexterm><primary>/proc/interrupts</primary></indexterm>
<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.
<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_work()</function> <function>mark_bh(BH_IMMEDIATE)</function> to schedule the bottom half.
</sect2>
<para>
Then, from within the interrupt handler, we communicate with the hardware and then use <function>queue_work()
</function> <function>mark_bh(BH_IMMEDIATE)</function> to schedule the bottom half.
</para>
</sect2>
<sect2 id="keyboard"><title>Keyboards on the Intel Architecture</title>
<sect2 id="keyboard"><title>Keyboards on the Intel Architecture</title>
<indexterm><primary>keyboard</primary></indexterm>
<indexterm><primary>Intel architecture</primary><secondary>keyboard</secondary></indexterm>
<indexterm><primary>keyboard</primary></indexterm>
<indexterm><primary>Intel architecture</primary><secondary>keyboard</secondary></indexterm>
<!-- <warning> -->
<para>The rest of this chapter is completely Intel specific. If you're not running on an Intel platform, it
will not work. Don't even try to compile the code here.</para>
<!-- </warning> -->
<!-- <warning> -->
<para>
The rest of this chapter is completely Intel specific. If you're not running on an Intel platform, it
will not work. Don't even try to compile the code here.
</para>
<para>I had a problem with writing the sample code for this chapter. On one hand, for an example to be useful it has to
run on everybody's computer with meaningful results. On the other hand, the kernel already includes device drivers for
all of the common devices, and those device drivers won't coexist with what I'm going to write. The solution I've found
was to write something for the keyboard interrupt, and disable the regular keyboard interrupt handler first. Since it is
defined as a static symbol in the kernel source files (specifically, <filename>drivers/char/keyboard.c</filename>), there
is no way to restore it. Before <userinput>insmod</userinput>'ing this code, do on another terminal <userinput>sleep 120
; reboot</userinput> if you value your file system.</para>
<!-- </warning> -->
<para>
I had a problem with writing the sample code for this chapter. On one hand, for an example to be useful
it has to run on everybody's computer with meaningful results. On the other hand, the kernel already
includes device drivers for all of the common devices, and those device drivers won't coexist with what
I'm going to write. The solution I've found was to write something for the keyboard interrupt, and disable
the regular keyboard interrupt handler first. Since it is defined as a static symbol in the kernel source
files (specifically, <filename>drivers/char/keyboard.c</filename>), there is no way to restore it. Before
<userinput>insmod</userinput>'ing this code, do on another terminal <userinput>sleep 120; reboot</userinput>
if you value your file system.
</para>
<indexterm><primary>inb</primary></indexterm>
<indexterm><primary>inb</primary></indexterm>
<para> This code binds itself to IRQ 1, which is the IRQ of the keyboard controlled under Intel architectures. Then, when
it receives a keyboard interrupt, it reads the keyboard's status (that's the purpose of the
<userinput>inb(0x64)</userinput>) and the scan code, which is the value returned by the keyboard. Then, as soon as the
kernel thinks it's feasible, it runs <function>got_char</function> which gives the code of the key used (the first seven
bits of the scan code) and whether it has been pressed (if the 8th bit is zero) or released (if it's one).</para>
<para>
This code binds itself to IRQ 1, which is the IRQ of the keyboard controlled under Intel architectures.
Then, when it receives a keyboard interrupt, it reads the keyboard's status (that's the purpose of the
<userinput>inb(0x64)</userinput>) and the scan code, which is the value returned by the keyboard. Then,
as soon as the kernel thinks it's feasible, it runs <function>got_char</function> which gives the code
of the key used (the first seven bits of the scan code) and whether it has been pressed (if the 8th bit
is zero) or released (if it's one).
</para>
<indexterm><primary>source file</primary><secondary><filename>intrpt.c</filename></secondary></indexterm>
<indexterm><primary>source file</primary><secondary><filename>intrpt.c</filename></secondary></indexterm>
<example><title>intrpt.c</title><programlisting><inlinegraphic fileref="lkmpg-examples/12-InterruptHandlers/intrpt.c" format="linespecific"/></inlinegraphic></programlisting></example>
<example>
<title>intrpt.c</title>
<programlisting>
<inlinegraphic fileref="lkmpg-examples/12-InterruptHandlers/intrpt.c" format="linespecific"/></inlinegraphic>
</programlisting>
</example>
</sect2>
</sect2>
</sect1>
<!--
vim: tw=128
-->

View File

@ -0,0 +1,48 @@
#FIG 3.2 Produced by xfig version 3.2.5-alpha5
Landscape
Center
Inches
Letter
100.00
Single
-2
1200 2
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
900 600 5700 600 5700 1200 900 1200 900 600
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
3300 1800 900 2250 3300 2700 5700 2250 3300 1800
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
900 3300 5700 3300 5700 3900 900 3900 900 3300
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
3310 4479 910 4929 3310 5379 5710 4929 3310 4479
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
900 6000 5700 6000 5700 6600 900 6600 900 6000
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
3300 1200 3300 1800
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
3300 2700 3300 3300
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
3300 3900 3300 4500
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
3300 5400 3300 6000
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 6
0 0 1.00 60.00 120.00
3300 6600 3300 6900 300 6900 300 300 3300 300 3300 600
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
900 4950 600 4950 600 3000 3300 3000
2 1 0 1 0 7 50 -1 -1 0.000 0 0 7 1 0 2
0 0 1.00 60.00 120.00
5700 2250 6900 2250
4 0 0 50 -1 0 16 0.0000 4 255 1890 2700 975 start() treatment\001
4 0 0 50 -1 0 16 0.0000 4 195 1725 2700 2325 return is NULL\001
4 0 0 50 -1 0 16 0.0000 4 255 1875 2550 3675 next() treatment\001
4 0 0 50 -1 0 16 0.0000 4 195 1725 2700 5025 return is NULL\001
4 0 0 50 -1 0 16 0.0000 4 255 1845 2700 6300 stop() treatment\001
4 0 0 50 -1 0 16 0.0000 4 195 405 600 5400 NO\001
4 0 0 50 -1 0 16 0.0000 4 195 495 3450 5850 YES\001
4 0 0 50 -1 0 16 0.0000 4 195 495 6150 2175 YES\001
4 0 0 50 -1 0 16 0.0000 4 195 405 3450 3150 NO\001

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,132 @@
/**
* procfs4.c - create a "file" in /proc
* This program uses the seq_file library to manage the /proc file.
*
*/
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/proc_fs.h> /* Necessary because we use proc fs */
#include <linux/seq_file.h> /* for seq_file */
#define PROC_NAME "iter"
MODULE_AUTHOR("Philippe Reynes");
MODULE_LICENSE("GPL");
/**
* This function is called at the beginning of a sequence.
* ie, when:
* - the /proc file is read (first time)
* - after the function stop (end of sequence)
*
*/
static void *my_seq_start(struct seq_file *s, loff_t *pos)
{
static unsigned long counter = 0;
/* beginning a new sequence ? */
if ( *pos == 0 )
{
/* yes => return a non null value to begin the sequence */
return &counter;
}
else
{
/* no => it's the end of the sequence, return end to stop reading */
*pos = 0;
return NULL;
}
}
/**
* This function is called after the beginning of a sequence.
* It's called untill the return is NULL (this ends the sequence).
*
*/
static void *my_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
unsigned long *tmp_v = (unsigned long *)v;
(*tmp_v)++;
(*pos)++;
return NULL;
}
/**
* This function is called at the end of a sequence
*
*/
static void my_seq_stop(struct seq_file *s, void *v)
{
/* nothing to do, we use a static value in start() */
}
/**
* This function is called for each "step" of a sequence
*
*/
static int my_seq_show(struct seq_file *s, void *v)
{
loff_t *spos = (loff_t *) v;
seq_printf(s, "%Ld\n", *spos);
return 0;
}
/**
* This structure gather "function" to manage the sequence
*
*/
static struct seq_operations my_seq_ops = {
.start = my_seq_start,
.next = my_seq_next,
.stop = my_seq_stop,
.show = my_seq_show
};
/**
* This function is called when the /proc file is open.
*
*/
static int my_open(struct inode *inode, struct file *file)
{
return seq_open(file, &my_seq_ops);
};
/**
* This structure gather "function" that manage the /proc file
*
*/
static struct file_operations my_file_ops = {
.owner = THIS_MODULE,
.open = my_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
/**
* This function is called when the module is loaded
*
*/
int init_module(void)
{
struct proc_dir_entry *entry;
entry = create_proc_entry(PROC_NAME, 0, NULL);
if (entry) {
entry->proc_fops = &my_file_ops;
}
return 0;
}
/**
* This function is called when the module is unloaded.
*
*/
void cleanup_module(void)
{
remove_proc_entry(PROC_NAME, NULL);
}

View File

@ -11,6 +11,8 @@
*/
#include "chardev.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h> /* open */
#include <unistd.h> /* exit */
#include <sys/ioctl.h> /* ioctl */
@ -62,7 +64,7 @@ ioctl_get_nth_byte(int file_desc)
printf("get_nth_byte message:");
i = 0;
while (c != 0) {
do {
c = ioctl(file_desc, IOCTL_GET_NTH_BYTE, i++);
if (c < 0) {
@ -73,7 +75,7 @@ ioctl_get_nth_byte(int file_desc)
}
putchar(c);
}
} while (c != 0);
putchar('\n');
}

View File

@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/tty.h> /* For fg_console, MAX_NR_CONSOLES */
#include <linux/kd.h> /* For KDSETLED */
#include <linux/vt.h>
#include <linux/console_struct.h> /* For vc_cons */
MODULE_DESCRIPTION("Example module illustrating the use of Keyboard LEDs.");

View File

@ -29,7 +29,7 @@
</authorgroup>
<!-- year-month-day -->
<pubdate>2005-05-26 ver 2.6.1</pubdate>
<pubdate>2005-12-31 ver 2.6.3</pubdate>
<copyright>