亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? mtdconcat.c

?? linux 內核源代碼
?? C
?? 第 1 頁 / 共 2 頁
字號:
/* * MTD device concatenation layer * * (C) 2002 Robert Kaiser <rkaiser@sysgo.de> * * NAND support by Christian Gan <cgan@iders.ca> * * This code is GPL * * $Id: mtdconcat.c,v 1.11 2005/11/07 11:14:20 gleixner Exp $ */#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/mtd/mtd.h>#include <linux/mtd/concat.h>#include <asm/div64.h>/* * Our storage structure: * Subdev points to an array of pointers to struct mtd_info objects * which is allocated along with this structure * */struct mtd_concat {	struct mtd_info mtd;	int num_subdev;	struct mtd_info **subdev;};/* * how to calculate the size required for the above structure, * including the pointer array subdev points to: */#define SIZEOF_STRUCT_MTD_CONCAT(num_subdev)	\	((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *)))/* * Given a pointer to the MTD object in the mtd_concat structure, * we can retrieve the pointer to that structure with this macro. */#define CONCAT(x)  ((struct mtd_concat *)(x))/* * MTD methods which look up the relevant subdevice, translate the * effective address and pass through to the subdevice. */static intconcat_read(struct mtd_info *mtd, loff_t from, size_t len,	    size_t * retlen, u_char * buf){	struct mtd_concat *concat = CONCAT(mtd);	int ret = 0, err;	int i;	*retlen = 0;	for (i = 0; i < concat->num_subdev; i++) {		struct mtd_info *subdev = concat->subdev[i];		size_t size, retsize;		if (from >= subdev->size) {			/* Not destined for this subdev */			size = 0;			from -= subdev->size;			continue;		}		if (from + len > subdev->size)			/* First part goes into this subdev */			size = subdev->size - from;		else			/* Entire transaction goes into this subdev */			size = len;		err = subdev->read(subdev, from, size, &retsize, buf);		/* Save information about bitflips! */		if (unlikely(err)) {			if (err == -EBADMSG) {				mtd->ecc_stats.failed++;				ret = err;			} else if (err == -EUCLEAN) {				mtd->ecc_stats.corrected++;				/* Do not overwrite -EBADMSG !! */				if (!ret)					ret = err;			} else				return err;		}		*retlen += retsize;		len -= size;		if (len == 0)			return ret;		buf += size;		from = 0;	}	return -EINVAL;}static intconcat_write(struct mtd_info *mtd, loff_t to, size_t len,	     size_t * retlen, const u_char * buf){	struct mtd_concat *concat = CONCAT(mtd);	int err = -EINVAL;	int i;	if (!(mtd->flags & MTD_WRITEABLE))		return -EROFS;	*retlen = 0;	for (i = 0; i < concat->num_subdev; i++) {		struct mtd_info *subdev = concat->subdev[i];		size_t size, retsize;		if (to >= subdev->size) {			size = 0;			to -= subdev->size;			continue;		}		if (to + len > subdev->size)			size = subdev->size - to;		else			size = len;		if (!(subdev->flags & MTD_WRITEABLE))			err = -EROFS;		else			err = subdev->write(subdev, to, size, &retsize, buf);		if (err)			break;		*retlen += retsize;		len -= size;		if (len == 0)			break;		err = -EINVAL;		buf += size;		to = 0;	}	return err;}static intconcat_writev(struct mtd_info *mtd, const struct kvec *vecs,		unsigned long count, loff_t to, size_t * retlen){	struct mtd_concat *concat = CONCAT(mtd);	struct kvec *vecs_copy;	unsigned long entry_low, entry_high;	size_t total_len = 0;	int i;	int err = -EINVAL;	if (!(mtd->flags & MTD_WRITEABLE))		return -EROFS;	*retlen = 0;	/* Calculate total length of data */	for (i = 0; i < count; i++)		total_len += vecs[i].iov_len;	/* Do not allow write past end of device */	if ((to + total_len) > mtd->size)		return -EINVAL;	/* Check alignment */	if (mtd->writesize > 1) {		uint64_t __to = to;		if (do_div(__to, mtd->writesize) || (total_len % mtd->writesize))			return -EINVAL;	}	/* make a copy of vecs */	vecs_copy = kmalloc(sizeof(struct kvec) * count, GFP_KERNEL);	if (!vecs_copy)		return -ENOMEM;	memcpy(vecs_copy, vecs, sizeof(struct kvec) * count);	entry_low = 0;	for (i = 0; i < concat->num_subdev; i++) {		struct mtd_info *subdev = concat->subdev[i];		size_t size, wsize, retsize, old_iov_len;		if (to >= subdev->size) {			to -= subdev->size;			continue;		}		size = min(total_len, (size_t)(subdev->size - to));		wsize = size; /* store for future use */		entry_high = entry_low;		while (entry_high < count) {			if (size <= vecs_copy[entry_high].iov_len)				break;			size -= vecs_copy[entry_high++].iov_len;		}		old_iov_len = vecs_copy[entry_high].iov_len;		vecs_copy[entry_high].iov_len = size;		if (!(subdev->flags & MTD_WRITEABLE))			err = -EROFS;		else			err = subdev->writev(subdev, &vecs_copy[entry_low],				entry_high - entry_low + 1, to, &retsize);		vecs_copy[entry_high].iov_len = old_iov_len - size;		vecs_copy[entry_high].iov_base += size;		entry_low = entry_high;		if (err)			break;		*retlen += retsize;		total_len -= wsize;		if (total_len == 0)			break;		err = -EINVAL;		to = 0;	}	kfree(vecs_copy);	return err;}static intconcat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops){	struct mtd_concat *concat = CONCAT(mtd);	struct mtd_oob_ops devops = *ops;	int i, err, ret = 0;	ops->retlen = ops->oobretlen = 0;	for (i = 0; i < concat->num_subdev; i++) {		struct mtd_info *subdev = concat->subdev[i];		if (from >= subdev->size) {			from -= subdev->size;			continue;		}		/* partial read ? */		if (from + devops.len > subdev->size)			devops.len = subdev->size - from;		err = subdev->read_oob(subdev, from, &devops);		ops->retlen += devops.retlen;		ops->oobretlen += devops.oobretlen;		/* Save information about bitflips! */		if (unlikely(err)) {			if (err == -EBADMSG) {				mtd->ecc_stats.failed++;				ret = err;			} else if (err == -EUCLEAN) {				mtd->ecc_stats.corrected++;				/* Do not overwrite -EBADMSG !! */				if (!ret)					ret = err;			} else				return err;		}		if (devops.datbuf) {			devops.len = ops->len - ops->retlen;			if (!devops.len)				return ret;			devops.datbuf += devops.retlen;		}		if (devops.oobbuf) {			devops.ooblen = ops->ooblen - ops->oobretlen;			if (!devops.ooblen)				return ret;			devops.oobbuf += ops->oobretlen;		}		from = 0;	}	return -EINVAL;}static intconcat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops){	struct mtd_concat *concat = CONCAT(mtd);	struct mtd_oob_ops devops = *ops;	int i, err;	if (!(mtd->flags & MTD_WRITEABLE))		return -EROFS;	ops->retlen = 0;	for (i = 0; i < concat->num_subdev; i++) {		struct mtd_info *subdev = concat->subdev[i];		if (to >= subdev->size) {			to -= subdev->size;			continue;		}		/* partial write ? */		if (to + devops.len > subdev->size)			devops.len = subdev->size - to;		err = subdev->write_oob(subdev, to, &devops);		ops->retlen += devops.retlen;		if (err)			return err;		if (devops.datbuf) {			devops.len = ops->len - ops->retlen;			if (!devops.len)				return 0;			devops.datbuf += devops.retlen;		}		if (devops.oobbuf) {			devops.ooblen = ops->ooblen - ops->oobretlen;			if (!devops.ooblen)				return 0;			devops.oobbuf += devops.oobretlen;		}		to = 0;	}	return -EINVAL;}static void concat_erase_callback(struct erase_info *instr){	wake_up((wait_queue_head_t *) instr->priv);}static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase){	int err;	wait_queue_head_t waitq;	DECLARE_WAITQUEUE(wait, current);	/*	 * This code was stol^H^H^H^Hinspired by mtdchar.c	 */	init_waitqueue_head(&waitq);	erase->mtd = mtd;	erase->callback = concat_erase_callback;	erase->priv = (unsigned long) &waitq;	/*	 * FIXME: Allow INTERRUPTIBLE. Which means	 * not having the wait_queue head on the stack.	 */	err = mtd->erase(mtd, erase);	if (!err) {		set_current_state(TASK_UNINTERRUPTIBLE);		add_wait_queue(&waitq, &wait);		if (erase->state != MTD_ERASE_DONE		    && erase->state != MTD_ERASE_FAILED)			schedule();		remove_wait_queue(&waitq, &wait);		set_current_state(TASK_RUNNING);		err = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0;	}	return err;}static int concat_erase(struct mtd_info *mtd, struct erase_info *instr){	struct mtd_concat *concat = CONCAT(mtd);	struct mtd_info *subdev;	int i, err;	u_int32_t length, offset = 0;	struct erase_info *erase;	if (!(mtd->flags & MTD_WRITEABLE))		return -EROFS;	if (instr->addr > concat->mtd.size)		return -EINVAL;	if (instr->len + instr->addr > concat->mtd.size)		return -EINVAL;	/*	 * Check for proper erase block alignment of the to-be-erased area.	 * It is easier to do this based on the super device's erase	 * region info rather than looking at each particular sub-device	 * in turn.	 */	if (!concat->mtd.numeraseregions) {		/* the easy case: device has uniform erase block size */		if (instr->addr & (concat->mtd.erasesize - 1))			return -EINVAL;		if (instr->len & (concat->mtd.erasesize - 1))			return -EINVAL;	} else {		/* device has variable erase size */		struct mtd_erase_region_info *erase_regions =		    concat->mtd.eraseregions;		/*		 * Find the erase region where the to-be-erased area begins:		 */		for (i = 0; i < concat->mtd.numeraseregions &&		     instr->addr >= erase_regions[i].offset; i++) ;		--i;		/*		 * Now erase_regions[i] is the region in which the		 * to-be-erased area begins. Verify that the starting		 * offset is aligned to this region's erase size:		 */		if (instr->addr & (erase_regions[i].erasesize - 1))			return -EINVAL;		/*		 * now find the erase region where the to-be-erased area ends:		 */		for (; i < concat->mtd.numeraseregions &&		     (instr->addr + instr->len) >= erase_regions[i].offset;		     ++i) ;		--i;		/*		 * check if the ending offset is aligned to this region's erase size		 */		if ((instr->addr + instr->len) & (erase_regions[i].erasesize -						  1))			return -EINVAL;	}	instr->fail_addr = 0xffffffff;	/* make a local copy of instr to avoid modifying the caller's struct */	erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);	if (!erase)		return -ENOMEM;	*erase = *instr;	length = instr->len;	/*	 * find the subdevice where the to-be-erased area begins, adjust	 * starting offset to be relative to the subdevice start	 */	for (i = 0; i < concat->num_subdev; i++) {		subdev = concat->subdev[i];		if (subdev->size <= erase->addr) {			erase->addr -= subdev->size;			offset += subdev->size;		} else {			break;		}	}

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
欧美精品视频www在线观看| 国产麻豆一精品一av一免费| 欧美日韩在线电影| 九九久久精品视频| 伊人婷婷欧美激情| 国产日韩精品久久久| 欧美色综合天天久久综合精品| 久久精品99国产精品日本| 亚洲欧美成人一区二区三区| 精品国产乱码91久久久久久网站| 色婷婷综合久色| 成人精品电影在线观看| 国产一区二区调教| 婷婷丁香久久五月婷婷| 亚洲色图在线看| 欧美国产激情一区二区三区蜜月| 91精品在线麻豆| 欧美三级韩国三级日本三斤 | 亚洲国产精品久久人人爱| 中文字幕成人av| 欧美成人艳星乳罩| 91精品国产色综合久久不卡电影| 色av成人天堂桃色av| 成人动漫精品一区二区| 国产精一区二区三区| 国产毛片精品视频| 激情深爱一区二区| 激情成人综合网| 久久精品国产一区二区三 | 国产精品卡一卡二卡三| 久久综合资源网| 91精品国产91久久久久久一区二区| jiyouzz国产精品久久| 国产精品亚洲专一区二区三区| 久久99久久99小草精品免视看| 亚洲成人精品在线观看| 一区av在线播放| 亚洲国产一区二区视频| 亚洲午夜久久久久久久久电影院 | 国产a视频精品免费观看| 精品一区二区免费视频| 久久国产精品第一页| 黄网站免费久久| 国产成人日日夜夜| 成人国产精品免费观看动漫| a在线播放不卡| 91在线观看地址| 色综合久久综合中文综合网| 亚洲国产欧美日韩另类综合| 久久色.com| 国产欧美一区二区精品仙草咪| 中文字幕第一页久久| 亚洲人成7777| 亚洲国产综合91精品麻豆| 亚欧色一区w666天堂| 美女视频黄a大片欧美| 国产真实乱对白精彩久久| 国产毛片精品视频| 91在线视频官网| 欧美日韩成人高清| 欧美一区二区三区日韩| 久久网站最新地址| 成人欧美一区二区三区1314| 亚洲一卡二卡三卡四卡五卡| 青青国产91久久久久久| 国产成人在线视频免费播放| aaa欧美色吧激情视频| 欧美色综合天天久久综合精品| 日韩美女在线视频| 国产精品毛片大码女人| 亚洲va欧美va人人爽午夜| 久久精工是国产品牌吗| 97精品视频在线观看自产线路二| 91麻豆精品久久久久蜜臀| 久久夜色精品国产欧美乱极品| 1024亚洲合集| 日本三级亚洲精品| 成人永久免费视频| 欧美日本一区二区三区| 国产日产精品1区| 亚洲国产aⅴ天堂久久| 国产主播一区二区三区| 欧美性猛交xxxx黑人交| 国产人妖乱国产精品人妖| 亚洲福中文字幕伊人影院| 国产一区二区三区香蕉| 日本精品一区二区三区高清| 精品国产欧美一区二区| 一区二区高清视频在线观看| 国产乱码精品一区二区三区忘忧草| 91天堂素人约啪| 精品欧美一区二区三区精品久久 | 国产一区二区网址| 欧美日韩一区二区三区在线看| 久久欧美一区二区| 五月天久久比比资源色| 不卡av在线网| 日韩欧美亚洲一区二区| 亚洲国产欧美一区二区三区丁香婷| 国产v综合v亚洲欧| 欧美大片国产精品| 亚洲国产精品久久人人爱蜜臀| 成人a区在线观看| 欧美电影免费观看高清完整版在 | 日韩av一区二| 91色在线porny| 中文字幕精品一区二区三区精品| 亚洲激情图片一区| 久久久噜噜噜久久人人看 | 亚洲高清免费视频| 岛国一区二区在线观看| 精品国产99国产精品| 午夜精品久久久久久久| 一本大道综合伊人精品热热| 久久久精品日韩欧美| 美洲天堂一区二卡三卡四卡视频| 色婷婷av一区| 国产精品女上位| 国产成人aaaa| 久久先锋影音av| 久久精品999| 日韩欧美国产一二三区| 香蕉加勒比综合久久| 色噜噜偷拍精品综合在线| 中文字幕乱码亚洲精品一区| 国产宾馆实践打屁股91| 久久久久国产一区二区三区四区| 青青草一区二区三区| 欧美精品一级二级三级| 亚洲一级在线观看| 欧美综合色免费| 一区二区三区精品在线| 91理论电影在线观看| 最新国产成人在线观看| 成人性视频免费网站| 欧美激情在线一区二区三区| 伦理电影国产精品| 337p粉嫩大胆噜噜噜噜噜91av| 久久国产福利国产秒拍| 久久久99精品免费观看不卡| 国产又黄又大久久| 国产免费成人在线视频| 国产精品亚洲一区二区三区在线| 久久精品欧美一区二区三区不卡| 国产精品一级二级三级| 亚洲国产精品高清| 91丨porny丨蝌蚪视频| 中文字幕在线不卡视频| 欧美卡1卡2卡| 91福利在线免费观看| 午夜电影网亚洲视频| 日韩欧美一级特黄在线播放| 国产一区二三区| 国产精品入口麻豆原神| 91小视频在线观看| 亚洲成a人片综合在线| 7777精品伊人久久久大香线蕉最新版| 日韩电影在线看| 日韩精品一区二区三区三区免费| 国产精品中文字幕日韩精品| 国产精品久久久久婷婷| 日本韩国精品在线| 男男视频亚洲欧美| 国产网站一区二区| 欧美自拍偷拍午夜视频| 奇米精品一区二区三区在线观看一| 精品电影一区二区三区| 成人黄页毛片网站| 亚洲妇女屁股眼交7| 日韩欧美亚洲一区二区| www.欧美色图| 七七婷婷婷婷精品国产| 国产蜜臀av在线一区二区三区| 91年精品国产| 日韩中文字幕一区二区三区| 欧美精品一区二区三区蜜桃视频 | 亚洲综合自拍偷拍| 日韩欧美不卡一区| 91同城在线观看| 精品一区二区三区久久久| 欧美激情艳妇裸体舞| 91麻豆国产精品久久| 激情综合网天天干| 亚洲男人天堂一区| 精品福利在线导航| 在线看国产一区二区| 国产在线精品视频| 亚洲高清免费在线| 日韩一区欧美一区| 精品99久久久久久| 欧美人成免费网站| 成人av动漫网站| 久久不见久久见免费视频1| 亚洲综合在线五月| 国产精品久久久久久久浪潮网站| 欧美一区二区视频在线观看| 欧美一区二区三级| 精品国产麻豆免费人成网站| 日本高清不卡在线观看| 国产一区二区久久|