虚拟字符设备的完整制作过程 模块源代码,应用,编译所有步骤均有详细介绍

来源:互联网 发布:淘宝鱼塘是什么意思 编辑:程序博客网 时间:2024/05/01 02:35

字符设备:设备发送与接收数据是以字符的形式进行;

块设备:是以数据缓冲区的形式进行


虚拟字符设备

驱动部分:

注册设备函数:register_chrdev()

举例: register_chrdev(MAJOR_NUM, " gobalvar ", &gobalvar_fops)

                                           MAJOR_NUM 为主设备号,“gobalvar”为设备名,gobalvar_fops 为包含基本函数入口点的结构体,类型为 file_operations

注销设备函数:unregister_chrdev(MAJOR_NUM, " gobalvar ")

对于字符设备来说,要提供的主要入口有:open ()、release ()、read ()、write ()、ioctl ()、llseek()、poll()等

open()函数  对设备特殊文件进行 open()系统调用时,将调用驱动程序的 open ()  函数

int (*open)(struct inode * ,struct file *); 参数 inode 为设备特殊文件的 inode (索引结点)  结构的指针,参数 file 是指向这一
设备的文件结构的指针。

返回状态码(0 表示成功,负数表示存在错误) 



举例:

static int globalvar_open(struct inode *inode, struct file *filp) 

struct file_operations globalvar_fops = 
{    

    read: globalvar_read, 

     write: globalvar_write,

     open: globalvar_open, 

     release: globalvar_release, 
}; 



release()函数  当最后一个打开设备的用户进程执行 close ()系统调用时,内核将调用驱
动程序的 release ()  函数: void (*release) (struct inode * ,struct file *) ; 
release  函数的主要任务是清理未结束的输入/输出操作、释放资源、用户自定义排他标
志的复位等。

举例:

static int globalvar_release(struct inode *inode, struct file *filp) 

    globalvar_count--; 
    return 0; 

read()函数  当对设备特殊文件进行 read()  系统调用时,将调用驱动程序 read()  函数: 
ssize_t (*read) (struct file *, char *, size_t, loff_t *); 

举例:

static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t 
    *off) 

    if (down_interruptible(&sem)) //获取信号量sem,不能被中断打断
    { 
        return    - ERESTARTSYS; 
    } 
    if (copy_to_user(buf, &global_var, sizeof(int))) 
    { 
        up(&sem); //释放信号量sem,唤醒等待者
        return    - EFAULT; 
    } 
    up(&sem); //释放信号量sem,唤醒等待者
    return sizeof(int); 

write( )  函数  当设备特殊文件进行 write ()  系统调用时,将调用驱动程序的 write ()  函
数: 

static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, 
    loff_t *off) 

    if (down_interruptible(&sem)) //获取信号量sem,不能被中断打断
    { 
        return    - ERESTARTSYS; 
          } 
    if (copy_from_user(&global_var, buf, sizeof(int))) 
    { 
        up(&sem); //释放信号量sem,唤醒等待者
        return    - EFAULT; 
    } 
    up(&sem); //释放信号量sem,唤醒等待者
    return sizeof(int); 

ioctl()  函数  该函数是特殊的控制函数,可以通过它向设备传递控制信息或从设备取得状态信息

llseek()函数  该函数用来修改文件的当前读写位置,并将新位置作为(正的)返回值返回

poll()函数  poll  方法是 poll  和 select  这两个系统调用的后端实现,用来查询设备是否可读或可写,或是否处于某种特殊状态


驱动代码:用信号量来控制每次只能有一个进程访问这个文件


#include <linux/module.h> 

#include <linux/init.h> 
#include <linux/fs.h> 
#include <asm/uaccess.h> 
//#include <asm/semaphore.h> 
 
MODULE_LICENSE("GPL"); 
 
#define MAJOR_NUM    255 
 
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*); 
static int globalvar_open(struct inode *inode, struct file *filp); 
static int globalvar_release(struct inode *inode, struct file *filp); 
 
struct file_operations globalvar_fops = 
{    read: globalvar_read, write: globalvar_write, open: globalvar_open, release: 
        globalvar_release, 
}; 
 
static int global_var = 0; 
static int globalvar_count = 0; 
static struct semaphore sem; 
static spinlock_t spin = SPIN_LOCK_UNLOCKED; 
 
 
static int __init globalvar_init(void) 

    int ret; 
    ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops); 
    if (ret) 
    { 
        printk("globalvar register failure"); 
    } 
    else 
    { 
        printk("globalvar register success"); 
        init_MUTEX(&sem); //初始化一个互斥锁
    } 
    return ret; 

 
static void __exit globalvar_exit(void) 

    //int ret; 
    //ret =
     unregister_chrdev(MAJOR_NUM, "globalvar"); 
   /* if (ret) 
    { 
        printk("globalvar unregister failure"); 
    } 
    else 
    { 
        printk("globalvar unregister success"); 
    } */

 
static int globalvar_open(struct inode *inode, struct file *filp) 

 
    //获得自选锁 
        spin_lock(&spin); //获得自旋锁,如果立即获得,它将马上返回,如果没有立即获得,则自旋在那里,直到自旋锁的保持者释
 
    //临界资源访问 
    if (globalvar_count)   //借助自旋锁来保护全局变量globalvar_count (记录打开设备的进程数)的访问来实现设备只能被一个进程打开
    { 
        spin_unlock(&spin); //释放自旋锁,与spin_lock搭配使用
        return    - EBUSY; 
    } 
    globalvar_count++; 
 
    //释放自选锁 
    spin_unlock(&spin); 
 
    return 0; 

 
static int globalvar_release(struct inode *inode, struct file *filp) 

    globalvar_count--; 
    return 0; 

 
static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t 
    *off) 

    if (down_interruptible(&sem)) //获取信号量sem,不能被中断打断
    { 
        return    - ERESTARTSYS; 
    } 
    if (copy_to_user(buf, &global_var, sizeof(int))) 
    { 
        up(&sem); //释放信号量sem,唤醒等待者
        return    - EFAULT; 
    } 
    up(&sem); //释放信号量sem,唤醒等待者
    return sizeof(int); 

 
static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, 
    loff_t *off) 

    if (down_interruptible(&sem)) //获取信号量sem,不能被中断打断
    { 
        return    - ERESTARTSYS; 
          } 
    if (copy_from_user(&global_var, buf, sizeof(int))) 
    { 
        up(&sem); //释放信号量sem,唤醒等待者
        return    - EFAULT; 
    } 
    up(&sem); //释放信号量sem,唤醒等待者
    return sizeof(int); 

 
module_init(globalvar_init); 

module_exit(globalvar_exit); 


Makefile编写:

ifeq ($(KERNELRELEASE),)
#KERNELDIR ?= /lib/modules/$(shell uname -r)/build
KERNELDIR ?= /usr/src/linux-headers-$(shell uname -r)/




PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
obj-m := globalvar.o
endif

编译完了,要加载内核模块:insmod globalvar.ko

要让应用可以访问还要创建节点:mknod /dev/globalvar c 255 0 

应用程序编写:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <stdio.h> 
#include <fcntl.h> 
main() 

    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 
    { 
        printf("Device open failure\n"); 
    } 

编译应用: gcc -o globalvar.o globalvartest.c


执行应用程序./globalvartest.o


0 0
原创粉丝点击