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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章