Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: sixad: improve coexistence of first & third-party controllers #19

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 0 additions & 4 deletions Makefile
Expand Up @@ -4,10 +4,6 @@ CXX ?= g++
CXXFLAGS += -O2 -Wall
LDFLAGS += -Wl,-Bsymbolic-functions

ifeq ($(GASIA_GAMEPAD_HACKS),1)
CXXFLAGS += -DGASIA_GAMEPAD_HACKS
endif

ifeq ($(DEVICE_SHORT_NAME),1)
CXXFLAGS += -DSHORT_NAME
endif
Expand Down
106 changes: 71 additions & 35 deletions bluetooth.cpp
Expand Up @@ -130,6 +130,25 @@ void do_connect(int ctl, bdaddr_t *src, bdaddr_t *dst, int debug)
}
}

void get_remote_name(bdaddr_t *bdaddr, char *name, int size) {

int dev_id, sock;

dev_id = hci_get_route(NULL);
sock = hci_open_dev(dev_id);

if (dev_id < 0 || sock < 0) {
syslog(LOG_ERR, "error opening socket");
return;
}

if (hci_read_remote_name(sock, bdaddr, size, name, 0) < 0)
strcpy(name, "[unknown]");

syslog(LOG_INFO, "remote name: %s", name);
close(sock);
}

int l2cap_listen(const bdaddr_t *bdaddr, unsigned short psm, int lm, int backlog)
{
struct sockaddr_l2 addr;
Expand Down Expand Up @@ -173,6 +192,8 @@ void l2cap_accept(int ctl, int csk, int isk, int debug, int legacy)
socklen_t addrlen;
bdaddr_t addr_src, addr_dst;
int ctrl_socket, intr_socket, err;
int vendor = UNKNOWN;
char name[248] = { 0 };

memset(&addr, 0, sizeof(addr));
memset(&req, 0, sizeof(req));
Expand Down Expand Up @@ -203,16 +224,25 @@ void l2cap_accept(int ctl, int csk, int isk, int debug, int legacy)
return;
}

#ifdef GASIA_GAMEPAD_HACKS
req.vendor = 0x054c;
req.product = 0x0268;
req.version = 0x0100;
req.parser = 0x0100;

strcpy(req.name, "Gasia Gamepad experimental driver");
#else
get_sdp_device_info(&addr_src, &addr_dst, &req);
#endif
// query controller name
get_remote_name(&addr_dst, name, sizeof(name));

if (strcmp(name, "PLAYSTATION(R)3 Controller") == 0)
vendor = OFFICIAL;
else if (strcmp(name, "PS(R) Gamepad") == 0)
vendor = GASIA;
else if (strcmp(name, "PLAYSTATION(R)3Conteroller-PANHAI") == 0)
vendor = SHANWAN;

if (vendor != OFFICIAL) {
req.vendor = 0x054c;
req.product = 0x0268;
req.version = 0x0100;
req.parser = 0x0100;
strcpy(req.name, name);
} else {
get_sdp_device_info(&addr_src, &addr_dst, &req);
}

if (!legacy && req.vendor == 0x054c && req.product == 0x0268) {
if (debug) syslog(LOG_INFO, "Will initiate Sixaxis now");
Expand All @@ -235,8 +265,10 @@ void l2cap_accept(int ctl, int csk, int isk, int debug, int legacy)

const char* uinput_sixaxis_cmd = "/usr/sbin/sixad-sixaxis";
const char* debug_mode = debug ? "1" : "0";
char vendor_mode[sizeof(vendor)];
sprintf(vendor_mode, "%d", vendor);

const char* argv[] = { uinput_sixaxis_cmd, bda, debug_mode, NULL };
const char* argv[] = { uinput_sixaxis_cmd, bda, debug_mode, vendor_mode, NULL };
char* envp[] = { NULL };

if (execve(argv[0], (char* const*)argv, envp) < 0) {
Expand Down Expand Up @@ -352,7 +384,9 @@ int create_device(int ctl, int csk, int isk)
socklen_t addrlen;
bdaddr_t src, dst;
char bda[18];
int err;
//int err;
int vendor = UNKNOWN;
char name[248] = { 0 };

memset(&addr, 0, sizeof(addr));
addrlen = sizeof(addr);
Expand All @@ -376,31 +410,33 @@ int create_device(int ctl, int csk, int isk)
req.flags = 0;
req.idle_to = 1800;


#ifdef GASIA_GAMEPAD_HACKS
req.vendor = 0x054c;
req.product = 0x0268;
req.version = 0x0100;
req.parser = 0x0100;

strcpy(req.name, "Gasia Gamepad experimental driver");

err = 0;
#else
err = get_sdp_device_info(&src, &dst, &req);
#endif

if (err < 0)
return err;
else {
ba2str(&dst, bda);
syslog(LOG_INFO, "Connected %s (%s)", req.name, bda);
if (req.vendor == 0x054c && req.product == 0x0268)
enable_sixaxis(csk);
err = ioctl(ctl, HIDPCONNADD, &req);
// query controller name
get_remote_name(&dst, name, sizeof(name));

if (strcmp(name, "PLAYSTATION(R)3 Controller") == 0)
vendor = OFFICIAL;
else if (strcmp(name, "PS(R) Gamepad") == 0)
vendor = GASIA;
else if (strcmp(name, "PLAYSTATION(R)3Conteroller-PANHAI") == 0)
vendor = SHANWAN;

if (vendor != OFFICIAL) {
req.vendor = 0x054c;
req.product = 0x0268;
req.version = 0x0100;
req.parser = 0x0100;
strcpy(req.name, name);
} else {
get_sdp_device_info(&src, &dst, &req);
}

return 0;
ba2str(&dst, bda);
syslog(LOG_INFO, "Connected %s (%s)", req.name, bda);
if (req.vendor == 0x054c && req.product == 0x0268)
enable_sixaxis(csk, vendor);
//err = ioctl(ctl, HIDPCONNADD, &req);

return 0;
}

int get_sdp_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req)
Expand Down
2 changes: 2 additions & 0 deletions bluetooth.h
Expand Up @@ -27,6 +27,8 @@
void do_search(int ctl, bdaddr_t *bdaddr, int debug);
void do_connect(int ctl, bdaddr_t *src, bdaddr_t *dst, int debug);

void get_remote_name(bdaddr_t *bdaddr, char *name, int size);

int l2cap_listen(const bdaddr_t *bdaddr, unsigned short psm, int lm, int backlog);
void l2cap_accept(int ctl, int csk, int isk, int debug, int legacy);
int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm);
Expand Down
52 changes: 27 additions & 25 deletions shared.cpp
Expand Up @@ -268,34 +268,36 @@ int get_joystick_number()
return js;
}

void enable_sixaxis(int csk)
void enable_sixaxis(int csk, int vendor)
{
#ifdef GASIA_GAMEPAD_HACKS
unsigned char enable[] = {
0xA2,
0x01,
0x00, 0x00, 0x00, 0x00, 0x00, // rumble values [0x00, right-timeout, right-force, left-timeout, left-force]
0x00, 0x00, 0x00, 0x00, 0x02, // 0x02=LED1 .. 0x10=LED4
0xff, 0x27, 0x10, 0x00, 0x32, // LED 4
0xff, 0x27, 0x10, 0x00, 0x32, // LED 3
0xff, 0x27, 0x10, 0x00, 0x32, // LED 2
0xff, 0x27, 0x10, 0x00, 0x32, // LED 1
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00
};
#else
char buf[128];
unsigned char enable_gasia[] = {
0xA2,
0x01,
0x00, 0x00, 0x00, 0x00, 0x00, // rumble values [0x00, right-timeout, right-force, left-timeout, left-force]
0x00, 0x00, 0x00, 0x00, 0x02, // 0x02=LED1 .. 0x10=LED4
0xff, 0x27, 0x10, 0x00, 0x32, // LED 4
0xff, 0x27, 0x10, 0x00, 0x32, // LED 3
0xff, 0x27, 0x10, 0x00, 0x32, // LED 2
0xff, 0x27, 0x10, 0x00, 0x32, // LED 1
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00
};
unsigned char enable[] = {
0x53, /* HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE */
0xf4, 0x42, 0x03, 0x00, 0x00
};
#endif
0x53, /* HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE */
0xf4, 0x42, 0x03, 0x00, 0x00
};

