From 9cc63f8bcd560c760d0b12e15bba8f81c86237cf Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 14 Aug 2026 15:43:51 -0700 Subject: Merge branches 'expcb.2026.07.24a', 'misc.2026.07.30a', 'rcu-tasks.2026.07.30a', 'srcu.2026.08.11a' and 'torture.2026.08.14a' into HEAD Changes: Make expedited grace periods expedite normal RCU callbacks Miscellaneous fixes: * Improve diagnostic output with character task states. * Mark accesses to inform KCSAN of concurrency design. * Move from kmalloc() to kmalloc_obj(). * Documentation updates. * Improve handling of RCU deferred quiescent states. * Clean up unused function arguments and structure fields. * Reduce show_rcu_gp_kthreads() stack space. Tasks RCU updates: * Clean up after SRCU re-implementation of Tasks Trace RCU. * Mark accesses to inform KCSAN of concurrency design. * Add ->lazy_timer status to diagnostic output. * Remove an unnecessary memory barrier. * Fix a data race, courtesy of KCSAN. * Documentation updates. * Convert cond_resched_tasks_rcu_qs() from macro to static inline function. SRCU updates: * Add Rust helpers for SRCU. * Avoid losing queued work at cleanup_srcu_struct() time. Torture-test updates: * Preparation work for immediate RCU priority deboosting. * Test RCU readers from real interrupt handlers (as opposed to softirq). * Simplify code through use of cpumask_next_wrap(). * Improve diagnostic output with character task states. * Add rcutorture.nwriters parameter to allow lightweight stall testing, and rcutorture.stall_only to make doing so easier. * Test an RCU Tasks Trace grace period implying an RCU grace period. * Make RCU Tasks Trace torturing track reader batches. * Fix a data race, courtesy of KCSAN. * Plug a shuffle_tmp_mask memory leak on kthread spawn failure. --- drivers/hid/hid-roccat-lua.c | 215 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 drivers/hid/hid-roccat-lua.c (limited to 'drivers/hid/hid-roccat-lua.c') 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 + */ + +/* + */ + +/* + * Roccat Lua is a gamer mouse which cpi, button and light settings can be + * configured. + */ + +#include +#include +#include +#include +#include +#include +#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"); -- cgit v1.3.1