1. 程式人生 > >linux驅動程式中的互斥體

linux驅動程式中的互斥體

/*
 * g_mtex.c
 *
 *  Created on: 2016年11月21日
 *      Author: chy
 */

#include <linux/types.h>
#include <linux/stat.h>
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/fcntl.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>
#define Buff_size 1024
#define dev_num 2

struct g_mutex{
	struct mutex mutex;
	char *buff;
};

struct g_mutex *g_buf = NULL;

static int open_file(struct inode *node,struct file *g_file)
{
	int ret = 1;
	int minor = MINOR(node->i_rdev);

	if(minor < dev_num){
		g_file->private_data = &g_buf[minor];
		ret = 0;
	}
	printk(KERN_INFO"開啟檔案\n");

	return ret;
}

static int close_file(struct inode *node,struct file *g_file)
{
	return 0;
}

static ssize_t read_file(struct file *g_file,char __user *buf,size_t size,loff_t *offt)
{
	int ret;
	loff_t ops = *offt;
	struct g_mutex *mutex = g_file->private_data;
	size_t count = size;

	if(ops >= strlen(mutex->buff) || ops >= Buff_size)
		return -1;

	if(ops + count > strlen(mutex->buff))
		count = strlen(mutex->buff) - ops;

	mutex_lock(&mutex->mutex); //獲得互斥鎖
	if(copy_to_user(buf,mutex->buff + ops,count))
		ret = -EFAULT;
	else{
		*offt += count;
		ret = count;
	}
	mutex_unlock(&mutex->mutex); //釋放互斥鎖

	return ret;
}

static ssize_t write_file(struct file *g_file,const char __user *buf,size_t size,loff_t* offt)
{
	int ret;
	loff_t ops = *offt;
	struct g_mutex *mutex = g_file->private_data;
	size_t count = size;

	if(ops >= Buff_size)
		return -1;

	if(Buff_size - ops > strlen(buf))
		count = strlen(buf);
	else count = Buff_size - ops;

	mutex_lock(&mutex->mutex); //獲得互斥鎖
	if(copy_from_user(mutex->buff + ops,buf,count)) //複製到使用者區
		ret = -EFAULT;
	else{
		*offt += count;
		ret = count;
	}
	mutex_unlock(&mutex->mutex); //釋放互斥鎖

	return ret;
}

static long g_ioctl(struct file *g_file,unsigned cmd,unsigned long ctl)
{
	struct g_mutex *mutex = g_file->private_data;

	switch(cmd){
	case 0:
		mutex_lock(&mutex->mutex); //獲取互斥鎖
		memset(mutex->buff, 0,sizeof(char) * Buff_size);
		mutex_unlock(&mutex->mutex); //釋放互斥鎖
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

struct file_operations file_ops = {
	.owner = THIS_MODULE,
	.open = open_file,
	.release = close_file,
	.read = read_file,
	.write = write_file,
	.unlocked_ioctl = g_ioctl,
};

struct cdev dev = {
		.owner = THIS_MODULE,
};

dev_t dev_no;
struct class *dev_class = NULL;
static int g_mutex_init(void)
{
	int ret = 0;
	int i;
	ret = alloc_chrdev_region(&dev_no,0,dev_num,"g_mutex"); //申請裝置號
	if(ret < 0)
		return ret;
	cdev_init(&dev,&file_ops); //初始化裝置
	cdev_add(&dev,dev_no,dev_num); //向核心註冊裝置

	g_buf = (struct g_mutex *)kmalloc(sizeof(struct g_mutex) * dev_num,GFP_KERNEL); //為虛擬裝置分配記憶體
	if(!g_buf){
		printk(KERN_INFO "記憶體分配失敗\n");
		unregister_chrdev_region(dev_no,dev_num);
		return -ENOMEM;
	}

	for(i = 0; i < dev_num; i++){
		g_buf[i].buff = (char *)kmalloc(sizeof(char) * Buff_size,GFP_KERNEL);
		memset(g_buf[i].buff,0,sizeof(char) * Buff_size);
		mutex_init(&(g_buf[i].mutex)); //初始化互斥變數
	}

	/*建立裝置檔案*/
	dev_class = class_create(THIS_MODULE,"mutex_device");
	device_create(dev_class,0,MKDEV(MAJOR(dev_no),0),0,"mutex_dev_0");
	device_create(dev_class,0,MKDEV(MAJOR(dev_no),1),0,"mutex_dev_1");

	printk(KERN_INFO"載入\n");

	return ret;
}

static void g_mutex_exit(void)
{
	int i;
	cdev_del(&dev); //刪除cdev
	for(i = 0; i < dev_num; i++)
		kfree(g_buf[i].buff);
	kfree(g_buf); //釋放記憶體

	/*刪除裝置檔案*/
	device_destroy(dev_class, MKDEV(MAJOR(dev_no),0));
	device_destroy(dev_class, MKDEV(MAJOR(dev_no),1));
	class_destroy(dev_class);

	unregister_chrdev_region(dev_no,dev_num); //釋放裝置號
	printk(KERN_INFO"解除安裝\n");

	return;
}

MODULE_LICENSE("GPL v2");
module_init(g_mutex_init);
module_exit(g_mutex_exit);//解除安裝