gen_vkeys.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/init.h>
  13. #include <linux/kernel.h>
  14. #include <linux/module.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/of.h>
  17. #include <linux/input.h>
  18. #include <linux/input/gen_vkeys.h>
  19. #define MAX_BUF_SIZE 256
  20. #define VKEY_VER_CODE "0x01"
  21. #define HEIGHT_SCALE_NUM 8
  22. #define HEIGHT_SCALE_DENOM 10
  23. #define VKEY_Y_OFFSET_DEFAULT 0
  24. /* numerator and denomenator for border equations */
  25. #define BORDER_ADJUST_NUM 3
  26. #define BORDER_ADJUST_DENOM 4
  27. static struct kobject *vkey_obj;
  28. static char *vkey_buf;
  29. static ssize_t vkey_show(struct kobject *obj,
  30. struct kobj_attribute *attr, char *buf)
  31. {
  32. strlcpy(buf, vkey_buf, MAX_BUF_SIZE);
  33. return strnlen(buf, MAX_BUF_SIZE);
  34. }
  35. static struct kobj_attribute vkey_obj_attr = {
  36. .attr = {
  37. .mode = S_IRUGO,
  38. },
  39. .show = vkey_show,
  40. };
  41. static struct attribute *vkey_attr[] = {
  42. &vkey_obj_attr.attr,
  43. NULL,
  44. };
  45. static struct attribute_group vkey_grp = {
  46. .attrs = vkey_attr,
  47. };
  48. static int __devinit vkey_parse_dt(struct device *dev,
  49. struct vkeys_platform_data *pdata)
  50. {
  51. struct device_node *np = dev->of_node;
  52. struct property *prop;
  53. int rc, val;
  54. rc = of_property_read_string(np, "label", &pdata->name);
  55. if (rc) {
  56. dev_err(dev, "Failed to read label\n");
  57. return -EINVAL;
  58. }
  59. rc = of_property_read_u32(np, "qcom,disp-maxx", &pdata->disp_maxx);
  60. if (rc) {
  61. dev_err(dev, "Failed to read display max x\n");
  62. return -EINVAL;
  63. }
  64. rc = of_property_read_u32(np, "qcom,disp-maxy", &pdata->disp_maxy);
  65. if (rc) {
  66. dev_err(dev, "Failed to read display max y\n");
  67. return -EINVAL;
  68. }
  69. rc = of_property_read_u32(np, "qcom,panel-maxx", &pdata->panel_maxx);
  70. if (rc) {
  71. dev_err(dev, "Failed to read panel max x\n");
  72. return -EINVAL;
  73. }
  74. rc = of_property_read_u32(np, "qcom,panel-maxy", &pdata->panel_maxy);
  75. if (rc) {
  76. dev_err(dev, "Failed to read panel max y\n");
  77. return -EINVAL;
  78. }
  79. prop = of_find_property(np, "qcom,key-codes", NULL);
  80. if (prop) {
  81. pdata->num_keys = prop->length / sizeof(u32);
  82. pdata->keycodes = devm_kzalloc(dev,
  83. sizeof(u32) * pdata->num_keys, GFP_KERNEL);
  84. if (!pdata->keycodes)
  85. return -ENOMEM;
  86. rc = of_property_read_u32_array(np, "qcom,key-codes",
  87. pdata->keycodes, pdata->num_keys);
  88. if (rc) {
  89. dev_err(dev, "Failed to read key codes\n");
  90. return -EINVAL;
  91. }
  92. }
  93. pdata->y_offset = VKEY_Y_OFFSET_DEFAULT;
  94. rc = of_property_read_u32(np, "qcom,y-offset", &val);
  95. if (!rc)
  96. pdata->y_offset = val;
  97. else if (rc != -EINVAL) {
  98. dev_err(dev, "Failed to read y position offset\n");
  99. return rc;
  100. }
  101. return 0;
  102. }
  103. static int __devinit vkeys_probe(struct platform_device *pdev)
  104. {
  105. struct vkeys_platform_data *pdata;
  106. int width, height, center_x, center_y;
  107. int x1 = 0, x2 = 0, i, c = 0, ret, border;
  108. char *name;
  109. vkey_buf = devm_kzalloc(&pdev->dev, MAX_BUF_SIZE, GFP_KERNEL);
  110. if (!vkey_buf) {
  111. dev_err(&pdev->dev, "Failed to allocate memory\n");
  112. return -ENOMEM;
  113. }
  114. if (pdev->dev.of_node) {
  115. pdata = devm_kzalloc(&pdev->dev,
  116. sizeof(struct vkeys_platform_data), GFP_KERNEL);
  117. if (!pdata) {
  118. dev_err(&pdev->dev, "Failed to allocate memory\n");
  119. return -ENOMEM;
  120. }
  121. ret = vkey_parse_dt(&pdev->dev, pdata);
  122. if (ret) {
  123. dev_err(&pdev->dev, "Parsing DT failed(%d)", ret);
  124. return ret;
  125. }
  126. } else
  127. pdata = pdev->dev.platform_data;
  128. if (!pdata || !pdata->name || !pdata->keycodes || !pdata->num_keys ||
  129. !pdata->disp_maxx || !pdata->disp_maxy || !pdata->panel_maxy) {
  130. dev_err(&pdev->dev, "pdata is invalid\n");
  131. return -EINVAL;
  132. }
  133. border = (pdata->panel_maxx - pdata->disp_maxx) * 2;
  134. width = ((pdata->disp_maxx - (border * (pdata->num_keys - 1)))
  135. / pdata->num_keys);
  136. height = (pdata->panel_maxy - pdata->disp_maxy);
  137. center_y = pdata->disp_maxy + (height / 2) + pdata->y_offset;
  138. height = height * HEIGHT_SCALE_NUM / HEIGHT_SCALE_DENOM;
  139. x2 -= border * BORDER_ADJUST_NUM / BORDER_ADJUST_DENOM;
  140. for (i = 0; i < pdata->num_keys; i++) {
  141. x1 = x2 + border;
  142. x2 = x2 + border + width;
  143. center_x = x1 + (x2 - x1) / 2;
  144. c += snprintf(vkey_buf + c, MAX_BUF_SIZE - c,
  145. "%s:%d:%d:%d:%d:%d\n",
  146. VKEY_VER_CODE, pdata->keycodes[i],
  147. center_x, center_y, width, height);
  148. }
  149. vkey_buf[c] = '\0';
  150. name = devm_kzalloc(&pdev->dev, sizeof(*name) * MAX_BUF_SIZE,
  151. GFP_KERNEL);
  152. if (!name)
  153. return -ENOMEM;
  154. snprintf(name, MAX_BUF_SIZE,
  155. "virtualkeys.%s", pdata->name);
  156. vkey_obj_attr.attr.name = name;
  157. vkey_obj = kobject_create_and_add("board_properties", NULL);
  158. if (!vkey_obj) {
  159. dev_err(&pdev->dev, "unable to create kobject\n");
  160. return -ENOMEM;
  161. }
  162. ret = sysfs_create_group(vkey_obj, &vkey_grp);
  163. if (ret) {
  164. dev_err(&pdev->dev, "failed to create attributes\n");
  165. goto destroy_kobj;
  166. }
  167. return 0;
  168. destroy_kobj:
  169. kobject_put(vkey_obj);
  170. return ret;
  171. }
  172. static int __devexit vkeys_remove(struct platform_device *pdev)
  173. {
  174. sysfs_remove_group(vkey_obj, &vkey_grp);
  175. kobject_put(vkey_obj);
  176. return 0;
  177. }
  178. static struct of_device_id vkey_match_table[] = {
  179. { .compatible = "qcom,gen-vkeys",},
  180. { },
  181. };
  182. static struct platform_driver vkeys_driver = {
  183. .probe = vkeys_probe,
  184. .remove = __devexit_p(vkeys_remove),
  185. .driver = {
  186. .owner = THIS_MODULE,
  187. .name = "gen_vkeys",
  188. .of_match_table = vkey_match_table,
  189. },
  190. };
  191. module_platform_driver(vkeys_driver);
  192. MODULE_LICENSE("GPL v2");