mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-15 01:01:56 -04:00
Merge tag 'ASB-2023-01-05_11-5.4' of https://android.googlesource.com/kernel/common into android13-5.4-lahaina
https://source.android.com/docs/security/bulletin/2023-01-01 CVE-2022-42719 CVE-2022-42720 CVE-2022-42721 CVE-2022-2959 CVE-2022-41674 CVE-2023-20928 * tag 'ASB-2023-01-05_11-5.4' of https://android.googlesource.com/kernel/common: UPSTREAM: HID: playstation: support updated DualSense rumble mode. UPSTREAM: HID: playstation: add initial DualSense Edge controller support UPSTREAM: HID: playstation: stop DualSense output work on remove. UPSTREAM: HID: playstation: convert to use dev_groups UPSTREAM: HID: playstation: fix return from dualsense_player_led_set_brightness() UPSTREAM: HID: playstation: expose DualSense player LEDs through LED class. BACKPORT: leds: add new LED_FUNCTION_PLAYER for player LEDs for game controllers. UPSTREAM: HID: playstation: expose DualSense lightbar through a multi-color LED. UPSTREAM: leds: flash: Fix multicolor no-ops registration by return 0 UPSTREAM: leds: multicolor: Introduce a multicolor class definition ANDROID: GKI: enable mulitcolor-led BACKPORT: Kconfig.debug: provide a little extra FRAME_WARN leeway when KASAN is enabled Change-Id: I5fc3bd24adbafa6c280c2f122b9492fb0bdad9a3
This commit is contained in:
commit
8050fa5150
13 changed files with 692 additions and 18 deletions
35
Documentation/ABI/testing/sysfs-class-led-multicolor
Normal file
35
Documentation/ABI/testing/sysfs-class-led-multicolor
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
What: /sys/class/leds/<led>/brightness
|
||||
Date: March 2020
|
||||
KernelVersion: 5.9
|
||||
Contact: Dan Murphy <dmurphy@ti.com>
|
||||
Description: read/write
|
||||
Writing to this file will update all LEDs within the group to a
|
||||
calculated percentage of what each color LED intensity is set
|
||||
to. The percentage is calculated for each grouped LED via the
|
||||
equation below:
|
||||
|
||||
led_brightness = brightness * multi_intensity/max_brightness
|
||||
|
||||
For additional details please refer to
|
||||
Documentation/leds/leds-class-multicolor.rst.
|
||||
|
||||
The value of the LED is from 0 to
|
||||
/sys/class/leds/<led>/max_brightness.
|
||||
|
||||
What: /sys/class/leds/<led>/multi_index
|
||||
Date: March 2020
|
||||
KernelVersion: 5.9
|
||||
Contact: Dan Murphy <dmurphy@ti.com>
|
||||
Description: read
|
||||
The multi_index array, when read, will output the LED colors
|
||||
as an array of strings as they are indexed in the
|
||||
multi_intensity file.
|
||||
|
||||
What: /sys/class/leds/<led>/multi_intensity
|
||||
Date: March 2020
|
||||
KernelVersion: 5.9
|
||||
Contact: Dan Murphy <dmurphy@ti.com>
|
||||
Description: read/write
|
||||
This file contains array of integers. Order of components is
|
||||
described by the multi_index array. The maximum intensity should
|
||||
not exceed /sys/class/leds/<led>/max_brightness.
|
||||
|
|
@ -9,6 +9,7 @@ LEDs
|
|||
|
||||
leds-class
|
||||
leds-class-flash
|
||||
leds-class-multicolor
|
||||
ledtrig-oneshot
|
||||
ledtrig-transient
|
||||
ledtrig-usbport
|
||||
|
|
|
|||
86
Documentation/leds/leds-class-multicolor.rst
Normal file
86
Documentation/leds/leds-class-multicolor.rst
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
====================================
|
||||
Multicolor LED handling under Linux
|
||||
====================================
|
||||
|
||||
Description
|
||||
===========
|
||||
The multicolor class groups monochrome LEDs and allows controlling two
|
||||
aspects of the final combined color: hue and lightness. The former is
|
||||
controlled via the multi_intensity array file and the latter is controlled
|
||||
via brightness file.
|
||||
|
||||
Multicolor Class Control
|
||||
========================
|
||||
The multicolor class presents files that groups the colors as indexes in an
|
||||
array. These files are children under the LED parent node created by the
|
||||
led_class framework. The led_class framework is documented in led-class.rst
|
||||
within this documentation directory.
|
||||
|
||||
Each colored LED will be indexed under the multi_* files. The order of the
|
||||
colors will be arbitrary. The multi_index file can be read to determine the
|
||||
color name to indexed value.
|
||||
|
||||
The multi_index file is an array that contains the string list of the colors as
|
||||
they are defined in each multi_* array file.
|
||||
|
||||
The multi_intensity is an array that can be read or written to for the
|
||||
individual color intensities. All elements within this array must be written in
|
||||
order for the color LED intensities to be updated.
|
||||
|
||||
Directory Layout Example
|
||||
========================
|
||||
root:/sys/class/leds/multicolor:status# ls -lR
|
||||
-rw-r--r-- 1 root root 4096 Oct 19 16:16 brightness
|
||||
-r--r--r-- 1 root root 4096 Oct 19 16:16 max_brightness
|
||||
-r--r--r-- 1 root root 4096 Oct 19 16:16 multi_index
|
||||
-rw-r--r-- 1 root root 4096 Oct 19 16:16 multi_intensity
|
||||
|
||||
Multicolor Class Brightness Control
|
||||
===================================
|
||||
The brightness level for each LED is calculated based on the color LED
|
||||
intensity setting divided by the global max_brightness setting multiplied by
|
||||
the requested brightness.
|
||||
|
||||
led_brightness = brightness * multi_intensity/max_brightness
|
||||
|
||||
Example:
|
||||
A user first writes the multi_intensity file with the brightness levels
|
||||
for each LED that are necessary to achieve a certain color output from a
|
||||
multicolor LED group.
|
||||
|
||||
cat /sys/class/leds/multicolor:status/multi_index
|
||||
green blue red
|
||||
|
||||
echo 43 226 138 > /sys/class/leds/multicolor:status/multi_intensity
|
||||
|
||||
red -
|
||||
intensity = 138
|
||||
max_brightness = 255
|
||||
green -
|
||||
intensity = 43
|
||||
max_brightness = 255
|
||||
blue -
|
||||
intensity = 226
|
||||
max_brightness = 255
|
||||
|
||||
The user can control the brightness of that multicolor LED group by writing the
|
||||
global 'brightness' control. Assuming a max_brightness of 255 the user
|
||||
may want to dim the LED color group to half. The user would write a value of
|
||||
128 to the global brightness file then the values written to each LED will be
|
||||
adjusted base on this value.
|
||||
|
||||
cat /sys/class/leds/multicolor:status/max_brightness
|
||||
255
|
||||
echo 128 > /sys/class/leds/multicolor:status/brightness
|
||||
|
||||
adjusted_red_value = 128 * 138/255 = 69
|
||||
adjusted_green_value = 128 * 43/255 = 21
|
||||
adjusted_blue_value = 128 * 226/255 = 113
|
||||
|
||||
Reading the global brightness file will return the current brightness value of
|
||||
the color LED group.
|
||||
|
||||
cat /sys/class/leds/multicolor:status/brightness
|
||||
128
|
||||
|
|
@ -434,6 +434,7 @@ CONFIG_MMC_CRYPTO=y
|
|||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_SDHCI_PLTFM=y
|
||||
CONFIG_LEDS_CLASS_FLASH=y
|
||||
CONFIG_LEDS_CLASS_MULTICOLOR=y
|
||||
CONFIG_LEDS_TRIGGER_TIMER=y
|
||||
CONFIG_EDAC=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
|
|
|
|||
|
|
@ -382,6 +382,7 @@ CONFIG_MMC_CRYPTO=y
|
|||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_SDHCI_PLTFM=y
|
||||
CONFIG_LEDS_CLASS_FLASH=y
|
||||
CONFIG_LEDS_CLASS_MULTICOLOR=y
|
||||
CONFIG_LEDS_TRIGGER_TIMER=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_DMADEVICES=y
|
||||
|
|
|
|||
|
|
@ -1079,6 +1079,7 @@
|
|||
#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_2 0x09cc
|
||||
#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE 0x0ba0
|
||||
#define USB_DEVICE_ID_SONY_PS5_CONTROLLER 0x0ce6
|
||||
#define USB_DEVICE_ID_SONY_PS5_CONTROLLER_2 0x0df2
|
||||
#define USB_DEVICE_ID_SONY_MOTION_CONTROLLER 0x03d5
|
||||
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
|
||||
#define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/led-class-multicolor.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
|
@ -38,11 +40,13 @@ struct ps_device {
|
|||
uint8_t battery_capacity;
|
||||
int battery_status;
|
||||
|
||||
const char *input_dev_name; /* Name of primary input device. */
|
||||
uint8_t mac_address[6]; /* Note: stored in little endian order. */
|
||||
uint32_t hw_version;
|
||||
uint32_t fw_version;
|
||||
|
||||
int (*parse_report)(struct ps_device *dev, struct hid_report *report, u8 *data, int size);
|
||||
void (*remove)(struct ps_device *dev);
|
||||
};
|
||||
|
||||
/* Calibration data for playstation motion sensors. */
|
||||
|
|
@ -53,6 +57,13 @@ struct ps_calibration_data {
|
|||
int sens_denom;
|
||||
};
|
||||
|
||||
struct ps_led_info {
|
||||
const char *name;
|
||||
const char *color;
|
||||
enum led_brightness (*brightness_get)(struct led_classdev *cdev);
|
||||
int (*brightness_set)(struct led_classdev *cdev, enum led_brightness);
|
||||
};
|
||||
|
||||
/* Seed values for DualShock4 / DualSense CRC32 for different report types. */
|
||||
#define PS_INPUT_CRC32_SEED 0xA1
|
||||
#define PS_OUTPUT_CRC32_SEED 0xA2
|
||||
|
|
@ -97,6 +108,9 @@ struct ps_calibration_data {
|
|||
#define DS_STATUS_CHARGING GENMASK(7, 4)
|
||||
#define DS_STATUS_CHARGING_SHIFT 4
|
||||
|
||||
/* Feature version from DualSense Firmware Info report. */
|
||||
#define DS_FEATURE_VERSION(major, minor) ((major & 0xff) << 8 | (minor & 0xff))
|
||||
|
||||
/*
|
||||
* Status of a DualSense touch point contact.
|
||||
* Contact IDs, with highest bit set are 'inactive'
|
||||
|
|
@ -115,6 +129,7 @@ struct ps_calibration_data {
|
|||
#define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3)
|
||||
#define DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE BIT(4)
|
||||
#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1)
|
||||
#define DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2 BIT(2)
|
||||
#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4)
|
||||
#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1)
|
||||
|
||||
|
|
@ -132,6 +147,9 @@ struct dualsense {
|
|||
struct input_dev *sensors;
|
||||
struct input_dev *touchpad;
|
||||
|
||||
/* Update version is used as a feature/capability version. */
|
||||
uint16_t update_version;
|
||||
|
||||
/* Calibration data for accelerometer and gyroscope. */
|
||||
struct ps_calibration_data accel_calib_data[3];
|
||||
struct ps_calibration_data gyro_calib_data[3];
|
||||
|
|
@ -142,11 +160,13 @@ struct dualsense {
|
|||
uint32_t sensor_timestamp_us;
|
||||
|
||||
/* Compatible rumble state */
|
||||
bool use_vibration_v2;
|
||||
bool update_rumble;
|
||||
uint8_t motor_left;
|
||||
uint8_t motor_right;
|
||||
|
||||
/* RGB lightbar */
|
||||
struct led_classdev_mc lightbar;
|
||||
bool update_lightbar;
|
||||
uint8_t lightbar_red;
|
||||
uint8_t lightbar_green;
|
||||
|
|
@ -163,6 +183,7 @@ struct dualsense {
|
|||
struct led_classdev player_leds[5];
|
||||
|
||||
struct work_struct output_worker;
|
||||
bool output_worker_initialized;
|
||||
void *output_report_dmabuf;
|
||||
uint8_t output_seq; /* Sequence number for output report. */
|
||||
};
|
||||
|
|
@ -288,6 +309,9 @@ static const struct {int x; int y; } ps_gamepad_hat_mapping[] = {
|
|||
{0, 0},
|
||||
};
|
||||
|
||||
static inline void dualsense_schedule_work(struct dualsense *ds);
|
||||
static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
/*
|
||||
* Add a new ps_device to ps_devices if it doesn't exist.
|
||||
* Return error on duplicate device, which can happen if the same
|
||||
|
|
@ -525,6 +549,71 @@ static int ps_get_report(struct hid_device *hdev, uint8_t report_id, uint8_t *bu
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ps_led_register(struct ps_device *ps_dev, struct led_classdev *led,
|
||||
const struct ps_led_info *led_info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
led->name = devm_kasprintf(&ps_dev->hdev->dev, GFP_KERNEL,
|
||||
"%s:%s:%s", ps_dev->input_dev_name, led_info->color, led_info->name);
|
||||
|
||||
if (!led->name)
|
||||
return -ENOMEM;
|
||||
|
||||
led->brightness = 0;
|
||||
led->max_brightness = 1;
|
||||
led->flags = LED_CORE_SUSPENDRESUME;
|
||||
led->brightness_get = led_info->brightness_get;
|
||||
led->brightness_set_blocking = led_info->brightness_set;
|
||||
|
||||
ret = devm_led_classdev_register(&ps_dev->hdev->dev, led);
|
||||
if (ret) {
|
||||
hid_err(ps_dev->hdev, "Failed to register LED %s: %d\n", led_info->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register a DualSense/DualShock4 RGB lightbar represented by a multicolor LED. */
|
||||
static int ps_lightbar_register(struct ps_device *ps_dev, struct led_classdev_mc *lightbar_mc_dev,
|
||||
int (*brightness_set)(struct led_classdev *, enum led_brightness))
|
||||
{
|
||||
struct hid_device *hdev = ps_dev->hdev;
|
||||
struct mc_subled *mc_led_info;
|
||||
struct led_classdev *led_cdev;
|
||||
int ret;
|
||||
|
||||
mc_led_info = devm_kmalloc_array(&hdev->dev, 3, sizeof(*mc_led_info),
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
if (!mc_led_info)
|
||||
return -ENOMEM;
|
||||
|
||||
mc_led_info[0].color_index = LED_COLOR_ID_RED;
|
||||
mc_led_info[1].color_index = LED_COLOR_ID_GREEN;
|
||||
mc_led_info[2].color_index = LED_COLOR_ID_BLUE;
|
||||
|
||||
lightbar_mc_dev->subled_info = mc_led_info;
|
||||
lightbar_mc_dev->num_colors = 3;
|
||||
|
||||
led_cdev = &lightbar_mc_dev->led_cdev;
|
||||
led_cdev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s:rgb:indicator",
|
||||
ps_dev->input_dev_name);
|
||||
if (!led_cdev->name)
|
||||
return -ENOMEM;
|
||||
led_cdev->brightness = 255;
|
||||
led_cdev->max_brightness = 255;
|
||||
led_cdev->brightness_set_blocking = brightness_set;
|
||||
|
||||
ret = devm_led_classdev_multicolor_register(&hdev->dev, lightbar_mc_dev);
|
||||
if (ret < 0) {
|
||||
hid_err(hdev, "Cannot register multicolor LED device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct input_dev *ps_sensors_create(struct hid_device *hdev, int accel_range, int accel_res,
|
||||
int gyro_range, int gyro_res)
|
||||
{
|
||||
|
|
@ -614,15 +703,12 @@ static ssize_t hardware_version_show(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR_RO(hardware_version);
|
||||
|
||||
static struct attribute *ps_device_attributes[] = {
|
||||
static struct attribute *ps_device_attrs[] = {
|
||||
&dev_attr_firmware_version.attr,
|
||||
&dev_attr_hardware_version.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ps_device_attribute_group = {
|
||||
.attrs = ps_device_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ps_device);
|
||||
|
||||
static int dualsense_get_calibration_data(struct dualsense *ds)
|
||||
{
|
||||
|
|
@ -714,6 +800,7 @@ err_free:
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int dualsense_get_firmware_info(struct dualsense *ds)
|
||||
{
|
||||
uint8_t *buf;
|
||||
|
|
@ -733,6 +820,15 @@ static int dualsense_get_firmware_info(struct dualsense *ds)
|
|||
ds->base.hw_version = get_unaligned_le32(&buf[24]);
|
||||
ds->base.fw_version = get_unaligned_le32(&buf[28]);
|
||||
|
||||
/* Update version is some kind of feature version. It is distinct from
|
||||
* the firmware version as there can be many different variations of a
|
||||
* controller over time with the same physical shell, but with different
|
||||
* PCBs and other internal changes. The update version (internal name) is
|
||||
* used as a means to detect what features are available and change behavior.
|
||||
* Note: the version is different between DualSense and DualSense Edge.
|
||||
*/
|
||||
ds->update_version = get_unaligned_le16(&buf[44]);
|
||||
|
||||
err_free:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
|
|
@ -761,6 +857,53 @@ err_free:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int dualsense_lightbar_set_brightness(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
|
||||
struct dualsense *ds = container_of(mc_cdev, struct dualsense, lightbar);
|
||||
uint8_t red, green, blue;
|
||||
|
||||
led_mc_calc_color_components(mc_cdev, brightness);
|
||||
red = mc_cdev->subled_info[0].brightness;
|
||||
green = mc_cdev->subled_info[1].brightness;
|
||||
blue = mc_cdev->subled_info[2].brightness;
|
||||
|
||||
dualsense_set_lightbar(ds, red, green, blue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum led_brightness dualsense_player_led_get_brightness(struct led_classdev *led)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(led->dev->parent);
|
||||
struct dualsense *ds = hid_get_drvdata(hdev);
|
||||
|
||||
return !!(ds->player_leds_state & BIT(led - ds->player_leds));
|
||||
}
|
||||
|
||||
static int dualsense_player_led_set_brightness(struct led_classdev *led, enum led_brightness value)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(led->dev->parent);
|
||||
struct dualsense *ds = hid_get_drvdata(hdev);
|
||||
unsigned long flags;
|
||||
unsigned int led_index;
|
||||
|
||||
spin_lock_irqsave(&ds->base.lock, flags);
|
||||
|
||||
led_index = led - ds->player_leds;
|
||||
if (value == LED_OFF)
|
||||
ds->player_leds_state &= ~BIT(led_index);
|
||||
else
|
||||
ds->player_leds_state |= BIT(led_index);
|
||||
|
||||
ds->update_player_leds = true;
|
||||
spin_unlock_irqrestore(&ds->base.lock, flags);
|
||||
|
||||
dualsense_schedule_work(ds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_output_report *rp,
|
||||
void *buf)
|
||||
{
|
||||
|
|
@ -800,6 +943,16 @@ static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_
|
|||
}
|
||||
}
|
||||
|
||||
static inline void dualsense_schedule_work(struct dualsense *ds)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ds->base.lock, flags);
|
||||
if (ds->output_worker_initialized)
|
||||
schedule_work(&ds->output_worker);
|
||||
spin_unlock_irqrestore(&ds->base.lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to send DualSense output reports. Applies a CRC at the end of a report
|
||||
* for Bluetooth reports.
|
||||
|
|
@ -838,7 +991,10 @@ static void dualsense_output_worker(struct work_struct *work)
|
|||
if (ds->update_rumble) {
|
||||
/* Select classic rumble style haptics and enable it. */
|
||||
common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT;
|
||||
common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION;
|
||||
if (ds->use_vibration_v2)
|
||||
common->valid_flag2 |= DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2;
|
||||
else
|
||||
common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION;
|
||||
common->motor_left = ds->motor_left;
|
||||
common->motor_right = ds->motor_right;
|
||||
ds->update_rumble = false;
|
||||
|
|
@ -960,7 +1116,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r
|
|||
spin_unlock_irqrestore(&ps_dev->lock, flags);
|
||||
|
||||
/* Schedule updating of microphone state at hardware level. */
|
||||
schedule_work(&ds->output_worker);
|
||||
dualsense_schedule_work(ds);
|
||||
}
|
||||
ds->last_btn_mic_state = btn_mic_state;
|
||||
|
||||
|
|
@ -1075,10 +1231,22 @@ static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_ef
|
|||
ds->motor_right = effect->u.rumble.weak_magnitude / 256;
|
||||
spin_unlock_irqrestore(&ds->base.lock, flags);
|
||||
|
||||
schedule_work(&ds->output_worker);
|
||||
dualsense_schedule_work(ds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dualsense_remove(struct ps_device *ps_dev)
|
||||
{
|
||||
struct dualsense *ds = container_of(ps_dev, struct dualsense, base);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ds->base.lock, flags);
|
||||
ds->output_worker_initialized = false;
|
||||
spin_unlock_irqrestore(&ds->base.lock, flags);
|
||||
|
||||
cancel_work_sync(&ds->output_worker);
|
||||
}
|
||||
|
||||
static int dualsense_reset_leds(struct dualsense *ds)
|
||||
{
|
||||
struct dualsense_output_report report;
|
||||
|
|
@ -1106,12 +1274,16 @@ static int dualsense_reset_leds(struct dualsense *ds)
|
|||
|
||||
static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ds->base.lock, flags);
|
||||
ds->update_lightbar = true;
|
||||
ds->lightbar_red = red;
|
||||
ds->lightbar_green = green;
|
||||
ds->lightbar_blue = blue;
|
||||
spin_unlock_irqrestore(&ds->base.lock, flags);
|
||||
|
||||
schedule_work(&ds->output_worker);
|
||||
dualsense_schedule_work(ds);
|
||||
}
|
||||
|
||||
static void dualsense_set_player_leds(struct dualsense *ds)
|
||||
|
|
@ -1134,7 +1306,7 @@ static void dualsense_set_player_leds(struct dualsense *ds)
|
|||
|
||||
ds->update_player_leds = true;
|
||||
ds->player_leds_state = player_ids[player_id];
|
||||
schedule_work(&ds->output_worker);
|
||||
dualsense_schedule_work(ds);
|
||||
}
|
||||
|
||||
static struct ps_device *dualsense_create(struct hid_device *hdev)
|
||||
|
|
@ -1142,7 +1314,20 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
|
|||
struct dualsense *ds;
|
||||
struct ps_device *ps_dev;
|
||||
uint8_t max_output_report_size;
|
||||
int ret;
|
||||
int i, ret;
|
||||
|
||||
static const struct ps_led_info player_leds_info[] = {
|
||||
{ LED_FUNCTION_PLAYER1, "white", dualsense_player_led_get_brightness,
|
||||
dualsense_player_led_set_brightness },
|
||||
{ LED_FUNCTION_PLAYER2, "white", dualsense_player_led_get_brightness,
|
||||
dualsense_player_led_set_brightness },
|
||||
{ LED_FUNCTION_PLAYER3, "white", dualsense_player_led_get_brightness,
|
||||
dualsense_player_led_set_brightness },
|
||||
{ LED_FUNCTION_PLAYER4, "white", dualsense_player_led_get_brightness,
|
||||
dualsense_player_led_set_brightness },
|
||||
{ LED_FUNCTION_PLAYER5, "white", dualsense_player_led_get_brightness,
|
||||
dualsense_player_led_set_brightness }
|
||||
};
|
||||
|
||||
ds = devm_kzalloc(&hdev->dev, sizeof(*ds), GFP_KERNEL);
|
||||
if (!ds)
|
||||
|
|
@ -1160,7 +1345,9 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
|
|||
ps_dev->battery_capacity = 100; /* initial value until parse_report. */
|
||||
ps_dev->battery_status = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
ps_dev->parse_report = dualsense_parse_report;
|
||||
ps_dev->remove = dualsense_remove;
|
||||
INIT_WORK(&ds->output_worker, dualsense_output_worker);
|
||||
ds->output_worker_initialized = true;
|
||||
hid_set_drvdata(hdev, ds);
|
||||
|
||||
max_output_report_size = sizeof(struct dualsense_output_report_bt);
|
||||
|
|
@ -1181,6 +1368,21 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
|
|||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/* Original DualSense firmware simulated classic controller rumble through
|
||||
* its new haptics hardware. It felt different from classic rumble users
|
||||
* were used to. Since then new firmwares were introduced to change behavior
|
||||
* and make this new 'v2' behavior default on PlayStation and other platforms.
|
||||
* The original DualSense requires a new enough firmware as bundled with PS5
|
||||
* software released in 2021. DualSense edge supports it out of the box.
|
||||
* Both devices also support the old mode, but it is not really used.
|
||||
*/
|
||||
if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER) {
|
||||
/* Feature version 2.21 introduced new vibration method. */
|
||||
ds->use_vibration_v2 = ds->update_version >= DS_FEATURE_VERSION(2, 21);
|
||||
} else if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) {
|
||||
ds->use_vibration_v2 = true;
|
||||
}
|
||||
|
||||
ret = ps_devices_list_add(ps_dev);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
|
@ -1196,6 +1398,8 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
|
|||
ret = PTR_ERR(ds->gamepad);
|
||||
goto err;
|
||||
}
|
||||
/* Use gamepad input device name as primary device name for e.g. LEDs */
|
||||
ps_dev->input_dev_name = dev_name(&ds->gamepad->dev);
|
||||
|
||||
ds->sensors = ps_sensors_create(hdev, DS_ACC_RANGE, DS_ACC_RES_PER_G,
|
||||
DS_GYRO_RANGE, DS_GYRO_RES_PER_DEG_S);
|
||||
|
|
@ -1223,8 +1427,21 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
|
|||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = ps_lightbar_register(ps_dev, &ds->lightbar, dualsense_lightbar_set_brightness);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* Set default lightbar color. */
|
||||
dualsense_set_lightbar(ds, 0, 0, 128); /* blue */
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(player_leds_info); i++) {
|
||||
const struct ps_led_info *led_info = &player_leds_info[i];
|
||||
|
||||
ret = ps_led_register(ps_dev, &ds->player_leds[i], led_info);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = ps_device_set_player_id(ps_dev);
|
||||
if (ret) {
|
||||
hid_err(hdev, "Failed to assign player id for DualSense: %d\n", ret);
|
||||
|
|
@ -1282,7 +1499,8 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
goto err_stop;
|
||||
}
|
||||
|
||||
if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER) {
|
||||
if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER ||
|
||||
hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) {
|
||||
dev = dualsense_create(hdev);
|
||||
if (IS_ERR(dev)) {
|
||||
hid_err(hdev, "Failed to create dualsense.\n");
|
||||
|
|
@ -1291,12 +1509,6 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
}
|
||||
}
|
||||
|
||||
ret = devm_device_add_group(&hdev->dev, &ps_device_attribute_group);
|
||||
if (ret) {
|
||||
hid_err(hdev, "Failed to register sysfs nodes.\n");
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_close:
|
||||
|
|
@ -1313,6 +1525,9 @@ static void ps_remove(struct hid_device *hdev)
|
|||
ps_devices_list_remove(dev);
|
||||
ps_device_release_player_id(dev);
|
||||
|
||||
if (dev->remove)
|
||||
dev->remove(dev);
|
||||
|
||||
hid_hw_close(hdev);
|
||||
hid_hw_stop(hdev);
|
||||
}
|
||||
|
|
@ -1320,6 +1535,8 @@ static void ps_remove(struct hid_device *hdev)
|
|||
static const struct hid_device_id ps_devices[] = {
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, ps_devices);
|
||||
|
|
@ -1330,6 +1547,9 @@ static struct hid_driver ps_driver = {
|
|||
.probe = ps_probe,
|
||||
.remove = ps_remove,
|
||||
.raw_event = ps_raw_event,
|
||||
.driver = {
|
||||
.dev_groups = ps_device_groups,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ps_init(void)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,16 @@ config LEDS_CLASS_FLASH
|
|||
for the flash related features of a LED device. It can be built
|
||||
as a module.
|
||||
|
||||
config LEDS_CLASS_MULTICOLOR
|
||||
tristate "LED Multicolor Class Support"
|
||||
depends on LEDS_CLASS
|
||||
help
|
||||
This option enables the multicolor LED sysfs class in /sys/class/leds.
|
||||
It wraps LED class and adds multicolor LED specific sysfs attributes
|
||||
and kernel internal API to it. You'll need this to provide support
|
||||
for multicolor LEDs that are grouped together. This class is not
|
||||
intended for single color LEDs. It can be built as a module.
|
||||
|
||||
config LEDS_BRIGHTNESS_HW_CHANGED
|
||||
bool "LED Class brightness_hw_changed attribute support"
|
||||
depends on LEDS_CLASS
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
obj-$(CONFIG_NEW_LEDS) += led-core.o
|
||||
obj-$(CONFIG_LEDS_CLASS) += led-class.o
|
||||
obj-$(CONFIG_LEDS_CLASS_FLASH) += led-class-flash.o
|
||||
obj-$(CONFIG_LEDS_CLASS_MULTICOLOR) += led-class-multicolor.o
|
||||
obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
|
||||
|
||||
# LED Platform Drivers
|
||||
|
|
|
|||
203
drivers/leds/led-class-multicolor.c
Normal file
203
drivers/leds/led-class-multicolor.c
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// LED Multicolor class interface
|
||||
// Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/
|
||||
// Author: Dan Murphy <dmurphy@ti.com>
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/led-class-multicolor.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "leds.h"
|
||||
|
||||
int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct led_classdev *led_cdev = &mcled_cdev->led_cdev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mcled_cdev->num_colors; i++)
|
||||
mcled_cdev->subled_info[i].brightness = brightness *
|
||||
mcled_cdev->subled_info[i].intensity /
|
||||
led_cdev->max_brightness;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_mc_calc_color_components);
|
||||
|
||||
static ssize_t multi_intensity_store(struct device *dev,
|
||||
struct device_attribute *intensity_attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
|
||||
int nrchars, offset = 0;
|
||||
int intensity_value[LED_COLOR_ID_MAX];
|
||||
int i;
|
||||
ssize_t ret;
|
||||
|
||||
mutex_lock(&led_cdev->led_access);
|
||||
|
||||
for (i = 0; i < mcled_cdev->num_colors; i++) {
|
||||
ret = sscanf(buf + offset, "%i%n",
|
||||
&intensity_value[i], &nrchars);
|
||||
if (ret != 1) {
|
||||
ret = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
offset += nrchars;
|
||||
}
|
||||
|
||||
offset++;
|
||||
if (offset < size) {
|
||||
ret = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
for (i = 0; i < mcled_cdev->num_colors; i++)
|
||||
mcled_cdev->subled_info[i].intensity = intensity_value[i];
|
||||
|
||||
led_set_brightness(led_cdev, led_cdev->brightness);
|
||||
ret = size;
|
||||
err_out:
|
||||
mutex_unlock(&led_cdev->led_access);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t multi_intensity_show(struct device *dev,
|
||||
struct device_attribute *intensity_attr,
|
||||
char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
|
||||
int len = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mcled_cdev->num_colors; i++) {
|
||||
len += sprintf(buf + len, "%d",
|
||||
mcled_cdev->subled_info[i].intensity);
|
||||
if (i < mcled_cdev->num_colors - 1)
|
||||
len += sprintf(buf + len, " ");
|
||||
}
|
||||
|
||||
buf[len++] = '\n';
|
||||
return len;
|
||||
}
|
||||
static DEVICE_ATTR_RW(multi_intensity);
|
||||
|
||||
static ssize_t multi_index_show(struct device *dev,
|
||||
struct device_attribute *multi_index_attr,
|
||||
char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
|
||||
int len = 0;
|
||||
int index;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mcled_cdev->num_colors; i++) {
|
||||
index = mcled_cdev->subled_info[i].color_index;
|
||||
len += sprintf(buf + len, "%s", led_colors[index]);
|
||||
if (i < mcled_cdev->num_colors - 1)
|
||||
len += sprintf(buf + len, " ");
|
||||
}
|
||||
|
||||
buf[len++] = '\n';
|
||||
return len;
|
||||
}
|
||||
static DEVICE_ATTR_RO(multi_index);
|
||||
|
||||
static struct attribute *led_multicolor_attrs[] = {
|
||||
&dev_attr_multi_intensity.attr,
|
||||
&dev_attr_multi_index.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(led_multicolor);
|
||||
|
||||
int led_classdev_multicolor_register_ext(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
struct led_classdev *led_cdev;
|
||||
|
||||
if (!mcled_cdev)
|
||||
return -EINVAL;
|
||||
|
||||
if (mcled_cdev->num_colors <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (mcled_cdev->num_colors > LED_COLOR_ID_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
led_cdev = &mcled_cdev->led_cdev;
|
||||
mcled_cdev->led_cdev.groups = led_multicolor_groups;
|
||||
|
||||
return led_classdev_register_ext(parent, led_cdev, init_data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext);
|
||||
|
||||
void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev)
|
||||
{
|
||||
if (!mcled_cdev)
|
||||
return;
|
||||
|
||||
led_classdev_unregister(&mcled_cdev->led_cdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_classdev_multicolor_unregister);
|
||||
|
||||
static void devm_led_classdev_multicolor_release(struct device *dev, void *res)
|
||||
{
|
||||
led_classdev_multicolor_unregister(*(struct led_classdev_mc **)res);
|
||||
}
|
||||
|
||||
int devm_led_classdev_multicolor_register_ext(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
struct led_classdev_mc **dr;
|
||||
int ret;
|
||||
|
||||
dr = devres_alloc(devm_led_classdev_multicolor_release,
|
||||
sizeof(*dr), GFP_KERNEL);
|
||||
if (!dr)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = led_classdev_multicolor_register_ext(parent, mcled_cdev,
|
||||
init_data);
|
||||
if (ret) {
|
||||
devres_free(dr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*dr = mcled_cdev;
|
||||
devres_add(parent, dr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register_ext);
|
||||
|
||||
static int devm_led_classdev_multicolor_match(struct device *dev,
|
||||
void *res, void *data)
|
||||
{
|
||||
struct led_classdev_mc **p = res;
|
||||
|
||||
if (WARN_ON(!p || !*p))
|
||||
return 0;
|
||||
|
||||
return *p == data;
|
||||
}
|
||||
|
||||
void devm_led_classdev_multicolor_unregister(struct device *dev,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
{
|
||||
WARN_ON(devres_release(dev,
|
||||
devm_led_classdev_multicolor_release,
|
||||
devm_led_classdev_multicolor_match, mcled_cdev));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_unregister);
|
||||
|
||||
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
|
||||
MODULE_DESCRIPTION("Multicolor LED class interface");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -58,6 +58,11 @@
|
|||
#define LED_FUNCTION_MUTE "mute"
|
||||
#define LED_FUNCTION_NUMLOCK "numlock"
|
||||
#define LED_FUNCTION_PANIC "panic"
|
||||
#define LED_FUNCTION_PLAYER1 "player-1"
|
||||
#define LED_FUNCTION_PLAYER2 "player-2"
|
||||
#define LED_FUNCTION_PLAYER3 "player-3"
|
||||
#define LED_FUNCTION_PLAYER4 "player-4"
|
||||
#define LED_FUNCTION_PLAYER5 "player-5"
|
||||
#define LED_FUNCTION_PROGRAMMING "programming"
|
||||
#define LED_FUNCTION_POWER "power"
|
||||
#define LED_FUNCTION_RX "rx"
|
||||
|
|
|
|||
109
include/linux/led-class-multicolor.h
Normal file
109
include/linux/led-class-multicolor.h
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* LED Multicolor class interface
|
||||
* Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_MULTICOLOR_LEDS_H_INCLUDED
|
||||
#define _LINUX_MULTICOLOR_LEDS_H_INCLUDED
|
||||
|
||||
#include <linux/leds.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
struct mc_subled {
|
||||
unsigned int color_index;
|
||||
unsigned int brightness;
|
||||
unsigned int intensity;
|
||||
unsigned int channel;
|
||||
};
|
||||
|
||||
struct led_classdev_mc {
|
||||
/* led class device */
|
||||
struct led_classdev led_cdev;
|
||||
unsigned int num_colors;
|
||||
|
||||
struct mc_subled *subled_info;
|
||||
};
|
||||
|
||||
static inline struct led_classdev_mc *lcdev_to_mccdev(
|
||||
struct led_classdev *led_cdev)
|
||||
{
|
||||
return container_of(led_cdev, struct led_classdev_mc, led_cdev);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR)
|
||||
/**
|
||||
* led_classdev_multicolor_register_ext - register a new object of led_classdev
|
||||
* class with support for multicolor LEDs
|
||||
* @parent: the multicolor LED to register
|
||||
* @mcled_cdev: the led_classdev_mc structure for this device
|
||||
* @init_data: the LED class multicolor device initialization data
|
||||
*
|
||||
* Returns: 0 on success or negative error value on failure
|
||||
*/
|
||||
int led_classdev_multicolor_register_ext(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data);
|
||||
|
||||
/**
|
||||
* led_classdev_multicolor_unregister - unregisters an object of led_classdev
|
||||
* class with support for multicolor LEDs
|
||||
* @mcled_cdev: the multicolor LED to unregister
|
||||
*
|
||||
* Unregister a previously registered via led_classdev_multicolor_register
|
||||
* object
|
||||
*/
|
||||
void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev);
|
||||
|
||||
/* Calculate brightness for the monochrome LED cluster */
|
||||
int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
|
||||
enum led_brightness brightness);
|
||||
|
||||
int devm_led_classdev_multicolor_register_ext(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data);
|
||||
|
||||
void devm_led_classdev_multicolor_unregister(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev);
|
||||
#else
|
||||
|
||||
static inline int led_classdev_multicolor_register_ext(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev) {};
|
||||
static inline int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int devm_led_classdev_multicolor_register_ext(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void devm_led_classdev_multicolor_unregister(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
{};
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) */
|
||||
|
||||
static inline int led_classdev_multicolor_register(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
{
|
||||
return led_classdev_multicolor_register_ext(parent, mcled_cdev, NULL);
|
||||
}
|
||||
|
||||
static inline int devm_led_classdev_multicolor_register(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
{
|
||||
return devm_led_classdev_multicolor_register_ext(parent, mcled_cdev,
|
||||
NULL);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_MULTICOLOR_LEDS_H_INCLUDED */
|
||||
|
|
@ -287,6 +287,7 @@ config FRAME_WARN
|
|||
int "Warn for stack frames larger than (needs gcc 4.4)"
|
||||
range 0 8192
|
||||
default 2048 if GCC_PLUGIN_LATENT_ENTROPY
|
||||
default 1280 if KASAN && !64BIT
|
||||
default 1280 if (!64BIT && PARISC)
|
||||
default 1024 if (!64BIT && !PARISC)
|
||||
default 2048 if 64BIT
|
||||
|
|
|
|||
Loading…
Reference in a new issue