diff options
| author | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 09:55:01 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 11:08:21 -0400 |
| commit | 4617721c502b2ddaa4e324e86da4997edf738fa5 (patch) | |
| tree | 350aa83b47da0b574a814795392b20b0bed83cbc /drivers/input/tablet/acecad.c | |
| download | linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.tar.gz linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.zip | |
ftrace: Synchronize the initialization of ftrace_opsgrafted
There's some internal state that ftrace_ops needs to have set, but since
it can be declared outside of the ftrace.c code, it calls
ftrace_ops_init() on the ops in every global function. The issue is that
if two tasks call it on the same ops at the same time it is possible to
have the initialization of one corrupt the initialization of the other
call.
Create a ops_mutex to use to synchronize every initialization of the
ftrace_ops. The mutex is taken within checking the ftrace_ops flag that
states it was initializied but the flag is checked again after the mutex
has been taken. Checking first outside the mutex allows it to shortcut
having to take the mutex. But then the check needs to be done again after
the mute is taken in case of races.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home
Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock")
Reported-by: sashiko-bot@kernel.org
Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'drivers/input/tablet/acecad.c')
| -rw-r--r-- | drivers/input/tablet/acecad.c | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c new file mode 100644 index 000000000..ba79dff21 --- /dev/null +++ b/drivers/input/tablet/acecad.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2001-2005 Edouard TISSERANT <edouard.tisserant@wanadoo.fr> + * Copyright (c) 2004-2005 Stephane VOLTZ <svoltz@numericable.fr> + * + * USB Acecad "Acecad Flair" tablet support + * + * Changelog: + * v3.2 - Added sysfs support + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/usb/input.h> + +MODULE_AUTHOR("Edouard TISSERANT <edouard.tisserant@wanadoo.fr>"); +MODULE_DESCRIPTION("USB Acecad Flair tablet driver"); +MODULE_LICENSE("GPL"); + +#define USB_VENDOR_ID_ACECAD 0x0460 +#define USB_DEVICE_ID_FLAIR 0x0004 +#define USB_DEVICE_ID_302 0x0008 + +struct usb_acecad { + char name[128]; + char phys[64]; + struct usb_interface *intf; + struct input_dev *input; + struct urb *irq; + + unsigned char *data; + dma_addr_t data_dma; +}; + +static void usb_acecad_irq(struct urb *urb) +{ + struct usb_acecad *acecad = urb->context; + unsigned char *data = acecad->data; + struct input_dev *dev = acecad->input; + struct usb_interface *intf = acecad->intf; + struct usb_device *udev = interface_to_usbdev(intf); + int prox, status; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n", + __func__, urb->status); + return; + default: + dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n", + __func__, urb->status); + goto resubmit; + } + + prox = (data[0] & 0x04) >> 2; + input_report_key(dev, BTN_TOOL_PEN, prox); + + if (prox) { + int x = data[1] | (data[2] << 8); + int y = data[3] | (data[4] << 8); + /* Pressure should compute the same way for flair and 302 */ + int pressure = data[5] | (data[6] << 8); + int touch = data[0] & 0x01; + int stylus = (data[0] & 0x10) >> 4; + int stylus2 = (data[0] & 0x20) >> 5; + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + input_report_abs(dev, ABS_PRESSURE, pressure); + input_report_key(dev, BTN_TOUCH, touch); + input_report_key(dev, BTN_STYLUS, stylus); + input_report_key(dev, BTN_STYLUS2, stylus2); + } + + /* event termination */ + input_sync(dev); + +resubmit: + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status) + dev_err(&intf->dev, + "can't resubmit intr, %s-%s/input0, status %d\n", + udev->bus->bus_name, + udev->devpath, status); +} + +static int usb_acecad_open(struct input_dev *dev) +{ + struct usb_acecad *acecad = input_get_drvdata(dev); + + acecad->irq->dev = interface_to_usbdev(acecad->intf); + if (usb_submit_urb(acecad->irq, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void usb_acecad_close(struct input_dev *dev) +{ + struct usb_acecad *acecad = input_get_drvdata(dev); + + usb_kill_urb(acecad->irq); +} + +static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_host_interface *interface = intf->cur_altsetting; + struct usb_endpoint_descriptor *endpoint; + struct usb_acecad *acecad; + struct input_dev *input_dev; + int pipe, maxp; + int err; + + if (interface->desc.bNumEndpoints != 1) + return -ENODEV; + + endpoint = &interface->endpoint[0].desc; + + if (!usb_endpoint_is_int_in(endpoint)) + return -ENODEV; + + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe); + + acecad = kzalloc_obj(*acecad); + input_dev = input_allocate_device(); + if (!acecad || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + acecad->data = usb_alloc_coherent(dev, 8, GFP_KERNEL, &acecad->data_dma); + if (!acecad->data) { + err= -ENOMEM; + goto fail1; + } + + acecad->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!acecad->irq) { + err = -ENOMEM; + goto fail2; + } + + acecad->intf = intf; + acecad->input = input_dev; + + if (dev->manufacturer) + strscpy(acecad->name, dev->manufacturer, sizeof(acecad->name)); + + if (dev->product) { + if (dev->manufacturer) + strlcat(acecad->name, " ", sizeof(acecad->name)); + strlcat(acecad->name, dev->product, sizeof(acecad->name)); + } + + usb_make_path(dev, acecad->phys, sizeof(acecad->phys)); + strlcat(acecad->phys, "/input0", sizeof(acecad->phys)); + + input_dev->name = acecad->name; + input_dev->phys = acecad->phys; + usb_to_input_id(dev, &input_dev->id); + input_dev->dev.parent = &intf->dev; + + input_set_drvdata(input_dev, acecad); + + input_dev->open = usb_acecad_open; + input_dev->close = usb_acecad_close; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_TOOL_PEN) | + BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS) | + BIT_MASK(BTN_STYLUS2); + + switch (id->driver_info) { + case 0: + input_set_abs_params(input_dev, ABS_X, 0, 5000, 4, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 3750, 4, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 512, 0, 0); + if (!strlen(acecad->name)) + snprintf(acecad->name, sizeof(acecad->name), + "USB Acecad Flair Tablet %04x:%04x", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + break; + + case 1: + input_set_abs_params(input_dev, ABS_X, 0, 53000, 4, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 2250, 4, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1024, 0, 0); + if (!strlen(acecad->name)) + snprintf(acecad->name, sizeof(acecad->name), + "USB Acecad 302 Tablet %04x:%04x", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + break; + } + + usb_fill_int_urb(acecad->irq, dev, pipe, + acecad->data, maxp > 8 ? 8 : maxp, + usb_acecad_irq, acecad, endpoint->bInterval); + acecad->irq->transfer_dma = acecad->data_dma; + acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + err = input_register_device(acecad->input); + if (err) + goto fail3; + + usb_set_intfdata(intf, acecad); + + return 0; + + fail3: usb_free_urb(acecad->irq); + fail2: usb_free_coherent(dev, 8, acecad->data, acecad->data_dma); + fail1: input_free_device(input_dev); + kfree(acecad); + return err; +} + +static void usb_acecad_disconnect(struct usb_interface *intf) +{ + struct usb_acecad *acecad = usb_get_intfdata(intf); + struct usb_device *udev = interface_to_usbdev(intf); + + usb_set_intfdata(intf, NULL); + + input_unregister_device(acecad->input); + usb_free_urb(acecad->irq); + usb_free_coherent(udev, 8, acecad->data, acecad->data_dma); + kfree(acecad); +} + +static const struct usb_device_id usb_acecad_id_table[] = { + { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 }, + { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302), .driver_info = 1 }, + { } +}; + +MODULE_DEVICE_TABLE(usb, usb_acecad_id_table); + +static struct usb_driver usb_acecad_driver = { + .name = "usb_acecad", + .probe = usb_acecad_probe, + .disconnect = usb_acecad_disconnect, + .id_table = usb_acecad_id_table, +}; + +module_usb_driver(usb_acecad_driver); |
