123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- /*
- * Copyright (c) 2023, Jelle Raaijmakers <jelle@gmta.nl>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include "Format.h"
- #include <AK/Array.h>
- namespace Kernel::Audio::IntelHDA {
- // 3.3.41: Input/Output/Bidirectional Stream Descriptor Format
- // 3.7.1: Stream Format Structure
- struct SampleRateParameters {
- u32 sample_rate;
- u8 base;
- u8 multiple;
- u8 divisor;
- };
- static constexpr Array<SampleRateParameters, 15> sample_rate_parameters { {
- // clang-format off
- { 6'000, 0b0, 0b000, 0b111 },
- { 8'000, 0b0, 0b000, 0b101 },
- { 9'600, 0b0, 0b000, 0b100 },
- { 11'025, 0b1, 0b000, 0b011 },
- { 16'000, 0b0, 0b000, 0b010 },
- { 22'050, 0b1, 0b000, 0b001 },
- { 24'000, 0b0, 0b000, 0b001 },
- { 32'000, 0b0, 0b001, 0b010 },
- { 44'100, 0b1, 0b000, 0b000 },
- { 48'000, 0b0, 0b000, 0b000 },
- { 88'200, 0b1, 0b001, 0b000 },
- { 96'000, 0b0, 0b001, 0b000 },
- { 144'000, 0b0, 0b010, 0b000 },
- { 176'400, 0b1, 0b011, 0b000 },
- { 192'000, 0b0, 0b011, 0b000 },
- // clang-format on
- } };
- struct PcmBitsParameters {
- u8 pcm_bits;
- u8 encoding;
- };
- static constexpr Array<PcmBitsParameters, 5> pcm_bits_parameters { {
- // clang-format off
- { 8, 0b000 },
- { 16, 0b001 },
- { 20, 0b010 },
- { 24, 0b011 },
- { 32, 0b100 },
- // clang-format on
- } };
- ErrorOr<u16> encode_format(FormatParameters format)
- {
- // 3.3.41: Input/Output/Bidirectional Stream Descriptor Format
- // 3.7.1: Stream Format Structure
- // Stream type
- // NOTE: we only support PCM streams
- auto is_pcm = true;
- // Sample rate parameters
- Optional<SampleRateParameters> selected_sample_rate {};
- for (auto sample_rate_parameter : sample_rate_parameters) {
- if (sample_rate_parameter.sample_rate == format.sample_rate) {
- selected_sample_rate = sample_rate_parameter;
- break;
- }
- }
- if (!selected_sample_rate.has_value())
- return ENOTSUP;
- // Bit size
- Optional<PcmBitsParameters> selected_bit_rate {};
- for (auto pcm_bits_parameter : pcm_bits_parameters) {
- if (pcm_bits_parameter.pcm_bits == format.pcm_bits) {
- selected_bit_rate = pcm_bits_parameter;
- break;
- }
- }
- if (!selected_bit_rate.has_value())
- return ENOTSUP;
- // Number of channels
- if (format.number_of_channels < 1 || format.number_of_channels > 16)
- return ENOTSUP;
- // Construct stream format
- return ((is_pcm ? 0 : 1) << 15)
- | ((selected_sample_rate->base & 0x1) << 14)
- | ((selected_sample_rate->multiple & 0x7) << 11)
- | ((selected_sample_rate->divisor & 0x7) << 8)
- | ((selected_bit_rate->encoding & 0x7) << 4)
- | ((format.number_of_channels - 1) & 0xf);
- }
- ErrorOr<FormatParameters> decode_format(u16 format)
- {
- // 3.3.41: Input/Output/Bidirectional Stream Descriptor Format
- // 3.7.1: Stream Format Structure
- // Sample rate
- u8 sample_rate_base = (format >> 14) & 0x1;
- u8 sample_rate_multiple = (format >> 11) & 0x7;
- u8 sample_rate_divisor = (format >> 8) & 0x7;
- Optional<SampleRateParameters> found_sample_rate {};
- for (auto sample_rate_parameter : sample_rate_parameters) {
- if (sample_rate_parameter.base == sample_rate_base
- && sample_rate_parameter.multiple == sample_rate_multiple
- && sample_rate_parameter.divisor == sample_rate_divisor) {
- found_sample_rate = sample_rate_parameter;
- break;
- }
- }
- // PCM bits
- u8 pcm_bits = (format >> 4) & 0x7;
- Optional<PcmBitsParameters> found_pcm_bits {};
- for (auto pcm_bits_parameter : pcm_bits_parameters) {
- if (pcm_bits_parameter.encoding == pcm_bits) {
- found_pcm_bits = pcm_bits_parameter;
- break;
- }
- }
- // Number of channels
- u8 number_of_channels = (format & 0xf) + 1;
- if (!found_sample_rate.has_value() || !found_pcm_bits.has_value())
- return EINVAL;
- return FormatParameters {
- .sample_rate = found_sample_rate.release_value().sample_rate,
- .pcm_bits = found_pcm_bits.release_value().pcm_bits,
- .number_of_channels = number_of_channels,
- };
- }
- }
|