Re: [RFC] [PATCH 2/2] ACPI: introduce ACPI ALS device driver

From: Jonathan Cameron
Date: Tue Sep 22 2009 - 08:55:26 EST


Note I have no familiarity at all with the acpi side of things!
Other than a few queries, this looks fine to me.

Jonathan
> ACPI spec defines ACPI Ambient Light Sensor device (hid ACPI0008),
> which provides a standard interface by which the OS may query properties
> of the ambient light environment the system is currently operating in,
> as well as the ability to detect meaningful changes in these values when
> the environment changes.
>
> This patch introduces the ACPI ALS device driver.
>
> Signed-off-by: Zhang Rui <rui.zhang@xxxxxxxxx>
> ---
> Documentation/acpi/debug.txt | 1
> MAINTAINERS | 7 +
> drivers/acpi/Kconfig | 9 +
> drivers/acpi/Makefile | 1
> drivers/acpi/als.c | 223 +++++++++++++++++++++++++++++++++++++++++++
> drivers/acpi/debug.c | 1
> include/acpi/acpi_drivers.h | 1
> 7 files changed, 243 insertions(+)
>
> Index: linux-2.6/drivers/acpi/als.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6/drivers/acpi/als.c
> @@ -0,0 +1,223 @@
> +/*
> + * als.c - ACPI Ambient Light Sensor Driver
> + *
> + * Copyright (C) 2009 Intel Corp
> + * Copyright (C) 2009 Zhang Rui <rui.zhang@xxxxxxxxx>
> + *
> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> + *
> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/als_sys.h>
> +#include <acpi/acpi_bus.h>
> +#include <acpi/acpi_drivers.h>
> +
> +#define PREFIX "ACPI: "
> +
> +#define ACPI_ALS_CLASS "als"
> +#define ACPI_ALS_DEVICE_NAME "Ambient Light Sensor"
> +#define ACPI_ALS_NOTIFY_ILLUMINANCE 0x80
> +#define ACPI_ALS_NOTIFY_COLOR_TEMP 0x81
> +#define ACPI_ALS_NOTIFY_RESPONSE 0x82
> +
> +#define _COMPONENT ACPI_ALS_COMPONENT
> +ACPI_MODULE_NAME("als");
> +
> +MODULE_AUTHOR("Zhang Rui");
> +MODULE_DESCRIPTION("ACPI Ambient Light Sensor Driver");
> +MODULE_LICENSE("GPL");
> +
> +static int acpi_als_add(struct acpi_device *device);
> +static int acpi_als_remove(struct acpi_device *device, int type);
> +static void acpi_als_notify(struct acpi_device *device, u32 event);
> +
> +static const struct acpi_device_id als_device_ids[] = {
> + {"ACPI0008", 0},
> + {"", 0},
> +};
> +
> +MODULE_DEVICE_TABLE(acpi, als_device_ids);
> +
> +static struct acpi_driver acpi_als_driver = {
> + .name = "als",
> + .class = ACPI_ALS_CLASS,
> + .ids = als_device_ids,
> + .ops = {
> + .add = acpi_als_add,
> + .remove = acpi_als_remove,
> + .notify = acpi_als_notify,
> + },
> +};
> +
> +struct acpi_als {
> + struct acpi_device *device;
> + struct device *classdev; /* pointer to als sysfs/class device */
> + int illuminance;
> +};
> +
> +/* --------------------------------------------------------------------------
> + Ambient Light Sensor device Management
> + -------------------------------------------------------------------------- */
> +
> +/*
> + * acpi_als_get_illuminance - get the current ambient light illuminance
> + */
> +static int acpi_als_get_illuminance(struct acpi_als *als)
> +{
> + acpi_status status;
> + unsigned long long illuminance;
> +
> + status =
> + acpi_evaluate_integer(als->device->handle, "_ALI", NULL,
> + &illuminance);
> + if (ACPI_FAILURE(status)) {
> + ACPI_EXCEPTION((AE_INFO, status,
> + "Error reading ALS illuminance"));
> + return -ENOENT;
> + }
> + als->illuminance = illuminance;
> + return 0;
> +}
> +
> +
> +/* --------------------------------------------------------------------------
> + sysfs I/F
> + -------------------------------------------------------------------------- */
> +static int
> +illuminance_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> + struct acpi_device *device = to_acpi_device(dev->parent);
> + struct acpi_als *als = acpi_driver_data(device);
> + int result;
> +
> + result = acpi_als_get_illuminance(als);
> + if (result)
> + return result;
> +
> + if (als->illuminance < -1)
> + return -EINVAL;
> +
> + return sprintf(buf, "%d\n", als->illuminance);
> +}
> +
> +DEVICE_ATTR(illuminance, 0444, illuminance_show, NULL);
> +
> +/* --------------------------------------------------------------------------
> + Driver Model
> + -------------------------------------------------------------------------- */
> +
> +static void acpi_als_notify(struct acpi_device *device, u32 event)
> +{
> + struct acpi_als *als = acpi_driver_data(device);
> +
> + if (!als)
> + return;
> +
> + switch (event) {
> + case ACPI_ALS_NOTIFY_ILLUMINANCE:
> + acpi_als_get_illuminance(als);
> + break;
> + case ACPI_ALS_NOTIFY_COLOR_TEMP:
> + /*
> + * TODO:
> + * re-evalute the color temperature and chromaticity
> + */
> + break;
> + case ACPI_ALS_NOTIFY_RESPONSE:
> + /*
> + * TODO:
> + * update the Ambient Light Illuminance to
> + * Display Luminance Adjustment Mappings
> + */
> + break;
> + default:
> + ACPI_DEBUG_PRINT((ACPI_DB_INFO,
> + "Unsupported event [0x%x]\n", event));
> + }
> + acpi_bus_generate_proc_event(device, event, (u32) als->illuminance);
> + acpi_bus_generate_netlink_event(device->pnp.device_class,
> + dev_name(&device->dev), event,
> + (u32) als->illuminance);
> +}
> +
> +static int acpi_als_add(struct acpi_device *device)
> +{
> + int result;
Are there any plausible race conditions associated with doing the allocation this way?
This variable may need some protection. (I'm guessing acpi may prevent simultaneous
add calls?)
> + static int als_id;
> + char name[10];
> + struct acpi_als *als;
> +
> + if (unlikely(als_id >= 10)) {
> + printk(KERN_WARNING PREFIX "Too many ALS device found\n");
> + return -ENODEV;
> + }
> +
> + als = kzalloc(sizeof(struct acpi_als), GFP_KERNEL);
> + if (!als)
> + return -ENOMEM;
> +
> + als->device = device;
> + strcpy(acpi_device_name(device), ACPI_ALS_DEVICE_NAME);
> + strcpy(acpi_device_class(device), ACPI_ALS_CLASS);
> + device->driver_data = als;
> +
> + result = acpi_als_get_illuminance(als);
> + if (result)
> + goto end;
> +
> + sprintf(name, "acpi_als%d", als_id++);
> + als->classdev = als_device_register(&device->dev, name);
> + if (IS_ERR(als->classdev)) {
> + result = PTR_ERR(als->classdev);
> + goto end;
> + }
> +
> + result = device_create_file(als->classdev, &dev_attr_illuminance);
> + if (result)
> + als_device_unregister(als->classdev);
> +
> +end:
> + if (result)
If it fails, do you want to decrement als_id (for consistency sake if nothing else)?
> + kfree(als);
> + return result;
> +}
> +
> +static int acpi_als_remove(struct acpi_device *device, int type)
> +{
> + struct acpi_als *als = acpi_driver_data(device);
> +
> + als_device_unregister(als->classdev);
> + kfree(als);
> + return 0;
> +}
> +
> +static int __init acpi_als_init(void)
> +{
> + return acpi_bus_register_driver(&acpi_als_driver);
> +}
> +
> +static void __exit acpi_als_exit(void)
> +{
> + acpi_bus_unregister_driver(&acpi_als_driver);
> +}
> +
> +module_init(acpi_als_init);
> +module_exit(acpi_als_exit);
> Index: linux-2.6/drivers/acpi/Kconfig
> ===================================================================
> --- linux-2.6.orig/drivers/acpi/Kconfig
> +++ linux-2.6/drivers/acpi/Kconfig
> @@ -333,4 +333,13 @@ config ACPI_SBS
> To compile this driver as a module, choose M here:
> the modules will be called sbs and sbshc.
>
> +config ACPI_ALS
> + tristate "Ambient Light Sensor driver"
> + select ALS
> + help
> + This driver supports the ACPI Ambient Light Sensor.
> +
> + To compile this driver as a module, choose M here:
> + the module will be called als.
> +
> endif # ACPI
> Index: linux-2.6/drivers/acpi/Makefile
> ===================================================================
> --- linux-2.6.orig/drivers/acpi/Makefile
> +++ linux-2.6/drivers/acpi/Makefile
> @@ -56,6 +56,7 @@ obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acp
> obj-$(CONFIG_ACPI_BATTERY) += battery.o
> obj-$(CONFIG_ACPI_SBS) += sbshc.o
> obj-$(CONFIG_ACPI_SBS) += sbs.o
> +obj-$(CONFIG_ACPI_ALS) += als.o
>
> # processor has its own "processor." module_param namespace
> processor-y := processor_core.o processor_throttling.o
> Index: linux-2.6/Documentation/acpi/debug.txt
> ===================================================================
> --- linux-2.6.orig/Documentation/acpi/debug.txt
> +++ linux-2.6/Documentation/acpi/debug.txt
> @@ -63,6 +63,7 @@ shows the supported mask values, current
> ACPI_MEMORY_DEVICE_COMPONENT 0x08000000
> ACPI_VIDEO_COMPONENT 0x10000000
> ACPI_PROCESSOR_COMPONENT 0x20000000
> + ACPI_ALS_COMPONENT 0x40000000
>
> debug_level
> -----------
> Index: linux-2.6/drivers/acpi/debug.c
> ===================================================================
> --- linux-2.6.orig/drivers/acpi/debug.c
> +++ linux-2.6/drivers/acpi/debug.c
> @@ -53,6 +53,7 @@ static const struct acpi_dlayer acpi_deb
> ACPI_DEBUG_INIT(ACPI_MEMORY_DEVICE_COMPONENT),
> ACPI_DEBUG_INIT(ACPI_VIDEO_COMPONENT),
> ACPI_DEBUG_INIT(ACPI_PROCESSOR_COMPONENT),
> + ACPI_DEBUG_INIT(ACPI_ALS_COMPONENT),
> };
>
> static const struct acpi_dlevel acpi_debug_levels[] = {
> Index: linux-2.6/include/acpi/acpi_drivers.h
> ===================================================================
> --- linux-2.6.orig/include/acpi/acpi_drivers.h
> +++ linux-2.6/include/acpi/acpi_drivers.h
> @@ -49,6 +49,7 @@
> #define ACPI_MEMORY_DEVICE_COMPONENT 0x08000000
> #define ACPI_VIDEO_COMPONENT 0x10000000
> #define ACPI_PROCESSOR_COMPONENT 0x20000000
> +#define ACPI_ALS_COMPONENT 0x40000000
>
> /*
> * _HID definitions
> Index: linux-2.6/MAINTAINERS
> ===================================================================
> --- linux-2.6.orig/MAINTAINERS
> +++ linux-2.6/MAINTAINERS
> @@ -234,6 +234,13 @@ F: drivers/acpi/
> F: drivers/pnp/pnpacpi/
> F: include/linux/acpi.h
>
> +ACPI AMBIENT LIGHT SENSOR DRIVER
> +M: Zhang Rui <rui.zhang@xxxxxxxxx>
> +L: linux-acpi@xxxxxxxxxxxxxxx
> +W: http://www.lesswatts.org/projects/acpi/
> +S: Supported
> +F: drivers/acpi/als.c
> +
> ACPI BATTERY DRIVERS
> M: Alexey Starikovskiy <astarikovskiy@xxxxxxx>
> L: linux-acpi@xxxxxxxxxxxxxxx
>
>
>

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/