⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 my.c

📁 Linux下的简单字符设备驱动的源码
💻 C
字号:
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif//编译选项

#include <linux/proc_fs.h>//头文件
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/seq_file.h>
#include <linux/ioctl.h>
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/slab.h>MODULE_LICENSE("GPL");//#define DEVICE_LENS 1024*1024;//设备缓冲区大小//函数原型声明ssize_t wxw_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t wxw_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
int wxw_open(struct inode *inode, struct file *filp);
int wxw_release(struct inode *inode, struct file *filp);

struct file_operations wxw_fops = {
  .owner   =    THIS_MODULE,
  .read    =    wxw_read,
  .write   =    wxw_write,
  .open    =    wxw_open,
  .release =    wxw_release,
};//file_operations结构体struct wxw_dev {//自定义设备结构
  char * data;//用于保存数据
  unsigned int size;// 缓冲区大小
  unsigned int len;// 缓冲区已有长度
  unsigned int start;// 起始数据偏移量
  struct semaphore sem;// 信号量,用于互斥访问
  struct cdev cdev;// 字符型设备结构
};

struct wxw_dev wxw_device;
dev_t dev_no = 0;
int wxw_init(void)// 初始化函数
{ 
  int err=0;
  cdev_init(&wxw_device.cdev, &wxw_fops);//初始化字符设备以及操作
  wxw_device.cdev.owner = THIS_MODULE;//模块计数
  wxw_device.cdev.ops = &wxw_fops;//指向自己的操作集
 
  alloc_chrdev_region(&dev_no, 0, 1, "wxwdev");//动态分配一个设备号 字符设备注册
  err = cdev_add(&wxw_device.cdev, dev_no, 1);//将字符设备添加到系统
  if (err){
    printk(KERN_NOTICE "Error %d adding device\n", err);
    return -1;
  }
  else{
    init_MUTEX(&wxw_device.sem); // 初始化互斥信号量
    printk(KERN_NOTICE "Device Initilize success.\n");
    return 0; 
  }
}
void wxw_exit(void)//将设备模块从系统中卸载
{
 unregister_chrdev_region(dev_no, 1);//释放设备
 cdev_del(&wxw_device.cdev);
}
int wxw_open(struct inode *inode, struct file *filp)// 打开设备
{
  struct wxw_dev *dev;
  dev = container_of(inode->i_cdev,struct wxw_dev,cdev);   //通过container_of宏获得cdev结构的wxw_dev结构
  
  filp->private_data = dev;//通过文件结构中的private_data数据段传递设备结构

  if (down_interruptible(&dev->sem))// 访问互斥
      return -ERESTARTSYS;
  up(&dev->sem);//将访问信号释放   if(!dev->data){ // 缓冲区为空,重新分配空间
    dev->data = (char *)kmalloc(1024, GFP_KERNEL);
    memset(dev->data, 0, 1024);// 初始化参数
    dev->size = 1024;
    dev->len = dev->start = 0;
             }
  return 0;
}

int wxw_release(struct inode *inode, struct file *filp)// 关闭设备
{
  return 0;
}//读取设备文件, read()使用,读取设备文件到用户缓冲区buf
//参数:文件结构指针filp, 用户缓冲区指针buf,要读出的字节数count, 当前文件指针f_posssize_t wxw_read(struct file *filp,char __user *buf, size_t count, loff_t *f_pos){  struct wxw_dev *dev=filp->private_data;// 读取数据 
  if (down_interruptible(&dev->sem))//访问互斥
  return -ERESTARTSYS;  if(dev->len>0){
    if(count > dev->len-dev->start)//如果要读的字节数目超过可读数,则只读剩余字节
       count = dev->len-dev->start;//获得实际可以读取的字节数
    if(copy_to_user(buf,dev->data+dev->start,count)){
       printk("reading error.\n"); }
  else{
      dev->start += count;//移动当前开始指针
      if(dev->start>=dev->size){//超出范围重新定位
       dev->start = 0;
       dev->len = 0;}
       }
  }
  else{
    printk("error! device file is null.\n");//设备文件为空
    goto end;
         }
 end:
  up(&dev->sem);// 将访问信号释放
  return 0;}//写设备文件, write()使用,将用户缓冲区数据写到设备文件
//参数:文件结构指针filp, 用户缓冲区指针buf, 写入字符数count, 当前文件指针f_pos
ssize_t wxw_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){  struct wxw_dev *dev=filp->private_data;// 读取数据    if (down_interruptible(&dev->sem))//访问互斥
  return -ERESTARTSYS; if(dev->start+dev->len+count > dev->size){//超过剩余空间范围
      memset(dev->data, 0, dev->size);//重新分配空间
      if(count > dev->size)//超过文件总长度,则只写一部分
      count = dev->size;
      dev->start = dev->len = 0;
    }
 if(copy_from_user(dev->data+dev->len,buf,count)){
      printk(KERN_NOTICE "writing error!\n");//写入失败
    }
 else{dev->len += count;}//更新已经使用的空间大小  up(&dev->sem);// 将访问信号释放
  return 0;}module_init(wxw_init);  //注册模块的初始化函数
module_exit(wxw_exit); // 注册模块的退出函数

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -