驱动1

来源:互联网 发布:linux less 向上查找 编辑:程序博客网 时间:2024/06/01 20:09
*****************************************************************************
一个简单的读写字符串设备驱动:
http://blog.chinaunix.net/uid-20799298-id-99675.html
http://blog.csdn.net/sunsea1026/article/details/6586143
*****************************************************************************
pc机上做driver例子:
1. 驱动程序源码及Makefile如下:

#------源程序------#
#include <linux/module.h>
#include <linux/init.h>
static int __init hello_init() //“__init”使hello_init()函数放到初始化代码段里
{
printk("Hello, driver!\n");
return 0;
}
static int __exit hello_exit()
{
printk("Goodbye, driver!\n");
return 0;
}
module_init(hello_init);
module_exit(hello_exit);


#------Makefile------#
KVERS = $(shell uname -r)
# Kernel modules, obj-m编译一个模块,obj-y编译到内核,obj-n不编译。在添加到内核中时他们的定义
obj-m += hello.o
# Specify flags for the module compilation.
#EXTRA_CFLAGS=-g -O0
build: kernel_modules
kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean

2.驱动程序编译、安装及结果显示:
a.在第一个终端里 root@book-desktop:~# make
//生成hello.ko
b.在第二个终端里 root@book-desktop:~# tail -f /var/log/syslog
//查看日志文件内容,-f选项使之不断刷新显示
c.在第一个终端里 root@book-desktop:~# insmod ./hello.ko
//安装驱动
在第二个终端里自动输出:
Apr 7 19:26:06 book-desktop kernel: [ 9345.546564] Hello, driver!
d.在第一个终端里 root@book-desktop:~# rmmod hello
//卸载驱动
在第二个终端里自动输出:
Apr 7 19:26:11 book-desktop kernel: [ 9349.953772] Goodbye, driver!

