免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1659 | 回复: 0
打印 上一主题 下一主题

[硬件及驱动] 驱动MMAP例子 加载后老是被操作系统killed 求指教! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-08-13 16:28 |只看该作者 |倒序浏览
kernel 2.6.32
1:kmalloc的内存想mmap到用户空间,书上说要先设置为保留,但是我看网上有的并没有先设置为保留,直接remap_pfn_range,而有的先设置为保留,到底需要先设置保留吗?
2: 不设置为保留内存的话,echo 到对应设备一串数据然后再通过应用层代码mmap,向其中写数据unmap,进程退出,再cat设备,发现数据并没有更新,这时为何?
3:所以我怀疑是要设置成保留,但是设置保留后SetPageReserved,加载该驱动时,老是被killed,求大侠指点?

/*======================================================================
    A globalmem driver as an example of char device drivers  
   
    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/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>

#define GLOBALMEM_SIZE        0x1000        /*諾ÖÄú′æ×î′ó4K×Ö½ú*/
#define MEM_CLEAR 0x1  /*Çå0諾ÖÄú′æ*/
#define GLOBALMEM_MAJOR 0    /*Ô¤éèμÄglobalmemμÄÖ÷é豸oÅ*/


struct my_kobj {
    int val;
    struct kobject kobj;
};


struct attribute name_attr = {
    .name = "name",
    .mode = 0444,
};

struct attribute val_attr = {
    .name = "val",
    .mode = 0666,
};

struct attribute *my_attrs[] = {
    &name_attr,
    &val_attr,
    NULL,/* ±ØDèéèÖÃÎaNULL */
};

ssize_t my_show(struct kobject *kobj, struct attribute *attr, char *buffer)
{
    struct my_kobj *obj = container_of(kobj, struct my_kobj, kobj);
    ssize_t count = 0;

    if (strcmp(attr->name, "name") == 0) {
        count = sprintf(buffer, "%s\n", kobject_name(kobj));
    } else if (strcmp(attr->name, "val") == 0) {
        count = sprintf(buffer, "%d\n", obj->val);
    }

    return count;
}

ssize_t my_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size)
{
    struct my_kobj *obj = container_of(kobj, struct my_kobj, kobj);

    if (strcmp(attr->name, "val") == 0) {
        sscanf(buffer, "%d", &obj->val);
    }

    return size;
}

struct sysfs_ops my_sysfsops = {
    .show = my_show,
    .store = my_store,
};




static int globalmem_major = GLOBALMEM_MAJOR;
/*globalmemé豸½á11ìå*/
struct globalmem_dev                                    
{                                                        
  struct cdev cdev; /*cdev½á11ìå*/                       
  unsigned char *mem; /*諾ÖÄú′æ*/        
};

struct globalmem_dev *globalmem_devp; /*é豸½á11ìåÖ¸Õë*/
/*Îļt′ò¿aoˉêy*/
int globalmem_open(struct inode *inode, struct file *filp)
{
  /*½«é豸½á11ìåÖ¸Õë¸3Öμ¸øÎļt˽óDêy¾YÖ¸Õë*/
  filp->private_data = globalmem_devp;
  return 0;
}
/*Îļtêí·Åoˉêy*/
int globalmem_release(struct inode *inode, struct file *filp)
{
  return 0;
}

/* ioctlé豸¿ØÖÆoˉêy */
static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned
  int cmd, unsigned long arg)
{
  struct globalmem_dev *dev = filp->private_data;/*»ñμÃé豸½á11ìåÖ¸Õë*/

  switch (cmd)
  {
    case MEM_CLEAR:
      memset(dev->mem, 0, GLOBALMEM_SIZE);      
      printk(KERN_INFO "globalmem is set to zero\n");
      break;

    default:
      return  - EINVAL;
  }
  return 0;
}

/*¶áoˉêy*/
static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,
  loff_t *ppos)
{
  unsigned long p =  *ppos;
  unsigned int count = size;
  int ret = 0;
  struct globalmem_dev *dev = filp->private_data; /*»ñμÃé豸½á11ìåÖ¸Õë*/

  /*·ÖÎöoí»ñè¡óDD§μÄD′3¤¶è*/
  if (p >= GLOBALMEM_SIZE)
    return count ?  - ENXIO: 0;
  if (count > GLOBALMEM_SIZE - p)
    count = GLOBALMEM_SIZE - p;

  /*ÄúoË¿Õ¼ä->óû§¿Õ¼ä*/
  if (copy_to_user(buf, (void*)(dev->mem + p), count))
  {
    ret =  - EFAULT;
  }
  else
  {
    *ppos += count;
    ret = count;
   
    printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
  }

  return ret;
}

/*D′oˉêy*/
static ssize_t globalmem_write(struct file *filp, const char __user *buf,
  size_t size, loff_t *ppos)
{
  unsigned long p =  *ppos;
  unsigned int count = size;
  int ret = 0;
  struct globalmem_dev *dev = filp->private_data; /*»ñμÃé豸½á11ìåÖ¸Õë*/

  printk(KERN_ERR "filp->f_pos is %d \n", filp->f_pos  );

  
  /*·ÖÎöoí»ñè¡óDD§μÄD′3¤¶è*/
  if (p >= GLOBALMEM_SIZE)
    return count ?  - ENXIO: 0;
  if (count > GLOBALMEM_SIZE - p)
    count = GLOBALMEM_SIZE - p;
   
  /*óû§¿Õ¼ä->ÄúoË¿Õ¼ä*/
  if (copy_from_user(dev->mem + p, buf, count))
    ret =  - EFAULT;
  else
  {
    *ppos += count;
    ret = count;
   
    printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
  }

  return ret;
}

