hid-picolcd_leds.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /***************************************************************************
  3. * Copyright (C) 2010-2012 by Bruno Prémont <[email protected]> *
  4. * *
  5. * Based on Logitech G13 driver (v0.4) *
  6. * Copyright (C) 2009 by Rick L. Vinyard, Jr. <[email protected]> *
  7. * *
  8. ***************************************************************************/
  9. #include <linux/hid.h>
  10. #include <linux/hid-debug.h>
  11. #include <linux/input.h>
  12. #include "hid-ids.h"
  13. #include <linux/fb.h>
  14. #include <linux/vmalloc.h>
  15. #include <linux/backlight.h>
  16. #include <linux/lcd.h>
  17. #include <linux/leds.h>
  18. #include <linux/seq_file.h>
  19. #include <linux/debugfs.h>
  20. #include <linux/completion.h>
  21. #include <linux/uaccess.h>
  22. #include <linux/module.h>
  23. #include "hid-picolcd.h"
  24. void picolcd_leds_set(struct picolcd_data *data)
  25. {
  26. struct hid_report *report;
  27. unsigned long flags;
  28. if (!data->led[0])
  29. return;
  30. report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
  31. if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
  32. return;
  33. spin_lock_irqsave(&data->lock, flags);
  34. hid_set_field(report->field[0], 0, data->led_state);
  35. if (!(data->status & PICOLCD_FAILED))
  36. hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
  37. spin_unlock_irqrestore(&data->lock, flags);
  38. }
  39. static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
  40. enum led_brightness value)
  41. {
  42. struct device *dev;
  43. struct hid_device *hdev;
  44. struct picolcd_data *data;
  45. int i, state = 0;
  46. dev = led_cdev->dev->parent;
  47. hdev = to_hid_device(dev);
  48. data = hid_get_drvdata(hdev);
  49. if (!data)
  50. return;
  51. for (i = 0; i < 8; i++) {
  52. if (led_cdev != data->led[i])
  53. continue;
  54. state = (data->led_state >> i) & 1;
  55. if (value == LED_OFF && state) {
  56. data->led_state &= ~(1 << i);
  57. picolcd_leds_set(data);
  58. } else if (value != LED_OFF && !state) {
  59. data->led_state |= 1 << i;
  60. picolcd_leds_set(data);
  61. }
  62. break;
  63. }
  64. }
  65. static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
  66. {
  67. struct device *dev;
  68. struct hid_device *hdev;
  69. struct picolcd_data *data;
  70. int i, value = 0;
  71. dev = led_cdev->dev->parent;
  72. hdev = to_hid_device(dev);
  73. data = hid_get_drvdata(hdev);
  74. for (i = 0; i < 8; i++)
  75. if (led_cdev == data->led[i]) {
  76. value = (data->led_state >> i) & 1;
  77. break;
  78. }
  79. return value ? LED_FULL : LED_OFF;
  80. }
  81. int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
  82. {
  83. struct device *dev = &data->hdev->dev;
  84. struct led_classdev *led;
  85. size_t name_sz = strlen(dev_name(dev)) + 8;
  86. char *name;
  87. int i, ret = 0;
  88. if (!report)
  89. return -ENODEV;
  90. if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
  91. report->field[0]->report_size != 8) {
  92. dev_err(dev, "unsupported LED_STATE report");
  93. return -EINVAL;
  94. }
  95. for (i = 0; i < 8; i++) {
  96. led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
  97. if (!led) {
  98. dev_err(dev, "can't allocate memory for LED %d\n", i);
  99. ret = -ENOMEM;
  100. goto err;
  101. }
  102. name = (void *)(&led[1]);
  103. snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
  104. led->name = name;
  105. led->brightness = 0;
  106. led->max_brightness = 1;
  107. led->brightness_get = picolcd_led_get_brightness;
  108. led->brightness_set = picolcd_led_set_brightness;
  109. data->led[i] = led;
  110. ret = led_classdev_register(dev, data->led[i]);
  111. if (ret) {
  112. data->led[i] = NULL;
  113. kfree(led);
  114. dev_err(dev, "can't register LED %d\n", i);
  115. goto err;
  116. }
  117. }
  118. return 0;
  119. err:
  120. for (i = 0; i < 8; i++)
  121. if (data->led[i]) {
  122. led = data->led[i];
  123. data->led[i] = NULL;
  124. led_classdev_unregister(led);
  125. kfree(led);
  126. }
  127. return ret;
  128. }
  129. void picolcd_exit_leds(struct picolcd_data *data)
  130. {
  131. struct led_classdev *led;
  132. int i;
  133. for (i = 0; i < 8; i++) {
  134. led = data->led[i];
  135. data->led[i] = NULL;
  136. if (!led)
  137. continue;
  138. led_classdev_unregister(led);
  139. kfree(led);
  140. }
  141. }