This commit is contained in:
gferg 2006-08-05 03:28:14 +00:00
parent 6abd9d59f4
commit b81ad25b5f
6 changed files with 277 additions and 151 deletions

View File

@ -13,7 +13,17 @@
<example><title>hello-1.c</title> <example><title>hello-1.c</title>
<programlisting><![CDATA[ <programlisting><![CDATA[
/* hello-1.c - The simplest kernel module. /* hello-1.c - The simplest kernel module.
*
* Copyright (C) 2001 by Peter Jay Salzman
*
* 08/02/2006 - Updated by Rodrigo Rubira Branco <rodrigo@kernelhacking.com>
*/ */
/* Kernel Programming */
#define MODULE
#define LINUX
#define __KERNEL__
#include <linux/module.h> /* Needed by all modules */ #include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_ALERT */ #include <linux/kernel.h> /* Needed for KERN_ALERT */
@ -31,6 +41,9 @@ void cleanup_module(void)
{ {
printk(KERN_ALERT "Goodbye world 1.\n"); printk(KERN_ALERT "Goodbye world 1.\n");
} }
MODULE_LICENSE("GPL");
]]></programlisting> ]]></programlisting>
</example> </example>
@ -189,7 +202,17 @@ clean:
<programlisting><![CDATA[ <programlisting><![CDATA[
/* hello-2.c - Demonstrating the module_init() and module_exit() macros. This is the /* hello-2.c - Demonstrating the module_init() and module_exit() macros. This is the
* preferred over using init_module() and cleanup_module(). * preferred over using init_module() and cleanup_module().
*
* Copyright (C) 2001 by Peter Jay Salzman
*
* 08/02/2006 - Updated by Rodrigo Rubira Branco <rodrigo@kernelhacking.com>
*/ */
/* Kernel Programming */
#define MODULE
#define LINUX
#define __KERNEL__
#include <linux/module.h> // Needed by all modules #include <linux/module.h> // Needed by all modules
#include <linux/kernel.h> // Needed for KERN_ALERT #include <linux/kernel.h> // Needed for KERN_ALERT
#include <linux/init.h> // Needed for the macros #include <linux/init.h> // Needed for the macros
@ -210,6 +233,9 @@ static void hello_2_exit(void)
module_init(hello_2_init); module_init(hello_2_init);
module_exit(hello_2_exit); module_exit(hello_2_exit);
MODULE_LICENSE("GPL");
]]></programlisting> ]]></programlisting>
</example> </example>
@ -275,7 +301,17 @@ clean:
<example><title>hello-3.c</title> <example><title>hello-3.c</title>
<programlisting><![CDATA[ <programlisting><![CDATA[
/* hello-3.c - Illustrating the __init, __initdata and __exit macros. /* hello-3.c - Illustrating the __init, __initdata and __exit macros.
*
* Copyright (C) 2001 by Peter Jay Salzman
*
* 08/02/2006 - Updated by Rodrigo Rubira Branco <rodrigo@kernelhacking.com>
*/ */
/* Kernel Programming */
#define MODULE
#define LINUX
#define __KERNEL__
#include <linux/module.h> /* Needed by all modules */ #include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_ALERT */ #include <linux/kernel.h> /* Needed for KERN_ALERT */
#include <linux/init.h> /* Needed for the macros */ #include <linux/init.h> /* Needed for the macros */
@ -298,6 +334,9 @@ static void __exit hello_3_exit(void)
module_init(hello_3_init); module_init(hello_3_init);
module_exit(hello_3_exit); module_exit(hello_3_exit);
MODULE_LICENSE("GPL");
]]></programlisting> ]]></programlisting>
</example> </example>
@ -363,11 +402,21 @@ Module hello-3 loaded, with warnings
<example><title>hello-4.c</title> <example><title>hello-4.c</title>
<programlisting><![CDATA[ <programlisting><![CDATA[
/* hello-4.c - Demonstrates module documentation. /* hello-4.c - Demonstrates module documentation.
*
* Copyright (C) 2001 by Peter Jay Salzman
*
* 08/02/2006 - Updated by Rodrigo Rubira Branco <rodrigo@kernelhacking.com>
*/ */
/* Kernel Programming */
#define MODULE
#define LINUX
#define __KERNEL__
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#define DRIVER_AUTHOR "Peiter Jay Salzman <p@dirac.org>" #define DRIVER_AUTHOR "Peter Jay Salzman <p@dirac.org>"
#define DRIVER_DESC "A sample driver" #define DRIVER_DESC "A sample driver"
int init_hello_3(void); int init_hello_3(void);
@ -463,12 +512,23 @@ MODULE_SUPPORTED_DEVICE("testdevice");
<example><title>hello-5.c</title> <example><title>hello-5.c</title>
<programlisting><![CDATA[ <programlisting><![CDATA[
/* hello-5.c - Demonstrates command line argument passing to a module. /* hello-5.c - Demonstrates command line argument passing to a module.
*
* Copyright (C) 2001 by Peter Jay Salzman
*
* 08/02/2006 - Updated by Rodrigo Rubira Branco <rodrigo@kernelhacking.com>
*/ */
/* Kernel Programming */
#define MODULE
#define LINUX
#define __KERNEL__
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Peiter Jay Salzman"); MODULE_AUTHOR("Peter Jay Salzman");
// These global variables can be set with command line arguments when you insmod // These global variables can be set with command line arguments when you insmod
// the module in. // the module in.
@ -502,7 +562,7 @@ static int __init hello_5_init(void)
printk(KERN_ALERT "myint is an integer: %i\n", myint); printk(KERN_ALERT "myint is an integer: %i\n", myint);
printk(KERN_ALERT "mylong is a long integer: %li\n", mylong); printk(KERN_ALERT "mylong is a long integer: %li\n", mylong);
printk(KERN_ALERT "mystring is a string: %s\n", mystring); printk(KERN_ALERT "mystring is a string: %s\n", mystring);
printk(KERN_ALERT "myintArray is %i and %i\n", myintArray[0], myintArray[1]); printk(KERN_ALERT "myintArray is %i and %i\n", myintArray[0], myintArray[1]);
return 0; return 0;
} }
@ -589,8 +649,17 @@ module_exit(hello_5_exit);
<example><title>start.c</title> <example><title>start.c</title>
<programlisting><![CDATA[ <programlisting><![CDATA[
/* start.c - Illustration of multi filed modules /* start.c - Illustration of multi filed modules
*
* Copyright (C) 2001 by Peter Jay Salzman
*
* 08/02/2006 - Updated by Rodrigo Rubira Branco <rodrigo@kernelhacking.com>
*/ */
/* Kernel Programming */
#define MODULE
#define LINUX
#define __KERNEL__
#include <linux/kernel.h> /* We're doing kernel work */ #include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */ #include <linux/module.h> /* Specifically, a module */
@ -599,6 +668,9 @@ int init_module(void)
printk("Hello, world - this is the kernel speaking\n"); printk("Hello, world - this is the kernel speaking\n");
return 0; return 0;
} }
MODULE_LICENSE("GPL");
]]></programlisting> ]]></programlisting>
</example> </example>
@ -611,12 +683,22 @@ int init_module(void)
<example><title>stop.c</title> <example><title>stop.c</title>
<programlisting><![CDATA[ <programlisting><![CDATA[
/* stop.c - Illustration of multi filed modules /* stop.c - Illustration of multi filed modules
*
* Copyright (C) 2001 by Peter Jay Salzman
*
* 08/02/2006 - Updated by Rodrigo Rubira Branco <rodrigo@kernelhacking.com>
*/ */
/* Kernel Programming */
#define MODULE
#define LINUX
#define __KERNEL__
#if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS) #if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
#include <linux/modversions.h> /* Will be explained later */ #include <linux/modversions.h> /* Will be explained later */
#define MODVERSIONS #define MODVERSIONS
#endif #endif
#include <linux/kernel.h> /* We're doing kernel work */ #include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */ #include <linux/module.h> /* Specifically, a module */
#define __NO_VERSION__ /* It's not THE file of the kernel module */ #define __NO_VERSION__ /* It's not THE file of the kernel module */

View File

@ -198,151 +198,160 @@
<programlisting><![CDATA[ <programlisting><![CDATA[
/* chardev.c: Creates a read-only char device that says how many times /* chardev.c: Creates a read-only char device that says how many times
* you've read from the dev file * you've read from the dev file
*
* Copyright (C) 2001 by Peter Jay Salzman
*
* 08/02/2006 - Updated by Rodrigo Rubira Branco <rodrigo@kernelhacking.com>
*/ */
#if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS) /* Kernel Programming */
#include <linux/modversions.h> #define MODULE
#define MODVERSIONS #define LINUX
#endif #define __KERNEL__
#include <linux/kernel.h>
#include <linux/module.h> #if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
#include <linux/fs.h> #include <linux/modversions.h>
#include <asm/uaccess.h> /* for put_user */ #define MODVERSIONS
#endif
/* Prototypes - this would normally go in a .h file #include <linux/kernel.h>
*/ #include <linux/module.h>
int init_module(void); #include <linux/fs.h>
void cleanup_module(void); #include <asm/uaccess.h> /* for put_user */
static int device_open(struct inode *, struct file *); #include <asm/errno.h>
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *); /* Prototypes - this would normally go in a .h file */
static ssize_t device_write(struct file *, const char *, size_t, loff_t *); int init_module(void);
void cleanup_module(void);
#define SUCCESS 0 static int device_open(struct inode *, struct file *);
#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */ static int device_release(struct inode *, struct file *);
#define BUF_LEN 80 /* Max length of the message from the device */ static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
/* Global variables are declared as static, so are global within the file. */ #define SUCCESS 0
#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */
static int Major; /* Major number assigned to our device driver */ #define BUF_LEN 80 /* Max length of the message from the device */
static int Device_Open = 0; /* Is device open? Used to prevent multiple */
access to the device */
static char msg[BUF_LEN]; /* The msg the device will give when asked */ /* Global variables are declared as static, so are global within the file. */
static char *msg_Ptr;
static int Major; /* Major number assigned to our device driver */
static struct file_operations fops = { static int Device_Open = 0; /* Is device open? Used to prevent multiple
.read = device_read, access to the device */
.write = device_write, static char msg[BUF_LEN]; /* The msg the device will give when asked */
.open = device_open, static char *msg_Ptr;
.release = device_release
}; static struct file_operations fops = {
.read = device_read,
.write = device_write,
/* Functions .open = device_open,
*/ .release = device_release
};
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops); /* Functions */
if (Major < 0) { int init_module(void)
printk ("Registering the character device failed with %d\n", Major); {
return Major; Major = register_chrdev(0, DEVICE_NAME, &fops);
}
if (Major < 0) {
printk("<1>I was assigned major number %d. To talk to\n", Major); printk ("Registering the character device failed with %d\n", Major);
printk("<1>the driver, create a dev file with\n"); return Major;
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>I was assigned major number %d. To talk to\n", Major);
printk("<1>Remove the device file and module when done.\n"); printk("<1>the driver, create a dev file with\n");
printk("'mknod /dev/hello c %d 0'.\n", Major);
return 0; 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");
void cleanup_module(void) return 0;
{ }
/* Unregister the device */
int ret = unregister_chrdev(Major, DEVICE_NAME);
if (ret < 0) printk("Error in unregister_chrdev: %d\n", ret); void cleanup_module(void)
} {
/* Unregister the device */
int ret = unregister_chrdev(Major, DEVICE_NAME);
/* Methods if (ret < 0) printk("Error in unregister_chrdev: %d\n", ret);
*/ }
/* Called when a process tries to open the device file, like
* "cat /dev/mycharfile" /* Methods */
*/
static int device_open(struct inode *inode, struct file *file) /* Called when a process tries to open the device file, like
{ * "cat /dev/mycharfile"
static int counter = 0; */
if (Device_Open) return -EBUSY; static int device_open(struct inode *inode, struct file *file)
Device_Open++; {
sprintf(msg,"I already told you %d times Hello world!\n", counter++"); static int counter = 0;
msg_Ptr = msg; if (Device_Open) return -EBUSY;
MOD_INC_USE_COUNT;
Device_Open++;
return SUCCESS; sprintf(msg,"I already told you %d times Hello world!\n", counter++);
} msg_Ptr = msg;
MOD_INC_USE_COUNT;
/* Called when a process closes the device file. return SUCCESS;
*/ }
static int device_release(struct inode *inode, struct file *file)
{
Device_Open --; /* We're now ready for our next caller */ /* Called when a process closes the device file */
static int device_release(struct inode *inode, struct file *file)
/* Decrement the usage count, or else once you opened the file, you'll {
never get get rid of the module. */ Device_Open --; /* We're now ready for our next caller */
MOD_DEC_USE_COUNT;
/* Decrement the usage count, or else once you opened the file, you'll
return 0; never get get rid of the module. */
} MOD_DEC_USE_COUNT;
return 0;
/* Called when a process, which already opened the dev file, attempts to }
read from it.
*/
static ssize_t device_read(struct file *filp, /* Called when a process, which already opened the dev file, attempts to
char *buffer, /* The buffer to fill with data */ read from it.
size_t length, /* The length of the buffer */ */
loff_t *offset) /* Our offset in the file */ static ssize_t device_read(struct file *filp,
{ char *buffer, /* The buffer to fill with data */
/* Number of bytes actually written to the buffer */ size_t length, /* The length of the buffer */
int bytes_read = 0; loff_t *offset) /* Our offset in the file */
{
/* If we're at the end of the message, return 0 signifying end of file */ /* Number of bytes actually written to the buffer */
if (*msg_Ptr == 0) return 0; int bytes_read = 0;
/* Actually put the data into the buffer */ /* If we're at the end of the message, return 0 signifying end of file */
while (length && *msg_Ptr) { if (*msg_Ptr == 0) return 0;
/* The buffer is in the user data segment, not the kernel segment; /* Actually put the data into the buffer */
* assignment won't work. We have to use put_user which copies data from while (length && *msg_Ptr) {
* the kernel data segment to the user data segment. */
put_user(*(msg_Ptr++), buffer++); /* The buffer is in the user data segment, not the kernel segment;
* assignment won't work. We have to use put_user which copies data from
length--; * the kernel data segment to the user data segment. */
bytes_read++; put_user(*(msg_Ptr++), buffer++);
}
length--;
/* Most read functions return the number of bytes put into the buffer */ bytes_read++;
return bytes_read; }
}
/* Most read functions return the number of bytes put into the buffer */
return bytes_read;
/* Called when a process writes to dev file: echo "hi" > /dev/hello */ }
static ssize_t device_write(struct file *filp,
const char *buff,
size_t len, /* Called when a process writes to dev file: echo "hi" > /dev/hello */
loff_t *off) static ssize_t device_write(struct file *filp,
{ const char *buff,
printk ("<1>Sorry, this operation isn't supported.\n"); size_t len,
return -EINVAL; loff_t *off)
} {
printk ("<1>Sorry, this operation isn't supported.\n");
return -EINVAL;
}
MODULE_LICENSE("GPL");
]]></programlisting> ]]></programlisting>
</example> </example>

View File

@ -40,8 +40,17 @@
<example><title>procfs.c</title> <example><title>procfs.c</title>
<programlisting><![CDATA[ <programlisting><![CDATA[
/* procfs.c - create a "file" in /proc /* procfs.c - create a "file" in /proc
*
* Copyright (C) 2001 by Peter Jay Salzman
*
* 08/02/2006 - Updated by Rodrigo Rubira Branco <rodrigo@kernelhacking.com>
*/ */
/* Kernel Programming */
#define MODULE
#define LINUX
#define __KERNEL__
#include <linux/kernel.h> /* We're doing kernel work */ #include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */ #include <linux/module.h> /* Specifically, a module */
@ -106,11 +115,17 @@
advantage of having the kernel source code for advantage of having the kernel source code for
free - use it. free - use it.
*/ */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
int procfile_read(char *buffer,
char **buffer_location, off_t offset,
int buffer_length, int *eof, void *data)
#else
int procfile_read(char *buffer, int procfile_read(char *buffer,
char **buffer_location, char **buffer_location,
off_t offset, off_t offset,
int buffer_length, int buffer_length,
int zero) int zero)
#endif
{ {
int len; /* The number of bytes actually used */ int len; /* The number of bytes actually used */
@ -150,7 +165,9 @@ int procfile_read(char *buffer,
return len; return len;
} }
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
struct proc_dir_entry *Our_Proc_File;
#else
struct proc_dir_entry Our_Proc_File = struct proc_dir_entry Our_Proc_File =
{ {
0, /* Inode number - ignore, it will be filled by 0, /* Inode number - ignore, it will be filled by
@ -169,13 +186,14 @@ struct proc_dir_entry Our_Proc_File =
NULL, /* functions which can be done on the inode NULL, /* functions which can be done on the inode
* (linking, removing, etc.) - we don't * (linking, removing, etc.) - we don't
* support any. */ * support any. */
procfile_read, /* The read function for this file, (struct file_operations *) procfile_read, /* The read function for this file,
* the function called when somebody * the function called when somebody
* tries to read something from it. */ * tries to read something from it. */
NULL /* We could have here a function to fill the NULL /* We could have here a function to fill the
* file's inode, to enable us to play with * file's inode, to enable us to play with
* permissions, ownership, etc. */ * permissions, ownership, etc. */
}; };
#endif
@ -192,7 +210,16 @@ int init_module()
* structure , so there's no more need for * structure , so there's no more need for
* proc_register_dynamic * proc_register_dynamic
*/ */
return proc_register(&proc_root, &Our_Proc_File); #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
Our_Proc_File=create_proc_read_entry("test", 0444, NULL, procfile_read, NULL);
if ( Our_Proc_File == NULL )
return -ENOMEM;
else
return 0;
#else
return proc_register(&proc_root, &Our_Proc_File);
#endif
#else #else
return proc_register_dynamic(&proc_root, &Our_Proc_File); return proc_register_dynamic(&proc_root, &Our_Proc_File);
#endif #endif
@ -207,9 +234,14 @@ int init_module()
/* Cleanup - unregister our file from /proc */ /* Cleanup - unregister our file from /proc */
void cleanup_module() void cleanup_module()
{ {
proc_unregister(&proc_root, Our_Proc_File.low_ino); #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
remove_proc_entry("test", NULL);
#else
proc_unregister(&proc_root, Our_Proc_File.low_ino);
#endif
} }
MODULE_LICENSE("GPL");
]]></programlisting> ]]></programlisting>
</example> </example>

View File

@ -4601,5 +4601,6 @@ little annoying.

View File

@ -1673,3 +1673,4 @@ little annoying.

View File

@ -2104,3 +2104,4 @@ little annoying.