diff options
author | Juuso Oikarinen <juuso.oikarinen@nokia.com> | 2010-04-01 04:38:20 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-04-06 16:55:12 -0400 |
commit | ebba60c66b3aa321a84c9a90a343c91fde972066 (patch) | |
tree | 49bf6e52a558b530a864c453a695bf0d4800dbed /drivers/net/wireless/wl12xx | |
parent | 40b359c61dc496508b77d1242726e40238e62128 (diff) |
wl1271: Use minimum rate for each band for control messages
Currently the mac80211 is not telling a hardware rate controlled driver a
rate to use for association frames etc. So to be safe, use the lowest rate
of each band for communication.
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_acx.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_cmd.c | 27 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_conf.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 98 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.h | 1 |
7 files changed, 108 insertions, 36 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index c5559efcf5a7..a29969efc861 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h | |||
@@ -447,6 +447,7 @@ struct wl1271 { | |||
447 | /* currently configured rate set */ | 447 | /* currently configured rate set */ |
448 | u32 sta_rate_set; | 448 | u32 sta_rate_set; |
449 | u32 basic_rate_set; | 449 | u32 basic_rate_set; |
450 | u32 basic_rate; | ||
450 | u32 rate_set; | 451 | u32 rate_set; |
451 | 452 | ||
452 | /* The current band */ | 453 | /* The current band */ |
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 8f0bd5bee6f9..621c94691e7e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c | |||
@@ -802,7 +802,7 @@ int wl1271_acx_rate_policies(struct wl1271 *wl) | |||
802 | 802 | ||
803 | /* configure one basic rate class */ | 803 | /* configure one basic rate class */ |
804 | idx = ACX_TX_BASIC_RATE; | 804 | idx = ACX_TX_BASIC_RATE; |
805 | acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate_set); | 805 | acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate); |
806 | acx->rate_class[idx].short_retry_limit = c->short_retry_limit; | 806 | acx->rate_class[idx].short_retry_limit = c->short_retry_limit; |
807 | acx->rate_class[idx].long_retry_limit = c->long_retry_limit; | 807 | acx->rate_class[idx].long_retry_limit = c->long_retry_limit; |
808 | acx->rate_class[idx].aflags = c->aflags; | 808 | acx->rate_class[idx].aflags = c->aflags; |
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index f11f9f47ffd5..5cee59fb8c5e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c | |||
@@ -317,18 +317,10 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) | |||
317 | join->rx_config_options = cpu_to_le32(wl->rx_config); | 317 | join->rx_config_options = cpu_to_le32(wl->rx_config); |
318 | join->rx_filter_options = cpu_to_le32(wl->rx_filter); | 318 | join->rx_filter_options = cpu_to_le32(wl->rx_filter); |
319 | join->bss_type = bss_type; | 319 | join->bss_type = bss_type; |
320 | join->basic_rate_set = wl->basic_rate_set; | ||
320 | 321 | ||
321 | if (wl->band == IEEE80211_BAND_2GHZ) | 322 | if (wl->band == IEEE80211_BAND_5GHZ) |
322 | join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS | | ||
323 | CONF_HW_BIT_RATE_2MBPS | | ||
324 | CONF_HW_BIT_RATE_5_5MBPS | | ||
325 | CONF_HW_BIT_RATE_11MBPS); | ||
326 | else { | ||
327 | join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; | 323 | join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; |
328 | join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_6MBPS | | ||
329 | CONF_HW_BIT_RATE_12MBPS | | ||
330 | CONF_HW_BIT_RATE_24MBPS); | ||
331 | } | ||
332 | 324 | ||
333 | join->beacon_interval = cpu_to_le16(wl->beacon_int); | 325 | join->beacon_interval = cpu_to_le16(wl->beacon_int); |
334 | join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; | 326 | join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; |
@@ -581,17 +573,21 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, | |||
581 | struct wl1271_cmd_trigger_scan_to *trigger = NULL; | 573 | struct wl1271_cmd_trigger_scan_to *trigger = NULL; |
582 | struct wl1271_cmd_scan *params = NULL; | 574 | struct wl1271_cmd_scan *params = NULL; |
583 | struct ieee80211_channel *channels; | 575 | struct ieee80211_channel *channels; |
576 | u32 rate; | ||
584 | int i, j, n_ch, ret; | 577 | int i, j, n_ch, ret; |
585 | u16 scan_options = 0; | 578 | u16 scan_options = 0; |
586 | u8 ieee_band; | 579 | u8 ieee_band; |
587 | 580 | ||
588 | if (band == WL1271_SCAN_BAND_2_4_GHZ) | 581 | if (band == WL1271_SCAN_BAND_2_4_GHZ) { |
589 | ieee_band = IEEE80211_BAND_2GHZ; | 582 | ieee_band = IEEE80211_BAND_2GHZ; |
590 | else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) | 583 | rate = wl->conf.tx.basic_rate; |
584 | } else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) { | ||
591 | ieee_band = IEEE80211_BAND_2GHZ; | 585 | ieee_band = IEEE80211_BAND_2GHZ; |
592 | else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) | 586 | rate = wl->conf.tx.basic_rate; |
587 | } else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) { | ||
593 | ieee_band = IEEE80211_BAND_5GHZ; | 588 | ieee_band = IEEE80211_BAND_5GHZ; |
594 | else | 589 | rate = wl->conf.tx.basic_rate_5; |
590 | } else | ||
595 | return -EINVAL; | 591 | return -EINVAL; |
596 | 592 | ||
597 | if (wl->hw->wiphy->bands[ieee_band]->channels == NULL) | 593 | if (wl->hw->wiphy->bands[ieee_band]->channels == NULL) |
@@ -618,8 +614,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, | |||
618 | params->params.scan_options = cpu_to_le16(scan_options); | 614 | params->params.scan_options = cpu_to_le16(scan_options); |
619 | 615 | ||
620 | params->params.num_probe_requests = probe_requests; | 616 | params->params.num_probe_requests = probe_requests; |
621 | /* Let the fw autodetect suitable tx_rate for probes */ | 617 | params->params.tx_rate = rate; |
622 | params->params.tx_rate = 0; | ||
623 | params->params.tid_trigger = 0; | 618 | params->params.tid_trigger = 0; |
624 | params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; | 619 | params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; |
625 | 620 | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 82b5dabb6e8d..0b34b6261176 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h | |||
@@ -674,6 +674,19 @@ struct conf_tx_settings { | |||
674 | */ | 674 | */ |
675 | u16 tx_compl_threshold; | 675 | u16 tx_compl_threshold; |
676 | 676 | ||
677 | /* | ||
678 | * The rate used for control messages and scanning on the 2.4GHz band | ||
679 | * | ||
680 | * Range: CONF_HW_BIT_RATE_* bit mask | ||
681 | */ | ||
682 | u32 basic_rate; | ||
683 | |||
684 | /* | ||
685 | * The rate used for control messages and scanning on the 5GHz band | ||
686 | * | ||
687 | * Range: CONF_HW_BIT_RATE_* bit mask | ||
688 | */ | ||
689 | u32 basic_rate_5; | ||
677 | }; | 690 | }; |
678 | 691 | ||
679 | enum { | 692 | enum { |
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 2494c967bb34..ca5cd325fac7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -116,8 +116,7 @@ static struct conf_drv_settings default_conf = { | |||
116 | .tx = { | 116 | .tx = { |
117 | .tx_energy_detection = 0, | 117 | .tx_energy_detection = 0, |
118 | .rc_conf = { | 118 | .rc_conf = { |
119 | .enabled_rates = CONF_HW_BIT_RATE_1MBPS | | 119 | .enabled_rates = 0, |
120 | CONF_HW_BIT_RATE_2MBPS, | ||
121 | .short_retry_limit = 10, | 120 | .short_retry_limit = 10, |
122 | .long_retry_limit = 10, | 121 | .long_retry_limit = 10, |
123 | .aflags = 0 | 122 | .aflags = 0 |
@@ -214,7 +213,9 @@ static struct conf_drv_settings default_conf = { | |||
214 | }, | 213 | }, |
215 | .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, | 214 | .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, |
216 | .tx_compl_timeout = 700, | 215 | .tx_compl_timeout = 700, |
217 | .tx_compl_threshold = 4 | 216 | .tx_compl_threshold = 4, |
217 | .basic_rate = CONF_HW_BIT_RATE_1MBPS, | ||
218 | .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS, | ||
218 | }, | 219 | }, |
219 | .conn = { | 220 | .conn = { |
220 | .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, | 221 | .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, |
@@ -1171,6 +1172,32 @@ out: | |||
1171 | return ret; | 1172 | return ret; |
1172 | } | 1173 | } |
1173 | 1174 | ||
1175 | static void wl1271_set_band_rate(struct wl1271 *wl) | ||
1176 | { | ||
1177 | if (wl->band == IEEE80211_BAND_2GHZ) | ||
1178 | wl->basic_rate_set = wl->conf.tx.basic_rate; | ||
1179 | else | ||
1180 | wl->basic_rate_set = wl->conf.tx.basic_rate_5; | ||
1181 | } | ||
1182 | |||
1183 | static u32 wl1271_min_rate_get(struct wl1271 *wl) | ||
1184 | { | ||
1185 | int i; | ||
1186 | u32 rate = 0; | ||
1187 | |||
1188 | if (!wl->basic_rate_set) { | ||
1189 | WARN_ON(1); | ||
1190 | wl->basic_rate_set = wl->conf.tx.basic_rate; | ||
1191 | } | ||
1192 | |||
1193 | for (i = 0; !rate; i++) { | ||
1194 | if ((wl->basic_rate_set >> i) & 0x1) | ||
1195 | rate = 1 << i; | ||
1196 | } | ||
1197 | |||
1198 | return rate; | ||
1199 | } | ||
1200 | |||
1174 | static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | 1201 | static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) |
1175 | { | 1202 | { |
1176 | struct wl1271 *wl = hw->priv; | 1203 | struct wl1271 *wl = hw->priv; |
@@ -1187,12 +1214,38 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | |||
1187 | 1214 | ||
1188 | mutex_lock(&wl->mutex); | 1215 | mutex_lock(&wl->mutex); |
1189 | 1216 | ||
1190 | wl->band = conf->channel->band; | ||
1191 | |||
1192 | ret = wl1271_ps_elp_wakeup(wl, false); | 1217 | ret = wl1271_ps_elp_wakeup(wl, false); |
1193 | if (ret < 0) | 1218 | if (ret < 0) |
1194 | goto out; | 1219 | goto out; |
1195 | 1220 | ||
1221 | /* if the channel changes while joined, join again */ | ||
1222 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | ||
1223 | wl->band = conf->channel->band; | ||
1224 | wl->channel = channel; | ||
1225 | |||
1226 | /* | ||
1227 | * FIXME: the mac80211 should really provide a fixed rate | ||
1228 | * to use here. for now, just use the smallest possible rate | ||
1229 | * for the band as a fixed rate for association frames and | ||
1230 | * other control messages. | ||
1231 | */ | ||
1232 | if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) | ||
1233 | wl1271_set_band_rate(wl); | ||
1234 | |||
1235 | wl->basic_rate = wl1271_min_rate_get(wl); | ||
1236 | ret = wl1271_acx_rate_policies(wl); | ||
1237 | if (ret < 0) | ||
1238 | wl1271_warning("rate policy for update channel " | ||
1239 | "failed %d", ret); | ||
1240 | |||
1241 | if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { | ||
1242 | ret = wl1271_cmd_join(wl, wl->set_bss_type); | ||
1243 | if (ret < 0) | ||
1244 | wl1271_warning("cmd join to update channel " | ||
1245 | "failed %d", ret); | ||
1246 | } | ||
1247 | } | ||
1248 | |||
1196 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { | 1249 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { |
1197 | if (conf->flags & IEEE80211_CONF_IDLE && | 1250 | if (conf->flags & IEEE80211_CONF_IDLE && |
1198 | test_bit(WL1271_FLAG_JOINED, &wl->flags)) | 1251 | test_bit(WL1271_FLAG_JOINED, &wl->flags)) |
@@ -1201,7 +1254,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | |||
1201 | wl1271_join_channel(wl, channel); | 1254 | wl1271_join_channel(wl, channel); |
1202 | 1255 | ||
1203 | if (conf->flags & IEEE80211_CONF_IDLE) { | 1256 | if (conf->flags & IEEE80211_CONF_IDLE) { |
1204 | wl->rate_set = CONF_TX_RATE_MASK_BASIC; | 1257 | wl->rate_set = wl1271_min_rate_get(wl); |
1205 | wl->sta_rate_set = 0; | 1258 | wl->sta_rate_set = 0; |
1206 | wl1271_acx_rate_policies(wl); | 1259 | wl1271_acx_rate_policies(wl); |
1207 | wl1271_acx_keep_alive_config( | 1260 | wl1271_acx_keep_alive_config( |
@@ -1210,18 +1263,6 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | |||
1210 | } | 1263 | } |
1211 | } | 1264 | } |
1212 | 1265 | ||
1213 | /* if the channel changes while joined, join again */ | ||
1214 | if (channel != wl->channel && | ||
1215 | test_bit(WL1271_FLAG_JOINED, &wl->flags)) { | ||
1216 | wl->channel = channel; | ||
1217 | /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */ | ||
1218 | ret = wl1271_cmd_join(wl, wl->set_bss_type); | ||
1219 | if (ret < 0) | ||
1220 | wl1271_warning("cmd join to update channel failed %d", | ||
1221 | ret); | ||
1222 | } else | ||
1223 | wl->channel = channel; | ||
1224 | |||
1225 | if (conf->flags & IEEE80211_CONF_PS && | 1266 | if (conf->flags & IEEE80211_CONF_PS && |
1226 | !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { | 1267 | !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { |
1227 | set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); | 1268 | set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); |
@@ -1659,10 +1700,23 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1659 | 1700 | ||
1660 | if (changed & BSS_CHANGED_ASSOC) { | 1701 | if (changed & BSS_CHANGED_ASSOC) { |
1661 | if (bss_conf->assoc) { | 1702 | if (bss_conf->assoc) { |
1703 | u32 rates; | ||
1662 | wl->aid = bss_conf->aid; | 1704 | wl->aid = bss_conf->aid; |
1663 | set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); | 1705 | set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); |
1664 | 1706 | ||
1665 | /* | 1707 | /* |
1708 | * use basic rates from AP, and determine lowest rate | ||
1709 | * to use with control frames. | ||
1710 | */ | ||
1711 | rates = bss_conf->basic_rates; | ||
1712 | wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, | ||
1713 | rates); | ||
1714 | wl->basic_rate = wl1271_min_rate_get(wl); | ||
1715 | ret = wl1271_acx_rate_policies(wl); | ||
1716 | if (ret < 0) | ||
1717 | goto out_sleep; | ||
1718 | |||
1719 | /* | ||
1666 | * with wl1271, we don't need to update the | 1720 | * with wl1271, we don't need to update the |
1667 | * beacon_int and dtim_period, because the firmware | 1721 | * beacon_int and dtim_period, because the firmware |
1668 | * updates it by itself when the first beacon is | 1722 | * updates it by itself when the first beacon is |
@@ -1712,6 +1766,13 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1712 | clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); | 1766 | clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); |
1713 | wl->aid = 0; | 1767 | wl->aid = 0; |
1714 | 1768 | ||
1769 | /* revert back to minimum rates for the current band */ | ||
1770 | wl1271_set_band_rate(wl); | ||
1771 | wl->basic_rate = wl1271_min_rate_get(wl); | ||
1772 | ret = wl1271_acx_rate_policies(wl); | ||
1773 | if (ret < 0) | ||
1774 | goto out_sleep; | ||
1775 | |||
1715 | /* disable connection monitor features */ | 1776 | /* disable connection monitor features */ |
1716 | ret = wl1271_acx_conn_monit_params(wl, false); | 1777 | ret = wl1271_acx_conn_monit_params(wl, false); |
1717 | 1778 | ||
@@ -2261,6 +2322,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
2261 | wl->psm_entry_retry = 0; | 2322 | wl->psm_entry_retry = 0; |
2262 | wl->power_level = WL1271_DEFAULT_POWER_LEVEL; | 2323 | wl->power_level = WL1271_DEFAULT_POWER_LEVEL; |
2263 | wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; | 2324 | wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; |
2325 | wl->basic_rate = CONF_TX_RATE_MASK_BASIC; | ||
2264 | wl->rate_set = CONF_TX_RATE_MASK_BASIC; | 2326 | wl->rate_set = CONF_TX_RATE_MASK_BASIC; |
2265 | wl->sta_rate_set = 0; | 2327 | wl->sta_rate_set = 0; |
2266 | wl->band = IEEE80211_BAND_2GHZ; | 2328 | wl->band = IEEE80211_BAND_2GHZ; |
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 66b48b70444e..0b8cdb4e22b6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c | |||
@@ -220,7 +220,7 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) | |||
220 | return ret; | 220 | return ret; |
221 | } | 221 | } |
222 | 222 | ||
223 | static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) | 223 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) |
224 | { | 224 | { |
225 | struct ieee80211_supported_band *band; | 225 | struct ieee80211_supported_band *band; |
226 | u32 enabled_rates = 0; | 226 | u32 enabled_rates = 0; |
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h index b03c95d9673f..3b8b7ac253fd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.h +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h | |||
@@ -160,5 +160,6 @@ void wl1271_tx_work(struct work_struct *work); | |||
160 | void wl1271_tx_complete(struct wl1271 *wl); | 160 | void wl1271_tx_complete(struct wl1271 *wl); |
161 | void wl1271_tx_flush(struct wl1271 *wl); | 161 | void wl1271_tx_flush(struct wl1271 *wl); |
162 | u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); | 162 | u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); |
163 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); | ||
163 | 164 | ||
164 | #endif | 165 | #endif |