前言
前两小节中介绍了字符设备的cdev和函数操作集 file_operations。理论还需要和实践结合起来,这节主要是给出一个示例代码和测试代码。
正文
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#define DEVICE_NAME "cdev_demo"
static struct cdev *pdev = NULL;
static int major = 0;
static int minor = 0;
static int count = 2;
static int cdev_demo_open(struct inode * inode, struct file * file)
{
printk("%s,%d\n",__func__,__LINE__);
return 0;
}
static int cdev_demo_release(struct inode *inode, struct file * file)
{
printk("%s,%d\n",__func__,__LINE__);
return 0;
}
static ssize_t cdev_demo_read(struct file * file, char __user * buffer, size_t size, loff_t * loff)
{
printk("%s,%d\n",__func__,__LINE__);
return 0;
}
static ssize_t cdev_demo_write(struct file * file, const char __user * buffer, size_t size, loff_t * loff)
{
printk("%s,%d\n",__func__,__LINE__);
return 0;
}
//函数操作集
static struct file_operations fops ={
.owner = THIS_MODULE,
.open = cdev_demo_open,
.release = cdev_demo_release,
.read = cdev_demo_read,
.write = cdev_demo_write,
};
//入口函数
static int __init cdev_demo_init(void)
{
dev_t dev;
int ret;
printk("%s,%d\n",__func__,__LINE__);
//申请一个cdev结构体
pdev = cdev_alloc();
if(NULL == pdev){
printk("cdev_alloc failed.\n");
return -ENOMEM;
}
//初始化cdev
cdev_init(pdev,&fops);
//申请设备号
ret = alloc_chrdev_region(&dev,minor,count,DEVICE_NAME);
if(ret){
printk("alloc_chrdev_region failed.\n");
goto ERROR_CDEV;
}
major = MAJOR(dev);
//添加cdev
ret = cdev_add(pdev, dev,count);
if(ret) {
printk("cdev_add failed.\n");
goto ERROR_ADD;
}
return 0;
ERROR_ADD:
unregister_chrdev_region(dev,count);
ERROR_CDEV:
cdev_del(pdev);
return ret;
}
//出口函数
static void __exit cdev_demo_exit(void)
{
printk("%s,%d\n",__func__,__LINE__);
unregister_chrdev_region(MKDEV(major,minor),count);
cdev_del(pdev);
}
module_init(cdev_demo_init);
module_exit(cdev_demo_exit);
MODULE_LICENSE("GPL");
测试程序:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char* argv[])
{
int fd = open("/dev/cdev_demo",O_RDWR);
if(0 > fd){
perror("open\n");
return -1;
}
printf("fd= %d\n",fd);
write(fd,0,1);
read(fd,0,1);
close(fd);
return 0;
}
操作步骤:
//安装模块
shell@tiny4412:/mnt # insmod cdev_demo.ko
[ 316.087934] cdev_demo_init,49
//查看申请的设备号
shell@tiny4412:/mnt # cat /proc/devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
21 sg
29 fb
81 video4linux
89 i2c
108 ppp
116 alsa
128 ptm
136 pts
153 spi
180 usb
188 ttyUSB
189 usb_device
204 ttySAC
247 cdev_demo //系统自动分配的设备号
248 hidraw
249 BaseRemoteCtl
250 media
251 ttyGS
252 ump
253 leds
254 rtc
//在我们的驱动程序中,没有创建设备,需要手动的创建设备
shell@tiny4412:/mnt # mknod /dev/cdev_demo c 247 0
// /dev/cdev_demo 表示我们的设备,c 表示字符设备 247 主设备号, 0 次设备号
运行测试程序
./test
测试程序:
shell@tiny4412:/mnt # ./test
[ 570.708740] cdev_demo_open,17
fd= 3
[ 570.709397] cdev_demo_write,33
[ 570.709483] cdev_demo_read,27
[ 570.709564] cdev_demo_release,22
总结
目前的代码是在Android系统下运行的,在测试的过程中,出现 no such file or directory。
解决方案,在编译的时候,使用静态连接 -static