Commit 0549fbac authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'for-6.4/logitech-hidpp' into for-linus

- support for ADC measurement (Bastien Nocera)
- support for Logitech G935 (Bastien Nocera)
parents d411b5aa 539adfed
...@@ -166,6 +166,23 @@ Description: ...@@ -166,6 +166,23 @@ Description:
The file will be present for all speeds of USB devices, and will The file will be present for all speeds of USB devices, and will
always read "no" for USB 1.1 and USB 2.0 devices. always read "no" for USB 1.1 and USB 2.0 devices.
What: /sys/bus/usb/devices/<INTERFACE>/wireless_status
Date: February 2023
Contact: Bastien Nocera <hadess@hadess.net>
Description:
Some USB devices use a USB receiver dongle to communicate
wirelessly with their device using proprietary protocols. This
attribute allows user-space to know whether the device is
connected to its receiver dongle, and, for example, consider
the device to be absent when choosing whether to show the
device's battery, show a headset in a list of outputs, or show
an on-screen keyboard if the only wireless keyboard is
turned off.
This attribute is not to be used to replace protocol specific
statuses available in WWAN, WLAN/Wi-Fi, Bluetooth, etc.
If the device does not use a receiver dongle with a wireless
device, then this attribute will not exist.
What: /sys/bus/usb/devices/.../<hub_interface>/port<X> What: /sys/bus/usb/devices/.../<hub_interface>/port<X>
Date: August 2012 Date: August 2012
Contact: Lan Tianyu <tianyu.lan@intel.com> Contact: Lan Tianyu <tianyu.lan@intel.com>
......
This diff is collapsed.
...@@ -1908,6 +1908,45 @@ static void __usb_queue_reset_device(struct work_struct *ws) ...@@ -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() */ 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
* @iface: the interface 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 * usb_set_configuration - Makes a particular device setting be current
...@@ -2100,6 +2139,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -2100,6 +2139,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
intf->dev.type = &usb_if_device_type; intf->dev.type = &usb_if_device_type;
intf->dev.groups = usb_interface_groups; intf->dev.groups = usb_interface_groups;
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device); INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
INIT_WORK(&intf->wireless_status_work, __usb_wireless_status_intf);
intf->minor = -1; intf->minor = -1;
device_initialize(&intf->dev); device_initialize(&intf->dev);
pm_runtime_no_callbacks(&intf->dev); pm_runtime_no_callbacks(&intf->dev);
......
...@@ -1227,9 +1227,59 @@ static const struct attribute_group intf_assoc_attr_grp = { ...@@ -1227,9 +1227,59 @@ static const struct attribute_group intf_assoc_attr_grp = {
.is_visible = intf_assoc_attrs_are_visible, .is_visible = intf_assoc_attrs_are_visible,
}; };
static ssize_t wireless_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_interface *intf;
intf = to_usb_interface(dev);
if (intf->wireless_status == USB_WIRELESS_STATUS_DISCONNECTED)
return sysfs_emit(buf, "%s\n", "disconnected");
return sysfs_emit(buf, "%s\n", "connected");
}
static DEVICE_ATTR_RO(wireless_status);
static struct attribute *intf_wireless_status_attrs[] = {
&dev_attr_wireless_status.attr,
NULL
};
static umode_t intf_wireless_status_attr_is_visible(struct kobject *kobj,
struct attribute *a, int n)
{
struct device *dev = kobj_to_dev(kobj);
struct usb_interface *intf = to_usb_interface(dev);
if (a != &dev_attr_wireless_status.attr ||
intf->wireless_status != USB_WIRELESS_STATUS_NA)
return a->mode;
return 0;
}
static const struct attribute_group intf_wireless_status_attr_grp = {
.attrs = intf_wireless_status_attrs,
.is_visible = intf_wireless_status_attr_is_visible,
};
int usb_update_wireless_status_attr(struct usb_interface *intf)
{
struct device *dev = &intf->dev;
int ret;
ret = sysfs_update_group(&dev->kobj, &intf_wireless_status_attr_grp);
if (ret < 0)
return ret;
sysfs_notify(&dev->kobj, NULL, "wireless_status");
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
return 0;
}
const struct attribute_group *usb_interface_groups[] = { const struct attribute_group *usb_interface_groups[] = {
&intf_attr_grp, &intf_attr_grp,
&intf_assoc_attr_grp, &intf_assoc_attr_grp,
&intf_wireless_status_attr_grp,
NULL NULL
}; };
......
...@@ -15,6 +15,7 @@ extern int usb_create_sysfs_dev_files(struct usb_device *dev); ...@@ -15,6 +15,7 @@ extern int usb_create_sysfs_dev_files(struct usb_device *dev);
extern void usb_remove_sysfs_dev_files(struct usb_device *dev); extern void usb_remove_sysfs_dev_files(struct usb_device *dev);
extern void usb_create_sysfs_intf_files(struct usb_interface *intf); extern void usb_create_sysfs_intf_files(struct usb_interface *intf);
extern void usb_remove_sysfs_intf_files(struct usb_interface *intf); extern void usb_remove_sysfs_intf_files(struct usb_interface *intf);
extern int usb_update_wireless_status_attr(struct usb_interface *intf);
extern int usb_create_ep_devs(struct device *parent, extern int usb_create_ep_devs(struct device *parent,
struct usb_host_endpoint *endpoint, struct usb_host_endpoint *endpoint,
struct usb_device *udev); struct usb_device *udev);
......
...@@ -170,6 +170,12 @@ usb_find_last_int_out_endpoint(struct usb_host_interface *alt, ...@@ -170,6 +170,12 @@ usb_find_last_int_out_endpoint(struct usb_host_interface *alt,
return usb_find_common_endpoints_reverse(alt, NULL, NULL, NULL, int_out); return usb_find_common_endpoints_reverse(alt, NULL, NULL, NULL, int_out);
} }
enum usb_wireless_status {
USB_WIRELESS_STATUS_NA = 0,
USB_WIRELESS_STATUS_DISCONNECTED,
USB_WIRELESS_STATUS_CONNECTED,
};
/** /**
* struct usb_interface - what usb device drivers talk to * struct usb_interface - what usb device drivers talk to
* @altsetting: array of interface structures, one for each alternate * @altsetting: array of interface structures, one for each alternate
...@@ -197,6 +203,10 @@ usb_find_last_int_out_endpoint(struct usb_host_interface *alt, ...@@ -197,6 +203,10 @@ usb_find_last_int_out_endpoint(struct usb_host_interface *alt,
* following a reset or suspend operation it doesn't support. * following a reset or suspend operation it doesn't support.
* @authorized: This allows to (de)authorize individual interfaces instead * @authorized: This allows to (de)authorize individual interfaces instead
* a whole device in contrast to the device authorization. * a whole device in contrast to the device authorization.
* @wireless_status: if the USB device uses a receiver/emitter combo, whether
* the emitter is connected.
* @wireless_status_work: Used for scheduling wireless status changes
* from atomic context.
* @dev: driver model's view of this device * @dev: driver model's view of this device
* @usb_dev: if an interface is bound to the USB major, this will point * @usb_dev: if an interface is bound to the USB major, this will point
* to the sysfs representation for that device. * to the sysfs representation for that device.
...@@ -253,6 +263,8 @@ struct usb_interface { ...@@ -253,6 +263,8 @@ struct usb_interface {
unsigned needs_binding:1; /* needs delayed unbind/rebind */ unsigned needs_binding:1; /* needs delayed unbind/rebind */
unsigned resetting_device:1; /* true: bandwidth alloc after reset */ unsigned resetting_device:1; /* true: bandwidth alloc after reset */
unsigned authorized:1; /* used for interface authorization */ 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 dev; /* interface specific device info */
struct device *usb_dev; struct device *usb_dev;
...@@ -887,6 +899,10 @@ static inline int usb_interface_claimed(struct usb_interface *iface) ...@@ -887,6 +899,10 @@ static inline int usb_interface_claimed(struct usb_interface *iface)
extern void usb_driver_release_interface(struct usb_driver *driver, extern void usb_driver_release_interface(struct usb_driver *driver,
struct usb_interface *iface); 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 *usb_match_id(struct usb_interface *interface,
const struct usb_device_id *id); const struct usb_device_id *id);
extern int usb_match_one_id(struct usb_interface *interface, extern int usb_match_one_id(struct usb_interface *interface,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment