SB16.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Memory.h>
  7. #include <AK/Singleton.h>
  8. #include <AK/StringView.h>
  9. #include <Kernel/Arch/x86/InterruptDisabler.h>
  10. #include <Kernel/Debug.h>
  11. #include <Kernel/Devices/SB16.h>
  12. #include <Kernel/IO.h>
  13. #include <Kernel/Memory/AnonymousVMObject.h>
  14. #include <Kernel/Memory/MemoryManager.h>
  15. #include <Kernel/Sections.h>
  16. #include <Kernel/Thread.h>
  17. #include <LibC/sys/ioctl_numbers.h>
  18. namespace Kernel {
  19. enum class SampleFormat : u8 {
  20. Signed = 0x10,
  21. Stereo = 0x20,
  22. };
  23. constexpr int SB16_DEFAULT_IRQ = 5;
  24. constexpr u16 DSP_READ = 0x22A;
  25. constexpr u16 DSP_WRITE = 0x22C;
  26. constexpr u16 DSP_STATUS = 0x22E;
  27. constexpr u16 DSP_R_ACK = 0x22F;
  28. /* Write a value to the DSP write register */
  29. void SB16::dsp_write(u8 value)
  30. {
  31. while (IO::in8(DSP_WRITE) & 0x80)
  32. ;
  33. IO::out8(DSP_WRITE, value);
  34. }
  35. /* Reads the value of the DSP read register */
  36. u8 SB16::dsp_read()
  37. {
  38. while (!(IO::in8(DSP_STATUS) & 0x80))
  39. ;
  40. return IO::in8(DSP_READ);
  41. }
  42. /* Changes the sample rate of sound output */
  43. void SB16::set_sample_rate(uint16_t hz)
  44. {
  45. dbgln("SB16: Changing sample rate to {} Hz", hz);
  46. m_sample_rate = hz;
  47. dsp_write(0x41); // output
  48. dsp_write((u8)(hz >> 8));
  49. dsp_write((u8)hz);
  50. dsp_write(0x42); // input
  51. dsp_write((u8)(hz >> 8));
  52. dsp_write((u8)hz);
  53. }
  54. static Singleton<SB16> s_the;
  55. UNMAP_AFTER_INIT SB16::SB16()
  56. : IRQHandler(SB16_DEFAULT_IRQ)
  57. // FIXME: We can't change version numbers later, i.e. after the sound card is initialized.
  58. , CharacterDevice(42, 42)
  59. {
  60. initialize();
  61. }
  62. UNMAP_AFTER_INIT SB16::~SB16()
  63. {
  64. }
  65. UNMAP_AFTER_INIT void SB16::detect()
  66. {
  67. IO::out8(0x226, 1);
  68. IO::delay(32);
  69. IO::out8(0x226, 0);
  70. auto data = dsp_read();
  71. if (data != 0xaa)
  72. return;
  73. SB16::create();
  74. }
  75. UNMAP_AFTER_INIT void SB16::create()
  76. {
  77. s_the.ensure_instance();
  78. }
  79. SB16& SB16::the()
  80. {
  81. return *s_the;
  82. }
  83. UNMAP_AFTER_INIT void SB16::initialize()
  84. {
  85. disable_irq();
  86. IO::out8(0x226, 1);
  87. IO::delay(32);
  88. IO::out8(0x226, 0);
  89. auto data = dsp_read();
  90. if (data != 0xaa) {
  91. dbgln("SB16: SoundBlaster not ready");
  92. return;
  93. }
  94. // Get the version info
  95. dsp_write(0xe1);
  96. m_major_version = dsp_read();
  97. auto vmin = dsp_read();
  98. dmesgln("SB16: Found version {}.{}", m_major_version, vmin);
  99. set_irq_register(SB16_DEFAULT_IRQ);
  100. dmesgln("SB16: IRQ {}", get_irq_line());
  101. set_sample_rate(m_sample_rate);
  102. }
  103. KResult SB16::ioctl(FileDescription&, unsigned request, Userspace<void*> arg)
  104. {
  105. switch (request) {
  106. case SOUNDCARD_IOCTL_GET_SAMPLE_RATE: {
  107. auto output = static_ptr_cast<u16*>(arg);
  108. if (!copy_to_user(output, &m_sample_rate))
  109. return EFAULT;
  110. return KSuccess;
  111. }
  112. case SOUNDCARD_IOCTL_SET_SAMPLE_RATE: {
  113. auto sample_rate_value = static_cast<u16>(arg.ptr());
  114. if (sample_rate_value == 0)
  115. return EINVAL;
  116. if (m_sample_rate != sample_rate_value)
  117. set_sample_rate(sample_rate_value);
  118. return KSuccess;
  119. }
  120. default:
  121. return EINVAL;
  122. }
  123. }
  124. void SB16::set_irq_register(u8 irq_number)
  125. {
  126. u8 bitmask;
  127. switch (irq_number) {
  128. case 2:
  129. bitmask = 0;
  130. break;
  131. case 5:
  132. bitmask = 0b10;
  133. break;
  134. case 7:
  135. bitmask = 0b100;
  136. break;
  137. case 10:
  138. bitmask = 0b1000;
  139. break;
  140. default:
  141. VERIFY_NOT_REACHED();
  142. }
  143. IO::out8(0x224, 0x80);
  144. IO::out8(0x225, bitmask);
  145. }
  146. u8 SB16::get_irq_line()
  147. {
  148. IO::out8(0x224, 0x80);
  149. u8 bitmask = IO::in8(0x225);
  150. switch (bitmask) {
  151. case 0:
  152. return 2;
  153. case 0b10:
  154. return 5;
  155. case 0b100:
  156. return 7;
  157. case 0b1000:
  158. return 10;
  159. }
  160. return bitmask;
  161. }
  162. void SB16::set_irq_line(u8 irq_number)
  163. {
  164. InterruptDisabler disabler;
  165. if (irq_number == get_irq_line())
  166. return;
  167. set_irq_register(irq_number);
  168. change_irq_number(irq_number);
  169. }
  170. bool SB16::can_read(FileDescription const&, size_t) const
  171. {
  172. return false;
  173. }
  174. KResultOr<size_t> SB16::read(FileDescription&, u64, UserOrKernelBuffer&, size_t)
  175. {
  176. return 0;
  177. }
  178. void SB16::dma_start(uint32_t length)
  179. {
  180. auto const addr = m_dma_region->physical_page(0)->paddr().get();
  181. u8 const channel = 5; // 16-bit samples use DMA channel 5 (on the master DMA controller)
  182. u8 const mode = 0x48;
  183. // Disable the DMA channel
  184. IO::out8(0xd4, 4 + (channel % 4));
  185. // Clear the byte pointer flip-flop
  186. IO::out8(0xd8, 0);
  187. // Write the DMA mode for the transfer
  188. IO::out8(0xd6, (channel % 4) | mode);
  189. // Write the offset of the buffer
  190. u16 offset = (addr / 2) % 65536;
  191. IO::out8(0xc4, (u8)offset);
  192. IO::out8(0xc4, (u8)(offset >> 8));
  193. // Write the transfer length
  194. IO::out8(0xc6, (u8)(length - 1));
  195. IO::out8(0xc6, (u8)((length - 1) >> 8));
  196. // Write the buffer
  197. IO::out8(0x8b, addr >> 16);
  198. auto page_number = addr >> 16;
  199. VERIFY(page_number <= NumericLimits<u8>::max());
  200. IO::out8(0x8b, page_number);
  201. // Enable the DMA channel
  202. IO::out8(0xd4, (channel % 4));
  203. }
  204. bool SB16::handle_irq(RegisterState const&)
  205. {
  206. // FIXME: Check if the interrupt was actually for us or not... (shared IRQs)
  207. // Stop sound output ready for the next block.
  208. dsp_write(0xd5);
  209. IO::in8(DSP_STATUS); // 8 bit interrupt
  210. if (m_major_version >= 4)
  211. IO::in8(DSP_R_ACK); // 16 bit interrupt
  212. m_irq_queue.wake_all();
  213. return true;
  214. }
  215. void SB16::wait_for_irq()
  216. {
  217. m_irq_queue.wait_forever("SB16");
  218. disable_irq();
  219. }
  220. KResultOr<size_t> SB16::write(FileDescription&, u64, UserOrKernelBuffer const& data, size_t length)
  221. {
  222. if (!m_dma_region) {
  223. auto page = MM.allocate_supervisor_physical_page();
  224. if (!page)
  225. return ENOMEM;
  226. auto nonnull_page = page.release_nonnull();
  227. auto maybe_vmobject = Memory::AnonymousVMObject::try_create_with_physical_pages({ &nonnull_page, 1 });
  228. if (maybe_vmobject.is_error())
  229. return maybe_vmobject.error();
  230. m_dma_region = MM.allocate_kernel_region_with_vmobject(maybe_vmobject.release_value(), PAGE_SIZE, "SB16 DMA buffer", Memory::Region::Access::Write);
  231. if (!m_dma_region)
  232. return ENOMEM;
  233. }
  234. dbgln_if(SB16_DEBUG, "SB16: Writing buffer of {} bytes", length);
  235. VERIFY(length <= PAGE_SIZE);
  236. int const BLOCK_SIZE = 32 * 1024;
  237. if (length > BLOCK_SIZE) {
  238. return ENOSPC;
  239. }
  240. u8 mode = (u8)SampleFormat::Signed | (u8)SampleFormat::Stereo;
  241. if (!data.read(m_dma_region->vaddr().as_ptr(), length))
  242. return EFAULT;
  243. dma_start(length);
  244. // 16-bit single-cycle output.
  245. // FIXME: Implement auto-initialized output.
  246. u8 command = 0xb0;
  247. u16 sample_count = length / sizeof(i16);
  248. if (mode & (u8)SampleFormat::Stereo)
  249. sample_count /= 2;
  250. sample_count -= 1;
  251. cli();
  252. enable_irq();
  253. dsp_write(command);
  254. dsp_write(mode);
  255. dsp_write((u8)sample_count);
  256. dsp_write((u8)(sample_count >> 8));
  257. wait_for_irq();
  258. return length;
  259. }
  260. }