zd_ieee80211.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /* zd_ieee80211.c
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  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. * You should have received a copy of the GNU General Public License
  14. * along with this program; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. */
  17. /*
  18. * A lot of this code is generic and should be moved into the upper layers
  19. * at some point.
  20. */
  21. #include <linux/errno.h>
  22. #include <linux/wireless.h>
  23. #include <linux/kernel.h>
  24. #include <net/ieee80211.h>
  25. #include "zd_def.h"
  26. #include "zd_ieee80211.h"
  27. #include "zd_mac.h"
  28. static const struct channel_range channel_ranges[] = {
  29. [0] = { 0, 0},
  30. [ZD_REGDOMAIN_FCC] = { 1, 12},
  31. [ZD_REGDOMAIN_IC] = { 1, 12},
  32. [ZD_REGDOMAIN_ETSI] = { 1, 14},
  33. [ZD_REGDOMAIN_JAPAN] = { 1, 14},
  34. [ZD_REGDOMAIN_SPAIN] = { 1, 14},
  35. [ZD_REGDOMAIN_FRANCE] = { 1, 14},
  36. [ZD_REGDOMAIN_JAPAN_ADD] = {14, 15},
  37. };
  38. const struct channel_range *zd_channel_range(u8 regdomain)
  39. {
  40. if (regdomain >= ARRAY_SIZE(channel_ranges))
  41. regdomain = 0;
  42. return &channel_ranges[regdomain];
  43. }
  44. int zd_regdomain_supports_channel(u8 regdomain, u8 channel)
  45. {
  46. const struct channel_range *range = zd_channel_range(regdomain);
  47. return range->start <= channel && channel < range->end;
  48. }
  49. int zd_regdomain_supported(u8 regdomain)
  50. {
  51. const struct channel_range *range = zd_channel_range(regdomain);
  52. return range->start != 0;
  53. }
  54. /* Stores channel frequencies in MHz. */
  55. static const u16 channel_frequencies[] = {
  56. 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
  57. 2452, 2457, 2462, 2467, 2472, 2484,
  58. };
  59. #define NUM_CHANNELS ARRAY_SIZE(channel_frequencies)
  60. static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz)
  61. {
  62. u32 factor;
  63. freq->e = 0;
  64. if (mhz >= 1000000000U) {
  65. pr_debug("zd1211 mhz %u to large\n", mhz);
  66. freq->m = 0;
  67. return -EINVAL;
  68. }
  69. factor = 1000;
  70. while (mhz >= factor) {
  71. freq->e += 1;
  72. factor *= 10;
  73. }
  74. factor /= 1000U;
  75. freq->m = mhz * (1000000U/factor) + hz/factor;
  76. return 0;
  77. }
  78. int zd_channel_to_freq(struct iw_freq *freq, u8 channel)
  79. {
  80. if (channel > NUM_CHANNELS) {
  81. freq->m = 0;
  82. freq->e = 0;
  83. return -EINVAL;
  84. }
  85. if (!channel) {
  86. freq->m = 0;
  87. freq->e = 0;
  88. return -EINVAL;
  89. }
  90. return compute_freq(freq, channel_frequencies[channel-1], 0);
  91. }
  92. static int freq_to_mhz(const struct iw_freq *freq)
  93. {
  94. u32 factor;
  95. int e;
  96. /* Such high frequencies are not supported. */
  97. if (freq->e > 6)
  98. return -EINVAL;
  99. factor = 1;
  100. for (e = freq->e; e > 0; --e) {
  101. factor *= 10;
  102. }
  103. factor = 1000000U / factor;
  104. if (freq->m % factor) {
  105. return -EINVAL;
  106. }
  107. return freq->m / factor;
  108. }
  109. int zd_find_channel(u8 *channel, const struct iw_freq *freq)
  110. {
  111. int i, r;
  112. u32 mhz;
  113. if (!(freq->flags & IW_FREQ_FIXED))
  114. return 0;
  115. if (freq->m < 1000) {
  116. if (freq->m > NUM_CHANNELS || freq->m == 0)
  117. return -EINVAL;
  118. *channel = freq->m;
  119. return 1;
  120. }
  121. r = freq_to_mhz(freq);
  122. if (r < 0)
  123. return r;
  124. mhz = r;
  125. for (i = 0; i < NUM_CHANNELS; i++) {
  126. if (mhz == channel_frequencies[i]) {
  127. *channel = i+1;
  128. return 1;
  129. }
  130. }
  131. return -EINVAL;
  132. }
  133. int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain)
  134. {
  135. struct ieee80211_geo geo;
  136. const struct channel_range *range;
  137. int i;
  138. u8 channel;
  139. dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)),
  140. "regdomain %#04x\n", regdomain);
  141. range = zd_channel_range(regdomain);
  142. if (range->start == 0) {
  143. dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)),
  144. "zd1211 regdomain %#04x not supported\n",
  145. regdomain);
  146. return -EINVAL;
  147. }
  148. memset(&geo, 0, sizeof(geo));
  149. for (i = 0, channel = range->start; channel < range->end; channel++) {
  150. struct ieee80211_channel *chan = &geo.bg[i++];
  151. chan->freq = channel_frequencies[channel - 1];
  152. chan->channel = channel;
  153. }
  154. geo.bg_channels = i;
  155. memcpy(geo.name, "XX ", 4);
  156. ieee80211_set_geo(ieee, &geo);
  157. return 0;
  158. }