Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  alienware-wmi-base.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Alienware special feature control
 *
 * Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com>
 * Copyright (C) 2025 Kurt Borja <kuurtb@gmail.com>
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/acpi.h>
#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dmi.h>
#include <linux/leds.h>
#include "alienware-wmi.h"

MODULE_AUTHOR("Mario Limonciello ");
MODULE_AUTHOR("Kurt Borja ");
MODULE_DESCRIPTION("Alienware special feature control");
MODULE_LICENSE("GPL");

struct alienfx_quirks *alienfx;

static struct alienfx_quirks quirk_inspiron5675 = {
 .num_zones = 2,
 .hdmi_mux = false,
 .amplifier = false,
 .deepslp = false,
};

static struct alienfx_quirks quirk_unknown = {
 .num_zones = 2,
 .hdmi_mux = false,
 .amplifier = false,
 .deepslp = false,
};

static struct alienfx_quirks quirk_x51_r1_r2 = {
 .num_zones = 3,
 .hdmi_mux = false,
 .amplifier = false,
 .deepslp = false,
};

static struct alienfx_quirks quirk_x51_r3 = {
 .num_zones = 4,
 .hdmi_mux = false,
 .amplifier = true,
 .deepslp = false,
};

static struct alienfx_quirks quirk_asm100 = {
 .num_zones = 2,
 .hdmi_mux = true,
 .amplifier = false,
 .deepslp = false,
};

static struct alienfx_quirks quirk_asm200 = {
 .num_zones = 2,
 .hdmi_mux = true,
 .amplifier = false,
 .deepslp = true,
};

static struct alienfx_quirks quirk_asm201 = {
 .num_zones = 2,
 .hdmi_mux = true,
 .amplifier = true,
 .deepslp = true,
};

static int __init dmi_matched(const struct dmi_system_id *dmi)
{
 alienfx = dmi->driver_data;
 return 1;
}

static const struct dmi_system_id alienware_quirks[] __initconst = {
 {
  .callback = dmi_matched,
  .ident = "Alienware ASM100",
  .matches = {
   DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
   DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"),
  },
  .driver_data = &quirk_asm100,
 },
 {
  .callback = dmi_matched,
  .ident = "Alienware ASM200",
  .matches = {
   DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
   DMI_MATCH(DMI_PRODUCT_NAME, "ASM200"),
  },
  .driver_data = &quirk_asm200,
 },
 {
  .callback = dmi_matched,
  .ident = "Alienware ASM201",
  .matches = {
   DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
   DMI_MATCH(DMI_PRODUCT_NAME, "ASM201"),
  },
  .driver_data = &quirk_asm201,
 },
 {
  .callback = dmi_matched,
  .ident = "Alienware X51 R1",
  .matches = {
   DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
   DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51"),
  },
  .driver_data = &quirk_x51_r1_r2,
 },
 {
  .callback = dmi_matched,
  .ident = "Alienware X51 R2",
  .matches = {
   DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
   DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R2"),
  },
  .driver_data = &quirk_x51_r1_r2,
 },
 {
  .callback = dmi_matched,
  .ident = "Alienware X51 R3",
  .matches = {
   DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
   DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R3"),
  },
  .driver_data = &quirk_x51_r3,
 },
 {
  .callback = dmi_matched,
  .ident = "Dell Inc. Inspiron 5675",
  .matches = {
   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
   DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"),
  },
  .driver_data = &quirk_inspiron5675,
 },
 {}
};

u8 alienware_interface;

int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
     void *in_args, size_t in_size, u32 *out_data)
{
 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
 struct acpi_buffer in = {in_size, in_args};
 acpi_status ret;

 ret = wmidev_evaluate_method(wdev, 0, method_id, &in, out_data ? &out : NULL);
 if (ACPI_FAILURE(ret))
  return -EIO;

 union acpi_object *obj __free(kfree) = out.pointer;

 if (out_data) {
  if (obj && obj->type == ACPI_TYPE_INTEGER)
   *out_data = (u32)obj->integer.value;
  else
   return -ENOMSG;
 }

 return 0;
}

/*
 * Helpers used for zone control
 */

static int parse_rgb(const char *buf, struct color_platform *colors)
{
 long unsigned int rgb;
 int ret;
 union color_union {
  struct color_platform cp;
  int package;
 } repackager;

 ret = kstrtoul(buf, 16, &rgb);
 if (ret)
  return ret;

 /* RGB triplet notation is 24-bit hexadecimal */
 if (rgb > 0xFFFFFF)
  return -EINVAL;

 repackager.package = rgb & 0x0f0f0f0f;
 pr_debug("alienware-wmi: r: %d g:%d b: %d\n",
   repackager.cp.red, repackager.cp.green, repackager.cp.blue);
 *colors = repackager.cp;
 return 0;
}

/*
 * Individual RGB zone control
 */

static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
    char *buf, u8 location)
{
 struct alienfx_priv *priv = dev_get_drvdata(dev);
 struct color_platform *colors = &priv->colors[location];

 return sprintf(buf, "red: %d, green: %d, blue: %d\n",
         colors->red, colors->green, colors->blue);

}

static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
     const char *buf, size_t count, u8 location)
{
 struct alienfx_priv *priv = dev_get_drvdata(dev);
 struct color_platform *colors = &priv->colors[location];
 struct alienfx_platdata *pdata = dev_get_platdata(dev);
 int ret;

 ret = parse_rgb(buf, colors);
 if (ret)
  return ret;

 ret = pdata->ops.upd_led(priv, pdata->wdev, location);

 return ret ? ret : count;
}

static ssize_t zone00_show(struct device *dev, struct device_attribute *attr,
      char *buf)
{
 return zone_show(dev, attr, buf, 0);
}

static ssize_t zone00_store(struct device *dev, struct device_attribute *attr,
       const char *buf, size_t count)
{
 return zone_store(dev, attr, buf, count, 0);
}

static DEVICE_ATTR_RW(zone00);

static ssize_t zone01_show(struct device *dev, struct device_attribute *attr,
      char *buf)
{
 return zone_show(dev, attr, buf, 1);
}

static ssize_t zone01_store(struct device *dev, struct device_attribute *attr,
       const char *buf, size_t count)
{
 return zone_store(dev, attr, buf, count, 1);
}

static DEVICE_ATTR_RW(zone01);

static ssize_t zone02_show(struct device *dev, struct device_attribute *attr,
      char *buf)
{
 return zone_show(dev, attr, buf, 2);
}

static ssize_t zone02_store(struct device *dev, struct device_attribute *attr,
       const char *buf, size_t count)
{
 return zone_store(dev, attr, buf, count, 2);
}

static DEVICE_ATTR_RW(zone02);

static ssize_t zone03_show(struct device *dev, struct device_attribute *attr,
      char *buf)
{
 return zone_show(dev, attr, buf, 3);
}

static ssize_t zone03_store(struct device *dev, struct device_attribute *attr,
       const char *buf, size_t count)
{
 return zone_store(dev, attr, buf, count, 3);
}

static DEVICE_ATTR_RW(zone03);

/*
 * Lighting control state device attribute (Global)
 */

static ssize_t lighting_control_state_show(struct device *dev,
        struct device_attribute *attr,
        char *buf)
{
 struct alienfx_priv *priv = dev_get_drvdata(dev);

 if (priv->lighting_control_state == LEGACY_BOOTING)
  return sysfs_emit(buf, "[booting] running suspend\n");
 else if (priv->lighting_control_state == LEGACY_SUSPEND)
  return sysfs_emit(buf, "booting running [suspend]\n");

 return sysfs_emit(buf, "booting [running] suspend\n");
}

static ssize_t lighting_control_state_store(struct device *dev,
         struct device_attribute *attr,
         const char *buf, size_t count)
{
 struct alienfx_priv *priv = dev_get_drvdata(dev);
 u8 val;

 if (strcmp(buf, "booting\n") == 0)
  val = LEGACY_BOOTING;
 else if (strcmp(buf, "suspend\n") == 0)
  val = LEGACY_SUSPEND;
 else if (alienware_interface == LEGACY)
  val = LEGACY_RUNNING;
 else
  val = WMAX_RUNNING;

 priv->lighting_control_state = val;
 pr_debug("alienware-wmi: updated control state to %d\n",
   priv->lighting_control_state);

 return count;
}

static DEVICE_ATTR_RW(lighting_control_state);

