This article explains how to compile a sample Linux character device driver and how to read and write from the device.
A Sample Character Device Driver
The sample code is a copy of ldd3's example code sleepy
.
/* * sleepy.c -- the writers awake the readers * * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet * Copyright (C) 2001 O'Reilly & Associates * * The source code in this file can be freely used, adapted, * and redistributed in source or binary form, so long as an * acknowledgment appears in derived source files. The citation * should list that the code comes from the book "Linux Device * Drivers" by Alessandro Rubini and Jonathan Corbet, published * by O'Reilly & Associates. No warranty is attached; * we cannot take responsibility for errors or fitness for use. * * $Id: sleepy.c,v 1.7 2004/09/26 07:02:43 gregkh Exp $ */ #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> /* current and everything */ #include <linux/kernel.h> /* printk() */ #include <linux/fs.h> /* everything... */ #include <linux/types.h> /* size_t */ #include <linux/wait.h> MODULE_LICENSE("Dual BSD/GPL"); static int sleepy_major = 0; static DECLARE_WAIT_QUEUE_HEAD(wq); static int flag = 0; ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos) { printk(KERN_DEBUG "process %i (%s) going to sleep\n", current->pid, current->comm); wait_event_interruptible(wq, flag != 0); flag = 0; printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm); return 0; /* EOF */ } ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos) { printk(KERN_DEBUG "process %i (%s) awakening the readers...\n", current->pid, current->comm); flag = 1; wake_up_interruptible(&wq); return count; /* succeed, to avoid retrial */ } struct file_operations sleepy_fops = { .owner = THIS_MODULE, .read = sleepy_read, .write = sleepy_write, }; int sleepy_init(void) { int result; /* * Register your major, and accept a dynamic number */ result = register_chrdev(sleepy_major, "sleepy", &sleepy_fops); if (result < 0) return result; if (sleepy_major == 0) sleepy_major = result; /* dynamic */ return 0; } void sleepy_cleanup(void) { unregister_chrdev(sleepy_major, "sleepy"); } module_init(sleepy_init); module_exit(sleepy_cleanup);
Makefile
obj-m = sleepy.o KVERSION = $(shell uname -r) PWD = $(shell pwd) all: make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules clean: make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
Compile The Driver
The ultimate way is to compile it along with a built kernel tree. However, for the time being, installing Linux kernel headers would suffice. It should already be installed by default.
sudo apt-get install linux-headers-$(uname -r)
If installed, type
make
Load and Remove The Driver
You will see some new files are generated, including sleepy.ko
, to load this module
sudo insmod sleepy.ko
To unload,
sudo rmmod sleepy
Read from and write to the device
The sleepy
is created with a dynamic major, we need to create a device file for it. First get the major number,
$ cat /proc/devices | grep sleepy 250 sleepy
Then create a node under /dev
, c
is to create a character file, 0
is its minor number.
sudo mknod /dev/sleepy c 250 0
Now we can read and write the device using C library function read
, write
, or from shell
echo "sleep" > /dev/sleepy cat /dev/sleepy
Though what sleepy
does is that it makes the reader process fall asleep while the writer process wakes all readers up.
#include <fcntl.h> #include <unistd.h> int fd; char buffer[32]; fd = open("/dev/sleepy", O_RDONLY); read(fd,buffer,10);
No comments:
Post a Comment