summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2023-03-02 11:55:54 +0100
committerBenjamin Tissoires <benjamin.tissoires@redhat.com>2023-04-03 13:30:32 +0200
commit0a4db185f0788dfc828512d0004c468921bf6c0a (patch)
tree9cb7f43786b627a3d111bf21e59a76e76d7f4286
parentf98e0640c5c6b8bb00336dae8d06ede862754c28 (diff)
USB: core: Add API to change the wireless_status
This adds the API that allows device specific drivers to tell user-space about whether the wireless device is connected to its receiver dongle. See "USB: core: Add wireless_status sysfs attribute" for a detailed explanation of what this attribute should be used for. Signed-off-by: Bastien Nocera <hadess@hadess.net> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/20230302105555.51417-5-hadess@hadess.net Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
-rw-r--r--drivers/usb/core/message.c40
-rw-r--r--include/linux/usb.h5
2 files changed, 45 insertions, 0 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index cc404bb7e8f7..33392a6f4972 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1908,6 +1908,45 @@ static void __usb_queue_reset_device(struct work_struct *ws)
usb_put_intf(iface); /* Undo _get_ in usb_queue_reset_device() */
}
+/*
+ * Internal function to set the wireless_status sysfs attribute
+ * See usb_set_wireless_status() for more details
+ */
+static void __usb_wireless_status_intf(struct work_struct *ws)
+{
+ struct usb_interface *iface =
+ container_of(ws, struct usb_interface, wireless_status_work);
+
+ device_lock(iface->dev.parent);
+ if (iface->sysfs_files_created)
+ usb_update_wireless_status_attr(iface);
+ device_unlock(iface->dev.parent);
+ usb_put_intf(iface); /* Undo _get_ in usb_set_wireless_status() */
+}
+
+/**
+ * usb_set_wireless_status - sets the wireless_status struct member
+ * @dev: the device to modify
+ * @status: the new wireless status
+ *
+ * Set the wireless_status struct member to the new value, and emit
+ * sysfs changes as necessary.
+ *
+ * Returns: 0 on success, -EALREADY if already set.
+ */
+int usb_set_wireless_status(struct usb_interface *iface,
+ enum usb_wireless_status status)
+{
+ if (iface->wireless_status == status)
+ return -EALREADY;
+
+ usb_get_intf(iface);
+ iface->wireless_status = status;
+ schedule_work(&iface->wireless_status_work);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_set_wireless_status);
/*
* usb_set_configuration - Makes a particular device setting be current
@@ -2100,6 +2139,7 @@ free_interfaces:
intf->dev.type = &usb_if_device_type;
intf->dev.groups = usb_interface_groups;
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
+ INIT_WORK(&intf->wireless_status_work, __usb_wireless_status_intf);
intf->minor = -1;
device_initialize(&intf->dev);
pm_runtime_no_callbacks(&intf->dev);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index eee54cc961b4..6dfd59d3d695 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -262,6 +262,7 @@ struct usb_interface {
unsigned resetting_device:1; /* true: bandwidth alloc after reset */
unsigned authorized:1; /* used for interface authorization */
enum usb_wireless_status wireless_status;
+ struct work_struct wireless_status_work;
struct device dev; /* interface specific device info */
struct device *usb_dev;
@@ -896,6 +897,10 @@ static inline int usb_interface_claimed(struct usb_interface *iface)
extern void usb_driver_release_interface(struct usb_driver *driver,
struct usb_interface *iface);
+
+int usb_set_wireless_status(struct usb_interface *iface,
+ enum usb_wireless_status status);
+
const struct usb_device_id *usb_match_id(struct usb_interface *interface,
const struct usb_device_id *id);
extern int usb_match_one_id(struct usb_interface *interface,