#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>

#define DEVICE_MEM_SIZE 20;

#define DEVICE_NAME    "xxxxxx";//设备名称

#define DEVICE_COUNT    1;//设备数量


static int xxx_major = 250;  //主设备号
static int xxx_minor = 0;  //次设备号

static dev_t dev_number;
static struct class *xxx_class = NULL;
static unsigned char mem[DEVICE_MEM_SIZE];

struct cdev xxx_cdev;


static long xxx_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
  switch(cmd)
  {
    case 0:
      break;
    case 1:
      break;
    default:
      return -EINVAL;
  }
  return 0;
}

static int xxx_open(struct inode *inodep, struct file * filep) // 打开设备
{
  printk("%s,%d\n", __func__, __LINE__);
  return 0;
}
static int xxx_release(struct inode * inodep, struct file * filep) // 关闭设备
{
  printk("%s,%d\n", __func__, __LINE__);
  return 0;
}
static ssize_t xxx_read(struct file *filp,char __user *buf, size_t size, loff_t *ppos)
{

  //读取数据到用户空间

  if(copy_to_user(buf,mem,count))
  {
    ret= -EFAULT;
    printk("copyfrom user failed\n");
  }
  else{
    ret= count;
    printk("read%d bytes from dev\n", count);
  }
  return ret;
}

static ssize_t xxx_write(struct file *filp,const char __user *buf, size_t size, loff_t *ppos)//注意:第二个参数和read方法不同
{
  if(copy_from_user(mem,buf,count))
  {
    ret= -EFAULT;
    printk("copyfrom user failed\n");

  }
  else{
    ret= count;
    printk("write%d bytes to dev\n", count);
  }
  return ret;
}

struct file_operations fops =
{
  .owner = THIS_MODULE,
  .unlocked_ioctl = xxx_ioctl,
  .open = xxx_open,
  .release = xxx_release,
  .read = xxx_read,
  .write = xxx_write,
};

static int __init xxx_init(void)
{
  int ret = 0;

  printk("%s,%d\n", __func__, __LINE__);

  //cdev_init()函数用于初始化 cdev 的成员,并建立 cdev 和 file_operations 之间的连接
  cdev_init(&xxx_cdev, &dev_fops);
  xxx_cdev.owner = THIS_MODULE;

  /**在调用 cdev_add()函数向系统注册字符设备之前,
  *应首先调用 register_chrdev_region()或alloc_chrdev_region()函数向系统申请设备号
  **/
  if (xxx_major)//静态申请
  {
    //使用下列宏则可以通过主设备号和次设备号生成 dev_t
    dev_number = MKDEV(xxx_major, xxx_minor);
    ret = register_chrdev_region(dev_number, DEVICE_COUNT, DEVICE_NAME);
  }
  else //动态分配
  {
    ret = alloc_chrdev_region(&xxx_cdev.dev, 10, DEVICE_COUNT, DEVICE_NAME);
    xxx_major = MAJOR(xxx_cdev.dev);
    xxx_minor = MINOR(xxx_cdev.dev);
    dev_number = xxx_cdev.dev;
  }
  if(ret)
  {
    printk("Failed to register_chrdev_region.\n");
    return ret;
  }

  //系统添加一个 cdev,完成字符设备的注册。
  ret = cdev_add(&xxx_cdev, dev_number, DEVICE_COUNT);
  if(ret)
  {
    printk(KERN_NOTICE " Failed to cdev_add [Error] %d adding xxx%d", ret, DEVICE_COUNT);
    unregister_chrdev_region(dev_number, DEVICE_NAME);
    return ret;
  }
  xxx_class = class_create(THIS_MODULE,DEVICE_NAME);
  device_create(xxx_class,NULL,dev_number,NULL,DEVICE_NAME);

  return 0;
}

static void __exit xxx_exit(void)
{
  printk("%s,%d\n", __func__, __LINE__);
  //删除一个 cdev,完成字符设备的注销。
  cdev_del(&xxx_cdev);
  //在调用cdev_del()函数从系统注销字符设备之后,unregister_chrdev_region()应该被调用以释放原先申请的设备号
  unregister_chrdev_region(dev_number, DEVICE_COUNT);
}

module_init(xxx_init);
module_exit(xxx_exit);

MODULE_AUTHOR(" lazybeee");
MODULE_LICENSE("GPL");

posted on 2019-02-19 15:00  懒床小蜜蜂  阅读(122)  评论(0编辑  收藏  举报