hog.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2012 Marcel Holtmann <marcel@holtmann.org>
  7. * Copyright (C) 2012 Nordic Semiconductor Inc.
  8. * Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT
  9. *
  10. *
  11. */
  12. #ifdef HAVE_CONFIG_H
  13. #include <config.h>
  14. #endif
  15. #include <stdlib.h>
  16. #include <stdbool.h>
  17. #include <errno.h>
  18. #include <unistd.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <fcntl.h>
  22. #include <glib.h>
  23. #include "lib/bluetooth.h"
  24. #include "lib/sdp.h"
  25. #include "lib/uuid.h"
  26. #include "src/log.h"
  27. #include "src/adapter.h"
  28. #include "src/device.h"
  29. #include "src/profile.h"
  30. #include "src/service.h"
  31. #include "src/shared/util.h"
  32. #include "src/shared/uhid.h"
  33. #include "src/shared/queue.h"
  34. #include "src/shared/att.h"
  35. #include "src/shared/gatt-client.h"
  36. #include "src/plugin.h"
  37. #include "device.h"
  38. #include "suspend.h"
  39. #include "attrib/att.h"
  40. #include "attrib/gattrib.h"
  41. #include "attrib/gatt.h"
  42. #include "hog-lib.h"
  43. struct hog_device {
  44. struct btd_device *device;
  45. struct bt_hog *hog;
  46. };
  47. static gboolean suspend_supported = FALSE;
  48. static bool auto_sec = true;
  49. static struct queue *devices = NULL;
  50. void input_set_auto_sec(bool state)
  51. {
  52. auto_sec = state;
  53. }
  54. static void hog_device_accept(struct hog_device *dev, struct gatt_db *db)
  55. {
  56. char name[248];
  57. uint16_t vendor, product, version;
  58. if (dev->hog)
  59. return;
  60. if (device_name_known(dev->device))
  61. device_get_name(dev->device, name, sizeof(name));
  62. else
  63. strcpy(name, "bluez-hog-device");
  64. vendor = btd_device_get_vendor(dev->device);
  65. product = btd_device_get_product(dev->device);
  66. version = btd_device_get_version(dev->device);
  67. DBG("name=%s vendor=0x%X, product=0x%X, version=0x%X", name, vendor,
  68. product, version);
  69. dev->hog = bt_hog_new_default(name, vendor, product, version, db);
  70. }
  71. static struct hog_device *hog_device_new(struct btd_device *device)
  72. {
  73. struct hog_device *dev;
  74. dev = new0(struct hog_device, 1);
  75. dev->device = btd_device_ref(device);
  76. if (!devices)
  77. devices = queue_new();
  78. queue_push_tail(devices, dev);
  79. return dev;
  80. }
  81. static void hog_device_free(void *data)
  82. {
  83. struct hog_device *dev = data;
  84. queue_remove(devices, dev);
  85. if (queue_isempty(devices)) {
  86. queue_destroy(devices, NULL);
  87. devices = NULL;
  88. }
  89. btd_device_unref(dev->device);
  90. bt_hog_unref(dev->hog);
  91. free(dev);
  92. }
  93. static void set_suspend(gpointer data, gpointer user_data)
  94. {
  95. struct hog_device *dev = data;
  96. gboolean suspend = GPOINTER_TO_INT(user_data);
  97. bt_hog_set_control_point(dev->hog, suspend);
  98. }
  99. static void suspend_callback(void)
  100. {
  101. gboolean suspend = TRUE;
  102. DBG("Suspending ...");
  103. queue_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
  104. }
  105. static void resume_callback(void)
  106. {
  107. gboolean suspend = FALSE;
  108. DBG("Resuming ...");
  109. queue_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
  110. }
  111. static int hog_probe(struct btd_service *service)
  112. {
  113. struct btd_device *device = btd_service_get_device(service);
  114. const char *path = device_get_path(device);
  115. struct hog_device *dev;
  116. DBG("path %s", path);
  117. dev = hog_device_new(device);
  118. if (!dev)
  119. return -EINVAL;
  120. btd_service_set_user_data(service, dev);
  121. device_set_wake_support(device, true);
  122. return 0;
  123. }
  124. static void hog_remove(struct btd_service *service)
  125. {
  126. struct hog_device *dev = btd_service_get_user_data(service);
  127. struct btd_device *device = btd_service_get_device(service);
  128. const char *path = device_get_path(device);
  129. DBG("path %s", path);
  130. hog_device_free(dev);
  131. }
  132. static int hog_accept(struct btd_service *service)
  133. {
  134. struct hog_device *dev = btd_service_get_user_data(service);
  135. struct btd_device *device = btd_service_get_device(service);
  136. struct gatt_db *db = btd_device_get_gatt_db(device);
  137. GAttrib *attrib = btd_device_get_attrib(device);
  138. if (!dev->hog) {
  139. hog_device_accept(dev, db);
  140. if (!dev->hog)
  141. return -EINVAL;
  142. }
  143. /* HOGP 1.0 Section 6.1 requires bonding */
  144. if (!device_is_bonded(device, btd_device_get_bdaddr_type(device))) {
  145. struct bt_gatt_client *client;
  146. if (!auto_sec)
  147. return -ECONNREFUSED;
  148. client = btd_device_get_gatt_client(device);
  149. if (!bt_gatt_client_set_security(client,
  150. BT_ATT_SECURITY_MEDIUM))
  151. return -ECONNREFUSED;
  152. }
  153. /* TODO: Replace GAttrib with bt_gatt_client */
  154. bt_hog_attach(dev->hog, attrib);
  155. btd_service_connecting_complete(service, 0);
  156. return 0;
  157. }
  158. static int hog_disconnect(struct btd_service *service)
  159. {
  160. struct hog_device *dev = btd_service_get_user_data(service);
  161. bt_hog_detach(dev->hog);
  162. btd_service_disconnecting_complete(service, 0);
  163. return 0;
  164. }
  165. static struct btd_profile hog_profile = {
  166. .name = "input-hog",
  167. .remote_uuid = HOG_UUID,
  168. .device_probe = hog_probe,
  169. .device_remove = hog_remove,
  170. .accept = hog_accept,
  171. .disconnect = hog_disconnect,
  172. .auto_connect = true,
  173. };
  174. static int hog_init(void)
  175. {
  176. int err;
  177. err = suspend_init(suspend_callback, resume_callback);
  178. if (err < 0)
  179. error("Loading suspend plugin failed: %s (%d)", strerror(-err),
  180. -err);
  181. else
  182. suspend_supported = TRUE;
  183. return btd_profile_register(&hog_profile);
  184. }
  185. static void hog_exit(void)
  186. {
  187. if (suspend_supported)
  188. suspend_exit();
  189. btd_profile_unregister(&hog_profile);
  190. }
  191. BLUETOOTH_PLUGIN_DEFINE(hog, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
  192. hog_init, hog_exit)