📄 iflash2+_mtd.c
字号:
A handler should call vpp_shutdown() once for each request that does a vpp_setup(). ======================================================================*/static int vpp_setup(dev_link_t *link, mtd_request_t *req){ flash_dev_t *dev = (flash_dev_t *)link->priv; mtd_vpp_req_t vpp_req; /* First time for this request? */ if (!(req->Function & MTD_REQ_TIMEOUT)) { /* If no other users, kill shutdown timer and apply power */ if (++dev->vpp_usage == 1) { if (!del_timer(&dev->vpp_timeout)) { DEBUG(1, "iflash2+_mtd: raising Vpp...\n"); dev->vpp_start = jiffies; vpp_req.Vpp1 = vpp_req.Vpp2 = 120; MTDHelperEntry(MTDSetVpp, link->handle, &vpp_req); } } } /* Wait for Vpp to settle if it was just applied */ if (jiffies < dev->vpp_start + vpp_settle) { req->Status = MTD_WAITTIMER; req->Timeout = vpp_settle * 1000 / HZ; return 1; } return 0;}static void vpp_off(u_long arg){ dev_link_t *link = (dev_link_t *)arg; flash_dev_t *dev; mtd_vpp_req_t req; DEBUG(1, "iflash2+_mtd: lowering Vpp...\n"); dev = (flash_dev_t *)link->priv; dev->vpp_timeout.expires = 0; req.Vpp1 = req.Vpp2 = 0; MTDHelperEntry(MTDSetVpp, link->handle, &req);}static void vpp_shutdown(dev_link_t *link){ flash_dev_t *dev; dev = (flash_dev_t *)link->priv; dev->vpp_usage--; if (dev->vpp_usage == 0) { dev->vpp_timeout.expires = jiffies + vpp_timeout_period; add_timer(&dev->vpp_timeout); }}/*====================================================================== flash_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered with Card Services.======================================================================*/static dev_link_t *flash_attach(void){ client_reg_t client_reg; dev_link_t *link; flash_dev_t *dev; int ret; DEBUG(0, "iflash2+_mtd: flash_attach()\n"); /* Create new memory card device */ dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; memset(dev, 0, sizeof(*dev)); link = &dev->link; link->priv = dev; link->release.function = &flash_release; link->release.data = (u_long)link; init_waitqueue_head(&link->pending); dev->vpp_timeout.function = vpp_off; dev->vpp_timeout.data = (u_long)link; /* Register with Card Services */ link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_MTD_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME | CS_EVENT_READY_CHANGE; client_reg.event_handler = &flash_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); flash_detach(link); return NULL; } return link;} /* flash_attach *//*====================================================================== This deletes a driver "instance". The device is de-registered with Card Services. If it has been released, all local data structures are freed. Otherwise, the structures will be freed when the device is released.======================================================================*/static void flash_detach(dev_link_t *link){ dev_link_t **linkp; int ret; DEBUG(0, "iflash2+_mtd: flash_detach(0x%p)\n", link); /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; if (*linkp == NULL) return; del_timer(&link->release); if (link->state & DEV_CONFIG) flash_release((u_long)link); if (link->handle) { ret = CardServices(DeregisterClient, link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } /* Unlink device structure, free bits */ *linkp = link->next; kfree(link->priv); } /* flash_detach *//*====================================================================== flash_config() is scheduled to run after a CARD_INSERTION event is received, to bind the MTD to appropriate memory regions. ======================================================================*/static void printk_size(u_int sz){ if (sz & 0x3ff) printk("%u bytes", sz); else if (sz & 0x0fffff) printk("%u kb", sz >> 10); else printk("%u mb", sz >> 20);}static void flash_config(dev_link_t *link){ client_handle_t handle = link->handle; flash_dev_t *dev = link->priv; win_req_t req; mtd_reg_t reg; region_info_t region; int i, attr, ret; DEBUG(0, "iflash2+_mtd: flash_config(0x%p)\n", link); /* Allocate a small memory window */ if (word_width) req.Attributes = WIN_DATA_WIDTH_16; else req.Attributes = WIN_DATA_WIDTH_8; req.Base = req.Size = 0; req.AccessSpeed = mem_speed; link->win = (window_handle_t)handle; ret = MTDHelperEntry(MTDRequestWindow, &link->win, &req); if (ret != 0) { cs_error(handle, RequestWindow, ret); link->state &= ~DEV_CONFIG_PENDING; flash_release((u_long)link); return; } dev->Base = ioremap(req.Base, req.Size); dev->Size = req.Size; /* Allocate a memory window for ESR accesses*/ req.Base = 0; dev->ESRwin = (window_handle_t)handle; ret = MTDHelperEntry(MTDRequestWindow, &dev->ESRwin, &req); if (ret != 0) { cs_error(handle, RequestWindow, ret); link->state &= ~DEV_CONFIG_PENDING; flash_release((u_long)link); return; } dev->ESRbase = ioremap(req.Base, req.Size); link->state |= DEV_CONFIG; /* Grab info for all the memory regions we can access */ i = 0; for (attr = 0; attr < 2; attr++) { region.Attributes = attr ? REGION_TYPE_AM : REGION_TYPE_CM; ret = CardServices(GetFirstRegion, handle, ®ion); while (ret == CS_SUCCESS) { reg.Attributes = region.Attributes; reg.Offset = region.CardOffset; dev->flash[i] = kmalloc(sizeof(struct flash_region_t), GFP_KERNEL); if (!dev->flash[i]) break; reg.MediaID = (u_long)dev->flash[i]; ret = CardServices(RegisterMTD, handle, ®); if (ret != 0) { kfree(dev->flash[i]); break; } printk(KERN_INFO "iflash2+_mtd: %s at 0x%x, ", attr ? "attr" : "common", region.CardOffset); printk_size(region.RegionSize); printk(", "); printk_size(region.BlockSize); printk(" blocks, %u ns\n", region.AccessSpeed); memset(dev->flash[i], 0, sizeof(struct flash_region_t)); dev->flash[i]->region = region; /* Distinguish between 4MB..20MB cards and 40MB cards */ if (region.RegionSize > 0x1400000) dev->flash[i]->cell_size = 0x800000; /* 8MB components */ else dev->flash[i]->cell_size = 0x400000; /* 4MB components */ i++; ret = CardServices(GetNextRegion, handle, ®ion); } } dev->flash[i] = NULL; } /* flash_config *//*====================================================================== After a card is removed, flash_release() will release the memory window allocated for this socket. ======================================================================*/static void flash_release(u_long arg){ dev_link_t *link = (dev_link_t *)arg; flash_dev_t *dev = link->priv; int i; DEBUG(0, "iflash2+_mtd: flash_release(0x%p)\n", link); link->state &= ~DEV_CONFIG; if (link->win) { iounmap(dev->Base); i = MTDHelperEntry(MTDReleaseWindow, link->win); if (i != CS_SUCCESS) cs_error(link->handle, ReleaseWindow, i); } if (dev->ESRwin) { iounmap(dev->ESRbase); i = MTDHelperEntry(MTDReleaseWindow, dev->ESRwin); if (i != CS_SUCCESS) cs_error(link->handle, ReleaseWindow, i); } if (dev->vpp_usage == 0) del_timer(&dev->vpp_timeout); vpp_off((u_long)link); for (i = 0; (i < 2*CISTPL_MAX_DEVICES) && dev->flash[i]; i++) kfree(dev->flash[i]); if (link->state & DEV_STALE_LINK) flash_detach(link); } /* flash_release *//*====================================================================== The read request handler. This handler supports suspending current erase requests. Reading from a block that is currently erasing is undefined. ======================================================================*/static int flash_read(dev_link_t *link, char *buf, mtd_request_t *req){ flash_dev_t *dev = (flash_dev_t *)link->priv; flash_region_t *flash; region_info_t *region; mtd_mod_win_t mod; u_int from, length, nb, cell; int ret;#ifdef BENCHMARK u_long time;#endif DEBUG(2, "iflash2+_mtd: flash_read(0x%p, 0x%lx, 0x%p, 0x%x, " "0x%x)\n", link, req->MediaID, buf, req->SrcCardOffset, req->TransferLength); flash = (flash_region_t *)(req->MediaID); region = &flash->region; if ((req->SrcCardOffset / region->BlockSize) != ((req->SrcCardOffset+req->TransferLength-1) / region->BlockSize)) return CS_BAD_SIZE; if (region->Attributes & REGION_TYPE_AM) mod.Attributes = WIN_MEMORY_TYPE_AM; else mod.Attributes = WIN_MEMORY_TYPE_CM; mod.AccessSpeed = region->AccessSpeed; /* Suspend an in-progress block erase */ cell = (req->SrcCardOffset - region->CardOffset) / flash->cell_size; if (flash->cell[cell].state & FLASH_ERASING) { if ((flash->cell[cell].erase_addr / region->BlockSize) == (req->SrcCardOffset / region->BlockSize)) { DEBUG(1, "iflash2+_mtd: delaying read...\n"); req->Status = MTD_WAITREQ; return CS_BUSY; } link->state |= DEV_BUSY; mod.CardOffset = flash->cell[cell].erase_addr; ret = MTDHelperEntry(MTDModifyWindow, dev->ESRwin, &mod); if (ret != CS_SUCCESS) goto done; ret = suspend_erase((u_short *)dev->ESRbase); if (ret != CS_SUCCESS) goto done; flash->cell[cell].state |= FLASH_ERASE_SUSPEND; } else link->state |= DEV_BUSY; mod.CardOffset = req->SrcCardOffset & ~(dev->Size-1); from = req->SrcCardOffset & (dev->Size-1); ret = CS_SUCCESS;#ifdef BENCHMARK time = uticks();#endif for (length = req->TransferLength; length > 0; length -= nb) { ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod); if (ret != CS_SUCCESS) goto done; nb = (from+length > dev->Size) ? dev->Size-from : length; if (req->Function & MTD_REQ_KERNEL) copy_from_pc(buf, &dev->Base[from], nb); else copy_pc_to_user(buf, &dev->Base[from], nb); buf += nb; from = 0; mod.CardOffset += dev->Size; } #ifdef BENCHMARK time = uticks() - time; if (time < 10000000) DEBUG(3, "iflash2+_mtd: read complete, time = %ld," " avg = %ld ns/word, rate = %ld kb/sec\n", time, time*2000/req->TransferLength, req->TransferLength*977/time);#endif done: if (flash->cell[cell].state & FLASH_ERASE_SUSPEND) { resume_erase((u_short *)dev->ESRbase); flash->cell[cell].state &= ~FLASH_ERASE_SUSPEND; } link->state &= ~DEV_BUSY; return ret;} /* flash_read *//*====================================================================== basic_write() handles a write that fits completely within a memory window that has already been set up. It does a series of pipelined page buffer writes. ======================================================================*/static int basic_write(wait_queue_head_t *queue, char *esr, char *dest, char *buf, u_int nb, u_int is_krnl){ u_short npb; int ret; /* Enable interrupts on write complete */ ret = set_rdy_mode((u_short *)esr, IF_RDY_LEVEL); if (ret != CS_SUCCESS) return ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -