diff --git a/examples/20150518/Makefile b/examples/20150518/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4679cbe65799d99c5a0e92add377986afb538615 --- /dev/null +++ b/examples/20150518/Makefile @@ -0,0 +1,8 @@ + +obj-m += mydriver2.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/examples/20150518/README b/examples/20150518/README new file mode 100644 index 0000000000000000000000000000000000000000..a2d2d280563663064b8f98384e6d151560be4143 --- /dev/null +++ b/examples/20150518/README @@ -0,0 +1,10 @@ +From: Merlin Klaßen <merlin.klassen@hs-bochum.de> +To: Peter Gerwinski <peter.gerwinski@hs-bochum.de> +Subject: code für Treiber-Entwicklung + +Hi. +Hier der Link den ich verwendet habe: +http://sysplay.in/blog/tag/character-device-files/ + +... und mein Quellcode (mit Makefile) im Anhang. +Gruß Merlin diff --git a/examples/20150518/mydriver2.c b/examples/20150518/mydriver2.c new file mode 100644 index 0000000000000000000000000000000000000000..54f8e7d403f5e77ded41af59645773868556bbb0 --- /dev/null +++ b/examples/20150518/mydriver2.c @@ -0,0 +1,177 @@ +/* see http://www.tldp.org/LDP/lkmpg/2.6/html/x569.html */ +#include <linux/kernel.h> /* Needed for KERN_INFO */ +#include <linux/module.h> /* Needed by all modules */ +#include <linux/init.h> /* Needed for the macros */ +#include <linux/fs.h> +#include <asm/uaccess.h> /* for put_user */ +#include <linux/device.h> +#include <linux/cdev.h> + +//#define _BSD_SOURCE +//#include <sys/types.h> +//#include <sys/stat.h> +//#include <fcntl.h> +//#include <unistd.h> + +#define DRIVER_AUTHOR "Merlin Klaszen" +#define DRIVER_DESC "My first own driver" +#define DRIVER_LICENSE "Dual BSD/GPL" +#define SUCCESS 0 +#define DEVICE_NAME "mydriver2" /* Dev name as it appears in /proc/devices */ +#define DEVICE_COUNT 1 +#define BUF_LEN 80 + +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 *); + +static int Device_Open = 0; +static char msg [ BUF_LEN ]; +static char *msg_Ptr; +static dev_t dev; /* a basic device struct, contains Major and Minor(-offset) */ +static struct cdev chardev; /* will be bound to dev, to add special fields for character devices */ +static struct class *cdc; /* the 'class' of the device(s) */ +static struct device *myDev; /* the struct, that represents the actual thing, which we will see in the file system */ + +static struct file_operations fops = +{ + .read = device_read, + .write = device_write, + .open = device_open, + .release = device_release +}; + +static int __init mydriver1_init ( void ) +{ + int e = alloc_chrdev_region ( &dev, 0, DEVICE_COUNT, DEVICE_NAME ); + if ( e < 0 ) + { + printk ( KERN_ALERT "Registering %s failed with %d\n", DEVICE_NAME, e ); + return e; + } + cdev_init ( &chardev, &fops ); + chardev.owner = THIS_MODULE; + chardev.ops = & fops; + e = cdev_add ( &chardev, dev, 1 ); + if ( e ) + { + printk ( KERN_INFO "%s: Error %d adding device", DEVICE_NAME, e ); + return e; + } + cdc = class_create ( THIS_MODULE, "myCharDevClass" ); + myDev = device_create ( cdc, NULL, dev, NULL, "myCharDev-%d-%d", MAJOR(dev), MINOR(dev) ); + + printk ( KERN_INFO "%s: Hello, world\n", DEVICE_NAME ); + printk ( KERN_INFO "%s: Major: %d, Minor %d.\n", DEVICE_NAME, MAJOR(dev), MINOR(dev) ); + + sprintf ( msg, "Try to write into this file\n" ); + + return SUCCESS; +} + +static void __exit mydriver1_exit ( void ) +{ + printk ( KERN_INFO "%s: Goodbye, world\n", DEVICE_NAME ); + + device_destroy ( cdc, dev ); + class_destroy ( cdc ); + cdev_del ( &chardev ); + unregister_chrdev_region ( dev, DEVICE_COUNT ); +} + +static int device_open ( struct inode *inode, struct file *file ) +{ + if ( Device_Open ) + { + return -EBUSY; + } + + Device_Open++; + msg_Ptr = msg; + try_module_get ( THIS_MODULE ); + printk ( KERN_INFO "%s was opened.\n", DEVICE_NAME ); + + return SUCCESS; +} + +static int device_release ( struct inode *inode, struct file *file ) +{ + Device_Open--; + + module_put(THIS_MODULE); + printk ( KERN_INFO "%s was closed.\n", DEVICE_NAME ); + + return 0; +} + +static ssize_t device_read ( struct file *fp, char *buf, size_t len, loff_t * off ) +{ + int bytes_read = 0; + + /* 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 ( len && *msg_Ptr ) + { + put_user(*(msg_Ptr++), buf++); + len--; + bytes_read++; + } + + printk ( KERN_INFO "%s: Someone read.\n", DEVICE_NAME ); + + /* return the number of bytes put into the buffer */ + return bytes_read; +} + +static ssize_t device_write ( struct file *fp, const char *buf, size_t len, loff_t * off ) +{ + int bytes_written = 0; + char c = ' '; + msg_Ptr = msg; + if ( len >= BUF_LEN ) + { + len = 79; + } + while ( len && c ) + { + get_user ( c, buf ); + if ( (c>='a') && (c<='z') ) + { + c = c & ~0x20; + } + *msg_Ptr = c; + msg_Ptr++; + len--; + bytes_written++; + buf++; + } + if ( *(msg_Ptr - 1) ) /* make sure the string is terminated */ + { + *msg_Ptr = '\0'; + } + msg_Ptr = msg; + printk ( KERN_INFO "%s: Someone wrote.\n", DEVICE_NAME ); + + return bytes_written; +} + +module_init(mydriver1_init); +module_exit(mydriver1_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); /* Who wrote this module? */ +MODULE_DESCRIPTION(DRIVER_DESC); /* What does this module do */ +MODULE_LICENSE(DRIVER_LICENSE); + +/* + MODULE_SUPPORTED_DEVICE("testdevice"); + * This module may use /dev/testdevice. The MODULE_SUPPORTED_DEVICE macro might + * be used in the future to help automatic configuration of modules, but is + * currently unused other than for documentation purposes. + */ +