Messages in this thread | | | Date | Fri, 7 Jan 2011 09:56:11 +0100 | Subject | Re: [PATCH V2] platform-driver-x86: ACPI EC Extra driver for Oaktrail | From | Corentin Chary <> |
| |
On Fri, Jan 7, 2011 at 8:41 AM, Yin Kangkai <kangkai.yin@linux.intel.com> wrote: > Patch V2 > Changes from V1: > - remove wifi, bt, gps, wwan from /sys/devices/platform. > - add some helper function for rfkill alloc and rfkill cleanup. > - add MODULE_ALIAS. > - add Documentation/ABI/testing/sysfs-platform-intel-oaktrail > - various other minor changes. > - bump driver version from 0.1 to 0.2 > > Thanks Corentin Chary and Joey Lee for the review. > > From ab28d41e89b40e0ab1d73489b7d1a9f6e745c14a Mon Sep 17 00:00:00 2001 > From: Yin Kangkai <kangkai.yin@intel.com> > Date: Wed, 22 Dec 2010 10:53:36 +0800 > Subject: [PATCH] platform-driver-x86: ACPI EC Extra driver for Oaktrail > > This driver implements an Extra ACPI EC driver for products based on Intel > Oaktrail platform. It is programming the EC space, through existing ACPI EC > driver, to provide user space layer the sysfs and rfkill interfaces to > enable/disable the Camera, Bluetooth, GPS, WiFi, 3G, and to show the status of > Touchscreen. > > Signed-off-by: Yin Kangkai <kangkai.yin@intel.com> > --- > .../ABI/testing/sysfs-platform-intel-oaktrail | 13 + > drivers/platform/x86/Kconfig | 9 + > drivers/platform/x86/Makefile | 1 + > drivers/platform/x86/intel_oaktrail.c | 347 ++++++++++++++++++++ > 4 files changed, 370 insertions(+), 0 deletions(-) > create mode 100644 Documentation/ABI/testing/sysfs-platform-intel-oaktrail > create mode 100644 drivers/platform/x86/intel_oaktrail.c > > diff --git a/Documentation/ABI/testing/sysfs-platform-intel-oaktrail b/Documentation/ABI/testing/sysfs-platform-intel-oaktrail > new file mode 100644 > index 0000000..0512235 > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-platform-intel-oaktrail > @@ -0,0 +1,13 @@ > +What: /sys/devices/platform/intel_oaktrail/camera > +Date: Jan 2011 > +KernelVersion: 2.6.37 > +Contact: "Yin Kangkai" <kangkai.yin@intel.com> > +Description: > + Control the camera. 1 means on, 0 means off. > + > +What: /sys/devices/platform/intel_oaktrail/touchscreen > +Date: Jan 2011 > +KernelVersion: 2.6.37 > +Contact: "Yin Kangkai" <kangkai.yin@intel.com> > +Description: > + Show the status of the touch screen. 1 means on, 0 means off. > diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig > index 2b4038a..d1f6981 100644 > --- a/drivers/platform/x86/Kconfig > +++ b/drivers/platform/x86/Kconfig > @@ -655,4 +655,13 @@ config XO1_RFKILL > Support for enabling/disabling the WLAN interface on the OLPC XO-1 > laptop. > > +config INTEL_OAKTRAIL > + tristate "Intel Oaktrail Platform Extras" > + depends on ACPI > + depends on RFKILL > + ---help--- > + Intel Oaktrail platform need this driver to provide interfaces to > + enable/disable the Camera, WiFi, BT etc. devices. If in doubt, say Y > + here; it will only load on supported platforms. > + > endif # X86_PLATFORM_DEVICES > diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile > index 7ff60e6..add8ab7 100644 > --- a/drivers/platform/x86/Makefile > +++ b/drivers/platform/x86/Makefile > @@ -35,3 +35,4 @@ obj-$(CONFIG_INTEL_IPS) += intel_ips.o > obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o > obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o > obj-$(CONFIG_IBM_RTL) += ibm_rtl.o > +obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o > diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c > new file mode 100644 > index 0000000..9ec71c5 > --- /dev/null > +++ b/drivers/platform/x86/intel_oaktrail.c > @@ -0,0 +1,347 @@ > +/* > + Copyright (C) 2010 Intel Corporation > + Author: Yin Kangkai (kangkai.yin@intel.com) > + > + based on Compal driver > + > + Copyright (C) 2008 Cezary Jackiewicz <cezary.jackiewicz (at) gmail.com> > + > + based on MSI driver > + > + Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de> > + > + 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; either version 2 of the License, or > + (at your option) any later version. > + > + 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., 51 Franklin Street, Fifth Floor, Boston, MA > + 02110-1301, USA. > + */ > + > +/* > + * intel_oaktrail.c - Intel OakTrail Platform support. > + * > + * This driver exports a few files in /sys/devices/platform/intel_oaktrail/: > + * > + * camera - Camera subsystem enabled: contains either 0 or 1. (rw) > + * touchscreen - Touchscreen subsystem enabled: contains either 0 or 1. (ro) > + * > + * In addition to these platform device attributes, the driver registers itself > + * in the Linux rfkill subsystem for these components: > + * > + * wifi > + * bluetooth > + * wwan (3g) > + * gps > + * > + * and is available to userspace under /sys/class/rfkill/rfkillX/ > + * > + * This driver might work on other products based on Oaktrail. If you > + * want to try it you can pass force=1 as argument to the module which > + * will force it to load even when the DMI data doesn't identify the > + * product as compatible. > + */ > + > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > + > +#include <linux/module.h> > +#include <linux/kernel.h> > +#include <linux/init.h> > +#include <linux/acpi.h> > +#include <linux/platform_device.h> > +#include <linux/dmi.h> > +#include <linux/rfkill.h> > + > +#define DRIVER_NAME "intel_oaktrail" > +#define DRIVER_VERSION "0.2" > + > +/* > + * This is the devices status address in EC space, and the control bits > + * definition: > + * > + * (1 << 0): Camera enable/disable, RW. > + * (1 << 1): Bluetooth enable/disable, RW. > + * (1 << 2): GPS enable/disable, RW. > + * (1 << 3): WiFi enable/disable, RW. > + * (1 << 4): WWAN (3G) enable/disalbe, RW. > + * (1 << 5): Touchscreen enable/disable, Read Only. > + */ > +#define OT_EC_DEVICE_STATE_ADDRESS 0xD6 > + > +#define OT_EC_CAMERA_MASK (1 << 0) > +#define OT_EC_BT_MASK (1 << 1) > +#define OT_EC_GPS_MASK (1 << 2) > +#define OT_EC_WIFI_MASK (1 << 3) > +#define OT_EC_WWAN_MASK (1 << 4) > +#define OT_EC_TS_MASK (1 << 5) > + > +static int force; > +module_param(force, bool, 0); > +MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); > + > +static struct platform_device *oaktrail_device; > +static struct rfkill *bt_rfkill; > +static struct rfkill *gps_rfkill; > +static struct rfkill *wifi_rfkill; > +static struct rfkill *wwan_rfkill; > + > +#define SIMPLE_MASKED_STORE_SHOW(NAME, MASK) \ > +static ssize_t NAME##_show(struct device *dev, \ > + struct device_attribute *attr, char *buf) \ > +{ \ > + u8 value; \ > + ec_read(OT_EC_DEVICE_STATE_ADDRESS, &value); \ > + return sprintf(buf, "%d\n", ((value & MASK) != 0)); \ > +} \ > +static ssize_t NAME##_store(struct device *dev, \ > + struct device_attribute *attr, const char *buf, size_t count) \ > +{ \ > + int state; \ > + u8 old_val; \ > + ec_read(OT_EC_DEVICE_STATE_ADDRESS, &old_val); \ > + if (sscanf(buf, "%d", &state) != 1 || (state < 0 || state > 1)) \ > + return -EINVAL; \ > + ec_write(OT_EC_DEVICE_STATE_ADDRESS, state ? \ > + (old_val | MASK) : (old_val & ~MASK)); \ > + return count; \ > +} > + > +SIMPLE_MASKED_STORE_SHOW(camera, OT_EC_CAMERA_MASK) > +SIMPLE_MASKED_STORE_SHOW(touchscreen, OT_EC_TS_MASK) > + > +static DEVICE_ATTR(camera, 0644, camera_show, camera_store); > +static DEVICE_ATTR(touchscreen, 0444, touchscreen_show, NULL); > + > +static struct attribute *oaktrail_attributes[] = { > + &dev_attr_camera.attr, > + &dev_attr_touchscreen.attr, > + NULL > +}; > + > +static struct attribute_group oaktrail_attribute_group = { > + .attrs = oaktrail_attributes > +}; > + > +static int oaktrail_rfkill_set(void *data, bool blocked) > +{ > + u8 value; > + u8 result; > + unsigned long radio = (unsigned long) data; > + > + ec_read(OT_EC_DEVICE_STATE_ADDRESS, &result); > + > + if (!blocked) > + value = (u8) (result | radio); > + else > + value = (u8) (result & ~radio); > + > + ec_write(OT_EC_DEVICE_STATE_ADDRESS, value); > + > + return 0; > +} > + > +static const struct rfkill_ops oaktrail_rfkill_ops = { > + .set_block = oaktrail_rfkill_set, > +}; > + > +static struct rfkill *oaktrail_rfkill_new(char *name, enum rfkill_type type, > + unsigned long mask) > +{ > + int err; > + struct rfkill *rfkill_dev; > + > + rfkill_dev = rfkill_alloc(name, &oaktrail_device->dev, type, > + &oaktrail_rfkill_ops, (void *)mask); > + if (!rfkill_dev) > + return ERR_PTR(-ENOMEM); > + > + err = rfkill_register(rfkill_dev);
Maybe you should add a rfkill_init_sw_state() call here, to be sure that the rfkill initial state is right.
> + if (err) { > + rfkill_destroy(rfkill_dev); > + return ERR_PTR(err); > + } > + return rfkill_dev; > +} > + > +static inline void _oaktrail_rfkill_cleanup(struct rfkill *rf)
I don't know if the coding style allow _ function prefix, I used to believe it did not, but I checked Documentation/CodingStyle, and I found nothing about that, so it's probably ok.
> +{ > + if (rf) { > + rfkill_unregister(rf); > + rfkill_destroy(rf); > + } > + > + return;
We don't need that return
> +} > + > +static void oaktrail_rfkill_cleanup(void) > +{ > + _oaktrail_rfkill_cleanup(wifi_rfkill); > + _oaktrail_rfkill_cleanup(bt_rfkill); > + _oaktrail_rfkill_cleanup(gps_rfkill); > + _oaktrail_rfkill_cleanup(wwan_rfkill); > + > + return;
And that one
> +} > + > +static int oaktrail_rfkill_init(void) > +{ > + int ret; > + > + wifi_rfkill = oaktrail_rfkill_new("oaktrail-wifi", > + RFKILL_TYPE_WLAN, > + OT_EC_WIFI_MASK); > + if (IS_ERR(wifi_rfkill)) { > + ret = PTR_ERR(wifi_rfkill); > + wifi_rfkill = NULL; > + goto cleanup; > + } > + > + bt_rfkill = oaktrail_rfkill_new("oaktrail-bluetooth", > + RFKILL_TYPE_BLUETOOTH, > + OT_EC_BT_MASK); > + if (IS_ERR(bt_rfkill)) { > + ret = PTR_ERR(bt_rfkill); > + bt_rfkill = NULL; > + goto cleanup; > + } > + > + gps_rfkill = oaktrail_rfkill_new("oaktrail-gps", > + RFKILL_TYPE_GPS, > + OT_EC_GPS_MASK); > + if (IS_ERR(gps_rfkill)) { > + ret = PTR_ERR(gps_rfkill); > + gps_rfkill = NULL; > + goto cleanup; > + } > + > + wwan_rfkill = oaktrail_rfkill_new("oaktrail-wwan", > + RFKILL_TYPE_WWAN, > + OT_EC_WWAN_MASK); > + if (IS_ERR(wwan_rfkill)) { > + ret = PTR_ERR(wwan_rfkill); > + wwan_rfkill = NULL; > + goto cleanup; > + } > + > + return 0; > + > +cleanup: > + oaktrail_rfkill_cleanup(); > + return ret; > +} > + > +static int __devinit oaktrail_probe(struct platform_device *pdev) > +{ > + return sysfs_create_group(&pdev->dev.kobj, &oaktrail_attribute_group); > +} > + > +static int __devexit oaktrail_remove(struct platform_device *pdev) > +{ > + sysfs_remove_group(&pdev->dev.kobj, &oaktrail_attribute_group); > + > + return 0; > +} > + > +static struct platform_driver oaktrail_driver = { > + .driver = { > + .name = DRIVER_NAME, > + .owner = THIS_MODULE, > + }, > + .probe = oaktrail_probe, > + .remove = __devexit_p(oaktrail_remove) > +}; > + > +static int dmi_check_cb(const struct dmi_system_id *id) > +{ > + pr_info("Identified model '%s'\n", id->ident); > + return 0; > +} > + > +static struct dmi_system_id __initdata oaktrail_dmi_table[] = { > + { > + .ident = "OakTrail platform", > + .matches = { > + DMI_MATCH(DMI_PRODUCT_NAME, "OakTrail platform"), > + }, > + .callback = dmi_check_cb > + }, > + { } > +}; > + > +static int __init oaktrail_init(void) > +{ > + int ret; > + > + if (acpi_disabled) { > + pr_err("ACPI needs to be enabled for this driver to work!\n"); > + return -ENODEV; > + } > + > + if (!force && !dmi_check_system(oaktrail_dmi_table)) { > + pr_err("Platform not recognized (You could try the module's force-parameter)"); > + return -ENODEV; > + } > + > + ret = platform_driver_register(&oaktrail_driver); > + if (ret) { > + pr_warning("Unable to register platform driver\n"); > + goto err_driver_reg; > + } > + > + oaktrail_device = platform_device_alloc(DRIVER_NAME, -1); > + if (!oaktrail_device) { > + pr_warning("Unable to allocate platform device\n"); > + ret = -ENOMEM; > + goto err_device_alloc; > + } > + > + ret = platform_device_add(oaktrail_device); > + if (ret) { > + pr_warning("Unable to add platform device\n"); > + goto err_device_add; > + } > + > + ret = oaktrail_rfkill_init(); > + if (ret) { > + pr_warning("Setup rfkill failed\n"); > + goto err_rfkill; > + } > + > + pr_info("Driver "DRIVER_VERSION" successfully loaded\n"); > + return 0; > + > +err_rfkill: > + platform_device_del(oaktrail_device); > +err_device_add: > + platform_device_put(oaktrail_device); > +err_device_alloc: > + platform_driver_unregister(&oaktrail_driver); > +err_driver_reg: > + return ret; > +} > + > +static void __exit oaktrail_cleanup(void) > +{ > + platform_device_unregister(oaktrail_device); > + platform_driver_unregister(&oaktrail_driver); > + oaktrail_rfkill_cleanup(); > + > + pr_info("Driver unloaded\n"); > +} > + > +module_init(oaktrail_init); > +module_exit(oaktrail_cleanup); > + > +MODULE_AUTHOR("Yin Kangkai (kangkai.yin@intel.com)"); > +MODULE_DESCRIPTION("Intel Oaktrail Platform ACPI Extras"); > +MODULE_VERSION(DRIVER_VERSION); > +MODULE_LICENSE("GPL"); > +MODULE_ALIAS("dmi:*:svnIntelCorporation:pnOakTrailplatform:*"); > -- > 1.6.5 > >
-- Corentin Chary http://xf.iksaif.net -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |