static void setup_ht_cap(struct ath_softc *sc, struct ieee80211_sta_ht_cap *ht_info) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); u8 tx_streams, rx_streams; int i, max_streams; ht_info->ht_supported = true; ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_SM_PS | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_DSSSCCK40; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; if (AR_SREV_9300_20_OR_LATER(ah)) max_streams = 3; else max_streams = 2; if (AR_SREV_9280_10_OR_LATER(ah)) { if (max_streams >= 2) ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); } /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); tx_streams = count_streams(common->tx_chainmask, max_streams); rx_streams = count_streams(common->rx_chainmask, max_streams); ath_print(common, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", tx_streams, rx_streams); if (tx_streams != rx_streams) { ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; ht_info->mcs.tx_params |= ((tx_streams - 1) << IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); } for (i = 0; i < rx_streams; i++) ht_info->mcs.rx_mask[i] = 0xff; ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; }
void nut_framecode_generate(const nut_stream_header_tt s[], nut_frame_table_input_tt fti[256]) { int stream_count = count_streams(s); int i, n = 0, m = 0, tot_con = 0; enum { e_consume_none = 0, e_consume_mpeg4, e_consume_h264, e_consume_video, e_consume_vorbis, } consume[stream_count]; for (i = 0; i < stream_count; i++) consume[i] = e_consume_none; // the basic framecodes. flag, pts, stream, mul, size, count fti[n++] = (fti_tt){ /*invalid 0x00*/ FLAG_INVALID, 0, 0, 1, 0, 1 }; fti[n++] = (fti_tt){ NUT_FLAG_KEY|FLAG_CODED_PTS|FLAG_STREAM_ID|FLAG_SIZE_MSB, 0, 0, 1, 0, 1 }; fti[n++] = (fti_tt){ FLAG_CODED_PTS|FLAG_STREAM_ID|FLAG_SIZE_MSB, 0, 0, 1, 0, 1 }; fti[n++] = (fti_tt){ /*extreme fallback*/ FLAG_CODED, 1, 0, 1, 0, 1 }; for (i = 0; i < stream_count; i++) { if (n + m > 230) break; // that's enough! don't overflow switch (s[i].type) { case NUT_VIDEO_CLASS: fti[n++] = (fti_tt){ NUT_FLAG_KEY| FLAG_SIZE_MSB, 1, i, 1, 0, 1 }; fti[n++] = (fti_tt){ NUT_FLAG_KEY|FLAG_CHECKSUM|FLAG_SIZE_MSB, 1, i, 1, 0, 1 }; fti[n++] = (fti_tt){ FLAG_CODED_PTS|FLAG_SIZE_MSB, 0, i, 1, 0, 1 }; if (s[i].fourcc_len == 4 && !strncmp((char*)s[i].fourcc, "mp4v", 4)) { fti[n++] = (fti_tt){ 0, 1, i, 7, 6, 1 }; fti[n++] = (fti_tt){ 0, 2, i, 7, 6, 1 }; consume[i] = e_consume_mpeg4; } else if (s[i].fourcc_len == 4 && !strncmp((char*)s[i].fourcc, "h264", 4)) { consume[i] = e_consume_h264; } else { consume[i] = e_consume_video; } break; case NUT_AUDIO_CLASS: fti[n++] = (fti_tt){NUT_FLAG_KEY| FLAG_SIZE_MSB, 1, i, 1, 0, 1 }; fti[n++] = (fti_tt){NUT_FLAG_KEY|FLAG_CODED_PTS|FLAG_SIZE_MSB, 0, i, 1, 0, 1 }; if (s[i].fourcc_len == 4 && !strncmp((char*)s[i].fourcc, "mp3 ", 4)) { int j, a[] = {288,336,384,480,576,672,768,960}; for (j = 0; j < sizeof a/sizeof*a; j++) fti[n++] = (fti_tt){ NUT_FLAG_KEY, 1, i, a[j]+1, a[j], 1 }; fti[n++] = (fti_tt){ NUT_FLAG_KEY|FLAG_SIZE_MSB, 1, i, 4, 0, 1 }; fti[n++] = (fti_tt){ NUT_FLAG_KEY|FLAG_SIZE_MSB, 1, i, 4, 2, 1 }; } else if (s[i].fourcc_len == 4 && !strncmp((char*)s[i].fourcc, "vrbs", 4)) { fti[n++] = (fti_tt){ NUT_FLAG_KEY|FLAG_SIZE_MSB, 2, i, 1, 0, 1 }; fti[n++] = (fti_tt){ NUT_FLAG_KEY|FLAG_SIZE_MSB, 9, i, 1, 0, 1 }; fti[n++] = (fti_tt){ NUT_FLAG_KEY|FLAG_SIZE_MSB, 23, i, 1, 0, 1 }; fti[n++] = (fti_tt){ NUT_FLAG_KEY|FLAG_SIZE_MSB, 16, i, 6, 0, 6 }; m+=5; consume[i] = e_consume_vorbis; } break; case NUT_SUBTITLE_CLASS: fti[n++] = (fti_tt){NUT_FLAG_KEY|FLAG_SIZE_MSB|FLAG_CODED_PTS, 0, i, 5, 0, 5 }; m+=4; fti[n++] = (fti_tt){NUT_FLAG_KEY|NUT_FLAG_EOR| FLAG_CODED_PTS, 0, i, 1, 0, 1 }; break; case NUT_USERDATA_CLASS: fti[n++] = (fti_tt){NUT_FLAG_KEY|FLAG_SIZE_MSB|FLAG_CODED_PTS, 0, i, 1, 0, 1 }; fti[n++] = (fti_tt){ FLAG_SIZE_MSB|FLAG_CODED_PTS, 0, i, 1, 0, 1 }; break; default: assert(0); } } for (i = 0; i < stream_count; i++) if (consume[i]) tot_con++; if (tot_con) tot_con = (254 - (n+m))/tot_con; // 256 - 'N' - 0xFF invalid if (tot_con) for (i = 0; i < stream_count; i++) { int al = tot_con; switch (consume[i]) { case e_consume_none: break; case e_consume_mpeg4: { int al1 = al*35/100; int al2 = al*45/100; int al3 = al-al1-al2; fti[n++] = (fti_tt){ FLAG_SIZE_MSB, 1, i, al1, 0, al1 }; m+=al1-1; fti[n++] = (fti_tt){ FLAG_SIZE_MSB, 2, i, al2, 0, al2 }; m+=al2-1; fti[n++] = (fti_tt){ FLAG_SIZE_MSB, -1, i, al3, 0, al3 }; m+=al3-1; break; } case e_consume_h264: { int al1 = al*35/100; int al2 = al*35/100; int al3 = al*20/100; int al4 = al-al1-al2-al3; fti[n++] = (fti_tt){ FLAG_SIZE_MSB, 1, i, al1, 0, al1 }; m+=al1-1; fti[n++] = (fti_tt){ FLAG_SIZE_MSB, 2, i, al2, 0, al2 }; m+=al2-1; fti[n++] = (fti_tt){ FLAG_SIZE_MSB, -1, i, al3, 0, al3 }; m+=al3-1; fti[n++] = (fti_tt){ FLAG_CODED_PTS|FLAG_SIZE_MSB, 0, i, al4, 0, al4 }; m+=al4-1; break; } case e_consume_video: fti[n++] = (fti_tt){ FLAG_SIZE_MSB, 1, i, al, 0, al }; m+=al-1; break; case e_consume_vorbis: { int al1 = al*70/100; int al2 = al-al1; al1 /= 2; al2 /= 2; fti[n++] = (fti_tt){ NUT_FLAG_KEY, 16, i,240+al1,240-al1, al1*2 }; m+=al1*2-1; fti[n++] = (fti_tt){ NUT_FLAG_KEY, 2, i, 65+al2, 65-al2, al2*2 }; m+=al2*2-1; break; } } } i = 255-n-m; fti[n++] = (fti_tt){ /*invalid 0xFF*/ FLAG_INVALID, 0, 0, i, 0, i }; // the final framecode. flag, pts, stream, mul, size, count fti[n++] = (fti_tt){ -1 }; }