设为首页 加入收藏

TOP

Linux内核驱动入门之阻塞操作实验:glob
2014-11-23 21:31:43 来源: 作者: 【 】 浏览:8
Tags:Linux 内核 驱动 入门 阻塞 操作 实验 glob

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


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


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


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


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


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



#include


#include


#include


#include


#include //有关等待队列的头文件


#include //有关信号量的头文件


#include


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


三,编译模块:


把上面的glob.c和Makefile两个文件放在同一个文件夹下,我这里的文件夹是“glob阻塞操作实验”,然后进入文件夹,打开终端,登录root,输入指令make,便开始进行模块的编译了,遇到编译错误,多百度,积累经验。


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇针对TQ2440开发板上Linux2.6.30.4.. 下一篇使用matlab进行mex编译时的路径问..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: