Linux内核驱动入门之阻塞操作实验:glob

首先,先来了解一下设备的阻塞与非阻塞操作以及实现阻塞操作的方法:

1.设备的阻塞与非阻塞操作:

阻塞操作是指,在执行设备操作时,若不能获得资源,则进程被挂起直到满足可操作的条件再进行操作。非阻塞操作是指,当进程不能进行设备操作时,并不挂起,它或者放弃,或者不停地查询,直到可以进行操作为止。

2.实现阻塞操作的方法:

在linux驱动程序中,可以使用等待队列(wait queue)来实现阻塞访问。

一,glob字符设备驱动程序的编写,把文件名命名为glob.c,源代码如下:


#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <asm/uaccess.h>

#include <linux/wait.h>  //有关等待队列的头文件

#include <linux/semaphore.h> //有关信号量的头文件

#include <linux/sched.h>

MODULE_LICENSE("GPL");

#define MAJOR_NUM 1400

#define DEVICE_NAME "glob"

static int glob_var = 0;

static struct semaphore sem; //定义信号量

static wait_queue_head_t outq;  //定义一个等待队列头 

static int flag = 0;

//*******************定义read方法****************************

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

{

//等待数据可获得

//wait_event_interruptible的返回一个整数值,非零值表示休眠被某个信号中断

//wait_event_interruptible中第一个参数是等待队列头,第二个参数是一个布尔表达式,在条件为真之前,进程会保持休眠

if (wait_event_interruptible(outq, flag != 0))

{

return - ERESTARTSYS;

}

//down_interruptible 函数返回非零值,表示操作被中断,调用者拥有信号量失败

if (down_interruptible(&sem))

{

return - ERESTARTSYS;

}

flag = 0;

//将内核空间中的数据移动到用户空间

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

{

up(&sem); //移动数据的操作不完全成功也需要释放信号量

return - EFAULT;

}

up(&sem);//移动数据成功,释放信号量

return sizeof(int);

}

//************************定义write方法******************************

//glob_write函数中,flip是文件指针,buf是指向用户空间的缓冲区,len表示请求传输数据的长度,

//off指向一个长偏移量类型对象的指针,这个对象指明用户在文件中进行存储操作的位置 

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

{

if (down_interruptible(&sem))

{

return - ERESTARTSYS;

}

//将用户空间的数据移动到内核空间

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

{

up(&sem); //移动数据不完全成功也需要释放信号量

return - EFAULT;

}

up(&sem); //移动数据成功,释放信号量

flag = 1;

//通知数据可获得

wake_up_interruptible(&outq); //唤醒休眠进程       

return sizeof(int);

}

//************初始化file_operations结构体*************

struct file_operations glob_fops =

{

.owner = THIS_MODULE,

.read = glob_read,

.write = glob_write,

};

//*******模块初始化函数*********

static int __init glob_init(void)

{

int ret;

ret = register_chrdev(MAJOR_NUM, DEVICE_NAME, &glob_fops);

if (ret)

{

printk("glob register failure");

}

else

{

printk("glob register success");

//init_MUTEX(&sem);

sema_init(&sem,1); //初始化一个互斥锁,把信号量sem的值设置为1

init_waitqueue_head(&outq); //初始化等候队列头     

}

return ret;

}

//************模块卸载函数**************

static void __exit glob_exit(void)

{

unregister_chrdev(MAJOR_NUM, DEVICE_NAME);

printk("glob unregister success!\n");

}

module_init(glob_init);

module_exit(glob_exit);

二,Makefile文件的编写,源代码如下:

12345

obj-m:=glob.o

default:

$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:

$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

怎样在 Ubuntu 上安装 Linux 3.11 内核

Ubuntu 13.10 (Saucy Salamander) 内核已升级至 Linux Kernel 3.10 RC5

Linux Kernel 3.4.62 LTS 现已经提供下载

如何在Ubuntu 13.10上安装Linux内核 3.12

三,编译模块:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/2cfef473832591f3e42302295955d168.html