3 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 #include <sound/audio.h>
33 #define AC97_VENDORID 0x8086
34 #define AC97_DEVICEID 0x2415
82 AC97_Master_Volume_Mute
= 0x02,
83 AC97_Headphone_Volume_Mute
= 0x04,
84 AC97_Master_Volume_Mono_Mute
= 0x06,
85 AC97_Master_Tone_RL
= 0x08,
86 AC97_PC_BEEP_Volume_Mute
= 0x0A,
87 AC97_Phone_Volume_Mute
= 0x0C,
88 AC97_Mic_Volume_Mute
= 0x0E,
89 AC97_Line_In_Volume_Mute
= 0x10,
90 AC97_CD_Volume_Mute
= 0x12,
91 AC97_Video_Volume_Mute
= 0x14,
92 AC97_Aux_Volume_Mute
= 0x16,
93 AC97_PCM_Out_Volume_Mute
= 0x18,
94 AC97_Record_Select
= 0x1A,
95 AC97_Record_Gain_Mute
= 0x1C,
96 AC97_Record_Gain_Mic_Mute
= 0x1E,
97 AC97_General_Purpose
= 0x20,
98 AC97_3D_Control
= 0x22,
99 AC97_AC_97_RESERVED
= 0x24,
100 AC97_Powerdown_Ctrl_Stat
= 0x26,
101 AC97_Extended_Audio_ID
= 0x28,
102 AC97_Extended_Audio_Ctrl_Stat
= 0x2A,
103 AC97_PCM_Front_DAC_Rate
= 0x2C,
104 AC97_PCM_Surround_DAC_Rate
= 0x2E,
105 AC97_PCM_LFE_DAC_Rate
= 0x30,
106 AC97_PCM_LR_ADC_Rate
= 0x32,
107 AC97_MIC_ADC_Rate
= 0x34,
108 AC97_6Ch_Vol_C_LFE_Mute
= 0x36,
109 AC97_6Ch_Vol_L_R_Surround_Mute
= 0x38,
110 AC97_Vendor_Reserved
= 0x58,
111 AC97_Vendor_ID1
= 0x7c,
112 AC97_Vendor_ID2
= 0x7e
115 /* buffer descriptor */
118 unsigned buffer
: 31;
120 unsigned reserved
: 14;
123 } __attribute__ ((__packed__
)) ac97_desc_t
;
125 /* device structure */
131 unsigned char pobdbar_imax
;
132 unsigned char pobdbar_icurr
;
133 ac97_desc_t
*pibdbar
;
134 ac97_desc_t
*pobdbar
;
135 ac97_desc_t
*mcbdbar
;
139 unsigned task_audio ();
142 unsigned char ac97_inb_nabm (ac97_t
*dev
, int port
)
144 return inb (dev
->bus_master
+ port
);
147 unsigned short ac97_inw_nabm (ac97_t
*dev
, int port
)
149 return inw (dev
->bus_master
+ port
);
152 unsigned ac97_inl_nabm (ac97_t
*dev
, int port
)
154 return inl (dev
->bus_master
+ port
);
157 void ac97_outb_nabm (ac97_t
*dev
, int port
, unsigned char value
)
159 outb (dev
->bus_master
+ port
, value
);
162 void ac97_outw_nabm (ac97_t
*dev
, int port
, unsigned short value
)
164 outw (dev
->bus_master
+ port
, value
);
167 void ac97_outl_nabm (ac97_t
*dev
, int port
, int value
)
169 outl (dev
->bus_master
+ port
, value
);
173 void ac97_outb_nam (ac97_t
*dev
, int port
, unsigned char value
)
175 outb (dev
->mixer_base
+ port
, value
);
178 void ac97_outw_nam (ac97_t
*dev
, int port
, unsigned short value
)
180 outw (dev
->mixer_base
+ port
, value
);
183 void ac97_outl_nam (ac97_t
*dev
, int port
, int value
)
185 outl (dev
->mixer_base
+ port
, value
);
188 /* detect ac97 device in PC */
189 pcidev_t
*ac97_detect ()
191 /* First detect sound card - is connected to PCI bus ?*/
192 pcidev_t
*pcidev
= pcidev_find (AC97_VENDORID
, AC97_DEVICEID
);
200 unsigned init_ac97 ()
202 pcidev_t
*pcidev
= ac97_detect ();
207 ac97_t
*dev
= (ac97_t
*) kmalloc (sizeof (ac97_t
));
213 dev
->irq
= pcidev
->u
.h0
.interrupt_line
;
214 dev
->mixer_base
= pcidev
->u
.h0
.base_registers
[0];
215 dev
->bus_master
= pcidev
->u
.h0
.base_registers
[1];
217 kprintf ("ac97 -> found at 0x%x, 0x%x; irq: %d\n", dev
->mixer_base
, dev
->bus_master
, dev
->irq
);
219 unsigned char *c
= (unsigned char *) dev
->mixer_base
;
221 //ac97_outb (dev, 0x0, 1);
224 //for (i = 0; i < 100; i ++)
225 //kprintf ("| 0x%x", c[i]);
227 unsigned mask
= 0x1 << 5;
228 unsigned char r
= ac97_inb_nabm (dev
, CAS
);
230 dev
->pibdbar
= (ac97_desc_t
*) 0x65000;
231 dev
->pobdbar
= (ac97_desc_t
*) 0x65100;
232 dev
->mcbdbar
= (ac97_desc_t
*) 0x65200;
234 ac97_outl_nabm (dev
, PIBDBAR
, (unsigned) dev
->pibdbar
);
235 ac97_outl_nabm (dev
, POBDBAR
, (unsigned) dev
->pobdbar
);
236 ac97_outl_nabm (dev
, MCBDBAR
, (unsigned) dev
->mcbdbar
);
239 ac97_outw_nam (dev
, AC97_Reset
, 0);
240 ac97_outw_nam (dev
, AC97_Powerdown_Ctrl_Stat
, 0);
242 ac97_outw_nam (dev
, AC97_Master_Volume_Mute
, 0x1 | 0x1 << 8);
243 ac97_outw_nam (dev
, AC97_PCM_Out_Volume_Mute
, 0x1 | 0x1 << 8);
247 unsigned int val = 0x8808;
248 int mute = (val >> MUTE_SHIFT) & 1;
249 unsigned char rvol = VOL_MASK - (val & VOL_MASK);
250 unsigned char lvol = VOL_MASK - ((val >> 8) & VOL_MASK);
251 rvol = 255 * rvol / VOL_MASK;
252 lvol = 255 * lvol / VOL_MASK;
254 kprintf ("lvol: 0x%x | rvol: 0x%x | mute: %d\n", lvol, rvol, mute);
257 /*unsigned char civ = ac97_inb_nabm (dev, POCIV);
258 kprintf ("civ: 0x%x\n", civ);
260 unsigned r2 = ac97_inl_nabm (dev, POBDBAR);
261 kprintf ("r: 0x%x\n", r2);*/
263 //dev->pobdbar_imax = 0x1;
264 //ac97_outb_nabm (dev, POLVI, dev->pobdbar_imax);
265 //dev->pobdbar_icurr = 0;
266 /* start new task/thread for network core */
267 task_create ("audio", (unsigned) task_audio
, 255);
269 //ac97_outl (dev, 0xab, mask);
270 //ac97_outb (dev, 54, 1);
275 int setup_ac97 (ac97_t
*dev
, snd_audio_t
*aud
)
280 if (!aud
->rate
|| !aud
->format
|| !aud
->channels
) {
281 ac97_outb_nabm (dev
, POCR
, 0x0);
285 /* we want to setup device for specific frequency rate, etc */
286 ac97_outw_nam (dev
, AC97_Extended_Audio_Ctrl_Stat
, 1);
287 ac97_outw_nam (dev
, AC97_PCM_Front_DAC_Rate
, aud
->channels
== 1 ? aud
->rate
/2 : aud
->rate
);
289 ac97_outb_nabm (dev
, POCR
, 0x1);
294 unsigned task_audio ()
297 ac97_desc_t
*pobdbar
= (ac97_desc_t
*) 0x65100;
298 ac97_t
*dev
= dev_ac97
;
300 unsigned char civ
= ac97_inb_nabm (dev
, POCIV
);
302 for (;; schedule ()) {
303 unsigned r3
= ac97_inw_nabm (dev
, POSR
);
305 //kprintf ("POSR: 0x%x\n", r3);
306 //kprintf ("POCIV: 0x%x\n", dev->pobdbar_icurr);
310 ac97_outw_nabm (dev
, POSR
, r3
);
314 ac97_outb_nabm (dev
, POLVI
, 0x1f);
317 /*unsigned c = ac97_inb_nabm (dev, POCIV);
321 printf ("civ: %d\n", c);
328 bool ac97_acthandler (unsigned act
, char *buf
, unsigned len
)
330 ac97_t
*dev
= dev_ac97
;
340 if (buf
&& len
== sizeof (snd_audio_t
))
341 return setup_ac97 (dev
, (snd_audio_t
*) buf
);
353 for (; ac97_inb_nabm (dev
, POCIV
) != 0x1f; schedule ());
355 //unsigned char *dma = 0x600000;
357 unsigned i
= 0, l
= 0;
359 for (i
= 0; i
< 32; i
++) {
365 dev
->pobdbar
[i
].zero
= 0;
366 dev
->pobdbar
[i
].buffer
= ((unsigned) (buf
+ (i
*0x1FFE0)) >> 1);
367 dev
->pobdbar
[i
].len
= (unsigned short) (l
/ 2);
368 dev
->pobdbar
[i
].reserved
= ~1;
369 dev
->pobdbar
[i
].bup
= 0;
370 dev
->pobdbar
[i
].ioc
= 0;
375 /* r3 = ac97_inw_nabm (dev, POSR);
379 ac97_outw_nabm (dev, POSR, r3);
383 ac97_outb_nabm (dev, POLVI, 0x1f);
385 ac97_outb_nabm (dev, POLVI, 0x1);
388 printf ("picb: %d\n", ac97_inw_nabm (dev, POPICB));*/
390 //printf ("dev->pobdbar_icurr: %d\n", dev->pobdbar_icurr);
391 //dev->pobdbar_icurr ++;
393 //ac97_outb_nabm (dev, POLVI, 0x1);
394 //if (dev->pobdbar_icurr)