diff --git a/Kbuild b/Kbuild index b13b9e7e3..13f9a863d 100644 --- a/Kbuild +++ b/Kbuild @@ -44,4 +44,5 @@ obj-$(CONFIG_LUNATIK_FIFO) += lib/luafifo.o obj-$(CONFIG_LUNATIK_XTABLE) += lib/luaxtable.o obj-$(CONFIG_LUNATIK_NETFILTER) += lib/luanetfilter.o obj-$(CONFIG_LUNATIK_COMPLETION) += lib/luacompletion.o +obj-$(CONFIG_LUNATIK_HID) += lib/luahid.o diff --git a/Makefile b/Makefile index 2dae95c3f..ceba7c414 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,8 @@ all: lunatik_sym.h CONFIG_LUNATIK_RCU=m CONFIG_LUNATIK_THREAD=m CONFIG_LUNATIK_FIB=m \ CONFIG_LUNATIK_DATA=m CONFIG_LUNATIK_PROBE=m CONFIG_LUNATIK_SYSCALL=m \ CONFIG_LUNATIK_XDP=m CONFIG_LUNATIK_FIFO=m CONFIG_LUNATIK_XTABLE=m \ - CONFIG_LUNATIK_NETFILTER=m CONFIG_LUNATIK_COMPLETION=m + CONFIG_LUNATIK_NETFILTER=m CONFIG_LUNATIK_COMPLETION=m \ + CONFIG_LUNATIK_HID=m clean: ${MAKE} -C ${MODULES_BUILD_PATH} M=${PWD} clean diff --git a/bin/lunatik b/bin/lunatik index 696f79063..fe57eb49d 100755 --- a/bin/lunatik +++ b/bin/lunatik @@ -9,7 +9,7 @@ local lunatik = { device = "/dev/lunatik", modules = {"lunatik", "luadevice", "lualinux", "luanotifier", "luasocket", "luarcu", "luathread", "luafib", "luadata", "luaprobe", "luasyscall", "luaxdp", "luafifo", "luaxtable", - "luanetfilter", "luacompletion", "lunatik_run"} + "luanetfilter", "luacompletion", "luahid", "lunatik_run"} } function lunatik.prompt() diff --git a/lib/luahid.c b/lib/luahid.c new file mode 100755 index 000000000..24a4be666 --- /dev/null +++ b/lib/luahid.c @@ -0,0 +1,122 @@ +/* +* SPDX-FileCopyrightText: (c) 2025 Jieming Zhou +* SPDX-License-Identifier: MIT OR GPL-2.0-only +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +typedef struct luahid_s { + lunatik_object_t *runtime; + struct hid_driver driver; +} luahid_t; + +/* + * kernel codes copied from drivers/hid/hid-generic.c + * links: https://elixir.bootlin.com/linux/v6.13.7/source/drivers/hid/hid-generic.c + */ +static int hid_generic_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret; + + hdev->quirks |= HID_QUIRK_INPUT_PER_APP; + + ret = hid_parse(hdev); + if (ret) + return ret; + + return hid_hw_start(hdev, HID_CONNECT_DEFAULT); +} +static const struct hid_device_id hid_table[] = { + { HID_USB_DEVICE(0x046D, 0xC542) }, + { } +}; +MODULE_DEVICE_TABLE(hid, hid_table); + + +static void luahid_release(void *private) +{ + luahid_t *hid = (luahid_t *)private; + if (hid) { + hid_unregister_driver(&hid->driver); + lunatik_putobject(hid->runtime); + } +} + +static int luahid_register(lua_State *L); + +static const luaL_Reg luahid_lib[] = { + {"register", luahid_register}, + {NULL, NULL} +}; + +static const luaL_Reg luahid_mt[] = { + {"__gc", lunatik_deleteobject}, + {NULL, NULL} +}; + +static const lunatik_class_t luahid_class = { + .name = "hid", + .methods = luahid_mt, + .release = luahid_release, + .sleep = true, +}; + +static int luahid_register(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TTABLE); /* assure that is a driver */ + + lunatik_object_t *object = lunatik_newobject(L, &luahid_class, sizeof(luahid_t)); + luahid_t *hid = (luahid_t *)object->private; + + /* + * configure the driver's properties & callbacks + */ + struct hid_driver *user_driver = &(hid->driver); + user_driver -> name = lunatik_checkalloc(L, NAME_MAX); + lunatik_setstring(L, 1, user_driver, name, NAME_MAX); + user_driver -> id_table = hid_table; + user_driver -> probe = hid_generic_probe; + + lunatik_registerobject(L, 1, object); + + int ret = __hid_register_driver(user_driver, THIS_MODULE, KBUILD_MODNAME); + if (ret) { + lunatik_unregisterobject(L, object); + luaL_error(L, "failed to register hid driver: %s", user_driver->name); + } + lunatik_setruntime(L, hid, hid); + lunatik_getobject(hid->runtime); + return 1; /* object */ +} + +LUNATIK_NEWLIB(hid, luahid_lib, &luahid_class, NULL); + +static int __init luahid_init(void) +{ + return 0; +} + +static void __exit luahid_exit(void) +{ +} + +module_init(luahid_init); +module_exit(luahid_exit); +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_AUTHOR("Jieming Zhou "); + diff --git a/lib/luanetfilter.h b/lib/luanetfilter.h index d2ef7ad6b..e2c03d5f8 100644 --- a/lib/luanetfilter.h +++ b/lib/luanetfilter.h @@ -29,17 +29,6 @@ do { \ lua_pop(L, 1); \ } while (0) -#define lunatik_setstring(L, idx, hook, field, maxlen) \ -do { \ - size_t len; \ - lunatik_checkfield(L, idx, #field, LUA_TSTRING); \ - const char *str = lua_tolstring(L, -1, &len); \ - if (len > maxlen) \ - luaL_error(L, "'%s' is too long", #field); \ - strncpy((char *)hook->field, str, maxlen); \ - lua_pop(L, 1); \ -} while (0) - const lunatik_reg_t luanetfilter_family[] = { {"UNSPEC", NFPROTO_UNSPEC}, {"INET", NFPROTO_INET}, diff --git a/lunatik.h b/lunatik.h index 4103bdba0..a6bd8f8a3 100644 --- a/lunatik.h +++ b/lunatik.h @@ -283,6 +283,17 @@ static inline T checker(lua_State *L, int ix) \ #define lunatik_getregistry(L, key) lua_rawgetp((L), LUA_REGISTRYINDEX, (key)) +#define lunatik_setstring(L, idx, hook, field, maxlen) \ +do { \ + size_t len; \ + lunatik_checkfield(L, idx, #field, LUA_TSTRING); \ + const char *str = lua_tolstring(L, -1, &len); \ + if (len > maxlen) \ + luaL_error(L, "'%s' is too long", #field); \ + strncpy((char *)hook->field, str, maxlen); \ + lua_pop(L, 1); \ +} while (0) + static inline void lunatik_setregistry(lua_State *L, int ix, void *key) { lua_pushvalue(L, ix);