diff --git a/Makefile.wii b/Makefile.wii
index 8d2788a23a..7eaf7ec46b 100644
--- a/Makefile.wii
+++ b/Makefile.wii
@@ -30,13 +30,13 @@ ELF2DOL = $(DEVKITPPC)/bin/elf2dol$(EXE_EXT)
DOL_TARGET := retroarch_wii.dol
ELF_TARGET := retroarch_wii.elf
-INCLUDE := -I. -I$(DEVKITPRO)/libogc/include
+INCLUDE := -I. -I$(DEVKITPRO)/libogc/include -I$(DEVKITPRO)/libogc/include/ogc
LIBDIRS := -L$(DEVKITPRO)/libogc/lib/wii -L.
MACHDEP := -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float
CFLAGS += -Wall -std=gnu99 $(MACHDEP) $(INCLUDE)
LDFLAGS := $(MACHDEP) -Wl,-Map,$(notdir $(ELF_TARGET)).map,-wrap,malloc,-wrap,free,-wrap,memalign,-wrap,calloc,-wrap,realloc,-wrap,strdup,-wrap,strndup,-wrap,malloc_usable_size -T gx/ld/rvl.ld
-LIBS := -lfat -lretro_wii -lwiiuse -logc -lbte
+LIBS := -lfat -lretro_wii -logc -lbte
APP_BOOTER_DIR = wii/app_booter
@@ -57,7 +57,7 @@ CFLAGS += -DHAVE_FILE_LOGGER
CFLAGS += -Iconsole/logger
endif
-CFLAGS += -std=gnu99 -DHAVE_DEFAULT_RETROPAD_INPUT -DHAVE_RGUI -DHAVE_THREAD -DRARCH_CONSOLE -DHAVE_LIBRETRO_MANAGEMENT -DHAVE_RARCH_EXEC -DHAVE_RMENU -DGEKKO -DHAVE_ZLIB -DWANT_RZLIB -DHAVE_RARCH_MAIN_WRAP -DHAVE_GRIFFIN=1 -DHAVE_SCREENSHOTS -DPACKAGE_VERSION=\"0.9.8-beta3\" -Dmain=rarch_main -Wno-char-subscripts
+CFLAGS += -std=gnu99 -DHAVE_DEFAULT_RETROPAD_INPUT -DHAVE_WIIUSE -DHAVE_RGUI -DHAVE_THREAD -DRARCH_CONSOLE -DHAVE_LIBRETRO_MANAGEMENT -DHAVE_RARCH_EXEC -DHAVE_RMENU -DGEKKO -DHAVE_ZLIB -DWANT_RZLIB -DHAVE_RARCH_MAIN_WRAP -DHAVE_GRIFFIN=1 -DHAVE_SCREENSHOTS -DPACKAGE_VERSION=\"0.9.8-beta3\" -Dmain=rarch_main -Wno-char-subscripts
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -g -DDEBUG
diff --git a/console/griffin/griffin.c b/console/griffin/griffin.c
index 590b5a8287..17ad14123f 100644
--- a/console/griffin/griffin.c
+++ b/console/griffin/griffin.c
@@ -227,6 +227,20 @@ INPUT
#include "../../input/overlay.c"
#endif
+#ifdef HAVE_WIIUSE
+#include "../../wii/wiiuse/classic.c"
+#include "../../wii/wiiuse/dynamics.c"
+#include "../../wii/wiiuse/events.c"
+#include "../../wii/wiiuse/io.c"
+#include "../../wii/wiiuse/io_wii.c"
+#include "../../wii/wiiuse/ir.c"
+#include "../../wii/wiiuse/motion_plus.c"
+#include "../../wii/wiiuse/nunchuk.c"
+#include "../../wii/wiiuse/speaker.c"
+#include "../../wii/wiiuse/wiiuse.c"
+#include "../../wii/wiiuse/wpad.c"
+#endif
+
#if defined(__CELLOS_LV2__)
#include "../../ps3/ps3_input.c"
#elif defined(SN_TARGET_PSP2) || defined(PSP)
diff --git a/wii/wiiuse/classic.c b/wii/wiiuse/classic.c
new file mode 100644
index 0000000000..c37e94f0a9
--- /dev/null
+++ b/wii/wiiuse/classic.c
@@ -0,0 +1,194 @@
+/*
+ * wiiuse
+ *
+ * Written By:
+ * Michael Laforest < para >
+ * Email: < thepara (--AT--) g m a i l [--DOT--] com >
+ *
+ * Copyright 2006-2007
+ *
+ * This file is part of wiiuse.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * $Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/libogc/wiiuse/classic.c,v 1.7 2008-11-14 13:34:57 shagkur Exp $
+ *
+ */
+
+/**
+ * @file
+ * @brief Classic controller expansion device.
+ */
+
+#include
+#include
+#include
+#include
+
+#ifdef WIN32
+ #include
+#endif
+
+#include "definitions.h"
+#include "wiiuse_internal.h"
+#include "dynamics.h"
+#include "events.h"
+#include "classic.h"
+#include "io.h"
+
+static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now);
+
+/**
+ * @brief Handle the handshake data from the classic controller.
+ *
+ * @param cc A pointer to a classic_ctrl_t structure.
+ * @param data The data read in from the device.
+ * @param len The length of the data block, in bytes.
+ *
+ * @return Returns 1 if handshake was successful, 0 if not.
+ */
+int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, ubyte* data, uword len) {
+ //int i;
+ int offset = 0;
+
+ cc->btns = 0;
+ cc->btns_held = 0;
+ cc->btns_released = 0;
+
+ /* decrypt data */
+ /*
+ for (i = 0; i < len; ++i)
+ data[i] = (data[i] ^ 0x17) + 0x17;
+ */
+ if (data[offset] == 0xFF) {
+ /*
+ * Sometimes the data returned here is not correct.
+ * This might happen because the wiimote is lagging
+ * behind our initialization sequence.
+ * To fix this just request the handshake again.
+ *
+ * Other times it's just the first 16 bytes are 0xFF,
+ * but since the next 16 bytes are the same, just use
+ * those.
+ */
+ if (data[offset + 16] == 0xFF) {
+ /* get the calibration data again */
+ //WIIUSE_DEBUG("Classic controller handshake appears invalid, trying again.");
+ wiiuse_read_data(wm, data, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN, wiiuse_handshake_expansion);
+ } else
+ offset += 16;
+ }
+
+
+ /* joystick stuff */
+ cc->ljs.max.x = data[0 + offset] / 4 == 0 ? 64 : data[0 + offset] / 4;
+ cc->ljs.min.x = data[1 + offset] / 4;
+ cc->ljs.center.x = data[2 + offset] / 4 == 0 ? 32 : data[2 + offset] / 4;
+ cc->ljs.max.y = data[3 + offset] / 4 == 0 ? 64 : data[3 + offset] / 4;
+ cc->ljs.min.y = data[4 + offset] / 4;
+ cc->ljs.center.y = data[5 + offset] / 4 == 0 ? 32 : data[5 + offset] / 4;
+
+ cc->rjs.max.x = data[6 + offset] / 8 == 0 ? 32 : data[6 + offset] / 8;
+ cc->rjs.min.x = data[7 + offset] / 8;
+ cc->rjs.center.x = data[8 + offset] / 8 == 0 ? 16 : data[8 + offset] / 8;
+ cc->rjs.max.y = data[9 + offset] / 8 == 0 ? 32 : data[9 + offset] / 8;
+ cc->rjs.min.y = data[10 + offset] / 8;
+ cc->rjs.center.y = data[11 + offset] / 8 == 0 ? 16 : data[11 + offset] / 8;
+
+ /* handshake done */
+ wm->event = WIIUSE_CLASSIC_CTRL_INSERTED;
+ wm->exp.type = EXP_CLASSIC;
+
+ #ifdef WIN32
+ wm->timeout = WIIMOTE_DEFAULT_TIMEOUT;
+ #endif
+
+ return 1;
+}
+
+
+/**
+ * @brief The classic controller disconnected.
+ *
+ * @param cc A pointer to a classic_ctrl_t structure.
+ */
+void classic_ctrl_disconnected(struct classic_ctrl_t* cc)
+{
+ memset(cc, 0, sizeof(struct classic_ctrl_t));
+}
+
+
+
+/**
+ * @brief Handle classic controller event.
+ *
+ * @param cc A pointer to a classic_ctrl_t structure.
+ * @param msg The message specified in the event packet.
+ */
+void classic_ctrl_event(struct classic_ctrl_t* cc, ubyte* msg) {
+ //int i;
+
+ /* decrypt data */
+ /*
+ for (i = 0; i < 6; ++i)
+ msg[i] = (msg[i] ^ 0x17) + 0x17;
+ */
+ classic_ctrl_pressed_buttons(cc, BIG_ENDIAN_SHORT(*(short*)(msg + 4)));
+
+ /* left/right buttons */
+ cc->ls_raw = (((msg[2] & 0x60) >> 2) | ((msg[3] & 0xE0) >> 5));
+ cc->rs_raw = (msg[3] & 0x1F);
+
+ /*
+ * TODO - LR range hardcoded from 0x00 to 0x1F.
+ * This is probably in the calibration somewhere.
+ */
+#ifndef GEKKO
+ cc->r_shoulder = ((float)r / 0x1F);
+ cc->l_shoulder = ((float)l / 0x1F);
+#endif
+ /* calculate joystick orientation */
+ cc->ljs.pos.x = (msg[0] & 0x3F);
+ cc->ljs.pos.y = (msg[1] & 0x3F);
+ cc->rjs.pos.x = ((msg[0] & 0xC0) >> 3) | ((msg[1] & 0xC0) >> 5) | ((msg[2] & 0x80) >> 7);
+ cc->rjs.pos.y = (msg[2] & 0x1F);
+#ifndef GEKKO
+ calc_joystick_state(&cc->ljs, cc->ljs.pos.x, cc->ljs.pos.y);
+ calc_joystick_state(&cc->rjs, cc->rjs.pos.x, cc->rjs.pos.y);
+#endif
+}
+
+
+/**
+ * @brief Find what buttons are pressed.
+ *
+ * @param cc A pointer to a classic_ctrl_t structure.
+ * @param msg The message byte specified in the event packet.
+ */
+static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now) {
+ /* message is inverted (0 is active, 1 is inactive) */
+ now = ~now & CLASSIC_CTRL_BUTTON_ALL;
+
+ /* preserve old btns pressed */
+ cc->btns_last = cc->btns;
+
+ /* pressed now & were pressed, then held */
+ cc->btns_held = (now & cc->btns);
+
+ /* were pressed or were held & not pressed now, then released */
+ cc->btns_released = ((cc->btns | cc->btns_held) & ~now);
+
+ /* buttons pressed now */
+ cc->btns = now;
+}
diff --git a/wii/wiiuse/classic.h b/wii/wiiuse/classic.h
new file mode 100644
index 0000000000..8ae62583f4
--- /dev/null
+++ b/wii/wiiuse/classic.h
@@ -0,0 +1,53 @@
+/*
+ * wiiuse
+ *
+ * Written By:
+ * Michael Laforest < para >
+ * Email: < thepara (--AT--) g m a i l [--DOT--] com >
+ *
+ * Copyright 2006-2007
+ *
+ * This file is part of wiiuse.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * $Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/libogc/wiiuse/classic.h,v 1.1 2008-05-08 09:42:14 shagkur Exp $
+ *
+ */
+
+/**
+ * @file
+ * @brief Classic controller expansion device.
+ */
+
+#ifndef CLASSIC_H_INCLUDED
+#define CLASSIC_H_INCLUDED
+
+#include "wiiuse_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, ubyte* data, uword len);
+
+void classic_ctrl_disconnected(struct classic_ctrl_t* cc);
+
+void classic_ctrl_event(struct classic_ctrl_t* cc, ubyte* msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CLASSIC_H_INCLUDED
diff --git a/wii/wiiuse/definitions.h b/wii/wiiuse/definitions.h
new file mode 100644
index 0000000000..04dc5be6d8
--- /dev/null
+++ b/wii/wiiuse/definitions.h
@@ -0,0 +1,55 @@
+#ifndef __DEFINITIONS_H__
+#define __DEFINITIONS_H__
+
+#include "os.h"
+
+#define WIIMOTE_PI 3.14159265f
+
+//#define WITH_WIIUSE_DEBUG
+
+/* Error output macros */
+#define WIIUSE_ERROR(fmt, ...) fprintf(stderr, "[ERROR] " fmt "\n", ##__VA_ARGS__)
+
+/* Warning output macros */
+#define WIIUSE_WARNING(fmt, ...) fprintf(stderr, "[WARNING] " fmt "\n", ##__VA_ARGS__)
+
+/* Information output macros */
+#define WIIUSE_INFO(fmt, ...) fprintf(stderr, "[INFO] " fmt "\n", ##__VA_ARGS__)
+
+#ifdef WITH_WIIUSE_DEBUG
+ #ifdef WIN32
+ #define WIIUSE_DEBUG(fmt, ...) do { \
+ char* file = __FILE__; \
+ int i = strlen(file) - 1; \
+ for (; i && (file[i] != '\\'); --i); \
+ fprintf(stderr, "[DEBUG] %s:%i: " fmt "\n", file+i+1, __LINE__, ##__VA_ARGS__); \
+ } while (0)
+ #else
+ #define WIIUSE_DEBUG(fmt, ...) fprintf(stderr, "[DEBUG] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__)
+ #endif
+#else
+ #define WIIUSE_DEBUG(fmt, ...)
+#endif
+
+#if 1
+#define WII_DEBUG(fmt, ...) do { \
+ printf("[WDEBUG] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__); \
+ usleep(3000000); \
+ } while (0)
+#else
+ #define WII_DEBUG(fmt, ...)
+#endif
+
+
+/* Convert between radians and degrees */
+#define RAD_TO_DEGREE(r) ((r * 180.0f) / WIIMOTE_PI)
+#define DEGREE_TO_RAD(d) (d * (WIIMOTE_PI / 180.0f))
+
+/* Convert to big endian */
+#define BIG_ENDIAN_LONG(i) (htonl(i))
+#define BIG_ENDIAN_SHORT(i) (htons(i))
+
+#define absf(x) ((x >= 0) ? (x) : (x * -1.0f))
+#define diff_f(x, y) ((x >= y) ? (absf(x - y)) : (absf(y - x)))
+
+#endif
diff --git a/wii/wiiuse/dynamics.c b/wii/wiiuse/dynamics.c
new file mode 100644
index 0000000000..805e3ba5e6
--- /dev/null
+++ b/wii/wiiuse/dynamics.c
@@ -0,0 +1,230 @@
+/*
+ * wiiuse
+ *
+ * Written By:
+ * Michael Laforest < para >
+ * Email: < thepara (--AT--) g m a i l [--DOT--] com >
+ *
+ * Copyright 2006-2007
+ *
+ * This file is part of wiiuse.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * $Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/libogc/wiiuse/dynamics.c,v 1.2 2008-11-14 13:34:57 shagkur Exp $
+ *
+ */
+
+/**
+ * @file
+ * @brief Handles the dynamics of the wiimote.
+ *
+ * The file includes functions that handle the dynamics
+ * of the wiimote. Such dynamics include orientation and
+ * motion sensing.
+ */
+
+#include
+#include
+#include
+
+#ifdef WIN32
+ #include
+#endif
+
+#include "definitions.h"
+#include "wiiuse_internal.h"
+#include "ir.h"
+#include "dynamics.h"
+
+/**
+ * @brief Calculate the roll, pitch, yaw.
+ *
+ * @param ac An accelerometer (accel_t) structure.
+ * @param accel [in] Pointer to a vec3w_t structure that holds the raw acceleration data.
+ * @param orient [out] Pointer to a orient_t structure that will hold the orientation data.
+ * @param rorient [out] Pointer to a orient_t structure that will hold the non-smoothed orientation data.
+ * @param smooth If smoothing should be performed on the angles calculated. 1 to enable, 0 to disable.
+ *
+ * Given the raw acceleration data from the accelerometer struct, calculate
+ * the orientation of the device and set it in the \a orient parameter.
+ */
+void calculate_orientation(struct accel_t* ac, struct vec3w_t* accel, struct orient_t* orient, int smooth) {
+ float xg, yg, zg;
+ float x, y, z;
+
+ /*
+ * roll - use atan(z / x) [ ranges from -180 to 180 ]
+ * pitch - use atan(z / y) [ ranges from -180 to 180 ]
+ * yaw - impossible to tell without IR
+ */
+
+ /* yaw - set to 0, IR will take care of it if it's enabled */
+ orient->yaw = 0.0f;
+
+ /* find out how much it has to move to be 1g */
+ xg = (float)ac->cal_g.x;
+ yg = (float)ac->cal_g.y;
+ zg = (float)ac->cal_g.z;
+
+ /* find out how much it actually moved and normalize to +/- 1g */
+ x = ((float)accel->x - (float)ac->cal_zero.x) / xg;
+ y = ((float)accel->y - (float)ac->cal_zero.y) / yg;
+ z = ((float)accel->z - (float)ac->cal_zero.z) / zg;
+
+ /* make sure x,y,z are between -1 and 1 for the tan functions */
+ if (x < -1.0f) x = -1.0f;
+ else if (x > 1.0f) x = 1.0f;
+ if (y < -1.0f) y = -1.0f;
+ else if (y > 1.0f) y = 1.0f;
+ if (z < -1.0f) z = -1.0f;
+ else if (z > 1.0f) z = 1.0f;
+
+ /* if it is over 1g then it is probably accelerating and not reliable */
+ if (abs(accel->x - ac->cal_zero.x) <= (ac->cal_g.x+10)) {
+ /* roll */
+ x = RAD_TO_DEGREE(atan2f(x, z));
+ if(isfinite(x)) {
+ orient->roll = x;
+ orient->a_roll = x;
+ }
+ }
+
+ if (abs(accel->y - ac->cal_zero.y) <= (ac->cal_g.y+10)) {
+ /* pitch */
+ y = RAD_TO_DEGREE(atan2f(y, z));
+ if(isfinite(y)) {
+ orient->pitch = y;
+ orient->a_pitch = y;
+ }
+ }
+
+ /* smooth the angles if enabled */
+ if (smooth) {
+ apply_smoothing(ac, orient, SMOOTH_ROLL);
+ apply_smoothing(ac, orient, SMOOTH_PITCH);
+ }
+}
+
+
+/**
+ * @brief Calculate the gravity forces on each axis.
+ *
+ * @param ac An accelerometer (accel_t) structure.
+ * @param accel [in] Pointer to a vec3w_t structure that holds the raw acceleration data.
+ * @param gforce [out] Pointer to a gforce_t structure that will hold the gravity force data.
+ */
+void calculate_gforce(struct accel_t* ac, struct vec3w_t* accel, struct gforce_t* gforce) {
+ float xg, yg, zg;
+
+ /* find out how much it has to move to be 1g */
+ xg = (float)ac->cal_g.x;
+ yg = (float)ac->cal_g.y;
+ zg = (float)ac->cal_g.z;
+
+ /* find out how much it actually moved and normalize to +/- 1g */
+ gforce->x = ((float)accel->x - (float)ac->cal_zero.x) / xg;
+ gforce->y = ((float)accel->y - (float)ac->cal_zero.y) / yg;
+ gforce->z = ((float)accel->z - (float)ac->cal_zero.z) / zg;
+}
+
+
+/**
+ * @brief Calculate the angle and magnitude of a joystick.
+ *
+ * @param js [out] Pointer to a joystick_t structure.
+ * @param x The raw x-axis value.
+ * @param y The raw y-axis value.
+ */
+void calc_joystick_state(struct joystick_t* js, float x, float y) {
+ float rx, ry, ang;
+
+ /*
+ * Since the joystick center may not be exactly:
+ * (min + max) / 2
+ * Then the range from the min to the center and the center to the max
+ * may be different.
+ * Because of this, depending on if the current x or y value is greater
+ * or less than the assoicated axis center value, it needs to be interpolated
+ * between the center and the minimum or maxmimum rather than between
+ * the minimum and maximum.
+ *
+ * So we have something like this:
+ * (x min) [-1] ---------*------ [0] (x center) [0] -------- [1] (x max)
+ * Where the * is the current x value.
+ * The range is therefore -1 to 1, 0 being the exact center rather than
+ * the middle of min and max.
+ */
+ if (x == js->center.x)
+ rx = 0;
+ else if (x >= js->center.x)
+ rx = ((float)(x - js->center.x) / (float)(js->max.x - js->center.x));
+ else
+ rx = ((float)(x - js->min.x) / (float)(js->center.x - js->min.x)) - 1.0f;
+
+ if (y == js->center.y)
+ ry = 0;
+ else if (y >= js->center.y)
+ ry = ((float)(y - js->center.y) / (float)(js->max.y - js->center.y));
+ else
+ ry = ((float)(y - js->min.y) / (float)(js->center.y - js->min.y)) - 1.0f;
+
+ /* calculate the joystick angle and magnitude */
+ ang = RAD_TO_DEGREE(atanf(ry / rx));
+ ang -= 90.0f;
+ if (rx < 0.0f)
+ ang -= 180.0f;
+ js->ang = absf(ang);
+ js->mag = (float) sqrt((rx * rx) + (ry * ry));
+}
+
+
+void apply_smoothing(struct accel_t* ac, struct orient_t* orient, int type) {
+ switch (type) {
+ case SMOOTH_ROLL:
+ {
+ /* it's possible last iteration was nan or inf, so set it to 0 if that happened */
+ if (isnan(ac->st_roll) || isinf(ac->st_roll))
+ ac->st_roll = 0.0f;
+
+ /*
+ * If the sign changes (which will happen if going from -180 to 180)
+ * or from (-1 to 1) then don't smooth, just use the new angle.
+ */
+ if (((ac->st_roll < 0) && (orient->roll > 0)) || ((ac->st_roll > 0) && (orient->roll < 0))) {
+ ac->st_roll = orient->roll;
+ } else {
+ orient->roll = ac->st_roll + (ac->st_alpha * (orient->a_roll - ac->st_roll));
+ ac->st_roll = orient->roll;
+ }
+
+ return;
+ }
+
+ case SMOOTH_PITCH:
+ {
+ if (isnan(ac->st_pitch) || isinf(ac->st_pitch))
+ ac->st_pitch = 0.0f;
+
+ if (((ac->st_pitch < 0) && (orient->pitch > 0)) || ((ac->st_pitch > 0) && (orient->pitch < 0))) {
+ ac->st_pitch = orient->pitch;
+ } else {
+ orient->pitch = ac->st_pitch + (ac->st_alpha * (orient->a_pitch - ac->st_pitch));
+ ac->st_pitch = orient->pitch;
+ }
+
+ return;
+ }
+ }
+}
diff --git a/wii/wiiuse/dynamics.h b/wii/wiiuse/dynamics.h
new file mode 100644
index 0000000000..4daec29f01
--- /dev/null
+++ b/wii/wiiuse/dynamics.h
@@ -0,0 +1,56 @@
+/*
+ * wiiuse
+ *
+ * Written By:
+ * Michael Laforest < para >
+ * Email: < thepara (--AT--) g m a i l [--DOT--] com >
+ *
+ * Copyright 2006-2007
+ *
+ * This file is part of wiiuse.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * $Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/libogc/wiiuse/dynamics.h,v 1.2 2008-11-14 13:34:57 shagkur Exp $
+ *
+ */
+
+/**
+ * @file
+ * @brief Handles the dynamics of the wiimote.
+ *
+ * The file includes functions that handle the dynamics
+ * of the wiimote. Such dynamics include orientation and
+ * motion sensing.
+ */
+
+#ifndef DYNAMICS_H_INCLUDED
+#define DYNAMICS_H_INCLUDED
+
+#include "wiiuse_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void calculate_orientation(struct accel_t* ac, struct vec3w_t* accel, struct orient_t* orient, int smooth);
+void calculate_gforce(struct accel_t* ac, struct vec3w_t* accel, struct gforce_t* gforce);
+void calc_joystick_state(struct joystick_t* js, float x, float y);
+void apply_smoothing(struct accel_t* ac, struct orient_t* orient, int type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DYNAMICS_H_INCLUDED
diff --git a/wii/wiiuse/events.c b/wii/wiiuse/events.c
new file mode 100644
index 0000000000..85b1768040
--- /dev/null
+++ b/wii/wiiuse/events.c
@@ -0,0 +1,331 @@
+#include
+
+#ifndef WIN32
+ #include
+ #include
+ #include
+#else
+ #include
+#endif
+
+#include
+#include
+#include
+#include
+
+#include "dynamics.h"
+#include "definitions.h"
+#include "wiiuse_internal.h"
+#include "events.h"
+#include "nunchuk.h"
+#include "classic.h"
+#include "motion_plus.h"
+#include "ir.h"
+#include "io.h"
+
+
+static void event_data_read(struct wiimote_t *wm,ubyte *msg)
+{
+ ubyte err;
+ ubyte len;
+ uword offset;
+ struct op_t *op;
+ struct cmd_blk_t *cmd = wm->cmd_head;
+
+ wiiuse_pressed_buttons(wm,msg);
+
+ if(!cmd) return;
+ if(!(cmd->state==CMD_SENT && cmd->data[0]==WM_CMD_READ_DATA)) return;
+
+ //printf("event_data_read(%p)\n",cmd);
+
+ err = msg[2]&0x0f;
+ op = (struct op_t*)cmd->data;
+ if(err) {
+ wm->cmd_head = cmd->next;
+
+ cmd->state = CMD_DONE;
+ if(cmd->cb!=NULL) cmd->cb(wm,op->buffer,(op->readdata.size - op->wait));
+
+ __lwp_queue_append(&wm->cmdq,&cmd->node);
+ wiiuse_send_next_command(wm);
+ return;
+ }
+
+ len = ((msg[2]&0xf0)>>4)+1;
+ offset = BIG_ENDIAN_SHORT(*(uword*)(msg+3));
+
+ //printf("addr: %08x\noffset: %d\nlen: %d\n",req->addr,offset,len);
+
+ op->readdata.addr = (op->readdata.addr&0xffff);
+ op->wait -= len;
+ if(op->wait>=op->readdata.size) op->wait = 0;
+
+ memcpy((op->buffer+offset-op->readdata.addr),(msg+5),len);
+ if(!op->wait) {
+ wm->cmd_head = cmd->next;
+
+ wm->event = WIIUSE_READ_DATA;
+ cmd->state = CMD_DONE;
+ if(cmd->cb!=NULL) cmd->cb(wm,op->buffer,op->readdata.size);
+
+ __lwp_queue_append(&wm->cmdq,&cmd->node);
+ wiiuse_send_next_command(wm);
+ }
+}
+
+static void event_ack(struct wiimote_t *wm,ubyte *msg)
+{
+ struct cmd_blk_t *cmd = wm->cmd_head;
+
+ wiiuse_pressed_buttons(wm,msg);
+
+ if(!cmd || cmd->state!=CMD_SENT || cmd->data[0]==WM_CMD_READ_DATA || cmd->data[0]==WM_CMD_CTRL_STATUS || cmd->data[0]!=msg[2]) {
+ //WIIUSE_WARNING("Unsolicited event ack: report %02x status %02x", msg[2], msg[3]);
+ return;
+ }
+ if(msg[3]) {
+ //WIIUSE_WARNING("Command %02x %02x failed: status %02x", cmd->data[0], cmd->data[1], msg[3]);
+ return;
+ }
+
+ //WIIUSE_DEBUG("Received ack for command %02x %02x", cmd->data[0], cmd->data[1]);
+
+ wm->cmd_head = cmd->next;
+
+ wm->event = WIIUSE_ACK;
+ cmd->state = CMD_DONE;
+ if(cmd->cb) cmd->cb(wm,NULL,0);
+
+ __lwp_queue_append(&wm->cmdq,&cmd->node);
+ wiiuse_send_next_command(wm);
+}
+
+static void event_status(struct wiimote_t *wm,ubyte *msg)
+{
+ int ir = 0;
+ int attachment = 0;
+ int speaker = 0;
+ //int led[4]= {0};
+ struct cmd_blk_t *cmd = wm->cmd_head;
+
+ wiiuse_pressed_buttons(wm,msg);
+
+ wm->event = WIIUSE_STATUS;
+ //if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_1) led[0] = 1;
+ //if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_2) led[1] = 1;
+ //if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_3) led[2] = 1;
+ //if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_4) led[3] = 1;
+
+ if((msg[2]&WM_CTRL_STATUS_BYTE1_ATTACHMENT)==WM_CTRL_STATUS_BYTE1_ATTACHMENT) attachment = 1;
+ if((msg[2]&WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED)==WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED) speaker = 1;
+ if((msg[2]&WM_CTRL_STATUS_BYTE1_IR_ENABLED)==WM_CTRL_STATUS_BYTE1_IR_ENABLED) ir = 1;
+
+ wm->battery_level = msg[5];
+
+ if(!ir && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR_INIT)) {
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR_INIT);
+ wiiuse_set_ir(wm, 1);
+ goto done;
+ }
+ if(ir && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_IR);
+ else if(!ir && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR);
+
+ if(!speaker && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER_INIT)) {
+ WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_SPEAKER_INIT);
+ wiiuse_set_speaker(wm,1);
+ goto done;
+ }
+ if(speaker && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_SPEAKER);
+ else if(!speaker && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_SPEAKER);
+
+ if(attachment) {
+ if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP) && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_FAILED) && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_HANDSHAKE)) {
+ wiiuse_handshake_expansion_start(wm);
+ goto done;
+ }
+ } else {
+ WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_EXP_FAILED);
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP)) {
+ wiiuse_disable_expansion(wm);
+ goto done;
+ }
+ }
+ wiiuse_set_report_type(wm,NULL);
+
+done:
+ if(!cmd) return;
+ if(!(cmd->state==CMD_SENT && cmd->data[0]==WM_CMD_CTRL_STATUS)) return;
+
+ wm->cmd_head = cmd->next;
+
+ cmd->state = CMD_DONE;
+ if(cmd->cb!=NULL) cmd->cb(wm,msg,6);
+
+ __lwp_queue_append(&wm->cmdq,&cmd->node);
+ wiiuse_send_next_command(wm);
+}
+
+static void handle_expansion(struct wiimote_t *wm,ubyte *msg)
+{
+ switch (wm->exp.type) {
+ case EXP_NUNCHUK:
+ nunchuk_event(&wm->exp.nunchuk, msg);
+ break;
+ case EXP_CLASSIC:
+ classic_ctrl_event(&wm->exp.classic, msg);
+ break;
+ case EXP_MOTION_PLUS:
+ motion_plus_event(&wm->exp.mp, msg);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * @brief Called on a cycle where no significant change occurs.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ */
+void idle_cycle(struct wiimote_t* wm)
+{
+ /*
+ * Smooth the angles.
+ *
+ * This is done to make sure that on every cycle the orientation
+ * angles are smoothed. Normally when an event occurs the angles
+ * are updated and smoothed, but if no packet comes in then the
+ * angles remain the same. This means the angle wiiuse reports
+ * is still an old value. Smoothing needs to be applied in this
+ * case in order for the angle it reports to converge to the true
+ * angle of the device.
+ */
+ //printf("idle_cycle()\n");///
+ if (WIIUSE_USING_ACC(wm) && WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)) {
+ apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_ROLL);
+ apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_PITCH);
+ }
+}
+
+void parse_event(struct wiimote_t *wm)
+{
+ ubyte event;
+ ubyte *msg;
+
+ event = wm->event_buf[0];
+ msg = wm->event_buf+1;
+ //printf("parse_event(%02x,%p)\n",event,msg);
+ switch(event) {
+ case WM_RPT_CTRL_STATUS:
+ event_status(wm,msg);
+ return;
+ case WM_RPT_READ:
+ event_data_read(wm,msg);
+ return;
+ case WM_RPT_ACK:
+ event_ack(wm,msg);
+ return;
+ case WM_RPT_BTN:
+ wiiuse_pressed_buttons(wm,msg);
+ break;
+ case WM_RPT_BTN_ACC:
+ wiiuse_pressed_buttons(wm,msg);
+
+ wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3);
+ wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2);
+ wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2);
+#ifndef GEKKO
+ /* calculate the remote orientation */
+ calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING));
+
+ /* calculate the gforces on each axis */
+ calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce);
+#endif
+ break;
+ case WM_RPT_BTN_ACC_IR:
+ wiiuse_pressed_buttons(wm,msg);
+
+ wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3);
+ wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2);
+ wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2);
+#ifndef GEKKO
+ /* calculate the remote orientation */
+ calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING));
+
+ /* calculate the gforces on each axis */
+ calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce);
+#endif
+ calculate_extended_ir(wm, msg+5);
+ break;
+ case WM_RPT_BTN_EXP:
+ wiiuse_pressed_buttons(wm,msg);
+ handle_expansion(wm,msg+2);
+ break;
+ case WM_RPT_BTN_ACC_EXP:
+ /* button - motion - expansion */
+ wiiuse_pressed_buttons(wm, msg);
+
+ wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3);
+ wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2);
+ wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2);
+#ifndef GEKKO
+ calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING));
+ calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce);
+#endif
+ handle_expansion(wm, msg+5);
+ break;
+ case WM_RPT_BTN_IR_EXP:
+ wiiuse_pressed_buttons(wm,msg);
+ calculate_basic_ir(wm, msg+2);
+ handle_expansion(wm,msg+12);
+ break;
+ case WM_RPT_BTN_ACC_IR_EXP:
+ /* button - motion - ir - expansion */
+ wiiuse_pressed_buttons(wm, msg);
+
+ wm->accel.x = (msg[2]<<2)|((msg[0]>>5)&3);
+ wm->accel.y = (msg[3]<<2)|((msg[1]>>4)&2);
+ wm->accel.z = (msg[4]<<2)|((msg[1]>>5)&2);
+#ifndef GEKKO
+ calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING));
+ calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce);
+#endif
+ /* ir */
+ calculate_basic_ir(wm, msg+5);
+
+ handle_expansion(wm, msg+15);
+ break;
+ default:
+ WIIUSE_WARNING("Unknown event, can not handle it [Code 0x%x].", event);
+ return;
+ }
+
+ /* was there an event? */
+ wm->event = WIIUSE_EVENT;
+}
+
+/**
+ * @brief Find what buttons are pressed.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ * @param msg The message specified in the event packet.
+ */
+void wiiuse_pressed_buttons(struct wiimote_t* wm, ubyte* msg) {
+ short now;
+
+ /* convert to big endian */
+ now = BIG_ENDIAN_SHORT(*(short*)msg) & WIIMOTE_BUTTON_ALL;
+
+ /* preserve old btns pressed */
+ wm->btns_last = wm->btns;
+
+ /* pressed now & were pressed, then held */
+ wm->btns_held = (now & wm->btns);
+
+ /* were pressed or were held & not pressed now, then released */
+ wm->btns_released = ((wm->btns | wm->btns_held) & ~now);
+
+ /* buttons pressed now */
+ wm->btns = now;
+}
diff --git a/wii/wiiuse/events.h b/wii/wiiuse/events.h
new file mode 100644
index 0000000000..b6f0c75542
--- /dev/null
+++ b/wii/wiiuse/events.h
@@ -0,0 +1,14 @@
+#ifndef __EVENTS_H__
+#define __EVENTS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void wiiuse_pressed_buttons(struct wiimote_t* wm, ubyte* msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/wii/wiiuse/io.c b/wii/wiiuse/io.c
new file mode 100644
index 0000000000..4266319ab3
--- /dev/null
+++ b/wii/wiiuse/io.c
@@ -0,0 +1,150 @@
+#include
+#include
+
+#include "definitions.h"
+#include "wiiuse_internal.h"
+#include "nunchuk.h"
+#include "classic.h"
+#include "motion_plus.h"
+#include "io.h"
+#include "lwp_wkspace.inl"
+
+void wiiuse_handshake(struct wiimote_t *wm,ubyte *data,uword len)
+{
+ ubyte *buf = NULL;
+ struct accel_t *accel = &wm->accel_calib;
+
+ //printf("wiiuse_handshake(%d,%p,%d)\n",wm->handshake_state,data,len);
+
+ switch(wm->handshake_state) {
+ case 0:
+ wm->handshake_state++;
+
+ wiiuse_set_leds(wm,WIIMOTE_LED_NONE,NULL);
+
+ buf = __lwp_wkspace_allocate(sizeof(ubyte)*8);
+ wiiuse_read_data(wm,buf,WM_MEM_OFFSET_CALIBRATION,7,wiiuse_handshake);
+ break;
+ case 1:
+ wm->handshake_state++;
+
+ accel->cal_zero.x = ((data[0]<<2)|((data[3]>>4)&3));
+ accel->cal_zero.y = ((data[1]<<2)|((data[3]>>2)&3));
+ accel->cal_zero.z = ((data[2]<<2)|(data[3]&3));
+
+ accel->cal_g.x = (((data[4]<<2)|((data[7]>>4)&3)) - accel->cal_zero.x);
+ accel->cal_g.y = (((data[5]<<2)|((data[7]>>2)&3)) - accel->cal_zero.y);
+ accel->cal_g.z = (((data[6]<<2)|(data[7]&3)) - accel->cal_zero.z);
+ __lwp_wkspace_free(data);
+
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE);
+ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE);
+
+ wm->event = WIIUSE_CONNECT;
+ wiiuse_status(wm,NULL);
+ break;
+ default:
+ break;
+
+ }
+}
+
+void wiiuse_handshake_expansion_start(struct wiimote_t *wm)
+{
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP) || WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_FAILED) || WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_HANDSHAKE))
+ return;
+
+ wm->expansion_state = 0;
+ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
+ wiiuse_handshake_expansion(wm, NULL, 0);
+}
+
+void wiiuse_handshake_expansion(struct wiimote_t *wm,ubyte *data,uword len)
+{
+ int id;
+ ubyte val;
+ ubyte *buf = NULL;
+
+ switch(wm->expansion_state) {
+ /* These two initialization writes disable the encryption */
+ case 0:
+ wm->expansion_state = 1;
+ val = 0x55;
+ wiiuse_write_data(wm,WM_EXP_MEM_ENABLE1,&val,1,wiiuse_handshake_expansion);
+ break;
+ case 1:
+ wm->expansion_state = 2;
+ val = 0x00;
+ wiiuse_write_data(wm,WM_EXP_MEM_ENABLE2,&val,1,wiiuse_handshake_expansion);
+ break;
+ case 2:
+ wm->expansion_state = 3;
+ buf = __lwp_wkspace_allocate(sizeof(ubyte)*EXP_HANDSHAKE_LEN);
+ wiiuse_read_data(wm,buf,WM_EXP_MEM_CALIBR,EXP_HANDSHAKE_LEN,wiiuse_handshake_expansion);
+ break;
+ case 3:
+ if(!data || !len) return;
+ id = BIG_ENDIAN_LONG(*(int*)(&data[220]));
+
+ switch(id) {
+ case EXP_ID_CODE_NUNCHUK:
+ if(!nunchuk_handshake(wm,&wm->exp.nunchuk,data,len)) return;
+ break;
+ case EXP_ID_CODE_CLASSIC_CONTROLLER:
+ case EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING:
+ case EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING2:
+ case EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING3:
+ case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC:
+ case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC2:
+ case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC3:
+ case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC4:
+ case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC5:
+ if(!classic_ctrl_handshake(wm,&wm->exp.classic,data,len)) return;
+ break;
+ default:
+ if(!classic_ctrl_handshake(wm,&wm->exp.classic,data,len)) return;
+ /*WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_EXP_HANDSHAKE);
+ WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_EXP_FAILED);
+ __lwp_wkspace_free(data);
+ wiiuse_status(wm,NULL);
+ return;*/
+ }
+ __lwp_wkspace_free(data);
+
+ WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_EXP_HANDSHAKE);
+ WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_EXP);
+ wiiuse_set_ir_mode(wm);
+ wiiuse_status(wm,NULL);
+ break;
+ }
+}
+
+void wiiuse_disable_expansion(struct wiimote_t *wm)
+{
+ if(!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) return;
+
+ /* tell the associated module the expansion was removed */
+ switch(wm->exp.type) {
+ case EXP_NUNCHUK:
+ nunchuk_disconnected(&wm->exp.nunchuk);
+ wm->event = WIIUSE_NUNCHUK_REMOVED;
+ break;
+ case EXP_CLASSIC:
+ classic_ctrl_disconnected(&wm->exp.classic);
+ wm->event = WIIUSE_CLASSIC_CTRL_REMOVED;
+ break;
+ case EXP_MOTION_PLUS:
+ motion_plus_disconnected(&wm->exp.mp);
+ wm->event = WIIUSE_MOTION_PLUS_REMOVED;
+ break;
+
+ default:
+ break;
+ }
+
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP);
+ wm->exp.type = EXP_NONE;
+
+ wiiuse_set_ir_mode(wm);
+ wiiuse_status(wm,NULL);
+}
diff --git a/wii/wiiuse/io.h b/wii/wiiuse/io.h
new file mode 100644
index 0000000000..d7a5326a82
--- /dev/null
+++ b/wii/wiiuse/io.h
@@ -0,0 +1,23 @@
+#ifndef __IO_H__
+#define __IO_H__
+
+#include "wiiuse_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void wiiuse_handshake(struct wiimote_t* wm,ubyte *data,uword len);
+void wiiuse_handshake_expansion_start(struct wiimote_t *wm);
+void wiiuse_handshake_expansion(struct wiimote_t *wm,ubyte *data,uword len);
+void wiiuse_disable_expansion(struct wiimote_t *wm);
+
+int wiiuse_io_read(struct wiimote_t* wm);
+int wiiuse_io_write(struct wiimote_t* wm, ubyte* buf, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/wii/wiiuse/io_wii.c b/wii/wiiuse/io_wii.c
new file mode 100644
index 0000000000..63a693395f
--- /dev/null
+++ b/wii/wiiuse/io_wii.c
@@ -0,0 +1,176 @@
+#ifdef GEKKO
+
+#include
+#include
+#include
+#include
+
+#include "definitions.h"
+#include "wiiuse_internal.h"
+#include "events.h"
+#include "io.h"
+#include "lwp_wkspace.h"
+
+#define MAX_COMMANDS 0x100
+#define MAX_WIIMOTES 5
+
+static vu32* const _ipcReg = (u32*)0xCD000000;
+static u8 *__queue_buffer[MAX_WIIMOTES] = { 0, 0, 0, 0, 0 };
+
+extern void parse_event(struct wiimote_t *wm);
+extern void idle_cycle(struct wiimote_t* wm);
+extern void hexdump(void *d, int len);
+
+static __inline__ u32 ACR_ReadReg(u32 reg)
+{
+ return _ipcReg[reg>>2];
+}
+
+static __inline__ void ACR_WriteReg(u32 reg,u32 val)
+{
+ _ipcReg[reg>>2] = val;
+}
+
+static s32 __wiiuse_disconnected(void *arg,struct bte_pcb *pcb,u8 err)
+{
+ struct wiimote_listen_t *wml = (struct wiimote_listen_t*)arg;
+ struct wiimote_t *wm = wml->wm;
+
+ if(!wm) return ERR_OK;
+
+ //printf("wiimote disconnected\n");
+ WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_IR|WIIMOTE_STATE_IR_INIT));
+ WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_SPEAKER|WIIMOTE_STATE_SPEAKER_INIT));
+ WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_EXP|WIIMOTE_STATE_EXP_HANDSHAKE|WIIMOTE_STATE_EXP_FAILED));
+ WIIMOTE_DISABLE_STATE(wm,(WIIMOTE_STATE_CONNECTED|WIIMOTE_STATE_HANDSHAKE|WIIMOTE_STATE_HANDSHAKE_COMPLETE));
+
+ while(wm->cmd_head) {
+ __lwp_queue_append(&wm->cmdq,&wm->cmd_head->node);
+ wm->cmd_head = wm->cmd_head->next;
+ }
+ wm->cmd_tail = NULL;
+
+ if(wm->event_cb) wm->event_cb(wm,WIIUSE_DISCONNECT);
+
+ wml->wm = NULL;
+ return ERR_OK;
+}
+
+static s32 __wiiuse_receive(void *arg,void *buffer,u16 len)
+{
+ struct wiimote_listen_t *wml = (struct wiimote_listen_t*)arg;
+ struct wiimote_t *wm = wml->wm;
+
+ if(!wm || !buffer || len==0) return ERR_OK;
+
+ //printf("__wiiuse_receive[%02x]\n",*(char*)buffer);
+ wm->event = WIIUSE_NONE;
+
+ memcpy(wm->event_buf,buffer,len);
+ memset(&(wm->event_buf[len]),0,(MAX_PAYLOAD - len));
+ parse_event(wm);
+
+ if(wm->event!=WIIUSE_NONE) {
+ if(wm->event_cb) wm->event_cb(wm,wm->event);
+ }
+
+ return ERR_OK;
+}
+
+static s32 __wiiuse_connected(void *arg,struct bte_pcb *pcb,u8 err)
+{
+ struct wiimote_listen_t *wml = (struct wiimote_listen_t*)arg;
+ struct wiimote_t *wm;
+
+ wm = wml->assign_cb(&wml->bdaddr);
+
+ if(!wm) {
+ bte_disconnect(wml->sock);
+ return ERR_OK;
+ }
+
+ wml->wm = wm;
+
+ wm->sock = wml->sock;
+ wm->bdaddr = wml->bdaddr;
+
+ //printf("__wiiuse_connected()\n");
+ WIIMOTE_ENABLE_STATE(wm,(WIIMOTE_STATE_CONNECTED|WIIMOTE_STATE_HANDSHAKE));
+
+ wm->handshake_state = 0;
+ wiiuse_handshake(wm,NULL,0);
+
+ return ERR_OK;
+}
+
+void __wiiuse_sensorbar_enable(int enable)
+{
+ u32 val;
+ u32 level;
+
+ level = IRQ_Disable();
+ val = (ACR_ReadReg(0xc0)&~0x100);
+ if(enable) val |= 0x100;
+ ACR_WriteReg(0xc0,val);
+ IRQ_Restore(level);
+}
+
+int wiiuse_register(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr))
+{
+ s32 err;
+
+ if(!wml || !bdaddr || !assign_cb) return 0;
+
+ wml->wm = NULL;
+ wml->bdaddr = *bdaddr;
+ wml->sock = bte_new();
+ wml->assign_cb = assign_cb;
+ if(wml->sock==NULL) return 0;
+
+ bte_arg(wml->sock,wml);
+ bte_received(wml->sock,__wiiuse_receive);
+ bte_disconnected(wml->sock,__wiiuse_disconnected);
+
+ err = bte_registerdeviceasync(wml->sock,bdaddr,__wiiuse_connected);
+ if(err==ERR_OK) return 1;
+
+ return 0;
+}
+
+void wiiuse_disconnect(struct wiimote_t *wm)
+{
+ if(wm==NULL || wm->sock==NULL) return;
+
+ WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_CONNECTED);
+ bte_disconnect(wm->sock);
+}
+
+void wiiuse_sensorbar_enable(int enable)
+{
+ __wiiuse_sensorbar_enable(enable);
+}
+
+
+void wiiuse_init_cmd_queue(struct wiimote_t *wm)
+{
+ u32 size;
+
+ if (!__queue_buffer[wm->unid]) {
+ size = (MAX_COMMANDS*sizeof(struct cmd_blk_t));
+ __queue_buffer[wm->unid] = __lwp_wkspace_allocate(size);
+ if(!__queue_buffer[wm->unid]) return;
+ }
+
+ __lwp_queue_initialize(&wm->cmdq,__queue_buffer[wm->unid],MAX_COMMANDS,sizeof(struct cmd_blk_t));
+}
+
+int wiiuse_io_write(struct wiimote_t *wm,ubyte *buf,int len)
+{
+ if(wm->sock) {
+ return bte_senddata(wm->sock,buf,len);
+ }
+
+ return ERR_CONN;
+}
+
+#endif
diff --git a/wii/wiiuse/ir.c b/wii/wiiuse/ir.c
new file mode 100644
index 0000000000..c369778fd7
--- /dev/null
+++ b/wii/wiiuse/ir.c
@@ -0,0 +1,834 @@
+#include
+#include
+#include
+
+#ifndef WIN32
+ #include
+#endif
+#ifdef GEKKO
+ #include
+#endif
+#include "definitions.h"
+#include "wiiuse_internal.h"
+#include "ir.h"
+
+static int ir_correct_for_bounds(float* x, float* y, enum aspect_t aspect, int offset_x, int offset_y);
+static void ir_convert_to_vres(float* x, float* y, enum aspect_t aspect, unsigned int vx, unsigned int vy);
+
+/**
+ * @brief Get the IR sensitivity settings.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ * @param block1 [out] Pointer to where block1 will be set.
+ * @param block2 [out] Pointer to where block2 will be set.
+ *
+ * @return Returns the sensitivity level.
+ */
+static int get_ir_sens(struct wiimote_t* wm, char** block1, char** block2) {
+ if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL1)) {
+ *block1 = WM_IR_BLOCK1_LEVEL1;
+ *block2 = WM_IR_BLOCK2_LEVEL1;
+ return 1;
+ } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL2)) {
+ *block1 = WM_IR_BLOCK1_LEVEL2;
+ *block2 = WM_IR_BLOCK2_LEVEL2;
+ return 2;
+ } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL3)) {
+ *block1 = WM_IR_BLOCK1_LEVEL3;
+ *block2 = WM_IR_BLOCK2_LEVEL3;
+ return 3;
+ } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL4)) {
+ *block1 = WM_IR_BLOCK1_LEVEL4;
+ *block2 = WM_IR_BLOCK2_LEVEL4;
+ return 4;
+ } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL5)) {
+ *block1 = WM_IR_BLOCK1_LEVEL5;
+ *block2 = WM_IR_BLOCK2_LEVEL5;
+ return 5;
+ }
+
+ *block1 = NULL;
+ *block2 = NULL;
+ return 0;
+}
+
+static void rotate_dots(struct fdot_t* in, struct fdot_t *out, int count, float ang) {
+ float s, c;
+ int i;
+
+ if (ang == 0) {
+ for (i = 0; i < count; ++i) {
+ out[i].x = in[i].x;
+ out[i].y = in[i].y;
+ }
+ return;
+ }
+
+ s = sin(DEGREE_TO_RAD(ang));
+ c = cos(DEGREE_TO_RAD(ang));
+
+ /*
+ * [ cos(theta) -sin(theta) ][ ir->rx ]
+ * [ sin(theta) cos(theta) ][ ir->ry ]
+ */
+
+ for (i = 0; i < count; ++i) {
+ out[i].x = (c * in[i].x) + (-s * in[i].y);
+ out[i].y = (s * in[i].x) + (c * in[i].y);
+ }
+}
+
+/**
+ * @brief Correct for the IR bounding box.
+ *
+ * @param x [out] The current X, it will be updated if valid.
+ * @param y [out] The current Y, it will be updated if valid.
+ * @param aspect Aspect ratio of the screen.
+ * @param offset_x The X offset of the bounding box.
+ * @param offset_y The Y offset of the bounding box.
+ *
+ * @return Returns 1 if the point is valid and was updated.
+ *
+ * Nintendo was smart with this bit. They sacrifice a little
+ * precision for a big increase in usability.
+ */
+static int ir_correct_for_bounds(float* x, float* y, enum aspect_t aspect, int offset_x, int offset_y) {
+ float x0, y0;
+ int xs, ys;
+
+ if (aspect == WIIUSE_ASPECT_16_9) {
+ xs = WM_ASPECT_16_9_X;
+ ys = WM_ASPECT_16_9_Y;
+ } else {
+ xs = WM_ASPECT_4_3_X;
+ ys = WM_ASPECT_4_3_Y;
+ }
+
+ x0 = ((1024 - xs) / 2) + offset_x;
+ y0 = ((768 - ys) / 2) + offset_y;
+
+ if ((*x >= x0)
+ && (*x <= (x0 + xs))
+ && (*y >= y0)
+ && (*y <= (y0 + ys)))
+ {
+ *x -= offset_x;
+ *y -= offset_y;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * @brief Interpolate the point to the user defined virtual screen resolution.
+ */
+static void ir_convert_to_vres(float* x, float* y, enum aspect_t aspect, unsigned int vx, unsigned int vy) {
+ int xs, ys;
+
+ if (aspect == WIIUSE_ASPECT_16_9) {
+ xs = WM_ASPECT_16_9_X;
+ ys = WM_ASPECT_16_9_Y;
+ } else {
+ xs = WM_ASPECT_4_3_X;
+ ys = WM_ASPECT_4_3_Y;
+ }
+
+ *x -= ((1024-xs)/2);
+ *y -= ((768-ys)/2);
+
+ *x = (*x / (float)xs) * vx;
+ *y = (*y / (float)ys) * vy;
+}
+
+void wiiuse_set_ir_mode(struct wiimote_t *wm)
+{
+ ubyte buf = 0x00;
+
+ if(!wm) return;
+ if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) return;
+
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP)) buf = WM_IR_TYPE_BASIC;
+ else buf = WM_IR_TYPE_EXTENDED;
+ wiiuse_write_data(wm,WM_REG_IR_MODENUM, &buf, 1, NULL);
+}
+
+void wiiuse_set_ir(struct wiimote_t *wm,int status)
+{
+ ubyte buf = 0x00;
+ int ir_level = 0;
+ char* block1 = NULL;
+ char* block2 = NULL;
+
+ if(!wm) return;
+
+ /*
+ * Wait for the handshake to finish first.
+ * When it handshake finishes and sees that
+ * IR is enabled, it will call this function
+ * again to actually enable IR.
+ */
+ if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) {
+ WIIUSE_DEBUG("Tried to enable IR, will wait until handshake finishes.\n");
+ if(status)
+ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_INIT);
+ else
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR_INIT);
+ return;
+ }
+
+ /*
+ * Check to make sure a sensitivity setting is selected.
+ */
+ ir_level = get_ir_sens(wm, &block1, &block2);
+ if (!ir_level) {
+ WIIUSE_ERROR("No IR sensitivity setting selected.");
+ return;
+ }
+
+ if (status) {
+ /* if already enabled then stop */
+ if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
+ wiiuse_status(wm,NULL);
+ return;
+ }
+ } else {
+ /* if already disabled then stop */
+ if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) {
+ wiiuse_status(wm,NULL);
+ return;
+ }
+ }
+
+ buf = (status ? 0x04 : 0x00);
+ wiiuse_sendcmd(wm,WM_CMD_IR,&buf,1,NULL);
+ wiiuse_sendcmd(wm,WM_CMD_IR_2,&buf,1,NULL);
+
+ if (!status) {
+ WIIUSE_DEBUG("Disabled IR cameras for wiimote id %i.", wm->unid);
+ wiiuse_status(wm,NULL);
+ return;
+ }
+
+ /* enable IR, set sensitivity */
+ buf = 0x08;
+ wiiuse_write_data(wm,WM_REG_IR,&buf,1,NULL);
+
+ wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (ubyte*)block1, 9, NULL);
+ wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (ubyte*)block2, 2, NULL);
+
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP)) buf = WM_IR_TYPE_BASIC;
+ else buf = WM_IR_TYPE_EXTENDED;
+ wiiuse_write_data(wm,WM_REG_IR_MODENUM, &buf, 1, NULL);
+
+ wiiuse_status(wm,NULL);
+ return;
+}
+
+/**
+ * @brief Set the virtual screen resolution for IR tracking.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ * @param status 1 to enable, 0 to disable.
+ */
+void wiiuse_set_ir_vres(struct wiimote_t* wm, unsigned int x, unsigned int y) {
+ if (!wm) return;
+
+ wm->ir.vres[0] = (x-1);
+ wm->ir.vres[1] = (y-1);
+}
+
+/**
+ * @brief Set the XY position for the IR cursor.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ */
+void wiiuse_set_ir_position(struct wiimote_t* wm, enum ir_position_t pos) {
+ if (!wm) return;
+
+ wm->ir.pos = pos;
+
+ switch (pos) {
+
+ case WIIUSE_IR_ABOVE:
+ wm->ir.offset[0] = 0;
+
+ if (wm->ir.aspect == WIIUSE_ASPECT_16_9)
+ wm->ir.offset[1] = WM_ASPECT_16_9_Y/2 - 70;
+ else if (wm->ir.aspect == WIIUSE_ASPECT_4_3)
+ wm->ir.offset[1] = WM_ASPECT_4_3_Y/2 - 100;
+
+ return;
+
+ case WIIUSE_IR_BELOW:
+ wm->ir.offset[0] = 0;
+
+ if (wm->ir.aspect == WIIUSE_ASPECT_16_9)
+ wm->ir.offset[1] = -WM_ASPECT_16_9_Y/2 + 70;
+ else if (wm->ir.aspect == WIIUSE_ASPECT_4_3)
+ wm->ir.offset[1] = -WM_ASPECT_4_3_Y/2 + 100;
+
+ return;
+
+ default:
+ return;
+ };
+}
+
+/**
+ * @brief Set the aspect ratio of the TV/monitor.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ * @param aspect Either WIIUSE_ASPECT_16_9 or WIIUSE_ASPECT_4_3
+ */
+void wiiuse_set_aspect_ratio(struct wiimote_t* wm, enum aspect_t aspect) {
+ if (!wm) return;
+
+ wm->ir.aspect = aspect;
+
+ if (aspect == WIIUSE_ASPECT_4_3) {
+ wm->ir.vres[0] = WM_ASPECT_4_3_X;
+ wm->ir.vres[1] = WM_ASPECT_4_3_Y;
+ } else {
+ wm->ir.vres[0] = WM_ASPECT_16_9_X;
+ wm->ir.vres[1] = WM_ASPECT_16_9_Y;
+ }
+
+ /* reset the position offsets */
+ wiiuse_set_ir_position(wm, wm->ir.pos);
+}
+
+
+/**
+ * @brief Set the IR sensitivity.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ * @param level 1-5, same as Wii system sensitivity setting.
+ *
+ * If the level is < 1, then level will be set to 1.
+ * If the level is > 5, then level will be set to 5.
+ */
+void wiiuse_set_ir_sensitivity(struct wiimote_t* wm, int level) {
+ char* block1 = NULL;
+ char* block2 = NULL;
+
+ if (!wm) return;
+
+ if (level > 5) level = 5;
+ if (level < 1) level = 1;
+
+ WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_IR_SENS_LVL1 |
+ WIIMOTE_STATE_IR_SENS_LVL2 |
+ WIIMOTE_STATE_IR_SENS_LVL3 |
+ WIIMOTE_STATE_IR_SENS_LVL4 |
+ WIIMOTE_STATE_IR_SENS_LVL5));
+
+ switch (level) {
+ case 1:
+ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL1);
+ break;
+ case 2:
+ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL2);
+ break;
+ case 3:
+ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL3);
+ break;
+ case 4:
+ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL4);
+ break;
+ case 5:
+ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL5);
+ break;
+ default:
+ return;
+ }
+
+ if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR)) return;
+
+ /* set the new sensitivity */
+ get_ir_sens(wm, &block1, &block2);
+
+ wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (ubyte*)block1, 9,NULL);
+ wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (ubyte*)block2, 2,NULL);
+
+ WIIUSE_DEBUG("Set IR sensitivity to level %i (unid %i)", level, wm->unid);
+}
+
+
+/**
+ * @brief Calculate the data from the IR spots. Basic IR mode.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ * @param data Data returned by the wiimote for the IR spots.
+ */
+void calculate_basic_ir(struct wiimote_t* wm, ubyte* data) {
+ struct ir_dot_t* dot = wm->ir.dot;
+ int i;
+
+ dot[0].rx = 1023 - (data[0] | ((data[2] & 0x30) << 4));
+ dot[0].ry = data[1] | ((data[2] & 0xC0) << 2);
+
+ dot[1].rx = 1023 - (data[3] | ((data[2] & 0x03) << 8));
+ dot[1].ry = data[4] | ((data[2] & 0x0C) << 6);
+
+ dot[2].rx = 1023 - (data[5] | ((data[7] & 0x30) << 4));
+ dot[2].ry = data[6] | ((data[7] & 0xC0) << 2);
+
+ dot[3].rx = 1023 - (data[8] | ((data[7] & 0x03) << 8));
+ dot[3].ry = data[9] | ((data[7] & 0x0C) << 6);
+
+ /* set each IR spot to visible if spot is in range */
+ for (i = 0; i < 4; ++i) {
+ dot[i].rx = BIG_ENDIAN_SHORT(dot[i].rx);
+ dot[i].ry = BIG_ENDIAN_SHORT(dot[i].ry);
+
+ if (dot[i].ry == 1023)
+ dot[i].visible = 0;
+ else {
+ dot[i].visible = 1;
+ dot[i].size = 0; /* since we don't know the size, set it as 0 */
+ }
+ }
+#ifndef GEKKO
+ interpret_ir_data(&wm->ir,&wm->orient,WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC));
+#endif
+}
+
+/**
+ * @brief Calculate the data from the IR spots. Extended IR mode.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ * @param data Data returned by the wiimote for the IR spots.
+ */
+void calculate_extended_ir(struct wiimote_t* wm, ubyte* data) {
+ struct ir_dot_t* dot = wm->ir.dot;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ dot[i].rx = 1023 - (data[3*i] | ((data[(3*i)+2] & 0x30) << 4));
+ dot[i].ry = data[(3*i)+1] | ((data[(3*i)+2] & 0xC0) << 2);
+
+ dot[i].size = data[(3*i)+2];
+
+ dot[i].rx = BIG_ENDIAN_SHORT(dot[i].rx);
+ dot[i].ry = BIG_ENDIAN_SHORT(dot[i].ry);
+
+ dot[i].size = dot[i].size&0x0f;
+
+ /* if in range set to visible */
+ if (dot[i].ry == 1023)
+ dot[i].visible = 0;
+ else
+ dot[i].visible = 1;
+ }
+#ifndef GEKKO
+ interpret_ir_data(&wm->ir,&wm->orient,WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC));
+#endif
+}
+
+enum {
+ IR_STATE_DEAD = 0,
+ IR_STATE_GOOD,
+ IR_STATE_SINGLE,
+ IR_STATE_LOST,
+};
+
+// half-height of the IR sensor if half-width is 1
+#define HEIGHT (384.0f / 512.0f)
+// maximum sensor bar slope (tan(35 degrees))
+#define MAX_SB_SLOPE 0.7f
+// minimum sensor bar width in view, relative to half of the IR sensor area
+#define MIN_SB_WIDTH 0.1f
+// reject "sensor bars" that happen to have a dot towards the middle
+#define SB_MIDDOT_REJECT 0.05f
+
+// physical dimensions
+// cm center to center of emitters
+#define SB_WIDTH 19.5f
+// half-width in cm of emitters
+#define SB_DOT_WIDTH 2.25f
+// half-height in cm of emitters (with some tolerance)
+#define SB_DOT_HEIGHT 1.0f
+
+#define SB_DOT_WIDTH_RATIO (SB_DOT_WIDTH / SB_WIDTH)
+#define SB_DOT_HEIGHT_RATIO (SB_DOT_HEIGHT / SB_WIDTH)
+
+// dots further out than these coords are allowed to not be picked up
+// otherwise assume something's wrong
+//#define SB_OFF_SCREEN_X 0.8f
+//#define SB_OFF_SCREEN_Y (0.8f * HEIGHT)
+
+// disable, may be doing more harm than good due to sensor pickup glitches
+#define SB_OFF_SCREEN_X 0.0f
+#define SB_OFF_SCREEN_Y 0.0f
+
+// if a point is closer than this to one of the previous SB points
+// when it reappears, consider it the same instead of trying to guess
+// which one of the two it is
+#define SB_SINGLE_NOGUESS_DISTANCE (100.0 * 100.0)
+
+// width of the sensor bar in pixels at one meter from the Wiimote
+#define SB_Z_COEFFICIENT 256.0f
+
+// distance in meters from the center of the FOV to the left or right edge,
+// when the wiimote is at one meter
+#define WIIMOTE_FOV_COEFFICIENT 0.39f
+
+#define SQUARED(x) ((x)*(x))
+#define WMAX(x,y) ((x>y)?(x):(y))
+#define WMIN(x,y) ((xroll);
+
+ /* count visible dots and populate dots structure */
+ /* dots[] is in -1..1 units for width */
+ ir->num_dots = 0;
+ for (i = 0; i < 4; i++) {
+ if (ir->dot[i].visible) {
+ dots[ir->num_dots].x = (ir->dot[i].rx - 512.0f) / 512.0f;
+ dots[ir->num_dots].y = (ir->dot[i].ry - 384.0f) / 512.0f;
+ WIIUSE_DEBUG("IR: dot %d at (%d,%d) (%.03f,%.03f)\n",ir->num_dots,ir->dot[i].rx,ir->dot[i].ry,dots[ir->num_dots].x,dots[ir->num_dots].y);
+ ir->num_dots++;
+ }
+ }
+
+ WIIUSE_DEBUG("IR: found %d dots\n",ir->num_dots);
+
+ // nothing to track
+ if(ir->num_dots == 0) {
+ if(ir->state != IR_STATE_DEAD)
+ ir->state = IR_STATE_LOST;
+ ir->ax = 0;
+ ir->ay = 0;
+ ir->distance = 0.0f;
+ ir->raw_valid = 0;
+ return;
+ }
+
+ /* ==== Find the Sensor Bar ==== */
+
+ // first rotate according to accelerometer orientation
+ rotate_dots(dots, acc_dots, ir->num_dots, orient->roll);
+ if(ir->num_dots > 1) {
+ WIIUSE_DEBUG("IR: locating sensor bar candidates\n");
+
+ // iterate through all dot pairs
+ for(first=0; first < (ir->num_dots-1); first++) {
+ for(second=(first+1); second < ir->num_dots; second++) {
+ WIIUSE_DEBUG("IR: trying dots %d and %d\n",first,second);
+ // order the dots leftmost first into cand
+ // storing both the raw dots and the accel-rotated dots
+ if(acc_dots[first].x > acc_dots[second].x) {
+ cand.dots[0] = dots[second];
+ cand.dots[1] = dots[first];
+ cand.acc_dots[0] = acc_dots[second];
+ cand.acc_dots[1] = acc_dots[first];
+ } else {
+ cand.dots[0] = dots[first];
+ cand.dots[1] = dots[second];
+ cand.acc_dots[0] = acc_dots[first];
+ cand.acc_dots[1] = acc_dots[second];
+ }
+ difference.x = cand.acc_dots[1].x - cand.acc_dots[0].x;
+ difference.y = cand.acc_dots[1].y - cand.acc_dots[0].y;
+
+ // check angle
+ if(fabsf(difference.y / difference.x) > MAX_SB_SLOPE)
+ continue;
+ WIIUSE_DEBUG("IR: passed angle check\n");
+ // rotate to the true sensor bar angle
+ cand.off_angle = -RAD_TO_DEGREE(atan2(difference.y, difference.x));
+ cand.angle = cand.off_angle + orient->roll;
+ rotate_dots(cand.dots, cand.rot_dots, 2, cand.angle);
+ WIIUSE_DEBUG("IR: off_angle: %.02f, angle: %.02f\n", cand.off_angle, cand.angle);
+ // recalculate x distance - y should be zero now, so ignore it
+ difference.x = cand.rot_dots[1].x - cand.rot_dots[0].x;
+
+ // check distance
+ if(difference.x < MIN_SB_WIDTH)
+ continue;
+ // middle dot check. If there's another source somewhere in the
+ // middle of this candidate, then this can't be a sensor bar
+
+ for(i=0; inum_dots; i++) {
+ float wadj, hadj;
+ struct fdot_t tdot;
+ if(i==first || i==second) continue;
+ hadj = SB_DOT_HEIGHT_RATIO * difference.x;
+ wadj = SB_DOT_WIDTH_RATIO * difference.x;
+ rotate_dots(&dots[i], &tdot, 1, cand.angle);
+ if( ((cand.rot_dots[0].x + wadj) < tdot.x) &&
+ ((cand.rot_dots[1].x - wadj) > tdot.x) &&
+ ((cand.rot_dots[0].y + hadj) > tdot.y) &&
+ ((cand.rot_dots[0].y - hadj) < tdot.y))
+ break;
+ }
+ // failed middle dot check
+ if(i < ir->num_dots) continue;
+ WIIUSE_DEBUG("IR: passed middle dot check\n");
+
+ cand.score = 1 / (cand.rot_dots[1].x - cand.rot_dots[0].x);
+
+ // we have a candidate, store it
+ WIIUSE_DEBUG("IR: new candidate %d\n",num_candidates);
+ candidates[num_candidates++] = cand;
+ }
+ }
+ }
+
+ if(num_candidates == 0) {
+ int closest = -1;
+ int closest_to = 0;
+ float best = 999.0f;
+ float d;
+ float dx[2];
+ struct sb_t sbx[2];
+ // no sensor bar candidates, try to work with a lone dot
+ WIIUSE_DEBUG("IR: no candidates\n");
+ switch(ir->state) {
+ case IR_STATE_DEAD:
+ WIIUSE_DEBUG("IR: we're dead\n");
+ // we've never seen a sensor bar before, so we're screwed
+ ir->ax = 0.0f;
+ ir->ay = 0.0f;
+ ir->distance = 0.0f;
+ ir->raw_valid = 0;
+ return;
+ case IR_STATE_GOOD:
+ case IR_STATE_SINGLE:
+ case IR_STATE_LOST:
+ WIIUSE_DEBUG("IR: trying to keep track of single dot\n");
+ // try to find the dot closest to the previous sensor bar position
+ for(i=0; inum_dots; i++) {
+ WIIUSE_DEBUG("IR: checking dot %d (%.02f, %.02f)\n",i, acc_dots[i].x,acc_dots[i].y);
+ for(j=0; j<2; j++) {
+ WIIUSE_DEBUG(" to dot %d (%.02f, %.02f)\n",j, ir->sensorbar.acc_dots[j].x,ir->sensorbar.acc_dots[j].y);
+ d = SQUARED(acc_dots[i].x - ir->sensorbar.acc_dots[j].x);
+ d += SQUARED(acc_dots[i].y - ir->sensorbar.acc_dots[j].y);
+ if(d < best) {
+ best = d;
+ closest_to = j;
+ closest = i;
+ }
+ }
+ }
+ WIIUSE_DEBUG("IR: closest dot is %d to %d\n",closest,closest_to);
+ if(ir->state != IR_STATE_LOST || best < SB_SINGLE_NOGUESS_DISTANCE) {
+ // now work out where the other dot would be, in the acc frame
+ sb.acc_dots[closest_to] = acc_dots[closest];
+ sb.acc_dots[closest_to^1].x = ir->sensorbar.acc_dots[closest_to^1].x - ir->sensorbar.acc_dots[closest_to].x + acc_dots[closest].x;
+ sb.acc_dots[closest_to^1].y = ir->sensorbar.acc_dots[closest_to^1].y - ir->sensorbar.acc_dots[closest_to].y + acc_dots[closest].y;
+ // get the raw frame
+ rotate_dots(sb.acc_dots, sb.dots, 2, -orient->roll);
+ if((fabsf(sb.dots[closest_to^1].x) < SB_OFF_SCREEN_X) && (fabsf(sb.dots[closest_to^1].y) < SB_OFF_SCREEN_Y)) {
+ // this dot should be visible but isn't, since the candidate section failed.
+ // fall through and try to pick out the sensor bar without previous information
+ WIIUSE_DEBUG("IR: dot falls on screen, falling through\n");
+ } else {
+ // calculate the rotated dots frame
+ // angle tends to drift, so recalculate
+ sb.off_angle = -RAD_TO_DEGREE(atan2(sb.acc_dots[1].y - sb.acc_dots[0].y, sb.acc_dots[1].x - sb.acc_dots[0].x));
+ sb.angle = ir->sensorbar.off_angle + orient->roll;
+ rotate_dots(sb.acc_dots, sb.rot_dots, 2, ir->sensorbar.off_angle);
+ WIIUSE_DEBUG("IR: kept track of single dot\n");
+ break;
+ }
+ } else {
+ WIIUSE_DEBUG("IR: lost the dot and new one is too far away\n");
+ }
+ // try to find the dot closest to the sensor edge
+ WIIUSE_DEBUG("IR: trying to find best dot\n");
+ for(i=0; inum_dots; i++) {
+ d = WMIN(1.0f - fabsf(dots[i].x), HEIGHT - fabsf(dots[i].y));
+ if(d < best) {
+ best = d;
+ closest = i;
+ }
+ }
+ WIIUSE_DEBUG("IR: best dot: %d\n",closest);
+ // now try it as both places in the sensor bar
+ // and pick the one that places the other dot furthest off-screen
+ for(i=0; i<2; i++) {
+ sbx[i].acc_dots[i] = acc_dots[closest];
+ sbx[i].acc_dots[i^1].x = ir->sensorbar.acc_dots[i^1].x - ir->sensorbar.acc_dots[i].x + acc_dots[closest].x;
+ sbx[i].acc_dots[i^1].y = ir->sensorbar.acc_dots[i^1].y - ir->sensorbar.acc_dots[i].y + acc_dots[closest].y;
+ rotate_dots(sbx[i].acc_dots, sbx[i].dots, 2, -orient->roll);
+ dx[i] = WMAX(fabsf(sbx[i].dots[i^1].x),fabsf(sbx[i].dots[i^1].y / HEIGHT));
+ }
+ if(dx[0] > dx[1]) {
+ WIIUSE_DEBUG("IR: dot is LEFT: %.02f > %.02f\n",dx[0],dx[1]);
+ sb = sbx[0];
+ } else {
+ WIIUSE_DEBUG("IR: dot is RIGHT: %.02f < %.02f\n",dx[0],dx[1]);
+ sb = sbx[1];
+ }
+ // angle tends to drift, so recalculate
+ sb.off_angle = -RAD_TO_DEGREE(atan2(sb.acc_dots[1].y - sb.acc_dots[0].y, sb.acc_dots[1].x - sb.acc_dots[0].x));
+ sb.angle = ir->sensorbar.off_angle + orient->roll;
+ rotate_dots(sb.acc_dots, sb.rot_dots, 2, ir->sensorbar.off_angle);
+ WIIUSE_DEBUG("IR: found new dot to track\n");
+ break;
+ }
+ sb.score = 0;
+ ir->state = IR_STATE_SINGLE;
+ } else {
+ int bestidx = 0;
+ float best = 0.0f;
+ WIIUSE_DEBUG("IR: finding best candidate\n");
+ // look for the best candidate
+ // for now, the formula is simple: pick the one with the smallest distance
+ for(i=0; i best) {
+ bestidx = i;
+ best = candidates[i].score;
+ }
+ }
+ WIIUSE_DEBUG("IR: best candidate: %d\n",bestidx);
+ sb = candidates[bestidx];
+ ir->state = IR_STATE_GOOD;
+ }
+
+ ir->raw_valid = 1;
+ ir->ax = ((sb.rot_dots[0].x + sb.rot_dots[1].x) / 2) * 512.0 + 512.0;
+ ir->ay = ((sb.rot_dots[0].y + sb.rot_dots[1].y) / 2) * 512.0 + 384.0;
+ ir->sensorbar = sb;
+ ir->distance = (sb.rot_dots[1].x - sb.rot_dots[0].x) * 512.0;
+
+}
+
+#define SMOOTH_IR_RADIUS 8.0f
+#define SMOOTH_IR_SPEED 0.25f
+#define SMOOTH_IR_DEADZONE 2.5f
+
+/**
+ * @brief Smooth the IR pointer position
+ *
+ * @param ir Pointer to an ir_t structure.
+ */
+void apply_ir_smoothing(struct ir_t *ir) {
+ f32 dx, dy, d, theta;
+
+ WIIUSE_DEBUG("Smooth: OK (%.02f, %.02f) LAST (%.02f, %.02f) ", ir->ax, ir->ay, ir->sx, ir->sy);
+ dx = ir->ax - ir->sx;
+ dy = ir->ay - ir->sy;
+ d = sqrtf(dx*dx + dy*dy);
+ if (d > SMOOTH_IR_DEADZONE) {
+ if (d < SMOOTH_IR_RADIUS) {
+ WIIUSE_DEBUG("INSIDE\n");
+ ir->sx += dx * SMOOTH_IR_SPEED;
+ ir->sy += dy * SMOOTH_IR_SPEED;
+ } else {
+ WIIUSE_DEBUG("OUTSIDE\n");
+ theta = atan2f(dy, dx);
+ ir->sx = ir->ax - cosf(theta) * SMOOTH_IR_RADIUS;
+ ir->sy = ir->ay - sinf(theta) * SMOOTH_IR_RADIUS;
+ }
+ } else {
+ WIIUSE_DEBUG("DEADZONE\n");
+ }
+}
+
+// max number of errors before cooked data drops out
+#define ERROR_MAX_COUNT 8
+// max number of glitches before cooked data updates
+#define GLITCH_MAX_COUNT 5
+// squared delta over which we consider something a glitch
+#define GLITCH_DIST (150.0f * 150.0f)
+
+/**
+ * @brief Interpret IR data into more user friendly variables.
+ *
+ * @param ir Pointer to an ir_t structure.
+ * @param orient Pointer to an orient_t structure.
+ */
+void interpret_ir_data(struct ir_t* ir, struct orient_t *orient) {
+
+ float x,y;
+ float d;
+
+ find_sensorbar(ir, orient);
+
+ if(ir->raw_valid) {
+ ir->angle = ir->sensorbar.angle;
+ ir->z = SB_Z_COEFFICIENT / ir->distance;
+ orient->yaw = calc_yaw(ir);
+ if(ir->error_cnt >= ERROR_MAX_COUNT) {
+ ir->sx = ir->ax;
+ ir->sy = ir->ay;
+ ir->glitch_cnt = 0;
+ } else {
+ d = SQUARED(ir->ax - ir->sx) + SQUARED(ir->ay - ir->sy);
+ if(d > GLITCH_DIST) {
+ if(ir->glitch_cnt > GLITCH_MAX_COUNT) {
+ apply_ir_smoothing(ir);
+ ir->glitch_cnt = 0;
+ } else {
+ ir->glitch_cnt++;
+ }
+ } else {
+ ir->glitch_cnt = 0;
+ apply_ir_smoothing(ir);
+ }
+ }
+ ir->smooth_valid = 1;
+ ir->error_cnt = 0;
+ } else {
+ if(ir->error_cnt >= ERROR_MAX_COUNT) {
+ ir->smooth_valid = 0;
+ } else {
+ ir->smooth_valid = 1;
+ ir->error_cnt++;
+ }
+ }
+ if(ir->smooth_valid) {
+ x = ir->sx;
+ y = ir->sy;
+ if (ir_correct_for_bounds(&x, &y, ir->aspect, ir->offset[0], ir->offset[1])) {
+ ir_convert_to_vres(&x, &y, ir->aspect, ir->vres[0], ir->vres[1]);
+ ir->x = x;
+ ir->y = y;
+ ir->valid = 1;
+ } else {
+ ir->valid = 0;
+ }
+ } else {
+ ir->valid = 0;
+ }
+}
+
+/**
+ * @brief Calculate yaw given the IR data.
+ *
+ * @param ir IR data structure.
+ */
+float calc_yaw(struct ir_t* ir) {
+ float x;
+
+ x = ir->ax - 512;
+ x *= WIIMOTE_FOV_COEFFICIENT / 512.0;
+
+ return RAD_TO_DEGREE( atanf(x) );
+}
+
diff --git a/wii/wiiuse/ir.h b/wii/wiiuse/ir.h
new file mode 100644
index 0000000000..f90cfc89c5
--- /dev/null
+++ b/wii/wiiuse/ir.h
@@ -0,0 +1,22 @@
+#ifndef __IR_H__
+#define __IR_H__
+
+#include "wiiuse_internal.h"
+
+#define WII_VRES_X 560
+#define WII_VRES_Y 340
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void calculate_basic_ir(struct wiimote_t* wm, ubyte* data);
+void calculate_extended_ir(struct wiimote_t* wm, ubyte* data);
+float calc_yaw(struct ir_t* ir);
+void interpret_ir_data(struct ir_t* ir, struct orient_t *orient);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/wii/wiiuse/license_libogc.txt b/wii/wiiuse/license_libogc.txt
new file mode 100644
index 0000000000..a149fce1ce
--- /dev/null
+++ b/wii/wiiuse/license_libogc.txt
@@ -0,0 +1,641 @@
+This license is valid ONLY for libogc and what this license
+defines as a "covered work" or a "combined work" with libogc.
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an officialder
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ 18. Exceptions
+
+ Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole combination.
+
+ As a special exception, the copyright holders of this library give
+you permission to link this library with independent modules to produce
+an executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from or
+based on this library. If you modify this library, you may extend this
+exception to your version of the library, but you are not obligated to
+do so. If you do not wish to do so, delete this exception statement from
+your version.
+
diff --git a/wii/wiiuse/lwp_priority.inl b/wii/wiiuse/lwp_priority.inl
new file mode 100644
index 0000000000..75c6438386
--- /dev/null
+++ b/wii/wiiuse/lwp_priority.inl
@@ -0,0 +1,49 @@
+#ifndef __LWP_PRIORITY_INL__
+#define __LWP_PRIORITY_INL__
+
+static __inline__ void __lwp_priomap_init(prio_cntrl *theprio,u32 prio)
+{
+ u32 major,minor,mask;
+
+ major = prio/16;
+ minor = prio%16;
+
+ theprio->minor = &_prio_bitmap[major];
+
+ mask = 0x80000000>>major;
+ theprio->ready_major = mask;
+ theprio->block_major = ~mask;
+
+ mask = 0x80000000>>minor;
+ theprio->ready_minor = mask;
+ theprio->block_minor = ~mask;
+#ifdef _LWPPRIO_DEBUG
+ printf("__lwp_priomap_init(%p,%d,%p,%d,%d,%d,%d)\n",theprio,prio,theprio->minor,theprio->ready_major,theprio->ready_minor,theprio->block_major,theprio->block_minor);
+#endif
+}
+
+static __inline__ void __lwp_priomap_addto(prio_cntrl *theprio)
+{
+ *theprio->minor |= theprio->ready_minor;
+ _prio_major_bitmap |= theprio->ready_major;
+}
+
+static __inline__ void __lwp_priomap_removefrom(prio_cntrl *theprio)
+{
+ *theprio->minor &= theprio->block_minor;
+ if(*theprio->minor==0)
+ _prio_major_bitmap &= theprio->block_major;
+}
+
+static __inline__ u32 __lwp_priomap_highest()
+{
+ u32 major,minor;
+ major = cntlzw(_prio_major_bitmap);
+ minor = cntlzw(_prio_bitmap[major]);
+#ifdef _LWPPRIO_DEBUG
+ printf("__lwp_priomap_highest(%d)\n",((major<<4)+minor));
+#endif
+ return ((major<<4)+minor);
+}
+
+#endif
diff --git a/wii/wiiuse/lwp_threads.inl b/wii/wiiuse/lwp_threads.inl
new file mode 100644
index 0000000000..a3b960ff82
--- /dev/null
+++ b/wii/wiiuse/lwp_threads.inl
@@ -0,0 +1,93 @@
+#ifndef __LWP_INL__
+#define __LWP_INL__
+
+static __inline__ u32 __lwp_thread_isexec(lwp_cntrl *thethread)
+{
+ return (thethread==_thr_executing);
+}
+
+static __inline__ u32 __lwp_thread_isheir(lwp_cntrl *thethread)
+{
+ return (thethread==_thr_heir);
+}
+
+static __inline__ void __lwp_thread_calcheir()
+{
+ _thr_heir = (lwp_cntrl*)_lwp_thr_ready[__lwp_priomap_highest()].first;
+#ifdef _LWPTHREADS_DEBUG
+ printf("__lwp_thread_calcheir(%p)\n",_thr_heir);
+#endif
+}
+
+static __inline__ u32 __lwp_thread_isallocatedfp(lwp_cntrl *thethread)
+{
+ return (thethread==_thr_allocated_fp);
+}
+
+static __inline__ void __lwp_thread_deallocatefp()
+{
+ _thr_allocated_fp = NULL;
+}
+
+static __inline__ void __lwp_thread_dispatchinitialize()
+{
+ _thread_dispatch_disable_level = 1;
+}
+
+static __inline__ void __lwp_thread_dispatchenable()
+{
+ if((--_thread_dispatch_disable_level)==0)
+ __thread_dispatch();
+}
+
+static __inline__ void __lwp_thread_dispatchdisable()
+{
+ ++_thread_dispatch_disable_level;
+}
+
+static __inline__ void __lwp_thread_dispatchunnest()
+{
+ --_thread_dispatch_disable_level;
+}
+
+static __inline__ void __lwp_thread_unblock(lwp_cntrl *thethread)
+{
+ __lwp_thread_clearstate(thethread,LWP_STATES_BLOCKED);
+}
+
+static __inline__ void** __lwp_thread_getlibcreent()
+{
+ return __lwp_thr_libc_reent;
+}
+
+static __inline__ void __lwp_thread_setlibcreent(void **libc_reent)
+{
+ __lwp_thr_libc_reent = libc_reent;
+}
+
+static __inline__ bool __lwp_thread_isswitchwant()
+{
+
+ return _context_switch_want;
+}
+
+static __inline__ bool __lwp_thread_isdispatchenabled()
+{
+ return (_thread_dispatch_disable_level==0);
+}
+
+static __inline__ void __lwp_thread_inittimeslice()
+{
+ __lwp_wd_initialize(&_lwp_wd_timeslice,__lwp_thread_tickle_timeslice,LWP_TIMESLICE_TIMER_ID,NULL);
+}
+
+static __inline__ void __lwp_thread_starttimeslice()
+{
+ __lwp_wd_insert_ticks(&_lwp_wd_timeslice,millisecs_to_ticks(1));
+}
+
+static __inline__ void __lwp_thread_stoptimeslice()
+{
+ __lwp_wd_remove_ticks(&_lwp_wd_timeslice);
+}
+#endif
diff --git a/wii/wiiuse/lwp_watchdog.inl b/wii/wiiuse/lwp_watchdog.inl
new file mode 100644
index 0000000000..5216e10996
--- /dev/null
+++ b/wii/wiiuse/lwp_watchdog.inl
@@ -0,0 +1,84 @@
+#ifndef __LWP_WATCHDOG_INL__
+#define __LWP_WATCHDOG_INL__
+
+static __inline__ void __lwp_wd_initialize(wd_cntrl *wd,wd_service_routine routine,u32 id,void *usr_data)
+{
+ wd->state = LWP_WD_INACTIVE;
+ wd->id = id;
+ wd->routine = routine;
+ wd->usr_data = usr_data;
+}
+
+static __inline__ wd_cntrl* __lwp_wd_first(lwp_queue *queue)
+{
+ return (wd_cntrl*)queue->first;
+}
+
+static __inline__ wd_cntrl* __lwp_wd_last(lwp_queue *queue)
+{
+ return (wd_cntrl*)queue->last;
+}
+
+static __inline__ wd_cntrl* __lwp_wd_next(wd_cntrl *wd)
+{
+ return (wd_cntrl*)wd->node.next;
+}
+
+static __inline__ wd_cntrl* __lwp_wd_prev(wd_cntrl *wd)
+{
+ return (wd_cntrl*)wd->node.prev;
+}
+
+static __inline__ void __lwp_wd_activate(wd_cntrl *wd)
+{
+ wd->state = LWP_WD_ACTIVE;
+}
+
+static __inline__ void __lwp_wd_deactivate(wd_cntrl *wd)
+{
+ wd->state = LWP_WD_REMOVE;
+}
+
+static __inline__ u32 __lwp_wd_isactive(wd_cntrl *wd)
+{
+ return (wd->state==LWP_WD_ACTIVE);
+}
+
+static __inline__ u64 __lwp_wd_calc_ticks(const struct timespec *time)
+{
+ u64 ticks;
+
+ ticks = secs_to_ticks(time->tv_sec);
+ ticks += nanosecs_to_ticks(time->tv_nsec);
+
+ return ticks;
+}
+
+static __inline__ void __lwp_wd_tickle_ticks()
+{
+ __lwp_wd_tickle(&_wd_ticks_queue);
+}
+
+static __inline__ void __lwp_wd_insert_ticks(wd_cntrl *wd,s64 interval)
+{
+ wd->start = gettime();
+ wd->fire = (wd->start+LWP_WD_ABS(interval));
+ __lwp_wd_insert(&_wd_ticks_queue,wd);
+}
+
+static __inline__ void __lwp_wd_adjust_ticks(u32 dir,s64 interval)
+{
+ __lwp_wd_adjust(&_wd_ticks_queue,dir,interval);
+}
+
+static __inline__ void __lwp_wd_remove_ticks(wd_cntrl *wd)
+{
+ __lwp_wd_remove(&_wd_ticks_queue,wd);
+}
+
+static __inline__ void __lwp_wd_reset(wd_cntrl *wd)
+{
+ __lwp_wd_remove(&_wd_ticks_queue,wd);
+ __lwp_wd_insert(&_wd_ticks_queue,wd);
+}
+#endif
diff --git a/wii/wiiuse/lwp_wkspace.inl b/wii/wiiuse/lwp_wkspace.inl
new file mode 100644
index 0000000000..4aa8f0faf0
--- /dev/null
+++ b/wii/wiiuse/lwp_wkspace.inl
@@ -0,0 +1,14 @@
+#ifndef __LWP_WKSPACE_INL__
+#define __LWP_WKSPACE_INL__
+
+static __inline__ void* __lwp_wkspace_allocate(u32 size)
+{
+ return __lwp_heap_allocate(&__wkspace_heap,size);
+}
+
+static __inline__ BOOL __lwp_wkspace_free(void *ptr)
+{
+ return __lwp_heap_free(&__wkspace_heap,ptr);
+}
+
+#endif
diff --git a/wii/wiiuse/motion_plus.c b/wii/wiiuse/motion_plus.c
new file mode 100644
index 0000000000..74ad17c98a
--- /dev/null
+++ b/wii/wiiuse/motion_plus.c
@@ -0,0 +1,92 @@
+#include
+#include
+#include
+#include
+
+#ifdef WIN32
+ #include
+#endif
+
+#include "definitions.h"
+#include "wiiuse_internal.h"
+#include "dynamics.h"
+#include "events.h"
+#include "io.h"
+
+void wiiuse_motion_plus_check(struct wiimote_t *wm,ubyte *data,uword len)
+{
+ u32 val;
+ if(data == NULL)
+ {
+ wiiuse_read_data(wm, wm->motion_plus_id, WM_EXP_ID, 6, wiiuse_motion_plus_check);
+ }
+ else
+ {
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP);
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_FAILED);
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
+ val = (data[3] << 16) | (data[2] << 24) | (data[4] << 8) | data[5];
+ if(val == EXP_ID_CODE_MOTION_PLUS)
+ {
+ /* handshake done */
+ wm->event = WIIUSE_MOTION_PLUS_ACTIVATED;
+ wm->exp.type = EXP_MOTION_PLUS;
+
+ WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_EXP);
+ wiiuse_set_ir_mode(wm);
+ }
+ }
+}
+
+static void wiiuse_set_motion_plus_clear2(struct wiimote_t *wm,ubyte *data,uword len)
+{
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP);
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_FAILED);
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
+ wiiuse_set_ir_mode(wm);
+ wiiuse_status(wm,NULL);
+}
+
+static void wiiuse_set_motion_plus_clear1(struct wiimote_t *wm,ubyte *data,uword len)
+{
+ ubyte val = 0x00;
+ wiiuse_write_data(wm,WM_EXP_MEM_ENABLE1,&val,1,wiiuse_set_motion_plus_clear2);
+}
+
+
+void wiiuse_set_motion_plus(struct wiimote_t *wm, int status)
+{
+ ubyte val;
+
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_HANDSHAKE))
+ return;
+
+ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
+ if(status)
+ {
+ val = 0x04;
+ wiiuse_write_data(wm,WM_EXP_MOTION_PLUS_ENABLE,&val,1,wiiuse_motion_plus_check);
+ }
+ else
+ {
+ wiiuse_disable_expansion(wm);
+ val = 0x55;
+ wiiuse_write_data(wm,WM_EXP_MEM_ENABLE1,&val,1,wiiuse_set_motion_plus_clear1);
+ }
+}
+
+void motion_plus_disconnected(struct motion_plus_t* mp)
+{
+ WIIUSE_DEBUG("Motion plus disconnected");
+ memset(mp, 0, sizeof(struct motion_plus_t));
+}
+
+void motion_plus_event(struct motion_plus_t* mp, ubyte* msg)
+{
+ mp->rx = ((msg[5] & 0xFC) << 6) | msg[2]; // Pitch
+ mp->ry = ((msg[4] & 0xFC) << 6) | msg[1]; // Roll
+ mp->rz = ((msg[3] & 0xFC) << 6) | msg[0]; // Yaw
+
+ mp->ext = msg[4] & 0x1;
+ mp->status = (msg[3] & 0x3) | ((msg[4] & 0x2) << 1); // roll, yaw, pitch
+}
diff --git a/wii/wiiuse/motion_plus.h b/wii/wiiuse/motion_plus.h
new file mode 100644
index 0000000000..9f587cacf5
--- /dev/null
+++ b/wii/wiiuse/motion_plus.h
@@ -0,0 +1,23 @@
+/**
+ * @file
+ * @brief Motion plus extension
+ */
+
+#ifndef MOTION_PLUS_H_INCLUDED
+#define MOTION_PLUS_H_INCLUDED
+
+#include "wiiuse_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void motion_plus_disconnected(struct motion_plus_t* mp);
+
+void motion_plus_event(struct motion_plus_t* mp, ubyte* msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/wii/wiiuse/nunchuk.c b/wii/wiiuse/nunchuk.c
new file mode 100644
index 0000000000..950c0eeb57
--- /dev/null
+++ b/wii/wiiuse/nunchuk.c
@@ -0,0 +1,154 @@
+#include
+#include
+#include
+#include
+
+#include "dynamics.h"
+#include "definitions.h"
+#include "wiiuse_internal.h"
+#include "nunchuk.h"
+#include "io.h"
+
+/**
+ * @brief Find what buttons are pressed.
+ *
+ * @param nc Pointer to a nunchuk_t structure.
+ * @param msg The message byte specified in the event packet.
+ */
+static void nunchuk_pressed_buttons(struct nunchuk_t* nc, ubyte now) {
+ /* message is inverted (0 is active, 1 is inactive) */
+ now = ~now & NUNCHUK_BUTTON_ALL;
+
+ /* preserve old btns pressed */
+ nc->btns_last = nc->btns;
+
+ /* pressed now & were pressed, then held */
+ nc->btns_held = (now & nc->btns);
+
+ /* were pressed or were held & not pressed now, then released */
+ nc->btns_released = ((nc->btns | nc->btns_held) & ~now);
+
+ /* buttons pressed now */
+ nc->btns = now;
+}
+
+int nunchuk_handshake(struct wiimote_t *wm,struct nunchuk_t *nc,ubyte *data,uword len)
+{
+ //int i;
+ int offset = 0;
+
+ nc->btns = 0;
+ nc->btns_held = 0;
+ nc->btns_released = 0;
+ nc->flags = &wm->flags;
+ nc->accel_calib = wm->accel_calib;
+
+ //for(i=0;iaccel_calib.cal_zero.x = (data[offset + 0]<<2)|((data[offset + 3]>>4)&3);
+ nc->accel_calib.cal_zero.y = (data[offset + 1]<<2)|((data[offset + 3]>>2)&3);
+ nc->accel_calib.cal_zero.z = (data[offset + 2]<<2)|(data[offset + 3]&3);
+ nc->accel_calib.cal_g.x = (data[offset + 4]<<2)|((data[offset + 7]>>4)&3);
+ nc->accel_calib.cal_g.y = (data[offset + 5]<<2)|((data[offset + 7]>>2)&3);
+ nc->accel_calib.cal_g.z = (data[offset + 6]<<2)|(data[offset + 7]&3);
+ nc->js.max.x = data[offset + 8];
+ nc->js.min.x = data[offset + 9];
+ nc->js.center.x = data[offset + 10];
+ nc->js.max.y = data[offset + 11];
+ nc->js.min.y = data[offset + 12];
+ nc->js.center.y = data[offset + 13];
+
+ // set to defaults (averages from 5 nunchuks) if calibration data is invalid
+ if(nc->accel_calib.cal_zero.x == 0)
+ nc->accel_calib.cal_zero.x = 499;
+ if(nc->accel_calib.cal_zero.y == 0)
+ nc->accel_calib.cal_zero.y = 509;
+ if(nc->accel_calib.cal_zero.z == 0)
+ nc->accel_calib.cal_zero.z = 507;
+ if(nc->accel_calib.cal_g.x == 0)
+ nc->accel_calib.cal_g.x = 703;
+ if(nc->accel_calib.cal_g.y == 0)
+ nc->accel_calib.cal_g.y = 709;
+ if(nc->accel_calib.cal_g.z == 0)
+ nc->accel_calib.cal_g.z = 709;
+ if(nc->js.max.x == 0)
+ nc->js.max.x = 223;
+ if(nc->js.min.x == 0)
+ nc->js.min.x = 27;
+ if(nc->js.center.x == 0)
+ nc->js.center.x = 126;
+ if(nc->js.max.y == 0)
+ nc->js.max.y = 222;
+ if(nc->js.min.y == 0)
+ nc->js.min.y = 30;
+ if(nc->js.center.y == 0)
+ nc->js.center.y = 131;
+
+ wm->event = WIIUSE_NUNCHUK_INSERTED;
+ wm->exp.type = EXP_NUNCHUK;
+
+ return 1;
+}
+
+/**
+ * @brief The nunchuk disconnected.
+ *
+ * @param nc A pointer to a nunchuk_t structure.
+ */
+void nunchuk_disconnected(struct nunchuk_t* nc)
+{
+ //printf("nunchuk_disconnected()\n");
+ memset(nc, 0, sizeof(struct nunchuk_t));
+}
+
+/**
+ * @brief Handle nunchuk event.
+ *
+ * @param nc A pointer to a nunchuk_t structure.
+ * @param msg The message specified in the event packet.
+ */
+void nunchuk_event(struct nunchuk_t* nc, ubyte* msg) {
+ //int i;
+
+ /* decrypt data */
+ /*
+ for (i = 0; i < 6; ++i)
+ msg[i] = (msg[i] ^ 0x17) + 0x17;
+ */
+ /* get button states */
+ nunchuk_pressed_buttons(nc, msg[5]);
+
+ nc->js.pos.x = msg[0];
+ nc->js.pos.y = msg[1];
+
+ /* extend min and max values to physical range of motion */
+ if (nc->js.center.x) {
+ if (nc->js.min.x > nc->js.pos.x) nc->js.min.x = nc->js.pos.x;
+ if (nc->js.max.x < nc->js.pos.x) nc->js.max.x = nc->js.pos.x;
+ }
+ if (nc->js.center.y) {
+ if (nc->js.min.y > nc->js.pos.y) nc->js.min.y = nc->js.pos.y;
+ if (nc->js.max.y < nc->js.pos.y) nc->js.max.y = nc->js.pos.y;
+ }
+
+#ifndef GEKKO
+ /* calculate joystick state */
+ calc_joystick_state(&nc->js, nc->js.pos.x, nc->js.pos.y);
+#endif
+ /* calculate orientation */
+ nc->accel.x = (msg[2]<<2) + ((msg[5]>>2)&3);
+ nc->accel.y = (msg[3]<<2) + ((msg[5]>>4)&3);
+ nc->accel.z = (msg[4]<<2) + ((msg[5]>>6)&3);
+#ifndef GEKKO
+ calculate_orientation(&nc->accel_calib, &nc->accel, &nc->orient, NUNCHUK_IS_FLAG_SET(nc, WIIUSE_SMOOTHING));
+ calculate_gforce(&nc->accel_calib, &nc->accel, &nc->gforce);
+#endif
+}
+
diff --git a/wii/wiiuse/nunchuk.h b/wii/wiiuse/nunchuk.h
new file mode 100644
index 0000000000..973412edda
--- /dev/null
+++ b/wii/wiiuse/nunchuk.h
@@ -0,0 +1,18 @@
+#ifndef __NUNCHUK_H__
+#define __NUNCHUK_H__
+
+#include "wiiuse_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, ubyte* data, uword len);
+void nunchuk_disconnected(struct nunchuk_t* nc);
+void nunchuk_event(struct nunchuk_t* nc, ubyte* msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/wii/wiiuse/os.h b/wii/wiiuse/os.h
new file mode 100644
index 0000000000..aa5bea37c5
--- /dev/null
+++ b/wii/wiiuse/os.h
@@ -0,0 +1,28 @@
+#ifndef __OS_H__
+#define __OS_H__
+
+#ifdef WIN32
+ /* windows */
+ #define isnan(x) _isnan(x)
+ #define isinf(x) !_finite(x)
+
+ /* disable warnings I don't care about */
+ #pragma warning(disable:4244) /* possible loss of data conversion */
+ #pragma warning(disable:4273) /* inconsistent dll linkage */
+ #pragma warning(disable:4217)
+#else
+ /* nix/gekko */
+ #ifdef GEKKO
+ #include
+ #include
+ #include
+ #include "network.h"
+ #include
+ #include
+ #include
+ #include
+ #else
+ #endif
+#endif
+
+#endif
diff --git a/wii/wiiuse/speaker.c b/wii/wiiuse/speaker.c
new file mode 100644
index 0000000000..4c35197b79
--- /dev/null
+++ b/wii/wiiuse/speaker.c
@@ -0,0 +1,142 @@
+#include
+#include
+#include
+#include
+
+#ifndef WIN32
+#include
+#endif
+#ifdef GEKKO
+#include
+#endif
+#include "definitions.h"
+#include "wiiuse_internal.h"
+#include "speaker.h"
+
+#define WENCMIN(a,b) ((a)>(b)?(b):(a))
+#define ABS(x) ((s32)(x)>0?(s32)(x):-((s32)(x)))
+
+static const int yamaha_indexscale[] = {
+ 230, 230, 230, 230, 307, 409, 512, 614,
+ 230, 230, 230, 230, 307, 409, 512, 614
+};
+
+static const int yamaha_difflookup[] = {
+ 1, 3, 5, 7, 9, 11, 13, 15,
+ -1, -3, -5, -7, -9, -11, -13, -15
+};
+
+static ubyte __wiiuse_speaker_vol = 0x40;
+static ubyte __wiiuse_speaker_defconf[7] = { 0x00,0x00,0xD0,0x07,0x40,0x0C,0x0E };
+
+static __inline__ short wenc_clip_short(int a)
+{
+ if((a+32768)&~65535) return (a>>31)^32767;
+ else return a;
+}
+
+static __inline__ int wenc_clip(int a,int amin,int amax)
+{
+ if(aamax) return amax;
+ else return a;
+}
+
+ubyte wencdata(WENCStatus *info,short sample)
+{
+ int nibble,delta;
+
+ if(!info->step) {
+ info->predictor = 0;
+ info->step = 127;
+ }
+
+ delta = sample - info->predictor;
+ nibble = WENCMIN(7,(ABS(delta)*4)/info->step) + ((delta<0)*8);
+
+ info->predictor += ((info->step*yamaha_difflookup[nibble])/8);
+ info->predictor = wenc_clip_short(info->predictor);
+ info->step = (info->step*yamaha_indexscale[nibble])>>8;
+ info->step = wenc_clip(info->step,127,24576);
+
+ return nibble;
+}
+
+void wiiuse_set_speaker(struct wiimote_t *wm,int status)
+{
+ ubyte conf[7];
+ ubyte buf = 0x00;
+
+ if(!wm) return;
+
+ if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) {
+ WIIUSE_DEBUG("Tried to enable speaker, will wait until handshake finishes.\n");
+ if(status)
+ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_SPEAKER_INIT);
+ else
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_SPEAKER_INIT);
+ return;
+ }
+
+ if(status) {
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) {
+ wiiuse_status(wm,NULL);
+ return;
+ }
+ } else {
+ if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) {
+ wiiuse_status(wm,NULL);
+ return;
+ }
+ }
+
+
+ buf = 0x04;
+ wiiuse_sendcmd(wm,WM_CMD_SPEAKER_MUTE,&buf,1,NULL);
+
+ if (!status) {
+ WIIUSE_DEBUG("Disabled speaker for wiimote id %i.", wm->unid);
+
+ buf = 0x01;
+ wiiuse_write_data(wm,WM_REG_SPEAKER_REG1,&buf,1,NULL);
+
+ buf = 0x00;
+ wiiuse_write_data(wm,WM_REG_SPEAKER_REG3,&buf,1,NULL);
+
+ buf = 0x00;
+ wiiuse_sendcmd(wm,WM_CMD_SPEAKER_ENABLE,&buf,1,NULL);
+
+ wiiuse_status(wm,NULL);
+ return;
+ }
+
+ memcpy(conf,__wiiuse_speaker_defconf,7);
+
+ buf = 0x04;
+ wiiuse_sendcmd(wm,WM_CMD_SPEAKER_ENABLE,&buf,1,NULL);
+
+ buf = 0x01;
+ wiiuse_write_data(wm,WM_REG_SPEAKER_REG3,&buf,1,NULL);
+
+ buf = 0x08;
+ wiiuse_write_data(wm,WM_REG_SPEAKER_REG1,&buf,1,NULL);
+
+ conf[2] = 0xd0;
+ conf[3] = 0x07;
+ conf[4] = __wiiuse_speaker_vol;
+ wiiuse_write_data(wm,WM_REG_SPEAKER_BLOCK,conf,7,NULL);
+
+ buf = 0x01;
+ wiiuse_write_data(wm,WM_REG_SPEAKER_REG2,&buf,1,NULL);
+
+ buf = 0x00;
+ wiiuse_sendcmd(wm,WM_CMD_SPEAKER_MUTE,&buf,1,NULL);
+
+ wiiuse_status(wm,NULL);
+ return;
+}
+
+void set_speakervol(struct wiimote_t *wm,ubyte vol)
+{
+ __wiiuse_speaker_vol = vol;
+}
diff --git a/wii/wiiuse/speaker.h b/wii/wiiuse/speaker.h
new file mode 100644
index 0000000000..d7c61cca0b
--- /dev/null
+++ b/wii/wiiuse/speaker.h
@@ -0,0 +1,30 @@
+#ifndef __SPEAKER_H__
+#define __SPEAKER_H__
+
+#include "wiiuse_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _wencstatus
+{
+ s32 predictor;
+ s16 step_index;
+ s32 step;
+ s32 prev_sample;
+ s16 sample1;
+ s16 sample2;
+ s32 coeff1;
+ s32 coeff2;
+ s32 idelta;
+} WENCStatus;
+
+u8 wencdata(WENCStatus *info,s16 sample);
+void set_speakervol(struct wiimote_t *wm,ubyte vol);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/wii/wiiuse/wiiuse.c b/wii/wiiuse/wiiuse.c
new file mode 100644
index 0000000000..43d43f0118
--- /dev/null
+++ b/wii/wiiuse/wiiuse.c
@@ -0,0 +1,330 @@
+#include
+#include
+#include
+
+#ifndef WIN32
+ #include
+#else
+ #include
+#endif
+
+#include "definitions.h"
+#include "wiiuse_internal.h"
+#include "io.h"
+
+static struct wiimote_t** __wm = NULL;
+
+void wiiuse_send_next_command(struct wiimote_t *wm)
+{
+ struct cmd_blk_t *cmd = wm->cmd_head;
+
+ if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return;
+
+ if(!cmd) return;
+ if(cmd->state!=CMD_READY) return;
+
+ cmd->state = CMD_SENT;
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_RUMBLE)) cmd->data[1] |= 0x01;
+
+ WIIUSE_DEBUG("Sending command: %02x %02x", cmd->data[0], cmd->data[1]);
+ wiiuse_io_write(wm,cmd->data,cmd->len);
+}
+
+static __inline__ void __wiiuse_push_command(struct wiimote_t *wm,struct cmd_blk_t *cmd)
+{
+ uint level;
+
+ if(!wm || !cmd) return;
+
+ cmd->next = NULL;
+ cmd->state = CMD_READY;
+
+ _CPU_ISR_Disable(level);
+ if(wm->cmd_head==NULL) {
+ wm->cmd_head = wm->cmd_tail = cmd;
+ wiiuse_send_next_command(wm);
+ } else {
+ wm->cmd_tail->next = cmd;
+ wm->cmd_tail = cmd;
+ }
+ _CPU_ISR_Restore(level);
+}
+
+#ifndef GEKKO
+struct wiimote_t** wiiuse_init(int wiimotes) {
+#else
+extern void __wiiuse_sensorbar_enable(int enable);
+struct wiimote_t** wiiuse_init(int wiimotes, wii_event_cb event_cb) {
+#endif
+ int i = 0;
+
+ if (!wiimotes)
+ return NULL;
+
+ if (!__wm) {
+ __wm = __lwp_wkspace_allocate(sizeof(struct wiimote_t*) * wiimotes);
+ if(!__wm) return NULL;
+ memset(__wm, 0, sizeof(struct wiimote_t*) * wiimotes);
+ }
+
+ for (i = 0; i < wiimotes; ++i) {
+ if(!__wm[i])
+ __wm[i] = __lwp_wkspace_allocate(sizeof(struct wiimote_t));
+
+ memset(__wm[i], 0, sizeof(struct wiimote_t));
+ __wm[i]->unid = i;
+
+ #if defined(WIN32)
+ __wm[i]->dev_handle = 0;
+ __wm[i]->stack = WIIUSE_STACK_UNKNOWN;
+ __wm[i]->normal_timeout = WIIMOTE_DEFAULT_TIMEOUT;
+ __wm[i]->exp_timeout = WIIMOTE_EXP_TIMEOUT;
+ __wm[i]->timeout = __wm[i]->normal_timeout;
+ #elif defined(GEKKO)
+ __wm[i]->sock = NULL;
+ __wm[i]->bdaddr = *BD_ADDR_ANY;
+ __wm[i]->event_cb = event_cb;
+ wiiuse_init_cmd_queue(__wm[i]);
+ #elif defined(unix)
+ __wm[i]->bdaddr = *BDADDR_ANY;
+ __wm[i]->out_sock = -1;
+ __wm[i]->in_sock = -1;
+ #endif
+
+ __wm[i]->state = WIIMOTE_INIT_STATES;
+ __wm[i]->flags = WIIUSE_INIT_FLAGS;
+
+ __wm[i]->event = WIIUSE_NONE;
+
+ __wm[i]->exp.type = EXP_NONE;
+
+ wiiuse_set_aspect_ratio(__wm[i], WIIUSE_ASPECT_4_3);
+ wiiuse_set_ir_position(__wm[i], WIIUSE_IR_ABOVE);
+
+ __wm[i]->accel_calib.st_alpha = WIIUSE_DEFAULT_SMOOTH_ALPHA;
+ }
+
+ return __wm;
+}
+
+/**
+ * @brief Set flags for the specified wiimote.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ * @param enable Flags to enable.
+ * @param disable Flags to disable.
+ *
+ * @return The flags set after 'enable' and 'disable' have been applied.
+ *
+ * The values 'enable' and 'disable' may be any flags OR'ed together.
+ * Flags are defined in wiiuse.h.
+ */
+int wiiuse_set_flags(struct wiimote_t* wm, int enable, int disable) {
+ if (!wm) return 0;
+
+ /* remove mutually exclusive flags */
+ enable &= ~disable;
+ disable &= ~enable;
+
+ wm->flags |= enable;
+ wm->flags &= ~disable;
+
+ return wm->flags;
+}
+
+/**
+ * @brief Set if the wiimote should report motion sensing.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ * @param status 1 to enable, 0 to disable.
+ *
+ * Since reporting motion sensing sends a lot of data,
+ * the wiimote saves power by not transmitting it
+ * by default.
+ */
+void wiiuse_motion_sensing(struct wiimote_t* wm, int status)
+{
+ if (status) {
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_ACC)) return;
+ WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_ACC);
+ } else {
+ if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_ACC)) return;
+ WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_ACC);
+ }
+
+ if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) return;
+
+ wiiuse_status(wm,NULL);
+}
+
+/**
+ * @brief Toggle the state of the rumble.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ */
+void wiiuse_toggle_rumble(struct wiimote_t* wm)
+{
+ if (!wm) return;
+
+ WIIMOTE_TOGGLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
+ if(!WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) return;
+
+ wiiuse_set_leds(wm,wm->leds,NULL);
+}
+
+/**
+ * @brief Enable or disable the rumble.
+ *
+ * @param wm Pointer to a wiimote_t structure.
+ * @param status 1 to enable, 0 to disable.
+ */
+void wiiuse_rumble(struct wiimote_t* wm, int status)
+{
+ if (status && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_RUMBLE)) return;
+ else if(!status && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_RUMBLE)) return;
+ wiiuse_toggle_rumble(wm);
+}
+
+void wiiuse_set_leds(struct wiimote_t *wm,int leds,cmd_blk_cb cb)
+{
+ ubyte buf;
+
+ if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return;
+
+ wm->leds = (leds&0xf0);
+
+ buf = wm->leds;
+ wiiuse_sendcmd(wm,WM_CMD_LED,&buf,1,cb);
+}
+
+int wiiuse_set_report_type(struct wiimote_t *wm,cmd_blk_cb cb)
+{
+ ubyte buf[2];
+ int motion,ir,exp;
+
+ if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0;
+
+ buf[0] = (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_CONTINUOUS) ? 0x04 : 0x00); /* set to 0x04 for continuous reporting */
+ buf[1] = 0x00;
+
+ motion = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC) || WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR);
+ exp = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP);
+ ir = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR);
+
+ if (motion && ir && exp) buf[1] = WM_RPT_BTN_ACC_IR_EXP;
+ else if (motion && exp) buf[1] = WM_RPT_BTN_ACC_EXP;
+ else if (motion && ir) buf[1] = WM_RPT_BTN_ACC_IR;
+ else if (ir && exp) buf[1] = WM_RPT_BTN_IR_EXP;
+ else if (ir) buf[1] = WM_RPT_BTN_ACC_IR;
+ else if (exp) buf[1] = WM_RPT_BTN_EXP;
+ else if (motion) buf[1] = WM_RPT_BTN_ACC;
+ else buf[1] = WM_RPT_BTN;
+
+ //WIIUSE_DEBUG("Setting report type: 0x%x", buf[1]);
+
+ wiiuse_sendcmd(wm,WM_CMD_REPORT_TYPE,buf,2,cb);
+ return buf[1];
+}
+
+void wiiuse_status(struct wiimote_t *wm,cmd_blk_cb cb)
+{
+ ubyte buf;
+
+ if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return;
+
+ buf = 0x00;
+ wiiuse_sendcmd(wm,WM_CMD_CTRL_STATUS,&buf,1,cb);
+}
+
+int wiiuse_read_data(struct wiimote_t *wm,ubyte *buffer,uint addr,uword len,cmd_blk_cb cb)
+{
+ struct op_t *op;
+ struct cmd_blk_t *cmd;
+
+ if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0;
+ if(!buffer || !len) return 0;
+
+ cmd = (struct cmd_blk_t*)__lwp_queue_get(&wm->cmdq);
+ if(!cmd) return 0;
+
+ cmd->cb = cb;
+ cmd->len = 7;
+
+ op = (struct op_t*)cmd->data;
+ op->cmd = WM_CMD_READ_DATA;
+ op->buffer = buffer;
+ op->wait = len;
+ op->readdata.addr = BIG_ENDIAN_LONG(addr);
+ op->readdata.size = BIG_ENDIAN_SHORT(len);
+ __wiiuse_push_command(wm,cmd);
+
+ return 1;
+}
+
+int wiiuse_write_data(struct wiimote_t *wm,uint addr,ubyte *data,ubyte len,cmd_blk_cb cb)
+{
+ struct op_t *op;
+ struct cmd_blk_t *cmd;
+
+ if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0;
+ if(!data || !len) return 0;
+
+ cmd = (struct cmd_blk_t*)__lwp_queue_get(&wm->cmdq);
+ if(!cmd) return 0;
+
+ cmd->cb = cb;
+ cmd->len = 22;
+
+ op = (struct op_t*)cmd->data;
+ op->cmd = WM_CMD_WRITE_DATA;
+ op->buffer = NULL;
+ op->wait = 0;
+ op->writedata.addr = BIG_ENDIAN_LONG(addr);
+ op->writedata.size = (len&0x0f);
+ memcpy(op->writedata.data,data,len);
+ memset(op->writedata.data+len,0,(16 - len));
+ __wiiuse_push_command(wm,cmd);
+
+ return 1;
+}
+
+int wiiuse_write_streamdata(struct wiimote_t *wm,ubyte *data,ubyte len,cmd_blk_cb cb)
+{
+ struct cmd_blk_t *cmd;
+
+ if(!wm || !WIIMOTE_IS_CONNECTED(wm)) return 0;
+ if(!data || !len || len>20) return 0;
+
+ cmd = (struct cmd_blk_t*)__lwp_queue_get(&wm->cmdq);
+ if(!cmd) return 0;
+
+ cmd->cb = cb;
+ cmd->len = 22;
+ cmd->data[0] = WM_CMD_STREAM_DATA;
+ cmd->data[1] = (len<<3);
+ memcpy(cmd->data+2,data,len);
+ __wiiuse_push_command(wm,cmd);
+
+ return 1;
+}
+
+int wiiuse_sendcmd(struct wiimote_t *wm,ubyte report_type,ubyte *msg,int len,cmd_blk_cb cb)
+{
+ struct cmd_blk_t *cmd;
+
+ cmd = (struct cmd_blk_t*)__lwp_queue_get(&wm->cmdq);
+ if(!cmd) return 0;
+
+ cmd->cb = cb;
+ cmd->len = (1+len);
+
+ cmd->data[0] = report_type;
+ memcpy(cmd->data+1,msg,len);
+ if(report_type!=WM_CMD_READ_DATA && report_type!=WM_CMD_CTRL_STATUS)
+ cmd->data[1] |= 0x02;
+
+ //WIIUSE_DEBUG("Pushing command: %02x %02x", cmd->data[0], cmd->data[1]);
+ __wiiuse_push_command(wm,cmd);
+
+ return 1;
+}
diff --git a/wii/wiiuse/wiiuse_internal.h b/wii/wiiuse/wiiuse_internal.h
new file mode 100644
index 0000000000..149695259d
--- /dev/null
+++ b/wii/wiiuse/wiiuse_internal.h
@@ -0,0 +1,275 @@
+/*
+ * wiiuse
+ *
+ * Written By:
+ * Michael Laforest < para >
+ * Email: < thepara (--AT--) g m a i l [--DOT--] com >
+ *
+ * Copyright 2006-2007
+ *
+ * This file is part of wiiuse.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * $Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/libogc/wiiuse/wiiuse_internal.h,v 1.8 2008-12-10 16:16:40 shagkur Exp $
+ *
+ */
+
+/**
+ * @file
+ * @brief General internal wiiuse stuff.
+ *
+ * Since Wiiuse is a library, wiiuse.h is a duplicate
+ * of the API header.
+ *
+ * The code that would normally go in that file, but
+ * which is not needed by third party developers,
+ * is put here.
+ *
+ * So wiiuse_internal.h is included by other files
+ * internally, wiiuse.h is included only here.
+ */
+
+#ifndef WIIUSE_INTERNAL_H_INCLUDED
+#define WIIUSE_INTERNAL_H_INCLUDED
+
+#if defined(__linux__)
+ #include /* htons() */
+ #include
+#endif
+
+#include "definitions.h"
+
+/* wiiuse version */
+#define WIIUSE_VERSION "0.12"
+
+/********************
+ *
+ * Wiimote internal codes
+ *
+ ********************/
+
+/* Communication channels */
+#define WM_OUTPUT_CHANNEL 0x11
+#define WM_INPUT_CHANNEL 0x13
+
+#define WM_SET_REPORT 0x50
+#define WM_DATA 0xA0
+
+/* commands */
+#define WM_CMD_RUMBLE 0x10
+#define WM_CMD_LED 0x11
+#define WM_CMD_REPORT_TYPE 0x12
+#define WM_CMD_IR 0x13
+#define WM_CMD_SPEAKER_ENABLE 0x14
+#define WM_CMD_CTRL_STATUS 0x15
+#define WM_CMD_WRITE_DATA 0x16
+#define WM_CMD_READ_DATA 0x17
+#define WM_CMD_STREAM_DATA 0x18
+#define WM_CMD_SPEAKER_MUTE 0x19
+#define WM_CMD_IR_2 0x1A
+
+/* input report ids */
+#define WM_RPT_CTRL_STATUS 0x20
+#define WM_RPT_READ 0x21
+#define WM_RPT_ACK 0x22
+#define WM_RPT_BTN 0x30
+#define WM_RPT_BTN_ACC 0x31
+#define WM_RPT_BTN_ACC_IR 0x33
+#define WM_RPT_BTN_EXP 0x34
+#define WM_RPT_BTN_ACC_EXP 0x35
+#define WM_RPT_BTN_IR_EXP 0x36
+#define WM_RPT_BTN_ACC_IR_EXP 0x37
+
+#define WM_BT_INPUT 0x01
+#define WM_BT_OUTPUT 0x02
+
+/* Identify the wiimote device by its class */
+#define WM_DEV_CLASS_0 0x04
+#define WM_DEV_CLASS_1 0x25
+#define WM_DEV_CLASS_2 0x00
+#define WM_VENDOR_ID 0x057E
+#define WM_PRODUCT_ID 0x0306
+
+/* controller status stuff */
+#define WM_MAX_BATTERY_CODE 0xC8
+
+/* offsets in wiimote memory */
+#define WM_MEM_OFFSET_CALIBRATION 0x16
+#define WM_EXP_MEM_BASE 0x04A40000
+#define WM_EXP_MEM_ENABLE1 0x04A400F0
+#define WM_EXP_MEM_ENABLE2 0x04A400FB
+#define WM_EXP_MEM_KEY 0x04A40040
+#define WM_EXP_MEM_CALIBR 0x04A40020
+#define WM_EXP_MOTION_PLUS_ENABLE 0x04A600FE
+#define WM_EXP_ID 0x04A400FA
+
+#define WM_REG_IR 0x04B00030
+#define WM_REG_IR_BLOCK1 0x04B00000
+#define WM_REG_IR_BLOCK2 0x04B0001A
+#define WM_REG_IR_MODENUM 0x04B00033
+
+#define WM_REG_SPEAKER_REG1 0x04A20001
+#define WM_REG_SPEAKER_REG2 0x04A20008
+#define WM_REG_SPEAKER_REG3 0x04A20009
+#define WM_REG_SPEAKER_BLOCK 0x04A20001
+
+/* ir block data */
+#define WM_IR_BLOCK1_LEVEL1 "\x02\x00\x00\x71\x01\x00\x64\x00\xfe"
+#define WM_IR_BLOCK2_LEVEL1 "\xfd\x05"
+#define WM_IR_BLOCK1_LEVEL2 "\x02\x00\x00\x71\x01\x00\x96\x00\xb4"
+#define WM_IR_BLOCK2_LEVEL2 "\xb3\x04"
+#define WM_IR_BLOCK1_LEVEL3 "\x02\x00\x00\x71\x01\x00\xaa\x00\x64"
+#define WM_IR_BLOCK2_LEVEL3 "\x63\x03"
+#define WM_IR_BLOCK1_LEVEL4 "\x02\x00\x00\x71\x01\x00\xc8\x00\x36"
+#define WM_IR_BLOCK2_LEVEL4 "\x35\x03"
+#define WM_IR_BLOCK1_LEVEL5 "\x07\x00\x00\x71\x01\x00\x72\x00\x20"
+#define WM_IR_BLOCK2_LEVEL5 "\x1f\x03"
+
+#define WM_IR_TYPE_BASIC 0x01
+#define WM_IR_TYPE_EXTENDED 0x03
+#define WM_IR_TYPE_FULL 0x05
+
+/* controller status flags for the first message byte */
+/* bit 1 is unknown */
+#define WM_CTRL_STATUS_BYTE1_ATTACHMENT 0x02
+#define WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED 0x04
+#define WM_CTRL_STATUS_BYTE1_IR_ENABLED 0x08
+#define WM_CTRL_STATUS_BYTE1_LED_1 0x10
+#define WM_CTRL_STATUS_BYTE1_LED_2 0x20
+#define WM_CTRL_STATUS_BYTE1_LED_3 0x40
+#define WM_CTRL_STATUS_BYTE1_LED_4 0x80
+
+/* aspect ratio */
+#define WM_ASPECT_16_9_X 660
+#define WM_ASPECT_16_9_Y 370
+#define WM_ASPECT_4_3_X 560
+#define WM_ASPECT_4_3_Y 420
+
+
+/**
+ * Expansion stuff
+ */
+
+/* encrypted expansion id codes (located at 0x04A400FC) */
+#define EXP_ID_CODE_NUNCHUK 0xa4200000
+#define EXP_ID_CODE_CLASSIC_CONTROLLER 0xa4200101
+#define EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING 0x90908f00
+#define EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING2 0x9e9f9c00
+#define EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING3 0x908f8f00
+#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC 0xa5a2a300
+#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC2 0x98999900
+#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC3 0xa0a1a000
+#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC4 0x8d8d8e00
+#define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC5 0x93949400
+//#define EXP_ID_CODE_GUITAR 0xa4200103
+//#define EXP_ID_CODE_WIIBOARD 0xa4200402
+#define EXP_ID_CODE_MOTION_PLUS 0xa4200405
+
+#define EXP_HANDSHAKE_LEN 224
+
+/********************
+ *
+ * End Wiimote internal codes
+ *
+ ********************/
+
+/* wiimote state flags - (some duplicated in wiiuse.h)*/
+#define WIIMOTE_STATE_DEV_FOUND 0x00001
+//#define WIIMOTE_STATE_DEV_REGISTER 0x00002
+#define WIIMOTE_STATE_HANDSHAKE 0x00004 /* actual connection exists but no handshake yet */
+#define WIIMOTE_STATE_HANDSHAKE_COMPLETE 0x00008 /* actual connection exists but no handshake yet */
+#define WIIMOTE_STATE_CONNECTED 0x00010
+#define WIIMOTE_STATE_EXP_HANDSHAKE 0x00020 /* actual connection exists but no handshake yet */
+#define WIIMOTE_STATE_EXP_FAILED 0x00040 /* actual connection exists but no handshake yet */
+#define WIIMOTE_STATE_RUMBLE 0x00080
+#define WIIMOTE_STATE_ACC 0x00100
+#define WIIMOTE_STATE_EXP 0x00200
+#define WIIMOTE_STATE_IR 0x00400
+#define WIIMOTE_STATE_SPEAKER 0x00800
+#define WIIMOTE_STATE_IR_SENS_LVL1 0x01000
+#define WIIMOTE_STATE_IR_SENS_LVL2 0x02000
+#define WIIMOTE_STATE_IR_SENS_LVL3 0x04000
+#define WIIMOTE_STATE_IR_SENS_LVL4 0x08000
+#define WIIMOTE_STATE_IR_SENS_LVL5 0x10000
+#define WIIMOTE_STATE_IR_INIT 0x20000
+#define WIIMOTE_STATE_SPEAKER_INIT 0x40000
+
+#define WIIMOTE_INIT_STATES (WIIMOTE_STATE_IR_SENS_LVL3)
+
+/* macro to manage states */
+#define WIIMOTE_IS_SET(wm, s) ((wm->state & (s)) == (s))
+#define WIIMOTE_ENABLE_STATE(wm, s) (wm->state |= (s))
+#define WIIMOTE_DISABLE_STATE(wm, s) (wm->state &= ~(s))
+#define WIIMOTE_TOGGLE_STATE(wm, s) ((wm->state & (s)) ? WIIMOTE_DISABLE_STATE(wm, s) : WIIMOTE_ENABLE_STATE(wm, s))
+
+#define WIIMOTE_IS_FLAG_SET(wm, s) ((wm->flags & (s)) == (s))
+#define WIIMOTE_ENABLE_FLAG(wm, s) (wm->flags |= (s))
+#define WIIMOTE_DISABLE_FLAG(wm, s) (wm->flags &= ~(s))
+#define WIIMOTE_TOGGLE_FLAG(wm, s) ((wm->flags & (s)) ? WIIMOTE_DISABLE_FLAG(wm, s) : WIIMOTE_ENABLE_FLAG(wm, s))
+
+#define NUNCHUK_IS_FLAG_SET(wm, s) ((*(wm->flags) & (s)) == (s))
+
+/* misc macros */
+#define WIIMOTE_ID(wm) (wm->unid)
+#define WIIMOTE_IS_CONNECTED(wm) (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_CONNECTED))
+
+/*
+ * Smooth tilt calculations are computed with the
+ * exponential moving average formula:
+ * St = St_last + (alpha * (tilt - St_last))
+ * alpha is between 0 and 1
+ */
+#define WIIUSE_DEFAULT_SMOOTH_ALPHA 0.3f
+
+#define SMOOTH_ROLL 0x01
+#define SMOOTH_PITCH 0x02
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct op_t
+{
+ ubyte cmd;
+ union {
+ struct {
+ uint addr;
+ uword size;
+ } readdata;
+ struct {
+ uint addr;
+ ubyte size;
+ ubyte data[16];
+ } writedata;
+ ubyte __data[MAX_PAYLOAD];
+ };
+
+ void *buffer;
+ int wait;
+} __attribute__((packed));
+
+/* not part of the api */
+void wiiuse_init_cmd_queue(struct wiimote_t *wm);
+void wiiuse_send_next_command(struct wiimote_t *wm);
+int wiiuse_set_report_type(struct wiimote_t* wm,cmd_blk_cb cb);
+int wiiuse_sendcmd(struct wiimote_t *wm,ubyte report_type,ubyte *msg,int len,cmd_blk_cb cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WIIUSE_INTERNAL_H_INCLUDED */
diff --git a/wii/wiiuse/wpad.c b/wii/wiiuse/wpad.c
new file mode 100644
index 0000000000..1f1c067114
--- /dev/null
+++ b/wii/wiiuse/wpad.c
@@ -0,0 +1,1242 @@
+/*-------------------------------------------------------------
+
+wpad.c -- Wiimote Application Programmers Interface
+
+Copyright (C) 2008
+Michael Wiedenbauer (shagkur)
+Dave Murphy (WinterMute)
+Hector Martin (marcan)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you
+must not claim that you wrote the original software. If you use
+this software in a product, an acknowledgment in the product
+documentation would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+
+-------------------------------------------------------------*/
+
+#include
+#include
+#include
+#include
+#include
+
+#include "os.h"
+#include "lwp_wkspace.inl"
+#include "lwp_priority.inl"
+#include "lwp_watchdog.inl"
+#include "lwp_threads.inl"
+#include "conf.h"
+#include "ir.h"
+#include "speaker.h"
+#include "dynamics.h"
+#include "wiiuse_internal.h"
+#include "wiiuse/wpad.h"
+#include "lwp_threads.h"
+#include "ogcsys.h"
+
+#define MAX_STREAMDATA_LEN 20
+#define EVENTQUEUE_LENGTH 16
+
+#define DISCONNECT_BATTERY_DIED 0x14
+#define DISCONNECT_POWER_OFF 0x15
+
+struct _wpad_thresh{
+ s32 btns;
+ s32 ir;
+ s32 js;
+ s32 acc;
+ s32 mp;
+};
+
+struct _wpad_cb {
+ wiimote *wm;
+ s32 data_fmt;
+ s32 queue_head;
+ s32 queue_tail;
+ s32 queue_full;
+ u32 queue_length;
+ u32 dropped_events;
+ s32 idle_time;
+ s32 speaker_enabled;
+ struct _wpad_thresh thresh;
+
+ void *sound_data;
+ u32 sound_len;
+ u32 sound_off;
+ syswd_t sound_alarm;
+
+ WPADData lstate;
+ WPADData *queue_ext;
+ WPADData queue_int[EVENTQUEUE_LENGTH];
+};
+
+static syswd_t __wpad_timer;
+static vu32 __wpads_inited = 0;
+static vs32 __wpads_ponded = 0;
+static u32 __wpad_idletimeout = 300;
+static vu32 __wpads_active = 0;
+static vu32 __wpads_used = 0;
+static wiimote **__wpads = NULL;
+static wiimote_listen __wpads_listen[CONF_PAD_MAX_REGISTERED];
+static WPADData wpaddata[WPAD_MAX_WIIMOTES];
+static struct _wpad_cb __wpdcb[WPAD_MAX_WIIMOTES];
+static conf_pads __wpad_devs;
+static struct linkkey_info __wpad_keys[WPAD_MAX_WIIMOTES];
+
+static s32 __wpad_onreset(s32 final);
+static s32 __wpad_disconnect(struct _wpad_cb *wpdcb);
+static void __wpad_eventCB(struct wiimote_t *wm,s32 event);
+
+static void __wpad_def_powcb(s32 chan);
+static WPADShutdownCallback __wpad_batcb = NULL;
+static WPADShutdownCallback __wpad_powcb = __wpad_def_powcb;
+
+extern void __wiiuse_sensorbar_enable(int enable);
+extern void __SYS_DoPowerCB(void);
+
+static sys_resetinfo __wpad_resetinfo = {
+ {},
+ __wpad_onreset,
+ 127
+};
+
+static s32 __wpad_onreset(s32 final)
+{
+ //printf("__wpad_onreset(%d)\n",final);
+ if(final==FALSE) {
+ WPAD_Shutdown();
+ }
+ return 1;
+}
+
+static void __wpad_def_powcb(s32 chan)
+{
+ __SYS_DoPowerCB();
+}
+
+static void __wpad_timeouthandler(syswd_t alarm,void *cbarg)
+{
+ s32 i;
+ struct wiimote_t *wm = NULL;
+ struct _wpad_cb *wpdcb = NULL;
+
+ if(!__wpads_active) return;
+
+ __lwp_thread_dispatchdisable();
+ for(i=0;iwm;
+ if(wm && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) {
+ wpdcb->idle_time++;
+ if(wpdcb->idle_time>=__wpad_idletimeout) {
+ wpdcb->idle_time = 0;
+ wiiuse_disconnect(wm);
+ }
+ }
+ }
+ __lwp_thread_dispatchunnest();
+}
+
+static void __wpad_sounddata_alarmhandler(syswd_t alarm,void *cbarg)
+{
+ u8 *snd_data;
+ u32 snd_off;
+ struct wiimote_t *wm;
+ struct _wpad_cb *wpdcb = (struct _wpad_cb*)cbarg;
+
+ if(!wpdcb) return;
+
+ if(wpdcb->sound_off>=wpdcb->sound_len) {
+ wpdcb->sound_data = NULL;
+ wpdcb->sound_len = 0;
+ wpdcb->sound_off = 0;
+ SYS_CancelAlarm(wpdcb->sound_alarm);
+ return;
+ }
+
+ wm = wpdcb->wm;
+ snd_data = wpdcb->sound_data;
+ snd_off = wpdcb->sound_off;
+ wpdcb->sound_off += MAX_STREAMDATA_LEN;
+ wiiuse_write_streamdata(wm,(snd_data+snd_off),MAX_STREAMDATA_LEN,NULL);
+}
+
+static void __wpad_setfmt(s32 chan)
+{
+ switch(__wpdcb[chan].data_fmt) {
+ case WPAD_FMT_BTNS:
+ wiiuse_set_flags(__wpads[chan], 0, WIIUSE_CONTINUOUS);
+ wiiuse_motion_sensing(__wpads[chan],0);
+ wiiuse_set_ir(__wpads[chan],0);
+ break;
+ case WPAD_FMT_BTNS_ACC:
+ wiiuse_set_flags(__wpads[chan], WIIUSE_CONTINUOUS, 0);
+ wiiuse_motion_sensing(__wpads[chan],1);
+ wiiuse_set_ir(__wpads[chan],0);
+ break;
+ case WPAD_FMT_BTNS_ACC_IR:
+ wiiuse_set_flags(__wpads[chan], WIIUSE_CONTINUOUS, 0);
+ wiiuse_motion_sensing(__wpads[chan],1);
+ wiiuse_set_ir(__wpads[chan],1);
+ break;
+ default:
+ break;
+ }
+}
+
+wiimote *__wpad_assign_slot(struct bd_addr *pad_addr)
+{
+ u32 i, level;
+ struct bd_addr bdaddr;
+ //printf("WPAD Assigning slot (active: 0x%02x)\n", __wpads_used);
+ _CPU_ISR_Disable(level);
+
+ // Try preassigned slots
+ for(i=0; iwm;
+ if(wm && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) {
+ wiiuse_disconnect(wm);
+ }
+
+ return 0;
+}
+
+static void __wpad_calc_data(WPADData *data,WPADData *lstate,struct accel_t *accel_calib,u32 smoothed)
+{
+ if(data->err!=WPAD_ERR_NONE) return;
+
+ data->orient = lstate->orient;
+
+ data->ir.state = lstate->ir.state;
+ data->ir.sensorbar = lstate->ir.sensorbar;
+ data->ir.x = lstate->ir.x;
+ data->ir.y = lstate->ir.y;
+ data->ir.sx = lstate->ir.sx;
+ data->ir.sy = lstate->ir.sy;
+ data->ir.ax = lstate->ir.ax;
+ data->ir.ay = lstate->ir.ay;
+ data->ir.distance = lstate->ir.distance;
+ data->ir.z = lstate->ir.z;
+ data->ir.angle = lstate->ir.angle;
+ data->ir.error_cnt = lstate->ir.error_cnt;
+ data->ir.glitch_cnt = lstate->ir.glitch_cnt;
+
+ if(data->data_present & WPAD_DATA_ACCEL) {
+ calculate_orientation(accel_calib, &data->accel, &data->orient, smoothed);
+ calculate_gforce(accel_calib, &data->accel, &data->gforce);
+ }
+ if(data->data_present & WPAD_DATA_IR) {
+ interpret_ir_data(&data->ir,&data->orient);
+ }
+ if(data->data_present & WPAD_DATA_EXPANSION) {
+ switch(data->exp.type) {
+ case EXP_NUNCHUK:
+ {
+ struct nunchuk_t *nc = &data->exp.nunchuk;
+
+ nc->orient = lstate->exp.nunchuk.orient;
+ calc_joystick_state(&nc->js,nc->js.pos.x,nc->js.pos.y);
+ calculate_orientation(&nc->accel_calib,&nc->accel,&nc->orient,smoothed);
+ calculate_gforce(&nc->accel_calib,&nc->accel,&nc->gforce);
+ data->btns_h |= (data->exp.nunchuk.btns<<16);
+ }
+ break;
+
+ case EXP_CLASSIC:
+ {
+ struct classic_ctrl_t *cc = &data->exp.classic;
+
+ cc->r_shoulder = ((f32)cc->rs_raw/0x1F);
+ cc->l_shoulder = ((f32)cc->ls_raw/0x1F);
+ calc_joystick_state(&cc->ljs, cc->ljs.pos.x, cc->ljs.pos.y);
+ calc_joystick_state(&cc->rjs, cc->rjs.pos.x, cc->rjs.pos.y);
+ data->btns_h |= (data->exp.classic.btns<<16);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ *lstate = *data;
+}
+
+static void __save_state(struct wiimote_t* wm) {
+ /* wiimote */
+ wm->lstate.btns = wm->btns;
+ wm->lstate.accel = wm->accel;
+
+ /* ir */
+ wm->lstate.ir = wm->ir;
+
+ /* expansion */
+ switch (wm->exp.type) {
+ case EXP_NUNCHUK:
+ wm->lstate.exp.nunchuk = wm->exp.nunchuk;
+ break;
+ case EXP_CLASSIC:
+ wm->lstate.exp.classic = wm->exp.classic;
+ break;
+ case EXP_MOTION_PLUS:
+ wm->lstate.exp.mp = wm->exp.mp;
+ break;
+ }
+}
+
+#define ABS(x) ((s32)(x)>0?(s32)(x):-((s32)(x)))
+
+#define STATE_CHECK(thresh, a, b) \
+ if(((thresh) > WPAD_THRESH_IGNORE) && (ABS((a)-(b)) > (thresh))) \
+ state_changed = 1;
+
+#define STATE_CHECK_SIMPLE(thresh, a, b) \
+ if(((thresh) > WPAD_THRESH_IGNORE) && ((a) != (b))) \
+ state_changed = 1;
+
+static u32 __wpad_read_expansion(struct wiimote_t *wm,WPADData *data, struct _wpad_thresh *thresh)
+{
+ int state_changed = 0;
+ switch(data->exp.type) {
+ case EXP_NUNCHUK:
+ data->exp.nunchuk = wm->exp.nunchuk;
+ STATE_CHECK_SIMPLE(thresh->btns, wm->exp.nunchuk.btns, wm->lstate.exp.nunchuk.btns);
+ STATE_CHECK(thresh->acc, wm->exp.nunchuk.accel.x, wm->lstate.exp.nunchuk.accel.x);
+ STATE_CHECK(thresh->acc, wm->exp.nunchuk.accel.y, wm->lstate.exp.nunchuk.accel.y);
+ STATE_CHECK(thresh->acc, wm->exp.nunchuk.accel.z, wm->lstate.exp.nunchuk.accel.z);
+ STATE_CHECK(thresh->js, wm->exp.nunchuk.js.pos.x, wm->lstate.exp.nunchuk.js.pos.x);
+ STATE_CHECK(thresh->js, wm->exp.nunchuk.js.pos.y, wm->lstate.exp.nunchuk.js.pos.y);
+ break;
+ case EXP_CLASSIC:
+ data->exp.classic = wm->exp.classic;
+ STATE_CHECK_SIMPLE(thresh->btns, wm->exp.classic.btns, wm->lstate.exp.classic.btns);
+ STATE_CHECK(thresh->js, wm->exp.classic.rs_raw, wm->lstate.exp.classic.rs_raw);
+ STATE_CHECK(thresh->js, wm->exp.classic.ls_raw, wm->lstate.exp.classic.ls_raw);
+ STATE_CHECK(thresh->js, wm->exp.classic.ljs.pos.x, wm->lstate.exp.classic.ljs.pos.x);
+ STATE_CHECK(thresh->js, wm->exp.classic.ljs.pos.y, wm->lstate.exp.classic.ljs.pos.y);
+ STATE_CHECK(thresh->js, wm->exp.classic.rjs.pos.x, wm->lstate.exp.classic.rjs.pos.x);
+ STATE_CHECK(thresh->js, wm->exp.classic.rjs.pos.y, wm->lstate.exp.classic.rjs.pos.y);
+ break;
+ case EXP_MOTION_PLUS:
+ data->exp.mp = wm->exp.mp;
+ STATE_CHECK(thresh->mp,wm->exp.mp.rx,wm->lstate.exp.mp.rx);
+ STATE_CHECK(thresh->mp,wm->exp.mp.ry,wm->lstate.exp.mp.ry);
+ STATE_CHECK(thresh->mp,wm->exp.mp.rz,wm->lstate.exp.mp.rz);
+ break;
+ }
+ return state_changed;
+}
+
+static void __wpad_read_wiimote(struct wiimote_t *wm, WPADData *data, s32 *idle_time, struct _wpad_thresh *thresh)
+{
+ int i;
+ int state_changed = 0;
+ data->err = WPAD_ERR_TRANSFER;
+ data->data_present = 0;
+ data->battery_level = wm->battery_level;
+ data->exp.type = wm->exp.type;
+ if(wm && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) {
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) {
+ switch(wm->event_buf[0]) {
+ case WM_RPT_BTN:
+ case WM_RPT_BTN_ACC:
+ case WM_RPT_BTN_ACC_IR:
+ case WM_RPT_BTN_EXP:
+ case WM_RPT_BTN_ACC_EXP:
+ case WM_RPT_BTN_IR_EXP:
+ case WM_RPT_BTN_ACC_IR_EXP:
+ data->btns_h = (wm->btns&0xffff);
+ data->data_present |= WPAD_DATA_BUTTONS;
+ STATE_CHECK_SIMPLE(thresh->btns, wm->btns, wm->lstate.btns);
+ }
+ switch(wm->event_buf[0]) {
+ case WM_RPT_BTN_ACC:
+ case WM_RPT_BTN_ACC_IR:
+ case WM_RPT_BTN_ACC_EXP:
+ case WM_RPT_BTN_ACC_IR_EXP:
+ data->accel = wm->accel;
+ data->data_present |= WPAD_DATA_ACCEL;
+ STATE_CHECK(thresh->acc, wm->accel.x, wm->lstate.accel.x);
+ STATE_CHECK(thresh->acc, wm->accel.y, wm->lstate.accel.y);
+ STATE_CHECK(thresh->acc, wm->accel.z, wm->lstate.accel.z);
+ }
+ switch(wm->event_buf[0]) {
+ //IR requires acceleration
+ //case WM_RPT_BTN_IR_EXP:
+ case WM_RPT_BTN_ACC_IR:
+ case WM_RPT_BTN_ACC_IR_EXP:
+ data->ir = wm->ir;
+ data->data_present |= WPAD_DATA_IR;
+ for(i=0; iir, wm->ir.dot[i].visible, wm->lstate.ir.dot[i].visible);
+ STATE_CHECK(thresh->ir, wm->ir.dot[i].rx, wm->lstate.ir.dot[i].rx);
+ STATE_CHECK(thresh->ir, wm->ir.dot[i].ry, wm->lstate.ir.dot[i].ry);
+ }
+ }
+ switch(wm->event_buf[0]) {
+ case WM_RPT_BTN_EXP:
+ case WM_RPT_BTN_ACC_EXP:
+ case WM_RPT_BTN_IR_EXP:
+ case WM_RPT_BTN_ACC_IR_EXP:
+ state_changed |= __wpad_read_expansion(wm,data,thresh);
+ data->data_present |= WPAD_DATA_EXPANSION;
+ }
+ data->err = WPAD_ERR_NONE;
+ if(state_changed) {
+ *idle_time = 0;
+ __save_state(wm);
+ }
+ } else
+ data->err = WPAD_ERR_NOT_READY;
+ } else
+ data->err = WPAD_ERR_NO_CONTROLLER;
+}
+
+static void __wpad_eventCB(struct wiimote_t *wm,s32 event)
+{
+ s32 chan;
+ u32 maxbufs;
+ WPADData *wpadd = NULL;
+ struct _wpad_cb *wpdcb = NULL;
+
+ switch(event) {
+ case WIIUSE_EVENT:
+ chan = wm->unid;
+ wpdcb = &__wpdcb[chan];
+
+ if(wpdcb->queue_ext!=NULL) {
+ maxbufs = wpdcb->queue_length;
+ wpadd = &(wpdcb->queue_ext[wpdcb->queue_tail]);
+ } else {
+ maxbufs = EVENTQUEUE_LENGTH;
+ wpadd = &(wpdcb->queue_int[wpdcb->queue_tail]);
+ }
+ if(wpdcb->queue_full == maxbufs) {
+ wpdcb->queue_head++;
+ wpdcb->queue_head %= maxbufs;
+ wpdcb->dropped_events++;
+ } else {
+ wpdcb->queue_full++;
+ }
+
+ __wpad_read_wiimote(wm, wpadd, &wpdcb->idle_time, &wpdcb->thresh);
+
+ wpdcb->queue_tail++;
+ wpdcb->queue_tail %= maxbufs;
+
+ break;
+ case WIIUSE_STATUS:
+ break;
+ case WIIUSE_CONNECT:
+ chan = wm->unid;
+ wpdcb = &__wpdcb[chan];
+ wpdcb->wm = wm;
+ wpdcb->queue_head = 0;
+ wpdcb->queue_tail = 0;
+ wpdcb->queue_full = 0;
+ wpdcb->idle_time = 0;
+ memset(&wpdcb->lstate,0,sizeof(WPADData));
+ memset(&wpaddata[chan],0,sizeof(WPADData));
+ memset(wpdcb->queue_int,0,(sizeof(WPADData)*EVENTQUEUE_LENGTH));
+ wiiuse_set_ir_position(wm,(CONF_GetSensorBarPosition()^1));
+ wiiuse_set_ir_sensitivity(wm,CONF_GetIRSensitivity());
+ wiiuse_set_leds(wm,(WIIMOTE_LED_1<<(chan%WPAD_BALANCE_BOARD)),NULL);
+ wiiuse_set_speaker(wm,wpdcb->speaker_enabled);
+ __wpad_setfmt(chan);
+ __wpads_active |= (0x01<unid;
+ wpdcb = &__wpdcb[chan];
+ wpdcb->wm = wm;
+ wpdcb->queue_head = 0;
+ wpdcb->queue_tail = 0;
+ wpdcb->queue_full = 0;
+ wpdcb->queue_length = 0;
+ wpdcb->queue_ext = NULL;
+ wpdcb->idle_time = -1;
+ memset(&wpdcb->lstate,0,sizeof(WPADData));
+ memset(&wpaddata[chan],0,sizeof(WPADData));
+ memset(wpdcb->queue_int,0,(sizeof(WPADData)*EVENTQUEUE_LENGTH));
+ __wpads_active &= ~(0x01< CONF_PAD_MAX_REGISTERED) {
+ WPAD_Shutdown();
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_BADCONF;
+ }
+
+ __wpads = wiiuse_init(WPAD_MAX_WIIMOTES,__wpad_eventCB);
+ if(__wpads==NULL) {
+ WPAD_Shutdown();
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_UNKNOWN;
+ }
+
+ __wiiuse_sensorbar_enable(1);
+
+ BTE_Init();
+ BTE_SetDisconnectCallback(__wpad_disconnectCB);
+ BTE_InitCore(__initcore_finished);
+
+ if (SYS_CreateAlarm(&__wpad_timer) < 0)
+ {
+ WPAD_Shutdown();
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_UNKNOWN;
+ }
+
+ SYS_RegisterResetFunc(&__wpad_resetinfo);
+
+ tb.tv_sec = 1;
+ tb.tv_nsec = 0;
+ SYS_SetPeriodicAlarm(__wpad_timer,&tb,&tb,__wpad_timeouthandler,NULL);
+ __wpads_inited = WPAD_STATE_ENABLING;
+ }
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NONE;
+}
+
+s32 WPAD_ReadEvent(s32 chan, WPADData *data)
+{
+ u32 level;
+ u32 maxbufs,smoothed = 0;
+ struct accel_t *accel_calib = NULL;
+ struct _wpad_cb *wpdcb = NULL;
+ WPADData *lstate = NULL,*wpadd = NULL;
+
+ if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ if(__wpads[chan] && WIIMOTE_IS_SET(__wpads[chan],WIIMOTE_STATE_CONNECTED)) {
+ if(WIIMOTE_IS_SET(__wpads[chan],WIIMOTE_STATE_HANDSHAKE_COMPLETE)) {
+ wpdcb = &__wpdcb[chan];
+ if(wpdcb->queue_ext!=NULL) {
+ maxbufs = wpdcb->queue_length;
+ wpadd = wpdcb->queue_ext;
+ } else {
+ maxbufs = EVENTQUEUE_LENGTH;
+ wpadd = wpdcb->queue_int;
+ }
+ if(wpdcb->queue_full == 0) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_QUEUE_EMPTY;
+ }
+ if(data)
+ *data = wpadd[wpdcb->queue_head];
+ wpdcb->queue_head++;
+ wpdcb->queue_head %= maxbufs;
+ wpdcb->queue_full--;
+ lstate = &wpdcb->lstate;
+ accel_calib = &__wpads[chan]->accel_calib;
+ smoothed = WIIMOTE_IS_FLAG_SET(__wpads[chan], WIIUSE_SMOOTHING);
+ } else {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+ } else {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NO_CONTROLLER;
+ }
+
+ _CPU_ISR_Restore(level);
+ if(data)
+ __wpad_calc_data(data,lstate,accel_calib,smoothed);
+ return 0;
+}
+
+s32 WPAD_DroppedEvents(s32 chan)
+{
+ u32 level;
+ s32 ret;
+ int i;
+ int dropped = 0;
+
+ if(chan == WPAD_CHAN_ALL) {
+ for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ if(__wpads[chan]!=NULL) {
+ dropped = __wpdcb[chan].dropped_events;
+ __wpdcb[chan].dropped_events = 0;
+ }
+ _CPU_ISR_Restore(level);
+ return dropped;
+}
+
+s32 WPAD_Flush(s32 chan)
+{
+ s32 ret;
+ int i;
+ int count = 0;
+ if(chan == WPAD_CHAN_ALL) {
+ for(i=WPAD_CHAN_0; i= 0)
+ count++;
+ if(ret == WPAD_ERR_QUEUE_EMPTY) return count;
+ return ret;
+}
+
+s32 WPAD_ReadPending(s32 chan, WPADDataCallback datacb)
+{
+ u32 i;
+ s32 count = 0;
+ s32 ret;
+
+ if(chan == WPAD_CHAN_ALL) {
+ for(i=WPAD_CHAN_0; i= WPAD_ERR_NONE)
+ count += ret;
+ return count;
+ }
+
+ while(1)
+ {
+ ret = WPAD_ReadEvent(chan,&wpaddata[chan]);
+ if(ret < WPAD_ERR_NONE)
+ break;
+ count++;
+ }
+ if(ret == WPAD_ERR_QUEUE_EMPTY) return count;
+ return ret;
+}
+
+s32 WPAD_SetDataFormat(s32 chan, s32 fmt)
+{
+ u32 level;
+ s32 ret;
+ int i;
+
+ if(chan == WPAD_CHAN_ALL) {
+ for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ if(__wpads[chan]!=NULL) {
+ switch(fmt) {
+ case WPAD_FMT_BTNS:
+ case WPAD_FMT_BTNS_ACC:
+ case WPAD_FMT_BTNS_ACC_IR:
+ __wpdcb[chan].data_fmt = fmt;
+ __wpad_setfmt(chan);
+ break;
+ default:
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_BADVALUE;
+ }
+ }
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NONE;
+}
+
+s32 WPAD_SetMotionPlus(s32 chan, u8 enable)
+{
+ u32 level;
+ s32 ret;
+ int i;
+
+ if(chan == WPAD_CHAN_ALL) {
+ for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ if(__wpads[chan]!=NULL) {
+ wiiuse_set_motion_plus(__wpads[chan], enable);
+ }
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NONE;
+}
+
+s32 WPAD_SetVRes(s32 chan,u32 xres,u32 yres)
+{
+ u32 level;
+ s32 ret;
+ int i;
+
+ if(chan == WPAD_CHAN_ALL) {
+ for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ if(__wpads[chan]!=NULL)
+ wiiuse_set_ir_vres(__wpads[chan],xres,yres);
+
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NONE;
+}
+
+s32 WPAD_GetStatus()
+{
+ s32 ret;
+ u32 level;
+
+ _CPU_ISR_Disable(level);
+ ret = __wpads_inited;
+ _CPU_ISR_Restore(level);
+
+ return ret;
+}
+
+s32 WPAD_Probe(s32 chan,u32 *type)
+{
+ s32 ret;
+ u32 level,dev;
+ wiimote *wm = NULL;
+
+ if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ wm = __wpads[chan];
+ if(wm && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) {
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)) {
+ dev = WPAD_EXP_NONE;
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP)) {
+ switch(wm->exp.type) {
+ case WPAD_EXP_NUNCHUK:
+ case WPAD_EXP_CLASSIC:
+ dev = wm->exp.type;
+ break;
+ }
+ }
+ if(type!=NULL) *type = dev;
+ ret = WPAD_ERR_NONE;
+ } else
+ ret = WPAD_ERR_NOT_READY;
+ } else
+ ret = WPAD_ERR_NO_CONTROLLER;
+ _CPU_ISR_Restore(level);
+
+ return ret;
+}
+
+s32 WPAD_SetEventBufs(s32 chan, WPADData *bufs, u32 cnt)
+{
+ u32 level;
+ struct _wpad_cb *wpdcb = NULL;
+
+ if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ wpdcb = &__wpdcb[chan];
+ wpdcb->queue_head = 0;
+ wpdcb->queue_tail = 0;
+ wpdcb->queue_full = 0;
+ wpdcb->queue_length = cnt;
+ wpdcb->queue_ext = bufs;
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NONE;
+}
+
+void WPAD_SetPowerButtonCallback(WPADShutdownCallback cb)
+{
+ u32 level;
+
+ _CPU_ISR_Disable(level);
+ if(cb)
+ __wpad_powcb = cb;
+ else
+ __wpad_powcb = __wpad_def_powcb;
+ _CPU_ISR_Restore(level);
+}
+
+void WPAD_SetBatteryDeadCallback(WPADShutdownCallback cb)
+{
+ u32 level;
+
+ _CPU_ISR_Disable(level);
+ __wpad_batcb = cb;
+ _CPU_ISR_Restore(level);
+}
+
+s32 WPAD_Disconnect(s32 chan)
+{
+ u32 level, cnt = 0;
+ struct _wpad_cb *wpdcb = NULL;
+
+ if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ wpdcb = &__wpdcb[chan];
+ __wpad_disconnect(wpdcb);
+
+ _CPU_ISR_Restore(level);
+
+ while(__wpads_active&(0x01< 3000) break;
+ }
+
+ return WPAD_ERR_NONE;
+}
+
+void WPAD_Shutdown()
+{
+ s32 i;
+ u32 level;
+ u32 cnt = 0;
+ struct _wpad_cb *wpdcb = NULL;
+
+ _CPU_ISR_Disable(level);
+
+ __wpads_inited = WPAD_STATE_DISABLED;
+ SYS_RemoveAlarm(__wpad_timer);
+ for(i=0;isound_alarm);
+ __wpad_disconnect(wpdcb);
+ }
+
+ __wiiuse_sensorbar_enable(0);
+ _CPU_ISR_Restore(level);
+
+ while(__wpads_active) {
+ usleep(50);
+ if(++cnt > 3000) break;
+ }
+
+ BTE_Shutdown();
+}
+
+void WPAD_SetIdleTimeout(u32 seconds)
+{
+ u32 level;
+
+ _CPU_ISR_Disable(level);
+ __wpad_idletimeout = seconds;
+ _CPU_ISR_Restore(level);
+}
+
+s32 WPAD_ScanPads()
+{
+ return WPAD_ReadPending(WPAD_CHAN_ALL, NULL);
+}
+
+s32 WPAD_Rumble(s32 chan, int status)
+{
+ int i;
+ s32 ret;
+ u32 level;
+
+ if(chan == WPAD_CHAN_ALL) {
+ for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ if(__wpads[chan]!=NULL)
+ wiiuse_rumble(__wpads[chan],status);
+
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NONE;
+}
+
+s32 WPAD_SetIdleThresholds(s32 chan, s32 btns, s32 ir, s32 accel, s32 js, s32 wb, s32 mp)
+{
+ int i;
+ s32 ret;
+ u32 level;
+
+ if(chan == WPAD_CHAN_ALL) {
+ for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ __wpdcb[chan].thresh.btns = (btns<0) ? -1 : 0;
+ __wpdcb[chan].thresh.ir = ir;
+ __wpdcb[chan].thresh.acc = accel;
+ __wpdcb[chan].thresh.js = js;
+ __wpdcb[chan].thresh.mp = mp;
+
+
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NONE;
+}
+
+s32 WPAD_ControlSpeaker(s32 chan,s32 enable)
+{
+ int i;
+ s32 ret;
+ u32 level;
+
+ if(chan == WPAD_CHAN_ALL) {
+ for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ if(__wpads[chan]!=NULL) {
+ __wpdcb[chan].speaker_enabled = enable;
+ wiiuse_set_speaker(__wpads[chan],enable);
+ }
+
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NONE;
+}
+
+s32 WPAD_IsSpeakerEnabled(s32 chan)
+{
+ s32 ret;
+ u32 level;
+ wiimote *wm = NULL;
+
+ if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ wm = __wpads[chan];
+ ret = WPAD_ERR_NOT_READY;
+ if(wm && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) {
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)
+ && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) ret = WPAD_ERR_NONE;
+ }
+
+ _CPU_ISR_Restore(level);
+ return ret;
+}
+
+s32 WPAD_SendStreamData(s32 chan,void *buf,u32 len)
+{
+ u32 level;
+ struct timespec tb;
+ wiimote *wm = NULL;
+
+ if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
+
+ _CPU_ISR_Disable(level);
+ if(__wpads_inited==WPAD_STATE_DISABLED) {
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NOT_READY;
+ }
+
+ wm = __wpads[chan];
+ if(wm!=NULL && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) {
+ if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_HANDSHAKE_COMPLETE)
+ && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_SPEAKER)) {
+ __wpdcb[chan].sound_data = buf;
+ __wpdcb[chan].sound_len = len;
+ __wpdcb[chan].sound_off = 0;
+
+ tb.tv_sec = 0;
+ tb.tv_nsec = 6666667;
+ SYS_SetPeriodicAlarm(__wpdcb[chan].sound_alarm,&tb,&tb,__wpad_sounddata_alarmhandler, &__wpdcb[chan]);
+ }
+ }
+
+ _CPU_ISR_Restore(level);
+ return WPAD_ERR_NONE;
+}
+
+void WPAD_EncodeData(WPADEncStatus *info,u32 flag,const s16 *pcmSamples,s32 numSamples,u8 *encData)
+{
+ int n;
+ short *samples = (short*)pcmSamples;
+ WENCStatus *status = (WENCStatus*)info;
+
+ if(!(flag&WPAD_ENC_CONT)) status->step = 0;
+
+ n = (numSamples+1)/2;
+ for(;n>0;n--) {
+ int nibble;
+ nibble = (wencdata(status,samples[0]))<<4;
+ nibble |= (wencdata(status,samples[1]));
+ *encData++ = nibble;
+ samples += 2;
+ }
+}
+
+WPADData *WPAD_Data(int chan)
+{
+ //if(chan<0 || chan>=WPAD_MAX_WIIMOTES) return NULL;
+ return &wpaddata[chan];
+}
+
+u8 WPAD_BatteryLevel(int chan)
+{
+ //if(chan<0 || chan>=WPAD_MAX_WIIMOTES) return 0;
+ return wpaddata[chan].battery_level;
+}
+
+u32 WPAD_ButtonsHeld(int chan)
+{
+ //if(chan<0 || chan>=WPAD_MAX_WIIMOTES) return 0;
+ return wpaddata[chan].btns_h;
+}
+
+void WPAD_IR(int chan, struct ir_t *ir)
+{
+ //if(chan<0 || chan>=WPAD_MAX_WIIMOTES || ir==NULL ) return;
+ *ir = wpaddata[chan].ir;
+}
+
+void WPAD_Orientation(int chan, struct orient_t *orient)
+{
+ //if(chan<0 || chan>=WPAD_MAX_WIIMOTES || orient==NULL ) return;
+ *orient = wpaddata[chan].orient;
+}
+
+void WPAD_GForce(int chan, struct gforce_t *gforce)
+{
+ //if(chan<0 || chan>=WPAD_MAX_WIIMOTES || gforce==NULL ) return;
+ *gforce = wpaddata[chan].gforce;
+}
+
+void WPAD_Accel(int chan, struct vec3w_t *accel)
+{
+ //if(chan<0 || chan>=WPAD_MAX_WIIMOTES || accel==NULL ) return;
+ *accel = wpaddata[chan].accel;
+}
+
+void WPAD_Expansion(int chan, struct expansion_t *exp)
+{
+ //if(chan<0 || chan>=WPAD_MAX_WIIMOTES || exp==NULL ) return;
+ *exp = wpaddata[chan].exp;
+}