首頁>技術>

英文單詞

gen

n. 訊息; 情報; 資料;v. (給...)提供情報(up); 供給內幕訊息;

disk

n. 磁碟; 磁碟;

gen disk

在磁碟上

之前講解了字元驅動程式,這期開始講解塊裝置驅動程式

字元裝置與塊裝置的區別

字元裝置驅動:

當應用層讀寫(read()/write())字元裝置驅動時,是按位元組/字元來讀寫資料的,期間沒有任何快取區,因為資料量小,不能隨機讀取資料,例如:按鍵、LED、滑鼠、鍵盤等

塊裝置:

塊裝置是i/o裝置中的一類, 當我們的應用層對該裝置讀寫時,是按扇區大小來讀寫資料的,若讀寫的資料小於扇區的大小,就會需要快取區, 可以隨機讀寫裝置的任意位置處的資料,例如 硬碟,隨身碟,SD卡。

總結:通俗來講就是:塊裝置相當於是多個字元裝置組成

塊裝置結構:段(Segments):由若干個塊組成。是Linux記憶體管理機制中一個記憶體頁或者記憶體頁的一部分。 (Blocks): 由Linux制定對核心或檔案系統等資料處理的基本單位。通常由1個或多個扇區組成。(對Linux作業系統而言)扇區(Sectors):塊裝置的基本單位。通常在512位元組到32768位元組之間,預設512位元組重要的結構體定義

buffer_head

struct buffer_head {	unsigned long b_state;		/* buffer state bitmap (see above) */	struct buffer_head *b_this_page;/* circular list of page's buffers */	struct page *b_page;		/* the page this bh is mapped to */	sector_t b_blocknr;		/* start block number */	size_t b_size;			/* size of mapping */	char *b_data;			/* pointer to data within the page */	struct block_device *b_bdev;	bh_end_io_t *b_end_io;		/* I/O completion */ 	void *b_private;		/* reserved for b_end_io */	struct list_head b_assoc_buffers; /* associated with another mapping */	struct address_space *b_assoc_map;	/* mapping this buffer is						   associated with */	atomic_t b_count;		/* users using this buffer_head */};

bio

struct bio {	sector_t		bi_sector;	/* device address in 512 byte						   sectors */	struct bio		*bi_next;	/* request queue link */	struct block_device	*bi_bdev;	unsigned long		bi_flags;	/* status, command, etc */	unsigned long		bi_rw;		/* bottom bits READ/WRITE,						 * top bits priority						 */	unsigned short		bi_vcnt;	/* how many bio_vec's */	unsigned short		bi_idx;		/* current index into bvl_vec */	/* Number of segments in this BIO after	 * physical address coalescing is performed.	 */	unsigned short		bi_phys_segments;	/* Number of segments after physical and DMA remapping	 * hardware coalescing is performed.	 */	unsigned short		bi_hw_segments;	unsigned int		bi_size;	/* residual I/O count */	/*	 * To keep track of the max hw size, we account for the	 * sizes of the first and last virtually mergeable segments	 * in this bio	 */	unsigned int		bi_hw_front_size;	unsigned int		bi_hw_back_size;	unsigned int		bi_max_vecs;	/* max bvl_vecs we can hold */	struct bio_vec		*bi_io_vec;	/* the actual vec list */	bio_end_io_t		*bi_end_io;	atomic_t		bi_cnt;		/* pin count */	void			*bi_private;	bio_destructor_t	*bi_destructor;	/* destructor */};

block_device

struct block_device {	dev_t			bd_dev;  /* not a kdev_t - it's a search key */	struct inode *		bd_inode;	/* will die */	int			bd_openers;	struct mutex		bd_mutex;	/* open/close mutex */	struct semaphore	bd_mount_sem;	struct list_head	bd_inodes;	void *			bd_holder;	int			bd_holders;#ifdef CONFIG_SYSFS	struct list_head	bd_holder_list;#endif	struct block_device *	bd_contains;	unsigned		bd_block_size;	struct hd_struct *	bd_part;	/* number of times partitions within this device have been opened. */	unsigned		bd_part_count;	int			bd_invalidated;	struct gendisk *	bd_disk;	struct list_head	bd_list;	struct backing_dev_info *bd_inode_backing_dev_info;	/*	 * Private data.  You must have bd_claim'ed the block_device	 * to use this.  NOTE:  bd_claim allows an owner to claim	 * the same device multiple times, the owner must take special	 * care to not mess up bd_private for that case.	 */	unsigned long		bd_private;};

gendisk

struct gendisk {	int major;			/* major number of driver */	int first_minor;	int minors;                     /* maximum number of minors, =1 for                                         * disks that can't be partitioned. */	char disk_name[32];		/* name of major driver */	struct hd_struct **part;	/* [indexed by minor] */	int part_uevent_suppress;	struct block_device_operations *fops;	struct request_queue *queue;	void *private_data;	sector_t capacity;	int flags;	struct device *driverfs_dev;	struct kobject kobj;	struct kobject *holder_dir;	struct kobject *slave_dir;	struct timer_rand_state *random;	int policy;	atomic_t sync_io;		/* RAID */	unsigned long stamp;	int in_flight;#ifdef	CONFIG_SMP	struct disk_stats *dkstats;#else	struct disk_stats dkstats;#endif	struct work_struct async_notify;};

block_device_operations

struct block_device_operations {	int (*open) (struct inode *, struct file *);	int (*release) (struct inode *, struct file *);	int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);	long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);	long (*compat_ioctl) (struct file *, unsigned, unsigned long);	int (*direct_access) (struct block_device *, sector_t, unsigned long *);	int (*media_changed) (struct gendisk *);	int (*revalidate_disk) (struct gendisk *);	int (*getgeo)(struct block_device *, struct hd_geometry *);	struct module *owner;};

buffer_head裡面重要的成員結構體:

bio裡面重要的成員結構體:

備註:typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);

在塊裝置操作中重要的函式ll_rw_block

ll_rw_block:low-level access to block devices(塊裝置低階訪問)

函式原型:void ll_rw_block(int rw, int nr, struct buffer_head *bhs[])

其呼叫過程:

1,ll_rw_block2,struct buffer_head *bh = bhs[i];3,submit_bh4,struct bio *bio;  bio = bio_alloc(GFP_NOIO, 1);5,bio->bi_end_io = end_bio_bh_io_sync;6,bio_get7,submit_bio8,bio_sectors9,generic_make_request(bio);10,__generic_make_request(bio);11,q = bdev_get_queue(bio->bi_bdev);12,return bdev->bd_disk->queue;13,blk_partition_remap(bio);14,ret = q->make_request_fn(q, bio);
編寫一個最簡單的塊裝置驅動程式
/* 參考: * drivers\block\xd.c * drivers\block\z2ram.c */#include <linux/module.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/mm.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/genhd.h>#include <linux/hdreg.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/wait.h>#include <linux/blkdev.h>#include <linux/blkpg.h>#include <linux/delay.h>#include <linux/io.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/dma.h>static struct gendisk *ramblock_disk;static request_queue_t *ramblock_queue;static int major;static DEFINE_SPINLOCK(ramblock_lock);#define RAMBLOCK_SIZE (1024*1024)static unsigned char *ramblock_buf;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;}static struct block_device_operations ramblock_fops = {	.owner	= THIS_MODULE,	.getgeo	= ramblock_getgeo,};static void do_ramblock_request(request_queue_t * q){	static int r_cnt = 0;	static int w_cnt = 0;	struct request *req;		//printk("do_ramblock_request %d\n", ++cnt);	while ((req = elv_next_request(q)) != NULL) {		/* 資料傳輸三要素: 源,目的,長度 */		/* 源/目的: */		unsigned long offset = req->sector * 512;		/* 目的/源: */		// req->buffer		/* 長度: */				unsigned long len = req->current_nr_sectors * 512;		if (rq_data_dir(req) == READ)		{			//printk("do_ramblock_request read %d\n", ++r_cnt);			memcpy(req->buffer, ramblock_buf+offset, len);		}		else		{			//printk("do_ramblock_request write %d\n", ++w_cnt);			memcpy(ramblock_buf+offset, req->buffer, len);		}						end_request(req, 1);	}}static int ramblock_init(void){	ramblock_disk = alloc_disk(16); 	ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock);	ramblock_disk->queue = ramblock_queue;		major = register_blkdev(0, "ramblock");  	ramblock_disk->major       = major;	ramblock_disk->first_minor = 0;	sprintf(ramblock_disk->disk_name, "ramblock");	ramblock_disk->fops        = &ramblock_fops;	set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512);	ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);	add_disk(ramblock_disk);	return 0;}static void ramblock_exit(void){	unregister_blkdev(major, "ramblock");	del_gendisk(ramblock_disk);	put_disk(ramblock_disk);	blk_cleanup_queue(ramblock_queue);	kfree(ramblock_buf);}module_init(ramblock_init);module_exit(ramblock_exit);MODULE_LICENSE("GPL");

9
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 探索JS的5個基本問題