예제 #1
0
static int
set_up_bluetooth_radio(const HANDLE hRadio)
{
    /* NOTE: Order matters for the following two operations: The radio must
     *       allow incoming connections prior to being made discoverable.
     */

    if (!BluetoothIsConnectable(hRadio)) {
        WINPAIR_DEBUG("Making radio accept incoming connections");
        if (BluetoothEnableIncomingConnections(hRadio, TRUE) == FALSE) {
            WINPAIR_DEBUG("Failed to enable incoming connections");
            return 1;
        }
    }

    if (!BluetoothIsDiscoverable(hRadio)) {
        WINPAIR_DEBUG("Making radio discoverable");
        if (BluetoothEnableDiscovery(hRadio, TRUE) == FALSE) {
            WINPAIR_DEBUG("Failed to make radio discoverable");
            return 1;
        }
    }

    if ((BluetoothIsConnectable(hRadio) != FALSE) && (BluetoothIsDiscoverable(hRadio) != FALSE)) {
        return 0;
    } else {
        return 1;
    }
}
예제 #2
0
static int
is_connection_established(const HANDLE hRadio, BLUETOOTH_DEVICE_INFO *device_info)
{
    /* NOTE: Sometimes the Bluetooth connection appears to be established
     *       even though the Move decided that it is not really connected
     *       yet. That is why we cannot simply stop trying to connect after
     *       the first successful check. Instead, we require a minimum
     *       number of successive successful checks to be sure.
     */

    unsigned int i;
    for (i = 0; i < CONN_CHECK_NUM_TRIES; i++) {
        /* read device info again to check if we have a connection */
        DWORD result = BluetoothGetDeviceInfo(hRadio, device_info);
        if (result != ERROR_SUCCESS) {
            WINPAIR_DEBUG("Failed to read device info");
            return 0;
        }

        if (device_info->fConnected && device_info->fRemembered && is_hid_service_enabled(hRadio, device_info)) {
        } else {
            return 0;
        }

        Sleep(CONN_CHECK_DELAY);
    }

    return 1;
}
예제 #3
0
static int
is_hid_service_enabled(const HANDLE hRadio, BLUETOOTH_DEVICE_INFO *device_info)
{
    /* retrieve number of installed services */
    DWORD num_services = 0;
    DWORD result = BluetoothEnumerateInstalledServices(hRadio, device_info, &num_services, NULL);
    if (result != ERROR_SUCCESS) {
        /* NOTE: Sometimes we get ERROR_MORE_DATA, sometimes we do not.
         *       The number of services seems to be correct in any case, so
         *       we will just ignore this.
         */
        if (result != ERROR_MORE_DATA) {
            WINPAIR_DEBUG("Failed to count installed services");
            return 0;
        }
    }

    if (num_services == 0) {
        return 0;
    }

    /* retrieve actual list of installed services */
    GUID *service_list = (GUID *) calloc(num_services, sizeof(GUID));
    if (!service_list) {
        return 0;
    }
    result = BluetoothEnumerateInstalledServices(hRadio, device_info, &num_services, service_list);
    if (result != ERROR_SUCCESS) {
        WINPAIR_DEBUG("Failed to enumerate installed services");
        return 0;
    }

    /* check if the HID service is part of that list */
    unsigned int i;
    int found = 0;
    GUID service = HumanInterfaceDeviceServiceClass_UUID;
    for (i = 0; i < num_services; i++) {
        if (IsEqualGUID(&service_list[i], &service)) {
            found = 1;
            break;
        }
    }

    free(service_list);

    return found;
}
예제 #4
0
static int
patch_registry(const BLUETOOTH_ADDRESS *move_addr, const BLUETOOTH_ADDRESS *radio_addr)
{
    int ret = 0;

    TCHAR sub_key[1024];
    HRESULT res = StringCchPrintf(
        sub_key,
        1024,
        _T("SYSTEM\\CurrentControlSet\\Services\\HidBth\\Parameters\\Devices\\" \
           "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"),
        radio_addr->rgBytes[5], radio_addr->rgBytes[4], radio_addr->rgBytes[3],
        radio_addr->rgBytes[2], radio_addr->rgBytes[1], radio_addr->rgBytes[0],
        move_addr->rgBytes[5], move_addr->rgBytes[4], move_addr->rgBytes[3],
        move_addr->rgBytes[2], move_addr->rgBytes[1], move_addr->rgBytes[0] );

    if (FAILED(res)) {
        WINPAIR_DEBUG("Failed to build registry subkey");
        return 1;
    }

    /* open registry key for modifying a value */
    HKEY hKey;
    LONG result;
    result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sub_key, 0, KEY_SET_VALUE | KEY_WOW64_64KEY, &hKey);
    if (result != ERROR_SUCCESS) {
        if (result == ERROR_FILE_NOT_FOUND) {
            WINPAIR_DEBUG("Failed to open registry key, it does not yet exist");
        } else {
            WINPAIR_DEBUG("Failed to open registry key");
        }

        return 1;
    }

    DWORD data = 1;
    result = RegSetValueEx(hKey, _T("VirtuallyCabled"), 0, REG_DWORD, (const BYTE *) &data, sizeof(data));
    if (result != ERROR_SUCCESS) {
        WINPAIR_DEBUG("Failed to set 'VirtuallyCabled'");
        ret = 1;
    }

    RegCloseKey(hKey);

    return ret;
}
예제 #5
0
static int
get_bluetooth_device_info(const HANDLE hRadio, const BLUETOOTH_ADDRESS *addr, BLUETOOTH_DEVICE_INFO *device_info)
{
    if (!addr || !device_info) {
        return 1;
    }

    BLUETOOTH_DEVICE_SEARCH_PARAMS search_params;
    search_params.dwSize               = sizeof(search_params);
    search_params.cTimeoutMultiplier   = 4;
    search_params.fIssueInquiry        = FALSE;
    search_params.fReturnAuthenticated = TRUE;
    search_params.fReturnConnected     = TRUE;
    search_params.fReturnRemembered    = TRUE;
    search_params.fReturnUnknown       = TRUE;
    search_params.hRadio               = hRadio;

    device_info->dwSize = sizeof(*device_info);

    HBLUETOOTH_DEVICE_FIND hFind = BluetoothFindFirstDevice(&search_params, device_info);

    if (!hFind) {
        if (GetLastError() != ERROR_NO_MORE_ITEMS) {
            WINPAIR_DEBUG("Failed to enumerate devices");
            return 1;
        }
    } else {
        do {
            /* check if the device's Bluetooth address matches the one we are looking for */
            if (device_info->Address.ullLong == addr->ullLong) {
                break;
            }
        } while(BluetoothFindNextDevice(hFind, device_info));

        if (!BluetoothFindDeviceClose(hFind)) {
            WINPAIR_DEBUG("Failed to close device enumeration handle");
            return 1;
        }
    }

    return 0;
}
예제 #6
0
static int
update_device_info(const HANDLE hRadio, BLUETOOTH_DEVICE_INFO *device_info)
{
    DWORD result = BluetoothGetDeviceInfo(hRadio, device_info);
    if (result != ERROR_SUCCESS) {
        WINPAIR_DEBUG("Failed to read device info");
        return 1;
    }

    return 0;
}
예제 #7
0
static int
windows_register_psmove(const char *move_addr_str, const BLUETOOTH_ADDRESS *radio_addr, const HANDLE hRadio)
{
    /* parse controller's Bluetooth device address string */
    BLUETOOTH_ADDRESS *move_addr = string_to_btaddr(move_addr_str);
    if (!move_addr) {
        WINPAIR_DEBUG("Cannot parse controller address: '%s'", move_addr_str);
        return 1;
    }

    if (!radio_addr) {
        WINPAIR_DEBUG("Invalid Bluetooth device address for radio");
        return 1;
    }

    if (set_up_bluetooth_radio(hRadio) != 0) {
        WINPAIR_DEBUG("Failed to configure Bluetooth radio for use");
        return 1;
    }

    printf("\n" \
           "    Unplug the controller.\n" \
           "\n"
           "    Now press the controller's PS button. The red status LED\n" \
           "    will start blinking. Whenever it goes off, press the\n" \
           "    PS button again. Repeat this until the status LED finally\n" \
           "    remains lit. Press Ctrl+C to cancel anytime.\n");

    if (is_windows8_or_later()) {
        WINPAIR_DEBUG("Dealing with Windows 8 or later");
        handle_windows8_and_later(move_addr, radio_addr, hRadio);
    } else {
        WINPAIR_DEBUG("Dealing with Windows version older than 8");
        handle_windows_pre8(move_addr, radio_addr, hRadio);
    }

    free(move_addr);

    return 0;
}
예제 #8
0
int
windows_get_first_bluetooth_radio(HANDLE *hRadio)
{
    if (!hRadio) {
        return 1;
    }

    BLUETOOTH_FIND_RADIO_PARAMS radio_params;
    radio_params.dwSize = sizeof(BLUETOOTH_FIND_RADIO_PARAMS);

    HBLUETOOTH_RADIO_FIND hFind = BluetoothFindFirstRadio(&radio_params, hRadio);

    if (!hFind) {
        WINPAIR_DEBUG("Failed to enumerate Bluetooth radios");
        return 1;
    }

    BluetoothFindRadioClose(hFind);

    return 0;
}
예제 #9
0
static void
handle_windows_pre8(const BLUETOOTH_ADDRESS *move_addr, const BLUETOOTH_ADDRESS *radio_addr, const HANDLE hRadio)
{
    int connected = 0;
    while (!connected) {
        BLUETOOTH_DEVICE_INFO device_info;
        if (get_bluetooth_device_info(hRadio, move_addr, &device_info, 0) != 0) {
            WINPAIR_DEBUG("No Bluetooth device found matching the given address");
        } else {
            if (is_move_motion_controller(&device_info)) {
                WINPAIR_DEBUG("Found Move Motion Controller matching the given address");

                if (device_info.fConnected) {
                    /* enable HID service only if necessary */
                    WINPAIR_DEBUG("Checking HID service ...");
                    if (!is_hid_service_enabled(hRadio, &device_info)) {
                        WINPAIR_DEBUG("Enabling HID service ...");
                        GUID service = HumanInterfaceDeviceServiceClass_UUID;
                        DWORD result = BluetoothSetServiceState(hRadio, &device_info, &service, BLUETOOTH_SERVICE_ENABLE);
                        if (result != ERROR_SUCCESS) {
                            WINPAIR_DEBUG("Failed to enable HID service");
                        }
                    }

                    WINPAIR_DEBUG("Verifying successful connection ...");
                    if (is_connection_established(hRadio, &device_info)) {
                        /* if we have a connection, stop trying to connect this device */
                        printf("Connection verified.\n");
                        connected = 1;
                        break;
                    }
                }
            } else {
                WINPAIR_DEBUG("Bluetooth device matching the given address is not a Move Motion Controller");
            }
        }

        Sleep(SLEEP_BETWEEN_SCANS);
    }
}
예제 #10
0
int
windows_register_psmove(const char *move_addr_str, const HANDLE hRadio)
{
    /* parse controller's Bluetooth device address string */
    BLUETOOTH_ADDRESS *move_addr = string_to_btaddr(move_addr_str);
    if (!move_addr) {
        WINPAIR_DEBUG("Cannot parse controller address: '%s'", move_addr_str);
        return 1;
    }

    if (set_up_bluetooth_radio(hRadio) != 0) {
        WINPAIR_DEBUG("Failed to configure Bluetooth radio for use");
        return 1;
    }

    /* Keep track of the number of times the loop iterates so we may timeout. */
    int timeout_duration = 30;  // seconds
    int sleep_interval = 1000; // msec
    int timeout_iterations = timeout_duration * 1000 / sleep_interval;
    int loop_count = 0;
    
    printf("\n" \
           "    Unplug the controller.\n" \
           "\n"
           "    Now press the controller's PS button. The red status LED\n" \
           "    will start blinking. Whenever it goes off, press the\n" \
           "    PS button again. Repeat this until the status LED finally\n" \
           "    remains lit. Press Ctrl+C to cancel anytime.\n");

    for(;;) {
        BLUETOOTH_DEVICE_INFO device_info;
        if (get_bluetooth_device_info(hRadio, move_addr, &device_info) != 0) {
            WINPAIR_DEBUG("No Bluetooth device found matching the given address");
        } else {
            if (is_move_motion_controller(&device_info)) {
                WINPAIR_DEBUG("Found Move Motion Controller matching the given address");

                if (device_info.fConnected) {
                    /* enable HID service only if necessary */
                    WINPAIR_DEBUG("Checking HID service ...");
                    if (!is_hid_service_enabled(hRadio, &device_info)) {
                        WINPAIR_DEBUG("Enabling HID service ...");
                        GUID service = HumanInterfaceDeviceServiceClass_UUID;
                        DWORD result = BluetoothSetServiceState(hRadio, &device_info, &service, BLUETOOTH_SERVICE_ENABLE);
                        if (result != ERROR_SUCCESS) {
                            WINPAIR_DEBUG("Failed to enable HID service");
                        }
                    }

                    WINPAIR_DEBUG("Verifying successful connection ...");
                    if (is_connection_established(hRadio, &device_info)) {
                        /* if we have a connection, stop trying to connect this device */
                        printf("Connection verified.\n");
                        break;
                    }
                }
            } else {
                WINPAIR_DEBUG("Bluetooth device matching the given address is not a Move Motion Controller");
            }
        }
        if (loop_count >= timeout_iterations) {
            printf("\n"
                   "    A connection could not be established. This is not\n"
                   "    unusual in Windows. Please refer to the README document\n"
                   "    for your platform for more information. Press Ctrl+C to cancel.");
        }

        /* sleep for 1 second */
        Sleep(1000);
        loop_count++;
    }

    free(move_addr);

    return 0;
}
예제 #11
0
static void
handle_windows8_and_later(const BLUETOOTH_ADDRESS *move_addr, const BLUETOOTH_ADDRESS *radio_addr, const HANDLE hRadio)
{
    unsigned int scan = 0;
    int connected = 0;
    while (!connected) {
        BLUETOOTH_DEVICE_INFO device_info;
        if (get_bluetooth_device_info(hRadio, move_addr, &device_info, scan == 0) != 0) {
            WINPAIR_DEBUG("No Bluetooth device found matching the given address");
        } else {
            if (is_move_motion_controller(&device_info)) {
                WINPAIR_DEBUG("Found Move Motion Controller matching the given address");

                unsigned int conn_try;
                for (conn_try = 1; conn_try <= CONN_RETRIES; conn_try++) {
                    WINPAIR_DEBUG("Connection try %d/%d", conn_try, CONN_RETRIES);

                    if (update_device_info(hRadio, &device_info) != 0) {
                        break;
                    }

                    if (device_info.fConnected) {
                        /* Windows 8 (and later) seems to require manual help with setting up
                         * the device in the registry.
                         */
                        WINPAIR_DEBUG("Patching the registry ...");
                        if (patch_registry(move_addr, radio_addr) != 0) {
                            WINPAIR_DEBUG("Failed to patch the registry");
                        }

                        /* enable HID service only if necessary */
                        WINPAIR_DEBUG("Checking HID service ...");
                        if (!is_hid_service_enabled(hRadio, &device_info)) {
                            WINPAIR_DEBUG("Enabling HID service ...");
                            GUID service = HumanInterfaceDeviceServiceClass_UUID;
                            DWORD result = BluetoothSetServiceState(hRadio, &device_info, &service, BLUETOOTH_SERVICE_ENABLE);
                            if (result != ERROR_SUCCESS) {
                                WINPAIR_DEBUG("Failed to enable HID service");
                            }

                            WINPAIR_DEBUG("Patching the registry ...");
                            if (patch_registry(move_addr, radio_addr) != 0) {
                                WINPAIR_DEBUG("Failed to patch the registry");
                            }
                        }

                        WINPAIR_DEBUG("Verifying successful connection ...");
                        if (is_connection_established(hRadio, &device_info)) {
                            /* if we have a connection, stop trying to connect this device */
                            printf("Connection verified.\n");
                            connected = 1;
                            break;
                        }
                    }

                    Sleep(CONN_DELAY);
                }

                if(!device_info.fConnected) {
                    BluetoothRemoveDevice(&(device_info.Address));
                    WINPAIR_DEBUG("Device removed, starting all over again");
                }
            } else {
                WINPAIR_DEBUG("Bluetooth device matching the given address is not a Move Motion Controller");
            }
        }

        Sleep(SLEEP_BETWEEN_SCANS);
        scan = (scan + 1) % BT_SCAN_NEW_INQUIRY;
    }
}