Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2422916
  • 博文数量: 298
  • 博客积分: 7876
  • 博客等级: 准将
  • 技术积分: 5500
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-23 13:39
文章存档

2013年(2)

2012年(142)

2011年(154)

分类: LINUX

2011-03-24 12:32:12

(1)          初识linux字符设备驱动程序

 

注:所以文章红色字体代表需要特别注意和有问题还未解决的地方,蓝色字体表示需要注意的地方

1.本文所介绍的程序平台

开发板:arm9-mini2440

虚拟机为:Red Hat Enterprise Linux 5

开发板上系统内核版本:linux-2.6.32.2

 

2.程序清单

本次实验程序为国嵌培训代码,本人作了改动和较为详细的注释,如有错误请指出。

memdev.h

 

#ifndef _MEMDEV_H_

#define _MEMDEV_H_

 

#ifndef MEMDEV_MAJOR

#define MEMDEV_MAJOR  260 

//memdev采用静态分配设备号,不要和其它设备重复

#endif

 

#ifndef MEMDEV_NR_DEVS

#define MEMDEV_NR_DEVS  2

#endif

 

#ifndef MEMDEV_SIZE

#define MEMDEV_SIZE  4096

#endif

 

struct mem_dev

{

    char *data;

    unsigned long size;

};

 

#endif

 

memdev.c

 

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

*memdev.c

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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#include "memdev.h"

 

static int mem_major = MEMDEV_MAJOR;

 

module_param(mem_major,int,S_IRUGO);

 

struct mem_dev *mem_devp;/*设备结构体指针*/

 

struct cdev cdev;

 

/*文件打开函数*/

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

{

    struct mem_dev *dev;

    /*获取次设备号*/

    int num = MINOR(inode->i_rdev);

   

    /*大于最大的次设备号就错误了 因为注册的时候要指定次设备的数目*/

    if(num >=MEMDEV_NR_DEVS)

        return -ENODEV;

    dev = &mem_devp[num];

/*将设备描述结构指针赋值给文件私有数据指针*/

    filp->private_data = dev;

 

    return 0;

}

/*文件释放函数*/

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

{

    return 0;

}

/*读函数*/

static ssize_t mem_read(struct file *filp,char __user *buf,size_t size,loff_t *poss)

{

    unsigned long p = *poss;

    unsigned int count = size;

    int ret = 0;

    /*获得设备结构体指针由于read没有struct inode *inode结构 而且函数的

    参数不能改 只能改函数名所以只能在open函数里面设置*/

    struct mem_dev *dev = filp->private_data;

/*判断读位置是否有效*/

    if(p >= MEMDEV_SIZE)

        return 0;

    if(count > MEMDEV_SIZE-p)

        count = MEMDEV_SIZE-p;

/*读数据到用户空间*/

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

    {

        ret = -EFAULT;

    }

    else

    {

        *poss +=count;

        ret = count;

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

    }

 

    return ret;

}

/*写函数*/

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

{

    unsigned long p = *poss;

    unsigned int count = size;

    int ret=0;

    struct mem_dev *dev = filp->private_data;

 

    if(p>=MEMDEV_SIZE)

        return 0;

    if(count>MEMDEV_SIZE-p)

        count = MEMDEV_SIZE-p;

 

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

    {

        ret = -EFAULT;

    }

    else

    {

        *poss += count;

        ret = count;

        printk(KERN_INFO "write %d bytes from %lu\n",count,p);

    }

   

    return ret;

}

 

static loff_t mem_llseek(struct file *filp,loff_t offset,int whence)

{

    loff_t newpos;

   

    switch(whence)

    {

        case 0:

            newpos = offset;

            break;

        case 1:

            newpos = filp->f_pos + offset;

            break;

        case 2:

            newpos = MEMDEV_SIZE - 1 + offset;

            break;

        default:

            return -EINVAL;

    }

    if((newpos<0) || (newpos>MEMDEV_SIZE))

        return -EINVAL;

 

    filp->f_pos = newpos;

    return newpos;

}

 

static const struct file_operations mem_fops =

{

    .owner = THIS_MODULE,

    .llseek = mem_llseek,

    .read = mem_read,

    .write = mem_write,

    .open = mem_open,

    .release = mem_release,

};

 

 

/*设备驱动模块加载函数*/

static int memdev_init(void)

{

    int result;

    int i;

    dev_t devno = MKDEV(mem_major,0);

 

    /*静态申请设备号*/

    if(mem_major)

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

    else/*动态申请设备号*/

    {

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

        mem_major = MAJOR(devno);

    }

 

    if(result < 0)

        return result;

    /*初始化cdev结构*/

    cdev_init(&cdev,&mem_fops);

    cdev.owner = THIS_MODULE;

    cdev.ops = &mem_fops;

/*注册字符设备*/

    cdev_add(&cdev,MKDEV(mem_major,0),MEMDEV_NR_DEVS);

/*为设备描述结构分配内存*/

    mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev),GFP_KERNEL);

    if(!mem_devp)/*申请失败*/

    {

        result = -ENOMEM;

        goto fail_malloc;

    }

   

    memset(mem_devp,0,MEMDEV_NR_DEVS * sizeof(struct mem_dev));

/*为设备分配内存*/

    for(i=0;i

    {

        mem_devp[i].size = MEMDEV_SIZE;

        mem_devp[i].data = kmalloc(MEMDEV_SIZE,GFP_KERNEL);

        memset(mem_devp[i].data,0,MEMDEV_SIZE);

    }

 

    return 0;

 

fail_malloc:

    unregister_chrdev_region(devno,1);

    return result;

}

 

static void memdev_exit(void)

{

    cdev_del(&cdev);

    kfree(mem_devp);

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

}

 

MODULE_AUTHOR("Zechin Liao");

MODULE_LICENSE("GPL");

 

module_init(memdev_init);

module_exit(memdev_exit);

 

Makefile

 

ifneq ($(KERNELRELEASE),) 

obj-m:=memdev.o 

else  

KERNELDIR:=/root/mini2440/linux/linux-2.6.32.2

PWD:=$(shell pwd) 

all: 

         make -C $(KERNELDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux- 

clean: 

         rm -rf *.ko *.o *.mod.c *.mod.o *.symvers 

endif

 

//KERNELDIR:=/root/mini2440/linux/linux-2.6.32.2为自己开发板当前运行的内核编译后的源码树位置

// ARCH=arm CROSS_COMPILE=arm-linux-  指明开发板平台和编译工具

//注意;Makefile的书写格式 该用tab键的时候一定要用, 若是安装驱动的时候显示的是

//[root@FriendlyARM /udisk]# insmod myadd.ko

//insmod: cannot insert 'myadd.ko': invalid module format

//表明linux内核版本不一致或者是平台不一致

 

memdevapp.c

 

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

*memdevapp.c 

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

#include  

#include  

#include  

#include   

 

int main()  

{  

    int fd;  

    char buf[4096];  

    //FILE *fp0 = NULL;

   

  /*初始化buf*/

    strcpy(buf,"This is a example of charactar devices driver");  

    printf("buf:%s\n",buf);  

    /*打开设备文件*/

    fd=open("/dev/memdev0",O_RDWR);  

    if(fd == -1)  

    {  

        printf("open memdev failed!\n");  

        return -1;            

    }  

      

       /*写入设备*/

    write(fd,buf,sizeof(buf));  

/*重定位文件设备(思考没有该指令 会有什么后果??)*/

/*如没有重新定位,读数据时就会从刚刚写入的末尾去读*/

    lseek(fd,0,SEEK_SET);  

    /*清除buf*/

    strcpy(buf,"nothing");  

    /*读出设备*/

    read(fd,buf,sizeof(buf));  

    /*检测结果*/

    printf("buf:%s\n",buf);  

 

    return 0;  

}

//注意;编译程序的工具-arm-linux-gcc 注意安装交叉编译链

//若是用gcc直接编译的 在我的平台上显示的是

//[root@FriendlyARM /udisk]# ./memdevapp1

//./memdevapp1: line 1: syntax error: "(" unexpected

 

Arm平台实验:

[root@FriendlyARM /mini_driver]# ls

memdev.ko  memdevapp  pwm_test   test

[root@FriendlyARM /mini_driver]# insmod memdev.ko

[root@FriendlyARM /mini_driver]# cat /proc/devices | more //查看当前运行的设备

Character devices:

  1 mem

  4 /dev/vc/0

  4 tty

  5 /dev/tty

  5 /dev/console

  5 /dev/ptmx

260 memdev

  7 vcs

 10 misc

 13 input

 14 sound

 21 sg

 29 fb

 81 video4linux

 89 i2c

 90 mtd

116 alsa

128 ptm

136 pts

180 usb

188 ttyUSB

189 usb_device

204 s3c2410_serial

254 rtc

 

Block devices:

259 blkext

  7 loop

  7 loop

 31 mtdblock

 65 sd

 66 sd

 67 sd

 68 sd

 69 sd

 70 sd

 71 sd

128 sd

129 sd

130 sd

131 sd

132 sd

133 sd

134 sd

135 sd

179 mmc

 

//创建设备在/dev下名字为memdev0 ‘c’代表为字符设备 ‘260 0’分别为主次设备号

[root@FriendlyARM /mini_driver]# mknod /dev/memdev0 c 260 0

[root@FriendlyARM /mini_driver]# ./memdevapp

buf:This is a example of charactar devices driver

write 4096 bytes from 0

read 4096 bytes from 0

buf:This is a example of charactar devices driver

[root@FriendlyARM /mini_driver]#

 

以上方法采用的动态编译驱动,也可以静态方式将驱动编译进内核

1.memdev.hmemdev.c两个驱动源文件拷贝至内核linux-2.6.24/drivers/char目录

 

2.修改该目录下Kconfig文件,添加如下内容

config MEMDEV_DRIVER

             tristate "memdev driver"

             depends on MACH_SMDK2440

             default y if MACH_SMDK2440

             help

                 this option enables support for memdev experiment

 

3.修改该目录下Makefile,添加如下内容

obj-$(CONFIG_MEMDEV_DRIVER)      +=memdev.o

 

4.make menuconfig时在字符设备中找到菜单项“memdev drinver”,选择为YM,编译进内核还是模块。

 

 

阅读(953) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~