通用的Makefile模板
ifeq ($(KERNELRELEASE),)
#KERNELDIR ?= /home/lht/kernel2.6/linux-2.6.14
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
obj-m := hello.o
endif
一、简单的模块
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE ("GPL");
int init_module (void)
{
printk (KERN_INFO "Hello world\n");
return 0;
}
void cleanup_module (void)
{
printk (KERN_INFO "Goodbye world\n");
二、标准的模块
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
MODULE_LICENSE ("GPL");
static int __init hello_2_init (void)
{
printk (KERN_INFO "Hello world\n");
return 0;
}
static void __exit hello_2_exit (void)
{
printk (KERN_INFO "Goodbye world\n");
}
module_init (hello_2_init);
mo
三、参数的学习
#define DRIVER_AUTHOR "Foobar"
#define DRIVER_DESC "A sample driver"
MODULE_LICENSE ("GPL");
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_SUPPORTED_DEVICE ("TestDevice");
static short int myshort = 1;
static int myint = 420;
static long int mylong = 9999;
static char *mystring = "blah";
static int array[2]= {-1, -1};
static int arr_argc = 0;
module_param (myshort, short, 0000);
MODULE_PARM_DESC (myshort, "A short integer");
module_param (myint, int, 0000);
MODULE_PARM_DESC (myint, "An integer");
module_param (mylong, long, 0000);
MODULE_PARM_DESC (mylong, "A long integer");
module_param (mystring, charp, 0000);
MODULE_PARM_DESC (mystring, "A character string");
module_param_array (array, int, &arr_argc, 0000);
//module_param_array (array, int, arr_argc, 0000); //for kernel<2.6.10
MODULE_PARM_DESC (array, "An array of integers");
static int __init hello_2_init (void)
{
int i;
printk (KERN_INFO "myshort is a short integer: %hd\n", myshort);
printk (KERN_INFO "myint is an integer: %d\n", myint);
printk (KERN_INFO "mylong is a long integer: %ld\n", mylong);
printk (KERN_INFO "mystring is a string: %s\n\n", mystring);
for (i=0; i<arr_argc; i++)
printk (KERN_INFO "array[%d] = %d\n",i, array[i]);
printk (KERN_INFO "Got %d arguments in array\n", arr_argc);
return 0;
}
static void __exit hello_2_exit (void)
{
printk (KERN_INFO "hello driver cleaned up\n");
}
module_init (hello_2_init);
module_exit (hello_2_exit);
四、proc的操作
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
MODULE_LICENSE ("GPL");
int hello_read_procmem (char *buf, char **start, off_t offset, int count, int *eof, void *data)
{
int len = 0;
len = sprintf (buf, "Hey, there! hello from hello_read_procmem\n");
*eof = 1;
return len;
}
static void hello_create_proc (void)
五、ioctl
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include "hello.h"
MODULE_LICENSE ("GPL");
int hello_major = 250;
int hello_minor = 0;
int number_of_devices = 1;
char data[128]="\0";
struct cdev cdev;
dev_t dev = 0;
static int hello_open (struct inode *inode, struct file *file)
{
printk (KERN_INFO "Hey! device opened\n");
return 0;
}
static int hello_release (struct inode *inode, struct file *file)
{
printk (KERN_INFO "Hmmm! device closed\n");
return 0;
}
int hello_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret=0;
switch (cmd) {
case HELLO_ONE:
printk (KERN_INFO "HELLO_ONE called\n");
break;
case HELLO_TWO:
printk (KERN_INFO "HELLO_TWO called\n");
break;
default:
break;
}
return ret;
}
struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.ioctl = hello_ioctl,
};
static void char_reg_setup_cdev (void)
{
int error, devno = MKDEV (hello_major, hello_minor);
cdev_init (&cdev, &hello_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &hello_fops;
error = cdev_add (&cdev, devno , 1);
if (error)
printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error);
}
static int __init hello_2_init (void)
{
int result;
dev = MKDEV (hello_major, hello_minor);
result = register_chrdev_region (dev, number_of_devices, "hello");
if (result<0) {
printk (KERN_WARNING "hello: can't get major number %d\n", hello_major);
return result;
}
char_reg_setup_cdev ();
printk (KERN_INFO "hello_ioctl driver done\n");
return 0;
}
static void __exit hello_2_exit (void)
{
dev_t devno = MKDEV (hello_major, hello_minor);
cdev_del (&cdev);
unregister_chrdev_region (devno, number_of_devices);
printk (KERN_INFO "hello_ioctl cleaned up\n");
}
module_init (hello_2_init);
module_exit (hello_2_exit);
测试程序:
int main (void)
{
int fd;
fd = open ("/dev/hello",O_RDWR);
if (fd < 0) {
printf ("fd open failed\n");
exit(0);
}
printf ("\n/dev/hello opened, fd=%d\n",fd);
ioctl (fd, HELLO_ONE);
ioctl (fd, HELLO_TWO);
close (fd);
printf ("/dev/hello closed :)\n");
return 0;
}