switch_class.c 4.3 KB

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