驱动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版本里面:
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.
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;
}
- 驱动1
- 1-驱动
- 驱动开发1:介绍驱动
- 驱动实战-----OK6410驱动编程之led驱动1
- LINUX驱动之字符设备驱动1
- linux驱动学习1---led驱动
- 键盘驱动系列---JIURL键盘驱动 1
- i2c驱动之普通设备驱动1
- windows驱动编程学习(1)--------了解驱动
- linux驱动:[1]LED驱动/dev/led
- 驱动学习1--最简单的驱动
- JIURL键盘驱动 1
- JIURL键盘驱动 1
- JIURL键盘驱动 1
- 驱动入门-1
- 驱动开发学习(1)
- windows驱动入门-1
- 字符驱动-1
- 欧拉项目第18题Maximum path sum I
- CarouselViewPager实现ViewPager的轮播效果
- WebP 探寻之路
- js 继承
- Aizu - 0033(深搜)
- 驱动1
- js 文件提交
- Multiple markers at this line @Override的解决方法
- JNI_Android项目中调用.so动态库实现详解(初探)
- react-native Navigator 填坑
- linux系统启动过程详解-开机加电后发生了什么 --linux内核剖析(零)
- Xcode因为证书问题经常报的那些错
- Composer自动加载机制源码剖析
- 腾讯实习生面试一面笔试题总结