Files
2017-10-26 20:06:07 +02:00

142 lines
3.7 KiB
C
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/fs.h>
#include <asm/uaccess.h> /* for put_user */
#define DEVICE_NAME "one"
static char outputchar = '1';
/*
* module_param(foo, int, 0000)
* The first param is the parameters name
* The second param is it's data type
* The final argument is the permissions bits,
* for exposing parameters in sysfs (if non−zero).
* e.g. change outputchar to 'a' with "echo "97" > /sys/module/one/parameter/outputchar"
*/
module_param(outputchar, byte, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP );
MODULE_PARM_DESC(outputchar, "Character that will be output by the device file");
static int major; /* Major number assigned to our device driver */
static int device_opened = 0;
/*
* Prototypes − this would normally go in a .h file
*/
static int one_init(void);
static void one_exit(void);
static int one_open(struct inode *, struct file *);
static int one_release(struct inode *, struct file *);
static ssize_t one_read(struct file *, char *, size_t, loff_t *);
static ssize_t one_write(struct file *, const char *, size_t, loff_t *);
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = one_read,
.write = one_write,
.open = one_open,
.release = one_release
};
static int __init one_init(void)
{
printk(KERN_INFO "Hello World from module one\n");
major = register_chrdev(0, DEVICE_NAME, &fops);
if (major < 0)
{
printk(KERN_ALERT "Error in register_chrdev:%d\n", major);
return major;
}
printk(KERN_INFO "I was assigned major number %d.\n", major);
printk(KERN_INFO "Execute \"mknod /dev/one c %d 0\" to create device file.\n", major);
return 0;
}
static void __exit one_exit(void)
{
// Unregister the device
unregister_chrdev(major, DEVICE_NAME);
printk(KERN_INFO "Goodbye World from module one\n");
}
/*
* Called when a process tries to open the device file, like
* "cat /dev/mycharfile"
*/
static int one_open(struct inode *inode, struct file *file)
{
if (device_opened)
return -EBUSY;
device_opened++;
return 0;
}
/*
* Called when a process closes the device file.
*/
static int one_release(struct inode *inode, struct file *file)
{
device_opened--; /* We're now ready for our next caller */
return 0;
}
/*
* Called when a process, which already opened the dev file, attempts to read from it.
*/
static ssize_t one_read( struct file *filp, /* see include/linux/fs.h */
char *buffer, /* buffer to fill with data */
size_t length, /* length of the buffer */
loff_t * offset)
{
/*
* Number of bytes actually written to the buffer
*/
int bytes_read = 0;
// Copying data to the buffer
int i;
for (i = 0; i < length; i++)
{
/*
* The buffer is in the user data segment, not the kernel
* segment so "*" 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(outputchar, buffer++);
bytes_read++;
}
/*
* Most read functions return the number of bytes put into the buffer
* return 0 would signify end of file
*/
return bytes_read;
}
/*
* Called when a process writes to dev file: echo "hi" > /dev/hello
*/
static ssize_t one_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk(KERN_ALERT "Sorry, write isn't supported.\n");
return -EINVAL;
}
module_init(one_init);
module_exit(one_exit);
MODULE_LICENSE("Some License");
MODULE_AUTHOR("Matthias Janetschek"); /* Who wrote this module? */
MODULE_DESCRIPTION("An example module"); /* What does this module do */