Merge tag 'for-linus-3.11-merge-window-part-1' of git://git.kernel.org/pub/scm/linux...
[firefly-linux-kernel-4.4.55.git] / drivers / hid / hid-wiimote-core.c
index fa58045cf7e054e93e60922303dae0208666d504..0c06054cab8f01033404f35375c0e12584db3c51 100644 (file)
@@ -452,6 +452,8 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem)
                return WIIMOTE_EXT_CLASSIC_CONTROLLER;
        if (rmem[4] == 0x04 && rmem[5] == 0x02)
                return WIIMOTE_EXT_BALANCE_BOARD;
+       if (rmem[4] == 0x01 && rmem[5] == 0x20)
+               return WIIMOTE_EXT_PRO_CONTROLLER;
 
        return WIIMOTE_EXT_UNKNOWN;
 }
@@ -555,6 +557,7 @@ static const __u8 * const wiimote_devtype_mods[WIIMOTE_DEV_NUM] = {
                WIIMOD_NULL,
        },
        [WIIMOTE_DEV_UNKNOWN] = (const __u8[]){
+               WIIMOD_NO_MP,
                WIIMOD_NULL,
        },
        [WIIMOTE_DEV_GENERIC] = (const __u8[]){
@@ -591,11 +594,22 @@ static const __u8 * const wiimote_devtype_mods[WIIMOTE_DEV_NUM] = {
                WIIMOD_LED4,
                WIIMOD_ACCEL,
                WIIMOD_IR,
+               WIIMOD_BUILTIN_MP,
                WIIMOD_NULL,
        },
        [WIIMOTE_DEV_BALANCE_BOARD] = (const __u8[]) {
                WIIMOD_BATTERY,
                WIIMOD_LED1,
+               WIIMOD_NO_MP,
+               WIIMOD_NULL,
+       },
+       [WIIMOTE_DEV_PRO_CONTROLLER] = (const __u8[]) {
+               WIIMOD_BATTERY,
+               WIIMOD_LED1,
+               WIIMOD_LED2,
+               WIIMOD_LED3,
+               WIIMOD_LED4,
+               WIIMOD_NO_MP,
                WIIMOD_NULL,
        },
 };
@@ -782,6 +796,7 @@ static const char *wiimote_devtype_names[WIIMOTE_DEV_NUM] = {
        [WIIMOTE_DEV_GEN10] = "Nintendo Wii Remote (Gen 1)",
        [WIIMOTE_DEV_GEN20] = "Nintendo Wii Remote Plus (Gen 2)",
        [WIIMOTE_DEV_BALANCE_BOARD] = "Nintendo Wii Balance Board",
+       [WIIMOTE_DEV_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller",
 };
 
 /* Try to guess the device type based on all collected information. We
@@ -802,6 +817,9 @@ static void wiimote_init_set_type(struct wiimote_data *wdata,
        if (exttype == WIIMOTE_EXT_BALANCE_BOARD) {
                devtype = WIIMOTE_DEV_BALANCE_BOARD;
                goto done;
+       } else if (exttype == WIIMOTE_EXT_PRO_CONTROLLER) {
+               devtype = WIIMOTE_DEV_PRO_CONTROLLER;
+               goto done;
        }
 
        if (!strcmp(name, "Nintendo RVL-CNT-01")) {
@@ -813,6 +831,9 @@ static void wiimote_init_set_type(struct wiimote_data *wdata,
        } else if (!strcmp(name, "Nintendo RVL-WBC-01")) {
                devtype = WIIMOTE_DEV_BALANCE_BOARD;
                goto done;
+       } else if (!strcmp(name, "Nintendo RVL-CNT-01-UC")) {
+               devtype = WIIMOTE_DEV_PRO_CONTROLLER;
+               goto done;
        }
 
        if (vendor == USB_VENDOR_ID_NINTENDO) {
@@ -867,8 +888,13 @@ static void wiimote_init_detect(struct wiimote_data *wdata)
 out_release:
        wiimote_cmd_release(wdata);
        wiimote_init_set_type(wdata, exttype);
+
        /* schedule MP timer */
-       mod_timer(&wdata->timer, jiffies + HZ * 4);
+       spin_lock_irq(&wdata->state.lock);
+       if (!(wdata->state.flags & WIIPROTO_FLAG_BUILTIN_MP) &&
+           !(wdata->state.flags & WIIPROTO_FLAG_NO_MP))
+               mod_timer(&wdata->timer, jiffies + HZ * 4);
+       spin_unlock_irq(&wdata->state.lock);
 }
 
 /*
@@ -1037,7 +1063,8 @@ out_release:
        wiimote_cmd_release(wdata);
 
        /* only poll for MP if requested and if state didn't change */
-       if (ret && poll_mp)
+       if (ret && poll_mp && !(flags & WIIPROTO_FLAG_BUILTIN_MP) &&
+           !(flags & WIIPROTO_FLAG_NO_MP))
                wiimote_init_poll_mp(wdata);
 
        return ret;
@@ -1049,6 +1076,7 @@ static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = {
        [WIIMOTE_EXT_NUNCHUK] = "Nintendo Wii Nunchuk",
        [WIIMOTE_EXT_CLASSIC_CONTROLLER] = "Nintendo Wii Classic Controller",
        [WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board",
+       [WIIMOTE_EXT_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller",
 };
 
 /*
@@ -1082,8 +1110,12 @@ static void wiimote_init_hotplug(struct wiimote_data *wdata)
 
        /* init extension and MP (deactivates current extension or MP) */
        wiimote_cmd_init_ext(wdata);
-       wiimote_cmd_init_mp(wdata);
-       mp = wiimote_cmd_read_mp(wdata, mpdata);
+       if (flags & WIIPROTO_FLAG_NO_MP) {
+               mp = false;
+       } else {
+               wiimote_cmd_init_mp(wdata);
+               mp = wiimote_cmd_read_mp(wdata, mpdata);
+       }
        exttype = wiimote_cmd_read_ext(wdata, extdata);
 
        wiimote_cmd_release(wdata);
@@ -1133,7 +1165,9 @@ static void wiimote_init_hotplug(struct wiimote_data *wdata)
                del_timer_sync(&wdata->timer);
        } else {
                /* reschedule MP hotplug timer */
-               mod_timer(&wdata->timer, jiffies + HZ * 4);
+               if (!(flags & WIIPROTO_FLAG_BUILTIN_MP) &&
+                   !(flags & WIIPROTO_FLAG_NO_MP))
+                       mod_timer(&wdata->timer, jiffies + HZ * 4);
        }
 
        spin_lock_irq(&wdata->state.lock);
@@ -1173,7 +1207,7 @@ static void wiimote_init_worker(struct work_struct *work)
                changed = true;
        }
 
-       if (!wiimote_init_check(wdata))
+       if (changed || !wiimote_init_check(wdata))
                wiimote_init_hotplug(wdata);
 
        if (changed)
@@ -1261,11 +1295,19 @@ static bool valid_ext_handler(const struct wiimod_ops *ops, size_t len)
 static void handler_ext(struct wiimote_data *wdata, const __u8 *payload,
                        size_t len)
 {
+       static const __u8 invalid[21] = { 0xff, 0xff, 0xff, 0xff,
+                                         0xff, 0xff, 0xff, 0xff,
+                                         0xff, 0xff, 0xff, 0xff,
+                                         0xff, 0xff, 0xff, 0xff,
+                                         0xff, 0xff, 0xff, 0xff,
+                                         0xff };
        const __u8 *iter, *mods;
        const struct wiimod_ops *ops;
        bool is_mp;
 
-       if (len < 6)
+       if (len > 21)
+               len = 21;
+       if (len < 6 || !memcmp(payload, invalid, len))
                return;
 
        /* if MP is active, track MP slot hotplugging */
@@ -1619,6 +1661,8 @@ static ssize_t wiimote_ext_show(struct device *dev,
                return sprintf(buf, "classic\n");
        case WIIMOTE_EXT_BALANCE_BOARD:
                return sprintf(buf, "balanceboard\n");
+       case WIIMOTE_EXT_PRO_CONTROLLER:
+               return sprintf(buf, "procontroller\n");
        case WIIMOTE_EXT_UNKNOWN:
                /* fallthrough */
        default:
@@ -1665,6 +1709,8 @@ static ssize_t wiimote_dev_show(struct device *dev,
                return sprintf(buf, "gen20\n");
        case WIIMOTE_DEV_BALANCE_BOARD:
                return sprintf(buf, "balanceboard\n");
+       case WIIMOTE_DEV_PRO_CONTROLLER:
+               return sprintf(buf, "procontroller\n");
        case WIIMOTE_DEV_PENDING:
                return sprintf(buf, "pending\n");
        case WIIMOTE_DEV_UNKNOWN: