扫一扫
关注微信公众号

深入浅出 Linux字符设备驱动程序解析
2007-04-30   网络

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

loff_t (*llseek) (struct file *, loff_t, int);

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

unsigned int (*poll) (struct file *, struct poll_table_struct *);

我们将在"设备的阻塞与非阻塞操作"一节对该函数进行更深入的介绍。

 设备"gobalvar"的驱动程序的这些函数应分别命名为gobalvar_open、 gobalvar_ release、gobalvar_read、gobalvar_write、gobalvar_ioctl,因此设备"gobalvar"的基本入口点结构变量gobalvar_fops 赋值如下:

struct file_operations gobalvar_fops = {

 read: gobalvar_read,

 write: gobalvar_write,

};

  上述代码中对gobalvar_fops的初始化方法并不是标准C所支持的,属于GNU扩展语法。

  完整的globalvar.c文件源代码如下:

#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <asm/uaccess.h> 

MODULE_LICENSE("GPL");

#define MAJOR_NUM 254 //主设备号

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*);

//初始化字符设备驱动的file_operations结构体

struct file_operations globalvar_fops =

{

 read: globalvar_read, write: globalvar_write,

};

static int global_var = 0; //"globalvar"设备的全局变量

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");

 }

 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 ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)

{

 //将global_var从内核空间复制到用户空间

 if (copy_to_user(buf, &global_var, sizeof(int)))

 {

  return - EFAULT;

 } 

 return sizeof(int);

}

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

{

 //将用户空间的数据复制到内核空间的global_var

 if (copy_from_user(&global_var, buf, sizeof(int)))

 {

  return - EFAULT;

 } 

 return sizeof(int);

}

module_init(globalvar_init);

module_exit(globalvar_exit); 

  运行:

gcc -D__KERNEL__ -DMODULE -DLINUX -I /usr/local/src/linux2.4/include -c -o globalvar.o globalvar.c 

  编译代码,运行:

inmod globalvar.o 

  加载globalvar模块,再运行:

cat /proc/devices 

  发现其中多出了"254 globalvar"一行,如下图:

 

  接着我们可以运行:

mknod /dev/globalvar c 254 0 

  创建设备节点,用户进程通过/dev/globalvar这个路径就可以访问到这个全局变量虚拟设备了。

我们写一个用户态的程序globalvartest.c来验证上述设备:

#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 globalvartest.o globalvartest.c 

  运行

./globalvartest.o 

  可以发现"globalvar"设备可以正确的读写。

热词搜索:

上一篇:深入浅出 Linux字符设备驱动程序解析 一
下一篇:在Linux操作系统下如何开启硬盘DMA 一

分享到: 收藏