LINUX 设备驱动(完善 版(三))

dev_fifo.c


#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <asm/uaccess.h>

#define MAJOR_NUM	250


struct MycDev{
	int len;
	unsigned char buff[50];
	struct cdev cdev;
};

static dev_t 	g_pDevNum = {0};
struct MycDev 	*g_pcDev;
struct class  	*g_pCla;

//register device num
static int 	m_Ndevices = 3;
module_param(m_Ndevices, int, 0644);
MODULE_PARM_DESC(m_Ndevices, "The number of devices for register.\n");


static 	int 	mydev_fifo_open(struct inode *inode, struct file *file);
static ssize_t 	mydev_llseek(struct file *file, loff_t offset, int whence);
static ssize_t 	mydev_fifo_read(struct file *file, char __user *ubuf, size_t size, loff_t *ppos);
static ssize_t 	mydev_fifo_write(struct file *file, const char __user *ubuf, size_t size, loff_t *ppos);
long 		mydev_fifo_unlocked_ioctl(struct file *file, unsigned int cmd,unsigned long arg);
int     __init 	MyDev_Fifo_Init(void);
void 	__exit	MyDev_Fifo_Exit(void);


//打开设备
static 	int mydev_fifo_open(struct inode *inode, struct file *file)
{	
   	printk("dev_fifo_open success!\n");
    	struct MycDev *cdev ;
	cdev = container_of(inode->i_cdev, struct MycDev, cdev);
    	file->private_data = cdev;
	return 0;	
}


static ssize_t 	mydev_llseek(struct file *file, loff_t offset, int whence)
{

	long newpos;
    	switch(whence) {
      case 0:
        newpos = offset;
        break;

      case 1:
        newpos = file->f_pos + offset;    
        break;

      case 2:
        newpos = 50 -1 + offset;
        break;

      default:
        return -EINVAL;
    }

    if ((newpos<0) || (newpos> 50))
        return -EINVAL;
        
    file->f_pos = newpos;
    return 0;
	
}


static ssize_t 	mydev_fifo_read(struct file *file, char __user *ubuf, size_t size, loff_t *ppos)
{
	char *kbuf = NULL;		
	int len = 0, ret = 0;
	struct MycDev *mycdv = file->private_data;
		
	printk("read: *ppos %lld\n", *ppos);
	// 读到末尾
	if(*ppos == mycdv->len){
		return 0;
	}
	
	//请求大大小 > buffer剩余的字节数 :读取实际记得字节数
	if(size > mycdv->len - *ppos){
		len = mycdv->len - *ppos;
	}	
	else{
		len = size;
	}

	//从上一次文件位置指针的位置开始读取数据
	kbuf = mycdv->buff + *ppos;
	
	// 拷贝数据到用户空间
	ret = copy_to_user(ubuf, kbuf, len);	
	if(ret != 0){
        	return -EFAULT;
	}else{
		printk("read ok\n");
	}

	//更新文件位置指针的值
	*ppos +=len; 	
	
	printk("read data success \n");	
	return len;	
	
}


static ssize_t 	mydev_fifo_write(struct file *file, const char __user *ubuf, size_t size, loff_t *ppos)
{
	int 	len = 0;
	char 	*writepos = NULL;
	struct  MycDev *mycdv = file->private_data;

	printk("write: ppos: %lld  ubuf: %s \n", *ppos, ubuf);	
	
	if(*ppos == sizeof(mycdv->buff) || NULL == ubuf){
		return -1;
	}
	
	if(size > sizeof(mycdv->buff) - *ppos){
		len = sizeof(mycdv->buff) - *ppos;
	}
	else{
		len = size;
	}

	//从上一次文件位置指针的位置开始写入数据
	writepos = mycdv->buff + *ppos;

	//拷贝数据到内核空间
	int ret = copy_from_user(writepos, ubuf, len);
	if(ret != 0){
        	return -EFAULT;
	}
	
	//更新文件位置指针的值
	*ppos +=len;

	//更新dev_fifo.len 
	mycdv->len +=len;		
	printk("write data success \n");

	return len;	
}


long 		mydev_fifo_unlocked_ioctl(struct file *file, unsigned int cmd,unsigned long arg)
{

	return 0;	

}


//设备操作函数接口
static const struct file_operations fifo_operations = {
	.owner = THIS_MODULE,
   	.open  = mydev_fifo_open,
	.llseek = mydev_llseek,
   	.read  = mydev_fifo_read,
    	.write = mydev_fifo_write,
    	.unlocked_ioctl = mydev_fifo_unlocked_ioctl,
};


int     __init 	MyDev_Fifo_Init(void)
{

	printk("\n\n************************************syw*********************************\n\n");
	int ret;
	int i =0;
	int j = 0;
	struct device *device;

	g_pcDev = kzalloc(m_Ndevices * sizeof(struct MycDev), GFP_KERNEL);
	if(!g_pcDev){
		return -ENOMEM;	
        	printk(KERN_NOTICE "Error add cdevdemo");  
	}
	
	//设备号 : 主设备号(12bit) | 次设备号(20bit)	
	g_pDevNum  = MKDEV(MAJOR_NUM, 0);
	
	//静态注册设备号
	 ret = register_chrdev_region(g_pDevNum, m_Ndevices, "dev_fifo");
   	 if(ret < 0){
		//静态注册失败,进行动态注册设备号
       		ret = alloc_chrdev_region(&g_pDevNum,0,m_Ndevices,"dev_fifo");
        	if(ret < 0){
            		printk("Fail to register_chrdev_region\n");
            		goto err_register_chrdev_region;
        	}
	}
	
	//创建设备类
    	g_pCla = class_create(THIS_MODULE, "dev_fifo");
	if(IS_ERR(g_pCla)){
       		ret = PTR_ERR(g_pCla);
        	goto err_class_create;
    	}	
	
	for(i=0; i < m_Ndevices; i++){
		//init 字符设备
		cdev_init(&g_pcDev[i].cdev, &fifo_operations);	
		//添加设备到操作系统
        	ret = cdev_add(&g_pcDev[i].cdev,g_pDevNum + i,1);
        	if (ret < 0){
            		goto err_cdev_add;
        	}
       		//导出设备信息到用户空间(/sys/class/类名/设备名)
		device = device_create(g_pCla,NULL,g_pDevNum + i,NULL,"dev_fifo%d",i);
        	if(IS_ERR(device)){
           		ret = PTR_ERR(device);
            		printk("Fail to device_create\n");
            		goto err_device_create;    
		}
	}

	printk("Register dev_fito to system,ok!\n");
	return 0;

err_register_chrdev_region:
	return ret;

err_class_create:
	unregister_chrdev_region(g_pDevNum, m_Ndevices);

err_cdev_add:
	//将已经添加的全部除去
	for(j=0; j < i; j++){
		cdev_del(&g_pcDev[j].cdev);
	}

err_device_create:
	//将已经导出的设备信息除去
    	for(j = 0;j < i; j++){
        	device_destroy(g_pCla,g_pDevNum + j);    
    	}
	
}


void 	__exit	MyDev_Fifo_Exit(void)
{
	int i;
   	 //删除sysfs文件系统中的设备
    	for(i = 0;i < m_Ndevices;i ++){
        	device_destroy(g_pCla,g_pDevNum + i);    
    	}

    	//删除系统中的设备类
    	class_destroy(g_pCla);

   	 //从系统中删除添加的字符设备
    	for(i = 0;i < m_Ndevices;i ++){
        	cdev_del(&g_pcDev[i].cdev);
    	}

    	//释放申请的设备号
    	unregister_chrdev_region(g_pDevNum, m_Ndevices);
    	return;
}


MODULE_LICENSE("GPL");
module_init(MyDev_Fifo_Init);
module_exit(MyDev_Fifo_Exit); 



Makefile

ifeq ($(KERNELRELEASE),)
KERNEL_DIR ?=/lib/modules/$(shell uname -r)/build 
PWD :=$(shell pwd)
modules:
	$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
.PHONY:modules clean 
clean:
	$(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean 
else 
    obj-m := dev_fifo.o 

endif



main.c


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>



int main(int argc, const char *argv[])
{

    int fd = 0;
    int n;
    char buf[1024] = "hello word";
    char tmp[1024] = {0};

    fd = open("/dev/dev_fifo0",O_RDWR);
    if(fd < 0){
        perror("Fail ot open");
        return -1;
    }
    printf("open successful ,fd = %d\n",fd);
    n = write(fd,buf,strlen(buf));
    if(n < 0){
        perror("Fail to write");
        return -1;
    }


    printf("write %d bytes!\n",n);
    n = write(fd,buf,strlen(buf));
    if(n < 0){
        perror("Fail to write");
        return -1;
    }

    printf("write %d bytes!\n",n);
    n = write(fd,buf,strlen(buf));
    if(n < 0){
        perror("Fail to write");
        return -1;
    }
    printf("write %d bytes!\n",n);
	/************************************************/
	lseek(fd, 0, SEEK_SET);	


	n = read(fd, tmp, 30);
	printf("read: %s\n", tmp);


    return 0;

}



测试结果:

yw@yw-VirtualBox:~/tmp/demo/charDrvice/demo2$ sudo ./a.out 
open successful ,fd = 3
write 10 bytes!
write 10 bytes!
write 10 bytes!
read: hello wordhello wordhello word



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值