/* enable reporting */
send(csk, enable, sizeof(enable), 0);
#ifndef GASIA_GAMEPAD_HACKS
recv(csk, buf, sizeof(buf), 0);
#endif
if (vendor == OFFICIAL || vendor == SHANWAN) {
send(csk, enable, sizeof(enable), 0);
} else {
send(csk, enable_gasia, sizeof(enable_gasia), 0);
}

if (vendor == OFFICIAL) {
recv(csk, buf, sizeof(buf), 0);
}
}
8 changes: 7 additions & 1 deletion shared.h
Expand Up @@ -20,6 +20,12 @@

#include <unistd.h>

// vendor types
#define UNKNOWN 0
#define OFFICIAL 1
#define GASIA 2
#define SHANWAN 3

struct dev_led {
bool enabled;
bool anim;
Expand Down Expand Up @@ -86,6 +92,6 @@ void open_log(const char *app_name);
struct device_settings init_values(const char *mac);

int get_joystick_number();
void enable_sixaxis(int csk);
void enable_sixaxis(int csk, int vendor);

#endif // SHARED_H
16 changes: 9 additions & 7 deletions sixad-sixaxis.cpp
Expand Up @@ -31,6 +31,7 @@
int csk = 0;
int isk = 1;
int debug;
int vendor;

int led_n;
bool old_rumble_mode;
Expand Down Expand Up @@ -126,14 +127,14 @@ static void uinput_listen()
if (event.value) {
for (i=0; i<MAX_RUMBLE_EFFECTS; i++) {
if (effects[i].id == event.code) {
do_rumble(csk, led_n, effects[i].weak, effects[i].strong, effects[i].timeout);
do_rumble(csk, vendor, led_n, effects[i].weak, effects[i].strong, effects[i].timeout);
if (debug) syslog(LOG_INFO, "RUMBLE now :: %i|%i|%i", effects[i].weak, effects[i].strong, effects[i].timeout);
break;
}
}
} else {
if (!old_rumble_mode) {
do_rumble(csk, led_n, 0, 0, 0);
do_rumble(csk, vendor, led_n, 0, 0, 0);
if (debug) syslog(LOG_INFO, "RUMBLE clean");
}
}
Expand All @@ -150,7 +151,7 @@ static void rumble_listen()
{
while (!io_canceled()) {
if (active) {
do_rumble(csk, led_n, weak, strong, timeout);
do_rumble(csk, vendor, led_n, weak, strong, timeout);
active = false;
} else
usleep(5000);
Expand Down Expand Up @@ -268,6 +269,7 @@ int main(int argc, char *argv[])

const char *mac = argv[1];
debug = atoi(argv[2]);
vendor = atoi(argv[3]);

open_log("sixad-sixaxis");
syslog(LOG_INFO, "started");
Expand All @@ -283,8 +285,8 @@ int main(int argc, char *argv[])
return 1;
}

enable_sixaxis(csk);
led_n = set_sixaxis_led(csk, settings.led, settings.rumble.enabled);
enable_sixaxis(csk, vendor);
led_n = set_sixaxis_led(csk, vendor, settings.led, settings.rumble.enabled);

if (settings.rumble.enabled) {
old_rumble_mode = settings.rumble.old_mode;
Expand Down Expand Up @@ -381,9 +383,9 @@ int main(int argc, char *argv[])
uinput_close(ufd->mk, debug);
}

do_rumble(csk, 10, 0xff, 0xff, 0x01);
do_rumble(csk, vendor, 10, 0xff, 0xff, 0x01);
usleep(10*1000);

delete ufd;

shutdown(isk, SHUT_RDWR); // Shutdown Interupt socket.
Expand Down
36 changes: 11 additions & 25 deletions sixaxis.cpp
Expand Up @@ -388,14 +388,10 @@ void do_input(int fd, unsigned char* buf, struct dev_input input)

}

void do_rumble(int csk, int led_n, int weak, int strong, int timeout)
void do_rumble(int csk, int vendor, int led_n, int weak, int strong, int timeout)
{
unsigned char setrumble[] = {
#ifdef GASIA_GAMEPAD_HACKS
0x92,
#else
0x52, /* HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUTPUT */
#endif
(vendor == GASIA ? (unsigned char)0x92 : (unsigned char)0x52), /* HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUTPUT */
0x01,
0x00, 0x00, 0x00, 0x00, 0x00, // rumble values [0x00, right-timeout, right-force, left-timeout, left-force]
0x00, 0x00, 0x00, 0x00, 0x1E, // 0x02=LED1 .. 0x10=LED4
Expand Down Expand Up @@ -432,27 +428,20 @@ void do_rumble(int csk, int led_n, int weak, int strong, int timeout)

setrumble[11] = ledpattern[led_n]; //keep old led
send(csk, setrumble, sizeof(setrumble), 0);
#ifndef GASIA_GAMEPAD_HACKS
unsigned char buf[128];
recv(csk, buf, sizeof(buf), 0); //MSG_DONTWAIT?
#endif
if (vendor == OFFICIAL) {
unsigned char buf[128];
recv(csk, buf, sizeof(buf), 0); //MSG_DONTWAIT?
}
}

int set_sixaxis_led(int csk, struct dev_led led, int rumble)
int set_sixaxis_led(int csk, int vendor, struct dev_led led, int rumble)
{
int led_n, led_number;

#ifndef GASIA_GAMEPAD_HACKS
int i;
unsigned char buf[128];
#endif

unsigned char setleds[] = {
#ifdef GASIA_GAMEPAD_HACKS
0x92,
#else
0x52, /* HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUTPUT */
#endif
(vendor == GASIA ? (unsigned char)0x92 : (unsigned char)0x52), /* HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUTPUT */
0x01,
0x00, 0x00, 0x00, 0x00, 0x00, // rumble values [0x00, right-timeout, right-force, left-timeout, left-force]
0x00, 0x00, 0x00, 0x00, 0x1E, // 0x02=LED1 .. 0x10=LED4
Expand Down Expand Up @@ -485,8 +474,7 @@ int set_sixaxis_led(int csk, struct dev_led led, int rumble)
} else
led_n = 0;

#ifndef GASIA_GAMEPAD_HACKS
if (led.enabled && led.anim)
if (vendor != GASIA && led.enabled && led.anim)
{
/* Sixaxis LED animation - Way Cool!! */
if (rumble) setleds[3] = setleds[5] = 0xfe;
Expand Down Expand Up @@ -549,15 +537,13 @@ int set_sixaxis_led(int csk, struct dev_led led, int rumble)
recv(csk, buf, sizeof(buf), 0);
}
}
#endif

/* set LEDs (final) */
setleds[11] = ledpattern[led_n];
if (rumble) setleds[3] = setleds[4] = setleds[5] = setleds[6] = 0x00;
send(csk, setleds, sizeof(setleds), 0);
#ifndef GASIA_GAMEPAD_HACKS
recv(csk, buf, sizeof(buf), 0);
#endif
if (vendor == OFFICIAL)
recv(csk, buf, sizeof(buf), 0);

return led_n;
}