Jorix
New member
I made a patch that adds rumblepak support to Blight's input plugin!
Last sunday I found/created a driver for the rumble function of my controller, but the only Linux game I know that uses it is bzflag. So I decided to add support for it in mupen64 (many games at once
). As I didn't find any documentation on how the plugins should work I decided to peek in the source code of the N-rage plugin to see how it should work and the fftest utility for an example of force feedback in Linux.
This patch is for version 0.0.10 of blight's input plugin as found in the mupen64 0.5 source code.
I added two extra configureable buttons to switch to either mempak or rumble pak, but it seems it doesn't work directly in game unless I make completely custom mempak handling, which is way too much work. So instead after you press the switch button, make a savestate and restart the rom to activate the changes.
The code is licensed under the GPL v2 of course just like the rest of blights input plugin.
Last sunday I found/created a driver for the rumble function of my controller, but the only Linux game I know that uses it is bzflag. So I decided to add support for it in mupen64 (many games at once
This patch is for version 0.0.10 of blight's input plugin as found in the mupen64 0.5 source code.
I added two extra configureable buttons to switch to either mempak or rumble pak, but it seems it doesn't work directly in game unless I make completely custom mempak handling, which is way too much work. So instead after you press the switch button, make a savestate and restart the rom to activate the changes.
The code is licensed under the GPL v2 of course just like the rest of blights input plugin.
Code:
diff blight_input_orig/configdialog_sdl.c blight_input/configdialog_sdl.c
55a56,57
> "Mempak switch",
> "Rumblepak switch",
105c107
< { checkbutton_clicked, 1, 120, 45, 90, 25 }, // mempak
---
> { checkbutton_clicked, 1, 120, 45, 100, 25 }, // plugin
122a125,126
> { pad_button_clicked, MEMPAK, 110, 350, 150, 20 },
> { pad_button_clicked, RUMBLEPAK, 110, 375, 150, 20 },
206c210
< memcpy( orig_cont[i].button, config[i].button, sizeof( SButtonMap ) * 14 );
---
> memcpy( orig_cont[i].button, config[i].button, sizeof( SButtonMap ) * 16 );
232c236
< if( config[cont].control.Plugin == PLUGIN_MEMPAK )
---
> if( config[cont].control.Plugin == PLUGIN_RAW )
234c238
< else
---
> else if( config[cont].control.Plugin == PLUGIN_NONE )
235a240,241
> else
> config[cont].control.Plugin = PLUGIN_RAW;
715a722,723
> write_text( screen, 110, 350, black, gray, button_names[MEMPAK] );
> write_text( screen, 110, 375, black, gray, button_names[RUMBLEPAK] );
727c735
< dstrect.x = 120; dstrect.y = 45; dstrect.w = 90; dstrect.h = 25;
---
> dstrect.x = 120; dstrect.y = 45; dstrect.w = 100; dstrect.h = 25;
730,731c738,744
< SDL_FillRect( screen, &dstrect, (config[cont].control.Plugin == PLUGIN_MEMPAK) ? u32gray : u32dark_gray );
< write_text( screen, dstrect.x + 12, dstrect.y, black, (config[cont].control.Plugin == PLUGIN_MEMPAK) ? gray : dark_gray, "Mem Pak" );
---
> SDL_FillRect( screen, &dstrect, (config[cont].control.Plugin != PLUGIN_NONE) ? u32gray : u32dark_gray );
> if (config[cont].control.Plugin == PLUGIN_NONE)
> write_text( screen, dstrect.x + 12, dstrect.y, black, dark_gray, "None" );
> if (config[cont].control.Plugin == PLUGIN_MEMPAK)
> write_text( screen, dstrect.x + 12, dstrect.y, black, gray, "Mem Pak" );
> if (config[cont].control.Plugin == PLUGIN_RAW)
> write_text( screen, dstrect.x + 12, dstrect.y, black, gray, "Rumble Pak" );
963c976
< memcpy( config[i].button, orig_cont[i].button, sizeof( SButtonMap ) * 14 );
---
> memcpy( config[i].button, orig_cont[i].button, sizeof( SButtonMap ) * 16 );
Common subdirectories: blight_input_orig/font and blight_input/font
diff blight_input_orig/plugin.c blight_input/plugin.c
17a18,24
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> #include <unistd.h>
> #include <dirent.h>
> #include <linux/input.h>
>
52c59,61
< 0x2000 // L_TRIG
---
> 0x2000, // L_TRIG
> 0x4000, // Mempak switch
> 0x8000 // Rumblepak switch
72a82,83
> "Mempak switch",
> "Rumblepak switch",
159c170
< int cont, plugged, mempak, mouse, i, b, dev;
---
> int cont, plugged, plugin, mouse, i, b, dev;
172c183
< for( b = 0; b < 14; b++ )
---
> for( b = 0; b < 16; b++ )
212c223
< if( sscanf( line, "mempak=%d", &mempak ) == 1 )
---
> if( sscanf( line, "plugin=%d", &plugin ) == 1 )
214,215c225
< if( mempak )
< controller[cont].control.Plugin = PLUGIN_MEMPAK;
---
> controller[cont].control.Plugin = plugin;
262c272
< printf( "%s, %d: num = %d, key_a = %s, key_b = %s, button_a = %s, button_b = %s, axis = %s, hat = %s, hat_pos_a = %s, hat_pos_b = %s\n", __FILE__, __LINE__, num,
---
> printf( "%s, %d: num = %d, key_a = %s, key_b = %s, button_a = %s, button_b = %s, axis = %s, hat = %s, hat_pos_a = %s, hat_pos_b = %s\n", button, b, num,
292c302
< printf( "%s, %d: num = %d, key = %s, button = %s, axis = %s, hat = %s, hat_pos = %s, mbutton = %s\n", __FILE__, __LINE__, num, key_a, button_a, axis, hat, hat_pos_a, mbutton );
---
> printf( "%s, %d: num = %d, key = %s, button = %s, axis = %s, hat = %s, hat_pos = %s, mbutton = %s\n", button, b, num, key_a, button_a, axis, hat, hat_pos_a, mbutton );
354c364
< fprintf( f, "mempak=%d\n", (controller[i].control.Plugin == PLUGIN_MEMPAK) ? 1 : 0 ); // ???
---
> fprintf( f, "plugin=%d\n", controller[i].control.Plugin );
363c373
< for( b = 0; b < 14; b++ )
---
> for( b = 0; b < 16; b++ )
427c437
< fprintf( f, "%s=key( %s , %s ); button( %s , %s ); axis( %s ); hat( %s , %s , %s )\n", button_names[b+14],
---
> fprintf( f, "%s=key( %s , %s ); button( %s , %s ); axis( %s ); hat( %s , %s , %s )\n", button_names[b+16],
466a477,507
>
> BYTE lastCommand[6];
>
> struct ff_effect ffeffect[3];
> struct ff_effect ffstrong[3];
> struct ff_effect ffweak[3];
>
> BYTE DataCRC( BYTE *Data, int iLenght )
> {
> register BYTE Remainder = Data[0];
>
> int iByte = 1;
> BYTE bBit = 0;
>
> while( iByte <= iLenght )
> {
> BOOL HighBit = ((Remainder & 0x80) != 0);
> Remainder = Remainder << 1;
>
> Remainder += ( iByte < iLenght && Data[iByte] & (0x80 >> bBit )) ? 1 : 0;
>
> Remainder ^= (HighBit) ? 0x85 : 0;
>
> bBit++;
> iByte += bBit/8;
> bBit %= 8;
> }
>
> return Remainder;
> }
>
470,474c511,591
< #if 0//def _DEBUG
< printf( "\nRaw Command (cont=%d):\n", Control );
< printf( "\t%02X %02X %02X %02X %02X %02X\n", Command[0], Command[1],
< Command[2], Command[3], Command[4], Command[5]);//, Command[6], Command[7] );
< #endif
---
> BYTE *Data = &Command[5];
> struct input_event play;
>
> if( Control == -1 )
> return;
>
> switch (Command[2]){
> case RD_GETSTATUS:
> {
> /*printf( "Get status\n" );*/
> break;
> }
> case RD_READKEYS:
> {
> /*printf( "Read keys\n" );*/
> break;
> }
> case RD_READPAK:
> {
> /*printf( "Read pak\n" );*/
> if (controller[Control].control.Plugin == PLUGIN_RAW)
> {
> DWORD dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
>
> if(( dwAddress >= 0x8000 ) && ( dwAddress < 0x9000 ) )
> memset( Data, 0x80, 32 );
> else
> memset( Data, 0x00, 32 );
>
> Data[32] = DataCRC( Data, 32 );
> break;
> }
> }
> case RD_WRITEPAK:
> {
> /*printf( "Write pak\n" );*/
> if (controller[Control].control.Plugin == PLUGIN_RAW)
> {
> DWORD dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
> if( dwAddress == PAK_IO_RUMBLE && controller[Control].event_joystick != 0)
> {
> if( *Data )
> {
> play.type = EV_FF;
> play.code = ffeffect[Control].id;
> play.value = 1;
>
> if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
> perror("Error starting rumble effect");
> }
> else
> {
> play.type = EV_FF;
> play.code = ffeffect[Control].id;
> play.value = 0;
>
> if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
> perror("Error stopping rumble effect");
> }
> }
>
> Data[32] = DataCRC( Data, 32 );
>
> break;
> }
> }
> case RD_RESETCONTROLLER:
> {
> /*printf( "Reset controller\n" );*/
> break;
> }
> case RD_READEEPROM:
> {
> /*printf( "Read eeprom\n" );*/
> break;
> }
> case RD_WRITEEPROM:
> {
> /*printf( "Write eeprom\n" );*/
> break;
> }}
754a872
> struct input_event play;
767c885
< for( b = 0; b < 14; b++ )
---
> for( b = 0; b < 16; b++ )
830c948
< for( b = 0; b < 14; b++ )
---
> for( b = 0; b < 16; b++ )
864c982
< for( b = 0; b < 14; b++ )
---
> for( b = 0; b < 16; b++ )
918a1037,1058
> if (controller[Control].buttons.button & button_bits[14])
> {
> controller[Control].control.Plugin = PLUGIN_MEMPAK;
> play.type = EV_FF;
> play.code = ffweak[Control].id;
> play.value = 1;
>
> if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
> perror("Error starting rumble effect");
> }
>
> if (controller[Control].buttons.button & button_bits[15])
> {
> controller[Control].control.Plugin = PLUGIN_RAW;
> play.type = EV_FF;
> play.code = ffstrong[Control].id;
> play.value = 1;
>
> if (write(controller[Control].event_joystick, (const void*) &play, sizeof(play)) == -1)
> perror("Error starting rumble effect");
> }
>
937a1078,1081
> DIR *dp;
> struct dirent *ep;
> char temp[64];
> char temp2[64];
945a1090
> {
947a1093,1148
> sprintf(temp,"/sys/class/input/js%d/device",controller[i].device);
> dp = opendir ( temp );
>
> if (dp != NULL)
> {
> while ((ep = readdir (dp)))
> if (!strncmp(ep->d_name,"input:event",11))
> {
> sscanf(ep->d_name,"input:%s",temp2);
> sprintf(temp,"/dev/input/%s",temp2);
> }
> (void) closedir (dp);
> }
>
> controller[i].event_joystick = open(temp, O_RDWR);
> if (controller[i].event_joystick == -1)
> {
> controller[i].event_joystick = 0;
> }
> /*else if (ioctl(controller[i].event_joystick, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features) == -1)
> {
> perror("Ioctl query");
> controller[i].event_joystick = 0;
> }*/
> else
> {
> ffeffect[i].type = FF_RUMBLE;
> ffeffect[i].id = -1;
> ffeffect[i].u.rumble.strong_magnitude = 0xFFFF;
> ffeffect[i].u.rumble.weak_magnitude = 0xFFFF;
>
> if (ioctl(controller[i].event_joystick, EVIOCSFF, &ffeffect[i]) == -1)
> perror("Upload effect");
>
> ffstrong[i].type = FF_RUMBLE;
> ffstrong[i].id = -1;
> ffstrong[i].u.rumble.strong_magnitude = 0xFFFF;
> ffstrong[i].u.rumble.weak_magnitude = 0x0000;
> ffstrong[i].replay.length = 500;
> ffstrong[i].replay.delay = 0;
>
> if (ioctl(controller[i].event_joystick, EVIOCSFF, &ffstrong[i]) == -1)
> perror("Upload effect");
>
> ffweak[i].type = FF_RUMBLE;
> ffweak[i].id = -1;
> ffweak[i].u.rumble.strong_magnitude = 0x0000;
> ffweak[i].u.rumble.weak_magnitude = 0xFFFF;
> ffweak[i].replay.length = 500;
> ffweak[i].replay.delay = 0;
>
> if (ioctl(controller[i].event_joystick, EVIOCSFF, &ffweak[i]) == -1)
> perror("Upload effect");
> }
> }
>
diff blight_input_orig/plugin.h blight_input/plugin.h
32d31
<
35a35,45
> // Some stuff from n-rage plugin
> #define RD_GETSTATUS 0x00 // get status
> #define RD_READKEYS 0x01 // read button values
> #define RD_READPAK 0x02 // read from controllerpack
> #define RD_WRITEPAK 0x03 // write to controllerpack
> #define RD_RESETCONTROLLER 0xff // reset controller
> #define RD_READEEPROM 0x04 // read eeprom
> #define RD_WRITEEPROM 0x05 // write eeprom
>
> #define PAK_IO_RUMBLE 0xC000 // the address where rumble-commands are sent to
>
51a62,63
> MEMPAK,
> RUMBLEPAK,
80c92
< SButtonMap button[14]; // 14 buttons; in the order of EButton
---
> SButtonMap button[16]; // 14 buttons; in the order of EButton
84a97,98
> int event_joystick; // the /dev/input/eventX device for force feeback
>
diff blight_input_orig/SDL_ttf.c blight_input/SDL_ttf.c
51c51
< #include <freetype/internal/ftobjs.h>
---
> /*#include <freetype/internal/ftobjs.h>*/
278c278
< stream->memory = library->memory;
---
> /* stream->memory = library->memory;*/