#include "routerboot.h"
-#define RB_HARDCONFIG_VER "0.06"
+#define RB_HARDCONFIG_VER "0.07"
#define RB_HC_PR_PFX "[rb_hardconfig] "
/* ID values for hardware settings */
return count;
}
-int __init rb_hardconfig_init(struct kobject *rb_kobj)
+int rb_hardconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd)
{
struct kobject *hc_wlan_kobj;
- struct mtd_info *mtd;
size_t bytes_read, buflen, outlen;
const u8 *buf;
void *outbuf;
hc_kobj = NULL;
hc_wlan_kobj = NULL;
- // TODO allow override
- mtd = get_mtd_device_nm(RB_MTD_HARD_CONFIG);
- if (IS_ERR(mtd))
+ ret = __get_mtd_device(mtd);
+ if (ret)
return -ENODEV;
hc_buflen = mtd->size;
hc_buf = kmalloc(hc_buflen, GFP_KERNEL);
if (!hc_buf) {
- put_mtd_device(mtd);
+ __put_mtd_device(mtd);
return -ENOMEM;
}
ret = mtd_read(mtd, 0, hc_buflen, &bytes_read, hc_buf);
- put_mtd_device(mtd);
+ __put_mtd_device(mtd);
if (ret)
goto fail;
return ret;
}
-void __exit rb_hardconfig_exit(void)
+void rb_hardconfig_exit(void)
{
kobject_put(hc_kobj);
+ hc_kobj = NULL;
kfree(hc_buf);
+ hc_buf = NULL;
}
#include "routerboot.h"
-#define RB_SOFTCONFIG_VER "0.04"
+#define RB_SOFTCONFIG_VER "0.05"
#define RB_SC_PR_PFX "[rb_softconfig] "
#define RB_SC_HAS_WRITE_SUPPORT true
static struct kobj_attribute sc_kattrcommit = __ATTR(commit, RB_SC_RMODE|RB_SC_WMODE, sc_commit_show, sc_commit_store);
-int __init rb_softconfig_init(struct kobject *rb_kobj)
+int rb_softconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd)
{
- struct mtd_info *mtd;
size_t bytes_read, buflen;
const u8 *buf;
int i, ret;
sc_buf = NULL;
sc_kobj = NULL;
- // TODO allow override
- mtd = get_mtd_device_nm(RB_MTD_SOFT_CONFIG);
- if (IS_ERR(mtd))
+ ret = __get_mtd_device(mtd);
+ if (ret)
return -ENODEV;
sc_buflen = mtd->size;
sc_buf = kmalloc(sc_buflen, GFP_KERNEL);
if (!sc_buf) {
- put_mtd_device(mtd);
+ __put_mtd_device(mtd);
return -ENOMEM;
}
ret = mtd_read(mtd, 0, sc_buflen, &bytes_read, sc_buf);
- put_mtd_device(mtd);
+ __put_mtd_device(mtd);
if (ret)
goto fail;
return ret;
}
-void __exit rb_softconfig_exit(void)
+void rb_softconfig_exit(void)
{
kobject_put(sc_kobj);
+ sc_kobj = NULL;
kfree(sc_buf);
+ sc_buf = NULL;
}
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
+#include <linux/mtd/mtd.h>
#include "routerboot.h"
return ret;
}
-static int __init routerboot_init(void)
+static void routerboot_mtd_notifier_add(struct mtd_info *mtd)
{
- rb_kobj = kobject_create_and_add("mikrotik", firmware_kobj);
- if (!rb_kobj)
- return -ENOMEM;
+ /* Currently routerboot is only known to live on NOR flash */
+ if (mtd->type != MTD_NORFLASH)
+ return;
/*
* We ignore the following return values and always register.
* These init() routines are designed so that their failed state is
* always manageable by the corresponding exit() calls.
+ * Notifier is called with MTD mutex held: use __get/__put variants.
+ * TODO: allow partition names override
*/
- rb_hardconfig_init(rb_kobj);
- rb_softconfig_init(rb_kobj);
+ if (!strcmp(mtd->name, RB_MTD_HARD_CONFIG))
+ rb_hardconfig_init(rb_kobj, mtd);
+ else if (!strcmp(mtd->name, RB_MTD_SOFT_CONFIG))
+ rb_softconfig_init(rb_kobj, mtd);
+}
+
+static void routerboot_mtd_notifier_remove(struct mtd_info *mtd)
+{
+ if (mtd->type != MTD_NORFLASH)
+ return;
+
+ if (!strcmp(mtd->name, RB_MTD_HARD_CONFIG))
+ rb_hardconfig_exit();
+ else if (!strcmp(mtd->name, RB_MTD_SOFT_CONFIG))
+ rb_softconfig_exit();
+}
+
+/* Note: using a notifier prevents qualifying init()/exit() functions with __init/__exit */
+static struct mtd_notifier routerboot_mtd_notifier = {
+ .add = routerboot_mtd_notifier_add,
+ .remove = routerboot_mtd_notifier_remove,
+};
+
+static int __init routerboot_init(void)
+{
+ rb_kobj = kobject_create_and_add("mikrotik", firmware_kobj);
+ if (!rb_kobj)
+ return -ENOMEM;
+
+ register_mtd_user(&routerboot_mtd_notifier);
return 0;
}
static void __exit routerboot_exit(void)
{
+ unregister_mtd_user(&routerboot_mtd_notifier);
+ /* Exit routines are idempotent */
rb_softconfig_exit();
rb_hardconfig_exit();
kobject_put(rb_kobj); // recursive afaict
int routerboot_tag_find(const u8 *bufhead, const size_t buflen, const u16 tag_id, u16 *pld_ofs, u16 *pld_len);
int routerboot_rle_decode(const u8 *in, size_t inlen, u8 *out, size_t *outlen);
-int __init rb_hardconfig_init(struct kobject *rb_kobj);
-void __exit rb_hardconfig_exit(void);
+int rb_hardconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd);
+void rb_hardconfig_exit(void);
-int __init rb_softconfig_init(struct kobject *rb_kobj);
-void __exit rb_softconfig_exit(void);
+int rb_softconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd);
+void rb_softconfig_exit(void);
ssize_t routerboot_tag_show_string(const u8 *pld, u16 pld_len, char *buf);
ssize_t routerboot_tag_show_u32s(const u8 *pld, u16 pld_len, char *buf);