switch_class.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * drivers/switch/switch_class.c
  3. *
  4. * Copyright (C) 2008 Google, Inc.
  5. * Copyright (C) 2021 XiaoMi, Inc.
  6. * Author: Mike Lockwood <lockwood@android.com>
  7. *
  8. * This software is licensed under the terms of the GNU General Public
  9. * License version 2, as published by the Free Software Foundation, and
  10. * may be copied, distributed, and modified under those terms.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. */
  18. #include <linux/module.h>
  19. #include <linux/types.h>
  20. #include <linux/init.h>
  21. #include <linux/device.h>
  22. #include <linux/fs.h>
  23. #include <linux/err.h>
  24. #include <linux/switch.h>
  25. struct class *switch_class;
  26. static atomic_t device_count;
  27. static ssize_t state_show(struct device *dev, struct device_attribute *attr,
  28. char *buf)
  29. {
  30. struct switch_dev *sdev = (struct switch_dev *)
  31. dev_get_drvdata(dev);
  32. if (sdev->print_state) {
  33. int ret = sdev->print_state(sdev, buf);
  34. if (ret >= 0)
  35. return ret;
  36. }
  37. return sprintf(buf, "%d\n", sdev->state);
  38. }
  39. static ssize_t name_show(struct device *dev, struct device_attribute *attr,
  40. char *buf)
  41. {
  42. struct switch_dev *sdev = (struct switch_dev *)
  43. dev_get_drvdata(dev);
  44. if (sdev->print_name) {
  45. int ret = sdev->print_name(sdev, buf);
  46. if (ret >= 0)
  47. return ret;
  48. }
  49. return sprintf(buf, "%s\n", sdev->name);
  50. }
  51. static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
  52. static DEVICE_ATTR(name, S_IRUGO, name_show, NULL);
  53. void switch_set_state(struct switch_dev *sdev, int state)
  54. {
  55. char name_buf[120];
  56. char state_buf[120];
  57. char *prop_buf;
  58. char *envp[3];
  59. int env_offset = 0;
  60. int length;
  61. if (sdev->state != state) {
  62. sdev->state = state;
  63. prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
  64. if (prop_buf) {
  65. length = name_show(sdev->dev, NULL, prop_buf);
  66. if (length > 0) {
  67. if (prop_buf[length - 1] == '\n')
  68. prop_buf[length - 1] = 0;
  69. snprintf(name_buf, sizeof(name_buf),
  70. "SWITCH_NAME=%s", prop_buf);
  71. envp[env_offset++] = name_buf;
  72. }
  73. length = state_show(sdev->dev, NULL, prop_buf);
  74. if (length > 0) {
  75. if (prop_buf[length - 1] == '\n')
  76. prop_buf[length - 1] = 0;
  77. snprintf(state_buf, sizeof(state_buf),
  78. "SWITCH_STATE=%s", prop_buf);
  79. envp[env_offset++] = state_buf;
  80. }
  81. envp[env_offset] = NULL;
  82. kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp);
  83. free_page((unsigned long)prop_buf);
  84. } else {
  85. printk(KERN_ERR "out of memory in switch_set_state\n");
  86. kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE);
  87. }
  88. }
  89. }
  90. EXPORT_SYMBOL_GPL(switch_set_state);
  91. static int create_switch_class(void)
  92. {
  93. if (!switch_class) {
  94. switch_class = class_create(THIS_MODULE, "switch");
  95. if (IS_ERR(switch_class))
  96. return PTR_ERR(switch_class);
  97. atomic_set(&device_count, 0);
  98. }
  99. return 0;
  100. }
  101. int switch_dev_register(struct switch_dev *sdev)
  102. {
  103. int ret;
  104. if (!switch_class) {
  105. ret = create_switch_class();
  106. if (ret < 0)
  107. return ret;
  108. }
  109. sdev->index = atomic_inc_return(&device_count);
  110. sdev->dev = device_create(switch_class, NULL,
  111. MKDEV(0, sdev->index), NULL, sdev->name);
  112. if (IS_ERR(sdev->dev))
  113. return PTR_ERR(sdev->dev);
  114. ret = device_create_file(sdev->dev, &dev_attr_state);
  115. if (ret < 0)
  116. goto err_create_file_1;
  117. ret = device_create_file(sdev->dev, &dev_attr_name);
  118. if (ret < 0)
  119. goto err_create_file_2;
  120. dev_set_drvdata(sdev->dev, sdev);
  121. sdev->state = 0;
  122. return 0;
  123. err_create_file_2:
  124. device_remove_file(sdev->dev, &dev_attr_state);
  125. err_create_file_1:
  126. device_destroy(switch_class, MKDEV(0, sdev->index));
  127. printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name);
  128. return ret;
  129. }
  130. EXPORT_SYMBOL_GPL(switch_dev_register);
  131. void switch_dev_unregister(struct switch_dev *sdev)
  132. {
  133. device_remove_file(sdev->dev, &dev_attr_name);
  134. device_remove_file(sdev->dev, &dev_attr_state);
  135. device_destroy(switch_class, MKDEV(0, sdev->index));
  136. dev_set_drvdata(sdev->dev, NULL);
  137. }
  138. EXPORT_SYMBOL_GPL(switch_dev_unregister);
  139. static int __init switch_class_init(void)
  140. {
  141. return create_switch_class();
  142. }
  143. static void __exit switch_class_exit(void)
  144. {
  145. class_destroy(switch_class);
  146. }
  147. module_init(switch_class_init);
  148. module_exit(switch_class_exit);
  149. MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
  150. MODULE_DESCRIPTION("Switch class driver");
  151. MODULE_LICENSE("GPL");