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

    本文代码参考《LINUX设备驱动程序》第十六章 块设备驱动程序

    本文中的“块设备”是一段大小为PAGE_SIZE的内存空间(两个扇区,每个扇区512字节)

    功能:向块设备中输入内容,从块设备中读出内容
    注:ldd自带块设备驱动源码在2.6.32内核的发行版上编译时会提示很多API未定义,原因是kernel 2.6中block layer API已经变更了很多,本文的程序参考了http://hi.baidu.com/casualfish/item/7931bbb58925fb951846977d,感谢!
     
    代码:
    1. sbull.c
      1 #include <linux/module.h>
      2 #include <linux/moduleparam.h>
      3 #include <linux/init.h>
      4 
      5 #include <linux/sched.h>
      6 #include <linux/kernel.h>
      7 #include <linux/slab.h>
      8 #include <linux/fs.h>
      9 #include <linux/errno.h>
     10 #include <linux/timer.h>
     11 #include <linux/types.h>
     12 #include <linux/fcntl.h>
     13 #include <linux/hdreg.h>
     14 #include <linux/kdev_t.h>
     15 #include <linux/vmalloc.h>
     16 #include <linux/genhd.h>
     17 #include <linux/blkdev.h>
     18 #include <linux/buffer_head.h>
     19 #include <linux/bio.h>
     20 
     21 #include "sbull.h"
     22 
     23 static int sbull_major = SBULL_MAJOR;
     24 static int hardsect_size = SBULL_HARDSECT;
     25 static int nsectors = 2;
     26 module_param(sbull_major, int, 0);
     27 module_param(hardsect_size, int, 0);
     28 module_param(nsectors, int, 0);
     29 
     30 struct sbull_dev {
     31     int size;
     32     u8 *data;
     33     short users;
     34     spinlock_t lock;
     35     struct request_queue *queue;
     36     struct gendisk *gd;
     37 };
     38 
     39 static struct sbull_dev *device = NULL;
     40 
     41 static void sbull_transfer(struct sbull_dev *dev, unsigned long sector, unsigned long nsect, char *buffer, int write)
     42 {
     43     unsigned long offset = sector*KERNEL_SECTOR_SIZE;
     44     unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE;
     45 
     46     if ((offset+nbytes) > dev->size)
     47     {
     48         return;
     49     }
     50 
     51     if (write)
     52     {
     53         memcpy(dev->data+offset, buffer, nbytes);
     54     }
     55     else
     56     {
     57         memcpy(buffer, dev->data+offset, nbytes);
     58     }
     59 }
     60 
     61 static int sbull_xfer_bio(struct sbull_dev *dev, struct bio *bio)
     62 {
     63     int i;
     64     struct bio_vec *bvec;
     65     sector_t sector = bio->bi_sector;
     66 
     67     bio_for_each_segment(bvec, bio, i)
     68     {
     69         char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);
     70         sbull_transfer(dev, sector, bio_cur_bytes(bio)>>9, buffer, bio_data_dir(bio) == WRITE);
     71         sector += bio_cur_bytes(bio)>>9;
     72         __bio_kunmap_atomic(bio, KM_USER0);
     73     }
     74     return 0;
     75 }
     76 
     77 static int sbull_xfer_request(struct sbull_dev *dev, struct request *req)
     78 {
     79     struct bio *bio;
     80     int nsect = 0;
     81 
     82     __rq_for_each_bio(bio, req) {
     83         sbull_xfer_bio(dev, bio);
     84         nsect += bio->bi_size/KERNEL_SECTOR_SIZE;
     85     }
     86     return nsect;
     87 }
     88 
     89 static void sbull_full_request(struct request_queue *q)
     90 {
     91     struct request *req;
     92     int sectors_xferred;
     93     struct sbull_dev *dev = q->queuedata;
     94 
     95     while((req = blk_fetch_request(q)) != NULL)
     96     {
     97         if (req->cmd_type != REQ_TYPE_FS)
     98         {
     99             __blk_end_request_all(req, -EIO);
    100             continue;
    101         }
    102 
    103         sectors_xferred = sbull_xfer_request(dev, req);
    104 
    105         __blk_end_request_cur(req, 0);
    106     }
    107 }
    108 
    109 static int sbull_open(struct block_device *device, fmode_t mode)
    110 {
    111     struct sbull_dev *dev = device->bd_disk->private_data;
    112 
    113     spin_lock(&dev->lock);
    114     dev->users++;
    115     spin_unlock(&dev->lock);
    116     return 0;
    117 }
    118 
    119 static int sbull_release(struct gendisk *disk, fmode_t mode)
    120 {
    121     struct sbull_dev *dev = disk->private_data;
    122 
    123     spin_lock(&dev->lock);
    124     dev->users--;
    125     spin_unlock(&dev->lock);
    126 
    127     return 0;
    128 }
    129 
    130 static struct block_device_operations sbull_ops = {
    131     .owner = THIS_MODULE,
    132     .open = sbull_open,
    133     .release = sbull_release,
    134 };
    135 
    136 static void setup_device(struct sbull_dev *dev)
    137 {
    138     memset(dev, 0, sizeof(struct sbull_dev));
    139     dev->size = nsectors*hardsect_size;
    140     dev->data = vmalloc(dev->size);
    141     if (dev->data == NULL)
    142     {
    143         return;
    144     }
    145 
    146     spin_lock_init(&dev->lock);
    147 
    148     dev->queue = blk_init_queue(sbull_full_request, &dev->lock);
    149     if (dev->queue == NULL)
    150     {
    151         goto out_vfree;
    152     }
    153 
    154     blk_queue_logical_block_size(dev->queue, hardsect_size);
    155     dev->queue->queuedata = dev;
    156 
    157     dev->gd = alloc_disk(1);
    158     if (!dev->gd)
    159     {
    160         goto out_vfree;
    161     }
    162 
    163     dev->gd->major = sbull_major;
    164     dev->gd->first_minor = 0;
    165     dev->gd->fops = &sbull_ops;
    166     dev->gd->queue = dev->queue;
    167     dev->gd->private_data = dev;
    168     snprintf(dev->gd->disk_name, 6, "sbull");    
    169     set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));
    170     add_disk(dev->gd);
    171 
    172     return;
    173 
    174     out_vfree:
    175         if (dev->data)
    176         {
    177             vfree(dev->data);
    178         }
    179 }
    180 
    181 static int __init sbull_init(void)
    182 {
    183     sbull_major = register_blkdev(sbull_major, "sbull");
    184     if (sbull_major <= 0)
    185     {
    186         return -EBUSY;    
    187     }
    188 
    189     device = kmalloc(sizeof(struct sbull_dev), GFP_KERNEL);
    190     if (device == NULL)
    191     {
    192         goto out_unregister;
    193     }
    194 
    195     setup_device(device);
    196 
    197     return 0;
    198 
    199     out_unregister:
    200         unregister_blkdev(sbull_major, "sbull");
    201         return -ENOMEM;
    202 }
    203 
    204 static void sbull_exit(void)
    205 {
    206     struct sbull_dev *dev = device;
    207 
    208     if (dev->gd)
    209     {
    210         del_gendisk(dev->gd);
    211         put_disk(dev->gd);
    212     }
    213 
    214     if (dev->queue)
    215     {
    216         blk_cleanup_queue(dev->queue);
    217     }
    218 
    219     if (dev->data)
    220     {
    221         vfree(dev->data);
    222     }
    223 
    224     unregister_blkdev(sbull_major, "sbull");
    225     kfree(device);
    226 }
    227 
    228 module_init(sbull_init);
    229 module_exit(sbull_exit);
    230 MODULE_LICENSE("GPL");

    2. sbull.h

    1 #ifndef _SBULL_H
    2 #define _SBULL_H
    3 
    4 #define SBULL_MAJOR    0
    5 #define SBULL_HARDSECT    512
    6 
    7 #define KERNEL_SECTOR_SIZE    512
    8 
    9 #endif

    3. Makefile

     1 obj-m += sbull.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 sbull.ko

    3)#ls /dev/    //会显示sbull

    4)#ls -lh /tmp/test1   

    -rw-r--r--. 1 root root 4.3k Dec 2 20:47 test1

    5)#dd if=/tmp/test1 of=/dev/sbull bs=512 count=2    //将test1中两个扇区的内容输入到块设备sbull中

    6)#dd if=/dev/sbull of=/tmp/test2 bs=512 count=2    //将块设备sbull中两个扇区的内容输入到临时文件test2中

    7)#ls -lh /tmp/test2

    -rw-r--r--. 1 root root 1.0k Dec 2 21:19 test2

    8)#vim test2    //test2中的内容跟test1前1024个字节的内容相同

  • 相关阅读:
    money 和 smallmoney
    Sql server decimal 和 numeric
    SQL server数据类型int、bigint、smallint、tinyint
    c# 的传递参数值传递与传递引用的区别,ref与out区别
    释放SQL Server占用的内存
    JavaScript学习总结(一)——JavaScript基础
    js1
    Expected URL scheme 'http' or 'https' but no colon was found
    转载:SpringBoot Process finished with exit code 0
    转载:十大经典排序算法(动图演示)
  • 原文地址:https://www.cnblogs.com/tanghuimin0713/p/3454698.html
Copyright © 2011-2022 走看看