/* seekÎļt¶¨Î»oˉêy */
static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
{
  loff_t ret = 0;
  switch (orig)
  {
    case 0:   /*Ïà¶ÔÎļt¿aê¼Î»ÖÃÆ«òÆ*/
      if (offset < 0)
      {
        ret =  - EINVAL;
        break;
      }
      if ((unsigned int)offset > GLOBALMEM_SIZE)
      {
        ret =  - EINVAL;
        break;
      }
      filp->f_pos = (unsigned int)offset;
      ret = filp->f_pos;
      break;
    case 1:   /*Ïà¶ÔÎļtμ±Ç°Î»ÖÃÆ«òÆ*/
      if ((filp->f_pos + offset) > GLOBALMEM_SIZE)
      {
        ret =  - EINVAL;
        break;
      }
      if ((filp->f_pos + offset) < 0)
      {
        ret =  - EINVAL;
        break;
      }
      filp->f_pos += offset;
      ret = filp->f_pos;
      break;
    default:
      ret =  - EINVAL;
      break;
  }
  return ret;
}

static int memdev_mmap(struct file*filp, struct vm_area_struct *vma)
{
      struct globalmem_dev *dev = filp->private_data; /*»ñμÃé豸½á11ìåÖ¸Õë*/
      
      vma->vm_flags |= VM_IO;
      vma->vm_flags |= VM_RESERVED;

      vma->vm_pgoff = ((u32)virt_to_phys(dev->mem)) >> PAGE_SHIFT;
      if (remap_pfn_range(vma,vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot))
          return  -EAGAIN;
      printk(KERN_NOTICE "mmap ok \n");
      return 0;
}
/*Îļt2ù×÷½á11ìå*/
static const struct file_operations globalmem_fops =
{
  .owner = THIS_MODULE,
  .llseek = globalmem_llseek,
  .read = globalmem_read,
  .write = globalmem_write,
  .ioctl = globalmem_ioctl,
  .open = globalmem_open,
  .release = globalmem_release,
   .mmap = memdev_mmap,
};
struct my_kobj *obj1;
struct my_kobj *obj2;
struct kobj_type my_type;

int init_sysfile_by_helun()
{
    obj1 = kzalloc(sizeof(struct my_kobj), GFP_KERNEL);
    if (!obj1) {
        return -ENOMEM;
    }
    obj1->val = 1;

    obj2 = kzalloc(sizeof(struct my_kobj), GFP_KERNEL);
    if (!obj2) {
        kfree(obj1);
        return -ENOMEM;
    }
    obj2->val = 2;

    my_type.release = NULL;
    my_type.default_attrs = my_attrs;
    my_type.sysfs_ops = &my_sysfsops;

    kobject_init_and_add(&obj1->kobj, &my_type, NULL, "mykobj-11");
    kobject_init_and_add(&obj2->kobj, &my_type, &obj1->kobj, "mykobj-22");
    return 0;
}

int exit_sysfile_by_helun()
{
    kobject_del(&obj2->kobj);
    kobject_put(&obj2->kobj);

    kobject_del(&obj1->kobj);
    kobject_put(&obj1->kobj);


    return 0;
}
/*3õê¼»ˉ2¢×¢2ácdev*/
static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
{
  int err, devno = MKDEV(globalmem_major, index);

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

/*é豸Çy¶ˉÄ£¿é¼óÔØoˉêy*/
int globalmem_init(void)
{
  int result;
  dev_t devno = MKDEV(globalmem_major, 0);

  /* éêÇëé豸oÅ*/
  if (globalmem_major)
    result = register_chrdev_region(devno, 1, "globalmmap");
  else  /* ¶ˉì¬éêÇëé豸oÅ */
  {
    result = alloc_chrdev_region(&devno, 0, 1, "globalmmap");
    globalmem_major = MAJOR(devno);
  }  
  if (result < 0) {
    printk(KERN_NOTICE "devo is busy \n");
    return result;
  }
   
  /* ¶ˉì¬éêÇëé豸½á11ìåμÄÄú′æ*/
  globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
  if (!globalmem_devp)    /*éêÇë꧰ü*/
  {
    printk(KERN_NOTICE "no mem \n");
    result =  - ENOMEM;
    goto fail_malloc;
  }
  memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
  
  globalmem_setup_cdev(globalmem_devp, 0);

  globalmem_devp->mem = kmalloc(GLOBALMEM_SIZE, GFP_KERNEL);
  if (globalmem_devp->mem == NULL) {
      printk("globalmem_devp->mem is alloc null \n");
      goto fail_malloc;
  }

  SetPageReserved(((u32)virt_to_phys(globalmem_devp->mem)) >> PAGE_SHIFT);
  
  init_sysfile_by_helun();
  return 0;

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

/*Ä£¿éD¶ÔØoˉêy*/
void globalmem_exit(void)
{
  exit_sysfile_by_helun();
  ClearPageReserved(((u32)virt_to_phys(globalmem_devp->mem)) >> PAGE_SHIFT);
  cdev_del(&globalmem_devp->cdev);   /*×¢Ïúcdev*/
  kfree(globalmem_devp);     /*êí·Åé豸½á11ìåÄú′æ*/
  unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*êí·Åé豸oÅ*/
}

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

module_param(globalmem_major, int, S_IRUGO);

module_init(globalmem_init);
module_exit(globalmem_exit);
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP