📄 cfi_cmdset_0002.c
字号:
chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } } /* Write buffer is worth it only if more than one word to write... */ while (len >= map_bankwidth(map) * 2) { /* We must not cross write block boundaries */ int size = wbufsize - (ofs & (wbufsize-1)); if (size > len) size = len; if (size % map_bankwidth(map)) size -= size % map_bankwidth(map); 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; } } if (len) { size_t retlen_dregs = 0; ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift), len, &retlen_dregs, buf); *retlen += retlen_dregs; return ret; } return 0;}/* * Handle devices with one erase region, that only implement * the chip erase command. */static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip){ struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; unsigned long int adr; DECLARE_WAITQUEUE(wait, current); int ret = 0; adr = cfi->addr_unlock1; spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_WRITING); if (ret) { spin_unlock(chip->mutex); return ret; } DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", __func__, chip->start ); XIP_INVAL_CACHED_RANGE(map, adr, map->size); ENABLE_VPP(map); xip_disable(map, chip, adr); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); chip->state = FL_ERASING; chip->erase_suspended = 0; chip->in_progress_block_addr = adr; INVALIDATE_CACHE_UDELAY(map, chip, adr, map->size, chip->erase_time*500); 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(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); spin_lock(chip->mutex); continue; } if (chip->erase_suspended) { /* This erase was suspended and resumed. Adjust the timeout */ timeo = jiffies + (HZ*20); /* FIXME */ chip->erase_suspended = 0; } if (chip_ready(map, adr)) break; if (time_after(jiffies, timeo)) { printk(KERN_WARNING "MTD %s(): software timeout\n", __func__ ); break; } /* Latency issues. Drop the lock, wait a while and retry */ UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ if (!chip_good(map, adr, map_word_ff(map))) { /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ ret = -EIO; } chip->state = FL_READY; xip_enable(map, chip, adr); put_chip(map, chip, adr); spin_unlock(chip->mutex); return ret;}static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk){ struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; DECLARE_WAITQUEUE(wait, current); int ret = 0; adr += chip->start; spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_ERASING); if (ret) { spin_unlock(chip->mutex); return ret; } DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", __func__, adr ); XIP_INVAL_CACHED_RANGE(map, adr, len); ENABLE_VPP(map); xip_disable(map, chip, adr); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); map_write(map, CMD(0x30), adr); chip->state = FL_ERASING; chip->erase_suspended = 0; chip->in_progress_block_addr = adr; INVALIDATE_CACHE_UDELAY(map, chip, adr, len, chip->erase_time*500); 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(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); spin_lock(chip->mutex); continue; } if (chip->erase_suspended) { /* This erase was suspended and resumed. Adjust the timeout */ timeo = jiffies + (HZ*20); /* FIXME */ chip->erase_suspended = 0; } if (chip_ready(map, adr)) { xip_enable(map, chip, adr); break; } if (time_after(jiffies, timeo)) { xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__ ); break; } /* Latency issues. Drop the lock, wait a while and retry */ UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ if (!chip_good(map, adr, map_word_ff(map))) { /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ ret = -EIO; } chip->state = FL_READY; put_chip(map, chip, adr); spin_unlock(chip->mutex); return ret;}int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr){ unsigned long ofs, len; int ret; ofs = instr->addr; len = instr->len; ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL); if (ret) return ret; instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0;}static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; int ret = 0; if (instr->addr != 0) return -EINVAL; if (instr->len != mtd->size) return -EINVAL; ret = do_erase_chip(map, &cfi->chips[0]); if (ret) return ret; instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0;}static void cfi_amdstd_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(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(chip->mutex); break; default: /* Not an idle state */ add_wait_queue(&chip->wq, &wait); spin_unlock(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(chip->mutex); if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; wake_up(&chip->wq); } spin_unlock(chip->mutex); }}static int cfi_amdstd_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(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(chip->mutex); } /* Unlock the chips again */ if (ret) { for (i--; i >=0; i--) { chip = &cfi->chips[i]; spin_lock(chip->mutex); if (chip->state == FL_PM_SUSPENDED) { chip->state = chip->oldstate; wake_up(&chip->wq); } spin_unlock(chip->mutex); } } return ret;}static void cfi_amdstd_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(chip->mutex); if (chip->state == FL_PM_SUSPENDED) { chip->state = FL_READY; map_write(map, CMD(0xF0), chip->start); wake_up(&chip->wq); } else printk(KERN_ERR "Argh. Chip not in PM_SUSPENDED state upon resume()\n"); spin_unlock(chip->mutex); }}static void cfi_amdstd_destroy(struct mtd_info *mtd){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; kfree(cfi->cmdset_priv); kfree(cfi->cfiq); kfree(cfi); kfree(mtd->eraseregions);}static char im_name[]="cfi_cmdset_0002";static int __init cfi_amdstd_init(void){ inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002); return 0;}static void __exit cfi_amdstd_exit(void){ inter_module_unregister(im_name);}module_init(cfi_amdstd_init);module_exit(cfi_amdstd_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -