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:
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.
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>
Date: August 2012
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)
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
......@@ -2100,6 +2139,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
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);
......
......@@ -1227,9 +1227,59 @@ static const struct attribute_group intf_assoc_attr_grp = {
.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[] = {
&intf_attr_grp,
&intf_assoc_attr_grp,
&intf_wireless_status_attr_grp,
NULL
};
......
......@@ -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_create_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,
struct usb_host_endpoint *endpoint,
struct usb_device *udev);
......
......@@ -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);
}
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
* @altsetting: array of interface structures, one for each alternate
......@@ -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.
* @authorized: This allows to (de)authorize individual interfaces instead
* 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
* @usb_dev: if an interface is bound to the USB major, this will point
* to the sysfs representation for that device.
......@@ -253,6 +263,8 @@ struct usb_interface {
unsigned needs_binding:1; /* needs delayed unbind/rebind */
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;
......@@ -887,6 +899,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,
......
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