红联Linux门户
Linux帮助

Linux Device Driver Template/Skeleton

发布时间:2005-11-14 17:09:04来源:红联作者:richardhesidu
别人写的代码, 我改了几个kernel api还有一些相应的代码, 使它能够在2.6.9内核下编译运行.
改的API是:
interruptible_sleep_on()--->wait_event_interruptible()
interrupt_handler() 返回值类型改为 irqreturn_t



This is a Linux Device Driver Template/Skeleton including an interrupt handler for the parallel port. The driver creates a device entry in /dev/, which can be used to communicate with the kernel module (read, write, ioctl).

Compile everything with the "Makefile" and before you load the kernel module with

Kernel 2.4:
# insmod ./skeleton.o
Kernel 2.6:
# insmod ./skeleton.ko

you must create the device entry in /dev with

# mknod -m 666 /dev/skeleton c 32 0


When the module is loaded, it creates an interrupt; you see some messages in the kernel log file:

initializing module
Generating interrupt now on all output pins (intr/ACK = pin 10)
>>> PARALLEL PORT INT HANDLED: interruptcount=1
Interrupt generated. You should see the handler-message



In order to see the interrupt, you need to make a parallel port "null-modem". Connect any output pin (pin 2 - 9) with the IRQ pin (pin 10). You see the "outb_p"'s in skeleton_init_module to generate the pulse signal on the output pins.

After loading the module, start the userspace program "user". This program opens the device (/dev/skeleton), writes data to it and reads the data back. The kernel module is programmed to block the read access until an interrupt occurs. After starting the userspace program, use the "set" and "reset" programs to generate another interrupt and to unblock the read function. You will these messages:

# ./user
String 'Skeleton Kernel Module Test' written to /dev/skeleton
String 'Skeleton Kernel Module Test' read from /dev/skeleton
IOCTL test: written: '55555555' - received: '55555555'

After starting "user", you will see "String 'Skeleton Kernel Module Test' written to /dev/skeleton" and the program waits. Generate the interrupt with "set" and "reset", the module unblocks the read function and the additional messages appear.

Furthermore the userspace program does some basic IOCTL access - you can use this to send commands to the module. i.e. to start sampling data with an ADC over the parallel port. If you want to do the interrupt handling in RTAI hard real time, have a look at RTAI Parallel Port Interrupt - Kernel module.

Another way to test the driver:
Write some data to the module:

# cat > /dev/skeleton
this is a pen.
[press CTRL-D]
#

Read the data back:

# cat < /dev/skeleton
this is a pen.
#



The device driver "skeleton.c":

// Linux Device Driver Template/Skeleton
// Kernel Module

#include
#include
#include
#include
#include
#include
#include
#include

#define SKELETON_MAJOR 32
#define SKELETON_NAME "skeleton"
#define BASEPORT 0x378
#define PARALLEL_PORT_INTERRUPT 7
#define CASE1 1
#define CASE2 2

static unsigned int counter = 0;
static char string [128];
static int data;
static int interruptcount = 0;

DECLARE_WAIT_QUEUE_HEAD(skeleton_wait);
static int data_not_ready = 1;

// open function - called when the "file" /dev/skeleton is opened in userspace
static int skeleton_open (struct inode *inode, struct file *file) {
printk("skeleton_open\n");
// we could do some checking on the flags supplied by "open"
// i.e. O_NONBLOCK
// -> set some flag to disable interruptible_sleep_on in skeleton_read
return 0;
}

// close function - called when the "file" /dev/skeleton is closed in userspace
static int skeleton_release (struct inode *inode, struct file *file) {
printk("skeleton_release\n");
return 0;
}

// read function called when from /dev/skeleton is read
static ssize_t skeleton_read (struct file *file, char *buf,
size_t count, loff_t *ppos) {
int len, err;

// check if we have data - if not, sleep
// wake up in interrupt_handler
wait_event_interruptible(skeleton_wait,data_not_ready!=1);
data_not_ready = 1;

if( counter <= 0 )
return 0;
err = copy_to_user(buf,string,counter);
if (err != 0)
return -EFAULT;
len = counter;
counter = 0;
return len;
}

// write function called when to /dev/skeleton is written
static ssize_t skeleton_write (struct file *file, const char *buf,
size_t count, loff_t *ppos) {
int err;
err = copy_from_user(string,buf,count);
if (err != 0)
return -EFAULT;
counter += count;
return count;
}

