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

一、开发环境
    内核版本: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 <[email protected]
 *                  All rights reserved.
 *
 *       Filename:  globalmem.c
 *    Description:  This file 
 *                 
 *        Version:  0.0.0(08/28/2014~)
 *         Author:  liuchengdeng <[email protected]>
 *      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 <[email protected]>");
MODULE_LICENSE("Dual BSD/GPL");KERNEL_VER = linux-3.0
LINUX_SRC ?=../linuxrom/$(KERNEL_VER)

/*********************************************************************************
 *      Copyright:  (C) 2014 liuchengdeng <[email protected]
 *                  All rights reserved.
 *
 *       Filename:  Make
 *    Description:  This file 
 *                 
 *        Version:  0.0.0(08/28/2014~)
 *         Author:  liuchengdeng <[email protected]>
 *      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

发布了39 篇原创文章 · 获赞 16 · 访问量 6万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章