# # Copyright (C) 2006 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # # $Id$ FS_MENU:=Filesystems define KernelPackage/nls/Depends ifneq ($(KERNEL),2.4) DEPENDS:= +kmod-nls-base endif endef define KernelPackage/fs-cifs SUBMENU:=$(FS_MENU) TITLE:=CIFS support KCONFIG:=CONFIG_CIFS FILES:=$(LINUX_DIR)/fs/cifs/cifs.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,cifs) $(call KernelPackage/nls/Depends) endef define KernelPackage/fs-cifs/description Kernel module for CIFS support endef $(eval $(call KernelPackage,fs-cifs)) define KernelPackage/fs-minix SUBMENU:=$(FS_MENU) TITLE:=Minix filesystem support KCONFIG:=CONFIG_MINIX_FS FILES:=$(LINUX_DIR)/fs/minix/minix.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,minix) endef define KernelPackage/fs-minix/description Kernel module for Minix filesystem support endef $(eval $(call KernelPackage,fs-minix)) define KernelPackage/fs-ntfs SUBMENU:=$(FS_MENU) TITLE:=NTFS filesystem support KCONFIG:=CONFIG_NTFS_FS FILES:=$(LINUX_DIR)/fs/ntfs/ntfs.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,ntfs) endef define KernelPackage/fs-ntfs/description Kernel module for NTFS filesystem support endef $(eval $(call KernelPackage,fs-ntfs)) define KernelPackage/fs-mbcache SUBMENU:=$(FS_MENU) TITLE:=mbcache (used by ext2/ext3) KCONFIG:=CONFIG_FS_MBCACHE ifneq ($(CONFIG_FS_MBCACHE),) FILES:=$(LINUX_DIR)/fs/mbcache.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,20,mbcache) endif endef define KernelPackage/fs-ext2/description Meta Block cache used by ext2/ext3 This package will only be installed if extended attributes are enabled for ext2/ext3 endef $(eval $(call KernelPackage,fs-mbcache)) define KernelPackage/fs-ext2 SUBMENU:=$(FS_MENU) TITLE:=EXT2 filesystem support KCONFIG:=CONFIG_EXT2_FS DEPENDS:=$(if $(DUMP)$(CONFIG_FS_MBCACHE),+kmod-fs-mbcache) FILES:=$(LINUX_DIR)/fs/ext2/ext2.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,ext2) endef define KernelPackage/fs-ext2/description Kernel module for EXT2 filesystem support endef $(eval $(call KernelPackage,fs-ext2)) define KernelPackage/fs-ext3 SUBMENU:=$(FS_MENU) TITLE:=EXT3 filesystem support KCONFIG:= \ CONFIG_EXT3_FS \ CONFIG_JBD DEPENDS:=$(if $(DUMP)$(CONFIG_FS_MBCACHE),+kmod-fs-mbcache) FILES:= \ $(LINUX_DIR)/fs/ext3/ext3.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/fs/jbd/jbd.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,jbd ext3) endef define KernelPackage/fs-ext3/description Kernel module for EXT3 filesystem support endef $(eval $(call KernelPackage,fs-ext3)) define KernelPackage/fs-hfs SUBMENU:=$(FS_MENU) TITLE:=HFS+ filesystem support KCONFIG:=CONFIG_HFS_FS FILES:=$(LINUX_DIR)/fs/hfs/hfs.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,hfs) $(call KernelPackage/nls/Depends) endef define KernelPackage/fs-hfs/description Kernel module for HFS filesystem support endef $(eval $(call KernelPackage,fs-hfs)) define KernelPackage/fs-hfsplus SUBMENU:=$(FS_MENU) TITLE:=HFS+ filesystem support KCONFIG:=CONFIG_HFSPLUS_FS FILES:=$(LINUX_DIR)/fs/hfsplus/hfsplus.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,hfsplus) $(call KernelPackage/nls/Depends,utf8) endef define KernelPackage/fs-hfsplus/description Kernel module for HFS+ filesystem support endef $(eval $(call KernelPackage,fs-hfsplus)) define KernelPackage/fs-isofs SUBMENU:=$(FS_MENU) TITLE:=ISO9660 filesystem support KCONFIG:=CONFIG_ISO9660_FS CONFIG_JOLIET=y CONFIG_ZISOFS=n FILES:=$(LINUX_DIR)/fs/isofs/isofs.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,isofs) $(call KernelPackage/nls/Depends) endef define KernelPackage/fs-isofs/description Kernel module for ISO9660 filesystem support endef $(eval $(call KernelPackage,fs-isofs)) define KernelPackage/fs-udf SUBMENU:=$(FS_MENU) TITLE:=UDF filesystem support KCONFIG:=CONFIG_UDF_FS FILES:=$(LINUX_DIR)/fs/udf/udf.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,udf) $(call KernelPackage/nls/Depends) endef define KernelPackage/fs-udf/description Kernel module for UDF filesystem support endef $(eval $(call KernelPackage,fs-udf)) define KernelPackage/fs-nfs-common SUBMENU:=$(FS_MENU) TITLE:=Common NFS filesystem modules KCONFIG:= \ CONFIG_LOCKD \ CONFIG_SUNRPC FILES:= \ $(LINUX_DIR)/fs/lockd/lockd.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/net/sunrpc/sunrpc.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,sunrpc lockd) endef $(eval $(call KernelPackage,fs-nfs-common)) define KernelPackage/fs-nfs SUBMENU:=$(FS_MENU) TITLE:=NFS filesystem support DEPENDS:=kmod-fs-nfs-common KCONFIG:= \ CONFIG_NFS_FS FILES:= \ $(LINUX_DIR)/fs/nfs/nfs.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,40,nfs) endef define KernelPackage/fs-nfs/description Kernel module for NFS support endef $(eval $(call KernelPackage,fs-nfs)) define KernelPackage/fs-nfsd SUBMENU:=$(FS_MENU) TITLE:=NFS kernel server support DEPENDS:=kmod-fs-nfs-common KCONFIG:=CONFIG_NFSD FILES:=$(LINUX_DIR)/fs/nfsd/nfsd.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,40,nfsd) endef define KernelPackage/fs-nfsd/2.6 KCONFIG+=CONFIG_EXPORTFS \ CONFIG_SUNRPC_GSS FILES+=$(LINUX_DIR)/fs/exportfs/exportfs.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/net/sunrpc/auth_gss/auth_rpcgss.$(LINUX_KMOD_SUFFIX) AUTOLOAD+=$(call AutoLoad,40,auth_rpcgss exportfs nfsd) endef define KernelPackage/fs-nfsd/description Kernel module for NFS kernel server support endef $(eval $(call KernelPackage,fs-nfsd)) define KernelPackage/fs-msdos SUBMENU:=$(FS_MENU) TITLE:=MSDOS filesystem support KCONFIG:=CONFIG_MSDOS_FS FILES:=$(LINUX_DIR)/fs/msdos/msdos.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,40,msdos) $(call KernelPackage/nls/Depends) endef define KernelPackage/fs-msdos/description Kernel module for MSDOS filesystem support endef $(eval $(call KernelPackage,fs-msdos)) define KernelPackage/fs-reiserfs SUBMENU:=$(FS_MENU) TITLE:=ReiserFS filesystem support KCONFIG:=CONFIG_REISERFS_FS FILES:=$(LINUX_DIR)/fs/reiserfs/reiserfs.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,reiserfs) endef define KernelPackage/fs-reiserfs/description Kernel module for ReiserFS support endef $(eval $(call KernelPackage,fs-reiserfs)) define KernelPackage/fs-vfat SUBMENU:=$(FS_MENU) TITLE:=VFAT filesystem support KCONFIG:= \ CONFIG_FAT_FS \ CONFIG_VFAT_FS FILES:= \ $(LINUX_DIR)/fs/fat/fat.$(LINUX_KMOD_SUFFIX) \ $(LINUX_DIR)/fs/vfat/vfat.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,fat vfat) $(call KernelPackage/nls/Depends) endef define KernelPackage/fs-vfat/description Kernel module for VFAT filesystem support endef $(eval $(call KernelPackage,fs-vfat)) define KernelPackage/fs-xfs SUBMENU:=$(FS_MENU) TITLE:=XFS filesystem support KCONFIG:=CONFIG_XFS_FS FILES:=$(LINUX_DIR)/fs/xfs/xfs.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,30,xfs) endef define KernelPackage/fs-xfs/description Kernel module for XFS support endef $(eval $(call KernelPackage,fs-xfs)) define KernelPackage/nls-base SUBMENU:=$(FS_MENU) TITLE:=Native Language Support KCONFIG:=CONFIG_NLS FILES:=$(LINUX_DIR)/fs/nls/nls_base.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,20,nls_base) endef define KernelPackage/nls-base/description Kernel module for NLS (Native Language Support) endef $(eval $(call KernelPackage,nls-base)) define KernelPackage/nls-cp437 SUBMENU:=$(FS_MENU) TITLE:=Codepage 437 (United States, Canada) KCONFIG:=CONFIG_NLS_CODEPAGE_437 FILES:=$(LINUX_DIR)/fs/nls/nls_cp437.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,25,nls_cp437) $(call KernelPackage/nls/Depends) endef define KernelPackage/nls-cp437/description Kernel module for NLS Codepage 437 (United States, Canada) endef $(eval $(call KernelPackage,nls-cp437)) define KernelPackage/nls-cp850 SUBMENU:=$(FS_MENU) TITLE:=Codepage 850 (Europe) KCONFIG:=CONFIG_NLS_CODEPAGE_850 FILES:=$(LINUX_DIR)/fs/nls/nls_cp850.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,25,nls_cp850) $(call KernelPackage/nls/Depends) endef define KernelPackage/nls-cp850/description Kernel module for NLS Codepage 850 (Europe) endef $(eval $(call KernelPackage,nls-cp850)) define KernelPackage/nls-cp1250 SUBMENU:=$(FS_MENU) TITLE:=Codepage 1250 (Eastern Europe) KCONFIG:=CONFIG_NLS_CODEPAGE_1250 FILES:=$(LINUX_DIR)/fs/nls/nls_cp1250.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,25,nls_cp1250) $(call KernelPackage/nls/Depends) endef define KernelPackage/nls-cp1250/description Kernel module for NLS Codepage 1250 (Eastern Europe) endef $(eval $(call KernelPackage,nls-cp1250)) define KernelPackage/nls-cp1251 SUBMENU:=$(FS_MENU) TITLE:=Codepage 1251 (Russian) KCONFIG:=CONFIG_NLS_CODEPAGE_1251 FILES:=$(LINUX_DIR)/fs/nls/nls_cp1251.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,25,nls_cp1251) $(call KernelPackage/nls/Depends) endef define KernelPackage/nls-cp1251/description Kernel module for NLS Codepage 1251 (Russian) endef $(eval $(call KernelPackage,nls-cp1251)) define KernelPackage/nls-iso8859-1 SUBMENU:=$(FS_MENU) TITLE:=ISO 8859-1 (Latin 1; Western European Languages) KCONFIG:=CONFIG_NLS_ISO8859_1 FILES:=$(LINUX_DIR)/fs/nls/nls_iso8859-1.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,25,nls_iso8859-1) $(call KernelPackage/nls/Depends) endef define KernelPackage/nls-iso8859-1/description Kernel module for NLS ISO 8859-1 (Latin 1) endef $(eval $(call KernelPackage,nls-iso8859-1)) define KernelPackage/nls-iso8859-2 SUBMENU:=$(FS_MENU) TITLE:=ISO 8859-2 (Latin 2; Central European Languages) KCONFIG:=CONFIG_NLS_ISO8859_2 FILES:=$(LINUX_DIR)/fs/nls/nls_iso8859-2.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,25,nls_iso8859-2) $(call KernelPackage/nls/Depends) endef define KernelPackage/nls-iso8859-2/description Kernel module for NLS ISO 8859-2 (Latin 2) endef $(eval $(call KernelPackage,nls-iso8859-2)) define KernelPackage/nls-iso8859-15 SUBMENU:=$(FS_MENU) TITLE:=ISO 8859-15 (Latin 9; Western, with Euro symbol) KCONFIG:=CONFIG_NLS_ISO8859_15 FILES:=$(LINUX_DIR)/fs/nls/nls_iso8859-15.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,25,nls_iso8859-15) $(call KernelPackage/nls/Depends) endef define KernelPackage/nls-iso8859-15/description Kernel module for NLS ISO 8859-15 (Latin 9) endef $(eval $(call KernelPackage,nls-iso8859-15)) define KernelPackage/nls-koi8r SUBMENU:=$(FS_MENU) TITLE:=KOI8-R (Russian) KCONFIG:=CONFIG_NLS_KOI8_R FILES:=$(LINUX_DIR)/fs/nls/nls_koi8-r.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,25,nls_koi8-r) $(call KernelPackage/nls/Depends) endef define KernelPackage/nls-koi8r/description Kernel module for NLS KOI8-R (Russian) endef $(eval $(call KernelPackage,nls-koi8r)) define KernelPackage/nls-utf8 SUBMENU:=$(FS_MENU) TITLE:=UTF-8 KCONFIG:=CONFIG_NLS_UTF8 FILES:=$(LINUX_DIR)/fs/nls/nls_utf8.$(LINUX_KMOD_SUFFIX) AUTOLOAD:=$(call AutoLoad,25,nls_utf8) $(call KernelPackage/nls/Depends) endef define KernelPackage/nls-utf8/description Kernel module for NLS UTF-8 endef $(eval $(call KernelPackage,nls-utf8)) 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
/*
 *  Button Hotplug driver
 *
 *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
 *
 *  Based on the diag.c - GPIO interface driver for Broadcom boards
 *    Copyright (C) 2006 Mike Baker <mbm@openwrt.org>,
 *    Copyright (C) 2006-2007 Felix Fietkau <nbd@openwrt.org>
 *    Copyright (C) 2008 Andy Boyett <agb@openwrt.org>
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License version 2 as published
 *  by the Free Software Foundation.
 */

