您的位置:首页 > 运维架构 > Linux

linux 驱动-----字符设备globalmem驱动实现

2014-08-28 16:57 92 查看
一、开发环境

内核版本:linux-3.0

开发板:FL2440(nandflash:K9F1G08 128M)

编译器:arm-linux-gcc 4.3.2

二、预先分析:

globalmem 意味着“全局内存”,在globalmem 字符设备驱动中会分配一片大小为GLOBALMEM_SIZE(这里是4K)的内存空间,并在驱动中提供该片内存的读写和定位函数,以供用户空间的进程能通过linux系统调用访问这片内存。本例这里是为了学习文件私有数据指针private_data,并包括两个设备,使得文件私有数据指针private_data的优势集中显现出来。

四、编写驱动并编译:

编写驱动程序globalmem.c文件,并编写Makefile文件,编译生成globalmem.ko文件,并下载到开发板/目录下面。
(所有代码实现都在后面贴出)

四、globalmem驱动在用户空间的验证:

[root@root
/]# ls

apps dev_adc init mnt sys var

bin etc jbs.mp3 proc tmp yw.mp3

data globalmem.ko lib root tslib

dev info linuxrc sbin usr

[root@root
/]# insmod globalmem.ko

[root@root
/]# mknod dev/globalmem0 c 250 0

[root@root /]# echo "hello" >/dev/globalmem0

written 6 bytes from 0

[root@root /]# cat /dev/globalmem0

read 4096 bytes from 0

hello

[root@root /]# mknod dev/globalmem1 c 250 1

[root@root /]# echo "world" >/dev/globalmem1

written 6 bytes from 0

[root@root /]# cat /dev/globalmem1

read 4096 bytes from 0

world

至此完毕,一下是相关代码:

/*********************************************************************************

* Copyright: (C) 2014 liuchengdeng <1037398771@qq.com>

* All rights reserved.

*

* Filename: globalmem.c

* Description: This file

*

* Version: 0.0.0(08/28/2014~)

* Author: liuchengdeng <1037398771@qq.com>

* ChangeLog: 1, Release initial version on "08/28/2014 09:42:22 AM"

*

********************************************************************************/

#include <linux/module.h>

#include <linux/types.h>

#include <linux/fs.h>

#include <linux/errno.h>

#include <linux/mm.h>

#include <linux/sched.h>

#include <linux/init.h>

#include <linux/cdev.h>

#include <asm/io.h>

#include <asm/system.h>

#include <asm/uaccess.h>

#include <linux/slab.h>

#include <asm/ioctl.h>

#define GLOBALMEM_SIZE 0x1000

#define MEM_CLEAR 0x1

#define GLOBALMEM_MAJOR 250

static int globalmem_major=GLOBALMEM_MAJOR;

struct globalmem_dev{

struct cdev cdev;

unsigned char mem[GLOBALMEM_SIZE];

};

struct globalmem_dev *globalmem_devp;

int globalmem_open(struct inode *inode ,struct file *filp)

{

struct globalmem_dev *dev;

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

filp->private_data=dev;

return 0;

}

int globalmem_release(struct inode *inode ,struct file *filp)

{

return 0;

}

static int globalmem_ioctl(struct inode *inodep,struct file *filp,unsigned int cmd ,unsigned long arg)

{

struct globalmem_dev *dev=filp->private_data;

switch (cmd){

case MEM_CLEAR:

memset(dev->mem,0,GLOBALMEM_SIZE);

printk(KERN_INFO "globalmem is set to zero\n");

break;

default:

return - EINVAL;

}

return 0;

}

static ssize_t globalmem_read(struct file *filp, char __user *buf ,size_t size ,loff_t *ppos)

{

unsigned long p=*ppos;

unsigned int count=size;

int ret=0;

struct globalmem_dev *dev=filp->private_data;

if(p>=GLOBALMEM_SIZE)

return 0;

if(count>GLOBALMEM_SIZE-p)

count=GLOBALMEM_SIZE-p;

if(copy_to_user(buf,(void *)(dev->mem+p),count)){

ret=-EFAULT;

}

else{

*ppos+=count;

ret=count;

printk(KERN_INFO "read %u bytes from %lu\n",count,p);

}

return ret;

}

static ssize_t globalmem_write(struct file *filp,const char __user *buf ,size_t size,loff_t *ppos)

{

unsigned long p=*ppos;

unsigned int count=size;

int ret=0;

struct globalmem_dev *dev=filp->private_data;

if(p>=GLOBALMEM_SIZE)

return 0;

if(count>GLOBALMEM_SIZE-p)

count=GLOBALMEM_SIZE-p;

if(copy_from_user(dev->mem+p,buf,count))

ret=-EFAULT;

else{

*ppos+=count;

ret=count;

printk(KERN_INFO "written %u bytes from %lu\n",count,p);

}

return ret;

}

static loff_t globalmem_llseek(struct file *filp,loff_t offset,int orig )

{

loff_t ret =0;

switch (orig)

{

case 0:

if(offset<0)

{

ret=-EINVAL;

break;

}

if((unsigned int)offset > GLOBALMEM_SIZE)

{

ret=-EINVAL;

break;

}

filp->f_pos=(unsigned int)offset;

ret=filp->f_pos;

break;

case 1:

if((filp->f_pos+offset)>GLOBALMEM_SIZE)

{

ret=-EINVAL;

break;

}

if((filp->f_pos+offset)<0)

{

ret=-EINVAL;

break;

}

filp->f_pos+=offset;

ret=filp->f_pos;

break;

default:

ret=-EINVAL;

break;

}

return ret;

}

static const struct file_operations globalmem_fops={

.owner = THIS_MODULE,

.llseek = globalmem_llseek,

.read = globalmem_read,

.write = globalmem_write,

// .ioctl=globalmem_ioctl,

.open = globalmem_open,

.release= globalmem_release,

};

static void globalmem_setup_cdev(struct globalmem_dev *dev,int index)

{

int err,devno=MKDEV(globalmem_major,index);

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

dev->cdev.owner=THIS_MODULE;

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

if(err)

printk(KERN_NOTICE "error %d adding globalmem %d",err,index);

}

int globalmem_init(void)

{

int result;

dev_t devno =MKDEV(globalmem_major,0);

if(globalmem_major)

result=register_chrdev_region(devno,2,"globalmem");

else

{

result=alloc_chrdev_region(&devno,0,2,"globalmem");

globalmem_major=MAJOR(devno);

}

if(result<0)

return result;

globalmem_devp=kmalloc(2*sizeof(struct globalmem_dev),GFP_KERNEL);

if(!globalmem_devp)

{

result = -ENOMEM;

goto fail_malloc;

}

memset(globalmem_devp,0,2*sizeof(struct globalmem_dev));

globalmem_setup_cdev(&globalmem_devp[0],0);

globalmem_setup_cdev(&globalmem_devp[1],1);

return 0;

fail_malloc:

unregister_chrdev_region(devno,1);

return result ;

}

void globalmem_exit(void)

{

cdev_del(&globalmem_devp[0].cdev);

cdev_del(&globalmem_devp[1].cdev);

kfree(globalmem_devp);

unregister_chrdev_region(MKDEV(globalmem_major,0),2);

}

module_init(globalmem_init);

module_exit(globalmem_exit);

module_param(globalmem_major,int ,S_IRUGO);

MODULE_AUTHOR("liu chengdeng <1037398771@qq.com>");

MODULE_LICENSE("Dual BSD/GPL");KERNEL_VER = linux-3.0

LINUX_SRC ?=../linuxrom/$(KERNEL_VER)

/*********************************************************************************

* Copyright: (C) 2014 liuchengdeng <1037398771@qq.com>

* All rights reserved.

*

* Filename: Make

* Description: This file

*

* Version: 0.0.0(08/28/2014~)

* Author: liuchengdeng <1037398771@qq.com>

* ChangeLog: 1, Release initial version on "08/28/2014 12:23:22 AM"

*

********************************************************************************/

PWD := $(shell pwd)

#Kernel module

obj-m +=globalmem.o

#Specify flags for the module compilation

#EXTRA_CFLAGS=-g -O0

mohule:

make -C $(LINUX_SRC) M=$(PWD) modules

make clear

clear:

@rm -rf *.o *.cmd *.mod.c .*ko.cmd .*.o.cmd .*.o.d

@rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f

clean: clear

@rm -f *.ko
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: