From 87043879f88173f7a3b7f1ab4be44012a833fb1a Mon Sep 17 00:00:00 2001 From: Glenn Rice Date: Fri, 30 Jul 2010 18:55:36 +0000 Subject: [PATCH] Fix a hang in linux with the wiimote new plugin caused by a critical section not being exited. Also removed the original wiiuse_find function and replaced it with my wiiuse_find_more function with a little tweak to speed up wiimote discovery. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6007 8ced0084-cf51-0410-be5f-012b33b47a6e --- Externals/WiiUse/Src/io_nix.c | 353 +++++++----------- Externals/WiiUse/Src/wiiuse.h | 5 - .../Src/WiimoteReal/WiimoteReal.cpp | 6 +- 3 files changed, 138 insertions(+), 226 deletions(-) diff --git a/Externals/WiiUse/Src/io_nix.c b/Externals/WiiUse/Src/io_nix.c index 9302cc077d..863b1b4421 100644 --- a/Externals/WiiUse/Src/io_nix.c +++ b/Externals/WiiUse/Src/io_nix.c @@ -22,17 +22,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * $Header$ - * */ -/** - * @file - * @brief Handles device I/O for *nix. - */ - -#ifndef WIN32 - #include #include @@ -48,190 +39,121 @@ #include #include -#include "definitions.h" #include "wiiuse_internal.h" - + static int wiiuse_connect_single(struct wiimote_t* wm, char* address); -/** - * @brief Find a wiimote or wiimotes. - * - * @param wm An array of wiimote_t structures. - * @param max_wiimotes The number of wiimote structures in \a wm. - * @param timeout The number of seconds before the search times out. - * - * @return The number of wiimotes found. - * - * @see wiimote_connect() - * - * This function will only look for wiimote devices. \n - * When a device is found the address in the structures will be set. \n - * You can then call wiimote_connect() to connect to the found \n - * devices. - */ -int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout) { +// Find a wiimote or wiimotes. +// Does not replace already found wiimotes even if they are disconnected. +// wm An array of wiimote_t structures. +// max_wiimotes The number of wiimote structures in wm. +// timeout The number of seconds before the search times out. +// Returns the total number of found wiimotes. +// This function will only look for wiimote devices. +// When a device is found the address in the structures will be set. +// You can then call wiimote_connect() to connect to the found devices. +int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout) +{ int device_id; int device_sock; int found_devices; - int found_wiimotes; + int found_wiimotes = 0; + int i; - /* reset all wiimote bluetooth device addresses */ - for (found_wiimotes = 0; found_wiimotes < max_wiimotes; ++found_wiimotes) - wm[found_wiimotes]->bdaddr = *BDADDR_ANY; - found_wiimotes = 0; + // Count the number of already found wiimotes + for (i = 0; i < max_wiimotes; ++i) + { + if (WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_DEV_FOUND)) + found_wiimotes++; + } - /* get the id of the first bluetooth device. */ + // get the id of the first bluetooth device. device_id = hci_get_route(NULL); - if (device_id < 0) { + if (device_id < 0) + { perror("hci_get_route"); return 0; } - /* create a socket to the device */ + // create a socket to the device device_sock = hci_open_dev(device_id); - if (device_sock < 0) { + if (device_sock < 0) + { perror("hci_open_dev"); return 0; } - inquiry_info scan_info_arr[128]; - inquiry_info* scan_info = scan_info_arr; - memset(&scan_info_arr, 0, sizeof(scan_info_arr)); + int try_num = 0; + while ((try_num < timeout) && (found_wiimotes < max_wiimotes)) + { + inquiry_info scan_info_arr[128]; + inquiry_info* scan_info = scan_info_arr; + memset(&scan_info_arr, 0, sizeof(scan_info_arr)); - /* scan for bluetooth devices for 'timeout' seconds */ - found_devices = hci_inquiry(device_id, timeout, 128, NULL, &scan_info, IREQ_CACHE_FLUSH); - if (found_devices < 0) { - perror("hci_inquiry"); - return 0; - } - - WIIUSE_INFO("Found %i bluetooth device(s).", found_devices); - - int i = 0; - - /* display discovered devices */ - for (; (i < found_devices) && (found_wiimotes < max_wiimotes); ++i) { - if ((scan_info[i].dev_class[0] == WM_DEV_CLASS_0) && - (scan_info[i].dev_class[1] == WM_DEV_CLASS_1) && - (scan_info[i].dev_class[2] == WM_DEV_CLASS_2)) + // scan for bluetooth devices for ~one second + found_devices = hci_inquiry(device_id, 1, 128, NULL, &scan_info, IREQ_CACHE_FLUSH); + if (found_devices < 0) { - /* found a device */ - ba2str(&scan_info[i].bdaddr, wm[found_wiimotes]->bdaddr_str); - - WIIUSE_INFO("Found wiimote (%s) [id %i].", wm[found_wiimotes]->bdaddr_str, wm[found_wiimotes]->unid); - - wm[found_wiimotes]->bdaddr = scan_info[i].bdaddr; - WIIMOTE_ENABLE_STATE(wm[found_wiimotes], WIIMOTE_STATE_DEV_FOUND); - ++found_wiimotes; + perror("hci_inquiry"); + return 0; } + + WIIUSE_INFO("Found %i bluetooth device(s).", found_devices); + + // display discovered devices + for (i = 0; (i < found_devices) && (found_wiimotes < max_wiimotes); ++i) + { + if ((scan_info[i].dev_class[0] == WM_DEV_CLASS_0) && + (scan_info[i].dev_class[1] == WM_DEV_CLASS_1) && + (scan_info[i].dev_class[2] == WM_DEV_CLASS_2)) + { + int new_wiimote = 1; + int j; + // Determine if this wiimote has already been found. + for (j = 0; j < found_wiimotes && new_wiimote; ++j) + { + if (WIIMOTE_IS_SET(wm[j], WIIMOTE_STATE_DEV_FOUND) && + bacmp(&scan_info[i].bdaddr,&wm[j]->bdaddr) == 0) + new_wiimote = 0; + } + + if (new_wiimote) + { + // found a new device + ba2str(&scan_info[i].bdaddr, wm[found_wiimotes]->bdaddr_str); + + WIIUSE_INFO("Found wiimote (%s) [id %i].", + wm[found_wiimotes]->bdaddr_str, wm[found_wiimotes]->unid); + + wm[found_wiimotes]->bdaddr = scan_info[i].bdaddr; + WIIMOTE_ENABLE_STATE(wm[found_wiimotes], WIIMOTE_STATE_DEV_FOUND); + ++found_wiimotes; + } + } + } + try_num++; } close(device_sock); return found_wiimotes; } -// Scan for more wiimotes and add them to the wm structure. -// Does not replace already found wiimotes even if they are disconnected. -// Returns the total number of found wiimotes. -// It would probably be safe to replace wiiuse_find with this function. The only thing -// it does that this does not is reset the bdaddr fields. -int wiiuse_find_more(struct wiimote_t** wm, int max_wiimotes, int timeout) { -int device_id; -int device_sock; -int found_devices; -int found_wiimotes = 0; -int i; - -// Count the number of already found wiimotes -for (i = 0; i < max_wiimotes; ++i) { - if (WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_DEV_FOUND)) - found_wiimotes++; -} - -// get the id of the first bluetooth device. -device_id = hci_get_route(NULL); -if (device_id < 0) { - perror("hci_get_route"); - return 0; -} - -// create a socket to the device -device_sock = hci_open_dev(device_id); -if (device_sock < 0) { - perror("hci_open_dev"); - return 0; -} - -inquiry_info scan_info_arr[128]; -inquiry_info* scan_info = scan_info_arr; -memset(&scan_info_arr, 0, sizeof(scan_info_arr)); - -// scan for bluetooth devices for timeout seconds -found_devices = hci_inquiry(device_id, timeout, 128, NULL, &scan_info, IREQ_CACHE_FLUSH); -if (found_devices < 0) { - perror("hci_inquiry"); - return 0; -} - -WIIUSE_INFO("Found %i bluetooth device(s).", found_devices); - -// display discovered devices -for (i = 0; (i < found_devices) && (found_wiimotes < max_wiimotes); ++i) { - if ((scan_info[i].dev_class[0] == WM_DEV_CLASS_0) && - (scan_info[i].dev_class[1] == WM_DEV_CLASS_1) && - (scan_info[i].dev_class[2] == WM_DEV_CLASS_2)) - { - int new_wiimote = 1; - int j; - // Determine if this wiimote has already been found. - for (j = 0; j < found_wiimotes && new_wiimote; ++j) - { - if (WIIMOTE_IS_SET(wm[j], WIIMOTE_STATE_DEV_FOUND) && - bacmp(&scan_info[i].bdaddr,&wm[j]->bdaddr) == 0) - new_wiimote = 0; - } - - if (new_wiimote) - { - // found a new device - ba2str(&scan_info[i].bdaddr, wm[found_wiimotes]->bdaddr_str); - - WIIUSE_INFO("Found wiimote (%s) [id %i].", wm[found_wiimotes]->bdaddr_str, wm[found_wiimotes]->unid); - - wm[found_wiimotes]->bdaddr = scan_info[i].bdaddr; - WIIMOTE_ENABLE_STATE(wm[found_wiimotes], WIIMOTE_STATE_DEV_FOUND); - ++found_wiimotes; - } - } -} - -close(device_sock); -return found_wiimotes; -} - -/** - * @brief Connect to a wiimote or wiimotes once an address is known. - * - * @param wm An array of wiimote_t structures. - * @param wiimotes The number of wiimote structures in \a wm. - * - * @return The number of wiimotes that successfully connected. - * - * @see wiiuse_find() - * @see wiiuse_connect_single() - * @see wiiuse_disconnect() - * - * Connect to a number of wiimotes when the address is already set - * in the wiimote_t structures. These addresses are normally set - * by the wiiuse_find() function, but can also be set manually. - */ -int wiiuse_connect(struct wiimote_t** wm, int wiimotes) { +// Connect to a wiimote or wiimotes once an address is known. +// wm An array of wiimote_t structures. +// wiimotes The number of wiimote structures in wm. +// Return the number of wiimotes that successfully connected. +// Connect to a number of wiimotes when the address is already set +// in the wiimote_t structures. These addresses are normally set +// by the wiiuse_find() function, but can also be set manually. +int wiiuse_connect(struct wiimote_t** wm, int wiimotes) +{ int connected = 0; int i = 0; - for (; i < wiimotes; ++i) { + for (; i < wiimotes; ++i) + { if (!WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_DEV_FOUND)) - /* if the device address is not set, skip it */ + // if the device address is not set, skip it continue; if (wiiuse_connect_single(wm[i], NULL)) @@ -241,17 +163,13 @@ int wiiuse_connect(struct wiimote_t** wm, int wiimotes) { return connected; } - -/** - * @brief Connect to a wiimote with a known address. - * - * @param wm Pointer to a wiimote_t structure. - * @param address The address of the device to connect to. - * If NULL, use the address in the struct set by wiiuse_find(). - * - * @return 1 on success, 0 on failure - */ -static int wiiuse_connect_single(struct wiimote_t* wm, char* address) { +// Connect to a wiimote with a known address. +// wm Pointer to a wiimote_t structure. +// address The address of the device to connect to. +// If NULL, use the address in the struct set by wiiuse_find(). +// Return 1 on success, 0 on failure +static int wiiuse_connect_single(struct wiimote_t* wm, char* address) +{ struct sockaddr_l2 addr; if (!wm || WIIMOTE_IS_CONNECTED(wm)) @@ -260,20 +178,18 @@ static int wiiuse_connect_single(struct wiimote_t* wm, char* address) { addr.l2_family = AF_BLUETOOTH; bdaddr_t *bdaddr = &wm->bdaddr; if (address) - /* use provided address */ + // use provided address str2ba(address, &addr.l2_bdaddr); else { if (bacmp(bdaddr, BDADDR_ANY) == 0) return 0; - /* use address of device discovered */ + // use address of device discovered addr.l2_bdaddr = *bdaddr; - + } - /* - * OUTPUT CHANNEL - */ + // OUTPUT CHANNEL wm->out_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); if (wm->out_sock == -1) return 0; @@ -281,17 +197,17 @@ static int wiiuse_connect_single(struct wiimote_t* wm, char* address) { addr.l2_cid = 0; addr.l2_psm = htobs(WM_OUTPUT_CHANNEL); - /* connect to wiimote */ - if (connect(wm->out_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + // connect to wiimote + if (connect(wm->out_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { perror("connect() output sock"); return 0; } - /* - * INPUT CHANNEL - */ + // INPUT CHANNEL wm->in_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); - if (wm->in_sock == -1) { + if (wm->in_sock == -1) + { close(wm->out_sock); wm->out_sock = -1; return 0; @@ -299,8 +215,9 @@ static int wiiuse_connect_single(struct wiimote_t* wm, char* address) { addr.l2_psm = htobs(WM_INPUT_CHANNEL); - /* connect to wiimote */ - if (connect(wm->in_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + // connect to wiimote + if (connect(wm->in_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { perror("connect() interrupt sock"); close(wm->out_sock); wm->out_sock = -1; @@ -308,25 +225,19 @@ static int wiiuse_connect_single(struct wiimote_t* wm, char* address) { } WIIUSE_INFO("Connected to wiimote [id %i].", wm->unid); - /* do the handshake */ + // do the handshake WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_CONNECTED); - + wiiuse_set_report_type(wm); return 1; } - -/** - * @brief Disconnect a wiimote. - * - * @param wm Pointer to a wiimote_t structure. - * - * @see wiiuse_connect() - * - * Note that this will not free the wiimote structure. - */ -void wiiuse_disconnect(struct wiimote_t* wm) { +// Disconnect a wiimote. +// wm Pointer to a wiimote_t structure. +// Note that this will not free the wiimote structure. +void wiiuse_disconnect(struct wiimote_t* wm) +{ if (!wm || !WIIMOTE_IS_CONNECTED(wm)) return; @@ -340,58 +251,65 @@ void wiiuse_disconnect(struct wiimote_t* wm) { WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED); WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); } -int wiiuse_io_read(struct wiimote_t* wm) { + +int wiiuse_io_read(struct wiimote_t* wm) +{ struct timeval tv; fd_set fds; int r; if (!wm) return 0; - /* block select() for 1/2000th of a second */ + // block select() for 1/2000th of a second tv.tv_sec = 0; tv.tv_usec = wm->timeout * 1000; // timeout is in Milliseconds tv_usec is in Microseconds! FD_ZERO(&fds); - /* only poll it if it is connected */ - if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_CONNECTED)) { + // only poll it if it is connected + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_CONNECTED)) + { FD_SET(wm->in_sock, &fds); //highest_fd = wm[i]->in_sock; } else - /* nothing to poll */ + // nothing to poll return 0; - if (select(wm->in_sock + 1, &fds, NULL, NULL, &tv) == -1) { + if (select(wm->in_sock + 1, &fds, NULL, NULL, &tv) == -1) + { WIIUSE_ERROR("Unable to select() the wiimote interrupt socket(s)."); perror("Error Details"); return 0; } - /* if this wiimote is not connected, skip it */ + // if this wiimote is not connected, skip it if (!WIIMOTE_IS_CONNECTED(wm)) return 0; if (FD_ISSET(wm->in_sock, &fds)) { //memset(wm->event_buf, 0, sizeof(wm->event_buf)); - /* read the pending message into the buffer */ + // read the pending message into the buffer r = read(wm->in_sock, wm->event_buf, sizeof(wm->event_buf)); - if (r == -1) { - /* error reading data */ + if (r == -1) + { + // error reading data WIIUSE_ERROR("Receiving wiimote data (id %i).", wm->unid); perror("Error Details"); - if (errno == ENOTCONN) { - /* this can happen if the bluetooth dongle is disconnected */ + if (errno == ENOTCONN) + { + // this can happen if the bluetooth dongle is disconnected WIIUSE_ERROR("Bluetooth appears to be disconnected. Wiimote unid %i will be disconnected.", wm->unid); wiiuse_disconnect(wm); wm->event = WIIUSE_UNEXPECTED_DISCONNECT; } - + return 0; } - if (!r) { - /* remote disconnect */ + if (!r) + { + // remote disconnect wiiuse_disconnected(wm); return 0; } @@ -401,14 +319,9 @@ int wiiuse_io_read(struct wiimote_t* wm) { return 0; } - int wiiuse_io_write(struct wiimote_t* wm, byte* buf, int len) { if(buf[0] == 0xa2) buf[0] = 0x52; // May not be needed. Will be changing/correcting in the next few revisions return write(wm->out_sock, buf, len); } - - - -#endif /* ifndef WIN32 */ diff --git a/Externals/WiiUse/Src/wiiuse.h b/Externals/WiiUse/Src/wiiuse.h index e6568f992a..5ab1e0f02e 100644 --- a/Externals/WiiUse/Src/wiiuse.h +++ b/Externals/WiiUse/Src/wiiuse.h @@ -225,12 +225,7 @@ WIIUSE_EXPORT extern int wiiuse_check_system_notification(unsigned int nMsg, WPA WIIUSE_EXPORT extern int wiiuse_register_system_notification(HWND hwnd); #endif -#ifdef __linux__ -int wiiuse_find_more(struct wiimote_t** wm, int max_wiimotes, int timeout); -#endif - /* ir.c */ - WIIUSE_EXPORT extern void wiiuse_set_ir_sensitivity(struct wiimote_t* wm, int level); /* io.c */ diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteReal/WiimoteReal.cpp b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteReal/WiimoteReal.cpp index afff1e95a3..ef06fe412d 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteReal/WiimoteReal.cpp +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteReal/WiimoteReal.cpp @@ -389,6 +389,7 @@ void Refresh() // this gets called from the GUI thread // make sure real wiimotes have been initialized if (!g_real_wiimotes_initialized) { + g_refresh_critsec.Leave(); Initialize(); return; } @@ -401,10 +402,13 @@ void Refresh() // this gets called from the GUI thread // don't scan for wiimotes if we don't want any more if (wanted_wiimotes <= g_wiimotes_found) + { + g_refresh_critsec.Leave(); return; + } // scan for wiimotes - unsigned int num_wiimotes = wiiuse_find_more(g_wiimotes_from_wiiuse, wanted_wiimotes, 5); + unsigned int num_wiimotes = wiiuse_find(g_wiimotes_from_wiiuse, wanted_wiimotes, 5); DEBUG_LOG(WIIMOTE, "Found %i Real Wiimotes, %i wanted", num_wiimotes, wanted_wiimotes);