platform-drivers-x86 for v7.1-1
Highlights:
- asus-wmi:
- Retain battery charge threshold during boot which avoids unsolicited
change to 100%. Return -ENODATA when the limit is not yet known
- Improve screenpad power/brightness handling consistency
- Fix screenpad brightness range
- barco-p50-gpio: Normalize gpio_get return values
- bitland-mifs-wmi: Add driver for Bitland laptops (supports platform
profile,hwmon, kbd backlight, gpu mode, hotkeys, and
fan boost)
- dell_rbu: Fix using uninitialized value in sysfs write function
- dell-wmi-sysman: Respect destination length when constructing enum
strings
- hp-wmi:
- Propagate fan setting apply failures and log an error
- Fix sysfs write vs work handler cancel_delayed_work_sync() deadlock
- Correct keepalive schedule_delayed_work() to mod_delayed_work()
- Fix u8 underflows in GPU delta calculation
- Use mutex to protect fan pwm/mode
- Ignore kbd backlight and FnLock key events that are handled by FW
- Fix fan table parsing (use correct field)
- Add support for Omen 14-fb0xxx, 16-n0xxx, 16-wf1xxx, and Omen MAX
16-ak0xxxx
- input: trackpoint & thinkpad_acpi: Enable doubletap by default and
add sysfs enable/disable
- int3472: Add support for GPIO type 0x02 (IR flood LED)
- intel-speed-select: (updated to v1.26)
- Avoid using current base frequency as maximum
- Fix CPU extended family ID decoding
- Fix exit code
- Improve error reporting
- intel/vsec: Refactor to support ACPI-enumerated PMT endpoints.
- pcengines-apuv2: Attach software node to the gpiochip
- uniwill:
- Refactor hwmon to smaller parts to accomodate HW diversity
- Support USB-C power/performance priority switch through sysfs
- Add another XMG Fusion 15 (L19) DMI vendor
- Enable fine-grained features to device lineup mapping
- wmi: Perform output size check within WMI core to allow simpler WMI
drivers
- acpi_driver -> platform driver conversions (a large number of changes
from Rafael J. Wysocki)
- Miscellaneous cleanups / refactoring / improvements
The following is an automated shortlog grouped by driver:
acer-wireless:
- Convert ACPI driver to a platform one
- Register ACPI notify handler directly
asus-laptop:
- Convert ACPI driver to a platform one
- Register ACPI notify handler directly
asus-wireless:
- Convert ACPI driver to a platform one
- Register ACPI notify handler directly
asus-wmi:
- adjust screenpad power/brightness handling
- do not enforce a battery charge threshold
- fix screenpad brightness range
barco-p50-gpio:
- convert to guard() notation
- normalize return value of gpio_get
bitland-mifs-wmi:
- Add new Bitland MIFS WMI driver
dell/dell-rbtn:
- Convert ACPI driver to a platform one
- Register ACPI notify handler directly
dell_rbu:
- avoid uninit value usage in packet_size_write()
dell-wmi-sysman:
- bound enumeration string aggregation
- Clean up security buffer helpers
- Fix typo in function comment
- Use standard kobj_sysfs_ops
- Use sysfs_emit{_at} in show functions
Documentation: laptops:
- Update documentation for uniwill laptops
Documentation:
- thinkpad-acpi - Document doubletap_enable attribute
eeepc-laptop:
- Convert ACPI driver to a platform one
- Register ACPI notify handler directly
fujitsu:
- Convert backlight driver to a platform one
- Convert laptop driver to a platform one
- Register ACPI notify handlers directly
- Reorder code to avoid forward declarations
fujitsu-tablet:
- Convert ACPI driver to a platform one
hp-wmi:
- add locking for concurrent hwmon access
- add Omen 14-fb0xxx (board 8C58) support
- Add support for Omen 16-n0xxx (8A44)
- Add support for Omen 16-wf1xxx (8C77)
- Add support for OMEN MAX 16-ak0xxx (8D87)
- avoid cancel_delayed_work_sync from work handler
- fix fan table parsing
- fix ignored return values in fan settings
- fix u8 underflow in gpu_delta calculation
- Ignore backlight and FnLock events
- use mod_delayed_work to reset keep-alive timer
input:
- trackpoint - Enable doubletap by default on capable devices
int3472:
- Add support for GPIO type 0x02 (IR flood LED)
- Parameterize LED con_id in registration
- Rename pled to led in LED registration code
- Use local variable for LED struct access
intel/rst:
- Convert ACPI driver to a platform one
intel/smartconnect:
- Convert ACPI driver to a platform one
intel/tpmi:
- Use 32 bit aligned address for debugfs mem write
intel/vsec:
- Decouple add/link helpers from PCI
- Make driver_data info const
- Plumb ACPI PMT discovery tables through vsec
- Refactor base_addr handling
- Return real error codes from registration path
- Switch exported helpers from pci_dev to device
lg-laptop:
- Convert ACPI driver to a platform one
- Drop debug-only ACPI notify handler
nvsw-sn2201:
- Drop unused include
panasonic-laptop:
- Convert ACPI driver to a platform one
- Fix OPTD notifier registration and cleanup
- Make pcc_register_optd_notifier() void
- Register ACPI notify handler directly
- Remove redundant checks from 3 functions
pcengines-apuv2:
- attach software node to the gpiochip
sony-laptop:
- Convert NC driver to a platform one
- Convert PIC driver to a platform one
- Register ACPI notify handler directly
surface: hotplug:
- Correct inclusion for GPIO APIs
surface: surfacepro3_button:
- Convert to a platform driver
- Drop wakeup source on remove
- Register ACPI notify handler
system76:
- Convert ACPI driver to a platform one
- Drop redundant devm_led_classdev_unregister()
- Register ACPI notify handler directly
thinkpad_acpi:
- Add sysfs control for TrackPoint double-tap
- Drop ACPI driver registration
- remove obsolete TODO comment
- use seq_puts() instead of seq_printf()
tools/power/x86/intel-speed-select:
- Avoid current base freq as maximum
- Fix cpu extended family ID decoding
- Fix output when running on unsupported CLX platforms
- Fix some program return value
- Print Version info when Incompatible API version is detected
- v1.26 release
topstar-laptop:
- Convert ACPI driver to a platform one
- Register ACPI notify handler directly
toshiba_acpi:
- Convert ACPI driver to a platform one
- Register ACPI notify handler directly
- Reorder code to avoid forward declaration
toshiba_bluetooth:
- Convert ACPI driver to a platform one
- Register ACPI notify handler directly
toshiba_haps:
- Convert ACPI driver to a platform one
- Register ACPI notify handler directly
uniwill-laptop:
- Apply features across all TUXEDO devices
- Fix signedness bug
- Fix XMG Fusion 15 (L19) entries
- Implement USB-C power priority setting
- Rework hwmon feature defines
wireless-hotkey:
- Convert ACPI driver to a platform one
- Register ACPI notify handler directly
wmi:
- Add wmidev_invoke_procedure()
- Convert drivers to use wmidev_invoke_procedure()
- Extend wmidev_invoke_method() to reject undersized data
- Extend wmidev_query_block() to reject undersized data
- Prepare to reject undersized unmarshalling results
- Replace .no_notify_data with .min_event_size
x86:
- remove unnecessary module_init/exit() functions
Merges:
- Merge branch 'intel-sst' of https://github.com/spandruvada/linux-kernel into review-ilpo-next
- Merge tag 'fixes' into 'for-next'
-----BEGIN PGP SIGNATURE-----
iHUEABYIAB0WIQSCSUwRdwTNL2MhaBlZrE9hU+XOMQUCaeYxSwAKCRBZrE9hU+XO
MRzTAQCPUKVOpSY/cjtPXVBn0uJbAo1MSvytv00Kv7dcatvrrwEA9lqmwOfl0kzr
CowEVVCD3om++W9vOsL65hachbAl1QA=
=1qkw
-----END PGP SIGNATURE-----
Merge tag 'platform-drivers-x86-v7.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver updates from Ilpo Järvinen:
"asus-wmi:
- Retain battery charge threshold during boot which avoids
unsolicited change to 100%. Return -ENODATA when the limit
is not yet known
- Improve screenpad power/brightness handling consistency
- Fix screenpad brightness range
barco-p50-gpio:
- Normalize gpio_get return values
bitland-mifs-wmi:
- Add driver for Bitland laptops (supports platform profile,
hwmon, kbd backlight, gpu mode, hotkeys, and fan boost)
dell_rbu:
- Fix using uninitialized value in sysfs write function
dell-wmi-sysman:
- Respect destination length when constructing enum strings
hp-wmi:
- Propagate fan setting apply failures and log an error
- Fix sysfs write vs work handler cancel_delayed_work_sync() deadlock
- Correct keepalive schedule_delayed_work() to mod_delayed_work()
- Fix u8 underflows in GPU delta calculation
- Use mutex to protect fan pwm/mode
- Ignore kbd backlight and FnLock key events that are handled by FW
- Fix fan table parsing (use correct field)
- Add support for Omen 14-fb0xxx, 16-n0xxx, 16-wf1xxx, and
Omen MAX 16-ak0xxxx
input: trackpoint & thinkpad_acpi:
- Enable doubletap by default and add sysfs enable/disable
int3472:
- Add support for GPIO type 0x02 (IR flood LED)
intel-speed-select: (updated to v1.26)
- Avoid using current base frequency as maximum
- Fix CPU extended family ID decoding
- Fix exit code
- Improve error reporting
intel/vsec:
- Refactor to support ACPI-enumerated PMT endpoints.
pcengines-apuv2:
- Attach software node to the gpiochip
uniwill:
- Refactor hwmon to smaller parts to accomodate HW diversity
- Support USB-C power/performance priority switch through sysfs
- Add another XMG Fusion 15 (L19) DMI vendor
- Enable fine-grained features to device lineup mapping
wmi:
- Perform output size check within WMI core to allow simpler WMI
drivers
misc:
- acpi_driver -> platform driver conversions (a large number of
changes from Rafael J. Wysocki)
- cleanups / refactoring / improvements"
* tag 'platform-drivers-x86-v7.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (106 commits)
platform/x86: hp-wmi: Add support for Omen 16-wf1xxx (8C77)
platform/x86: hp-wmi: Add support for Omen 16-n0xxx (8A44)
platform/x86: hp-wmi: Add support for OMEN MAX 16-ak0xxx (8D87)
platform/x86: hp-wmi: fix fan table parsing
platform/x86: hp-wmi: add Omen 14-fb0xxx (board 8C58) support
platform/wmi: Replace .no_notify_data with .min_event_size
platform/wmi: Extend wmidev_query_block() to reject undersized data
platform/wmi: Extend wmidev_invoke_method() to reject undersized data
platform/wmi: Prepare to reject undersized unmarshalling results
platform/wmi: Convert drivers to use wmidev_invoke_procedure()
platform/wmi: Add wmidev_invoke_procedure()
platform/x86: int3472: Add support for GPIO type 0x02 (IR flood LED)
platform/x86: int3472: Parameterize LED con_id in registration
platform/x86: int3472: Rename pled to led in LED registration code
platform/x86: int3472: Use local variable for LED struct access
platform/x86: thinkpad_acpi: remove obsolete TODO comment
platform/x86: dell-wmi-sysman: bound enumeration string aggregation
platform/x86: hp-wmi: Ignore backlight and FnLock events
platform/x86: uniwill-laptop: Fix signedness bug
platform/x86: dell_rbu: avoid uninit value usage in packet_size_write()
...
master
commit
da6b5aae84
|
|
@ -51,3 +51,30 @@ Description:
|
|||
|
||||
Reading this file returns the current status of the breathing animation
|
||||
functionality.
|
||||
|
||||
What: /sys/bus/platform/devices/INOU0000:XX/ctgp_offset
|
||||
Date: January 2026
|
||||
KernelVersion: 7.0
|
||||
Contact: Werner Sembach <wse@tuxedocomputers.com>
|
||||
Description:
|
||||
Allows userspace applications to set the configurable TGP offset on top of the base
|
||||
TGP. Base TGP and max TGP and therefore the max cTGP offset are device specific.
|
||||
Note that setting the maximum cTGP leaves no window open for Dynamic Boost as
|
||||
Dynamic Boost also can not go over max TGP. Setting the cTGP to maximum is
|
||||
effectively disabling Dynamic Boost and telling the device to always prioritize the
|
||||
GPU over the CPU.
|
||||
|
||||
Reading this file returns the current configurable TGP offset.
|
||||
|
||||
What: /sys/bus/platform/devices/INOU0000:XX/usb_c_power_priority
|
||||
Date: February 2026
|
||||
KernelVersion: 7.1
|
||||
Contact: Werner Sembach <wse@tuxedocomputers.com>
|
||||
Description:
|
||||
Allows userspace applications to choose the USB-C power distribution profile between
|
||||
one that offers a bigger share of the power to the battery and one that offers more
|
||||
of it to the CPU. Writing "charging"/"performance" into this file selects the
|
||||
respective profile.
|
||||
|
||||
Reading this file returns the profile names with the currently active one in
|
||||
brackets.
|
||||
|
|
|
|||
|
|
@ -1522,6 +1522,27 @@ Currently 2 antenna types are supported as mentioned below:
|
|||
The property is read-only. If the platform doesn't have support the sysfs
|
||||
class is not created.
|
||||
|
||||
doubletap_enable
|
||||
----------------
|
||||
|
||||
sysfs: doubletap_enable
|
||||
|
||||
Controls whether TrackPoint doubletap events are filtered out. Doubletap is a
|
||||
feature where quickly tapping the TrackPoint twice triggers a special function key event.
|
||||
|
||||
The available commands are::
|
||||
|
||||
cat /sys/devices/platform/thinkpad_acpi/doubletap_enable
|
||||
echo 1 | sudo tee /sys/devices/platform/thinkpad_acpi/doubletap_enable
|
||||
echo 0 | sudo tee /sys/devices/platform/thinkpad_acpi/doubletap_enable
|
||||
|
||||
Values:
|
||||
|
||||
* 1 - doubletap events are processed (default)
|
||||
* 0 - doubletap events are filtered out (ignored)
|
||||
|
||||
This setting can also be toggled via the Fn+doubletap hotkey.
|
||||
|
||||
Auxmac
|
||||
------
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,10 @@ between 1 and 100 percent are supported.
|
|||
Additionally the driver signals the presence of battery charging issues through the standard
|
||||
``health`` power supply sysfs attribute.
|
||||
|
||||
It also lets you set whether a USB-C power source should prioritise charging the battery or
|
||||
delivering immediate power to the cpu. See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for
|
||||
details.
|
||||
|
||||
Lightbar
|
||||
--------
|
||||
|
||||
|
|
@ -58,3 +62,11 @@ LED class device. The default name of this LED class device is ``uniwill:multico
|
|||
|
||||
See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details on how to control the various
|
||||
animation modes of the lightbar.
|
||||
|
||||
Configurable TGP
|
||||
----------------
|
||||
|
||||
The ``uniwill-laptop`` driver allows to set the configurable TGP for devices with NVIDIA GPUs that
|
||||
allow it.
|
||||
|
||||
See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,207 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
========================================
|
||||
Bitland MIFS driver (bitland-mifs-wmi)
|
||||
========================================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
|
||||
EC WMI interface description
|
||||
============================
|
||||
|
||||
The EC WMI interface description can be decoded from the embedded binary MOF (bmof)
|
||||
data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
|
||||
|
||||
::
|
||||
|
||||
class WMIEvent : __ExtrinsicEvent {
|
||||
};
|
||||
|
||||
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT20"), guid("{46c93e13-ee9b-4262-8488-563bca757fef}")]
|
||||
class HID_EVENT20 : WmiEvent {
|
||||
[key, read] string InstanceName;
|
||||
[read] boolean Active;
|
||||
[WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8];
|
||||
};
|
||||
|
||||
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT21"), guid("{fa78e245-2c0f-4ca1-91cf-15f34e474850}")]
|
||||
class HID_EVENT21 : WmiEvent {
|
||||
[key, read] string InstanceName;
|
||||
[read] boolean Active;
|
||||
[WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8];
|
||||
};
|
||||
|
||||
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT22"), guid("{1dceaf0a-4d63-44bb-bd0c-0d6281bfddc5}")]
|
||||
class HID_EVENT22 : WmiEvent {
|
||||
[key, read] string InstanceName;
|
||||
[read] boolean Active;
|
||||
[WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8];
|
||||
};
|
||||
|
||||
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT23"), guid("{3f9e3c26-b077-4f86-91f5-37ff64d8c7ed}")]
|
||||
class HID_EVENT23 : WmiEvent {
|
||||
[key, read] string InstanceName;
|
||||
[read] boolean Active;
|
||||
[WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8];
|
||||
};
|
||||
|
||||
[WMI, Dynamic, provider("WmiProv"), Locale("MS\\0x409"), Description("Class used to operate firmware interface"), guid("{b60bfb48-3e5b-49e4-a0e9-8cffe1b3434b}")]
|
||||
class MICommonInterface {
|
||||
[key, read] string InstanceName;
|
||||
[read] boolean Active;
|
||||
|
||||
[WmiMethodId(1), Implemented, read, write, Description("Method used to support system functions.")] void MiInterface([in, Description("WMI Interface")] uint8 InData[32], [out] uint8 OutData[30], [out] uint16 Reserved);
|
||||
};
|
||||
|
||||
Reverse-Engineering the EC WMI interface
|
||||
========================================
|
||||
|
||||
The OEM software can be download from `this link <https://iknow.lenovo.com.cn/detail/429447>`_
|
||||
|
||||
Nothing is obfuscated, In this case, `ILSpy <https://github.com/icsharpcode/ILSpy>`_ could be helpful.
|
||||
|
||||
WMI Methods (MICommonInterface)
|
||||
========================================
|
||||
|
||||
The ``MICommonInterface`` class (GUID: ``{b60bfb48-3e5b-49e4-a0e9-8cffe1b3434b}``)
|
||||
is the primary control interface. It uses a 32-byte buffer for both input
|
||||
(``InData``) and output (``OutData``).
|
||||
|
||||
Method Structure
|
||||
----------------
|
||||
|
||||
The data packet follows a standardized format:
|
||||
|
||||
+----------+------------------------------------------------------------------+
|
||||
| Byte | Description |
|
||||
+==========+==================================================================+
|
||||
| 1 | Method Type: Get (0xFA / 250) or Set (0xFB / 251) |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 3 | Command ID (Method Name) |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 4 - 31 | Arguments (for Set) or Return Data (for Get) |
|
||||
+----------+------------------------------------------------------------------+
|
||||
|
||||
|
||||
Command IDs
|
||||
-----------
|
||||
|
||||
The following Command IDs are used in the third byte of the buffer:
|
||||
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| ID | Name | Values / Description |
|
||||
+==========+=======================+==========================================+
|
||||
| 8 | SystemPerMode | 0: Balance, 1: Performance, 2: Quiet, |
|
||||
| | | 3: Full-speed |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 9 | GPUMode | 0: Hybrid, 1: Discrete, 2: UMA |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 10 | KeyboardType | 0: White, 1: Single RGB, 2: Zone RGB |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 11 | FnLock | 0: Off, 1: On |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 12 | TPLock | 0: Unlock, 1: Lock (Touchpad) |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 13 | CPUGPUSYSFanSpeed | Returns 12 bytes of fan data: |
|
||||
| | | Bytes 4-5: CPU Fan RPM (Little Endian) |
|
||||
| | | Bytes 6-7: GPU Fan RPM (Little Endian) |
|
||||
| | | Bytes 10-11: SYS Fan RPM (Little Endian) |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 16 | RGBKeyboardMode | 0: Off, 1: Auto Cyclic, 2: Fixed, |
|
||||
| | | 3: Custom |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 17 | RGBKeyboardColor | Bytes 4, 5, 6: Red, Green, Blue values |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 18 | RGBKeyboardBrightness | 0-10: Brightness Levels, 128: Auto |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 19 | SystemAcType | 1: Type-C, 2: Circular Hole (DC) |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 20 | MaxFanSpeedSwitch | Byte 4: Fan Type (0: CPU/GPU, 1: SYS) |
|
||||
| | | Byte 5: State (0: Off, 1: On) |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 21 | MaxFanSpeed | Sets manual fan speed duty cycle |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
| 22 | CPUThermometer | Returns CPU Temperature |
|
||||
+----------+-----------------------+------------------------------------------+
|
||||
|
||||
WMI Events (HID_EVENT20)
|
||||
========================
|
||||
|
||||
The driver listens for events from the ``HID_EVENT20`` class
|
||||
(GUID: ``{46c93e13-ee9b-4262-8488-563bca757fef}``). These events are triggered
|
||||
by hotkeys or system state changes (e.g., plugging in AC power).
|
||||
|
||||
Event Structure
|
||||
---------------
|
||||
|
||||
The event data is provided in an 8-byte array (``EventDetail``):
|
||||
|
||||
+----------+------------------------------------------------------------------+
|
||||
| Byte | Description |
|
||||
+==========+==================================================================+
|
||||
| 0 | Event Type (Always 0x01 for HotKey/Notification) |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 1 | Event ID (Corresponds to the Command IDs above) |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 2 | Value (The new state or value of the feature) |
|
||||
+----------+------------------------------------------------------------------+
|
||||
|
||||
Common Event IDs:
|
||||
-----------------
|
||||
|
||||
Note: reserved event ids are not listed there
|
||||
|
||||
+----------+------------------------------------------------------------------+
|
||||
| Event Id | Description |
|
||||
+==========+==================================================================+
|
||||
| 4 | AirPlane mode change |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 5 | Keyboard brightness change |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 6 | Touchpad state (enabled/disabled) change |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 7 | FnLock state (enabled/disabled) change |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 8 | Keyboard mode change |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 9 | CapsLock state change |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 13 | NumLock state change |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 14 | ScrollLock state change |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 15 | Performance plan change |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 25 | Display refresh rate change |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 33 | Super key lock state (enabled/disabled) change |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| 35 | Open control center key |
|
||||
+----------+------------------------------------------------------------------+
|
||||
|
||||
Implementation Details
|
||||
======================
|
||||
|
||||
Performance Modes
|
||||
-----------------
|
||||
Changing the performance mode via Command ID 0x08 (SystemPerMode) affects the
|
||||
power limits (PL1/PL2) and fan curves managed by the Embedded Controller (EC).
|
||||
Note that the "Full-speed" and "Performance" mode (1, 3) is typically only
|
||||
available when the system is connected to a DC power source (not USB-C/PD).
|
||||
|
||||
In the driver implementation, switch to performance/full-speed mode without
|
||||
DC power connected will throw the EOPNOTSUPP error.
|
||||
|
||||
Graphics Switching
|
||||
------------------
|
||||
The ``GPUMode`` (0x09) allows switching between Hybrid (Muxless) and Discrete
|
||||
(Muxed) graphics. Changing this value usually requires a system reboot to
|
||||
take effect in the BIOS/Firmware.
|
||||
|
||||
Fan Control
|
||||
-----------
|
||||
The system supports both automatic EC control and manual overrides. Command ID
|
||||
0x14 (``MaxFanSpeedSwitch``) is used to toggle manual control, while ID 0x15
|
||||
sets the actual PWM duty cycle.
|
||||
|
|
@ -71,7 +71,7 @@ to matching WMI devices using a struct wmi_device_id table:
|
|||
.remove = foo_remove, /* optional, devres is preferred */
|
||||
.shutdown = foo_shutdown, /* optional, called during shutdown */
|
||||
.notify_new = foo_notify, /* optional, for event handling */
|
||||
.no_notify_data = true, /* optional, enables events containing no additional data */
|
||||
.min_event_size = X, /* optional, simplifies event payload size verification */
|
||||
.no_singleton = true, /* required for new WMI drivers */
|
||||
};
|
||||
module_wmi_driver(foo_driver);
|
||||
|
|
@ -106,7 +106,8 @@ WMI method drivers
|
|||
|
||||
WMI drivers can call WMI device methods using wmidev_invoke_method(). For each WMI method
|
||||
invocation the WMI driver needs to provide the instance number and the method ID, as well as
|
||||
a buffer with the method arguments and optionally a buffer for the results.
|
||||
a buffer with the method arguments and optionally a buffer for the results. When calling WMI
|
||||
methods that do not return any values, wmidev_invoke_procedure() should be used instead.
|
||||
|
||||
The layout of said buffers is device-specific and described by the Binary MOF data associated
|
||||
with a given WMI device. Said Binary MOF data also describes the method ID of a given WMI method
|
||||
|
|
@ -141,8 +142,10 @@ right before and after calling its remove() or shutdown() callback.
|
|||
However WMI driver developers should be aware that multiple WMI events can be received concurrently,
|
||||
so any locking (if necessary) needs to be provided by the WMI driver itself.
|
||||
|
||||
In order to be able to receive WMI events containing no additional event data,
|
||||
the ``no_notify_data`` flag inside struct wmi_driver should be set to ``true``.
|
||||
The WMI driver can furthermore instruct the WMI driver core to automatically reject WMI events
|
||||
that contain a undersized event payload by populating the ``min_event_size`` field inside
|
||||
struct wmi_driver. Setting this field to 0 will thus enable the WMI driver to receive WMI events
|
||||
without any event payload.
|
||||
|
||||
Take a look at drivers/platform/x86/xiaomi-wmi.c for an example WMI event driver.
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ static void read_residency_counter(struct xe_device *xe, struct xe_mmio *mmio,
|
|||
u64 residency = 0;
|
||||
int ret;
|
||||
|
||||
ret = xe_pmt_telem_read(to_pci_dev(xe->drm.dev),
|
||||
ret = xe_pmt_telem_read(xe->drm.dev,
|
||||
xe_mmio_read32(mmio, PUNIT_TELEMETRY_GUID),
|
||||
&residency, offset, sizeof(residency));
|
||||
if (ret != sizeof(residency)) {
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@ xe_hwmon_energy_get(struct xe_hwmon *hwmon, int channel, long *energy)
|
|||
if (hwmon->xe->info.platform == XE_BATTLEMAGE) {
|
||||
u64 pmt_val;
|
||||
|
||||
ret = xe_pmt_telem_read(to_pci_dev(hwmon->xe->drm.dev),
|
||||
ret = xe_pmt_telem_read(hwmon->xe->drm.dev,
|
||||
xe_mmio_read32(mmio, PUNIT_TELEMETRY_GUID),
|
||||
&pmt_val, BMG_ENERGY_STATUS_PMT_OFFSET, sizeof(pmt_val));
|
||||
if (ret != sizeof(pmt_val)) {
|
||||
|
|
|
|||
|
|
@ -140,10 +140,10 @@ static int xe_guid_decode(u32 guid, int *index, u32 *offset)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int xe_pmt_telem_read(struct pci_dev *pdev, u32 guid, u64 *data, loff_t user_offset,
|
||||
int xe_pmt_telem_read(struct device *dev, u32 guid, u64 *data, loff_t user_offset,
|
||||
u32 count)
|
||||
{
|
||||
struct xe_device *xe = pdev_to_xe_device(pdev);
|
||||
struct xe_device *xe = kdev_to_xe_device(dev);
|
||||
void __iomem *telem_addr = xe->mmio.regs + BMG_TELEMETRY_OFFSET;
|
||||
u32 mem_region;
|
||||
u32 offset;
|
||||
|
|
@ -198,7 +198,6 @@ void xe_vsec_init(struct xe_device *xe)
|
|||
{
|
||||
struct intel_vsec_platform_info *info;
|
||||
struct device *dev = xe->drm.dev;
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
enum xe_vsec platform;
|
||||
|
||||
platform = get_platform_info(xe);
|
||||
|
|
@ -221,6 +220,6 @@ void xe_vsec_init(struct xe_device *xe)
|
|||
* Register a VSEC. Cleanup is handled using device managed
|
||||
* resources.
|
||||
*/
|
||||
intel_vsec_register(pdev, info);
|
||||
intel_vsec_register(dev, info);
|
||||
}
|
||||
MODULE_IMPORT_NS("INTEL_VSEC");
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct pci_dev;
|
||||
struct device;
|
||||
struct xe_device;
|
||||
|
||||
void xe_vsec_init(struct xe_device *xe);
|
||||
int xe_pmt_telem_read(struct pci_dev *pdev, u32 guid, u64 *data, loff_t user_offset, u32 count);
|
||||
int xe_pmt_telem_read(struct device *dev, u32 guid, u64 *data, loff_t user_offset, u32 count);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
* Trademarks are the property of their respective owners.
|
||||
*/
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/serio.h>
|
||||
|
|
@ -12,6 +13,7 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/libps2.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include "psmouse.h"
|
||||
#include "trackpoint.h"
|
||||
|
|
@ -393,6 +395,44 @@ static int trackpoint_reconnect(struct psmouse *psmouse)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* List of known incapable device PNP IDs */
|
||||
static const char * const dt_incompatible_devices[] = {
|
||||
"LEN0304",
|
||||
"LEN0306",
|
||||
"LEN0317",
|
||||
"LEN031A",
|
||||
"LEN031B",
|
||||
"LEN031C",
|
||||
"LEN031D",
|
||||
};
|
||||
|
||||
/*
|
||||
* Checks if it's a doubletap capable device.
|
||||
* The PNP ID format is "PNP: LEN030d PNP0f13".
|
||||
*/
|
||||
static bool trackpoint_is_dt_capable(const char *pnp_id)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!pnp_id)
|
||||
return false;
|
||||
|
||||
/* Must start with "PNP: LEN03" */
|
||||
if (!strstarts(pnp_id, "PNP: LEN03"))
|
||||
return false;
|
||||
|
||||
/* Ensure enough length before comparing */
|
||||
if (strlen(pnp_id) < 12)
|
||||
return false;
|
||||
|
||||
/* Check deny-list */
|
||||
for (i = 0; i < ARRAY_SIZE(dt_incompatible_devices); i++) {
|
||||
if (!strncmp(pnp_id + 5, dt_incompatible_devices[i], 7))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
|
|
@ -470,6 +510,12 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
|
|||
psmouse->vendor, firmware_id,
|
||||
(button_info & 0xf0) >> 4, button_info & 0x0f);
|
||||
|
||||
if (trackpoint_is_dt_capable(ps2dev->serio->firmware_id)) {
|
||||
error = trackpoint_write(ps2dev, TP_DOUBLETAP, TP_DOUBLETAP_ENABLE);
|
||||
if (error)
|
||||
psmouse_warn(psmouse, "Failed to enable doubletap: %d\n", error);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@
|
|||
/* (how hard it is to drag */
|
||||
/* with Z-axis pressed) */
|
||||
|
||||
#define TP_DOUBLETAP 0x58 /* TrackPoint doubletap register */
|
||||
|
||||
#define TP_MINDRAG 0x59 /* Minimum amount of force needed */
|
||||
/* to trigger dragging */
|
||||
|
||||
|
|
@ -110,6 +112,9 @@
|
|||
external device will be forced to 1 */
|
||||
#define TP_MASK_EXT_TAG 0x04
|
||||
|
||||
/* Doubletap register values */
|
||||
#define TP_DOUBLETAP_ENABLE 0xFF /* Enable value */
|
||||
#define TP_DOUBLETAP_DISABLE 0xFE /* Disable value */
|
||||
|
||||
/* Power on Self Test Results */
|
||||
#define TP_POR_SUCCESS 0x3B
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/mlxcpld.h>
|
||||
#include <linux/platform_data/mlxreg.h>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <acpi/button.h>
|
||||
|
||||
#define SURFACE_PRO3_BUTTON_HID "MSHW0028"
|
||||
|
|
@ -72,9 +73,10 @@ struct surface_button {
|
|||
bool suspended;
|
||||
};
|
||||
|
||||
static void surface_button_notify(struct acpi_device *device, u32 event)
|
||||
static void surface_button_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct surface_button *button = acpi_driver_data(device);
|
||||
struct device *dev = data;
|
||||
struct surface_button *button = dev_get_drvdata(dev);
|
||||
struct input_dev *input;
|
||||
int key_code = KEY_RESERVED;
|
||||
bool pressed = false;
|
||||
|
|
@ -109,18 +111,17 @@ static void surface_button_notify(struct acpi_device *device, u32 event)
|
|||
key_code = KEY_VOLUMEDOWN;
|
||||
break;
|
||||
case SURFACE_BUTTON_NOTIFY_TABLET_MODE:
|
||||
dev_warn_once(&device->dev, "Tablet mode is not supported\n");
|
||||
dev_warn_once(dev, "Tablet mode is not supported\n");
|
||||
break;
|
||||
default:
|
||||
dev_info_ratelimited(&device->dev,
|
||||
"Unsupported event [0x%x]\n", event);
|
||||
dev_info_ratelimited(dev, "Unsupported event [0x%x]\n", event);
|
||||
break;
|
||||
}
|
||||
input = button->input;
|
||||
if (key_code == KEY_RESERVED)
|
||||
return;
|
||||
if (pressed)
|
||||
pm_wakeup_dev_event(&device->dev, 0, button->suspended);
|
||||
pm_wakeup_dev_event(dev, 0, button->suspended);
|
||||
if (button->suspended)
|
||||
return;
|
||||
input_report_key(input, key_code, pressed?1:0);
|
||||
|
|
@ -130,8 +131,7 @@ static void surface_button_notify(struct acpi_device *device, u32 event)
|
|||
#ifdef CONFIG_PM_SLEEP
|
||||
static int surface_button_suspend(struct device *dev)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(dev);
|
||||
struct surface_button *button = acpi_driver_data(device);
|
||||
struct surface_button *button = dev_get_drvdata(dev);
|
||||
|
||||
button->suspended = true;
|
||||
return 0;
|
||||
|
|
@ -139,8 +139,7 @@ static int surface_button_suspend(struct device *dev)
|
|||
|
||||
static int surface_button_resume(struct device *dev)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(dev);
|
||||
struct surface_button *button = acpi_driver_data(device);
|
||||
struct surface_button *button = dev_get_drvdata(dev);
|
||||
|
||||
button->suspended = false;
|
||||
return 0;
|
||||
|
|
@ -155,9 +154,8 @@ static int surface_button_resume(struct device *dev)
|
|||
* Returns true if the driver should bind to this device, i.e. the device is
|
||||
* either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1.
|
||||
*/
|
||||
static bool surface_button_check_MSHW0040(struct acpi_device *dev)
|
||||
static bool surface_button_check_MSHW0040(struct device *dev, acpi_handle handle)
|
||||
{
|
||||
acpi_handle handle = dev->handle;
|
||||
union acpi_object *result;
|
||||
u64 oem_platform_rev = 0; // valid revisions are nonzero
|
||||
|
||||
|
|
@ -179,14 +177,15 @@ static bool surface_button_check_MSHW0040(struct acpi_device *dev)
|
|||
ACPI_FREE(result);
|
||||
}
|
||||
|
||||
dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev);
|
||||
dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
|
||||
|
||||
return oem_platform_rev == 0;
|
||||
}
|
||||
|
||||
|
||||
static int surface_button_add(struct acpi_device *device)
|
||||
static int surface_button_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct surface_button *button;
|
||||
struct input_dev *input;
|
||||
const char *hid = acpi_device_hid(device);
|
||||
|
|
@ -196,14 +195,14 @@ static int surface_button_add(struct acpi_device *device)
|
|||
strlen(SURFACE_BUTTON_OBJ_NAME)))
|
||||
return -ENODEV;
|
||||
|
||||
if (!surface_button_check_MSHW0040(device))
|
||||
if (!surface_button_check_MSHW0040(&pdev->dev, device->handle))
|
||||
return -ENODEV;
|
||||
|
||||
button = kzalloc_obj(struct surface_button);
|
||||
if (!button)
|
||||
return -ENOMEM;
|
||||
|
||||
device->driver_data = button;
|
||||
platform_set_drvdata(pdev, button);
|
||||
button->input = input = input_allocate_device();
|
||||
if (!input) {
|
||||
error = -ENOMEM;
|
||||
|
|
@ -216,7 +215,7 @@ static int surface_button_add(struct acpi_device *device)
|
|||
input->name = acpi_device_name(device);
|
||||
input->phys = button->phys;
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->dev.parent = &device->dev;
|
||||
input->dev.parent = &pdev->dev;
|
||||
input_set_capability(input, EV_KEY, KEY_POWER);
|
||||
input_set_capability(input, EV_KEY, KEY_LEFTMETA);
|
||||
input_set_capability(input, EV_KEY, KEY_VOLUMEUP);
|
||||
|
|
@ -226,8 +225,17 @@ static int surface_button_add(struct acpi_device *device)
|
|||
if (error)
|
||||
goto err_free_input;
|
||||
|
||||
device_init_wakeup(&device->dev, true);
|
||||
dev_info(&device->dev, "%s [%s]\n", acpi_device_name(device),
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
|
||||
error = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
surface_button_notify, &pdev->dev);
|
||||
if (error) {
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
input_unregister_device(input);
|
||||
goto err_free_button;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "%s [%s]\n", acpi_device_name(device),
|
||||
acpi_device_bid(device));
|
||||
return 0;
|
||||
|
||||
|
|
@ -238,10 +246,13 @@ static int surface_button_add(struct acpi_device *device)
|
|||
return error;
|
||||
}
|
||||
|
||||
static void surface_button_remove(struct acpi_device *device)
|
||||
static void surface_button_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct surface_button *button = acpi_driver_data(device);
|
||||
struct surface_button *button = platform_get_drvdata(pdev);
|
||||
|
||||
acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
|
||||
ACPI_DEVICE_NOTIFY, surface_button_notify);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
input_unregister_device(button->input);
|
||||
kfree(button);
|
||||
}
|
||||
|
|
@ -249,16 +260,14 @@ static void surface_button_remove(struct acpi_device *device)
|
|||
static SIMPLE_DEV_PM_OPS(surface_button_pm,
|
||||
surface_button_suspend, surface_button_resume);
|
||||
|
||||
static struct acpi_driver surface_button_driver = {
|
||||
.name = "surface_pro3_button",
|
||||
.class = "SurfacePro3",
|
||||
.ids = surface_button_device_ids,
|
||||
.ops = {
|
||||
.add = surface_button_add,
|
||||
.remove = surface_button_remove,
|
||||
.notify = surface_button_notify,
|
||||
static struct platform_driver surface_button_driver = {
|
||||
.probe = surface_button_probe,
|
||||
.remove = surface_button_remove,
|
||||
.driver = {
|
||||
.name = "surface_pro3_button",
|
||||
.acpi_match_table = surface_button_device_ids,
|
||||
.pm = &surface_button_pm,
|
||||
},
|
||||
.drv.pm = &surface_button_pm,
|
||||
};
|
||||
|
||||
module_acpi_driver(surface_button_driver);
|
||||
module_platform_driver(surface_button_driver);
|
||||
|
|
|
|||
|
|
@ -364,20 +364,23 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 met
|
|||
EXPORT_SYMBOL_GPL(wmidev_evaluate_method);
|
||||
|
||||
/**
|
||||
* wmidev_invoke_method - Invoke a WMI method
|
||||
* wmidev_invoke_method - Invoke a WMI method that returns values
|
||||
* @wdev: A wmi bus device from a driver
|
||||
* @instance: Instance index
|
||||
* @method_id: Method ID to call
|
||||
* @in: Mandatory WMI buffer containing input for the method call
|
||||
* @out: Optional WMI buffer to return the method results
|
||||
* @out: Mandatory WMI buffer to return the method results
|
||||
* @min_size: Minimum size of the method result data in bytes
|
||||
*
|
||||
* Invoke a WMI method, the caller must free the resulting data inside @out.
|
||||
* Said data is guaranteed to be aligned on a 8-byte boundary.
|
||||
* Invoke a WMI method that returns values, the caller must free the resulting
|
||||
* data inside @out using kfree(). Said data is guaranteed to be aligned on a
|
||||
* 8-byte boundary. Use wmidev_invoke_procedure() for WMI methods that
|
||||
* return no values.
|
||||
*
|
||||
* Return: 0 on success or negative error code on failure.
|
||||
*/
|
||||
int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
|
||||
const struct wmi_buffer *in, struct wmi_buffer *out)
|
||||
const struct wmi_buffer *in, struct wmi_buffer *out, size_t min_size)
|
||||
{
|
||||
struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);
|
||||
struct acpi_buffer aout = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
|
|
@ -398,10 +401,7 @@ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
|
|||
ain.pointer = in->data;
|
||||
}
|
||||
|
||||
if (out)
|
||||
status = wmidev_evaluate_method(wdev, instance, method_id, &ain, &aout);
|
||||
else
|
||||
status = wmidev_evaluate_method(wdev, instance, method_id, &ain, NULL);
|
||||
status = wmidev_evaluate_method(wdev, instance, method_id, &ain, &aout);
|
||||
|
||||
if (wblock->gblock.flags & ACPI_WMI_STRING)
|
||||
kfree(ain.pointer);
|
||||
|
|
@ -409,9 +409,6 @@ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
|
|||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
if (!out)
|
||||
return 0;
|
||||
|
||||
obj = aout.pointer;
|
||||
if (!obj) {
|
||||
out->length = 0;
|
||||
|
|
@ -420,13 +417,57 @@ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
|
|||
return 0;
|
||||
}
|
||||
|
||||
ret = wmi_unmarshal_acpi_object(obj, out);
|
||||
ret = wmi_unmarshal_acpi_object(obj, out, min_size);
|
||||
kfree(obj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmidev_invoke_method);
|
||||
|
||||
/**
|
||||
* wmidev_invoke_procedure - Invoke a WMI method that does not return values
|
||||
* @wdev: A wmi bus device from a driver
|
||||
* @instance: Instance index
|
||||
* @method_id: Method ID to call
|
||||
* @in: Mandatory WMI buffer containing input for the method call
|
||||
*
|
||||
* Invoke a WMI method that does not return any values. Use wmidev_invoke_method()
|
||||
* for WMI methods that do return values.
|
||||
*
|
||||
* Return: 0 on success or negative error code on failure.
|
||||
*/
|
||||
int wmidev_invoke_procedure(struct wmi_device *wdev, u8 instance, u32 method_id,
|
||||
const struct wmi_buffer *in)
|
||||
{
|
||||
struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);
|
||||
struct acpi_buffer ain;
|
||||
acpi_status status;
|
||||
int ret;
|
||||
|
||||
if (wblock->gblock.flags & ACPI_WMI_STRING) {
|
||||
ret = wmi_marshal_string(in, &ain);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
if (in->length > U32_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
ain.length = in->length;
|
||||
ain.pointer = in->data;
|
||||
}
|
||||
|
||||
status = wmidev_evaluate_method(wdev, instance, method_id, &ain, NULL);
|
||||
|
||||
if (wblock->gblock.flags & ACPI_WMI_STRING)
|
||||
kfree(ain.pointer);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmidev_invoke_procedure);
|
||||
|
||||
static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
|
||||
struct acpi_buffer *out)
|
||||
{
|
||||
|
|
@ -524,13 +565,15 @@ EXPORT_SYMBOL_GPL(wmidev_block_query);
|
|||
* @wdev: A wmi bus device from a driver
|
||||
* @instance: Instance index
|
||||
* @out: WMI buffer to fill
|
||||
* @min_size: Minimum size of the result data in bytes
|
||||
*
|
||||
* Query a WMI data block, the caller must free the resulting data inside @out.
|
||||
* Said data is guaranteed to be aligned on a 8-byte boundary.
|
||||
* Query a WMI data block, the caller must free the resulting data inside @out
|
||||
* using kfree(). Said data is guaranteed to be aligned on a 8-byte boundary.
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer *out)
|
||||
int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer *out,
|
||||
size_t min_size)
|
||||
{
|
||||
union acpi_object *obj;
|
||||
int ret;
|
||||
|
|
@ -539,7 +582,7 @@ int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer *
|
|||
if (!obj)
|
||||
return -EIO;
|
||||
|
||||
ret = wmi_unmarshal_acpi_object(obj, out);
|
||||
ret = wmi_unmarshal_acpi_object(obj, out, min_size);
|
||||
kfree(obj);
|
||||
|
||||
return ret;
|
||||
|
|
@ -970,7 +1013,7 @@ static int wmi_dev_probe(struct device *dev)
|
|||
}
|
||||
|
||||
if (wdriver->notify || wdriver->notify_new) {
|
||||
if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags) && !wdriver->no_notify_data)
|
||||
if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags) && wdriver->min_event_size)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -1329,10 +1372,14 @@ static int wmi_get_notify_data(struct wmi_block *wblock, union acpi_object **obj
|
|||
static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj)
|
||||
{
|
||||
struct wmi_driver *driver = to_wmi_driver(wblock->dev.dev.driver);
|
||||
struct wmi_buffer dummy = {
|
||||
.length = 0,
|
||||
.data = ZERO_SIZE_PTR,
|
||||
};
|
||||
struct wmi_buffer buffer;
|
||||
int ret;
|
||||
|
||||
if (!obj && !driver->no_notify_data) {
|
||||
if (!obj && driver->min_event_size) {
|
||||
dev_warn(&wblock->dev.dev, "Event contains no event data\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -1342,11 +1389,11 @@ static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj)
|
|||
|
||||
if (driver->notify_new) {
|
||||
if (!obj) {
|
||||
driver->notify_new(&wblock->dev, NULL);
|
||||
driver->notify_new(&wblock->dev, &dummy);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = wmi_unmarshal_acpi_object(obj, &buffer);
|
||||
ret = wmi_unmarshal_acpi_object(obj, &buffer, driver->min_event_size);
|
||||
if (ret < 0) {
|
||||
dev_warn(&wblock->dev.dev, "Failed to unmarshal event data: %d\n", ret);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@
|
|||
union acpi_object;
|
||||
struct wmi_buffer;
|
||||
|
||||
int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer);
|
||||
int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer,
|
||||
size_t min_size);
|
||||
int wmi_marshal_string(const struct wmi_buffer *buffer, struct acpi_buffer *out);
|
||||
|
||||
#endif /* _WMI_INTERNAL_H_ */
|
||||
|
|
|
|||
|
|
@ -151,7 +151,8 @@ static int wmi_obj_transform(const union acpi_object *obj, u8 *buffer)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer)
|
||||
int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer,
|
||||
size_t min_size)
|
||||
{
|
||||
size_t length, alloc_length;
|
||||
u8 *data;
|
||||
|
|
@ -161,6 +162,9 @@ int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *b
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (length < min_size)
|
||||
return -ENODATA;
|
||||
|
||||
if (ARCH_KMALLOC_MINALIGN < 8) {
|
||||
/*
|
||||
* kmalloc() guarantees that the alignment of the resulting memory allocation is at
|
||||
|
|
|
|||
|
|
@ -372,7 +372,7 @@ static void wmi_unmarshal_acpi_object_test(struct kunit *test)
|
|||
struct wmi_buffer result;
|
||||
int ret;
|
||||
|
||||
ret = wmi_unmarshal_acpi_object(¶m->obj, &result);
|
||||
ret = wmi_unmarshal_acpi_object(¶m->obj, &result, param->buffer.length);
|
||||
if (ret < 0)
|
||||
KUNIT_FAIL_AND_ABORT(test, "Unmarshalling of ACPI object failed\n");
|
||||
|
||||
|
|
@ -389,7 +389,7 @@ static void wmi_unmarshal_acpi_object_failure_test(struct kunit *test)
|
|||
struct wmi_buffer result;
|
||||
int ret;
|
||||
|
||||
ret = wmi_unmarshal_acpi_object(¶m->obj, &result);
|
||||
ret = wmi_unmarshal_acpi_object(¶m->obj, &result, 0);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
|
|
@ -427,6 +427,25 @@ static void wmi_marshal_string_failure_test(struct kunit *test)
|
|||
KUNIT_FAIL(test, "Invalid string was not rejected\n");
|
||||
}
|
||||
|
||||
static void wmi_unmarshal_acpi_object_undersized_test(struct kunit *test)
|
||||
{
|
||||
const union acpi_object obj = {
|
||||
.integer = {
|
||||
.type = ACPI_TYPE_INTEGER,
|
||||
.value = 0xdeadbeef,
|
||||
},
|
||||
};
|
||||
struct wmi_buffer result;
|
||||
int ret;
|
||||
|
||||
ret = wmi_unmarshal_acpi_object(&obj, &result, sizeof(expected_single_integer) + 1);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
kfree(result.data);
|
||||
KUNIT_FAIL(test, "Undersized unmarshalling result was not rejected\n");
|
||||
}
|
||||
|
||||
static struct kunit_case wmi_marshalling_test_cases[] = {
|
||||
KUNIT_CASE_PARAM(wmi_unmarshal_acpi_object_test,
|
||||
wmi_unmarshal_acpi_object_gen_params),
|
||||
|
|
@ -436,6 +455,7 @@ static struct kunit_case wmi_marshalling_test_cases[] = {
|
|||
wmi_unmarshal_acpi_object_failure_gen_params),
|
||||
KUNIT_CASE_PARAM(wmi_marshal_string_failure_test,
|
||||
wmi_marshal_string_failure_gen_params),
|
||||
KUNIT_CASE(wmi_unmarshal_acpi_object_undersized_test),
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -113,6 +113,24 @@ config GIGABYTE_WMI
|
|||
To compile this driver as a module, choose M here: the module will
|
||||
be called gigabyte-wmi.
|
||||
|
||||
config BITLAND_MIFS_WMI
|
||||
tristate "Bitland MIFS (MiInterface) WMI driver"
|
||||
depends on ACPI_WMI
|
||||
depends on HWMON
|
||||
depends on INPUT
|
||||
depends on POWER_SUPPLY
|
||||
select ACPI_PLATFORM_PROFILE
|
||||
select INPUT_SPARSEKMAP
|
||||
help
|
||||
This is a driver for Bitland MiInterface based laptops.
|
||||
|
||||
It provides the access to the temperature, fan speed, gpu
|
||||
control, keyboard backlight brightness and platform profile
|
||||
via hwmon and sysfs.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called bitland-mifs-wmi.
|
||||
|
||||
config ACERHDF
|
||||
tristate "Acer Aspire One temperature and fan driver"
|
||||
depends on ACPI_EC && THERMAL
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ obj-$(CONFIG_NVIDIA_WMI_EC_BACKLIGHT) += nvidia-wmi-ec-backlight.o
|
|||
obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o
|
||||
obj-$(CONFIG_REDMI_WMI) += redmi-wmi.o
|
||||
obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o
|
||||
obj-$(CONFIG_BITLAND_MIFS_WMI) += bitland-mifs-wmi.o
|
||||
|
||||
# Acer
|
||||
obj-$(CONFIG_ACERHDF) += acerhdf.o
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
static const struct acpi_device_id acer_wireless_acpi_ids[] = {
|
||||
|
|
@ -18,13 +19,14 @@ static const struct acpi_device_id acer_wireless_acpi_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, acer_wireless_acpi_ids);
|
||||
|
||||
static void acer_wireless_notify(struct acpi_device *adev, u32 event)
|
||||
static void acer_wireless_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct input_dev *idev = acpi_driver_data(adev);
|
||||
struct device *dev = data;
|
||||
struct input_dev *idev = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(&adev->dev, "event=%#x\n", event);
|
||||
dev_dbg(dev, "event=%#x\n", event);
|
||||
if (event != 0x80) {
|
||||
dev_notice(&adev->dev, "Unknown SMKB event: %#x\n", event);
|
||||
dev_notice(dev, "Unknown SMKB event: %#x\n", event);
|
||||
return;
|
||||
}
|
||||
input_report_key(idev, KEY_RFKILL, 1);
|
||||
|
|
@ -33,15 +35,16 @@ static void acer_wireless_notify(struct acpi_device *adev, u32 event)
|
|||
input_sync(idev);
|
||||
}
|
||||
|
||||
static int acer_wireless_add(struct acpi_device *adev)
|
||||
static int acer_wireless_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct input_dev *idev;
|
||||
int ret;
|
||||
|
||||
idev = devm_input_allocate_device(&adev->dev);
|
||||
idev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
adev->driver_data = idev;
|
||||
platform_set_drvdata(pdev, idev);
|
||||
idev->name = "Acer Wireless Radio Control";
|
||||
idev->phys = "acer-wireless/input0";
|
||||
idev->id.bustype = BUS_HOST;
|
||||
|
|
@ -50,19 +53,32 @@ static int acer_wireless_add(struct acpi_device *adev)
|
|||
set_bit(EV_KEY, idev->evbit);
|
||||
set_bit(KEY_RFKILL, idev->keybit);
|
||||
|
||||
return input_register_device(idev);
|
||||
ret = input_register_device(idev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return acpi_dev_install_notify_handler(ACPI_COMPANION(&pdev->dev),
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
acer_wireless_notify,
|
||||
&pdev->dev);
|
||||
}
|
||||
|
||||
static struct acpi_driver acer_wireless_driver = {
|
||||
.name = "Acer Wireless Radio Control Driver",
|
||||
.class = "hotkey",
|
||||
.ids = acer_wireless_acpi_ids,
|
||||
.ops = {
|
||||
.add = acer_wireless_add,
|
||||
.notify = acer_wireless_notify,
|
||||
static void acer_wireless_remove(struct platform_device *pdev)
|
||||
{
|
||||
acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
acer_wireless_notify);
|
||||
}
|
||||
|
||||
static struct platform_driver acer_wireless_driver = {
|
||||
.probe = acer_wireless_probe,
|
||||
.remove = acer_wireless_remove,
|
||||
.driver = {
|
||||
.name = "Acer Wireless Radio Control Driver",
|
||||
.acpi_match_table = acer_wireless_acpi_ids,
|
||||
},
|
||||
};
|
||||
module_acpi_driver(acer_wireless_driver);
|
||||
module_platform_driver(acer_wireless_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Acer Wireless Radio Control Driver");
|
||||
MODULE_AUTHOR("Chris Chiu <chiu@gmail.com>");
|
||||
|
|
|
|||
|
|
@ -1517,9 +1517,9 @@ static void asus_input_exit(struct asus_laptop *asus)
|
|||
/*
|
||||
* ACPI driver
|
||||
*/
|
||||
static void asus_acpi_notify(struct acpi_device *device, u32 event)
|
||||
static void asus_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct asus_laptop *asus = acpi_driver_data(device);
|
||||
struct asus_laptop *asus = data;
|
||||
u16 count;
|
||||
|
||||
/* TODO Find a better way to handle events count. */
|
||||
|
|
@ -1824,8 +1824,9 @@ static void asus_dmi_check(void)
|
|||
|
||||
static bool asus_device_present;
|
||||
|
||||
static int asus_acpi_add(struct acpi_device *device)
|
||||
static int asus_acpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct asus_laptop *asus;
|
||||
int result;
|
||||
|
||||
|
|
@ -1837,7 +1838,6 @@ static int asus_acpi_add(struct acpi_device *device)
|
|||
asus->handle = device->handle;
|
||||
strscpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME);
|
||||
strscpy(acpi_device_class(device), ASUS_LAPTOP_CLASS);
|
||||
device->driver_data = asus;
|
||||
asus->device = device;
|
||||
|
||||
asus_dmi_check();
|
||||
|
|
@ -1846,6 +1846,8 @@ static int asus_acpi_add(struct acpi_device *device)
|
|||
if (result)
|
||||
goto fail_platform;
|
||||
|
||||
platform_set_drvdata(pdev, asus);
|
||||
|
||||
/*
|
||||
* Need platform type detection first, then the platform
|
||||
* device. It is used as a parent for the sub-devices below.
|
||||
|
|
@ -1881,6 +1883,11 @@ static int asus_acpi_add(struct acpi_device *device)
|
|||
if (result && result != -ENODEV)
|
||||
goto fail_pega_rfkill;
|
||||
|
||||
result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
asus_acpi_notify, asus);
|
||||
if (result)
|
||||
goto fail_pega_rfkill;
|
||||
|
||||
asus_device_present = true;
|
||||
return 0;
|
||||
|
||||
|
|
@ -1902,10 +1909,12 @@ fail_platform:
|
|||
return result;
|
||||
}
|
||||
|
||||
static void asus_acpi_remove(struct acpi_device *device)
|
||||
static void asus_acpi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct asus_laptop *asus = acpi_driver_data(device);
|
||||
struct asus_laptop *asus = platform_get_drvdata(pdev);
|
||||
|
||||
acpi_dev_remove_notify_handler(asus->device, ACPI_DEVICE_NOTIFY,
|
||||
asus_acpi_notify);
|
||||
asus_backlight_exit(asus);
|
||||
asus_rfkill_exit(asus);
|
||||
asus_led_exit(asus);
|
||||
|
|
@ -1924,16 +1933,13 @@ static const struct acpi_device_id asus_device_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, asus_device_ids);
|
||||
|
||||
static struct acpi_driver asus_acpi_driver = {
|
||||
.name = ASUS_LAPTOP_NAME,
|
||||
.class = ASUS_LAPTOP_CLASS,
|
||||
.ids = asus_device_ids,
|
||||
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
|
||||
.ops = {
|
||||
.add = asus_acpi_add,
|
||||
.remove = asus_acpi_remove,
|
||||
.notify = asus_acpi_notify,
|
||||
},
|
||||
static struct platform_driver asus_acpi_driver = {
|
||||
.probe = asus_acpi_probe,
|
||||
.remove = asus_acpi_remove,
|
||||
.driver = {
|
||||
.name = ASUS_LAPTOP_NAME,
|
||||
.acpi_match_table = asus_device_ids,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init asus_laptop_init(void)
|
||||
|
|
@ -1944,7 +1950,7 @@ static int __init asus_laptop_init(void)
|
|||
if (result < 0)
|
||||
return result;
|
||||
|
||||
result = acpi_bus_register_driver(&asus_acpi_driver);
|
||||
result = platform_driver_register(&asus_acpi_driver);
|
||||
if (result < 0)
|
||||
goto fail_acpi_driver;
|
||||
if (!asus_device_present) {
|
||||
|
|
@ -1954,7 +1960,7 @@ static int __init asus_laptop_init(void)
|
|||
return 0;
|
||||
|
||||
fail_no_device:
|
||||
acpi_bus_unregister_driver(&asus_acpi_driver);
|
||||
platform_driver_unregister(&asus_acpi_driver);
|
||||
fail_acpi_driver:
|
||||
platform_driver_unregister(&platform_driver);
|
||||
return result;
|
||||
|
|
@ -1962,7 +1968,7 @@ fail_acpi_driver:
|
|||
|
||||
static void __exit asus_laptop_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&asus_acpi_driver);
|
||||
platform_driver_unregister(&asus_acpi_driver);
|
||||
platform_driver_unregister(&platform_driver);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
struct hswc_params {
|
||||
|
|
@ -108,9 +109,10 @@ static void led_state_set(struct led_classdev *led, enum led_brightness value)
|
|||
queue_work(data->wq, &data->led_work);
|
||||
}
|
||||
|
||||
static void asus_wireless_notify(struct acpi_device *adev, u32 event)
|
||||
static void asus_wireless_notify(acpi_handle handle, u32 event, void *context)
|
||||
{
|
||||
struct asus_wireless_data *data = acpi_driver_data(adev);
|
||||
struct asus_wireless_data *data = context;
|
||||
struct acpi_device *adev = data->adev;
|
||||
|
||||
dev_dbg(&adev->dev, "event=%#x\n", event);
|
||||
if (event != 0x88) {
|
||||
|
|
@ -123,19 +125,22 @@ static void asus_wireless_notify(struct acpi_device *adev, u32 event)
|
|||
input_sync(data->idev);
|
||||
}
|
||||
|
||||
static int asus_wireless_add(struct acpi_device *adev)
|
||||
static int asus_wireless_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
|
||||
struct asus_wireless_data *data;
|
||||
const struct acpi_device_id *id;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL);
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
adev->driver_data = data;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
data->adev = adev;
|
||||
|
||||
data->idev = devm_input_allocate_device(&adev->dev);
|
||||
data->idev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!data->idev)
|
||||
return -ENOMEM;
|
||||
data->idev->name = "Asus Wireless Radio Control";
|
||||
|
|
@ -164,34 +169,44 @@ static int asus_wireless_add(struct acpi_device *adev)
|
|||
data->led.flags = LED_CORE_SUSPENDRESUME;
|
||||
data->led.max_brightness = 1;
|
||||
data->led.default_trigger = "rfkill-none";
|
||||
err = devm_led_classdev_register(&adev->dev, &data->led);
|
||||
err = devm_led_classdev_register(&pdev->dev, &data->led);
|
||||
if (err)
|
||||
destroy_workqueue(data->wq);
|
||||
goto err;
|
||||
|
||||
err = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY,
|
||||
asus_wireless_notify, data);
|
||||
if (err) {
|
||||
devm_led_classdev_unregister(&pdev->dev, &data->led);
|
||||
goto err;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
destroy_workqueue(data->wq);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void asus_wireless_remove(struct acpi_device *adev)
|
||||
static void asus_wireless_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct asus_wireless_data *data = acpi_driver_data(adev);
|
||||
struct asus_wireless_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
acpi_dev_remove_notify_handler(data->adev, ACPI_DEVICE_NOTIFY,
|
||||
asus_wireless_notify);
|
||||
if (data->wq) {
|
||||
devm_led_classdev_unregister(&adev->dev, &data->led);
|
||||
devm_led_classdev_unregister(&pdev->dev, &data->led);
|
||||
destroy_workqueue(data->wq);
|
||||
}
|
||||
}
|
||||
|
||||
static struct acpi_driver asus_wireless_driver = {
|
||||
.name = "Asus Wireless Radio Control Driver",
|
||||
.class = "hotkey",
|
||||
.ids = device_ids,
|
||||
.ops = {
|
||||
.add = asus_wireless_add,
|
||||
.remove = asus_wireless_remove,
|
||||
.notify = asus_wireless_notify,
|
||||
static struct platform_driver asus_wireless_driver = {
|
||||
.probe = asus_wireless_probe,
|
||||
.remove = asus_wireless_remove,
|
||||
.driver = {
|
||||
.name = "Asus Wireless Radio Control Driver",
|
||||
.acpi_match_table = device_ids,
|
||||
},
|
||||
};
|
||||
module_acpi_driver(asus_wireless_driver);
|
||||
module_platform_driver(asus_wireless_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Asus Wireless Radio Control Driver");
|
||||
MODULE_AUTHOR("João Paulo Rechi Vita <jprvita@gmail.com>");
|
||||
|
|
|
|||
|
|
@ -125,7 +125,6 @@ module_param(fnlock_default, bool, 0444);
|
|||
#define NVIDIA_TEMP_MIN 75
|
||||
#define NVIDIA_TEMP_MAX 87
|
||||
|
||||
#define ASUS_SCREENPAD_BRIGHT_MIN 20
|
||||
#define ASUS_SCREENPAD_BRIGHT_MAX 255
|
||||
#define ASUS_SCREENPAD_BRIGHT_DEFAULT 60
|
||||
|
||||
|
|
@ -1557,7 +1556,10 @@ static ssize_t charge_control_end_threshold_show(struct device *device,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%d\n", charge_end_threshold);
|
||||
if ((charge_end_threshold >= 0) && (charge_end_threshold <= 100))
|
||||
return sysfs_emit(buf, "%d\n", charge_end_threshold);
|
||||
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(charge_control_end_threshold);
|
||||
|
|
@ -1580,11 +1582,11 @@ static int asus_wmi_battery_add(struct power_supply *battery, struct acpi_batter
|
|||
return -ENODEV;
|
||||
|
||||
/* The charge threshold is only reset when the system is power cycled,
|
||||
* and we can't get the current threshold so let set it to 100% when
|
||||
* a battery is added.
|
||||
* and we can't read the current threshold, however the majority of
|
||||
* platforms retains it, therefore signal the threshold as unknown
|
||||
* until user explicitly sets it to a new value.
|
||||
*/
|
||||
asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, 100, NULL);
|
||||
charge_end_threshold = 100;
|
||||
charge_end_threshold = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -4408,43 +4410,35 @@ static int read_screenpad_brightness(struct backlight_device *bd)
|
|||
return err;
|
||||
/* The device brightness can only be read if powered, so return stored */
|
||||
if (err == BACKLIGHT_POWER_OFF)
|
||||
return asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
return bd->props.brightness;
|
||||
|
||||
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return (retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK) - ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
|
||||
}
|
||||
|
||||
static int update_screenpad_bl_status(struct backlight_device *bd)
|
||||
{
|
||||
struct asus_wmi *asus = bl_get_data(bd);
|
||||
int power, err = 0;
|
||||
u32 ctrl_param;
|
||||
u32 ctrl_param = bd->props.brightness;
|
||||
int err = 0;
|
||||
|
||||
power = read_screenpad_backlight_power(asus);
|
||||
if (power < 0)
|
||||
return power;
|
||||
if (bd->props.power) {
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 1, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (bd->props.power != power) {
|
||||
if (power != BACKLIGHT_POWER_ON) {
|
||||
/* Only brightness > 0 can power it back on */
|
||||
ctrl_param = asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT,
|
||||
ctrl_param, NULL);
|
||||
} else {
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL);
|
||||
}
|
||||
} else if (power == BACKLIGHT_POWER_ON) {
|
||||
/* Only set brightness if powered on or we get invalid/unsync state */
|
||||
ctrl_param = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Ensure brightness is stored to turn back on with */
|
||||
if (err == 0)
|
||||
asus->driver->screenpad_brightness = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
if (!bd->props.power) {
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -4462,22 +4456,19 @@ static int asus_screenpad_init(struct asus_wmi *asus)
|
|||
int err, power;
|
||||
int brightness = 0;
|
||||
|
||||
power = read_screenpad_backlight_power(asus);
|
||||
power = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER);
|
||||
if (power < 0)
|
||||
return power;
|
||||
|
||||
if (power != BACKLIGHT_POWER_OFF) {
|
||||
if (power) {
|
||||
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
/* default to an acceptable min brightness on boot if too low */
|
||||
if (brightness < ASUS_SCREENPAD_BRIGHT_MIN)
|
||||
brightness = ASUS_SCREENPAD_BRIGHT_DEFAULT;
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */
|
||||
props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX - ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX;
|
||||
bd = backlight_device_register("asus_screenpad",
|
||||
&asus->platform_device->dev, asus,
|
||||
&asus_screenpad_bl_ops, &props);
|
||||
|
|
@ -4488,7 +4479,7 @@ static int asus_screenpad_init(struct asus_wmi *asus)
|
|||
|
||||
asus->screenpad_backlight_device = bd;
|
||||
asus->driver->screenpad_brightness = brightness;
|
||||
bd->props.brightness = brightness - ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
bd->props.brightness = brightness;
|
||||
bd->props.power = power;
|
||||
backlight_update_status(bd);
|
||||
|
||||
|
|
@ -5413,17 +5404,3 @@ void asus_wmi_unregister_driver(struct asus_wmi_driver *driver)
|
|||
used = false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver);
|
||||
|
||||
static int __init asus_wmi_init(void)
|
||||
{
|
||||
pr_info("ASUS WMI generic driver loaded\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit asus_wmi_exit(void)
|
||||
{
|
||||
pr_info("ASUS WMI generic driver unloaded\n");
|
||||
}
|
||||
|
||||
module_init(asus_wmi_init);
|
||||
module_exit(asus_wmi_exit);
|
||||
|
|
|
|||
|
|
@ -272,30 +272,27 @@ static int p50_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
|||
struct p50_gpio *p50 = gpiochip_get_data(gc);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&p50->lock);
|
||||
guard(mutex)(&p50->lock);
|
||||
|
||||
ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_READ_GPIO, gpio_params[offset], 0);
|
||||
if (ret == 0)
|
||||
ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_unlock(&p50->lock);
|
||||
ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
static int p50_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
|
||||
{
|
||||
struct p50_gpio *p50 = gpiochip_get_data(gc);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&p50->lock);
|
||||
guard(mutex)(&p50->lock);
|
||||
|
||||
ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_WRITE_GPIO,
|
||||
gpio_params[offset], value);
|
||||
|
||||
mutex_unlock(&p50->lock);
|
||||
|
||||
return ret;
|
||||
return p50_send_mbox_cmd(p50, P50_MBOX_CMD_WRITE_GPIO,
|
||||
gpio_params[offset], value);
|
||||
}
|
||||
|
||||
static int p50_gpio_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,837 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Linux driver for Bitland notebooks.
|
||||
*
|
||||
* Copyright (C) 2026 2 Mingyou Chen <qby140326@gmail.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/device/devres.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/platform_profile.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/units.h>
|
||||
#include <linux/wmi.h>
|
||||
|
||||
#define DRV_NAME "bitland-mifs-wmi"
|
||||
#define BITLAND_MIFS_GUID "B60BFB48-3E5B-49E4-A0E9-8CFFE1B3434B"
|
||||
#define BITLAND_EVENT_GUID "46C93E13-EE9B-4262-8488-563BCA757FEF"
|
||||
|
||||
enum bitland_mifs_operation {
|
||||
WMI_METHOD_GET = 250,
|
||||
WMI_METHOD_SET = 251,
|
||||
};
|
||||
|
||||
enum bitland_mifs_function {
|
||||
WMI_FN_SYSTEM_PER_MODE = 8,
|
||||
WMI_FN_GPU_MODE = 9,
|
||||
WMI_FN_KBD_TYPE = 10,
|
||||
WMI_FN_FN_LOCK = 11,
|
||||
WMI_FN_TP_LOCK = 12,
|
||||
WMI_FN_FAN_SPEEDS = 13,
|
||||
WMI_FN_RGB_KB_MODE = 16,
|
||||
WMI_FN_RGB_KB_COLOR = 17,
|
||||
WMI_FN_RGB_KB_BRIGHTNESS = 18,
|
||||
WMI_FN_SYSTEM_AC_TYPE = 19,
|
||||
WMI_FN_MAX_FAN_SWITCH = 20,
|
||||
WMI_FN_MAX_FAN_SPEED = 21,
|
||||
WMI_FN_CPU_THERMOMETER = 22,
|
||||
WMI_FN_CPU_POWER = 23,
|
||||
};
|
||||
|
||||
enum bitland_system_ac_mode {
|
||||
WMI_SYSTEM_AC_TYPEC = 1,
|
||||
/* Unknown type, this is unused in the original driver */
|
||||
WMI_SYSTEM_AC_CIRCULARHOLE = 2,
|
||||
};
|
||||
|
||||
enum bitland_mifs_power_profile {
|
||||
WMI_PP_BALANCED = 0,
|
||||
WMI_PP_PERFORMANCE = 1,
|
||||
WMI_PP_QUIET = 2,
|
||||
WMI_PP_FULL_SPEED = 3,
|
||||
};
|
||||
|
||||
enum bitland_mifs_event_id {
|
||||
WMI_EVENT_RESERVED_1 = 1,
|
||||
WMI_EVENT_RESERVED_2 = 2,
|
||||
WMI_EVENT_RESERVED_3 = 3,
|
||||
WMI_EVENT_AIRPLANE_MODE = 4,
|
||||
WMI_EVENT_KBD_BRIGHTNESS = 5,
|
||||
WMI_EVENT_TOUCHPAD_STATE = 6,
|
||||
WMI_EVENT_FNLOCK_STATE = 7,
|
||||
WMI_EVENT_KBD_MODE = 8,
|
||||
WMI_EVENT_CAPSLOCK_STATE = 9,
|
||||
WMI_EVENT_CALCULATOR_START = 11,
|
||||
WMI_EVENT_BROWSER_START = 12,
|
||||
WMI_EVENT_NUMLOCK_STATE = 13,
|
||||
WMI_EVENT_SCROLLLOCK_STATE = 14,
|
||||
WMI_EVENT_PERFORMANCE_PLAN = 15,
|
||||
WMI_EVENT_FN_J = 16,
|
||||
WMI_EVENT_FN_F = 17,
|
||||
WMI_EVENT_FN_0 = 18,
|
||||
WMI_EVENT_FN_1 = 19,
|
||||
WMI_EVENT_FN_2 = 20,
|
||||
WMI_EVENT_FN_3 = 21,
|
||||
WMI_EVENT_FN_4 = 22,
|
||||
WMI_EVENT_FN_5 = 24,
|
||||
WMI_EVENT_REFRESH_RATE = 25,
|
||||
WMI_EVENT_CPU_FAN_SPEED = 26,
|
||||
WMI_EVENT_GPU_FAN_SPEED = 32,
|
||||
WMI_EVENT_WIN_KEY_LOCK = 33,
|
||||
WMI_EVENT_RESERVED_23 = 34,
|
||||
WMI_EVENT_OPEN_APP = 35,
|
||||
};
|
||||
|
||||
enum bitland_mifs_event_type {
|
||||
WMI_EVENT_TYPE_HOTKEY = 1,
|
||||
};
|
||||
|
||||
enum bitland_wmi_device_type {
|
||||
BITLAND_WMI_CONTROL = 0,
|
||||
BITLAND_WMI_EVENT = 1,
|
||||
};
|
||||
|
||||
struct bitland_mifs_input {
|
||||
u8 reserved1;
|
||||
u8 operation;
|
||||
u8 reserved2;
|
||||
u8 function;
|
||||
u8 payload[28];
|
||||
} __packed;
|
||||
|
||||
struct bitland_mifs_output {
|
||||
u8 reserved1;
|
||||
u8 operation;
|
||||
u8 reserved2;
|
||||
u8 function;
|
||||
u8 data[28];
|
||||
} __packed;
|
||||
|
||||
struct bitland_mifs_event {
|
||||
u8 event_type;
|
||||
u8 event_id;
|
||||
u8 value_low; /* For most events, this is the value */
|
||||
u8 value_high; /* For fan speed events, combined with value_low */
|
||||
u8 reserved[4];
|
||||
} __packed;
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(bitland_notifier_list);
|
||||
|
||||
enum bitland_notifier_actions {
|
||||
BITLAND_NOTIFY_KBD_BRIGHTNESS,
|
||||
BITLAND_NOTIFY_PLATFORM_PROFILE,
|
||||
BITLAND_NOTIFY_HWMON,
|
||||
};
|
||||
|
||||
struct bitland_fan_notify_data {
|
||||
int channel; /* 0 = CPU, 1 = GPU */
|
||||
u16 speed;
|
||||
};
|
||||
|
||||
struct bitland_mifs_wmi_data {
|
||||
struct wmi_device *wdev;
|
||||
struct mutex lock; /* Protects WMI calls */
|
||||
struct led_classdev kbd_led;
|
||||
struct notifier_block notifier;
|
||||
struct input_dev *input_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct device *pp_dev;
|
||||
enum platform_profile_option saved_profile;
|
||||
};
|
||||
|
||||
static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
|
||||
const struct bitland_mifs_input *input,
|
||||
struct bitland_mifs_output *output)
|
||||
{
|
||||
struct wmi_buffer in_buf = { .length = sizeof(*input), .data = (void *)input };
|
||||
struct wmi_buffer out_buf = { 0 };
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&data->lock);
|
||||
|
||||
if (!output)
|
||||
return wmidev_invoke_procedure(data->wdev, 0, 1, &in_buf);
|
||||
|
||||
ret = wmidev_invoke_method(data->wdev, 0, 1, &in_buf, &out_buf, sizeof(*output));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memcpy(output, out_buf.data, sizeof(*output));
|
||||
kfree(out_buf.data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int laptop_profile_get(struct device *dev,
|
||||
enum platform_profile_option *profile)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
|
||||
struct bitland_mifs_input input = {
|
||||
.reserved1 = 0,
|
||||
.operation = WMI_METHOD_GET,
|
||||
.reserved2 = 0,
|
||||
.function = WMI_FN_SYSTEM_PER_MODE,
|
||||
};
|
||||
struct bitland_mifs_output result;
|
||||
int ret;
|
||||
|
||||
ret = bitland_mifs_wmi_call(data, &input, &result);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (result.data[0]) {
|
||||
case WMI_PP_BALANCED:
|
||||
*profile = PLATFORM_PROFILE_BALANCED;
|
||||
break;
|
||||
case WMI_PP_PERFORMANCE:
|
||||
*profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
|
||||
break;
|
||||
case WMI_PP_QUIET:
|
||||
*profile = PLATFORM_PROFILE_LOW_POWER;
|
||||
break;
|
||||
case WMI_PP_FULL_SPEED:
|
||||
*profile = PLATFORM_PROFILE_PERFORMANCE;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bitland_check_performance_capability(struct bitland_mifs_wmi_data *data)
|
||||
{
|
||||
struct bitland_mifs_input input = {
|
||||
.operation = WMI_METHOD_GET,
|
||||
.function = WMI_FN_SYSTEM_AC_TYPE,
|
||||
};
|
||||
struct bitland_mifs_output output;
|
||||
int ret;
|
||||
|
||||
/* Full-speed/performance mode requires DC power (not USB-C) */
|
||||
if (!power_supply_is_system_supplied())
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = bitland_mifs_wmi_call(data, &input, &output);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (output.data[0] != WMI_SYSTEM_AC_CIRCULARHOLE)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int laptop_profile_set(struct device *dev,
|
||||
enum platform_profile_option profile)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
|
||||
struct bitland_mifs_input input = {
|
||||
.reserved1 = 0,
|
||||
.operation = WMI_METHOD_SET,
|
||||
.reserved2 = 0,
|
||||
.function = WMI_FN_SYSTEM_PER_MODE,
|
||||
};
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
switch (profile) {
|
||||
case PLATFORM_PROFILE_LOW_POWER:
|
||||
val = WMI_PP_QUIET;
|
||||
break;
|
||||
case PLATFORM_PROFILE_BALANCED:
|
||||
val = WMI_PP_BALANCED;
|
||||
break;
|
||||
case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
|
||||
ret = bitland_check_performance_capability(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
val = WMI_PP_PERFORMANCE;
|
||||
break;
|
||||
case PLATFORM_PROFILE_PERFORMANCE:
|
||||
ret = bitland_check_performance_capability(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
val = WMI_PP_FULL_SPEED;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
input.payload[0] = val;
|
||||
|
||||
return bitland_mifs_wmi_call(data, &input, NULL);
|
||||
}
|
||||
|
||||
static int platform_profile_probe(void *drvdata, unsigned long *choices)
|
||||
{
|
||||
set_bit(PLATFORM_PROFILE_LOW_POWER, choices);
|
||||
set_bit(PLATFORM_PROFILE_BALANCED, choices);
|
||||
set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices);
|
||||
set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bitland_mifs_wmi_suspend(struct device *dev)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
|
||||
enum platform_profile_option profile;
|
||||
int ret;
|
||||
|
||||
ret = laptop_profile_get(data->pp_dev, &profile);
|
||||
if (ret == 0)
|
||||
data->saved_profile = profile;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bitland_mifs_wmi_resume(struct device *dev)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(dev, "Resuming, restoring profile %d\n", data->saved_profile);
|
||||
return laptop_profile_set(dev, data->saved_profile);
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(bitland_mifs_wmi_pm_ops,
|
||||
bitland_mifs_wmi_suspend,
|
||||
bitland_mifs_wmi_resume);
|
||||
|
||||
static const struct platform_profile_ops laptop_profile_ops = {
|
||||
.probe = platform_profile_probe,
|
||||
.profile_get = laptop_profile_get,
|
||||
.profile_set = laptop_profile_set,
|
||||
};
|
||||
|
||||
static const char *const fan_labels[] = {
|
||||
"CPU", /* 0 */
|
||||
"GPU", /* 1 */
|
||||
"SYS", /* 2 */
|
||||
};
|
||||
|
||||
static int laptop_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
|
||||
struct bitland_mifs_input input = {
|
||||
.reserved1 = 0,
|
||||
.operation = WMI_METHOD_GET,
|
||||
.reserved2 = 0,
|
||||
};
|
||||
struct bitland_mifs_output res;
|
||||
int ret;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
input.function = WMI_FN_CPU_THERMOMETER;
|
||||
ret = bitland_mifs_wmi_call(data, &input, &res);
|
||||
if (!ret)
|
||||
*val = res.data[0] * MILLIDEGREE_PER_DEGREE;
|
||||
return ret;
|
||||
case hwmon_fan:
|
||||
input.function = WMI_FN_FAN_SPEEDS;
|
||||
ret = bitland_mifs_wmi_call(data, &input, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (channel) {
|
||||
case 0: /* CPU */
|
||||
*val = get_unaligned_le16(&res.data[0]);
|
||||
return 0;
|
||||
case 1: /* GPU */
|
||||
*val = get_unaligned_le16(&res.data[2]);
|
||||
return 0;
|
||||
case 2: /* SYS */
|
||||
*val = get_unaligned_le16(&res.data[6]);
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int laptop_hwmon_read_string(struct device *dev,
|
||||
enum hwmon_sensor_types type, u32 attr,
|
||||
int channel, const char **str)
|
||||
{
|
||||
if (type == hwmon_fan && attr == hwmon_fan_label) {
|
||||
if (channel >= 0 && channel < ARRAY_SIZE(fan_labels)) {
|
||||
*str = fan_labels[channel];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *laptop_hwmon_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
|
||||
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL,
|
||||
HWMON_F_INPUT | HWMON_F_LABEL,
|
||||
HWMON_F_INPUT | HWMON_F_LABEL),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_ops laptop_hwmon_ops = {
|
||||
.visible = 0444,
|
||||
.read = laptop_hwmon_read,
|
||||
.read_string = laptop_hwmon_read_string,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info laptop_chip_info = {
|
||||
.ops = &laptop_hwmon_ops,
|
||||
.info = laptop_hwmon_info,
|
||||
};
|
||||
|
||||
static int laptop_kbd_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data =
|
||||
container_of(led_cdev, struct bitland_mifs_wmi_data, kbd_led);
|
||||
struct bitland_mifs_input input = {
|
||||
.reserved1 = 0,
|
||||
.operation = WMI_METHOD_SET,
|
||||
.reserved2 = 0,
|
||||
.function = WMI_FN_RGB_KB_BRIGHTNESS,
|
||||
};
|
||||
|
||||
input.payload[0] = (u8)value;
|
||||
|
||||
return bitland_mifs_wmi_call(data, &input, NULL);
|
||||
}
|
||||
|
||||
static enum led_brightness laptop_kbd_led_get(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data =
|
||||
container_of(led_cdev, struct bitland_mifs_wmi_data, kbd_led);
|
||||
struct bitland_mifs_input input = {
|
||||
.reserved1 = 0,
|
||||
.operation = WMI_METHOD_GET,
|
||||
.reserved2 = 0,
|
||||
.function = WMI_FN_RGB_KB_BRIGHTNESS,
|
||||
};
|
||||
struct bitland_mifs_output res;
|
||||
int ret;
|
||||
|
||||
ret = bitland_mifs_wmi_call(data, &input, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return res.data[0];
|
||||
}
|
||||
|
||||
static const char *const gpu_mode_strings[] = {
|
||||
"hybrid",
|
||||
"discrete",
|
||||
"uma",
|
||||
};
|
||||
|
||||
/* GPU Mode: 0:Hybrid, 1:Discrete, 2:UMA */
|
||||
static ssize_t gpu_mode_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
|
||||
struct bitland_mifs_input input = {
|
||||
.reserved1 = 0,
|
||||
.operation = WMI_METHOD_GET,
|
||||
.reserved2 = 0,
|
||||
.function = WMI_FN_GPU_MODE,
|
||||
};
|
||||
struct bitland_mifs_output res;
|
||||
u8 mode_val;
|
||||
int ret;
|
||||
|
||||
ret = bitland_mifs_wmi_call(data, &input, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mode_val = res.data[0];
|
||||
if (mode_val >= ARRAY_SIZE(gpu_mode_strings))
|
||||
return -EPROTO;
|
||||
|
||||
return sysfs_emit(buf, "%s\n", gpu_mode_strings[mode_val]);
|
||||
}
|
||||
|
||||
static ssize_t gpu_mode_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
|
||||
struct bitland_mifs_input input = {
|
||||
.reserved1 = 0,
|
||||
.operation = WMI_METHOD_SET,
|
||||
.reserved2 = 0,
|
||||
.function = WMI_FN_GPU_MODE,
|
||||
};
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
val = sysfs_match_string(gpu_mode_strings, buf);
|
||||
if (val < 0)
|
||||
return -EINVAL;
|
||||
|
||||
input.payload[0] = (u8)val;
|
||||
|
||||
ret = bitland_mifs_wmi_call(data, &input, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const char *const kb_mode_strings[] = {
|
||||
"off", /* 0 */
|
||||
"cyclic", /* 1 */
|
||||
"fixed", /* 2 */
|
||||
"custom", /* 3 */
|
||||
};
|
||||
|
||||
static ssize_t kb_mode_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
|
||||
struct bitland_mifs_input input = {
|
||||
.reserved1 = 0,
|
||||
.operation = WMI_METHOD_GET,
|
||||
.reserved2 = 0,
|
||||
.function = WMI_FN_RGB_KB_MODE,
|
||||
};
|
||||
struct bitland_mifs_output res;
|
||||
u8 mode_val;
|
||||
int ret;
|
||||
|
||||
ret = bitland_mifs_wmi_call(data, &input, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mode_val = res.data[0];
|
||||
if (mode_val >= ARRAY_SIZE(kb_mode_strings))
|
||||
return -EPROTO;
|
||||
|
||||
return sysfs_emit(buf, "%s\n", kb_mode_strings[mode_val]);
|
||||
}
|
||||
|
||||
static ssize_t kb_mode_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
|
||||
struct bitland_mifs_input input = {
|
||||
.reserved1 = 0,
|
||||
.operation = WMI_METHOD_SET,
|
||||
.reserved2 = 0,
|
||||
.function = WMI_FN_RGB_KB_MODE,
|
||||
};
|
||||
// the wmi value (0, 1, 2 or 3)
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
val = sysfs_match_string(kb_mode_strings, buf);
|
||||
if (val < 0)
|
||||
return -EINVAL;
|
||||
|
||||
input.payload[0] = (u8)val;
|
||||
|
||||
ret = bitland_mifs_wmi_call(data, &input, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Fan Boost: 0:Normal, 1:Max Speed */
|
||||
static ssize_t fan_boost_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
|
||||
struct bitland_mifs_input input = {
|
||||
.reserved1 = 0,
|
||||
.operation = WMI_METHOD_SET,
|
||||
.reserved2 = 0,
|
||||
.function = WMI_FN_MAX_FAN_SWITCH,
|
||||
};
|
||||
bool val;
|
||||
int ret;
|
||||
|
||||
if (kstrtobool(buf, &val))
|
||||
return -EINVAL;
|
||||
|
||||
input.payload[0] = 0; /* CPU/GPU Fan */
|
||||
input.payload[1] = val;
|
||||
|
||||
ret = bitland_mifs_wmi_call(data, &input, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const DEVICE_ATTR_RW(gpu_mode);
|
||||
static const DEVICE_ATTR_RW(kb_mode);
|
||||
static const DEVICE_ATTR_WO(fan_boost);
|
||||
|
||||
static const struct attribute *const laptop_attrs[] = {
|
||||
&dev_attr_gpu_mode.attr,
|
||||
&dev_attr_kb_mode.attr,
|
||||
&dev_attr_fan_boost.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(laptop);
|
||||
|
||||
static const struct key_entry bitland_mifs_wmi_keymap[] = {
|
||||
{ KE_KEY, WMI_EVENT_OPEN_APP, { KEY_PROG1 } },
|
||||
{ KE_KEY, WMI_EVENT_CALCULATOR_START, { KEY_CALC } },
|
||||
{ KE_KEY, WMI_EVENT_BROWSER_START, { KEY_WWW } },
|
||||
{ KE_IGNORE, WMI_EVENT_FN_J, { KEY_RESERVED } },
|
||||
{ KE_IGNORE, WMI_EVENT_FN_F, { KEY_RESERVED } },
|
||||
{ KE_IGNORE, WMI_EVENT_FN_0, { KEY_RESERVED } },
|
||||
{ KE_IGNORE, WMI_EVENT_FN_1, { KEY_RESERVED } },
|
||||
{ KE_IGNORE, WMI_EVENT_FN_2, { KEY_RESERVED } },
|
||||
{ KE_IGNORE, WMI_EVENT_FN_3, { KEY_RESERVED } },
|
||||
{ KE_IGNORE, WMI_EVENT_FN_4, { KEY_RESERVED } },
|
||||
{ KE_IGNORE, WMI_EVENT_FN_5, { KEY_RESERVED } },
|
||||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
static void bitland_notifier_unregister(void *data)
|
||||
{
|
||||
struct notifier_block *nb = data;
|
||||
|
||||
blocking_notifier_chain_unregister(&bitland_notifier_list, nb);
|
||||
}
|
||||
|
||||
static int bitland_notifier_callback(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data_ctx =
|
||||
container_of(nb, struct bitland_mifs_wmi_data, notifier);
|
||||
struct bitland_fan_notify_data *fan_info;
|
||||
u8 *brightness;
|
||||
|
||||
switch (action) {
|
||||
case BITLAND_NOTIFY_KBD_BRIGHTNESS:
|
||||
brightness = data;
|
||||
led_classdev_notify_brightness_hw_changed(&data_ctx->kbd_led,
|
||||
*brightness);
|
||||
break;
|
||||
case BITLAND_NOTIFY_PLATFORM_PROFILE:
|
||||
platform_profile_notify(data_ctx->pp_dev);
|
||||
break;
|
||||
case BITLAND_NOTIFY_HWMON:
|
||||
fan_info = data;
|
||||
|
||||
hwmon_notify_event(data_ctx->hwmon_dev, hwmon_fan,
|
||||
hwmon_fan_input, fan_info->channel);
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *drv_data;
|
||||
enum bitland_wmi_device_type dev_type =
|
||||
(enum bitland_wmi_device_type)(unsigned long)context;
|
||||
struct led_init_data init_data = {
|
||||
.devicename = DRV_NAME,
|
||||
.default_label = ":" LED_FUNCTION_KBD_BACKLIGHT,
|
||||
.devname_mandatory = true,
|
||||
};
|
||||
int ret;
|
||||
|
||||
drv_data = devm_kzalloc(&wdev->dev, sizeof(*drv_data), GFP_KERNEL);
|
||||
if (!drv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
drv_data->wdev = wdev;
|
||||
|
||||
ret = devm_mutex_init(&wdev->dev, &drv_data->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_set_drvdata(&wdev->dev, drv_data);
|
||||
|
||||
if (dev_type == BITLAND_WMI_EVENT) {
|
||||
/* Register input device for hotkeys */
|
||||
drv_data->input_dev = devm_input_allocate_device(&wdev->dev);
|
||||
if (!drv_data->input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
drv_data->input_dev->name = "Bitland MIFS WMI hotkeys";
|
||||
drv_data->input_dev->phys = "wmi/input0";
|
||||
drv_data->input_dev->id.bustype = BUS_HOST;
|
||||
drv_data->input_dev->dev.parent = &wdev->dev;
|
||||
|
||||
ret = sparse_keymap_setup(drv_data->input_dev,
|
||||
bitland_mifs_wmi_keymap, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return input_register_device(drv_data->input_dev);
|
||||
}
|
||||
|
||||
/* Register platform profile */
|
||||
drv_data->pp_dev = devm_platform_profile_register(&wdev->dev, DRV_NAME, drv_data,
|
||||
&laptop_profile_ops);
|
||||
if (IS_ERR(drv_data->pp_dev))
|
||||
return PTR_ERR(drv_data->pp_dev);
|
||||
|
||||
/* Register hwmon */
|
||||
drv_data->hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev,
|
||||
"bitland_mifs",
|
||||
drv_data,
|
||||
&laptop_chip_info,
|
||||
NULL);
|
||||
if (IS_ERR(drv_data->hwmon_dev))
|
||||
return PTR_ERR(drv_data->hwmon_dev);
|
||||
|
||||
/* Register keyboard LED */
|
||||
drv_data->kbd_led.max_brightness = 3;
|
||||
drv_data->kbd_led.brightness_set_blocking = laptop_kbd_led_set;
|
||||
drv_data->kbd_led.brightness_get = laptop_kbd_led_get;
|
||||
drv_data->kbd_led.brightness = laptop_kbd_led_get(&drv_data->kbd_led);
|
||||
drv_data->kbd_led.flags = LED_CORE_SUSPENDRESUME |
|
||||
LED_BRIGHT_HW_CHANGED |
|
||||
LED_REJECT_NAME_CONFLICT;
|
||||
ret = devm_led_classdev_register_ext(&wdev->dev, &drv_data->kbd_led, &init_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drv_data->notifier.notifier_call = bitland_notifier_callback;
|
||||
ret = blocking_notifier_chain_register(&bitland_notifier_list, &drv_data->notifier);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_add_action_or_reset(&wdev->dev,
|
||||
bitland_notifier_unregister,
|
||||
&drv_data->notifier);
|
||||
}
|
||||
|
||||
static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
|
||||
const struct wmi_buffer *buffer)
|
||||
{
|
||||
struct bitland_mifs_wmi_data *data = dev_get_drvdata(&wdev->dev);
|
||||
const struct bitland_mifs_event *event = buffer->data;
|
||||
struct bitland_fan_notify_data fan_data;
|
||||
u8 brightness;
|
||||
|
||||
/* Validate event type */
|
||||
if (event->event_type != WMI_EVENT_TYPE_HOTKEY)
|
||||
return;
|
||||
|
||||
dev_dbg(&wdev->dev,
|
||||
"WMI event: id=0x%02x value_low=0x%02x value_high=0x%02x\n",
|
||||
event->event_id, event->value_low, event->value_high);
|
||||
|
||||
switch (event->event_id) {
|
||||
case WMI_EVENT_KBD_BRIGHTNESS:
|
||||
brightness = event->value_low;
|
||||
blocking_notifier_call_chain(&bitland_notifier_list,
|
||||
BITLAND_NOTIFY_KBD_BRIGHTNESS,
|
||||
&brightness);
|
||||
break;
|
||||
|
||||
case WMI_EVENT_PERFORMANCE_PLAN:
|
||||
blocking_notifier_call_chain(&bitland_notifier_list,
|
||||
BITLAND_NOTIFY_PLATFORM_PROFILE,
|
||||
NULL);
|
||||
break;
|
||||
|
||||
case WMI_EVENT_OPEN_APP:
|
||||
case WMI_EVENT_CALCULATOR_START:
|
||||
case WMI_EVENT_BROWSER_START: {
|
||||
guard(mutex)(&data->lock);
|
||||
if (!sparse_keymap_report_event(data->input_dev,
|
||||
event->event_id, 1, true))
|
||||
dev_warn(&wdev->dev, "Unknown key pressed: 0x%02x\n",
|
||||
event->event_id);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* The device has 3 fans (CPU, GPU, SYS),
|
||||
* but there are only the CPU and GPU fan has events
|
||||
*/
|
||||
case WMI_EVENT_CPU_FAN_SPEED:
|
||||
case WMI_EVENT_GPU_FAN_SPEED:
|
||||
if (event->event_id == WMI_EVENT_CPU_FAN_SPEED)
|
||||
fan_data.channel = 0;
|
||||
else
|
||||
fan_data.channel = 1;
|
||||
|
||||
/* Fan speed is 16-bit value (value_low is LSB, value_high is MSB) */
|
||||
fan_data.speed = (event->value_high << 8) | event->value_low;
|
||||
blocking_notifier_call_chain(&bitland_notifier_list,
|
||||
BITLAND_NOTIFY_HWMON,
|
||||
&fan_data);
|
||||
break;
|
||||
|
||||
case WMI_EVENT_AIRPLANE_MODE:
|
||||
case WMI_EVENT_TOUCHPAD_STATE:
|
||||
case WMI_EVENT_FNLOCK_STATE:
|
||||
case WMI_EVENT_KBD_MODE:
|
||||
case WMI_EVENT_CAPSLOCK_STATE:
|
||||
case WMI_EVENT_NUMLOCK_STATE:
|
||||
case WMI_EVENT_SCROLLLOCK_STATE:
|
||||
case WMI_EVENT_REFRESH_RATE:
|
||||
case WMI_EVENT_WIN_KEY_LOCK:
|
||||
/* These events are informational or handled by firmware */
|
||||
dev_dbg(&wdev->dev, "State change event: id=%d value=%d\n",
|
||||
event->event_id, event->value_low);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_dbg(&wdev->dev, "Unknown event: id=0x%02x value=0x%02x\n",
|
||||
event->event_id, event->value_low);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wmi_device_id bitland_mifs_wmi_id_table[] = {
|
||||
{ BITLAND_MIFS_GUID, (void *)BITLAND_WMI_CONTROL },
|
||||
{ BITLAND_EVENT_GUID, (void *)BITLAND_WMI_EVENT },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(wmi, bitland_mifs_wmi_id_table);
|
||||
|
||||
static struct wmi_driver bitland_mifs_wmi_driver = {
|
||||
.no_singleton = true,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.dev_groups = laptop_groups,
|
||||
.pm = pm_sleep_ptr(&bitland_mifs_wmi_pm_ops),
|
||||
},
|
||||
.id_table = bitland_mifs_wmi_id_table,
|
||||
.min_event_size = sizeof(struct bitland_mifs_event),
|
||||
.probe = bitland_mifs_wmi_probe,
|
||||
.notify_new = bitland_mifs_wmi_notify,
|
||||
};
|
||||
|
||||
module_wmi_driver(bitland_mifs_wmi_driver);
|
||||
|
||||
MODULE_AUTHOR("Mingyou Chen <qby140326@gmail.com>");
|
||||
MODULE_DESCRIPTION("Bitland MIFS (MiInterface) WMI driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "dell-rbtn.h"
|
||||
|
||||
|
|
@ -109,9 +110,9 @@ static const struct rfkill_ops rbtn_ops = {
|
|||
.set_block = rbtn_rfkill_set_block,
|
||||
};
|
||||
|
||||
static int rbtn_rfkill_init(struct acpi_device *device)
|
||||
static int rbtn_rfkill_init(struct device *dev)
|
||||
{
|
||||
struct rbtn_data *rbtn_data = device->driver_data;
|
||||
struct rbtn_data *rbtn_data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (rbtn_data->rfkill)
|
||||
|
|
@ -122,8 +123,8 @@ static int rbtn_rfkill_init(struct acpi_device *device)
|
|||
* but rfkill interface does not support "ANY" type
|
||||
* so "WLAN" type is used
|
||||
*/
|
||||
rbtn_data->rfkill = rfkill_alloc("dell-rbtn", &device->dev,
|
||||
RFKILL_TYPE_WLAN, &rbtn_ops, device);
|
||||
rbtn_data->rfkill = rfkill_alloc("dell-rbtn", dev, RFKILL_TYPE_WLAN,
|
||||
&rbtn_ops, ACPI_COMPANION(dev));
|
||||
if (!rbtn_data->rfkill)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -137,9 +138,9 @@ static int rbtn_rfkill_init(struct acpi_device *device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rbtn_rfkill_exit(struct acpi_device *device)
|
||||
static void rbtn_rfkill_exit(struct device *dev)
|
||||
{
|
||||
struct rbtn_data *rbtn_data = device->driver_data;
|
||||
struct rbtn_data *rbtn_data = dev_get_drvdata(dev);
|
||||
|
||||
if (!rbtn_data->rfkill)
|
||||
return;
|
||||
|
|
@ -149,12 +150,12 @@ static void rbtn_rfkill_exit(struct acpi_device *device)
|
|||
rbtn_data->rfkill = NULL;
|
||||
}
|
||||
|
||||
static void rbtn_rfkill_event(struct acpi_device *device)
|
||||
static void rbtn_rfkill_event(struct device *dev)
|
||||
{
|
||||
struct rbtn_data *rbtn_data = device->driver_data;
|
||||
struct rbtn_data *rbtn_data = dev_get_drvdata(dev);
|
||||
|
||||
if (rbtn_data->rfkill)
|
||||
rbtn_rfkill_query(rbtn_data->rfkill, device);
|
||||
rbtn_rfkill_query(rbtn_data->rfkill, ACPI_COMPANION(dev));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -205,9 +206,9 @@ static void rbtn_input_event(struct rbtn_data *rbtn_data)
|
|||
* acpi driver
|
||||
*/
|
||||
|
||||
static int rbtn_add(struct acpi_device *device);
|
||||
static void rbtn_remove(struct acpi_device *device);
|
||||
static void rbtn_notify(struct acpi_device *device, u32 event);
|
||||
static int rbtn_probe(struct platform_device *pdev);
|
||||
static void rbtn_remove(struct platform_device *pdev);
|
||||
static void rbtn_notify(acpi_handle handle, u32 event, void *data);
|
||||
|
||||
static const struct acpi_device_id rbtn_ids[] = {
|
||||
{ "DELRBTN", 0 },
|
||||
|
|
@ -251,8 +252,7 @@ static void ACPI_SYSTEM_XFACE rbtn_clear_suspended_flag(void *context)
|
|||
|
||||
static int rbtn_suspend(struct device *dev)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(dev);
|
||||
struct rbtn_data *rbtn_data = acpi_driver_data(device);
|
||||
struct rbtn_data *rbtn_data = dev_get_drvdata(dev);
|
||||
|
||||
rbtn_data->suspended = true;
|
||||
|
||||
|
|
@ -261,8 +261,7 @@ static int rbtn_suspend(struct device *dev)
|
|||
|
||||
static int rbtn_resume(struct device *dev)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(dev);
|
||||
struct rbtn_data *rbtn_data = acpi_driver_data(device);
|
||||
struct rbtn_data *rbtn_data = dev_get_drvdata(dev);
|
||||
acpi_status status;
|
||||
|
||||
/*
|
||||
|
|
@ -286,14 +285,13 @@ static int rbtn_resume(struct device *dev)
|
|||
|
||||
static SIMPLE_DEV_PM_OPS(rbtn_pm_ops, rbtn_suspend, rbtn_resume);
|
||||
|
||||
static struct acpi_driver rbtn_driver = {
|
||||
.name = "dell-rbtn",
|
||||
.ids = rbtn_ids,
|
||||
.drv.pm = &rbtn_pm_ops,
|
||||
.ops = {
|
||||
.add = rbtn_add,
|
||||
.remove = rbtn_remove,
|
||||
.notify = rbtn_notify,
|
||||
static struct platform_driver rbtn_driver = {
|
||||
.probe = rbtn_probe,
|
||||
.remove = rbtn_remove,
|
||||
.driver = {
|
||||
.name = "dell-rbtn",
|
||||
.acpi_match_table = rbtn_ids,
|
||||
.pm = &rbtn_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -308,8 +306,7 @@ static ATOMIC_NOTIFIER_HEAD(rbtn_chain_head);
|
|||
|
||||
static int rbtn_inc_count(struct device *dev, void *data)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(dev);
|
||||
struct rbtn_data *rbtn_data = device->driver_data;
|
||||
struct rbtn_data *rbtn_data = dev_get_drvdata(dev);
|
||||
int *count = data;
|
||||
|
||||
if (rbtn_data->type == RBTN_SLIDER)
|
||||
|
|
@ -320,17 +317,16 @@ static int rbtn_inc_count(struct device *dev, void *data)
|
|||
|
||||
static int rbtn_switch_dev(struct device *dev, void *data)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(dev);
|
||||
struct rbtn_data *rbtn_data = device->driver_data;
|
||||
struct rbtn_data *rbtn_data = dev_get_drvdata(dev);
|
||||
bool enable = data;
|
||||
|
||||
if (rbtn_data->type != RBTN_SLIDER)
|
||||
return 0;
|
||||
|
||||
if (enable)
|
||||
rbtn_rfkill_init(device);
|
||||
rbtn_rfkill_init(dev);
|
||||
else
|
||||
rbtn_rfkill_exit(device);
|
||||
rbtn_rfkill_exit(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -342,7 +338,7 @@ int dell_rbtn_notifier_register(struct notifier_block *nb)
|
|||
int ret;
|
||||
|
||||
count = 0;
|
||||
ret = driver_for_each_device(&rbtn_driver.drv, NULL, &count,
|
||||
ret = driver_for_each_device(&rbtn_driver.driver, NULL, &count,
|
||||
rbtn_inc_count);
|
||||
if (ret || count == 0)
|
||||
return -ENODEV;
|
||||
|
|
@ -354,7 +350,7 @@ int dell_rbtn_notifier_register(struct notifier_block *nb)
|
|||
return ret;
|
||||
|
||||
if (auto_remove_rfkill && first)
|
||||
ret = driver_for_each_device(&rbtn_driver.drv, NULL,
|
||||
ret = driver_for_each_device(&rbtn_driver.driver, NULL,
|
||||
(void *)false, rbtn_switch_dev);
|
||||
|
||||
return ret;
|
||||
|
|
@ -370,7 +366,7 @@ int dell_rbtn_notifier_unregister(struct notifier_block *nb)
|
|||
return ret;
|
||||
|
||||
if (auto_remove_rfkill && !rbtn_chain_head.head)
|
||||
ret = driver_for_each_device(&rbtn_driver.drv, NULL,
|
||||
ret = driver_for_each_device(&rbtn_driver.driver, NULL,
|
||||
(void *)true, rbtn_switch_dev);
|
||||
|
||||
return ret;
|
||||
|
|
@ -382,30 +378,48 @@ EXPORT_SYMBOL_GPL(dell_rbtn_notifier_unregister);
|
|||
* acpi driver functions
|
||||
*/
|
||||
|
||||
static int rbtn_add(struct acpi_device *device)
|
||||
static void rbtn_cleanup(struct device *dev)
|
||||
{
|
||||
struct rbtn_data *rbtn_data = dev_get_drvdata(dev);
|
||||
|
||||
switch (rbtn_data->type) {
|
||||
case RBTN_TOGGLE:
|
||||
rbtn_input_exit(rbtn_data);
|
||||
break;
|
||||
case RBTN_SLIDER:
|
||||
rbtn_rfkill_exit(dev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int rbtn_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct rbtn_data *rbtn_data;
|
||||
enum rbtn_type type;
|
||||
int ret = 0;
|
||||
|
||||
type = rbtn_check(device);
|
||||
if (type == RBTN_UNKNOWN) {
|
||||
dev_info(&device->dev, "Unknown device type\n");
|
||||
dev_info(&pdev->dev, "Unknown device type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rbtn_data = devm_kzalloc(&device->dev, sizeof(*rbtn_data), GFP_KERNEL);
|
||||
rbtn_data = devm_kzalloc(&pdev->dev, sizeof(*rbtn_data), GFP_KERNEL);
|
||||
if (!rbtn_data)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = rbtn_acquire(device, true);
|
||||
if (ret < 0) {
|
||||
dev_err(&device->dev, "Cannot enable device\n");
|
||||
dev_err(&pdev->dev, "Cannot enable device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, rbtn_data);
|
||||
|
||||
rbtn_data->type = type;
|
||||
device->driver_data = rbtn_data;
|
||||
|
||||
switch (rbtn_data->type) {
|
||||
case RBTN_TOGGLE:
|
||||
|
|
@ -415,51 +429,54 @@ static int rbtn_add(struct acpi_device *device)
|
|||
if (auto_remove_rfkill && rbtn_chain_head.head)
|
||||
ret = 0;
|
||||
else
|
||||
ret = rbtn_rfkill_init(device);
|
||||
ret = rbtn_rfkill_init(&pdev->dev);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
rbtn_acquire(device, false);
|
||||
goto err;
|
||||
|
||||
ret = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
rbtn_notify, &pdev->dev);
|
||||
if (ret)
|
||||
goto err_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
err_cleanup:
|
||||
rbtn_cleanup(&pdev->dev);
|
||||
err:
|
||||
rbtn_acquire(device, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rbtn_remove(struct acpi_device *device)
|
||||
static void rbtn_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rbtn_data *rbtn_data = device->driver_data;
|
||||
|
||||
switch (rbtn_data->type) {
|
||||
case RBTN_TOGGLE:
|
||||
rbtn_input_exit(rbtn_data);
|
||||
break;
|
||||
case RBTN_SLIDER:
|
||||
rbtn_rfkill_exit(device);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
|
||||
acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, rbtn_notify);
|
||||
rbtn_cleanup(&pdev->dev);
|
||||
rbtn_acquire(device, false);
|
||||
}
|
||||
|
||||
static void rbtn_notify(struct acpi_device *device, u32 event)
|
||||
static void rbtn_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct rbtn_data *rbtn_data = device->driver_data;
|
||||
struct device *dev = data;
|
||||
struct rbtn_data *rbtn_data = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* Some BIOSes send a notification at resume.
|
||||
* Ignore it to prevent unwanted input events.
|
||||
*/
|
||||
if (rbtn_data->suspended) {
|
||||
dev_dbg(&device->dev, "ACPI notification ignored\n");
|
||||
dev_dbg(dev, "ACPI notification ignored\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (event != 0x80) {
|
||||
dev_info(&device->dev, "Received unknown event (0x%x)\n",
|
||||
dev_info(dev, "Received unknown event (0x%x)\n",
|
||||
event);
|
||||
return;
|
||||
}
|
||||
|
|
@ -469,20 +486,15 @@ static void rbtn_notify(struct acpi_device *device, u32 event)
|
|||
rbtn_input_event(rbtn_data);
|
||||
break;
|
||||
case RBTN_SLIDER:
|
||||
rbtn_rfkill_event(device);
|
||||
atomic_notifier_call_chain(&rbtn_chain_head, event, device);
|
||||
rbtn_rfkill_event(dev);
|
||||
atomic_notifier_call_chain(&rbtn_chain_head, event, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* module functions
|
||||
*/
|
||||
|
||||
module_acpi_driver(rbtn_driver);
|
||||
module_platform_driver(rbtn_driver);
|
||||
|
||||
module_param(auto_remove_rfkill, bool, 0444);
|
||||
|
||||
|
|
|
|||
|
|
@ -825,6 +825,7 @@ static struct wmi_driver dell_wmi_driver = {
|
|||
.name = "dell-wmi",
|
||||
},
|
||||
.id_table = dell_wmi_id_table,
|
||||
.min_event_size = sizeof(u16),
|
||||
.probe = dell_wmi_probe,
|
||||
.remove = dell_wmi_remove,
|
||||
.notify = dell_wmi_notify,
|
||||
|
|
|
|||
|
|
@ -189,8 +189,8 @@ void exit_bios_attr_set_interface(void);
|
|||
int init_bios_attr_set_interface(void);
|
||||
int map_wmi_error(int error_code);
|
||||
size_t calculate_string_buffer(const char *str);
|
||||
size_t calculate_security_buffer(char *authentication);
|
||||
void populate_security_buffer(char *buffer, char *authentication);
|
||||
size_t calculate_security_buffer(const char *authentication);
|
||||
void populate_security_buffer(char *buffer, const char *authentication);
|
||||
ssize_t populate_string_buffer(char *buffer, size_t buffer_len, const char *str);
|
||||
int set_new_password(const char *password_type, const char *new);
|
||||
int init_bios_attr_pass_interface(void);
|
||||
|
|
|
|||
|
|
@ -6,10 +6,32 @@
|
|||
* Copyright (c) 2020 Dell Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
|
||||
#include "dell-wmi-sysman.h"
|
||||
|
||||
get_instance_id(enumeration);
|
||||
|
||||
static int append_enum_string(char *dest, const char *src)
|
||||
{
|
||||
size_t dest_len = strlen(dest);
|
||||
ssize_t copied;
|
||||
|
||||
if (WARN_ON_ONCE(dest_len >= MAX_BUFF))
|
||||
return -EINVAL;
|
||||
|
||||
copied = strscpy(dest + dest_len, src, MAX_BUFF - dest_len);
|
||||
if (copied < 0)
|
||||
return -EINVAL;
|
||||
|
||||
dest_len += copied;
|
||||
copied = strscpy(dest + dest_len, ";", MAX_BUFF - dest_len);
|
||||
if (copied < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int instance_id = get_enumeration_instance_id(kobj);
|
||||
|
|
@ -176,9 +198,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
|
|||
return -EINVAL;
|
||||
if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING))
|
||||
return -EINVAL;
|
||||
strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier,
|
||||
enumeration_obj[next_obj++].string.pointer);
|
||||
strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";");
|
||||
if (append_enum_string(wmi_priv.enumeration_data[instance_id].dell_value_modifier,
|
||||
enumeration_obj[next_obj++].string.pointer))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (next_obj >= enum_property_count)
|
||||
|
|
@ -193,9 +215,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
|
|||
return -EINVAL;
|
||||
if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING))
|
||||
return -EINVAL;
|
||||
strcat(wmi_priv.enumeration_data[instance_id].possible_values,
|
||||
enumeration_obj[next_obj++].string.pointer);
|
||||
strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";");
|
||||
if (append_enum_string(wmi_priv.enumeration_data[instance_id].possible_values,
|
||||
enumeration_obj[next_obj++].string.pointer))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
|
||||
|
|
|
|||
|
|
@ -7,10 +7,13 @@
|
|||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/align.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/wmi.h>
|
||||
#include "dell-wmi-sysman.h"
|
||||
#include "../../firmware_attributes_class.h"
|
||||
|
|
@ -72,13 +75,9 @@ size_t calculate_string_buffer(const char *str)
|
|||
*
|
||||
* Currently only supported type is Admin password
|
||||
*/
|
||||
size_t calculate_security_buffer(char *authentication)
|
||||
size_t calculate_security_buffer(const char *authentication)
|
||||
{
|
||||
if (strlen(authentication) > 0) {
|
||||
return (sizeof(u32) * 2) + strlen(authentication) +
|
||||
strlen(authentication) % 2;
|
||||
}
|
||||
return sizeof(u32) * 2;
|
||||
return sizeof(u32) * 2 + ALIGN(strlen(authentication), 2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -88,18 +87,18 @@ size_t calculate_security_buffer(char *authentication)
|
|||
*
|
||||
* Currently only supported type is PLAIN TEXT
|
||||
*/
|
||||
void populate_security_buffer(char *buffer, char *authentication)
|
||||
void populate_security_buffer(char *buffer, const char *authentication)
|
||||
{
|
||||
size_t seclen = strlen(authentication);
|
||||
char *auth = buffer + sizeof(u32) * 2;
|
||||
u32 *sectype = (u32 *) buffer;
|
||||
u32 *seclen = sectype + 1;
|
||||
u32 *seclenp = sectype + 1;
|
||||
|
||||
*sectype = strlen(authentication) > 0 ? 1 : 0;
|
||||
*seclen = strlen(authentication);
|
||||
*sectype = !!seclen;
|
||||
*seclenp = seclen;
|
||||
|
||||
/* plain text */
|
||||
if (strlen(authentication) > 0)
|
||||
memcpy(auth, authentication, *seclen);
|
||||
memcpy(auth, authentication, seclen);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -143,17 +142,17 @@ int map_wmi_error(int error_code)
|
|||
*/
|
||||
static ssize_t reset_bios_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
char *start = buf;
|
||||
ssize_t len = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_TYPES; i++) {
|
||||
if (i == reset_option)
|
||||
buf += sprintf(buf, "[%s] ", reset_types[i]);
|
||||
len += sysfs_emit_at(buf, len, "[%s] ", reset_types[i]);
|
||||
else
|
||||
buf += sprintf(buf, "%s ", reset_types[i]);
|
||||
len += sysfs_emit_at(buf, len, "%s ", reset_types[i]);
|
||||
}
|
||||
buf += sprintf(buf, "\n");
|
||||
return buf-start;
|
||||
len += sysfs_emit_at(buf, len, "\n");
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -194,7 +193,7 @@ static ssize_t reset_bios_store(struct kobject *kobj,
|
|||
static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", wmi_priv.pending_changes);
|
||||
return sysfs_emit(buf, "%d\n", wmi_priv.pending_changes);
|
||||
}
|
||||
|
||||
static struct kobj_attribute reset_bios = __ATTR_RW(reset_bios);
|
||||
|
|
@ -220,35 +219,6 @@ static int create_attributes_level_sysfs_files(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t wmi_sysman_attr_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct kobj_attribute *kattr;
|
||||
ssize_t ret = -EIO;
|
||||
|
||||
kattr = container_of(attr, struct kobj_attribute, attr);
|
||||
if (kattr->show)
|
||||
ret = kattr->show(kobj, kattr, buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t wmi_sysman_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct kobj_attribute *kattr;
|
||||
ssize_t ret = -EIO;
|
||||
|
||||
kattr = container_of(attr, struct kobj_attribute, attr);
|
||||
if (kattr->store)
|
||||
ret = kattr->store(kobj, kattr, buf, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct sysfs_ops wmi_sysman_kobj_sysfs_ops = {
|
||||
.show = wmi_sysman_attr_show,
|
||||
.store = wmi_sysman_attr_store,
|
||||
};
|
||||
|
||||
static void attr_name_release(struct kobject *kobj)
|
||||
{
|
||||
kfree(kobj);
|
||||
|
|
@ -256,7 +226,7 @@ static void attr_name_release(struct kobject *kobj)
|
|||
|
||||
static const struct kobj_type attr_name_ktype = {
|
||||
.release = attr_name_release,
|
||||
.sysfs_ops = &wmi_sysman_kobj_sysfs_ops,
|
||||
.sysfs_ops = &kobj_sysfs_ops,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -343,7 +313,7 @@ static int alloc_attributes_data(int attr_type)
|
|||
* destroy_attribute_objs() - Free a kset of kobjects
|
||||
* @kset: The kset to destroy
|
||||
*
|
||||
* Fress kobjects created for each attribute_name under attribute type kset
|
||||
* Frees kobjects created for each attribute_name under attribute type kset.
|
||||
*/
|
||||
static void destroy_attribute_objs(struct kset *kset)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
|
@ -619,9 +620,12 @@ static ssize_t packet_size_write(struct file *filp, struct kobject *kobj,
|
|||
char *buffer, loff_t pos, size_t count)
|
||||
{
|
||||
unsigned long temp;
|
||||
|
||||
if (kstrtoul(buffer, 10, &temp))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&rbu_data.lock);
|
||||
packet_empty_list();
|
||||
sscanf(buffer, "%lu", &temp);
|
||||
if (temp < 0xffffffff)
|
||||
rbu_data.packetsize = temp;
|
||||
|
||||
|
|
|
|||
|
|
@ -1204,9 +1204,10 @@ static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
|
|||
pr_info("Unknown key %x pressed\n", event);
|
||||
}
|
||||
|
||||
static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
|
||||
static void eeepc_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct eeepc_laptop *eeepc = acpi_driver_data(device);
|
||||
struct eeepc_laptop *eeepc = data;
|
||||
struct acpi_device *device = eeepc->device;
|
||||
int old_brightness, new_brightness;
|
||||
u16 count;
|
||||
|
||||
|
|
@ -1360,8 +1361,9 @@ static void eeepc_enable_camera(struct eeepc_laptop *eeepc)
|
|||
|
||||
static bool eeepc_device_present;
|
||||
|
||||
static int eeepc_acpi_add(struct acpi_device *device)
|
||||
static int eeepc_acpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct eeepc_laptop *eeepc;
|
||||
int result;
|
||||
|
||||
|
|
@ -1372,9 +1374,10 @@ static int eeepc_acpi_add(struct acpi_device *device)
|
|||
eeepc->handle = device->handle;
|
||||
strscpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME);
|
||||
strscpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
|
||||
device->driver_data = eeepc;
|
||||
eeepc->device = device;
|
||||
|
||||
platform_set_drvdata(pdev, eeepc);
|
||||
|
||||
eeepc->hotplug_disabled = hotplug_disabled;
|
||||
|
||||
eeepc_dmi_check(eeepc);
|
||||
|
|
@ -1422,9 +1425,16 @@ static int eeepc_acpi_add(struct acpi_device *device)
|
|||
if (result)
|
||||
goto fail_rfkill;
|
||||
|
||||
result = acpi_dev_install_notify_handler(device, ACPI_ALL_NOTIFY,
|
||||
eeepc_acpi_notify, eeepc);
|
||||
if (result)
|
||||
goto fail_acpi_notifier;
|
||||
|
||||
eeepc_device_present = true;
|
||||
return 0;
|
||||
|
||||
fail_acpi_notifier:
|
||||
eeepc_rfkill_exit(eeepc);
|
||||
fail_rfkill:
|
||||
eeepc_led_exit(eeepc);
|
||||
fail_led:
|
||||
|
|
@ -1440,10 +1450,12 @@ fail_platform:
|
|||
return result;
|
||||
}
|
||||
|
||||
static void eeepc_acpi_remove(struct acpi_device *device)
|
||||
static void eeepc_acpi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct eeepc_laptop *eeepc = acpi_driver_data(device);
|
||||
struct eeepc_laptop *eeepc = platform_get_drvdata(pdev);
|
||||
|
||||
acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
|
||||
ACPI_ALL_NOTIFY, eeepc_acpi_notify);
|
||||
eeepc_backlight_exit(eeepc);
|
||||
eeepc_rfkill_exit(eeepc);
|
||||
eeepc_input_exit(eeepc);
|
||||
|
|
@ -1460,15 +1472,12 @@ static const struct acpi_device_id eeepc_device_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
|
||||
|
||||
static struct acpi_driver eeepc_acpi_driver = {
|
||||
.name = EEEPC_LAPTOP_NAME,
|
||||
.class = EEEPC_ACPI_CLASS,
|
||||
.ids = eeepc_device_ids,
|
||||
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
|
||||
.ops = {
|
||||
.add = eeepc_acpi_add,
|
||||
.remove = eeepc_acpi_remove,
|
||||
.notify = eeepc_acpi_notify,
|
||||
static struct platform_driver eeepc_acpi_driver = {
|
||||
.probe = eeepc_acpi_probe,
|
||||
.remove = eeepc_acpi_remove,
|
||||
.driver = {
|
||||
.name = EEEPC_LAPTOP_NAME,
|
||||
.acpi_match_table = eeepc_device_ids,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -1481,7 +1490,7 @@ static int __init eeepc_laptop_init(void)
|
|||
if (result < 0)
|
||||
return result;
|
||||
|
||||
result = acpi_bus_register_driver(&eeepc_acpi_driver);
|
||||
result = platform_driver_register(&eeepc_acpi_driver);
|
||||
if (result < 0)
|
||||
goto fail_acpi_driver;
|
||||
|
||||
|
|
@ -1493,7 +1502,7 @@ static int __init eeepc_laptop_init(void)
|
|||
return 0;
|
||||
|
||||
fail_no_device:
|
||||
acpi_bus_unregister_driver(&eeepc_acpi_driver);
|
||||
platform_driver_unregister(&eeepc_acpi_driver);
|
||||
fail_acpi_driver:
|
||||
platform_driver_unregister(&platform_driver);
|
||||
return result;
|
||||
|
|
@ -1501,7 +1510,7 @@ fail_acpi_driver:
|
|||
|
||||
static void __exit eeepc_laptop_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&eeepc_acpi_driver);
|
||||
platform_driver_unregister(&eeepc_acpi_driver);
|
||||
platform_driver_unregister(&platform_driver);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -144,11 +144,11 @@ struct fujitsu_laptop {
|
|||
bool charge_control_supported;
|
||||
};
|
||||
|
||||
static struct acpi_device *fext;
|
||||
static struct device *fext;
|
||||
|
||||
/* Fujitsu ACPI interface function */
|
||||
|
||||
static int call_fext_func(struct acpi_device *device,
|
||||
static int call_fext_func(struct device *dev,
|
||||
int func, int op, int feature, int state)
|
||||
{
|
||||
union acpi_object params[4] = {
|
||||
|
|
@ -158,18 +158,17 @@ static int call_fext_func(struct acpi_device *device,
|
|||
{ .integer.type = ACPI_TYPE_INTEGER, .integer.value = state }
|
||||
};
|
||||
struct acpi_object_list arg_list = { 4, params };
|
||||
acpi_handle handle = ACPI_HANDLE(dev);
|
||||
unsigned long long value;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_evaluate_integer(device->handle, "FUNC", &arg_list,
|
||||
&value);
|
||||
status = acpi_evaluate_integer(handle, "FUNC", &arg_list, &value);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_handle_err(device->handle, "Failed to evaluate FUNC\n");
|
||||
acpi_handle_err(handle, "Failed to evaluate FUNC\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
acpi_handle_debug(device->handle,
|
||||
"FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
|
||||
acpi_handle_debug(handle, "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
|
||||
func, op, feature, state, (int)value);
|
||||
return value;
|
||||
}
|
||||
|
|
@ -251,9 +250,9 @@ static struct acpi_battery_hook battery_hook = {
|
|||
* These functions are intended to be called from acpi_fujitsu_laptop_add and
|
||||
* acpi_fujitsu_laptop_remove.
|
||||
*/
|
||||
static int fujitsu_battery_charge_control_add(struct acpi_device *device)
|
||||
static int fujitsu_battery_charge_control_add(struct device *dev)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
struct fujitsu_laptop *priv = dev_get_drvdata(dev);
|
||||
int s006_cc_return;
|
||||
|
||||
priv->charge_control_supported = false;
|
||||
|
|
@ -274,9 +273,9 @@ static int fujitsu_battery_charge_control_add(struct acpi_device *device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void fujitsu_battery_charge_control_remove(struct acpi_device *device)
|
||||
static void fujitsu_battery_charge_control_remove(struct device *dev)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
struct fujitsu_laptop *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (priv->charge_control_supported)
|
||||
battery_hook_unregister(&battery_hook);
|
||||
|
|
@ -284,15 +283,16 @@ static void fujitsu_battery_charge_control_remove(struct acpi_device *device)
|
|||
|
||||
/* Hardware access for LCD brightness control */
|
||||
|
||||
static int set_lcd_level(struct acpi_device *device, int level)
|
||||
static int set_lcd_level(struct device *dev, int level)
|
||||
{
|
||||
struct fujitsu_bl *priv = acpi_driver_data(device);
|
||||
struct fujitsu_bl *priv = dev_get_drvdata(dev);
|
||||
acpi_handle handle = ACPI_HANDLE(dev);
|
||||
acpi_status status;
|
||||
char *method;
|
||||
|
||||
switch (use_alt_lcd_levels) {
|
||||
case -1:
|
||||
if (acpi_has_method(device->handle, "SBL2"))
|
||||
if (acpi_has_method(handle, "SBL2"))
|
||||
method = "SBL2";
|
||||
else
|
||||
method = "SBLL";
|
||||
|
|
@ -305,16 +305,14 @@ static int set_lcd_level(struct acpi_device *device, int level)
|
|||
break;
|
||||
}
|
||||
|
||||
acpi_handle_debug(device->handle, "set lcd level via %s [%d]\n", method,
|
||||
level);
|
||||
acpi_handle_debug(handle, "set lcd level via %s [%d]\n", method, level);
|
||||
|
||||
if (level < 0 || level >= priv->max_brightness)
|
||||
return -EINVAL;
|
||||
|
||||
status = acpi_execute_simple_method(device->handle, method, level);
|
||||
status = acpi_execute_simple_method(handle, method, level);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_handle_err(device->handle, "Failed to evaluate %s\n",
|
||||
method);
|
||||
acpi_handle_err(handle, "Failed to evaluate %s\n", method);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -323,15 +321,16 @@ static int set_lcd_level(struct acpi_device *device, int level)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int get_lcd_level(struct acpi_device *device)
|
||||
static int get_lcd_level(struct device *dev)
|
||||
{
|
||||
struct fujitsu_bl *priv = acpi_driver_data(device);
|
||||
struct fujitsu_bl *priv = dev_get_drvdata(dev);
|
||||
acpi_handle handle = ACPI_HANDLE(dev);
|
||||
unsigned long long state = 0;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
acpi_handle_debug(device->handle, "get lcd level via GBLL\n");
|
||||
acpi_handle_debug(handle, "get lcd level via GBLL\n");
|
||||
|
||||
status = acpi_evaluate_integer(device->handle, "GBLL", NULL, &state);
|
||||
status = acpi_evaluate_integer(handle, "GBLL", NULL, &state);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
|
||||
|
|
@ -340,15 +339,16 @@ static int get_lcd_level(struct acpi_device *device)
|
|||
return priv->brightness_level;
|
||||
}
|
||||
|
||||
static int get_max_brightness(struct acpi_device *device)
|
||||
static int get_max_brightness(struct device *dev)
|
||||
{
|
||||
struct fujitsu_bl *priv = acpi_driver_data(device);
|
||||
struct fujitsu_bl *priv = dev_get_drvdata(dev);
|
||||
acpi_handle handle = ACPI_HANDLE(dev);
|
||||
unsigned long long state = 0;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
acpi_handle_debug(device->handle, "get max lcd level via RBLL\n");
|
||||
acpi_handle_debug(handle, "get max lcd level via RBLL\n");
|
||||
|
||||
status = acpi_evaluate_integer(device->handle, "RBLL", NULL, &state);
|
||||
status = acpi_evaluate_integer(handle, "RBLL", NULL, &state);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -1;
|
||||
|
||||
|
|
@ -361,15 +361,13 @@ static int get_max_brightness(struct acpi_device *device)
|
|||
|
||||
static int bl_get_brightness(struct backlight_device *b)
|
||||
{
|
||||
struct acpi_device *device = bl_get_data(b);
|
||||
struct device *dev = bl_get_data(b);
|
||||
|
||||
return b->props.power == BACKLIGHT_POWER_OFF ? 0 : get_lcd_level(device);
|
||||
return b->props.power == BACKLIGHT_POWER_OFF ? 0 : get_lcd_level(dev);
|
||||
}
|
||||
|
||||
static int bl_update_status(struct backlight_device *b)
|
||||
{
|
||||
struct acpi_device *device = bl_get_data(b);
|
||||
|
||||
if (fext) {
|
||||
if (b->props.power == BACKLIGHT_POWER_OFF)
|
||||
call_fext_func(fext, FUNC_BACKLIGHT, 0x1,
|
||||
|
|
@ -379,7 +377,7 @@ static int bl_update_status(struct backlight_device *b)
|
|||
BACKLIGHT_PARAM_POWER, BACKLIGHT_ON);
|
||||
}
|
||||
|
||||
return set_lcd_level(device, b->props.brightness);
|
||||
return set_lcd_level(bl_get_data(b), b->props.brightness);
|
||||
}
|
||||
|
||||
static const struct backlight_ops fujitsu_bl_ops = {
|
||||
|
|
@ -455,12 +453,13 @@ static const struct key_entry keymap_backlight[] = {
|
|||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
static int acpi_fujitsu_bl_input_setup(struct acpi_device *device)
|
||||
static int acpi_fujitsu_bl_input_setup(struct device *dev)
|
||||
{
|
||||
struct fujitsu_bl *priv = acpi_driver_data(device);
|
||||
struct fujitsu_bl *priv = dev_get_drvdata(dev);
|
||||
struct acpi_device *device = ACPI_COMPANION(dev);
|
||||
int ret;
|
||||
|
||||
priv->input = devm_input_allocate_device(&device->dev);
|
||||
priv->input = devm_input_allocate_device(dev);
|
||||
if (!priv->input)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -479,9 +478,9 @@ static int acpi_fujitsu_bl_input_setup(struct acpi_device *device)
|
|||
return input_register_device(priv->input);
|
||||
}
|
||||
|
||||
static int fujitsu_backlight_register(struct acpi_device *device)
|
||||
static int fujitsu_backlight_register(struct device *dev)
|
||||
{
|
||||
struct fujitsu_bl *priv = acpi_driver_data(device);
|
||||
struct fujitsu_bl *priv = dev_get_drvdata(dev);
|
||||
const struct backlight_properties props = {
|
||||
.brightness = priv->brightness_level,
|
||||
.max_brightness = priv->max_brightness - 1,
|
||||
|
|
@ -489,9 +488,8 @@ static int fujitsu_backlight_register(struct acpi_device *device)
|
|||
};
|
||||
struct backlight_device *bd;
|
||||
|
||||
bd = devm_backlight_device_register(&device->dev, "fujitsu-laptop",
|
||||
&device->dev, device,
|
||||
&fujitsu_bl_ops, &props);
|
||||
bd = devm_backlight_device_register(dev, "fujitsu-laptop",
|
||||
dev, dev, &fujitsu_bl_ops, &props);
|
||||
if (IS_ERR(bd))
|
||||
return PTR_ERR(bd);
|
||||
|
||||
|
|
@ -500,65 +498,78 @@ static int fujitsu_backlight_register(struct acpi_device *device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_fujitsu_bl_add(struct acpi_device *device)
|
||||
/* Brightness notify */
|
||||
|
||||
static void acpi_fujitsu_bl_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
struct fujitsu_bl *priv = dev_get_drvdata(dev);
|
||||
int oldb, newb;
|
||||
|
||||
if (event != ACPI_FUJITSU_NOTIFY_CODE) {
|
||||
acpi_handle_info(handle, "unsupported event [0x%x]\n", event);
|
||||
sparse_keymap_report_event(priv->input, -1, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
oldb = priv->brightness_level;
|
||||
get_lcd_level(dev);
|
||||
newb = priv->brightness_level;
|
||||
|
||||
acpi_handle_debug(handle, "brightness button event [%i -> %i]\n",
|
||||
oldb, newb);
|
||||
|
||||
if (oldb == newb)
|
||||
return;
|
||||
|
||||
if (!disable_brightness_adjust)
|
||||
set_lcd_level(dev, newb);
|
||||
|
||||
sparse_keymap_report_event(priv->input, oldb < newb, 1, true);
|
||||
}
|
||||
|
||||
static int acpi_fujitsu_bl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct fujitsu_bl *priv;
|
||||
int ret;
|
||||
|
||||
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
|
||||
return -ENODEV;
|
||||
|
||||
priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
fujitsu_bl = priv;
|
||||
strscpy(acpi_device_name(device), ACPI_FUJITSU_BL_DEVICE_NAME);
|
||||
strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
|
||||
device->driver_data = priv;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
pr_info("ACPI: %s [%s]\n",
|
||||
acpi_device_name(device), acpi_device_bid(device));
|
||||
|
||||
if (get_max_brightness(device) <= 0)
|
||||
if (get_max_brightness(&pdev->dev) <= 0)
|
||||
priv->max_brightness = FUJITSU_LCD_N_LEVELS;
|
||||
get_lcd_level(device);
|
||||
get_lcd_level(&pdev->dev);
|
||||
|
||||
ret = acpi_fujitsu_bl_input_setup(device);
|
||||
ret = acpi_fujitsu_bl_input_setup(&pdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return fujitsu_backlight_register(device);
|
||||
ret = fujitsu_backlight_register(&pdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
acpi_fujitsu_bl_notify, &pdev->dev);
|
||||
}
|
||||
|
||||
/* Brightness notify */
|
||||
|
||||
static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event)
|
||||
static void acpi_fujitsu_bl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct fujitsu_bl *priv = acpi_driver_data(device);
|
||||
int oldb, newb;
|
||||
|
||||
if (event != ACPI_FUJITSU_NOTIFY_CODE) {
|
||||
acpi_handle_info(device->handle, "unsupported event [0x%x]\n",
|
||||
event);
|
||||
sparse_keymap_report_event(priv->input, -1, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
oldb = priv->brightness_level;
|
||||
get_lcd_level(device);
|
||||
newb = priv->brightness_level;
|
||||
|
||||
acpi_handle_debug(device->handle,
|
||||
"brightness button event [%i -> %i]\n", oldb, newb);
|
||||
|
||||
if (oldb == newb)
|
||||
return;
|
||||
|
||||
if (!disable_brightness_adjust)
|
||||
set_lcd_level(device, newb);
|
||||
|
||||
sparse_keymap_report_event(priv->input, oldb < newb, 1, true);
|
||||
acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
|
||||
ACPI_DEVICE_NOTIFY, acpi_fujitsu_bl_notify);
|
||||
}
|
||||
|
||||
/* ACPI device for hotkey handling */
|
||||
|
|
@ -653,12 +664,13 @@ static const struct dmi_system_id fujitsu_laptop_dmi_table[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device)
|
||||
static int acpi_fujitsu_laptop_input_setup(struct device *dev)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
struct fujitsu_laptop *priv = dev_get_drvdata(dev);
|
||||
struct acpi_device *device = ACPI_COMPANION(dev);
|
||||
int ret;
|
||||
|
||||
priv->input = devm_input_allocate_device(&device->dev);
|
||||
priv->input = devm_input_allocate_device(dev);
|
||||
if (!priv->input)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -677,9 +689,9 @@ static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device)
|
|||
return input_register_device(priv->input);
|
||||
}
|
||||
|
||||
static int fujitsu_laptop_platform_add(struct acpi_device *device)
|
||||
static int fujitsu_laptop_platform_add(struct device *dev)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
struct fujitsu_laptop *priv = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
priv->pf_device = platform_device_alloc("fujitsu-laptop", PLATFORM_DEVID_NONE);
|
||||
|
|
@ -707,9 +719,9 @@ err_put_platform_device:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void fujitsu_laptop_platform_remove(struct acpi_device *device)
|
||||
static void fujitsu_laptop_platform_remove(struct device *dev)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
struct fujitsu_laptop *priv = dev_get_drvdata(dev);
|
||||
|
||||
sysfs_remove_group(&priv->pf_device->dev.kobj,
|
||||
&fujitsu_pf_attribute_group);
|
||||
|
|
@ -719,7 +731,7 @@ static void fujitsu_laptop_platform_remove(struct acpi_device *device)
|
|||
static int logolamp_set(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(cdev->dev->parent);
|
||||
struct device *parent = cdev->dev->parent;
|
||||
int poweron = FUNC_LED_ON, always = FUNC_LED_ON;
|
||||
int ret;
|
||||
|
||||
|
|
@ -729,23 +741,23 @@ static int logolamp_set(struct led_classdev *cdev,
|
|||
if (brightness < LED_FULL)
|
||||
always = FUNC_LED_OFF;
|
||||
|
||||
ret = call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
|
||||
ret = call_fext_func(parent, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
|
||||
return call_fext_func(parent, FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
|
||||
}
|
||||
|
||||
static enum led_brightness logolamp_get(struct led_classdev *cdev)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(cdev->dev->parent);
|
||||
struct device *parent = cdev->dev->parent;
|
||||
int ret;
|
||||
|
||||
ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
|
||||
ret = call_fext_func(parent, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
|
||||
if (ret == FUNC_LED_ON)
|
||||
return LED_FULL;
|
||||
|
||||
ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
|
||||
ret = call_fext_func(parent, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
|
||||
if (ret == FUNC_LED_ON)
|
||||
return LED_HALF;
|
||||
|
||||
|
|
@ -755,22 +767,21 @@ static enum led_brightness logolamp_get(struct led_classdev *cdev)
|
|||
static int kblamps_set(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(cdev->dev->parent);
|
||||
struct device *parent = cdev->dev->parent;
|
||||
|
||||
if (brightness >= LED_FULL)
|
||||
return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
|
||||
return call_fext_func(parent, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
|
||||
FUNC_LED_ON);
|
||||
else
|
||||
return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
|
||||
return call_fext_func(parent, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
|
||||
FUNC_LED_OFF);
|
||||
}
|
||||
|
||||
static enum led_brightness kblamps_get(struct led_classdev *cdev)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(cdev->dev->parent);
|
||||
enum led_brightness brightness = LED_OFF;
|
||||
|
||||
if (call_fext_func(device,
|
||||
if (call_fext_func(cdev->dev->parent,
|
||||
FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
|
||||
brightness = LED_FULL;
|
||||
|
||||
|
|
@ -780,22 +791,22 @@ static enum led_brightness kblamps_get(struct led_classdev *cdev)
|
|||
static int radio_led_set(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(cdev->dev->parent);
|
||||
struct device *parent = cdev->dev->parent;
|
||||
|
||||
if (brightness >= LED_FULL)
|
||||
return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON,
|
||||
return call_fext_func(parent, FUNC_FLAGS, 0x5, RADIO_LED_ON,
|
||||
RADIO_LED_ON);
|
||||
else
|
||||
return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON,
|
||||
return call_fext_func(parent, FUNC_FLAGS, 0x5, RADIO_LED_ON,
|
||||
0x0);
|
||||
}
|
||||
|
||||
static enum led_brightness radio_led_get(struct led_classdev *cdev)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(cdev->dev->parent);
|
||||
struct device *parent = cdev->dev->parent;
|
||||
enum led_brightness brightness = LED_OFF;
|
||||
|
||||
if (call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON)
|
||||
if (call_fext_func(parent, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON)
|
||||
brightness = LED_FULL;
|
||||
|
||||
return brightness;
|
||||
|
|
@ -804,60 +815,58 @@ static enum led_brightness radio_led_get(struct led_classdev *cdev)
|
|||
static int eco_led_set(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(cdev->dev->parent);
|
||||
struct device *parent = cdev->dev->parent;
|
||||
int curr;
|
||||
|
||||
curr = call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0);
|
||||
curr = call_fext_func(parent, FUNC_LEDS, 0x2, ECO_LED, 0x0);
|
||||
if (brightness >= LED_FULL)
|
||||
return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED,
|
||||
return call_fext_func(parent, FUNC_LEDS, 0x1, ECO_LED,
|
||||
curr | ECO_LED_ON);
|
||||
else
|
||||
return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED,
|
||||
return call_fext_func(parent, FUNC_LEDS, 0x1, ECO_LED,
|
||||
curr & ~ECO_LED_ON);
|
||||
}
|
||||
|
||||
static enum led_brightness eco_led_get(struct led_classdev *cdev)
|
||||
{
|
||||
struct acpi_device *device = to_acpi_device(cdev->dev->parent);
|
||||
struct device *parent = cdev->dev->parent;
|
||||
enum led_brightness brightness = LED_OFF;
|
||||
|
||||
if (call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
|
||||
if (call_fext_func(parent, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
|
||||
brightness = LED_FULL;
|
||||
|
||||
return brightness;
|
||||
}
|
||||
|
||||
static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
||||
static int acpi_fujitsu_laptop_leds_register(struct device *dev)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
struct fujitsu_laptop *priv = dev_get_drvdata(dev);
|
||||
struct led_classdev *led;
|
||||
int ret;
|
||||
|
||||
if (call_fext_func(device,
|
||||
FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
|
||||
led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
|
||||
if (call_fext_func(dev, FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
|
||||
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
|
||||
if (!led)
|
||||
return -ENOMEM;
|
||||
|
||||
led->name = "fujitsu::logolamp";
|
||||
led->brightness_set_blocking = logolamp_set;
|
||||
led->brightness_get = logolamp_get;
|
||||
ret = devm_led_classdev_register(&device->dev, led);
|
||||
ret = devm_led_classdev_register(dev, led);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((call_fext_func(device,
|
||||
FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
|
||||
(call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
|
||||
led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
|
||||
if ((call_fext_func(dev, FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
|
||||
(call_fext_func(dev, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
|
||||
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
|
||||
if (!led)
|
||||
return -ENOMEM;
|
||||
|
||||
led->name = "fujitsu::kblamps";
|
||||
led->brightness_set_blocking = kblamps_set;
|
||||
led->brightness_get = kblamps_get;
|
||||
ret = devm_led_classdev_register(&device->dev, led);
|
||||
ret = devm_led_classdev_register(dev, led);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -872,7 +881,7 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
|||
* whether given model has a radio toggle button.
|
||||
*/
|
||||
if (priv->flags_supported & BIT(17)) {
|
||||
led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
|
||||
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
|
||||
if (!led)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -880,7 +889,7 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
|||
led->brightness_set_blocking = radio_led_set;
|
||||
led->brightness_get = radio_led_get;
|
||||
led->default_trigger = "rfkill-any";
|
||||
ret = devm_led_classdev_register(&device->dev, led);
|
||||
ret = devm_led_classdev_register(dev, led);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -890,17 +899,16 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
|||
* bit 14 seems to indicate presence of said led as well.
|
||||
* Confirm by testing the status.
|
||||
*/
|
||||
if ((call_fext_func(device, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
|
||||
(call_fext_func(device,
|
||||
FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
|
||||
led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
|
||||
if ((call_fext_func(dev, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
|
||||
(call_fext_func(dev, FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
|
||||
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
|
||||
if (!led)
|
||||
return -ENOMEM;
|
||||
|
||||
led->name = "fujitsu::eco_led";
|
||||
led->brightness_set_blocking = eco_led_set;
|
||||
led->brightness_get = eco_led_get;
|
||||
ret = devm_led_classdev_register(&device->dev, led);
|
||||
ret = devm_led_classdev_register(dev, led);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -908,102 +916,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_fujitsu_laptop_add(struct acpi_device *device)
|
||||
static void acpi_fujitsu_laptop_press(struct device *dev, int scancode)
|
||||
{
|
||||
struct fujitsu_laptop *priv;
|
||||
int ret, i = 0;
|
||||
|
||||
priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended.");
|
||||
fext = device;
|
||||
|
||||
strscpy(acpi_device_name(device), ACPI_FUJITSU_LAPTOP_DEVICE_NAME);
|
||||
strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
|
||||
device->driver_data = priv;
|
||||
|
||||
/* kfifo */
|
||||
spin_lock_init(&priv->fifo_lock);
|
||||
ret = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int),
|
||||
GFP_KERNEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pr_info("ACPI: %s [%s]\n",
|
||||
acpi_device_name(device), acpi_device_bid(device));
|
||||
|
||||
while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 &&
|
||||
i++ < MAX_HOTKEY_RINGBUFFER_SIZE)
|
||||
; /* No action, result is discarded */
|
||||
acpi_handle_debug(device->handle, "Discarded %i ringbuffer entries\n",
|
||||
i);
|
||||
|
||||
priv->flags_supported = call_fext_func(device, FUNC_FLAGS, 0x0, 0x0,
|
||||
0x0);
|
||||
|
||||
/* Make sure our bitmask of supported functions is cleared if the
|
||||
RFKILL function block is not implemented, like on the S7020. */
|
||||
if (priv->flags_supported == UNSUPPORTED_CMD)
|
||||
priv->flags_supported = 0;
|
||||
|
||||
if (priv->flags_supported)
|
||||
priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0,
|
||||
0x0);
|
||||
|
||||
/* Suspect this is a keymap of the application panel, print it */
|
||||
acpi_handle_info(device->handle, "BTNI: [0x%x]\n",
|
||||
call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0));
|
||||
|
||||
/* Sync backlight power status */
|
||||
if (fujitsu_bl && fujitsu_bl->bl_device &&
|
||||
acpi_video_get_backlight_type() == acpi_backlight_vendor) {
|
||||
if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2,
|
||||
BACKLIGHT_PARAM_POWER, 0x0) == BACKLIGHT_OFF)
|
||||
fujitsu_bl->bl_device->props.power = BACKLIGHT_POWER_OFF;
|
||||
else
|
||||
fujitsu_bl->bl_device->props.power = BACKLIGHT_POWER_ON;
|
||||
}
|
||||
|
||||
ret = acpi_fujitsu_laptop_input_setup(device);
|
||||
if (ret)
|
||||
goto err_free_fifo;
|
||||
|
||||
ret = acpi_fujitsu_laptop_leds_register(device);
|
||||
if (ret)
|
||||
goto err_free_fifo;
|
||||
|
||||
ret = fujitsu_laptop_platform_add(device);
|
||||
if (ret)
|
||||
goto err_free_fifo;
|
||||
|
||||
ret = fujitsu_battery_charge_control_add(device);
|
||||
if (ret < 0)
|
||||
pr_warn("Unable to register battery charge control: %d\n", ret);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_fifo:
|
||||
kfifo_free(&priv->fifo);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void acpi_fujitsu_laptop_remove(struct acpi_device *device)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
|
||||
fujitsu_battery_charge_control_remove(device);
|
||||
|
||||
fujitsu_laptop_platform_remove(device);
|
||||
|
||||
kfifo_free(&priv->fifo);
|
||||
}
|
||||
|
||||
static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
struct fujitsu_laptop *priv = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode,
|
||||
|
|
@ -1018,9 +933,9 @@ static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode)
|
|||
scancode);
|
||||
}
|
||||
|
||||
static void acpi_fujitsu_laptop_release(struct acpi_device *device)
|
||||
static void acpi_fujitsu_laptop_release(struct device *dev)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
struct fujitsu_laptop *priv = dev_get_drvdata(dev);
|
||||
int scancode, ret;
|
||||
|
||||
while (true) {
|
||||
|
|
@ -1034,35 +949,32 @@ static void acpi_fujitsu_laptop_release(struct acpi_device *device)
|
|||
}
|
||||
}
|
||||
|
||||
static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
|
||||
static void acpi_fujitsu_laptop_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
struct device *dev = data;
|
||||
struct fujitsu_laptop *priv = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
int scancode, i = 0;
|
||||
unsigned int irb;
|
||||
|
||||
if (event != ACPI_FUJITSU_NOTIFY_CODE) {
|
||||
acpi_handle_info(device->handle, "Unsupported event [0x%x]\n",
|
||||
event);
|
||||
acpi_handle_info(handle, "Unsupported event [0x%x]\n", event);
|
||||
sparse_keymap_report_event(priv->input, -1, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->flags_supported)
|
||||
priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0,
|
||||
0x0);
|
||||
priv->flags_state = call_fext_func(dev, FUNC_FLAGS, 0x4, 0x0, 0x0);
|
||||
|
||||
while ((irb = call_fext_func(device,
|
||||
FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 &&
|
||||
while ((irb = call_fext_func(dev, FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 &&
|
||||
i++ < MAX_HOTKEY_RINGBUFFER_SIZE) {
|
||||
scancode = irb & 0x4ff;
|
||||
if (sparse_keymap_entry_from_scancode(priv->input, scancode))
|
||||
acpi_fujitsu_laptop_press(device, scancode);
|
||||
acpi_fujitsu_laptop_press(dev, scancode);
|
||||
else if (scancode == 0)
|
||||
acpi_fujitsu_laptop_release(device);
|
||||
acpi_fujitsu_laptop_release(dev);
|
||||
else
|
||||
acpi_handle_info(device->handle,
|
||||
"Unknown GIRB result [%x]\n", irb);
|
||||
acpi_handle_info(handle, "Unknown GIRB result [%x]\n", irb);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1072,13 +984,117 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
|
|||
* status flags queried using FUNC_FLAGS.
|
||||
*/
|
||||
if (priv->flags_supported & (FLAG_SOFTKEYS)) {
|
||||
flags = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0);
|
||||
flags = call_fext_func(dev, FUNC_FLAGS, 0x1, 0x0, 0x0);
|
||||
flags &= (FLAG_SOFTKEYS);
|
||||
for_each_set_bit(i, &flags, BITS_PER_LONG)
|
||||
sparse_keymap_report_event(priv->input, BIT(i), 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
static int acpi_fujitsu_laptop_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct fujitsu_laptop *priv;
|
||||
int ret, i = 0;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended.");
|
||||
fext = &pdev->dev;
|
||||
|
||||
strscpy(acpi_device_name(device), ACPI_FUJITSU_LAPTOP_DEVICE_NAME);
|
||||
strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
/* kfifo */
|
||||
spin_lock_init(&priv->fifo_lock);
|
||||
ret = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int),
|
||||
GFP_KERNEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pr_info("ACPI: %s [%s]\n",
|
||||
acpi_device_name(device), acpi_device_bid(device));
|
||||
|
||||
while (call_fext_func(fext, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 &&
|
||||
i++ < MAX_HOTKEY_RINGBUFFER_SIZE)
|
||||
; /* No action, result is discarded */
|
||||
acpi_handle_debug(device->handle, "Discarded %i ringbuffer entries\n",
|
||||
i);
|
||||
|
||||
priv->flags_supported = call_fext_func(fext, FUNC_FLAGS, 0x0, 0x0, 0x0);
|
||||
|
||||
/* Make sure our bitmask of supported functions is cleared if the
|
||||
RFKILL function block is not implemented, like on the S7020. */
|
||||
if (priv->flags_supported == UNSUPPORTED_CMD)
|
||||
priv->flags_supported = 0;
|
||||
|
||||
if (priv->flags_supported)
|
||||
priv->flags_state = call_fext_func(fext, FUNC_FLAGS, 0x4, 0x0,
|
||||
0x0);
|
||||
|
||||
/* Suspect this is a keymap of the application panel, print it */
|
||||
acpi_handle_info(device->handle, "BTNI: [0x%x]\n",
|
||||
call_fext_func(fext, FUNC_BUTTONS, 0x0, 0x0, 0x0));
|
||||
|
||||
/* Sync backlight power status */
|
||||
if (fujitsu_bl && fujitsu_bl->bl_device &&
|
||||
acpi_video_get_backlight_type() == acpi_backlight_vendor) {
|
||||
if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2,
|
||||
BACKLIGHT_PARAM_POWER, 0x0) == BACKLIGHT_OFF)
|
||||
fujitsu_bl->bl_device->props.power = BACKLIGHT_POWER_OFF;
|
||||
else
|
||||
fujitsu_bl->bl_device->props.power = BACKLIGHT_POWER_ON;
|
||||
}
|
||||
|
||||
ret = acpi_fujitsu_laptop_input_setup(fext);
|
||||
if (ret)
|
||||
goto err_free_fifo;
|
||||
|
||||
ret = acpi_fujitsu_laptop_leds_register(fext);
|
||||
if (ret)
|
||||
goto err_free_fifo;
|
||||
|
||||
ret = fujitsu_laptop_platform_add(fext);
|
||||
if (ret)
|
||||
goto err_free_fifo;
|
||||
|
||||
ret = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
acpi_fujitsu_laptop_notify, fext);
|
||||
if (ret)
|
||||
goto err_platform_remove;
|
||||
|
||||
ret = fujitsu_battery_charge_control_add(fext);
|
||||
if (ret < 0)
|
||||
pr_warn("Unable to register battery charge control: %d\n", ret);
|
||||
|
||||
return 0;
|
||||
|
||||
err_platform_remove:
|
||||
fujitsu_laptop_platform_remove(fext);
|
||||
err_free_fifo:
|
||||
kfifo_free(&priv->fifo);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void acpi_fujitsu_laptop_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct fujitsu_laptop *priv = platform_get_drvdata(pdev);
|
||||
|
||||
fujitsu_battery_charge_control_remove(&pdev->dev);
|
||||
|
||||
acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), ACPI_DEVICE_NOTIFY,
|
||||
acpi_fujitsu_laptop_notify);
|
||||
|
||||
fujitsu_laptop_platform_remove(&pdev->dev);
|
||||
|
||||
kfifo_free(&priv->fifo);
|
||||
}
|
||||
|
||||
/* Initialization */
|
||||
|
||||
static const struct acpi_device_id fujitsu_bl_device_ids[] = {
|
||||
|
|
@ -1086,14 +1102,13 @@ static const struct acpi_device_id fujitsu_bl_device_ids[] = {
|
|||
{"", 0},
|
||||
};
|
||||
|
||||
static struct acpi_driver acpi_fujitsu_bl_driver = {
|
||||
.name = ACPI_FUJITSU_BL_DRIVER_NAME,
|
||||
.class = ACPI_FUJITSU_CLASS,
|
||||
.ids = fujitsu_bl_device_ids,
|
||||
.ops = {
|
||||
.add = acpi_fujitsu_bl_add,
|
||||
.notify = acpi_fujitsu_bl_notify,
|
||||
},
|
||||
static struct platform_driver acpi_fujitsu_bl_driver = {
|
||||
.probe = acpi_fujitsu_bl_probe,
|
||||
.remove = acpi_fujitsu_bl_remove,
|
||||
.driver = {
|
||||
.name = ACPI_FUJITSU_BL_DRIVER_NAME,
|
||||
.acpi_match_table = fujitsu_bl_device_ids,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct acpi_device_id fujitsu_laptop_device_ids[] = {
|
||||
|
|
@ -1101,15 +1116,13 @@ static const struct acpi_device_id fujitsu_laptop_device_ids[] = {
|
|||
{"", 0},
|
||||
};
|
||||
|
||||
static struct acpi_driver acpi_fujitsu_laptop_driver = {
|
||||
.name = ACPI_FUJITSU_LAPTOP_DRIVER_NAME,
|
||||
.class = ACPI_FUJITSU_CLASS,
|
||||
.ids = fujitsu_laptop_device_ids,
|
||||
.ops = {
|
||||
.add = acpi_fujitsu_laptop_add,
|
||||
.remove = acpi_fujitsu_laptop_remove,
|
||||
.notify = acpi_fujitsu_laptop_notify,
|
||||
},
|
||||
static struct platform_driver acpi_fujitsu_laptop_driver = {
|
||||
.probe = acpi_fujitsu_laptop_probe,
|
||||
.remove = acpi_fujitsu_laptop_remove,
|
||||
.driver = {
|
||||
.name = ACPI_FUJITSU_LAPTOP_DRIVER_NAME,
|
||||
.acpi_match_table = fujitsu_laptop_device_ids,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct acpi_device_id fujitsu_ids[] __used = {
|
||||
|
|
@ -1123,7 +1136,7 @@ static int __init fujitsu_init(void)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver);
|
||||
ret = platform_driver_register(&acpi_fujitsu_bl_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1135,7 +1148,7 @@ static int __init fujitsu_init(void)
|
|||
|
||||
/* Register laptop driver */
|
||||
|
||||
ret = acpi_bus_register_driver(&acpi_fujitsu_laptop_driver);
|
||||
ret = platform_driver_register(&acpi_fujitsu_laptop_driver);
|
||||
if (ret)
|
||||
goto err_unregister_platform_driver;
|
||||
|
||||
|
|
@ -1146,18 +1159,18 @@ static int __init fujitsu_init(void)
|
|||
err_unregister_platform_driver:
|
||||
platform_driver_unregister(&fujitsu_pf_driver);
|
||||
err_unregister_acpi:
|
||||
acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver);
|
||||
platform_driver_unregister(&acpi_fujitsu_bl_driver);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fujitsu_cleanup(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&acpi_fujitsu_laptop_driver);
|
||||
platform_driver_unregister(&acpi_fujitsu_laptop_driver);
|
||||
|
||||
platform_driver_unregister(&fujitsu_pf_driver);
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver);
|
||||
platform_driver_unregister(&acpi_fujitsu_bl_driver);
|
||||
|
||||
pr_info("driver unloaded\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define MODULENAME "fujitsu-tablet"
|
||||
|
||||
|
|
@ -442,14 +443,12 @@ static acpi_status fujitsu_walk_resources(struct acpi_resource *res, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
static int acpi_fujitsu_add(struct acpi_device *adev)
|
||||
static int acpi_fujitsu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
|
||||
acpi_status status;
|
||||
int error;
|
||||
|
||||
if (!adev)
|
||||
return -EINVAL;
|
||||
|
||||
status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
|
||||
fujitsu_walk_resources, NULL);
|
||||
if (ACPI_FAILURE(status) || !fujitsu.irq || !fujitsu.io_base)
|
||||
|
|
@ -461,7 +460,7 @@ static int acpi_fujitsu_add(struct acpi_device *adev)
|
|||
snprintf(fujitsu.phys, sizeof(fujitsu.phys),
|
||||
"%s/input0", acpi_device_hid(adev));
|
||||
|
||||
error = input_fujitsu_setup(&adev->dev,
|
||||
error = input_fujitsu_setup(&pdev->dev,
|
||||
acpi_device_name(adev), fujitsu.phys);
|
||||
if (error)
|
||||
return error;
|
||||
|
|
@ -484,7 +483,7 @@ static int acpi_fujitsu_add(struct acpi_device *adev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_fujitsu_remove(struct acpi_device *adev)
|
||||
static void acpi_fujitsu_remove(struct platform_device *pdev)
|
||||
{
|
||||
free_irq(fujitsu.irq, fujitsu_interrupt);
|
||||
release_region(fujitsu.io_base, fujitsu.io_length);
|
||||
|
|
@ -501,15 +500,14 @@ static int acpi_fujitsu_resume(struct device *dev)
|
|||
|
||||
static SIMPLE_DEV_PM_OPS(acpi_fujitsu_pm, NULL, acpi_fujitsu_resume);
|
||||
|
||||
static struct acpi_driver acpi_fujitsu_driver = {
|
||||
.name = MODULENAME,
|
||||
.class = "hotkey",
|
||||
.ids = fujitsu_ids,
|
||||
.ops = {
|
||||
.add = acpi_fujitsu_add,
|
||||
.remove = acpi_fujitsu_remove,
|
||||
static struct platform_driver acpi_fujitsu_driver = {
|
||||
.probe = acpi_fujitsu_probe,
|
||||
.remove = acpi_fujitsu_remove,
|
||||
.driver = {
|
||||
.name = MODULENAME,
|
||||
.acpi_match_table = fujitsu_ids,
|
||||
.pm = &acpi_fujitsu_pm,
|
||||
},
|
||||
.drv.pm = &acpi_fujitsu_pm,
|
||||
};
|
||||
|
||||
static int __init fujitsu_module_init(void)
|
||||
|
|
@ -518,7 +516,7 @@ static int __init fujitsu_module_init(void)
|
|||
|
||||
dmi_check_system(dmi_ids);
|
||||
|
||||
error = acpi_bus_register_driver(&acpi_fujitsu_driver);
|
||||
error = platform_driver_register(&acpi_fujitsu_driver);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
@ -527,7 +525,7 @@ static int __init fujitsu_module_init(void)
|
|||
|
||||
static void __exit fujitsu_module_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&acpi_fujitsu_driver);
|
||||
platform_driver_unregister(&acpi_fujitsu_driver);
|
||||
}
|
||||
|
||||
module_init(fujitsu_module_init);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45E9-BE91-3D44E2C707E4");
|
|||
|
||||
enum hp_ec_offsets {
|
||||
HP_EC_OFFSET_UNKNOWN = 0x00,
|
||||
HP_NO_THERMAL_PROFILE_OFFSET = 0x01,
|
||||
HP_VICTUS_S_EC_THERMAL_PROFILE_OFFSET = 0x59,
|
||||
HP_OMEN_EC_THERMAL_PROFILE_FLAGS_OFFSET = 0x62,
|
||||
HP_OMEN_EC_THERMAL_PROFILE_TIMER_OFFSET = 0x63,
|
||||
|
|
@ -125,6 +126,13 @@ static const struct thermal_profile_params omen_v1_legacy_thermal_params = {
|
|||
.ec_tp_offset = HP_OMEN_EC_THERMAL_PROFILE_OFFSET,
|
||||
};
|
||||
|
||||
static const struct thermal_profile_params omen_v1_no_ec_thermal_params = {
|
||||
.performance = HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE,
|
||||
.balanced = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT,
|
||||
.low_power = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT,
|
||||
.ec_tp_offset = HP_NO_THERMAL_PROFILE_OFFSET,
|
||||
};
|
||||
|
||||
/*
|
||||
* A generic pointer for the currently-active board's thermal profile
|
||||
* parameters.
|
||||
|
|
@ -151,6 +159,7 @@ static const char * const omen_thermal_profile_boards[] = {
|
|||
"8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB",
|
||||
"8A15", "8A42",
|
||||
"8BAD",
|
||||
"8C58",
|
||||
"8E41",
|
||||
};
|
||||
|
||||
|
|
@ -180,6 +189,10 @@ static const char * const victus_thermal_profile_boards[] = {
|
|||
|
||||
/* DMI Board names of Victus 16-r and Victus 16-s laptops */
|
||||
static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = {
|
||||
{
|
||||
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8A44") },
|
||||
.driver_data = (void *)&omen_v1_legacy_thermal_params,
|
||||
},
|
||||
{
|
||||
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8A4D") },
|
||||
.driver_data = (void *)&omen_v1_legacy_thermal_params,
|
||||
|
|
@ -212,6 +225,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst
|
|||
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8C76") },
|
||||
.driver_data = (void *)&omen_v1_thermal_params,
|
||||
},
|
||||
{
|
||||
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8C77") },
|
||||
.driver_data = (void *)&omen_v1_thermal_params,
|
||||
},
|
||||
{
|
||||
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8C78") },
|
||||
.driver_data = (void *)&omen_v1_thermal_params,
|
||||
|
|
@ -228,6 +245,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst
|
|||
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8D41") },
|
||||
.driver_data = (void *)&victus_s_thermal_params,
|
||||
},
|
||||
{
|
||||
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8D87") },
|
||||
.driver_data = (void *)&omen_v1_no_ec_thermal_params,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
@ -397,6 +418,11 @@ static const struct key_entry hp_wmi_keymap[] = {
|
|||
{ KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } },
|
||||
{ KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } },
|
||||
{ KE_KEY, 0x231b, { KEY_HELP } },
|
||||
{ KE_IGNORE, 0x21ab, }, /* FnLock on */
|
||||
{ KE_IGNORE, 0x121ab, }, /* FnLock off */
|
||||
{ KE_IGNORE, 0x30021aa, }, /* kbd backlight: level 2 -> off */
|
||||
{ KE_IGNORE, 0x33221aa, }, /* kbd backlight: off -> level 1 */
|
||||
{ KE_IGNORE, 0x36421aa, }, /* kbd backlight: level 1 -> level 2*/
|
||||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
|
|
@ -451,23 +477,24 @@ enum pwm_modes {
|
|||
};
|
||||
|
||||
struct hp_wmi_hwmon_priv {
|
||||
struct mutex lock; /* protects mode, pwm */
|
||||
u8 min_rpm;
|
||||
u8 max_rpm;
|
||||
u8 gpu_delta;
|
||||
int gpu_delta;
|
||||
u8 mode;
|
||||
u8 pwm;
|
||||
struct delayed_work keep_alive_dwork;
|
||||
};
|
||||
|
||||
struct victus_s_fan_table_header {
|
||||
u8 num_fans;
|
||||
u8 unknown;
|
||||
u8 num_entries;
|
||||
} __packed;
|
||||
|
||||
struct victus_s_fan_table_entry {
|
||||
u8 cpu_rpm;
|
||||
u8 gpu_rpm;
|
||||
u8 unknown;
|
||||
u8 noise_db;
|
||||
} __packed;
|
||||
|
||||
struct victus_s_fan_table {
|
||||
|
|
@ -1828,7 +1855,8 @@ static int platform_profile_victus_s_get_ec(enum platform_profile_option *profil
|
|||
const struct thermal_profile_params *params;
|
||||
|
||||
params = active_thermal_profile_params;
|
||||
if (params->ec_tp_offset == HP_EC_OFFSET_UNKNOWN) {
|
||||
if (params->ec_tp_offset == HP_EC_OFFSET_UNKNOWN ||
|
||||
params->ec_tp_offset == HP_NO_THERMAL_PROFILE_OFFSET) {
|
||||
*profile = active_platform_profile;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2183,7 +2211,8 @@ static int thermal_profile_setup(struct platform_device *device)
|
|||
* behaves like a wrapper around active_platform_profile, to avoid using
|
||||
* uninitialized data, we default to PLATFORM_PROFILE_BALANCED.
|
||||
*/
|
||||
if (active_thermal_profile_params->ec_tp_offset == HP_EC_OFFSET_UNKNOWN) {
|
||||
if (active_thermal_profile_params->ec_tp_offset == HP_EC_OFFSET_UNKNOWN ||
|
||||
active_thermal_profile_params->ec_tp_offset == HP_NO_THERMAL_PROFILE_OFFSET) {
|
||||
active_platform_profile = PLATFORM_PROFILE_BALANCED;
|
||||
} else {
|
||||
err = platform_profile_victus_s_get_ec(&active_platform_profile);
|
||||
|
|
@ -2351,13 +2380,16 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv)
|
|||
|
||||
switch (priv->mode) {
|
||||
case PWM_MODE_MAX:
|
||||
if (is_victus_s_thermal_profile())
|
||||
hp_wmi_get_fan_count_userdefine_trigger();
|
||||
if (is_victus_s_thermal_profile()) {
|
||||
ret = hp_wmi_get_fan_count_userdefine_trigger();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
ret = hp_wmi_fan_speed_max_set(1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
schedule_delayed_work(&priv->keep_alive_dwork,
|
||||
secs_to_jiffies(KEEP_ALIVE_DELAY_SECS));
|
||||
mod_delayed_work(system_wq, &priv->keep_alive_dwork,
|
||||
secs_to_jiffies(KEEP_ALIVE_DELAY_SECS));
|
||||
return 0;
|
||||
case PWM_MODE_MANUAL:
|
||||
if (!is_victus_s_thermal_profile())
|
||||
|
|
@ -2365,26 +2397,26 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv)
|
|||
ret = hp_wmi_fan_speed_set(priv, pwm_to_rpm(priv->pwm, priv));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
schedule_delayed_work(&priv->keep_alive_dwork,
|
||||
secs_to_jiffies(KEEP_ALIVE_DELAY_SECS));
|
||||
mod_delayed_work(system_wq, &priv->keep_alive_dwork,
|
||||
secs_to_jiffies(KEEP_ALIVE_DELAY_SECS));
|
||||
return 0;
|
||||
case PWM_MODE_AUTO:
|
||||
if (is_victus_s_thermal_profile()) {
|
||||
hp_wmi_get_fan_count_userdefine_trigger();
|
||||
ret = hp_wmi_get_fan_count_userdefine_trigger();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = hp_wmi_fan_speed_max_reset(priv);
|
||||
} else {
|
||||
ret = hp_wmi_fan_speed_max_set(0);
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cancel_delayed_work_sync(&priv->keep_alive_dwork);
|
||||
cancel_delayed_work(&priv->keep_alive_dwork);
|
||||
return 0;
|
||||
default:
|
||||
/* shouldn't happen */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static umode_t hp_wmi_hwmon_is_visible(const void *data,
|
||||
|
|
@ -2417,6 +2449,7 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
{
|
||||
struct hp_wmi_hwmon_priv *priv;
|
||||
int rpm, ret;
|
||||
u8 mode;
|
||||
|
||||
priv = dev_get_drvdata(dev);
|
||||
switch (type) {
|
||||
|
|
@ -2440,11 +2473,13 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
*val = rpm_to_pwm(rpm / 100, priv);
|
||||
return 0;
|
||||
}
|
||||
switch (priv->mode) {
|
||||
scoped_guard(mutex, &priv->lock)
|
||||
mode = priv->mode;
|
||||
switch (mode) {
|
||||
case PWM_MODE_MAX:
|
||||
case PWM_MODE_MANUAL:
|
||||
case PWM_MODE_AUTO:
|
||||
*val = priv->mode;
|
||||
*val = mode;
|
||||
return 0;
|
||||
default:
|
||||
/* shouldn't happen */
|
||||
|
|
@ -2462,6 +2497,7 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
int rpm;
|
||||
|
||||
priv = dev_get_drvdata(dev);
|
||||
guard(mutex)(&priv->lock);
|
||||
switch (type) {
|
||||
case hwmon_pwm:
|
||||
if (attr == hwmon_pwm_input) {
|
||||
|
|
@ -2526,22 +2562,30 @@ static void hp_wmi_hwmon_keep_alive_handler(struct work_struct *work)
|
|||
{
|
||||
struct delayed_work *dwork;
|
||||
struct hp_wmi_hwmon_priv *priv;
|
||||
int ret;
|
||||
|
||||
dwork = to_delayed_work(work);
|
||||
priv = container_of(dwork, struct hp_wmi_hwmon_priv, keep_alive_dwork);
|
||||
|
||||
guard(mutex)(&priv->lock);
|
||||
/*
|
||||
* Re-apply the current hwmon context settings.
|
||||
* NOTE: hp_wmi_apply_fan_settings will handle the re-scheduling.
|
||||
*/
|
||||
hp_wmi_apply_fan_settings(priv);
|
||||
ret = hp_wmi_apply_fan_settings(priv);
|
||||
if (ret)
|
||||
pr_warn_ratelimited("keep-alive failed to refresh fan settings: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv)
|
||||
{
|
||||
u8 fan_data[128] = { 0 };
|
||||
struct victus_s_fan_table *fan_table;
|
||||
u8 min_rpm, max_rpm, gpu_delta;
|
||||
int ret;
|
||||
u8 min_rpm, max_rpm;
|
||||
u8 cpu_rpm, gpu_rpm, noise_db;
|
||||
int gpu_delta, i, num_entries, ret;
|
||||
size_t header_size, entry_size;
|
||||
|
||||
/* Default behaviour on hwmon init is automatic mode */
|
||||
priv->mode = PWM_MODE_AUTO;
|
||||
|
|
@ -2556,13 +2600,36 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv)
|
|||
return ret;
|
||||
|
||||
fan_table = (struct victus_s_fan_table *)fan_data;
|
||||
if (fan_table->header.num_entries == 0 ||
|
||||
sizeof(struct victus_s_fan_table_header) +
|
||||
sizeof(struct victus_s_fan_table_entry) * fan_table->header.num_entries > sizeof(fan_data))
|
||||
if (fan_table->header.num_fans == 0)
|
||||
return -EINVAL;
|
||||
|
||||
header_size = sizeof(struct victus_s_fan_table_header);
|
||||
entry_size = sizeof(struct victus_s_fan_table_entry);
|
||||
num_entries = (sizeof(fan_data) - header_size) / entry_size;
|
||||
min_rpm = U8_MAX;
|
||||
max_rpm = 0;
|
||||
|
||||
for (i = 0 ; i < num_entries ; i++) {
|
||||
cpu_rpm = fan_table->entries[i].cpu_rpm;
|
||||
gpu_rpm = fan_table->entries[i].gpu_rpm;
|
||||
noise_db = fan_table->entries[i].noise_db;
|
||||
|
||||
/*
|
||||
* On some devices, the fan table is truncated with an all-zero row,
|
||||
* hence we stop parsing here.
|
||||
*/
|
||||
if (cpu_rpm == 0 && gpu_rpm == 0 && noise_db == 0)
|
||||
break;
|
||||
|
||||
if (cpu_rpm < min_rpm)
|
||||
min_rpm = cpu_rpm;
|
||||
if (cpu_rpm > max_rpm)
|
||||
max_rpm = cpu_rpm;
|
||||
}
|
||||
|
||||
if (min_rpm == U8_MAX || max_rpm == 0)
|
||||
return -EINVAL;
|
||||
|
||||
min_rpm = fan_table->entries[0].cpu_rpm;
|
||||
max_rpm = fan_table->entries[fan_table->header.num_entries - 1].cpu_rpm;
|
||||
gpu_delta = fan_table->entries[0].gpu_rpm - fan_table->entries[0].cpu_rpm;
|
||||
priv->min_rpm = min_rpm;
|
||||
priv->max_rpm = max_rpm;
|
||||
|
|
@ -2582,6 +2649,10 @@ static int hp_wmi_hwmon_init(void)
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_mutex_init(dev, &priv->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = hp_wmi_setup_fan_settings(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -2595,7 +2666,9 @@ static int hp_wmi_hwmon_init(void)
|
|||
|
||||
INIT_DELAYED_WORK(&priv->keep_alive_dwork, hp_wmi_hwmon_keep_alive_handler);
|
||||
platform_set_drvdata(hp_wmi_platform_dev, priv);
|
||||
hp_wmi_apply_fan_settings(priv);
|
||||
ret = hp_wmi_apply_fan_settings(priv);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to apply initial fan settings: %d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,7 +212,11 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3
|
|||
*gpio_flags = GPIO_ACTIVE_HIGH;
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_PRIVACY_LED:
|
||||
*con_id = "privacy-led";
|
||||
*con_id = "privacy";
|
||||
*gpio_flags = GPIO_ACTIVE_HIGH;
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_STROBE:
|
||||
*con_id = "ir_flood";
|
||||
*gpio_flags = GPIO_ACTIVE_HIGH;
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_HOTPLUG_DETECT:
|
||||
|
|
@ -252,6 +256,7 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3
|
|||
*
|
||||
* 0x00 Reset
|
||||
* 0x01 Power down
|
||||
* 0x02 Strobe
|
||||
* 0x0b Power enable
|
||||
* 0x0c Clock enable
|
||||
* 0x0d Privacy LED
|
||||
|
|
@ -336,6 +341,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
|
|||
break;
|
||||
case INT3472_GPIO_TYPE_CLK_ENABLE:
|
||||
case INT3472_GPIO_TYPE_PRIVACY_LED:
|
||||
case INT3472_GPIO_TYPE_STROBE:
|
||||
case INT3472_GPIO_TYPE_POWER_ENABLE:
|
||||
case INT3472_GPIO_TYPE_DOVDD:
|
||||
case INT3472_GPIO_TYPE_HANDSHAKE:
|
||||
|
|
@ -354,7 +360,8 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
|
|||
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_PRIVACY_LED:
|
||||
ret = skl_int3472_register_pled(int3472, gpio);
|
||||
case INT3472_GPIO_TYPE_STROBE:
|
||||
ret = skl_int3472_register_led(int3472, gpio, con_id);
|
||||
if (ret)
|
||||
err_msg = "Failed to register LED\n";
|
||||
|
||||
|
|
@ -429,7 +436,7 @@ void int3472_discrete_cleanup(struct int3472_discrete_device *int3472)
|
|||
gpiod_remove_lookup_table(&int3472->gpios);
|
||||
|
||||
skl_int3472_unregister_clock(int3472);
|
||||
skl_int3472_unregister_pled(int3472);
|
||||
skl_int3472_unregister_leds(int3472);
|
||||
skl_int3472_unregister_regulator(int3472);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(int3472_discrete_cleanup, "INTEL_INT3472_DISCRETE");
|
||||
|
|
|
|||
|
|
@ -6,55 +6,58 @@
|
|||
#include <linux/leds.h>
|
||||
#include <linux/platform_data/x86/int3472.h>
|
||||
|
||||
static int int3472_pled_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
static int int3472_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
|
||||
{
|
||||
struct int3472_discrete_device *int3472 =
|
||||
container_of(led_cdev, struct int3472_discrete_device, pled.classdev);
|
||||
struct int3472_led *led = container_of(led_cdev, struct int3472_led, classdev);
|
||||
|
||||
gpiod_set_value_cansleep(int3472->pled.gpio, brightness);
|
||||
gpiod_set_value_cansleep(led->gpio, brightness);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int skl_int3472_register_pled(struct int3472_discrete_device *int3472, struct gpio_desc *gpio)
|
||||
int skl_int3472_register_led(struct int3472_discrete_device *int3472, struct gpio_desc *gpio,
|
||||
const char *con_id)
|
||||
{
|
||||
struct int3472_led *led;
|
||||
char *p;
|
||||
int ret;
|
||||
|
||||
if (int3472->pled.classdev.dev)
|
||||
return -EBUSY;
|
||||
if (int3472->n_leds >= INT3472_MAX_LEDS)
|
||||
return -ENOSPC;
|
||||
|
||||
int3472->pled.gpio = gpio;
|
||||
led = &int3472->leds[int3472->n_leds];
|
||||
led->gpio = gpio;
|
||||
|
||||
/* Generate the name, replacing the ':' in the ACPI devname with '_' */
|
||||
snprintf(int3472->pled.name, sizeof(int3472->pled.name),
|
||||
"%s::privacy_led", acpi_dev_name(int3472->sensor));
|
||||
p = strchr(int3472->pled.name, ':');
|
||||
snprintf(led->name, sizeof(led->name),
|
||||
"%s::%s_led", acpi_dev_name(int3472->sensor), con_id);
|
||||
p = strchr(led->name, ':');
|
||||
if (p)
|
||||
*p = '_';
|
||||
|
||||
int3472->pled.classdev.name = int3472->pled.name;
|
||||
int3472->pled.classdev.max_brightness = 1;
|
||||
int3472->pled.classdev.brightness_set_blocking = int3472_pled_set;
|
||||
led->classdev.name = led->name;
|
||||
led->classdev.max_brightness = 1;
|
||||
led->classdev.brightness_set_blocking = int3472_led_set;
|
||||
|
||||
ret = led_classdev_register(int3472->dev, &int3472->pled.classdev);
|
||||
ret = led_classdev_register(int3472->dev, &led->classdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
int3472->pled.lookup.provider = int3472->pled.name;
|
||||
int3472->pled.lookup.dev_id = int3472->sensor_name;
|
||||
int3472->pled.lookup.con_id = "privacy";
|
||||
led_add_lookup(&int3472->pled.lookup);
|
||||
led->lookup.provider = led->name;
|
||||
led->lookup.dev_id = int3472->sensor_name;
|
||||
led->lookup.con_id = con_id;
|
||||
led_add_lookup(&led->lookup);
|
||||
|
||||
int3472->n_leds++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472)
|
||||
void skl_int3472_unregister_leds(struct int3472_discrete_device *int3472)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(int3472->pled.classdev.dev))
|
||||
return;
|
||||
for (unsigned int i = 0; i < int3472->n_leds; i++) {
|
||||
struct int3472_led *led = &int3472->leds[i];
|
||||
|
||||
led_remove_lookup(&int3472->pled.lookup);
|
||||
led_classdev_unregister(&int3472->pled.classdev);
|
||||
gpiod_put(int3472->pled.gpio);
|
||||
led_remove_lookup(&led->lookup);
|
||||
led_classdev_unregister(&led->classdev);
|
||||
gpiod_put(led->gpio);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1315,7 +1315,7 @@ static struct telem_endpoint *pmc_core_register_endpoint(struct pci_dev *pcidev,
|
|||
unsigned int i;
|
||||
|
||||
for (i = 0; guids[i]; i++) {
|
||||
ep = pmt_telem_find_and_register_endpoint(pcidev, guids[i], 0);
|
||||
ep = pmt_telem_find_and_register_endpoint(&pcidev->dev, guids[i], 0);
|
||||
if (!IS_ERR(ep))
|
||||
return ep;
|
||||
}
|
||||
|
|
@ -1600,7 +1600,7 @@ static int pmc_core_get_telem_info(struct pmc_dev *pmcdev, struct pmc_dev_info *
|
|||
if (!pmc->map->lpm_req_guid)
|
||||
return -ENXIO;
|
||||
|
||||
ep = pmt_telem_find_and_register_endpoint(pcidev, pmc->map->lpm_req_guid, 0);
|
||||
ep = pmt_telem_find_and_register_endpoint(&pcidev->dev, pmc->map->lpm_req_guid, 0);
|
||||
if (IS_ERR(ep)) {
|
||||
dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %pe", ep);
|
||||
return -EPROBE_DEFER;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ pmc_ssram_telemetry_add_pmt(struct pci_dev *pcidev, u64 ssram_base, void __iomem
|
|||
info.base_addr = ssram_base;
|
||||
info.parent = &pcidev->dev;
|
||||
|
||||
return intel_vsec_register(pcidev, &info);
|
||||
return intel_vsec_register(&pcidev->dev, &info);
|
||||
}
|
||||
|
||||
static inline u64 get_base(void __iomem *addr, u32 offset)
|
||||
|
|
|
|||
|
|
@ -60,11 +60,11 @@ pmt_memcpy64_fromio(void *to, const u64 __iomem *from, size_t count)
|
|||
return count;
|
||||
}
|
||||
|
||||
int pmt_telem_read_mmio(struct pci_dev *pdev, struct pmt_callbacks *cb, u32 guid, void *buf,
|
||||
int pmt_telem_read_mmio(struct device *dev, struct pmt_callbacks *cb, u32 guid, void *buf,
|
||||
void __iomem *addr, loff_t off, u32 count)
|
||||
{
|
||||
if (cb && cb->read_telem)
|
||||
return cb->read_telem(pdev, guid, buf, off, count);
|
||||
return cb->read_telem(dev, guid, buf, off, count);
|
||||
|
||||
addr += off;
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ intel_pmt_read(struct file *filp, struct kobject *kobj,
|
|||
if (count > entry->size - off)
|
||||
count = entry->size - off;
|
||||
|
||||
count = pmt_telem_read_mmio(entry->pcidev, entry->cb, entry->header.guid, buf,
|
||||
count = pmt_telem_read_mmio(entry->ep->dev, entry->cb, entry->header.guid, buf,
|
||||
entry->base, off, count);
|
||||
|
||||
return count;
|
||||
|
|
@ -208,7 +208,7 @@ static int intel_pmt_populate_entry(struct intel_pmt_entry *entry,
|
|||
struct intel_vsec_device *ivdev,
|
||||
struct resource *disc_res)
|
||||
{
|
||||
struct pci_dev *pci_dev = ivdev->pcidev;
|
||||
struct pci_dev *pci_dev = to_pci_dev(ivdev->dev);
|
||||
struct device *dev = &ivdev->auxdev.dev;
|
||||
struct intel_pmt_header *header = &entry->header;
|
||||
u8 bir;
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@
|
|||
#define GET_BIR(v) ((v) & GENMASK(2, 0))
|
||||
#define GET_ADDRESS(v) ((v) & GENMASK(31, 3))
|
||||
|
||||
struct device;
|
||||
struct pci_dev;
|
||||
extern struct class intel_pmt_class;
|
||||
|
||||
struct telem_endpoint {
|
||||
struct pci_dev *pcidev;
|
||||
struct device *dev;
|
||||
struct telem_header header;
|
||||
struct pmt_callbacks *cb;
|
||||
void __iomem *base;
|
||||
|
|
@ -65,7 +66,7 @@ struct intel_pmt_namespace {
|
|||
struct intel_pmt_entry *entry);
|
||||
};
|
||||
|
||||
int pmt_telem_read_mmio(struct pci_dev *pdev, struct pmt_callbacks *cb, u32 guid, void *buf,
|
||||
int pmt_telem_read_mmio(struct device *dev, struct pmt_callbacks *cb, u32 guid, void *buf,
|
||||
void __iomem *addr, loff_t off, u32 count);
|
||||
bool intel_pmt_is_early_client_hw(struct device *dev);
|
||||
int intel_pmt_dev_create(struct intel_pmt_entry *entry,
|
||||
|
|
|
|||
|
|
@ -542,7 +542,7 @@ static int pmt_features_probe(struct auxiliary_device *auxdev, const struct auxi
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->parent = &ivdev->pcidev->dev;
|
||||
priv->parent = ivdev->dev;
|
||||
auxiliary_set_drvdata(auxdev, priv);
|
||||
|
||||
priv->dev = device_create(&intel_pmt_class, &auxdev->dev, MKDEV(0, 0), priv,
|
||||
|
|
@ -609,7 +609,7 @@ void intel_pmt_get_features(struct intel_pmt_entry *entry)
|
|||
|
||||
mutex_lock(&feature_list_lock);
|
||||
list_for_each_entry(feature, &pmt_feature_list, list) {
|
||||
if (feature->priv->parent != &entry->ep->pcidev->dev)
|
||||
if (feature->priv->parent != entry->ep->dev)
|
||||
continue;
|
||||
|
||||
pmt_get_features(entry, feature);
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ static int pmt_telem_add_endpoint(struct intel_vsec_device *ivdev,
|
|||
return -ENOMEM;
|
||||
|
||||
ep = entry->ep;
|
||||
ep->pcidev = ivdev->pcidev;
|
||||
ep->dev = ivdev->dev;
|
||||
ep->header.access_type = entry->header.access_type;
|
||||
ep->header.guid = entry->header.guid;
|
||||
ep->header.base_offset = entry->header.base_offset;
|
||||
|
|
@ -204,7 +204,7 @@ int pmt_telem_get_endpoint_info(int devid, struct telem_endpoint_info *info)
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
info->pdev = entry->ep->pcidev;
|
||||
info->dev = entry->ep->dev;
|
||||
info->header = entry->ep->header;
|
||||
|
||||
unlock:
|
||||
|
|
@ -218,9 +218,10 @@ static int pmt_copy_region(struct telemetry_region *region,
|
|||
struct intel_pmt_entry *entry)
|
||||
{
|
||||
|
||||
struct pci_dev *pdev = to_pci_dev(entry->ep->dev);
|
||||
struct oobmsm_plat_info *plat_info;
|
||||
|
||||
plat_info = intel_vsec_get_mapping(entry->ep->pcidev);
|
||||
plat_info = intel_vsec_get_mapping(pdev);
|
||||
if (IS_ERR(plat_info))
|
||||
return PTR_ERR(plat_info);
|
||||
|
||||
|
|
@ -308,7 +309,7 @@ int pmt_telem_read(struct telem_endpoint *ep, u32 id, u64 *data, u32 count)
|
|||
if (offset + NUM_BYTES_QWORD(count) > size)
|
||||
return -EINVAL;
|
||||
|
||||
pmt_telem_read_mmio(ep->pcidev, ep->cb, ep->header.guid, data, ep->base, offset,
|
||||
pmt_telem_read_mmio(ep->dev, ep->cb, ep->header.guid, data, ep->base, offset,
|
||||
NUM_BYTES_QWORD(count));
|
||||
|
||||
return ep->present ? 0 : -EPIPE;
|
||||
|
|
@ -335,7 +336,7 @@ int pmt_telem_read32(struct telem_endpoint *ep, u32 id, u32 *data, u32 count)
|
|||
EXPORT_SYMBOL_NS_GPL(pmt_telem_read32, "INTEL_PMT_TELEMETRY");
|
||||
|
||||
struct telem_endpoint *
|
||||
pmt_telem_find_and_register_endpoint(struct pci_dev *pcidev, u32 guid, u16 pos)
|
||||
pmt_telem_find_and_register_endpoint(struct device *dev, u32 guid, u16 pos)
|
||||
{
|
||||
int devid = 0;
|
||||
int inst = 0;
|
||||
|
|
@ -348,7 +349,7 @@ pmt_telem_find_and_register_endpoint(struct pci_dev *pcidev, u32 guid, u16 pos)
|
|||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
if (ep_info.header.guid == guid && ep_info.pdev == pcidev) {
|
||||
if (ep_info.header.guid == guid && ep_info.dev == dev) {
|
||||
if (inst == pos)
|
||||
return pmt_telem_register_endpoint(devid);
|
||||
++inst;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
#define PMT_TELEM_TELEMETRY 0
|
||||
#define PMT_TELEM_CRASHLOG 1
|
||||
|
||||
struct device;
|
||||
struct telem_endpoint;
|
||||
struct pci_dev;
|
||||
|
||||
struct telem_header {
|
||||
u8 access_type;
|
||||
|
|
@ -17,7 +17,7 @@ struct telem_header {
|
|||
};
|
||||
|
||||
struct telem_endpoint_info {
|
||||
struct pci_dev *pdev;
|
||||
struct device *dev;
|
||||
struct telem_header header;
|
||||
};
|
||||
|
||||
|
|
@ -71,8 +71,8 @@ int pmt_telem_get_endpoint_info(int devid, struct telem_endpoint_info *info);
|
|||
|
||||
/**
|
||||
* pmt_telem_find_and_register_endpoint() - Get a telemetry endpoint from
|
||||
* pci_dev device, guid and pos
|
||||
* @pdev: PCI device inside the Intel vsec
|
||||
* device, guid and pos
|
||||
* @dev: device inside the Intel vsec
|
||||
* @guid: GUID of the telemetry space
|
||||
* @pos: Instance of the guid
|
||||
*
|
||||
|
|
@ -80,8 +80,8 @@ int pmt_telem_get_endpoint_info(int devid, struct telem_endpoint_info *info);
|
|||
* * endpoint - On success returns pointer to the telemetry endpoint
|
||||
* * -ENXIO - telemetry endpoint not found
|
||||
*/
|
||||
struct telem_endpoint *pmt_telem_find_and_register_endpoint(struct pci_dev *pcidev,
|
||||
u32 guid, u16 pos);
|
||||
struct telem_endpoint *
|
||||
pmt_telem_find_and_register_endpoint(struct device *dev, u32 guid, u16 pos);
|
||||
|
||||
/**
|
||||
* pmt_telem_read() - Read qwords from counter sram using sample id
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
MODULE_DESCRIPTION("Intel Rapid Start Technology Driver");
|
||||
|
|
@ -99,8 +100,9 @@ static struct device_attribute irst_timeout_attr = {
|
|||
.store = irst_store_wakeup_time
|
||||
};
|
||||
|
||||
static int irst_add(struct acpi_device *acpi)
|
||||
static int irst_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *acpi = ACPI_COMPANION(&pdev->dev);
|
||||
int error;
|
||||
|
||||
error = device_create_file(&acpi->dev, &irst_timeout_attr);
|
||||
|
|
@ -114,8 +116,10 @@ static int irst_add(struct acpi_device *acpi)
|
|||
return error;
|
||||
}
|
||||
|
||||
static void irst_remove(struct acpi_device *acpi)
|
||||
static void irst_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *acpi = ACPI_COMPANION(&pdev->dev);
|
||||
|
||||
device_remove_file(&acpi->dev, &irst_wakeup_attr);
|
||||
device_remove_file(&acpi->dev, &irst_timeout_attr);
|
||||
}
|
||||
|
|
@ -125,16 +129,15 @@ static const struct acpi_device_id irst_ids[] = {
|
|||
{"", 0}
|
||||
};
|
||||
|
||||
static struct acpi_driver irst_driver = {
|
||||
.name = "intel_rapid_start",
|
||||
.class = "intel_rapid_start",
|
||||
.ids = irst_ids,
|
||||
.ops = {
|
||||
.add = irst_add,
|
||||
.remove = irst_remove,
|
||||
static struct platform_driver irst_driver = {
|
||||
.probe = irst_probe,
|
||||
.remove = irst_remove,
|
||||
.driver = {
|
||||
.name = "intel_rapid_start",
|
||||
.acpi_match_table = irst_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_acpi_driver(irst_driver);
|
||||
module_platform_driver(irst_driver);
|
||||
|
||||
MODULE_DEVICE_TABLE(acpi, irst_ids);
|
||||
|
|
|
|||
|
|
@ -599,13 +599,14 @@ static int sdsi_get_layout(struct sdsi_priv *priv, struct disc_table *table)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *parent,
|
||||
static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct device *dev,
|
||||
struct disc_table *disc_table, struct resource *disc_res)
|
||||
{
|
||||
u32 access_type = FIELD_GET(DT_ACCESS_TYPE, disc_table->access_info);
|
||||
u32 size = FIELD_GET(DT_SIZE, disc_table->access_info);
|
||||
u32 tbir = FIELD_GET(DT_TBIR, disc_table->offset);
|
||||
u32 offset = DT_OFFSET(disc_table->offset);
|
||||
struct pci_dev *parent = to_pci_dev(dev);
|
||||
struct resource res = {};
|
||||
|
||||
/* Starting location of SDSi MMIO region based on access type */
|
||||
|
|
@ -681,7 +682,7 @@ static int sdsi_probe(struct auxiliary_device *auxdev, const struct auxiliary_de
|
|||
return ret;
|
||||
|
||||
/* Map the SDSi mailbox registers */
|
||||
ret = sdsi_map_mbox_registers(priv, intel_cap_dev->pcidev, &disc_table, disc_res);
|
||||
ret = sdsi_map_mbox_registers(priv, intel_cap_dev->dev, &disc_table, disc_res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,22 +5,24 @@
|
|||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
MODULE_DESCRIPTION("Intel Smart Connect disabling driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int smartconnect_acpi_init(struct acpi_device *acpi)
|
||||
static int smartconnect_acpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
acpi_handle handle = ACPI_HANDLE(&pdev->dev);
|
||||
unsigned long long value;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_evaluate_integer(acpi->handle, "GAOS", NULL, &value);
|
||||
status = acpi_evaluate_integer(handle, "GAOS", NULL, &value);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EINVAL;
|
||||
|
||||
if (value & 0x1) {
|
||||
dev_info(&acpi->dev, "Disabling Intel Smart Connect\n");
|
||||
status = acpi_execute_simple_method(acpi->handle, "SAOS", 0);
|
||||
dev_info(&pdev->dev, "Disabling Intel Smart Connect\n");
|
||||
status = acpi_execute_simple_method(handle, "SAOS", 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -32,13 +34,12 @@ static const struct acpi_device_id smartconnect_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, smartconnect_ids);
|
||||
|
||||
static struct acpi_driver smartconnect_driver = {
|
||||
.name = "intel_smart_connect",
|
||||
.class = "intel_smart_connect",
|
||||
.ids = smartconnect_ids,
|
||||
.ops = {
|
||||
.add = smartconnect_acpi_init,
|
||||
static struct platform_driver smartconnect_driver = {
|
||||
.probe = smartconnect_acpi_probe,
|
||||
.driver = {
|
||||
.name = "intel_smart_connect",
|
||||
.acpi_match_table = smartconnect_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_acpi_driver(smartconnect_driver);
|
||||
module_platform_driver(smartconnect_driver);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@
|
|||
#include <linux/intel_vsec.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define PMT_XA_START 0
|
||||
|
|
@ -42,7 +44,7 @@ enum vsec_device_state {
|
|||
};
|
||||
|
||||
struct vsec_priv {
|
||||
struct intel_vsec_platform_info *info;
|
||||
const struct intel_vsec_platform_info *info;
|
||||
struct device *suppliers[VSEC_FEATURE_COUNT];
|
||||
struct oobmsm_plat_info plat_info;
|
||||
enum vsec_device_state state[VSEC_FEATURE_COUNT];
|
||||
|
|
@ -109,6 +111,7 @@ static void intel_vsec_dev_release(struct device *dev)
|
|||
|
||||
ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id);
|
||||
|
||||
kfree(intel_vsec_dev->acpi_disc);
|
||||
kfree(intel_vsec_dev->resource);
|
||||
kfree(intel_vsec_dev);
|
||||
}
|
||||
|
|
@ -158,18 +161,23 @@ static bool vsec_driver_present(int cap_id)
|
|||
*/
|
||||
static const struct pci_device_id intel_vsec_pci_ids[];
|
||||
|
||||
static int intel_vsec_link_devices(struct pci_dev *pdev, struct device *dev,
|
||||
static int intel_vsec_link_devices(struct device *parent, struct device *dev,
|
||||
int consumer_id)
|
||||
{
|
||||
const struct vsec_feature_dependency *deps;
|
||||
enum vsec_device_state *state;
|
||||
struct device **suppliers;
|
||||
struct vsec_priv *priv;
|
||||
struct pci_dev *pdev;
|
||||
int supplier_id;
|
||||
|
||||
if (!consumer_id)
|
||||
return 0;
|
||||
|
||||
if (!dev_is_pci(parent))
|
||||
return 0;
|
||||
|
||||
pdev = to_pci_dev(parent);
|
||||
if (!pci_match_id(intel_vsec_pci_ids, pdev))
|
||||
return 0;
|
||||
|
||||
|
|
@ -204,7 +212,7 @@ static int intel_vsec_link_devices(struct pci_dev *pdev, struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent,
|
||||
int intel_vsec_add_aux(struct device *parent,
|
||||
struct intel_vsec_device *intel_vsec_dev,
|
||||
const char *name)
|
||||
{
|
||||
|
|
@ -252,7 +260,7 @@ int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent,
|
|||
if (ret)
|
||||
goto cleanup_aux;
|
||||
|
||||
ret = intel_vsec_link_devices(pdev, &auxdev->dev, intel_vsec_dev->cap_id);
|
||||
ret = intel_vsec_link_devices(parent, &auxdev->dev, intel_vsec_dev->cap_id);
|
||||
if (ret)
|
||||
goto cleanup_aux;
|
||||
|
||||
|
|
@ -269,33 +277,32 @@ cleanup_aux:
|
|||
}
|
||||
EXPORT_SYMBOL_NS_GPL(intel_vsec_add_aux, "INTEL_VSEC");
|
||||
|
||||
static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header,
|
||||
struct intel_vsec_platform_info *info,
|
||||
unsigned long cap_id)
|
||||
static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *header,
|
||||
const struct intel_vsec_platform_info *info,
|
||||
unsigned long cap_id, u64 base_addr)
|
||||
{
|
||||
struct intel_vsec_device __free(kfree) *intel_vsec_dev = NULL;
|
||||
struct resource __free(kfree) *res = NULL;
|
||||
struct resource *tmp;
|
||||
struct device *parent;
|
||||
unsigned long quirks = info->quirks;
|
||||
u64 base_addr;
|
||||
int i;
|
||||
|
||||
if (info->parent)
|
||||
parent = info->parent;
|
||||
else
|
||||
parent = &pdev->dev;
|
||||
parent = dev;
|
||||
|
||||
if (!intel_vsec_supported(header->id, info->caps))
|
||||
return -EINVAL;
|
||||
|
||||
if (!header->num_entries) {
|
||||
dev_dbg(&pdev->dev, "Invalid 0 entry count for header id %d\n", header->id);
|
||||
dev_dbg(dev, "Invalid 0 entry count for header id %d\n", header->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!header->entry_size) {
|
||||
dev_dbg(&pdev->dev, "Invalid 0 entry size for header id %d\n", header->id);
|
||||
dev_dbg(dev, "Invalid 0 entry size for header id %d\n", header->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -310,17 +317,19 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he
|
|||
if (quirks & VSEC_QUIRK_TABLE_SHIFT)
|
||||
header->offset >>= TABLE_OFFSET_SHIFT;
|
||||
|
||||
if (info->base_addr)
|
||||
base_addr = info->base_addr;
|
||||
else
|
||||
base_addr = pdev->resource[header->tbir].start;
|
||||
|
||||
/*
|
||||
* The DVSEC/VSEC contains the starting offset and count for a block of
|
||||
* discovery tables. Create a resource array of these tables to the
|
||||
* auxiliary device driver.
|
||||
*/
|
||||
for (i = 0, tmp = res; i < header->num_entries; i++, tmp++) {
|
||||
/*
|
||||
* Skip resource mapping check for ACPI-based discovery
|
||||
* since those tables are read from _DSD, not MMIO.
|
||||
*/
|
||||
if (info->src == INTEL_VSEC_DISC_ACPI)
|
||||
break;
|
||||
|
||||
tmp->start = base_addr + header->offset + i * (header->entry_size * sizeof(u32));
|
||||
tmp->end = tmp->start + (header->entry_size * sizeof(u32)) - 1;
|
||||
tmp->flags = IORESOURCE_MEM;
|
||||
|
|
@ -332,13 +341,26 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he
|
|||
release_mem_region(tmp->start, resource_size(tmp));
|
||||
}
|
||||
|
||||
intel_vsec_dev->pcidev = pdev;
|
||||
intel_vsec_dev->dev = dev;
|
||||
intel_vsec_dev->resource = no_free_ptr(res);
|
||||
intel_vsec_dev->num_resources = header->num_entries;
|
||||
intel_vsec_dev->quirks = info->quirks;
|
||||
intel_vsec_dev->base_addr = info->base_addr;
|
||||
intel_vsec_dev->priv_data = info->priv_data;
|
||||
intel_vsec_dev->cap_id = cap_id;
|
||||
intel_vsec_dev->src = info->src;
|
||||
|
||||
if (info->src == INTEL_VSEC_DISC_ACPI) {
|
||||
size_t bytes;
|
||||
|
||||
if (check_mul_overflow(intel_vsec_dev->num_resources,
|
||||
sizeof(*info->acpi_disc), &bytes))
|
||||
return -EOVERFLOW;
|
||||
|
||||
intel_vsec_dev->acpi_disc = kmemdup(info->acpi_disc, bytes, GFP_KERNEL);
|
||||
if (!intel_vsec_dev->acpi_disc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (header->id == VSEC_ID_SDSI)
|
||||
intel_vsec_dev->ida = &intel_vsec_sdsi_ida;
|
||||
|
|
@ -349,7 +371,7 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he
|
|||
* Pass the ownership of intel_vsec_dev and resource within it to
|
||||
* intel_vsec_add_aux()
|
||||
*/
|
||||
return intel_vsec_add_aux(pdev, parent, no_free_ptr(intel_vsec_dev),
|
||||
return intel_vsec_add_aux(parent, no_free_ptr(intel_vsec_dev),
|
||||
intel_vsec_name(header->id));
|
||||
}
|
||||
|
||||
|
|
@ -410,12 +432,14 @@ static int get_cap_id(u32 header_id, unsigned long *cap_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int intel_vsec_register_device(struct pci_dev *pdev,
|
||||
static int intel_vsec_register_device(struct device *dev,
|
||||
struct intel_vsec_header *header,
|
||||
struct intel_vsec_platform_info *info)
|
||||
const struct intel_vsec_platform_info *info,
|
||||
u64 base_addr)
|
||||
{
|
||||
const struct vsec_feature_dependency *consumer_deps;
|
||||
struct vsec_priv *priv;
|
||||
struct pci_dev *pdev;
|
||||
unsigned long cap_id;
|
||||
int ret;
|
||||
|
||||
|
|
@ -427,8 +451,12 @@ static int intel_vsec_register_device(struct pci_dev *pdev,
|
|||
* Only track dependencies for devices probed by the VSEC driver.
|
||||
* For others using the exported APIs, add the device directly.
|
||||
*/
|
||||
if (!dev_is_pci(dev))
|
||||
return intel_vsec_add_dev(dev, header, info, cap_id, base_addr);
|
||||
|
||||
pdev = to_pci_dev(dev);
|
||||
if (!pci_match_id(intel_vsec_pci_ids, pdev))
|
||||
return intel_vsec_add_dev(pdev, header, info, cap_id);
|
||||
return intel_vsec_add_dev(dev, header, info, cap_id, base_addr);
|
||||
|
||||
priv = pci_get_drvdata(pdev);
|
||||
if (priv->state[cap_id] == STATE_REGISTERED ||
|
||||
|
|
@ -444,7 +472,7 @@ static int intel_vsec_register_device(struct pci_dev *pdev,
|
|||
|
||||
consumer_deps = get_consumer_dependencies(priv, cap_id);
|
||||
if (!consumer_deps || suppliers_ready(priv, consumer_deps, cap_id)) {
|
||||
ret = intel_vsec_add_dev(pdev, header, info, cap_id);
|
||||
ret = intel_vsec_add_dev(dev, header, info, cap_id, base_addr);
|
||||
if (ret)
|
||||
priv->state[cap_id] = STATE_SKIP;
|
||||
else
|
||||
|
|
@ -456,24 +484,23 @@ static int intel_vsec_register_device(struct pci_dev *pdev,
|
|||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static bool intel_vsec_walk_header(struct pci_dev *pdev,
|
||||
struct intel_vsec_platform_info *info)
|
||||
static int intel_vsec_walk_header(struct device *dev,
|
||||
const struct intel_vsec_platform_info *info)
|
||||
{
|
||||
struct intel_vsec_header **header = info->headers;
|
||||
bool have_devices = false;
|
||||
int ret;
|
||||
|
||||
for ( ; *header; header++) {
|
||||
ret = intel_vsec_register_device(pdev, *header, info);
|
||||
if (!ret)
|
||||
have_devices = true;
|
||||
ret = intel_vsec_register_device(dev, *header, info, info->base_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return have_devices;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool intel_vsec_walk_dvsec(struct pci_dev *pdev,
|
||||
struct intel_vsec_platform_info *info)
|
||||
const struct intel_vsec_platform_info *info)
|
||||
{
|
||||
bool have_devices = false;
|
||||
int pos = 0;
|
||||
|
|
@ -512,7 +539,8 @@ static bool intel_vsec_walk_dvsec(struct pci_dev *pdev,
|
|||
pci_read_config_dword(pdev, pos + PCI_DVSEC_HEADER2, &hdr);
|
||||
header.id = PCI_DVSEC_HEADER2_ID(hdr);
|
||||
|
||||
ret = intel_vsec_register_device(pdev, &header, info);
|
||||
ret = intel_vsec_register_device(&pdev->dev, &header, info,
|
||||
pci_resource_start(pdev, header.tbir));
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
|
|
@ -523,7 +551,7 @@ static bool intel_vsec_walk_dvsec(struct pci_dev *pdev,
|
|||
}
|
||||
|
||||
static bool intel_vsec_walk_vsec(struct pci_dev *pdev,
|
||||
struct intel_vsec_platform_info *info)
|
||||
const struct intel_vsec_platform_info *info)
|
||||
{
|
||||
bool have_devices = false;
|
||||
int pos = 0;
|
||||
|
|
@ -557,7 +585,8 @@ static bool intel_vsec_walk_vsec(struct pci_dev *pdev,
|
|||
header.tbir = INTEL_DVSEC_TABLE_BAR(table);
|
||||
header.offset = INTEL_DVSEC_TABLE_OFFSET(table);
|
||||
|
||||
ret = intel_vsec_register_device(pdev, &header, info);
|
||||
ret = intel_vsec_register_device(&pdev->dev, &header, info,
|
||||
pci_resource_start(pdev, header.tbir));
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
|
|
@ -567,21 +596,18 @@ static bool intel_vsec_walk_vsec(struct pci_dev *pdev,
|
|||
return have_devices;
|
||||
}
|
||||
|
||||
int intel_vsec_register(struct pci_dev *pdev,
|
||||
struct intel_vsec_platform_info *info)
|
||||
int intel_vsec_register(struct device *dev,
|
||||
const struct intel_vsec_platform_info *info)
|
||||
{
|
||||
if (!pdev || !info || !info->headers)
|
||||
if (!dev || !info || !info->headers)
|
||||
return -EINVAL;
|
||||
|
||||
if (!intel_vsec_walk_header(pdev, info))
|
||||
return -ENODEV;
|
||||
else
|
||||
return 0;
|
||||
return intel_vsec_walk_header(dev, info);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(intel_vsec_register, "INTEL_VSEC");
|
||||
|
||||
static bool intel_vsec_get_features(struct pci_dev *pdev,
|
||||
struct intel_vsec_platform_info *info)
|
||||
const struct intel_vsec_platform_info *info)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
|
|
@ -599,7 +625,7 @@ static bool intel_vsec_get_features(struct pci_dev *pdev,
|
|||
found = true;
|
||||
|
||||
if (info && (info->quirks & VSEC_QUIRK_NO_DVSEC) &&
|
||||
intel_vsec_walk_header(pdev, info))
|
||||
intel_vsec_walk_header(&pdev->dev, info))
|
||||
found = true;
|
||||
|
||||
return found;
|
||||
|
|
@ -625,7 +651,7 @@ static void intel_vsec_skip_missing_dependencies(struct pci_dev *pdev)
|
|||
|
||||
static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct intel_vsec_platform_info *info;
|
||||
const struct intel_vsec_platform_info *info;
|
||||
struct vsec_priv *priv;
|
||||
int num_caps, ret;
|
||||
int run_once = 0;
|
||||
|
|
@ -636,7 +662,7 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id
|
|||
return ret;
|
||||
|
||||
pci_save_state(pdev);
|
||||
info = (struct intel_vsec_platform_info *)id->driver_data;
|
||||
info = (const struct intel_vsec_platform_info *)id->driver_data;
|
||||
if (!info)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -671,7 +697,10 @@ int intel_vsec_set_mapping(struct oobmsm_plat_info *plat_info,
|
|||
{
|
||||
struct vsec_priv *priv;
|
||||
|
||||
priv = pci_get_drvdata(vsec_dev->pcidev);
|
||||
if (!dev_is_pci(vsec_dev->dev))
|
||||
return -ENODEV;
|
||||
|
||||
priv = pci_get_drvdata(to_pci_dev(vsec_dev->dev));
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -819,7 +848,7 @@ static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev)
|
|||
|
||||
xa_for_each(&auxdev_array, index, intel_vsec_dev) {
|
||||
/* check if pdev doesn't match */
|
||||
if (pdev != intel_vsec_dev->pcidev)
|
||||
if (&pdev->dev != intel_vsec_dev->dev)
|
||||
continue;
|
||||
devm_release_action(&pdev->dev, intel_vsec_remove_aux,
|
||||
&intel_vsec_dev->auxdev);
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
* provided by the Intel VSEC driver.
|
||||
*/
|
||||
|
||||
#include <linux/align.h>
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
|
@ -479,6 +480,9 @@ static ssize_t mem_write(struct file *file, const char __user *userbuf, size_t l
|
|||
addr = array[2];
|
||||
value = array[3];
|
||||
|
||||
if (!IS_ALIGNED(addr, sizeof(u32)))
|
||||
return -EINVAL;
|
||||
|
||||
if (punit >= pfs->pfs_header.num_entries) {
|
||||
ret = -EINVAL;
|
||||
goto exit_write;
|
||||
|
|
@ -530,7 +534,7 @@ static const struct file_operations mem_write_ops = {
|
|||
.release = single_release,
|
||||
};
|
||||
|
||||
#define tpmi_to_dev(info) (&info->vsec_dev->pcidev->dev)
|
||||
#define tpmi_to_dev(info) ((info)->vsec_dev->dev)
|
||||
|
||||
static void tpmi_dbgfs_register(struct intel_tpmi_info *tpmi_info)
|
||||
{
|
||||
|
|
@ -642,7 +646,7 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info,
|
|||
tmp->flags = IORESOURCE_MEM;
|
||||
}
|
||||
|
||||
feature_vsec_dev->pcidev = vsec_dev->pcidev;
|
||||
feature_vsec_dev->dev = vsec_dev->dev;
|
||||
feature_vsec_dev->resource = res;
|
||||
feature_vsec_dev->num_resources = pfs->pfs_header.num_entries;
|
||||
feature_vsec_dev->priv_data = &tpmi_info->plat_info;
|
||||
|
|
@ -655,7 +659,7 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info,
|
|||
* feature_vsec_dev and res memory are also freed as part of
|
||||
* device deletion.
|
||||
*/
|
||||
return intel_vsec_add_aux(vsec_dev->pcidev, &vsec_dev->auxdev.dev,
|
||||
return intel_vsec_add_aux(&vsec_dev->auxdev.dev,
|
||||
feature_vsec_dev, feature_id_name);
|
||||
}
|
||||
|
||||
|
|
@ -742,7 +746,7 @@ static int tpmi_fetch_pfs_header(struct intel_tpmi_pm_feature *pfs, u64 start, i
|
|||
static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev)
|
||||
{
|
||||
struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev);
|
||||
struct pci_dev *pci_dev = vsec_dev->pcidev;
|
||||
struct pci_dev *pci_dev = to_pci_dev(vsec_dev->dev);
|
||||
struct intel_tpmi_info *tpmi_info;
|
||||
u64 pfs_start = 0;
|
||||
int ret, i;
|
||||
|
|
|
|||
|
|
@ -28,15 +28,10 @@ static int get_fwu_request(struct device *dev, u32 *out)
|
|||
__le32 *result;
|
||||
int ret;
|
||||
|
||||
ret = wmidev_query_block(to_wmi_device(dev), 0, &buffer);
|
||||
ret = wmidev_query_block(to_wmi_device(dev), 0, &buffer, sizeof(*result));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (buffer.length < sizeof(*result)) {
|
||||
kfree(buffer.data);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
result = buffer.data;
|
||||
*out = le32_to_cpu(*result);
|
||||
kfree(result);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ static ssize_t force_power_store(struct device *dev,
|
|||
if (mode > 1)
|
||||
return -EINVAL;
|
||||
|
||||
ret = wmidev_invoke_method(to_wmi_device(dev), 0, 1, &buffer, NULL);
|
||||
ret = wmidev_invoke_procedure(to_wmi_device(dev), 0, 1, &buffer);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -2340,6 +2340,7 @@ static struct wmi_driver ideapad_wmi_driver = {
|
|||
.name = "ideapad_wmi",
|
||||
},
|
||||
.id_table = ideapad_wmi_ids,
|
||||
.min_event_size = sizeof(u32),
|
||||
.probe = ideapad_wmi_probe,
|
||||
.notify = ideapad_wmi_notify,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -299,7 +299,6 @@ struct ibm_struct;
|
|||
|
||||
struct tp_acpi_drv_struct {
|
||||
const struct acpi_device_id *hid;
|
||||
struct acpi_driver *driver;
|
||||
|
||||
void (*notify) (struct ibm_struct *, u32);
|
||||
acpi_handle *handle;
|
||||
|
|
@ -322,7 +321,6 @@ struct ibm_struct {
|
|||
struct tp_acpi_drv_struct *acpi;
|
||||
|
||||
struct {
|
||||
u8 acpi_driver_registered:1;
|
||||
u8 acpi_notify_installed:1;
|
||||
u8 proc_created:1;
|
||||
u8 init_called:1;
|
||||
|
|
@ -374,7 +372,7 @@ static struct {
|
|||
u32 hotkey_poll_active:1;
|
||||
u32 has_adaptive_kbd:1;
|
||||
u32 kbd_lang:1;
|
||||
u32 trackpoint_doubletap:1;
|
||||
u32 trackpoint_doubletap_enable:1;
|
||||
struct quirk_entry *quirks;
|
||||
} tp_features;
|
||||
|
||||
|
|
@ -832,9 +830,9 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
|
|||
vdbg_printk(TPACPI_DBG_INIT,
|
||||
"setting up ACPI notify for %s\n", ibm->name);
|
||||
|
||||
ibm->acpi->device = acpi_fetch_acpi_dev(*ibm->acpi->handle);
|
||||
ibm->acpi->device = acpi_get_acpi_dev(*ibm->acpi->handle);
|
||||
if (!ibm->acpi->device) {
|
||||
pr_err("acpi_fetch_acpi_dev(%s) failed\n", ibm->name);
|
||||
pr_err("acpi_get_acpi_dev(%s) failed\n", ibm->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -859,44 +857,6 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init tpacpi_device_add(struct acpi_device *device)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
|
||||
{
|
||||
int rc;
|
||||
|
||||
dbg_printk(TPACPI_DBG_INIT,
|
||||
"registering %s as an ACPI driver\n", ibm->name);
|
||||
|
||||
BUG_ON(!ibm->acpi);
|
||||
|
||||
ibm->acpi->driver = kzalloc_obj(struct acpi_driver);
|
||||
if (!ibm->acpi->driver) {
|
||||
pr_err("failed to allocate memory for ibm->acpi->driver\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sprintf(ibm->acpi->driver->name, "%s_%s", TPACPI_NAME, ibm->name);
|
||||
ibm->acpi->driver->ids = ibm->acpi->hid;
|
||||
|
||||
ibm->acpi->driver->ops.add = &tpacpi_device_add;
|
||||
|
||||
rc = acpi_bus_register_driver(ibm->acpi->driver);
|
||||
if (rc < 0) {
|
||||
pr_err("acpi_bus_register_driver(%s) failed: %d\n",
|
||||
ibm->name, rc);
|
||||
kfree(ibm->acpi->driver);
|
||||
ibm->acpi->driver = NULL;
|
||||
} else if (!rc)
|
||||
ibm->flags.acpi_driver_registered = 1;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
****************************************************************************
|
||||
*
|
||||
|
|
@ -1315,7 +1275,7 @@ static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id,
|
|||
static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, struct seq_file *m)
|
||||
{
|
||||
if (id >= TPACPI_RFK_SW_MAX)
|
||||
seq_printf(m, "status:\t\tnot supported\n");
|
||||
seq_puts(m, "status:\t\tnot supported\n");
|
||||
else {
|
||||
int status;
|
||||
|
||||
|
|
@ -1330,7 +1290,7 @@ static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, struct seq_file *
|
|||
}
|
||||
|
||||
seq_printf(m, "status:\t\t%s\n", str_enabled_disabled(status == TPACPI_RFK_RADIO_ON));
|
||||
seq_printf(m, "commands:\tenable, disable\n");
|
||||
seq_puts(m, "commands:\tenable, disable\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -3019,6 +2979,31 @@ static const struct attribute_group adaptive_kbd_attr_group = {
|
|||
.attrs = adaptive_kbd_attributes,
|
||||
};
|
||||
|
||||
/* sysfs doubletap enable --------------------------------------------- */
|
||||
static ssize_t doubletap_enable_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%d\n", tp_features.trackpoint_doubletap_enable);
|
||||
}
|
||||
|
||||
static ssize_t doubletap_enable_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
bool enable;
|
||||
int err;
|
||||
|
||||
err = kstrtobool(buf, &enable);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
tp_features.trackpoint_doubletap_enable = enable;
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(doubletap_enable);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static struct attribute *hotkey_attributes[] = {
|
||||
|
|
@ -3033,6 +3018,7 @@ static struct attribute *hotkey_attributes[] = {
|
|||
&dev_attr_hotkey_recommended_mask.attr,
|
||||
&dev_attr_hotkey_tablet_mode.attr,
|
||||
&dev_attr_hotkey_radio_sw.attr,
|
||||
&dev_attr_doubletap_enable.attr,
|
||||
#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
|
||||
&dev_attr_hotkey_source_mask.attr,
|
||||
&dev_attr_hotkey_poll_freq.attr,
|
||||
|
|
@ -3558,8 +3544,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
|
||||
hotkey_poll_setup_safe(true);
|
||||
|
||||
/* Enable doubletap by default */
|
||||
tp_features.trackpoint_doubletap = 1;
|
||||
/* Enable TrackPoint doubletap event reporting by default. */
|
||||
tp_features.trackpoint_doubletap_enable = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3864,9 +3850,9 @@ static bool hotkey_notify_8xxx(const u32 hkey, bool *send_acpi_ev)
|
|||
{
|
||||
switch (hkey) {
|
||||
case TP_HKEY_EV_TRACK_DOUBLETAP:
|
||||
if (tp_features.trackpoint_doubletap)
|
||||
tpacpi_input_send_key(hkey, send_acpi_ev);
|
||||
|
||||
/* Only send event if doubletap is enabled */
|
||||
if (!tp_features.trackpoint_doubletap_enable)
|
||||
*send_acpi_ev = false;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -4017,7 +4003,7 @@ static int hotkey_read(struct seq_file *m)
|
|||
int res, status;
|
||||
|
||||
if (!tp_features.hotkey) {
|
||||
seq_printf(m, "status:\t\tnot supported\n");
|
||||
seq_puts(m, "status:\t\tnot supported\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4033,10 +4019,10 @@ static int hotkey_read(struct seq_file *m)
|
|||
seq_printf(m, "status:\t\t%s\n", str_enabled_disabled(status & BIT(0)));
|
||||
if (hotkey_all_mask) {
|
||||
seq_printf(m, "mask:\t\t0x%08x\n", hotkey_user_mask);
|
||||
seq_printf(m, "commands:\tenable, disable, reset, <mask>\n");
|
||||
seq_puts(m, "commands:\tenable, disable, reset, <mask>\n");
|
||||
} else {
|
||||
seq_printf(m, "mask:\t\tnot supported\n");
|
||||
seq_printf(m, "commands:\tenable, disable, reset\n");
|
||||
seq_puts(m, "mask:\t\tnot supported\n");
|
||||
seq_puts(m, "commands:\tenable, disable, reset\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -4933,7 +4919,7 @@ static int video_read(struct seq_file *m)
|
|||
int status, autosw;
|
||||
|
||||
if (video_supported == TPACPI_VIDEO_NONE) {
|
||||
seq_printf(m, "status:\t\tnot supported\n");
|
||||
seq_puts(m, "status:\t\tnot supported\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4949,18 +4935,18 @@ static int video_read(struct seq_file *m)
|
|||
if (autosw < 0)
|
||||
return autosw;
|
||||
|
||||
seq_printf(m, "status:\t\tsupported\n");
|
||||
seq_puts(m, "status:\t\tsupported\n");
|
||||
seq_printf(m, "lcd:\t\t%s\n", str_enabled_disabled(status & BIT(0)));
|
||||
seq_printf(m, "crt:\t\t%s\n", str_enabled_disabled(status & BIT(1)));
|
||||
if (video_supported == TPACPI_VIDEO_NEW)
|
||||
seq_printf(m, "dvi:\t\t%s\n", str_enabled_disabled(status & BIT(3)));
|
||||
seq_printf(m, "auto:\t\t%s\n", str_enabled_disabled(autosw & BIT(0)));
|
||||
seq_printf(m, "commands:\tlcd_enable, lcd_disable\n");
|
||||
seq_printf(m, "commands:\tcrt_enable, crt_disable\n");
|
||||
seq_puts(m, "commands:\tlcd_enable, lcd_disable\n");
|
||||
seq_puts(m, "commands:\tcrt_enable, crt_disable\n");
|
||||
if (video_supported == TPACPI_VIDEO_NEW)
|
||||
seq_printf(m, "commands:\tdvi_enable, dvi_disable\n");
|
||||
seq_printf(m, "commands:\tauto_enable, auto_disable\n");
|
||||
seq_printf(m, "commands:\tvideo_switch, expand_toggle\n");
|
||||
seq_puts(m, "commands:\tdvi_enable, dvi_disable\n");
|
||||
seq_puts(m, "commands:\tauto_enable, auto_disable\n");
|
||||
seq_puts(m, "commands:\tvideo_switch, expand_toggle\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -5204,14 +5190,14 @@ static int kbdlight_read(struct seq_file *m)
|
|||
int level;
|
||||
|
||||
if (!tp_features.kbdlight) {
|
||||
seq_printf(m, "status:\t\tnot supported\n");
|
||||
seq_puts(m, "status:\t\tnot supported\n");
|
||||
} else {
|
||||
level = kbdlight_get_level();
|
||||
if (level < 0)
|
||||
seq_printf(m, "status:\t\terror %d\n", level);
|
||||
else
|
||||
seq_printf(m, "status:\t\t%d\n", level);
|
||||
seq_printf(m, "commands:\t0, 1, 2\n");
|
||||
seq_puts(m, "commands:\t0, 1, 2\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -5378,16 +5364,16 @@ static int light_read(struct seq_file *m)
|
|||
int status;
|
||||
|
||||
if (!tp_features.light) {
|
||||
seq_printf(m, "status:\t\tnot supported\n");
|
||||
seq_puts(m, "status:\t\tnot supported\n");
|
||||
} else if (!tp_features.light_status) {
|
||||
seq_printf(m, "status:\t\tunknown\n");
|
||||
seq_printf(m, "commands:\ton, off\n");
|
||||
seq_puts(m, "status:\t\tunknown\n");
|
||||
seq_puts(m, "commands:\ton, off\n");
|
||||
} else {
|
||||
status = light_get_status();
|
||||
if (status < 0)
|
||||
return status;
|
||||
seq_printf(m, "status:\t\t%s\n", str_on_off(status & BIT(0)));
|
||||
seq_printf(m, "commands:\ton, off\n");
|
||||
seq_puts(m, "commands:\ton, off\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -5477,10 +5463,10 @@ static int cmos_read(struct seq_file *m)
|
|||
/* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
|
||||
R30, R31, T20-22, X20-21 */
|
||||
if (!cmos_handle)
|
||||
seq_printf(m, "status:\t\tnot supported\n");
|
||||
seq_puts(m, "status:\t\tnot supported\n");
|
||||
else {
|
||||
seq_printf(m, "status:\t\tsupported\n");
|
||||
seq_printf(m, "commands:\t<cmd> (<cmd> is 0-21)\n");
|
||||
seq_puts(m, "status:\t\tsupported\n");
|
||||
seq_puts(m, "commands:\t<cmd> (<cmd> is 0-21)\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -5846,10 +5832,10 @@ static int __init led_init(struct ibm_init_struct *iibm)
|
|||
static int led_read(struct seq_file *m)
|
||||
{
|
||||
if (!led_supported) {
|
||||
seq_printf(m, "status:\t\tnot supported\n");
|
||||
seq_puts(m, "status:\t\tnot supported\n");
|
||||
return 0;
|
||||
}
|
||||
seq_printf(m, "status:\t\tsupported\n");
|
||||
seq_puts(m, "status:\t\tsupported\n");
|
||||
|
||||
if (led_supported == TPACPI_LED_570) {
|
||||
/* 570 */
|
||||
|
|
@ -5862,7 +5848,7 @@ static int led_read(struct seq_file *m)
|
|||
}
|
||||
}
|
||||
|
||||
seq_printf(m, "commands:\t<led> on, <led> off, <led> blink (<led> is 0-15)\n");
|
||||
seq_puts(m, "commands:\t<led> on, <led> off, <led> blink (<led> is 0-15)\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -5946,10 +5932,10 @@ static int __init beep_init(struct ibm_init_struct *iibm)
|
|||
static int beep_read(struct seq_file *m)
|
||||
{
|
||||
if (!beep_handle)
|
||||
seq_printf(m, "status:\t\tnot supported\n");
|
||||
seq_puts(m, "status:\t\tnot supported\n");
|
||||
else {
|
||||
seq_printf(m, "status:\t\tsupported\n");
|
||||
seq_printf(m, "commands:\t<cmd> (<cmd> is 0-17)\n");
|
||||
seq_puts(m, "status:\t\tsupported\n");
|
||||
seq_puts(m, "commands:\t<cmd> (<cmd> is 0-17)\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -6398,14 +6384,14 @@ static int thermal_read(struct seq_file *m)
|
|||
if (unlikely(n < 0))
|
||||
return n;
|
||||
|
||||
seq_printf(m, "temperatures:\t");
|
||||
seq_puts(m, "temperatures:\t");
|
||||
|
||||
if (n > 0) {
|
||||
for (i = 0; i < (n - 1); i++)
|
||||
seq_printf(m, "%d ", t.temp[i] / 1000);
|
||||
seq_printf(m, "%d\n", t.temp[i] / 1000);
|
||||
} else
|
||||
seq_printf(m, "not supported\n");
|
||||
seq_puts(m, "not supported\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -6918,10 +6904,10 @@ static int brightness_read(struct seq_file *m)
|
|||
|
||||
level = brightness_get(NULL);
|
||||
if (level < 0) {
|
||||
seq_printf(m, "level:\t\tunreadable\n");
|
||||
seq_puts(m, "level:\t\tunreadable\n");
|
||||
} else {
|
||||
seq_printf(m, "level:\t\t%d\n", level);
|
||||
seq_printf(m, "commands:\tup, down\n");
|
||||
seq_puts(m, "commands:\tup, down\n");
|
||||
seq_printf(m, "commands:\tlevel <level> (<level> is 0-%d)\n",
|
||||
bright_maxlvl);
|
||||
}
|
||||
|
|
@ -7637,10 +7623,10 @@ static int volume_read(struct seq_file *m)
|
|||
u8 status;
|
||||
|
||||
if (volume_get_status(&status) < 0) {
|
||||
seq_printf(m, "level:\t\tunreadable\n");
|
||||
seq_puts(m, "level:\t\tunreadable\n");
|
||||
} else {
|
||||
if (tp_features.mixer_no_level_control)
|
||||
seq_printf(m, "level:\t\tunsupported\n");
|
||||
seq_puts(m, "level:\t\tunsupported\n");
|
||||
else
|
||||
seq_printf(m, "level:\t\t%d\n",
|
||||
status & TP_EC_AUDIO_LVL_MSK);
|
||||
|
|
@ -7648,9 +7634,9 @@ static int volume_read(struct seq_file *m)
|
|||
seq_printf(m, "mute:\t\t%s\n", str_on_off(status & BIT(TP_EC_AUDIO_MUTESW)));
|
||||
|
||||
if (volume_control_allowed) {
|
||||
seq_printf(m, "commands:\tunmute, mute\n");
|
||||
seq_puts(m, "commands:\tunmute, mute\n");
|
||||
if (!tp_features.mixer_no_level_control) {
|
||||
seq_printf(m, "commands:\tup, down\n");
|
||||
seq_puts(m, "commands:\tup, down\n");
|
||||
seq_printf(m, "commands:\tlevel <level> (<level> is 0-%d)\n",
|
||||
TP_EC_VOLUME_MAX);
|
||||
}
|
||||
|
|
@ -9156,9 +9142,9 @@ static int fan_read(struct seq_file *m)
|
|||
} else if (fan_status_access_mode == TPACPI_FAN_RD_TPEC) {
|
||||
if (status & TP_EC_FAN_FULLSPEED)
|
||||
/* Disengaged mode takes precedence */
|
||||
seq_printf(m, "level:\t\tdisengaged\n");
|
||||
seq_puts(m, "level:\t\tdisengaged\n");
|
||||
else if (status & TP_EC_FAN_AUTO)
|
||||
seq_printf(m, "level:\t\tauto\n");
|
||||
seq_puts(m, "level:\t\tauto\n");
|
||||
else
|
||||
seq_printf(m, "level:\t\t%d\n", status);
|
||||
}
|
||||
|
|
@ -9166,19 +9152,19 @@ static int fan_read(struct seq_file *m)
|
|||
|
||||
case TPACPI_FAN_NONE:
|
||||
default:
|
||||
seq_printf(m, "status:\t\tnot supported\n");
|
||||
seq_puts(m, "status:\t\tnot supported\n");
|
||||
}
|
||||
|
||||
if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) {
|
||||
seq_printf(m, "commands:\tlevel <level>");
|
||||
seq_puts(m, "commands:\tlevel <level>");
|
||||
|
||||
switch (fan_control_access_mode) {
|
||||
case TPACPI_FAN_WR_ACPI_SFAN:
|
||||
seq_printf(m, " (<level> is 0-7)\n");
|
||||
seq_puts(m, " (<level> is 0-7)\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
seq_printf(m, " (<level> is 0-7, auto, disengaged, full-speed)\n");
|
||||
seq_puts(m, " (<level> is 0-7, auto, disengaged, full-speed)\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -9188,7 +9174,7 @@ static int fan_read(struct seq_file *m)
|
|||
"commands:\twatchdog <timeout> (<timeout> is 0 (off), 1-120 (seconds))\n");
|
||||
|
||||
if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
|
||||
seq_printf(m, "commands:\tspeed <speed> (<speed> is 0-65535)\n");
|
||||
seq_puts(m, "commands:\tspeed <speed> (<speed> is 0-65535)\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -9249,9 +9235,6 @@ static int fan_write_cmd_speed(const char *cmd, int *rc)
|
|||
{
|
||||
int speed;
|
||||
|
||||
/* TODO:
|
||||
* Support speed <low> <medium> <high> ? */
|
||||
|
||||
if (sscanf(cmd, "speed %d", &speed) != 1)
|
||||
return 0;
|
||||
|
||||
|
|
@ -11488,7 +11471,9 @@ static bool tpacpi_driver_event(const unsigned int hkey_event)
|
|||
mutex_unlock(&tpacpi_inputdev_send_mutex);
|
||||
return true;
|
||||
case TP_HKEY_EV_DOUBLETAP_TOGGLE:
|
||||
tp_features.trackpoint_doubletap = !tp_features.trackpoint_doubletap;
|
||||
/* Toggle kernel-level doubletap event filtering */
|
||||
tp_features.trackpoint_doubletap_enable =
|
||||
!tp_features.trackpoint_doubletap_enable;
|
||||
return true;
|
||||
case TP_HKEY_EV_PROFILE_TOGGLE:
|
||||
case TP_HKEY_EV_PROFILE_TOGGLE2:
|
||||
|
|
@ -11532,6 +11517,8 @@ static void ibm_exit(struct ibm_struct *ibm)
|
|||
acpi_remove_notify_handler(*ibm->acpi->handle,
|
||||
ibm->acpi->type,
|
||||
dispatch_acpi_notify);
|
||||
ibm->acpi->device->driver_data = NULL;
|
||||
acpi_dev_put(ibm->acpi->device);
|
||||
ibm->flags.acpi_notify_installed = 0;
|
||||
}
|
||||
|
||||
|
|
@ -11542,16 +11529,6 @@ static void ibm_exit(struct ibm_struct *ibm)
|
|||
ibm->flags.proc_created = 0;
|
||||
}
|
||||
|
||||
if (ibm->flags.acpi_driver_registered) {
|
||||
dbg_printk(TPACPI_DBG_EXIT,
|
||||
"%s: acpi_bus_unregister_driver\n", ibm->name);
|
||||
BUG_ON(!ibm->acpi);
|
||||
acpi_bus_unregister_driver(ibm->acpi->driver);
|
||||
kfree(ibm->acpi->driver);
|
||||
ibm->acpi->driver = NULL;
|
||||
ibm->flags.acpi_driver_registered = 0;
|
||||
}
|
||||
|
||||
if (ibm->flags.init_called && ibm->exit) {
|
||||
ibm->exit();
|
||||
ibm->flags.init_called = 0;
|
||||
|
|
@ -11587,12 +11564,6 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
|
|||
}
|
||||
|
||||
if (ibm->acpi) {
|
||||
if (ibm->acpi->hid) {
|
||||
ret = register_tpacpi_subdriver(ibm);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (ibm->acpi->notify) {
|
||||
ret = setup_acpi_notify(ibm);
|
||||
if (ret == -ENODEV) {
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ static struct wmi_driver lenovo_wmi_driver = {
|
|||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.id_table = lenovo_wmi_id_table,
|
||||
.min_event_size = sizeof(u8),
|
||||
.no_singleton = true,
|
||||
.probe = lenovo_wmi_probe,
|
||||
.notify = lenovo_wmi_notify,
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ static struct wmi_driver lwmi_events_driver = {
|
|||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.id_table = lwmi_events_id_table,
|
||||
.min_event_size = sizeof(u32),
|
||||
.probe = lwmi_events_probe,
|
||||
.notify = lwmi_events_notify,
|
||||
.no_singleton = true,
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ static struct wmi_driver lenovo_ymc_driver = {
|
|||
.name = "lenovo-ymc",
|
||||
},
|
||||
.id_table = lenovo_ymc_wmi_id_table,
|
||||
.min_event_size = sizeof(u32),
|
||||
.probe = lenovo_ymc_probe,
|
||||
.notify = lenovo_ymc_notify,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -411,8 +411,8 @@ static struct wmi_driver yogabook_wmi_driver = {
|
|||
.name = "yogabook-wmi",
|
||||
.pm = pm_sleep_ptr(&yogabook_pm_ops),
|
||||
},
|
||||
.no_notify_data = true,
|
||||
.id_table = yogabook_wmi_id_table,
|
||||
.min_event_size = 0,
|
||||
.probe = yogabook_wmi_probe,
|
||||
.remove = yogabook_wmi_remove,
|
||||
.notify = yogabook_wmi_notify,
|
||||
|
|
|
|||
|
|
@ -271,11 +271,6 @@ static void wmi_input_setup(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void acpi_notify(struct acpi_device *device, u32 event)
|
||||
{
|
||||
acpi_handle_debug(device->handle, "notify: %d\n", event);
|
||||
}
|
||||
|
||||
static ssize_t fan_mode_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buffer, size_t count)
|
||||
|
|
@ -764,8 +759,9 @@ static void lg_laptop_remove_address_space_handler(void *data)
|
|||
&lg_laptop_address_space_handler);
|
||||
}
|
||||
|
||||
static int acpi_add(struct acpi_device *device)
|
||||
static int acpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct platform_device_info pdev_info = {
|
||||
.fwnode = acpi_fwnode_handle(device),
|
||||
.name = PLATFORM_NAME,
|
||||
|
|
@ -781,11 +777,11 @@ static int acpi_add(struct acpi_device *device)
|
|||
|
||||
status = acpi_install_address_space_handler(device->handle, LG_ADDRESS_SPACE_ID,
|
||||
&lg_laptop_address_space_handler,
|
||||
NULL, &device->dev);
|
||||
NULL, &pdev->dev);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
ret = devm_add_action_or_reset(&device->dev, lg_laptop_remove_address_space_handler,
|
||||
ret = devm_add_action_or_reset(&pdev->dev, lg_laptop_remove_address_space_handler,
|
||||
device);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -879,7 +875,7 @@ out_platform_registered:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void acpi_remove(struct acpi_device *device)
|
||||
static void acpi_remove(struct platform_device *pdev)
|
||||
{
|
||||
sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group);
|
||||
|
||||
|
|
@ -899,34 +895,13 @@ static const struct acpi_device_id device_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, device_ids);
|
||||
|
||||
static struct acpi_driver acpi_driver = {
|
||||
.name = "LG Gram Laptop Support",
|
||||
.class = "lg-laptop",
|
||||
.ids = device_ids,
|
||||
.ops = {
|
||||
.add = acpi_add,
|
||||
.remove = acpi_remove,
|
||||
.notify = acpi_notify,
|
||||
},
|
||||
static struct platform_driver acpi_driver = {
|
||||
.probe = acpi_probe,
|
||||
.remove = acpi_remove,
|
||||
.driver = {
|
||||
.name = "LG Gram Laptop Support",
|
||||
.acpi_match_table = device_ids,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init acpi_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = acpi_bus_register_driver(&acpi_driver);
|
||||
if (result < 0) {
|
||||
pr_debug("Error registering driver\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit acpi_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&acpi_driver);
|
||||
}
|
||||
|
||||
module_init(acpi_init);
|
||||
module_exit(acpi_exit);
|
||||
module_platform_driver(acpi_driver);
|
||||
|
|
|
|||
|
|
@ -80,15 +80,3 @@ bool mxm_wmi_supported(void)
|
|||
return guid_valid;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mxm_wmi_supported);
|
||||
|
||||
static int __init mxm_wmi_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit mxm_wmi_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(mxm_wmi_init);
|
||||
module_exit(mxm_wmi_exit);
|
||||
|
|
|
|||
|
|
@ -183,9 +183,9 @@ enum SINF_BITS { SINF_NUM_BATTERIES = 0,
|
|||
};
|
||||
/* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
|
||||
|
||||
static int acpi_pcc_hotkey_add(struct acpi_device *device);
|
||||
static void acpi_pcc_hotkey_remove(struct acpi_device *device);
|
||||
static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event);
|
||||
static int acpi_pcc_hotkey_probe(struct platform_device *pdev);
|
||||
static void acpi_pcc_hotkey_remove(struct platform_device *pdev);
|
||||
static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data);
|
||||
|
||||
static const struct acpi_device_id pcc_device_ids[] = {
|
||||
{ "MAT0012", 0},
|
||||
|
|
@ -201,16 +201,14 @@ static int acpi_pcc_hotkey_resume(struct device *dev);
|
|||
#endif
|
||||
static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume);
|
||||
|
||||
static struct acpi_driver acpi_pcc_driver = {
|
||||
.name = ACPI_PCC_DRIVER_NAME,
|
||||
.class = ACPI_PCC_CLASS,
|
||||
.ids = pcc_device_ids,
|
||||
.ops = {
|
||||
.add = acpi_pcc_hotkey_add,
|
||||
.remove = acpi_pcc_hotkey_remove,
|
||||
.notify = acpi_pcc_hotkey_notify,
|
||||
},
|
||||
.drv.pm = &acpi_pcc_hotkey_pm,
|
||||
static struct platform_driver acpi_pcc_driver = {
|
||||
.probe = acpi_pcc_hotkey_probe,
|
||||
.remove = acpi_pcc_hotkey_remove,
|
||||
.driver = {
|
||||
.name = ACPI_PCC_DRIVER_NAME,
|
||||
.acpi_match_table = pcc_device_ids,
|
||||
.pm = &acpi_pcc_hotkey_pm,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct key_entry panasonic_keymap[] = {
|
||||
|
|
@ -869,9 +867,9 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
|
|||
pr_err("Unknown hotkey event: 0x%04llx\n", result);
|
||||
}
|
||||
|
||||
static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
|
||||
static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct pcc_acpi *pcc = acpi_driver_data(device);
|
||||
struct pcc_acpi *pcc = data;
|
||||
|
||||
switch (event) {
|
||||
case HKEY_NOTIFY:
|
||||
|
|
@ -891,7 +889,7 @@ static void pcc_optd_notify(acpi_handle handle, u32 event, void *data)
|
|||
set_optd_power_state(0);
|
||||
}
|
||||
|
||||
static int pcc_register_optd_notifier(struct pcc_acpi *pcc, char *node)
|
||||
static void pcc_register_optd_notifier(struct pcc_acpi *pcc, char *node)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle handle;
|
||||
|
|
@ -904,10 +902,7 @@ static int pcc_register_optd_notifier(struct pcc_acpi *pcc, char *node)
|
|||
pcc_optd_notify, pcc);
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_err("Failed to register notify on %s\n", node);
|
||||
} else
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pcc_unregister_optd_notifier(struct pcc_acpi *pcc, char *node)
|
||||
|
|
@ -968,14 +963,7 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc)
|
|||
#ifdef CONFIG_PM_SLEEP
|
||||
static int acpi_pcc_hotkey_resume(struct device *dev)
|
||||
{
|
||||
struct pcc_acpi *pcc;
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
pcc = acpi_driver_data(to_acpi_device(dev));
|
||||
if (!pcc)
|
||||
return -EINVAL;
|
||||
struct pcc_acpi *pcc = acpi_driver_data(ACPI_COMPANION(dev));
|
||||
|
||||
if (pcc->num_sifr > SINF_MUTE)
|
||||
acpi_pcc_write_sset(pcc, SINF_MUTE, pcc->mute);
|
||||
|
|
@ -991,15 +979,13 @@ static int acpi_pcc_hotkey_resume(struct device *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int acpi_pcc_hotkey_add(struct acpi_device *device)
|
||||
static int acpi_pcc_hotkey_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct backlight_properties props;
|
||||
struct pcc_acpi *pcc;
|
||||
int num_sifr, result;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
num_sifr = acpi_pcc_get_sqty(device);
|
||||
|
||||
/*
|
||||
|
|
@ -1083,19 +1069,25 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
|
|||
if (result)
|
||||
goto out_backlight;
|
||||
|
||||
result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
acpi_pcc_hotkey_notify, pcc);
|
||||
if (result)
|
||||
goto out_sysfs;
|
||||
|
||||
/* optical drive initialization */
|
||||
if (ACPI_SUCCESS(check_optd_present())) {
|
||||
pcc->platform = platform_device_register_simple("panasonic",
|
||||
PLATFORM_DEVID_NONE, NULL, 0);
|
||||
if (IS_ERR(pcc->platform)) {
|
||||
result = PTR_ERR(pcc->platform);
|
||||
goto out_sysfs;
|
||||
goto out_notify_handler;
|
||||
}
|
||||
result = device_create_file(&pcc->platform->dev,
|
||||
&dev_attr_cdpower);
|
||||
pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
|
||||
if (result)
|
||||
goto out_platform;
|
||||
|
||||
pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
|
||||
} else {
|
||||
pcc->platform = NULL;
|
||||
}
|
||||
|
|
@ -1105,6 +1097,9 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
|
|||
|
||||
out_platform:
|
||||
platform_device_unregister(pcc->platform);
|
||||
out_notify_handler:
|
||||
acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
acpi_pcc_hotkey_notify);
|
||||
out_sysfs:
|
||||
sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
|
||||
out_backlight:
|
||||
|
|
@ -1112,6 +1107,7 @@ out_backlight:
|
|||
out_input:
|
||||
input_unregister_device(pcc->input_dev);
|
||||
out_sinf:
|
||||
device->driver_data = NULL;
|
||||
kfree(pcc->sinf);
|
||||
out_hotkey:
|
||||
kfree(pcc);
|
||||
|
|
@ -1119,20 +1115,21 @@ out_hotkey:
|
|||
return result;
|
||||
}
|
||||
|
||||
static void acpi_pcc_hotkey_remove(struct acpi_device *device)
|
||||
static void acpi_pcc_hotkey_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct pcc_acpi *pcc = acpi_driver_data(device);
|
||||
|
||||
if (!device || !pcc)
|
||||
return;
|
||||
|
||||
i8042_remove_filter(panasonic_i8042_filter);
|
||||
|
||||
if (pcc->platform) {
|
||||
pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
|
||||
device_remove_file(&pcc->platform->dev, &dev_attr_cdpower);
|
||||
platform_device_unregister(pcc->platform);
|
||||
}
|
||||
pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
|
||||
|
||||
acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
acpi_pcc_hotkey_notify);
|
||||
|
||||
sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
|
||||
|
||||
|
|
@ -1140,8 +1137,10 @@ static void acpi_pcc_hotkey_remove(struct acpi_device *device)
|
|||
|
||||
input_unregister_device(pcc->input_dev);
|
||||
|
||||
device->driver_data = NULL;
|
||||
|
||||
kfree(pcc->sinf);
|
||||
kfree(pcc);
|
||||
}
|
||||
|
||||
module_acpi_driver(acpi_pcc_driver);
|
||||
module_platform_driver(acpi_pcc_driver);
|
||||
|
|
|
|||
|
|
@ -294,7 +294,8 @@ static int __init apu_board_init(void)
|
|||
}
|
||||
|
||||
apu_gpio_pdev = apu_create_pdev(AMD_FCH_GPIO_DRIVER_NAME,
|
||||
id->driver_data, sizeof(struct amd_fch_gpio_pdata), NULL);
|
||||
id->driver_data, sizeof(struct amd_fch_gpio_pdata),
|
||||
&apu2_gpiochip_node);
|
||||
err = PTR_ERR_OR_ZERO(apu_gpio_pdev);
|
||||
if (err)
|
||||
goto err_unregister_swnodes;
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ static struct wmi_driver redmi_wmi_driver = {
|
|||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.id_table = redmi_wmi_id_table,
|
||||
.min_event_size = 32,
|
||||
.probe = redmi_wmi_probe,
|
||||
.notify = redmi_wmi_notify,
|
||||
.no_singleton = true,
|
||||
|
|
|
|||
|
|
@ -178,8 +178,7 @@ enum sony_nc_rfkill {
|
|||
static int sony_rfkill_handle;
|
||||
static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
|
||||
static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
|
||||
static int sony_nc_rfkill_setup(struct acpi_device *device,
|
||||
unsigned int handle);
|
||||
static int sony_nc_rfkill_setup(struct device *dev, unsigned int handle);
|
||||
static void sony_nc_rfkill_cleanup(void);
|
||||
static void sony_nc_rfkill_update(void);
|
||||
|
||||
|
|
@ -435,7 +434,7 @@ static void sony_laptop_report_input_event(u8 event)
|
|||
dprintk("unknown input event %.2x\n", event);
|
||||
}
|
||||
|
||||
static int sony_laptop_setup_input(struct acpi_device *acpi_device)
|
||||
static int sony_laptop_setup_input(struct device *parent)
|
||||
{
|
||||
struct input_dev *jog_dev;
|
||||
struct input_dev *key_dev;
|
||||
|
|
@ -468,7 +467,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
|
|||
key_dev->name = "Sony Vaio Keys";
|
||||
key_dev->id.bustype = BUS_ISA;
|
||||
key_dev->id.vendor = PCI_VENDOR_ID_SONY;
|
||||
key_dev->dev.parent = &acpi_device->dev;
|
||||
key_dev->dev.parent = parent;
|
||||
|
||||
/* Initialize the Input Drivers: special keys */
|
||||
input_set_capability(key_dev, EV_MSC, MSC_SCAN);
|
||||
|
|
@ -497,7 +496,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
|
|||
jog_dev->name = "Sony Vaio Jogdial";
|
||||
jog_dev->id.bustype = BUS_ISA;
|
||||
jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
|
||||
jog_dev->dev.parent = &acpi_device->dev;
|
||||
jog_dev->dev.parent = parent;
|
||||
|
||||
input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
|
||||
input_set_capability(jog_dev, EV_REL, REL_WHEEL);
|
||||
|
|
@ -1176,7 +1175,7 @@ enum event_types {
|
|||
KILLSWITCH,
|
||||
GFX_SWITCH
|
||||
};
|
||||
static void sony_nc_notify(struct acpi_device *device, u32 event)
|
||||
static void sony_nc_notify(acpi_handle ah, u32 event, void *data)
|
||||
{
|
||||
u32 real_ev = event;
|
||||
u8 ev_type = 0;
|
||||
|
|
@ -1287,7 +1286,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
|
|||
/*
|
||||
* ACPI device
|
||||
*/
|
||||
static void sony_nc_function_setup(struct acpi_device *device,
|
||||
static void sony_nc_function_setup(struct device *dev,
|
||||
struct platform_device *pf_device)
|
||||
{
|
||||
unsigned int i, result, bitmask, arg;
|
||||
|
|
@ -1360,7 +1359,7 @@ static void sony_nc_function_setup(struct acpi_device *device,
|
|||
break;
|
||||
case 0x0124:
|
||||
case 0x0135:
|
||||
result = sony_nc_rfkill_setup(device, handle);
|
||||
result = sony_nc_rfkill_setup(dev, handle);
|
||||
if (result)
|
||||
pr_err("couldn't set up rfkill support (%d)\n",
|
||||
result);
|
||||
|
|
@ -1600,8 +1599,7 @@ static const struct rfkill_ops sony_rfkill_ops = {
|
|||
.set_block = sony_nc_rfkill_set,
|
||||
};
|
||||
|
||||
static int sony_nc_setup_rfkill(struct acpi_device *device,
|
||||
enum sony_nc_rfkill nc_type)
|
||||
static int sony_nc_setup_rfkill(struct device *parent, enum sony_nc_rfkill nc_type)
|
||||
{
|
||||
int err;
|
||||
struct rfkill *rfk;
|
||||
|
|
@ -1631,8 +1629,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
rfk = rfkill_alloc(name, &device->dev, type,
|
||||
&sony_rfkill_ops, (void *)nc_type);
|
||||
rfk = rfkill_alloc(name, parent, type, &sony_rfkill_ops, (void *)nc_type);
|
||||
if (!rfk)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -1692,8 +1689,7 @@ static void sony_nc_rfkill_update(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int sony_nc_rfkill_setup(struct acpi_device *device,
|
||||
unsigned int handle)
|
||||
static int sony_nc_rfkill_setup(struct device *parent, unsigned int handle)
|
||||
{
|
||||
u64 offset;
|
||||
int i;
|
||||
|
|
@ -1734,18 +1730,18 @@ static int sony_nc_rfkill_setup(struct acpi_device *device,
|
|||
dprintk("Radio devices, found 0x%.2x\n", buffer[i]);
|
||||
|
||||
if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI])
|
||||
sony_nc_setup_rfkill(device, SONY_WIFI);
|
||||
sony_nc_setup_rfkill(parent, SONY_WIFI);
|
||||
|
||||
if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
|
||||
sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
|
||||
sony_nc_setup_rfkill(parent, SONY_BLUETOOTH);
|
||||
|
||||
if (((0xf0 & buffer[i]) == 0x20 ||
|
||||
(0xf0 & buffer[i]) == 0x50) &&
|
||||
!sony_rfkill_devices[SONY_WWAN])
|
||||
sony_nc_setup_rfkill(device, SONY_WWAN);
|
||||
sony_nc_setup_rfkill(parent, SONY_WWAN);
|
||||
|
||||
if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
|
||||
sony_nc_setup_rfkill(device, SONY_WIMAX);
|
||||
sony_nc_setup_rfkill(parent, SONY_WIMAX);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3149,8 +3145,9 @@ static void sony_nc_backlight_cleanup(void)
|
|||
backlight_device_unregister(sony_bl_props.dev);
|
||||
}
|
||||
|
||||
static int sony_nc_add(struct acpi_device *device)
|
||||
static int sony_nc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
acpi_status status;
|
||||
int result = 0;
|
||||
struct sony_nc_value *item;
|
||||
|
|
@ -3184,7 +3181,7 @@ static int sony_nc_add(struct acpi_device *device)
|
|||
}
|
||||
}
|
||||
|
||||
result = sony_laptop_setup_input(device);
|
||||
result = sony_laptop_setup_input(&pdev->dev);
|
||||
if (result) {
|
||||
pr_err("Unable to create input devices\n");
|
||||
goto outplatform;
|
||||
|
|
@ -3201,7 +3198,7 @@ static int sony_nc_add(struct acpi_device *device)
|
|||
/* retrieve the available handles */
|
||||
result = sony_nc_handles_setup(sony_pf_device);
|
||||
if (!result)
|
||||
sony_nc_function_setup(device, sony_pf_device);
|
||||
sony_nc_function_setup(&pdev->dev, sony_pf_device);
|
||||
}
|
||||
|
||||
if (acpi_video_get_backlight_type() == acpi_backlight_vendor)
|
||||
|
|
@ -3244,6 +3241,11 @@ static int sony_nc_add(struct acpi_device *device)
|
|||
}
|
||||
}
|
||||
|
||||
result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
sony_nc_notify, NULL);
|
||||
if (result)
|
||||
goto out_sysfs;
|
||||
|
||||
pr_info("SNC setup done.\n");
|
||||
return 0;
|
||||
|
||||
|
|
@ -3266,10 +3268,13 @@ outwalk:
|
|||
return result;
|
||||
}
|
||||
|
||||
static void sony_nc_remove(struct acpi_device *device)
|
||||
static void sony_nc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sony_nc_value *item;
|
||||
|
||||
acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
|
||||
ACPI_DEVICE_NOTIFY, sony_nc_notify);
|
||||
|
||||
sony_nc_backlight_cleanup();
|
||||
|
||||
sony_nc_acpi_device = NULL;
|
||||
|
|
@ -3297,16 +3302,14 @@ static const struct acpi_device_id sony_nc_device_ids[] = {
|
|||
{"", 0},
|
||||
};
|
||||
|
||||
static struct acpi_driver sony_nc_driver = {
|
||||
.name = SONY_NC_DRIVER_NAME,
|
||||
.class = SONY_NC_CLASS,
|
||||
.ids = sony_nc_device_ids,
|
||||
.ops = {
|
||||
.add = sony_nc_add,
|
||||
.remove = sony_nc_remove,
|
||||
.notify = sony_nc_notify,
|
||||
},
|
||||
.drv.pm = &sony_nc_pm,
|
||||
static struct platform_driver sony_nc_driver = {
|
||||
.probe = sony_nc_probe,
|
||||
.remove = sony_nc_remove,
|
||||
.driver = {
|
||||
.name = SONY_NC_DRIVER_NAME,
|
||||
.acpi_match_table = sony_nc_device_ids,
|
||||
.pm = &sony_nc_pm,
|
||||
},
|
||||
};
|
||||
|
||||
/*********** SPIC (SNY6001) Device ***********/
|
||||
|
|
@ -4276,9 +4279,9 @@ end:
|
|||
/*
|
||||
* Disable the spic device by calling its _DIS method
|
||||
*/
|
||||
static int sony_pic_disable(struct acpi_device *device)
|
||||
static int sony_pic_disable(struct device *dev)
|
||||
{
|
||||
acpi_status ret = acpi_evaluate_object(device->handle, "_DIS", NULL,
|
||||
acpi_status ret = acpi_evaluate_object(ACPI_HANDLE(dev), "_DIS", NULL,
|
||||
NULL);
|
||||
|
||||
if (ACPI_FAILURE(ret) && ret != AE_NOT_FOUND)
|
||||
|
|
@ -4294,7 +4297,7 @@ static int sony_pic_disable(struct acpi_device *device)
|
|||
*
|
||||
* Call _SRS to set current resources
|
||||
*/
|
||||
static int sony_pic_enable(struct acpi_device *device,
|
||||
static int sony_pic_enable(struct device *dev,
|
||||
struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
|
||||
{
|
||||
acpi_status status;
|
||||
|
|
@ -4376,7 +4379,7 @@ static int sony_pic_enable(struct acpi_device *device,
|
|||
|
||||
/* Attempt to set the resource */
|
||||
dprintk("Evaluating _SRS\n");
|
||||
status = acpi_set_current_resources(device->handle, &buffer);
|
||||
status = acpi_set_current_resources(ACPI_HANDLE(dev), &buffer);
|
||||
|
||||
/* check for total failure */
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
|
@ -4465,12 +4468,12 @@ found:
|
|||
* ACPI driver
|
||||
*
|
||||
*****************/
|
||||
static void sony_pic_remove(struct acpi_device *device)
|
||||
static void sony_pic_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sony_pic_ioport *io, *tmp_io;
|
||||
struct sony_pic_irq *irq, *tmp_irq;
|
||||
|
||||
if (sony_pic_disable(device)) {
|
||||
if (sony_pic_disable(&pdev->dev)) {
|
||||
pr_err("Couldn't disable device\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -4504,11 +4507,12 @@ static void sony_pic_remove(struct acpi_device *device)
|
|||
dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
|
||||
}
|
||||
|
||||
static int sony_pic_add(struct acpi_device *device)
|
||||
static int sony_pic_probe(struct platform_device *pdev)
|
||||
{
|
||||
int result;
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct sony_pic_ioport *io, *tmp_io;
|
||||
struct sony_pic_irq *irq, *tmp_irq;
|
||||
int result;
|
||||
|
||||
spic_dev.acpi_dev = device;
|
||||
strscpy(acpi_device_class(device), "sony/hotkey");
|
||||
|
|
@ -4523,7 +4527,7 @@ static int sony_pic_add(struct acpi_device *device)
|
|||
}
|
||||
|
||||
/* setup input devices and helper fifo */
|
||||
result = sony_laptop_setup_input(device);
|
||||
result = sony_laptop_setup_input(&pdev->dev);
|
||||
if (result) {
|
||||
pr_err("Unable to create input devices\n");
|
||||
goto err_free_resources;
|
||||
|
|
@ -4593,7 +4597,7 @@ static int sony_pic_add(struct acpi_device *device)
|
|||
}
|
||||
|
||||
/* set resource status _SRS */
|
||||
result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
|
||||
result = sony_pic_enable(&pdev->dev, spic_dev.cur_ioport, spic_dev.cur_irq);
|
||||
if (result) {
|
||||
pr_err("Couldn't enable device\n");
|
||||
goto err_free_irq;
|
||||
|
|
@ -4616,7 +4620,7 @@ err_remove_pf:
|
|||
sony_pf_remove();
|
||||
|
||||
err_disable_device:
|
||||
sony_pic_disable(device);
|
||||
sony_pic_disable(&pdev->dev);
|
||||
|
||||
err_free_irq:
|
||||
free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
|
||||
|
|
@ -4652,15 +4656,14 @@ err_free_resources:
|
|||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sony_pic_suspend(struct device *dev)
|
||||
{
|
||||
if (sony_pic_disable(to_acpi_device(dev)))
|
||||
if (sony_pic_disable(dev))
|
||||
return -ENXIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sony_pic_resume(struct device *dev)
|
||||
{
|
||||
sony_pic_enable(to_acpi_device(dev),
|
||||
spic_dev.cur_ioport, spic_dev.cur_irq);
|
||||
sony_pic_enable(dev, spic_dev.cur_ioport, spic_dev.cur_irq);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -4672,15 +4675,14 @@ static const struct acpi_device_id sony_pic_device_ids[] = {
|
|||
{"", 0},
|
||||
};
|
||||
|
||||
static struct acpi_driver sony_pic_driver = {
|
||||
.name = SONY_PIC_DRIVER_NAME,
|
||||
.class = SONY_PIC_CLASS,
|
||||
.ids = sony_pic_device_ids,
|
||||
.ops = {
|
||||
.add = sony_pic_add,
|
||||
.remove = sony_pic_remove,
|
||||
},
|
||||
.drv.pm = &sony_pic_pm,
|
||||
static struct platform_driver sony_pic_driver = {
|
||||
.probe = sony_pic_probe,
|
||||
.remove = sony_pic_remove,
|
||||
.driver = {
|
||||
.name = SONY_PIC_DRIVER_NAME,
|
||||
.acpi_match_table = sony_pic_device_ids,
|
||||
.pm = &sony_pic_pm,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct dmi_system_id sonypi_dmi_table[] __initconst = {
|
||||
|
|
@ -4706,7 +4708,7 @@ static int __init sony_laptop_init(void)
|
|||
int result;
|
||||
|
||||
if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
|
||||
result = acpi_bus_register_driver(&sony_pic_driver);
|
||||
result = platform_driver_register(&sony_pic_driver);
|
||||
if (result) {
|
||||
pr_err("Unable to register SPIC driver\n");
|
||||
goto out;
|
||||
|
|
@ -4714,7 +4716,7 @@ static int __init sony_laptop_init(void)
|
|||
spic_drv_registered = 1;
|
||||
}
|
||||
|
||||
result = acpi_bus_register_driver(&sony_nc_driver);
|
||||
result = platform_driver_register(&sony_nc_driver);
|
||||
if (result) {
|
||||
pr_err("Unable to register SNC driver\n");
|
||||
goto out_unregister_pic;
|
||||
|
|
@ -4724,16 +4726,16 @@ static int __init sony_laptop_init(void)
|
|||
|
||||
out_unregister_pic:
|
||||
if (spic_drv_registered)
|
||||
acpi_bus_unregister_driver(&sony_pic_driver);
|
||||
platform_driver_unregister(&sony_pic_driver);
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static void __exit sony_laptop_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&sony_nc_driver);
|
||||
platform_driver_unregister(&sony_nc_driver);
|
||||
if (spic_drv_registered)
|
||||
acpi_bus_unregister_driver(&sony_pic_driver);
|
||||
platform_driver_unregister(&sony_pic_driver);
|
||||
}
|
||||
|
||||
module_init(sony_laptop_init);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
|
|
@ -644,11 +645,10 @@ static void input_key(struct system76_data *data, unsigned int code)
|
|||
}
|
||||
|
||||
// Handle ACPI notification
|
||||
static void system76_notify(struct acpi_device *acpi_dev, u32 event)
|
||||
static void system76_notify(acpi_handle handle, u32 event, void *context)
|
||||
{
|
||||
struct system76_data *data;
|
||||
struct system76_data *data = context;
|
||||
|
||||
data = acpi_driver_data(acpi_dev);
|
||||
switch (event) {
|
||||
case 0x80:
|
||||
kb_led_hotkey_hardware(data);
|
||||
|
|
@ -671,16 +671,19 @@ static void system76_notify(struct acpi_device *acpi_dev, u32 event)
|
|||
}
|
||||
}
|
||||
|
||||
// Add a System76 ACPI device
|
||||
static int system76_add(struct acpi_device *acpi_dev)
|
||||
// Probe a System76 platform device
|
||||
static int system76_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev);
|
||||
struct system76_data *data;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&acpi_dev->dev, sizeof(*data), GFP_KERNEL);
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
acpi_dev->driver_data = data;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
data->acpi_dev = acpi_dev;
|
||||
|
||||
// Some models do not run open EC firmware. Check for an ACPI method
|
||||
|
|
@ -696,7 +699,7 @@ static int system76_add(struct acpi_device *acpi_dev)
|
|||
data->ap_led.brightness_set_blocking = ap_led_set;
|
||||
data->ap_led.max_brightness = 1;
|
||||
data->ap_led.default_trigger = "rfkill-none";
|
||||
err = devm_led_classdev_register(&acpi_dev->dev, &data->ap_led);
|
||||
err = devm_led_classdev_register(&pdev->dev, &data->ap_led);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -740,24 +743,29 @@ static int system76_add(struct acpi_device *acpi_dev)
|
|||
}
|
||||
|
||||
if (data->kbled_type != KBLED_NONE) {
|
||||
err = devm_led_classdev_register(&acpi_dev->dev, &data->kb_led);
|
||||
err = devm_led_classdev_register(&pdev->dev, &data->kb_led);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
data->input = devm_input_allocate_device(&acpi_dev->dev);
|
||||
data->input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!data->input)
|
||||
return -ENOMEM;
|
||||
|
||||
data->input->name = "System76 ACPI Hotkeys";
|
||||
data->input->phys = "system76_acpi/input0";
|
||||
data->input->id.bustype = BUS_HOST;
|
||||
data->input->dev.parent = &acpi_dev->dev;
|
||||
data->input->dev.parent = &pdev->dev;
|
||||
input_set_capability(data->input, EV_KEY, KEY_SCREENLOCK);
|
||||
|
||||
err = input_register_device(data->input);
|
||||
if (err)
|
||||
goto error;
|
||||
return err;
|
||||
|
||||
err = acpi_dev_install_notify_handler(acpi_dev, ACPI_DEVICE_NOTIFY,
|
||||
system76_notify, data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (data->has_open_ec) {
|
||||
err = system76_get_object(data, "NFAN", &data->nfan);
|
||||
|
|
@ -768,7 +776,7 @@ static int system76_add(struct acpi_device *acpi_dev)
|
|||
if (err)
|
||||
goto error;
|
||||
|
||||
data->therm = devm_hwmon_device_register_with_info(&acpi_dev->dev,
|
||||
data->therm = devm_hwmon_device_register_with_info(&pdev->dev,
|
||||
"system76_acpi", data, &thermal_chip_info, NULL);
|
||||
err = PTR_ERR_OR_ZERO(data->therm);
|
||||
if (err)
|
||||
|
|
@ -784,15 +792,14 @@ error:
|
|||
kfree(data->ntmp);
|
||||
kfree(data->nfan);
|
||||
}
|
||||
acpi_dev_remove_notify_handler(acpi_dev, ACPI_DEVICE_NOTIFY, system76_notify);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Remove a System76 ACPI device
|
||||
static void system76_remove(struct acpi_device *acpi_dev)
|
||||
// Remove a System76 platform device
|
||||
static void system76_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct system76_data *data;
|
||||
|
||||
data = acpi_driver_data(acpi_dev);
|
||||
struct system76_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
if (data->has_open_ec) {
|
||||
system76_battery_exit();
|
||||
|
|
@ -800,23 +807,21 @@ static void system76_remove(struct acpi_device *acpi_dev)
|
|||
kfree(data->ntmp);
|
||||
}
|
||||
|
||||
devm_led_classdev_unregister(&acpi_dev->dev, &data->ap_led);
|
||||
devm_led_classdev_unregister(&acpi_dev->dev, &data->kb_led);
|
||||
acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
|
||||
ACPI_DEVICE_NOTIFY, system76_notify);
|
||||
|
||||
system76_get(data, "FINI");
|
||||
}
|
||||
|
||||
static struct acpi_driver system76_driver = {
|
||||
.name = "System76 ACPI Driver",
|
||||
.class = "hotkey",
|
||||
.ids = device_ids,
|
||||
.ops = {
|
||||
.add = system76_add,
|
||||
.remove = system76_remove,
|
||||
.notify = system76_notify,
|
||||
static struct platform_driver system76_driver = {
|
||||
.probe = system76_probe,
|
||||
.remove = system76_remove,
|
||||
.driver = {
|
||||
.name = "System76 ACPI Driver",
|
||||
.acpi_match_table = device_ids,
|
||||
},
|
||||
};
|
||||
module_acpi_driver(system76_driver);
|
||||
module_platform_driver(system76_driver);
|
||||
|
||||
MODULE_DESCRIPTION("System76 ACPI Driver");
|
||||
MODULE_AUTHOR("Jeremy Soller <jeremy@system76.com>");
|
||||
|
|
|
|||
|
|
@ -232,9 +232,9 @@ static int topstar_acpi_fncx_switch(struct acpi_device *device, bool state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void topstar_acpi_notify(struct acpi_device *device, u32 event)
|
||||
static void topstar_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct topstar_laptop *topstar = acpi_driver_data(device);
|
||||
struct topstar_laptop *topstar = data;
|
||||
static bool dup_evnt[2];
|
||||
bool *dup;
|
||||
|
||||
|
|
@ -285,8 +285,9 @@ static const struct dmi_system_id topstar_dmi_ids[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static int topstar_acpi_add(struct acpi_device *device)
|
||||
static int topstar_acpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct topstar_laptop *topstar;
|
||||
int err;
|
||||
|
||||
|
|
@ -296,9 +297,10 @@ static int topstar_acpi_add(struct acpi_device *device)
|
|||
if (!topstar)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, topstar);
|
||||
|
||||
strscpy(acpi_device_name(device), "Topstar TPSACPI");
|
||||
strscpy(acpi_device_class(device), TOPSTAR_LAPTOP_CLASS);
|
||||
device->driver_data = topstar;
|
||||
topstar->device = device;
|
||||
|
||||
err = topstar_acpi_init(topstar);
|
||||
|
|
@ -313,14 +315,21 @@ static int topstar_acpi_add(struct acpi_device *device)
|
|||
if (err)
|
||||
goto err_platform_exit;
|
||||
|
||||
err = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
topstar_acpi_notify, topstar);
|
||||
if (err)
|
||||
goto err_input_exit;
|
||||
|
||||
if (led_workaround) {
|
||||
err = topstar_led_init(topstar);
|
||||
if (err)
|
||||
goto err_input_exit;
|
||||
goto err_notify_handler_exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_notify_handler_exit:
|
||||
acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, topstar_acpi_notify);
|
||||
err_input_exit:
|
||||
topstar_input_exit(topstar);
|
||||
err_platform_exit:
|
||||
|
|
@ -332,13 +341,15 @@ err_free:
|
|||
return err;
|
||||
}
|
||||
|
||||
static void topstar_acpi_remove(struct acpi_device *device)
|
||||
static void topstar_acpi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct topstar_laptop *topstar = acpi_driver_data(device);
|
||||
struct topstar_laptop *topstar = platform_get_drvdata(pdev);
|
||||
|
||||
if (led_workaround)
|
||||
topstar_led_exit(topstar);
|
||||
|
||||
acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
|
||||
ACPI_DEVICE_NOTIFY, topstar_acpi_notify);
|
||||
topstar_input_exit(topstar);
|
||||
topstar_platform_exit(topstar);
|
||||
topstar_acpi_exit(topstar);
|
||||
|
|
@ -353,14 +364,12 @@ static const struct acpi_device_id topstar_device_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, topstar_device_ids);
|
||||
|
||||
static struct acpi_driver topstar_acpi_driver = {
|
||||
.name = "Topstar laptop ACPI driver",
|
||||
.class = TOPSTAR_LAPTOP_CLASS,
|
||||
.ids = topstar_device_ids,
|
||||
.ops = {
|
||||
.add = topstar_acpi_add,
|
||||
.remove = topstar_acpi_remove,
|
||||
.notify = topstar_acpi_notify,
|
||||
static struct platform_driver topstar_acpi_driver = {
|
||||
.probe = topstar_acpi_probe,
|
||||
.remove = topstar_acpi_remove,
|
||||
.driver = {
|
||||
.name = "Topstar laptop ACPI driver",
|
||||
.acpi_match_table = topstar_device_ids,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -372,7 +381,7 @@ static int __init topstar_laptop_init(void)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = acpi_bus_register_driver(&topstar_acpi_driver);
|
||||
ret = platform_driver_register(&topstar_acpi_driver);
|
||||
if (ret < 0)
|
||||
goto err_driver_unreg;
|
||||
|
||||
|
|
@ -386,7 +395,7 @@ err_driver_unreg:
|
|||
|
||||
static void __exit topstar_laptop_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&topstar_acpi_driver);
|
||||
platform_driver_unregister(&topstar_acpi_driver);
|
||||
platform_driver_unregister(&topstar_platform_driver);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include <linux/rfkill.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/toshiba.h>
|
||||
#include <acpi/battery.h>
|
||||
#include <acpi/video.h>
|
||||
|
|
@ -223,6 +224,7 @@ struct toshiba_acpi_dev {
|
|||
unsigned int cooling_method_supported:1;
|
||||
unsigned int battery_charge_mode_supported:1;
|
||||
unsigned int sysfs_created:1;
|
||||
unsigned int notify_handler_installed:1;
|
||||
unsigned int special_functions;
|
||||
|
||||
bool kbd_event_generated;
|
||||
|
|
@ -3193,14 +3195,80 @@ static void print_supported_features(struct toshiba_acpi_dev *dev)
|
|||
pr_cont("\n");
|
||||
}
|
||||
|
||||
static void toshiba_acpi_remove(struct acpi_device *acpi_dev)
|
||||
static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
|
||||
struct toshiba_acpi_dev *dev = data;
|
||||
struct acpi_device *acpi_dev = dev->acpi_dev;
|
||||
|
||||
switch (event) {
|
||||
case 0x80: /* Hotkeys and some system events */
|
||||
/*
|
||||
* Machines with this WMI GUID aren't supported due to bugs in
|
||||
* their AML.
|
||||
*
|
||||
* Return silently to avoid triggering a netlink event.
|
||||
*/
|
||||
if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
|
||||
return;
|
||||
toshiba_acpi_process_hotkeys(dev);
|
||||
break;
|
||||
case 0x81: /* Dock events */
|
||||
case 0x82:
|
||||
case 0x83:
|
||||
pr_info("Dock event received %x\n", event);
|
||||
break;
|
||||
case 0x88: /* Thermal events */
|
||||
pr_info("Thermal event received\n");
|
||||
break;
|
||||
case 0x8f: /* LID closed */
|
||||
case 0x90: /* LID is closed and Dock has been ejected */
|
||||
break;
|
||||
case 0x8c: /* SATA power events */
|
||||
case 0x8b:
|
||||
pr_info("SATA power event received %x\n", event);
|
||||
break;
|
||||
case 0x92: /* Keyboard backlight mode changed */
|
||||
dev->kbd_event_generated = true;
|
||||
/* Update sysfs entries */
|
||||
if (sysfs_update_group(&acpi_dev->dev.kobj,
|
||||
&toshiba_attr_group))
|
||||
pr_err("Unable to update sysfs entries\n");
|
||||
/* Notify LED subsystem about keyboard backlight change */
|
||||
if (dev->kbd_type == 2 && dev->kbd_mode != SCI_KBD_MODE_AUTO)
|
||||
led_classdev_notify_brightness_hw_changed(&dev->kbd_led,
|
||||
(dev->kbd_mode == SCI_KBD_MODE_ON) ?
|
||||
LED_FULL : LED_OFF);
|
||||
break;
|
||||
case 0x8e: /* Power button pressed */
|
||||
break;
|
||||
case 0x85: /* Unknown */
|
||||
case 0x8d: /* Unknown */
|
||||
case 0x94: /* Unknown */
|
||||
case 0x95: /* Unknown */
|
||||
default:
|
||||
pr_info("Unknown event received %x\n", event);
|
||||
break;
|
||||
}
|
||||
|
||||
acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class,
|
||||
dev_name(&acpi_dev->dev),
|
||||
event, (event == 0x80) ?
|
||||
dev->last_key_event : 0);
|
||||
}
|
||||
|
||||
static void toshiba_acpi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct toshiba_acpi_dev *dev = platform_get_drvdata(pdev);
|
||||
|
||||
misc_deregister(&dev->miscdev);
|
||||
|
||||
remove_toshiba_proc_entries(dev);
|
||||
|
||||
if (dev->notify_handler_installed)
|
||||
acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
toshiba_acpi_notify);
|
||||
|
||||
#if IS_ENABLED(CONFIG_HWMON)
|
||||
if (dev->hwmon_device)
|
||||
hwmon_device_unregister(dev->hwmon_device);
|
||||
|
|
@ -3240,6 +3308,8 @@ static void toshiba_acpi_remove(struct acpi_device *acpi_dev)
|
|||
if (toshiba_acpi)
|
||||
toshiba_acpi = NULL;
|
||||
|
||||
dev_set_drvdata(&dev->acpi_dev->dev, NULL);
|
||||
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
|
|
@ -3302,8 +3372,9 @@ static const struct dmi_system_id toshiba_dmi_quirks[] __initconst = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
||||
static int toshiba_acpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev);
|
||||
struct toshiba_acpi_dev *dev;
|
||||
const char *hci_method;
|
||||
u32 dummy;
|
||||
|
|
@ -3337,7 +3408,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
acpi_dev->driver_data = dev;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
dev_set_drvdata(&acpi_dev->dev, dev);
|
||||
|
||||
/* Query the BIOS for supported features */
|
||||
|
|
@ -3368,7 +3439,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
|||
dev->led_dev.max_brightness = 1;
|
||||
dev->led_dev.brightness_set = toshiba_illumination_set;
|
||||
dev->led_dev.brightness_get = toshiba_illumination_get;
|
||||
led_classdev_register(&acpi_dev->dev, &dev->led_dev);
|
||||
led_classdev_register(&pdev->dev, &dev->led_dev);
|
||||
}
|
||||
|
||||
toshiba_eco_mode_available(dev);
|
||||
|
|
@ -3377,7 +3448,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
|||
dev->eco_led.max_brightness = 1;
|
||||
dev->eco_led.brightness_set = toshiba_eco_mode_set_status;
|
||||
dev->eco_led.brightness_get = toshiba_eco_mode_get_status;
|
||||
led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led);
|
||||
led_classdev_register(&pdev->dev, &dev->eco_led);
|
||||
}
|
||||
|
||||
toshiba_kbd_illum_available(dev);
|
||||
|
|
@ -3393,7 +3464,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
|||
dev->kbd_led.max_brightness = 1;
|
||||
dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
|
||||
dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
|
||||
led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led);
|
||||
led_classdev_register(&pdev->dev, &dev->kbd_led);
|
||||
}
|
||||
|
||||
ret = toshiba_touchpad_get(dev, &dummy);
|
||||
|
|
@ -3401,7 +3472,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
|||
|
||||
toshiba_accelerometer_available(dev);
|
||||
if (dev->accelerometer_supported) {
|
||||
dev->indio_dev = iio_device_alloc(&acpi_dev->dev, sizeof(*dev));
|
||||
dev->indio_dev = iio_device_alloc(&pdev->dev, sizeof(*dev));
|
||||
if (!dev->indio_dev) {
|
||||
pr_err("Unable to allocate iio device\n");
|
||||
goto iio_error;
|
||||
|
|
@ -3450,7 +3521,7 @@ iio_error:
|
|||
#if IS_ENABLED(CONFIG_HWMON)
|
||||
if (dev->fan_rpm_supported) {
|
||||
dev->hwmon_device = hwmon_device_register_with_info(
|
||||
&dev->acpi_dev->dev, "toshiba_acpi_sensors", NULL,
|
||||
&pdev->dev, "toshiba_acpi_sensors", NULL,
|
||||
&toshiba_acpi_hwmon_chip_info, NULL);
|
||||
if (IS_ERR(dev->hwmon_device)) {
|
||||
dev->hwmon_device = NULL;
|
||||
|
|
@ -3477,6 +3548,13 @@ iio_error:
|
|||
}
|
||||
dev->sysfs_created = !ret;
|
||||
|
||||
ret = acpi_dev_install_notify_handler(acpi_dev, ACPI_DEVICE_NOTIFY,
|
||||
toshiba_acpi_notify, dev);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
dev->notify_handler_installed = 1;
|
||||
|
||||
create_toshiba_proc_entries(dev);
|
||||
|
||||
toshiba_acpi = dev;
|
||||
|
|
@ -3491,74 +3569,14 @@ iio_error:
|
|||
return 0;
|
||||
|
||||
error:
|
||||
toshiba_acpi_remove(acpi_dev);
|
||||
toshiba_acpi_remove(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
|
||||
{
|
||||
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
|
||||
|
||||
switch (event) {
|
||||
case 0x80: /* Hotkeys and some system events */
|
||||
/*
|
||||
* Machines with this WMI GUID aren't supported due to bugs in
|
||||
* their AML.
|
||||
*
|
||||
* Return silently to avoid triggering a netlink event.
|
||||
*/
|
||||
if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
|
||||
return;
|
||||
toshiba_acpi_process_hotkeys(dev);
|
||||
break;
|
||||
case 0x81: /* Dock events */
|
||||
case 0x82:
|
||||
case 0x83:
|
||||
pr_info("Dock event received %x\n", event);
|
||||
break;
|
||||
case 0x88: /* Thermal events */
|
||||
pr_info("Thermal event received\n");
|
||||
break;
|
||||
case 0x8f: /* LID closed */
|
||||
case 0x90: /* LID is closed and Dock has been ejected */
|
||||
break;
|
||||
case 0x8c: /* SATA power events */
|
||||
case 0x8b:
|
||||
pr_info("SATA power event received %x\n", event);
|
||||
break;
|
||||
case 0x92: /* Keyboard backlight mode changed */
|
||||
dev->kbd_event_generated = true;
|
||||
/* Update sysfs entries */
|
||||
if (sysfs_update_group(&acpi_dev->dev.kobj,
|
||||
&toshiba_attr_group))
|
||||
pr_err("Unable to update sysfs entries\n");
|
||||
/* Notify LED subsystem about keyboard backlight change */
|
||||
if (dev->kbd_type == 2 && dev->kbd_mode != SCI_KBD_MODE_AUTO)
|
||||
led_classdev_notify_brightness_hw_changed(&dev->kbd_led,
|
||||
(dev->kbd_mode == SCI_KBD_MODE_ON) ?
|
||||
LED_FULL : LED_OFF);
|
||||
break;
|
||||
case 0x8e: /* Power button pressed */
|
||||
break;
|
||||
case 0x85: /* Unknown */
|
||||
case 0x8d: /* Unknown */
|
||||
case 0x94: /* Unknown */
|
||||
case 0x95: /* Unknown */
|
||||
default:
|
||||
pr_info("Unknown event received %x\n", event);
|
||||
break;
|
||||
}
|
||||
|
||||
acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class,
|
||||
dev_name(&acpi_dev->dev),
|
||||
event, (event == 0x80) ?
|
||||
dev->last_key_event : 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int toshiba_acpi_suspend(struct device *device)
|
||||
{
|
||||
struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
|
||||
struct toshiba_acpi_dev *dev = dev_get_drvdata(device);
|
||||
|
||||
if (dev->hotkey_dev) {
|
||||
u32 result;
|
||||
|
|
@ -3573,7 +3591,7 @@ static int toshiba_acpi_suspend(struct device *device)
|
|||
|
||||
static int toshiba_acpi_resume(struct device *device)
|
||||
{
|
||||
struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
|
||||
struct toshiba_acpi_dev *dev = dev_get_drvdata(device);
|
||||
|
||||
if (dev->hotkey_dev) {
|
||||
if (toshiba_acpi_enable_hotkeys(dev))
|
||||
|
|
@ -3595,16 +3613,14 @@ static int toshiba_acpi_resume(struct device *device)
|
|||
static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
|
||||
toshiba_acpi_suspend, toshiba_acpi_resume);
|
||||
|
||||
static struct acpi_driver toshiba_acpi_driver = {
|
||||
.name = "Toshiba ACPI driver",
|
||||
.ids = toshiba_device_ids,
|
||||
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
|
||||
.ops = {
|
||||
.add = toshiba_acpi_add,
|
||||
.remove = toshiba_acpi_remove,
|
||||
.notify = toshiba_acpi_notify,
|
||||
static struct platform_driver toshiba_acpi_driver = {
|
||||
.probe = toshiba_acpi_probe,
|
||||
.remove = toshiba_acpi_remove,
|
||||
.driver = {
|
||||
.name = "Toshiba ACPI driver",
|
||||
.acpi_match_table = toshiba_device_ids,
|
||||
.pm = &toshiba_acpi_pm,
|
||||
},
|
||||
.drv.pm = &toshiba_acpi_pm,
|
||||
};
|
||||
|
||||
static void __init toshiba_dmi_init(void)
|
||||
|
|
@ -3634,7 +3650,7 @@ static int __init toshiba_acpi_init(void)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = acpi_bus_register_driver(&toshiba_acpi_driver);
|
||||
ret = platform_driver_register(&toshiba_acpi_driver);
|
||||
if (ret) {
|
||||
pr_err("Failed to register ACPI driver: %d\n", ret);
|
||||
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
|
||||
|
|
@ -3645,7 +3661,7 @@ static int __init toshiba_acpi_init(void)
|
|||
|
||||
static void __exit toshiba_acpi_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&toshiba_acpi_driver);
|
||||
platform_driver_unregister(&toshiba_acpi_driver);
|
||||
if (toshiba_proc_dir)
|
||||
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define BT_KILLSWITCH_MASK 0x01
|
||||
#define BT_PLUGGED_MASK 0x40
|
||||
|
|
@ -35,9 +36,9 @@ struct toshiba_bluetooth_dev {
|
|||
bool powered;
|
||||
};
|
||||
|
||||
static int toshiba_bt_rfkill_add(struct acpi_device *device);
|
||||
static void toshiba_bt_rfkill_remove(struct acpi_device *device);
|
||||
static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
|
||||
static int toshiba_bt_rfkill_probe(struct platform_device *pdev);
|
||||
static void toshiba_bt_rfkill_remove(struct platform_device *pdev);
|
||||
static void toshiba_bt_rfkill_notify(acpi_handle handle, u32 event, void *data);
|
||||
|
||||
static const struct acpi_device_id bt_device_ids[] = {
|
||||
{ "TOS6205", 0},
|
||||
|
|
@ -50,16 +51,14 @@ static int toshiba_bt_resume(struct device *dev);
|
|||
#endif
|
||||
static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume);
|
||||
|
||||
static struct acpi_driver toshiba_bt_rfkill_driver = {
|
||||
.name = "Toshiba BT",
|
||||
.class = "Toshiba",
|
||||
.ids = bt_device_ids,
|
||||
.ops = {
|
||||
.add = toshiba_bt_rfkill_add,
|
||||
.remove = toshiba_bt_rfkill_remove,
|
||||
.notify = toshiba_bt_rfkill_notify,
|
||||
},
|
||||
.drv.pm = &toshiba_bt_pm,
|
||||
static struct platform_driver toshiba_bt_rfkill_driver = {
|
||||
.probe = toshiba_bt_rfkill_probe,
|
||||
.remove = toshiba_bt_rfkill_remove,
|
||||
.driver = {
|
||||
.name = "Toshiba BT",
|
||||
.acpi_match_table = bt_device_ids,
|
||||
.pm = &toshiba_bt_pm,
|
||||
},
|
||||
};
|
||||
|
||||
static int toshiba_bluetooth_present(acpi_handle handle)
|
||||
|
|
@ -203,9 +202,9 @@ static const struct rfkill_ops rfk_ops = {
|
|||
};
|
||||
|
||||
/* ACPI driver functions */
|
||||
static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
|
||||
static void toshiba_bt_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device);
|
||||
struct toshiba_bluetooth_dev *bt_dev = data;
|
||||
|
||||
if (toshiba_bluetooth_sync_status(bt_dev))
|
||||
return;
|
||||
|
|
@ -216,11 +215,9 @@ static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
|
|||
#ifdef CONFIG_PM_SLEEP
|
||||
static int toshiba_bt_resume(struct device *dev)
|
||||
{
|
||||
struct toshiba_bluetooth_dev *bt_dev;
|
||||
struct toshiba_bluetooth_dev *bt_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
bt_dev = acpi_driver_data(to_acpi_device(dev));
|
||||
|
||||
ret = toshiba_bluetooth_sync_status(bt_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -231,8 +228,9 @@ static int toshiba_bt_resume(struct device *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int toshiba_bt_rfkill_add(struct acpi_device *device)
|
||||
static int toshiba_bt_rfkill_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct toshiba_bluetooth_dev *bt_dev;
|
||||
int result;
|
||||
|
||||
|
|
@ -246,8 +244,8 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device)
|
|||
if (!bt_dev)
|
||||
return -ENOMEM;
|
||||
bt_dev->acpi_dev = device;
|
||||
device->driver_data = bt_dev;
|
||||
dev_set_drvdata(&device->dev, bt_dev);
|
||||
|
||||
platform_set_drvdata(pdev, bt_dev);
|
||||
|
||||
result = toshiba_bluetooth_sync_status(bt_dev);
|
||||
if (result) {
|
||||
|
|
@ -256,14 +254,14 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device)
|
|||
}
|
||||
|
||||
bt_dev->rfk = rfkill_alloc("Toshiba Bluetooth",
|
||||
&device->dev,
|
||||
&pdev->dev,
|
||||
RFKILL_TYPE_BLUETOOTH,
|
||||
&rfk_ops,
|
||||
bt_dev);
|
||||
if (!bt_dev->rfk) {
|
||||
pr_err("Unable to allocate rfkill device\n");
|
||||
kfree(bt_dev);
|
||||
return -ENOMEM;
|
||||
result = -ENOMEM;
|
||||
goto err_free_bt_dev;
|
||||
}
|
||||
|
||||
rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch);
|
||||
|
|
@ -271,18 +269,36 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device)
|
|||
result = rfkill_register(bt_dev->rfk);
|
||||
if (result) {
|
||||
pr_err("Unable to register rfkill device\n");
|
||||
rfkill_destroy(bt_dev->rfk);
|
||||
kfree(bt_dev);
|
||||
goto err_rfkill_destroy;
|
||||
}
|
||||
|
||||
result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
toshiba_bt_rfkill_notify, bt_dev);
|
||||
if (result) {
|
||||
pr_err("Unable to register ACPI notify handler\n");
|
||||
goto err_rfkill_unregister;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_rfkill_unregister:
|
||||
rfkill_unregister(bt_dev->rfk);
|
||||
err_rfkill_destroy:
|
||||
rfkill_destroy(bt_dev->rfk);
|
||||
err_free_bt_dev:
|
||||
kfree(bt_dev);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void toshiba_bt_rfkill_remove(struct acpi_device *device)
|
||||
static void toshiba_bt_rfkill_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device);
|
||||
struct toshiba_bluetooth_dev *bt_dev = platform_get_drvdata(pdev);
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
|
||||
/* clean up */
|
||||
acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
toshiba_bt_rfkill_notify);
|
||||
|
||||
if (bt_dev->rfk) {
|
||||
rfkill_unregister(bt_dev->rfk);
|
||||
rfkill_destroy(bt_dev->rfk);
|
||||
|
|
@ -293,4 +309,4 @@ static void toshiba_bt_rfkill_remove(struct acpi_device *device)
|
|||
toshiba_bluetooth_disable(device->handle);
|
||||
}
|
||||
|
||||
module_acpi_driver(toshiba_bt_rfkill_driver);
|
||||
module_platform_driver(toshiba_bt_rfkill_driver);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
MODULE_AUTHOR("Azael Avalos <coproscefalo@gmail.com>");
|
||||
MODULE_DESCRIPTION("Toshiba HDD Active Protection Sensor");
|
||||
|
|
@ -129,8 +130,10 @@ static const struct attribute_group haps_attr_group = {
|
|||
/*
|
||||
* ACPI stuff
|
||||
*/
|
||||
static void toshiba_haps_notify(struct acpi_device *device, u32 event)
|
||||
static void toshiba_haps_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct acpi_device *device = data;
|
||||
|
||||
pr_debug("Received event: 0x%x\n", event);
|
||||
|
||||
acpi_bus_generate_netlink_event(device->pnp.device_class,
|
||||
|
|
@ -138,12 +141,19 @@ static void toshiba_haps_notify(struct acpi_device *device, u32 event)
|
|||
event, 0);
|
||||
}
|
||||
|
||||
static void toshiba_haps_remove(struct acpi_device *device)
|
||||
static void toshiba_haps_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
|
||||
acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
toshiba_haps_notify);
|
||||
|
||||
sysfs_remove_group(&device->dev.kobj, &haps_attr_group);
|
||||
|
||||
if (toshiba_haps)
|
||||
toshiba_haps = NULL;
|
||||
|
||||
dev_set_drvdata(&device->dev, NULL);
|
||||
}
|
||||
|
||||
/* Helper function */
|
||||
|
|
@ -170,8 +180,9 @@ static int toshiba_haps_available(acpi_handle handle)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int toshiba_haps_add(struct acpi_device *acpi_dev)
|
||||
static int toshiba_haps_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev);
|
||||
struct toshiba_haps_dev *haps;
|
||||
int ret;
|
||||
|
||||
|
|
@ -183,14 +194,15 @@ static int toshiba_haps_add(struct acpi_device *acpi_dev)
|
|||
|
||||
pr_info("Toshiba HDD Active Protection Sensor device\n");
|
||||
|
||||
haps = devm_kzalloc(&acpi_dev->dev, sizeof(*haps), GFP_KERNEL);
|
||||
haps = devm_kzalloc(&pdev->dev, sizeof(*haps), GFP_KERNEL);
|
||||
if (!haps)
|
||||
return -ENOMEM;
|
||||
|
||||
haps->acpi_dev = acpi_dev;
|
||||
haps->protection_level = 2;
|
||||
acpi_dev->driver_data = haps;
|
||||
|
||||
dev_set_drvdata(&acpi_dev->dev, haps);
|
||||
platform_set_drvdata(pdev, haps);
|
||||
|
||||
/* Set the protection level, currently at level 2 (Medium) */
|
||||
ret = toshiba_haps_protection_level(acpi_dev->handle, 2);
|
||||
|
|
@ -201,19 +213,26 @@ static int toshiba_haps_add(struct acpi_device *acpi_dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = acpi_dev_install_notify_handler(acpi_dev, ACPI_DEVICE_NOTIFY,
|
||||
toshiba_haps_notify, acpi_dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
toshiba_haps = haps;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
sysfs_remove_group(&acpi_dev->dev.kobj, &haps_attr_group);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int toshiba_haps_suspend(struct device *device)
|
||||
{
|
||||
struct toshiba_haps_dev *haps;
|
||||
struct toshiba_haps_dev *haps = dev_get_drvdata(device);
|
||||
int ret;
|
||||
|
||||
haps = acpi_driver_data(to_acpi_device(device));
|
||||
|
||||
/* Deactivate the protection on suspend */
|
||||
ret = toshiba_haps_protection_level(haps->acpi_dev->handle, 0);
|
||||
|
||||
|
|
@ -222,11 +241,9 @@ static int toshiba_haps_suspend(struct device *device)
|
|||
|
||||
static int toshiba_haps_resume(struct device *device)
|
||||
{
|
||||
struct toshiba_haps_dev *haps;
|
||||
struct toshiba_haps_dev *haps = dev_get_drvdata(device);
|
||||
int ret;
|
||||
|
||||
haps = acpi_driver_data(to_acpi_device(device));
|
||||
|
||||
/* Set the stored protection level */
|
||||
ret = toshiba_haps_protection_level(haps->acpi_dev->handle,
|
||||
haps->protection_level);
|
||||
|
|
@ -249,16 +266,14 @@ static const struct acpi_device_id haps_device_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, haps_device_ids);
|
||||
|
||||
static struct acpi_driver toshiba_haps_driver = {
|
||||
.name = "Toshiba HAPS",
|
||||
.ids = haps_device_ids,
|
||||
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
|
||||
.ops = {
|
||||
.add = toshiba_haps_add,
|
||||
.remove = toshiba_haps_remove,
|
||||
.notify = toshiba_haps_notify,
|
||||
static struct platform_driver toshiba_haps_driver = {
|
||||
.probe = toshiba_haps_probe,
|
||||
.remove = toshiba_haps_remove,
|
||||
.driver = {
|
||||
.name = "Toshiba HAPS",
|
||||
.acpi_match_table = haps_device_ids,
|
||||
.pm = &toshiba_haps_pm,
|
||||
},
|
||||
.drv.pm = &toshiba_haps_pm,
|
||||
};
|
||||
|
||||
module_acpi_driver(toshiba_haps_driver);
|
||||
module_platform_driver(toshiba_haps_driver);
|
||||
|
|
|
|||
|
|
@ -110,6 +110,8 @@
|
|||
#define EC_ADDR_BAT_CYCLE_COUNT_2 0x04A7
|
||||
|
||||
#define EC_ADDR_PROJECT_ID 0x0740
|
||||
#define PROJECT_ID_PH4TRX1 0x12
|
||||
#define PROJECT_ID_PH6TRX1 0x15
|
||||
|
||||
#define EC_ADDR_AP_OEM 0x0741
|
||||
#define ENABLE_MANUAL_CTRL BIT(0)
|
||||
|
|
@ -266,8 +268,8 @@
|
|||
#define BATTERY_CHARGE_FULL_OVER_24H BIT(3)
|
||||
#define BATTERY_ERM_STATUS_REACHED BIT(4)
|
||||
|
||||
#define EC_ADDR_CHARGE_PRIO 0x07CC
|
||||
#define CHARGING_PERFORMANCE BIT(7)
|
||||
#define EC_ADDR_USB_C_POWER_PRIORITY 0x07CC
|
||||
#define USB_C_POWER_PRIORITY BIT(7)
|
||||
|
||||
/* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */
|
||||
#define EC_ADDR_LIGHTBAR_BAT_CTRL 0x07E2
|
||||
|
|
@ -319,8 +321,17 @@
|
|||
#define UNIWILL_FEATURE_TOUCHPAD_TOGGLE BIT(2)
|
||||
#define UNIWILL_FEATURE_LIGHTBAR BIT(3)
|
||||
#define UNIWILL_FEATURE_BATTERY BIT(4)
|
||||
#define UNIWILL_FEATURE_HWMON BIT(5)
|
||||
#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL BIT(6)
|
||||
#define UNIWILL_FEATURE_CPU_TEMP BIT(5)
|
||||
#define UNIWILL_FEATURE_GPU_TEMP BIT(6)
|
||||
#define UNIWILL_FEATURE_PRIMARY_FAN BIT(7)
|
||||
#define UNIWILL_FEATURE_SECONDARY_FAN BIT(8)
|
||||
#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL BIT(9)
|
||||
#define UNIWILL_FEATURE_USB_C_POWER_PRIORITY BIT(10)
|
||||
|
||||
enum usb_c_power_priority_options {
|
||||
USB_C_POWER_PRIORITY_CHARGING = 0,
|
||||
USB_C_POWER_PRIORITY_PERFORMANCE,
|
||||
};
|
||||
|
||||
struct uniwill_data {
|
||||
struct device *dev;
|
||||
|
|
@ -340,6 +351,8 @@ struct uniwill_data {
|
|||
struct mutex input_lock; /* Protects input sequence during notify */
|
||||
struct input_dev *input_device;
|
||||
struct notifier_block nb;
|
||||
struct mutex usb_c_power_priority_lock; /* Protects dependent bit write and state safe */
|
||||
enum usb_c_power_priority_options last_usb_c_power_priority_option;
|
||||
};
|
||||
|
||||
struct uniwill_battery_entry {
|
||||
|
|
@ -427,7 +440,7 @@ static const struct key_entry uniwill_keymap[] = {
|
|||
{ KE_END }
|
||||
};
|
||||
|
||||
static inline bool uniwill_device_supports(struct uniwill_data *data,
|
||||
static inline bool uniwill_device_supports(const struct uniwill_data *data,
|
||||
unsigned int features)
|
||||
{
|
||||
return (data->features & features) == features;
|
||||
|
|
@ -524,6 +537,7 @@ static bool uniwill_writeable_reg(struct device *dev, unsigned int reg)
|
|||
case EC_ADDR_CTGP_DB_CTGP_OFFSET:
|
||||
case EC_ADDR_CTGP_DB_TPP_OFFSET:
|
||||
case EC_ADDR_CTGP_DB_DB_OFFSET:
|
||||
case EC_ADDR_USB_C_POWER_PRIORITY:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -562,6 +576,7 @@ static bool uniwill_readable_reg(struct device *dev, unsigned int reg)
|
|||
case EC_ADDR_CTGP_DB_CTGP_OFFSET:
|
||||
case EC_ADDR_CTGP_DB_TPP_OFFSET:
|
||||
case EC_ADDR_CTGP_DB_DB_OFFSET:
|
||||
case EC_ADDR_USB_C_POWER_PRIORITY:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -584,6 +599,7 @@ static bool uniwill_volatile_reg(struct device *dev, unsigned int reg)
|
|||
case EC_ADDR_TRIGGER:
|
||||
case EC_ADDR_SWITCH_STATUS:
|
||||
case EC_ADDR_CHARGE_CTRL:
|
||||
case EC_ADDR_USB_C_POWER_PRIORITY:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -880,6 +896,105 @@ static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char * const usb_c_power_priority_text[] = {
|
||||
[USB_C_POWER_PRIORITY_CHARGING] = "charging",
|
||||
[USB_C_POWER_PRIORITY_PERFORMANCE] = "performance",
|
||||
};
|
||||
|
||||
static const u8 usb_c_power_priority_value[] = {
|
||||
[USB_C_POWER_PRIORITY_CHARGING] = 0,
|
||||
[USB_C_POWER_PRIORITY_PERFORMANCE] = USB_C_POWER_PRIORITY,
|
||||
};
|
||||
|
||||
static ssize_t usb_c_power_priority_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct uniwill_data *data = dev_get_drvdata(dev);
|
||||
enum usb_c_power_priority_options option;
|
||||
unsigned int value;
|
||||
int ret;
|
||||
|
||||
ret = sysfs_match_string(usb_c_power_priority_text, buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
option = ret;
|
||||
value = usb_c_power_priority_value[option];
|
||||
|
||||
guard(mutex)(&data->usb_c_power_priority_lock);
|
||||
|
||||
ret = regmap_update_bits(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY,
|
||||
USB_C_POWER_PRIORITY, value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->last_usb_c_power_priority_option = option;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t usb_c_power_priority_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct uniwill_data *data = dev_get_drvdata(dev);
|
||||
unsigned int value;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
value &= USB_C_POWER_PRIORITY;
|
||||
|
||||
if (usb_c_power_priority_value[USB_C_POWER_PRIORITY_PERFORMANCE] == value)
|
||||
return sysfs_emit(buf, "%s\n",
|
||||
usb_c_power_priority_text[USB_C_POWER_PRIORITY_PERFORMANCE]);
|
||||
|
||||
return sysfs_emit(buf, "%s\n", usb_c_power_priority_text[USB_C_POWER_PRIORITY_CHARGING]);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(usb_c_power_priority);
|
||||
|
||||
static int usb_c_power_priority_restore(struct uniwill_data *data)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
value = usb_c_power_priority_value[data->last_usb_c_power_priority_option];
|
||||
|
||||
guard(mutex)(&data->usb_c_power_priority_lock);
|
||||
|
||||
return regmap_update_bits(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY,
|
||||
USB_C_POWER_PRIORITY, value);
|
||||
}
|
||||
|
||||
static int usb_c_power_priority_init(struct uniwill_data *data)
|
||||
{
|
||||
unsigned int value;
|
||||
int ret;
|
||||
|
||||
if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY))
|
||||
return 0;
|
||||
|
||||
ret = devm_mutex_init(data->dev, &data->usb_c_power_priority_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
value &= USB_C_POWER_PRIORITY;
|
||||
|
||||
data->last_usb_c_power_priority_option =
|
||||
usb_c_power_priority_value[USB_C_POWER_PRIORITY_PERFORMANCE] == value ?
|
||||
USB_C_POWER_PRIORITY_PERFORMANCE :
|
||||
USB_C_POWER_PRIORITY_CHARGING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct attribute *uniwill_attrs[] = {
|
||||
/* Keyboard-related */
|
||||
&dev_attr_fn_lock.attr,
|
||||
|
|
@ -890,6 +1005,7 @@ static struct attribute *uniwill_attrs[] = {
|
|||
&dev_attr_breathing_in_suspend.attr,
|
||||
/* Power-management-related */
|
||||
&dev_attr_ctgp_offset.attr,
|
||||
&dev_attr_usb_c_power_priority.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -924,6 +1040,11 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
|
|||
return attr->mode;
|
||||
}
|
||||
|
||||
if (attr == &dev_attr_usb_c_power_priority.attr) {
|
||||
if (uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY))
|
||||
return attr->mode;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -937,6 +1058,48 @@ static const struct attribute_group *uniwill_groups[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static umode_t uniwill_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
|
||||
int channel)
|
||||
{
|
||||
const struct uniwill_data *data = drvdata;
|
||||
unsigned int feature;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
switch (channel) {
|
||||
case 0:
|
||||
feature = UNIWILL_FEATURE_CPU_TEMP;
|
||||
break;
|
||||
case 1:
|
||||
feature = UNIWILL_FEATURE_GPU_TEMP;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case hwmon_fan:
|
||||
case hwmon_pwm:
|
||||
switch (channel) {
|
||||
case 0:
|
||||
feature = UNIWILL_FEATURE_PRIMARY_FAN;
|
||||
break;
|
||||
case 1:
|
||||
feature = UNIWILL_FEATURE_SECONDARY_FAN;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uniwill_device_supports(data, feature))
|
||||
return 0444;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniwill_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
|
||||
long *val)
|
||||
{
|
||||
|
|
@ -1020,7 +1183,7 @@ static int uniwill_read_string(struct device *dev, enum hwmon_sensor_types type,
|
|||
}
|
||||
|
||||
static const struct hwmon_ops uniwill_ops = {
|
||||
.visible = 0444,
|
||||
.is_visible = uniwill_is_visible,
|
||||
.read = uniwill_read,
|
||||
.read_string = uniwill_read_string,
|
||||
};
|
||||
|
|
@ -1048,7 +1211,10 @@ static int uniwill_hwmon_init(struct uniwill_data *data)
|
|||
{
|
||||
struct device *hdev;
|
||||
|
||||
if (!uniwill_device_supports(data, UNIWILL_FEATURE_HWMON))
|
||||
if (!uniwill_device_supports(data, UNIWILL_FEATURE_CPU_TEMP) &&
|
||||
!uniwill_device_supports(data, UNIWILL_FEATURE_GPU_TEMP) &&
|
||||
!uniwill_device_supports(data, UNIWILL_FEATURE_PRIMARY_FAN) &&
|
||||
!uniwill_device_supports(data, UNIWILL_FEATURE_SECONDARY_FAN))
|
||||
return 0;
|
||||
|
||||
hdev = devm_hwmon_device_register_with_info(data->dev, "uniwill", data,
|
||||
|
|
@ -1369,11 +1535,10 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
|
|||
|
||||
return NOTIFY_OK;
|
||||
case UNIWILL_OSD_DC_ADAPTER_CHANGED:
|
||||
/* noop for the time being, will change once charging priority
|
||||
* gets implemented.
|
||||
*/
|
||||
if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
return NOTIFY_OK;
|
||||
return notifier_from_errno(usb_c_power_priority_restore(data));
|
||||
case UNIWILL_OSD_FN_LOCK:
|
||||
if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
|
||||
return NOTIFY_DONE;
|
||||
|
|
@ -1467,6 +1632,7 @@ static int uniwill_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(regmap);
|
||||
|
||||
data->regmap = regmap;
|
||||
|
||||
ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -1504,6 +1670,10 @@ static int uniwill_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = usb_c_power_priority_init(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return uniwill_input_init(data);
|
||||
}
|
||||
|
||||
|
|
@ -1633,6 +1803,14 @@ static int uniwill_resume_nvidia_ctgp(struct uniwill_data *data)
|
|||
CTGP_DB_DB_ENABLE | CTGP_DB_CTGP_ENABLE);
|
||||
}
|
||||
|
||||
static int uniwill_resume_usb_c_power_priority(struct uniwill_data *data)
|
||||
{
|
||||
if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY))
|
||||
return 0;
|
||||
|
||||
return usb_c_power_priority_restore(data);
|
||||
}
|
||||
|
||||
static int uniwill_resume(struct device *dev)
|
||||
{
|
||||
struct uniwill_data *data = dev_get_drvdata(dev);
|
||||
|
|
@ -1656,7 +1834,11 @@ static int uniwill_resume(struct device *dev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return uniwill_resume_nvidia_ctgp(data);
|
||||
ret = uniwill_resume_nvidia_ctgp(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return uniwill_resume_usb_c_power_priority(data);
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, uniwill_resume);
|
||||
|
|
@ -1682,12 +1864,24 @@ static struct platform_driver uniwill_driver = {
|
|||
.shutdown = uniwill_shutdown,
|
||||
};
|
||||
|
||||
static struct uniwill_device_descriptor lapqc71a_lapqc71b_descriptor __initdata = {
|
||||
.features = UNIWILL_FEATURE_SUPER_KEY |
|
||||
UNIWILL_FEATURE_BATTERY |
|
||||
UNIWILL_FEATURE_CPU_TEMP |
|
||||
UNIWILL_FEATURE_GPU_TEMP |
|
||||
UNIWILL_FEATURE_PRIMARY_FAN |
|
||||
UNIWILL_FEATURE_SECONDARY_FAN,
|
||||
};
|
||||
|
||||
static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
|
||||
.features = UNIWILL_FEATURE_FN_LOCK |
|
||||
UNIWILL_FEATURE_SUPER_KEY |
|
||||
UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
|
||||
UNIWILL_FEATURE_BATTERY |
|
||||
UNIWILL_FEATURE_HWMON,
|
||||
UNIWILL_FEATURE_CPU_TEMP |
|
||||
UNIWILL_FEATURE_GPU_TEMP |
|
||||
UNIWILL_FEATURE_PRIMARY_FAN |
|
||||
UNIWILL_FEATURE_SECONDARY_FAN,
|
||||
};
|
||||
|
||||
static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
|
||||
|
|
@ -1696,7 +1890,89 @@ static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
|
|||
UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
|
||||
UNIWILL_FEATURE_LIGHTBAR |
|
||||
UNIWILL_FEATURE_BATTERY |
|
||||
UNIWILL_FEATURE_HWMON,
|
||||
UNIWILL_FEATURE_CPU_TEMP |
|
||||
UNIWILL_FEATURE_GPU_TEMP |
|
||||
UNIWILL_FEATURE_PRIMARY_FAN |
|
||||
UNIWILL_FEATURE_SECONDARY_FAN,
|
||||
};
|
||||
|
||||
/*
|
||||
* The featuresets below reflect somewhat chronological changes:
|
||||
* 1 -> 2: UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL is added to the EC firmware.
|
||||
* 2 -> 3: UNIWILL_FEATURE_USB_C_POWER_PRIORITY is removed from the EC firmware.
|
||||
* Some devices might divert from this timeline.
|
||||
*/
|
||||
|
||||
static struct uniwill_device_descriptor tux_featureset_1_descriptor __initdata = {
|
||||
.features = UNIWILL_FEATURE_FN_LOCK |
|
||||
UNIWILL_FEATURE_SUPER_KEY |
|
||||
UNIWILL_FEATURE_CPU_TEMP |
|
||||
UNIWILL_FEATURE_PRIMARY_FAN |
|
||||
UNIWILL_FEATURE_SECONDARY_FAN |
|
||||
UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
|
||||
};
|
||||
|
||||
static struct uniwill_device_descriptor tux_featureset_1_nvidia_descriptor __initdata = {
|
||||
.features = UNIWILL_FEATURE_FN_LOCK |
|
||||
UNIWILL_FEATURE_SUPER_KEY |
|
||||
UNIWILL_FEATURE_CPU_TEMP |
|
||||
UNIWILL_FEATURE_GPU_TEMP |
|
||||
UNIWILL_FEATURE_PRIMARY_FAN |
|
||||
UNIWILL_FEATURE_SECONDARY_FAN |
|
||||
UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
|
||||
};
|
||||
|
||||
static struct uniwill_device_descriptor tux_featureset_2_nvidia_descriptor __initdata = {
|
||||
.features = UNIWILL_FEATURE_FN_LOCK |
|
||||
UNIWILL_FEATURE_SUPER_KEY |
|
||||
UNIWILL_FEATURE_CPU_TEMP |
|
||||
UNIWILL_FEATURE_GPU_TEMP |
|
||||
UNIWILL_FEATURE_PRIMARY_FAN |
|
||||
UNIWILL_FEATURE_SECONDARY_FAN |
|
||||
UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL |
|
||||
UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
|
||||
};
|
||||
|
||||
static struct uniwill_device_descriptor tux_featureset_3_descriptor __initdata = {
|
||||
.features = UNIWILL_FEATURE_FN_LOCK |
|
||||
UNIWILL_FEATURE_SUPER_KEY |
|
||||
UNIWILL_FEATURE_CPU_TEMP |
|
||||
UNIWILL_FEATURE_PRIMARY_FAN |
|
||||
UNIWILL_FEATURE_SECONDARY_FAN,
|
||||
};
|
||||
|
||||
static struct uniwill_device_descriptor tux_featureset_3_nvidia_descriptor __initdata = {
|
||||
.features = UNIWILL_FEATURE_FN_LOCK |
|
||||
UNIWILL_FEATURE_SUPER_KEY |
|
||||
UNIWILL_FEATURE_CPU_TEMP |
|
||||
UNIWILL_FEATURE_GPU_TEMP |
|
||||
UNIWILL_FEATURE_PRIMARY_FAN |
|
||||
UNIWILL_FEATURE_SECONDARY_FAN |
|
||||
UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL,
|
||||
};
|
||||
|
||||
static int phxtxx1_probe(struct uniwill_data *data)
|
||||
{
|
||||
unsigned int value;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, EC_ADDR_PROJECT_ID, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (value == PROJECT_ID_PH4TRX1 || value == PROJECT_ID_PH6TRX1)
|
||||
data->features |= UNIWILL_FEATURE_SECONDARY_FAN;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static struct uniwill_device_descriptor phxtxx1_descriptor __initdata = {
|
||||
.features = UNIWILL_FEATURE_FN_LOCK |
|
||||
UNIWILL_FEATURE_SUPER_KEY |
|
||||
UNIWILL_FEATURE_CPU_TEMP |
|
||||
UNIWILL_FEATURE_PRIMARY_FAN |
|
||||
UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
|
||||
.probe = phxtxx1_probe,
|
||||
};
|
||||
|
||||
static int phxarx1_phxaqf1_probe(struct uniwill_data *data)
|
||||
|
|
@ -1709,37 +1985,61 @@ static int phxarx1_phxaqf1_probe(struct uniwill_data *data)
|
|||
return ret;
|
||||
|
||||
if (value & HAS_GPU)
|
||||
data->features |= UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL;
|
||||
data->features |= UNIWILL_FEATURE_GPU_TEMP |
|
||||
UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static struct uniwill_device_descriptor phxarx1_phxaqf1_descriptor __initdata = {
|
||||
.features = UNIWILL_FEATURE_FN_LOCK |
|
||||
UNIWILL_FEATURE_SUPER_KEY |
|
||||
UNIWILL_FEATURE_CPU_TEMP |
|
||||
UNIWILL_FEATURE_PRIMARY_FAN |
|
||||
UNIWILL_FEATURE_SECONDARY_FAN |
|
||||
UNIWILL_FEATURE_USB_C_POWER_PRIORITY,
|
||||
.probe = phxarx1_phxaqf1_probe,
|
||||
};
|
||||
|
||||
static struct uniwill_device_descriptor tux_featureset_1_descriptor __initdata = {
|
||||
.features = UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL,
|
||||
static struct uniwill_device_descriptor pf5pu1g_descriptor __initdata = {
|
||||
.features = UNIWILL_FEATURE_FN_LOCK |
|
||||
UNIWILL_FEATURE_SUPER_KEY |
|
||||
UNIWILL_FEATURE_CPU_TEMP |
|
||||
UNIWILL_FEATURE_PRIMARY_FAN,
|
||||
};
|
||||
|
||||
static struct uniwill_device_descriptor empty_descriptor __initdata = {};
|
||||
|
||||
static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
||||
{
|
||||
.ident = "XMG FUSION 15",
|
||||
.ident = "XMG FUSION 15 (L19)",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &lapqc71a_lapqc71b_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "XMG FUSION 15",
|
||||
.ident = "XMG FUSION 15 (L19)",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &lapqc71a_lapqc71b_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "XMG FUSION 15 (L19)",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
|
||||
},
|
||||
.driver_data = &lapqc71a_lapqc71b_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "XMG FUSION 15 (L19)",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
|
||||
},
|
||||
.driver_data = &lapqc71a_lapqc71b_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "Intel NUC x15",
|
||||
|
|
@ -1763,7 +2063,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTxX1"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &phxtxx1_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
|
||||
|
|
@ -1771,7 +2071,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_2_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
|
||||
|
|
@ -1787,7 +2087,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_2_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
|
||||
|
|
@ -1795,7 +2095,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PRX1_PH6PRX1"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Pro 14 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
|
||||
|
|
@ -1803,7 +2103,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_2_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
|
||||
|
|
@ -1811,7 +2111,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_2_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
|
||||
|
|
@ -1819,7 +2119,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxHRXx"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_3_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 Intel/Commodore Omnia-Book 15 Gen9",
|
||||
|
|
@ -1827,7 +2127,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxMRXx"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_3_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
|
||||
|
|
@ -1835,7 +2135,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxHP4NAx"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_3_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
|
||||
|
|
@ -1843,7 +2143,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_3_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Pro 15 Gen10 Intel",
|
||||
|
|
@ -1851,7 +2151,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxAR4NAx"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_3_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Max 15 Gen10 AMD",
|
||||
|
|
@ -1859,7 +2159,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5KK45xS_X5SP45xS"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
|
||||
|
|
@ -1867,7 +2167,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6HP45xU"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
|
||||
|
|
@ -1875,7 +2175,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Max 15 Gen10 Intel",
|
||||
|
|
@ -1883,7 +2183,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5AR45xS"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO InfinityBook Max 16 Gen10 Intel",
|
||||
|
|
@ -1891,7 +2191,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR55xU"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Polaris 15 Gen1 AMD",
|
||||
|
|
@ -1899,7 +2199,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Polaris 15 Gen1 AMD",
|
||||
|
|
@ -1907,7 +2207,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Polaris 17 Gen1 AMD",
|
||||
|
|
@ -1915,7 +2215,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Polaris 17 Gen1 AMD",
|
||||
|
|
@ -1923,7 +2223,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Polaris 15 Gen1 Intel",
|
||||
|
|
@ -1931,7 +2231,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I1650TI"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Polaris 15 Gen1 Intel",
|
||||
|
|
@ -1939,7 +2239,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I2060"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Polaris 17 Gen1 Intel",
|
||||
|
|
@ -1947,7 +2247,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I1650TI"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Polaris 17 Gen1 Intel",
|
||||
|
|
@ -1955,7 +2255,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I2060"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Trinity 15 Intel Gen1",
|
||||
|
|
@ -1963,7 +2263,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1501I"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Trinity 17 Intel Gen1",
|
||||
|
|
@ -1971,7 +2271,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1701I"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Polaris 15/17 Gen2 AMD",
|
||||
|
|
@ -1979,7 +2279,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_2_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Polaris 15/17 Gen2 Intel",
|
||||
|
|
@ -1987,7 +2287,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_2_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
|
||||
|
|
@ -1995,7 +2295,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_2_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
|
||||
|
|
@ -2003,7 +2303,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_2_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
|
||||
|
|
@ -2011,7 +2311,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris 15 Gen4 Intel",
|
||||
|
|
@ -2019,7 +2319,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Polaris 15/17 Gen5 AMD",
|
||||
|
|
@ -2027,7 +2327,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_2_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris 16 Gen5 AMD",
|
||||
|
|
@ -2035,7 +2335,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
|
||||
|
|
@ -2043,7 +2343,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
|
||||
|
|
@ -2051,7 +2351,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6",
|
||||
|
|
@ -2059,7 +2359,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
|
||||
|
|
@ -2067,7 +2367,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
|
||||
|
|
@ -2075,7 +2375,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
|
||||
|
|
@ -2083,7 +2383,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris 16 Gen7 AMD",
|
||||
|
|
@ -2091,7 +2391,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris 16 Gen7 Intel",
|
||||
|
|
@ -2099,7 +2399,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Stellaris 16 Gen7 Intel",
|
||||
|
|
@ -2107,7 +2407,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
|
||||
},
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
.driver_data = &tux_featureset_3_nvidia_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Book BA15 Gen10 AMD",
|
||||
|
|
@ -2115,7 +2415,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &pf5pu1g_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Pulse 14 Gen1 AMD",
|
||||
|
|
@ -2123,7 +2423,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1401"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Pulse 15 Gen1 AMD",
|
||||
|
|
@ -2131,7 +2431,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1501"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
},
|
||||
{
|
||||
.ident = "TUXEDO Pulse 15 Gen2 AMD",
|
||||
|
|
@ -2139,7 +2439,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
|
||||
},
|
||||
.driver_data = &empty_descriptor,
|
||||
.driver_data = &tux_featureset_1_descriptor,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ static struct wmi_driver uniwill_wmi_driver = {
|
|||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.id_table = uniwill_wmi_id_table,
|
||||
.min_event_size = sizeof(u32),
|
||||
.notify = uniwill_wmi_notify,
|
||||
.no_singleton = true,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,16 +35,17 @@ static const struct acpi_device_id wl_ids[] = {
|
|||
{"", 0},
|
||||
};
|
||||
|
||||
static int wireless_input_setup(struct acpi_device *device)
|
||||
static int wireless_input_setup(struct device *dev)
|
||||
{
|
||||
struct wl_button *button = acpi_driver_data(device);
|
||||
struct wl_button *button = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
button->input_dev = input_allocate_device();
|
||||
if (!button->input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(button->phys, sizeof(button->phys), "%s/input0", acpi_device_hid(device));
|
||||
snprintf(button->phys, sizeof(button->phys), "%s/input0",
|
||||
acpi_device_hid(ACPI_COMPANION(dev)));
|
||||
|
||||
button->input_dev->name = "Wireless hotkeys";
|
||||
button->input_dev->phys = button->phys;
|
||||
|
|
@ -63,17 +64,17 @@ err_free_dev:
|
|||
return err;
|
||||
}
|
||||
|
||||
static void wireless_input_destroy(struct acpi_device *device)
|
||||
static void wireless_input_destroy(struct device *dev)
|
||||
{
|
||||
struct wl_button *button = acpi_driver_data(device);
|
||||
struct wl_button *button = dev_get_drvdata(dev);
|
||||
|
||||
input_unregister_device(button->input_dev);
|
||||
kfree(button);
|
||||
}
|
||||
|
||||
static void wl_notify(struct acpi_device *acpi_dev, u32 event)
|
||||
static void wl_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct wl_button *button = acpi_driver_data(acpi_dev);
|
||||
struct wl_button *button = data;
|
||||
|
||||
if (event != 0x80) {
|
||||
pr_info("Received unknown event (0x%x)\n", event);
|
||||
|
|
@ -86,7 +87,7 @@ static void wl_notify(struct acpi_device *acpi_dev, u32 event)
|
|||
input_sync(button->input_dev);
|
||||
}
|
||||
|
||||
static int wl_add(struct acpi_device *device)
|
||||
static int wl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wl_button *button;
|
||||
int err;
|
||||
|
|
@ -95,30 +96,38 @@ static int wl_add(struct acpi_device *device)
|
|||
if (!button)
|
||||
return -ENOMEM;
|
||||
|
||||
device->driver_data = button;
|
||||
platform_set_drvdata(pdev, button);
|
||||
|
||||
err = wireless_input_setup(device);
|
||||
err = wireless_input_setup(&pdev->dev);
|
||||
if (err) {
|
||||
pr_err("Failed to setup wireless hotkeys\n");
|
||||
kfree(button);
|
||||
return err;
|
||||
}
|
||||
err = acpi_dev_install_notify_handler(ACPI_COMPANION(&pdev->dev),
|
||||
ACPI_DEVICE_NOTIFY, wl_notify, button);
|
||||
if (err) {
|
||||
pr_err("Failed to install ACPI notify handler\n");
|
||||
wireless_input_destroy(&pdev->dev);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void wl_remove(struct acpi_device *device)
|
||||
static void wl_remove(struct platform_device *pdev)
|
||||
{
|
||||
wireless_input_destroy(device);
|
||||
acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
|
||||
ACPI_DEVICE_NOTIFY, wl_notify);
|
||||
wireless_input_destroy(&pdev->dev);
|
||||
}
|
||||
|
||||
static struct acpi_driver wl_driver = {
|
||||
.name = "wireless-hotkey",
|
||||
.ids = wl_ids,
|
||||
.ops = {
|
||||
.add = wl_add,
|
||||
.remove = wl_remove,
|
||||
.notify = wl_notify,
|
||||
static struct platform_driver wl_driver = {
|
||||
.probe = wl_probe,
|
||||
.remove = wl_remove,
|
||||
.driver = {
|
||||
.name = "wireless-hotkey",
|
||||
.acpi_match_table = wl_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_acpi_driver(wl_driver);
|
||||
module_platform_driver(wl_driver);
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ static int wmi_bmof_probe(struct wmi_device *wdev, const void *context)
|
|||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = wmidev_query_block(wdev, 0, buffer);
|
||||
ret = wmidev_query_block(wdev, 0, buffer, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ static struct wmi_driver xiaomi_wmi_driver = {
|
|||
.name = "xiaomi-wmi",
|
||||
},
|
||||
.id_table = xiaomi_wmi_id_table,
|
||||
.min_event_size = 0,
|
||||
.probe = xiaomi_wmi_probe,
|
||||
.notify_new = xiaomi_wmi_notify,
|
||||
.no_singleton = true,
|
||||
|
|
|
|||
|
|
@ -29,9 +29,15 @@
|
|||
#define INTEL_DVSEC_TABLE_OFFSET(x) ((x) & GENMASK(31, 3))
|
||||
#define TABLE_OFFSET_SHIFT 3
|
||||
|
||||
struct device;
|
||||
struct pci_dev;
|
||||
struct resource;
|
||||
|
||||
enum intel_vsec_disc_source {
|
||||
INTEL_VSEC_DISC_PCI, /* PCI, default */
|
||||
INTEL_VSEC_DISC_ACPI, /* ACPI */
|
||||
};
|
||||
|
||||
enum intel_vsec_id {
|
||||
VSEC_ID_TELEMETRY = 2,
|
||||
VSEC_ID_WATCHER = 3,
|
||||
|
|
@ -82,14 +88,14 @@ enum intel_vsec_quirks {
|
|||
* struct pmt_callbacks - Callback infrastructure for PMT devices
|
||||
* @read_telem: when specified, called by client driver to access PMT
|
||||
* data (instead of direct copy).
|
||||
* * pdev: PCI device reference for the callback's use
|
||||
* * dev: device reference for the callback's use
|
||||
* * guid: ID of data to acccss
|
||||
* * data: buffer for the data to be copied
|
||||
* * off: offset into the requested buffer
|
||||
* * count: size of buffer
|
||||
*/
|
||||
struct pmt_callbacks {
|
||||
int (*read_telem)(struct pci_dev *pdev, u32 guid, u64 *data, loff_t off, u32 count);
|
||||
int (*read_telem)(struct device *dev, u32 guid, u64 *data, loff_t off, u32 count);
|
||||
};
|
||||
|
||||
struct vsec_feature_dependency {
|
||||
|
|
@ -102,6 +108,10 @@ struct vsec_feature_dependency {
|
|||
* @parent: parent device in the auxbus chain
|
||||
* @headers: list of headers to define the PMT client devices to create
|
||||
* @deps: array of feature dependencies
|
||||
* @acpi_disc: ACPI discovery tables, each entry is two QWORDs
|
||||
* in little-endian format as defined by the PMT ACPI spec.
|
||||
* Valid only when @provider == INTEL_VSEC_DISC_ACPI.
|
||||
* @src: source of discovery table data
|
||||
* @priv_data: private data, usable by parent devices, currently a callback
|
||||
* @caps: bitmask of PMT capabilities for the given headers
|
||||
* @quirks: bitmask of VSEC device quirks
|
||||
|
|
@ -112,6 +122,8 @@ struct intel_vsec_platform_info {
|
|||
struct device *parent;
|
||||
struct intel_vsec_header **headers;
|
||||
const struct vsec_feature_dependency *deps;
|
||||
u32 (*acpi_disc)[4];
|
||||
enum intel_vsec_disc_source src;
|
||||
void *priv_data;
|
||||
unsigned long caps;
|
||||
unsigned long quirks;
|
||||
|
|
@ -122,8 +134,13 @@ struct intel_vsec_platform_info {
|
|||
/**
|
||||
* struct intel_vsec_device - Auxbus specific device information
|
||||
* @auxdev: auxbus device struct for auxbus access
|
||||
* @pcidev: pci device associated with the device
|
||||
* @resource: any resources shared by the parent
|
||||
* @dev: struct device associated with the device
|
||||
* @resource: PCI discovery resources (BAR windows), one per discovery
|
||||
* instance. Valid only when @src == INTEL_VSEC_DISC_PCI
|
||||
* @acpi_disc: ACPI discovery tables, each entry is two QWORDs
|
||||
* in little-endian format as defined by the PMT ACPI spec.
|
||||
* Valid only when @src == INTEL_VSEC_DISC_ACPI.
|
||||
* @src: source of discovery table data
|
||||
* @ida: id reference
|
||||
* @num_resources: number of resources
|
||||
* @id: xarray id
|
||||
|
|
@ -135,8 +152,10 @@ struct intel_vsec_platform_info {
|
|||
*/
|
||||
struct intel_vsec_device {
|
||||
struct auxiliary_device auxdev;
|
||||
struct pci_dev *pcidev;
|
||||
struct device *dev;
|
||||
struct resource *resource;
|
||||
u32 (*acpi_disc)[4];
|
||||
enum intel_vsec_disc_source src;
|
||||
struct ida *ida;
|
||||
int num_resources;
|
||||
int id; /* xa */
|
||||
|
|
@ -184,7 +203,7 @@ struct pmt_feature_group {
|
|||
struct telemetry_region regions[];
|
||||
};
|
||||
|
||||
int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent,
|
||||
int intel_vsec_add_aux(struct device *parent,
|
||||
struct intel_vsec_device *intel_vsec_dev,
|
||||
const char *name);
|
||||
|
||||
|
|
@ -199,14 +218,14 @@ static inline struct intel_vsec_device *auxdev_to_ivdev(struct auxiliary_device
|
|||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_INTEL_VSEC)
|
||||
int intel_vsec_register(struct pci_dev *pdev,
|
||||
struct intel_vsec_platform_info *info);
|
||||
int intel_vsec_register(struct device *dev,
|
||||
const struct intel_vsec_platform_info *info);
|
||||
int intel_vsec_set_mapping(struct oobmsm_plat_info *plat_info,
|
||||
struct intel_vsec_device *vsec_dev);
|
||||
struct oobmsm_plat_info *intel_vsec_get_mapping(struct pci_dev *pdev);
|
||||
#else
|
||||
static inline int intel_vsec_register(struct pci_dev *pdev,
|
||||
struct intel_vsec_platform_info *info)
|
||||
static inline int intel_vsec_register(struct device *dev,
|
||||
const struct intel_vsec_platform_info *info)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
/* PMIC GPIO Types */
|
||||
#define INT3472_GPIO_TYPE_RESET 0x00
|
||||
#define INT3472_GPIO_TYPE_POWERDOWN 0x01
|
||||
#define INT3472_GPIO_TYPE_STROBE 0x02
|
||||
#define INT3472_GPIO_TYPE_POWER_ENABLE 0x0b
|
||||
#define INT3472_GPIO_TYPE_CLK_ENABLE 0x0c
|
||||
#define INT3472_GPIO_TYPE_PRIVACY_LED 0x0d
|
||||
|
|
@ -32,6 +33,7 @@
|
|||
|
||||
#define INT3472_PDEV_MAX_NAME_LEN 23
|
||||
#define INT3472_MAX_SENSOR_GPIOS 3
|
||||
#define INT3472_MAX_LEDS 2
|
||||
#define INT3472_MAX_REGULATORS 3
|
||||
|
||||
/* E.g. "dovdd\0" */
|
||||
|
|
@ -122,16 +124,17 @@ struct int3472_discrete_device {
|
|||
u8 imgclk_index;
|
||||
} clock;
|
||||
|
||||
struct int3472_pled {
|
||||
struct int3472_led {
|
||||
struct led_classdev classdev;
|
||||
struct led_lookup_data lookup;
|
||||
char name[INT3472_LED_MAX_NAME_LEN];
|
||||
struct gpio_desc *gpio;
|
||||
} pled;
|
||||
} leds[INT3472_MAX_LEDS];
|
||||
|
||||
struct int3472_discrete_quirks quirks;
|
||||
|
||||
unsigned int ngpios; /* how many GPIOs have we seen */
|
||||
unsigned int n_leds; /* how many LEDs have we registered */
|
||||
unsigned int n_sensor_gpios; /* how many have we mapped to sensor */
|
||||
unsigned int n_regulator_gpios; /* how many have we mapped to a regulator */
|
||||
struct gpiod_lookup_table gpios;
|
||||
|
|
@ -161,7 +164,8 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
|
|||
const char *second_sensor);
|
||||
void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472);
|
||||
|
||||
int skl_int3472_register_pled(struct int3472_discrete_device *int3472, struct gpio_desc *gpio);
|
||||
void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472);
|
||||
int skl_int3472_register_led(struct int3472_discrete_device *int3472, struct gpio_desc *gpio,
|
||||
const char *con_id);
|
||||
void skl_int3472_unregister_leds(struct int3472_discrete_device *int3472);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -64,9 +64,13 @@ ssize_t wmi_string_from_utf8s(struct wmi_string *str, size_t max_chars, const u8
|
|||
size_t src_length);
|
||||
|
||||
int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
|
||||
const struct wmi_buffer *in, struct wmi_buffer *out);
|
||||
const struct wmi_buffer *in, struct wmi_buffer *out, size_t min_size);
|
||||
|
||||
int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer *out);
|
||||
int wmidev_invoke_procedure(struct wmi_device *wdev, u8 instance, u32 method_id,
|
||||
const struct wmi_buffer *in);
|
||||
|
||||
int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer *out,
|
||||
size_t min_size);
|
||||
|
||||
int wmidev_set_block(struct wmi_device *wdev, u8 instance, const struct wmi_buffer *in);
|
||||
|
||||
|
|
@ -83,7 +87,7 @@ u8 wmidev_instance_count(struct wmi_device *wdev);
|
|||
* struct wmi_driver - WMI driver structure
|
||||
* @driver: Driver model structure
|
||||
* @id_table: List of WMI GUIDs supported by this driver
|
||||
* @no_notify_data: Driver supports WMI events which provide no event data
|
||||
* @min_event_size: Minimum event payload size supported by this driver
|
||||
* @no_singleton: Driver can be instantiated multiple times
|
||||
* @probe: Callback for device binding
|
||||
* @remove: Callback for device unbinding
|
||||
|
|
@ -93,11 +97,14 @@ u8 wmidev_instance_count(struct wmi_device *wdev);
|
|||
*
|
||||
* This represents WMI drivers which handle WMI devices. The data inside the buffer
|
||||
* passed to the @notify_new callback is guaranteed to be aligned on a 8-byte boundary.
|
||||
* The minimum supported size for said buffer can be specified using @min_event_size.
|
||||
* WMI drivers that still use the deprecated @notify callback can still set @min_event_size
|
||||
* to 0 in order to signal that they support WMI events which provide no event data.
|
||||
*/
|
||||
struct wmi_driver {
|
||||
struct device_driver driver;
|
||||
const struct wmi_device_id *id_table;
|
||||
bool no_notify_data;
|
||||
size_t min_event_size;
|
||||
bool no_singleton;
|
||||
|
||||
int (*probe)(struct wmi_device *wdev, const void *context);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ struct process_cmd_struct {
|
|||
int arg;
|
||||
};
|
||||
|
||||
static const char *version_str = "v1.25";
|
||||
static const char *version_str = "v1.26";
|
||||
|
||||
static const int supported_api_ver = 3;
|
||||
static struct isst_if_platform_info isst_platform_info;
|
||||
|
|
@ -26,7 +26,7 @@ static FILE *outf;
|
|||
|
||||
static int cpu_model;
|
||||
static int cpu_stepping;
|
||||
static int extended_family;
|
||||
static int cpu_family;
|
||||
|
||||
#define MAX_CPUS_IN_ONE_REQ 512
|
||||
static short max_target_cpus;
|
||||
|
|
@ -82,6 +82,11 @@ struct cpu_topology {
|
|||
|
||||
static int read_only;
|
||||
|
||||
static void print_version(void)
|
||||
{
|
||||
fprintf(outf, "Version %s\n", version_str);
|
||||
}
|
||||
|
||||
static void check_privilege(void)
|
||||
{
|
||||
if (!read_only)
|
||||
|
|
@ -158,7 +163,7 @@ int is_icx_platform(void)
|
|||
|
||||
static int is_dmr_plus_platform(void)
|
||||
{
|
||||
if (extended_family == 0x04)
|
||||
if (cpu_family == 19)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
|
@ -167,13 +172,14 @@ static int is_dmr_plus_platform(void)
|
|||
static int update_cpu_model(void)
|
||||
{
|
||||
unsigned int ebx, ecx, edx;
|
||||
unsigned int fms, family;
|
||||
unsigned int fms;
|
||||
|
||||
__cpuid(1, fms, ebx, ecx, edx);
|
||||
family = (fms >> 8) & 0xf;
|
||||
extended_family = (fms >> 20) & 0x0f;
|
||||
cpu_family = (fms >> 8) & 0xf;
|
||||
if (cpu_family == 0xf)
|
||||
cpu_family += (fms >> 20) & 0xff;
|
||||
cpu_model = (fms >> 4) & 0xf;
|
||||
if (family == 6 || family == 0xf)
|
||||
if (cpu_family == 6 || cpu_family == 0xf)
|
||||
cpu_model += ((fms >> 16) & 0xf) << 4;
|
||||
|
||||
cpu_stepping = fms & 0xf;
|
||||
|
|
@ -1137,8 +1143,9 @@ static int isst_fill_platform_info(void)
|
|||
close(fd);
|
||||
|
||||
if (isst_platform_info.api_version > supported_api_ver) {
|
||||
print_version();
|
||||
printf("Incompatible API versions; Upgrade of tool is required\n");
|
||||
return -1;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
set_platform_ops:
|
||||
|
|
@ -1744,6 +1751,9 @@ static int no_turbo(void)
|
|||
return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo");
|
||||
}
|
||||
|
||||
#define U32_MAX ((unsigned int)~0U)
|
||||
#define S32_MAX ((int)(U32_MAX >> 1))
|
||||
|
||||
static void adjust_scaling_max_from_base_freq(int cpu)
|
||||
{
|
||||
int base_freq, scaling_max_freq;
|
||||
|
|
@ -1751,7 +1761,7 @@ static void adjust_scaling_max_from_base_freq(int cpu)
|
|||
scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
|
||||
base_freq = get_cpufreq_base_freq(cpu);
|
||||
if (scaling_max_freq < base_freq || no_turbo())
|
||||
set_cpufreq_scaling_min_max(cpu, 1, base_freq);
|
||||
set_cpufreq_scaling_min_max(cpu, 1, S32_MAX);
|
||||
}
|
||||
|
||||
static void adjust_scaling_min_from_base_freq(int cpu)
|
||||
|
|
@ -3191,12 +3201,6 @@ static void usage(void)
|
|||
printf("\tTo get full turbo-freq information dump:\n");
|
||||
printf("\t\tintel-speed-select turbo-freq info -l 0\n");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void print_version(void)
|
||||
{
|
||||
fprintf(outf, "Version %s\n", version_str);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
|
@ -3246,8 +3250,10 @@ static void cmdline(int argc, char **argv)
|
|||
}
|
||||
|
||||
ret = update_cpu_model();
|
||||
if (ret)
|
||||
err(-1, "Invalid CPU model (%d)\n", cpu_model);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Invalid CPU model (%d)\n", cpu_model);
|
||||
exit(1);
|
||||
}
|
||||
printf("Intel(R) Speed Select Technology\n");
|
||||
printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model);
|
||||
|
||||
|
|
@ -3311,6 +3317,7 @@ static void cmdline(int argc, char **argv)
|
|||
break;
|
||||
case 'v':
|
||||
print_version();
|
||||
exit(0);
|
||||
break;
|
||||
case 'b':
|
||||
oob_mode = 1;
|
||||
|
|
|
|||
Loading…
Reference in New Issue