写Linux字符设备驱动模板--测试通过

1,首先,建立文件夹driver,在该文件夹下面新建globalvar.c和Makefile文件,然后编写驱动程序,保存到globalvar.c中

/*
 *	Simple Char_device Driver Test-- globalvar.c
 *	Date	2012/08/21
 *	Author	Jerryz
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/uaccess.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jerryz");

#define MINIOR_NUM 0
#define DEVICE_SUM 1
#define MAJOR_NUM 100 	/* major device number */
#define MINOR_NUM 0 	/* minor device number */

static int globalvar_open(struct inode *inode, struct file *filp);
static int globalvar_release(struct inode *, struct file *filp);
static ssize_t globalvar_read(struct file*, char*, size_t, loff_t*);
static ssize_t globalvar_write(struct file*, const char*, size_t, loff_t*);

/* the major device number */
static int globalvar_major = MAJOR_NUM;
static int globalvar_minor = MINOR_NUM;

/* init the file_operations structure */
struct file_operations globalvar_fops =
{
   .owner = THIS_MODULE,
   .open = globalvar_open,
   .release = globalvar_release,
   .read = globalvar_read,
   .write = globalvar_write,
};

/* define a cdev device */
struct cdev *cdev;

static int global_var = 0; /* global var */

/* module init */
static int __init globalvar_init(void)
{
   int ret = 0;
   dev_t devno = MKDEV(MAJOR_NUM, MINOR_NUM);
   cdev = cdev_alloc();

   /* register the device driver */
   /*ret = alloc_chrdev_region(MAJOR_NUM, "globalvar", &globalvar_fops);*/
   if(register_chrdev_region(devno, DEVICE_SUM, "globalvar"))
   {
       /* register fail, so use automatic allocate */
       if(alloc_chrdev_region(&devno, globalvar_minor, DEVICE_SUM, "globalvar"))
           printk("globalvar register failure.\n");
       globalvar_major = MAJOR(devno);
   }
   else
   {
       /*
       * cdev_init should be use if use the way of static statement.
       * struct cdev cdev;
       * cdev_init(&cdev, &globalvar_fops);
       * cdev.owner = THIS_MODULE;
       *
       * if using dymatic allocation.
       * struct cdev *cdev;
       * cdev = cdev_alloc();
       * cdev->owner = THIS_MODULE;
       * cdev->ops = &globalvar_fops;
       */

       cdev->owner = THIS_MODULE;
       cdev->ops = &globalvar_fops;
       if ((ret = cdev_add(cdev, devno, 1)))
           printk(KERN_NOTICE "Error %d adding globalvar.\n", ret);
       else
           printk("globalvar register success.\n");
   }

   return ret;
}

/* module exit */
static void __exit globalvar_exit(void)
{
   dev_t devno = MKDEV(globalvar_major, 0);

   /* remove cdev from kernel */
   cdev_del(cdev);

   /* unregister the device driver */
   unregister_chrdev_region(devno, 1);

   /* free the dev structure */
   if(cdev)
       kfree(cdev);
   cdev = NULL;
}

/* open device */
static int globalvar_open(struct inode *inode, struct file *filp)
{
   int ret = 0;
   printk("open success.\n");
   return ret;
}

/* release device */
static int globalvar_release(struct inode *inode, struct file *filp)
{
   printk("release success.\n");
   return 0;
}

/* read device */
static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
   printk("reading...\n");
   if(copy_to_user(buf, &global_var, sizeof(int)))
   {
       return -EFAULT;
   }
   return sizeof(int);
}

/* write device */
static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
   printk("writing...\n");
   if(copy_from_user(&global_var, buf, sizeof(int)))
   {
       return -EFAULT;
   }
   return sizeof(int);
}

/* module register */
module_init(globalvar_init);
module_exit(globalvar_exit);


2,编写驱动程序的Makefile,保存到driver文件夹下的Makefile中

#
# Makefile -- for driver 
#

module=globalvar

ifneq ($(KERNELRELEASE),)
	obj-m := ${module}.o
else
	KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
	rm -f *.o *.ko *.mod.c *~
insmod:
	sudo insmod ${module}.ko
	dmesg | tail
rmmod:
	sudo rmmod ${module}
	dmesg | tail
endif


3,新建文件夹AppTest,然后在该文件夹下新建test.c和Makefile文件,然后编写应用程序,保存到test.c中

