📄 memory_cs.c
字号:
/* Find a free erase slot, or wait for one to become available */ for (;;) { for (i = 0; i < MAX_ERASE; i++) if (!ERASE_IN_PROGRESS(dev->eraseq[i].State)) break; if (i < MAX_ERASE) break; DEBUG(2, "waiting for erase slot...\n"); interruptible_sleep_on(&dev->erase_pending); if (signal_pending(current)) return -ERESTARTSYS; } /* Queue a new request */ init_waitqueue_head((wait_queue_head_t *)&dev->eraseq[i].Optional); dev->eraseq[i].State = ERASE_QUEUED; dev->eraseq[i].Handle = minor_dev->handle; dev->eraseq[i].Offset = f_pos; dev->eraseq[i].Size = count; ret = CardServices(CheckEraseQueue, dev->eraseq_handle); if (ret != CS_SUCCESS) { cs_error(link->handle, CheckEraseQueue, ret); return -EIO; } /* Wait for request to complete */ if (ERASE_IN_PROGRESS(dev->eraseq[i].State)) sleep_on((wait_queue_head_t *)&dev->eraseq[i].Optional); if (dev->eraseq[i].State != ERASE_PASSED) return -EIO; return 0;}/*====================================================================== Write for character-mode device ======================================================================*/static ssize_t direct_write FOPS(struct inode *inode, struct file *file, const 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, wrote, to, nb; int ret; modwin_t mod; memreq_t mem; DEBUG(2, "direct_write(%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; /* Check for write protect */ if (direct->flags & MEM_WRPROT) return -EROFS; /* Boundary checks */ size = (IS_DIRECT(minor)) ? HIGH_ADDR : direct->cardsize; pos = FPOS; if (pos >= size) return -ENOSPC; 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; to = pos & (direct->Size-1); for (wrote = 0; count > 0; count -= nb, wrote += nb) { ret = CardServices(MapMemPage, link->win, &mem); if (ret != CS_SUCCESS) { cs_error(link->handle, MapMemPage, ret); return -EIO; } nb = (to+count > direct->Size) ? direct->Size-to : count; copy_user_to_pc(direct->Base+to, buf, nb); buf += nb; to = 0; mem.CardOffset += direct->Size; } FPOS += wrote; return wrote;} /* direct_write */static ssize_t memory_write FOPS(struct inode *inode, struct file *file, const 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_write FOPS(inode, file, buf, count, ppos); DEBUG(2, "memory_write(0x%p, 0x%lx, %ld)\n", minor->handle, (u_long)FPOS, (u_long)count); if ((minor->region.BlockSize > 1) && ((FPOS & (minor->region.BlockSize-1)) == 0) && ((count & (minor->region.BlockSize-1)) == 0)) { ret = memory_erase(MINOR(F_INODE(file)->i_rdev), FPOS, count); if (ret != 0) return ret; } req.Attributes = 0; req.Offset = FPOS; req.Count = count; ret = CardServices(WriteMemory, minor->handle, &req, buf); if (ret == CS_SUCCESS) { FPOS += count; return count; } else return -EIO;} /* memory_write *//*====================================================================== IOCTL calls for getting device parameters.======================================================================*/static int memory_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg){ int minor = MINOR(inode->i_rdev); dev_link_t *link; memory_dev_t *dev; minor_dev_t *minor_dev; erase_info_t erase; u_int size; int ret = 0; link = dev_table[DEVICE_NR(minor)]; if (!DEV_OK(link)) return -ENODEV; dev = (memory_dev_t *)link->priv; minor_dev = &dev->minor[REGION_NR(minor)]; size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; if (cmd & IOC_IN) { ret = verify_area(VERIFY_READ, (char *)arg, size); if (ret) return ret; } if (cmd & IOC_OUT) { ret = verify_area(VERIFY_WRITE, (char *)arg, size); if (ret) return ret; } switch (cmd) { case BLKGETSIZE: if (IS_DIRECT(minor)) size = dev->direct.cardsize - dev->direct.offset; else size = minor_dev->region.RegionSize - minor_dev->offset; put_user(size/SECTOR_SIZE, (long *)arg); break; case MEMGETINFO: if (!IS_DIRECT(minor)) { copy_to_user((region_info_t *)arg, &minor_dev->region, sizeof(struct region_info_t)); } else ret = -EINVAL; break; case MEMERASE: if (!IS_DIRECT(minor)) { copy_from_user(&erase, (erase_info_t *)arg, sizeof(struct erase_info_t)); ret = memory_erase(minor, erase.Offset, erase.Size); } else ret = -EINVAL; break;#if (LINUX_VERSION_CODE < VERSION(2,3,3)) case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!(inode->i_rdev)) return -EINVAL; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); break;#else case BLKROSET: case BLKROGET: case BLKFLSBUF: ret = blk_ioctl(inode->i_rdev, cmd, arg); break;#endif default: ret = -EINVAL; } return ret;} /* memory_ioctl *//*====================================================================== Handler for block device requests ======================================================================*/static void do_direct_request(dev_link_t *link){ memory_dev_t *dev = link->priv; int addr, len, from, nb, ret; char *buf; direct_dev_t *direct; modwin_t mod; memreq_t mem; direct = &dev->direct; addr = CURRENT->sector * SECTOR_SIZE + direct->offset; len = CURRENT->current_nr_sectors * SECTOR_SIZE; if ((addr + len) > direct->cardsize) { end_request(0); return; } mod.Attributes = WIN_ENABLE | WIN_MEMORY_TYPE_CM; 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); end_request(0); return; } buf = CURRENT->buffer; mem.Page = 0; mem.CardOffset = addr & ~(direct->Size-1); from = addr & (direct->Size-1); ret = 0; if ((CURRENT->cmd == READ) || (CURRENT->cmd == WRITE)) for ( ; len > 0; len -= nb, buf += nb, from = 0) { ret = CardServices(MapMemPage, link->win, &mem); if (ret != CS_SUCCESS) break; nb = (from+len > direct->Size) ? direct->Size-from : len; if (CURRENT->cmd == READ) copy_from_pc(buf, &direct->Base[from], nb); else copy_to_pc(&direct->Base[from], buf, nb); mem.CardOffset += direct->Size; } else panic("pcmem_cs: unknown block command!\n"); if (ret == CS_SUCCESS) end_request(1); else { cs_error(link->handle, MapMemPage, ret); end_request(0); }} /* do_direct_request */static void do_memory_request(request_arg_t){ int ret, minor; char *buf; mem_op_t req; dev_link_t *link; memory_dev_t *dev; minor_dev_t *minor_dev; sti(); do { INIT_REQUEST; minor = MINOR(CURRENT->rq_dev); link = dev_table[DEVICE_NR(minor)]; dev = (memory_dev_t *)link->priv; if (IS_DIRECT(minor) || (dev->direct.cardsize > 0)) { do_direct_request(link); continue; } minor_dev = &dev->minor[REGION_NR(minor)]; req.Attributes = MEM_OP_BUFFER_KERNEL; req.Offset = CURRENT->sector * SECTOR_SIZE + minor_dev->offset; req.Count = CURRENT->current_nr_sectors * SECTOR_SIZE; buf = CURRENT->buffer; ret = CS_SUCCESS; if (CURRENT->cmd == READ) { ret = CardServices(ReadMemory, minor_dev->handle, &req, buf); if (ret != CS_SUCCESS) cs_error(link->handle, ReadMemory, ret); } else if (CURRENT->cmd == WRITE) { ret = CardServices(WriteMemory, minor_dev->handle, &req, buf); if (ret != CS_SUCCESS) cs_error(link->handle, WriteMemory, ret); } else panic("memory_cs: unknown block command!\n"); if (ret == CS_SUCCESS) end_request(1); else end_request(0); } while (1);} /* do_memory_request *//*====================================================================*/static int __init init_memory_cs(void){ servinfo_t serv; int i; DEBUG(0, "%s\n", version); CardServices(GetCardServicesInfo, &serv); if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_NOTICE "memory_cs: Card Services release " "does not match!\n"); return -EINVAL; } register_pccard_driver(&dev_info, &memory_attach, &memory_detach); for (i = MAX_CHRDEV-1; i > 0; i--) { if (register_chrdev(i, "memory", &memory_chr_fops) == 0) { if (register_blkdev(i, "memory", &memory_blk_fops) == 0) break; else unregister_chrdev(i, "memory"); } } if (i == 0) { printk(KERN_NOTICE "memory_cs: unable to grab a device #\n"); return -ENODEV; } major_dev = i; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &do_memory_request); for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0, 0); i++) memory_blocksizes[i] = 1024; blksize_size[major_dev] = memory_blocksizes; return 0;}static void __exit exit_memory_cs(void){ int i; dev_link_t *link; DEBUG(0, "memory_cs: unloading\n"); unregister_pccard_driver(&dev_info); if (major_dev != 0) { unregister_chrdev(major_dev, "memory"); unregister_blkdev(major_dev, "memory"); blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); blksize_size[major_dev] = NULL; } for (i = 0; i < MAX_DEV; i++) { link = dev_table[i]; if (link) { if (link->state & DEV_CONFIG) memory_release((u_long)link); memory_detach(link); } }}module_init(init_memory_cs);module_exit(exit_memory_cs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -