0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/module.h>
0013 #include <linux/slab.h>
0014 #include <linux/ioport.h>
0015 #include <linux/vmalloc.h>
0016 #include <linux/mm.h>
0017 #include <linux/init.h>
0018 #include <linux/mtd/mtd.h>
0019 #include <linux/mtd/mtdram.h>
0020
0021 static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
0022 static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
0023 static unsigned long writebuf_size = 64;
0024 #define MTDRAM_TOTAL_SIZE (total_size * 1024)
0025 #define MTDRAM_ERASE_SIZE (erase_size * 1024)
0026
0027 module_param(total_size, ulong, 0);
0028 MODULE_PARM_DESC(total_size, "Total device size in KiB");
0029 module_param(erase_size, ulong, 0);
0030 MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
0031 module_param(writebuf_size, ulong, 0);
0032 MODULE_PARM_DESC(writebuf_size, "Device write buf size in Bytes (Default: 64)");
0033
0034
0035 static struct mtd_info *mtd_info;
0036
0037 static int check_offs_len(struct mtd_info *mtd, loff_t ofs, uint64_t len)
0038 {
0039 int ret = 0;
0040
0041
0042 if (mtd_mod_by_eb(ofs, mtd)) {
0043 pr_debug("%s: unaligned address\n", __func__);
0044 ret = -EINVAL;
0045 }
0046
0047
0048 if (mtd_mod_by_eb(len, mtd)) {
0049 pr_debug("%s: length not block aligned\n", __func__);
0050 ret = -EINVAL;
0051 }
0052
0053 return ret;
0054 }
0055
0056 static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
0057 {
0058 if (check_offs_len(mtd, instr->addr, instr->len))
0059 return -EINVAL;
0060 memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
0061
0062 return 0;
0063 }
0064
0065 static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
0066 size_t *retlen, void **virt, resource_size_t *phys)
0067 {
0068 *virt = mtd->priv + from;
0069 *retlen = len;
0070
0071 if (phys) {
0072
0073 unsigned long page_ofs = offset_in_page(*virt);
0074 void *addr = *virt - page_ofs;
0075 unsigned long pfn1, pfn0 = vmalloc_to_pfn(addr);
0076
0077 *phys = __pfn_to_phys(pfn0) + page_ofs;
0078 len += page_ofs;
0079 while (len > PAGE_SIZE) {
0080 len -= PAGE_SIZE;
0081 addr += PAGE_SIZE;
0082 pfn0++;
0083 pfn1 = vmalloc_to_pfn(addr);
0084 if (pfn1 != pfn0) {
0085 *retlen = addr - *virt;
0086 break;
0087 }
0088 }
0089 }
0090
0091 return 0;
0092 }
0093
0094 static int ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
0095 {
0096 return 0;
0097 }
0098
0099 static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
0100 size_t *retlen, u_char *buf)
0101 {
0102 memcpy(buf, mtd->priv + from, len);
0103 *retlen = len;
0104 return 0;
0105 }
0106
0107 static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
0108 size_t *retlen, const u_char *buf)
0109 {
0110 memcpy((char *)mtd->priv + to, buf, len);
0111 *retlen = len;
0112 return 0;
0113 }
0114
0115 static void __exit cleanup_mtdram(void)
0116 {
0117 if (mtd_info) {
0118 mtd_device_unregister(mtd_info);
0119 vfree(mtd_info->priv);
0120 kfree(mtd_info);
0121 }
0122 }
0123
0124 int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
0125 unsigned long size, const char *name)
0126 {
0127 memset(mtd, 0, sizeof(*mtd));
0128
0129
0130 mtd->name = name;
0131 mtd->type = MTD_RAM;
0132 mtd->flags = MTD_CAP_RAM;
0133 mtd->size = size;
0134 mtd->writesize = 1;
0135 mtd->writebufsize = writebuf_size;
0136 mtd->erasesize = MTDRAM_ERASE_SIZE;
0137 mtd->priv = mapped_address;
0138
0139 mtd->owner = THIS_MODULE;
0140 mtd->_erase = ram_erase;
0141 mtd->_point = ram_point;
0142 mtd->_unpoint = ram_unpoint;
0143 mtd->_read = ram_read;
0144 mtd->_write = ram_write;
0145
0146 if (mtd_device_register(mtd, NULL, 0))
0147 return -EIO;
0148
0149 return 0;
0150 }
0151
0152 static int __init init_mtdram(void)
0153 {
0154 void *addr;
0155 int err;
0156
0157 if (!total_size)
0158 return -EINVAL;
0159
0160
0161 mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
0162 if (!mtd_info)
0163 return -ENOMEM;
0164
0165 addr = vmalloc(MTDRAM_TOTAL_SIZE);
0166 if (!addr) {
0167 kfree(mtd_info);
0168 mtd_info = NULL;
0169 return -ENOMEM;
0170 }
0171 err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device");
0172 if (err) {
0173 vfree(addr);
0174 kfree(mtd_info);
0175 mtd_info = NULL;
0176 return err;
0177 }
0178 memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
0179 return err;
0180 }
0181
0182 module_init(init_mtdram);
0183 module_exit(cleanup_mtdram);
0184
0185 MODULE_LICENSE("GPL");
0186 MODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>");
0187 MODULE_DESCRIPTION("Simulated MTD driver for testing");