Format.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. * Copyright (c) 2023, Jelle Raaijmakers <jelle@gmta.nl>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "Format.h"
  7. #include <AK/Array.h>
  8. namespace Kernel::Audio::IntelHDA {
  9. // 3.3.41: Input/Output/Bidirectional Stream Descriptor Format
  10. // 3.7.1: Stream Format Structure
  11. struct SampleRateParameters {
  12. u32 sample_rate;
  13. u8 base;
  14. u8 multiple;
  15. u8 divisor;
  16. };
  17. static constexpr Array<SampleRateParameters, 15> sample_rate_parameters { {
  18. // clang-format off
  19. { 6'000, 0b0, 0b000, 0b111 },
  20. { 8'000, 0b0, 0b000, 0b101 },
  21. { 9'600, 0b0, 0b000, 0b100 },
  22. { 11'025, 0b1, 0b000, 0b011 },
  23. { 16'000, 0b0, 0b000, 0b010 },
  24. { 22'050, 0b1, 0b000, 0b001 },
  25. { 24'000, 0b0, 0b000, 0b001 },
  26. { 32'000, 0b0, 0b001, 0b010 },
  27. { 44'100, 0b1, 0b000, 0b000 },
  28. { 48'000, 0b0, 0b000, 0b000 },
  29. { 88'200, 0b1, 0b001, 0b000 },
  30. { 96'000, 0b0, 0b001, 0b000 },
  31. { 144'000, 0b0, 0b010, 0b000 },
  32. { 176'400, 0b1, 0b011, 0b000 },
  33. { 192'000, 0b0, 0b011, 0b000 },
  34. // clang-format on
  35. } };
  36. struct PcmBitsParameters {
  37. u8 pcm_bits;
  38. u8 encoding;
  39. };
  40. static constexpr Array<PcmBitsParameters, 5> pcm_bits_parameters { {
  41. // clang-format off
  42. { 8, 0b000 },
  43. { 16, 0b001 },
  44. { 20, 0b010 },
  45. { 24, 0b011 },
  46. { 32, 0b100 },
  47. // clang-format on
  48. } };
  49. ErrorOr<u16> encode_format(FormatParameters format)
  50. {
  51. // 3.3.41: Input/Output/Bidirectional Stream Descriptor Format
  52. // 3.7.1: Stream Format Structure
  53. // Stream type
  54. // NOTE: we only support PCM streams
  55. auto is_pcm = true;
  56. // Sample rate parameters
  57. Optional<SampleRateParameters> selected_sample_rate {};
  58. for (auto sample_rate_parameter : sample_rate_parameters) {
  59. if (sample_rate_parameter.sample_rate == format.sample_rate) {
  60. selected_sample_rate = sample_rate_parameter;
  61. break;
  62. }
  63. }
  64. if (!selected_sample_rate.has_value())
  65. return ENOTSUP;
  66. // Bit size
  67. Optional<PcmBitsParameters> selected_bit_rate {};
  68. for (auto pcm_bits_parameter : pcm_bits_parameters) {
  69. if (pcm_bits_parameter.pcm_bits == format.pcm_bits) {
  70. selected_bit_rate = pcm_bits_parameter;
  71. break;
  72. }
  73. }
  74. if (!selected_bit_rate.has_value())
  75. return ENOTSUP;
  76. // Number of channels
  77. if (format.number_of_channels < 1 || format.number_of_channels > 16)
  78. return ENOTSUP;
  79. // Construct stream format
  80. return ((is_pcm ? 0 : 1) << 15)
  81. | ((selected_sample_rate->base & 0x1) << 14)
  82. | ((selected_sample_rate->multiple & 0x7) << 11)
  83. | ((selected_sample_rate->divisor & 0x7) << 8)
  84. | ((selected_bit_rate->encoding & 0x7) << 4)
  85. | ((format.number_of_channels - 1) & 0xf);
  86. }
  87. ErrorOr<FormatParameters> decode_format(u16 format)
  88. {
  89. // 3.3.41: Input/Output/Bidirectional Stream Descriptor Format
  90. // 3.7.1: Stream Format Structure
  91. // Sample rate
  92. u8 sample_rate_base = (format >> 14) & 0x1;
  93. u8 sample_rate_multiple = (format >> 11) & 0x7;
  94. u8 sample_rate_divisor = (format >> 8) & 0x7;
  95. Optional<SampleRateParameters> found_sample_rate {};
  96. for (auto sample_rate_parameter : sample_rate_parameters) {
  97. if (sample_rate_parameter.base == sample_rate_base
  98. && sample_rate_parameter.multiple == sample_rate_multiple
  99. && sample_rate_parameter.divisor == sample_rate_divisor) {
  100. found_sample_rate = sample_rate_parameter;
  101. break;
  102. }
  103. }
  104. // PCM bits
  105. u8 pcm_bits = (format >> 4) & 0x7;
  106. Optional<PcmBitsParameters> found_pcm_bits {};
  107. for (auto pcm_bits_parameter : pcm_bits_parameters) {
  108. if (pcm_bits_parameter.encoding == pcm_bits) {
  109. found_pcm_bits = pcm_bits_parameter;
  110. break;
  111. }
  112. }
  113. // Number of channels
  114. u8 number_of_channels = (format & 0xf) + 1;
  115. if (!found_sample_rate.has_value() || !found_pcm_bits.has_value())
  116. return EINVAL;
  117. return FormatParameters {
  118. .sample_rate = found_sample_rate.release_value().sample_rate,
  119. .pcm_bits = found_pcm_bits.release_value().pcm_bits,
  120. .number_of_channels = number_of_channels,
  121. };
  122. }
  123. }