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

📄 iflash2+_mtd.c

📁 pcmcia source code
💻 C
📖 第 1 页 / 共 3 页
字号:
    /* 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 + -