Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1264472
  • 博文数量: 404
  • 博客积分: 10011
  • 博客等级: 上将
  • 技术积分: 5382
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-03 16:29
文章存档

2010年(40)

2009年(140)

2008年(224)

我的朋友

分类: LINUX

2008-09-26 10:55:36

#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
//#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

MODULE_LICENSE("GPL");
// 常量定义
#define BUFFERLENS 1024*1024;
// 函数申明
ssize_t chuan_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t chuan_write(
struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
int chuan_open(struct inode *inode, struct file *filp);
int chuan_release(struct inode *inode, struct file *filp);

// 初始化字符设备驱动的file_operations结构体
// 
很奇怪的语法……
struct file_operations chuan_fops = {
  .owner =    THIS_MODULE,
  .read =     chuan_read,
  .write =    chuan_write,
  .open =     chuan_open,
  .release =  chuan_release,
};

// 主力结构————表示设备结构
struct chuan_dev {
  
char * rer;
  unsigned 
int buffersize;// 缓冲区大小
  unsigned int len;// 缓冲区已有长度
  unsigned int start;// 起始数据偏移量
  struct semaphore sem;// 信号量,用于互斥访问
  struct cdev cdev;// 字符型设备结构
};


// 全局变量
struct chuan_dev chuan_device;
dev_t dev_no = 0;


// 初始化
int chuan_init(void)

  
int err=0;
  
// 初始化cdev
  cdev_init(&chuan_device.cdev, &chuan_fops);
  chuan_device.cdev.owner = THIS_MODULE;
  chuan_device.cdev.ops = &chuan_fops;
  
// 动态分配一个设备号
  alloc_chrdev_region(&dev_no, 0, 1, "Rer'sPersonalDevices v1.11");
  
// 字符设备注册
  err = cdev_add(&chuan_device.cdev, dev_no, 1);
  
if (err){
    printk(KERN_NOTICE "Error %d adding device\n", err);
    
return -1;
  }
  
else{
    
// 初始化互斥信号量
    init_MUTEX(&chuan_device.sem);
    

//printk("互斥信号量初始化成功\n");
    printk(KERN_NOTICE "Device Initilize success.\n");
    
return 0; /* succeed */
  }
}

// 注销
void chuan_exit(void)
{
  unregister_chrdev_region(dev_no, 1);
  cdev_del(&chuan_device.cdev);
}

// 打开
int chuan_open(struct inode *inode, struct file *filp)
{
  
struct chuan_dev *mydev;
  
// 高级技巧,,我不是很明白
  mydev = container_of(inode->i_cdev,struct chuan_dev,cdev);
  
// private_data保存chuan_dev指针
  filp->private_data = mydev;

  
// 信号量,如果已经无资源了,就不打开
  if (down_interruptible(&mydev->sem))
    
return -ERESTARTSYS;
  up(&mydev->sem);

  
if(!mydev->rer){
    
// 如果缓冲区是空的,那么分配1k的内容给它
    //printk("
缓冲区还是空的.\n");
    mydev->rer = (char *)kmalloc(1024, GFP_KERNEL);
    memset(mydev->rer, 0, 1024);
    
// 初始化参数
    mydev->buffersize = 1024;
    mydev->len = mydev->start = 0;
  }
  
else{
    
//printk("缓冲区已经有东西了.现将其初始化\n");
  }
  
return 0;
}
// 关闭
int chuan_release(struct inode *inode, struct file *filp)
{
  
return 0;
}

