第一个驱动--内存分配

几天前一直在看Linux驱动开发,看了几天,今天才主动动手开始去抄袭代码.第一眼见这东西,我迷糊迷糊的.摸不着头脑,太可怕了..今天抄袭了一边.把Linux驱动的大概给观摩了一遍,总之也就那样吧...

第一个驱动

首先实现一个简单的字符型驱动,在内存区分配一块可读可写的内存,通过文件读写接口对这块内核中的内存进行区域操作.

模块定义:

struct DEMO_dev { struct cdev cdev; }; //设备结构 struct file_operations DEMO_fops = { .owner = THIS_MODULE, .llseek = DEMO_llseek, .read = DEMO_read, .write = DEMO_write, .ioctl = DEMO_ioctl, .release = DEMO_release, }; //初始化一个系统调用的结构体 struct DEMO_dev *DEMO_devices; static unsigned char demo_inc = 0; static u8 demoBuffer[256]; //分配的内存空间 #define DEMO_MAJOR 224 //主设备号

模块初始化:

int DEMO_init_module(void) { int result; dev_t dev = 0; //设备号 dev = MKDEV(DEMO_MAJOR,0); //转换设备号 result = register_chrdev_region(dev,1,"DEMO"); //按照指定的设备号注册设备 if( result < 0 ) { printk(KERN_WARNING "DEMO:can't get major %d/n",DEMO_MAJOR); //注册失败输出错误信息 return result; } //分配DEMO_dev,该结构是自定义的 DEMO_devices = kmalloc(sizeof(struct DEMO_dev),GFP_KERNEL); //分配设备结构内存 if(!DEMO_devices) { result = -ENOMEM; goto fail; } memset( DEMO_devices,0,sizeof( struct DEMO_dev ) ); //初始化一个字符驱动 cdev_init(&DEMO_devices->cdev,&DEMO_fops); //cdev初始化 DEMO_devices->cdev.owner = THIS_MODULE; //写入模块所属者 DEMO_devices->cdev.ops = &DEMO_fops; //模块操作接口 //向内核添加字符设备 result = cdev_add(&DEMO_devices->cdev,dev,1); if( result ) { printk(KERN_NOTICE "Error %d adding DEMO/n",result); goto fail; } return 0; fail: DEMO_cleanup_module(); //失败清除模块 return result; }

模块卸载:

void DEMO_cleanup_module(void) { dev_t devno = MKDEV( DEMO_MAJOR,0 ); //删除键盘 if( DEMO_devices ) { cdev_del(&DEMO_devices->cdev); kfree(DEMO_devices); } //释放设备号 unregister_chrdev_region(devno,1); }

//模块的打开操作

int DEMO_open(struct inode *inode, struct file *filp) { struct DEMO_dev *dev; //防止多次打开设备 if( demo_inc > 0 )return -ERESTARTSYS; demo_inc++; //获取DEMO_dev结构,并将它赋给filp->private_data,以后可以用filp->private_data访问DEMO_dev结构 dev = container_of(inode->i_cdev,struct DEMO_dev,cdev); //container_of宏 filp->private_data = dev; return 0; }

//模块的释放操作

int DEMO_release(struct inode *inode, struct file *filp) { //引用技术减少 demo_inc--; return 0; }

//模块的读操作

ssize_t DEMO_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { int result; //得到文件的当前地址 loff_t pos = *f_pos; //判断位置合法性 if(pos >= 256) { result = 0; goto out; } if( count > ( 256 - pos ) ) { count = 256 - pos; } pos += count; if( copy_to_user(buf,demoBuffer + *f_pos,count) ) { count = -EFAULT; goto out; } //改变文件的当前位置 *f_pos = pos; out: return count; }

//模块的写操作

ssize_t DEMO_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { ssize_t retval = -ENOMEM; loff_t pos = *f_pos; //判断位置的合法性 if( pos >= 256 ) { goto out; } if( count > ( 256 - pos ) ) { count = 256 - pos; } pos += count; //将数据复制到内核空间 if( copy_from_user(demoBuffer + *f_pos,buf,count) ) { retval = -EFAULT; goto out; } //改变文件的当前位置 *f_pos = pos; return count; out: return retval; }

//模块的调整操作

loff_t DEMO_llseek(struct file *filp, loff_t off, int whence) { loff_t pos; pos = filp->f_pos; switch( whence ) { case 0: pos = off; break; case 1: pos += off; break; case 2: default: return -EINVAL; } //超出范围 if( (pos > 256) || (pos < 0) ) { return -EINVAL; } return filp->f_pos = pos; }

//模块的控制

int DEMO_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { if( cmd == 0 ) { printk("ioctl command1 successfully/n"); return 0; } if( cmd == 1 ) { printk("ioctl command2 successfully/n"); return 0; } printk("ioctl error/n"); return -EFAULT; }

 

抱歉.我还不是很会写Makefile所以.我就用很见的方法来编译的.下面给出我的Makefile

obj-m := Memory.o

 

编译驱动是需要源代码的.我用的是ubLinux.

make -C /forlinx/Linux-2.6.28.6/ M$=(pwd) modules

 

给出测试代码跟驱动代码的完整版:

驱动代码:

 

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/errno.h>

#include <linux/types.h>

#include <linux/fcntl.h>

#include <linux/cdev.h>

#include <linux/version.h>

#include <linux/vmalloc.h>

#include <linux/ctype.h>

#include <linux/pagemap.h>

 

MODULE_AUTHOR("fgj");

MODULE_LICENSE("Dual BSD/GPL");

 

int DEMO_init_module(void);

void DEMO_cleanup_module(void);

int DEMO_release(struct inode *inode, struct file *filp);

int DEMO_open(struct inode *inode, struct file *filp);

ssize_t DEMO_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);

ssize_t DEMO_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);

loff_t DEMO_llseek(struct file *filp, loff_t off, int whence);

int DEMO_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);

 

struct DEMO_dev

{

struct cdev cdev;

};

 

struct file_operations DEMO_fops = {

.owner = THIS_MODULE,

.llseek = DEMO_llseek,

.read = DEMO_read,

.write = DEMO_write,

.ioctl = DEMO_ioctl,

.release = DEMO_release,

};

 

struct  DEMO_dev *DEMO_devices;

static unsigned char demo_inc = 0;

static u8 demoBuffer[256]; //分配的内存空间

#define DEMO_MAJOR 224 //主设备号

 

int DEMO_init_module(void)

{

int result;

dev_t dev = 0;

dev = MKDEV(DEMO_MAJOR,0);

result = register_chrdev_region(dev,1,"DEMO");

if( result < 0 )

{

printk(KERN_WARNING "DEMO:can't get major %d/n",DEMO_MAJOR);

return result;

}

//分配DEMO_dev,该结构是自定义的

DEMO_devices = kmalloc(sizeof(struct DEMO_dev),GFP_KERNEL);

if(!DEMO_devices)

{

result = -ENOMEM;

goto fail;

}

memset( DEMO_devices,0,sizeof( struct DEMO_dev ) );

//初始化一个字符驱动

cdev_init(&DEMO_devices->cdev,&DEMO_fops);

DEMO_devices->cdev.owner = THIS_MODULE;

DEMO_devices->cdev.ops = &DEMO_fops;

//向内核添加字符设备

result = cdev_add(&DEMO_devices->cdev,dev,1);

if( result )

{

printk(KERN_NOTICE "Error %d adding DEMO/n",result);

goto fail;

}

return 0;

fail:

DEMO_cleanup_module();

return result;

}

void DEMO_cleanup_module(void)

{

dev_t devno = MKDEV( DEMO_MAJOR,0 );

//删除键盘

if( DEMO_devices )

{

cdev_del(&DEMO_devices->cdev);

kfree(DEMO_devices);

}

//释放设备号

unregister_chrdev_region(devno,1);

}

module_init(DEMO_init_module);

module_exit(DEMO_cleanup_module);

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

{

struct DEMO_dev *dev;

//防止多次打开设备

if( demo_inc > 0 )return -ERESTARTSYS;

demo_inc++;

//获取DEMO_dev结构,并将它赋给filp->private_data,以后可以用filp->private_data访问DEMO_dev结构

dev = container_of(inode->i_cdev,struct DEMO_dev,cdev); //container_of宏

filp->private_data = dev;

return 0;

}

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

{

//引用技术减少

demo_inc--;

return 0;

}

ssize_t DEMO_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)

{

int result;

//得到文件的当前地址

loff_t pos = *f_pos;

//判断位置合法性

if(pos >= 256)

{

result = 0;

goto out;

}

if( count > ( 256 - pos ) )

{

count = 256 - pos;

}

pos += count;

if( copy_to_user(buf,demoBuffer + *f_pos,count) )

{

count = -EFAULT;

goto out;

}

//改变文件的当前位置

*f_pos = pos;

out:

return count;

}

ssize_t DEMO_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)

{

ssize_t retval = -ENOMEM;

loff_t pos = *f_pos;

//判断位置的合法性

if( pos >= 256 )

{

goto out;

}

if( count > ( 256 - pos ) )

{

count = 256 - pos;

}

pos += count;

//将数据复制到内核空间

if( copy_from_user(demoBuffer + *f_pos,buf,count) )

{

retval = -EFAULT;

goto out;

}

//改变文件的当前位置

*f_pos = pos;

return count;

out:

return retval;

}

loff_t DEMO_llseek(struct file *filp, loff_t off, int whence)

{

loff_t pos;

pos = filp->f_pos;

switch( whence )

{

case 0:

pos = off;

break;

case 1:

pos += off;

break;

case 2:

default:

return -EINVAL;

}

//超出范围

if( (pos > 256) || (pos < 0) )

{

return -EINVAL;

}

return filp->f_pos = pos;

}

int DEMO_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)

{

if( cmd == 0 )

{

printk("ioctl command1 successfully/n");

return 0;

}

if( cmd == 1 )

{

printk("ioctl command2 successfully/n");

return 0;

}

printk("ioctl error/n");

return -EFAULT;

}

 

//测试代码

#include<sys/types.h>

#include<unistd.h>

#include<fcntl.h>

#include<linux/rtc.h>

#include<linux/ioctl.h>

#include<stdio.h>

#include<stdlib.h>

#define COMMAND1 0

#define COMMAND2 1

void main()

{

int fd;

int i;

char data[256];

int retval;

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

if(fd==-1)

{

perror("error open/n");

exit(-1);

}

printf("open /dev/smbus successfully/n");

retval=ioctl(fd,COMMAND1,0);

if(retval==-1)

{

perror("ioctl error/n");

exit(-1);

}

printf("send command1 successfully/n");

retval=write(fd,"LvApp",5);

if(retval==-1)

{

perror("write error/n");

exit(-1);

}

retval=lseek(fd,0,0);

if(retval==-1)

{

perror("lseek error/n");

exit(-1);

}

retval=read(fd,data,5);

if(retval==-1)

{

perror("read error/n");

exit(-1);

}

printf("read successfully:%s/n",data);

close(fd);

}

 


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值