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>
<programlisting><![CDATA[
/* 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/kernel.h> /* Needed for KERN_ALERT */
@ -31,6 +41,9 @@ void cleanup_module(void)
{
printk(KERN_ALERT "Goodbye world 1.\n");
}
MODULE_LICENSE("GPL");
]]></programlisting>
</example>
@ -189,7 +202,17 @@ clean:
<programlisting><![CDATA[
/* hello-2.c - Demonstrating the module_init() and module_exit() macros. This is the
* 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/kernel.h> // Needed for KERN_ALERT
#include <linux/init.h> // Needed for the macros
@ -210,6 +233,9 @@ static void hello_2_exit(void)
module_init(hello_2_init);
module_exit(hello_2_exit);
MODULE_LICENSE("GPL");
]]></programlisting>
</example>
@ -275,7 +301,17 @@ clean:
<example><title>hello-3.c</title>
<programlisting><![CDATA[
/* 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/kernel.h> /* Needed for KERN_ALERT */
#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_exit(hello_3_exit);
MODULE_LICENSE("GPL");
]]></programlisting>
</example>
@ -363,11 +402,21 @@ Module hello-3 loaded, with warnings
<example><title>hello-4.c</title>
<programlisting><![CDATA[
/* 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/kernel.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"
int init_hello_3(void);
@ -463,12 +512,23 @@ MODULE_SUPPORTED_DEVICE("testdevice");
<example><title>hello-5.c</title>
<programlisting><![CDATA[
/* 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/kernel.h>
#include <linux/init.h>
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
// 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 "mylong is a long integer: %li\n", mylong);
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;
}
@ -589,8 +649,17 @@ module_exit(hello_5_exit);
<example><title>start.c</title>
<programlisting><![CDATA[
/* 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/module.h> /* Specifically, a module */
@ -599,6 +668,9 @@ int init_module(void)
printk("Hello, world - this is the kernel speaking\n");
return 0;
}
MODULE_LICENSE("GPL");
]]></programlisting>
</example>
@ -611,12 +683,22 @@ int init_module(void)
<example><title>stop.c</title>
<programlisting><![CDATA[
/* 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)
#include <linux/modversions.h> /* Will be explained later */
#define MODVERSIONS
#endif
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#define __NO_VERSION__ /* It's not THE file of the kernel module */

View File

@ -198,151 +198,160 @@
<programlisting><![CDATA[
/* chardev.c: Creates a read-only char device that says how many times
* 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)
#include <linux/modversions.h>
#define MODVERSIONS
#endif
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* for put_user */
/* Prototypes - this would normally go in a .h file
*/
int init_module(void);
void cleanup_module(void);
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
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 *);
#define SUCCESS 0
#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */
#define BUF_LEN 80 /* Max length of the message from the device */
/* Global variables are declared as static, so are global within the file. */
static int Major; /* Major number assigned to our device driver */
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 */
static char *msg_Ptr;
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
/* Functions
*/
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk ("Registering the character 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");
return 0;
}
void cleanup_module(void)
{
/* Unregister the device */
int ret = unregister_chrdev(Major, DEVICE_NAME);
if (ret < 0) printk("Error in unregister_chrdev: %d\n", ret);
}
/* Methods
*/
/* Called when a process tries to open the device file, like
* "cat /dev/mycharfile"
*/
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;
MOD_INC_USE_COUNT;
return SUCCESS;
}
/* Called when a process closes the device file.
*/
static int device_release(struct inode *inode, struct file *file)
{
Device_Open --; /* We're now ready for our next caller */
/* Decrement the usage count, or else once you opened the file, you'll
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,
char *buffer, /* The buffer to fill with data */
size_t length, /* The length of the buffer */
loff_t *offset) /* Our offset in the file */
{
/* Number of bytes actually written to the buffer */
int bytes_read = 0;
/* If we're at the end of the message, return 0 signifying end of file */
if (*msg_Ptr == 0) return 0;
/* Actually put the data into the buffer */
while (length && *msg_Ptr) {
/* 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
* the kernel data segment to the user data segment. */
put_user(*(msg_Ptr++), buffer++);
length--;
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,
loff_t *off)
{
printk ("<1>Sorry, this operation isn't supported.\n");
return -EINVAL;
}
/* Kernel Programming */
#define MODULE
#define LINUX
#define __KERNEL__
#if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
#include <linux/modversions.h>
#define MODVERSIONS
#endif
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* for put_user */
#include <asm/errno.h>
/* Prototypes - this would normally go in a .h file */
int init_module(void);
void cleanup_module(void);
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
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 *);
#define SUCCESS 0
#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */
#define BUF_LEN 80 /* Max length of the message from the device */
/* Global variables are declared as static, so are global within the file. */
static int Major; /* Major number assigned to our device driver */
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 */
static char *msg_Ptr;
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
/* Functions */
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk ("Registering the character 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");
return 0;
}
void cleanup_module(void)
{
/* Unregister the device */
int ret = unregister_chrdev(Major, DEVICE_NAME);
if (ret < 0) printk("Error in unregister_chrdev: %d\n", ret);
}
/* Methods */
/* Called when a process tries to open the device file, like
* "cat /dev/mycharfile"
*/
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;
MOD_INC_USE_COUNT;
return SUCCESS;
}
/* Called when a process closes the device file */
static int device_release(struct inode *inode, struct file *file)
{
Device_Open --; /* We're now ready for our next caller */
/* Decrement the usage count, or else once you opened the file, you'll
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,
char *buffer, /* The buffer to fill with data */
size_t length, /* The length of the buffer */
loff_t *offset) /* Our offset in the file */
{
/* Number of bytes actually written to the buffer */
int bytes_read = 0;
/* If we're at the end of the message, return 0 signifying end of file */
if (*msg_Ptr == 0) return 0;
/* Actually put the data into the buffer */
while (length && *msg_Ptr) {
/* 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
* the kernel data segment to the user data segment. */
put_user(*(msg_Ptr++), buffer++);
length--;
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,
loff_t *off)
{
printk ("<1>Sorry, this operation isn't supported.\n");
return -EINVAL;
}
MODULE_LICENSE("GPL");
]]></programlisting>
</example>

View File

@ -40,8 +40,17 @@
<example><title>procfs.c</title>
<programlisting><![CDATA[
/* 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/module.h> /* Specifically, a module */
@ -106,11 +115,17 @@
advantage of having the kernel source code for
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,
char **buffer_location,
off_t offset,
int buffer_length,
int zero)
#endif
{
int len; /* The number of bytes actually used */
@ -150,7 +165,9 @@ int procfile_read(char *buffer,
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 =
{
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
* (linking, removing, etc.) - we don't
* 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
* tries to read something from it. */
NULL /* We could have here a function to fill the
* file's inode, to enable us to play with
* permissions, ownership, etc. */
};
#endif
@ -192,7 +210,16 @@ int init_module()
* structure , so there's no more need for
* 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
return proc_register_dynamic(&proc_root, &Our_Proc_File);
#endif
@ -207,9 +234,14 @@ int init_module()
/* Cleanup - unregister our file from /proc */
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>
</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.