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

📄 cfi_cmdset_0001.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	if (z > 1) 		chip->word_write_time++;	/* Done and happy. */	DISABLE_VPP(map);	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);		wake_up(&chip->wq);		spin_unlock_bh(chip->mutex);		return -EROFS;	}	wake_up(&chip->wq);	spin_unlock_bh(chip->mutex);	return 0;}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[4];		__u32 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 {			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) {		__u32 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 {			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[4];		__u32 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 {			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;	__u32 status, status_OK;	unsigned long cmd_adr, timeo;	DECLARE_WAITQUEUE(wait, current);	int wbufsize, z;	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);	timeo = jiffies + HZ; retry:	spin_lock_bh(chip->mutex);	/* Check that the chip's ready to talk to us.	 * Later, we can actually think about interrupting it	 * if it's in FL_ERASING state.	 * Not just yet, though.	 */	switch (chip->state) {	case FL_READY:		break;			case FL_CFI_QUERY:	case FL_JEDEC_QUERY:		cfi_write(map, CMD(0x70), cmd_adr);		chip->state = FL_STATUS;	case FL_STATUS:		status = cfi_read(map, cmd_adr);		if ((status & status_OK) == status_OK)			break;		/* Urgh. Chip not yet ready to talk to us. */		if (time_after(jiffies, timeo)) {			spin_unlock_bh(chip->mutex);			printk(KERN_ERR "waiting for chip to be ready timed out in buffer write\n");			return -EIO;		}		/* Latency issues. Drop the lock, wait a while and retry */		spin_unlock_bh(chip->mutex);		cfi_udelay(1);		goto retry;	default:		/* Stick ourselves on a wait queue to be woken when		   someone changes the status */		set_current_state(TASK_UNINTERRUPTIBLE);		add_wait_queue(&chip->wq, &wait);		spin_unlock_bh(chip->mutex);		schedule();		remove_wait_queue(&chip->wq, &wait);		timeo = jiffies + HZ;		goto retry;	}	ENABLE_VPP(map);	cfi_write(map, CMD(0xe8), cmd_adr);	chip->state = FL_WRITING_TO_BUFFER;	z = 0;	for (;;) {		status = cfi_read(map, cmd_adr);		if ((status & status_OK) == status_OK)			break;		spin_unlock_bh(chip->mutex);		cfi_udelay(1);		spin_lock_bh(chip->mutex);		if (++z > 20) {			/* Argh. Not ready for write to buffer */			cfi_write(map, CMD(0x70), cmd_adr);			chip->state = FL_STATUS;			DISABLE_VPP(map);			spin_unlock_bh(chip->mutex);			printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x, status = %x\n", status, cfi_read(map, cmd_adr));			return -EIO;		}	}	/* Write length of data to come */	cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr );	/* Write data */	for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {		if (cfi_buswidth_is_1()) {			map->write8 (map, *((__u8*)buf)++, adr+z);		} else if (cfi_buswidth_is_2()) {			map->write16 (map, *((__u16*)buf)++, adr+z);		} else if (cfi_buswidth_is_4()) {			map->write32 (map, *((__u32*)buf)++, adr+z);		} else {			DISABLE_VPP(map);			return -EINVAL;		}	}	/* GO GO GO */	cfi_write(map, CMD(0xd0), cmd_adr);	chip->state = FL_WRITING;	spin_unlock_bh(chip->mutex);	cfi_udelay(chip->buffer_write_time);	spin_lock_bh(chip->mutex);	timeo = jiffies + (HZ/2);	z = 0;	for (;;) {		if (chip->state != FL_WRITING) {			/* Someone's suspended the write. Sleep */			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&chip->wq, &wait);			spin_unlock_bh(chip->mutex);			schedule();			remove_wait_queue(&chip->wq, &wait);			timeo = jiffies + (HZ / 2); /* FIXME */			spin_lock_bh(chip->mutex);			continue;		}		status = cfi_read(map, cmd_adr);		if ((status & status_OK) == status_OK)			break;		/* OK Still waiting */		if (time_after(jiffies, timeo)) {			chip->state = FL_STATUS;			DISABLE_VPP(map);			spin_unlock_bh(chip->mutex);			printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");			return -EIO;		}				/* Latency issues. Drop the lock, wait a while and retry */		spin_unlock_bh(chip->mutex);		cfi_udelay(1);		z++;		spin_lock_bh(chip->mutex);	}	if (!z) {		chip->buffer_write_time--;		if (!chip->buffer_write_time)			chip->buffer_write_time++;	}	if (z > 1) 		chip->buffer_write_time++;	/* Done and happy. */	DISABLE_VPP(map);	chip->state = FL_STATUS;	/* check for lock bit */	if (status & CMD(0x02)) {		/* clear status */		cfi_write(map, CMD(0x50), cmd_adr);		/* put back into read status register mode */		cfi_write(map, CMD(0x70), adr);		wake_up(&chip->wq);		spin_unlock_bh(chip->mutex);		return -EROFS;	}	wake_up(&chip->wq);	spin_unlock_bh(chip->mutex);	return 0;}static int cfi_intelext_write_buffers (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 wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;	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 word write */	if (ofs & (CFIDEV_BUSWIDTH-1)) {		size_t local_len = (-ofs)&(CFIDEV_BUSWIDTH-1);		if (local_len > len)			local_len = len;		ret = cfi_intelext_write_words(mtd, to, local_len,					       retlen, buf);		if (ret)			return ret;		ofs += local_len;		buf += local_len;		len -= local_len;		if (ofs >> cfi->chipshift) {			chipnum ++;			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}	/* Write buffer is worth it only if more than one word to write... */	while(len > CFIDEV_BUSWIDTH) {		/* We must not cross write block boundaries */		int size = wbufsize - (ofs & (wbufsize-1));		if (size > len)			size = len & ~(CFIDEV_BUSWIDTH-1);		ret = do_write_buffer(map, &cfi->chips[chipnum], 				      ofs, buf, size);		if (ret)			return ret;		ofs += size;		buf += size;		(*retlen) += size;		len -= size;		if (ofs >> cfi->chipshift) {			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}	/* ... and write the remaining bytes */	if (len > 0) {		size_t local_retlen;		ret = cfi_intelext_write_words(mtd, ofs + (chipnum << cfi->chipshift),					       len, &local_retlen, buf);		if (ret)			return ret;		(*retlen) += local_retlen;	}	return 0;}static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr){	struct cfi_private *cfi = map->fldrv_priv;	__u32 status, status_OK;	unsigned long timeo;	int retries = 3;	DECLARE_WAITQUEUE(wait, current);	int ret = 0;	adr += chip->start;	/* Let's determine this according to the interleave only once */	status_OK = CMD(0x80);	timeo = jiffies + HZ;retry:	spin_lock_bh(chip->mutex);	/* Check that the chip's ready to talk to us. */	switch (chip->state) {	case FL_CFI_QUERY:	case FL_JEDEC_QUERY:	case FL_READY:		cfi_write(map, CMD(0x70), adr);		chip->state = FL_STATUS;	case FL_STATUS:		status = cfi_read(map, adr);		if ((status & status_OK) == status_OK)			break;				/* Urgh. Chip not yet ready to talk to us. */		if (time_after(jiffies, timeo)) {			spin_unlock_bh(chip->mutex);			printk(KERN_ERR "waiting for chip to be ready timed out in erase\n");			return -EIO;		}		/* Latency issues. Drop the lock, wait a while and retry */		spin_unlock_bh(chip->mutex);		cfi_udelay(1);		goto retry;	default:		/* Stick ourselves on a wait queue to be woken when		   someone changes the status */		set_current_state(TASK_UNINTERRUPTIBLE);		add_wait_queue(&chip->wq, &wait);		spin_unlock_bh(chip->mutex);		schedule();		remove_wait_queue(&chip->wq, &wait);		timeo = jiffies + HZ;		goto retry;	}	ENABLE_VPP(map);	/* Clear the status register first */	cfi_write(map, CMD(0x50), adr);	/* Now erase */	cfi_write(map, CMD(0x20), adr);	cfi_write(map, CMD(0xD0), adr);	chip->state = FL_ERASING;		spin_unlock_bh(chip->mutex);	schedule_timeout(HZ);	spin_lock_bh(chip->mutex);	/* FIXME. Use a timer to check this, and return immediately. */	/* Once the state machine's known to be working I'll do that */	timeo = jiffies + (HZ*20);	for (;;) {		if (chip->state != FL_ERASING) {			/* Someone's suspended the erase. Sleep */			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&chip->wq, &wait);			spin_unlock_bh(chip->mutex);			schedule();			remove_wait_queue(&chip->wq, &wait);			timeo = jiffies + (HZ*20); /* FIXME */			spin_lock_bh(chip->mutex);			continue;		}		status = cfi_read(map, adr);		if ((status & status_OK) == status_OK)			break;				/* OK Still waiting */		if (time_after(jiffies, timeo)) {			cfi_write(map, CMD(0x70), adr);			chip->state = FL_STATUS;			printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));			DISABLE_VPP(map);			spin_unlock_bh(chip->mutex);			return -EIO;		}				/* Latency issues. Drop the lock, wait a while and retry */		spin_unlock_bh(chip->mutex);		cfi_udelay(1);		spin_lock_bh(chip->mutex);	}		DISABLE_VPP(map);	ret = 0;	/* We've broken this before. It doesn't hurt to be safe */	cfi_write(map, CMD(0x70), adr);	chip->state = FL_STATUS;	status = cfi_read(map, adr);	/* check for lock bit */	if (status & CMD(0x3a)) {		unsigned char chipstatus = status;		if (status != CMD(status & 0xff)) {			int i;			for (i = 1; i<CFIDEV_INTERLEAVE; i++) {				      chipstatus |= status >> (cfi->device_type * 8);			}			printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus);		}		/* Reset the error bits */		cfi_write(map, CMD(0x50), adr);		cfi_write(map, CMD(0x70), adr);				if ((chipstatus & 0x30) == 0x30) {			printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status);			ret = -EIO;		} else if (chipstatus & 0x02) {			/* Protection bit set */			ret = -EROFS;		} else if (chipstatus & 0x8) {			/* Voltage */			printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", status);			ret = -EIO;		} else if (chipstatus & 0x20) {			if (retries--) {				printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status);				timeo = jiffies + HZ;				chip->state = FL_STATUS;				spin_unlock_bh(chip->mutex);				goto retry;			}			printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status);			ret = -EIO;		}	}	wake_up(&chip->wq);	spin_unlock_bh(chip->mutex);	return ret;}

⌨️ 快捷键说明

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