#include <linux/module.h>
#include <linux/version.h>
#include <linux/kmod.h>
#include <linux/input.h>

#include <linux/workqueue.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/kobject.h>

#define DRV_NAME	"button-hotplug"
#define DRV_VERSION	"0.4.1"
#define DRV_DESC	"Button Hotplug driver"

#define BH_SKB_SIZE	2048

#define PFX	DRV_NAME ": "

#undef BH_DEBUG

#ifdef BH_DEBUG
#define BH_DBG(fmt, args...) printk(KERN_DEBUG "%s: " fmt, DRV_NAME, ##args )
#else
#define BH_DBG(fmt, args...) do {} while (0)
#endif

#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, DRV_NAME, ##args )

#ifndef BIT_MASK
#define BIT_MASK(nr)            (1UL << ((nr) % BITS_PER_LONG))
#endif

struct bh_priv {
	unsigned long		*seen;
	struct input_handle	handle;
};

struct bh_event {
	const char		*name;
	char			*action;
	unsigned long		seen;

	struct sk_buff		*skb;
	struct work_struct	work;
};

struct bh_map {
	unsigned int	code;
	const char	*name;
};

extern u64 uevent_next_seqnum(void);

#define BH_MAP(_code, _name)		\
	{				\
		.code = (_code),	\
		.name = (_name),	\
	}

