(7)x210:2.4之前的驅動--memdev模擬驅動-涉及阻塞

1 memdev.h

#ifndef _MEMDEV_H_
#define _MEMDEV_H_

#include <linux/ioctl.h>

#ifndef MEMDEV_MAJOR
#define MEMDEV_MAJOR 0    //默認爲0,由系統分配主設備號
#endif

#ifndef MEMDEV_NR_DEVS
#define MEMDEV_NR_DEVS 3    
#endif

#ifndef MEMDEV_SIZE
#define MEMDEV_SIZE 4096
#endif


typedef struct Mem_Dev {

wait_queue_head_t inq, outq;           //阻塞隊列,入對,出對
   int rp;                                                      //讀的到的位子
  int wp;                                                     //寫到的位子
   char *data;
   struct Mem_Dev *next;   /* next listitem */
   unsigned long size;
   unsigned long remain_size;
} Mem_Dev;


2.memdev.c

#ifndef __KERNEL__

#define __KERNEL__
#endif

#ifndef MODULE
#define MODULE
#endif

//#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>

#include <linux/kernel.h>   
#include <linux/init.h>     
#include <linux/slab.h>   
#include <linux/fs.h>       
#include <linux/errno.h>    
#include <linux/types.h>    
#include <linux/proc_fs.h>

//#include <asm/system.h>  
#include <asm/uaccess.h>

#include "memdev.h"

MODULE_LICENSE("GPL");

Mem_Dev *mem_devices;
int memdev_major = MEMDEV_MAJOR;

int memdev_open(struct inode *inode, struct file *filp)
{
    Mem_Dev *dev;
    
   
    int num = MINOR(inode->i_rdev);

    dev = (Mem_Dev *)filp->private_data;
    if (!dev)
    {
        if (num >= MEMDEV_NR_DEVS)
            return -ENODEV;
        dev = &mem_devices[num];
        filp->private_data = dev;
    }


    
    return 0;          
}


int memdev_release(struct inode *inode, struct file *filp)
{

printk(KERN_INFO "close module");
    return 0;
}


ssize_t memdev_read(struct file *filp, char *buf, size_t count,
                loff_t *f_pos)
{
    Mem_Dev *dev = filp->private_data;
    int pos = *f_pos;
    ssize_t ret = 0;
            
    while (dev->rp == dev->wp) //如果讀與寫頭相遇,表示讀完了
    {
        if (filp->f_flags & O_NONBLOCK) //如果是非阻塞,立即返回
            return -EAGAIN;
    
    interruptible_sleep_on(&(dev->inq));  //驅動進入睡眠,進程也即睡眠,進入阻塞隊列等待
    }
    
    count = min(count, (ssize_t)(dev->wp - dev->rp));
    
   
    if (copy_to_user(buf, &(dev->data[pos]), count))
    {
        ret = -EFAULT;
    goto out;
    }
    *f_pos += count; //當前打開的文件指針位置加 count
    dev->rp += count;  //驅動的讀頭也加

    ret = count;
printk(KERN_INFO "read =%s,count =%d\n",buf,count);
    
 out:
    return ret;
}

/*ÎÄŒþÐŽ²Ù×÷*/
ssize_t memdev_write(struct file *filp, const char *buf, size_t count,
                loff_t *f_pos)
{
    Mem_Dev *dev = filp->private_data;
    int pos = *f_pos;
    ssize_t ret = -ENOMEM;

    /*ÅжÏЎλÖÃÊÇ·ñÓÐЧ*/
    if (dev->wp + count > dev->size)
        count = (dev->size) - (dev->wp);
    
    /*ŽÓÓû§¿ÕŒäÐŽÈëÊýŸÝ*/
    if (copy_from_user(&(dev->data[pos]), buf, count))
    {
        ret = -EFAULT;
    goto out;
    }

printk(KERN_INFO "write =%s,count =%d\n",buf,count);
    /* »œÐѶÁœø³Ì */
    wake_up(&dev->inq);
    
    *f_pos += count;
    dev->wp += count;
    ret = count;

  out:
    return ret;
}


/*ÎÄŒþ¶šÎ»*/
loff_t memdev_llseek(struct file *filp, loff_t off, int whence)
{
    Mem_Dev *dev = filp->private_data;
    loff_t newpos;

    switch(whence) {
      case 0: /* SEEK_SET */
        newpos = off;
        break;

      case 1: /* SEEK_CUR */
        newpos = filp->f_pos + off;
        break;

      case 2: /* SEEK_END */
        newpos = dev->size -1 + off;
        break;

      default: /* can't happen */
        return -EINVAL;
    }
    if (newpos<0)
        return -EINVAL;
        
    filp->f_pos = newpos;
    return newpos;
}


/*
 * The following wrappers are meant to make things work with 2.0 kernels
 */

struct file_operations memdev_fops = {
    llseek:     memdev_llseek,
    read:       memdev_read,
    write:      memdev_write,
    open:       memdev_open,
    release:    memdev_release,
};


/*жÔغ¯Êý*/
void memdev_cleanup_module(void)
{
    int i;
    
   
    unregister_chrdev(memdev_major, "memdev");

    /*ÊÍ·ÅÄÚŽæ*/
    if (mem_devices)
    {
        for (i=0; i<MEMDEV_NR_DEVS; i++)
        kfree(mem_devices[i].data);
        kfree(mem_devices);
    }

}

/*ŒÓÔغ¯Êý*/
int memdev_init_module(void)
{
    int result, i;
    
    
    /*×¢²á×Ö·ûÉ豞*/
    result = register_chrdev(memdev_major, "memdev", &memdev_fops);
    if (result < 0)
    {
        printk(KERN_WARNING "mem: can't get major %d\n",memdev_major);
        return result;
    }
    if (memdev_major == 0)
        memdev_major = result;

    mem_devices = kmalloc(MEMDEV_NR_DEVS * sizeof(Mem_Dev), GFP_KERNEL);
    if (!mem_devices)
    {
        result = -ENOMEM;
        goto fail;
    }
    memset(mem_devices, 0, MEMDEV_NR_DEVS * sizeof(Mem_Dev));
 
    for (i=0; i < MEMDEV_NR_DEVS; i++)
    {
        mem_devices[i].size = MEMDEV_SIZE;
        mem_devices[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
        memset(mem_devices[i].data, 0, MEMDEV_SIZE);
        
        init_waitqueue_head(&(mem_devices[i].inq));
    }
    
    return 0;

  fail:
    memdev_cleanup_module();
    return result;
}


module_init(memdev_init_module);

module_exit(memdev_cleanup_module);


3. fork.c

   #include <unistd.h>  
    #include <stdio.h>   
    #include <stdlib.h>   
    int main ()   
    {   
        pid_t fpid; //fpid表示fork函數返回的值  
        int count=0;  
        fpid=fork();   
        if (fpid < 0)   
            printf("error in fork!");   
        else if (fpid == 0) {  
            printf("i am the child process, my process id is %d\n",getpid());   
            count++;  

      FILE *fp = NULL;
        FILE *fp2 = NULL;
        char Buf[128];
        int i=0;    
        
        fp = fopen("/dev/memdev","r+");
        if (fp == NULL)
        {
        printf("Open Dev memdev0 Error!\n");
        return -1;
        }
      
 
       while(i<5)
       {
            i++;
             memset(Buf,128,0);
            fflush(stdin);
            fflush(stdout);
            gets(Buf);
         
                fwrite(Buf, sizeof(Buf), 1, fp);
            
            fflush(fp);
        }   
       sleep(5);
       fclose(fp);
           fclose(fp2);


        }  
        else {  
        printf("i am the parent process, my process id is %d\n",getpid());   
        count++;  

        FILE *fp = NULL;
            char Buf[128];
        int i=0;    
    
            fp = fopen("/dev/memdev","r+");
            if (fp == NULL)
            {
            printf("Open memdev0 Error!\n");
            return -1;
            }
    
    
        while(i<5)
        {        i++;
            memset(Buf,128,0);
            fread(Buf, sizeof(Buf), 1, fp);
            
            printf("Read BUF: %s\n",Buf);
         }   
            fclose(fp);

    }  
        printf("count=: %d/n",count);  
        return 0;  
    }  


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章