linux/drivers/hwmon/applesmc.c
<<
>>
Prefs
   1/*
   2 * drivers/hwmon/applesmc.c - driver for Apple's SMC (accelerometer, temperature
   3 * sensors, fan control, keyboard backlight control) used in Intel-based Apple
   4 * computers.
   5 *
   6 * Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
   7 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
   8 *
   9 * Based on hdaps.c driver:
  10 * Copyright (C) 2005 Robert Love <rml@novell.com>
  11 * Copyright (C) 2005 Jesper Juhl <jj@chaosbits.net>
  12 *
  13 * Fan control based on smcFanControl:
  14 * Copyright (C) 2006 Hendrik Holtmann <holtmann@mac.com>
  15 *
  16 * This program is free software; you can redistribute it and/or modify it
  17 * under the terms of the GNU General Public License v2 as published by the
  18 * Free Software Foundation.
  19 *
  20 * This program is distributed in the hope that it will be useful, but WITHOUT
  21 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  22 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  23 * more details.
  24 *
  25 * You should have received a copy of the GNU General Public License along with
  26 * this program; if not, write to the Free Software Foundation, Inc.,
  27 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  28 */
  29
  30#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  31
  32#include <linux/delay.h>
  33#include <linux/platform_device.h>
  34#include <linux/input-polldev.h>
  35#include <linux/kernel.h>
  36#include <linux/slab.h>
  37#include <linux/module.h>
  38#include <linux/timer.h>
  39#include <linux/dmi.h>
  40#include <linux/mutex.h>
  41#include <linux/hwmon-sysfs.h>
  42#include <linux/io.h>
  43#include <linux/leds.h>
  44#include <linux/hwmon.h>
  45#include <linux/workqueue.h>
  46#include <linux/err.h>
  47
  48/* data port used by Apple SMC */
  49#define APPLESMC_DATA_PORT      0x300
  50/* command/status port used by Apple SMC */
  51#define APPLESMC_CMD_PORT       0x304
  52
  53#define APPLESMC_NR_PORTS       32 /* 0x300-0x31f */
  54
  55#define APPLESMC_MAX_DATA_LENGTH 32
  56
  57/* wait up to 128 ms for a status change. */
  58#define APPLESMC_MIN_WAIT       0x0010
  59#define APPLESMC_RETRY_WAIT     0x0100
  60#define APPLESMC_MAX_WAIT       0x20000
  61
  62#define APPLESMC_READ_CMD       0x10
  63#define APPLESMC_WRITE_CMD      0x11
  64#define APPLESMC_GET_KEY_BY_INDEX_CMD   0x12
  65#define APPLESMC_GET_KEY_TYPE_CMD       0x13
  66
  67#define KEY_COUNT_KEY           "#KEY" /* r-o ui32 */
  68
  69#define LIGHT_SENSOR_LEFT_KEY   "ALV0" /* r-o {alv (6-10 bytes) */
  70#define LIGHT_SENSOR_RIGHT_KEY  "ALV1" /* r-o {alv (6-10 bytes) */
  71#define BACKLIGHT_KEY           "LKSB" /* w-o {lkb (2 bytes) */
  72
  73#define CLAMSHELL_KEY           "MSLD" /* r-o ui8 (unused) */
  74
  75#define MOTION_SENSOR_X_KEY     "MO_X" /* r-o sp78 (2 bytes) */
  76#define MOTION_SENSOR_Y_KEY     "MO_Y" /* r-o sp78 (2 bytes) */
  77#define MOTION_SENSOR_Z_KEY     "MO_Z" /* r-o sp78 (2 bytes) */
  78#define MOTION_SENSOR_KEY       "MOCN" /* r/w ui16 */
  79
  80#define FANS_COUNT              "FNum" /* r-o ui8 */
  81#define FANS_MANUAL             "FS! " /* r-w ui16 */
  82#define FAN_ID_FMT              "F%dID" /* r-o char[16] */
  83
  84#define TEMP_SENSOR_TYPE        "sp78"
  85
  86/* List of keys used to read/write fan speeds */
  87static const char *const fan_speed_fmt[] = {
  88        "F%dAc",                /* actual speed */
  89        "F%dMn",                /* minimum speed (rw) */
  90        "F%dMx",                /* maximum speed */
  91        "F%dSf",                /* safe speed - not all models */
  92        "F%dTg",                /* target speed (manual: rw) */
  93};
  94
  95#define INIT_TIMEOUT_MSECS      5000    /* wait up to 5s for device init ... */
  96#define INIT_WAIT_MSECS         50      /* ... in 50ms increments */
  97
  98#define APPLESMC_POLL_INTERVAL  50      /* msecs */
  99#define APPLESMC_INPUT_FUZZ     4       /* input event threshold */
 100#define APPLESMC_INPUT_FLAT     4
 101
 102#define to_index(attr) (to_sensor_dev_attr(attr)->index & 0xffff)
 103#define to_option(attr) (to_sensor_dev_attr(attr)->index >> 16)
 104
 105/* Dynamic device node attributes */
 106struct applesmc_dev_attr {
 107        struct sensor_device_attribute sda;     /* hwmon attributes */
 108        char name[32];                          /* room for node file name */
 109};
 110
 111/* Dynamic device node group */
 112struct applesmc_node_group {
 113        char *format;                           /* format string */
 114        void *show;                             /* show function */
 115        void *store;                            /* store function */
 116        int option;                             /* function argument */
 117        struct applesmc_dev_attr *nodes;        /* dynamic node array */
 118};
 119
 120/* AppleSMC entry - cached register information */
 121struct applesmc_entry {
 122        char key[5];            /* four-letter key code */
 123        u8 valid;               /* set when entry is successfully read once */
 124        u8 len;                 /* bounded by APPLESMC_MAX_DATA_LENGTH */
 125        char type[5];           /* four-letter type code */
 126        u8 flags;               /* 0x10: func; 0x40: write; 0x80: read */
 127};
 128
 129/* Register lookup and registers common to all SMCs */
 130static struct applesmc_registers {
 131        struct mutex mutex;             /* register read/write mutex */
 132        unsigned int key_count;         /* number of SMC registers */
 133        unsigned int fan_count;         /* number of fans */
 134        unsigned int temp_count;        /* number of temperature registers */
 135        unsigned int temp_begin;        /* temperature lower index bound */
 136        unsigned int temp_end;          /* temperature upper index bound */
 137        unsigned int index_count;       /* size of temperature index array */
 138        int num_light_sensors;          /* number of light sensors */
 139        bool has_accelerometer;         /* has motion sensor */
 140        bool has_key_backlight;         /* has keyboard backlight */
 141        bool init_complete;             /* true when fully initialized */
 142        struct applesmc_entry *cache;   /* cached key entries */
 143        const char **index;             /* temperature key index */
 144} smcreg = {
 145        .mutex = __MUTEX_INITIALIZER(smcreg.mutex),
 146};
 147
 148static const int debug;
 149static struct platform_device *pdev;
 150static s16 rest_x;
 151static s16 rest_y;
 152static u8 backlight_state[2];
 153
 154static struct device *hwmon_dev;
 155static struct input_polled_dev *applesmc_idev;
 156
 157/*
 158 * Last index written to key_at_index sysfs file, and value to use for all other
 159 * key_at_index_* sysfs files.
 160 */
 161static unsigned int key_at_index;
 162
 163static struct workqueue_struct *applesmc_led_wq;
 164
 165/*
 166 * wait_read - Wait for a byte to appear on SMC port. Callers must
 167 * hold applesmc_lock.
 168 */
 169static int wait_read(void)
 170{
 171        u8 status;
 172        int us;
 173        for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
 174                udelay(us);
 175                status = inb(APPLESMC_CMD_PORT);
 176                /* read: wait for smc to settle */
 177                if (status & 0x01)
 178                        return 0;
 179        }
 180
 181        pr_warn("wait_read() fail: 0x%02x\n", status);
 182        return -EIO;
 183}
 184
 185/*
 186 * send_byte - Write to SMC port, retrying when necessary. Callers
 187 * must hold applesmc_lock.
 188 */
 189static int send_byte(u8 cmd, u16 port)
 190{
 191        u8 status;
 192        int us;
 193
 194        outb(cmd, port);
 195        for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
 196                udelay(us);
 197                status = inb(APPLESMC_CMD_PORT);
 198                /* write: wait for smc to settle */
 199                if (status & 0x02)
 200                        continue;
 201                /* ready: cmd accepted, return */
 202                if (status & 0x04)
 203                        return 0;
 204                /* timeout: give up */
 205                if (us << 1 == APPLESMC_MAX_WAIT)
 206                        break;
 207                /* busy: long wait and resend */
 208                udelay(APPLESMC_RETRY_WAIT);
 209                outb(cmd, port);
 210        }
 211
 212        pr_warn("send_byte(0x%02x, 0x%04x) fail: 0x%02x\n", cmd, port, status);
 213        return -EIO;
 214}
 215
 216static int send_command(u8 cmd)
 217{
 218        return send_byte(cmd, APPLESMC_CMD_PORT);
 219}
 220
 221static int send_argument(const char *key)
 222{
 223        int i;
 224
 225        for (i = 0; i < 4; i++)
 226                if (send_byte(key[i], APPLESMC_DATA_PORT))
 227                        return -EIO;
 228        return 0;
 229}
 230
 231static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
 232{
 233        int i;
 234
 235        if (send_command(cmd) || send_argument(key)) {
 236                pr_warn("%.4s: read arg fail\n", key);
 237                return -EIO;
 238        }
 239
 240        if (send_byte(len, APPLESMC_DATA_PORT)) {
 241                pr_warn("%.4s: read len fail\n", key);
 242                return -EIO;
 243        }
 244
 245        for (i = 0; i < len; i++) {
 246                if (wait_read()) {
 247                        pr_warn("%.4s: read data[%d] fail\n", key, i);
 248                        return -EIO;
 249                }
 250                buffer[i] = inb(APPLESMC_DATA_PORT);
 251        }
 252
 253        return 0;
 254}
 255
 256static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
 257{
 258        int i;
 259
 260        if (send_command(cmd) || send_argument(key)) {
 261                pr_warn("%s: write arg fail\n", key);
 262                return -EIO;
 263        }
 264
 265        if (send_byte(len, APPLESMC_DATA_PORT)) {
 266                pr_warn("%.4s: write len fail\n", key);
 267                return -EIO;
 268        }
 269
 270        for (i = 0; i < len; i++) {
 271                if (send_byte(buffer[i], APPLESMC_DATA_PORT)) {
 272                        pr_warn("%s: write data fail\n", key);
 273                        return -EIO;
 274                }
 275        }
 276
 277        return 0;
 278}
 279
 280static int read_register_count(unsigned int *count)
 281{
 282        __be32 be;
 283        int ret;
 284
 285        ret = read_smc(APPLESMC_READ_CMD, KEY_COUNT_KEY, (u8 *)&be, 4);
 286        if (ret)
 287                return ret;
 288
 289        *count = be32_to_cpu(be);
 290        return 0;
 291}
 292
 293/*
 294 * Serialized I/O
 295 *
 296 * Returns zero on success or a negative error on failure.
 297 * All functions below are concurrency safe - callers should NOT hold lock.
 298 */
 299
 300static int applesmc_read_entry(const struct applesmc_entry *entry,
 301                               u8 *buf, u8 len)
 302{
 303        int ret;
 304
 305        if (entry->len != len)
 306                return -EINVAL;
 307        mutex_lock(&smcreg.mutex);
 308        ret = read_smc(APPLESMC_READ_CMD, entry->key, buf, len);
 309        mutex_unlock(&smcreg.mutex);
 310
 311        return ret;
 312}
 313
 314static int applesmc_write_entry(const struct applesmc_entry *entry,
 315                                const u8 *buf, u8 len)
 316{
 317        int ret;
 318
 319        if (entry->len != len)
 320                return -EINVAL;
 321        mutex_lock(&smcreg.mutex);
 322        ret = write_smc(APPLESMC_WRITE_CMD, entry->key, buf, len);
 323        mutex_unlock(&smcreg.mutex);
 324        return ret;
 325}
 326
 327static const struct applesmc_entry *applesmc_get_entry_by_index(int index)
 328{
 329        struct applesmc_entry *cache = &smcreg.cache[index];
 330        u8 key[4], info[6];
 331        __be32 be;
 332        int ret = 0;
 333
 334        if (cache->valid)
 335                return cache;
 336
 337        mutex_lock(&smcreg.mutex);
 338
 339        if (cache->valid)
 340                goto out;
 341        be = cpu_to_be32(index);
 342        ret = read_smc(APPLESMC_GET_KEY_BY_INDEX_CMD, (u8 *)&be, key, 4);
 343        if (ret)
 344                goto out;
 345        ret = read_smc(APPLESMC_GET_KEY_TYPE_CMD, key, info, 6);
 346        if (ret)
 347                goto out;
 348
 349        memcpy(cache->key, key, 4);
 350        cache->len = info[0];
 351        memcpy(cache->type, &info[1], 4);
 352        cache->flags = info[5];
 353        cache->valid = 1;
 354
 355out:
 356        mutex_unlock(&smcreg.mutex);
 357        if (ret)
 358                return ERR_PTR(ret);
 359        return cache;
 360}
 361
 362static int applesmc_get_lower_bound(unsigned int *lo, const char *key)
 363{
 364        int begin = 0, end = smcreg.key_count;
 365        const struct applesmc_entry *entry;
 366
 367        while (begin != end) {
 368                int middle = begin + (end - begin) / 2;
 369                entry = applesmc_get_entry_by_index(middle);
 370                if (IS_ERR(entry)) {
 371                        *lo = 0;
 372                        return PTR_ERR(entry);
 373                }
 374                if (strcmp(entry->key, key) < 0)
 375                        begin = middle + 1;
 376                else
 377                        end = middle;
 378        }
 379
 380        *lo = begin;
 381        return 0;
 382}
 383
 384static int applesmc_get_upper_bound(unsigned int *hi, const char *key)
 385{
 386        int begin = 0, end = smcreg.key_count;
 387        const struct applesmc_entry *entry;
 388
 389        while (begin != end) {
 390                int middle = begin + (end - begin) / 2;
 391                entry = applesmc_get_entry_by_index(middle);
 392                if (IS_ERR(entry)) {
 393                        *hi = smcreg.key_count;
 394                        return PTR_ERR(entry);
 395                }
 396                if (strcmp(key, entry->key) < 0)
 397                        end = middle;
 398                else
 399                        begin = middle + 1;
 400        }
 401
 402        *hi = begin;
 403        return 0;
 404}
 405
 406static const struct applesmc_entry *applesmc_get_entry_by_key(const char *key)
 407{
 408        int begin, end;
 409        int ret;
 410
 411        ret = applesmc_get_lower_bound(&begin, key);
 412        if (ret)
 413                return ERR_PTR(ret);
 414        ret = applesmc_get_upper_bound(&end, key);
 415        if (ret)
 416                return ERR_PTR(ret);
 417        if (end - begin != 1)
 418                return ERR_PTR(-EINVAL);
 419
 420        return applesmc_get_entry_by_index(begin);
 421}
 422
 423static int applesmc_read_key(const char *key, u8 *buffer, u8 len)
 424{
 425        const struct applesmc_entry *entry;
 426
 427        entry = applesmc_get_entry_by_key(key);
 428        if (IS_ERR(entry))
 429                return PTR_ERR(entry);
 430
 431        return applesmc_read_entry(entry, buffer, len);
 432}
 433
 434static int applesmc_write_key(const char *key, const u8 *buffer, u8 len)
 435{
 436        const struct applesmc_entry *entry;
 437
 438        entry = applesmc_get_entry_by_key(key);
 439        if (IS_ERR(entry))
 440                return PTR_ERR(entry);
 441
 442        return applesmc_write_entry(entry, buffer, len);
 443}
 444
 445static int applesmc_has_key(const char *key, bool *value)
 446{
 447        const struct applesmc_entry *entry;
 448
 449        entry = applesmc_get_entry_by_key(key);
 450        if (IS_ERR(entry) && PTR_ERR(entry) != -EINVAL)
 451                return PTR_ERR(entry);
 452
 453        *value = !IS_ERR(entry);
 454        return 0;
 455}
 456
 457/*
 458 * applesmc_read_s16 - Read 16-bit signed big endian register
 459 */
 460static int applesmc_read_s16(const char *key, s16 *value)
 461{
 462        u8 buffer[2];
 463        int ret;
 464
 465        ret = applesmc_read_key(key, buffer, 2);
 466        if (ret)
 467                return ret;
 468
 469        *value = ((s16)buffer[0] << 8) | buffer[1];
 470        return 0;
 471}
 472
 473/*
 474 * applesmc_device_init - initialize the accelerometer.  Can sleep.
 475 */
 476static void applesmc_device_init(void)
 477{
 478        int total;
 479        u8 buffer[2];
 480
 481        if (!smcreg.has_accelerometer)
 482                return;
 483
 484        for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
 485                if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
 486                                (buffer[0] != 0x00 || buffer[1] != 0x00))
 487                        return;
 488                buffer[0] = 0xe0;
 489                buffer[1] = 0x00;
 490                applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
 491                msleep(INIT_WAIT_MSECS);
 492        }
 493
 494        pr_warn("failed to init the device\n");
 495}
 496
 497static int applesmc_init_index(struct applesmc_registers *s)
 498{
 499        const struct applesmc_entry *entry;
 500        unsigned int i;
 501
 502        if (s->index)
 503                return 0;
 504
 505        s->index = kcalloc(s->temp_count, sizeof(s->index[0]), GFP_KERNEL);
 506        if (!s->index)
 507                return -ENOMEM;
 508
 509        for (i = s->temp_begin; i < s->temp_end; i++) {
 510                entry = applesmc_get_entry_by_index(i);
 511                if (IS_ERR(entry))
 512                        continue;
 513                if (strcmp(entry->type, TEMP_SENSOR_TYPE))
 514                        continue;
 515                s->index[s->index_count++] = entry->key;
 516        }
 517
 518        return 0;
 519}
 520
 521/*
 522 * applesmc_init_smcreg_try - Try to initialize register cache. Idempotent.
 523 */
 524static int applesmc_init_smcreg_try(void)
 525{
 526        struct applesmc_registers *s = &smcreg;
 527        bool left_light_sensor, right_light_sensor;
 528        u8 tmp[1];
 529        int ret;
 530
 531        if (s->init_complete)
 532                return 0;
 533
 534        ret = read_register_count(&s->key_count);
 535        if (ret)
 536                return ret;
 537
 538        if (!s->cache)
 539                s->cache = kcalloc(s->key_count, sizeof(*s->cache), GFP_KERNEL);
 540        if (!s->cache)
 541                return -ENOMEM;
 542
 543        ret = applesmc_read_key(FANS_COUNT, tmp, 1);
 544        if (ret)
 545                return ret;
 546        s->fan_count = tmp[0];
 547
 548        ret = applesmc_get_lower_bound(&s->temp_begin, "T");
 549        if (ret)
 550                return ret;
 551        ret = applesmc_get_lower_bound(&s->temp_end, "U");
 552        if (ret)
 553                return ret;
 554        s->temp_count = s->temp_end - s->temp_begin;
 555
 556        ret = applesmc_init_index(s);
 557        if (ret)
 558                return ret;
 559
 560        ret = applesmc_has_key(LIGHT_SENSOR_LEFT_KEY, &left_light_sensor);
 561        if (ret)
 562                return ret;
 563        ret = applesmc_has_key(LIGHT_SENSOR_RIGHT_KEY, &right_light_sensor);
 564        if (ret)
 565                return ret;
 566        ret = applesmc_has_key(MOTION_SENSOR_KEY, &s->has_accelerometer);
 567        if (ret)
 568                return ret;
 569        ret = applesmc_has_key(BACKLIGHT_KEY, &s->has_key_backlight);
 570        if (ret)
 571                return ret;
 572
 573        s->num_light_sensors = left_light_sensor + right_light_sensor;
 574        s->init_complete = true;
 575
 576        pr_info("key=%d fan=%d temp=%d index=%d acc=%d lux=%d kbd=%d\n",
 577               s->key_count, s->fan_count, s->temp_count, s->index_count,
 578               s->has_accelerometer,
 579               s->num_light_sensors,
 580               s->has_key_backlight);
 581
 582        return 0;
 583}
 584
 585static void applesmc_destroy_smcreg(void)
 586{
 587        kfree(smcreg.index);
 588        smcreg.index = NULL;
 589        kfree(smcreg.cache);
 590        smcreg.cache = NULL;
 591        smcreg.init_complete = false;
 592}
 593
 594/*
 595 * applesmc_init_smcreg - Initialize register cache.
 596 *
 597 * Retries until initialization is successful, or the operation times out.
 598 *
 599 */
 600static int applesmc_init_smcreg(void)
 601{
 602        int ms, ret;
 603
 604        for (ms = 0; ms < INIT_TIMEOUT_MSECS; ms += INIT_WAIT_MSECS) {
 605                ret = applesmc_init_smcreg_try();
 606                if (!ret) {
 607                        if (ms)
 608                                pr_info("init_smcreg() took %d ms\n", ms);
 609                        return 0;
 610                }
 611                msleep(INIT_WAIT_MSECS);
 612        }
 613
 614        applesmc_destroy_smcreg();
 615
 616        return ret;
 617}
 618
 619/* Device model stuff */
 620static int applesmc_probe(struct platform_device *dev)
 621{
 622        int ret;
 623
 624        ret = applesmc_init_smcreg();
 625        if (ret)
 626                return ret;
 627
 628        applesmc_device_init();
 629
 630        return 0;
 631}
 632
 633/* Synchronize device with memorized backlight state */
 634static int applesmc_pm_resume(struct device *dev)
 635{
 636        if (smcreg.has_key_backlight)
 637                applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
 638        return 0;
 639}
 640
 641/* Reinitialize device on resume from hibernation */
 642static int applesmc_pm_restore(struct device *dev)
 643{
 644        applesmc_device_init();
 645        return applesmc_pm_resume(dev);
 646}
 647
 648static const struct dev_pm_ops applesmc_pm_ops = {
 649        .resume = applesmc_pm_resume,
 650        .restore = applesmc_pm_restore,
 651};
 652
 653static struct platform_driver applesmc_driver = {
 654        .probe = applesmc_probe,
 655        .driver = {
 656                .name = "applesmc",
 657                .owner = THIS_MODULE,
 658                .pm = &applesmc_pm_ops,
 659        },
 660};
 661
 662/*
 663 * applesmc_calibrate - Set our "resting" values.  Callers must
 664 * hold applesmc_lock.
 665 */
 666static void applesmc_calibrate(void)
 667{
 668        applesmc_read_s16(MOTION_SENSOR_X_KEY, &rest_x);
 669        applesmc_read_s16(MOTION_SENSOR_Y_KEY, &rest_y);
 670        rest_x = -rest_x;
 671}
 672
 673static void applesmc_idev_poll(struct input_polled_dev *dev)
 674{
 675        struct input_dev *idev = dev->input;
 676        s16 x, y;
 677
 678        if (applesmc_read_s16(MOTION_SENSOR_X_KEY, &x))
 679                return;
 680        if (applesmc_read_s16(MOTION_SENSOR_Y_KEY, &y))
 681                return;
 682
 683        x = -x;
 684        input_report_abs(idev, ABS_X, x - rest_x);
 685        input_report_abs(idev, ABS_Y, y - rest_y);
 686        input_sync(idev);
 687}
 688
 689/* Sysfs Files */
 690
 691static ssize_t applesmc_name_show(struct device *dev,
 692                                   struct device_attribute *attr, char *buf)
 693{
 694        return snprintf(buf, PAGE_SIZE, "applesmc\n");
 695}
 696
 697static ssize_t applesmc_position_show(struct device *dev,
 698                                   struct device_attribute *attr, char *buf)
 699{
 700        int ret;
 701        s16 x, y, z;
 702
 703        ret = applesmc_read_s16(MOTION_SENSOR_X_KEY, &x);
 704        if (ret)
 705                goto out;
 706        ret = applesmc_read_s16(MOTION_SENSOR_Y_KEY, &y);
 707        if (ret)
 708                goto out;
 709        ret = applesmc_read_s16(MOTION_SENSOR_Z_KEY, &z);
 710        if (ret)
 711                goto out;
 712
 713out:
 714        if (ret)
 715                return ret;
 716        else
 717                return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
 718}
 719
 720static ssize_t applesmc_light_show(struct device *dev,
 721                                struct device_attribute *attr, char *sysfsbuf)
 722{
 723        const struct applesmc_entry *entry;
 724        static int data_length;
 725        int ret;
 726        u8 left = 0, right = 0;
 727        u8 buffer[10];
 728
 729        if (!data_length) {
 730                entry = applesmc_get_entry_by_key(LIGHT_SENSOR_LEFT_KEY);
 731                if (IS_ERR(entry))
 732                        return PTR_ERR(entry);
 733                if (entry->len > 10)
 734                        return -ENXIO;
 735                data_length = entry->len;
 736                pr_info("light sensor data length set to %d\n", data_length);
 737        }
 738
 739        ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
 740        /* newer macbooks report a single 10-bit bigendian value */
 741        if (data_length == 10) {
 742                left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
 743                goto out;
 744        }
 745        left = buffer[2];
 746        if (ret)
 747                goto out;
 748        ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
 749        right = buffer[2];
 750
 751out:
 752        if (ret)
 753                return ret;
 754        else
 755                return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
 756}
 757
 758/* Displays sensor key as label */
 759static ssize_t applesmc_show_sensor_label(struct device *dev,
 760                        struct device_attribute *devattr, char *sysfsbuf)
 761{
 762        const char *key = smcreg.index[to_index(devattr)];
 763
 764        return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
 765}
 766
 767/* Displays degree Celsius * 1000 */
 768static ssize_t applesmc_show_temperature(struct device *dev,
 769                        struct device_attribute *devattr, char *sysfsbuf)
 770{
 771        const char *key = smcreg.index[to_index(devattr)];
 772        int ret;
 773        s16 value;
 774        int temp;
 775
 776        ret = applesmc_read_s16(key, &value);
 777        if (ret)
 778                return ret;
 779
 780        temp = 250 * (value >> 6);
 781
 782        return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", temp);
 783}
 784
 785static ssize_t applesmc_show_fan_speed(struct device *dev,
 786                                struct device_attribute *attr, char *sysfsbuf)
 787{
 788        int ret;
 789        unsigned int speed = 0;
 790        char newkey[5];
 791        u8 buffer[2];
 792
 793        sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
 794
 795        ret = applesmc_read_key(newkey, buffer, 2);
 796        speed = ((buffer[0] << 8 | buffer[1]) >> 2);
 797
 798        if (ret)
 799                return ret;
 800        else
 801                return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
 802}
 803
 804static ssize_t applesmc_store_fan_speed(struct device *dev,
 805                                        struct device_attribute *attr,
 806                                        const char *sysfsbuf, size_t count)
 807{
 808        int ret;
 809        unsigned long speed;
 810        char newkey[5];
 811        u8 buffer[2];
 812
 813        if (kstrtoul(sysfsbuf, 10, &speed) < 0 || speed >= 0x4000)
 814                return -EINVAL;         /* Bigger than a 14-bit value */
 815
 816        sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
 817
 818        buffer[0] = (speed >> 6) & 0xff;
 819        buffer[1] = (speed << 2) & 0xff;
 820        ret = applesmc_write_key(newkey, buffer, 2);
 821
 822        if (ret)
 823                return ret;
 824        else
 825                return count;
 826}
 827
 828static ssize_t applesmc_show_fan_manual(struct device *dev,
 829                        struct device_attribute *attr, char *sysfsbuf)
 830{
 831        int ret;
 832        u16 manual = 0;
 833        u8 buffer[2];
 834
 835        ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
 836        manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
 837
 838        if (ret)
 839                return ret;
 840        else
 841                return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
 842}
 843
 844static ssize_t applesmc_store_fan_manual(struct device *dev,
 845                                         struct device_attribute *attr,
 846                                         const char *sysfsbuf, size_t count)
 847{
 848        int ret;
 849        u8 buffer[2];
 850        unsigned long input;
 851        u16 val;
 852
 853        if (kstrtoul(sysfsbuf, 10, &input) < 0)
 854                return -EINVAL;
 855
 856        ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
 857        val = (buffer[0] << 8 | buffer[1]);
 858        if (ret)
 859                goto out;
 860
 861        if (input)
 862                val = val | (0x01 << to_index(attr));
 863        else
 864                val = val & ~(0x01 << to_index(attr));
 865
 866        buffer[0] = (val >> 8) & 0xFF;
 867        buffer[1] = val & 0xFF;
 868
 869        ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
 870
 871out:
 872        if (ret)
 873                return ret;
 874        else
 875                return count;
 876}
 877
 878static ssize_t applesmc_show_fan_position(struct device *dev,
 879                                struct device_attribute *attr, char *sysfsbuf)
 880{
 881        int ret;
 882        char newkey[5];
 883        u8 buffer[17];
 884
 885        sprintf(newkey, FAN_ID_FMT, to_index(attr));
 886
 887        ret = applesmc_read_key(newkey, buffer, 16);
 888        buffer[16] = 0;
 889
 890        if (ret)
 891                return ret;
 892        else
 893                return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
 894}
 895
 896static ssize_t applesmc_calibrate_show(struct device *dev,
 897                                struct device_attribute *attr, char *sysfsbuf)
 898{
 899        return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
 900}
 901
 902static ssize_t applesmc_calibrate_store(struct device *dev,
 903        struct device_attribute *attr, const char *sysfsbuf, size_t count)
 904{
 905        applesmc_calibrate();
 906
 907        return count;
 908}
 909
 910static void applesmc_backlight_set(struct work_struct *work)
 911{
 912        applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
 913}
 914static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
 915
 916static void applesmc_brightness_set(struct led_classdev *led_cdev,
 917                                                enum led_brightness value)
 918{
 919        int ret;
 920
 921        backlight_state[0] = value;
 922        ret = queue_work(applesmc_led_wq, &backlight_work);
 923
 924        if (debug && (!ret))
 925                printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
 926}
 927
 928static ssize_t applesmc_key_count_show(struct device *dev,
 929                                struct device_attribute *attr, char *sysfsbuf)
 930{
 931        int ret;
 932        u8 buffer[4];
 933        u32 count;
 934
 935        ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
 936        count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
 937                                                ((u32)buffer[2]<<8) + buffer[3];
 938
 939        if (ret)
 940                return ret;
 941        else
 942                return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
 943}
 944
 945static ssize_t applesmc_key_at_index_read_show(struct device *dev,
 946                                struct device_attribute *attr, char *sysfsbuf)
 947{
 948        const struct applesmc_entry *entry;
 949        int ret;
 950
 951        entry = applesmc_get_entry_by_index(key_at_index);
 952        if (IS_ERR(entry))
 953                return PTR_ERR(entry);
 954        ret = applesmc_read_entry(entry, sysfsbuf, entry->len);
 955        if (ret)
 956                return ret;
 957
 958        return entry->len;
 959}
 960
 961static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
 962                                struct device_attribute *attr, char *sysfsbuf)
 963{
 964        const struct applesmc_entry *entry;
 965
 966        entry = applesmc_get_entry_by_index(key_at_index);
 967        if (IS_ERR(entry))
 968                return PTR_ERR(entry);
 969
 970        return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", entry->len);
 971}
 972
 973static ssize_t applesmc_key_at_index_type_show(struct device *dev,
 974                                struct device_attribute *attr, char *sysfsbuf)
 975{
 976        const struct applesmc_entry *entry;
 977
 978        entry = applesmc_get_entry_by_index(key_at_index);
 979        if (IS_ERR(entry))
 980                return PTR_ERR(entry);
 981
 982        return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->type);
 983}
 984
 985static ssize_t applesmc_key_at_index_name_show(struct device *dev,
 986                                struct device_attribute *attr, char *sysfsbuf)
 987{
 988        const struct applesmc_entry *entry;
 989
 990        entry = applesmc_get_entry_by_index(key_at_index);
 991        if (IS_ERR(entry))
 992                return PTR_ERR(entry);
 993
 994        return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->key);
 995}
 996
 997static ssize_t applesmc_key_at_index_show(struct device *dev,
 998                                struct device_attribute *attr, char *sysfsbuf)
 999{
1000        return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
1001}
1002
1003static ssize_t applesmc_key_at_index_store(struct device *dev,
1004        struct device_attribute *attr, const char *sysfsbuf, size_t count)
1005{
1006        unsigned long newkey;
1007
1008        if (kstrtoul(sysfsbuf, 10, &newkey) < 0
1009            || newkey >= smcreg.key_count)
1010                return -EINVAL;
1011
1012        key_at_index = newkey;
1013        return count;
1014}
1015
1016static struct led_classdev applesmc_backlight = {
1017        .name                   = "smc::kbd_backlight",
1018        .default_trigger        = "nand-disk",
1019        .brightness_set         = applesmc_brightness_set,
1020};
1021
1022static struct applesmc_node_group info_group[] = {
1023        { "name", applesmc_name_show },
1024        { "key_count", applesmc_key_count_show },
1025        { "key_at_index", applesmc_key_at_index_show, applesmc_key_at_index_store },
1026        { "key_at_index_name", applesmc_key_at_index_name_show },
1027        { "key_at_index_type", applesmc_key_at_index_type_show },
1028        { "key_at_index_data_length", applesmc_key_at_index_data_length_show },
1029        { "key_at_index_data", applesmc_key_at_index_read_show },
1030        { }
1031};
1032
1033static struct applesmc_node_group accelerometer_group[] = {
1034        { "position", applesmc_position_show },
1035        { "calibrate", applesmc_calibrate_show, applesmc_calibrate_store },
1036        { }
1037};
1038
1039static struct applesmc_node_group light_sensor_group[] = {
1040        { "light", applesmc_light_show },
1041        { }
1042};
1043
1044static struct applesmc_node_group fan_group[] = {
1045        { "fan%d_label", applesmc_show_fan_position },
1046        { "fan%d_input", applesmc_show_fan_speed, NULL, 0 },
1047        { "fan%d_min", applesmc_show_fan_speed, applesmc_store_fan_speed, 1 },
1048        { "fan%d_max", applesmc_show_fan_speed, NULL, 2 },
1049        { "fan%d_safe", applesmc_show_fan_speed, NULL, 3 },
1050        { "fan%d_output", applesmc_show_fan_speed, applesmc_store_fan_speed, 4 },
1051        { "fan%d_manual", applesmc_show_fan_manual, applesmc_store_fan_manual },
1052        { }
1053};
1054
1055static struct applesmc_node_group temp_group[] = {
1056        { "temp%d_label", applesmc_show_sensor_label },
1057        { "temp%d_input", applesmc_show_temperature },
1058        { }
1059};
1060
1061/* Module stuff */
1062
1063/*
1064 * applesmc_destroy_nodes - remove files and free associated memory
1065 */
1066static void applesmc_destroy_nodes(struct applesmc_node_group *groups)
1067{
1068        struct applesmc_node_group *grp;
1069        struct applesmc_dev_attr *node;
1070
1071        for (grp = groups; grp->nodes; grp++) {
1072                for (node = grp->nodes; node->sda.dev_attr.attr.name; node++)
1073                        sysfs_remove_file(&pdev->dev.kobj,
1074                                          &node->sda.dev_attr.attr);
1075                kfree(grp->nodes);
1076                grp->nodes = NULL;
1077        }
1078}
1079
1080/*
1081 * applesmc_create_nodes - create a two-dimensional group of sysfs files
1082 */
1083static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
1084{
1085        struct applesmc_node_group *grp;
1086        struct applesmc_dev_attr *node;
1087        struct attribute *attr;
1088        int ret, i;
1089
1090        for (grp = groups; grp->format; grp++) {
1091                grp->nodes = kcalloc(num + 1, sizeof(*node), GFP_KERNEL);
1092                if (!grp->nodes) {
1093                        ret = -ENOMEM;
1094                        goto out;
1095                }
1096                for (i = 0; i < num; i++) {
1097                        node = &grp->nodes[i];
1098                        sprintf(node->name, grp->format, i + 1);
1099                        node->sda.index = (grp->option << 16) | (i & 0xffff);
1100                        node->sda.dev_attr.show = grp->show;
1101                        node->sda.dev_attr.store = grp->store;
1102                        attr = &node->sda.dev_attr.attr;
1103                        sysfs_attr_init(attr);
1104                        attr->name = node->name;
1105                        attr->mode = S_IRUGO | (grp->store ? S_IWUSR : 0);
1106                        ret = sysfs_create_file(&pdev->dev.kobj, attr);
1107                        if (ret) {
1108                                attr->name = NULL;
1109                                goto out;
1110                        }
1111                }
1112        }
1113
1114        return 0;
1115out:
1116        applesmc_destroy_nodes(groups);
1117        return ret;
1118}
1119
1120/* Create accelerometer ressources */
1121static int applesmc_create_accelerometer(void)
1122{
1123        struct input_dev *idev;
1124        int ret;
1125
1126        if (!smcreg.has_accelerometer)
1127                return 0;
1128
1129        ret = applesmc_create_nodes(accelerometer_group, 1);
1130        if (ret)
1131                goto out;
1132
1133        applesmc_idev = input_allocate_polled_device();
1134        if (!applesmc_idev) {
1135                ret = -ENOMEM;
1136                goto out_sysfs;
1137        }
1138
1139        applesmc_idev->poll = applesmc_idev_poll;
1140        applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
1141
1142        /* initial calibrate for the input device */
1143        applesmc_calibrate();
1144
1145        /* initialize the input device */
1146        idev = applesmc_idev->input;
1147        idev->name = "applesmc";
1148        idev->id.bustype = BUS_HOST;
1149        idev->dev.parent = &pdev->dev;
1150        idev->evbit[0] = BIT_MASK(EV_ABS);
1151        input_set_abs_params(idev, ABS_X,
1152                        -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1153        input_set_abs_params(idev, ABS_Y,
1154                        -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1155
1156        ret = input_register_polled_device(applesmc_idev);
1157        if (ret)
1158                goto out_idev;
1159
1160        return 0;
1161
1162out_idev:
1163        input_free_polled_device(applesmc_idev);
1164
1165out_sysfs:
1166        applesmc_destroy_nodes(accelerometer_group);
1167
1168out:
1169        pr_warn("driver init failed (ret=%d)!\n", ret);
1170        return ret;
1171}
1172
1173/* Release all ressources used by the accelerometer */
1174static void applesmc_release_accelerometer(void)
1175{
1176        if (!smcreg.has_accelerometer)
1177                return;
1178        input_unregister_polled_device(applesmc_idev);
1179        input_free_polled_device(applesmc_idev);
1180        applesmc_destroy_nodes(accelerometer_group);
1181}
1182
1183static int applesmc_create_light_sensor(void)
1184{
1185        if (!smcreg.num_light_sensors)
1186                return 0;
1187        return applesmc_create_nodes(light_sensor_group, 1);
1188}
1189
1190static void applesmc_release_light_sensor(void)
1191{
1192        if (!smcreg.num_light_sensors)
1193                return;
1194        applesmc_destroy_nodes(light_sensor_group);
1195}
1196
1197static int applesmc_create_key_backlight(void)
1198{
1199        if (!smcreg.has_key_backlight)
1200                return 0;
1201        applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
1202        if (!applesmc_led_wq)
1203                return -ENOMEM;
1204        return led_classdev_register(&pdev->dev, &applesmc_backlight);
1205}
1206
1207static void applesmc_release_key_backlight(void)
1208{
1209        if (!smcreg.has_key_backlight)
1210                return;
1211        led_classdev_unregister(&applesmc_backlight);
1212        destroy_workqueue(applesmc_led_wq);
1213}
1214
1215static int applesmc_dmi_match(const struct dmi_system_id *id)
1216{
1217        return 1;
1218}
1219
1220/*
1221 * Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
1222 * So we need to put "Apple MacBook Pro" before "Apple MacBook".
1223 */
1224static __initdata struct dmi_system_id applesmc_whitelist[] = {
1225        { applesmc_dmi_match, "Apple MacBook Air", {
1226          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1227          DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
1228        },
1229        { applesmc_dmi_match, "Apple MacBook Pro", {
1230          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1231          DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro") },
1232        },
1233        { applesmc_dmi_match, "Apple MacBook", {
1234          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1235          DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") },
1236        },
1237        { applesmc_dmi_match, "Apple Macmini", {
1238          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1239          DMI_MATCH(DMI_PRODUCT_NAME, "Macmini") },
1240        },
1241        { applesmc_dmi_match, "Apple MacPro", {
1242          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1243          DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
1244        },
1245        { applesmc_dmi_match, "Apple iMac", {
1246          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1247          DMI_MATCH(DMI_PRODUCT_NAME, "iMac") },
1248        },
1249        { .ident = NULL }
1250};
1251
1252static int __init applesmc_init(void)
1253{
1254        int ret;
1255
1256        if (!dmi_check_system(applesmc_whitelist)) {
1257                pr_warn("supported laptop not found!\n");
1258                ret = -ENODEV;
1259                goto out;
1260        }
1261
1262        if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
1263                                                                "applesmc")) {
1264                ret = -ENXIO;
1265                goto out;
1266        }
1267
1268        ret = platform_driver_register(&applesmc_driver);
1269        if (ret)
1270                goto out_region;
1271
1272        pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
1273                                               NULL, 0);
1274        if (IS_ERR(pdev)) {
1275                ret = PTR_ERR(pdev);
1276                goto out_driver;
1277        }
1278
1279        /* create register cache */
1280        ret = applesmc_init_smcreg();
1281        if (ret)
1282                goto out_device;
1283
1284        ret = applesmc_create_nodes(info_group, 1);
1285        if (ret)
1286                goto out_smcreg;
1287
1288        ret = applesmc_create_nodes(fan_group, smcreg.fan_count);
1289        if (ret)
1290                goto out_info;
1291
1292        ret = applesmc_create_nodes(temp_group, smcreg.index_count);
1293        if (ret)
1294                goto out_fans;
1295
1296        ret = applesmc_create_accelerometer();
1297        if (ret)
1298                goto out_temperature;
1299
1300        ret = applesmc_create_light_sensor();
1301        if (ret)
1302                goto out_accelerometer;
1303
1304        ret = applesmc_create_key_backlight();
1305        if (ret)
1306                goto out_light_sysfs;
1307
1308        hwmon_dev = hwmon_device_register(&pdev->dev);
1309        if (IS_ERR(hwmon_dev)) {
1310                ret = PTR_ERR(hwmon_dev);
1311                goto out_light_ledclass;
1312        }
1313
1314        return 0;
1315
1316out_light_ledclass:
1317        applesmc_release_key_backlight();
1318out_light_sysfs:
1319        applesmc_release_light_sensor();
1320out_accelerometer:
1321        applesmc_release_accelerometer();
1322out_temperature:
1323        applesmc_destroy_nodes(temp_group);
1324out_fans:
1325        applesmc_destroy_nodes(fan_group);
1326out_info:
1327        applesmc_destroy_nodes(info_group);
1328out_smcreg:
1329        applesmc_destroy_smcreg();
1330out_device:
1331        platform_device_unregister(pdev);
1332out_driver:
1333        platform_driver_unregister(&applesmc_driver);
1334out_region:
1335        release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1336out:
1337        pr_warn("driver init failed (ret=%d)!\n", ret);
1338        return ret;
1339}
1340
1341static void __exit applesmc_exit(void)
1342{
1343        hwmon_device_unregister(hwmon_dev);
1344        applesmc_release_key_backlight();
1345        applesmc_release_light_sensor();
1346        applesmc_release_accelerometer();
1347        applesmc_destroy_nodes(temp_group);
1348        applesmc_destroy_nodes(fan_group);
1349        applesmc_destroy_nodes(info_group);
1350        applesmc_destroy_smcreg();
1351        platform_device_unregister(pdev);
1352        platform_driver_unregister(&applesmc_driver);
1353        release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1354}
1355
1356module_init(applesmc_init);
1357module_exit(applesmc_exit);
1358
1359MODULE_AUTHOR("Nicolas Boichat");
1360MODULE_DESCRIPTION("Apple SMC");
1361MODULE_LICENSE("GPL v2");
1362MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);
1363
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.