3dsp.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2012 Intel Corporation. All rights reserved.
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #include <ctype.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <getopt.h>
  18. #include "monitor/bt.h"
  19. #include "src/shared/mainloop.h"
  20. #include "src/shared/timeout.h"
  21. #include "src/shared/util.h"
  22. #include "src/shared/hci.h"
  23. #define LT_ADDR 0x01
  24. #define PKT_TYPE 0x0008 /* 0x0008 = EDR + DM1, 0xff1e = BR only */
  25. #define SERVICE_DATA 0x00
  26. struct broadcast_message {
  27. uint32_t frame_sync_instant;
  28. uint16_t bluetooth_clock_phase;
  29. uint16_t left_open_offset;
  30. uint16_t left_close_offset;
  31. uint16_t right_open_offset;
  32. uint16_t right_close_offset;
  33. uint16_t frame_sync_period;
  34. uint8_t frame_sync_period_fraction;
  35. } __attribute__ ((packed));
  36. struct brcm_evt_sync_train_received {
  37. uint8_t status;
  38. uint8_t bdaddr[6];
  39. uint32_t offset;
  40. uint8_t map[10];
  41. uint8_t service_data;
  42. uint8_t lt_addr;
  43. uint32_t instant;
  44. uint16_t interval;
  45. } __attribute__ ((packed));
  46. static struct bt_hci *hci_dev;
  47. static bool reset_on_init = false;
  48. static bool reset_on_shutdown = false;
  49. static bool shutdown_timeout(void *user_data)
  50. {
  51. mainloop_quit();
  52. return false;
  53. }
  54. static void shutdown_complete(const void *data, uint8_t size, void *user_data)
  55. {
  56. unsigned int id = PTR_TO_UINT(user_data);
  57. timeout_remove(id);
  58. mainloop_quit();
  59. }
  60. static void shutdown_device(void)
  61. {
  62. unsigned int id;
  63. bt_hci_flush(hci_dev);
  64. if (reset_on_shutdown) {
  65. id = timeout_add(5000, shutdown_timeout, NULL, NULL);
  66. bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
  67. shutdown_complete, UINT_TO_PTR(id), NULL);
  68. } else
  69. mainloop_quit();
  70. }
  71. static void inquiry_started(const void *data, uint8_t size, void *user_data)
  72. {
  73. uint8_t status = *((uint8_t *) data);
  74. if (status) {
  75. printf("Failed to search for 3D display\n");
  76. shutdown_device();
  77. return;
  78. }
  79. printf("Searching for 3D display\n");
  80. }
  81. static void start_inquiry(void)
  82. {
  83. struct bt_hci_cmd_inquiry cmd;
  84. cmd.lap[0] = 0x33;
  85. cmd.lap[1] = 0x8b;
  86. cmd.lap[2] = 0x9e;
  87. cmd.length = 0x08;
  88. cmd.num_resp = 0x00;
  89. bt_hci_send(hci_dev, BT_HCI_CMD_INQUIRY, &cmd, sizeof(cmd),
  90. inquiry_started, NULL, NULL);
  91. }
  92. static void set_peripheral_broadcast_receive(const void *data, uint8_t size,
  93. void *user_data)
  94. {
  95. printf("Peripheral broadcast reception enabled\n");
  96. }
  97. static void sync_train_received(const void *data, uint8_t size,
  98. void *user_data)
  99. {
  100. const struct bt_hci_evt_sync_train_received *evt = data;
  101. struct bt_hci_cmd_set_peripheral_broadcast_receive cmd;
  102. if (evt->status) {
  103. printf("Failed to synchronize with 3D display\n");
  104. start_inquiry();
  105. return;
  106. }
  107. if (evt->lt_addr != LT_ADDR) {
  108. printf("Ignoring synchronization for non 3D display\n");
  109. return;
  110. }
  111. cmd.enable = 0x01;
  112. memcpy(cmd.bdaddr, evt->bdaddr, 6);
  113. cmd.lt_addr = evt->lt_addr;
  114. cmd.interval = evt->interval;
  115. cmd.offset = evt->offset;
  116. cmd.instant = evt->instant;
  117. cmd.timeout = cpu_to_le16(0xfffe);
  118. cmd.accuracy = 250;
  119. cmd.skip = 20;
  120. cmd.pkt_type = cpu_to_le16(PKT_TYPE);
  121. memcpy(cmd.map, evt->map, 10);
  122. bt_hci_send(hci_dev, BT_HCI_CMD_SET_PERIPHERAL_BROADCAST_RECEIVE,
  123. &cmd, sizeof(cmd),
  124. set_peripheral_broadcast_receive, NULL, NULL);
  125. }
  126. static void brcm_sync_train_received(const void *data, uint8_t size,
  127. void *user_data)
  128. {
  129. const struct brcm_evt_sync_train_received *evt = data;
  130. struct bt_hci_cmd_set_peripheral_broadcast_receive cmd;
  131. if (evt->status) {
  132. printf("Failed to synchronize with 3D display\n");
  133. start_inquiry();
  134. return;
  135. }
  136. if (evt->lt_addr != LT_ADDR) {
  137. printf("Ignoring synchronization for non 3D display\n");
  138. return;
  139. }
  140. cmd.enable = 0x01;
  141. memcpy(cmd.bdaddr, evt->bdaddr, 6);
  142. cmd.lt_addr = evt->lt_addr;
  143. cmd.interval = evt->interval;
  144. cmd.offset = evt->offset;
  145. cmd.instant = evt->instant;
  146. cmd.timeout = cpu_to_le16(0xfffe);
  147. cmd.accuracy = 250;
  148. cmd.skip = 20;
  149. cmd.pkt_type = cpu_to_le16(PKT_TYPE);
  150. memcpy(cmd.map, evt->map, 10);
  151. bt_hci_send(hci_dev, BT_HCI_CMD_SET_PERIPHERAL_BROADCAST_RECEIVE,
  152. &cmd, sizeof(cmd),
  153. set_peripheral_broadcast_receive, NULL, NULL);
  154. }
  155. static void truncated_page_complete(const void *data, uint8_t size,
  156. void *user_data)
  157. {
  158. const struct bt_hci_evt_truncated_page_complete *evt = data;
  159. struct bt_hci_cmd_receive_sync_train cmd;
  160. if (evt->status) {
  161. printf("Failed to contact 3D display\n");
  162. shutdown_device();
  163. return;
  164. }
  165. printf("Attempt to synchronize with 3D display\n");
  166. memcpy(cmd.bdaddr, evt->bdaddr, 6);
  167. cmd.timeout = cpu_to_le16(0x4000);
  168. cmd.window = cpu_to_le16(0x0100);
  169. cmd.interval = cpu_to_le16(0x0080);
  170. bt_hci_send(hci_dev, BT_HCI_CMD_RECEIVE_SYNC_TRAIN, &cmd, sizeof(cmd),
  171. NULL, NULL, NULL);
  172. }
  173. static void peripheral_broadcast_timeout(const void *data, uint8_t size,
  174. void *user_data)
  175. {
  176. const struct bt_hci_evt_peripheral_broadcast_timeout *evt = data;
  177. struct bt_hci_cmd_receive_sync_train cmd;
  178. printf("Re-synchronizing with 3D display\n");
  179. memcpy(cmd.bdaddr, evt->bdaddr, 6);
  180. cmd.timeout = cpu_to_le16(0x4000);
  181. cmd.window = cpu_to_le16(0x0100);
  182. cmd.interval = cpu_to_le16(0x0080);
  183. bt_hci_send(hci_dev, BT_HCI_CMD_RECEIVE_SYNC_TRAIN, &cmd, sizeof(cmd),
  184. NULL, NULL, NULL);
  185. }
  186. static void peripheral_broadcast_receive(const void *data, uint8_t size,
  187. void *user_data)
  188. {
  189. const struct bt_hci_evt_peripheral_broadcast_receive *evt = data;
  190. struct bt_hci_cmd_read_clock cmd;
  191. if (evt->status != 0x00)
  192. return;
  193. if (le32_to_cpu(evt->clock) != 0x00000000)
  194. return;
  195. cmd.handle = cpu_to_le16(0x0000);
  196. cmd.type = 0x00;
  197. bt_hci_send(hci_dev, BT_HCI_CMD_READ_CLOCK, &cmd, sizeof(cmd),
  198. NULL, NULL, NULL);
  199. }
  200. static void ext_inquiry_result(const void *data, uint8_t size, void *user_data)
  201. {
  202. const struct bt_hci_evt_ext_inquiry_result *evt = data;
  203. if (evt->dev_class[0] != 0x3c || evt->dev_class[1] != 0x04
  204. || evt->dev_class[2] != 0x08)
  205. return;
  206. if (evt->data[0]) {
  207. struct bt_hci_cmd_truncated_page cmd;
  208. printf("Found 3D display\n");
  209. bt_hci_send(hci_dev, BT_HCI_CMD_INQUIRY_CANCEL, NULL, 0,
  210. NULL, NULL, NULL);
  211. memcpy(cmd.bdaddr, evt->bdaddr, 6);
  212. cmd.pscan_rep_mode = evt->pscan_rep_mode;
  213. cmd.clock_offset = evt->clock_offset;
  214. bt_hci_send(hci_dev, BT_HCI_CMD_TRUNCATED_PAGE,
  215. &cmd, sizeof(cmd), NULL, NULL, NULL);
  216. }
  217. }
  218. static void inquiry_complete(const void *data, uint8_t size, void *user_data)
  219. {
  220. printf("No 3D display found\n");
  221. start_inquiry();
  222. }
  223. static void read_local_version(const void *data, uint8_t size, void *user_data)
  224. {
  225. const struct bt_hci_rsp_read_local_version *rsp = data;
  226. if (rsp->status) {
  227. printf("Failed to read local version information\n");
  228. shutdown_device();
  229. return;
  230. }
  231. if (rsp->manufacturer == 15) {
  232. printf("Enabling receiver workaround for Broadcom\n");
  233. bt_hci_register(hci_dev, BT_HCI_EVT_SYNC_TRAIN_RECEIVED,
  234. brcm_sync_train_received, NULL, NULL);
  235. } else {
  236. bt_hci_register(hci_dev, BT_HCI_EVT_SYNC_TRAIN_RECEIVED,
  237. sync_train_received, NULL, NULL);
  238. }
  239. }
  240. static void start_glasses(void)
  241. {
  242. uint8_t evtmask1[] = { 0x03, 0xe0, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00 };
  243. uint8_t evtmask2[] = { 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00 };
  244. uint8_t inqmode = 0x02;
  245. if (reset_on_init) {
  246. bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
  247. NULL, NULL, NULL);
  248. bt_hci_send(hci_dev, BT_HCI_CMD_SET_EVENT_MASK, evtmask1, 8,
  249. NULL, NULL, NULL);
  250. }
  251. bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_VERSION, NULL, 0,
  252. read_local_version, NULL, NULL);
  253. bt_hci_send(hci_dev, BT_HCI_CMD_SET_EVENT_MASK_PAGE2, evtmask2, 8,
  254. NULL, NULL, NULL);
  255. bt_hci_send(hci_dev, BT_HCI_CMD_WRITE_INQUIRY_MODE, &inqmode, 1,
  256. NULL, NULL, NULL);
  257. bt_hci_register(hci_dev, BT_HCI_EVT_INQUIRY_COMPLETE,
  258. inquiry_complete, NULL, NULL);
  259. bt_hci_register(hci_dev, BT_HCI_EVT_EXT_INQUIRY_RESULT,
  260. ext_inquiry_result, NULL, NULL);
  261. bt_hci_register(hci_dev, BT_HCI_EVT_TRUNCATED_PAGE_COMPLETE,
  262. truncated_page_complete, NULL, NULL);
  263. bt_hci_register(hci_dev, BT_HCI_EVT_PERIPHERAL_BROADCAST_TIMEOUT,
  264. peripheral_broadcast_timeout, NULL, NULL);
  265. bt_hci_register(hci_dev, BT_HCI_EVT_PERIPHERAL_BROADCAST_RECEIVE,
  266. peripheral_broadcast_receive, NULL, NULL);
  267. start_inquiry();
  268. }
  269. static bool sync_train_active = false;
  270. static void sync_train_complete(const void *data, uint8_t size,
  271. void *user_data)
  272. {
  273. sync_train_active = false;
  274. }
  275. static void start_sync_train(void)
  276. {
  277. struct bt_hci_cmd_write_sync_train_params cmd;
  278. if (sync_train_active)
  279. return;
  280. printf("Starting new synchronization train\n");
  281. cmd.min_interval = cpu_to_le16(0x0050);
  282. cmd.max_interval = cpu_to_le16(0x00a0);
  283. cmd.timeout = cpu_to_le32(0x0002ee00); /* 120 sec */
  284. cmd.service_data = SERVICE_DATA;
  285. bt_hci_send(hci_dev, BT_HCI_CMD_WRITE_SYNC_TRAIN_PARAMS,
  286. &cmd, sizeof(cmd), NULL, NULL, NULL);
  287. bt_hci_send(hci_dev, BT_HCI_CMD_START_SYNC_TRAIN, NULL, 0,
  288. NULL, NULL, NULL);
  289. sync_train_active = true;
  290. }
  291. static void conn_request(const void *data, uint8_t size, void *user_data)
  292. {
  293. const struct bt_hci_evt_conn_request *evt = data;
  294. struct bt_hci_cmd_accept_conn_request cmd;
  295. printf("Incoming connection from 3D glasses\n");
  296. memcpy(cmd.bdaddr, evt->bdaddr, 6);
  297. cmd.role = 0x00;
  298. bt_hci_send(hci_dev, BT_HCI_CMD_ACCEPT_CONN_REQUEST, &cmd, sizeof(cmd),
  299. NULL, NULL, NULL);
  300. start_sync_train();
  301. }
  302. static void peripheral_page_response_timeout(const void *data, uint8_t size,
  303. void *user_data)
  304. {
  305. printf("Incoming truncated page received\n");
  306. start_sync_train();
  307. }
  308. static void peripheral_broadcast_channel_map_change(const void *data,
  309. uint8_t size, void *user_data)
  310. {
  311. printf("Broadcast channel map changed\n");
  312. start_sync_train();
  313. }
  314. static void inquiry_resp_tx_power(const void *data, uint8_t size,
  315. void *user_data)
  316. {
  317. const struct bt_hci_rsp_read_inquiry_resp_tx_power *rsp = data;
  318. struct bt_hci_cmd_write_ext_inquiry_response cmd;
  319. uint8_t inqdata[] = { 0x03, 0x3d, 0x03, 0x43, 0x02, 0x0a, 0x00, 0x00 };
  320. uint8_t devclass[] = { 0x3c, 0x04, 0x08 };
  321. uint8_t scanmode = 0x03;
  322. inqdata[6] = (uint8_t) rsp->level;
  323. cmd.fec = 0x00;
  324. memset(cmd.data, 0, sizeof(cmd.data));
  325. memcpy(cmd.data, inqdata, sizeof(inqdata));
  326. bt_hci_send(hci_dev, BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
  327. &cmd, sizeof(cmd), NULL, NULL, NULL);
  328. bt_hci_send(hci_dev, BT_HCI_CMD_WRITE_CLASS_OF_DEV, devclass, 3,
  329. NULL, NULL, NULL);
  330. bt_hci_send(hci_dev, BT_HCI_CMD_WRITE_SCAN_ENABLE, &scanmode, 1,
  331. NULL, NULL, NULL);
  332. }
  333. static void read_clock(const void *data, uint8_t size, void *user_data)
  334. {
  335. const struct bt_hci_rsp_read_clock *rsp = data;
  336. struct broadcast_message msg;
  337. uint8_t bcastdata[sizeof(msg) + 3] = { LT_ADDR, 0x03, 0x11, };
  338. if (rsp->status) {
  339. printf("Failed to read local clock information\n");
  340. shutdown_device();
  341. return;
  342. }
  343. msg.frame_sync_instant = rsp->clock;
  344. msg.bluetooth_clock_phase = rsp->accuracy;
  345. msg.left_open_offset = cpu_to_le16(50);
  346. msg.left_close_offset = cpu_to_le16(300);
  347. msg.right_open_offset = cpu_to_le16(350);
  348. msg.right_close_offset = cpu_to_le16(600);
  349. msg.frame_sync_period = cpu_to_le16(650);
  350. msg.frame_sync_period_fraction = 0;
  351. memcpy(bcastdata + 3, &msg, sizeof(msg));
  352. bt_hci_send(hci_dev, BT_HCI_CMD_SET_PERIPHERAL_BROADCAST_DATA,
  353. bcastdata, sizeof(bcastdata), NULL, NULL, NULL);
  354. }
  355. static void set_peripheral_broadcast(const void *data, uint8_t size,
  356. void *user_data)
  357. {
  358. const struct bt_hci_rsp_set_peripheral_broadcast *rsp = data;
  359. struct bt_hci_cmd_read_clock cmd;
  360. if (rsp->status) {
  361. printf("Failed to set peripheral broadcast transmission\n");
  362. shutdown_device();
  363. return;
  364. }
  365. cmd.handle = cpu_to_le16(0x0000);
  366. cmd.type = 0x00;
  367. bt_hci_send(hci_dev, BT_HCI_CMD_READ_CLOCK, &cmd, sizeof(cmd),
  368. read_clock, NULL, NULL);
  369. }
  370. static void start_display(void)
  371. {
  372. struct bt_hci_cmd_set_peripheral_broadcast cmd;
  373. uint8_t evtmask1[] = { 0x1c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  374. uint8_t evtmask2[] = { 0x00, 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00 };
  375. uint8_t sspmode = 0x01;
  376. uint8_t ltaddr = LT_ADDR;
  377. if (reset_on_init) {
  378. bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
  379. NULL, NULL, NULL);
  380. bt_hci_send(hci_dev, BT_HCI_CMD_SET_EVENT_MASK, evtmask1, 8,
  381. NULL, NULL, NULL);
  382. }
  383. bt_hci_send(hci_dev, BT_HCI_CMD_SET_EVENT_MASK_PAGE2, evtmask2, 8,
  384. NULL, NULL, NULL);
  385. bt_hci_send(hci_dev, BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE, &sspmode, 1,
  386. NULL, NULL, NULL);
  387. bt_hci_send(hci_dev, BT_HCI_CMD_SET_RESERVED_LT_ADDR, &ltaddr, 1,
  388. NULL, NULL, NULL);
  389. bt_hci_send(hci_dev, BT_HCI_CMD_READ_SYNC_TRAIN_PARAMS, NULL, 0,
  390. NULL, NULL, NULL);
  391. bt_hci_register(hci_dev, BT_HCI_EVT_CONN_REQUEST,
  392. conn_request, NULL, NULL);
  393. bt_hci_register(hci_dev, BT_HCI_EVT_PERIPHERAL_PAGE_RESPONSE_TIMEOUT,
  394. peripheral_page_response_timeout, NULL, NULL);
  395. bt_hci_register(hci_dev,
  396. BT_HCI_EVT_PERIPHERAL_BROADCAST_CHANNEL_MAP_CHANGE,
  397. peripheral_broadcast_channel_map_change, NULL, NULL);
  398. bt_hci_register(hci_dev, BT_HCI_EVT_SYNC_TRAIN_COMPLETE,
  399. sync_train_complete, NULL, NULL);
  400. bt_hci_send(hci_dev, BT_HCI_CMD_READ_INQUIRY_RESP_TX_POWER, NULL, 0,
  401. inquiry_resp_tx_power, NULL, NULL);
  402. cmd.enable = 0x01;
  403. cmd.lt_addr = LT_ADDR;
  404. cmd.lpo_allowed = 0x01;
  405. cmd.pkt_type = cpu_to_le16(PKT_TYPE);
  406. cmd.min_interval = cpu_to_le16(0x0050); /* 50 ms */
  407. cmd.max_interval = cpu_to_le16(0x00a0); /* 100 ms */
  408. cmd.timeout = cpu_to_le16(0xfffe);
  409. bt_hci_send(hci_dev, BT_HCI_CMD_SET_PERIPHERAL_BROADCAST, &cmd,
  410. sizeof(cmd), set_peripheral_broadcast, NULL, NULL);
  411. }
  412. static void signal_callback(int signum, void *user_data)
  413. {
  414. static bool terminated = false;
  415. switch (signum) {
  416. case SIGINT:
  417. case SIGTERM:
  418. if (!terminated) {
  419. shutdown_device();
  420. terminated = true;
  421. }
  422. break;
  423. }
  424. }
  425. static void usage(void)
  426. {
  427. printf("3dsp - 3D Synchronization Profile testing\n"
  428. "Usage:\n");
  429. printf("\t3dsp [options]\n");
  430. printf("options:\n"
  431. "\t-D, --display Use display role\n"
  432. "\t-G, --glasses Use glasses role\n"
  433. "\t-i, --index <num> Use specified controller\n"
  434. "\t-h, --help Show help options\n");
  435. }
  436. static const struct option main_options[] = {
  437. { "display", no_argument, NULL, 'D' },
  438. { "glasses", no_argument, NULL, 'G' },
  439. { "index", required_argument, NULL, 'i' },
  440. { "raw", no_argument, NULL, 'r' },
  441. { "version", no_argument, NULL, 'v' },
  442. { "help", no_argument, NULL, 'h' },
  443. { }
  444. };
  445. int main(int argc, char *argv[])
  446. {
  447. bool display_role = false, glasses_role = false;
  448. uint16_t index = 0;
  449. const char *str;
  450. bool use_raw = false;
  451. int exit_status;
  452. for (;;) {
  453. int opt;
  454. opt = getopt_long(argc, argv, "DGi:rvh", main_options, NULL);
  455. if (opt < 0)
  456. break;
  457. switch (opt) {
  458. case 'D':
  459. display_role = true;
  460. break;
  461. case 'G':
  462. glasses_role = true;
  463. break;
  464. case 'i':
  465. if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
  466. str = optarg + 3;
  467. else
  468. str = optarg;
  469. if (!isdigit(*str)) {
  470. usage();
  471. return EXIT_FAILURE;
  472. }
  473. index = atoi(str);
  474. break;
  475. case 'r':
  476. use_raw = true;
  477. break;
  478. case 'v':
  479. printf("%s\n", VERSION);
  480. return EXIT_SUCCESS;
  481. case 'h':
  482. usage();
  483. return EXIT_SUCCESS;
  484. default:
  485. return EXIT_FAILURE;
  486. }
  487. }
  488. if (argc - optind > 0) {
  489. fprintf(stderr, "Invalid command line parameters\n");
  490. return EXIT_FAILURE;
  491. }
  492. if (display_role == glasses_role) {
  493. fprintf(stderr, "Specify either display or glasses role\n");
  494. return EXIT_FAILURE;
  495. }
  496. mainloop_init();
  497. printf("3D Synchronization Profile testing ver %s\n", VERSION);
  498. if (use_raw) {
  499. hci_dev = bt_hci_new_raw_device(index);
  500. if (!hci_dev) {
  501. fprintf(stderr, "Failed to open HCI raw device\n");
  502. return EXIT_FAILURE;
  503. }
  504. } else {
  505. hci_dev = bt_hci_new_user_channel(index);
  506. if (!hci_dev) {
  507. fprintf(stderr, "Failed to open HCI user channel\n");
  508. return EXIT_FAILURE;
  509. }
  510. reset_on_init = true;
  511. reset_on_shutdown = true;
  512. }
  513. if (display_role)
  514. start_display();
  515. else if (glasses_role)
  516. start_glasses();
  517. exit_status = mainloop_run_with_signal(signal_callback, NULL);
  518. bt_hci_unref(hci_dev);
  519. return exit_status;
  520. }