Skip to content
Snippets Groups Projects
Commit c00edd6c authored by Christian Löpke's avatar Christian Löpke
Browse files

Created modified version of chardev-1 which is able to hold a given name and...

Created modified version of chardev-1 which is able to hold a given name and make personalized outputs.
parent f80d47f8
No related branches found
No related tags found
No related merge requests found
obj-m += hellomod-1.o
obj-m += chardev-1.o
obj-m += chardev-1write.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
......
/* Modified by: Christian Löpke <christian.loepke@hs-bochum.de>
* chardev-1write.c: Creates a char device that says Mr. Anderson or a
* written name how many times he read from the dev
* file.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* for put_user */
/*
* Prototypes - this would normally go in a .h file
*/
int init_module(void);
void cleanup_module(void);
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 *);
#define SUCCESS 0
#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */
#define BUF_LEN 80 /* Max length of the message from the device */
#define USERBUF_LEN 20 /* Max length for user definable name */
/*
* Global variables are declared as static, so are global within the file.
*/
static int Major; /* Major number assigned to our device driver */
static int Device_Open = 0; /* Is device open?
* Used to prevent multiple access to device */
static char msg[BUF_LEN]; /* The msg the device will give when asked */
static char *msg_Ptr; /* The current char from msg we are writing */
static char msg_username[USERBUF_LEN]; /* User definable name */
static int told_you_counter = 0; /* Counts the outputs I've made */
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
/*
* This function is called when the module is loaded
*/
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk( KERN_ALERT
"%s: Registering char device failed with %d\n",
DEVICE_NAME,
Major);
return Major;
}
printk( KERN_INFO "%s: I was assigned major number %d. To talk to\n",
DEVICE_NAME,
Major);
printk( KERN_INFO
"%s: the driver, create a dev file with\n", DEVICE_NAME);
printk( KERN_INFO "%s: 'mknod /dev/%s c %d 0'.\n",
DEVICE_NAME,
DEVICE_NAME,
Major);
printk( KERN_INFO
"%s: Try various minor numbers. Try to cat and echo to\n",
DEVICE_NAME);
printk( KERN_INFO "%s: the device file.\n", DEVICE_NAME);
printk( KERN_INFO
"%s: Remove the device file and module when done.\n",
DEVICE_NAME);
sprintf(msg_username, "Mr. Anderson"); //Setup initial username.
return SUCCESS;
}
/*
* This function is called when the module is unloaded
*/
void cleanup_module(void)
{
/*
* Unregister the device
*/
unregister_chrdev(Major, DEVICE_NAME);
}
/*
* Methods
*/
/*
* Called when a process tries to open the device file, like
* "cat /dev/mycharfile"
*/
static int device_open(struct inode *inode, struct file *file)
{
if (Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg,
"I already told you %d times Hello world!, %s.\n",
told_you_counter++,
msg_username);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS; /* Device successfully opened */
}
/*
* Called when a process closes the device file.
*/
static int device_release(struct inode *inode, struct file *file)
{
Device_Open--; /* We're now ready for our next caller */
/*
* Decrement the usage count, or else once you opened the file, you'll
* never get get rid of the module.
*/
module_put(THIS_MODULE);
return 0; /* Device sucessfully closed */
}
/*
* Called when a process, which already opened the dev file, attempts to
* read from it.
*/
static ssize_t device_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;
/*
* If we're 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 (length && *msg_Ptr) {
/*
* 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(*(msg_Ptr++), buffer++);
length--;
bytes_read++;
}
/*
* Most read functions return the number of bytes put into the buffer
*/
return bytes_read;
}
/*
* Called when a process writes to dev file: echo "hi" > /dev/hello
*/
static ssize_t
device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
/* Since nobody wants to read I have to correct the already told you
counter! */
told_you_counter--;
if(len > USERBUF_LEN) {
printk( KERN_WARNING
"%s: Sorry, your input is too long. Max %d allowed!\n",
DEVICE_NAME,
USERBUF_LEN);
return -ENOMEM; //Return not enaugh memory
}
else {
int i;
for(i = 0; i < len; i++) //Save the given string
msg_username[i] = buff[i];
for(i = len; i < USERBUF_LEN; i++) //Zeroing out the rest of mem
msg_username[i] = 0;
printk( KERN_INFO "%s: Successfully got %d bytes!\n",
DEVICE_NAME, (int)len);
if(msg_username[len-1] == '\n') //Got new line terminator ?
msg_username[len-1] = 0; //Then terminate it!
return len; //Emit successfully stored len bytes
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment