linux下塊裝置驅動程式

來源:互聯網
上載者:User

標籤:style   blog   color   使用   width   資料   

塊裝置不能向字元裝置那樣訪問,而是要先將請求放入隊列,最佳化調整順序後再執行,這種訪問方式稱為"電梯調度演算法"。

本篇文章通過ramdisk、nand flash、nor flash來講解如何寫塊裝置驅動程式。

一、ramdisk

1.因為塊裝置驅動程式是將請求放入隊列然後調整順序後執行,所以我們需要先定義請求隊列:

static unsigned char *ramblock_buf;ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);static DEFINE_SPINLOCK(ramblock_lock);struct request_queue_t *ramblock_queue = blk_init_queue(do_ramblock_request,&ramblock_lock);//提供讀寫函數和自旋鎖static void do_ramblock_request(request_queue_t *q){     struct request *req;     while ((req == elv_next_request(q) != NULL)) {          unsigned long offset = req->sector * 512;          unsigned long len = req->current_nr_sectors * 512;          if (rq_data_dir(req) == READ) {               memcpy(req->buffer,ramblock_buf+offset, len);          } else {               memcpy(ramblock_buf+offset, req->buffer, len);          }          end_request(req, 1);     }}

 

request結構體的主要成員包括:
sector_t sector;第一個尚未傳輸的扇區
unsigned long nr_sectors;尚待完成的扇區數
unsigned int current_nr_sectors;當前I/O操作中待完成的扇區數
驅動中會經常與這3個成員打交道,這3個成員在核心和驅動互動中發揮著重大作用。它們以512位元組大小為一個扇區,如果硬體的扇區大小不是512位元組,則需要進行相應的調整。例如,如果硬體的扇區大小是2048位元組,則在進行硬體操作之前,需要用4來除起始扇區號。

2.註冊塊裝置,並讓系統為我們自動分配主裝置號:

static int major;major = register_blkdev(0,"ramblock");

3.構造block_device_operations結構體:

#define RAMBLOCK_SIZE (1024*1024)struct blcok_device_operations = rameblcok_fops = {     .owner = THIS_MODULE,     .getgeo = ramblock_getgeo,};static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo){    /* 容量=heads*cylinders*sectors*512 */    geo->heads     = 2;    geo->cylinders = 32;    geo->sectors   = RAMBLOCK_SIZE/2/32/512;    return 0;}

4.分配設定gendisk結構體:

struct gendisk *ramblock_disk = alloc_disk(16);/* 次裝置號個數:分區個數+1 */ramblock_disk->major = majorramblock_disk->first_minor = 0;sprintf(ramblcok_disk->disk_name, "ramblock");ramblcok_disk->fops = &ramblcok_fops;set_capacity(ramblock_disk, RAMBLOCK_SIZE/512);add_disk(ramblock_disk);

 5.測試:

(1) insmod ramblock.ko
(2) ls /dev/ramblock*   資訊如下:brw-rw----    1 0        0        254,   0 Jan  1 02:26 /dev/ramblock(3)分區:fdisk /dev/ramblock
輸入:m 可以查看協助資訊
輸入:n 用於建立新的分區
輸入:p   用於建立主要磁碟分割
然後根據提示可以建立分區二、Nand flash1.定義S3C2440的Nand flash控制寄存器結構體:
struct s3c_nand_regs {    unsigned long nfconf  ;    unsigned long nfcont  ;    unsigned long nfcmd   ;    unsigned long nfaddr  ;    unsigned long nfdata  ;    unsigned long nfeccd0 ;    unsigned long nfeccd1 ;    unsigned long nfeccd  ;    unsigned long nfstat  ;    unsigned long nfestat0;    unsigned long nfestat1;    unsigned long nfmecc0 ;    unsigned long nfmecc1 ;    unsigned long nfsecc  ;    unsigned long nfsblk  ;    unsigned long nfeblk  ;};static struct s3c_nand_regs *s3c_nand_regs;s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs));

2.手動定義分區:

static struct mtd_partition s3c_nand_parts[] = {    [0] = {        .name   = "bootloader",        .size   = 0x00040000,        .offset    = 0,    },    [1] = {        .name   = "params",        .offset = MTDPART_OFS_APPEND,        .size   = 0x00020000,    },    [2] = {        .name   = "kernel",        .offset = MTDPART_OFS_APPEND,        .size   = 0x00200000,    },    [3] = {        .name   = "root",        .offset = MTDPART_OFS_APPEND,        .size   = MTDPART_SIZ_FULL,    }};

3.使能S3C2440的Nand flash控制器的時鐘:

struct clk *clk = clk_get(NULL, "nand");clk_enable(clk);/* HCLK=100MHz     * TACLS:  發出CLE/ALE之後多長時間才發出nWE訊號, 從NAND手冊可知CLE/ALE與nWE可以同時發出,所以TACLS=0     * TWRPH0: nWE的脈衝寬度, HCLK x ( TWRPH0 + 1 ), 從NAND手冊可知它要>=12ns, 所以TWRPH0>=1     * TWRPH1: nWE變為高電平後多長時間CLE/ALE才能變為低電平, 從NAND手冊可知它要>=5ns, 所以TWRPH1>=0     */#define TACLS    0#define TWRPH0   1#define TWRPH1   0    s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);    /* NFCONT:      * BIT1-設為1, 取消片選      * BIT0-設為1, 使能NAND FLASH控制器     */    s3c_nand_regs->nfcont = (1<<1) | (1<<0);

 

4.分配nand_chip和mtd_info結構體,並初始化:

struct nand_chip *s3c_nand = kzmalloc(sizeof(struct nand_chip), GFP_KERNEL);struct mtd_info *s3c_mtd = kzmalloc(sizeof(struct mtd_info), GFP_KERNEL);s3c_nand->select_chip = s3c2440_select_chip;s3c_nand->cmd_ctrl = s3c2440_cmd_ctrl;s3c_nand->IO_ADDR_R = &s3c_nand_regs->nfdata;s3c_nand->IO_ADDR_W = &s3c_nand_regs->nfdata;s3c_nand->dev_ready = s3c2440_dev_ready;s3c_nand->ecc.mode = NAND_ECC_SOFT;s3c_mtd->owner = THIS_MODULE;s3c_mtd->priv = s3c_nand;nand_scan(s3c_mtd,1);//識別Nand flashadd_mtd_partitions(s3c_mtd, s3c_nand_parts, 4);static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr){     if (chipnr == -1)     {          /* 取消選中: NFCONT[1]設為1 */          s3c_nand_regs->nfcont |= (1<<1);              }     else     {          /* 選中: NFCONT[1]設為0 */          s3c_nand_regs->nfcont &= ~(1<<1);     }}/* *當ALE為高電平時傳輸的是地址, *當CLE為高電平時傳輸的是命令 *當ALE和CLE都為低電平時傳輸的是資料 */static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl){     if (ctrl & NAND_CLE)     {          /* 發命令: NFCMMD=dat */          s3c_nand_regs->nfcmd = dat;     }     else     {          /* 發地址: NFADDR=dat */          s3c_nand_regs->nfaddr = dat;     }}static int s3c2440_dev_ready(struct mtd_info *mtd){     return (s3c_nand_regs->nfstat & (1<<0));}

5.測試:

使用mtd-utils-05.07.23.tar.bz2

 三、Nor flash

1.分配map_info和mtd_info結構體並初始化:

static struct map_info *s3c_nor_map;static struct mtd_info *s3c_nor_mtd;s3c_nor_map = kzalloc(sizeof(struct map_info), GFP_KERNEL);
/* 設定:位寬、物理基地址、虛擬基地址、大小 */

s3c_nor_map->name = "s3c_nor";
s3c_nor_map->phys = 0;
s3c_nor_map->size = 0x1000000; /* >= NOR的真正大小 */
s3c_nor_map->bankwidth = 2;
s3c_nor_map->virt = ioremap(s3c_nor_map->phys, s3c_nor_map->size);

simple_map_init(s3c_nor_map);//這裡面設定了讀寫和擦除等函數

2.手動分區:

static struct mtd_partition s3c_nor_parts[] = {    [0] = {        .name   = "bootloader_nor",        .size   = 0x00040000,        .offset    = 0,    },    [1] = {        .name   = "root_nor",        .offset = MTDPART_OFS_APPEND,        .size   = MTDPART_SIZ_FULL,    }};

3.探測Nor flash:

/* 使用cfi協議探測NOR Flash */s3c_nor_mtd = do_map_probe("cfi_probe", s3c_nor_map);if (!s3c_nor_mtd) {    /* 使用jedec協議探測NOR Flash */     s3c_nor_mtd = do_map_probe("jedec_probe", s3c_nor_map);}if (!s3c_nor_mtd) {            iounmap(s3c_nor_map->virt);    kfree(s3c_nor_map);    return -EIO;}add_mtd_partitions(s3c_nor_mtd, s3c_nor_parts, 2);

4.測試:

使用mtd-utils-05.07.23.tar.bz2

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.