实现系统的read,write,思考实现的fangf

参考:宋宝华,设备驱动开发详解 。ldd3

作者:me

内核2.6.35.22

gcc 4.4.5

编译模块和test程序,

insmod 模块  //lsmod    //cat /dev/devices  验证加载的效果

mknod /dev/my_char c 258 0//创建设被节点

运行$echo dddff > /dev/my_char//每部运行使用dmesg看消息

运行$cat  /dev/my_char 看效果

运行test程序

root@andy-virtual-machine:/home/xiao/four/new_char/R_W_L# cat test.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>


int main (void)
{
    int fd;
    int ret;
    char buf[] = "hello/n";
    fd = open ("/dev/my_char", O_WRONLY|O_APPEND, 0777);
    if (-1 == fd) {
        perror ("open err:");
    }
    while (1)
    {
        static int count;
    ret = write (fd, buf, sizeof(buf));
    printf ("ok count %d/n",++count);
    }
    if (-1 == fd) {
        perror ("write err:");
    }
    close (fd);
}

 

 

root@andy-virtual-machine:/home/xiao/four/new_char/R_W_L# vi test.c
root@andy-virtual-machine:/home/xiao/four/new_char/R_W_L# cat char.c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/mm.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/slab.h>

#define  MAJOR_CHAR 258
#define  SIZE_CHAR  1024
#define  DBUG_ME 1

struct char_dev {
    struct cdev cdev;
    char mem[SIZE_CHAR];
};
struct char_dev *char_devp;
int char_major = MAJOR_CHAR;

MODULE_LICENSE ("GPL");
/*    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);*/
static ssize_t char_read (struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
    int ret = 0;
    loff_t p = filp->f_pos;
    struct char_dev *dev = filp->private_data;
#if DBUG_ME
    printk (KERN_INFO "in char_read,befor read ,and filp->f_pos = %llu,and ppos = %llu/n", filp->f_pos,*ppos);
#endif
    if (count > SIZE_CHAR - p)
        count = SIZE_CHAR - p;
    if (copy_to_user (buf, (void *)(dev->mem + p), count))
        ret = -EFAULT;
    else {
        ret = count ;
        filp->f_pos += count;
        *ppos += count;//read end of //if not have this read will all go on , never stop; 如果不加这句话,cat时后就一直读,用test程序里写的read也是一直读
#if DBUG_ME
    printk (KERN_INFO "in char_read,after read ,and filp->f_pos = %llu , count = %d,and ppos = %llu/n", filp->f_pos, count,*ppos);
#endif
    }
    return ret;//没有实现,读走的功能,光是只读功能
}
static ssize_t char_write (struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
    int ret = 0;
    loff_t p = filp->f_pos;
    struct char_dev *dev = filp->private_data;
#if DBUG_ME
    printk (KERN_INFO "in char_write,befor write ,and filp->f_pos = %llu,and ppos = %llu/n", filp->f_pos, *ppos);
#endif
    if (count > SIZE_CHAR - p)
        count = SIZE_CHAR - p;
    if (copy_from_user ((void *)(dev->mem + p), buf, count))   //extern inline long copy_from_user(void *to, const void __user *from, long n)
        ret = -EFAULT;
    else {
        ret = count ;
        filp->f_pos += count;
        *ppos += count;//add for 如果没有这话,用test程序里的write循环写,一直覆盖以前的东西,有了后就是一次打开中不断的追加
#if DBUG_ME
    printk (KERN_INFO "in char_write,after write ,and filp->f_pos = %llu , count = %d,and ppos = %llu/n", filp->f_pos, count, *ppos);
#endif
    }
    return ret;

//程序没有实现,关闭文件后再次打开时写也追加在文件后,看宋老师的程序,最后在struct char_dev里放了个unsigned long 的变量,用来记录现在文件的结尾标志,这个方法可以解决问题,但是不好,思考内核是如何实现的

}
static int char_open (struct inode *inode, struct file *filp)
{
    struct char_dev *char_me_devp;
    char_me_devp = container_of (inode->i_cdev, struct char_dev, cdev);
    filp->private_data = char_me_devp;
#if DBUG_ME
    printk (KERN_INFO "in char_open,and filp->f_pos = %llu/n", filp->f_pos);
#endif
    return 0;
}
static int   char_release (struct inode *inode, struct file *filp)
{
#if DBUG_ME
    printk (KERN_INFO "in char_release/n");
#endif
    return 0;
}
struct file_operations char_fops = {
    .owner   = THIS_MODULE,
    .open    = char_open,
    .release = char_release,
    .read    = char_read,
    .write   = char_write,
};
static void char_setup_cdev (struct char_dev *dev, int index)
{
    int ret;
    dev_t devno = MKDEV (char_major, index);
    cdev_init (&dev->cdev, &char_fops);
    dev->cdev.owner = THIS_MODULE;
    ret = cdev_add (&dev->cdev, devno, 1);
    if (ret)
        printk (KERN_NOTICE "error %d/n adding char_dev %d/n", ret, index);
}
static int char_me_init (void)
{
    int ret;
    dev_t devno = MKDEV (char_major, 0);
    if (char_major)
        ret = register_chrdev_region (devno, 1, "my_char");
    else {
        ret = alloc_chrdev_region (&devno, 0, 1, "my_char");
        char_major = MAJOR (devno);
    }
    if (ret < 0)
        return ret;
    char_devp = (struct char_dev*)kmalloc (sizeof(struct char_dev), GFP_KERNEL);
    if (NULL == char_devp) {
        ret = -ENOMEM;
        goto fail_kmalloc;
    }
    memset (char_devp, 0, sizeof(struct char_dev));
    char_setup_cdev (char_devp, 0);
#if DBUG_ME
    printk (KERN_INFO "in char_me_init/n");
#endif
    return 0;
fail_kmalloc:
    unregister_chrdev_region (devno, 1);
    return ret;
}
static void char_me_exit (void)
{
    dev_t devno = MKDEV (char_major, 0);
    cdev_del (&char_devp->cdev);
    kfree (char_devp);  
    unregister_chrdev_region (devno, 1);
#if DBUG_ME
    printk (KERN_INFO "in char_me_exit/n");
#endif
}
module_init (char_me_init);
module_exit (char_me_exit);

 

加入lseek后的代码,依据实现的代码可以看出,filp->f_pos,是定位当前读写文件指针的

test代码ruxia

root@andy-virtual-machine:/home/xiao/four/new_char/race# cat test.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>


int main (void)
{
    int fd;
    int ret;
    char buf[] = "0";
    fd = open ("/dev/my_char", O_RDWR|O_APPEND, 0777);
    if (-1 == fd) {
        perror ("open err:");
    }
        ret = read (fd, buf, 1);
        printf ("ok count %s/n",buf);
        sleep(1);
        lseek (fd,1,SEEK_CUR);
        ret = read (fd, buf, 1);
        printf ("ok count %s/n",buf);
        sleep(1);

/*    while (1)
    {
        sleep (1);
        static int count;
    ret = write (fd, buf, sizeof(buf));
    printf ("ok count %d/n",++count);
    }*/
    if (-1 == fd) {
        perror ("write err:");
    }
    close (fd);
}

root@andy-virtual-machine:/home/xiao/four/new_char/race# cat char.c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/mm.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/slab.h>

#define  MAJOR_CHAR 258
#define  SIZE_CHAR  1024
#define  DBUG_ME 1

struct char_dev {
    struct cdev cdev;
    char mem[SIZE_CHAR];
};
struct char_dev *char_devp;
int char_major = MAJOR_CHAR;

MODULE_LICENSE ("GPL");
/*    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
 loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);*/
static loff_t char_lseek (struct file *filp, loff_t offset, int orig)
{
    struct char_dev *dev = filp->private_data;
    int ret;
    switch (orig) {
    case SEEK_SET:
        if ((offset < 0) || (((unsigned int) offset) > SIZE_CHAR)) {
            ret = -EINVAL;
            break;
        }
        filp->f_pos  = (unsigned long)offset;
        ret = filp->f_pos;
        break;
    case SEEK_CUR:
        if (((filp->f_pos + offset) > SIZE_CHAR) || ((filp->f_pos + offset) < 0)) {
            ret = -EINVAL;
            break;
        }
        filp->f_pos += offset;
        ret = filp->f_pos;
        break;
    }
    return ret;
   
}

static ssize_t char_read (struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
    int ret = 0;
    loff_t p = *ppos;
    struct char_dev *dev = filp->private_data;
    if (p >= SIZE_CHAR) {
        return 0;
    }

#if DBUG_ME
    printk (KERN_INFO "in char_read,befor read ,and filp->f_pos = %llu,and ppos = %llu/n", filp->f_pos,*ppos);
#endif
    if (count > SIZE_CHAR - p)
        count = SIZE_CHAR - p;
    if (copy_to_user (buf, (void *)(dev->mem + p), count))
        ret = -EFAULT;
    else {
        ret = count ;
        filp->f_pos += count;
        *ppos += count;//read end of //if not have this read will all go on , never stop;
#if DBUG_ME
    printk (KERN_INFO "in char_read,after read ,and filp->f_pos = %llu , count = %d,and ppos = %llu/n", filp->f_pos, count,*ppos);
#endif
    }
    return ret;
}
static ssize_t char_write (struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
    int ret = 0;
    loff_t p = *ppos;
    struct char_dev *dev = filp->private_data;
#if DBUG_ME
    printk (KERN_INFO "in char_write,befor write ,and filp->f_pos = %llu,and ppos = %llu/n", filp->f_pos, *ppos);
#endif
    if (count > SIZE_CHAR - p)
        count = SIZE_CHAR - p;
    if (copy_from_user ((void *)(dev->mem + p), buf, count))   //extern inline long copy_from_user(void *to, const void __user *from, long n)
        ret = -EFAULT;
    else {
        ret = count ;
        filp->f_pos += count;
        *ppos += count;//add for
#if DBUG_ME
    printk (KERN_INFO "in char_write,after write ,and filp->f_pos = %llu , count = %d,and ppos = %llu/n", filp->f_pos, count, *ppos);
#endif
    }
    return ret;


}
static int char_open (struct inode *inode, struct file *filp)
{
    struct char_dev *char_me_devp;
    char_me_devp = container_of (inode->i_cdev, struct char_dev, cdev);
    filp->private_data = char_me_devp;
#if DBUG_ME
    printk (KERN_INFO "in char_open,and filp->f_pos = %llu/n", filp->f_pos);
#endif
    return 0;
}
static int   char_release (struct inode *inode, struct file *filp)
{
#if DBUG_ME
    printk (KERN_INFO "in char_release/n");
#endif
    return 0;
}
struct file_operations char_fops = {
    .owner   = THIS_MODULE,
    .open    = char_open,
    .release = char_release,
    .read    = char_read,
    .write   = char_write,
    .llseek   = char_lseek
};
static void char_setup_cdev (struct char_dev *dev, int index)
{
    int ret;
    dev_t devno = MKDEV (char_major, index);
    cdev_init (&dev->cdev, &char_fops);
    dev->cdev.owner = THIS_MODULE;
    ret = cdev_add (&dev->cdev, devno, 1);
    if (ret)
        printk (KERN_NOTICE "error %d/n adding char_dev %d/n", ret, index);
}
static int char_me_init (void)
{
    int ret;
    dev_t devno = MKDEV (char_major, 0);
    if (char_major)
        ret = register_chrdev_region (devno, 1, "my_char");
    else {
        ret = alloc_chrdev_region (&devno, 0, 1, "my_char");
        char_major = MAJOR (devno);
    }
    if (ret < 0)
        return ret;
    char_devp = (struct char_dev*)kmalloc (sizeof(struct char_dev), GFP_KERNEL);
    if (NULL == char_devp) {
        ret = -ENOMEM;
        goto fail_kmalloc;
    }
    memset (char_devp, 0, sizeof(struct char_dev));
    char_setup_cdev (char_devp, 0);
#if DBUG_ME
    printk (KERN_INFO "in char_me_init/n");
#endif
    return 0;
fail_kmalloc:
    unregister_chrdev_region (devno, 1);
    return ret;
}
static void char_me_exit (void)
{
    dev_t devno = MKDEV (char_major, 0);
    cdev_del (&char_devp->cdev);
    kfree (char_devp);
    unregister_chrdev_region (devno, 1);
#if DBUG_ME
    printk (KERN_INFO "in char_me_exit/n");
#endif
}
module_init (char_me_init);
module_exit (char_me_exit);

 


宋老师代码/ *======================================================================
    A globalfifo driver as an example of char device drivers 
    This example is to introduce asynchronous notifier
     
    The initial developer of the original code is Baohua Song
    <author@linuxdriver.cn>. All Rights Reserved.
======================================================================*/
#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/slab.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/poll.h>

#define GLOBALFIFO_SIZE    0x1000    /*È«ŸÖfifo×îŽó4K×ÖœÚ*/
#define FIFO_CLEAR 0x1  /*Çå0È«ŸÖÄÚŽæµÄ³€¶È*/
#define GLOBALFIFO_MAJOR 250    /*Ô€ÉèµÄglobalfifoµÄÖ÷É豞ºÅ*/
static int globalfifo_fasync(int fd, struct file *filp, int mode); //add by lht
static int globalfifo_major = GLOBALFIFO_MAJOR;
/*globalfifoÉ豞œá¹¹Ìå*/
struct globalfifo_dev                                    
{                                                       
  struct cdev cdev; /*cdevœá¹¹Ìå*/                      
  unsigned int current_len;    /*fifoÓÐЧÊýŸÝ³€¶È*/
  unsigned char mem[GLOBALFIFO_SIZE]; /*È«ŸÖÄÚŽæ*/       
  struct semaphore sem; /*²¢·¢¿ØÖÆÓõÄÐźÅÁ¿*/          
  wait_queue_head_t r_wait; /*×èÈû¶ÁÓõĵȎý¶ÓÁÐÍ·*/    
  wait_queue_head_t w_wait; /*×èÈûÐŽÓõĵȎý¶ÓÁÐÍ·*/   
  struct fasync_struct *async_queue; /* Ò천œá¹¹ÌåÖžÕ룬ÓÃÓÚ¶Á */
};

struct globalfifo_dev *globalfifo_devp; /*É豞œá¹¹ÌåÖžÕë*/
/*ÎÄŒþŽò¿ªº¯Êý*/
int globalfifo_open(struct inode *inode, struct file *filp)
{
  /*œ«É豞œá¹¹ÌåÖžÕëž³ÖµžøÎÄŒþËœÓÐÊýŸÝÖžÕë*/
  filp->private_data = globalfifo_devp;
  return 0;
}
/*ÎÄŒþÊͷź¯Êý*/
int globalfifo_release(struct inode *inode, struct file *filp)
{
    /* œ«ÎÄŒþŽÓÒ천͚֪ÁбíÖÐÉŸ³ý */
  //globalmem_fasync( - 1, filp, 0);//modified by lht
   globalfifo_fasync( - 1, filp, 0);
 
  return 0;
}

/* ioctlÉ豞¿ØÖƺ¯Êý */
static int globalfifo_ioctl(struct inode *inodep, struct file *filp, unsigned
  int cmd, unsigned long arg)
{
  struct globalfifo_dev *dev = filp->private_data;/*»ñµÃÉ豞œá¹¹ÌåÖžÕë*/

  switch (cmd)
  {
    case FIFO_CLEAR:
        down(&dev->sem); //»ñµÃÐźÅÁ¿       
      dev->current_len = 0;
      memset(dev->mem,0,GLOBALFIFO_SIZE);
      up(&dev->sem); //ÊÍ·ÅÐźÅÁ¿
        
      printk(KERN_INFO "globalfifo is set to zero/n");     
      break;

    default:
      return  - EINVAL;
  }
  return 0;
}

static unsigned int globalfifo_poll(struct file *filp, poll_table *wait)
{
  unsigned int mask = 0;
  struct globalfifo_dev *dev = filp->private_data; /*»ñµÃÉ豞œá¹¹ÌåÖžÕë*/
 
  down(&dev->sem);
 
  poll_wait(filp, &dev->r_wait, wait);
  poll_wait(filp, &dev->w_wait, wait); 
  /*fifo·Ç¿Õ*/
  if (dev->current_len != 0)
  {
    mask |= POLLIN | POLLRDNORM; /*±êÊŸÊýŸÝ¿É»ñµÃ*/
  }
  /*fifo·ÇÂú*/
  if (dev->current_len != GLOBALFIFO_SIZE)
  {
    mask |= POLLOUT | POLLWRNORM; /*±êÊŸÊýŸÝ¿ÉÐŽÈë*/
  }
    
  up(&dev->sem);
  return mask;
}

/* globalfifo fasyncº¯Êý*/
static int globalfifo_fasync(int fd, struct file *filp, int mode)
{
    struct globalfifo_dev *dev = filp->private_data;
    return fasync_helper(fd, filp, mode, &dev->async_queue);
}


/*globalfifo¶Áº¯Êý*/
static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t count,
  loff_t *ppos)
{
  int ret;
  struct globalfifo_dev *dev = filp->private_data; //»ñµÃÉ豞œá¹¹ÌåÖžÕë
  DECLARE_WAITQUEUE(wait, current); //¶šÒåµÈŽý¶ÓÁÐ

  down(&dev->sem); //»ñµÃÐźÅÁ¿
  add_wait_queue(&dev->r_wait, &wait); //œøÈë¶ÁµÈŽý¶ÓÁÐÍ·

  /* µÈŽýFIFO·Ç¿Õ */
  if (dev->current_len == 0)
  {
    if (filp->f_flags &O_NONBLOCK)
    {
      ret =  - EAGAIN;
      goto out;
    }
    __set_current_state(TASK_INTERRUPTIBLE); //žÄ±äœø³Ì׎̬Ϊ˯Ãß
    up(&dev->sem);

    schedule(); //µ÷¶ÈÆäËûœø³ÌÖŽÐÐ
    if (signal_pending(current))
    //Èç¹ûÊÇÒòΪÐźŻœÐÑ
    {
      ret =  - ERESTARTSYS;
      goto out2;
    }

    down(&dev->sem);
  }

  /* ¿œ±ŽµœÓû§¿ÕŒä */
  if (count > dev->current_len)
    count = dev->current_len;

  if (copy_to_user(buf, dev->mem, count))
  {
    ret =  - EFAULT;
    goto out;
  }
  else
  {
    memcpy(dev->mem, dev->mem + count, dev->current_len - count); //fifoÊýŸÝÇ°ÒÆ
    dev->current_len -= count; //ÓÐЧÊýŸÝ³€¶ÈŒõÉÙ
    printk(KERN_INFO "read %d bytes(s),current_len:%d/n", count, dev->current_len);
    
    wake_up_interruptible(&dev->w_wait); //»œÐÑÐŽµÈŽý¶ÓÁÐ
   
    ret = count;
  }
  out: up(&dev->sem); //ÊÍ·ÅÐźÅÁ¿
  out2:remove_wait_queue(&dev->w_wait, &wait); //ŽÓžœÊôµÄµÈŽý¶ÓÁÐÍ·ÒƳý
  set_current_state(TASK_RUNNING);
  return ret;
}


/*globalfifoÐŽ²Ù×÷*/
static ssize_t globalfifo_write(struct file *filp, const char __user *buf,
  size_t count, loff_t *ppos)
{
  struct globalfifo_dev *dev = filp->private_data; //»ñµÃÉ豞œá¹¹ÌåÖžÕë
  int ret;
  DECLARE_WAITQUEUE(wait, current); //¶šÒåµÈŽý¶ÓÁÐ

  down(&dev->sem); //»ñÈ¡ÐźÅÁ¿
  add_wait_queue(&dev->w_wait, &wait); //œøÈëÐŽµÈŽý¶ÓÁÐÍ·

  /* µÈŽýFIFO·ÇÂú */
  if (dev->current_len == GLOBALFIFO_SIZE)
  {
    if (filp->f_flags &O_NONBLOCK)
    //Èç¹ûÊÇ·Ç×èÈû·ÃÎÊ
    {
      ret =  - EAGAIN;
      goto out;
    }
    __set_current_state(TASK_INTERRUPTIBLE); //žÄ±äœø³Ì׎̬Ϊ˯Ãß
    up(&dev->sem);

    schedule(); //µ÷¶ÈÆäËûœø³ÌÖŽÐÐ
    if (signal_pending(current))
    //Èç¹ûÊÇÒòΪÐźŻœÐÑ
    {
      ret =  - ERESTARTSYS;
      goto out2;
    }

    down(&dev->sem); //»ñµÃÐźÅÁ¿
  }

  /*ŽÓÓû§¿ÕŒä¿œ±ŽµœÄں˿Ռä*/
  if (count > GLOBALFIFO_SIZE - dev->current_len)
    count = GLOBALFIFO_SIZE - dev->current_len;

  if (copy_from_user(dev->mem + dev->current_len, buf, count))
  {
    ret =  - EFAULT;
    goto out;
  }
  else
  {
    dev->current_len += count;
    printk(KERN_INFO "written %d bytes(s),current_len:%d/n", count, dev
      ->current_len);

    wake_up_interruptible(&dev->r_wait); //»œÐѶÁµÈŽý¶ÓÁÐ
    /* ²úÉúÒ천¶ÁÐźŠ*/
    if (dev->async_queue)
       kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
   
    ret = count;
  }

  out: up(&dev->sem); //ÊÍ·ÅÐźÅÁ¿
  out2:remove_wait_queue(&dev->w_wait, &wait); //ŽÓžœÊôµÄµÈŽý¶ÓÁÐÍ·ÒƳý
  set_current_state(TASK_RUNNING);
  return ret;
}


/*ÎÄŒþ²Ù×÷œá¹¹Ìå*/
static const struct file_operations globalfifo_fops =
{
  .owner = THIS_MODULE,
  .read = globalfifo_read,
  .write = globalfifo_write,
  .ioctl = globalfifo_ioctl,
  .poll = globalfifo_poll,
  .open = globalfifo_open,
  .release = globalfifo_release,
  .fasync = globalfifo_fasync,
};

/*³õÊŒ»¯²¢×¢²ácdev*/
static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)
{
  int err, devno = MKDEV(globalfifo_major, index);

  cdev_init(&dev->cdev, &globalfifo_fops);
  dev->cdev.owner = THIS_MODULE;
  dev->cdev.ops = &globalfifo_fops;
  err = cdev_add(&dev->cdev, devno, 1);
  if (err)
    printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}

/*É豞Çý¶¯Ä£¿éŒÓÔغ¯Êý*/
int globalfifo_init(void)
{
  int ret;
  dev_t devno = MKDEV(globalfifo_major, 0);

  /* ÉêÇëÉ豞ºÅ*/
  if (globalfifo_major)
    ret = register_chrdev_region(devno, 1, "globalfifo");
  else  /* ¶¯Ì¬ÉêÇëÉ豞ºÅ */
  {
    ret = alloc_chrdev_region(&devno, 0, 1, "globalfifo");
    globalfifo_major = MAJOR(devno);
  }
  if (ret < 0)
    return ret;
  /* ¶¯Ì¬ÉêÇëÉ豞œá¹¹ÌåµÄÄÚŽæ*/
  globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);
  if (!globalfifo_devp)    /*ÉêÇëʧ°Ü*/
  {
    ret =  - ENOMEM;
    goto fail_malloc;
  }

  memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));

  globalfifo_setup_cdev(globalfifo_devp, 0);

  init_MUTEX(&globalfifo_devp->sem);   /*³õÊŒ»¯ÐźÅÁ¿*/
  init_waitqueue_head(&globalfifo_devp->r_wait); /*³õÊŒ»¯¶ÁµÈŽý¶ÓÁÐÍ·*/
  init_waitqueue_head(&globalfifo_devp->w_wait); /*³õÊŒ»¯ÐŽµÈŽý¶ÓÁÐÍ·*/

  return 0;

  fail_malloc: unregister_chrdev_region(devno, 1);
  return ret;
}


/*Ä£¿éжÔغ¯Êý*/
void globalfifo_exit(void)
{
  cdev_del(&globalfifo_devp->cdev);   /*×¢Ïúcdev*/
  kfree(globalfifo_devp);     /*ÊÍ·ÅÉ豞œá¹¹ÌåÄÚŽæ*/
  unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1); /*ÊÍ·ÅÉ豞ºÅ*/
}

MODULE_AUTHOR("Song Baohua");
MODULE_LICENSE("Dual BSD/GPL");

module_param(globalfifo_major, int, S_IRUGO);

module_init(globalfifo_init);
module_exit(globalfifo_exit);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值