Home | History | Annotate | Download | only in input
      1 /* To compile
      2  * 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
      3  */
      4 
      5 #include <unistd.h>
      6 #include <stdio.h>
      7 #include <inttypes.h>
      8 
      9 #include <sdp.h>
     10 #include <bluetooth/bluetooth.h>
     11 #include <bluetooth/sdp_lib.h>
     12 #include <glib.h>
     13 #include <libusb.h>
     14 
     15 #include "storage.h"
     16 
     17 /* Vendor and product ID for the Sixaxis PS3 controller */
     18 #define VENDOR 0x054c
     19 #define PRODUCT 0x0268
     20 
     21 #define PS3_PNP_RECORD "3601920900000A000100000900013503191124090004350D35061901000900113503190011090006350909656E09006A0901000900093508350619112409010009000D350F350D350619010009001335031900110901002513576972656C65737320436F6E74726F6C6C65720901012513576972656C65737320436F6E74726F6C6C6572090102251B536F6E7920436F6D707574657220456E7465727461696E6D656E740902000901000902010901000902020800090203082109020428010902052801090206359A35980822259405010904A101A102850175089501150026FF00810375019513150025013500450105091901291381027501950D0600FF8103150026FF0005010901A10075089504350046FF0009300931093209358102C0050175089527090181027508953009019102750895300901B102C0A1028502750895300901B102C0A10285EE750895300901B102C0A10285EF750895300901B102C0C0090207350835060904090901000902082800090209280109020A280109020B09010009020C093E8009020D280009020E2800"
     22 
     23 gboolean option_get_master = TRUE;
     24 char *option_master= NULL;
     25 gboolean option_store_info = TRUE;
     26 const char *option_device = NULL;
     27 gboolean option_quiet = FALSE;
     28 
     29 const GOptionEntry options[] = {
     30 	{ "get-master", '\0', 0, G_OPTION_ARG_NONE, &option_get_master, "Get currently set master address", NULL },
     31 	{ "set-master", '\0', 0, G_OPTION_ARG_STRING, &option_master, "Set master address (\"auto\" for automatic)", NULL },
     32 	{ "store-info", '\0', 0, G_OPTION_ARG_NONE, &option_store_info, "Store the HID info into the input database", NULL },
     33 	{ "device", '\0', 0, G_OPTION_ARG_STRING, &option_device, "Only handle one device (default, all supported", NULL },
     34 	{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &option_quiet, "Quieten the output", NULL },
     35 	{ NULL }
     36 };
     37 
     38 static gboolean
     39 show_master (libusb_device_handle *devh, int itfnum)
     40 {
     41 	unsigned char msg[8];
     42 	int res;
     43 
     44 	res = libusb_control_transfer (devh,
     45 				       LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
     46 				       0x01, 0x03f5, itfnum,
     47 				       (void*) msg, sizeof(msg),
     48 				       5000);
     49 
     50 	if (res < 0) {
     51 		g_warning ("Getting the master Bluetooth address failed");
     52 		return FALSE;
     53 	}
     54 	g_print ("Current Bluetooth master: %02X:%02X:%02X:%02X:%02X:%02X\n",
     55 		 msg[2], msg[3], msg[4], msg[5], msg[6], msg[7]);
     56 
     57 	return TRUE;
     58 }
     59 
     60 static char *
     61 get_bdaddr (libusb_device_handle *devh, int itfnum)
     62 {
     63 	unsigned char msg[17];
     64 	char *address;
     65 	int res;
     66 
     67 	res = libusb_control_transfer (devh,
     68 				       LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
     69 				       0x01, 0x03f2, itfnum,
     70 				       (void*) msg, sizeof(msg),
     71 				       5000);
     72 
     73 	if (res < 0) {
     74 		g_warning ("Getting the device Bluetooth address failed");
     75 		return NULL;
     76 	}
     77 
     78 	address = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
     79 				   msg[4], msg[5], msg[6], msg[7], msg[8], msg[9]);
     80 
     81 	if (option_quiet == FALSE) {
     82 		g_print ("Device Bluetooth address: %s\n", address);
     83 	}
     84 
     85 	return address;
     86 }
     87 
     88 static gboolean
     89 set_master_bdaddr (libusb_device_handle *devh, int itfnum, char *host)
     90 {
     91 	unsigned char msg[8];
     92 	int mac[6];
     93 	int res;
     94 
     95 	if (sscanf(host, "%X:%X:%X:%X:%X:%X",
     96 		   &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
     97 		return FALSE;
     98 	}
     99 
    100 	msg[0] = 0x01;
    101 	msg[1] = 0x00;
    102 	msg[2] = mac[0];
    103 	msg[3] = mac[1];
    104 	msg[4] = mac[2];
    105 	msg[5] = mac[3];
    106 	msg[6] = mac[4];
    107 	msg[7] = mac[5];
    108 
    109 	res = libusb_control_transfer (devh,
    110 				       LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
    111 				       0x09, 0x03f5, itfnum,
    112 				       (void*) msg, sizeof(msg),
    113 				       5000);
    114 
    115 	if (res < 0) {
    116 		g_warning ("Setting the master Bluetooth address failed");
    117 		return FALSE;
    118 	}
    119 
    120 	return TRUE;
    121 }
    122 
    123 static char *
    124 get_host_bdaddr (void)
    125 {
    126 	FILE *f;
    127 	int mac[6];
    128 
    129 	//FIXME use dbus to get the default adapter
    130 
    131 	f = popen("hcitool dev", "r");
    132 
    133 	if (f == NULL) {
    134 		//FIXME
    135 		return NULL;
    136 	}
    137 	if (fscanf(f, "%*s\n%*s %X:%X:%X:%X:%X:%X",
    138 		   &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
    139 		//FIXME
    140 		return NULL;
    141 	}
    142 
    143 	return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    144 }
    145 
    146 static int
    147 handle_device (libusb_device *dev, struct libusb_config_descriptor *cfg, int itfnum, const struct libusb_interface_descriptor *alt)
    148 {
    149 	libusb_device_handle *devh;
    150 	int res, retval;
    151 
    152 	retval = -1;
    153 
    154 	if (libusb_open (dev, &devh) < 0) {
    155 		g_warning ("Can't open device");
    156 		goto bail;
    157 	}
    158 	libusb_detach_kernel_driver (devh, itfnum);
    159 
    160 	res = libusb_claim_interface (devh, itfnum);
    161 	if (res < 0) {
    162 		g_warning ("Can't claim interface %d", itfnum);
    163 		goto bail;
    164 	}
    165 
    166 	if (option_get_master != FALSE) {
    167 		if (show_master (devh, itfnum) == FALSE)
    168 			goto bail;
    169 		retval = 0;
    170 	}
    171 
    172 	if (option_master != NULL) {
    173 		if (strcmp (option_master, "auto") == 0) {
    174 			g_free (option_master);
    175 			option_master = get_host_bdaddr ();
    176 			if (option_master == NULL) {
    177 				g_warning ("Can't get bdaddr from default device");
    178 				retval = -1;
    179 				goto bail;
    180 			}
    181 		}
    182 	} else {
    183 		option_master = get_host_bdaddr ();
    184 		if (option_master == NULL) {
    185 			g_warning ("Can't get bdaddr from default device");
    186 			retval = -1;
    187 			goto bail;
    188 		}
    189 	}
    190 
    191 	if (option_store_info != FALSE) {
    192 		sdp_record_t *rec;
    193 		char *device;
    194 		bdaddr_t dst, src;
    195 
    196 		device = get_bdaddr (devh, itfnum);
    197 		if (device == NULL) {
    198 			retval = -1;
    199 			goto bail;
    200 		}
    201 
    202 		rec = record_from_string (PS3_PNP_RECORD);
    203 		store_record(option_master, device, rec);
    204 		write_trust(option_master, device, "[all]", TRUE);
    205 		store_device_id(option_master, device, 0xffff, 0x054c, 0x0268, 0);
    206 		str2ba(option_master, &src);
    207 		str2ba(device, &dst);
    208 		write_device_profiles(&src, &dst, "");
    209 		write_device_name(&src, &dst, "PLAYSTATION(R)3 Controller");
    210 		sdp_record_free(rec);
    211 
    212 		if (set_master_bdaddr (devh, itfnum, option_master) == FALSE) {
    213 			retval = -1;
    214 			goto bail;
    215 		}
    216 	}
    217 
    218 bail:
    219 	libusb_release_interface (devh, itfnum);
    220 	res = libusb_attach_kernel_driver(devh, itfnum);
    221 	if (res < 0) {
    222 		//FIXME sometimes the kernel tells us ENOENT, but succeeds anyway...
    223 		g_warning ("Reattaching the driver failed: %d", res);
    224 	}
    225 	if (devh != NULL)
    226 		libusb_close (devh);
    227 
    228 	return retval;
    229 }
    230 
    231 int main (int argc, char **argv)
    232 {
    233 	GOptionContext *context;
    234 	GError *error = NULL;
    235 	libusb_device **list;
    236 	ssize_t num_devices, i;
    237 
    238 	context = g_option_context_new ("- Manage Sixaxis PS3 controllers");
    239 	g_option_context_add_main_entries (context, options, NULL);
    240 	if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) {
    241 		g_warning ("Couldn't parse command-line options: %s", error->message);
    242 		return 1;
    243 	}
    244 
    245 	/* Check that the passed bdaddr is correct */
    246 	if (option_master != NULL && strcmp (option_master, "auto") != 0) {
    247 		//FIXME check bdaddr
    248 	}
    249 
    250 	libusb_init (NULL);
    251 
    252 	/* Find device(s) */
    253 	num_devices = libusb_get_device_list (NULL, &list);
    254 	if (num_devices < 0) {
    255 		g_warning ("libusb_get_device_list failed");
    256 		return 1;
    257 	}
    258 
    259 	for (i = 0; i < num_devices; i++) {
    260 		struct libusb_config_descriptor *cfg;
    261 		libusb_device *dev = list[i];
    262 		struct libusb_device_descriptor desc;
    263 		guint8 j;
    264 
    265 		if (libusb_get_device_descriptor (dev, &desc) < 0) {
    266 			g_warning ("libusb_get_device_descriptor failed");
    267 			continue;
    268 		}
    269 
    270 		/* Here we check for the supported devices */
    271 		if (desc.idVendor != VENDOR || desc.idProduct != PRODUCT)
    272 			continue;
    273 
    274 		/* Look for the interface number that interests us */
    275 		for (j = 0; j < desc.bNumConfigurations; j++) {
    276 			struct libusb_config_descriptor *config;
    277 			guint8 k;
    278 
    279 			libusb_get_config_descriptor (dev, j, &config);
    280 
    281 			for (k = 0; k < config->bNumInterfaces; k++) {
    282 				const struct libusb_interface *itf = &config->interface[k];
    283 				int l;
    284 
    285 				for (l = 0; l < itf->num_altsetting ; l++) {
    286 					struct libusb_interface_descriptor alt;
    287 
    288 					alt = itf->altsetting[l];
    289 					if (alt.bInterfaceClass == 3) {
    290 						handle_device (dev, cfg, l, &alt);
    291 					}
    292 				}
    293 			}
    294 		}
    295 	}
    296 
    297 	return 0;
    298 }
    299 
    300