[Bnis] Linux驱动:动态创建字符设备,和调用驱动api测试

文件: 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 查看这个模块的信息.

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值