📄 memory_cs.c
字号:
win_req_t req; int nd, i, last_ret, last_fn, attr, ret, nr[2]; DEBUG(0, "memory_config(0x%p)\n", link); /* Configure card */ link->state |= DEV_CONFIG; for (nd = 0; nd < MAX_DEV; nd++) if (dev_table[nd] == link) break; /* Allocate a small memory window for direct access */ req.Attributes = WIN_WIDTH(word_width); req.Base = req.Size = 0; req.AccessSpeed = mem_speed; link->win = (window_handle_t)link->handle; CS_CHECK(RequestWindow, &link->win, &req); /* Get write protect status */ CS_CHECK(GetStatus, link->handle, &status); dev->direct.Base = ioremap(req.Base, req.Size); dev->direct.Size = req.Size; dev->direct.cardsize = 0; for (attr = 0; attr < 2; attr++) { nr[attr] = 0; minor = dev->minor + attr*MAX_PART; region.Attributes = (attr) ? REGION_TYPE_AM : REGION_TYPE_CM; ret = CardServices(GetFirstRegion, link->handle, ®ion); while (ret == CS_SUCCESS) { minor->region = region; minor++; nr[attr]++; ret = CardServices(GetNextRegion, link->handle, ®ion); } } sprintf(dev->node.dev_name, "mem%d", nd); dev->node.major = major_dev; dev->node.minor = MINOR_NR(nd, 0, 0, 0); link->dev = &dev->node;#ifdef CISTPL_FORMAT_MEM /* This is a hack, not a complete solution */ { cisinfo_t info; tuple_t tuple; cisparse_t parse; u_char buf[64]; tuple.Attributes = 0; tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_FORMAT; if ((CardServices(ValidateCIS, &info) == CS_SUCCESS) && (info.Chains > 0) && (CardServices(GetFirstTuple, link->handle, &tuple) == CS_SUCCESS)) { CS_CHECK(GetTupleData, link->handle, &tuple); CS_CHECK(ParseTuple, link->handle, &tuple, &parse); dev->direct.offset = dev->minor[0].offset = parse.format.offset; } }#endif printk(KERN_INFO "memory_cs: mem%d:", nd); if ((nr[0] == 0) && (nr[1] == 0)) { cisinfo_t cisinfo; if ((CardServices(ValidateCIS, link->handle, &cisinfo) == CS_SUCCESS) && (cisinfo.Chains == 0)) { dev->direct.cardsize = force_size ? force_size : get_size(link,&dev->direct); printk(" anonymous: "); if (dev->direct.cardsize == 0) { dev->direct.cardsize = HIGH_ADDR; printk("unknown size"); } else { print_size(dev->direct.cardsize); } } else { printk(" no regions found."); } } else { for (attr = 0; attr < 2; attr++) { minor = dev->minor + attr*MAX_PART; if (attr && nr[0] && nr[1]) printk(","); if (nr[attr]) printk(" %s", attr ? "attribute" : "common"); for (i = 0; i < nr[attr]; i++) { printk(" "); print_size(minor[i].region.RegionSize); } } } printk("\n"); link->state &= ~DEV_CONFIG_PENDING; return;cs_failed: cs_error(link->handle, last_fn, last_ret); memory_release((u_long)link); link->state &= ~DEV_CONFIG_PENDING;} /* memory_config *//*====================================================================== After a card is removed, memory_release() will unregister the device, and release the PCMCIA configuration. If the device is still open, this will be postponed until it is closed. ======================================================================*/static void memory_release(u_long arg){ dev_link_t *link = (dev_link_t *)arg; int nd; DEBUG(0, "memory_release(0x%p)\n", link); for (nd = 0; nd < MAX_DEV; nd++) if (dev_table[nd] == link) break; if (link->open) { DEBUG(0, "memory_cs: release postponed, 'mem%d'" " still open\n", nd); link->state |= DEV_STALE_CONFIG; return; } link->dev = NULL; if (link->win) { memory_dev_t *dev = link->priv; iounmap(dev->direct.Base); CardServices(ReleaseWindow, link->win); } link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) memory_detach(link); } /* memory_release *//*====================================================================== 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 memory_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; memory_dev_t *dev = link->priv; eraseq_entry_t *erase; DEBUG(1, "memory_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; memory_config(link); break; case CS_EVENT_ERASE_COMPLETE: erase = (eraseq_entry_t *)(args->info); wake_up((wait_queue_head_t *)&erase->Optional); wake_up_interruptible(&dev->erase_pending); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: /* get_lock(link); */ break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: /* free_lock(link); */ break; } return 0;} /* memory_event *//*====================================================================== This gets a memory handle for the region corresponding to the minor device number. ======================================================================*/static int memory_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); dev_link_t *link; memory_dev_t *dev; minor_dev_t *minor_dev; open_mem_t open; int ret; DEBUG(0, "memory_open(%d)\n", minor); link = dev_table[DEVICE_NR(minor)]; if (!DEV_OK(link)) return -ENODEV; dev = (memory_dev_t *)link->priv; if (IS_DIRECT(minor) || (dev->direct.cardsize > 0)) { if ((file->f_mode & 2) && (dev->direct.flags & MEM_WRPROT)) return -EROFS; dev->direct.open++; file->private_data = NULL; } else { minor_dev = &dev->minor[REGION_NR(minor)]; if (minor_dev->region.RegionSize == 0) return -ENODEV; if (minor_dev->handle == NULL) { minor_dev->handle = (memory_handle_t)link->handle; open.Attributes = minor_dev->region.Attributes; open.Offset = minor_dev->region.CardOffset; ret = CardServices(OpenMemory, &minor_dev->handle, &open); if (ret != CS_SUCCESS) return -ENOMEM; } minor_dev->open++; file->private_data = minor_dev; } link->open++; MOD_INC_USE_COUNT; return 0;} /* memory_open *//*====================================================================*/static FS_RELEASE_T memory_close(struct inode *inode, struct file *file){ dev_link_t *link; int minor = MINOR(inode->i_rdev); memory_dev_t *dev; minor_dev_t *minor_dev; DEBUG(0, "memory_close(%d)\n", minor); link = dev_table[DEVICE_NR(minor)]; dev = (memory_dev_t *)link->priv; if (IS_DIRECT(minor) || (dev->direct.cardsize > 0)) { dev->direct.open--; } else { minor_dev = &dev->minor[REGION_NR(minor)]; minor_dev->open--; if (minor_dev->open == 0) { CardServices(CloseMemory, minor_dev->handle); minor_dev->handle = NULL; } } link->open--; MOD_DEC_USE_COUNT; return (FS_RELEASE_T)0;} /* memory_close */static FS_RELEASE_T memory_blk_close(struct inode *inode, struct file *file){ fsync_dev(inode->i_rdev); INVALIDATE_INODES(inode->i_rdev); invalidate_buffers(inode->i_rdev); return memory_close(inode, file);}/*====================================================================== Read for character-mode device ======================================================================*/static ssize_t direct_read FOPS(struct inode *inode, struct file *file, char *buf, size_t count, loff_t *ppos){ int minor = MINOR(F_INODE(file)->i_rdev); dev_link_t *link; memory_dev_t *dev; direct_dev_t *direct; size_t size, pos, read, from, nb; int ret; modwin_t mod; memreq_t mem; DEBUG(2, "direct_read(%d, 0x%lx, %ld)\n", minor, (u_long)FPOS, (u_long)count); link = dev_table[DEVICE_NR(minor)]; if (!DEV_OK(link)) return -ENODEV; dev = (memory_dev_t *)link->priv; direct = &dev->direct; /* Boundary checks */ pos = FPOS; size = (IS_DIRECT(minor)) ? HIGH_ADDR : direct->cardsize; if (pos >= size) return 0; if (count > size - pos) count = size - pos; mod.Attributes = WIN_ENABLE | WIN_TYPE(REGION_AM(minor)); mod.Attributes |= WIN_WIDTH(word_width); mod.AccessSpeed = mem_speed; ret = CardServices(ModifyWindow, link->win, &mod); if (ret != CS_SUCCESS) { cs_error(link->handle, ModifyWindow, ret); return -EIO; } mem.CardOffset = pos & ~(direct->Size-1); mem.Page = 0; from = pos & (direct->Size-1); for (read = 0; count > 0; count -= nb, read += nb) { ret = CardServices(MapMemPage, link->win, &mem); if (ret != CS_SUCCESS) { cs_error(link->handle, MapMemPage, ret); return -EIO; } nb = (from+count > direct->Size) ? direct->Size-from : count; copy_pc_to_user(buf, direct->Base+from, nb); buf += nb; from = 0; mem.CardOffset += direct->Size; } FPOS += read; return read;} /* direct_read */static ssize_t memory_read FOPS(struct inode *inode, struct file *file, char *buf, size_t count, loff_t *ppos){ minor_dev_t *minor; mem_op_t req; int ret; minor = file->private_data; if (minor == NULL) return direct_read FOPS(inode, file, buf, count, ppos); DEBUG(2, "memory_read(0x%p, 0x%lx, %ld)\n", minor->handle, (u_long)FPOS, (u_long)count); req.Attributes = MEM_OP_BUFFER_USER; req.Offset = FPOS; req.Count = count; ret = CardServices(ReadMemory, minor->handle, &req, buf); if (ret == CS_SUCCESS) { FPOS += count; return count; } else if (ret == CS_BAD_OFFSET) return 0; else return -EIO;} /* memory_read *//*====================================================================== Erase a memory region. This is used by the write routine for suitably aligned and sized blocks. It is also used for the MEMERASE ioctl(). ======================================================================*/static int memory_erase(int minor, u_long f_pos, size_t count){ dev_link_t *link = dev_table[DEVICE_NR(minor)]; memory_dev_t *dev = link->priv; minor_dev_t *minor_dev = &dev->minor[REGION_NR(minor)]; int i, ret; DEBUG(2, "memory_erase(%d, 0x%lx, %ld)\n", minor, f_pos, (u_long)count);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -