Tizen 2.0 Release
[framework/connectivity/bluez.git] / input / sixpair.c
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 }