/*
* test.c -- a test file for globalvar reading and writing
*/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>

int main(void)
{
    int fd, num;
    /*打开"/dev/globalvar"*/
    fd = open("/dev/globalvar", O_RDWR, S_IRUSR | S_IWUSR);
    if (fd != -1 )
    {
        /*初次读globalvar*/
        read(fd, &num, sizeof(int));
        printf("The globalvar is %d\n", num);

        /*写globalvar*/
        printf("Please input the num written to globalvar\n");
        scanf("%d", &num);
        write(fd, &num, sizeof(int));

        /*再次读globalvar*/
        read(fd, &num, sizeof(int));
        printf("The globalvar is %d\n", num);

        /*关闭"/dev/globalvar"*/
        close(fd);
    }
    else
    {
        /* if not sudo, maybe come here */
        printf("Device open failure\n");
	}
}
 

4,编写应用程序Makefile,保存到AppTest文件夹下的Makefile中

CROSS=

all: test

test:test.c
	$(CROSS)gcc -o test test.c
	$(CROSS)strip test
clean:
	@rm -vf test *.o *~


5,进入终端, 分别进入目录driver和AppTest中,敲入make命令,编译完成后,我们要用到的是globalvar.ko文件,下面的操作把驱动程序加载到内核,然后创建设备节点:

一、insmod -f globalvar.ko

二、mknod /dev/globalvar c 100 0

其中c表示字符设备,100是主设备号,0是从设备号。

6,测试程序。进入AppTest目录中,执行以下命令测试

./test





以下是一个简单的Linux字符设备驱动程序模板,供参考: ```c #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/uaccess.h> #define DEVICE_NAME "mychardev" #define CLASS_NAME "mycharclass" static int major_num = 0; static struct class* mycharclass = NULL; static struct device* mychardev = NULL; static struct cdev mycdev; static int mychardev_open(struct inode*, struct file*); static int mychardev_release(struct inode*, struct file*); static ssize_t mychardev_read(struct file*, char*, size_t, loff_t*); static ssize_t mychardev_write(struct file*, const char*, size_t, loff_t*); static struct file_operations mychardev_fops = { .owner = THIS_MODULE, .open = mychardev_open, .release = mychardev_release, .read = mychardev_read, .write = mychardev_write, }; static int __init mychardev_init(void) { // allocate major number dynamically if (alloc_chrdev_region(&major_num, 0, 1, DEVICE_NAME) < 0) { return -1; } // create device class if ((mycharclass = class_create(THIS_MODULE, CLASS_NAME)) == NULL) { unregister_chrdev_region(major_num, 1); return -1; } // create device if ((mychardev = device_create(mycharclass, NULL, major_num, NULL, DEVICE_NAME)) == NULL) { class_destroy(mycharclass); unregister_chrdev_region(major_num, 1); return -1; } // initialize cdev cdev_init(&mycdev, &mychardev_fops); mycdev.owner = THIS_MODULE; // add cdev to kernel if (cdev_add(&mycdev, major_num, 1) < 0) { device_destroy(mycharclass, major_num); class_destroy(mycharclass); unregister_chrdev_region(major_num, 1); return -1; } printk(KERN_INFO "mychardev: registered\n"); return 0; } static void __exit mychardev_exit(void) { cdev_del(&mycdev); device_destroy(mycharclass, major_num); class_destroy(mycharclass); unregister_chrdev_region(major_num, 1); printk(KERN_INFO "mychardev: unregistered\n"); } static int mychardev_open(struct inode* inodep, struct file* filep) { printk(KERN_INFO "mychardev: opened\n"); return 0; } static int mychardev_release(struct inode* inodep, struct file* filep) { printk(KERN_INFO "mychardev: closed\n"); return 0; } static ssize_t mychardev_read(struct file* filep, char* buffer, size_t len, loff_t* offset) { printk(KERN_INFO "mychardev: read from device\n"); return 0; } static ssize_t mychardev_write(struct file* filep, const char* buffer, size_t len, loff_t* offset) { printk(KERN_INFO "mychardev: wrote to device\n"); return len; } module_init(mychardev_init); module_exit(mychardev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple character device driver"); ``` 需要注意的是,该模板仅提供了一个最基本的字符设备驱动程序框架,需要根据实际需求进行修改。此外,还需要在Makefile中添加相应的编译规则,将驱动程序编译成内核模块
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术在路上

帮助需要的人

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值