diff options
| author | Miguel Ojeda <ojeda@kernel.org> | 2026-08-16 15:32:33 +0200 |
|---|---|---|
| committer | Miguel Ojeda <ojeda@kernel.org> | 2026-08-23 21:27:17 +0200 |
| commit | 5febf432df1cfa5b25d99b54c32103fafbdd0eb9 (patch) | |
| tree | 93a1ed1d337bc53adf1e572c2586d347703b286e /drivers/hid/hid-roccat-lua.c | |
| download | linux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.tar.gz linux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.zip | |
kbuild: rust: keep Rust objects out of Clang LTO with inline helpersgrafted
Under `CONFIG_LTO_CLANG` + `CONFIG_RUST_INLINE_HELPERS`, one may hit
`objtool` errors such as:
vmlinux.o: error: objtool: _R..._3Gsp4boot+0xd6a:
can't find jump dest instruction at .text._R..._3Gsp4boot+0x1dfd
The reason is that in such builds, the Clang invocation that compiles
the combined Rust plus helpers bitcode emits LLVM bitcode (again) --
the final code generation happens in the linker's LTO step, which the
`-mllvm` trap options passed to Clang do not reach.
This, in turn, means that unreachable traps are missing, and the
impossible paths do not merely fallthrough to the next symbol, but past
the end of their own section, since LTO builds place each function in
its own section.
Thus filter `CC_FLAGS_LTO` out of the Clang invocation, so that it always
emits machine code directly, with the traps in place.
Assisted-by: LLM
Cc: Gary Guo <gary@garyguo.net>
Cc: Boqun Feng <boqun@kernel.org>
Cc: Alice Ryhl <aliceryhl@google.com>
Cc: Matthew Maurer <mmaurer@google.com>
Cc: Josh Poimboeuf <jpoimboe@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: stable@vger.kernel.org
Fixes: 3a2486cc1da5 ("kbuild: rust: provide an option to inline C helpers into Rust")
Acked-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260816133233.197500-2-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Diffstat (limited to 'drivers/hid/hid-roccat-lua.c')
| -rw-r--r-- | drivers/hid/hid-roccat-lua.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/drivers/hid/hid-roccat-lua.c b/drivers/hid/hid-roccat-lua.c new file mode 100644 index 000000000..8e35e1a06 --- /dev/null +++ b/drivers/hid/hid-roccat-lua.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Roccat Lua driver for Linux + * + * Copyright (c) 2012 Stefan Achatz <erazor_de@users.sourceforge.net> + */ + +/* + */ + +/* + * Roccat Lua is a gamer mouse which cpi, button and light settings can be + * configured. + */ + +#include <linux/device.h> +#include <linux/input.h> +#include <linux/hid.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/hid-roccat.h> +#include "hid-ids.h" +#include "hid-roccat-common.h" +#include "hid-roccat-lua.h" + +static ssize_t lua_sysfs_read(struct file *fp, struct kobject *kobj, + char *buf, loff_t off, size_t count, + size_t real_size, uint command) +{ + struct device *dev = kobj_to_dev(kobj); + struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev)); + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); + int retval; + + if (off >= real_size) + return 0; + + if (off != 0 || count != real_size) + return -EINVAL; + + mutex_lock(&lua->lua_lock); + retval = roccat_common2_receive(usb_dev, command, buf, real_size); + mutex_unlock(&lua->lua_lock); + + return retval ? retval : real_size; +} + +static ssize_t lua_sysfs_write(struct file *fp, struct kobject *kobj, + void const *buf, loff_t off, size_t count, + size_t real_size, uint command) +{ + struct device *dev = kobj_to_dev(kobj); + struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev)); + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); + int retval; + + if (off != 0 || count != real_size) + return -EINVAL; + + mutex_lock(&lua->lua_lock); + retval = roccat_common2_send(usb_dev, command, buf, real_size); + mutex_unlock(&lua->lua_lock); + + return retval ? retval : real_size; +} + +#define LUA_SYSFS_W(thingy, THINGY) \ +static ssize_t lua_sysfs_write_ ## thingy(struct file *fp, \ + struct kobject *kobj, const struct bin_attribute *attr, \ + char *buf, loff_t off, size_t count) \ +{ \ + return lua_sysfs_write(fp, kobj, buf, off, count, \ + LUA_SIZE_ ## THINGY, LUA_COMMAND_ ## THINGY); \ +} + +#define LUA_SYSFS_R(thingy, THINGY) \ +static ssize_t lua_sysfs_read_ ## thingy(struct file *fp, \ + struct kobject *kobj, const struct bin_attribute *attr, \ + char *buf, loff_t off, size_t count) \ +{ \ + return lua_sysfs_read(fp, kobj, buf, off, count, \ + LUA_SIZE_ ## THINGY, LUA_COMMAND_ ## THINGY); \ +} + +#define LUA_BIN_ATTRIBUTE_RW(thingy, THINGY) \ +LUA_SYSFS_W(thingy, THINGY) \ +LUA_SYSFS_R(thingy, THINGY) \ +static const struct bin_attribute lua_ ## thingy ## _attr = { \ + .attr = { .name = #thingy, .mode = 0660 }, \ + .size = LUA_SIZE_ ## THINGY, \ + .read = lua_sysfs_read_ ## thingy, \ + .write = lua_sysfs_write_ ## thingy \ +}; + +LUA_BIN_ATTRIBUTE_RW(control, CONTROL) + +static int lua_create_sysfs_attributes(struct usb_interface *intf) +{ + return sysfs_create_bin_file(&intf->dev.kobj, &lua_control_attr); +} + +static void lua_remove_sysfs_attributes(struct usb_interface *intf) +{ + sysfs_remove_bin_file(&intf->dev.kobj, &lua_control_attr); +} + +static int lua_init_lua_device_struct(struct usb_device *usb_dev, + struct lua_device *lua) +{ + mutex_init(&lua->lua_lock); + + return 0; +} + +static int lua_init_specials(struct hid_device *hdev) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *usb_dev = interface_to_usbdev(intf); + struct lua_device *lua; + int retval; + + lua = kzalloc_obj(*lua); + if (!lua) { + hid_err(hdev, "can't alloc device descriptor\n"); + return -ENOMEM; + } + hid_set_drvdata(hdev, lua); + + retval = lua_init_lua_device_struct(usb_dev, lua); + if (retval) { + hid_err(hdev, "couldn't init struct lua_device\n"); + goto exit; + } + + retval = lua_create_sysfs_attributes(intf); + if (retval) { + hid_err(hdev, "cannot create sysfs files\n"); + goto exit; + } + + return 0; +exit: + kfree(lua); + return retval; +} + +static void lua_remove_specials(struct hid_device *hdev) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct lua_device *lua; + + lua_remove_sysfs_attributes(intf); + + lua = hid_get_drvdata(hdev); + kfree(lua); +} + +static int lua_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int retval; + + if (!hid_is_usb(hdev)) + return -EINVAL; + + retval = hid_parse(hdev); + if (retval) { + hid_err(hdev, "parse failed\n"); + goto exit; + } + + retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (retval) { + hid_err(hdev, "hw start failed\n"); + goto exit; + } + + retval = lua_init_specials(hdev); + if (retval) { + hid_err(hdev, "couldn't install mouse\n"); + goto exit_stop; + } + + return 0; + +exit_stop: + hid_hw_stop(hdev); +exit: + return retval; +} + +static void lua_remove(struct hid_device *hdev) +{ + lua_remove_specials(hdev); + hid_hw_stop(hdev); +} + +static const struct hid_device_id lua_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) }, + { } +}; + +MODULE_DEVICE_TABLE(hid, lua_devices); + +static struct hid_driver lua_driver = { + .name = "lua", + .id_table = lua_devices, + .probe = lua_probe, + .remove = lua_remove +}; +module_hid_driver(lua_driver); + +MODULE_AUTHOR("Stefan Achatz"); +MODULE_DESCRIPTION("USB Roccat Lua driver"); +MODULE_LICENSE("GPL v2"); |
