fwil.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * Copyright (c) 2012 Broadcom Corporation
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  11. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  13. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. /* FWIL is the Firmware Interface Layer. In this module the support functions
  17. * are located to set and get variables to and from the firmware.
  18. */
  19. #include <linux/kernel.h>
  20. #include <linux/netdevice.h>
  21. #include <brcmu_utils.h>
  22. #include <brcmu_wifi.h>
  23. #include "dhd.h"
  24. #include "dhd_bus.h"
  25. #include "dhd_dbg.h"
  26. #include "fwil.h"
  27. #define MAX_HEX_DUMP_LEN 64
  28. static s32
  29. brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
  30. {
  31. struct brcmf_pub *drvr = ifp->drvr;
  32. s32 err;
  33. if (drvr->bus_if->state != BRCMF_BUS_DATA) {
  34. brcmf_err("bus is down. we have nothing to do.\n");
  35. return -EIO;
  36. }
  37. if (data != NULL)
  38. len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
  39. if (set)
  40. err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data,
  41. len);
  42. else
  43. err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data,
  44. len);
  45. if (err >= 0)
  46. err = 0;
  47. else
  48. brcmf_err("Failed err=%d\n", err);
  49. return err;
  50. }
  51. s32
  52. brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
  53. {
  54. s32 err;
  55. mutex_lock(&ifp->drvr->proto_block);
  56. brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
  57. brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
  58. min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
  59. err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);
  60. mutex_unlock(&ifp->drvr->proto_block);
  61. return err;
  62. }
  63. s32
  64. brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
  65. {
  66. s32 err;
  67. mutex_lock(&ifp->drvr->proto_block);
  68. err = brcmf_fil_cmd_data(ifp, cmd, data, len, false);
  69. brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
  70. brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
  71. min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
  72. mutex_unlock(&ifp->drvr->proto_block);
  73. return err;
  74. }
  75. s32
  76. brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data)
  77. {
  78. s32 err;
  79. __le32 data_le = cpu_to_le32(data);
  80. mutex_lock(&ifp->drvr->proto_block);
  81. brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data);
  82. err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
  83. mutex_unlock(&ifp->drvr->proto_block);
  84. return err;
  85. }
  86. s32
  87. brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
  88. {
  89. s32 err;
  90. __le32 data_le = cpu_to_le32(*data);
  91. mutex_lock(&ifp->drvr->proto_block);
  92. err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
  93. mutex_unlock(&ifp->drvr->proto_block);
  94. *data = le32_to_cpu(data_le);
  95. brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data);
  96. return err;
  97. }
  98. static u32
  99. brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen)
  100. {
  101. u32 len;
  102. len = strlen(name) + 1;
  103. if ((len + datalen) > buflen)
  104. return 0;
  105. memcpy(buf, name, len);
  106. /* append data onto the end of the name string */
  107. if (data && datalen)
  108. memcpy(&buf[len], data, datalen);
  109. return len + datalen;
  110. }
  111. s32
  112. brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
  113. u32 len)
  114. {
  115. struct brcmf_pub *drvr = ifp->drvr;
  116. s32 err;
  117. u32 buflen;
  118. mutex_lock(&drvr->proto_block);
  119. brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
  120. brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
  121. min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
  122. buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
  123. sizeof(drvr->proto_buf));
  124. if (buflen) {
  125. err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
  126. buflen, true);
  127. } else {
  128. err = -EPERM;
  129. brcmf_err("Creating iovar failed\n");
  130. }
  131. mutex_unlock(&drvr->proto_block);
  132. return err;
  133. }
  134. s32
  135. brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
  136. u32 len)
  137. {
  138. struct brcmf_pub *drvr = ifp->drvr;
  139. s32 err;
  140. u32 buflen;
  141. mutex_lock(&drvr->proto_block);
  142. buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
  143. sizeof(drvr->proto_buf));
  144. if (buflen) {
  145. err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
  146. buflen, false);
  147. if (err == 0)
  148. memcpy(data, drvr->proto_buf, len);
  149. } else {
  150. err = -EPERM;
  151. brcmf_err("Creating iovar failed\n");
  152. }
  153. brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
  154. brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
  155. min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
  156. mutex_unlock(&drvr->proto_block);
  157. return err;
  158. }
  159. s32
  160. brcmf_fil_iovar_int_set(struct brcmf_if *ifp, char *name, u32 data)
  161. {
  162. __le32 data_le = cpu_to_le32(data);
  163. return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le));
  164. }
  165. s32
  166. brcmf_fil_iovar_int_get(struct brcmf_if *ifp, char *name, u32 *data)
  167. {
  168. __le32 data_le = cpu_to_le32(*data);
  169. s32 err;
  170. err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le));
  171. if (err == 0)
  172. *data = le32_to_cpu(data_le);
  173. return err;
  174. }
  175. static u32
  176. brcmf_create_bsscfg(s32 bssidx, char *name, char *data, u32 datalen, char *buf,
  177. u32 buflen)
  178. {
  179. const s8 *prefix = "bsscfg:";
  180. s8 *p;
  181. u32 prefixlen;
  182. u32 namelen;
  183. u32 iolen;
  184. __le32 bssidx_le;
  185. if (bssidx == 0)
  186. return brcmf_create_iovar(name, data, datalen, buf, buflen);
  187. prefixlen = strlen(prefix);
  188. namelen = strlen(name) + 1; /* lengh of iovar name + null */
  189. iolen = prefixlen + namelen + sizeof(bssidx_le) + datalen;
  190. if (buflen < iolen) {
  191. brcmf_err("buffer is too short\n");
  192. return 0;
  193. }
  194. p = buf;
  195. /* copy prefix, no null */
  196. memcpy(p, prefix, prefixlen);
  197. p += prefixlen;
  198. /* copy iovar name including null */
  199. memcpy(p, name, namelen);
  200. p += namelen;
  201. /* bss config index as first data */
  202. bssidx_le = cpu_to_le32(bssidx);
  203. memcpy(p, &bssidx_le, sizeof(bssidx_le));
  204. p += sizeof(bssidx_le);
  205. /* parameter buffer follows */
  206. if (datalen)
  207. memcpy(p, data, datalen);
  208. return iolen;
  209. }
  210. s32
  211. brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,
  212. void *data, u32 len)
  213. {
  214. struct brcmf_pub *drvr = ifp->drvr;
  215. s32 err;
  216. u32 buflen;
  217. mutex_lock(&drvr->proto_block);
  218. brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
  219. brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
  220. min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
  221. buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
  222. drvr->proto_buf, sizeof(drvr->proto_buf));
  223. if (buflen) {
  224. err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
  225. buflen, true);
  226. } else {
  227. err = -EPERM;
  228. brcmf_err("Creating bsscfg failed\n");
  229. }
  230. mutex_unlock(&drvr->proto_block);
  231. return err;
  232. }
  233. s32
  234. brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
  235. void *data, u32 len)
  236. {
  237. struct brcmf_pub *drvr = ifp->drvr;
  238. s32 err;
  239. u32 buflen;
  240. mutex_lock(&drvr->proto_block);
  241. buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
  242. drvr->proto_buf, sizeof(drvr->proto_buf));
  243. if (buflen) {
  244. err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
  245. buflen, false);
  246. if (err == 0)
  247. memcpy(data, drvr->proto_buf, len);
  248. } else {
  249. err = -EPERM;
  250. brcmf_err("Creating bsscfg failed\n");
  251. }
  252. brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
  253. brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
  254. min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
  255. mutex_unlock(&drvr->proto_block);
  256. return err;
  257. }
  258. s32
  259. brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data)
  260. {
  261. __le32 data_le = cpu_to_le32(data);
  262. return brcmf_fil_bsscfg_data_set(ifp, name, &data_le,
  263. sizeof(data_le));
  264. }
  265. s32
  266. brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data)
  267. {
  268. __le32 data_le = cpu_to_le32(*data);
  269. s32 err;
  270. err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le,
  271. sizeof(data_le));
  272. if (err == 0)
  273. *data = le32_to_cpu(data_le);
  274. return err;
  275. }