static struct bh_map button_map[] = {
	BH_MAP(BTN_0,		"BTN_0"),
	BH_MAP(BTN_1,		"BTN_1"),
	BH_MAP(BTN_2,		"BTN_2"),
	BH_MAP(BTN_3,		"BTN_3"),
	BH_MAP(BTN_4,		"BTN_4"),
	BH_MAP(BTN_5,		"BTN_5"),
	BH_MAP(BTN_6,		"BTN_6"),
	BH_MAP(BTN_7,		"BTN_7"),
	BH_MAP(BTN_8,		"BTN_8"),
	BH_MAP(BTN_9,		"BTN_9"),
	BH_MAP(KEY_RESTART,	"reset"),
	BH_MAP(KEY_POWER,	"power"),
	BH_MAP(KEY_RFKILL,	"rfkill"),
	BH_MAP(KEY_WPS_BUTTON,	"wps"),
	BH_MAP(KEY_WIMAX,	"wwan"),
};

/* -------------------------------------------------------------------------*/

static int bh_event_add_var(struct bh_event *event, int argv,
		const char *format, ...)
{
	static char buf[128];
	char *s;
	va_list args;
	int len;

	if (argv)
		return 0;

	va_start(args, format);
	len = vsnprintf(buf, sizeof(buf), format, args);
	va_end(args);

	if (len >= sizeof(buf)) {
		BH_ERR("buffer size too small\n");
		WARN_ON(1);
		return -ENOMEM;
	}

	s = skb_put(event->skb, len + 1);
	strcpy(s, buf);

	BH_DBG("added variable '%s'\n", s);

	return 0;
}

