zoukankan      html  css  js  c++  java
  • 简单linux字符设备驱动程序

    本文代码参考《LINUX设备驱动程序》第三章 字符设备驱动程序
    本文中的“字符设备”是一段大小为PAGE_SIZE的内存空间
    功能:向字符设备写入字符串;从字符设备读出字符串
    代码:
    1. scull.c
      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/fs.h>
      4 #include <linux/slab.h>
      5 #include <linux/errno.h>
      6 #include <linux/types.h>
      7 #include <linux/cdev.h>
      8 #include <asm/uaccess.h>
      9 
     10 #include "scull.h"
     11 
     12 int scull_major = SCULL_MAJOR;
     13 int scull_minor = 0;
     14 
     15 module_param(scull_major, int, S_IRUGO);
     16 module_param(scull_minor, int, S_IRUGO);
     17 
     18 struct scull_dev *scull_device;
     19 
     20 int scull_trim(struct scull_dev *dev)
     21 {
     22     if (dev)
     23     {
     24         if (dev->data)
     25         {
     26             kfree(dev->data);
     27         }
     28         dev->data = NULL;
     29         dev->size = 0;
     30     }
     31     return 0;
     32 }
     33 
     34 int scull_open(struct inode *inode, struct file *filp)
     35 {
     36     struct scull_dev *dev;
     37 
     38     dev = container_of(inode->i_cdev, struct scull_dev, cdev);
     39     filp->private_data = dev;
     40 
     41     if ((filp->f_flags & O_ACCMODE) == O_WRONLY)
     42     {
     43         if (down_interruptible(&dev->sem))
     44         {
     45             return -ERESTARTSYS;
     46         }
     47         scull_trim(dev);
     48         up(&dev->sem);
     49     }
     50 
     51     return 0;
     52 }
     53 
     54 int scull_release(struct inode *inode, struct file *filp)
     55 {
     56     return 0;
     57 }
     58 
     59 ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
     60 {
     61     struct scull_dev *dev = filp->private_data;
     62     ssize_t retval = 0;
     63 
     64     if (down_interruptible(&dev->sem))
     65     {
     66         return -ERESTARTSYS;
     67     }
     68     if (*f_pos >= dev->size)
     69     {
     70         goto out;
     71     }
     72     if (*f_pos + count > dev->size)
     73     {
     74         count = dev->size - *f_pos;
     75     }
     76 
     77     if (!dev->data)
     78     {
     79         goto out;
     80     }
     81 
     82     if (copy_to_user(buf, dev->data + *f_pos, count))
     83     {
     84         retval = -EFAULT;
     85         goto out;
     86     }
     87 
     88     *f_pos += count;
     89     retval = count;
     90 
     91     out:
     92         up(&dev->sem);
     93         return retval;
     94 }
     95 
     96 ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
     97 {
     98     struct scull_dev *dev = filp->private_data;
     99     ssize_t retval = -ENOMEM;
    100 
    101     if (down_interruptible(&dev->sem))    
    102     {
    103         return -ERESTARTSYS; 
    104     }
    105 
    106     if (!dev->data)    
    107     {
    108         dev->data = kmalloc(SCULL_BUFFER_SIZE, GFP_KERNEL);
    109         if (!dev->data)
    110         {
    111             goto out;
    112         }
    113         memset(dev->data, 0, SCULL_BUFFER_SIZE);
    114      }
    115 
    116     if (count > SCULL_BUFFER_SIZE - dev->size)
    117     {
    118         count = SCULL_BUFFER_SIZE - dev->size;
    119     }
    120 
    121     if (copy_from_user(dev->data + dev->size, buf, count))
    122     {
    123         retval = -EFAULT;
    124         goto out;
    125     }
    126     
    127     dev->size += count;
    128     retval = count;
    129 
    130     out:
    131         up(&dev->sem);
    132         return retval;
    133 }
    134 
    135 loff_t scull_llseek(struct file *filp, loff_t off, int whence)
    136 {
    137     struct scull_dev *dev = filp->private_data;
    138     loff_t newpos;
    139 
    140     switch(whence)
    141     {
    142         case 0:
    143             newpos = off;
    144             break;
    145         case 1:
    146             newpos = filp->f_pos + off;
    147             break;
    148         case 2:
    149             newpos = dev->size + off;
    150             break;
    151         default:
    152             return -EINVAL;
    153     }
    154     if (newpos < 0)
    155     {
    156         return -EINVAL;
    157     }
    158     filp->f_pos = newpos;
    159     return newpos;
    160 }
    161 
    162 struct file_operations scull_fops = {
    163     .owner = THIS_MODULE,
    164     .llseek = scull_llseek,
    165     .read = scull_read,
    166     .write = scull_write,
    167     .open = scull_open,
    168     .release = scull_release,    
    169 };
    170 
    171 void  scull_cleanup_module(void)
    172 {
    173     dev_t devno = MKDEV(scull_major, scull_minor);
    174 
    175     if (scull_device)
    176     {
    177         scull_trim(scull_device);
    178         cdev_del(&scull_device->cdev);
    179         kfree(scull_device);    
    180     }
    181     unregister_chrdev_region(devno, 1);
    182 }
    183 
    184 static void scull_setup_cdev(struct scull_dev *dev)
    185 {
    186     int err, devno = MKDEV(scull_major, scull_minor);
    187 
    188     cdev_init(&dev->cdev, &scull_fops);
    189     dev->cdev.owner = THIS_MODULE;
    190     dev->cdev.ops = &scull_fops;
    191     err = cdev_add(&dev->cdev, devno, 1);
    192 
    193     if (err)
    194     {
    195         printk(KERN_NOTICE "Error %d adding scull", err);
    196     }
    197 }
    198 
    199 static int __init scull_init_module(void)
    200 {
    201     int result;
    202     dev_t dev = 0;
    203 
    204     if (scull_major)    
    205     {
    206         dev = MKDEV(scull_major, scull_minor);
    207         result = register_chrdev_region(dev, 1, "scull");
    208     }
    209     else
    210     {
    211         result = alloc_chrdev_region(&dev, scull_minor, 1, "scull");
    212         scull_major = MAJOR(dev);
    213     }
    214     if (result < 0)
    215     {
    216         printk(KERN_WARNING "scull: can't get major %d
    ", scull_major);
    217         return result;
    218     }
    219 
    220     scull_device = kmalloc(sizeof(struct scull_dev), GFP_KERNEL);        
    221     if (!scull_device)
    222     {
    223         result = -ENOMEM;
    224         goto fail;
    225     }
    226     memset(scull_device, 0, sizeof(struct scull_dev));
    227 
    228     init_MUTEX(&scull_device->sem);
    229 
    230     scull_setup_cdev(scull_device);
    231 
    232     return 0;
    233 
    234     fail:
    235         scull_cleanup_module();
    236         return result;
    237 }
    238 
    239 module_init(scull_init_module);
    240 module_exit(scull_cleanup_module);
    241 
    242 MODULE_LICENSE("GPL");

    2. scull.h

     1 #ifndef _SCULL_H
     2 #define _SCULL_H
     3 
     4 #define SCULL_MAJOR 0
     5 #define SCULL_BUFFER_SIZE PAGE_SIZE
     6 
     7 struct scull_dev {
     8     char *data;
     9     unsigned long size;
    10     struct semaphore sem;
    11     struct cdev cdev;
    12 };
    13 
    14 #endif

    3. Makefile

     1 obj-m += scull.o
     2 
     3 CURRENT_PATH:=$(shell pwd)
     4 LINUX_KERNEL:=$(shell uname -r)
     5 LINUX_KERNEL_PATH:=/usr/src/kernels/$(LINUX_KERNEL)
     6 
     7 all:
     8     make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
     9 clean:
    10     make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

    4. 验证效果

    1) make

    2) insmod scull.ko

    3) cat /proc/devices | grep scull    //获取字符设备scull的主设备号,我的是248

    4) cd /dev/

    5) mknod scull c 248 0

    6) echo hello, world > scull    //向字符设备写入“hello, world”

    7) cat scull    //读出字符设备中的内容,这里应该显示“hello, world”

  • 相关阅读:
    python高级特性和高阶函数
    代理模式及案例
    我的报错错误记录
    摘抄-编码规范
    测试java的Lambda语法
    测试IDEA将新建项目提交到github上
    js处理科学计数法
    测试java操作运算符
    java根据模板生成,导出word和pdf(aspose.words实现word转换pdf)
    sqlserver日期函数
  • 原文地址:https://www.cnblogs.com/tanghuimin0713/p/3439475.html
Copyright © 2011-2022 走看看