Difference between revisions of "Writing sound drivers for KolibriOS"

From KolibriOS wiki
Jump to navigation Jump to search
(Created page with '== Intro == == Layers == File:sound_layers.gif An application wich wants to output sound has to: # create a buffer using the SND_CREATE_BUFF service routine of Infinity. #...')
 
(Fixes for <asm> tags - replaced with <syntaxhighlight>)
 
(3 intermediate revisions by one other user not shown)
Line 3: Line 3:
 
== Layers ==
 
== Layers ==
  
[[File:sound_layers.gif]]
+
[[File:sound_layers.gif|thumb|250px]]
  
 
An application wich wants to output sound has to:
 
An application wich wants to output sound has to:
Line 11: Line 11:
 
# Update the sound samples in the buffer.
 
# Update the sound samples in the buffer.
  
Infinity gets the samples from all sound buffers of all applications that output sound and mixes them together in one buffer wich is then send to sound.obj.<br><br>
+
Infinity gets the samples from all sound buffers of all applications that output sound and mixes them together in one buffer wich is then send to sound.obj.
  
When Infinity is called for the first time, it inits itself and then calls sound.obj wich also initialises.<br>
+
When Infinity is called for the first time, it inits itself and then calls sound.obj wich also initialises.
Infinity calls the DEV_CALLBACK service routine of sound.obj to insert the address of the callback function to the [ctrl.user_callback] variable. <br>
+
Infinity calls the DEV_CALLBACK service routine of sound.obj to insert the address of the callback function to the [ctrl.user_callback] variable.
Sound.obj is responsible for calling this callback function every time the buffers need to be refilled.<br>
+
Sound.obj is responsible for calling this callback function every time the buffers need to be refilled.
The driver, sound.obj will do this when it gets an interrupt from the soundcard.<br>
+
The driver, sound.obj will do this when it gets an interrupt from the soundcard.
Before doing this, the interrupt handler should check to see if the interrupt was generated because of an 'end of buffer' event.<br>
+
Before doing this, the interrupt handler should check to see if the interrupt was generated because of an 'end of buffer' event.
It is possible that there are multiple, e.g. 2, buffers (like in HDA) wich sound.obj needs to fill, one after the other. <br>
+
It is possible that there are multiple, e.g. 2, buffers (like in HDA) wich sound.obj needs to fill, one after the other.
In this case, one buffer is given to Infinity to refill it with new portion of samples, while the second is being outputed by souncard.<br><br>
+
In this case, one buffer is given to Infinity to refill it with new portion of samples, while the second is being outputed by souncard.
  
Here is an example HDA IRQ handler, where you can see the piece of code that changes buffers and calls the callback function of Infinity.<br>
+
Here is an example HDA IRQ handler, where you can see the piece of code that changes buffers and calls the callback function of Infinity.
 
(I have selected that piece by ;!!!!!!!!!!! [ .... ;!!!!!!!!!!! ] brackets).
 
(I have selected that piece by ;!!!!!!!!!!! [ .... ;!!!!!!!!!!! ] brackets).
  
<asm>
+
<syntaxhighlight lang="asm">
 
align 4
 
align 4
 
proc hda_irq  ;+
 
proc hda_irq  ;+
Line 56: Line 56:
 
       cmp    [ctrl.user_callback], 0
 
       cmp    [ctrl.user_callback], 0
 
       je    @f
 
       je    @f
       stdcall [ctrl.user_callback], ebx[/b]
+
       stdcall [ctrl.user_callback], ebx
 
;!!!!!!!!!!! ]
 
;!!!!!!!!!!! ]
 
   @@:
 
   @@:
Line 78: Line 78:
 
       ret
 
       ret
 
endp
 
endp
</asm>
+
</syntaxhighlight>
  
  
Sound.obj is also responsible for creating the sound buffers that will be read by souncard and filled in by Infinity.<br>
+
Sound.obj is also responsible for creating the sound buffers that will be read by souncard and filled in by Infinity.
Every buffer has to be page aligned and be exactly 16Kbytes.<br><br>
+
Every buffer has to be page aligned and be exactly 16Kbytes.
  
 
So for two buffers we would have:
 
So for two buffers we would have:
  
<asm>
+
<syntaxhighlight lang="asm">
 
       stdcall KernelAlloc, 0x8000
 
       stdcall KernelAlloc, 0x8000
 
       mov [ctrl.buffer], eax
 
       mov [ctrl.buffer], eax
Line 95: Line 95:
 
       cld
 
       cld
 
       rep stosd
 
       rep stosd
</asm>
+
</syntaxhighlight>
  
Infinity does not need to know how the sound is outputed to the sound card, it is the matter of sound.obj to operate with it.<br>
+
Infinity does not need to know how the sound is outputed to the sound card, it is the matter of sound.obj to operate with it.
All that Infinity has to know is address of the sound buffer and when to fill it (all this information is given to it by sound.obj).<br>
+
All that Infinity has to know is address of the sound buffer and when to fill it (all this information is given to it by sound.obj).
 
This approach gives us HAL (hardware abstraction layer) wich makes the KolibriOS sound system universal and usefull for any soundcard.
 
This approach gives us HAL (hardware abstraction layer) wich makes the KolibriOS sound system universal and usefull for any soundcard.
 +
 +
[[Category:Coding]]

Latest revision as of 12:46, 22 April 2012

Intro

Layers

Sound layers.gif

An application wich wants to output sound has to:

  1. create a buffer using the SND_CREATE_BUFF service routine of Infinity.
  2. Set the format of the buffer using the SND_SET_FORMAT service routine of Infinity.
  3. Start playing using the SND_PLAY service routine of Infinity.
  4. Update the sound samples in the buffer.

Infinity gets the samples from all sound buffers of all applications that output sound and mixes them together in one buffer wich is then send to sound.obj.

When Infinity is called for the first time, it inits itself and then calls sound.obj wich also initialises. Infinity calls the DEV_CALLBACK service routine of sound.obj to insert the address of the callback function to the [ctrl.user_callback] variable. Sound.obj is responsible for calling this callback function every time the buffers need to be refilled. The driver, sound.obj will do this when it gets an interrupt from the soundcard. Before doing this, the interrupt handler should check to see if the interrupt was generated because of an 'end of buffer' event. It is possible that there are multiple, e.g. 2, buffers (like in HDA) wich sound.obj needs to fill, one after the other. In this case, one buffer is given to Infinity to refill it with new portion of samples, while the second is being outputed by souncard.

Here is an example HDA IRQ handler, where you can see the piece of code that changes buffers and calls the callback function of Infinity. (I have selected that piece by ;!!!!!!!!!!! [ .... ;!!!!!!!!!!! ] brackets).

align 4
proc hda_irq   ;+
;     if DEBUG_IRQ
;           mov esi, msgIRQ
;           call SysMsgBoardStr
;     end if
      mov    edx, ICH6_REG_INTSTS
      call  azx_readl
      test  eax, eax
      jnz    @f
      popa
      ret
  @@:
;!!!!!!!!!!! [
      mov    ebx, eax ; status
      mov    eax, 1 shl 4
      test  ebx, eax
      jz    @f

      mov     al, SD_INT_MASK
      mov    edx, ICH6_REG_SD_STS + SDO0_SD_OFFSET
      call  azx_writeb

      mov    eax, [civ_val]
      inc    eax
      and    eax, 1
      mov    [civ_val], eax

      mov    ebx, dword [buff_list+eax*4]
      cmp    [ctrl.user_callback], 0
      je    @f
      stdcall [ctrl.user_callback], ebx
;!!!!!!!!!!! ]
  @@:

      ; clear rirb int
      mov    edx, ICH6_REG_RIRBSTS
      call  azx_readb

      test  al, RIRB_INT_MASK
      jz    .l1
      test  al, RIRB_INT_RESPONSE
      jz    @f

      call  azx_update_rirb
  @@:
      mov     al, RIRB_INT_MASK
      mov    edx, ICH6_REG_RIRBSTS
      call  azx_writeb
  .l1:

      ret
endp


Sound.obj is also responsible for creating the sound buffers that will be read by souncard and filled in by Infinity. Every buffer has to be page aligned and be exactly 16Kbytes.

So for two buffers we would have:

      stdcall KernelAlloc, 0x8000
      mov [ctrl.buffer], eax

      mov edi, eax
      mov ecx, 0x8000/4
      xor eax, eax
      cld
      rep stosd

Infinity does not need to know how the sound is outputed to the sound card, it is the matter of sound.obj to operate with it. All that Infinity has to know is address of the sound buffer and when to fill it (all this information is given to it by sound.obj). This approach gives us HAL (hardware abstraction layer) wich makes the KolibriOS sound system universal and usefull for any soundcard.