2 * Common function shared by Linux WEXT, cfg80211 and p2p drivers
4 * $Copyright Open Broadcom Corporation$
6 * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
10 #include <linux/kernel.h>
11 #include <linux/kthread.h>
12 #include <linux/netdevice.h>
14 #include <wldev_common.h>
21 #define htodchanspec(i) i
22 #define dtohchanspec(i) i
24 #define WLDEV_ERROR(args) \
26 printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__); \
30 extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd);
33 struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
39 memset(&ioc, 0, sizeof(ioc));
45 ret = dhd_ioctl_entry_local(dev, &ioc, cmd);
50 /* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be
51 * taken care of in dhd_ioctl_entry. Internal use only, not exposed to
52 * wl_iw, wl_cfg80211 and wl_cfgp2p
54 static s32 wldev_mkiovar(
55 s8 *iovar_name, s8 *param, s32 paramlen,
56 s8 *iovar_buf, u32 buflen)
60 iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen);
64 s32 wldev_iovar_getbuf(
65 struct net_device *dev, s8 *iovar_name,
66 void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
72 wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
73 ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
75 mutex_unlock(buf_sync);
80 s32 wldev_iovar_setbuf(
81 struct net_device *dev, s8 *iovar_name,
82 void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
89 iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
91 ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
93 ret = BCME_BUFTOOSHORT;
96 mutex_unlock(buf_sync);
100 s32 wldev_iovar_setint(
101 struct net_device *dev, s8 *iovar, s32 val)
103 s8 iovar_buf[WLC_IOCTL_SMLEN];
106 memset(iovar_buf, 0, sizeof(iovar_buf));
107 return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf,
108 sizeof(iovar_buf), NULL);
112 s32 wldev_iovar_getint(
113 struct net_device *dev, s8 *iovar, s32 *pval)
115 s8 iovar_buf[WLC_IOCTL_SMLEN];
118 memset(iovar_buf, 0, sizeof(iovar_buf));
119 err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf,
120 sizeof(iovar_buf), NULL);
123 memcpy(pval, iovar_buf, sizeof(*pval));
124 *pval = dtoh32(*pval);
129 /** Format a bsscfg indexed iovar buffer. The bsscfg index will be
130 * taken care of in dhd_ioctl_entry. Internal use only, not exposed to
131 * wl_iw, wl_cfg80211 and wl_cfgp2p
133 s32 wldev_mkiovar_bsscfg(
134 const s8 *iovar_name, s8 *param, s32 paramlen,
135 s8 *iovar_buf, s32 buflen, s32 bssidx)
137 const s8 *prefix = "bsscfg:";
144 return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen,
145 (s8 *) iovar_buf, buflen);
148 prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */
149 namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */
150 iolen = prefixlen + namelen + sizeof(u32) + paramlen;
152 if (buflen < 0 || iolen > (u32)buflen)
154 WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__));
155 return BCME_BUFTOOSHORT;
160 /* copy prefix, no null */
161 memcpy(p, prefix, prefixlen);
164 /* copy iovar name including null */
165 memcpy(p, iovar_name, namelen);
168 /* bss config index as first param */
169 bssidx = htod32(bssidx);
170 memcpy(p, &bssidx, sizeof(u32));
173 /* parameter buffer follows */
175 memcpy(p, param, paramlen);
181 s32 wldev_iovar_getbuf_bsscfg(
182 struct net_device *dev, s8 *iovar_name,
183 void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
187 mutex_lock(buf_sync);
190 wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
191 ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
193 mutex_unlock(buf_sync);
199 s32 wldev_iovar_setbuf_bsscfg(
200 struct net_device *dev, s8 *iovar_name,
201 void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
206 mutex_lock(buf_sync);
208 iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
210 ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
212 ret = BCME_BUFTOOSHORT;
216 mutex_unlock(buf_sync);
221 s32 wldev_iovar_setint_bsscfg(
222 struct net_device *dev, s8 *iovar, s32 val, s32 bssidx)
224 s8 iovar_buf[WLC_IOCTL_SMLEN];
227 memset(iovar_buf, 0, sizeof(iovar_buf));
228 return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf,
229 sizeof(iovar_buf), bssidx, NULL);
233 s32 wldev_iovar_getint_bsscfg(
234 struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx)
236 s8 iovar_buf[WLC_IOCTL_SMLEN];
239 memset(iovar_buf, 0, sizeof(iovar_buf));
240 err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf,
241 sizeof(iovar_buf), bssidx, NULL);
244 memcpy(pval, iovar_buf, sizeof(*pval));
245 *pval = dtoh32(*pval);
250 int wldev_get_link_speed(
251 struct net_device *dev, int *plink_speed)
257 error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0);
261 /* Convert internal 500Kbps to Kbps */
267 struct net_device *dev, int *prssi)
274 bzero(&scb_val, sizeof(scb_val_t));
276 error = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0);
280 *prssi = dtoh32(scb_val.val);
285 struct net_device *dev, wlc_ssid_t *pssid)
291 error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0);
294 pssid->SSID_len = dtoh32(pssid->SSID_len);
299 struct net_device *dev, uint *pband)
303 error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0);
308 struct net_device *dev, uint band)
312 if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
313 error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true);
315 dhd_bus_band_set(dev, band);
320 int wldev_set_country(
321 struct net_device *dev, char *country_code, bool notify, bool user_enforced)
324 wl_country_t cspec = {{0}, 0, {0}};
326 char smbuf[WLC_IOCTL_SMLEN];
331 bzero(&scbval, sizeof(scb_val_t));
332 error = wldev_iovar_getbuf(dev, "country", NULL, 0, &cspec, sizeof(cspec), NULL);
334 WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
339 (strncmp(country_code, cspec.ccode, WLC_CNTRY_BUF_SZ) != 0)) {
342 bzero(&scbval, sizeof(scb_val_t));
343 error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true);
345 WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n",
346 __FUNCTION__, error));
352 memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
353 memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
354 get_customized_country_code((char *)&cspec.country_abbrev, &cspec);
355 error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
356 smbuf, sizeof(smbuf), NULL);
358 WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n",
359 __FUNCTION__, country_code, cspec.ccode, cspec.rev));
362 dhd_bus_country_set(dev, &cspec, notify);
363 WLDEV_ERROR(("%s: set country for %s as %s rev %d\n",
364 __FUNCTION__, country_code, cspec.ccode, cspec.rev));