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

📄 iflash2+_mtd.c

📁 pcmcia source code
💻 C
📖 第 1 页 / 共 3 页
字号:
    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, &region);	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, &reg);	    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, &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->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 + -