注意的问题:/lib/modules/$(KVERS)/build 是内核路径。
第二error: function declaration isn’t a prototype。static int __init hello_init()没有带入参数也要用void: static int __init hello_init(void)
第三No rule to make target `/home/surpas1/actiontec/workspace/tempdir/driver1/hello.c'。看看路径在存在否。
insmod: ERROR: could not insert module kthread.ko: Unknown symbol in module在加载模块时出错,解决:代码添加MODULE_LICENSE("GPL");
dereferencing pointer to incomplete type:我们使用了没有定义的类型,有可能结构体没有这个数据,可能我们结构体写错了。



***********************************************************************************************************
***********************************************************************************************************
***********************************************************************************************************
第二个驱动,带内核任务的:内核任务队列是一个线程轮询执行任务列表,所以任务不要死循环,或占太长时间。如果中断函数需要花较长时间的可以用这种方法来实现。还有就是顶半部和底半部:tasklet
#include <linux/module.h>
#include <linux/init.h>
//#include <linux/workqueue.h>

struct my_work_struct{
    int test;
    struct work_struct save;
}a;

struct my_work_struct test_work;
struct workqueue_struct *test_workqueue;
void do_save(struct work_struct *p_work)
{
    struct my_work_struct *p_test_work = container_of(p_work, struct my_work_struct, save);
/*
#define container_of(ptr, type, member) ({            \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - offsetof(type,member) );})
通过my_work_struct的成员work_struct的地址,找到my_work_struct实例的地址。
*/
    printk("%d\n", p_test_work->test);
}
 
void test_init(void)
{
    test_workqueue = create_workqueue("test_workqueue");//创建一个任务队列(相当与一个数组)结构体,名字:。
    if (!test_workqueue)
        panic("Failed to create test_workqueue\n");
    test_work.test = 1024;
    INIT_WORK(&(test_work.save), do_save);//将一个work_struct和任务函数绑定在一起

    queue_work(test_workqueue, &(test_work.save));//这里请求执行任务do_save,应该从test_work.save得到任务函数的。
}

void test_destory(void)
{
    if(test_workqueue)
        destroy_workqueue(test_workqueue);
}

static int __init hello_init(void) //“__init”使hello_init()函数放到初始化代码段里
{
    printk("Hello, driver!\n");
    test_init();
    return 0;
}
static int __exit hello_exit(void)
{
    printk("Goodbye, driver!\n");
    test_destory();
    return 0;
}
MODULE_LICENSE("GPL"); //没加这行,报错:
module_init(hello_init);
module_exit(hello_exit);
***********************************************************************************************************
#------Makefile------#
KVERS = $(shell uname -r)
# Kernel modules
obj-m += hello.o
# Specify flags for the module compilation.
#EXTRA_CFLAGS=-g -O0
build: kernel_modules
kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
***********************************************************************************************************






***********************************************************************************************************
***********************************************************************************************************
***********************************************************************************************************
第三个:字符设备与用户层交互。源码地址:http://blog.chinaunix.net/uid-20799298-id-99675.html
#include <linux/init.h>
//#include

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
//#include

#include <linux/uaccess.h>

MODULE_LICENSE("Dual BSD/GPL");

int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);

struct file_operations memory_fops = {
        read:memory_read,
        write:memory_write,
        open:memory_open,
        release:memory_release
    /*这里还可以有很多其他函数:ioctl,poll等*/
};

module_init(memory_init);
module_exit(memory_exit);

int memory_major = 60;

char *memory_buffer;

int memory_init(void)
{
        int result;

        result = register_chrdev(memory_major, "memory", &memory_fops);//memory_major=0由系统分配主设备号,返回主设备号。

/*

在linux2.6版本里面:

register_chrdev_region是register_chrdev的升级版本。register_chrdev_region是用来声请设备号的。
**********************************************************************************
参考代码:
dev_t dev = MKDEV(beep_major, 0);
char dev_name[]="beep";
/* Figure out our device number. */
if (beep_major)//判断主设备号
result = register_chrdev_region(dev, 1, dev_name);//声请设备号。如果dev的主设备号=0,返回主设备号。但是他一般用于指定主设备号的情况。
else {
result = alloc_chrdev_region(&dev, 0, 1, dev_name);//动态声请,主设备号=0,系统分配,到dev
beep_major = MAJOR(dev);//获得主设备号
}
if (result < 0) {
printk(KERN_WARNING "beep: unable to get major %d\n", beep_major);
return result;
}
   cdev_init(dev, &memory_fops);初始化cdev,指定file_operations.
err = cdev_add (dev, devno, 1);//需要字符设备注册到内核才可以,对应void cdev_del(struct cdev *);   
******************************************************************************************************
2.6内核中使用module_init()和module_exit()来作为模块的入口和出口,而老版本中使用init_module()和cleanup_module()来作为模块的入口和出口。
*/

        if (result < 0) {
                printk("<1>memory: can't obtain major number %d\n", memory_major);
                return result;
        }

        memory_buffer = kmalloc(1, GFP_KERNEL);
        if (!memory_buffer) {
                result = - ENOMEM;
                goto fail;
        }
        memset(memory_buffer, 0, 1);

        printk("<1>Inserting memory module\n");
        return 0;

fail:
        memory_exit();
        return result;
}

void memory_exit(void)
{
        unregister_chrdev(memory_major, "memory");

        if (memory_buffer)
                kfree(memory_buffer);

        printk("<1>Removing memory module\n");
}

int memory_open(struct inode *inode, struct file *filp)
{
        return 0;
}

int memory_release(struct inode *inode, struct file *filp)
{
        return 0;
}

ssize_t memory_read(struct file *filp, char *buf,
        size_t count, loff_t *f_pos)
{
        copy_to_user(buf, memory_buffer, 1);

        if (*f_pos == 0) {
                *f_pos += 1;
                return 1;
        } else
                return 0;
}

ssize_t memory_write(struct file *filp, char *buf,
        size_t count, loff_t *f_pos)
{
        char *tmp;
        
        tmp = buf + count - 1;
        copy_from_user(memory_buffer, tmp, 1);

        return 1;
}
***********************************************************************************************************
#------Makefile------#
KVERS = $(shell uname -r)
# Kernel modules
obj-m += hello.o
# Specify flags for the module compilation.
#EXTRA_CFLAGS=-g -O0
build: kernel_modules
kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
***********************************************************************************************************
注意:register_chrdev并没有在dev中建立设备,需要自己手动添加:(60是主设备号,11次设备号-随便写)
注意:sudo mknod /dev/mychardevice c 60 11
在cat /proc/devices | grep 60   可以看到这里已经有了。
cat /dev/mychardevice就会调用读取函数。
echo 我试了不行,但是使用函数open,read,write,close是可以用的。
***********************************************************************************************************





***********************************************************************************************************
***********************************************************************************************************
***********************************************************************************************************
第四,因为我们需要手动创建字符设备太麻烦了,对第三例进行修改:
#include <linux/init.h>
//#include

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
//#include

#include <linux/uaccess.h>
#include <linux/device.h>

//用他们来创建字符设备,在/dev目录中创建一个设备
#define DEVICE_NAME "memory"
static struct class *myclass = NULL;
static struct device *mydevice = NULL;



MODULE_LICENSE("Dual BSD/GPL");

int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);

struct file_operations memory_fops = {
        read:memory_read,
        write:memory_write,
        open:memory_open,
        release:memory_release
};

module_init(memory_init);
module_exit(memory_exit);

int memory_major = 60;

char *memory_buffer;

int memory_init(void)
{
        int result;

        result = register_chrdev(memory_major, "memory", &memory_fops);
        if (result < 0) {
                printk("<1>memory: can't obtain major number %d\n", memory_major);
                return result;
        }

        memory_buffer = kmalloc(1, GFP_KERNEL);
        if (!memory_buffer) {
                result = - ENOMEM;
                goto fail;
        }
        memset(memory_buffer, 0, 1);

    myclass = class_create(THIS_MODULE,DEVICE_NAME);
    if(IS_ERR(myclass)){
        //ret = PTR_ERR(myclass);
        goto fail;
    }
    mydevice = device_create(myclass,NULL,MKDEV(60,0),NULL,"mydevicechr");//创建一个设备,60,0为设备号,mydevicechr为/dev/下面的设备名字。
    if(IS_ERR(mydevice)){
    //ret = PTR_ERR(mydevice);
        goto fail;
    }


        printk("<1>Inserting memory module\n");
        return 0;

fail:
    printk("<1>Inserting memory error\n");
        memory_exit();
    if (mydevice)
        device_destroy(myclass, MKDEV(60,0));
    if (myclass)
        class_destroy(myclass);
        return result;
}

void memory_exit(void)
{
        unregister_chrdev(memory_major, "memory");

        if (memory_buffer)
                kfree(memory_buffer);

    //模块卸载的时候,将目录设备移出。
    if (mydevice)
        device_destroy(myclass, MKDEV(60,0));
    if (myclass)
        class_destroy(myclass);

        printk("<1>Removing memory module\n");
}

int memory_open(struct inode *inode, struct file *filp)
{
        return 0;
}

int memory_release(struct inode *inode, struct file *filp)
{
        return 0;
}

ssize_t memory_read(struct file *filp, char *buf,
        size_t count, loff_t *f_pos)
{
        copy_to_user(buf, memory_buffer, 1);

        if (*f_pos == 0) {
                *f_pos += 1;
                return 1;
        } else
                return 0;
}

ssize_t memory_write(struct file *filp, const char __user *buf,
        size_t count, loff_t *f_pos)
{
        const char __user *tmp;
        
        tmp = buf + count - 1;
        copy_from_user(memory_buffer, tmp, 1);

        return 1;
}
***********************************************************************************************************
#------Makefile------#
KVERS = $(shell uname -r)
# Kernel modules
obj-m += hello.o
# Specify flags for the module compilation.
#EXTRA_CFLAGS=-g -O0
build: kernel_modules
kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
***********************************************************************************************************
调试和三一样。
class_create
device_create
device_destroy
class_destroy

***********************************************************************************************************

***********************************************************************************************************

***********************************************************************************************************


#include <linux/init.h>
//#include

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
//#include

#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/miscdevice.h>

#define DEVICE_NAME "memory"
//static struct class *myclass = NULL;
static struct miscdevice mydevice;//杂项设备定义,我用指针容易报错,还要自己分配和释放空间,于是直接用全局。



MODULE_LICENSE("Dual BSD/GPL");

int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);

struct file_operations memory_fops = {
        read:memory_read,
        write:memory_write,
        open:memory_open,
        release:memory_release
};

module_init(memory_init);
module_exit(memory_exit);

//int memory_major = 60;

char *memory_buffer;

int memory_init(void)
{
        int result;
        memory_buffer = kmalloc(1, GFP_KERNEL);
        if (!memory_buffer) {
                result = - ENOMEM;
                goto fail;
        }
        memset(memory_buffer, 0, 1);

    //mydevice = kmalloc(sizeof(struct miscdevice), GFP_KERNEL);
    mydevice.minor = MISC_DYNAMIC_MINOR;//主设备号为10,从设备号 : MISC_DYNAMIC_MINOR -- 系统分配
    mydevice.name = "mydevicechr";
    mydevice.fops = &memory_fops;
    mydevice.parent = NULL;

    printk("init addr = 0x%p\n", &mydevice);
    result = misc_register(&mydevice);//一个函数直接定义了杂项设备,并且创建/dev/mydevicechr,并且打开设备文件时file->private_data就是mydevice的地址。

    if(result){
    //ret = PTR_ERR(mydevice);
        goto fail;
    }


        printk("<1>Inserting memory module\n");
        return 0;

fail:
    printk("<1>Inserting memory error\n");
        memory_exit();
        return result;
}

void memory_exit(void)
{
       printk("<1>Removing memory module\n");
       //unregister_chrdev(memory_major, "memory");

        if (memory_buffer)
                kfree(memory_buffer);

    //if (mydevice)
    {
        misc_deregister(&mydevice);
        //kfree(mydevice);    
    }


        printk("<1>Removing memory module\n");
}

int memory_open(struct inode *inode, struct file *filp)
{
    char * i = filp->private_data;   

//file->private_data  == mydevice

    printk("open addr = 0x%p\n", i);
        return 0;
}

int memory_release(struct inode *inode, struct file *filp)
{
        return 0;
}

ssize_t memory_read(struct file *filp, char *buf,
        size_t count, loff_t *f_pos)
{
        copy_to_user(buf, memory_buffer, 1);

        if (*f_pos == 0) {
                *f_pos += 1;
                return 1;
        } else
                return 0;
}

ssize_t memory_write(struct file *filp, const char __user *buf,
        size_t count, loff_t *f_pos)
{
        const char __user *tmp;
        
        tmp = buf + count - 1;
        copy_from_user(memory_buffer, tmp, 1);

        return 1;
}

0 0
原创粉丝点击