static int button_hotplug_fill_event(struct bh_event *event)
{
	int ret;

	ret = bh_event_add_var(event, 0, "HOME=%s", "/");
	if (ret)
		return ret;

	ret = bh_event_add_var(event, 0, "PATH=%s",
					"/sbin:/bin:/usr/sbin:/usr/bin");
	if (ret)
		return ret;

	ret = bh_event_add_var(event, 0, "SUBSYSTEM=%s", "button");
	if (ret)
		return ret;

	ret = bh_event_add_var(event, 0, "ACTION=%s", event->action);
	if (ret)
		return ret;

	ret = bh_event_add_var(event, 0, "BUTTON=%s", event->name);
	if (ret)
		return ret;

	ret = bh_event_add_var(event, 0, "SEEN=%ld", event->seen);
	if (ret)
		return ret;

	ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());

	return ret;
}

static void button_hotplug_work(struct work_struct *work)
{
	struct bh_event *event = container_of(work, struct bh_event, work);
	int ret = 0;

	event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
	if (!event->skb)
		goto out_free_event;

	ret = bh_event_add_var(event, 0, "%s@", event->action);
	if (ret)
		goto out_free_skb;

	ret = button_hotplug_fill_event(event);
	if (ret)
		goto out_free_skb;

	NETLINK_CB(event->skb).dst_group = 1;
	broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);

 out_free_skb:
	if (ret) {
		BH_ERR("work error %d\n", ret);
		kfree_skb(event->skb);
	}
 out_free_event:
	kfree(event);
}

