Initial commit
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
obj-m := one.o
|
||||||
|
|
||||||
|
CURRENT = $(shell uname -r)
|
||||||
|
KDIR = /lib/modules/$(CURRENT)/build
|
||||||
|
PWD = $(shell pwd)
|
||||||
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
make -C $(KDIR) M=$(PWD) modules
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C $(KDIR) M=$(PWD) clean
|
||||||
|
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
|
||||||
|
#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 */
|
||||||
Reference in New Issue
Block a user