mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-17 01:04:40 +08:00
7d3d42ac10
The name won't be there until we connect otherwise
300 lines
8.1 KiB
C
300 lines
8.1 KiB
C
/* To compile
|
|
* gcc -g -Wall -I../src -I../lib/ -I../include -DSTORAGEDIR=\"/var/lib/bluetooth\" -o sixpair sixpair.c ../src/storage.c ../common/libhelper.a -I../common `pkg-config --libs --cflags glib-2.0 libusb-1.0` -lbluetooth
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <inttypes.h>
|
|
|
|
#include <sdp.h>
|
|
#include <bluetooth/bluetooth.h>
|
|
#include <bluetooth/sdp_lib.h>
|
|
#include <glib.h>
|
|
#include <libusb.h>
|
|
|
|
#include "storage.h"
|
|
|
|
/* Vendor and product ID for the Sixaxis PS3 controller */
|
|
#define VENDOR 0x054c
|
|
#define PRODUCT 0x0268
|
|
|
|
#define PS3_PNP_RECORD "3601920900000A000100000900013503191124090004350D35061901000900113503190011090006350909656E09006A0901000900093508350619112409010009000D350F350D350619010009001335031900110901002513576972656C65737320436F6E74726F6C6C65720901012513576972656C65737320436F6E74726F6C6C6572090102251B536F6E7920436F6D707574657220456E7465727461696E6D656E740902000901000902010901000902020800090203082109020428010902052801090206359A35980822259405010904A101A102850175089501150026FF00810375019513150025013500450105091901291381027501950D0600FF8103150026FF0005010901A10075089504350046FF0009300931093209358102C0050175089527090181027508953009019102750895300901B102C0A1028502750895300901B102C0A10285EE750895300901B102C0A10285EF750895300901B102C0C0090207350835060904090901000902082800090209280109020A280109020B09010009020C093E8009020D280009020E2800"
|
|
|
|
gboolean option_get_master = TRUE;
|
|
char *option_master= NULL;
|
|
gboolean option_store_info = TRUE;
|
|
const char *option_device = NULL;
|
|
gboolean option_quiet = FALSE;
|
|
|
|
const GOptionEntry options[] = {
|
|
{ "get-master", '\0', 0, G_OPTION_ARG_NONE, &option_get_master, "Get currently set master address", NULL },
|
|
{ "set-master", '\0', 0, G_OPTION_ARG_STRING, &option_master, "Set master address (\"auto\" for automatic)", NULL },
|
|
{ "store-info", '\0', 0, G_OPTION_ARG_NONE, &option_store_info, "Store the HID info into the input database", NULL },
|
|
{ "device", '\0', 0, G_OPTION_ARG_STRING, &option_device, "Only handle one device (default, all supported", NULL },
|
|
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &option_quiet, "Quieten the output", NULL },
|
|
{ NULL }
|
|
};
|
|
|
|
static gboolean
|
|
show_master (libusb_device_handle *devh, int itfnum)
|
|
{
|
|
unsigned char msg[8];
|
|
int res;
|
|
|
|
res = libusb_control_transfer (devh,
|
|
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
|
|
0x01, 0x03f5, itfnum,
|
|
(void*) msg, sizeof(msg),
|
|
5000);
|
|
|
|
if (res < 0) {
|
|
g_warning ("Getting the master Bluetooth address failed");
|
|
return FALSE;
|
|
}
|
|
g_print ("Current Bluetooth master: %02X:%02X:%02X:%02X:%02X:%02X\n",
|
|
msg[2], msg[3], msg[4], msg[5], msg[6], msg[7]);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static char *
|
|
get_bdaddr (libusb_device_handle *devh, int itfnum)
|
|
{
|
|
unsigned char msg[17];
|
|
char *address;
|
|
int res;
|
|
|
|
res = libusb_control_transfer (devh,
|
|
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
|
|
0x01, 0x03f2, itfnum,
|
|
(void*) msg, sizeof(msg),
|
|
5000);
|
|
|
|
if (res < 0) {
|
|
g_warning ("Getting the device Bluetooth address failed");
|
|
return NULL;
|
|
}
|
|
|
|
address = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
|
|
msg[4], msg[5], msg[6], msg[7], msg[8], msg[9]);
|
|
|
|
if (option_quiet == FALSE) {
|
|
g_print ("Device Bluetooth address: %s\n", address);
|
|
}
|
|
|
|
return address;
|
|
}
|
|
|
|
static gboolean
|
|
set_master_bdaddr (libusb_device_handle *devh, int itfnum, char *host)
|
|
{
|
|
unsigned char msg[8];
|
|
int mac[6];
|
|
int res;
|
|
|
|
if (sscanf(host, "%X:%X:%X:%X:%X:%X",
|
|
&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
|
|
return FALSE;
|
|
}
|
|
|
|
msg[0] = 0x01;
|
|
msg[1] = 0x00;
|
|
msg[2] = mac[0];
|
|
msg[3] = mac[1];
|
|
msg[4] = mac[2];
|
|
msg[5] = mac[3];
|
|
msg[6] = mac[4];
|
|
msg[7] = mac[5];
|
|
|
|
res = libusb_control_transfer (devh,
|
|
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
|
|
0x09, 0x03f5, itfnum,
|
|
(void*) msg, sizeof(msg),
|
|
5000);
|
|
|
|
if (res < 0) {
|
|
g_warning ("Setting the master Bluetooth address failed");
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static char *
|
|
get_host_bdaddr (void)
|
|
{
|
|
FILE *f;
|
|
int mac[6];
|
|
|
|
//FIXME use dbus to get the default adapter
|
|
|
|
f = popen("hcitool dev", "r");
|
|
|
|
if (f == NULL) {
|
|
//FIXME
|
|
return NULL;
|
|
}
|
|
if (fscanf(f, "%*s\n%*s %X:%X:%X:%X:%X:%X",
|
|
&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
|
|
//FIXME
|
|
return NULL;
|
|
}
|
|
|
|
return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
}
|
|
|
|
static int
|
|
handle_device (libusb_device *dev, struct libusb_config_descriptor *cfg, int itfnum, const struct libusb_interface_descriptor *alt)
|
|
{
|
|
libusb_device_handle *devh;
|
|
int res, retval;
|
|
|
|
retval = -1;
|
|
|
|
if (libusb_open (dev, &devh) < 0) {
|
|
g_warning ("Can't open device");
|
|
goto bail;
|
|
}
|
|
libusb_detach_kernel_driver (devh, itfnum);
|
|
|
|
res = libusb_claim_interface (devh, itfnum);
|
|
if (res < 0) {
|
|
g_warning ("Can't claim interface %d", itfnum);
|
|
goto bail;
|
|
}
|
|
|
|
if (option_get_master != FALSE) {
|
|
if (show_master (devh, itfnum) == FALSE)
|
|
goto bail;
|
|
retval = 0;
|
|
}
|
|
|
|
if (option_master != NULL) {
|
|
if (strcmp (option_master, "auto") == 0) {
|
|
g_free (option_master);
|
|
option_master = get_host_bdaddr ();
|
|
if (option_master == NULL) {
|
|
g_warning ("Can't get bdaddr from default device");
|
|
retval = -1;
|
|
goto bail;
|
|
}
|
|
}
|
|
} else {
|
|
option_master = get_host_bdaddr ();
|
|
if (option_master == NULL) {
|
|
g_warning ("Can't get bdaddr from default device");
|
|
retval = -1;
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
if (option_store_info != FALSE) {
|
|
sdp_record_t *rec;
|
|
char *device;
|
|
bdaddr_t dst, src;
|
|
|
|
device = get_bdaddr (devh, itfnum);
|
|
if (device == NULL) {
|
|
retval = -1;
|
|
goto bail;
|
|
}
|
|
|
|
rec = record_from_string (PS3_PNP_RECORD);
|
|
store_record(option_master, device, rec);
|
|
write_trust(option_master, device, "[all]", TRUE);
|
|
store_device_id(option_master, device, 0xffff, 0x054c, 0x0268, 0);
|
|
str2ba(option_master, &src);
|
|
str2ba(device, &dst);
|
|
write_device_profiles(&src, &dst, "");
|
|
write_device_name(&src, &dst, "PLAYSTATION(R)3 Controller");
|
|
sdp_record_free(rec);
|
|
|
|
if (set_master_bdaddr (devh, itfnum, option_master) == FALSE) {
|
|
retval = -1;
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
bail:
|
|
libusb_release_interface (devh, itfnum);
|
|
res = libusb_attach_kernel_driver(devh, itfnum);
|
|
if (res < 0) {
|
|
//FIXME sometimes the kernel tells us ENOENT, but succeeds anyway...
|
|
g_warning ("Reattaching the driver failed: %d", res);
|
|
}
|
|
if (devh != NULL)
|
|
libusb_close (devh);
|
|
|
|
return retval;
|
|
}
|
|
|
|
int main (int argc, char **argv)
|
|
{
|
|
GOptionContext *context;
|
|
GError *error = NULL;
|
|
libusb_device **list;
|
|
ssize_t num_devices, i;
|
|
|
|
context = g_option_context_new ("- Manage Sixaxis PS3 controllers");
|
|
g_option_context_add_main_entries (context, options, NULL);
|
|
if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) {
|
|
g_warning ("Couldn't parse command-line options: %s", error->message);
|
|
return 1;
|
|
}
|
|
|
|
/* Check that the passed bdaddr is correct */
|
|
if (option_master != NULL && strcmp (option_master, "auto") != 0) {
|
|
//FIXME check bdaddr
|
|
}
|
|
|
|
libusb_init (NULL);
|
|
|
|
/* Find device(s) */
|
|
num_devices = libusb_get_device_list (NULL, &list);
|
|
if (num_devices < 0) {
|
|
g_warning ("libusb_get_device_list failed");
|
|
return 1;
|
|
}
|
|
|
|
for (i = 0; i < num_devices; i++) {
|
|
struct libusb_config_descriptor *cfg;
|
|
libusb_device *dev = list[i];
|
|
struct libusb_device_descriptor desc;
|
|
guint8 j;
|
|
|
|
if (libusb_get_device_descriptor (dev, &desc) < 0) {
|
|
g_warning ("libusb_get_device_descriptor failed");
|
|
continue;
|
|
}
|
|
|
|
/* Here we check for the supported devices */
|
|
if (desc.idVendor != VENDOR || desc.idProduct != PRODUCT)
|
|
continue;
|
|
|
|
/* Look for the interface number that interests us */
|
|
for (j = 0; j < desc.bNumConfigurations; j++) {
|
|
struct libusb_config_descriptor *config;
|
|
guint8 k;
|
|
|
|
libusb_get_config_descriptor (dev, j, &config);
|
|
|
|
for (k = 0; k < config->bNumInterfaces; k++) {
|
|
const struct libusb_interface *itf = &config->interface[k];
|
|
int l;
|
|
|
|
for (l = 0; l < itf->num_altsetting ; l++) {
|
|
struct libusb_interface_descriptor alt;
|
|
|
|
alt = itf->altsetting[l];
|
|
if (alt.bInterfaceClass == 3) {
|
|
handle_device (dev, cfg, l, &alt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|