1. 程式人生 > >linux塊裝置驅動與其測試

linux塊裝置驅動與其測試

1 驅動程式
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>/* printk() */
#include <linux/slab.h>/* kmalloc() */
#include <linux/fs.h>/* everything... */
#include <linux/errno.h>/* error codes */
#include <linux/timer.h>
#include <linux/types.h>
/* size_t */ #include <linux/fcntl.h>/* O_ACCMODE */ #include <linux/hdreg.h>/* HDIO_GETGEO */ #include <linux/kdev_t.h> #include <linux/vmalloc.h> #include <linux/genhd.h> #include <linux/blkdev.h> #include <linux/buffer_head.h>/* invalidate_bdev */ #include <linux/bio.h> //塊裝置檔案主裝置號  72 #define BLOCK_DEVICEMAJOR        COMPAQ_SMART2_MAJOR // 塊裝置名字 #define BLOCK_DISKNAME           "queue_block"  //塊裝置容量 #define BLOCK_DEV_BYTES        (1*1024*1024)   // 1M //請求佇列指標 static struct request_queue *block_request_queue; // gendisk結構體指標變數 static struct gendisk *block_dev_disk; //模擬磁碟空間 unsigned char block_dev_data[BLOCK_DEV_BYTES];
//該函式不能由驅動自己呼叫 由系統呼叫 系統認為是時候呼叫的時候呼叫 static void block_dev_do_request(struct request_queue *q) {      //獲取請求佇列第一個IO請求         struct request *req =blk_fetch_request(q);            while ( req  != NULL) {                sector_t sector = blk_rq_pos(req);  //獲取扇區第一個位置                unsigned long nsector = blk_rq_cur_sectors(req);//獲取扇區數目  //判斷是否大於總容量                 if ((sector + nsector)<<9 > BLOCK_DEV_BYTES)                    {                         printk(KERN_ERR BLOCK_DISKNAME                                 ": bad request: block=%llu, count=%llu\n",                                 (unsigned long long)sector,                                  (unsigned long long)nsector);                         __blk_end_request_all(req, -EIO);                         continue;                 }    //判斷資料傳輸方向                 switch (rq_data_dir(req)) {                 case READ:                         memcpy(req->buffer,                                 block_dev_data + (sector<<9),                                 nsector<<9);                                                 break;                 case WRITE:                         memcpy(block_dev_data + (sector<<9),                                 req->buffer,  nsector<<9);                                                 break;                 default:                                                break;                 }               //通知請求隊列當前IO已經處理完畢              if ( ! __blk_end_request_cur(req, 0) ) {
req = blk_fetch_request(q); //繼續讀取下一個IO請求 }         } } static int block_dev_open (struct block_device *device, fmode_t mode) {     printk("open %s\n", device->bd_disk->disk_name);     return 0; } //  釋放塊裝置 static int block_dev_release(struct gendisk *gendisk, fmode_t mode) {        printk("release %s\n", gendisk->disk_name);     return 0; } //類似字元裝置 struct block_device_operations block_dev_fops = {         .owner                = THIS_MODULE,.open=block_dev_open, .release=block_dev_release }; static int __init block_dev_init(void) {         int ret;         //初始化請求佇列         block_request_queue = blk_init_queue(block_dev_do_request, NULL);         if (!block_request_queue) {                 ret = -ENOMEM;                 goto err_init_queue;         }       //分配磁碟         block_dev_disk = alloc_disk(1);         if (!block_dev_disk) {                 ret = -ENOMEM;                 goto err_alloc_disk;         }         strcpy(block_dev_disk->disk_name, BLOCK_DISKNAME);//裝置檔名         block_dev_disk->major = BLOCK_DEVICEMAJOR;         block_dev_disk->first_minor = 0;         block_dev_disk->fops = &block_dev_fops;         block_dev_disk->queue = block_request_queue;//指定請求佇列         set_capacity(block_dev_disk, BLOCK_DEV_BYTES>>9);//設定磁碟容量         add_disk(block_dev_disk);//新增磁碟         return 0; err_alloc_disk:         blk_cleanup_queue(block_request_queue); err_init_queue:         return ret; } static void __exit block_dev_exit(void) {         del_gendisk(block_dev_disk);//刪除磁碟         put_disk(block_dev_disk);//gendisk引用次數減一         blk_cleanup_queue(block_request_queue);//清除請求佇列 } module_init(block_dev_init); module_exit(block_dev_exit);
測試:
第一步:編譯安裝驅動程式
makefile;
ifneq ($(KERNELRELEASE),)  
    obj-m :=queue_block.o  
else  
    KERNELDIR :=/home/litingting/gec2440/linux-2.6.30.4
all:  
    make -C $(KERNELDIR) M=$(PWD)  modules  ARCH=arm  CROSS_COMPILE=arm-linux-  
clean:  
    rm -f *.o *.ko *.mod.o *.mod.c *.symvers modul* *.*~  

endif  
接下來  insmod   queue_block.ko 
第二步:格式化塊裝置   
例如將裝置格式化為Ext2檔案系統格式  mkfs.ext2  /dev/queue_block
第三步:掛載
mount  /dev/queue_block  /mnt/queue_block 
關於掛載解釋如下:
A  
我把U盤插到USB口上了,下一步我該如何做才能檢視U盤裡的內容? 

我不能確定你的Linux系統會不會自動載入。所以,你應該先去/media目錄下檢視一下,看看是不是已經自動載入上了。如果是的話,應該在/media裡有一個目錄,
名字類似於disk,你進入目錄就等於進入你的U盤了。 

如果/media沒有你想要的東西,那就要自己mount了! 

$mkdir /mnt/usb 

$mount -t vfat /dev/sda /mnt/usb 

這樣就可以了,你去/mnt/usb目錄看看,應該有你想要的了。如果mount命令不管用,那麼你可以將/dev/sda改成/dev/sdb或者/dev/sdc試試! 

-t選項用於設定檔案系統型別,我假設你的U盤是fat32的。(因為大部分U盤都是這樣的)如果是其他檔案系統,你可以man mount來檢視一下,方法類似。 

B  
我把光碟放到光碟機裡了,下一步咋辦? 

如果系統沒有自動載入光碟機的話,那麼用下面命令一般有效: 

$mkdir /mnt/cdrom 

$mount -t iso9660 /dev/cdrom /mnt/cdrom