PageRenderTime 30ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/net/wireless/bcmdhd/src/wl/sys/wldev_common.c

https://bitbucket.org/cyanogenmod/android_kernel_samsung_msm8660-common
C | 381 lines | 285 code | 58 blank | 38 comment | 40 complexity | f465d7d8dc40fe07cd97fe058143dc86 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1. /*
  2. * Common function shared by Linux WEXT, cfg80211 and p2p drivers
  3. *
  4. * Copyright (C) 1999-2011, Broadcom Corporation
  5. *
  6. * Unless you and Broadcom execute a separate written software license
  7. * agreement governing use of this software, this software is licensed to you
  8. * under the terms of the GNU General Public License version 2 (the "GPL"),
  9. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  10. * following added to such license:
  11. *
  12. * As a special exception, the copyright holders of this software give you
  13. * permission to link this software with independent modules, and to copy and
  14. * distribute the resulting executable under terms of your choice, provided that
  15. * you also meet, for each linked independent module, the terms and conditions of
  16. * the license of that module. An independent module is a module which is not
  17. * derived from this software. The special exception does not apply to any
  18. * modifications of the software.
  19. *
  20. * Notwithstanding the above, under no circumstances may you combine this
  21. * software in any way with any other Broadcom software provided under a license
  22. * other than the GPL, without Broadcom's express prior written consent.
  23. *
  24. * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
  25. */
  26. #include <osl.h>
  27. #include <linux/kernel.h>
  28. #include <linux/kthread.h>
  29. #include <linux/netdevice.h>
  30. #include <wldev_common.h>
  31. #include <bcmutils.h>
  32. #define htod32(i) i
  33. #define htod16(i) i
  34. #define dtoh32(i) i
  35. #define dtoh16(i) i
  36. #define htodchanspec(i) i
  37. #define dtohchanspec(i) i
  38. #define WLDEV_ERROR(args) \
  39. do { \
  40. printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__); \
  41. printk args; \
  42. } while (0)
  43. #define WLDEV_INFO(args) \
  44. do { \
  45. printk(KERN_INFO "WLDEV-ERROR) %s : ", __func__); \
  46. printk args; \
  47. } while (0)
  48. extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd);
  49. s32 wldev_ioctl(
  50. struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
  51. {
  52. s32 ret = 0;
  53. struct wl_ioctl ioc;
  54. memset(&ioc, 0, sizeof(ioc));
  55. ioc.cmd = cmd;
  56. ioc.buf = arg;
  57. ioc.len = len;
  58. ioc.set = set;
  59. ret = dhd_ioctl_entry_local(dev, &ioc, cmd);
  60. return ret;
  61. }
  62. /* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be
  63. * taken care of in dhd_ioctl_entry. Internal use only, not exposed to
  64. * wl_iw, wl_cfg80211 and wl_cfgp2p
  65. */
  66. static s32 wldev_mkiovar(
  67. s8 *iovar_name, s8 *param, s32 paramlen,
  68. s8 *iovar_buf, u32 buflen)
  69. {
  70. s32 iolen = 0;
  71. iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen);
  72. return iolen;
  73. }
  74. s32 wldev_iovar_getbuf(
  75. struct net_device *dev, s8 *iovar_name,
  76. void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
  77. {
  78. s32 ret = 0;
  79. if (buf_sync) {
  80. mutex_lock(buf_sync);
  81. }
  82. wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
  83. ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
  84. if (buf_sync)
  85. mutex_unlock(buf_sync);
  86. return ret;
  87. }
  88. s32 wldev_iovar_setbuf(
  89. struct net_device *dev, s8 *iovar_name,
  90. void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
  91. {
  92. s32 ret = 0;
  93. s32 iovar_len;
  94. if (buf_sync) {
  95. mutex_lock(buf_sync);
  96. }
  97. iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
  98. ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
  99. if (buf_sync)
  100. mutex_unlock(buf_sync);
  101. return ret;
  102. }
  103. s32 wldev_iovar_setint(
  104. struct net_device *dev, s8 *iovar, s32 val)
  105. {
  106. s8 iovar_buf[WLC_IOCTL_SMLEN];
  107. val = htod32(val);
  108. memset(iovar_buf, 0, sizeof(iovar_buf));
  109. return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf,
  110. sizeof(iovar_buf), NULL);
  111. }
  112. s32 wldev_iovar_getint(
  113. struct net_device *dev, s8 *iovar, s32 *pval)
  114. {
  115. s8 iovar_buf[WLC_IOCTL_SMLEN];
  116. s32 err;
  117. memset(iovar_buf, 0, sizeof(iovar_buf));
  118. err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf,
  119. sizeof(iovar_buf), NULL);
  120. if (err == 0)
  121. {
  122. memcpy(pval, iovar_buf, sizeof(*pval));
  123. *pval = dtoh32(*pval);
  124. }
  125. return err;
  126. }
  127. /** Format a bsscfg indexed iovar buffer. The bsscfg index will be
  128. * taken care of in dhd_ioctl_entry. Internal use only, not exposed to
  129. * wl_iw, wl_cfg80211 and wl_cfgp2p
  130. */
  131. s32 wldev_mkiovar_bsscfg(
  132. const s8 *iovar_name, s8 *param, s32 paramlen,
  133. s8 *iovar_buf, s32 buflen, s32 bssidx)
  134. {
  135. const s8 *prefix = "bsscfg:";
  136. s8 *p;
  137. u32 prefixlen;
  138. u32 namelen;
  139. u32 iolen;
  140. if (bssidx == 0) {
  141. return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen,
  142. (s8 *) iovar_buf, buflen);
  143. }
  144. prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */
  145. namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */
  146. iolen = prefixlen + namelen + sizeof(u32) + paramlen;
  147. if (buflen < 0 || iolen > (u32)buflen)
  148. {
  149. WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__));
  150. return BCME_BUFTOOSHORT;
  151. }
  152. p = (s8 *)iovar_buf;
  153. /* copy prefix, no null */
  154. memcpy(p, prefix, prefixlen);
  155. p += prefixlen;
  156. /* copy iovar name including null */
  157. memcpy(p, iovar_name, namelen);
  158. p += namelen;
  159. /* bss config index as first param */
  160. bssidx = htod32(bssidx);
  161. memcpy(p, &bssidx, sizeof(u32));
  162. p += sizeof(u32);
  163. /* parameter buffer follows */
  164. if (paramlen)
  165. memcpy(p, param, paramlen);
  166. return iolen;
  167. }
  168. s32 wldev_iovar_getbuf_bsscfg(
  169. struct net_device *dev, s8 *iovar_name,
  170. void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
  171. {
  172. s32 ret = 0;
  173. if (buf_sync) {
  174. mutex_lock(buf_sync);
  175. }
  176. wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
  177. ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
  178. if (buf_sync) {
  179. mutex_unlock(buf_sync);
  180. }
  181. return ret;
  182. }
  183. s32 wldev_iovar_setbuf_bsscfg(
  184. struct net_device *dev, s8 *iovar_name,
  185. void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
  186. {
  187. s32 ret = 0;
  188. s32 iovar_len;
  189. if (buf_sync) {
  190. mutex_lock(buf_sync);
  191. }
  192. iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
  193. if (iovar_len > 0)
  194. ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
  195. else {
  196. if (buf_sync) {
  197. mutex_unlock(buf_sync);
  198. }
  199. return BCME_BUFTOOSHORT;
  200. }
  201. if (buf_sync) {
  202. mutex_unlock(buf_sync);
  203. }
  204. return ret;
  205. }
  206. s32 wldev_iovar_setint_bsscfg(
  207. struct net_device *dev, s8 *iovar, s32 val, s32 bssidx)
  208. {
  209. s8 iovar_buf[WLC_IOCTL_SMLEN];
  210. val = htod32(val);
  211. memset(iovar_buf, 0, sizeof(iovar_buf));
  212. return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf,
  213. sizeof(iovar_buf), bssidx, NULL);
  214. }
  215. s32 wldev_iovar_getint_bsscfg(
  216. struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx)
  217. {
  218. s8 iovar_buf[WLC_IOCTL_SMLEN];
  219. s32 err;
  220. memset(iovar_buf, 0, sizeof(iovar_buf));
  221. err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf,
  222. sizeof(iovar_buf), bssidx, NULL);
  223. if (err == 0)
  224. {
  225. memcpy(pval, iovar_buf, sizeof(*pval));
  226. *pval = dtoh32(*pval);
  227. }
  228. return err;
  229. }
  230. int wldev_get_link_speed(
  231. struct net_device *dev, int *plink_speed)
  232. {
  233. int error;
  234. if (!plink_speed)
  235. return -ENOMEM;
  236. error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0);
  237. if (unlikely(error))
  238. return error;
  239. /* Convert internal 500Kbps to Kbps */
  240. *plink_speed *= 500;
  241. return error;
  242. }
  243. int wldev_get_rssi(
  244. struct net_device *dev, int *prssi)
  245. {
  246. scb_val_t scb_val;
  247. int error;
  248. if (!prssi)
  249. return -ENOMEM;
  250. bzero(&scb_val, sizeof(scb_val_t));
  251. error = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0);
  252. if (unlikely(error))
  253. return error;
  254. *prssi = dtoh32(scb_val.val);
  255. return error;
  256. }
  257. int wldev_get_ssid(
  258. struct net_device *dev, wlc_ssid_t *pssid)
  259. {
  260. int error;
  261. if (!pssid)
  262. return -ENOMEM;
  263. error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0);
  264. if (unlikely(error))
  265. return error;
  266. pssid->SSID_len = dtoh32(pssid->SSID_len);
  267. return error;
  268. }
  269. int wldev_get_band(
  270. struct net_device *dev, uint *pband)
  271. {
  272. int error;
  273. error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0);
  274. return error;
  275. }
  276. int wldev_set_band(
  277. struct net_device *dev, uint band)
  278. {
  279. int error = -1;
  280. if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
  281. error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), 1);
  282. }
  283. return error;
  284. }
  285. int wldev_set_country(
  286. struct net_device *dev, char *country_code)
  287. {
  288. int error = -1;
  289. wl_country_t cspec = {{0}, 0, {0}};
  290. scb_val_t scbval;
  291. char smbuf[WLC_IOCTL_SMLEN];
  292. if (!country_code)
  293. return error;
  294. error = wldev_iovar_getbuf(dev, "country", &cspec, sizeof(cspec),
  295. smbuf, sizeof(smbuf), NULL);
  296. if (error < 0)
  297. WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
  298. if ((error < 0) ||
  299. (strncmp(country_code, smbuf, WLC_CNTRY_BUF_SZ) != 0)) {
  300. bzero(&scbval, sizeof(scb_val_t));
  301. error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), 1);
  302. if (error < 0) {
  303. WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n",
  304. __FUNCTION__, error));
  305. return error;
  306. }
  307. }
  308. cspec.rev = -1;
  309. memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
  310. memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
  311. get_customized_country_code((char *)&cspec.country_abbrev, &cspec);
  312. error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
  313. smbuf, sizeof(smbuf), NULL);
  314. if (error < 0) {
  315. WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n",
  316. __FUNCTION__, country_code, cspec.ccode, cspec.rev));
  317. return error;
  318. }
  319. dhd_bus_country_set(dev, &cspec);
  320. WLDEV_INFO(("%s: set country for %s as %s rev %d\n",
  321. __FUNCTION__, country_code, cspec.ccode, cspec.rev));
  322. return 0;
  323. }