HID: hid-cypress: validate length of report
[pandora-kernel.git] / drivers / hwmon / applesmc.c
index 4c07436..0b86d47 100644 (file)
@@ -212,23 +212,36 @@ static int send_argument(const char *key)
 
 static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
 {
+       u8 status, data = 0;
        int i;
 
        if (send_command(cmd) || send_argument(key)) {
-               pr_warn("%s: read arg fail\n", key);
+               pr_warn("%.4s: read arg fail\n", key);
                return -EIO;
        }
 
+       /* This has no effect on newer (2012) SMCs */
        outb(len, APPLESMC_DATA_PORT);
 
        for (i = 0; i < len; i++) {
                if (__wait_status(0x05)) {
-                       pr_warn("%s: read data fail\n", key);
+                       pr_warn("%.4s: read data fail\n", key);
                        return -EIO;
                }
                buffer[i] = inb(APPLESMC_DATA_PORT);
        }
 
+       /* Read the data port until bit0 is cleared */
+       for (i = 0; i < 16; i++) {
+               udelay(APPLESMC_MIN_WAIT);
+               status = inb(APPLESMC_CMD_PORT);
+               if (!(status & 0x01))
+                       break;
+               data = inb(APPLESMC_DATA_PORT);
+       }
+       if (i)
+               pr_warn("flushed %d bytes, last value is: %d\n", i, data);
+
        return 0;
 }
 
@@ -344,8 +357,10 @@ static int applesmc_get_lower_bound(unsigned int *lo, const char *key)
        while (begin != end) {
                int middle = begin + (end - begin) / 2;
                entry = applesmc_get_entry_by_index(middle);
-               if (IS_ERR(entry))
+               if (IS_ERR(entry)) {
+                       *lo = 0;
                        return PTR_ERR(entry);
+               }
                if (strcmp(entry->key, key) < 0)
                        begin = middle + 1;
                else
@@ -364,8 +379,10 @@ static int applesmc_get_upper_bound(unsigned int *hi, const char *key)
        while (begin != end) {
                int middle = begin + (end - begin) / 2;
                entry = applesmc_get_entry_by_index(middle);
-               if (IS_ERR(entry))
+               if (IS_ERR(entry)) {
+                       *hi = smcreg.key_count;
                        return PTR_ERR(entry);
+               }
                if (strcmp(key, entry->key) < 0)
                        end = middle;
                else
@@ -485,16 +502,25 @@ static int applesmc_init_smcreg_try(void)
 {
        struct applesmc_registers *s = &smcreg;
        bool left_light_sensor, right_light_sensor;
+       unsigned int count;
        u8 tmp[1];
        int ret;
 
        if (s->init_complete)
                return 0;
 
-       ret = read_register_count(&s->key_count);
+       ret = read_register_count(&count);
        if (ret)
                return ret;
 
+       if (s->cache && s->key_count != count) {
+               pr_warn("key count changed from %d to %d\n",
+                       s->key_count, count);
+               kfree(s->cache);
+               s->cache = NULL;
+       }
+       s->key_count = count;
+
        if (!s->cache)
                s->cache = kcalloc(s->key_count, sizeof(*s->cache), GFP_KERNEL);
        if (!s->cache)