static umode_t zone_attr_visible(struct kobject *kobj,
     struct attribute *attr, int n)
{
 if (n < alienfx->num_zones + 1)
  return attr->mode;

 return 0;
}

static bool zone_group_visible(struct kobject *kobj)
{
 return alienfx->num_zones > 0;
}
DEFINE_SYSFS_GROUP_VISIBLE(zone);

static struct attribute *zone_attrs[] = {
 &dev_attr_lighting_control_state.attr,
 &dev_attr_zone00.attr,
 &dev_attr_zone01.attr,
 &dev_attr_zone02.attr,
 &dev_attr_zone03.attr,
 NULL
};

static struct attribute_group zone_attribute_group = {
 .name = "rgb_zones",
 .is_visible = SYSFS_GROUP_VISIBLE(zone),
 .attrs = zone_attrs,
};

/*
 * LED Brightness (Global)
 */

static void global_led_set(struct led_classdev *led_cdev,
      enum led_brightness brightness)
{
 struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
       global_led);
 struct alienfx_platdata *pdata = dev_get_platdata(&priv->pdev->dev);
 int ret;

 priv->global_brightness = brightness;

 ret = pdata->ops.upd_brightness(priv, pdata->wdev, brightness);
 if (ret)
  pr_err("LED brightness update failed\n");
}

static enum led_brightness global_led_get(struct led_classdev *led_cdev)
{
 struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
       global_led);

 return priv->global_brightness;
}

/*
 * Platform Driver
 */

static int alienfx_probe(struct platform_device *pdev)
{
 struct alienfx_priv *priv;

 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 if (!priv)
  return -ENOMEM;

 if (alienware_interface == WMAX)
  priv->lighting_control_state = WMAX_RUNNING;
 else
  priv->lighting_control_state = LEGACY_RUNNING;

 priv->pdev = pdev;
 priv->global_led.name = "alienware::global_brightness";
 priv->global_led.brightness_set = global_led_set;
 priv->global_led.brightness_get = global_led_get;
 priv->global_led.max_brightness = 0x0F;
 priv->global_brightness = priv->global_led.max_brightness;
 platform_set_drvdata(pdev, priv);

 return devm_led_classdev_register(&pdev->dev, &priv->global_led);
}

static const struct attribute_group *alienfx_groups[] = {
 &zone_attribute_group,
 WMAX_DEV_GROUPS
 NULL
};

static struct platform_driver platform_driver = {
 .driver = {
  .name = "alienware-wmi",
  .dev_groups = alienfx_groups,
 },
 .probe = alienfx_probe,
};

static void alienware_alienfx_remove(void *data)
{
 struct platform_device *pdev = data;

 platform_device_unregister(pdev);
}

int alienware_alienfx_setup(struct alienfx_platdata *pdata)
{
 struct device *dev = &pdata->wdev->dev;
 struct platform_device *pdev;
 int ret;

 pdev = platform_device_register_data(NULL, "alienware-wmi",
          PLATFORM_DEVID_NONE, pdata,
          sizeof(*pdata));
 if (IS_ERR(pdev))
  return PTR_ERR(pdev);

 dev_set_drvdata(dev, pdev);
 ret = devm_add_action_or_reset(dev, alienware_alienfx_remove, pdev);
 if (ret)
  return ret;

 return 0;
}

static int __init alienware_wmi_init(void)
{
 int ret;

 dmi_check_system(alienware_quirks);
 if (!alienfx)
  alienfx = &quirk_unknown;

 ret = platform_driver_register(&platform_driver);
 if (ret < 0)
  return ret;

 if (wmi_has_guid(WMAX_CONTROL_GUID)) {
  alienware_interface = WMAX;
  ret = alienware_wmax_wmi_init();
 } else {
  alienware_interface = LEGACY;
  ret = alienware_legacy_wmi_init();
 }

 if (ret < 0)
  platform_driver_unregister(&platform_driver);

 return ret;
}

module_init(alienware_wmi_init);

static void __exit alienware_wmi_exit(void)
{
 if (alienware_interface == WMAX)
  alienware_wmax_wmi_exit();
 else
  alienware_legacy_wmi_exit();

 platform_driver_unregister(&platform_driver);
}

module_exit(alienware_wmi_exit);

Messung V0.5
C=94 H=95 G=94

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge