linux字符设备驱动基础框架

字符设备驱动

基础框架

  • 驱动模块框架
  • 设备号审请
  • cdev初始化和file_operations初始化
  • class初始化
  • device自动分配设备文件

模块框架

源文件

#include <linux/init.h>
#include <linux/module.h>

int __init XXX_init(void);
void __exit XXX_exit(void);

module_init(XXX_init);
module_exit(XXX_exit);
MODULE_LICENSE("GPL");

int __init XXX_init(void){
  return 0;
}

void __exit XXX_exit(void){
}

Makefile

CONFIG_MODULE_SIG=n
KERNDIR:=/lib/modules/`uname -r`/build
PWD:= $(shell pwd)

obj-m:= XXX.o

all:
  make -C $(KERNDIR) M=$(PWD) modules

clean:
  make -C $(KERNDIR) M=$(PWD) clean

设备号审请

/*
 * 设备号是系统资源因此每次要使用设备号都要向系统审请
 * 静态审请函数:
 * register_chrdev_region(device_id, device_count, "device_name");
 * 动态宴请函数:
 * alloc_chrdev_region(device_id, device_minor, device_count, "device_name")
 * 设备号注销:
 * unregister_chrdev_region(device_id);
 * 相关宏定义
 * MKDEV(主设备号,次设备号)
 * MAJOR(设备号)
 * MINOR(设备号)
 * cat /proc/devices
 */

// 设备号
dev_t dev_id;
#define DEVICE_MAJOR   220
#define DEVICE_MINOR   0
#define DEVICE_COUNT   1


// 静态审请设备号
int get_device_id_static(void){
  int ret = 0;

  dev_id = MKDEV(DEVICE_MAJOR, DEVICE_MINOR);

  // 向内核请求设备号
  // 静态审请设备号的第一个参数是dev_t类型
  ret = register_chrdev_region(dev_id,DEVICE_COUNT, "cdd_demo");
  if(ret < 0){
    printk("KERN_INFO ""alloc device id static error\n");
    return ret;
  }
  return 0;
}

// 动态审请设备号
int get_device_id_automatic(void){
   int ret = 0;
   // 向内核动态审请设备号
   // 动态审请设备号的第一个参数是dev_t *类型
   ret = alloc_chrdev_region(&dev_id, DEVICE_MINOR, DEVICE_COUNT, "cdd_demon");
   if(ret < 0)
     return ret;
   printk("KERN_INFO ""alloc chrdev region OK\n");
   printk("KERN_INFO ""alloc a char device id %d\n",dev_id);
   return 0;
}

void __exit device_id_exit(void){
  unregister_chrdev_region(dev_id, DEVICE_COUNT);
  printk("KERN_INFO ""device id module exit\n");
}

cdev初始化和file_operations初始化

/*
 * cdev初始化:
 * void cdev_init(struct cdev *cdev, const struct file_operations *fops)
 * 两个参数都要自己声明
 * cdev加入内核:
 * void cdev_add(struct cdev *cdev, dev_t device_id, unsigned count);
 * 手动创建设备文件: mknod device_name device_type device_major device_minor
 */

 #include <linux/fs.h>
 #include <linux/cdev.h>

static int device_open(struct inode *node, struct file *file){
  printk("KERN_INFO device id module opening\n");
  return 0;
}

static int device_close(struct inode *node, struct file *file){
  printk("KERN_INFO device id module closing\n");
  return 0;
}

ssize_t device_read(struct file *file, char __user *buf, size_t size, loff_t *len){
  printk("KERN_INFO device id module reading\n");
  return 0;
}

ssize_t device_write(struct file *file, const char __user *buf, size_t size, loff_t *len){
  printk("KERN_INFO device id module writing\n");
  return 0;
}

// struct cdev
struct cdev device_cdev;

// struct file_operations
struct file_operations device_fops = {
  .owner = THIS_MODULE,
  .open = device_open,
  .release = device_close,
  .read = device_read,
  .write = device_write
};

// cdev 初始化和注册到内核
  cdev_init(&device_cdev, &device_fops);
  ret = cdev_add(&device_cdev, dev_id, DEVICE_COUNT);

// 卸装cdev
  cdev_del(&device_cdev);

class 初始化

/*
 * 自动生成设备文件面不使用mknod命令
 * 先建立类:
 * struct class *class_create(模块所有者, 设备类名);
 * 销毁类:
 * void class_destroy(struct class *);
 * 出错检测:
 * PTR_ERR(void *)
 * ERR_PTR(int)
 * IS_ERR(void *)
 * IS_ERR_OR_NULL(void *)
 */

// device class
struct class *device_class;

  // create class
 device_class = class_create(THIS_MODULE, "cdd_class");

 if(IS_ERR(&device_class)){
    //放cdev
    cdev_del(&device_cdev);
    //放设备号
    unregister_chrdev_region(dev_id, DEVICE_COUNT);
    ret = PTR_ERR(device_close);
    printk("KERN_INFO class create failed\n");
    return ret;
  }

// 释放class
  class_destroy(device_class);

device自动分配设备文件

/*
 * 建立设备文件:
 * struct device *device_create(设备类指针,父设备指针,设备号,额外数据,“设备文件名”);
 * 销毁设备文件:
 * void device_destory(设备类指针,设备号);
 * 出错检测:
 * PTR_ERR(void *)
 * ERR_PTR(int)
 * IS_ERR(void *)
 * IS_ERR_OR_NULL(void *)
 */
 struct device *device_device;
 
  device_device = device_create(device_class, NULL, dev_id, NULL, "cdd");

  if(IS_ERR(device_device)){
    //放class
    class_destroy(device_class);
    //放cdev
    cdev_del(&device_cdev);
    //放设备号
    unregister_chrdev_region(dev_id, DEVICE_COUNT);
    ret = PTR_ERR(device_device);
    printk("KERN_INFO device create failed\n");
    return ret;
  }

  void __exit device_id_exit(void){
  // 放device
  device_destroy(device_class, dev_id);
  // 放class
  class_destroy(device_class);
  // 卸装cdev
  cdev_del(&device_cdev);
  // 释放使用的设备号
  unregister_chrdev_region(dev_id, DEVICE_COUNT);
  printk("KERN_INFO ""device id module exit\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值