Cleanup in elf.c with .bss section clean; adm command mounts cdrom instead of floppy...
[ZeXOS.git] / kernel / drivers / char / sound / ac97.c
blobd7aa33db89266c0f5282dffdca7a934c073288e8
1 /*
2 * ZeX/OS
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/>.
20 #include <config.h>
21 #include <build.h>
23 #ifdef ARCH_i386
25 #include <system.h>
26 #include <dev.h>
27 #include <arch/io.h>
28 #include <pci.h>
29 #include <its.h>
30 #include <task.h>
31 #include <sound/audio.h>
33 #define AC97_VENDORID 0x8086
34 #define AC97_DEVICEID 0x2415
36 enum
38 GLOB_CNT = 0x2c,
39 GLOB_STA = 0x30,
40 CAS = 0x34
43 enum {
44 PIBDBAR = 0x00,
45 POBDBAR = 0x10,
46 MCBDBAR = 0x20
49 enum {
50 PICIV = 0x04,
51 POCIV = 0x14,
52 MCCIV = 0x24
55 enum {
56 PISR = 0x06,
57 POSR = 0x16,
58 MCSR = 0x26
61 enum {
62 PILVI = 0x05,
63 POLVI = 0x15,
64 MCLVI = 0x25
68 enum {
69 PIPICB = 0x08,
70 POPICB = 0x18,
71 MCPICB = 0x28
74 enum {
75 PICR = 0x0b,
76 POCR = 0x1b,
77 MCCR = 0x2b
80 enum {
81 AC97_Reset = 0x00,
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 */
116 typedef struct {
117 unsigned zero : 1;
118 unsigned buffer : 31;
119 unsigned len : 16;
120 unsigned reserved : 14;
121 unsigned bup : 1;
122 unsigned ioc : 1;
123 } __attribute__ ((__packed__)) ac97_desc_t;
125 /* device structure */
126 typedef struct {
127 unsigned char state;
128 unsigned mixer_base;
129 unsigned bus_master;
130 int irq;
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;
136 } ac97_t;
137 ac97_t *dev_ac97;
139 unsigned task_audio ();
141 /* NABM */
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);
172 /* NAM */
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);
194 if (!pcidev)
195 return 0;
197 return pcidev;
200 unsigned init_ac97 ()
202 pcidev_t *pcidev = ac97_detect ();
204 if (!pcidev)
205 return 0;
207 ac97_t *dev = (ac97_t *) kmalloc (sizeof (ac97_t));
209 if (!dev)
210 return 0;
212 /* get irq id */
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);
223 unsigned i, y;
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);
238 /* open */
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);
245 dev_ac97 = dev;
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);
272 return 1;
275 int setup_ac97 (ac97_t *dev, snd_audio_t *aud)
277 if (!aud)
278 return 0;
280 if (!aud->rate || !aud->format || !aud->channels) {
281 ac97_outb_nabm (dev, POCR, 0x0);
282 return 1;
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);
291 return 1;
294 unsigned task_audio ()
296 unsigned i;
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);
308 if (r3 & 0x8) {
309 //kprintf ("0x8\n");
310 ac97_outw_nabm (dev, POSR, r3);
312 if (r3 & 0x1) {
313 //kprintf ("0x1\n");
314 ac97_outb_nabm (dev, POLVI, 0x1f);
317 /*unsigned c = ac97_inb_nabm (dev, POCIV);
319 if (c != civ) {
320 civ = c;
321 printf ("civ: %d\n", c);
325 return 1;
328 bool ac97_acthandler (unsigned act, char *buf, unsigned len)
330 ac97_t *dev = dev_ac97;
332 switch (act) {
333 case DEV_ACT_INIT:
335 return init_ac97 ();
337 break;
338 case DEV_ACT_UPDATE:
340 if (buf && len == sizeof (snd_audio_t))
341 return setup_ac97 (dev, (snd_audio_t *) buf);
343 break;
344 case DEV_ACT_STOP:
346 return 1;
348 break;
349 case DEV_ACT_WRITE:
351 unsigned r3 = 0;
353 for (; ac97_inb_nabm (dev, POCIV) != 0x1f; schedule ());
355 //unsigned char *dma = 0x600000;
357 unsigned i = 0, l = 0;
358 unsigned p = len;
359 for (i = 0; i < 32; i ++) {
360 if (p > 0x1FFE0)
361 l = 0x1FFE0;
362 else
363 l = p;
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;
372 p -= l;
375 /* r3 = ac97_inw_nabm (dev, POSR);
377 if (r3 & 0x8) {
378 kprintf ("0x8\n");
379 ac97_outw_nabm (dev, POSR, r3);
381 if (r3 & 0x1) {
382 kprintf ("0x1\n");
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)
397 return 1;
399 break;
402 return 0;
404 #endif