新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > ARM的嵌入式Linux移植體驗之設備驅動

ARM的嵌入式Linux移植體驗之設備驅動

作者: 時間:2012-11-13 來源:網絡 收藏

static struct block_device_operations mtd_fops =
{
 owner: THIS_MODULE,
 open: mtdblock_open,
 release: mtdblock_release,
 ioctl: mtdblock_ioctl
};

static void mtd_notify_add(struct mtd_info* mtd)
{
 …
}

static void mtd_notify_remove(struct mtd_info* mtd)
{
 if (!mtd || mtd->type == MTD_ABSENT)
  return;

 devfs_unregister(devfs_rw_handle[mtd->index]);
}

int __init init_mtdblock(void)
{
 int i;

 spin_lock_init(mtdblks_lock);
 /* this lock is used just in kernels >= 2.5.x */
 spin_lock_init(mtdblock_lock);

 #ifdef CONFIG_DEVFS_FS
 if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, mtd_fops))
 {
  printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices./n",
MTD_BLOCK_MAJOR);
  return -EAGAIN;
 }

 devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
 register_mtd_user(notifier);
 #else
  if (register_blkdev(MAJOR_NR,DEVICE_NAME,mtd_fops)) {
   printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices./n",
MTD_BLOCK_MAJOR);
  return -EAGAIN;
 }
 #endif

/* We fill it in at open() time. */
for (i=0; i MAX_MTD_DEVICES; i++) {
 mtd_sizes[i] = 0;
 mtd_blksizes[i] = BLOCK_SIZE;
}
init_waitqueue_head(thr_wq);
/* Allow the block size to default to BLOCK_SIZE. */
blksize_size[MAJOR_NR] = mtd_blksizes;
blk_size[MAJOR_NR] = mtd_sizes;

BLK_INIT_QUEUE(BLK_DEFAULT_QUEUE(MAJOR_NR), mtdblock_request, mtdblock_lock);

kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
return 0;
}

static void __exit cleanup_mtdblock(void)
{
 leaving = 1;
 wake_up(thr_wq);
 down(thread_sem);
 #ifdef CONFIG_DEVFS_FS
  unregister_mtd_user(notifier);
  devfs_unregister(devfs_dir_handle);
  devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME);
 #else
  unregister_blkdev(MAJOR_NR,DEVICE_NAME);
 #endif
 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 blksize_size[MAJOR_NR] = NULL;
 blk_size[MAJOR_NR] = NULL;
}

module_init(init_mtdblock);
module_exit(cleanup_mtdblock);

  從上述源代碼中我們發(fā)現(xiàn),塊設備也以與字符設備register_chrdev、unregister_ chrdev 函數類似的方法進行設備的注冊與釋放:

int register_blkdev(unsigned int major, const char *name, struct block_device_operations *bdops);
int unregister_blkdev(unsigned int major, const char *name);

  但是,register_chrdev使用一個向 file_operations 結構的指針,而register_blkdev 則使用 block_device_operations 結構的指針,其中定義的open、release 和 ioctl 方法和字符設備的對應方法相同,但未定義 read 或者 write 操作。這是因為,所有涉及到塊設備的 I/O 通常由系統(tǒng)進行緩沖處理。

  塊驅動程序最終必須提供完成實際塊 I/O 操作的機制,在 Linux 當中,用于這些 I/O 操作的方法稱為"request(請求)"。在塊設備的注冊過程中,需要初始化request隊列,這一動作通過blk_init_queue來完成,blk_init_queue函數建立隊列,并將該驅動程序的 request 函數關聯(lián)到隊列。在模塊的清除階段,應調用 blk_cleanup_queue 函數。

  本例中相關的代碼為:

BLK_INIT_QUEUE(BLK_DEFAULT_QUEUE(MAJOR_NR), mtdblock_request, mtdblock_lock);
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));

  每個設備有一個默認使用的請求隊列,必要時,可使用 BLK_DEFAULT_QUEUE(major) 宏得到該默認隊列。這個宏在 blk_dev_struct 結構形成的全局數組(該數組名為 blk_dev)中搜索得到對應的默認隊列。blk_dev 數組由內核維護,并可通過主設備號索引。blk_dev_struct 接口定義如下:

struct blk_dev_struct {
 /*
 * queue_proc has to be atomic
 */
 request_queue_t request_queue;
 queue_proc *queue;
 void *data;
};

  request_queue 成員包含了初始化之后的 I/O 請求隊列,data 成員可由驅動程序使用,以便保存一些私有數據。

  request_queue定義為:

struct request_queue
{
 /*
 * the queue request freelist, one for reads and one for writes
 */
 struct request_list rq[2];

 /*
 * Together with queue_head for cacheline sharing
 */
 struct list_head queue_head;
 elevator_t elevator;

 request_fn_proc * request_fn;
 merge_request_fn * back_merge_fn;
 merge_request_fn * front_merge_fn;
 merge_requests_fn * merge_requests_fn;
 make_request_fn * make_request_fn;
 plug_device_fn * plug_device_fn;
 /*
 * The queue owner gets to use this for whatever they like.
 * ll_rw_blk doesn't touch it.
 */
 void * queuedata;

 /*
 * This is used to remove the plug when tq_disk runs.
 */
 struct tq_struct plug_tq;

 /*
 * Boolean that indicates whether this queue is plugged or not.
 */
 char plugged;

 /*
 * Boolean that indicates whether current_request is active or
 * not.
 */
 char head_active;

 /*
 * Is meant to protect the queue in the future instead of
 * io_request_lock
 */
 spinlock_t queue_lock;

 /*
 * Tasks wait here for free request
 */
 wait_queue_head_t wait_for_request;
};

  下圖表征了blk_dev、blk_dev_struct和request_queue的關系:

  下圖則表征了塊設備的注冊和釋放過程:

  5.小結

  本章講述了Linux設備驅動程序的入口函數及驅動程序中的內存申請、中斷等,并分別以實例講述了字符設備及塊設備的驅動開發(fā)方法。

linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)

linux相關文章:linux教程



上一頁 1 2 3 下一頁

關鍵詞: ARM 嵌入式 Linux移植

評論


相關推薦

技術專區(qū)

關閉