0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/module.h>
0034 #include <linux/uaccess.h>
0035 #include <linux/types.h>
0036 #include <linux/kernel.h>
0037 #include <linux/ptrace.h>
0038 #include <linux/slab.h>
0039 #include <linux/string.h>
0040 #include <linux/timer.h>
0041 #include <linux/major.h>
0042 #include <linux/fs.h>
0043 #include <linux/ioctl.h>
0044 #include <linux/init.h>
0045 #include <linux/io.h>
0046
0047 #include <linux/mtd/mtd.h>
0048
0049 #define SLRAM_MAX_DEVICES_PARAMS 6
0050 #define SLRAM_BLK_SZ 0x4000
0051
0052 #define T(fmt, args...) printk(KERN_DEBUG fmt, ## args)
0053 #define E(fmt, args...) printk(KERN_NOTICE fmt, ## args)
0054
0055 typedef struct slram_priv {
0056 u_char *start;
0057 u_char *end;
0058 } slram_priv_t;
0059
0060 typedef struct slram_mtd_list {
0061 struct mtd_info *mtdinfo;
0062 struct slram_mtd_list *next;
0063 } slram_mtd_list_t;
0064
0065 #ifdef MODULE
0066 static char *map[SLRAM_MAX_DEVICES_PARAMS];
0067
0068 module_param_array(map, charp, NULL, 0);
0069 MODULE_PARM_DESC(map, "List of memory regions to map. \"map=<name>, <start>, <length / end>\"");
0070 #else
0071 static char *map;
0072 #endif
0073
0074 static slram_mtd_list_t *slram_mtdlist = NULL;
0075
0076 static int slram_erase(struct mtd_info *, struct erase_info *);
0077 static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **,
0078 resource_size_t *);
0079 static int slram_unpoint(struct mtd_info *, loff_t, size_t);
0080 static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
0081 static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
0082
0083 static int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
0084 {
0085 slram_priv_t *priv = mtd->priv;
0086
0087 memset(priv->start + instr->addr, 0xff, instr->len);
0088
0089 return(0);
0090 }
0091
0092 static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
0093 size_t *retlen, void **virt, resource_size_t *phys)
0094 {
0095 slram_priv_t *priv = mtd->priv;
0096
0097 *virt = priv->start + from;
0098 *retlen = len;
0099 return(0);
0100 }
0101
0102 static int slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
0103 {
0104 return 0;
0105 }
0106
0107 static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
0108 size_t *retlen, u_char *buf)
0109 {
0110 slram_priv_t *priv = mtd->priv;
0111
0112 memcpy(buf, priv->start + from, len);
0113 *retlen = len;
0114 return(0);
0115 }
0116
0117 static int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
0118 size_t *retlen, const u_char *buf)
0119 {
0120 slram_priv_t *priv = mtd->priv;
0121
0122 memcpy(priv->start + to, buf, len);
0123 *retlen = len;
0124 return(0);
0125 }
0126
0127
0128
0129 static int register_device(char *name, unsigned long start, unsigned long length)
0130 {
0131 slram_mtd_list_t **curmtd;
0132
0133 curmtd = &slram_mtdlist;
0134 while (*curmtd) {
0135 curmtd = &(*curmtd)->next;
0136 }
0137
0138 *curmtd = kmalloc(sizeof(slram_mtd_list_t), GFP_KERNEL);
0139 if (!(*curmtd)) {
0140 E("slram: Cannot allocate new MTD device.\n");
0141 return(-ENOMEM);
0142 }
0143 (*curmtd)->mtdinfo = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
0144 (*curmtd)->next = NULL;
0145
0146 if ((*curmtd)->mtdinfo) {
0147 (*curmtd)->mtdinfo->priv =
0148 kzalloc(sizeof(slram_priv_t), GFP_KERNEL);
0149
0150 if (!(*curmtd)->mtdinfo->priv) {
0151 kfree((*curmtd)->mtdinfo);
0152 (*curmtd)->mtdinfo = NULL;
0153 }
0154 }
0155
0156 if (!(*curmtd)->mtdinfo) {
0157 E("slram: Cannot allocate new MTD device.\n");
0158 return(-ENOMEM);
0159 }
0160
0161 if (!(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start =
0162 memremap(start, length,
0163 MEMREMAP_WB | MEMREMAP_WT | MEMREMAP_WC))) {
0164 E("slram: memremap failed\n");
0165 return -EIO;
0166 }
0167 ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end =
0168 ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start + length;
0169
0170
0171 (*curmtd)->mtdinfo->name = name;
0172 (*curmtd)->mtdinfo->size = length;
0173 (*curmtd)->mtdinfo->flags = MTD_CAP_RAM;
0174 (*curmtd)->mtdinfo->_erase = slram_erase;
0175 (*curmtd)->mtdinfo->_point = slram_point;
0176 (*curmtd)->mtdinfo->_unpoint = slram_unpoint;
0177 (*curmtd)->mtdinfo->_read = slram_read;
0178 (*curmtd)->mtdinfo->_write = slram_write;
0179 (*curmtd)->mtdinfo->owner = THIS_MODULE;
0180 (*curmtd)->mtdinfo->type = MTD_RAM;
0181 (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
0182 (*curmtd)->mtdinfo->writesize = 1;
0183
0184 if (mtd_device_register((*curmtd)->mtdinfo, NULL, 0)) {
0185 E("slram: Failed to register new device\n");
0186 memunmap(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start);
0187 kfree((*curmtd)->mtdinfo->priv);
0188 kfree((*curmtd)->mtdinfo);
0189 return(-EAGAIN);
0190 }
0191 T("slram: Registered device %s from %luKiB to %luKiB\n", name,
0192 (start / 1024), ((start + length) / 1024));
0193 T("slram: Mapped from 0x%p to 0x%p\n",
0194 ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start,
0195 ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end);
0196 return(0);
0197 }
0198
0199 static void unregister_devices(void)
0200 {
0201 slram_mtd_list_t *nextitem;
0202
0203 while (slram_mtdlist) {
0204 nextitem = slram_mtdlist->next;
0205 mtd_device_unregister(slram_mtdlist->mtdinfo);
0206 memunmap(((slram_priv_t *)slram_mtdlist->mtdinfo->priv)->start);
0207 kfree(slram_mtdlist->mtdinfo->priv);
0208 kfree(slram_mtdlist->mtdinfo);
0209 kfree(slram_mtdlist);
0210 slram_mtdlist = nextitem;
0211 }
0212 }
0213
0214 static unsigned long handle_unit(unsigned long value, char *unit)
0215 {
0216 if ((*unit == 'M') || (*unit == 'm')) {
0217 return(value * 1024 * 1024);
0218 } else if ((*unit == 'K') || (*unit == 'k')) {
0219 return(value * 1024);
0220 }
0221 return(value);
0222 }
0223
0224 static int parse_cmdline(char *devname, char *szstart, char *szlength)
0225 {
0226 char *buffer;
0227 unsigned long devstart;
0228 unsigned long devlength;
0229
0230 if ((!devname) || (!szstart) || (!szlength)) {
0231 unregister_devices();
0232 return(-EINVAL);
0233 }
0234
0235 devstart = simple_strtoul(szstart, &buffer, 0);
0236 devstart = handle_unit(devstart, buffer);
0237
0238 if (*(szlength) != '+') {
0239 devlength = simple_strtoul(szlength, &buffer, 0);
0240 devlength = handle_unit(devlength, buffer);
0241 if (devlength < devstart)
0242 goto err_out;
0243
0244 devlength -= devstart;
0245 } else {
0246 devlength = simple_strtoul(szlength + 1, &buffer, 0);
0247 devlength = handle_unit(devlength, buffer);
0248 }
0249 T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n",
0250 devname, devstart, devlength);
0251 if (devlength % SLRAM_BLK_SZ != 0)
0252 goto err_out;
0253
0254 if ((devstart = register_device(devname, devstart, devlength))){
0255 unregister_devices();
0256 return((int)devstart);
0257 }
0258 return(0);
0259
0260 err_out:
0261 E("slram: Illegal length parameter.\n");
0262 return(-EINVAL);
0263 }
0264
0265 #ifndef MODULE
0266
0267 static int __init mtd_slram_setup(char *str)
0268 {
0269 map = str;
0270 return(1);
0271 }
0272
0273 __setup("slram=", mtd_slram_setup);
0274
0275 #endif
0276
0277 static int __init init_slram(void)
0278 {
0279 char *devname;
0280
0281 #ifndef MODULE
0282 char *devstart;
0283 char *devlength;
0284
0285 if (!map) {
0286 E("slram: not enough parameters.\n");
0287 return(-EINVAL);
0288 }
0289 while (map) {
0290 devname = devstart = devlength = NULL;
0291
0292 if (!(devname = strsep(&map, ","))) {
0293 E("slram: No devicename specified.\n");
0294 break;
0295 }
0296 T("slram: devname = %s\n", devname);
0297 if ((!map) || (!(devstart = strsep(&map, ",")))) {
0298 E("slram: No devicestart specified.\n");
0299 }
0300 T("slram: devstart = %s\n", devstart);
0301 if ((!map) || (!(devlength = strsep(&map, ",")))) {
0302 E("slram: No devicelength / -end specified.\n");
0303 }
0304 T("slram: devlength = %s\n", devlength);
0305 if (parse_cmdline(devname, devstart, devlength) != 0) {
0306 return(-EINVAL);
0307 }
0308 }
0309 #else
0310 int count;
0311 int i;
0312
0313 for (count = 0; count < SLRAM_MAX_DEVICES_PARAMS && map[count];
0314 count++) {
0315 }
0316
0317 if ((count % 3 != 0) || (count == 0)) {
0318 E("slram: not enough parameters.\n");
0319 return(-EINVAL);
0320 }
0321 for (i = 0; i < (count / 3); i++) {
0322 devname = map[i * 3];
0323
0324 if (parse_cmdline(devname, map[i * 3 + 1], map[i * 3 + 2])!=0) {
0325 return(-EINVAL);
0326 }
0327
0328 }
0329 #endif
0330
0331 return(0);
0332 }
0333
0334 static void __exit cleanup_slram(void)
0335 {
0336 unregister_devices();
0337 }
0338
0339 module_init(init_slram);
0340 module_exit(cleanup_slram);
0341
0342 MODULE_LICENSE("GPL");
0343 MODULE_AUTHOR("Jochen Schaeuble <psionic@psionic.de>");
0344 MODULE_DESCRIPTION("MTD driver for uncached system RAM");