AHI/SB128: port fixes from ABI_V0 that make the card output correct sound
[aros:aros.git] / AROS / workbench / devs / AHI / Drivers / SB128 / interrupt.c
1 /*
2
3 The contents of this file are subject to the AROS Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
4 http://www.aros.org/license.html
5
6 Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
7 ANY KIND, either express or implied. See the License for the specific language governing rights and
8 limitations under the License.
9
10 The Original Code is (C) Copyright 2004-2011 Ross Vumbaca.
11
12 The Initial Developer of the Original Code is Ross Vumbaca.
13
14 All Rights Reserved.
15
16 */
17
18 #if !defined(__AROS__)
19 #undef __USE_INLINE__
20 #include <proto/expansion.h>
21 #endif
22 #include <libraries/ahi_sub.h>
23 #include <proto/exec.h>
24 #include <stddef.h>
25 #include "library.h"
26 #include "regs.h"
27 #include "interrupt.h"
28 #include "pci_wrapper.h"
29 #ifdef __AROS__
30 #include <aros/debug.h>
31 #endif
32
33 #define min(a,b) ((a)<(b)?(a):(b))
34
35 unsigned long z = 0;
36 /******************************************************************************
37 ** Hardware interrupt handler *************************************************
38 ******************************************************************************/
39
40
41 LONG
42 CardInterrupt( struct SB128_DATA* card )
43 {
44   struct AHIAudioCtrlDrv* AudioCtrl = card->audioctrl;
45   struct DriverBase*  AHIsubBase = (struct DriverBase*) card->ahisubbase;
46   struct PCIDevice *dev = (struct PCIDevice * ) card->pci_dev;
47
48   ULONG intreq;
49   LONG  handled = 0;
50     
51   D(bug("[CMI8738]: %s(card @ 0x%p)\n", __PRETTY_FUNCTION__, card));
52
53   while (((intreq = (pci_inl(SB128_STATUS, card))) & SB128_INT_PENDING) != 0)
54   {
55     if( intreq & SB128_INT_DAC2 && AudioCtrl != NULL )
56     {
57       /* Clear interrupt pending bit(s) and re-enable playback interrupts */
58       pci_outl((pci_inl(SB128_SCON, card) & ~SB128_DAC2_INTEN), SB128_SCON, card);
59       pci_outl((pci_inl(SB128_SCON, card) | SB128_DAC2_INTEN), SB128_SCON, card);
60
61       if (card->flip == 0) /* just played buf 1 */
62       {
63          card->flip = 1;
64          card->current_buffer = card->playback_buffer;
65       }
66       else  /* just played buf 2 */
67       {
68          card->flip = 0;
69          card->current_buffer = (APTR) ((unsigned long) card->playback_buffer + card->current_bytesize);
70       }
71       
72       card->playback_interrupt_enabled = FALSE;
73       Cause( &card->playback_interrupt );
74     }
75
76     if( intreq & SB128_INT_ADC && AudioCtrl != NULL )
77     {
78       /* Clear interrupt pending bit(s) and re-enable record interrupts */
79       pci_outl((pci_inl(SB128_SCON, card) & ~SB128_ADC_INTEN), SB128_SCON, card);
80       pci_outl((pci_inl(SB128_SCON, card) | SB128_ADC_INTEN), SB128_SCON, card);
81
82       if( card->record_interrupt_enabled )
83       {
84          /* Invoke softint to convert and feed AHI with the new sample data */
85
86          if (card->recflip == 0) /* just filled buf 1 */
87          {
88             card->recflip = 1;
89             card->current_record_buffer = card->record_buffer;
90             }
91          else  /* just filled buf 2 */
92          {
93             card->recflip = 0;
94             card->current_record_buffer = (APTR) ((unsigned long) card->record_buffer + card->current_record_bytesize);
95          }
96          card->record_interrupt_enabled = FALSE;
97          Cause( &card->record_interrupt );
98       }
99     }
100     exit:
101     handled = 1;
102     
103   }
104   
105   return handled;
106 }
107
108
109 /******************************************************************************
110 ** Playback interrupt handler *************************************************
111 ******************************************************************************/
112
113 void
114 PlaybackInterrupt( struct SB128_DATA* card )
115 {
116   struct AHIAudioCtrlDrv* AudioCtrl = card->audioctrl;
117   struct DriverBase*  AHIsubBase = (struct DriverBase*) card->ahisubbase;
118   struct PCIDevice *dev = (struct PCIDevice * ) card->pci_dev;
119
120   if( card->mix_buffer != NULL && card->current_buffer != NULL )
121   {
122     BOOL   skip_mix;
123
124     WORD*  src;
125     WORD*  dst;
126     size_t skip;
127     size_t samples;
128     int    i;
129     
130         skip_mix = CallHookPkt( AudioCtrl->ahiac_PreTimerFunc, (Object*) AudioCtrl, 0 );  
131     CallHookPkt( AudioCtrl->ahiac_PlayerFunc, (Object*) AudioCtrl, NULL );
132
133   if( ! skip_mix )
134     {
135       CallHookPkt( AudioCtrl->ahiac_MixerFunc, (Object*) AudioCtrl, card->mix_buffer );
136     }
137     
138     /* Now translate and transfer to the DMA buffer */
139
140     skip    = ( AudioCtrl->ahiac_Flags & AHIACF_HIFI ) ? 2 : 1;
141     samples = card->current_bytesize >> 1;
142
143     src     = card->mix_buffer;
144 #if !AROS_BIG_ENDIAN
145     if(skip == 2)
146         src++;
147 #endif
148     dst     = card->current_buffer;
149
150     i = samples;
151
152     while( i > 0 )
153     {
154 #ifdef __AMIGAOS4__
155       *dst = ( ( *src & 0xff ) << 8 ) | ( ( *src & 0xff00 ) >> 8 );
156 #else
157       *dst = *src;
158 #endif
159
160       src += skip;
161       dst += 1;
162
163       --i;
164     }
165     
166     //Flush cache so that data is completely written to the DMA buffer - Articia hack
167     CacheClearE(card->current_buffer, card->current_bytesize, CACRF_ClearD);
168     
169     CallHookPkt( AudioCtrl->ahiac_PostTimerFunc, (Object*) AudioCtrl, 0 );
170   }
171   card->playback_interrupt_enabled = TRUE;
172 }
173
174
175 /******************************************************************************
176 ** Record interrupt handler ***************************************************
177 ******************************************************************************/
178
179 void
180 RecordInterrupt( struct SB128_DATA* card )
181 {
182   struct AHIAudioCtrlDrv* AudioCtrl = card->audioctrl;
183   struct DriverBase*  AHIsubBase = (struct DriverBase*) card->ahisubbase;
184   struct PCIDevice *dev = (struct PCIDevice * ) card->pci_dev;
185
186   struct AHIRecordMessage rm =
187   {
188     AHIST_S16S,
189     card->current_record_buffer,
190     RECORD_BUFFER_SAMPLES
191   };
192
193   int   i   = 0, shorts = card->current_record_bytesize / 2;
194   WORD* ptr = card->current_record_buffer;
195
196   //Invalidate cache so that data read from DMA buffer is correct - Articia hack
197   CacheClearE(card->current_record_buffer, card->current_record_bytesize, CACRF_InvalidateD);
198
199 #ifdef __AMIGAOS4__
200   while( i < shorts )
201   {
202     *ptr = ( ( *ptr & 0xff ) << 8 ) | ( ( *ptr & 0xff00 ) >> 8 );
203
204     ++i;
205     ++ptr;
206   }
207 #else
208 #endif
209
210   CallHookPkt( AudioCtrl->ahiac_SamplerFunc, (Object*) AudioCtrl, &rm );
211
212   //Invalidate cache so that data read from DMA buffer is correct - Articia hack
213   CacheClearE(card->current_record_buffer, card->current_record_bytesize, CACRF_InvalidateD);
214
215   card->record_interrupt_enabled = TRUE;
216 }