买了本中文的ldd3,都说中文的翻译差劲,可是英文实在太费劲
看了模块和字符驱动,下面是最简单的应用吧
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
int hello_open(struct inode *,struct file *);
int hello_release(struct inode *,struct file *);
struct file_operations hello_fops=
{
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
};
int hello_open(struct inode *pNode,struct file *pFile)
{
try_module_get(THIS_MODULE);
return 0;
}
int hello_release(struct inode *pNode,struct file *pFile)
{
module_put(THIS_MODULE);
return 0;
}
struct cdev *hello_cdev ;
static struct class *led_class;
dev_t dev;
static int hello_init(void)
{
int iMajor;
int result;
result = alloc_chrdev_region(&dev,0,1,"hello");
if (result < 0)
{
printk("alloc_chrdev_region error\n");
return 0;
}
iMajor = MAJOR(dev);
hello_cdev = cdev_alloc();
cdev_init(hello_cdev,&hello_fops);
hello_cdev->owner = THIS_MODULE;
cdev_add(hello_cdev,dev,1);
led_class = class_create(THIS_MODULE,"hello");
if (!led_class)
{
printk(KERN_ALERT"create class error\n");
return 0;
}
device_create(led_class,NULL,dev,NULL,"hello%d",MINOR(dev));
printk(KERN_ALERT "HELLO,WORLD\n");
return 0;
}
static void hello_exit(void)
{
cdev_del(hello_cdev);
unregister_chrdev_region(dev,1);
device_destroy(led_class,dev);
class_destroy(led_class);
printk(KERN_ALERT "GOODBYE\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
分三段
第一段 初识模块
1.必须编译内核树
进入内核根目录,make modules,make modules_install install(ps:用的是自己下载的2.6.35内核)
此时内核树路劲在/lib/modules/2.6.35
2.新手必写,hello world
static int hello_init(void)
{
printk(KERN_ALERT "HELLO,WORLD\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "GOODBYE\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
3.Makefile
借鉴的lld3
CROSS_COMPILE = /home/sprink/toolchain/bin/arm-sprink-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc
CFLAGS=
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
KERNELDIR ?= /lib/modules/2.6.35/build/
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
mv hello.c hello
rm -rf hello.*
mv hello hello.c
endif
第二阶段 初识字符设备
ldd3上讲的scull设备说实话没搞明白干什么用的。只明白了既然是设备,就必须得用设备号
1.设备号
有主设备号和次设备号,主设备号是和字符设备驱动关联的,次设备号是给内核使用的(此类设备的个数,一般从0开始,不知道这样理解有没有错误)。MKDEV,MAJOR,MINOR。
建立字符设备的第一件事就是获得一个或者多个设备编号,于是就有了动态注册和静态注册
register_chrdev;
register_chrdev_region;
alloc_chrdev_region;
register_chrdev是之前的内核使用的,可以动态或者静态分配一个设备号。现在可以用,但是既然出现了替代者,我们还是使用替代者的好。
register_chrdev_region(dev_t first,unsigned int count,char *name);是静态分配一个设备号。但是出于管理需要,最好是动态分配。
也就是使用alloc_chrdev_region(dev_t * dev ,unsigned int firstminor,unsigned int count,char *name);
同样unregister_chrdev_region();就是在退出模块时使用,来释放设备号。
dev_t dev;
static int hello_init(void)
{
int iMajor;
int result;
result = alloc_chrdev_region(&dev,0,1,"hello");
if (result < 0)
{
printk("alloc_chrdev_region error\n");
return 0;
}
printk(KERN_ALERT "HELLO,WORLD\n");
return 0;
}
static void hello_exit(void)
{
unregister_chrdev_region(dev,1);
printk(KERN_ALERT "GOODBYE\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
第三阶段 udev
第二阶段中注册设备后可以再/proc/device中看到自己的设备,但是在/dev下面却没有。
我知道的有两种方法:
1.mknod
2.udev
static struct class *led_class;
class_create;
device_create;
只知道用而已,说不出个所以然来
另:
在编译的时候出现个一个问题我就简单描述下,带下次出现时有迹可循:
两个静态全局变量
static int i = 1;
static int i = j;
第二句是错误的,编译的时候有问题
涉及静态全局变量的初识化问题,j是变量,在编译的时候是没有值的,所以编译器任务是错的