// ioctl - I/O control
static int skeleton_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) {
int retval = 0;
switch ( cmd ) {
case CASE1:/* for writing data to arg */
if (copy_from_user(&data, (int *)arg, sizeof(int)))
return -EFAULT;
break;
case CASE2:/* for reading data from arg */
if (copy_to_user((int *)arg, &data, sizeof(int)))
return -EFAULT;
break;
default:
retval = -EINVAL;
}
return retval;
}

// interrupt handler
irqreturn_t interrupt_handler(int irq,void *dev_id,struct pt_regs *regs)
{
// do stuff
interruptcount++;
printk(">>> PARALLEL PORT INT HANDLED: interruptcount=%d\n", interruptcount);

// wake up (unblock) for reading data from userspace
// and ignore first interrupt generated in module init
if (interruptcount > 1) {
data_not_ready = 0;
wake_up_interruptible(&skeleton_wait);
}

return IRQ_HANDLED;
}

// define which file operations are supported
struct file_operations skeleton_fops = {
.owner = THIS_MODULE,
.llseek = NULL,
.read = skeleton_read,
.write = skeleton_write,
.readdir = NULL,
.poll = NULL,
.ioctl = skeleton_ioctl,
.mmap = NULL,
.open = skeleton_open,
.flush = NULL,
.release = skeleton_release,
.fsync = NULL,
.fasync = NULL,
.lock = NULL,
.readv = NULL,
.writev = NULL,
};

// initialize module (and interrupt)
static int __init skeleton_init_module (void) {
int i;
int ret;
printk("initializing module\n");

i = register_chrdev (SKELETON_MAJOR, SKELETON_NAME, &skeleton_fops);
if (i != 0) return -EIO;

// INIT AND GENERATE INTERRUPT
ret = request_irq(PARALLEL_PORT_INTERRUPT, &interrupt_handler,
SA_INTERRUPT, "parallelport", NULL);
enable_irq(7);
//set parallel port to interrupt mode; pins are output
outb_p(0x10, BASEPORT + 2);
printk("Generating interrupt now on all output pins (intr/ACK = pin 10)\n");
//generate interrupt
outb_p(0, BASEPORT);
outb_p(255, BASEPORT);
outb_p(0, BASEPORT);
printk("Interrupt generated. You should see the handler-message\n");

return 0;
}

// close and cleanup module
static void __exit skeleton_cleanup_module (void) {
printk("cleaning up module\n");
unregister_chrdev (SKELETON_MAJOR, SKELETON_NAME);
disable_irq(7);
free_irq(7, NULL);
}

module_init(skeleton_init_module);
module_exit(skeleton_cleanup_module);
MODULE_AUTHOR("www.captain.at");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Linux Device Driver Template/Skeleton with Interrupt Handler");



Userspace test program "user.c"

// Linux Device Driver Template/Skeleton
// Userspace test program

#include
#include
#include
#include
#include
#include
#define CASE1 1
#define CASE2 2

main() {
int fd, len, wlen;
char string[] = "Skeleton Kernel Module Test";
char receive[128];
int data, rdata;

fd = open("/dev/skeleton", O_RDWR);
if( fd == -1) {
printf("open error...\n");
exit(0);
}

wlen = strlen(string) + 1;
len = write(fd, string, wlen);
if( len == -1 ) {
printf("write error...\n");
exit(1);
}

printf("String '%s' written to /dev/skeleton\n", string);

len = read(fd, receive, 128);
if( len == -1 ) {
printf("read error...\n");
exit(1);
}

printf("String '%s' read from /dev/skeleton\n", receive);

data = 0x55555555;
ioctl(fd, CASE1, &data);
ioctl(fd, CASE2, &rdata);

printf("IOCTL test: written: '%x' - received: '%x'\n", data, rdata);

close(fd);
}



Makefile

UNAME := $(shell uname -r)
KERNEL26 := 2.6
KERNELVERSION := $(findstring $(KERNEL26),$(UNAME))

all:: user

ifeq ($(KERNELVERSION),2.6)

obj-m := skeleton.o

INCLUDE := -I/usr/include/asm/mach-default/
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all::
$(MAKE) -C $(KDIR) $(INCLUDE) SUBDIRS=$(PWD) modules

else

TARGET := skeleton
INCLUDE := -I/lib/modules/`uname -r`/build/include -I/usr/include/asm/mach-default/
CFLAGS := -O2 -Wall -DMODULE -D__KERNEL__ -DLINUX
CC := gcc

all:: ${TARGET}.o

${TARGET}.o: ${TARGET}.c
$(CC) $(CFLAGS) ${INCLUDE} -c ${TARGET}.c

endif

user: user.c
gcc -o $@ $<
文章评论

共有 0 条评论