On Fri, Jan 7, 2011 at 8:41 AM, Yin Kangkai <kangkai.yin@xxxxxxxxxxxxxxx> 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@xxxxxxxxx> > 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@xxxxxxxxx> > --- > Â.../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@xxxxxxxxx> > +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@xxxxxxxxx> > +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@xxxxxxxxx) > + > + Â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@xxxxxxxxx)"); > +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 platform-driver-x86" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html