memdev驱动试验 今天开始驱动的学习,根据国嵌驱动开发视频一边学习,一边试验。国嵌视频上首先讲述字符驱动开发过程,memdev就是最好的例子。首先在看懂源码的基础上学习怎么将驱动装载到开发板。下面是memdev源码:
- #ifndef _MEMDEV_H_
- #define _MEMDEV_H_
-
- #ifndef MEMDEV_MAJOR
- #define MEMDEV_MAJOR 260
-
- #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
-
-
-
- #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 "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;
- 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_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<MEMDEV_NR_DEVS;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,2);
- 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);
- ifneq ($(KERNELRELEASE),)
- obj-m:=memdev.o
- else
- KERNELDIR:=/home/liao/image/linux-2.6.24
- 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
执行make就会生成memdev.ko驱动文件,将编译好的驱动memdev.ko拷贝至开发板/lib/modules目录。 注意:驱动程序的编译依赖内核源代码,并且内核源代码(KERNELDIR指明)要与目标板运行的内核一致。 编写应用程序,对驱动程序测试
-
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
-
- int main()
- {
- int fd;
- char buf[4096];
-
- 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);
- strcpy(buf,"nothing");
- read(fd,buf,sizeof(buf));
- printf("buf:%s/n",buf);
-
- return 0;
- }
arm-linux-gcc –o memdevapp memdevapp.c编译应用程序,将其下载至开板 添加模块: # cd /lib/modules # insmod memdev.ko 添加设备节点: # cd /dev # cat /proc/devices 查看设备号 # mknod memdev0 c 260 0 运行应用程序 # ./memdevapp 以上方法采用的动态编译驱动,也可以静态方式将驱动编译进内核 1.将memdev.h和memdev.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”,选择为Y或M,编译进内核还是模块。
|