📄 iflash2+_mtd.c
字号:
/* Fix for mis-aligned writes */ if ((u_long)dest & 1) { DEBUG(2, "iflash2+_mtd: odd address fixup at 0x%p\n", dest); ret = page_setup(queue, (u_short *)esr, (u_short *)dest, 1); if (ret != CS_SUCCESS) return ret; if (is_krnl) writeb(*buf, dest); else { char c; get_user(c, buf); writeb(c, dest); } ret = page_write((u_short *)esr, (u_short *)dest, 1); if (ret != CS_SUCCESS) return ret; dest++; buf++; nb--; } for (; nb > 0; nb -= npb) { /* npb = # of bytes to write to page buffer */ npb = (nb > 512) ? 512 : nb; /* sleep until page buffer is free */ ret = page_setup(queue, (u_short *)esr, (u_short *)dest, npb); if (ret != CS_SUCCESS) return ret; if (is_krnl) copy_to_pc(dest, buf, npb); else copy_user_to_pc(dest, buf, npb); ret = page_write((u_short *)esr, (u_short *)dest, npb); if (ret != CS_SUCCESS) return ret; check_write(queue, (u_short *)esr); dest += npb; buf += npb; } /* sleep until block is ready */ return check_write(queue, (u_short *)esr);} /*====================================================================== The write request handler. The Series 2+ cards support automatic erase suspend for writes. ======================================================================*/static int flash_write(dev_link_t *link, char *buf, mtd_request_t *req){ flash_dev_t *dev = (flash_dev_t *)link->priv; mtd_mod_win_t mod; mtd_rdy_req_t rdy; flash_region_t *flash; region_info_t *region; u_int from, length, nb, retry, cell; cs_status_t status; int ret;#ifdef BENCHMARK u_long time;#endif DEBUG(2, "iflash2+_mtd: flash_write(0x%p, 0x%lx, " "0x%p, 0x%x, 0x%x)\n", link, req->MediaID, buf, req->DestCardOffset, req->TransferLength); /* Check card write protect status */ ret = CardServices(GetStatus, link->handle, &status); if (ret != CS_SUCCESS) { cs_error(link->handle, GetStatus, ret); return CS_GENERAL_FAILURE; } if (status.CardState & CS_EVENT_WRITE_PROTECT) return CS_WRITE_PROTECTED; flash = (flash_region_t *)(req->MediaID); region = &flash->region; if ((req->DestCardOffset / region->BlockSize) != ((req->DestCardOffset+req->TransferLength-1) / region->BlockSize)) return CS_BAD_SIZE; if (vpp_setup(link, req) != 0) return CS_BUSY; /* Is this cell being erased or written? */ cell = (req->DestCardOffset - region->CardOffset) / flash->cell_size; if (flash->cell[cell].state & FLASH_ERASING) { DEBUG(1, "iflash2+_mtd: delaying write...\n"); req->Status = MTD_WAITREQ; return CS_BUSY; } link->state |= DEV_BUSY; if (region->Attributes & REGION_TYPE_AM) mod.Attributes = WIN_MEMORY_TYPE_AM; else mod.Attributes = WIN_MEMORY_TYPE_CM; mod.AccessSpeed = region->AccessSpeed; /* Set up window for ESR accesses */ mod.CardOffset = req->DestCardOffset & ~(region->BlockSize-1); ret = MTDHelperEntry(MTDModifyWindow, dev->ESRwin, &mod); if (ret != CS_SUCCESS) goto done; rdy.Mask = CS_EVENT_READY_CHANGE; MTDHelperEntry(MTDRDYMask, link->handle, &rdy);#ifdef BENCHMARK time = uticks();#endif mod.CardOffset = req->DestCardOffset & ~(dev->Size-1); from = req->DestCardOffset & (dev->Size-1); 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; for (retry = 0; retry < retry_limit; retry++) { ret = basic_write(&link->pending, dev->ESRbase, dev->Base+from, buf, nb, (req->Function & MTD_REQ_KERNEL)); if (ret == CS_SUCCESS) break; abort_cmd((u_short *)dev->ESRbase); } if (retry == retry_limit) { printk(KERN_NOTICE "iflash2+_mtd: write at 0x%06x failed:" " too many retries!\n", mod.CardOffset); goto done; } buf += nb; from = 0; mod.CardOffset += dev->Size; }#ifdef BENCHMARK time = uticks() - time; if (time < 10000000) DEBUG(3, "iflash2+_mtd: write complete, time = %ld," " avg = %ld us/word, rate = %ld kb/sec\n", time, time*2/req->TransferLength, req->TransferLength*977/time);#endif done: reset_block((u_short *)dev->ESRbase); rdy.Mask = 0; MTDHelperEntry(MTDRDYMask, link->handle, &rdy); link->state &= ~DEV_BUSY; /* Fire up the Vpp timer */ vpp_shutdown(link); return ret;} /* flash_write *//*====================================================================== The erase request handler. This handler supports simultaneous erases in different device components. ======================================================================*/static int flash_erase(dev_link_t *link, mtd_request_t *req){ flash_dev_t *dev = (flash_dev_t *)link->priv; cs_status_t status; flash_region_t *flash; region_info_t *region; mtd_mod_win_t mod; int i, ret; DEBUG(2, "iflash2+_mtd: flash_erase(0x%p, 0x%lx, 0x%x, 0x%x)\n", link, req->MediaID, req->DestCardOffset, req->TransferLength); flash = (flash_region_t *)(req->MediaID); region = &flash->region; if (region->BlockSize != req->TransferLength) return CS_BAD_SIZE; i = (req->DestCardOffset-region->CardOffset)/flash->cell_size; if (!(req->Function & MTD_REQ_TIMEOUT)) { if (flash->cell[i].state & (FLASH_ERASING|FLASH_PENDING)) { DEBUG(1, "iflash2+_mtd: delaying erase...\n"); req->Status = MTD_WAITREQ; return CS_BUSY; } /* Check card write protect status */ ret = CardServices(GetStatus, link->handle, &status); if (ret != CS_SUCCESS) { cs_error(link->handle, GetStatus, ret); return CS_GENERAL_FAILURE; } if (status.CardState & CS_EVENT_WRITE_PROTECT) return CS_WRITE_PROTECTED; flash->cell[i].state |= FLASH_PENDING; /* Activate Vpp if necessary */ if (vpp_setup(link, req) != 0) return CS_BUSY; } if (region->Attributes & REGION_TYPE_AM) mod.Attributes = WIN_MEMORY_TYPE_AM; else mod.Attributes = WIN_MEMORY_TYPE_CM; mod.AccessSpeed = region->AccessSpeed; mod.CardOffset = req->DestCardOffset; ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod); if (ret != CS_SUCCESS) goto done; if (flash->cell[i].state & FLASH_PENDING) { /* Start a new block erase */ flash->cell[i].state &= ~FLASH_PENDING; flash->cell[i].state |= FLASH_ERASING; flash->cell[i].erase_addr = mod.CardOffset; flash->cell[i].erase_time = jiffies; flash->cell[i].erase_retries = 0; set_global_lock(dev->ESRwin, dev->ESRbase, 0); /* Disable busy signal during the erase */ set_rdy_mode((u_short *)dev->Base, IF_RDY_DISABLE); block_erase((u_short *)dev->Base); } else { /* Check on an already started erase */ ret = check_erase((u_short *)dev->Base); if (ret == CS_SUCCESS) goto done; else if (ret != CS_BUSY) { if (++flash->cell[i].erase_retries > retry_limit) { printk(KERN_NOTICE "iflash2+_mtd: erase failed: " "too many retries!\n"); goto done; } else { flash->cell[i].erase_time = jiffies; abort_cmd((u_short *)dev->Base); block_erase((u_short *)dev->Base); } } } /* If the request is not complete, has it taken too long? */ if (jiffies > flash->cell[i].erase_time + erase_limit) { printk(KERN_NOTICE "iflash2+_mtd: erase timed out!\n"); log_esr(NULL, (u_short *)dev->Base); abort_cmd((u_short *)dev->Base); ret = CS_GENERAL_FAILURE; goto done; } req->Status = MTD_WAITTIMER; req->Timeout = erase_timeout; return CS_BUSY; done: DEBUG(2, "iflash2+_mtd: erase complete, time = %ld\n", jiffies - flash->cell[i].erase_time); flash->cell[i].state &= ~(FLASH_ERASING|FLASH_PENDING); reset_block((u_short *)dev->ESRbase); set_global_lock(dev->ESRwin, dev->ESRbase, 1); vpp_shutdown(link); return ret;} /* flash_erase */ /*====================================================================*/static int flash_request(dev_link_t *link, void *buf, mtd_request_t *req){ int ret = 0; if (!(link->state & DEV_PRESENT)) return CS_NO_CARD; if (link->state & DEV_BUSY) { /* We do this because the erase routine uses the TIMEOUT flag to decide if this is a new request or a status check, so we need to propagate it */ if (req->Function & MTD_REQ_TIMEOUT) { req->Timeout = erase_timeout; req->Status = MTD_WAITTIMER; } else req->Status = MTD_WAITREQ; return CS_BUSY; } switch (req->Function & MTD_REQ_ACTION) { case MTD_REQ_READ: ret = flash_read(link, buf, req); break; case MTD_REQ_WRITE: ret = flash_write(link, buf, req); break; case MTD_REQ_ERASE: ret = flash_erase(link, req); break; case MTD_REQ_COPY: ret = CS_UNSUPPORTED_FUNCTION; break; } if (!(link->state & DEV_PRESENT)) return CS_GENERAL_FAILURE; return ret;} /* flash_request *//*====================================================================== The card status event handler. Mostly, this schedules other stuff to run after an event is received. A CARD_REMOVAL event also sets some flags to discourage the driver from trying to talk to the card any more. ======================================================================*/static int flash_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; DEBUG(3, "iflash2+_mtd: flash_event(0x%06x)\n", event); switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) mod_timer(&link->release, jiffies + HZ/20); break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; flash_config(link); break; case CS_EVENT_READY_CHANGE: wake_up_interruptible(&link->pending); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: break; case CS_EVENT_MTD_REQUEST: return flash_request(link, args->buffer, args->mtdrequest); break; } return CS_SUCCESS;} /* flash_event *//*====================================================================*/static int __init init_iflash2x_mtd(void){ servinfo_t serv; DEBUG(0, "%s\n", version); /* Rescale parameters */ vpp_timeout_period = (vpp_timeout_period * HZ) / 1000; vpp_settle = (vpp_settle * HZ) / 1000; write_timeout = (write_timeout * HZ) / 1000; erase_limit = (erase_limit * HZ) / 1000; CardServices(GetCardServicesInfo, &serv); if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_NOTICE "iflash2+_mtd: Card Services release " "does not match!\n"); return -1; } register_pccard_driver(&dev_info, &flash_attach, &flash_detach); return 0;}static void __exit exit_iflash2x_mtd(void){ DEBUG(0, "iflash2+_mtd: unloading\n"); unregister_pccard_driver(&dev_info); while (dev_list != NULL) flash_detach(dev_list);}module_init(init_iflash2x_mtd);module_exit(exit_iflash2x_mtd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -