bcm43xx_wx.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. /*
  2. Broadcom BCM43xx wireless driver
  3. Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
  4. Stefano Brivio <st3@riseup.net>
  5. Michael Buesch <mbuesch@freenet.de>
  6. Danny van Dyk <kugelfang@gentoo.org>
  7. Andreas Jaggi <andreas.jaggi@waterwave.ch>
  8. Some parts of the code in this file are derived from the ipw2200
  9. driver Copyright(c) 2003 - 2004 Intel Corporation.
  10. This program is free software; you can redistribute it and/or modify
  11. it under the terms of the GNU General Public License as published by
  12. the Free Software Foundation; either version 2 of the License, or
  13. (at your option) any later version.
  14. This program is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. GNU General Public License for more details.
  18. You should have received a copy of the GNU General Public License
  19. along with this program; see the file COPYING. If not, write to
  20. the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
  21. Boston, MA 02110-1301, USA.
  22. */
  23. #include <linux/wireless.h>
  24. #include <net/iw_handler.h>
  25. #include <net/ieee80211softmac.h>
  26. #include <net/ieee80211softmac_wx.h>
  27. #include <linux/capability.h>
  28. #include <linux/sched.h> /* for capable() */
  29. #include <linux/delay.h>
  30. #include "bcm43xx.h"
  31. #include "bcm43xx_wx.h"
  32. #include "bcm43xx_main.h"
  33. #include "bcm43xx_radio.h"
  34. /* The WIRELESS_EXT version, which is implemented by this driver. */
  35. #define BCM43xx_WX_VERSION 18
  36. /* Define to enable a printk on each wx handler function invocation */
  37. //#define BCM43xx_WX_DEBUG
  38. #ifdef BCM43xx_WX_DEBUG
  39. # define printk_wx printk
  40. #else
  41. # define printk_wx(x...) do { /* nothing */ } while (0)
  42. #endif
  43. #define wx_enter() printk_wx(KERN_INFO PFX "WX handler called: %s\n", __FUNCTION__);
  44. #define MAX_WX_STRING 80
  45. static int bcm43xx_wx_get_name(struct net_device *net_dev,
  46. struct iw_request_info *info,
  47. union iwreq_data *data,
  48. char *extra)
  49. {
  50. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  51. unsigned long flags;
  52. int i, nr_80211;
  53. struct bcm43xx_phyinfo *phy;
  54. char suffix[7] = { 0 };
  55. int have_a = 0, have_b = 0, have_g = 0;
  56. wx_enter();
  57. spin_lock_irqsave(&bcm->lock, flags);
  58. nr_80211 = bcm43xx_num_80211_cores(bcm);
  59. for (i = 0; i < nr_80211; i++) {
  60. phy = bcm->phy + i;
  61. switch (phy->type) {
  62. case BCM43xx_PHYTYPE_A:
  63. have_a = 1;
  64. break;
  65. case BCM43xx_PHYTYPE_G:
  66. have_g = 1;
  67. case BCM43xx_PHYTYPE_B:
  68. have_b = 1;
  69. break;
  70. default:
  71. assert(0);
  72. }
  73. }
  74. spin_unlock_irqrestore(&bcm->lock, flags);
  75. i = 0;
  76. if (have_a) {
  77. suffix[i++] = 'a';
  78. suffix[i++] = '/';
  79. }
  80. if (have_b) {
  81. suffix[i++] = 'b';
  82. suffix[i++] = '/';
  83. }
  84. if (have_g) {
  85. suffix[i++] = 'g';
  86. suffix[i++] = '/';
  87. }
  88. if (i != 0)
  89. suffix[i - 1] = '\0';
  90. snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix);
  91. return 0;
  92. }
  93. static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
  94. struct iw_request_info *info,
  95. union iwreq_data *data,
  96. char *extra)
  97. {
  98. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  99. struct ieee80211softmac_device *softmac = bcm->softmac;
  100. unsigned long flags;
  101. u8 channel;
  102. int freq;
  103. int err = 0;
  104. wx_enter();
  105. if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
  106. channel = data->freq.m;
  107. freq = bcm43xx_channel_to_freq(bcm, channel);
  108. } else {
  109. channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
  110. freq = data->freq.m;
  111. }
  112. if (!bcm43xx_is_valid_channel(bcm, channel))
  113. return -EINVAL;
  114. spin_lock_irqsave(&bcm->lock, flags);
  115. if (bcm->initialized) {
  116. //ieee80211softmac_disassoc(softmac, $REASON);
  117. bcm43xx_mac_suspend(bcm);
  118. err = bcm43xx_radio_selectchannel(bcm, channel, 0);
  119. bcm43xx_mac_enable(bcm);
  120. } else
  121. bcm->current_core->radio->initial_channel = channel;
  122. spin_unlock_irqrestore(&bcm->lock, flags);
  123. if (!err)
  124. printk_wx(KERN_INFO PFX "Selected channel: %d\n", channel);
  125. return err;
  126. }
  127. static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
  128. struct iw_request_info *info,
  129. union iwreq_data *data,
  130. char *extra)
  131. {
  132. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  133. unsigned long flags;
  134. int err = -ENODEV;
  135. u16 channel;
  136. wx_enter();
  137. spin_lock_irqsave(&bcm->lock, flags);
  138. channel = bcm->current_core->radio->channel;
  139. if (channel == 0xFF) {
  140. assert(!bcm->initialized);
  141. channel = bcm->current_core->radio->initial_channel;
  142. if (channel == 0xFF)
  143. goto out_unlock;
  144. }
  145. assert(channel > 0 && channel <= 1000);
  146. data->freq.e = 1;
  147. data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000;
  148. data->freq.flags = 1;
  149. err = 0;
  150. out_unlock:
  151. spin_unlock_irqrestore(&bcm->lock, flags);
  152. return err;
  153. }
  154. static int bcm43xx_wx_set_mode(struct net_device *net_dev,
  155. struct iw_request_info *info,
  156. union iwreq_data *data,
  157. char *extra)
  158. {
  159. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  160. unsigned long flags;
  161. int mode;
  162. wx_enter();
  163. mode = data->mode;
  164. if (mode == IW_MODE_AUTO)
  165. mode = BCM43xx_INITIAL_IWMODE;
  166. spin_lock_irqsave(&bcm->lock, flags);
  167. if (bcm->ieee->iw_mode != mode)
  168. bcm43xx_set_iwmode(bcm, mode);
  169. spin_unlock_irqrestore(&bcm->lock, flags);
  170. return 0;
  171. }
  172. static int bcm43xx_wx_get_mode(struct net_device *net_dev,
  173. struct iw_request_info *info,
  174. union iwreq_data *data,
  175. char *extra)
  176. {
  177. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  178. unsigned long flags;
  179. wx_enter();
  180. spin_lock_irqsave(&bcm->lock, flags);
  181. data->mode = bcm->ieee->iw_mode;
  182. spin_unlock_irqrestore(&bcm->lock, flags);
  183. return 0;
  184. }
  185. static int bcm43xx_wx_set_sensitivity(struct net_device *net_dev,
  186. struct iw_request_info *info,
  187. union iwreq_data *data,
  188. char *extra)
  189. {
  190. wx_enter();
  191. /*TODO*/
  192. return 0;
  193. }
  194. static int bcm43xx_wx_get_sensitivity(struct net_device *net_dev,
  195. struct iw_request_info *info,
  196. union iwreq_data *data,
  197. char *extra)
  198. {
  199. wx_enter();
  200. /*TODO*/
  201. return 0;
  202. }
  203. static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
  204. struct iw_request_info *info,
  205. union iwreq_data *data,
  206. char *extra)
  207. {
  208. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  209. struct iw_range *range = (struct iw_range *)extra;
  210. const struct ieee80211_geo *geo;
  211. unsigned long flags;
  212. int i, j;
  213. wx_enter();
  214. data->data.length = sizeof(*range);
  215. memset(range, 0, sizeof(*range));
  216. //TODO: What about 802.11b?
  217. /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
  218. range->throughput = 27 * 1000 * 1000;
  219. range->max_qual.qual = 100;
  220. /* TODO: Real max RSSI */
  221. range->max_qual.level = 0;
  222. range->max_qual.noise = 0;
  223. range->max_qual.updated = 7;
  224. range->avg_qual.qual = 70;
  225. range->avg_qual.level = 0;
  226. range->avg_qual.noise = 0;
  227. range->avg_qual.updated = 7;
  228. range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
  229. range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
  230. range->min_frag = MIN_FRAG_THRESHOLD;
  231. range->max_frag = MAX_FRAG_THRESHOLD;
  232. range->encoding_size[0] = 5;
  233. range->encoding_size[1] = 13;
  234. range->num_encoding_sizes = 2;
  235. range->max_encoding_tokens = WEP_KEYS;
  236. range->we_version_compiled = WIRELESS_EXT;
  237. range->we_version_source = BCM43xx_WX_VERSION;
  238. range->enc_capa = IW_ENC_CAPA_WPA |
  239. IW_ENC_CAPA_WPA2 |
  240. IW_ENC_CAPA_CIPHER_TKIP |
  241. IW_ENC_CAPA_CIPHER_CCMP;
  242. spin_lock_irqsave(&bcm->lock, flags);
  243. range->num_bitrates = 0;
  244. i = 0;
  245. if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ||
  246. bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
  247. range->num_bitrates = 8;
  248. range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
  249. range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
  250. range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
  251. range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
  252. range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
  253. range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
  254. range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
  255. range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
  256. }
  257. if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B ||
  258. bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
  259. range->num_bitrates += 4;
  260. range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
  261. range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
  262. range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
  263. range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
  264. }
  265. geo = ieee80211_get_geo(bcm->ieee);
  266. range->num_channels = geo->a_channels + geo->bg_channels;
  267. j = 0;
  268. for (i = 0; i < geo->a_channels; i++) {
  269. if (j == IW_MAX_FREQUENCIES)
  270. break;
  271. range->freq[j].i = j + 1;
  272. range->freq[j].m = geo->a[i].freq;//FIXME?
  273. range->freq[j].e = 1;
  274. j++;
  275. }
  276. for (i = 0; i < geo->bg_channels; i++) {
  277. if (j == IW_MAX_FREQUENCIES)
  278. break;
  279. range->freq[j].i = j + 1;
  280. range->freq[j].m = geo->bg[i].freq;//FIXME?
  281. range->freq[j].e = 1;
  282. j++;
  283. }
  284. range->num_frequency = j;
  285. spin_unlock_irqrestore(&bcm->lock, flags);
  286. return 0;
  287. }
  288. static int bcm43xx_wx_set_nick(struct net_device *net_dev,
  289. struct iw_request_info *info,
  290. union iwreq_data *data,
  291. char *extra)
  292. {
  293. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  294. unsigned long flags;
  295. size_t len;
  296. wx_enter();
  297. spin_lock_irqsave(&bcm->lock, flags);
  298. len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
  299. memcpy(bcm->nick, extra, len);
  300. bcm->nick[len] = '\0';
  301. spin_unlock_irqrestore(&bcm->lock, flags);
  302. return 0;
  303. }
  304. static int bcm43xx_wx_get_nick(struct net_device *net_dev,
  305. struct iw_request_info *info,
  306. union iwreq_data *data,
  307. char *extra)
  308. {
  309. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  310. unsigned long flags;
  311. size_t len;
  312. wx_enter();
  313. spin_lock_irqsave(&bcm->lock, flags);
  314. len = strlen(bcm->nick) + 1;
  315. memcpy(extra, bcm->nick, len);
  316. data->data.length = (__u16)len;
  317. data->data.flags = 1;
  318. spin_unlock_irqrestore(&bcm->lock, flags);
  319. return 0;
  320. }
  321. static int bcm43xx_wx_set_rts(struct net_device *net_dev,
  322. struct iw_request_info *info,
  323. union iwreq_data *data,
  324. char *extra)
  325. {
  326. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  327. unsigned long flags;
  328. int err = -EINVAL;
  329. wx_enter();
  330. spin_lock_irqsave(&bcm->lock, flags);
  331. if (data->rts.disabled) {
  332. bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
  333. err = 0;
  334. } else {
  335. if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD &&
  336. data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) {
  337. bcm->rts_threshold = data->rts.value;
  338. err = 0;
  339. }
  340. }
  341. spin_unlock_irqrestore(&bcm->lock, flags);
  342. return err;
  343. }
  344. static int bcm43xx_wx_get_rts(struct net_device *net_dev,
  345. struct iw_request_info *info,
  346. union iwreq_data *data,
  347. char *extra)
  348. {
  349. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  350. unsigned long flags;
  351. wx_enter();
  352. spin_lock_irqsave(&bcm->lock, flags);
  353. data->rts.value = bcm->rts_threshold;
  354. data->rts.fixed = 0;
  355. data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
  356. spin_unlock_irqrestore(&bcm->lock, flags);
  357. return 0;
  358. }
  359. static int bcm43xx_wx_set_frag(struct net_device *net_dev,
  360. struct iw_request_info *info,
  361. union iwreq_data *data,
  362. char *extra)
  363. {
  364. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  365. unsigned long flags;
  366. int err = -EINVAL;
  367. wx_enter();
  368. spin_lock_irqsave(&bcm->lock, flags);
  369. if (data->frag.disabled) {
  370. bcm->ieee->fts = MAX_FRAG_THRESHOLD;
  371. err = 0;
  372. } else {
  373. if (data->frag.value >= MIN_FRAG_THRESHOLD &&
  374. data->frag.value <= MAX_FRAG_THRESHOLD) {
  375. bcm->ieee->fts = data->frag.value & ~0x1;
  376. err = 0;
  377. }
  378. }
  379. spin_unlock_irqrestore(&bcm->lock, flags);
  380. return err;
  381. }
  382. static int bcm43xx_wx_get_frag(struct net_device *net_dev,
  383. struct iw_request_info *info,
  384. union iwreq_data *data,
  385. char *extra)
  386. {
  387. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  388. unsigned long flags;
  389. wx_enter();
  390. spin_lock_irqsave(&bcm->lock, flags);
  391. data->frag.value = bcm->ieee->fts;
  392. data->frag.fixed = 0;
  393. data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
  394. spin_unlock_irqrestore(&bcm->lock, flags);
  395. return 0;
  396. }
  397. static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
  398. struct iw_request_info *info,
  399. union iwreq_data *data,
  400. char *extra)
  401. {
  402. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  403. struct bcm43xx_radioinfo *radio;
  404. struct bcm43xx_phyinfo *phy;
  405. unsigned long flags;
  406. int err = -ENODEV;
  407. u16 maxpower;
  408. wx_enter();
  409. if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
  410. printk(PFX KERN_ERR "TX power not in dBm.\n");
  411. return -EOPNOTSUPP;
  412. }
  413. spin_lock_irqsave(&bcm->lock, flags);
  414. if (!bcm->initialized)
  415. goto out_unlock;
  416. radio = bcm->current_core->radio;
  417. phy = bcm->current_core->phy;
  418. if (data->txpower.disabled != (!(radio->enabled))) {
  419. if (data->txpower.disabled)
  420. bcm43xx_radio_turn_off(bcm);
  421. else
  422. bcm43xx_radio_turn_on(bcm);
  423. }
  424. if (data->txpower.value > 0) {
  425. /* desired and maxpower dBm values are in Q5.2 */
  426. if (phy->type == BCM43xx_PHYTYPE_A)
  427. maxpower = bcm->sprom.maxpower_aphy;
  428. else
  429. maxpower = bcm->sprom.maxpower_bgphy;
  430. radio->txpower_desired = limit_value(data->txpower.value << 2,
  431. 0, maxpower);
  432. bcm43xx_phy_xmitpower(bcm);
  433. }
  434. err = 0;
  435. out_unlock:
  436. spin_unlock_irqrestore(&bcm->lock, flags);
  437. return err;
  438. }
  439. static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
  440. struct iw_request_info *info,
  441. union iwreq_data *data,
  442. char *extra)
  443. {
  444. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  445. struct bcm43xx_radioinfo *radio;
  446. unsigned long flags;
  447. int err = -ENODEV;
  448. wx_enter();
  449. spin_lock_irqsave(&bcm->lock, flags);
  450. if (!bcm->initialized)
  451. goto out_unlock;
  452. radio = bcm->current_core->radio;
  453. /* desired dBm value is in Q5.2 */
  454. data->txpower.value = radio->txpower_desired >> 2;
  455. data->txpower.fixed = 1;
  456. data->txpower.flags = IW_TXPOW_DBM;
  457. data->txpower.disabled = !(radio->enabled);
  458. err = 0;
  459. out_unlock:
  460. spin_unlock_irqrestore(&bcm->lock, flags);
  461. return err;
  462. }
  463. static int bcm43xx_wx_set_retry(struct net_device *net_dev,
  464. struct iw_request_info *info,
  465. union iwreq_data *data,
  466. char *extra)
  467. {
  468. wx_enter();
  469. /*TODO*/
  470. return 0;
  471. }
  472. static int bcm43xx_wx_get_retry(struct net_device *net_dev,
  473. struct iw_request_info *info,
  474. union iwreq_data *data,
  475. char *extra)
  476. {
  477. wx_enter();
  478. /*TODO*/
  479. return 0;
  480. }
  481. static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
  482. struct iw_request_info *info,
  483. union iwreq_data *data,
  484. char *extra)
  485. {
  486. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  487. int err;
  488. wx_enter();
  489. err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
  490. return err;
  491. }
  492. static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
  493. struct iw_request_info *info,
  494. union iwreq_data *data,
  495. char *extra)
  496. {
  497. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  498. int err;
  499. wx_enter();
  500. err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
  501. return err;
  502. }
  503. static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
  504. struct iw_request_info *info,
  505. union iwreq_data *data,
  506. char *extra)
  507. {
  508. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  509. int err;
  510. wx_enter();
  511. err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
  512. return err;
  513. }
  514. static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
  515. struct iw_request_info *info,
  516. union iwreq_data *data,
  517. char *extra)
  518. {
  519. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  520. int err;
  521. wx_enter();
  522. err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
  523. return err;
  524. }
  525. static int bcm43xx_wx_set_power(struct net_device *net_dev,
  526. struct iw_request_info *info,
  527. union iwreq_data *data,
  528. char *extra)
  529. {
  530. wx_enter();
  531. /*TODO*/
  532. return 0;
  533. }
  534. static int bcm43xx_wx_get_power(struct net_device *net_dev,
  535. struct iw_request_info *info,
  536. union iwreq_data *data,
  537. char *extra)
  538. {
  539. wx_enter();
  540. /*TODO*/
  541. return 0;
  542. }
  543. static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
  544. struct iw_request_info *info,
  545. union iwreq_data *data,
  546. char *extra)
  547. {
  548. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  549. unsigned long flags;
  550. int mode, err = 0;
  551. wx_enter();
  552. mode = *((int *)extra);
  553. switch (mode) {
  554. case 0:
  555. mode = BCM43xx_RADIO_INTERFMODE_NONE;
  556. break;
  557. case 1:
  558. mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
  559. break;
  560. case 2:
  561. mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
  562. break;
  563. case 3:
  564. mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
  565. break;
  566. default:
  567. printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
  568. "0 => None, 1 => Non-WLAN, 2 => WLAN, "
  569. "3 => Auto-WLAN\n");
  570. return -EINVAL;
  571. }
  572. spin_lock_irqsave(&bcm->lock, flags);
  573. if (bcm->initialized) {
  574. err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
  575. if (err) {
  576. printk(KERN_ERR PFX "Interference Mitigation not "
  577. "supported by device\n");
  578. }
  579. } else {
  580. if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
  581. printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
  582. "not supported while the interface is down.\n");
  583. err = -ENODEV;
  584. } else
  585. bcm->current_core->radio->interfmode = mode;
  586. }
  587. spin_unlock_irqrestore(&bcm->lock, flags);
  588. return err;
  589. }
  590. static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
  591. struct iw_request_info *info,
  592. union iwreq_data *data,
  593. char *extra)
  594. {
  595. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  596. unsigned long flags;
  597. int mode;
  598. wx_enter();
  599. spin_lock_irqsave(&bcm->lock, flags);
  600. mode = bcm->current_core->radio->interfmode;
  601. spin_unlock_irqrestore(&bcm->lock, flags);
  602. switch (mode) {
  603. case BCM43xx_RADIO_INTERFMODE_NONE:
  604. strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
  605. break;
  606. case BCM43xx_RADIO_INTERFMODE_NONWLAN:
  607. strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
  608. break;
  609. case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
  610. strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
  611. break;
  612. default:
  613. assert(0);
  614. }
  615. data->data.length = strlen(extra) + 1;
  616. return 0;
  617. }
  618. static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
  619. struct iw_request_info *info,
  620. union iwreq_data *data,
  621. char *extra)
  622. {
  623. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  624. unsigned long flags;
  625. int on;
  626. wx_enter();
  627. on = *((int *)extra);
  628. spin_lock_irqsave(&bcm->lock, flags);
  629. bcm->short_preamble = !!on;
  630. spin_unlock_irqrestore(&bcm->lock, flags);
  631. return 0;
  632. }
  633. static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
  634. struct iw_request_info *info,
  635. union iwreq_data *data,
  636. char *extra)
  637. {
  638. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  639. unsigned long flags;
  640. int on;
  641. wx_enter();
  642. spin_lock_irqsave(&bcm->lock, flags);
  643. on = bcm->short_preamble;
  644. spin_unlock_irqrestore(&bcm->lock, flags);
  645. if (on)
  646. strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
  647. else
  648. strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
  649. data->data.length = strlen(extra) + 1;
  650. return 0;
  651. }
  652. static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
  653. struct iw_request_info *info,
  654. union iwreq_data *data,
  655. char *extra)
  656. {
  657. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  658. unsigned long flags;
  659. int on;
  660. wx_enter();
  661. on = *((int *)extra);
  662. spin_lock_irqsave(&bcm->lock, flags);
  663. bcm->ieee->host_encrypt = !!on;
  664. bcm->ieee->host_decrypt = !!on;
  665. bcm->ieee->host_build_iv = !on;
  666. spin_unlock_irqrestore(&bcm->lock, flags);
  667. return 0;
  668. }
  669. static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
  670. struct iw_request_info *info,
  671. union iwreq_data *data,
  672. char *extra)
  673. {
  674. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  675. unsigned long flags;
  676. int on;
  677. wx_enter();
  678. spin_lock_irqsave(&bcm->lock, flags);
  679. on = bcm->ieee->host_encrypt;
  680. spin_unlock_irqrestore(&bcm->lock, flags);
  681. if (on)
  682. strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
  683. else
  684. strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
  685. data->data.length = strlen(extra + 1);
  686. return 0;
  687. }
  688. /* Enough buffer to hold a hexdump of the sprom data. */
  689. #define SPROM_BUFFERSIZE 512
  690. static int sprom2hex(const u16 *sprom, char *dump)
  691. {
  692. int i, pos = 0;
  693. for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
  694. pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
  695. "%04X", swab16(sprom[i]) & 0xFFFF);
  696. }
  697. return pos + 1;
  698. }
  699. static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
  700. {
  701. char tmp[5] = { 0 };
  702. int cnt = 0;
  703. unsigned long parsed;
  704. u8 crc, expected_crc;
  705. if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
  706. return -EINVAL;
  707. while (cnt < BCM43xx_SPROM_SIZE) {
  708. memcpy(tmp, dump, 4);
  709. dump += 4;
  710. parsed = simple_strtoul(tmp, NULL, 16);
  711. sprom[cnt++] = swab16((u16)parsed);
  712. }
  713. crc = bcm43xx_sprom_crc(sprom);
  714. expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
  715. if (crc != expected_crc) {
  716. printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
  717. return -EINVAL;
  718. }
  719. return 0;
  720. }
  721. static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
  722. struct iw_request_info *info,
  723. union iwreq_data *data,
  724. char *extra)
  725. {
  726. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  727. int err = -EPERM, i;
  728. u16 *sprom;
  729. unsigned long flags;
  730. if (!capable(CAP_SYS_RAWIO))
  731. goto out;
  732. err = -ENOMEM;
  733. sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
  734. GFP_KERNEL);
  735. if (!sprom)
  736. goto out;
  737. spin_lock_irqsave(&bcm->lock, flags);
  738. err = -ENODEV;
  739. if (!bcm->initialized) {
  740. spin_unlock_irqrestore(&bcm->lock, flags);
  741. goto out_kfree;
  742. }
  743. for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
  744. sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
  745. spin_unlock_irqrestore(&bcm->lock, flags);
  746. data->data.length = sprom2hex(sprom, extra);
  747. err = 0;
  748. out_kfree:
  749. kfree(sprom);
  750. out:
  751. return err;
  752. }
  753. static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
  754. struct iw_request_info *info,
  755. union iwreq_data *data,
  756. char *extra)
  757. {
  758. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  759. int err = -EPERM;
  760. u16 *sprom;
  761. unsigned long flags;
  762. char *input;
  763. unsigned int len;
  764. u32 spromctl;
  765. int i;
  766. if (!capable(CAP_SYS_RAWIO))
  767. goto out;
  768. err = -ENOMEM;
  769. sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
  770. GFP_KERNEL);
  771. if (!sprom)
  772. goto out;
  773. len = data->data.length;
  774. extra[len - 1] = '\0';
  775. input = strchr(extra, ':');
  776. if (input) {
  777. input++;
  778. len -= input - extra;
  779. } else
  780. input = extra;
  781. err = hex2sprom(sprom, input, len);
  782. if (err)
  783. goto out_kfree;
  784. spin_lock_irqsave(&bcm->lock, flags);
  785. err = -ENODEV;
  786. if (!bcm->initialized) {
  787. spin_unlock_irqrestore(&bcm->lock, flags);
  788. goto out_kfree;
  789. }
  790. printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
  791. err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
  792. if (err) {
  793. printk(KERN_ERR PFX "Could not access SPROM control register.\n");
  794. goto out_unlock;
  795. }
  796. spromctl |= 0x10; /* SPROM WRITE enable. */
  797. bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
  798. if (err) {
  799. printk(KERN_ERR PFX "Could not access SPROM control register.\n");
  800. goto out_unlock;
  801. }
  802. /* We must burn lots of CPU cycles here, but that does not
  803. * really matter as one does not write the SPROM every other minute...
  804. */
  805. printk(KERN_INFO PFX "[ 0%%");
  806. mdelay(500);
  807. for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
  808. if (i == 16)
  809. printk("25%%");
  810. else if (i == 32)
  811. printk("50%%");
  812. else if (i == 48)
  813. printk("75%%");
  814. else if (i % 2)
  815. printk(".");
  816. //TODO bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
  817. mdelay(20);
  818. }
  819. spromctl &= ~0x10; /* SPROM WRITE enable. */
  820. bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
  821. if (err) {
  822. printk(KERN_ERR PFX "Could not access SPROM control register.\n");
  823. goto out_unlock;
  824. }
  825. mdelay(500);
  826. printk("100%% ]\n");
  827. printk(KERN_INFO PFX "SPROM written.\n");
  828. err = 0;
  829. out_unlock:
  830. spin_unlock_irqrestore(&bcm->lock, flags);
  831. out_kfree:
  832. kfree(sprom);
  833. out:
  834. return err;
  835. }
  836. #ifdef WX
  837. # undef WX
  838. #endif
  839. #define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT]
  840. static const iw_handler bcm43xx_wx_handlers[] = {
  841. /* Wireless Identification */
  842. WX(SIOCGIWNAME) = bcm43xx_wx_get_name,
  843. /* Basic operations */
  844. WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq,
  845. WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq,
  846. WX(SIOCSIWMODE) = bcm43xx_wx_set_mode,
  847. WX(SIOCGIWMODE) = bcm43xx_wx_get_mode,
  848. /* Informative stuff */
  849. WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams,
  850. /* Access Point manipulation */
  851. WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
  852. WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
  853. WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
  854. WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
  855. /* 802.11 specific support */
  856. WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
  857. WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
  858. WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick,
  859. WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick,
  860. /* Other parameters */
  861. WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
  862. WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
  863. WX(SIOCSIWRTS) = bcm43xx_wx_set_rts,
  864. WX(SIOCGIWRTS) = bcm43xx_wx_get_rts,
  865. WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag,
  866. WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag,
  867. WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower,
  868. WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower,
  869. //TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry,
  870. //TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry,
  871. /* Encoding */
  872. WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding,
  873. WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding,
  874. WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext,
  875. WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext,
  876. /* Power saving */
  877. //TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power,
  878. //TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power,
  879. WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
  880. WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
  881. WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
  882. WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
  883. };
  884. #undef WX
  885. static const iw_handler bcm43xx_priv_wx_handlers[] = {
  886. /* Set Interference Mitigation Mode. */
  887. bcm43xx_wx_set_interfmode,
  888. /* Get Interference Mitigation Mode. */
  889. bcm43xx_wx_get_interfmode,
  890. /* Enable/Disable Short Preamble mode. */
  891. bcm43xx_wx_set_shortpreamble,
  892. /* Get Short Preamble mode. */
  893. bcm43xx_wx_get_shortpreamble,
  894. /* Enable/Disable Software Encryption mode */
  895. bcm43xx_wx_set_swencryption,
  896. /* Get Software Encryption mode */
  897. bcm43xx_wx_get_swencryption,
  898. /* Write SRPROM data. */
  899. bcm43xx_wx_sprom_write,
  900. /* Read SPROM data. */
  901. bcm43xx_wx_sprom_read,
  902. };
  903. #define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0)
  904. #define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1)
  905. #define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2)
  906. #define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3)
  907. #define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4)
  908. #define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5)
  909. #define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6)
  910. #define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7)
  911. #define PRIV_WX_DUMMY(ioctl) \
  912. { \
  913. .cmd = (ioctl), \
  914. .name = "__unused" \
  915. }
  916. static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
  917. {
  918. .cmd = PRIV_WX_SET_INTERFMODE,
  919. .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  920. .name = "set_interfmode",
  921. },
  922. {
  923. .cmd = PRIV_WX_GET_INTERFMODE,
  924. .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
  925. .name = "get_interfmode",
  926. },
  927. {
  928. .cmd = PRIV_WX_SET_SHORTPREAMBLE,
  929. .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  930. .name = "set_shortpreambl",
  931. },
  932. {
  933. .cmd = PRIV_WX_GET_SHORTPREAMBLE,
  934. .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
  935. .name = "get_shortpreambl",
  936. },
  937. {
  938. .cmd = PRIV_WX_SET_SWENCRYPTION,
  939. .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  940. .name = "set_swencryption",
  941. },
  942. {
  943. .cmd = PRIV_WX_GET_SWENCRYPTION,
  944. .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
  945. .name = "get_swencryption",
  946. },
  947. {
  948. .cmd = PRIV_WX_SPROM_WRITE,
  949. .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
  950. .name = "write_sprom",
  951. },
  952. {
  953. .cmd = PRIV_WX_SPROM_READ,
  954. .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
  955. .name = "read_sprom",
  956. },
  957. };
  958. const struct iw_handler_def bcm43xx_wx_handlers_def = {
  959. .standard = bcm43xx_wx_handlers,
  960. .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers),
  961. .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers),
  962. .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args),
  963. .private = bcm43xx_priv_wx_handlers,
  964. .private_args = bcm43xx_priv_wx_args,
  965. };
  966. /* vim: set ts=8 sw=8 sts=8: */