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

📄 cfi_cmdset_0001.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 3 页
字号:
int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	unsigned long adr, len;	int chipnum, ret = 0;	int i, first;	struct mtd_erase_region_info *regions = mtd->eraseregions;	if (instr->addr > mtd->size)		return -EINVAL;	if ((instr->len + instr->addr) > mtd->size)		return -EINVAL;	/* Check that both start and end of the requested erase are	 * aligned with the erasesize at the appropriate addresses.	 */	i = 0;	/* Skip all erase regions which are ended before the start of 	   the requested erase. Actually, to save on the calculations,	   we skip to the first erase region which starts after the	   start of the requested erase, and then go back one.	*/		while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)	       i++;	i--;	/* OK, now i is pointing at the erase region in which this 	   erase request starts. Check the start of the requested	   erase range is aligned with the erase size which is in	   effect here.	*/	if (instr->addr & (regions[i].erasesize-1))		return -EINVAL;	/* Remember the erase region we start on */	first = i;	/* Next, check that the end of the requested erase is aligned	 * with the erase region at that address.	 */	while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)		i++;	/* As before, drop back one to point at the region in which	   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;	if (instr->callback)		instr->callback(instr);		return 0;}static void cfi_intelext_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 */			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;	__u32 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:		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 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);	cfi_write(map, CMD(0x60), adr);	cfi_write(map, CMD(0x01), adr);	chip->state = FL_LOCKING;		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*2);	for (;;) {		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 lock 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);	}		/* Done and happy. */	chip->state = FL_STATUS;	DISABLE_VPP(map);	wake_up(&chip->wq);	spin_unlock_bh(chip->mutex);	return 0;}static int cfi_intelext_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;	__u32 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:		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 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);	cfi_write(map, CMD(0x60), adr);	cfi_write(map, CMD(0xD0), adr);	chip->state = FL_UNLOCKING;		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*2);	for (;;) {		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 unlock 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 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_intelext_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_intelext_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_intelext_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) {			cfi_write(map, CMD(0xFF), 0);			chip->state = FL_READY;			wake_up(&chip->wq);		}		spin_unlock_bh(chip->mutex);	}}static void cfi_intelext_destroy(struct mtd_info *mtd){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	kfree(cfi->cmdset_priv);	kfree(cfi);}static char im_name_1[]="cfi_cmdset_0001";static char im_name_3[]="cfi_cmdset_0003";int __init cfi_intelext_init(void){	inter_module_register(im_name_1, THIS_MODULE, &cfi_cmdset_0001);	inter_module_register(im_name_3, THIS_MODULE, &cfi_cmdset_0001);	return 0;}static void __exit cfi_intelext_exit(void){	inter_module_unregister(im_name_1);	inter_module_unregister(im_name_3);}module_init(cfi_intelext_init);module_exit(cfi_intelext_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");MODULE_DESCRIPTION("MTD chip driver for Intel/Sharp flash chips");

⌨️ 快捷键说明

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