162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Common code to handle absent "placeholder" devices 462306a36Sopenharmony_ci * Copyright 2001 Resilience Corporation <ebrower@resilience.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This map driver is used to allocate "placeholder" MTD 762306a36Sopenharmony_ci * devices on systems that have socketed/removable media. 862306a36Sopenharmony_ci * Use of this driver as a fallback preserves the expected 962306a36Sopenharmony_ci * registration of MTD device nodes regardless of probe outcome. 1062306a36Sopenharmony_ci * A usage example is as follows: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * my_dev[i] = do_map_probe("cfi", &my_map[i]); 1362306a36Sopenharmony_ci * if(NULL == my_dev[i]) { 1462306a36Sopenharmony_ci * my_dev[i] = do_map_probe("map_absent", &my_map[i]); 1562306a36Sopenharmony_ci * } 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Any device 'probed' with this driver will return -ENODEV 1862306a36Sopenharmony_ci * upon open. 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/module.h> 2262306a36Sopenharmony_ci#include <linux/types.h> 2362306a36Sopenharmony_ci#include <linux/kernel.h> 2462306a36Sopenharmony_ci#include <linux/errno.h> 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci#include <linux/init.h> 2762306a36Sopenharmony_ci#include <linux/mtd/mtd.h> 2862306a36Sopenharmony_ci#include <linux/mtd/map.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int map_absent_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); 3162306a36Sopenharmony_cistatic int map_absent_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); 3262306a36Sopenharmony_cistatic int map_absent_erase (struct mtd_info *, struct erase_info *); 3362306a36Sopenharmony_cistatic void map_absent_sync (struct mtd_info *); 3462306a36Sopenharmony_cistatic struct mtd_info *map_absent_probe(struct map_info *map); 3562306a36Sopenharmony_cistatic void map_absent_destroy (struct mtd_info *); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic struct mtd_chip_driver map_absent_chipdrv = { 3962306a36Sopenharmony_ci .probe = map_absent_probe, 4062306a36Sopenharmony_ci .destroy = map_absent_destroy, 4162306a36Sopenharmony_ci .name = "map_absent", 4262306a36Sopenharmony_ci .module = THIS_MODULE 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic struct mtd_info *map_absent_probe(struct map_info *map) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci struct mtd_info *mtd; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); 5062306a36Sopenharmony_ci if (!mtd) { 5162306a36Sopenharmony_ci return NULL; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci map->fldrv = &map_absent_chipdrv; 5562306a36Sopenharmony_ci mtd->priv = map; 5662306a36Sopenharmony_ci mtd->name = map->name; 5762306a36Sopenharmony_ci mtd->type = MTD_ABSENT; 5862306a36Sopenharmony_ci mtd->size = map->size; 5962306a36Sopenharmony_ci mtd->_erase = map_absent_erase; 6062306a36Sopenharmony_ci mtd->_read = map_absent_read; 6162306a36Sopenharmony_ci mtd->_write = map_absent_write; 6262306a36Sopenharmony_ci mtd->_sync = map_absent_sync; 6362306a36Sopenharmony_ci mtd->flags = 0; 6462306a36Sopenharmony_ci mtd->erasesize = PAGE_SIZE; 6562306a36Sopenharmony_ci mtd->writesize = 1; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci __module_get(THIS_MODULE); 6862306a36Sopenharmony_ci return mtd; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int map_absent_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci return -ENODEV; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci return -ENODEV; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int map_absent_erase(struct mtd_info *mtd, struct erase_info *instr) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci return -ENODEV; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void map_absent_sync(struct mtd_info *mtd) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci /* nop */ 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic void map_absent_destroy(struct mtd_info *mtd) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci /* nop */ 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int __init map_absent_init(void) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci register_mtd_chip_driver(&map_absent_chipdrv); 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void __exit map_absent_exit(void) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci unregister_mtd_chip_driver(&map_absent_chipdrv); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cimodule_init(map_absent_init); 10962306a36Sopenharmony_cimodule_exit(map_absent_exit); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 11262306a36Sopenharmony_ciMODULE_AUTHOR("Resilience Corporation - Eric Brower <ebrower@resilience.com>"); 11362306a36Sopenharmony_ciMODULE_DESCRIPTION("Placeholder MTD chip driver for 'absent' chips"); 114