mirror of
https://github.com/sysprog21/lkmpg.git
synced 2024-11-28 03:09:07 +08:00
Apply editorial changes
This patch makes source listing shorter and more compact, that helps when browsing.
This commit is contained in:
parent
d43259c553
commit
10c7a9433a
|
@ -17,11 +17,13 @@
|
||||||
static int button_irqs[] = {-1, -1};
|
static int button_irqs[] = {-1, -1};
|
||||||
|
|
||||||
/* Define GPIOs for LEDs.
|
/* Define GPIOs for LEDs.
|
||||||
Change the numbers for the GPIO on your board. */
|
* TODO: Change the numbers for the GPIO on your board.
|
||||||
|
*/
|
||||||
static struct gpio leds[] = {{4, GPIOF_OUT_INIT_LOW, "LED 1"}};
|
static struct gpio leds[] = {{4, GPIOF_OUT_INIT_LOW, "LED 1"}};
|
||||||
|
|
||||||
/* Define GPIOs for BUTTONS
|
/* Define GPIOs for BUTTONS
|
||||||
Change the numbers for the GPIO on your board. */
|
* TODO: Change the numbers for the GPIO on your board.
|
||||||
|
*/
|
||||||
static struct gpio buttons[] = {
|
static struct gpio buttons[] = {
|
||||||
{17, GPIOF_IN, "LED 1 ON BUTTON"},
|
{17, GPIOF_IN, "LED 1 ON BUTTON"},
|
||||||
{18, GPIOF_IN, "LED 1 OFF BUTTON"},
|
{18, GPIOF_IN, "LED 1 OFF BUTTON"},
|
||||||
|
@ -38,9 +40,7 @@ static void bottomhalf_tasklet_fn(unsigned long data)
|
||||||
|
|
||||||
DECLARE_TASKLET(buttontask, bottomhalf_tasklet_fn, 0L);
|
DECLARE_TASKLET(buttontask, bottomhalf_tasklet_fn, 0L);
|
||||||
|
|
||||||
/*
|
/* interrupt function triggered when a button is pressed */
|
||||||
* interrupt function triggered when a button is pressed
|
|
||||||
*/
|
|
||||||
static irqreturn_t button_isr(int irq, void *data)
|
static irqreturn_t button_isr(int irq, void *data)
|
||||||
{
|
{
|
||||||
/* Do something quickly right now */
|
/* Do something quickly right now */
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* chardev.h - the header file with the ioctl definitions.
|
* chardev.h - the header file with the ioctl definitions.
|
||||||
*
|
*
|
||||||
* The declarations here have to be in a header file, because
|
* The declarations here have to be in a header file, because they need
|
||||||
* they need to be known both to the kernel module
|
* to be known both to the kernel module (in chardev.c) and the process
|
||||||
* (in chardev.c) and the process calling ioctl (ioctl.c)
|
* calling ioctl (ioctl.c).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CHARDEV_H
|
#ifndef CHARDEV_H
|
||||||
|
@ -11,56 +11,39 @@
|
||||||
|
|
||||||
#include <linux/ioctl.h>
|
#include <linux/ioctl.h>
|
||||||
|
|
||||||
/*
|
/* The major device number. We can not rely on dynamic registration
|
||||||
* The major device number. We can't rely on dynamic
|
* any more, because ioctls need to know it.
|
||||||
* registration any more, because ioctls need to know
|
|
||||||
* it.
|
|
||||||
*/
|
*/
|
||||||
#define MAJOR_NUM 100
|
#define MAJOR_NUM 100
|
||||||
|
|
||||||
/*
|
/* Set the message of the device driver */
|
||||||
* Set the message of the device driver
|
|
||||||
*/
|
|
||||||
#define IOCTL_SET_MSG _IOW(MAJOR_NUM, 0, char *)
|
#define IOCTL_SET_MSG _IOW(MAJOR_NUM, 0, char *)
|
||||||
/*
|
/* _IOW means that we are creating an ioctl command number for passing
|
||||||
* _IOW means that we're creating an ioctl command
|
* information from a user process to the kernel module.
|
||||||
* number for passing information from a user process
|
|
||||||
* to the kernel module.
|
|
||||||
*
|
*
|
||||||
* The first arguments, MAJOR_NUM, is the major device
|
* The first arguments, MAJOR_NUM, is the major device number we are using.
|
||||||
* number we're using.
|
|
||||||
*
|
*
|
||||||
* The second argument is the number of the command
|
* The second argument is the number of the command (there could be several
|
||||||
* (there could be several with different meanings).
|
* with different meanings).
|
||||||
*
|
*
|
||||||
* The third argument is the type we want to get from
|
* The third argument is the type we want to get from the process to the
|
||||||
* the process to the kernel.
|
* kernel.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/* Get the message of the device driver */
|
||||||
* Get the message of the device driver
|
|
||||||
*/
|
|
||||||
#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)
|
#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)
|
||||||
/*
|
/* This IOCTL is used for output, to get the message of the device driver.
|
||||||
* This IOCTL is used for output, to get the message
|
* However, we still need the buffer to place the message in to be input,
|
||||||
* of the device driver. However, we still need the
|
|
||||||
* buffer to place the message in to be input,
|
|
||||||
* as it is allocated by the process.
|
* as it is allocated by the process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/* Get the n'th byte of the message */
|
||||||
* Get the n'th byte of the message
|
|
||||||
*/
|
|
||||||
#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int)
|
#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int)
|
||||||
/*
|
/* The IOCTL is used for both input and output. It receives from the user
|
||||||
* The IOCTL is used for both input and output. It
|
* a number, n, and returns Message[n].
|
||||||
* receives from the user a number, n, and returns
|
|
||||||
* Message[n].
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/* The name of the device file */
|
||||||
* The name of the device file
|
|
||||||
*/
|
|
||||||
#define DEVICE_FILE_NAME "char_dev"
|
#define DEVICE_FILE_NAME "char_dev"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,44 +17,34 @@
|
||||||
#define DEVICE_NAME "char_dev"
|
#define DEVICE_NAME "char_dev"
|
||||||
#define BUF_LEN 80
|
#define BUF_LEN 80
|
||||||
|
|
||||||
/*
|
/* Is the device open right now? Used to prevent concurent access into
|
||||||
* Is the device open right now? Used to prevent
|
* the same device
|
||||||
* concurent access into the same device
|
|
||||||
*/
|
*/
|
||||||
static int Device_Open = 0;
|
static int Device_Open = 0;
|
||||||
|
|
||||||
/*
|
/* The message the device will give when asked */
|
||||||
* The message the device will give when asked
|
|
||||||
*/
|
|
||||||
static char Message[BUF_LEN];
|
static char Message[BUF_LEN];
|
||||||
|
|
||||||
/*
|
/* How far did the process reading the message get? Useful if the message
|
||||||
* How far did the process reading the message get?
|
* is larger than the size of the buffer we get to fill in device_read.
|
||||||
* Useful if the message is larger than the size of the
|
|
||||||
* buffer we get to fill in device_read.
|
|
||||||
*/
|
*/
|
||||||
static char *Message_Ptr;
|
static char *Message_Ptr;
|
||||||
|
|
||||||
static int Major; /* Major number assigned to our device driver */
|
/* Major number assigned to our device driver */
|
||||||
|
static int Major;
|
||||||
static struct class *cls;
|
static struct class *cls;
|
||||||
|
|
||||||
/*
|
/* This is called whenever a process attempts to open the device file */
|
||||||
* This is called whenever a process attempts to open the device file
|
|
||||||
*/
|
|
||||||
static int device_open(struct inode *inode, struct file *file)
|
static int device_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
pr_info("device_open(%p)\n", file);
|
pr_info("device_open(%p)\n", file);
|
||||||
|
|
||||||
/*
|
/* We don't want to talk to two processes at the same time. */
|
||||||
* We don't want to talk to two processes at the same time
|
|
||||||
*/
|
|
||||||
if (Device_Open)
|
if (Device_Open)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
Device_Open++;
|
Device_Open++;
|
||||||
/*
|
/* Initialize the message */
|
||||||
* Initialize the message
|
|
||||||
*/
|
|
||||||
Message_Ptr = Message;
|
Message_Ptr = Message;
|
||||||
try_module_get(THIS_MODULE);
|
try_module_get(THIS_MODULE);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
@ -64,49 +54,36 @@ static int device_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
pr_info("device_release(%p,%p)\n", inode, file);
|
pr_info("device_release(%p,%p)\n", inode, file);
|
||||||
|
|
||||||
/*
|
/* We're now ready for our next caller */
|
||||||
* We're now ready for our next caller
|
|
||||||
*/
|
|
||||||
Device_Open--;
|
Device_Open--;
|
||||||
|
|
||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* This function is called whenever a process which has already opened the
|
||||||
* This function is called whenever a process which has already opened the
|
|
||||||
* device file attempts to read from it.
|
* device file attempts to read from it.
|
||||||
*/
|
*/
|
||||||
static ssize_t device_read(struct file *file, /* see include/linux/fs.h */
|
static ssize_t device_read(struct file *file, /* see include/linux/fs.h */
|
||||||
char __user *buffer, /* buffer to be
|
char __user *buffer, /* buffer to be filled */
|
||||||
* filled with data */
|
|
||||||
size_t length, /* length of the buffer */
|
size_t length, /* length of the buffer */
|
||||||
loff_t *offset)
|
loff_t *offset)
|
||||||
{
|
{
|
||||||
/*
|
/* Number of bytes actually written to the buffer */
|
||||||
* Number of bytes actually written to the buffer
|
|
||||||
*/
|
|
||||||
int bytes_read = 0;
|
int bytes_read = 0;
|
||||||
|
|
||||||
pr_info("device_read(%p,%p,%ld)\n", file, buffer, length);
|
pr_info("device_read(%p,%p,%ld)\n", file, buffer, length);
|
||||||
|
|
||||||
/*
|
/* If at the end of message, return 0 (which signifies end of file). */
|
||||||
* If we're at the end of the message, return 0
|
|
||||||
* (which signifies end of file)
|
|
||||||
*/
|
|
||||||
if (*Message_Ptr == 0)
|
if (*Message_Ptr == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/* Actually put the data into the buffer */
|
||||||
* Actually put the data into the buffer
|
|
||||||
*/
|
|
||||||
while (length && *Message_Ptr) {
|
while (length && *Message_Ptr) {
|
||||||
/*
|
/* Because the buffer is in the user data segment, not the kernel
|
||||||
* Because the buffer is in the user data segment,
|
* data segment, assignment would not work. Instead, we have to
|
||||||
* not the kernel data segment, assignment wouldn't
|
* use put_user which copies data from the kernel data segment to
|
||||||
* work. Instead, we have to use put_user which
|
* the user data segment.
|
||||||
* copies data from the kernel data segment to the
|
|
||||||
* user data segment.
|
|
||||||
*/
|
*/
|
||||||
put_user(*(Message_Ptr++), buffer++);
|
put_user(*(Message_Ptr++), buffer++);
|
||||||
length--;
|
length--;
|
||||||
|
@ -115,17 +92,13 @@ static ssize_t device_read(struct file *file, /* see include/linux/fs.h */
|
||||||
|
|
||||||
pr_info("Read %d bytes, %ld left\n", bytes_read, length);
|
pr_info("Read %d bytes, %ld left\n", bytes_read, length);
|
||||||
|
|
||||||
/*
|
/* Read functions are supposed to return the number of bytes actually
|
||||||
* Read functions are supposed to return the number
|
* inserted into the buffer.
|
||||||
* of bytes actually inserted into the buffer
|
|
||||||
*/
|
*/
|
||||||
return bytes_read;
|
return bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* called when somebody tries to write into our device file. */
|
||||||
* This function is called when somebody tries to
|
|
||||||
* write into our device file.
|
|
||||||
*/
|
|
||||||
static ssize_t device_write(struct file *file,
|
static ssize_t device_write(struct file *file,
|
||||||
const char __user *buffer,
|
const char __user *buffer,
|
||||||
size_t length,
|
size_t length,
|
||||||
|
@ -140,21 +113,17 @@ static ssize_t device_write(struct file *file,
|
||||||
|
|
||||||
Message_Ptr = Message;
|
Message_Ptr = Message;
|
||||||
|
|
||||||
/*
|
/* Again, return the number of input characters used. */
|
||||||
* Again, return the number of input characters used
|
|
||||||
*/
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* This function is called whenever a process tries to do an ioctl on our
|
||||||
* This function is called whenever a process tries to do an ioctl on our
|
|
||||||
* device file. We get two extra parameters (additional to the inode and file
|
* device file. We get two extra parameters (additional to the inode and file
|
||||||
* structures, which all device functions get): the number of the ioctl called
|
* structures, which all device functions get): the number of the ioctl called
|
||||||
* and the parameter given to the ioctl function.
|
* and the parameter given to the ioctl function.
|
||||||
*
|
*
|
||||||
* If the ioctl is write or read/write (meaning output is returned to the
|
* If the ioctl is write or read/write (meaning output is returned to the
|
||||||
* calling process), the ioctl call returns the output of this function.
|
* calling process), the ioctl call returns the output of this function.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
long device_ioctl(struct file *file, /* ditto */
|
long device_ioctl(struct file *file, /* ditto */
|
||||||
unsigned int ioctl_num, /* number and param for ioctl */
|
unsigned int ioctl_num, /* number and param for ioctl */
|
||||||
|
@ -164,21 +133,16 @@ long device_ioctl(struct file *file, /* ditto */
|
||||||
char *temp;
|
char *temp;
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
/*
|
/* Switch according to the ioctl called */
|
||||||
* Switch according to the ioctl called
|
|
||||||
*/
|
|
||||||
switch (ioctl_num) {
|
switch (ioctl_num) {
|
||||||
case IOCTL_SET_MSG:
|
case IOCTL_SET_MSG:
|
||||||
/*
|
/* Receive a pointer to a message (in user space) and set that to
|
||||||
* Receive a pointer to a message (in user space) and set that
|
* be the device's message. Get the parameter given to ioctl by
|
||||||
* to be the device's message. Get the parameter given to
|
* the process.
|
||||||
* ioctl by the process.
|
|
||||||
*/
|
*/
|
||||||
temp = (char *) ioctl_param;
|
temp = (char *) ioctl_param;
|
||||||
|
|
||||||
/*
|
/* Find the length of the message */
|
||||||
* Find the length of the message
|
|
||||||
*/
|
|
||||||
get_user(ch, temp);
|
get_user(ch, temp);
|
||||||
for (i = 0; ch && i < BUF_LEN; i++, temp++)
|
for (i = 0; ch && i < BUF_LEN; i++, temp++)
|
||||||
get_user(ch, temp);
|
get_user(ch, temp);
|
||||||
|
@ -187,23 +151,20 @@ long device_ioctl(struct file *file, /* ditto */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IOCTL_GET_MSG:
|
case IOCTL_GET_MSG:
|
||||||
/*
|
/* Give the current message to the calling process - the parameter
|
||||||
* Give the current message to the calling process -
|
* we got is a pointer, fill it.
|
||||||
* the parameter we got is a pointer, fill it.
|
|
||||||
*/
|
*/
|
||||||
i = device_read(file, (char *) ioctl_param, 99, 0);
|
i = device_read(file, (char *) ioctl_param, 99, 0);
|
||||||
|
|
||||||
/*
|
/* Put a zero at the end of the buffer, so it will be properly
|
||||||
* Put a zero at the end of the buffer, so it will be
|
* terminated.
|
||||||
* properly terminated
|
|
||||||
*/
|
*/
|
||||||
put_user('\0', (char *) ioctl_param + i);
|
put_user('\0', (char *) ioctl_param + i);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IOCTL_GET_NTH_BYTE:
|
case IOCTL_GET_NTH_BYTE:
|
||||||
/*
|
/* This ioctl is both input (ioctl_param) and output (the return
|
||||||
* This ioctl is both input (ioctl_param) and
|
* value of this function).
|
||||||
* output (the return value of this function)
|
|
||||||
*/
|
*/
|
||||||
return Message[ioctl_param];
|
return Message[ioctl_param];
|
||||||
break;
|
break;
|
||||||
|
@ -214,12 +175,10 @@ long device_ioctl(struct file *file, /* ditto */
|
||||||
|
|
||||||
/* Module Declarations */
|
/* Module Declarations */
|
||||||
|
|
||||||
/*
|
/* This structure will hold the functions to be called when a process does
|
||||||
* This structure will hold the functions to be called
|
* something to the device we created. Since a pointer to this structure
|
||||||
* when a process does something to the device we
|
* is kept in the devices table, it can't be local to init_module. NULL is
|
||||||
* created. Since a pointer to this structure is kept in
|
* for unimplemented functions.
|
||||||
* the devices table, it can't be local to
|
|
||||||
* init_module. NULL is for unimplemented functions.
|
|
||||||
*/
|
*/
|
||||||
struct file_operations Fops = {
|
struct file_operations Fops = {
|
||||||
.read = device_read,
|
.read = device_read,
|
||||||
|
|
|
@ -67,7 +67,6 @@ static int test_skcipher_result(struct skcipher_def *sk, int rc)
|
||||||
static void test_skcipher_callback(struct crypto_async_request *req, int error)
|
static void test_skcipher_callback(struct crypto_async_request *req, int error)
|
||||||
{
|
{
|
||||||
struct tcrypt_result *result = req->data;
|
struct tcrypt_result *result = req->data;
|
||||||
/* int ret; */
|
|
||||||
|
|
||||||
if (error == -EINPROGRESS)
|
if (error == -EINPROGRESS)
|
||||||
return;
|
return;
|
||||||
|
@ -77,7 +76,7 @@ static void test_skcipher_callback(struct crypto_async_request *req, int error)
|
||||||
pr_info("Encryption finished successfully\n");
|
pr_info("Encryption finished successfully\n");
|
||||||
|
|
||||||
/* decrypt data */
|
/* decrypt data */
|
||||||
/*
|
#if 0
|
||||||
memset((void*)sk.scratchpad, '-', CIPHER_BLOCK_SIZE);
|
memset((void*)sk.scratchpad, '-', CIPHER_BLOCK_SIZE);
|
||||||
ret = crypto_skcipher_decrypt(sk.req);
|
ret = crypto_skcipher_decrypt(sk.req);
|
||||||
ret = test_skcipher_result(&sk, ret);
|
ret = test_skcipher_result(&sk, ret);
|
||||||
|
@ -89,7 +88,7 @@ static void test_skcipher_callback(struct crypto_async_request *req, int error)
|
||||||
|
|
||||||
pr_info("Decryption request successful\n");
|
pr_info("Decryption request successful\n");
|
||||||
pr_info("Decrypted: %s\n", sk.scratchpad);
|
pr_info("Decrypted: %s\n", sk.scratchpad);
|
||||||
*/
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_skcipher_encrypt(char *plaintext,
|
static int test_skcipher_encrypt(char *plaintext,
|
||||||
|
|
|
@ -17,10 +17,9 @@ static void example_spinlock_static(void)
|
||||||
spin_lock_irqsave(&sl_static, flags);
|
spin_lock_irqsave(&sl_static, flags);
|
||||||
pr_info("Locked static spinlock\n");
|
pr_info("Locked static spinlock\n");
|
||||||
|
|
||||||
/* Do something or other safely.
|
/* Do something or other safely. Because this uses 100% CPU time, this
|
||||||
Because this uses 100% CPU time this
|
* code should take no more than a few milliseconds to run.
|
||||||
code should take no more than a few
|
*/
|
||||||
milliseconds to run */
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&sl_static, flags);
|
spin_unlock_irqrestore(&sl_static, flags);
|
||||||
pr_info("Unlocked static spinlock\n");
|
pr_info("Unlocked static spinlock\n");
|
||||||
|
@ -34,10 +33,9 @@ static void example_spinlock_dynamic(void)
|
||||||
spin_lock_irqsave(&sl_dynamic, flags);
|
spin_lock_irqsave(&sl_dynamic, flags);
|
||||||
pr_info("Locked dynamic spinlock\n");
|
pr_info("Locked dynamic spinlock\n");
|
||||||
|
|
||||||
/* Do something or other safely.
|
/* Do something or other safely. Because this uses 100% CPU time, this
|
||||||
Because this uses 100% CPU time this
|
* code should take no more than a few milliseconds to run.
|
||||||
code should take no more than a few
|
*/
|
||||||
milliseconds to run */
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&sl_dynamic, flags);
|
spin_unlock_irqrestore(&sl_dynamic, flags);
|
||||||
pr_info("Unlocked dynamic spinlock\n");
|
pr_info("Unlocked dynamic spinlock\n");
|
||||||
|
|
|
@ -16,14 +16,12 @@ static char *mystring = "blah";
|
||||||
static int myintArray[2] = {420, 420};
|
static int myintArray[2] = {420, 420};
|
||||||
static int arr_argc = 0;
|
static int arr_argc = 0;
|
||||||
|
|
||||||
/*
|
/* module_param(foo, int, 0000)
|
||||||
* module_param(foo, int, 0000)
|
* The first param is the parameters name.
|
||||||
* The first param is the parameters name
|
* The second param is its data type.
|
||||||
* The second param is it's data type
|
|
||||||
* The final argument is the permissions bits,
|
* The final argument is the permissions bits,
|
||||||
* for exposing parameters in sysfs (if non-zero) at a later stage.
|
* for exposing parameters in sysfs (if non-zero) at a later stage.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module_param(myshort, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
module_param(myshort, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||||
MODULE_PARM_DESC(myshort, "A short integer");
|
MODULE_PARM_DESC(myshort, "A short integer");
|
||||||
module_param(myint, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
module_param(myint, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||||
|
@ -33,13 +31,12 @@ MODULE_PARM_DESC(mylong, "A long integer");
|
||||||
module_param(mystring, charp, 0000);
|
module_param(mystring, charp, 0000);
|
||||||
MODULE_PARM_DESC(mystring, "A character string");
|
MODULE_PARM_DESC(mystring, "A character string");
|
||||||
|
|
||||||
/*
|
/* module_param_array(name, type, num, perm);
|
||||||
* module_param_array(name, type, num, perm);
|
* The first param is the parameter's (in this case the array's) name.
|
||||||
* The first param is the parameter's (in this case the array's) name
|
* The second param is the data type of the elements of the array.
|
||||||
* The second param is the data type of the elements of the array
|
* The third argument is a pointer to the variable that will store the number.
|
||||||
* The third argument is a pointer to the variable that will store the number
|
* of elements of the array initialized by the user at module loading time.
|
||||||
* of elements of the array initialized by the user at module loading time
|
* The fourth argument is the permission bits.
|
||||||
* The fourth argument is the permission bits
|
|
||||||
*/
|
*/
|
||||||
module_param_array(myintArray, int, &arr_argc, 0000);
|
module_param_array(myintArray, int, &arr_argc, 0000);
|
||||||
MODULE_PARM_DESC(myintArray, "An array of integers");
|
MODULE_PARM_DESC(myintArray, "An array of integers");
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/sysfs.h>
|
#include <linux/sysfs.h>
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
|
|
||||||
static struct kobject *mymodule;
|
static struct kobject *mymodule;
|
||||||
|
|
||||||
/* the variable you want to be able to change */
|
/* the variable you want to be able to change */
|
||||||
|
@ -63,3 +61,5 @@ static void __exit mymodule_exit(void)
|
||||||
|
|
||||||
module_init(mymodule_init);
|
module_init(mymodule_init);
|
||||||
module_exit(mymodule_exit);
|
module_exit(mymodule_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* from:
|
* from:
|
||||||
* https://github.com/wendlers/rpi-kmod-samples
|
* https://github.com/wendlers/rpi-kmod-samples
|
||||||
*
|
*
|
||||||
* Press one button to turn on a LED and another to turn it off
|
* Press one button to turn on a LED and another to turn it off.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
|
@ -16,17 +16,17 @@
|
||||||
static int button_irqs[] = {-1, -1};
|
static int button_irqs[] = {-1, -1};
|
||||||
|
|
||||||
/* Define GPIOs for LEDs.
|
/* Define GPIOs for LEDs.
|
||||||
Change the numbers for the GPIO on your board. */
|
* TODO: Change the numbers for the GPIO on your board.
|
||||||
|
*/
|
||||||
static struct gpio leds[] = {{4, GPIOF_OUT_INIT_LOW, "LED 1"}};
|
static struct gpio leds[] = {{4, GPIOF_OUT_INIT_LOW, "LED 1"}};
|
||||||
|
|
||||||
/* Define GPIOs for BUTTONS
|
/* Define GPIOs for BUTTONS
|
||||||
Change the numbers for the GPIO on your board. */
|
* TODO: Change the numbers for the GPIO on your board.
|
||||||
|
*/
|
||||||
static struct gpio buttons[] = {{17, GPIOF_IN, "LED 1 ON BUTTON"},
|
static struct gpio buttons[] = {{17, GPIOF_IN, "LED 1 ON BUTTON"},
|
||||||
{18, GPIOF_IN, "LED 1 OFF BUTTON"}};
|
{18, GPIOF_IN, "LED 1 OFF BUTTON"}};
|
||||||
|
|
||||||
/*
|
/* interrupt function triggered when a button is pressed. */
|
||||||
* interrupt function triggered when a button is pressed
|
|
||||||
*/
|
|
||||||
static irqreturn_t button_isr(int irq, void *data)
|
static irqreturn_t button_isr(int irq, void *data)
|
||||||
{
|
{
|
||||||
/* first button */
|
/* first button */
|
||||||
|
|
|
@ -47,17 +47,6 @@ static long test_ioctl_ioctl(struct file *filp,
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case IOCTL_VALSET:
|
case IOCTL_VALSET:
|
||||||
|
|
||||||
/*
|
|
||||||
if (!capable(CAP_SYS_ADMIN)) {
|
|
||||||
retval = -EPERM;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (!access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd))) {
|
|
||||||
retval = -EFAULT;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if (copy_from_user(&data, (int __user *) arg, sizeof(data))) {
|
if (copy_from_user(&data, (int __user *) arg, sizeof(data))) {
|
||||||
retval = -EFAULT;
|
retval = -EFAULT;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -70,12 +59,6 @@ static long test_ioctl_ioctl(struct file *filp,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IOCTL_VALGET:
|
case IOCTL_VALGET:
|
||||||
/*
|
|
||||||
if (!access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd))) {
|
|
||||||
retval = -EFAULT;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
read_lock(&ioctl_data->lock);
|
read_lock(&ioctl_data->lock);
|
||||||
val = ioctl_data->val;
|
val = ioctl_data->val;
|
||||||
read_unlock(&ioctl_data->lock);
|
read_unlock(&ioctl_data->lock);
|
||||||
|
@ -93,10 +76,6 @@ static long test_ioctl_ioctl(struct file *filp,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IOCTL_VALSET_NUM:
|
case IOCTL_VALSET_NUM:
|
||||||
/*
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
|
||||||
return -EPERM;
|
|
||||||
*/
|
|
||||||
ioctl_num = arg;
|
ioctl_num = arg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include <linux/console_struct.h> /* For vc_cons */
|
#include <linux/console_struct.h> /* For vc_cons */
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Example module illustrating the use of Keyboard LEDs.");
|
MODULE_DESCRIPTION("Example module illustrating the use of Keyboard LEDs.");
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
|
|
||||||
struct timer_list my_timer;
|
struct timer_list my_timer;
|
||||||
struct tty_driver *my_driver;
|
struct tty_driver *my_driver;
|
||||||
|
@ -22,19 +21,16 @@ char kbledstatus = 0;
|
||||||
#define ALL_LEDS_ON 0x07
|
#define ALL_LEDS_ON 0x07
|
||||||
#define RESTORE_LEDS 0xFF
|
#define RESTORE_LEDS 0xFF
|
||||||
|
|
||||||
/*
|
/* Function my_timer_func blinks the keyboard LEDs periodically by invoking
|
||||||
* Function my_timer_func blinks the keyboard LEDs periodically by invoking
|
|
||||||
* command KDSETLED of ioctl() on the keyboard driver. To learn more on virtual
|
* command KDSETLED of ioctl() on the keyboard driver. To learn more on virtual
|
||||||
* terminal ioctl operations, please see file:
|
* terminal ioctl operations, please see file:
|
||||||
* /usr/src/linux/drivers/char/vt_ioctl.c, function vt_ioctl().
|
* drivers/char/vt_ioctl.c, function vt_ioctl().
|
||||||
*
|
*
|
||||||
* The argument to KDSETLED is alternatively set to 7 (thus causing the led
|
* The argument to KDSETLED is alternatively set to 7 (thus causing the led
|
||||||
* mode to be set to LED_SHOW_IOCTL, and all the leds are lit) and to 0xFF
|
* mode to be set to LED_SHOW_IOCTL, and all the leds are lit) and to 0xFF
|
||||||
* (any value above 7 switches back the led mode to LED_SHOW_FLAGS, thus
|
* (any value above 7 switches back the led mode to LED_SHOW_FLAGS, thus
|
||||||
* the LEDs reflect the actual keyboard status). To learn more on this,
|
* the LEDs reflect the actual keyboard status). To learn more on this,
|
||||||
* please see file:
|
* please see file: drivers/char/keyboard.c, function setledstate().
|
||||||
* /usr/src/linux/drivers/char/keyboard.c, function setledstate().
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void my_timer_func(unsigned long ptr)
|
static void my_timer_func(unsigned long ptr)
|
||||||
|
@ -70,9 +66,7 @@ static int __init kbleds_init(void)
|
||||||
my_driver = vc_cons[fg_console].d->port.tty->driver;
|
my_driver = vc_cons[fg_console].d->port.tty->driver;
|
||||||
pr_info("kbleds: tty driver magic %x\n", my_driver->magic);
|
pr_info("kbleds: tty driver magic %x\n", my_driver->magic);
|
||||||
|
|
||||||
/*
|
/* Set up the LED blink timer the first time. */
|
||||||
* Set up the LED blink timer the first time
|
|
||||||
*/
|
|
||||||
timer_setup(&my_timer, (void *) &my_timer_func,
|
timer_setup(&my_timer, (void *) &my_timer_func,
|
||||||
(unsigned long) &kbledstatus);
|
(unsigned long) &kbledstatus);
|
||||||
my_timer.expires = jiffies + BLINK_DELAY;
|
my_timer.expires = jiffies + BLINK_DELAY;
|
||||||
|
@ -91,3 +85,5 @@ static void __exit kbleds_cleanup(void)
|
||||||
|
|
||||||
module_init(kbleds_init);
|
module_init(kbleds_init);
|
||||||
module_exit(kbleds_cleanup);
|
module_exit(kbleds_cleanup);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* print_string.c - Send output to the tty we're running on, regardless if it's
|
* print_string.c - Send output to the tty we're running on, regardless if
|
||||||
* through X11, telnet, etc. We do this by printing the string to the tty
|
* it is through X11, telnet, etc. We do this by printing the string to the
|
||||||
* associated with the current task.
|
* tty associated with the current task.
|
||||||
*/
|
*/
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
@ -9,60 +9,52 @@
|
||||||
#include <linux/sched.h> /* For current */
|
#include <linux/sched.h> /* For current */
|
||||||
#include <linux/tty.h> /* For the tty declarations */
|
#include <linux/tty.h> /* For the tty declarations */
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
|
|
||||||
static void print_string(char *str)
|
static void print_string(char *str)
|
||||||
{
|
{
|
||||||
struct tty_struct *my_tty;
|
struct tty_struct *my_tty;
|
||||||
const struct tty_operations *ttyops;
|
const struct tty_operations *ttyops;
|
||||||
|
|
||||||
/*
|
/* The tty for the current task, for 2.6.6+ kernels */
|
||||||
* The tty for the current task, for 2.6.6+ kernels
|
|
||||||
*/
|
|
||||||
my_tty = get_current_tty();
|
my_tty = get_current_tty();
|
||||||
ttyops = my_tty->driver->ops;
|
ttyops = my_tty->driver->ops;
|
||||||
|
|
||||||
/*
|
/* If my_tty is NULL, the current task has no tty you can print to (i.e.,
|
||||||
* If my_tty is NULL, the current task has no tty you can print to
|
* if it is a daemon). If so, there is nothing we can do.
|
||||||
* (ie, if it's a daemon). If so, there's nothing we can do.
|
|
||||||
*/
|
*/
|
||||||
if (my_tty != NULL) {
|
if (my_tty) {
|
||||||
/*
|
/* my_tty->driver is a struct which holds the tty's functions,
|
||||||
* my_tty->driver is a struct which holds the tty's functions,
|
|
||||||
* one of which (write) is used to write strings to the tty.
|
* one of which (write) is used to write strings to the tty.
|
||||||
* It can be used to take a string either from the user's or
|
* It can be used to take a string either from the user's or
|
||||||
* kernel's memory segment.
|
* kernel's memory segment.
|
||||||
*
|
*
|
||||||
* The function's 1st parameter is the tty to write to,
|
* The function's 1st parameter is the tty to write to, because the
|
||||||
* because the same function would normally be used for all
|
* same function would normally be used for all tty's of a certain
|
||||||
* tty's of a certain type.
|
* type.
|
||||||
* The 2nd parameter is a pointer to a string.
|
* The 2nd parameter is a pointer to a string.
|
||||||
* The 3rd parameter is the length of the string.
|
* The 3rd parameter is the length of the string.
|
||||||
*
|
*
|
||||||
* As you will see below, sometimes it's necessary to use
|
* As you will see below, sometimes it's necessary to use
|
||||||
* preprocessor stuff to create code that works for different
|
* preprocessor stuff to create code that works for different
|
||||||
* kernel versions. The (naive) approach we've taken here
|
* kernel versions. The (naive) approach we've taken here does not
|
||||||
* does not scale well. The right way to deal with this
|
* scale well. The right way to deal with this is described in
|
||||||
* is described in section 2 of
|
* section 2 of
|
||||||
* linux/Documentation/SubmittingPatches
|
* linux/Documentation/SubmittingPatches
|
||||||
*/
|
*/
|
||||||
(ttyops->write)(my_tty, /* The tty itself */
|
(ttyops->write)(my_tty, /* The tty itself */
|
||||||
str, /* String */
|
str, /* String */
|
||||||
strlen(str)); /* Length */
|
strlen(str)); /* Length */
|
||||||
|
|
||||||
/*
|
/* ttys were originally hardware devices, which (usually) strictly
|
||||||
* ttys were originally hardware devices, which (usually)
|
* followed the ASCII standard. In ASCII, to move to a new line you
|
||||||
* strictly followed the ASCII standard. In ASCII, to move to
|
* need two characters, a carriage return and a line feed. On Unix,
|
||||||
* a new line you need two characters, a carriage return and a
|
* the ASCII line feed is used for both purposes - so we can not
|
||||||
* line feed. On Unix, the ASCII line feed is used for both
|
* just use \n, because it would not have a carriage return and the
|
||||||
* purposes - so we can't just use \n, because it wouldn't have
|
* next line will start at the column right after the line feed.
|
||||||
* a carriage return and the next line will start at the
|
|
||||||
* column right after the line feed.
|
|
||||||
*
|
*
|
||||||
* This is why text files are different between Unix and
|
* This is why text files are different between Unix and MS Windows.
|
||||||
* MS Windows. In CP/M and derivatives, like MS-DOS and
|
* In CP/M and derivatives, like MS-DOS and MS Windows, the ASCII
|
||||||
* MS Windows, the ASCII standard was strictly adhered to,
|
* standard was strictly adhered to, and therefore a newline requirs
|
||||||
* and therefore a newline requirs both a LF and a CR.
|
* both a LF and a CR.
|
||||||
*/
|
*/
|
||||||
(ttyops->write)(my_tty, "\015\012", 2);
|
(ttyops->write)(my_tty, "\015\012", 2);
|
||||||
}
|
}
|
||||||
|
@ -81,3 +73,5 @@ static void __exit print_string_exit(void)
|
||||||
|
|
||||||
module_init(print_string_init);
|
module_init(print_string_init);
|
||||||
module_exit(print_string_exit);
|
module_exit(print_string_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -15,28 +15,16 @@
|
||||||
#define PROCFS_MAX_SIZE 1024
|
#define PROCFS_MAX_SIZE 1024
|
||||||
#define PROCFS_NAME "buffer1k"
|
#define PROCFS_NAME "buffer1k"
|
||||||
|
|
||||||
/**
|
/* This structure hold information about the /proc file */
|
||||||
* This structure hold information about the /proc file
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static struct proc_dir_entry *Our_Proc_File;
|
static struct proc_dir_entry *Our_Proc_File;
|
||||||
|
|
||||||
/**
|
/* The buffer used to store character for this module */
|
||||||
* The buffer used to store character for this module
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static char procfs_buffer[PROCFS_MAX_SIZE];
|
static char procfs_buffer[PROCFS_MAX_SIZE];
|
||||||
|
|
||||||
/**
|
/* The size of the buffer */
|
||||||
* The size of the buffer
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static unsigned long procfs_buffer_size = 0;
|
static unsigned long procfs_buffer_size = 0;
|
||||||
|
|
||||||
/**
|
/* This function is called then the /proc file is read */
|
||||||
* This function is called then the /proc file is read
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
ssize_t procfile_read(struct file *filePointer,
|
ssize_t procfile_read(struct file *filePointer,
|
||||||
char *buffer,
|
char *buffer,
|
||||||
size_t buffer_length,
|
size_t buffer_length,
|
||||||
|
@ -57,11 +45,7 @@ ssize_t procfile_read(struct file *filePointer,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function is called with the /proc file is written. */
|
||||||
/**
|
|
||||||
* This function is called with the /proc file is written
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static ssize_t procfile_write(struct file *file,
|
static ssize_t procfile_write(struct file *file,
|
||||||
const char *buff,
|
const char *buff,
|
||||||
size_t len,
|
size_t len,
|
||||||
|
|
136
examples/sleep.c
136
examples/sleep.c
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* sleep.c - create a /proc file, and if several processes try to open it at
|
* sleep.c - create a /proc file, and if several processes try to open it
|
||||||
* the same time, put all but one to sleep
|
* at the same time, put all but one to sleep.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h> /* We're doing kernel work */
|
#include <linux/kernel.h> /* We're doing kernel work */
|
||||||
|
@ -15,13 +15,8 @@
|
||||||
#define HAVE_PROC_OPS
|
#define HAVE_PROC_OPS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/* Here we keep the last message received, to prove that we can process our
|
||||||
* The module's file functions
|
* input.
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Here we keep the last message received, to prove that we can process our
|
|
||||||
* input
|
|
||||||
*/
|
*/
|
||||||
#define MESSAGE_LENGTH 80
|
#define MESSAGE_LENGTH 80
|
||||||
static char Message[MESSAGE_LENGTH];
|
static char Message[MESSAGE_LENGTH];
|
||||||
|
@ -29,10 +24,9 @@ static char Message[MESSAGE_LENGTH];
|
||||||
static struct proc_dir_entry *Our_Proc_File;
|
static struct proc_dir_entry *Our_Proc_File;
|
||||||
#define PROC_ENTRY_FILENAME "sleep"
|
#define PROC_ENTRY_FILENAME "sleep"
|
||||||
|
|
||||||
/*
|
/* Since we use the file operations struct, we can't use the special proc
|
||||||
* Since we use the file operations struct, we can't use the special proc
|
|
||||||
* output provisions - we have to use a standard read function, which is this
|
* output provisions - we have to use a standard read function, which is this
|
||||||
* function
|
* function.
|
||||||
*/
|
*/
|
||||||
static ssize_t module_output(struct file *file, /* see include/linux/fs.h */
|
static ssize_t module_output(struct file *file, /* see include/linux/fs.h */
|
||||||
char *buf, /* The buffer to put data to
|
char *buf, /* The buffer to put data to
|
||||||
|
@ -44,19 +38,14 @@ static ssize_t module_output(struct file *file, /* see include/linux/fs.h */
|
||||||
int i;
|
int i;
|
||||||
char message[MESSAGE_LENGTH + 30];
|
char message[MESSAGE_LENGTH + 30];
|
||||||
|
|
||||||
/*
|
/* Return 0 to signify end of file - that we have nothing more to say
|
||||||
* Return 0 to signify end of file - that we have nothing
|
* at this point.
|
||||||
* more to say at this point.
|
|
||||||
*/
|
*/
|
||||||
if (finished) {
|
if (finished) {
|
||||||
finished = 0;
|
finished = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If you don't understand this by now, you're hopeless as a kernel
|
|
||||||
* programmer.
|
|
||||||
*/
|
|
||||||
sprintf(message, "Last input:%s\n", Message);
|
sprintf(message, "Last input:%s\n", Message);
|
||||||
for (i = 0; i < len && message[i]; i++)
|
for (i = 0; i < len && message[i]; i++)
|
||||||
put_user(message[i], buf + i);
|
put_user(message[i], buf + i);
|
||||||
|
@ -65,9 +54,8 @@ static ssize_t module_output(struct file *file, /* see include/linux/fs.h */
|
||||||
return i; /* Return the number of bytes "read" */
|
return i; /* Return the number of bytes "read" */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* This function receives input from the user when the user writes to the
|
||||||
* This function receives input from the user when the user writes to the /proc
|
* /proc file.
|
||||||
* file.
|
|
||||||
*/
|
*/
|
||||||
static ssize_t module_input(struct file *file, /* The file itself */
|
static ssize_t module_input(struct file *file, /* The file itself */
|
||||||
const char *buf, /* The buffer with input */
|
const char *buf, /* The buffer with input */
|
||||||
|
@ -76,62 +64,46 @@ static ssize_t module_input(struct file *file, /* The file itself */
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/* Put the input into Message, where module_output will later be able
|
||||||
* Put the input into Message, where module_output will later be
|
* to use it.
|
||||||
* able to use it
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < MESSAGE_LENGTH - 1 && i < length; i++)
|
for (i = 0; i < MESSAGE_LENGTH - 1 && i < length; i++)
|
||||||
get_user(Message[i], buf + i);
|
get_user(Message[i], buf + i);
|
||||||
/*
|
/* we want a standard, zero terminated string */
|
||||||
* we want a standard, zero terminated string
|
|
||||||
*/
|
|
||||||
Message[i] = '\0';
|
Message[i] = '\0';
|
||||||
|
|
||||||
/*
|
/* We need to return the number of input characters used */
|
||||||
* We need to return the number of input characters used
|
|
||||||
*/
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* 1 if the file is currently open by somebody */
|
||||||
* 1 if the file is currently open by somebody
|
|
||||||
*/
|
|
||||||
int Already_Open = 0;
|
int Already_Open = 0;
|
||||||
|
|
||||||
/*
|
/* Queue of processes who want our file */
|
||||||
* Queue of processes who want our file
|
|
||||||
*/
|
|
||||||
DECLARE_WAIT_QUEUE_HEAD(WaitQ);
|
DECLARE_WAIT_QUEUE_HEAD(WaitQ);
|
||||||
/*
|
|
||||||
* Called when the /proc file is opened
|
/* Called when the /proc file is opened */
|
||||||
*/
|
|
||||||
static int module_open(struct inode *inode, struct file *file)
|
static int module_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
/*
|
/* If the file's flags include O_NONBLOCK, it means the process does not
|
||||||
* If the file's flags include O_NONBLOCK, it means the process doesn't
|
* want to wait for the file. In this case, if the file is already open,
|
||||||
* want to wait for the file. In this case, if the file is already
|
* we should fail with -EAGAIN, meaning "you will have to try again",
|
||||||
* open, we should fail with -EAGAIN, meaning "you'll have to try
|
* instead of blocking a process which would rather stay awake.
|
||||||
* again", instead of blocking a process which would rather stay awake.
|
|
||||||
*/
|
*/
|
||||||
if ((file->f_flags & O_NONBLOCK) && Already_Open)
|
if ((file->f_flags & O_NONBLOCK) && Already_Open)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
/*
|
/* This is the correct place for try_module_get(THIS_MODULE) because if
|
||||||
* This is the correct place for try_module_get(THIS_MODULE) because
|
* a process is in the loop, which is within the kernel module,
|
||||||
* if a process is in the loop, which is within the kernel module,
|
|
||||||
* the kernel module must not be removed.
|
* the kernel module must not be removed.
|
||||||
*/
|
*/
|
||||||
try_module_get(THIS_MODULE);
|
try_module_get(THIS_MODULE);
|
||||||
|
|
||||||
/*
|
/* If the file is already open, wait until it is not. */
|
||||||
* If the file is already open, wait until it isn't
|
|
||||||
*/
|
|
||||||
|
|
||||||
while (Already_Open) {
|
while (Already_Open) {
|
||||||
int i, is_sig = 0;
|
int i, is_sig = 0;
|
||||||
|
|
||||||
/*
|
/* This function puts the current process, including any system
|
||||||
* This function puts the current process, including any system
|
|
||||||
* calls, such as us, to sleep. Execution will be resumed right
|
* calls, such as us, to sleep. Execution will be resumed right
|
||||||
* after the function call, either because somebody called
|
* after the function call, either because somebody called
|
||||||
* wake_up(&WaitQ) (only module_close does that, when the file
|
* wake_up(&WaitQ) (only module_close does that, when the file
|
||||||
|
@ -140,38 +112,20 @@ static int module_open(struct inode *inode, struct file *file)
|
||||||
*/
|
*/
|
||||||
wait_event_interruptible(WaitQ, !Already_Open);
|
wait_event_interruptible(WaitQ, !Already_Open);
|
||||||
|
|
||||||
/*
|
/* If we woke up because we got a signal we're not blocking,
|
||||||
* If we woke up because we got a signal we're not blocking,
|
|
||||||
* return -EINTR (fail the system call). This allows processes
|
* return -EINTR (fail the system call). This allows processes
|
||||||
* to be killed or stopped.
|
* to be killed or stopped.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Emmanuel Papirakis:
|
|
||||||
*
|
|
||||||
* This is a little update to work with 2.2.*. Signals now are
|
|
||||||
* contained in two words (64 bits) and are stored in a structure that
|
|
||||||
* contains an array of two unsigned longs. We now have to make 2
|
|
||||||
* checks in our if.
|
|
||||||
*
|
|
||||||
* Ori Pomerantz:
|
|
||||||
*
|
|
||||||
* Nobody promised me they'll never use more than 64 bits, or that this
|
|
||||||
* book won't be used for a version of Linux with a word size of 16
|
|
||||||
* bits. This code would work in any case.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < _NSIG_WORDS && !is_sig; i++)
|
for (i = 0; i < _NSIG_WORDS && !is_sig; i++)
|
||||||
is_sig = current->pending.signal.sig[i] & ~current->blocked.sig[i];
|
is_sig = current->pending.signal.sig[i] & ~current->blocked.sig[i];
|
||||||
|
|
||||||
if (is_sig) {
|
if (is_sig) {
|
||||||
/*
|
/* It is important to put module_put(THIS_MODULE) here, because
|
||||||
* It's important to put module_put(THIS_MODULE) here,
|
* for processes where the open is interrupted there will never
|
||||||
* because for processes where the open is interrupted
|
* be a corresponding close. If we do not decrement the usage
|
||||||
* there will never be a corresponding close. If we
|
* count here, we will be left with a positive usage count
|
||||||
* don't decrement the usage count here, we will be
|
* which we will have no way to bring down to zero, giving us
|
||||||
* left with a positive usage count which we'll have no
|
* an immortal module, which can only be killed by rebooting
|
||||||
* way to bring down to zero, giving us an immortal
|
|
||||||
* module, which can only be killed by rebooting
|
|
||||||
* the machine.
|
* the machine.
|
||||||
*/
|
*/
|
||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
|
@ -179,32 +133,24 @@ static int module_open(struct inode *inode, struct file *file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* If we got here, Already_Open must be zero. */
|
||||||
* If we got here, Already_Open must be zero
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/* Open the file */
|
||||||
* Open the file
|
|
||||||
*/
|
|
||||||
Already_Open = 1;
|
Already_Open = 1;
|
||||||
return 0; /* Allow the access */
|
return 0; /* Allow the access */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Called when the /proc file is closed */
|
||||||
* Called when the /proc file is closed
|
|
||||||
*/
|
|
||||||
int module_close(struct inode *inode, struct file *file)
|
int module_close(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
/*
|
/* Set Already_Open to zero, so one of the processes in the WaitQ will
|
||||||
* Set Already_Open to zero, so one of the processes in the WaitQ will
|
|
||||||
* be able to set Already_Open back to one and to open the file. All
|
* be able to set Already_Open back to one and to open the file. All
|
||||||
* the other processes will be called when Already_Open is back to one,
|
* the other processes will be called when Already_Open is back to one,
|
||||||
* so they'll go back to sleep.
|
* so they'll go back to sleep.
|
||||||
*/
|
*/
|
||||||
Already_Open = 0;
|
Already_Open = 0;
|
||||||
|
|
||||||
/*
|
/* Wake up all the processes in WaitQ, so if anybody is waiting for the
|
||||||
* Wake up all the processes in WaitQ, so if anybody is waiting for the
|
|
||||||
* file, they can have it.
|
* file, they can have it.
|
||||||
*/
|
*/
|
||||||
wake_up(&WaitQ);
|
wake_up(&WaitQ);
|
||||||
|
@ -214,13 +160,11 @@ int module_close(struct inode *inode, struct file *file)
|
||||||
return 0; /* success */
|
return 0; /* success */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Structures to register as the /proc file, with pointers to all the relevant
|
||||||
* Structures to register as the /proc file, with pointers to all the relevant
|
|
||||||
* functions.
|
* functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/* File operations for our proc file. This is where we place pointers to all
|
||||||
* File operations for our proc file. This is where we place pointers to all
|
|
||||||
* the functions called when somebody tries to do something to our file. NULL
|
* the functions called when somebody tries to do something to our file. NULL
|
||||||
* means we don't want to deal with something.
|
* means we don't want to deal with something.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* start.c - Illustration of multi filed modules
|
* start.c - Illustration of multi filed modules
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h> /* We're doing kernel work */
|
#include <linux/kernel.h> /* We are doing kernel work */
|
||||||
#include <linux/module.h> /* Specifically, a module */
|
#include <linux/module.h> /* Specifically, a module */
|
||||||
|
|
||||||
int init_module(void)
|
int init_module(void)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* stop.c - Illustration of multi filed modules
|
* stop.c - Illustration of multi filed modules
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h> /* We're doing kernel work */
|
#include <linux/kernel.h> /* We are doing kernel work */
|
||||||
#include <linux/module.h> /* Specifically, a module */
|
#include <linux/module.h> /* Specifically, a module */
|
||||||
|
|
||||||
void cleanup_module()
|
void cleanup_module()
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
*
|
*
|
||||||
* System call "stealing" sample.
|
* System call "stealing" sample.
|
||||||
*
|
*
|
||||||
* Disables page protection at a processor level by
|
* Disables page protection at a processor level by changing the 16th bit
|
||||||
* changing the 16th bit in the cr0 register (could be Intel specific)
|
* in the cr0 register (could be Intel specific).
|
||||||
*
|
*
|
||||||
* Based on example by Peter Jay Salzman and
|
* Based on example by Peter Jay Salzman and
|
||||||
* https://bbs.archlinux.org/viewtopic.php?id=139406
|
* https://bbs.archlinux.org/viewtopic.php?id=139406
|
||||||
|
@ -17,9 +17,8 @@
|
||||||
#include <linux/syscalls.h>
|
#include <linux/syscalls.h>
|
||||||
#include <linux/unistd.h> /* The list of system calls */
|
#include <linux/unistd.h> /* The list of system calls */
|
||||||
|
|
||||||
/*
|
/* For the current (process) structure, we need this to know who the
|
||||||
* For the current (process) structure, we need
|
* current user is.
|
||||||
* this to know who the current user is.
|
|
||||||
*/
|
*/
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
@ -27,50 +26,38 @@
|
||||||
unsigned long **sys_call_table;
|
unsigned long **sys_call_table;
|
||||||
unsigned long original_cr0;
|
unsigned long original_cr0;
|
||||||
|
|
||||||
/*
|
/* UID we want to spy on - will be filled from the command line. */
|
||||||
* UID we want to spy on - will be filled from the
|
|
||||||
* command line
|
|
||||||
*/
|
|
||||||
static int uid;
|
static int uid;
|
||||||
module_param(uid, int, 0644);
|
module_param(uid, int, 0644);
|
||||||
|
|
||||||
/*
|
/* A pointer to the original system call. The reason we keep this, rather
|
||||||
* A pointer to the original system call. The reason
|
* than call the original function (sys_open), is because somebody else
|
||||||
* we keep this, rather than call the original function
|
* might have replaced the system call before us. Note that this is not
|
||||||
* (sys_open), is because somebody else might have
|
* 100% safe, because if another module replaced sys_open before us,
|
||||||
* replaced the system call before us. Note that this
|
* then when we are inserted, we will call the function in that module -
|
||||||
* is not 100% safe, because if another module
|
* and it might be removed before we are.
|
||||||
* replaced sys_open before us, then when we're inserted
|
|
||||||
* we'll call the function in that module - and it
|
|
||||||
* might be removed before we are.
|
|
||||||
*
|
*
|
||||||
* Another reason for this is that we can't get sys_open.
|
* Another reason for this is that we can not get sys_open.
|
||||||
* It's a static variable, so it is not exported.
|
* It is a static variable, so it is not exported.
|
||||||
*/
|
*/
|
||||||
asmlinkage int (*original_call)(const char *, int, int);
|
asmlinkage int (*original_call)(const char *, int, int);
|
||||||
|
|
||||||
/*
|
/* The function we will replace sys_open (the function called when you
|
||||||
* The function we'll replace sys_open (the function
|
* call the open system call) with. To find the exact prototype, with
|
||||||
* called when you call the open system call) with. To
|
* the number and type of arguments, we find the original function first
|
||||||
* find the exact prototype, with the number and type
|
* (it is at fs/open.c).
|
||||||
* of arguments, we find the original function first
|
|
||||||
* (it's at fs/open.c).
|
|
||||||
*
|
*
|
||||||
* In theory, this means that we're tied to the
|
* In theory, this means that we are tied to the current version of the
|
||||||
* current version of the kernel. In practice, the
|
* kernel. In practice, the system calls almost never change (it would
|
||||||
* system calls almost never change (it would wreck havoc
|
* wreck havoc and require programs to be recompiled, since the system
|
||||||
* and require programs to be recompiled, since the system
|
* calls are the interface between the kernel and the processes).
|
||||||
* calls are the interface between the kernel and the
|
|
||||||
* processes).
|
|
||||||
*/
|
*/
|
||||||
asmlinkage int our_sys_open(const char *filename, int flags, int mode)
|
asmlinkage int our_sys_open(const char *filename, int flags, int mode)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
/*
|
/* Report the file, if relevant */
|
||||||
* Report the file, if relevant
|
|
||||||
*/
|
|
||||||
pr_info("Opened file by %d: ", uid);
|
pr_info("Opened file by %d: ", uid);
|
||||||
do {
|
do {
|
||||||
get_user(ch, filename + i);
|
get_user(ch, filename + i);
|
||||||
|
@ -79,9 +66,8 @@ asmlinkage int our_sys_open(const char *filename, int flags, int mode)
|
||||||
} while (ch != 0);
|
} while (ch != 0);
|
||||||
pr_info("\n");
|
pr_info("\n");
|
||||||
|
|
||||||
/*
|
/* Call the original sys_open - otherwise, we lose the ability to
|
||||||
* Call the original sys_open - otherwise, we lose
|
* open files.
|
||||||
* the ability to open files
|
|
||||||
*/
|
*/
|
||||||
return original_call(filename, flags, mode);
|
return original_call(filename, flags, mode);
|
||||||
}
|
}
|
||||||
|
@ -127,13 +113,10 @@ static int __init syscall_start(void)
|
||||||
|
|
||||||
static void __exit syscall_end(void)
|
static void __exit syscall_end(void)
|
||||||
{
|
{
|
||||||
if (!sys_call_table) {
|
if (!sys_call_table)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/* Return the system call back to normal */
|
||||||
* Return the system call back to normal
|
|
||||||
*/
|
|
||||||
if (sys_call_table[__NR_open] != (unsigned long *) our_sys_open) {
|
if (sys_call_table[__NR_open] != (unsigned long *) our_sys_open) {
|
||||||
pr_alert("Somebody else also played with the ");
|
pr_alert("Somebody else also played with the ");
|
||||||
pr_alert("open system call\n");
|
pr_alert("open system call\n");
|
||||||
|
|
Loading…
Reference in New Issue
Block a user