mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:57:35 +00:00
Kernel: Allow writes larger than PAGE_SIZE
to AC97 device
Previously, `cat /dev/random > /dev/audio` would crash Serenity. Fix this by splitting up the written data into `PAGE_SIZE` chunks.
This commit is contained in:
parent
70ca8b24dc
commit
eb2b0d847e
2 changed files with 18 additions and 6 deletions
|
@ -169,8 +169,6 @@ void AC97::set_pcm_output_volume(u8 left_channel, u8 right_channel, Muted mute)
|
||||||
|
|
||||||
ErrorOr<size_t> AC97::write(OpenFileDescription&, u64, UserOrKernelBuffer const& data, size_t length)
|
ErrorOr<size_t> AC97::write(OpenFileDescription&, u64, UserOrKernelBuffer const& data, size_t length)
|
||||||
{
|
{
|
||||||
VERIFY(length <= PAGE_SIZE);
|
|
||||||
|
|
||||||
if (!m_output_buffer) {
|
if (!m_output_buffer) {
|
||||||
m_output_buffer = TRY(allocate_physical_buffer(m_output_buffer_page_count * PAGE_SIZE, "AC97 Output buffer"sv));
|
m_output_buffer = TRY(allocate_physical_buffer(m_output_buffer_page_count * PAGE_SIZE, "AC97 Output buffer"sv));
|
||||||
}
|
}
|
||||||
|
@ -179,9 +177,23 @@ ErrorOr<size_t> AC97::write(OpenFileDescription&, u64, UserOrKernelBuffer const&
|
||||||
m_buffer_descriptor_list = TRY(allocate_physical_buffer(buffer_descriptor_list_size, "AC97 Buffer Descriptor List"sv));
|
m_buffer_descriptor_list = TRY(allocate_physical_buffer(buffer_descriptor_list_size, "AC97 Buffer Descriptor List"sv));
|
||||||
}
|
}
|
||||||
|
|
||||||
cli();
|
auto remaining = length;
|
||||||
|
size_t offset = 0;
|
||||||
|
while (remaining > 0) {
|
||||||
|
TRY(write_single_buffer(data, offset, min(remaining, PAGE_SIZE)));
|
||||||
|
offset += PAGE_SIZE;
|
||||||
|
remaining -= PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> AC97::write_single_buffer(UserOrKernelBuffer const& data, size_t offset, size_t length)
|
||||||
|
{
|
||||||
|
VERIFY(length <= PAGE_SIZE);
|
||||||
|
|
||||||
// Block until we can write into an unused buffer
|
// Block until we can write into an unused buffer
|
||||||
|
cli();
|
||||||
do {
|
do {
|
||||||
auto pcm_out_status = m_pcm_out_channel.reg(AC97Channel::Register::Status).in<u16>();
|
auto pcm_out_status = m_pcm_out_channel.reg(AC97Channel::Register::Status).in<u16>();
|
||||||
auto is_dma_controller_halted = (pcm_out_status & AudioStatusRegisterFlag::DMAControllerHalted) > 0;
|
auto is_dma_controller_halted = (pcm_out_status & AudioStatusRegisterFlag::DMAControllerHalted) > 0;
|
||||||
|
@ -199,11 +211,10 @@ ErrorOr<size_t> AC97::write(OpenFileDescription&, u64, UserOrKernelBuffer const&
|
||||||
|
|
||||||
m_irq_queue.wait_forever("AC97"sv);
|
m_irq_queue.wait_forever("AC97"sv);
|
||||||
} while (m_pcm_out_channel.dma_running());
|
} while (m_pcm_out_channel.dma_running());
|
||||||
|
|
||||||
sti();
|
sti();
|
||||||
|
|
||||||
// Copy data from userspace into one of our buffers
|
// Copy data from userspace into one of our buffers
|
||||||
TRY(data.read(m_output_buffer->vaddr_from_page_index(m_output_buffer_page_index).as_ptr(), length));
|
TRY(data.read(m_output_buffer->vaddr_from_page_index(m_output_buffer_page_index).as_ptr(), offset, length));
|
||||||
|
|
||||||
if (!m_pcm_out_channel.dma_running()) {
|
if (!m_pcm_out_channel.dma_running()) {
|
||||||
reset_pcm_out();
|
reset_pcm_out();
|
||||||
|
@ -226,7 +237,7 @@ ErrorOr<size_t> AC97::write(OpenFileDescription&, u64, UserOrKernelBuffer const&
|
||||||
m_output_buffer_page_index = (m_output_buffer_page_index + 1) % m_output_buffer_page_count;
|
m_output_buffer_page_index = (m_output_buffer_page_index + 1) % m_output_buffer_page_count;
|
||||||
m_buffer_descriptor_list_index = (m_buffer_descriptor_list_index + 1) % buffer_descriptor_list_max_entries;
|
m_buffer_descriptor_list_index = (m_buffer_descriptor_list_index + 1) % buffer_descriptor_list_max_entries;
|
||||||
|
|
||||||
return length;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void AC97::AC97Channel::reset()
|
void AC97::AC97Channel::reset()
|
||||||
|
|
|
@ -152,6 +152,7 @@ private:
|
||||||
void set_master_output_volume(u8, u8, Muted);
|
void set_master_output_volume(u8, u8, Muted);
|
||||||
void set_pcm_output_sample_rate(u16);
|
void set_pcm_output_sample_rate(u16);
|
||||||
void set_pcm_output_volume(u8, u8, Muted);
|
void set_pcm_output_volume(u8, u8, Muted);
|
||||||
|
ErrorOr<void> write_single_buffer(UserOrKernelBuffer const&, size_t, size_t);
|
||||||
|
|
||||||
OwnPtr<Memory::Region> m_buffer_descriptor_list;
|
OwnPtr<Memory::Region> m_buffer_descriptor_list;
|
||||||
u8 m_buffer_descriptor_list_index = 0;
|
u8 m_buffer_descriptor_list_index = 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue