⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cfi_cmdset_0001.c

📁 linux下的MTD设备驱动源代码,配合jffs2 yaffss2文件系统.
💻 C
📖 第 1 页 / 共 2 页
字号:
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	unsigned long ofs;	int chipnum;	int ret = 0;	if (!map->virt || (from + len > mtd->size))		return -EINVAL;		*mtdbuf = (void *)map->virt + from;	*retlen = 0;	/* Now lock the chip(s) to POINT state */	/* ofs: offset within the first chip that the first read should start */	chipnum = (from >> cfi->chipshift);	ofs = from - (chipnum << cfi->chipshift);	while (len) {		unsigned long thislen;		if (chipnum >= cfi->numchips)			break;		if ((len + ofs -1) >> cfi->chipshift)			thislen = (1<<cfi->chipshift) - ofs;		else			thislen = len;		ret = do_point_onechip(map, &cfi->chips[chipnum], ofs, thislen);		if (ret)			break;		*retlen += thislen;		len -= thislen;				ofs = 0;		chipnum++;	}	return 0;}static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	unsigned long ofs;	int chipnum;	/* Now unlock the chip(s) POINT state */	/* ofs: offset within the first chip that the first read should start */	chipnum = (from >> cfi->chipshift);	ofs = from - (chipnum <<  cfi->chipshift);	while (len) {		unsigned long thislen;		struct flchip *chip;		chip = &cfi->chips[chipnum];		if (chipnum >= cfi->numchips)			break;		if ((len + ofs -1) >> cfi->chipshift)			thislen = (1<<cfi->chipshift) - ofs;		else			thislen = len;		spin_lock(chip->mutex);		if (chip->state == FL_POINT) {			chip->ref_point_counter--;			if(chip->ref_point_counter == 0)				chip->state = FL_READY;		} else			printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */		put_chip(map, chip, chip->start);		spin_unlock(chip->mutex);		len -= thislen;		ofs = 0;		chipnum++;	}}static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf){	unsigned long cmd_addr;	struct cfi_private *cfi = map->fldrv_priv;	int ret;	adr += chip->start;	/* Ensure cmd read/writes are aligned. */ 	cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 	spin_lock(chip->mutex);	ret = get_chip(map, chip, cmd_addr, FL_READY);	if (ret) {		spin_unlock(chip->mutex);		return ret;	}	if (chip->state != FL_POINT && chip->state != FL_READY) {		cfi_write(map, CMD(0xff), cmd_addr);		chip->state = FL_READY;	}	map_copy_from(map, buf, adr, len);	put_chip(map, chip, cmd_addr);	spin_unlock(chip->mutex);	return 0;}static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	unsigned long ofs;	int chipnum;	int ret = 0;	/* ofs: offset within the first chip that the first read should start */	chipnum = (from >> cfi->chipshift);	ofs = from - (chipnum <<  cfi->chipshift);	*retlen = 0;	while (len) {		unsigned long thislen;		if (chipnum >= cfi->numchips)			break;		if ((len + ofs -1) >> cfi->chipshift)			thislen = (1<<cfi->chipshift) - ofs;		else			thislen = len;		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);		if (ret)			break;		*retlen += thislen;		len -= thislen;		buf += thislen;				ofs = 0;		chipnum++;	}	return ret;}static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	struct cfi_pri_intelext *extp = cfi->cmdset_priv;	struct flchip *chip;	int ofs_factor = cfi->interleave * cfi->device_type;	int count = len;	int chip_num, offst;	int ret;	chip_num = ((unsigned int)from/reg_sz);	offst = from - (reg_sz*chip_num)+base_offst;	while (count) {	/* Calculate which chip & protection register offset we need */		if (chip_num >= cfi->numchips)			goto out;		chip = &cfi->chips[chip_num];				spin_lock(chip->mutex);		ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);		if (ret) {			spin_unlock(chip->mutex);			return (len-count)?:ret;		}		if (chip->state != FL_JEDEC_QUERY) {			cfi_write(map, CMD(0x90), chip->start);			chip->state = FL_JEDEC_QUERY;		}		while (count && ((offst-base_offst) < reg_sz)) {			*buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));			buf++;			offst++;			count--;		}		put_chip(map, chip, chip->start);		spin_unlock(chip->mutex);		/* Move on to the next chip */		chip_num++;		offst = base_offst;	}	 out:		return len-count;}	static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	struct cfi_pri_intelext *extp=cfi->cmdset_priv;	int base_offst,reg_sz;		/* Check that we actually have some protection registers */	if(!(extp->FeatureSupport&64)){		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);		return 0;	}	base_offst=(1<<extp->FactProtRegSize);	reg_sz=(1<<extp->UserProtRegSize);	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);}static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	struct cfi_pri_intelext *extp=cfi->cmdset_priv;	int base_offst,reg_sz;		/* Check that we actually have some protection registers */	if(!(extp->FeatureSupport&64)){		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);		return 0;	}	base_offst=0;	reg_sz=(1<<extp->FactProtRegSize);	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);}static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum){	struct cfi_private *cfi = map->fldrv_priv;	cfi_word status, status_OK;	unsigned long timeo;	int z, ret=0;	adr += chip->start;	/* Let's determine this according to the interleave only once */	status_OK = CMD(0x80);	spin_lock(chip->mutex);	ret = get_chip(map, chip, adr, FL_WRITING);	if (ret) {		spin_unlock(chip->mutex);		return ret;	}	ENABLE_VPP(map);	cfi_write(map, CMD(0x40), adr);	cfi_write(map, datum, adr);	chip->state = FL_WRITING;	spin_unlock(chip->mutex);	cfi_udelay(chip->word_write_time);	spin_lock(chip->mutex);	timeo = jiffies + (HZ/2);	z = 0;	for (;;) {		if (chip->state != FL_WRITING) {			/* Someone's suspended the write. Sleep */			DECLARE_WAITQUEUE(wait, current);			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&chip->wq, &wait);			spin_unlock(chip->mutex);			schedule();			remove_wait_queue(&chip->wq, &wait);			timeo = jiffies + (HZ / 2); /* FIXME */			spin_lock(chip->mutex);			continue;		}		status = cfi_read(map, adr);		if ((status & status_OK) == status_OK)			break;				/* OK Still waiting */		if (time_after(jiffies, timeo)) {			chip->state = FL_STATUS;			printk(KERN_ERR "waiting for chip to be ready timed out in word write\n");			ret = -EIO;			goto out;		}		/* Latency issues. Drop the lock, wait a while and retry */		spin_unlock(chip->mutex);		z++;		cfi_udelay(1);		spin_lock(chip->mutex);	}	if (!z) {		chip->word_write_time--;		if (!chip->word_write_time)			chip->word_write_time++;	}	if (z > 1) 		chip->word_write_time++;	/* Done and happy. */	chip->state = FL_STATUS;	/* check for lock bit */	if (status & CMD(0x02)) {		/* clear status */		cfi_write(map, CMD(0x50), adr);		/* put back into read status register mode */		cfi_write(map, CMD(0x70), adr);		ret = -EROFS;	} out:	put_chip(map, chip, adr);	spin_unlock(chip->mutex);	return ret;}static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	int ret = 0;	int chipnum;	unsigned long ofs;	*retlen = 0;	if (!len)		return 0;	chipnum = to >> cfi->chipshift;	ofs = to  - (chipnum << cfi->chipshift);	/* If it's not bus-aligned, do the first byte write */	if (ofs & (CFIDEV_BUSWIDTH-1)) {		unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);		int gap = ofs - bus_ofs;		int i = 0, n = 0;		u_char tmp_buf[8];		cfi_word datum;		while (gap--)			tmp_buf[i++] = 0xff;		while (len && i < CFIDEV_BUSWIDTH)			tmp_buf[i++] = buf[n++], len--;		while (i < CFIDEV_BUSWIDTH)			tmp_buf[i++] = 0xff;		if (cfi_buswidth_is_2()) {			datum = *(__u16*)tmp_buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)tmp_buf;		} else if (cfi_buswidth_is_8()) {			datum = *(__u64*)tmp_buf;		} else {			return -EINVAL;  /* should never happen, but be safe */		}		ret = do_write_oneword(map, &cfi->chips[chipnum],					       bus_ofs, datum);		if (ret) 			return ret;				ofs += n;		buf += n;		(*retlen) += n;		if (ofs >> cfi->chipshift) {			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}		while(len >= CFIDEV_BUSWIDTH) {		cfi_word datum;		if (cfi_buswidth_is_1()) {			datum = *(__u8*)buf;		} else if (cfi_buswidth_is_2()) {			datum = *(__u16*)buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)buf;		} else if (cfi_buswidth_is_8()) {			datum = *(__u64*)buf;		} else {			return -EINVAL;		}		ret = do_write_oneword(map, &cfi->chips[chipnum],				ofs, datum);		if (ret)			return ret;		ofs += CFIDEV_BUSWIDTH;		buf += CFIDEV_BUSWIDTH;		(*retlen) += CFIDEV_BUSWIDTH;		len -= CFIDEV_BUSWIDTH;		if (ofs >> cfi->chipshift) {			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}	if (len & (CFIDEV_BUSWIDTH-1)) {		int i = 0, n = 0;		u_char tmp_buf[8];		cfi_word datum;		while (len--)			tmp_buf[i++] = buf[n++];		while (i < CFIDEV_BUSWIDTH)			tmp_buf[i++] = 0xff;		if (cfi_buswidth_is_2()) {			datum = *(__u16*)tmp_buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)tmp_buf;		} else if (cfi_buswidth_is_8()) {			datum = *(__u64*)tmp_buf;		} else {			return -EINVAL;  /* should never happen, but be safe */		}		ret = do_write_oneword(map, &cfi->chips[chipnum],					       ofs, datum);		if (ret) 			return ret;				(*retlen) += n;	}	return 0;}static inline int do_write_buffer(struct map_info *map, struct flchip *chip, 				  unsigned long adr, const u_char *buf, int len){	struct cfi_private *cfi = map->fldrv_priv;	cfi_word status, status_OK;	unsigned long cmd_adr, timeo;	int wbufsize, z, ret=0, bytes, words;	wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;	adr += chip->start;	cmd_adr = adr & ~(wbufsize-1);		/* Let's determine this according to the interleave only once */	status_OK = CMD(0x80);	spin_lock(chip->mutex);	ret = get_chip(map, chip, cmd_adr, FL_WRITING);	if (ret) {		spin_unlock(chip->mutex);		return ret;	}	if (chip->state != FL_STATUS)		cfi_write(map, CMD(0x70), cmd_adr);	status = cfi_read(map, cmd_adr);	/* 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -