1*09c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Common code to handle absent "placeholder" devices 41da177e4SLinus Torvalds * Copyright 2001 Resilience Corporation <ebrower@resilience.com> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This map driver is used to allocate "placeholder" MTD 71da177e4SLinus Torvalds * devices on systems that have socketed/removable media. 81da177e4SLinus Torvalds * Use of this driver as a fallback preserves the expected 91da177e4SLinus Torvalds * registration of MTD device nodes regardless of probe outcome. 101da177e4SLinus Torvalds * A usage example is as follows: 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * my_dev[i] = do_map_probe("cfi", &my_map[i]); 131da177e4SLinus Torvalds * if(NULL == my_dev[i]) { 141da177e4SLinus Torvalds * my_dev[i] = do_map_probe("map_absent", &my_map[i]); 151da177e4SLinus Torvalds * } 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * Any device 'probed' with this driver will return -ENODEV 181da177e4SLinus Torvalds * upon open. 191da177e4SLinus Torvalds */ 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #include <linux/module.h> 221da177e4SLinus Torvalds #include <linux/types.h> 231da177e4SLinus Torvalds #include <linux/kernel.h> 241da177e4SLinus Torvalds #include <linux/errno.h> 251da177e4SLinus Torvalds #include <linux/slab.h> 261da177e4SLinus Torvalds #include <linux/init.h> 271da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 281da177e4SLinus Torvalds #include <linux/mtd/map.h> 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds static int map_absent_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); 311da177e4SLinus Torvalds static int map_absent_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); 321da177e4SLinus Torvalds static int map_absent_erase (struct mtd_info *, struct erase_info *); 331da177e4SLinus Torvalds static void map_absent_sync (struct mtd_info *); 341da177e4SLinus Torvalds static struct mtd_info *map_absent_probe(struct map_info *map); 351da177e4SLinus Torvalds static void map_absent_destroy (struct mtd_info *); 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds static struct mtd_chip_driver map_absent_chipdrv = { 391da177e4SLinus Torvalds .probe = map_absent_probe, 401da177e4SLinus Torvalds .destroy = map_absent_destroy, 411da177e4SLinus Torvalds .name = "map_absent", 421da177e4SLinus Torvalds .module = THIS_MODULE 431da177e4SLinus Torvalds }; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds static struct mtd_info *map_absent_probe(struct map_info *map) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds struct mtd_info *mtd; 481da177e4SLinus Torvalds 4995b93a0cSBurman Yan mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); 501da177e4SLinus Torvalds if (!mtd) { 511da177e4SLinus Torvalds return NULL; 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds map->fldrv = &map_absent_chipdrv; 551da177e4SLinus Torvalds mtd->priv = map; 561da177e4SLinus Torvalds mtd->name = map->name; 571da177e4SLinus Torvalds mtd->type = MTD_ABSENT; 581da177e4SLinus Torvalds mtd->size = map->size; 593c3c10bbSArtem Bityutskiy mtd->_erase = map_absent_erase; 603c3c10bbSArtem Bityutskiy mtd->_read = map_absent_read; 613c3c10bbSArtem Bityutskiy mtd->_write = map_absent_write; 623c3c10bbSArtem Bityutskiy mtd->_sync = map_absent_sync; 631da177e4SLinus Torvalds mtd->flags = 0; 641da177e4SLinus Torvalds mtd->erasesize = PAGE_SIZE; 6517ffc7baSArtem B. Bityutskiy mtd->writesize = 1; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds __module_get(THIS_MODULE); 681da177e4SLinus Torvalds return mtd; 691da177e4SLinus Torvalds } 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds static int map_absent_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) 731da177e4SLinus Torvalds { 741da177e4SLinus Torvalds return -ENODEV; 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) 781da177e4SLinus Torvalds { 791da177e4SLinus Torvalds return -ENODEV; 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds static int map_absent_erase(struct mtd_info *mtd, struct erase_info *instr) 831da177e4SLinus Torvalds { 841da177e4SLinus Torvalds return -ENODEV; 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds static void map_absent_sync(struct mtd_info *mtd) 881da177e4SLinus Torvalds { 891da177e4SLinus Torvalds /* nop */ 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds static void map_absent_destroy(struct mtd_info *mtd) 931da177e4SLinus Torvalds { 941da177e4SLinus Torvalds /* nop */ 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds static int __init map_absent_init(void) 981da177e4SLinus Torvalds { 991da177e4SLinus Torvalds register_mtd_chip_driver(&map_absent_chipdrv); 1001da177e4SLinus Torvalds return 0; 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds static void __exit map_absent_exit(void) 1041da177e4SLinus Torvalds { 1051da177e4SLinus Torvalds unregister_mtd_chip_driver(&map_absent_chipdrv); 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds module_init(map_absent_init); 1091da177e4SLinus Torvalds module_exit(map_absent_exit); 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 1121da177e4SLinus Torvalds MODULE_AUTHOR("Resilience Corporation - Eric Brower <ebrower@resilience.com>"); 1131da177e4SLinus Torvalds MODULE_DESCRIPTION("Placeholder MTD chip driver for 'absent' chips"); 114