zd_ieee80211.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. /* Japan originally only had channel 14 available (see CHNL_ID 0x40 in
  37. * 802.11). However, in 2001 the range was extended to include channels
  38. * 1-13. The ZyDAS devices still use the old region code but are
  39. * designed to allow the extra channel access in Japan. */
  40. [ZD_REGDOMAIN_JAPAN_ADD] = { 1, 15},
  41. };
  42. const struct channel_range *zd_channel_range(u8 regdomain)
  43. {
  44. if (regdomain >= ARRAY_SIZE(channel_ranges))
  45. regdomain = 0;
  46. return &channel_ranges[regdomain];
  47. }
  48. int zd_regdomain_supports_channel(u8 regdomain, u8 channel)
  49. {
  50. const struct channel_range *range = zd_channel_range(regdomain);
  51. return range->start <= channel && channel < range->end;
  52. }
  53. int zd_regdomain_supported(u8 regdomain)
  54. {
  55. const struct channel_range *range = zd_channel_range(regdomain);
  56. return range->start != 0;
  57. }
  58. /* Stores channel frequencies in MHz. */
  59. static const u16 channel_frequencies[] = {
  60. 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
  61. 2452, 2457, 2462, 2467, 2472, 2484,
  62. };
  63. #define NUM_CHANNELS ARRAY_SIZE(channel_frequencies)
  64. static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz)
  65. {
  66. u32 factor;
  67. freq->e = 0;
  68. if (mhz >= 1000000000U) {
  69. pr_debug("zd1211 mhz %u to large\n", mhz);
  70. freq->m = 0;
  71. return -EINVAL;
  72. }
  73. factor = 1000;
  74. while (mhz >= factor) {
  75. freq->e += 1;
  76. factor *= 10;
  77. }
  78. factor /= 1000U;
  79. freq->m = mhz * (1000000U/factor) + hz/factor;
  80. return 0;
  81. }
  82. int zd_channel_to_freq(struct iw_freq *freq, u8 channel)
  83. {
  84. if (channel > NUM_CHANNELS) {
  85. freq->m = 0;
  86. freq->e = 0;
  87. return -EINVAL;
  88. }
  89. if (!channel) {
  90. freq->m = 0;
  91. freq->e = 0;
  92. return -EINVAL;
  93. }
  94. return compute_freq(freq, channel_frequencies[channel-1], 0);
  95. }
  96. static int freq_to_mhz(const struct iw_freq *freq)
  97. {
  98. u32 factor;
  99. int e;
  100. /* Such high frequencies are not supported. */
  101. if (freq->e > 6)
  102. return -EINVAL;
  103. factor = 1;
  104. for (e = freq->e; e > 0; --e) {
  105. factor *= 10;
  106. }
  107. factor = 1000000U / factor;
  108. if (freq->m % factor) {
  109. return -EINVAL;
  110. }
  111. return freq->m / factor;
  112. }
  113. int zd_find_channel(u8 *channel, const struct iw_freq *freq)
  114. {
  115. int i, r;
  116. u32 mhz;
  117. if (freq->m < 1000) {
  118. if (freq->m > NUM_CHANNELS || freq->m == 0)
  119. return -EINVAL;
  120. *channel = freq->m;
  121. return 1;
  122. }
  123. r = freq_to_mhz(freq);
  124. if (r < 0)
  125. return r;
  126. mhz = r;
  127. for (i = 0; i < NUM_CHANNELS; i++) {
  128. if (mhz == channel_frequencies[i]) {
  129. *channel = i+1;
  130. return 1;
  131. }
  132. }
  133. return -EINVAL;
  134. }
  135. int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain)
  136. {
  137. struct ieee80211_geo geo;
  138. const struct channel_range *range;
  139. int i;
  140. u8 channel;
  141. dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)),
  142. "regdomain %#04x\n", regdomain);
  143. range = zd_channel_range(regdomain);
  144. if (range->start == 0) {
  145. dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)),
  146. "zd1211 regdomain %#04x not supported\n",
  147. regdomain);
  148. return -EINVAL;
  149. }
  150. memset(&geo, 0, sizeof(geo));
  151. for (i = 0, channel = range->start; channel < range->end; channel++) {
  152. struct ieee80211_channel *chan = &geo.bg[i++];
  153. chan->freq = channel_frequencies[channel - 1];
  154. chan->channel = channel;
  155. }
  156. geo.bg_channels = i;
  157. memcpy(geo.name, "XX ", 4);
  158. ieee80211_set_geo(ieee, &geo);
  159. return 0;
  160. }