diff -uNr linux-2.2.17-clean/Makefile linux-2.2.17-mtd/Makefile --- linux-2.2.17-clean/Makefile Mon Sep 11 09:27:12 2000 +++ linux-2.2.17-mtd/Makefile Thu Nov 30 11:55:53 2000 @@ -210,6 +210,10 @@ DRIVERS := $(DRIVERS) drivers/telephony/telephony.a endif +ifeq ($(CONFIG_MTD),y) +DRIVERS := $(DRIVERS) drivers/mtd/mtdlink.o +endif + include arch/$(ARCH)/Makefile .S.s: @@ -233,7 +237,7 @@ $(LIBS) \ --end-group \ -o vmlinux - $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map + $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map symlinks: rm -f include/asm @@ -348,6 +352,7 @@ if [ -f VIDEO_MODULES ]; then inst_mod VIDEO_MODULES video; fi; \ if [ -f FC4_MODULES ]; then inst_mod FC4_MODULES fc4; fi; \ if [ -f IRDA_MODULES ]; then inst_mod IRDA_MODULES net; fi; \ + if [ -f MTD_MODULES ]; then inst_mod MTD_MODULES mtd; fi; \ if [ -f SK98LIN_MODULES ]; then inst_mod SK98LIN_MODULES net; fi; \ \ for f in *.o; do [ -r $$f ] && echo $$f; done | sort > $$MODLIB/.allmods; \ diff -uNr linux-2.2.17-clean/arch/alpha/config.in linux-2.2.17-mtd/arch/alpha/config.in --- linux-2.2.17-clean/arch/alpha/config.in Thu Aug 3 13:25:14 2000 +++ linux-2.2.17-mtd/arch/alpha/config.in Thu Nov 30 11:55:53 2000 @@ -218,6 +218,8 @@ fi endmenu +source drivers/mtd/Config.in + source drivers/pnp/Config.in source drivers/block/Config.in diff -uNr linux-2.2.17-clean/arch/arm/config.in linux-2.2.17-mtd/arch/arm/config.in --- linux-2.2.17-clean/arch/arm/config.in Thu Jun 8 10:06:05 2000 +++ linux-2.2.17-mtd/arch/arm/config.in Thu Nov 30 11:55:53 2000 @@ -136,6 +136,8 @@ fi endmenu +source drivers/mtd/Config.in + source drivers/pnp/Config.in source drivers/block/Config.in diff -uNr linux-2.2.17-clean/arch/i386/config.in linux-2.2.17-mtd/arch/i386/config.in --- linux-2.2.17-clean/arch/i386/config.in Thu Jul 20 20:40:19 2000 +++ linux-2.2.17-mtd/arch/i386/config.in Thu Nov 30 11:55:53 2000 @@ -118,6 +118,8 @@ endmenu +source drivers/mtd/Config.in + source drivers/pnp/Config.in source drivers/block/Config.in diff -uNr linux-2.2.17-clean/arch/m68k/config.in linux-2.2.17-mtd/arch/m68k/config.in --- linux-2.2.17-clean/arch/m68k/config.in Thu Jun 8 10:06:05 2000 +++ linux-2.2.17-mtd/arch/m68k/config.in Thu Nov 30 11:55:53 2000 @@ -123,6 +123,8 @@ endmenu +source drivers/mtd/Config.in + source drivers/block/Config.in if [ "$CONFIG_NET" = "y" ]; then diff -uNr linux-2.2.17-clean/arch/mips/config.in linux-2.2.17-mtd/arch/mips/config.in --- linux-2.2.17-clean/arch/mips/config.in Thu Jun 8 10:06:05 2000 +++ linux-2.2.17-mtd/arch/mips/config.in Thu Nov 30 11:55:53 2000 @@ -124,6 +124,8 @@ endmenu fi +source drivers/mtd/Config.in + source drivers/block/Config.in if [ "$CONFIG_NET" = "y" ]; then diff -uNr linux-2.2.17-clean/arch/ppc/config.in linux-2.2.17-mtd/arch/ppc/config.in --- linux-2.2.17-clean/arch/ppc/config.in Thu Jul 20 20:40:19 2000 +++ linux-2.2.17-mtd/arch/ppc/config.in Thu Nov 30 11:55:53 2000 @@ -125,7 +125,7 @@ fi endmenu - +source drivers/mtd/Config.in source drivers/pnp/Config.in source drivers/block/Config.in #source drivers.new/Config.in diff -uNr linux-2.2.17-clean/arch/s390/config.in linux-2.2.17-mtd/arch/s390/config.in --- linux-2.2.17-clean/arch/s390/config.in Thu Jun 8 10:06:05 2000 +++ linux-2.2.17-mtd/arch/s390/config.in Thu Nov 30 11:55:53 2000 @@ -55,6 +55,9 @@ source fs/Config.in +# Not sure about this one. dwmw2 +# source drivers/mtd/Config.in + # source drivers/char/Config.in mainmenu_option next_comment diff -uNr linux-2.2.17-clean/arch/sparc/config.in linux-2.2.17-mtd/arch/sparc/config.in --- linux-2.2.17-clean/arch/sparc/config.in Thu Jun 8 10:06:09 2000 +++ linux-2.2.17-mtd/arch/sparc/config.in Thu Nov 30 11:55:53 2000 @@ -78,6 +78,8 @@ bool 'SunOS binary emulation' CONFIG_SUNOS_EMUL endmenu +source drivers/mtd/Config.in + mainmenu_option next_comment comment 'Floppy, IDE, and other block devices' diff -uNr linux-2.2.17-clean/arch/sparc64/config.in linux-2.2.17-mtd/arch/sparc64/config.in --- linux-2.2.17-clean/arch/sparc64/config.in Thu Aug 3 13:25:14 2000 +++ linux-2.2.17-mtd/arch/sparc64/config.in Thu Nov 30 11:55:53 2000 @@ -45,6 +45,7 @@ define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y bool 'PCI support' CONFIG_PCI +source drivers/mtd/Config.in source drivers/sbus/char/Config.in source drivers/sbus/audio/Config.in diff -uNr linux-2.2.17-clean/drivers/Makefile linux-2.2.17-mtd/drivers/Makefile --- linux-2.2.17-clean/drivers/Makefile Wed Jun 7 11:00:14 2000 +++ linux-2.2.17-mtd/drivers/Makefile Thu Nov 30 11:55:53 2000 @@ -9,7 +9,7 @@ SUB_DIRS := block char net misc sound MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp \ +ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp mtd \ macintosh video dio zorro fc4 usb telephony i2o ifdef CONFIG_DIO @@ -46,6 +46,15 @@ ifdef CONFIG_PPC SUB_DIRS += macintosh MOD_SUB_DIRS += macintosh +endif + +ifeq ($(CONFIG_MTD),y) +SUB_DIRS += mtd +MOD_SUB_DIRS += mtd +else + ifeq ($(CONFIG_MTD),m) + MOD_SUB_DIRS += mtd + endif endif ifeq ($(CONFIG_USB),y) diff -uNr linux-2.2.17-clean/fs/Config.in linux-2.2.17-mtd/fs/Config.in --- linux-2.2.17-clean/fs/Config.in Wed Jun 7 11:00:29 2000 +++ linux-2.2.17-mtd/fs/Config.in Thu Nov 30 11:55:53 2000 @@ -59,6 +59,11 @@ if [ "$CONFIG_EFS_FS" != "n" ]; then define_bool CONFIG_SGI_PARTITION y fi + tristate 'Journalling Flash filesystem (JFFS) support (experimental)' CONFIG_JFFS_FS + if [ "$CONFIG_JFFS_FS" = "y" -o "$CONFIG_JFFS_FS" = "m" ]; then + bool ' /proc filesystem support' CONFIG_JFFS_PROC_FS $CONFIG_JFFS_FS + int ' JFFS verbose level 0 (quiet), 1, 2, or 3' CONFIG_JFFS_FS_VERBOSE 0 + fi fi if [ "$CONFIG_NET" = "y" ]; then diff -uNr linux-2.2.17-clean/fs/Makefile linux-2.2.17-mtd/fs/Makefile --- linux-2.2.17-clean/fs/Makefile Wed Jun 7 10:56:34 2000 +++ linux-2.2.17-mtd/fs/Makefile Thu Nov 30 11:55:53 2000 @@ -18,7 +18,7 @@ MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ hpfs sysv smbfs ncpfs ufs affs romfs autofs hfs lockd \ - nfsd nls devpts adfs qnx4 efs + nfsd nls devpts adfs qnx4 efs jffs ifeq ($(CONFIG_QUOTA),y) O_OBJS += dquot.o @@ -220,6 +220,14 @@ else ifeq ($(CONFIG_EFS_FS),m) MOD_SUB_DIRS += efs + endif +endif + +ifeq ($(CONFIG_JFFS_FS),y) +SUB_DIRS += jffs +else + ifeq ($(CONFIG_JFFS_FS),m) + MOD_SUB_DIRS += jffs endif endif diff -uNr linux-2.2.17-clean/fs/filesystems.c linux-2.2.17-mtd/fs/filesystems.c --- linux-2.2.17-clean/fs/filesystems.c Wed Jun 7 10:58:40 2000 +++ linux-2.2.17-mtd/fs/filesystems.c Thu Nov 30 11:55:53 2000 @@ -49,6 +49,10 @@ extern int init_devpts_fs(void); #endif +#ifdef CONFIG_JFFS_FS +extern int init_jffs_fs(void); +#endif + void __init filesystem_setup(void) { #ifdef CONFIG_EXT2_FS @@ -133,6 +137,10 @@ #ifdef CONFIG_EFS_FS init_efs_fs(); +#endif + +#ifdef CONFIG_JFFS_FS + init_jffs_fs(); #endif #ifdef CONFIG_AUTOFS_FS diff -uNr linux-2.2.17-clean/include/linux/list.h linux-2.2.17-mtd/include/linux/list.h --- linux-2.2.17-clean/include/linux/list.h Wed Jun 7 09:41:09 2000 +++ linux-2.2.17-mtd/include/linux/list.h Thu Nov 30 11:55:53 2000 @@ -17,6 +17,8 @@ struct list_head *next, *prev; }; +#define LIST_HEAD_INIT(name) { &(name), &(name) } + #define LIST_HEAD(name) \ struct list_head name = { &name, &name } @@ -49,6 +51,14 @@ } /* + * Insert a new entry at the tail + */ +static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* * Delete a list entry by making the prev/next entries * point to each other. * @@ -93,6 +103,9 @@ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) #endif /* __KERNEL__ */ diff -uNr linux-2.2.17-clean/include/linux/module.h linux-2.2.17-mtd/include/linux/module.h --- linux-2.2.17-clean/include/linux/module.h Wed Jun 7 11:00:29 2000 +++ linux-2.2.17-mtd/include/linux/module.h Thu Nov 30 11:55:53 2000 @@ -8,6 +8,7 @@ #define _LINUX_MODULE_H #include +#include #ifdef __GENKSYMS__ # define _set_ver(sym) sym @@ -141,8 +142,38 @@ #define __MODULE_STRING_1(x) #x #define __MODULE_STRING(x) __MODULE_STRING_1(x) +/* Generic inter module communication. + * + * NOTE: This interface is intended for small amounts of data that are + * passed between two objects and either or both of the objects + * might be compiled as modules. Do not over use this interface. + * + * If more than two objects need to communicate then you probably + * need a specific interface instead of abusing this generic + * interface. If both objects are *always* built into the kernel + * then a global extern variable is good enough, you do not need + * this interface. + * + * Keith Owens 28 Oct 2000. + */ + +#define HAVE_INTER_MODULE +extern void inter_module_register(const char *, struct module *, const void *); +extern void inter_module_unregister(const char *); +extern const void *inter_module_get(const char *); +extern const void *inter_module_get_request(const char *, const char *); +extern void inter_module_put(const char *); + +struct inter_module_entry { + struct list_head list; + const char *im_name; + struct module *owner; + const void *userdata; +}; + /* Find a symbol exported by the kernel or another module */ extern unsigned long get_module_symbol(char *, char *); +extern void put_module_symbol(unsigned long); #if defined(MODULE) && !defined(__GENKSYMS__) diff -uNr linux-2.2.17-clean/init/main.c linux-2.2.17-mtd/init/main.c --- linux-2.2.17-clean/init/main.c Thu Aug 3 13:25:15 2000 +++ linux-2.2.17-mtd/init/main.c Thu Nov 30 11:55:53 2000 @@ -101,7 +101,9 @@ #ifdef CONFIG_ARCH_ACORN extern void ecard_init(void); #endif - +#ifdef CONFIG_MTD +extern void init_mtd(void); +#endif extern void smp_setup(char *str, int *ints); #ifdef __i386__ extern void ioapic_pirq_setup(char *str, int *ints); @@ -1552,6 +1554,9 @@ /* Set up devices .. */ device_setup(); +#ifdef CONFIG_MTD + init_mtd(); +#endif /* .. executable formats .. */ binfmt_setup(); diff -uNr linux-2.2.17-clean/kernel/ksyms.c linux-2.2.17-mtd/kernel/ksyms.c --- linux-2.2.17-clean/kernel/ksyms.c Mon Sep 11 09:27:25 2000 +++ linux-2.2.17-mtd/kernel/ksyms.c Thu Nov 30 11:55:53 2000 @@ -80,7 +80,13 @@ #ifdef CONFIG_MODULES EXPORT_SYMBOL(get_module_symbol); +EXPORT_SYMBOL(put_module_symbol); #endif +EXPORT_SYMBOL(inter_module_register); +EXPORT_SYMBOL(inter_module_unregister); +EXPORT_SYMBOL(inter_module_get); +EXPORT_SYMBOL(inter_module_get_request); +EXPORT_SYMBOL(inter_module_put); EXPORT_SYMBOL(get_options); /* process memory management */ diff -uNr linux-2.2.17-clean/kernel/module.c linux-2.2.17-mtd/kernel/module.c --- linux-2.2.17-clean/kernel/module.c Wed Jun 7 11:00:30 2000 +++ linux-2.2.17-mtd/kernel/module.c Thu Nov 30 11:55:53 2000 @@ -6,6 +6,8 @@ #include #include #include +#include +#include /* * Originally by Anonymous (as far as I know...) @@ -14,11 +16,12 @@ * Heavily modified by Bjorn Ekwall May 1994 (C) * Rewritten by Richard Henderson Dec 1996 * Add MOD_INITIALIZING Keith Owens Nov 1999 + * Backport inter_module_xxx from 2.4. Keith Owens Oct 2000 * * This source is covered by the GNU GPL, the same as all kernel sources. */ -#ifdef CONFIG_MODULES /* a *big* #ifdef block... */ +#ifdef CONFIG_MODULES extern struct module_symbol __start___ksymtab[]; extern struct module_symbol __stop___ksymtab[]; @@ -48,6 +51,174 @@ struct module *module_list = &kernel_module; +#endif /* CONFIG_MODULES */ + +/* inter_module functions are always available, even when the kernel is + * compiled without modules. Consumers of inter_module_xxx routines + * will always work, even when both are built into the kernel, this + * approach removes lots of #ifdefs in mainline code. + */ + +static struct list_head ime_list = LIST_HEAD_INIT(ime_list); +static spinlock_t ime_lock = SPIN_LOCK_UNLOCKED; +static int kmalloc_failed; + +/** + * inter_module_register - register a new set of inter module data. + * @im_name: an arbitrary string to identify the data, must be unique + * @owner: module that is registering the data, always use THIS_MODULE + * @userdata: pointer to arbitrary userdata to be registered + * + * Description: Check that the im_name has not already been registered, + * complain if it has. For new data, add it to the inter_module_entry + * list. + */ +void inter_module_register(const char *im_name, struct module *owner, const void *userdata) +{ + struct list_head *tmp; + struct inter_module_entry *ime, *ime_new; + + if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) { + /* Overloaded kernel, not fatal */ + printk(KERN_ERR + "Aiee, inter_module_register: cannot kmalloc entry for '%s'\n", + im_name); + kmalloc_failed = 1; + return; + } + memset(ime_new, 0, sizeof(*ime_new)); + ime_new->im_name = im_name; + ime_new->owner = owner; + ime_new->userdata = userdata; + + spin_lock(&ime_lock); + list_for_each(tmp, &ime_list) { + ime = list_entry(tmp, struct inter_module_entry, list); + if (strcmp(ime->im_name, im_name) == 0) { + spin_unlock(&ime_lock); + kfree(ime_new); + /* Program logic error, fatal */ + panic("inter_module_register: duplicate im_name '%s'", im_name); + } + } + list_add(&(ime_new->list), &ime_list); + spin_unlock(&ime_lock); +} + +/** + * inter_module_unregister - unregister a set of inter module data. + * @im_name: an arbitrary string to identify the data, must be unique + * + * Description: Check that the im_name has been registered, complain if + * it has not. For existing data, remove it from the + * inter_module_entry list. + */ +void inter_module_unregister(const char *im_name) +{ + struct list_head *tmp; + struct inter_module_entry *ime; + + spin_lock(&ime_lock); + list_for_each(tmp, &ime_list) { + ime = list_entry(tmp, struct inter_module_entry, list); + if (strcmp(ime->im_name, im_name) == 0) { + list_del(&(ime->list)); + spin_unlock(&ime_lock); + kfree(ime); + return; + } + } + spin_unlock(&ime_lock); + if (kmalloc_failed) { + printk(KERN_ERR + "inter_module_unregister: no entry for '%s', " + "probably caused by previous kmalloc failure\n", + im_name); + return; + } + else { + /* Program logic error, fatal */ + panic("inter_module_unregister: no entry for '%s'", im_name); + } +} + +/** + * inter_module_get - return arbitrary userdata from another module. + * @im_name: an arbitrary string to identify the data, must be unique + * + * Description: If the im_name has not been registered, return NULL. + * Try to increment the use count on the owning module, if that fails + * then return NULL. Otherwise return the userdata. + */ +const void *inter_module_get(const char *im_name) +{ + struct list_head *tmp; + struct inter_module_entry *ime; + const void *result = NULL; + + spin_lock(&ime_lock); + list_for_each(tmp, &ime_list) { + ime = list_entry(tmp, struct inter_module_entry, list); + if (strcmp(ime->im_name, im_name) == 0) { + /* This should be try_inc_use_count but that function is + * not in 2.2 kernels. I am not opening that can of worms + * for 2.2. Keith Owens + */ + if (ime->owner) + __MOD_INC_USE_COUNT(ime->owner); + result = ime->userdata; + break; + } + } + spin_unlock(&ime_lock); + return(result); +} + +/** + * inter_module_get_request - im get with automatic request_module. + * @im_name: an arbitrary string to identify the data, must be unique + * @modname: module that is expected to register im_name + * + * Description: If inter_module_get fails, do request_module then retry. + */ +const void *inter_module_get_request(const char *im_name, const char *modname) +{ + const void *result = inter_module_get(im_name); + if (!result) { + request_module(modname); + result = inter_module_get(im_name); + } + return(result); +} + +/** + * inter_module_put - release use of data from another module. + * @im_name: an arbitrary string to identify the data, must be unique + * + * Description: If the im_name has not been registered, complain, + * otherwise decrement the use count on the owning module. + */ +void inter_module_put(const char *im_name) +{ + struct list_head *tmp; + struct inter_module_entry *ime; + + spin_lock(&ime_lock); + list_for_each(tmp, &ime_list) { + ime = list_entry(tmp, struct inter_module_entry, list); + if (strcmp(ime->im_name, im_name) == 0) { + if (ime->owner) + __MOD_DEC_USE_COUNT(ime->owner); + spin_unlock(&ime_lock); + return; + } + } + spin_unlock(&ime_lock); + panic("inter_module_put: no entry for '%s'", im_name); +} + +#if defined(CONFIG_MODULES) /* The rest of the source */ + static long get_mod_name(const char *user_name, char **buf); static void put_mod_name(char *buf); static struct module *find_module(const char *name); @@ -952,7 +1123,9 @@ * Gets the address for a symbol in the given module. If modname is * NULL, it looks for the name in any registered symbol table. If the * modname is an empty string, it looks for the symbol in kernel exported - * symbol tables. + * symbol tables. Increase the usage count of the module in which the + * symbol was found - it's the only way we can guarantee that it's still + * there by the time our caller actually uses it. */ unsigned long get_module_symbol(char *modname, char *symname) @@ -969,12 +1142,29 @@ i > 0; --i, ++sym) { if (strcmp(sym->name, symname) == 0) { + __MOD_INC_USE_COUNT(mp); return sym->value; } } } } return 0; +} + +/* Decrease the use count of the module containing a symbol with the + * address passed. + */ +void put_module_symbol(unsigned long addr) +{ + struct module *mp; + + for (mp = module_list; mp; mp = mp->next) { + if (addr >= (unsigned long)mp && + addr < (unsigned long)mp + mp->size) { + __MOD_DEC_USE_COUNT(mp); + return; + } + } } #else /* CONFIG_MODULES */