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