Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / 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! ");} module_init(glob_init);module_exit(glob_exit);二,Makefile文件的编写,源代码如下:12345obj-m:=glob.odefault:$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean:$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean怎样在 Ubuntu 上安装 Linux 3.11 内核 http://www.linuxidc.com/Linux/2013-09/89674.htmUbuntu 13.10 (Saucy Salamander) 内核已升级至 Linux Kernel 3.10 RC5 http://www.linuxidc.com/Linux/2013-06/86110.htmLinux Kernel 3.4.62 LTS 现已经提供下载 http://www.linuxidc.com/Linux/2013-09/90368.htm如何在Ubuntu 13.10上安装Linux内核 3.12 http://www.linuxidc.com/Linux/2013-11/92930.htm三,编译模块:把上面的glob.c和Makefile两个文件放在同一个文件夹下,我这里的文件夹是“glob阻塞操作实验”,然后进入文件夹,打开终端,登录root,输入指令make,便开始进行模块的编译了,遇到编译错误,多百度,积累经验。更多详情见请继续阅读下一页的精彩内容: http://www.linuxidc.com/Linux/2014-08/106012p2.htm