hid-wiimote-ext.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*
  2. * HID driver for Nintendo Wiimote extension devices
  3. * Copyright (c) 2011 David Herrmann
  4. */
  5. /*
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the Free
  8. * Software Foundation; either version 2 of the License, or (at your option)
  9. * any later version.
  10. */
  11. #include <linux/atomic.h>
  12. #include <linux/module.h>
  13. #include <linux/spinlock.h>
  14. #include <linux/workqueue.h>
  15. #include "hid-wiimote.h"
  16. struct wiimote_ext {
  17. struct wiimote_data *wdata;
  18. struct work_struct worker;
  19. atomic_t opened;
  20. atomic_t mp_opened;
  21. bool plugged;
  22. bool motionp;
  23. __u8 ext_type;
  24. };
  25. enum wiiext_type {
  26. WIIEXT_NONE, /* placeholder */
  27. WIIEXT_CLASSIC, /* Nintendo classic controller */
  28. WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */
  29. };
  30. static void wiiext_worker(struct work_struct *work)
  31. {
  32. struct wiimote_ext *ext = container_of(work, struct wiimote_ext,
  33. worker);
  34. }
  35. /* schedule work only once, otherwise mark for reschedule */
  36. static void wiiext_schedule(struct wiimote_ext *ext)
  37. {
  38. queue_work(system_nrt_wq, &ext->worker);
  39. }
  40. /*
  41. * Reacts on extension port events
  42. * Whenever the driver gets an event from the wiimote that an extension has been
  43. * plugged or unplugged, this funtion shall be called. It checks what extensions
  44. * are connected and initializes and activates them.
  45. * This can be called in atomic context. The initialization is done in a
  46. * separate worker thread. The state.lock spinlock must be held by the caller.
  47. */
  48. void wiiext_event(struct wiimote_data *wdata, bool plugged)
  49. {
  50. if (!wdata->ext)
  51. return;
  52. if (wdata->ext->plugged == plugged)
  53. return;
  54. wdata->ext->plugged = plugged;
  55. /*
  56. * We need to call wiiext_schedule(wdata->ext) here, however, the
  57. * extension initialization logic is not fully understood and so
  58. * automatic initialization is not supported, yet.
  59. */
  60. }
  61. /*
  62. * Returns true if the current DRM mode should contain extension data and false
  63. * if there is no interest in extension data.
  64. * All supported extensions send 6 byte extension data so any DRM that contains
  65. * extension bytes is fine.
  66. * The caller must hold the state.lock spinlock.
  67. */
  68. bool wiiext_active(struct wiimote_data *wdata)
  69. {
  70. if (!wdata->ext)
  71. return false;
  72. return wdata->ext->motionp || wdata->ext->ext_type;
  73. }
  74. /* Initializes the extension driver of a wiimote */
  75. int wiiext_init(struct wiimote_data *wdata)
  76. {
  77. struct wiimote_ext *ext;
  78. unsigned long flags;
  79. ext = kzalloc(sizeof(*ext), GFP_KERNEL);
  80. if (!ext)
  81. return -ENOMEM;
  82. ext->wdata = wdata;
  83. INIT_WORK(&ext->worker, wiiext_worker);
  84. spin_lock_irqsave(&wdata->state.lock, flags);
  85. wdata->ext = ext;
  86. spin_unlock_irqrestore(&wdata->state.lock, flags);
  87. return 0;
  88. }
  89. /* Deinitializes the extension driver of a wiimote */
  90. void wiiext_deinit(struct wiimote_data *wdata)
  91. {
  92. struct wiimote_ext *ext = wdata->ext;
  93. unsigned long flags;
  94. if (!ext)
  95. return;
  96. /*
  97. * We first unset wdata->ext to avoid further input from the wiimote
  98. * core. The worker thread does not access this pointer so it is not
  99. * affected by this.
  100. * We kill the worker after this so it does not get respawned during
  101. * deinitialization.
  102. */
  103. spin_lock_irqsave(&wdata->state.lock, flags);
  104. wdata->ext = NULL;
  105. spin_unlock_irqrestore(&wdata->state.lock, flags);
  106. cancel_work_sync(&ext->worker);
  107. kfree(ext);
  108. }