static int button_hotplug_create_event(const char *name, unsigned long seen,
		int pressed)
{
	struct bh_event *event;

	BH_DBG("create event, name=%s, seen=%lu, pressed=%d\n",
		name, seen, pressed);

	event = kzalloc(sizeof(*event), GFP_KERNEL);
	if (!event)
		return -ENOMEM;

	event->name = name;
	event->seen = seen;
	event->action = pressed ? "pressed" : "released";

	INIT_WORK(&event->work, (void *)(void *)button_hotplug_work);
	schedule_work(&event->work);

	return 0;
}

/* -------------------------------------------------------------------------*/

static int button_get_index(unsigned int code)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(button_map); i++)
		if (button_map[i].code == code)
			return i;

	return -1;
}
static void button_hotplug_event(struct input_handle *handle,
			   unsigned int type, unsigned int code, int value)
{
	struct bh_priv *priv = handle->private;
	unsigned long seen = jiffies;
	int btn;

	BH_DBG("event type=%u, code=%u, value=%d\n", type, code, value);

	if (type != EV_KEY)
		return;

	btn = button_get_index(code);
	if (btn < 0)
		return;

	button_hotplug_create_event(button_map[btn].name,
			(seen - priv->seen[btn]) / HZ, value);
	priv->seen[btn] = seen;
}

static int button_hotplug_connect(struct input_handler *handler,
		struct input_dev *dev, const struct input_device_id *id)
{
	struct bh_priv *priv;
	int ret;
	int i;

	for (i = 0; i < ARRAY_SIZE(button_map); i++)
		if (test_bit(button_map[i].code, dev->keybit))
			break;

	if (i == ARRAY_SIZE(button_map))
		return -ENODEV;

	priv = kzalloc(sizeof(*priv) +
		       (sizeof(unsigned long) * ARRAY_SIZE(button_map)),
		       GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	priv->seen = (unsigned long *) &priv[1];
	priv->handle.private = priv;
	priv->handle.dev = dev;
	priv->handle.handler = handler;
	priv->handle.name = DRV_NAME;

	ret = input_register_handle(&priv->handle);
	if (ret)
		goto err_free_priv;

	ret = input_open_device(&priv->handle);
	if (ret)
		goto err_unregister_handle;

	BH_DBG("connected to %s\n", dev->name);

	return 0;

 err_unregister_handle:
	input_unregister_handle(&priv->handle);

 err_free_priv:
	kfree(priv);
	return ret;
}

static void button_hotplug_disconnect(struct input_handle *handle)
{
	struct bh_priv *priv = handle->private;

	input_close_device(handle);
	input_unregister_handle(handle);

	kfree(priv);
}

static const struct input_device_id button_hotplug_ids[] = {
	{
                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
                .evbit = { BIT_MASK(EV_KEY) },
        },
	{
		/* Terminating entry */
	},
};

MODULE_DEVICE_TABLE(input, button_hotplug_ids);

static struct input_handler button_hotplug_handler = {
	.event =	button_hotplug_event,
	.connect =	button_hotplug_connect,
	.disconnect =	button_hotplug_disconnect,
	.name =		DRV_NAME,
	.id_table =	button_hotplug_ids,
};

/* -------------------------------------------------------------------------*/

static int __init button_hotplug_init(void)
{
	int ret;

	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
	ret = input_register_handler(&button_hotplug_handler);
	if (ret)
		BH_ERR("unable to register input handler\n");

	return ret;
}
module_init(button_hotplug_init);

static void __exit button_hotplug_exit(void)
{
	input_unregister_handler(&button_hotplug_handler);
}
module_exit(button_hotplug_exit);

MODULE_DESCRIPTION(DRV_DESC);
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
MODULE_LICENSE("GPL v2");