通用的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; }