root/drivers/platform/x86/dell-wmi-led.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dell_led_perform_fn
  2. led_on
  3. led_off
  4. led_blink
  5. dell_led_set
  6. dell_led_blink
  7. dell_led_init
  8. dell_led_exit

   1 /*
   2  * Copyright (C) 2010 Dell Inc.
   3  * Louis Davis <louis_davis@dell.com>
   4  * Jim Dailey <jim_dailey@dell.com>
   5  *
   6  * This program is free software; you can redistribute it and/or modify
   7  * it under the terms of the GNU General Public License as
   8  * published by the Free Software Foundation.
   9  *
  10  */
  11 
  12 #include <linux/acpi.h>
  13 #include <linux/leds.h>
  14 #include <linux/slab.h>
  15 #include <linux/module.h>
  16 
  17 MODULE_AUTHOR("Louis Davis/Jim Dailey");
  18 MODULE_DESCRIPTION("Dell LED Control Driver");
  19 MODULE_LICENSE("GPL");
  20 
  21 #define DELL_LED_BIOS_GUID "F6E4FE6E-909D-47cb-8BAB-C9F6F2F8D396"
  22 MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID);
  23 
  24 /* Error Result Codes: */
  25 #define INVALID_DEVICE_ID       250
  26 #define INVALID_PARAMETER       251
  27 #define INVALID_BUFFER          252
  28 #define INTERFACE_ERROR         253
  29 #define UNSUPPORTED_COMMAND     254
  30 #define UNSPECIFIED_ERROR       255
  31 
  32 /* Device ID */
  33 #define DEVICE_ID_PANEL_BACK    1
  34 
  35 /* LED Commands */
  36 #define CMD_LED_ON      16
  37 #define CMD_LED_OFF     17
  38 #define CMD_LED_BLINK   18
  39 
  40 struct bios_args {
  41         unsigned char length;
  42         unsigned char result_code;
  43         unsigned char device_id;
  44         unsigned char command;
  45         unsigned char on_time;
  46         unsigned char off_time;
  47 };
  48 
  49 static int dell_led_perform_fn(u8 length, u8 result_code, u8 device_id,
  50                                u8 command, u8 on_time, u8 off_time)
  51 {
  52         struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
  53         struct bios_args *bios_return;
  54         struct acpi_buffer input;
  55         union acpi_object *obj;
  56         acpi_status status;
  57         u8 return_code;
  58 
  59         struct bios_args args = {
  60                 .length = length,
  61                 .result_code = result_code,
  62                 .device_id = device_id,
  63                 .command = command,
  64                 .on_time = on_time,
  65                 .off_time = off_time
  66         };
  67 
  68         input.length = sizeof(struct bios_args);
  69         input.pointer = &args;
  70 
  71         status = wmi_evaluate_method(DELL_LED_BIOS_GUID, 0, 1, &input, &output);
  72         if (ACPI_FAILURE(status))
  73                 return status;
  74 
  75         obj = output.pointer;
  76 
  77         if (!obj)
  78                 return -EINVAL;
  79         if (obj->type != ACPI_TYPE_BUFFER) {
  80                 kfree(obj);
  81                 return -EINVAL;
  82         }
  83 
  84         bios_return = ((struct bios_args *)obj->buffer.pointer);
  85         return_code = bios_return->result_code;
  86 
  87         kfree(obj);
  88 
  89         return return_code;
  90 }
  91 
  92 static int led_on(void)
  93 {
  94         return dell_led_perform_fn(3,   /* Length of command */
  95                 INTERFACE_ERROR,        /* Init to  INTERFACE_ERROR */
  96                 DEVICE_ID_PANEL_BACK,   /* Device ID */
  97                 CMD_LED_ON,             /* Command */
  98                 0,                      /* not used */
  99                 0);                     /* not used */
 100 }
 101 
 102 static int led_off(void)
 103 {
 104         return dell_led_perform_fn(3,   /* Length of command */
 105                 INTERFACE_ERROR,        /* Init to  INTERFACE_ERROR */
 106                 DEVICE_ID_PANEL_BACK,   /* Device ID */
 107                 CMD_LED_OFF,            /* Command */
 108                 0,                      /* not used */
 109                 0);                     /* not used */
 110 }
 111 
 112 static int led_blink(unsigned char on_eighths, unsigned char off_eighths)
 113 {
 114         return dell_led_perform_fn(5,   /* Length of command */
 115                 INTERFACE_ERROR,        /* Init to  INTERFACE_ERROR */
 116                 DEVICE_ID_PANEL_BACK,   /* Device ID */
 117                 CMD_LED_BLINK,          /* Command */
 118                 on_eighths,             /* blink on in eigths of a second */
 119                 off_eighths);           /* blink off in eights of a second */
 120 }
 121 
 122 static void dell_led_set(struct led_classdev *led_cdev,
 123                          enum led_brightness value)
 124 {
 125         if (value == LED_OFF)
 126                 led_off();
 127         else
 128                 led_on();
 129 }
 130 
 131 static int dell_led_blink(struct led_classdev *led_cdev,
 132                           unsigned long *delay_on, unsigned long *delay_off)
 133 {
 134         unsigned long on_eighths;
 135         unsigned long off_eighths;
 136 
 137         /*
 138          * The Dell LED delay is based on 125ms intervals.
 139          * Need to round up to next interval.
 140          */
 141 
 142         on_eighths = DIV_ROUND_UP(*delay_on, 125);
 143         on_eighths = clamp_t(unsigned long, on_eighths, 1, 255);
 144         *delay_on = on_eighths * 125;
 145 
 146         off_eighths = DIV_ROUND_UP(*delay_off, 125);
 147         off_eighths = clamp_t(unsigned long, off_eighths, 1, 255);
 148         *delay_off = off_eighths * 125;
 149 
 150         led_blink(on_eighths, off_eighths);
 151 
 152         return 0;
 153 }
 154 
 155 static struct led_classdev dell_led = {
 156         .name           = "dell::lid",
 157         .brightness     = LED_OFF,
 158         .max_brightness = 1,
 159         .brightness_set = dell_led_set,
 160         .blink_set      = dell_led_blink,
 161         .flags          = LED_CORE_SUSPENDRESUME,
 162 };
 163 
 164 static int __init dell_led_init(void)
 165 {
 166         int error = 0;
 167 
 168         if (!wmi_has_guid(DELL_LED_BIOS_GUID))
 169                 return -ENODEV;
 170 
 171         error = led_off();
 172         if (error != 0)
 173                 return -ENODEV;
 174 
 175         return led_classdev_register(NULL, &dell_led);
 176 }
 177 
 178 static void __exit dell_led_exit(void)
 179 {
 180         led_classdev_unregister(&dell_led);
 181 
 182         led_off();
 183 }
 184 
 185 module_init(dell_led_init);
 186 module_exit(dell_led_exit);

/* [<][>][^][v][top][bottom][index][help] */