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

📄 cfi_cmdset_0020.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	   the address actually falls	*/	i--;	if ((instr->addr + instr->len) & (regions[i].erasesize-1))		return -EINVAL;	chipnum = instr->addr >> cfi->chipshift;	adr = instr->addr - (chipnum << cfi->chipshift);	len = instr->len;	i=first;	while(len) {		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);		if (ret)			return ret;		adr += regions[i].erasesize;		len -= regions[i].erasesize;		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))			i++;		if (adr >> cfi->chipshift) {			adr = 0;			chipnum++;			if (chipnum >= cfi->numchips)			break;		}	}	instr->state = MTD_ERASE_DONE;	mtd_erase_callback(instr);	return 0;}static void cfi_staa_sync (struct mtd_info *mtd){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	int i;	struct flchip *chip;	int ret = 0;	DECLARE_WAITQUEUE(wait, current);	for (i=0; !ret && i<cfi->numchips; i++) {		chip = &cfi->chips[i];	retry:		spin_lock_bh(chip->mutex);		switch(chip->state) {		case FL_READY:		case FL_STATUS:		case FL_CFI_QUERY:		case FL_JEDEC_QUERY:			chip->oldstate = chip->state;			chip->state = FL_SYNCING;			/* No need to wake_up() on this state change -			 * as the whole point is that nobody can do anything			 * with the chip now anyway.			 */		case FL_SYNCING:			spin_unlock_bh(chip->mutex);			break;		default:			/* Not an idle state */			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&chip->wq, &wait);			spin_unlock_bh(chip->mutex);			schedule();		        remove_wait_queue(&chip->wq, &wait);			goto retry;		}	}	/* Unlock the chips again */	for (i--; i >=0; i--) {		chip = &cfi->chips[i];		spin_lock_bh(chip->mutex);		if (chip->state == FL_SYNCING) {			chip->state = chip->oldstate;			wake_up(&chip->wq);		}		spin_unlock_bh(chip->mutex);	}}static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr){	struct cfi_private *cfi = map->fldrv_priv;	map_word status, status_OK;	unsigned long timeo = jiffies + HZ;	DECLARE_WAITQUEUE(wait, current);	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:		map_write(map, CMD(0x70), adr);		chip->state = FL_STATUS;	case FL_STATUS:		status = map_read(map, adr);		if (map_word_andequal(map, 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 lock\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);	map_write(map, CMD(0x60), adr);	map_write(map, CMD(0x01), adr);	chip->state = FL_LOCKING;	spin_unlock_bh(chip->mutex);	msleep(1000);	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*2);	for (;;) {		status = map_read(map, adr);		if (map_word_andequal(map, status, status_OK, status_OK))			break;		/* OK Still waiting */		if (time_after(jiffies, timeo)) {			map_write(map, CMD(0x70), adr);			chip->state = FL_STATUS;			printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]);			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);	}	/* Done and happy. */	chip->state = FL_STATUS;	DISABLE_VPP(map);	wake_up(&chip->wq);	spin_unlock_bh(chip->mutex);	return 0;}static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	unsigned long adr;	int chipnum, ret = 0;#ifdef DEBUG_LOCK_BITS	int ofs_factor = cfi->interleave * cfi->device_type;#endif	if (ofs & (mtd->erasesize - 1))		return -EINVAL;	if (len & (mtd->erasesize -1))		return -EINVAL;	if ((len + ofs) > mtd->size)		return -EINVAL;	chipnum = ofs >> cfi->chipshift;	adr = ofs - (chipnum << cfi->chipshift);	while(len) {#ifdef DEBUG_LOCK_BITS		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);		printk("before lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);#endif		ret = do_lock_oneblock(map, &cfi->chips[chipnum], adr);#ifdef DEBUG_LOCK_BITS		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);		printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);#endif		if (ret)			return ret;		adr += mtd->erasesize;		len -= mtd->erasesize;		if (adr >> cfi->chipshift) {			adr = 0;			chipnum++;			if (chipnum >= cfi->numchips)			break;		}	}	return 0;}static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr){	struct cfi_private *cfi = map->fldrv_priv;	map_word status, status_OK;	unsigned long timeo = jiffies + HZ;	DECLARE_WAITQUEUE(wait, current);	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:		map_write(map, CMD(0x70), adr);		chip->state = FL_STATUS;	case FL_STATUS:		status = map_read(map, adr);		if (map_word_andequal(map, 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 unlock\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);	map_write(map, CMD(0x60), adr);	map_write(map, CMD(0xD0), adr);	chip->state = FL_UNLOCKING;	spin_unlock_bh(chip->mutex);	msleep(1000);	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*2);	for (;;) {		status = map_read(map, adr);		if (map_word_andequal(map, status, status_OK, status_OK))			break;		/* OK Still waiting */		if (time_after(jiffies, timeo)) {			map_write(map, CMD(0x70), adr);			chip->state = FL_STATUS;			printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]);			DISABLE_VPP(map);			spin_unlock_bh(chip->mutex);			return -EIO;		}		/* Latency issues. Drop the unlock, wait a while and retry */		spin_unlock_bh(chip->mutex);		cfi_udelay(1);		spin_lock_bh(chip->mutex);	}	/* Done and happy. */	chip->state = FL_STATUS;	DISABLE_VPP(map);	wake_up(&chip->wq);	spin_unlock_bh(chip->mutex);	return 0;}static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	unsigned long adr;	int chipnum, ret = 0;#ifdef DEBUG_LOCK_BITS	int ofs_factor = cfi->interleave * cfi->device_type;#endif	chipnum = ofs >> cfi->chipshift;	adr = ofs - (chipnum << cfi->chipshift);#ifdef DEBUG_LOCK_BITS	{		unsigned long temp_adr = adr;		unsigned long temp_len = len;		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);                while (temp_len) {			printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor)));			temp_adr += mtd->erasesize;			temp_len -= mtd->erasesize;		}		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);	}#endif	ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr);#ifdef DEBUG_LOCK_BITS	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);	printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));	cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);#endif	return ret;}static int cfi_staa_suspend(struct mtd_info *mtd){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	int i;	struct flchip *chip;	int ret = 0;	for (i=0; !ret && i<cfi->numchips; i++) {		chip = &cfi->chips[i];		spin_lock_bh(chip->mutex);		switch(chip->state) {		case FL_READY:		case FL_STATUS:		case FL_CFI_QUERY:		case FL_JEDEC_QUERY:			chip->oldstate = chip->state;			chip->state = FL_PM_SUSPENDED;			/* No need to wake_up() on this state change -			 * as the whole point is that nobody can do anything			 * with the chip now anyway.			 */		case FL_PM_SUSPENDED:			break;		default:			ret = -EAGAIN;			break;		}		spin_unlock_bh(chip->mutex);	}	/* Unlock the chips again */	if (ret) {		for (i--; i >=0; i--) {			chip = &cfi->chips[i];			spin_lock_bh(chip->mutex);			if (chip->state == FL_PM_SUSPENDED) {				/* No need to force it into a known state here,				   because we're returning failure, and it didn't				   get power cycled */				chip->state = chip->oldstate;				wake_up(&chip->wq);			}			spin_unlock_bh(chip->mutex);		}	}	return ret;}static void cfi_staa_resume(struct mtd_info *mtd){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	int i;	struct flchip *chip;	for (i=0; i<cfi->numchips; i++) {		chip = &cfi->chips[i];		spin_lock_bh(chip->mutex);		/* Go to known state. Chip may have been power cycled */		if (chip->state == FL_PM_SUSPENDED) {			map_write(map, CMD(0xFF), 0);			chip->state = FL_READY;			wake_up(&chip->wq);		}		spin_unlock_bh(chip->mutex);	}}static void cfi_staa_destroy(struct mtd_info *mtd){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	kfree(cfi->cmdset_priv);	kfree(cfi);}MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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