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

📄 iflash2_mtd.c

📁 pcmcia source code
💻 C
📖 第 1 页 / 共 2 页
字号:
	    printk(", ");	    printk_size(region.BlockSize);	    printk(" blocks, %u ns\n", region.AccessSpeed);	    memset(dev->flash[i], 0, sizeof(struct flash_region_t));	    /* Assume 128K blocks, if no geometry info present */	    if (region.BlockSize == 1)		region.BlockSize = 0x20000;	    dev->flash[i]->region = region;	    /* If not Series 100, then we'll use Vpp=12V */	    if (region.JedecInfo != 0xaa) dev->vpp = 120;	    /* All Series 2 cards have 2MB component pairs */	    dev->flash[i]->cell_size = 0x200000;	    i++;	    ret = CardServices(GetNextRegion, handle, &region);	}    }    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->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;    u_long time;    int ret;        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)) {	    req->Status = MTD_WAITREQ;	    return CS_BUSY;	}	link->state |= DEV_BUSY;	mod.CardOffset = flash->cell[cell].erase_addr;	ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);	if (ret != CS_SUCCESS) goto done;	ret = suspend_erase((u_short *)dev->Base);	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;    time = jiffies;    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 PCMCIA_DEBUG    time = jiffies - time;    if (time > 1)	DEBUG(3, "iflash2_mtd: read complete, time = %ld, "	      "avg = %ld ns/word, rate = %ld kb/sec\n", time,	      time*20000000/req->TransferLength,	      req->TransferLength*100/(time*1024));#endif    done:    if (flash->cell[cell].state & FLASH_ERASE_SUSPEND) {	mod.CardOffset = flash->cell[cell].erase_addr;	ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);	if (ret == CS_SUCCESS)	    resume_erase((u_short *)dev->Base);	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.    ======================================================================*/static int basic_write(char *dest, char *buf,		       u_int nb, u_int is_krnl){    char *start = dest;    int ret;        *(u_short *)dest = IF_READ_CSR;    if (is_krnl) {	if (nb & 1) {	    ret = byte_write(dest, *buf);	    if (ret != CS_SUCCESS) return ret;		dest++; buf++; nb--;	}	for (; nb != 0; dest += 2, buf += 2, nb -= 2) {	    ret = word_write((u_short *)dest, *(u_short *)buf);	    if (ret != CS_SUCCESS) return ret;	}    } else {	if (nb & 1) {	    char c;	    get_user(c, buf);	    ret = byte_write(dest, c);	    if (ret != CS_SUCCESS) return ret;	    dest++; buf++; nb--;	}	for (; nb != 0; dest += 2, buf += 2, nb -= 2) {	    u_short s;	    get_user(s, (u_short *)buf);	    ret = word_write((u_short *)dest, s);	    if (ret != CS_SUCCESS) return ret;	}    }    return check_write((u_short *)start);	} /* basic_write *//*======================================================================    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;    flash_region_t *flash;    region_info_t *region;    u_int from, length, nb, retry, cell;    u_long time;    cs_status_t status;    int ret;    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? */    cell = (req->DestCardOffset - region->CardOffset) / flash->cell_size;    if (flash->cell[cell].state & FLASH_ERASING) {	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;    time = jiffies;    mod.CardOffset = req->DestCardOffset & ~(dev->Size-1);    from = req->DestCardOffset & (dev->Size-1);        for (length = req->TransferLength ; length > 0; length -= nb) {	nb = (from+length > dev->Size) ? dev->Size-from : length;	ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);	if (ret != CS_SUCCESS) goto done;	for (retry = 0; retry < retry_limit; retry++) {	    ret = basic_write(dev->Base+from, buf, nb,			      (req->Function & MTD_REQ_KERNEL));	    if (ret == CS_SUCCESS)		break;	    abort_cmd(link, dev->Base, cell, &mod);	}	if (retry == retry_limit) {	    printk(KERN_NOTICE "iflash2_mtd: write failed: "		   "too many retries!\n");	    goto done;	}		buf += nb;	from = 0;	mod.CardOffset += dev->Size;    }#ifdef PCMCIA_DEBUG    time = jiffies - time;    if (time > 1)	DEBUG(3, "iflash2_mtd: write complete, time = %ld, "	      "avg = %ld us/word, rate = %ld kb/sec\n", time,	      time*20000/req->TransferLength,	      req->TransferLength*100/(time*1024));#endif    done:    reset_block((u_short *)dev->Base);    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)) {	    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;	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(link, dev->Base, i, &mod);		reset_block((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");	reset_block((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->Base);    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(1, "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_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_iflash2_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;    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_iflash2_mtd(void){    DEBUG(0, "iflash2_mtd: unloading\n");    unregister_pccard_driver(&dev_info);    while (dev_list != NULL)	flash_detach(dev_list);}module_init(init_iflash2_mtd);module_exit(exit_iflash2_mtd);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -