]> Pileus Git - ~andy/linux/blobdiff - drivers/hid/hid-wiimote-core.c
HID: hyperv: Properly disconnect the input device
[~andy/linux] / drivers / hid / hid-wiimote-core.c
index c955d500c81fa17141c2cc30d9440065465b747b..61881b35c6702fa976b6e289cefb74ebbbe0ec4b 100644 (file)
@@ -22,8 +22,6 @@
 #include "hid-ids.h"
 #include "hid-wiimote.h"
 
-#define WIIMOTE_VERSION "0.2"
-
 enum wiiproto_keys {
        WIIPROTO_KEY_LEFT,
        WIIPROTO_KEY_RIGHT,
@@ -201,6 +199,7 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
 static __u8 select_drm(struct wiimote_data *wdata)
 {
        __u8 ir = wdata->state.flags & WIIPROTO_FLAGS_IR;
+       bool ext = wiiext_active(wdata);
 
        if (ir == WIIPROTO_FLAG_IR_BASIC) {
                if (wdata->state.flags & WIIPROTO_FLAG_ACCEL)
@@ -212,10 +211,17 @@ static __u8 select_drm(struct wiimote_data *wdata)
        } else if (ir == WIIPROTO_FLAG_IR_FULL) {
                return WIIPROTO_REQ_DRM_SKAI1;
        } else {
-               if (wdata->state.flags & WIIPROTO_FLAG_ACCEL)
-                       return WIIPROTO_REQ_DRM_KA;
-               else
-                       return WIIPROTO_REQ_DRM_K;
+               if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) {
+                       if (ext)
+                               return WIIPROTO_REQ_DRM_KAE;
+                       else
+                               return WIIPROTO_REQ_DRM_KA;
+               } else {
+                       if (ext)
+                               return WIIPROTO_REQ_DRM_KE;
+                       else
+                               return WIIPROTO_REQ_DRM_K;
+               }
        }
 }
 
@@ -230,6 +236,7 @@ void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
        cmd[1] = 0;
        cmd[2] = drm;
 
+       wdata->state.drm = drm;
        wiiproto_keep_rumble(wdata, &cmd[1]);
        wiimote_queue(wdata, cmd, sizeof(cmd));
 }
@@ -312,6 +319,31 @@ static void wiiproto_req_wmem(struct wiimote_data *wdata, bool eeprom,
        wiimote_queue(wdata, cmd, sizeof(cmd));
 }
 
+void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom, __u32 offset,
+                                                               __u16 size)
+{
+       __u8 cmd[7];
+
+       if (size == 0) {
+               hid_warn(wdata->hdev, "Invalid length %d rmem request\n", size);
+               return;
+       }
+
+       cmd[0] = WIIPROTO_REQ_RMEM;
+       cmd[1] = 0;
+       cmd[2] = (offset >> 16) & 0xff;
+       cmd[3] = (offset >> 8) & 0xff;
+       cmd[4] = offset & 0xff;
+       cmd[5] = (size >> 8) & 0xff;
+       cmd[6] = size & 0xff;
+
+       if (!eeprom)
+               cmd[1] |= 0x04;
+
+       wiiproto_keep_rumble(wdata, &cmd[1]);
+       wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
 /* requries the cmd-mutex to be held */
 int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
                                                const __u8 *wmem, __u8 size)
@@ -331,6 +363,36 @@ int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
        return ret;
 }
 
+/* requries the cmd-mutex to be held */
+ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset, __u8 *rmem,
+                                                               __u8 size)
+{
+       unsigned long flags;
+       ssize_t ret;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       wdata->state.cmd_read_size = size;
+       wdata->state.cmd_read_buf = rmem;
+       wiimote_cmd_set(wdata, WIIPROTO_REQ_RMEM, offset & 0xffff);
+       wiiproto_req_rreg(wdata, offset, size);
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+       ret = wiimote_cmd_wait(wdata);
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       wdata->state.cmd_read_buf = NULL;
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+       if (!ret) {
+               if (wdata->state.cmd_read_size == 0)
+                       ret = -EIO;
+               else
+                       ret = wdata->state.cmd_read_size;
+       }
+
+       return ret;
+}
+
 static int wiimote_battery_get_property(struct power_supply *psy,
                                                enum power_supply_property psp,
                                                union power_supply_propval *val)
@@ -734,6 +796,8 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
        /* on status reports the drm is reset so we need to resend the drm */
        wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
 
+       wiiext_event(wdata, payload[2] & 0x02);
+
        if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_SREQ, 0)) {
                wdata->state.cmd_battery = payload[5];
                wiimote_cmd_complete(wdata);
@@ -742,7 +806,23 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
 
 static void handler_data(struct wiimote_data *wdata, const __u8 *payload)
 {
+       __u16 offset = payload[3] << 8 | payload[4];
+       __u8 size = (payload[2] >> 4) + 1;
+       __u8 err = payload[2] & 0x0f;
+
        handler_keys(wdata, payload);
+
+       if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_RMEM, offset)) {
+               if (err)
+                       size = 0;
+               else if (size > wdata->state.cmd_read_size)
+                       size = wdata->state.cmd_read_size;
+
+               wdata->state.cmd_read_size = size;
+               if (wdata->state.cmd_read_buf)
+                       memcpy(wdata->state.cmd_read_buf, &payload[5], size);
+               wiimote_cmd_complete(wdata);
+       }
 }
 
 static void handler_return(struct wiimote_data *wdata, const __u8 *payload)
@@ -770,6 +850,7 @@ static void handler_drm_KA(struct wiimote_data *wdata, const __u8 *payload)
 static void handler_drm_KE(struct wiimote_data *wdata, const __u8 *payload)
 {
        handler_keys(wdata, payload);
+       wiiext_handle(wdata, &payload[2]);
 }
 
 static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload)
@@ -786,6 +867,7 @@ static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload)
 static void handler_drm_KEE(struct wiimote_data *wdata, const __u8 *payload)
 {
        handler_keys(wdata, payload);
+       wiiext_handle(wdata, &payload[2]);
 }
 
 static void handler_drm_KIE(struct wiimote_data *wdata, const __u8 *payload)
@@ -796,12 +878,14 @@ static void handler_drm_KIE(struct wiimote_data *wdata, const __u8 *payload)
        ir_to_input2(wdata, &payload[7], false);
        ir_to_input3(wdata, &payload[9], true);
        input_sync(wdata->ir);
+       wiiext_handle(wdata, &payload[12]);
 }
 
 static void handler_drm_KAE(struct wiimote_data *wdata, const __u8 *payload)
 {
        handler_keys(wdata, payload);
        handler_accel(wdata, payload);
+       wiiext_handle(wdata, &payload[5]);
 }
 
 static void handler_drm_KAIE(struct wiimote_data *wdata, const __u8 *payload)
@@ -813,10 +897,12 @@ static void handler_drm_KAIE(struct wiimote_data *wdata, const __u8 *payload)
        ir_to_input2(wdata, &payload[10], false);
        ir_to_input3(wdata, &payload[12], true);
        input_sync(wdata->ir);
+       wiiext_handle(wdata, &payload[15]);
 }
 
 static void handler_drm_E(struct wiimote_data *wdata, const __u8 *payload)
 {
+       wiiext_handle(wdata, payload);
 }
 
 static void handler_drm_SKAI1(struct wiimote_data *wdata, const __u8 *payload)
@@ -1054,6 +1140,7 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
        spin_lock_init(&wdata->state.lock);
        init_completion(&wdata->state.ready);
        mutex_init(&wdata->state.sync);
+       wdata->state.drm = WIIPROTO_REQ_DRM_K;
 
        return wdata;
 
@@ -1068,6 +1155,8 @@ err:
 
 static void wiimote_destroy(struct wiimote_data *wdata)
 {
+       wiidebug_deinit(wdata);
+       wiiext_deinit(wdata);
        wiimote_leds_destroy(wdata);
 
        power_supply_unregister(&wdata->battery);
@@ -1086,6 +1175,8 @@ static int wiimote_hid_probe(struct hid_device *hdev,
        struct wiimote_data *wdata;
        int ret;
 
+       hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
+
        wdata = wiimote_create(hdev);
        if (!wdata) {
                hid_err(hdev, "Can't alloc device\n");
@@ -1139,6 +1230,14 @@ static int wiimote_hid_probe(struct hid_device *hdev,
        if (ret)
                goto err_free;
 
+       ret = wiiext_init(wdata);
+       if (ret)
+               goto err_free;
+
+       ret = wiidebug_init(wdata);
+       if (ret)
+               goto err_free;
+
        hid_info(hdev, "New device registered\n");
 
        /* by default set led1 after device initialization */
@@ -1215,4 +1314,3 @@ module_exit(wiimote_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
 MODULE_DESCRIPTION(WIIMOTE_NAME " Device Driver");
-MODULE_VERSION(WIIMOTE_VERSION);