文件: first_drv.c,主要是做内核驱动测试,操作函数有open,release,read,write.
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#define BUFSIZE 1024
/*主设备和从设备号变量*/
static int test_major = 0;
static int test_minor = 0;
/*设备类别和设备变量*/
static struct cdev cdev;
static struct class *test_class = NULL;
static struct device *test_class_dev = NULL;
int number_of_devices = 1;
dev_t dev = 0;
static char *buf;
static unsigned int len;
/*打开设备方法,空实现*/
static int test_open(struct inode *inode, struct file *filp) {
printk("--test_open---\n");
return 0;
}
/*设备文件释放时调用,空实现*/
static int test_release(struct inode *inode, struct file *filp) {
printk("--test_release---\n");
return 0;
}
/************************
* file_operations->read
* 函数原型:static ssize_t read(struct file *file, char *buf, size_t count, loff_t *ppos)
************************/
static ssize_t test_read(struct file *file, char __user *buffer,size_t count, loff_t *f_pos)
{
if(*f_pos > 0)
return 0;
printk("---start read---\n");
printk("string is >>>>> %s\n", buf);
if(copy_to_user(buffer, buf, len))
return -EFAULT;
*f_pos = *f_pos + len;
return len;
}
/************************
* file_operations->write
* 函数原型:static ssize_t write(struct file *file, const char *buf, size_t count, loff_t *ppos)
************************/
static ssize_t test_write(struct file *file, const char __user *buffer,size_t count, loff_t *f_pos)
{
if(count <= 0)
return -EFAULT;
printk("---start write---\n");
len = count > BUFSIZE ? BUFSIZE : count;
// kfree memory by kmalloc before
if(buf != NULL)
kfree(buf);
buf = (char*)kmalloc(len+1, GFP_KERNEL);
if(buf == NULL)
{
printk("-device_create kmalloc fail!\n");
return -EFAULT;
}
//memset(buf, 0, sizeof(buf));
memset(buf, 0, len+1);
if(copy_from_user(buf, buffer, len))
return -EFAULT;
printk("#device_create writing :%s",buf);
return len;
}
/*设备文件操作方法表*/
static struct file_operations test_fops = {
.owner = THIS_MODULE,
.open = test_open,
.release = test_release,
.read = test_read,
.write = test_write,
};
static void test_setup_cdev (void)
{
int error;
dev_t devno = MKDEV(test_major, test_minor);
cdev_init (&cdev, &test_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &test_fops;
/*注册字符设备*/
error = cdev_add (&cdev, devno, 1);
if(error)
printk("-Error %d : adding test_setup_cdev", error);
}
static int __init test_init (void)
{
int err = -1;
dev_t dev = 0;
printk("# Initializing test device.\n");
/*动态分配主设备和从设备号*/
err = alloc_chrdev_region(&dev, 0, number_of_devices, "testDev");
if(err < 0) {
printk("-Failed to alloc char dev region.\n");
return err;
}
test_major = MAJOR(dev);
test_minor = MINOR(dev);
printk("# id: test_major ==> %d ; test_minor ==> %d \n",test_major,test_minor);
/*初始化设备,Register*/
test_setup_cdev();
/*在/sys/class/目录下创建设备类test_class别目录test*/
test_class = class_create(THIS_MODULE, "test_class");
if(IS_ERR(test_class))
{
printk("-Err: failed in creating class.\n");
return -1;
}
/*
* device_create - creates a device and registers it with sysfs
* @class: pointer to the struct class that this device should be registered to
* @parent: pointer to the parent struct device of this new device, if any
* @devt: the dev_t for the char device to be added
* @drvdata: the data to be added to the device for callbacks
* @fmt: string for the device's name
*
* struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
*
*/
/*在/dev/目录和/sys/class/testDev目录下分别创建设备文件testDev*/
test_class_dev = device_create(test_class, NULL, MKDEV(test_major, 0), NULL, "testDev");
if(IS_ERR(test_class_dev))
{
printk("Err: failed in creating device.\n");
return -1;
}
printk("#Succedded to initialize test device.\n");
return 0;
}
/*模块卸载方法*/
static void __exit test_exit (void)
{
dev_t devno = MKDEV (test_major, test_minor);
cdev_del(&cdev);
device_destroy(test_class, devno); //delete device node under /dev
class_destroy(test_class); //delete class created by us
unregister_chrdev_region (devno, number_of_devices);
printk ("#Char driver test_exit.\n");
}
module_init (test_init);
module_exit (test_exit);
MODULE_AUTHOR("bnis");
MODULE_DESCRIPTION("Device_create Driver");
MODULE_LICENSE("GPL");
user.c 文件是测试调用api接口.将一串字符串往内核发送,然后读回来显示
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h> //sleep,write,read
#include <stdlib.h> //system()
int main(int argc, char **argv)
{
int fd;
int val;
char sendDat[]="this_is_kernel_exam!";
char readDat[100]={0};
fd = open("/dev/testDev", O_RDWR);
if (fd < 0)
{
printf("--------can't open device-----!\n");
return 0;
}
val = write(fd, sendDat, strlen(sendDat));
printf("------Write done----------ret=%d. \n" , val);
val = read(fd, readDat, strlen(readDat));
printf("------Read done----------ret=%d.str=%s \n" , val,readDat);
sleep(1);
system("dmesg -T -c ");//for kernel print
return 0;
}
Makefile文件:
#!/bin/bash
$(warning KERNELRELEASE = $(KERNELRELEASE))
ifeq ($(KERNELRELEASE),)
#内核的源码路径, ?= 条件赋值, uname -r 得到内核版本号
#KERNELDIR ?= /home/mint/itop/linux_3.0
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
# := 立即赋值, 得到当前的绝对路径
PWD := $(shell pwd)
# -C 切换工作路径, $(MAKE) = make
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules*
.PHONY: modules clean
else
# 生成模块
obj-m := first_drv.o
endif
user:
gcc user.c -o runTest
######################################
在终端输入 make 编译ko文件, make user 编译调用文件生成runTest,最后安装模块,并运行测试,指令如下;
#make
#make user
# insmod first_drv.ko
# ./runTest
最后看到结果如下图
当insmod安装该模块时,在 /sys/class目录下会生成一个test_class文件夹,里面有一个testDev快捷链接文件夹.
modinfo first_drv.ko 查看这个模块的信息.