Line 64: |
Line 64: |
| |} | | |} |
| | | |
− | For example, to reset the Bluetooth HCI (and therefore break the connection with the [[Wiimote]]), send a message with the parameters (0x20,0,0,0,0x0300,0) and data 03 0C 00. (0x0300 is the length, 3, in little-endian format). The operation returns the number of bytes read or written. | + | For example, to reset the Bluetooth HCI (and therefore break the connection with the [[Wiimote]]), send a message with the parameters (0x20,0,0,0,0x0300,0) and data 03 0C 00. (0x0300 is the length, 3, in little-endian format). The operation returns the number of bytes read or written. Vectors are an array of the following structure: |
| + | typedef struct _ioctlv |
| + | { |
| + | /** Pointer to _aligned_ data to be transfered. */ |
| + | void *data; |
| + | /** Size of data in byte. */ |
| + | u32 len; |
| + | } ioctlv; |
| | | |
| === Send Or Receive Bulk/Interrupt Message === | | === Send Or Receive Bulk/Interrupt Message === |
Line 99: |
Line 106: |
| | | |
| The same request is used for both sending and receiving data. Which operation is used depends on the endpoint number (>=0x80 are input endpoints, <0x80 are output). The operation returns the number of bytes read or written. | | The same request is used for both sending and receiving data. Which operation is used depends on the endpoint number (>=0x80 are input endpoints, <0x80 are output). The operation returns the number of bytes read or written. |
| + | |
| + | |
| + | |
| + | == Example Code: Reset Bluetooth == |
| + | |
| + | Here is an example code which resets the internal bluetooth dongle and breaks the connection to the wiimote. To compile it, you need devkitPro/devkitPPC and libogc with WII support. |
| + | |
| + | <pre> |
| + | #include <stdio.h> |
| + | #include <stdint.h> |
| + | #include <stdlib.h> |
| + | #include <string.h> |
| + | #include <malloc.h> |
| + | #include <ogcsys.h> |
| + | #include <gccore.h> |
| + | #include <ogc/ipc.h> |
| + | #include <ogc/pad.h> |
| + | |
| + | /** Enable interrupt flag. */ |
| + | #define MSR_EE 0x00008000 |
| + | |
| + | /** Disable interrupts. */ |
| + | #define _CPU_ISR_Disable( _isr_cookie ) \ |
| + | { register u32 _disable_mask = MSR_EE; \ |
| + | _isr_cookie = 0; \ |
| + | asm volatile ( \ |
| + | "mfmsr %0; andc %1,%0,%1; mtmsr %1" : \ |
| + | "=&r" ((_isr_cookie)), "=&r" ((_disable_mask)) : \ |
| + | "0" ((_isr_cookie)), "1" ((_disable_mask)) \ |
| + | ); \ |
| + | } |
| + | |
| + | /** Alignment required for USB structures (I don't know if this is 32 or less). */ |
| + | #define USB_ALIGN __attribute__ ((aligned(32))) |
| + | |
| + | static void *xfb = NULL; |
| + | static GXRModeObj *rmode = NULL; |
| + | |
| + | /** Entry point for Twilight Hack. */ |
| + | static void ( * Reload ) () = ( void ( * ) () ) 0x80001800; |
| + | |
| + | /** Return buttons pressed on gamecube controller. */ |
| + | u16 getButtons(void) |
| + | { |
| + | PAD_ScanPads(); |
| + | |
| + | return PAD_ButtonsDown(0); |
| + | } |
| + | |
| + | char bluetoothResetData1[] USB_ALIGN = { |
| + | /* bmRequestType */ |
| + | 0x20 |
| + | }; |
| + | |
| + | char bluetoothResetData2[] USB_ALIGN = { |
| + | /* bmRequest */ |
| + | 0x00 |
| + | }; |
| + | |
| + | char bluetoothResetData3[] USB_ALIGN = { |
| + | /* wValue */ |
| + | 0x00, 0x00 |
| + | }; |
| + | |
| + | char bluetoothResetData4[] USB_ALIGN = { |
| + | /* wIndex */ |
| + | 0x00, 0x00 |
| + | }; |
| + | |
| + | char bluetoothResetData5[] USB_ALIGN = { |
| + | /* wLength */ |
| + | 0x03, 0x00 |
| + | }; |
| + | |
| + | char bluetoothResetData6[] USB_ALIGN = { |
| + | /* unknown; set to zero. */ |
| + | 0x00 |
| + | }; |
| + | |
| + | char bluetoothResetData7[] USB_ALIGN = { |
| + | /* Mesage payload. */ |
| + | 0x03, 0x0c, 0x00 |
| + | }; |
| + | |
| + | /** Vectors of data transfered. */ |
| + | ioctlv bluetoothReset[] USB_ALIGN = { |
| + | { |
| + | bluetoothResetData1, |
| + | sizeof(bluetoothResetData1) |
| + | }, |
| + | { |
| + | bluetoothResetData2, |
| + | sizeof(bluetoothResetData2) |
| + | }, |
| + | { |
| + | bluetoothResetData3, |
| + | sizeof(bluetoothResetData3) |
| + | }, |
| + | { |
| + | bluetoothResetData4, |
| + | sizeof(bluetoothResetData4) |
| + | }, |
| + | { |
| + | bluetoothResetData5, |
| + | sizeof(bluetoothResetData5) |
| + | }, |
| + | { |
| + | bluetoothResetData6, |
| + | sizeof(bluetoothResetData6) |
| + | }, |
| + | { |
| + | bluetoothResetData7, |
| + | sizeof(bluetoothResetData7) |
| + | } |
| + | }; |
| + | |
| + | /** Entry point of example program. */ |
| + | int main(int argc, char **argv) { |
| + | s32 fd; |
| + | int rv; |
| + | uint32_t level; |
| + | |
| + | VIDEO_Init(); |
| + | PAD_Init(); |
| + | |
| + | switch(VIDEO_GetCurrentTvMode()) { |
| + | case VI_NTSC: |
| + | rmode = &TVNtsc480IntDf; |
| + | break; |
| + | case VI_PAL: |
| + | rmode = &TVPal528IntDf; |
| + | break; |
| + | case VI_MPAL: |
| + | rmode = &TVMpal480IntDf; |
| + | break; |
| + | default: |
| + | rmode = &TVNtsc480IntDf; |
| + | break; |
| + | } |
| + | |
| + | xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); |
| + | console_init(xfb, 20, 20, |
| + | rmode->fbWidth, |
| + | rmode->xfbHeight, |
| + | rmode->fbWidth * VI_DISPLAY_PIX_SZ); |
| + | |
| + | VIDEO_Configure(rmode); |
| + | VIDEO_SetNextFramebuffer(xfb); |
| + | VIDEO_SetBlack(FALSE); |
| + | VIDEO_Flush(); |
| + | VIDEO_WaitVSync(); |
| + | if(rmode->viTVMode&VI_NON_INTERLACE) { |
| + | VIDEO_WaitVSync(); |
| + | } |
| + | |
| + | printf("Wiimote Bluetooth Reset Example\n"); |
| + | |
| + | printf("Open Bluetooth Dongle\n"); |
| + | fd = IOS_Open("/dev/usb/oh1/57e/305", 2 /* 2 = write, 1 = read */); |
| + | printf("fd = %d\n", fd); |
| + | |
| + | printf("Closing connection to blutooth\n"); |
| + | rv = IOS_Ioctlv(fd, 0, 6, 1, bluetoothReset); |
| + | printf("ret = %d\n", rv); |
| + | |
| + | IOS_Close(fd); |
| + | |
| + | printf("Press Z to load other application.\n"); |
| + | |
| + | while (!(getButtons() & PAD_TRIGGER_Z)) { |
| + | } |
| + | |
| + | /* Restart Twilight Hack. */ |
| + | _CPU_ISR_Disable(level); |
| + | Reload(); |
| + | |
| + | return 0; |
| + | } |