wcdcal-hwdep.c 6.2 KB

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