1 /* 2 * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: reg_opclass.c 21 * This file defines regulatory opclass functions. 22 */ 23 24 #include <qdf_types.h> 25 #include <wlan_cmn.h> 26 #include <reg_services_public_struct.h> 27 #include <wlan_objmgr_psoc_obj.h> 28 #include "reg_priv_objs.h" 29 #include "reg_utils.h" 30 #include "reg_db.h" 31 #include "reg_db_parser.h" 32 #include "reg_host_11d.h" 33 #include <scheduler_api.h> 34 #include "reg_build_chan_list.h" 35 #include "reg_opclass.h" 36 37 #ifdef HOST_OPCLASS 38 static struct reg_dmn_supp_op_classes reg_dmn_curr_supp_opp_classes = { 0 }; 39 #endif 40 41 static const struct reg_dmn_op_class_map_t global_op_class[] = { 42 {81, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} }, 43 {82, 25, BW20, {14} }, 44 {83, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7, 8, 9} }, 45 {84, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11, 12, 13} }, 46 {115, 20, BW20, {36, 40, 44, 48} }, 47 {116, 40, BW40_LOW_PRIMARY, {36, 44} }, 48 {117, 40, BW40_HIGH_PRIMARY, {40, 48} }, 49 {118, 20, BW20, {52, 56, 60, 64} }, 50 {119, 40, BW40_LOW_PRIMARY, {52, 60} }, 51 {120, 40, BW40_HIGH_PRIMARY, {56, 64} }, 52 {121, 20, BW20, 53 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} }, 54 {122, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} }, 55 {123, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} }, 56 {125, 20, BW20, {149, 153, 157, 161, 165, 169} }, 57 {126, 40, BW40_LOW_PRIMARY, {149, 157} }, 58 {127, 40, BW40_HIGH_PRIMARY, {153, 161} }, 59 {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 60 112, 116, 120, 124, 128, 132, 136, 140, 144, 61 149, 153, 157, 161} }, 62 {0, 0, 0, {0} }, 63 }; 64 65 static const struct reg_dmn_op_class_map_t us_op_class[] = { 66 {1, 20, BW20, {36, 40, 44, 48} }, 67 {2, 20, BW20, {52, 56, 60, 64} }, 68 {4, 20, BW20, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 69 144} }, 70 {5, 20, BW20, {149, 153, 157, 161, 165} }, 71 {12, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} }, 72 {22, 40, BW40_LOW_PRIMARY, {36, 44} }, 73 {23, 40, BW40_LOW_PRIMARY, {52, 60} }, 74 {24, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} }, 75 {26, 40, BW40_LOW_PRIMARY, {149, 157} }, 76 {27, 40, BW40_HIGH_PRIMARY, {40, 48} }, 77 {28, 40, BW40_HIGH_PRIMARY, {56, 64} }, 78 {29, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} }, 79 {30, 40, BW40_HIGH_PRIMARY, {153, 161} }, 80 {31, 40, BW40_HIGH_PRIMARY, {153, 161} }, 81 {32, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7} }, 82 {33, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11} }, 83 {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 84 112, 116, 120, 124, 128, 132, 136, 140, 144, 85 149, 153, 157, 161} }, 86 {0, 0, 0, {0} }, 87 }; 88 89 static const struct reg_dmn_op_class_map_t euro_op_class[] = { 90 {1, 20, BW20, {36, 40, 44, 48} }, 91 {2, 20, BW20, {52, 56, 60, 64} }, 92 {3, 20, BW20, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} }, 93 {4, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} }, 94 {5, 40, BW40_LOW_PRIMARY, {36, 44} }, 95 {6, 40, BW40_LOW_PRIMARY, {52, 60} }, 96 {7, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} }, 97 {8, 40, BW40_HIGH_PRIMARY, {40, 48} }, 98 {9, 40, BW40_HIGH_PRIMARY, {56, 64} }, 99 {10, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} }, 100 {11, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7, 8, 9} }, 101 {12, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11, 12, 13} }, 102 {17, 20, BW20, {149, 153, 157, 161, 165, 169} }, 103 {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 104 116, 120, 124, 128} }, 105 {0, 0, 0, {0} }, 106 }; 107 108 static const struct reg_dmn_op_class_map_t japan_op_class[] = { 109 {1, 20, BW20, {36, 40, 44, 48} }, 110 {30, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} }, 111 {31, 25, BW20, {14} }, 112 {32, 20, BW20, {52, 56, 60, 64} }, 113 {34, 20, BW20, 114 {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} }, 115 {36, 40, BW40_LOW_PRIMARY, {36, 44} }, 116 {37, 40, BW40_LOW_PRIMARY, {52, 60} }, 117 {39, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} }, 118 {41, 40, BW40_HIGH_PRIMARY, {40, 48} }, 119 {42, 40, BW40_HIGH_PRIMARY, {56, 64} }, 120 {44, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} }, 121 {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 122 116, 120, 124, 128} }, 123 {0, 0, 0, {0} }, 124 }; 125 126 #ifdef HOST_OPCLASS 127 /** 128 * reg_get_class_from_country()- Get Class from country 129 * @country- Country 130 * 131 * Return: class. 132 */ 133 static 134 const struct reg_dmn_op_class_map_t *reg_get_class_from_country(uint8_t 135 *country) 136 { 137 const struct reg_dmn_op_class_map_t *class = NULL; 138 139 qdf_debug("Country %c%c 0x%x", 140 country[0], country[1], country[2]); 141 142 switch (country[2]) { 143 case OP_CLASS_US: 144 class = us_op_class; 145 break; 146 147 case OP_CLASS_EU: 148 class = euro_op_class; 149 break; 150 151 case OP_CLASS_JAPAN: 152 class = japan_op_class; 153 break; 154 155 case OP_CLASS_GLOBAL: 156 class = global_op_class; 157 break; 158 159 default: 160 if (!qdf_mem_cmp(country, "US", 2)) 161 class = us_op_class; 162 else if (!qdf_mem_cmp(country, "EU", 2)) 163 class = euro_op_class; 164 else if (!qdf_mem_cmp(country, "JP", 2)) 165 class = japan_op_class; 166 else 167 class = global_op_class; 168 } 169 return class; 170 } 171 172 uint16_t reg_dmn_get_chanwidth_from_opclass(uint8_t *country, uint8_t channel, 173 uint8_t opclass) 174 { 175 const struct reg_dmn_op_class_map_t *class; 176 uint16_t i; 177 178 class = reg_get_class_from_country(country); 179 180 while (class->op_class) { 181 if (opclass == class->op_class) { 182 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 183 class->channels[i]); i++) { 184 if (channel == class->channels[i]) 185 return class->ch_spacing; 186 } 187 } 188 class++; 189 } 190 191 return 0; 192 } 193 194 uint16_t reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel, 195 uint8_t offset) 196 { 197 const struct reg_dmn_op_class_map_t *class = NULL; 198 uint16_t i = 0; 199 200 class = reg_get_class_from_country(country); 201 while (class && class->op_class) { 202 if ((offset == class->offset) || (offset == BWALL)) { 203 for (i = 0; (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 204 class->channels[i]); i++) { 205 if (channel == class->channels[i]) 206 return class->op_class; 207 } 208 } 209 class++; 210 } 211 212 return 0; 213 } 214 215 void reg_dmn_print_channels_in_opclass(uint8_t *country, uint8_t op_class) 216 { 217 const struct reg_dmn_op_class_map_t *class = NULL; 218 uint16_t i = 0; 219 220 class = reg_get_class_from_country(country); 221 222 if (!class) { 223 reg_err("class is NULL"); 224 return; 225 } 226 227 while (class->op_class) { 228 if (class->op_class == op_class) { 229 for (i = 0; 230 (i < REG_MAX_CHANNELS_PER_OPERATING_CLASS && 231 class->channels[i]); i++) { 232 reg_debug("Valid channel(%d) in requested RC(%d)", 233 class->channels[i], op_class); 234 } 235 break; 236 } 237 class++; 238 } 239 if (!class->op_class) 240 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 241 "Invalid requested RC (%d)", op_class); 242 } 243 244 uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class) 245 { 246 uint8_t i; 247 248 if (num_classes > REG_MAX_SUPP_OPER_CLASSES) { 249 reg_err("invalid num classes %d", num_classes); 250 return 0; 251 } 252 253 for (i = 0; i < num_classes; i++) 254 reg_dmn_curr_supp_opp_classes.classes[i] = class[i]; 255 256 reg_dmn_curr_supp_opp_classes.num_classes = num_classes; 257 258 return 0; 259 } 260 261 uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class) 262 { 263 uint8_t i; 264 265 if (!num_classes || !class) { 266 reg_err("either num_classes or class is null"); 267 return 0; 268 } 269 270 for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++) 271 class[i] = reg_dmn_curr_supp_opp_classes.classes[i]; 272 273 *num_classes = reg_dmn_curr_supp_opp_classes.num_classes; 274 275 return 0; 276 } 277 #endif 278