linux字符设备驱动学习笔记(一):简单的字符设备驱动

最近在鼓捣lnux字符设备驱动,在网上搜集的各种关于linux设备驱动的代码和注释,要么是针对2.4的,要么是错误百出,根本就不能运行成功,真希望大家在发博客的时候能认真核对下代码的正确性,特别是要把代码的运行环境和依赖条件列举出来,否则会对读者造成很大的误解。

以下代码的运行环境为:

操作系统:debian 6

内核版本:2.6.32(amd 64)

gcc版本:4.4.5

源代码如下所示(源代码确保编译可通过,运行无bug):

#include<linux/module.h>

#include<linux/kernel.h>

#include<linux/fs.h>

#include<linux/types.h>

#include<linux/cdev.h>

#include<asm/uaccess.h>

#include <linux/init.h> 



MODULE_LICENSE("GPL");





static int yang_open(struct inode*, struct file*);

static int yang_release(struct inode*, struct file*);



static ssize_t yang_read(struct file*, char *,size_t, loff_t*);

static ssize_t yang_write(struct file*,const char*, size_t,loff_t*);



loff_t yang_llseek(struct file *filp, loff_t off, int whence);



static int major;

static int device_open = 0;



static char *device_name = "myvar";



static dev_t devid;



static struct mydev *my_cdev;



struct mydev{

	char *data;

	struct cdev cdev;

	unsigned long size;

};





static struct file_operations fops = 

{

	.owner = THIS_MODULE,

	.read  = yang_read,

	.write = yang_write,

	.open  = yang_open,

	.release = yang_release,

	.llseek = yang_llseek

};



int init_yang_module(void)

{

	struct mydev *dev = (struct mydev *)kmalloc(sizeof(struct mydev),GFP_KERNEL);



	my_cdev = dev;//注册为全局变量,便于模块卸载



	memset(dev, 0, sizeof(struct mydev));



	dev->size = 10;

	

	int err;



	alloc_chrdev_region(&devid, 0, 1, "myvar");

	

	major = MAJOR(devid);

	

	cdev_init(&dev->cdev, &fops);



	err = cdev_add(&dev->cdev, devid, 1);



	if(err)

	{

		printk(KERN_INFO"I was major number %d.\n",major);

		return -1;

	}

	

	printk("major number is %d\n",MAJOR(devid));

	

	dev->data = (char*)kmalloc(dev->size * sizeof(char),GFP_KERNEL);



	memset(dev->data,0,dev->size * sizeof(char));

       

	return 0;

}



void cleanup_yang_module(void)

{

	cdev_del(&my_cdev->cdev);

	unregister_chrdev_region(devid, 1);

	printk("cleanup done\n");

}



loff_t yang_llseek(struct file *filp, loff_t off, int whence)

{

	struct mydev *dev = filp->private_data;



	loff_t newpos;

	switch(whence)

	{

		case SEEK_SET:

			newpos = off;

		case SEEK_CUR:

			newpos = filp->f_pos + off;

		case SEEK_END:

			newpos = dev->size + off;

	 		break;

		default:

	 		return -EINVAL;

	}

	if(newpos < 0) return -EINVAL;

	filp->f_pos = newpos;

	 return newpos;

}



static int yang_open(struct inode* inode, struct file* file)

{

	struct mydev *dev;



	dev = container_of(inode->i_cdev, struct mydev, cdev);



	file->private_data = dev;



	return 0;

}



static int yang_release(struct inode* inode, struct file* file)

{

	return 0;

}



static ssize_t yang_read(struct file* filp, char *buffer,size_t length, loff_t* off)

{

	struct mydev *dev = filp->private_data;



	if(*off >= dev->size)

	{

		return 0;

	}

	if(*off + length > dev->size)

	length = dev->size - *off;

	if(copy_to_user(buffer,dev->data + *off,length * sizeof(char)))

	{

		return -EFAULT;	

	}

	*off += length;



 	return length;

}

static ssize_t yang_write(struct file* filp,const char* buffer, size_t length,loff_t* off)

{

	struct mydev *dev = filp->private_data;



	if(length > dev->size)

	{

		return -EFAULT;

	}

	if(copy_from_user(dev->data,buffer,dev->size * sizeof(char)))

	{

		return -EFAULT;

	}

	*off += length;

	return dev->size;

}



module_init(init_yang_module);       

module_exit(cleanup_yang_module);        

  

以后有时间我再把注释加上,如果有兄弟刚刚学习linux设备驱动,这份源代码是最好的礼物。

你可能感兴趣的:(linux)