分类: 嵌入式
2010-03-15 23:14:42
2.6驱动的开发相对以前各版本来说有了很大的改变 先是初始化与退出函数
以前使用init_module函数来声明模块初始化过程 使用cleanup_module来定义模块退出时的清除过程
而在2.6中 必须使用 module_init 标志来说明初始化函数 使用module_exit来说明清理函数
在2.4中,可以单独编译一个模块 而在2.6中,一个模块的编译,必须编译全部所有模块
下面是一个2.6内核的模板
#define MODULE
#include linux/module.h>
#include linux/config.h>
#include linux/init.h>
static int __init name_of_initialization_routine(void) {
/*
* code here
*/
}
static void __exit name_of_cleanup_routine(void) {
/*
* code here
*/
}
module_init(name_of_initialization_routine);
module_exit(name_of_cleanup_routine);
MODULE宏也不再是必须的了,在编译时可不定义
下面给出一个简单的字符类型事例:
/* chardev.c: Creates a read-only char device that says how many
* times
* * you've read from the dev file
* */
#include
#include
#include
#include
#include
#include
static int __init testmod_init(void);
static void __exit testmod_exit(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 */
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
};//注意这里需要是静态变量, 不然会出现内核访问错误情况
//.open = device_read,对fops里面的open变量赋值为device_read,
//,这是c99;里面定义的新标准,表示定义结构变量时同时对它进行子元素的赋值
// gcc扩展使用的是open:device_read,
/* Functions
* */
static int __init testmod_init(void)
{
Major = register_chrdev(240, DEVICE_NAME, &fops);
//注册字符驱动 第一个参数是主设备号 如果第一个参数是0 表示由内核自动分配
//第二个是设备名 可以在/proc/devices里面看到
//第三个是对此设备的操作函数 具体操作可以看file_operations结构定义 在linux/fs.h里面
if (Major < 0) {
printk ("Registering the character device failed with %d\n", Major);
return Major;
}
Major = 240;
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;
}
static void __exit testmod_exit(void)
{
/* Unregister the device */
int ret = unregister_chrdev(Major, DEVICE_NAME);//取消注册 取消了后模块可以unload
if (ret < 0) printk("Error in unregister_chrdev: %d\n", ret);
}
/* 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;
//MOD_INC_USE_COUNT;在2.6中,会自动维护引用计数,所以不再需要这个宏,但是如果要考虑兼容性那最好保存这个宏
printk("<1>device_open call\n");
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 */
printk("<1>device_release call\n");
/* Decrement the usage count, or else once you
* opened the file, you'll
* never get get rid of the module.
* */
//MOD_DEC_USE_COUNT;
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,
char *buffer, /* The buffer to fill with data */
size_t length, /* The length of the buffer */
loff_t *offset) /* Our offset in the file */
{
/* 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;
* * 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;
}
module_init(testmod_init);
module_exit(testmod_exit);