mirror of https://github.com/tLDP/LDP
updated
This commit is contained in:
parent
6abd9d59f4
commit
b81ad25b5f
|
@ -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 */
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -4601,5 +4601,6 @@ little annoying.
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1673,3 +1673,4 @@ little annoying.
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -2104,3 +2104,4 @@ little annoying.
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue