Читать «Энциклопедия разработчика модулей ядра Linux» онлайн - страница 7
Ори Померанц
#define MODVERSIONS
#include <linux/modversions.h>
#endif
/* For character devices */
#include <linux/fs.h> /* The character device definitions are here */
#include <linux/wrapper.h> /* A wrapper which does next to nothing at present, but may help for compatibility with future versions of Linux */
/* In 2.2.3 /usr/include/linux/version.h includes a macro for this, but 2.0.35 doesn't - so I add it here if necessary. */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c)
((a)*65536+(b)*256+(c))
#endif
/* Conditional compilation. LINUX_VERSION_CODE is the code (as per KERNEL_VERSION) of this version. */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)
#include <asm/uaccess.h> /* for put_user */
#endif
#define SUCCESS 0
/* Device Declarations **************************** */
/* The name for our device, as it will appear in /proc/devices */
#define DEVICE_NAME "char_dev"
/* The maximum length of the message from the device */
#define BUF_LEN 80
/* Is the device open right now? Used to prevent concurent access into the same device */
static int Device_Open = 0;
/* The message the device will give when asked */
static char Message[BUF_LEN];
/* How far did the process reading the message get? Useful if the message is larger than the size of the buffer we get to fill in device_read. */
static char *Message_Ptr;
/* This function is called whenever a process attempts to open the device file */
static int device_open(struct inode *inode, struct file *file) {
static int counter = 0;
#ifdef DEBUG
printk("device_open(%p,%p)\n", inode, file);
#endif
/* This is how you get the minor device number in case you have more than one physical device using the driver. */
printk("Device: %d.%d\n", inode->i_rdev >> 8, inode->i_rdev & 0xFF);
/* We don't want to talk to two processes at the same time */
if (Device_Open) return -EBUSY;
/* If this was a process, we would have had to be
* more careful here.
*
* In the case of processes, the danger would be
* that one process might have check Device_Open
* and then be replaced by the schedualer by another
* process which runs this function. Then, when the
* first process was back on the CPU, it would assume
* the device is still not open.
*
* However, Linux guarantees that a process won't be
* replaced while it is running in kernel context.
*
* In the case of SMP, one CPU might increment
* Device_Open while another CPU is here, right after
* the check. However, in version 2.0 of the
* kernel this is not a problem because there's a lock
* to guarantee only one CPU will be kernel module at
* the same time. This is bad in terms of
* performance, so version 2.2 changed it.
* Unfortunately, I don't have access to an SMP box
* to check how it works with SMP. */
Device_Open++;
/* Initialize the message. */
sprintf(Message, "If I told you once, I told you %d times - %s", counter++, "Hello, world\n");
/* The only reason we're allowed to do this sprintf
* is because the maximum length of the message