From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: Pauli Virtanen <pav@iki.fi>
Cc: linux-bluetooth@vger.kernel.org
Subject: Re: [PATCH BlueZ v5 4/7] shared/uinput-util: extract uinput utility function from AVCTP
Date: Fri, 12 Dec 2025 11:07:40 -0500 [thread overview]
Message-ID: <CABBYNZJe58G1xg0-4eu7ZRiA8kTLL-6g2fm-81bAwVZj3P56rw@mail.gmail.com> (raw)
In-Reply-To: <081f864de65d00f024fd2418cafd2309eef5dc67.camel@iki.fi>
Hi Pauli,
On Thu, Dec 11, 2025 at 5:50 PM Pauli Virtanen <pav@iki.fi> wrote:
>
> to, 2025-12-11 kello 17:05 -0500, Luiz Augusto von Dentz kirjoitti:
> > Hi Pauli,
> >
> > On Thu, Dec 11, 2025 at 3:16 PM Pauli Virtanen <pav@iki.fi> wrote:
> > >
> > > Extract uinput utility function from AVCTP to src/shared so that it can
> > > be reused for MCS.
> > > ---
> > > Makefile.am | 4 +-
> > > src/shared/uinput-util.c | 191 +++++++++++++++++++++++++++++++++++++++
> > > src/shared/uinput-util.h | 31 +++++++
> > > 3 files changed, 225 insertions(+), 1 deletion(-)
> > > create mode 100644 src/shared/uinput-util.c
> > > create mode 100644 src/shared/uinput-util.h
> > >
> > > diff --git a/Makefile.am b/Makefile.am
> > > index ba0262d5f..4c7177886 100644
> > > --- a/Makefile.am
> > > +++ b/Makefile.am
> > > @@ -247,7 +247,9 @@ shared_sources = src/shared/io.h src/shared/timeout.h \
> > > src/shared/lc3.h src/shared/tty.h \
> > > src/shared/bap-defs.h \
> > > src/shared/asha.h src/shared/asha.c \
> > > - src/shared/battery.h src/shared/battery.c
> > > + src/shared/battery.h src/shared/battery.c \
> > > + src/shared/uinput-util.h \
> > > + src/shared/uinput-util.c
> > >
> > > if READLINE
> > > shared_sources += src/shared/shell.c src/shared/shell.h
> > > diff --git a/src/shared/uinput-util.c b/src/shared/uinput-util.c
> > > new file mode 100644
> > > index 000000000..4e9644661
> > > --- /dev/null
> > > +++ b/src/shared/uinput-util.c
> > > @@ -0,0 +1,191 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > +/*
> > > + *
> > > + * BlueZ - Bluetooth protocol stack for Linux
> > > + *
> > > + * Copyright (C) 2006-2010 Nokia Corporation
> > > + * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
> > > + * Copyright (C) 2011 Texas Instruments, Inc.
> > > + *
> > > + *
> > > + */
> > > +
> > > +#ifdef HAVE_CONFIG_H
> > > +#include <config.h>
> > > +#endif
> > > +
> > > +#include <unistd.h>
> > > +#include <fcntl.h>
> > > +#include <sys/ioctl.h>
> > > +#include <errno.h>
> > > +#include <string.h>
> > > +#include <stdio.h>
> > > +#include <stdarg.h>
> > > +#include <linux/uinput.h>
> > > +
> > > +#include "bluetooth/bluetooth.h"
> > > +
> > > +#include "src/shared/util.h"
> > > +#include "src/shared/uinput-util.h"
> > > +
> > > +
> > > +#define DBG(uinput, fmt, arg...) \
> > > + uinput_debug(uinput->debug_func, uinput->debug_data, "%s:%s() " fmt, \
> > > + __FILE__, __func__, ## arg)
> > > +
> > > +struct bt_uinput {
> > > + int fd;
> > > + bt_uinput_debug_func_t debug_func;
> > > + void *debug_data;
> > > +};
> > > +
> > > +static void uinput_debug(bt_uinput_debug_func_t debug_func, void *debug_data,
> > > + const char *format, ...)
> > > +{
> > > + va_list ap;
> > > +
> > > + if (!debug_func || !format)
> > > + return;
> > > +
> > > + va_start(ap, format);
> > > + util_debug_va(debug_func, debug_data, format, ap);
> > > + va_end(ap);
> > > +}
> > > +
> > > +static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
> > > +{
> > > + struct input_event event;
> > > +
> > > + memset(&event, 0, sizeof(event));
> > > + event.type = type;
> > > + event.code = code;
> > > + event.value = value;
> > > +
> > > + return write(fd, &event, sizeof(event));
> > > +}
> > > +
> > > +void bt_uinput_send_key(struct bt_uinput *uinput, uint16_t key, bool pressed)
> > > +{
> > > + if (!uinput)
> > > + return;
> > > +
> > > + DBG(uinput, "%d", key);
> > > +
> > > + send_event(uinput->fd, EV_KEY, key, pressed ? 1 : 0);
> > > + send_event(uinput->fd, EV_SYN, SYN_REPORT, 0);
> > > +}
> > > +
> > > +struct bt_uinput *bt_uinput_new(const char *name, const char *suffix,
> > > + const bdaddr_t *addr,
> > > + const struct input_id *dev_id,
> > > + const struct bt_uinput_key_map *key_map,
> > > + bt_uinput_debug_func_t debug,
> > > + void *user_data)
> > > +{
> > > + struct bt_uinput *uinput;
> > > + struct uinput_user_dev dev;
> > > + int fd, err, i;
> > > + char src[18];
> > > +
> > > + uinput = new0(struct bt_uinput, 1);
> > > + uinput->debug_func = debug;
> > > + uinput->debug_data = user_data;
> > > +
> > > + fd = open("/dev/uinput", O_RDWR);
> > > + if (fd < 0) {
> > > + fd = open("/dev/input/uinput", O_RDWR);
> > > + if (fd < 0) {
> > > + fd = open("/dev/misc/uinput", O_RDWR);
> > > + if (fd < 0) {
> > > + err = errno;
> > > + DBG(uinput, "Can't open input device: %s (%d)",
> > > + strerror(err), err);
> > > + free(uinput);
> >
> > It is probably worth reordering the uinput allocation so it is after
> > the open, that way we don't need to free on bail out.
>
> This is on purpose for the DBG macro, so I'd not change it.
Just to be able to print that uinput was not be able to be open? I
suspect we want to decouple the opening of the uinput with the device
creation, like it is done in bt_uhid.
>
> > > + errno = err;
> > > + return NULL;
> > > + }
> > > + }
> > > + }
> > > +
> > > + memset(&dev, 0, sizeof(dev));
> > > +
> > > + if (name)
> > > + snprintf(dev.name, UINPUT_MAX_NAME_SIZE, "%s", name);
> > > +
> > > + if (suffix) {
> > > + int len, slen;
> > > +
> > > + len = strlen(dev.name);
> > > + slen = strlen(suffix);
> > > +
> > > + /* If name + suffix don't fit, truncate the name, then add the
> > > + * suffix.
> > > + */
> > > + if (slen >= UINPUT_MAX_NAME_SIZE)
> > > + slen = UINPUT_MAX_NAME_SIZE - 1;
> > > + if (len > UINPUT_MAX_NAME_SIZE - slen - 1)
> > > + len = UINPUT_MAX_NAME_SIZE - slen - 1;
> > > +
> > > + snprintf(dev.name + len, UINPUT_MAX_NAME_SIZE - len,
> > > + "%s", suffix);
> > > + }
> > > +
> > > + if (dev_id) {
> > > + dev.id.bustype = dev_id->bustype;
> > > + dev.id.vendor = dev_id->vendor;
> > > + dev.id.product = dev_id->product;
> > > + dev.id.version = dev_id->version;
> > > + } else {
> > > + dev.id.bustype = BUS_VIRTUAL;
> > > + }
> > > +
> > > + if (write(fd, &dev, sizeof(dev)) < 0) {
> > > + err = errno;
> > > + DBG(uinput, "Can't write device information: %s (%d)",
> > > + strerror(err), err);
> > > + close(fd);
> > > + free(uinput);
> > > + errno = err;
> > > + return NULL;
> > > + }
> > > +
> > > + ioctl(fd, UI_SET_EVBIT, EV_KEY);
> > > + ioctl(fd, UI_SET_EVBIT, EV_REL);
> > > + ioctl(fd, UI_SET_EVBIT, EV_REP);
> > > + ioctl(fd, UI_SET_EVBIT, EV_SYN);
> > > +
> > > + ba2strlc(addr, src);
> > > + ioctl(fd, UI_SET_PHYS, src);
> > > +
> > > + for (i = 0; key_map[i].name != NULL; i++)
> > > + ioctl(fd, UI_SET_KEYBIT, key_map[i].uinput);
> > > +
> > > + if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
> > > + err = errno;
> > > + DBG(uinput, "Can't create uinput device: %s (%d)",
> > > + strerror(err), err);
> > > + close(fd);
> > > + free(uinput);
> > > + errno = err;
> > > + return NULL;
> > > + }
> > > +
> > > + send_event(fd, EV_REP, REP_DELAY, 300);
> > > +
> > > + DBG(uinput, "%p", uinput);
> > > +
> > > + uinput->fd = fd;
> > > + return uinput;
> > > +}
> > > +
> > > +void bt_uinput_destroy(struct bt_uinput *uinput)
> > > +{
> > > + if (!uinput)
> > > + return;
> > > +
> > > + DBG(uinput, "%p", uinput);
> > > +
> > > + ioctl(uinput->fd, UI_DEV_DESTROY);
> > > + close(uinput->fd);
> > > + free(uinput);
> > > +}
> > > diff --git a/src/shared/uinput-util.h b/src/shared/uinput-util.h
> > > new file mode 100644
> > > index 000000000..fb8f7e6bd
> > > --- /dev/null
> > > +++ b/src/shared/uinput-util.h
> > > @@ -0,0 +1,31 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> >
> > In theory we should only place LGPL code into src/shared, now I see we
> > are copying some code thus it should continue using the same license
> > as the original code, but perhaps it is worth reworking the copied
> > code since it is quite simple and I think it is worth it to not
> > contaminate shared library with GPL.
>
> That, or decide it's small enough to not be copyrightable, given it's
> anyway partly rewritten already.
Yeah, most of the existing code comes from code snips from uinput
documentation anyway and since we are doing many changes to the code I
think it is probably safe to relicense under LGPL.
> > > +/*
> > > + *
> > > + * BlueZ - Bluetooth protocol stack for Linux
> > > + *
> > > + * Copyright (C) 2006-2010 Nokia Corporation
> > > + * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
> > > + * Copyright (C) 2011 Texas Instruments, Inc.
> > > + *
> > > + *
> > > + */
> > > +
> > > +struct bt_uinput;
> > > +
> > > +struct bt_uinput_key_map {
> > > + const char *name;
> > > + unsigned int code;
> > > + uint16_t uinput;
> > > +};
> > > +
> > > +typedef void (*bt_uinput_debug_func_t)(const char *str, void *user_data);
> > > +
> > > +struct bt_uinput *bt_uinput_new(const char *name, const char *suffix,
> > > + const bdaddr_t *addr,
> > > + const struct input_id *dev_id,
> > > + const struct bt_uinput_key_map *key_map,
> > > + bt_uinput_debug_func_t debug,
> > > + void *user_data);
> >
> > I'd leave the debug function to be initialized with its own function
> > (e.g. bt_uinput_set_debug).
> >
> > > +void bt_uinput_destroy(struct bt_uinput *uinput);
> > > +
> > > +void bt_uinput_send_key(struct bt_uinput *uinput, uint16_t key, bool pressed);
> > > --
> > > 2.51.1
> > >
> > >
> >
>
> --
> Pauli Virtanen
>
>
--
Luiz Augusto von Dentz
next prev parent reply other threads:[~2025-12-12 16:07 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-11 20:15 [PATCH BlueZ v5 0/7] mcp: support multiple MCP and implement local GMCS Pauli Virtanen
2025-12-11 20:15 ` [PATCH BlueZ v5 1/7] shared/mcp: support multiple MCP, and add non-stub MCS server Pauli Virtanen
2025-12-12 15:17 ` Luiz Augusto von Dentz
2025-12-12 15:50 ` Pauli Virtanen
2025-12-12 15:57 ` Luiz Augusto von Dentz
2025-12-11 20:15 ` [PATCH BlueZ v5 2/7] test-mcp: add tests for MCP / MCS Pauli Virtanen
2025-12-11 20:15 ` [PATCH BlueZ v5 3/7] mcp: adapt to new MCP API to support multiple remote MCS services Pauli Virtanen
2025-12-11 20:15 ` [PATCH BlueZ v5 4/7] shared/uinput-util: extract uinput utility function from AVCTP Pauli Virtanen
2025-12-11 22:05 ` Luiz Augusto von Dentz
2025-12-11 22:48 ` Pauli Virtanen
2025-12-12 16:07 ` Luiz Augusto von Dentz [this message]
2025-12-11 20:15 ` [PATCH BlueZ v5 5/7] avctp: use uinput utilities from src/shared Pauli Virtanen
2025-12-11 20:15 ` [PATCH BlueZ v5 6/7] mcp: add local GMCS service that emits uinput media keys Pauli Virtanen
2025-12-11 20:15 ` [PATCH BlueZ v5 7/7] shared/gatt-client: fix notify_data leak in notify_data_write_ccc Pauli Virtanen
2025-12-12 15:30 ` [PATCH BlueZ v5 0/7] mcp: support multiple MCP and implement local GMCS patchwork-bot+bluetooth
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CABBYNZJe58G1xg0-4eu7ZRiA8kTLL-6g2fm-81bAwVZj3P56rw@mail.gmail.com \
--to=luiz.dentz@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=pav@iki.fi \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).