What:          /sys/bus/hid/drivers/wiimote/<dev>/extension
 Date:          August 2011
 KernelVersion: 3.2
-Contact:       David Herrmann <dh.herrmann@googlemail.com>
+Contact:       David Herrmann <dh.herrmann@gmail.com>
 Description:   This file contains the currently connected and initialized
                extensions. It can be one of: none, motionp, nunchuck, classic,
                motionp+nunchuck, motionp+classic
                the official Nintendo Nunchuck extension and classic is the
                Nintendo Classic Controller extension. The motionp extension can
                be combined with the other two.
+               Starting with kernel-version 3.11 Motion Plus hotplugging is
+               supported and if detected, it's no longer reported as static
+               extension. You will get uevent notifications for the motion-plus
+               device then.
+
+What:          /sys/bus/hid/drivers/wiimote/<dev>/devtype
+Date:          May 2013
+KernelVersion: 3.11
+Contact:       David Herrmann <dh.herrmann@gmail.com>
+Description:   While a device is initialized by the wiimote driver, we perform
+               a device detection and signal a "change" uevent after it is
+               done. This file shows the detected device type. "pending" means
+               that the detection is still ongoing, "unknown" means, that the
+               device couldn't be detected or loaded. "generic" means, that the
+               device couldn't be detected but supports basic Wii Remote
+               features and can be used.
+               Other strings for each device-type are available and may be
+               added if new device-specific detections are added.
+               Currently supported are:
+                       gen10: First Wii Remote generation
+                       gen20: Second Wii Remote Plus generation (builtin MP)
+                       balanceboard: Wii Balance Board
 
 {
        struct wiimote_data *wdata = container_of(work, struct wiimote_data,
                                                  init_worker);
+       bool changed = false;
 
-       if (wdata->state.devtype == WIIMOTE_DEV_PENDING)
+       if (wdata->state.devtype == WIIMOTE_DEV_PENDING) {
                wiimote_init_detect(wdata);
+               changed = true;
+       }
+
        if (!wiimote_init_check(wdata))
                wiimote_init_hotplug(wdata);
+
+       if (changed)
+               kobject_uevent(&wdata->hdev->dev.kobj, KOBJ_CHANGE);
 }
 
 void __wiimote_schedule(struct wiimote_data *wdata)
        return 0;
 }
 
+static ssize_t wiimote_ext_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct wiimote_data *wdata = dev_to_wii(dev);
+       __u8 type;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       type = wdata->state.exttype;
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+       switch (type) {
+       case WIIMOTE_EXT_NONE:
+               return sprintf(buf, "none\n");
+       case WIIMOTE_EXT_NUNCHUK:
+               return sprintf(buf, "nunchuk\n");
+       case WIIMOTE_EXT_CLASSIC_CONTROLLER:
+               return sprintf(buf, "classic\n");
+       case WIIMOTE_EXT_BALANCE_BOARD:
+               return sprintf(buf, "balanceboard\n");
+       case WIIMOTE_EXT_UNKNOWN:
+               /* fallthrough */
+       default:
+               return sprintf(buf, "unknown\n");
+       }
+}
+
+static ssize_t wiimote_ext_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct wiimote_data *wdata = dev_to_wii(dev);
+
+       if (!strcmp(buf, "scan")) {
+               wiimote_schedule(wdata);
+       } else {
+               return -EINVAL;
+       }
+
+       return strnlen(buf, PAGE_SIZE);
+}
+
+static DEVICE_ATTR(extension, S_IRUGO | S_IWUSR | S_IWGRP, wiimote_ext_show,
+                  wiimote_ext_store);
+
+static ssize_t wiimote_dev_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct wiimote_data *wdata = dev_to_wii(dev);
+       __u8 type;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       type = wdata->state.devtype;
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+       switch (type) {
+       case WIIMOTE_DEV_GENERIC:
+               return sprintf(buf, "generic\n");
+       case WIIMOTE_DEV_GEN10:
+               return sprintf(buf, "gen10\n");
+       case WIIMOTE_DEV_GEN20:
+               return sprintf(buf, "gen20\n");
+       case WIIMOTE_DEV_BALANCE_BOARD:
+               return sprintf(buf, "balanceboard\n");
+       case WIIMOTE_DEV_PENDING:
+               return sprintf(buf, "pending\n");
+       case WIIMOTE_DEV_UNKNOWN:
+               /* fallthrough */
+       default:
+               return sprintf(buf, "unknown\n");
+       }
+}
+
+static DEVICE_ATTR(devtype, S_IRUGO, wiimote_dev_show, NULL);
+
 static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 {
        struct wiimote_data *wdata;
        cancel_work_sync(&wdata->init_worker);
        del_timer_sync(&wdata->timer);
 
+       device_remove_file(&wdata->hdev->dev, &dev_attr_devtype);
+       device_remove_file(&wdata->hdev->dev, &dev_attr_extension);
+
        wiimote_mp_unload(wdata);
        wiimote_ext_unload(wdata);
        wiimote_modules_unload(wdata);
                goto err_stop;
        }
 
+       ret = device_create_file(&hdev->dev, &dev_attr_extension);
+       if (ret) {
+               hid_err(hdev, "cannot create sysfs attribute\n");
+               goto err_close;
+       }
+
+       ret = device_create_file(&hdev->dev, &dev_attr_devtype);
+       if (ret) {
+               hid_err(hdev, "cannot create sysfs attribute\n");
+               goto err_ext;
+       }
+
        ret = wiidebug_init(wdata);
        if (ret)
                goto err_free;
        wiimote_destroy(wdata);
        return ret;
 
+err_ext:
+       device_remove_file(&wdata->hdev->dev, &dev_attr_extension);
+err_close:
+       hid_hw_close(hdev);
 err_stop:
        hid_hw_stop(hdev);
 err: