Ubuntu linux driver examples

6 views
Skip to first unread message

Copper Hill

unread,
Apr 22, 2009, 11:20:45 PM4/22/09
to worldhunter
/*
* chardev.c: Creates a read-only char device that says how many
times
* you've 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
*/

/*
* 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;

static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};

/*
* Functions
*/

int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);

if (Major < 0) {
printk("Registering the character device failed with %d\n",
Major);
return Major;
}

printk("<1>I was assigned major number %d. To talk to\n", Major);
printk("<1>the driver, create a dev file with\n");
printk("'mknod /dev/hello c %d 0'.\n", Major);
printk("<1>Try various minor numbers. Try to cat and echo to\n");
printk("the device file.\n");
printk("<1>Remove the device file and module when done.\n");

return 0;
}

void cleanup_module(void)
{
/*
* Unregister the device
int ret = unregister_chrdev(Major, DEVICE_NAME);
if (ret < 0)
printk("Error in unregister_chrdev: %d\n", ret);
*/
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)
{
static int counter = 0;
if (Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg, "I already told you %d times Hello world!\n", counter+
+);
msg_Ptr = msg;
try_module_get(THIS_MODULE);

return SUCCESS;
}

/*
* 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;
}

/*
* 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)
{
printk("<1>Sorry, this operation isn't supported.\n");
return -EINVAL;
}

Hong Zhaogang

unread,
Apr 22, 2009, 11:21:37 PM4/22/09
to worldhunter
/*
* procfs.c - create a "file" in /proc
*/

#include <linux/module.h> /* Specifically, a module */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */

struct proc_dir_entry *Our_Proc_File;

/* Put data into the proc fs file.
*
* Arguments
* =========
* 1. The buffer where the data is to be inserted, if
* you decide to use it.
* 2. A pointer to a pointer to characters. This is
* useful if you don't want to use the buffer
* allocated by the kernel.
* 3. The current position in the file
* 4. The size of the buffer in the first argument.
* 5. Write a "1" here to indicate EOF.
* 6. A pointer to data (useful in case one common
* read for multiple /proc/... entries)
*
* Usage and Return Value
* ======================
* A return value of zero means you have no further
* information at this time (end of file). A negative
* return value is an error condition.
*
* For More Information
* ====================
* The way I discovered what to do with this function
* wasn't by reading documentation, but by reading the
* code which used it. I just looked to see what uses
* the get_info field of proc_dir_entry struct (I used a
* combination of find and grep, if you're interested),
* and I saw that it is used in <kernel source
* directory>/fs/proc/array.c.
*
* If something is unknown about the kernel, this is
* usually the way to go. In Linux we have the great
* advantage of having the kernel source code for
* free - use it.
*/
ssize_t
procfile_read(char *buffer,
char **buffer_location,
off_t offset, int buffer_length, int *eof, void *data)
{
int len = 0; /* The number of bytes actually used */
static int count = 1;

printk(KERN_INFO "inside /proc/test : procfile_read\n");

/*
* We give all of our information in one go, so if the
* user asks us if we have more information the
* answer should always be no.
*
* This is important because the standard read
* function from the library would continue to issue
* the read system call until the kernel replies
* that it has no more information, or until its
* buffer is filled.
*/
if (offset > 0) {
printk(KERN_INFO "offset %d : /proc/test : procfile_read, \
wrote %d Bytes\n", (int)(offset), len);
*eof = 1;
return len;
}

/*
* Fill the buffer and get its length
*/
len = sprintf(buffer,
"For the %d%s time, go away!\n", count,
(count % 100 > 10 && count % 100 < 14) ? "th" :
(count % 10 == 1) ? "st" :
(count % 10 == 2) ? "nd" :
(count % 10 == 3) ? "rd" : "th");
count++;

/*
* Return the length
*/
printk(KERN_INFO
"leaving /proc/test : procfile_read, wrote %d Bytes\n",
len);
return len;
}

int init_module()
{
int rv = 0;
Our_Proc_File = create_proc_entry("test", 0644, NULL);
Our_Proc_File->read_proc = procfile_read;
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->mode = S_IFREG | S_IRUGO;
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 37;

printk(KERN_INFO "Trying to create /proc/test:\n");

if (Our_Proc_File == NULL) {
rv = -ENOMEM;
remove_proc_entry("test", NULL);
printk(KERN_INFO "Error: Could not initialize /proc/test\n");
} else {
printk(KERN_INFO "Success!\n");
}

return rv;
}

void cleanup_module()
{
remove_proc_entry("test", NULL);
printk(KERN_INFO "/proc/test removed\n");
}
Reply all
Reply to author
Forward
0 new messages