📄 cfi_cmdset_0001.c
字号:
} /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock_bh(chip->mutex); z++; if ( 0 && !(z % 100 )) printk("chip not ready yet after write. looping\n"); udelay(1); spin_lock_bh(chip->mutex); continue; } 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; wake_up(&chip->wq); spin_unlock_bh(chip->mutex); // printk("write ret OK at %lx\n", adr); return 0;}/* This version only uses the 'word write' instruction. We should update it * to write using 'buffer write' if it's available */static int cfi_intelext_write_1_by_16 (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; chipnum = to >> cfi->chipshift; ofs = to - (chipnum << cfi->chipshift); /* If it's not word-aligned, do the first byte write */ if (ofs & 1) {#if defined(__LITTLE_ENDIAN) ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum], ofs, 0xFF | (*buf << 8));#elif defined(__BIG_ENDIAN) ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum], ofs, 0xFF00 | (*buf));#else#error define a sensible endianness#endif if (ret) return ret; ofs++; buf++; (*retlen)++; len--; if (ofs >> cfi->chipshift) { chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } } while(len > 1) { ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum], ofs, *(__u16 *)buf); if (ret) return ret; ofs += 2; buf += 2; (*retlen) += 2; len -= 2; if (ofs >> cfi->chipshift) { chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } } if (len) { /* Final byte to write */#if defined(__LITTLE_ENDIAN) ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum], ofs, 0xFF00 | (*buf));#elif defined(__BIG_ENDIAN) ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum], ofs, 0xFF | (*buf << 8));#else#error define a sensible endianness#endif if (ret) return ret; (*retlen)++; } return 0;}static inline int do_erase_1_by_16_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr){ __u16 status; unsigned long timeo = jiffies + HZ; DECLARE_WAITQUEUE(wait, current); adr += chip->start; 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->write16(map, cpu_to_le16(0x0070), adr); chip->state = FL_STATUS; timeo = jiffies + HZ; case FL_STATUS: status = le16_to_cpu(map->read16(map, adr)); if (!(status & (1<<7))) { static int z=0; /* Urgh. Chip not yet ready to talk to us. */ if (time_after(jiffies, timeo)) { spin_unlock_bh(chip->mutex); printk("waiting for chip to be ready timed out in erase"); return -EIO; } /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock_bh(chip->mutex); z++; if ( 0 && !(z % 100 )) printk("chip not ready yet before erase. looping\n"); udelay(1); goto retry; } break; default: printk("Waiting for chip, status = %d\n", chip->state); /* Stick ourselves on a wait queue to be woken when someone changes the status */ set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock_bh(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); if(signal_pending(current)) return -EINTR; timeo = jiffies + HZ; goto retry; } map->write16(map, cpu_to_le16(0x0020), adr); map->write16(map, cpu_to_le16(0x00D0), adr); chip->state = FL_ERASING; timeo = jiffies + (HZ*2); 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 */ while ( !( (status = le16_to_cpu(map->read16(map, adr))) & 0x80 ) ) { static int z=0; if (chip->state != FL_ERASING) { /* Someone's suspended the erase. Sleep */ set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock_bh(chip->mutex); printk("erase suspended. Sleeping\n"); schedule(); remove_wait_queue(&chip->wq, &wait); if (signal_pending(current)) return -EINTR; timeo = jiffies + (HZ*2); /* FIXME */ spin_lock_bh(chip->mutex); continue; } /* OK Still waiting */ if (time_after(jiffies, timeo)) { chip->state = FL_STATUS; spin_unlock_bh(chip->mutex); printk("waiting for erase to complete timed out."); return -EIO; } /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock_bh(chip->mutex); z++; if ( 0 && !(z % 100 )) printk("chip not ready yet after erase. looping\n"); udelay(1); spin_lock_bh(chip->mutex); continue; } /* Done and happy. */ chip->state = FL_STATUS; wake_up(&chip->wq); spin_unlock_bh(chip->mutex); //printk("erase ret OK\n"); return 0;}static int cfi_intelext_erase_1_by_16 (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; if (instr->addr & (mtd->erasesize - 1)) return -EINVAL; if (instr->len & (mtd->erasesize -1)) return -EINVAL; if ((instr->len + instr->addr) > mtd->size) return -EINVAL; chipnum = instr->addr >> cfi->chipshift; adr = instr->addr - (chipnum << cfi->chipshift); len = instr->len; while(len) { ret = do_erase_1_by_16_oneblock(map, &cfi->chips[chipnum], adr); if (ret) return ret; adr += mtd->erasesize; len -= mtd->erasesize; if (adr >> cfi->chipshift) { adr = 0; chipnum++; if (chipnum >= cfi->numchips) break; } } 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. */ 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 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. */ spin_unlock_bh(chip->mutex); break; default: ret = -EAGAIN; break; } } /* Unlock the chips again */ for (i--; i >=0; i--) { chip = &cfi->chips[i]; spin_lock_bh(chip->mutex); if (chip->state == FL_PM_SUSPENDED) { 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); if (chip->state == FL_PM_SUSPENDED) { chip->state = chip->oldstate; wake_up(&chip->wq); } else printk("Argh. Chip not in PM_SUSPENDED state upon resume()\n"); 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); inter_module_put(cfi->im_name); kfree(cfi);}static int __init cfi_intelext_init(void){ inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0001); return 0;}static void __exit cfi_intelext_exit(void){ inter_module_unregister(im_name);}module_init(cfi_intelext_init);module_exit(cfi_intelext_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -