wcdcal-hwdep.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 and
  6. * only version 2 as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. */
  14. #include <linux/kernel.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/slab.h>
  17. #include <linux/ioctl.h>
  18. #include <linux/bitops.h>
  19. #include <sound/hwdep.h>
  20. #include <sound/msmcal-hwdep.h>
  21. #include <sound/soc.h>
  22. #include "wcdcal-hwdep.h"
  23. const int cal_size_info[WCD9XXX_MAX_CAL] = {
  24. [WCD9XXX_ANC_CAL] = 16384,
  25. [WCD9XXX_MBHC_CAL] = 4096,
  26. [WCD9XXX_MAD_CAL] = 4096,
  27. [WCD9XXX_VBAT_CAL] = 72,
  28. };
  29. const char *cal_name_info[WCD9XXX_MAX_CAL] = {
  30. [WCD9XXX_ANC_CAL] = "anc",
  31. [WCD9XXX_MBHC_CAL] = "mbhc",
  32. [WCD9XXX_MAD_CAL] = "mad",
  33. [WCD9XXX_VBAT_CAL] = "vbat",
  34. };
  35. struct firmware_cal *wcdcal_get_fw_cal(struct fw_info *fw_data,
  36. enum wcd_cal_type type)
  37. {
  38. if (!fw_data) {
  39. pr_err("%s: fw_data is NULL\n", __func__);
  40. return NULL;
  41. }
  42. if (type >= WCD9XXX_MAX_CAL ||
  43. type < WCD9XXX_MIN_CAL) {
  44. pr_err("%s: wrong cal type sent %d\n", __func__, type);
  45. return NULL;
  46. }
  47. mutex_lock(&fw_data->lock);
  48. if (!test_bit(WCDCAL_RECIEVED,
  49. &fw_data->wcdcal_state[type])) {
  50. pr_err("%s: cal not sent by userspace %d\n",
  51. __func__, type);
  52. mutex_unlock(&fw_data->lock);
  53. return NULL;
  54. }
  55. mutex_unlock(&fw_data->lock);
  56. return fw_data->fw[type];
  57. }
  58. EXPORT_SYMBOL(wcdcal_get_fw_cal);
  59. static int wcdcal_hwdep_ioctl_shared(struct snd_hwdep *hw,
  60. struct wcdcal_ioctl_buffer fw_user)
  61. {
  62. struct fw_info *fw_data = hw->private_data;
  63. struct firmware_cal **fw = fw_data->fw;
  64. void *data;
  65. if (!test_bit(fw_user.cal_type, fw_data->cal_bit)) {
  66. pr_err("%s: codec didn't set this %d!!\n",
  67. __func__, fw_user.cal_type);
  68. return -EFAULT;
  69. }
  70. if (fw_user.cal_type >= WCD9XXX_MAX_CAL ||
  71. fw_user.cal_type < WCD9XXX_MIN_CAL) {
  72. pr_err("%s: wrong cal type sent %d\n",
  73. __func__, fw_user.cal_type);
  74. return -EFAULT;
  75. }
  76. if (fw_user.size > cal_size_info[fw_user.cal_type] ||
  77. fw_user.size <= 0) {
  78. pr_err("%s: incorrect firmware size %d for %s\n",
  79. __func__, fw_user.size,
  80. cal_name_info[fw_user.cal_type]);
  81. return -EFAULT;
  82. }
  83. data = fw[fw_user.cal_type]->data;
  84. if (copy_from_user(data, fw_user.buffer, fw_user.size))
  85. return -EFAULT;
  86. fw[fw_user.cal_type]->size = fw_user.size;
  87. mutex_lock(&fw_data->lock);
  88. set_bit(WCDCAL_RECIEVED, &fw_data->wcdcal_state[fw_user.cal_type]);
  89. mutex_unlock(&fw_data->lock);
  90. return 0;
  91. }
  92. #ifdef CONFIG_COMPAT
  93. struct wcdcal_ioctl_buffer32 {
  94. u32 size;
  95. compat_uptr_t buffer;
  96. enum wcd_cal_type cal_type;
  97. };
  98. enum {
  99. SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE32 =
  100. _IOW('U', 0x1, struct wcdcal_ioctl_buffer32),
  101. };
  102. static int wcdcal_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file,
  103. unsigned int cmd, unsigned long arg)
  104. {
  105. struct wcdcal_ioctl_buffer __user *argp = (void __user *)arg;
  106. struct wcdcal_ioctl_buffer32 fw_user32;
  107. struct wcdcal_ioctl_buffer fw_user_compat;
  108. if (cmd != SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE32) {
  109. pr_err("%s: wrong ioctl command sent %u!\n", __func__, cmd);
  110. return -ENOIOCTLCMD;
  111. }
  112. if (copy_from_user(&fw_user32, argp, sizeof(fw_user32))) {
  113. pr_err("%s: failed to copy\n", __func__);
  114. return -EFAULT;
  115. }
  116. fw_user_compat.size = fw_user32.size;
  117. fw_user_compat.buffer = compat_ptr(fw_user32.buffer);
  118. fw_user_compat.cal_type = fw_user32.cal_type;
  119. return wcdcal_hwdep_ioctl_shared(hw, fw_user_compat);
  120. }
  121. #else
  122. #define wcdcal_hwdep_ioctl_compat NULL
  123. #endif
  124. static int wcdcal_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
  125. unsigned int cmd, unsigned long arg)
  126. {
  127. struct wcdcal_ioctl_buffer __user *argp = (void __user *)arg;
  128. struct wcdcal_ioctl_buffer fw_user;
  129. if (cmd != SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE) {
  130. pr_err("%s: wrong ioctl command sent %d!\n", __func__, cmd);
  131. return -ENOIOCTLCMD;
  132. }
  133. if (copy_from_user(&fw_user, argp, sizeof(fw_user))) {
  134. pr_err("%s: failed to copy\n", __func__);
  135. return -EFAULT;
  136. }
  137. return wcdcal_hwdep_ioctl_shared(hw, fw_user);
  138. }
  139. static int wcdcal_hwdep_release(struct snd_hwdep *hw, struct file *file)
  140. {
  141. struct fw_info *fw_data = hw->private_data;
  142. mutex_lock(&fw_data->lock);
  143. /* clear all the calibrations */
  144. memset(fw_data->wcdcal_state, 0,
  145. sizeof(fw_data->wcdcal_state));
  146. mutex_unlock(&fw_data->lock);
  147. return 0;
  148. }
  149. int wcd_cal_create_hwdep(void *data, int node, struct snd_soc_codec *codec)
  150. {
  151. char hwname[40];
  152. struct snd_hwdep *hwdep;
  153. struct firmware_cal **fw;
  154. struct fw_info *fw_data = data;
  155. int err, cal_bit;
  156. if (!fw_data || !codec) {
  157. pr_err("%s: wrong arguments passed\n", __func__);
  158. return -EINVAL;
  159. }
  160. fw = fw_data->fw;
  161. snprintf(hwname, strlen("Codec %s"), "Codec %s",
  162. codec->component.name);
  163. err = snd_hwdep_new(codec->component.card->snd_card,
  164. hwname, node, &hwdep);
  165. if (err < 0) {
  166. dev_err(codec->dev, "%s: new hwdep failed %d\n",
  167. __func__, err);
  168. return err;
  169. }
  170. snprintf(hwdep->name, strlen("Codec %s"), "Codec %s",
  171. codec->component.name);
  172. hwdep->iface = SNDRV_HWDEP_IFACE_AUDIO_CODEC;
  173. hwdep->private_data = fw_data;
  174. hwdep->ops.ioctl_compat = wcdcal_hwdep_ioctl_compat;
  175. hwdep->ops.ioctl = wcdcal_hwdep_ioctl;
  176. hwdep->ops.release = wcdcal_hwdep_release;
  177. mutex_init(&fw_data->lock);
  178. for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
  179. set_bit(WCDCAL_UNINITIALISED,
  180. &fw_data->wcdcal_state[cal_bit]);
  181. fw[cal_bit] = kzalloc(sizeof *(fw[cal_bit]), GFP_KERNEL);
  182. if (!fw[cal_bit]) {
  183. dev_err(codec->dev, "%s: no memory for %s cal\n",
  184. __func__, cal_name_info[cal_bit]);
  185. goto end;
  186. }
  187. }
  188. for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
  189. fw[cal_bit]->data = kzalloc(cal_size_info[cal_bit],
  190. GFP_KERNEL);
  191. if (!fw[cal_bit]->data)
  192. goto exit;
  193. set_bit(WCDCAL_INITIALISED,
  194. &fw_data->wcdcal_state[cal_bit]);
  195. }
  196. return 0;
  197. exit:
  198. for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
  199. kfree(fw[cal_bit]->data);
  200. fw[cal_bit]->data = NULL;
  201. }
  202. end:
  203. for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
  204. kfree(fw[cal_bit]);
  205. fw[cal_bit] = NULL;
  206. }
  207. return -ENOMEM;
  208. }
  209. EXPORT_SYMBOL(wcd_cal_create_hwdep);