/src/hid-lg-mx5500-receiver.c

https://github.com/RobertMe/linux-hid-lg-extended · C · 330 lines · 253 code · 71 blank · 6 comment · 50 complexity · 75d1d7505888aa3c2584a4c3faf7e727 MD5 · raw file

  1. /*
  2. * This program is free software; you can redistribute it and/or modify it
  3. * under the terms of the GNU General Public License as published by the Free
  4. * Software Foundation; either version 2 of the License, or (at your option)
  5. * any later version.
  6. */
  7. #include <linux/hid.h>
  8. #include <asm/atomic.h>
  9. #include "hid-lg-mx5500.h"
  10. #include "hid-lg-mx5500-receiver.h"
  11. struct lg_mx5500_receiver {
  12. u8 initialized;
  13. u8 max_devices;
  14. struct lg_device device;
  15. struct lg_device *connected_devices[LG_MX5500_RECEIVER_MAX_DEVICES];
  16. };
  17. int lg_mx5500_receiver_init_new(struct hid_device *hdev);
  18. void lg_mx5500_receiver_exit(struct lg_device *device);
  19. void lg_mx5500_receiver_hid_receive(struct lg_device *device, const u8 *buffer,
  20. size_t count);
  21. struct lg_device *lg_mx5500_receiver_find_device(struct lg_device *device,
  22. struct hid_device_id device_id);
  23. static struct lg_driver driver = {
  24. .name = "logitech-mx5500-receiver",
  25. .device_name = "Logitech MX5500 Receiver",
  26. .device_id = { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
  27. USB_DEVICE_ID_MX5500_RECEIVER) },
  28. .device_code = LG_DRIVER_NO_CODE,
  29. .init = lg_mx5500_receiver_init_new,
  30. .exit = lg_mx5500_receiver_exit,
  31. .receive_handler = lg_mx5500_receiver_hid_receive,
  32. .find_device = lg_mx5500_receiver_find_device,
  33. };
  34. #define get_on_lg_device(device) container_of( \
  35. lg_find_device_on_lg_device(device, driver.device_id),\
  36. struct lg_mx5500_receiver, device)
  37. struct lg_mx5500_receiver_handler {
  38. u8 action;
  39. u8 first;
  40. void (*func)(struct lg_mx5500_receiver *receiver, const u8 *payload, size_t size);
  41. };
  42. static int lg_mx5500_receiver_update_max_devices(struct lg_mx5500_receiver *receiver,
  43. const u8 *buffer, size_t count)
  44. {
  45. if (count < 6) {
  46. lg_device_err(receiver->device, "Too few bytes to set maximum number of devices");
  47. return 1;
  48. }
  49. receiver->max_devices = buffer[5];
  50. lg_device_dbg(receiver->device, "Maximum number of devices changed to 0x%02x",
  51. receiver->max_devices);
  52. return 0;
  53. }
  54. static void lg_mx5500_receiver_set_max_devices(struct lg_mx5500_receiver *receiver,
  55. u8 max_devices)
  56. {
  57. u8 cmd[7] = { 0x10, 0xFF, LG_DEVICE_ACTION_SET, 0x00, 0x00, 0x00, 0x00 };
  58. cmd[5] = max_devices;
  59. lg_device_queue_out(receiver->device, cmd, sizeof(cmd));
  60. if (receiver->initialized)
  61. return;
  62. receiver->initialized = 1;
  63. }
  64. static void lg_mx5500_receiver_logon_device(struct lg_mx5500_receiver *receiver,
  65. const u8 *buffer, size_t count)
  66. {
  67. int pos;
  68. int code;
  69. struct lg_device *new_device;
  70. if (count < 7)
  71. return;
  72. pos = buffer[1];
  73. if (pos < 1 || pos > LG_MX5500_RECEIVER_MAX_DEVICES)
  74. return;
  75. if (receiver->connected_devices[pos])
  76. receiver->connected_devices[pos]->driver->exit(
  77. receiver->connected_devices[pos]);
  78. code = buffer[6];
  79. new_device = lg_create_on_receiver(&receiver->device, code,
  80. buffer, count);
  81. if (!new_device)
  82. lg_device_err(receiver->device, "Couldn't initialize new device "
  83. "with code 0x%02x", code);
  84. receiver->connected_devices[pos] = new_device;
  85. }
  86. static void lg_mx5500_receiver_logoff_device(struct lg_mx5500_receiver *receiver,
  87. const u8 *buffer, size_t count)
  88. {
  89. struct lg_device *device;
  90. int pos;
  91. if (count < 2)
  92. return;
  93. pos = buffer[1];
  94. if (pos < 1 || pos > LG_MX5500_RECEIVER_MAX_DEVICES)
  95. return;
  96. device = receiver->connected_devices[pos];
  97. if (!device)
  98. return;
  99. device->driver->exit(device);
  100. receiver->connected_devices[pos] = NULL;
  101. }
  102. static void lg_mx5500_receiver_devices_logon(struct lg_mx5500_receiver *receiver)
  103. {
  104. u8 cmd[7] = { 0x10, 0xFF, LG_DEVICE_ACTION_SET, 0x02, 0x02, 0x00, 0x00 };
  105. lg_device_queue_out(receiver->device, cmd, sizeof(cmd));
  106. }
  107. static void lg_mx5500_receiver_handle_get_max_devices(struct lg_mx5500_receiver *receiver,
  108. const u8 *buffer, size_t count)
  109. {
  110. if (lg_mx5500_receiver_update_max_devices(receiver, buffer, count))
  111. return;
  112. if (receiver->initialized)
  113. return;
  114. if (receiver->max_devices != 0x03)
  115. lg_mx5500_receiver_set_max_devices(receiver, 0x03);
  116. else
  117. lg_mx5500_receiver_devices_logon(receiver);
  118. }
  119. static void lg_mx5500_receiver_handle_set_max_devices(struct lg_mx5500_receiver *receiver,
  120. const u8 *buffer, size_t count)
  121. {
  122. if (lg_mx5500_receiver_update_max_devices(receiver, buffer, count))
  123. return;
  124. if (receiver->initialized)
  125. return;
  126. lg_mx5500_receiver_devices_logon(receiver);
  127. }
  128. static struct lg_mx5500_receiver_handler lg_mx5500_receiver_handlers[] = {
  129. { .action = LG_DEVICE_ACTION_GET, .first = 0x00,
  130. .func = lg_mx5500_receiver_handle_get_max_devices },
  131. { .action = LG_DEVICE_ACTION_SET, .first = 0x00,
  132. .func = lg_mx5500_receiver_handle_set_max_devices },
  133. { .action = LG_DEVICE_ACTION_SET, .first = 0x02,
  134. .func = LG_DEVICE_HANDLER_IGNORE },
  135. { }
  136. };
  137. void lg_mx5500_receiver_handle(struct lg_device *device, const u8 *buffer,
  138. size_t count)
  139. {
  140. int i;
  141. int handeld = 0;
  142. struct lg_mx5500_receiver *receiver;
  143. struct lg_mx5500_receiver_handler *handler;
  144. receiver = get_on_lg_device(device);
  145. for (i = 0; lg_mx5500_receiver_handlers[i].action ||
  146. lg_mx5500_receiver_handlers[i].first; i++) {
  147. handler = &lg_mx5500_receiver_handlers[i];
  148. if (handler->action == buffer[2] &&
  149. handler->first == buffer[3]) {
  150. if (handler->func != LG_DEVICE_HANDLER_IGNORE)
  151. handler->func(receiver, buffer, count);
  152. handeld = 1;
  153. }
  154. }
  155. if (!handeld)
  156. lg_device_err(receiver->device, "Unhandeld receiver message %02x %02x", buffer[2], buffer[3]);
  157. }
  158. static void lg_mx5500_receiver_handle_on_device(struct lg_mx5500_receiver *receiver,
  159. const u8 *buffer, size_t count)
  160. {
  161. struct lg_device *handling_device;
  162. handling_device = receiver->connected_devices[buffer[1]];
  163. if (!handling_device)
  164. return;
  165. handling_device->driver->receive_handler(handling_device,
  166. buffer, count);
  167. }
  168. void lg_mx5500_receiver_hid_receive(struct lg_device *device, const u8 *buffer,
  169. size_t count)
  170. {
  171. struct lg_mx5500_receiver *receiver = get_on_lg_device(device);
  172. if (count < 4) {
  173. lg_device_err((*device), "Too few bytes to handle");
  174. return;
  175. }
  176. if(!receiver)
  177. return;
  178. if (buffer[1] == 0xFF) {
  179. lg_mx5500_receiver_handle(device, buffer, count);
  180. } else if (buffer[2] == 0x41) {
  181. lg_mx5500_receiver_logon_device(receiver, buffer, count);
  182. } else if (buffer[2] == 0x40) {
  183. lg_mx5500_receiver_logoff_device(receiver, buffer, count);
  184. } else if (buffer[1] >= 1 && buffer[1] <= LG_MX5500_RECEIVER_MAX_DEVICES) {
  185. lg_mx5500_receiver_handle_on_device(receiver, buffer, count);
  186. }
  187. }
  188. struct lg_device *lg_mx5500_receiver_find_device(struct lg_device *device,
  189. struct hid_device_id device_id)
  190. {
  191. struct lg_mx5500_receiver *receiver = get_on_lg_device(device);
  192. struct lg_driver *compare_driver;
  193. int i;
  194. for (i = 0; i < LG_MX5500_RECEIVER_MAX_DEVICES; i++) {
  195. if (!receiver->connected_devices[i])
  196. continue;
  197. compare_driver = receiver->connected_devices[i]->driver;
  198. if (compare_driver->device_id.bus == device_id.bus &&
  199. compare_driver->device_id.vendor == device_id.vendor &&
  200. compare_driver->device_id.product == device_id.product)
  201. return receiver->connected_devices[i];
  202. }
  203. return NULL;
  204. }
  205. static struct lg_mx5500_receiver *lg_mx5500_receiver_create(void)
  206. {
  207. struct lg_mx5500_receiver *receiver;
  208. int i;
  209. receiver = kzalloc(sizeof(*receiver), GFP_KERNEL);
  210. if (!receiver)
  211. return NULL;
  212. for (i = 0; i < LG_MX5500_RECEIVER_MAX_DEVICES; i++) {
  213. receiver->connected_devices[i] = NULL;
  214. }
  215. receiver->initialized = 0;
  216. return receiver;
  217. }
  218. static void lg_mx5500_receiver_destroy(struct lg_mx5500_receiver *receiver)
  219. {
  220. int i;
  221. for (i = 0; i < LG_MX5500_RECEIVER_MAX_DEVICES; i++) {
  222. if (receiver->connected_devices[i]) {
  223. receiver->connected_devices[i]->driver->exit(
  224. receiver->connected_devices[i]);
  225. }
  226. }
  227. lg_device_destroy(&receiver->device);
  228. kfree(receiver);
  229. }
  230. int lg_mx5500_receiver_init_new(struct hid_device *hdev)
  231. {
  232. int ret;
  233. struct lg_mx5500_receiver *receiver;
  234. u8 cmd[7] = { 0x10, 0xFF, LG_DEVICE_ACTION_GET, 0x00, 0x00, 0x00, 0x00 };
  235. receiver = lg_mx5500_receiver_create();
  236. if (!receiver) {
  237. hid_err(hdev, "Can't allocate MX5500 receiver\n");
  238. ret = -ENOMEM;
  239. goto err;
  240. }
  241. ret = lg_device_init(&receiver->device, hdev, &driver);
  242. if (ret)
  243. goto err_free;
  244. lg_device_queue_out(receiver->device, cmd, sizeof(cmd));
  245. return 0;
  246. err_free:
  247. lg_mx5500_receiver_destroy(receiver);
  248. err:
  249. return ret;
  250. }
  251. void lg_mx5500_receiver_exit(struct lg_device *device)
  252. {
  253. struct lg_mx5500_receiver *receiver= get_on_lg_device(device);
  254. lg_mx5500_receiver_destroy(receiver);
  255. }
  256. struct lg_driver *lg_mx5500_receiver_get_driver()
  257. {
  258. return &driver;
  259. }