162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2010 Broadcom Corporation 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 1162306a36Sopenharmony_ci * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 1362306a36Sopenharmony_ci * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 1462306a36Sopenharmony_ci * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <net/mac80211.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "types.h" 2162306a36Sopenharmony_ci#include "main.h" 2262306a36Sopenharmony_ci#include "phy_shim.h" 2362306a36Sopenharmony_ci#include "antsel.h" 2462306a36Sopenharmony_ci#include "debug.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */ 2762306a36Sopenharmony_ci#define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */ 2862306a36Sopenharmony_ci#define ANT_SELCFG_TX_UNICAST 0 /* unicast tx antenna configuration */ 2962306a36Sopenharmony_ci#define ANT_SELCFG_RX_UNICAST 1 /* unicast rx antenna configuration */ 3062306a36Sopenharmony_ci#define ANT_SELCFG_TX_DEF 2 /* default tx antenna configuration */ 3162306a36Sopenharmony_ci#define ANT_SELCFG_RX_DEF 3 /* default rx antenna configuration */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* useful macros */ 3462306a36Sopenharmony_ci#define BRCMS_ANTSEL_11N_0(ant) ((((ant) & ANT_SELCFG_MASK) >> 4) & 0xf) 3562306a36Sopenharmony_ci#define BRCMS_ANTSEL_11N_1(ant) (((ant) & ANT_SELCFG_MASK) & 0xf) 3662306a36Sopenharmony_ci#define BRCMS_ANTIDX_11N(ant) (((BRCMS_ANTSEL_11N_0(ant)) << 2) +\ 3762306a36Sopenharmony_ci (BRCMS_ANTSEL_11N_1(ant))) 3862306a36Sopenharmony_ci#define BRCMS_ANT_ISAUTO_11N(ant) (((ant) & ANT_SELCFG_AUTO) == ANT_SELCFG_AUTO) 3962306a36Sopenharmony_ci#define BRCMS_ANTSEL_11N(ant) ((ant) & ANT_SELCFG_MASK) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* antenna switch */ 4262306a36Sopenharmony_ci/* defines for no boardlevel antenna diversity */ 4362306a36Sopenharmony_ci#define ANT_SELCFG_DEF_2x2 0x01 /* default antenna configuration */ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 2x3 antdiv defines and tables for GPIO communication */ 4662306a36Sopenharmony_ci#define ANT_SELCFG_NUM_2x3 3 4762306a36Sopenharmony_ci#define ANT_SELCFG_DEF_2x3 0x01 /* default antenna configuration */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* 2x4 antdiv rev4 defines and tables for GPIO communication */ 5062306a36Sopenharmony_ci#define ANT_SELCFG_NUM_2x4 4 5162306a36Sopenharmony_ci#define ANT_SELCFG_DEF_2x4 0x02 /* default antenna configuration */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const u16 mimo_2x4_div_antselpat_tbl[] = { 5462306a36Sopenharmony_ci 0, 0, 0x9, 0xa, /* ant0: 0 ant1: 2,3 */ 5562306a36Sopenharmony_ci 0, 0, 0x5, 0x6, /* ant0: 1 ant1: 2,3 */ 5662306a36Sopenharmony_ci 0, 0, 0, 0, /* n.a. */ 5762306a36Sopenharmony_ci 0, 0, 0, 0 /* n.a. */ 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic const u8 mimo_2x4_div_antselid_tbl[16] = { 6162306a36Sopenharmony_ci 0, 0, 0, 0, 0, 2, 3, 0, 6262306a36Sopenharmony_ci 0, 0, 1, 0, 0, 0, 0, 0 /* pat to antselid */ 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic const u16 mimo_2x3_div_antselpat_tbl[] = { 6662306a36Sopenharmony_ci 16, 0, 1, 16, /* ant0: 0 ant1: 1,2 */ 6762306a36Sopenharmony_ci 16, 16, 16, 16, /* n.a. */ 6862306a36Sopenharmony_ci 16, 2, 16, 16, /* ant0: 2 ant1: 1 */ 6962306a36Sopenharmony_ci 16, 16, 16, 16 /* n.a. */ 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic const u8 mimo_2x3_div_antselid_tbl[16] = { 7362306a36Sopenharmony_ci 0, 1, 2, 0, 0, 0, 0, 0, 7462306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0 /* pat to antselid */ 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* boardlevel antenna selection: init antenna selection structure */ 7862306a36Sopenharmony_cistatic void 7962306a36Sopenharmony_cibrcms_c_antsel_init_cfg(struct antsel_info *asi, struct brcms_antselcfg *antsel, 8062306a36Sopenharmony_ci bool auto_sel) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci if (asi->antsel_type == ANTSEL_2x3) { 8362306a36Sopenharmony_ci u8 antcfg_def = ANT_SELCFG_DEF_2x3 | 8462306a36Sopenharmony_ci ((asi->antsel_avail && auto_sel) ? ANT_SELCFG_AUTO : 0); 8562306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_TX_DEF] = antcfg_def; 8662306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_TX_UNICAST] = antcfg_def; 8762306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_RX_DEF] = antcfg_def; 8862306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_RX_UNICAST] = antcfg_def; 8962306a36Sopenharmony_ci antsel->num_antcfg = ANT_SELCFG_NUM_2x3; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci } else if (asi->antsel_type == ANTSEL_2x4) { 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x4; 9462306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x4; 9562306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x4; 9662306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x4; 9762306a36Sopenharmony_ci antsel->num_antcfg = ANT_SELCFG_NUM_2x4; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci } else { /* no antenna selection available */ 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x2; 10262306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x2; 10362306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x2; 10462306a36Sopenharmony_ci antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x2; 10562306a36Sopenharmony_ci antsel->num_antcfg = 0; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistruct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct antsel_info *asi; 11262306a36Sopenharmony_ci struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC); 11562306a36Sopenharmony_ci if (!asi) 11662306a36Sopenharmony_ci return NULL; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci asi->wlc = wlc; 11962306a36Sopenharmony_ci asi->pub = wlc->pub; 12062306a36Sopenharmony_ci asi->antsel_type = ANTSEL_NA; 12162306a36Sopenharmony_ci asi->antsel_avail = false; 12262306a36Sopenharmony_ci asi->antsel_antswitch = sprom->antswitch; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if ((asi->pub->sromrev >= 4) && (asi->antsel_antswitch != 0)) { 12562306a36Sopenharmony_ci switch (asi->antsel_antswitch) { 12662306a36Sopenharmony_ci case ANTSWITCH_TYPE_1: 12762306a36Sopenharmony_ci case ANTSWITCH_TYPE_2: 12862306a36Sopenharmony_ci case ANTSWITCH_TYPE_3: 12962306a36Sopenharmony_ci /* 4321/2 board with 2x3 switch logic */ 13062306a36Sopenharmony_ci asi->antsel_type = ANTSEL_2x3; 13162306a36Sopenharmony_ci /* Antenna selection availability */ 13262306a36Sopenharmony_ci if ((sprom->ant_available_bg == 7) || 13362306a36Sopenharmony_ci (sprom->ant_available_a == 7)) { 13462306a36Sopenharmony_ci asi->antsel_avail = true; 13562306a36Sopenharmony_ci } else if ( 13662306a36Sopenharmony_ci sprom->ant_available_bg == 3 || 13762306a36Sopenharmony_ci sprom->ant_available_a == 3) { 13862306a36Sopenharmony_ci asi->antsel_avail = false; 13962306a36Sopenharmony_ci } else { 14062306a36Sopenharmony_ci asi->antsel_avail = false; 14162306a36Sopenharmony_ci brcms_err(wlc->hw->d11core, 14262306a36Sopenharmony_ci "antsel_attach: 2o3 " 14362306a36Sopenharmony_ci "board cfg invalid\n"); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci default: 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci } else if ((asi->pub->sromrev == 4) && 15162306a36Sopenharmony_ci (sprom->ant_available_bg == 7) && 15262306a36Sopenharmony_ci (sprom->ant_available_a == 0)) { 15362306a36Sopenharmony_ci /* hack to match old 4321CB2 cards with 2of3 antenna switch */ 15462306a36Sopenharmony_ci asi->antsel_type = ANTSEL_2x3; 15562306a36Sopenharmony_ci asi->antsel_avail = true; 15662306a36Sopenharmony_ci } else if (asi->pub->boardflags2 & BFL2_2X4_DIV) { 15762306a36Sopenharmony_ci asi->antsel_type = ANTSEL_2x4; 15862306a36Sopenharmony_ci asi->antsel_avail = true; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Set the antenna selection type for the low driver */ 16262306a36Sopenharmony_ci brcms_b_antsel_type_set(wlc->hw, asi->antsel_type); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Init (auto/manual) antenna selection */ 16562306a36Sopenharmony_ci brcms_c_antsel_init_cfg(asi, &asi->antcfg_11n, true); 16662306a36Sopenharmony_ci brcms_c_antsel_init_cfg(asi, &asi->antcfg_cur, true); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return asi; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_civoid brcms_c_antsel_detach(struct antsel_info *asi) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci kfree(asi); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* 17762306a36Sopenharmony_ci * boardlevel antenna selection: 17862306a36Sopenharmony_ci * convert ant_cfg to mimo_antsel (ucode interface) 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_cistatic u16 brcms_c_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci u8 idx = BRCMS_ANTIDX_11N(BRCMS_ANTSEL_11N(ant_cfg)); 18362306a36Sopenharmony_ci u16 mimo_antsel = 0; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (asi->antsel_type == ANTSEL_2x4) { 18662306a36Sopenharmony_ci /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */ 18762306a36Sopenharmony_ci mimo_antsel = (mimo_2x4_div_antselpat_tbl[idx] & 0xf); 18862306a36Sopenharmony_ci return mimo_antsel; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci } else if (asi->antsel_type == ANTSEL_2x3) { 19162306a36Sopenharmony_ci /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */ 19262306a36Sopenharmony_ci mimo_antsel = (mimo_2x3_div_antselpat_tbl[idx] & 0xf); 19362306a36Sopenharmony_ci return mimo_antsel; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return mimo_antsel; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* boardlevel antenna selection: ucode interface control */ 20062306a36Sopenharmony_cistatic int brcms_c_antsel_cfgupd(struct antsel_info *asi, 20162306a36Sopenharmony_ci struct brcms_antselcfg *antsel) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct brcms_c_info *wlc = asi->wlc; 20462306a36Sopenharmony_ci u8 ant_cfg; 20562306a36Sopenharmony_ci u16 mimo_antsel; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* 1) Update TX antconfig for all frames that are not unicast data 20862306a36Sopenharmony_ci * (aka default TX) 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_ci ant_cfg = antsel->ant_config[ANT_SELCFG_TX_DEF]; 21162306a36Sopenharmony_ci mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg); 21262306a36Sopenharmony_ci brcms_b_write_shm(wlc->hw, M_MIMO_ANTSEL_TXDFLT, mimo_antsel); 21362306a36Sopenharmony_ci /* 21462306a36Sopenharmony_ci * Update driver stats for currently selected 21562306a36Sopenharmony_ci * default tx/rx antenna config 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci asi->antcfg_cur.ant_config[ANT_SELCFG_TX_DEF] = ant_cfg; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* 2) Update RX antconfig for all frames that are not unicast data 22062306a36Sopenharmony_ci * (aka default RX) 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci ant_cfg = antsel->ant_config[ANT_SELCFG_RX_DEF]; 22362306a36Sopenharmony_ci mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg); 22462306a36Sopenharmony_ci brcms_b_write_shm(wlc->hw, M_MIMO_ANTSEL_RXDFLT, mimo_antsel); 22562306a36Sopenharmony_ci /* 22662306a36Sopenharmony_ci * Update driver stats for currently selected 22762306a36Sopenharmony_ci * default tx/rx antenna config 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_ci asi->antcfg_cur.ant_config[ANT_SELCFG_RX_DEF] = ant_cfg; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_civoid brcms_c_antsel_init(struct antsel_info *asi) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci if ((asi->antsel_type == ANTSEL_2x3) || 23762306a36Sopenharmony_ci (asi->antsel_type == ANTSEL_2x4)) 23862306a36Sopenharmony_ci brcms_c_antsel_cfgupd(asi, &asi->antcfg_11n); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* boardlevel antenna selection: convert id to ant_cfg */ 24262306a36Sopenharmony_cistatic u8 brcms_c_antsel_id2antcfg(struct antsel_info *asi, u8 id) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci u8 antcfg = ANT_SELCFG_DEF_2x2; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (asi->antsel_type == ANTSEL_2x4) { 24762306a36Sopenharmony_ci /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */ 24862306a36Sopenharmony_ci antcfg = (((id & 0x2) << 3) | ((id & 0x1) + 2)); 24962306a36Sopenharmony_ci return antcfg; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci } else if (asi->antsel_type == ANTSEL_2x3) { 25262306a36Sopenharmony_ci /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */ 25362306a36Sopenharmony_ci antcfg = (((id & 0x02) << 4) | ((id & 0x1) + 1)); 25462306a36Sopenharmony_ci return antcfg; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return antcfg; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_civoid 26162306a36Sopenharmony_cibrcms_c_antsel_antcfg_get(struct antsel_info *asi, bool usedef, bool sel, 26262306a36Sopenharmony_ci u8 antselid, u8 fbantselid, u8 *antcfg, 26362306a36Sopenharmony_ci u8 *fbantcfg) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci u8 ant; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* if use default, assign it and return */ 26862306a36Sopenharmony_ci if (usedef) { 26962306a36Sopenharmony_ci *antcfg = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_DEF]; 27062306a36Sopenharmony_ci *fbantcfg = *antcfg; 27162306a36Sopenharmony_ci return; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (!sel) { 27562306a36Sopenharmony_ci *antcfg = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST]; 27662306a36Sopenharmony_ci *fbantcfg = *antcfg; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci } else { 27962306a36Sopenharmony_ci ant = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST]; 28062306a36Sopenharmony_ci if ((ant & ANT_SELCFG_AUTO) == ANT_SELCFG_AUTO) { 28162306a36Sopenharmony_ci *antcfg = brcms_c_antsel_id2antcfg(asi, antselid); 28262306a36Sopenharmony_ci *fbantcfg = brcms_c_antsel_id2antcfg(asi, fbantselid); 28362306a36Sopenharmony_ci } else { 28462306a36Sopenharmony_ci *antcfg = 28562306a36Sopenharmony_ci asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST]; 28662306a36Sopenharmony_ci *fbantcfg = *antcfg; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci return; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* boardlevel antenna selection: convert mimo_antsel (ucode interface) to id */ 29362306a36Sopenharmony_ciu8 brcms_c_antsel_antsel2id(struct antsel_info *asi, u16 antsel) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci u8 antselid = 0; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (asi->antsel_type == ANTSEL_2x4) { 29862306a36Sopenharmony_ci /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */ 29962306a36Sopenharmony_ci antselid = mimo_2x4_div_antselid_tbl[(antsel & 0xf)]; 30062306a36Sopenharmony_ci return antselid; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci } else if (asi->antsel_type == ANTSEL_2x3) { 30362306a36Sopenharmony_ci /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */ 30462306a36Sopenharmony_ci antselid = mimo_2x3_div_antselid_tbl[(antsel & 0xf)]; 30562306a36Sopenharmony_ci return antselid; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return antselid; 30962306a36Sopenharmony_ci} 310