// 读取
ssize_t chuan_read(struct file *filp, char __user *buf, size_t countloff_t *f_pos)
{  
  
//  int i;
  struct chuan_dev *mydev; 
  
//printk("读取\n");
  // 
读取数据  
  mydev = filp->private_data;

  
// 信号量,如果已经无资源了,就不打开
  if (down_interruptible(&mydev->sem))
    
return -ERESTARTSYS;
  
/*  printk("缓冲区数据量长度: %d\n",mydev->len);
      printk("
缓冲区起始位置: %d\n",mydev->start);  
      for(i=0;ilen+mydev->start;++i)
      printk("
缓冲区: %d values %c\n",i,*(mydev->rer+i));
  */

  
if(mydev->len>0){
    
if(count > mydev->len-mydev->start)  //如果要拷贝的字节数比实际空间大,则以空间拷满为准。
      count = mydev->len-mydev->start;
    
if(copy_to_user(buf,mydev->rer+mydev->start,count)){ 

//返回0表示成功,正数表示未拷贝成功的字节数
      printk("
拷贝失败.\n");
    }
    
else{
      mydev->start += count;
      
if(mydev->start>=mydev->buffersize){
    mydev->start = 0;
    mydev->len = 0;
      }
      printk("
拷贝成功.\n");
      printk("start =  %d\n",mydev->start);
      printk("len =  %d\n",mydev->len);
    }
  }
  
else{
    printk("
缓冲区还没有东西,,无法进行读取.\n");
    
goto end;
  }
 end:
  
// 将访问信号释放
  up(&mydev->sem);
  
return 0;
}

// 写入
ssize_t chuan_write(struct file *filp, const char __user *buf, size_t countloff_t *f_pos)
{  
  
struct chuan_dev *mydev; 
  
// 写入数据  
  mydev = filp->private_data;

  
// 信号量,如果已经无资源了,就不打开
  if (down_interruptible(&mydev->sem))
    
return -ERESTARTSYS;

  
if(!mydev->rer){
    
//printk(KERN_NOTICE "写入过程,《, 空的。.\n");
  }
  
else{
    
//printk(KERN_NOTICE "写入过程, 已经有东西了。.\n");
    // 
向缓冲区中写数据
    if(mydev->start+mydev->len+count > mydev->buffersize){
      
// 如果预感到要溢出,那么就从头写 并且舍弃已有数据(这样很不好)
      memset(mydev->rer, 0, mydev->buffersize);
      
if(count > mydev->buffersize)
    count = mydev->buffersize;
      mydev->start = mydev->len = 0;
    }
    
if(copy_from_user(mydev->rer+mydev->len,buf,count)){
      printk(KERN_NOTICE "
写入失败.\n");
    }
    
else{
      mydev->len += count;
      printk(KERN_NOTICE "
写入成功,当前缓冲区的大小为: %d.\n",mydev->len);
    }
  }

  up(&mydev->sem);
  
return 0;
}

module_init(chuan_init);
module_exit(chuan_exit);

 

use.c 测试驱动代码

#include 
#include 
#include 
#include 
#include <
string.h>
main()
{
  
int testdev;
  
int i;
  
char buf[10];
  
char redbuf[10];
  
// 先打开/dev/lala(从设备号为0),进行写入操作
  testdev = open("/dev/lala",O_RDWR);
  
if ( testdev == -1 ){
    printf("Cann't open file \n");
  }
else{
    printf("Open file Success.\n");
    
for(i=0;i<10;++i)
      buf[i] = i+'a';
    write(testdev,buf,10);
    write(testdev,buf,10);
    printf("
写入设备成功/dev/lala\n");

    memset(buf,0,10);
    read(testdev,redbuf,5);
    printf("
读取设备成功/dev/lala\n");
    
for (i = 0; i < 5;i++)
      printf("
收到数据: %c\n",redbuf[i]);
    printf("\n");
    memset(buf,0,10);
    read(testdev,redbuf,5);
    printf("
读取设备成功/dev/lala\n");
    
for (i = 0; i < 5;i++)
      printf("
收到数据: %c\n",redbuf[i]);
    printf("\n");
    close(testdev); 
  }
}


ac.sh
wa.sh,挂载和卸载驱动的shell

#!/bin/bash
insmod dev.ko
mknod /dev/lala c 253 0
chmod 777 /dev/lala
mknod /dev/lala2 c 253 1
chmod 777 /dev/lala2

 

#!/bin/bash
rm /dev/lala
rm /dev/lala2
rmmod dev

 

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