grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / AHI / Drivers / EMU10kx / hwaccess.c
blobba33086c875a90087c20560ba3e636f3cb2f8f2c
1 /*
2 **********************************************************************
3 * hwaccess.c -- Hardware access layer
4 * Copyright 1999, 2000 Creative Labs, Inc.
6 **********************************************************************
8 * Date Author Summary of changes
9 * ---- ------ ------------------
10 * October 20, 1999 Bertrand Lee base code release
11 * December 9, 1999 Jon Taylor rewrote the I/O subsystem
13 **********************************************************************
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public
26 * License along with this program; if not, write to the Free
27 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
28 * USA.
30 **********************************************************************
34 #ifdef AHI
36 #include <config.h>
38 #include <proto/exec.h>
39 #include <proto/ahi_sub.h>
40 #include <utility/hooks.h>
42 #include <stdarg.h>
44 #include "library.h"
46 #include "linuxsupport.h"
47 #include "hwaccess.h"
48 #include "8010.h"
49 #include "pci_wrapper.h"
51 /* uncomment next line to use midi port on Audigy drive */
52 //#define USE_AUDIGY_DRIVE_MIDI
54 #ifdef USE_AUDIGY_DRIVE_MIDI
55 #define A_MUDATA A_MUDATA2
56 #define A_MUCMD A_MUCMD2
57 #define A_MUSTAT A_MUCMD2
58 #define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY2
59 #define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY2
60 #define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE2
61 #define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE2
62 #else
63 #define A_MUDATA A_MUDATA1
64 #define A_MUCMD A_MUCMD1
65 #define A_MUSTAT A_MUCMD1
66 #define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY1
67 #define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY1
68 #define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE1
69 #define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE1
70 #endif
72 #define inb(port) (unsigned short)ahi_pci_inb(port, card->pci_dev)
73 #define inw(port) (unsigned short)ahi_pci_inw(port, card->pci_dev)
74 #define inl(port) (unsigned int)ahi_pci_inl(port, card->pci_dev)
75 #define outb(value,port) ahi_pci_outb(value, port, card->pci_dev)
76 #define outw(value,port) ahi_pci_outw(value, port, card->pci_dev)
77 #define outl(value,port) ahi_pci_outl(value, port, card->pci_dev)
79 #else // AHI
81 #include <asm/io.h>
83 #include "hwaccess.h"
84 #include "8010.h"
85 #include "icardmid.h"
87 #endif // AHI
90 /*************************************************************************
91 * Function : srToPitch *
92 * Input : sampleRate - sampling rate *
93 * Return : pitch value *
94 * About : convert sampling rate to pitch *
95 * Note : for 8010, sampling rate is at 48kHz, this function should *
96 * be changed. *
97 *************************************************************************/
98 u32 srToPitch(u32 sampleRate)
100 int i;
102 /* FIXME: These tables should be defined in a headerfile */
103 static u32 logMagTable[128] = {
104 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
105 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
106 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
107 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
108 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
109 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
110 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
111 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
112 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
113 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
114 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
115 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
116 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
117 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
118 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
119 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
122 static char logSlopeTable[128] = {
123 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
124 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
125 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
126 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
127 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
128 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
129 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
130 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
131 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
132 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
133 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
134 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
135 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
136 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
137 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
138 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
141 if (sampleRate == 0)
142 return 0; /* Bail out if no leading "1" */
144 sampleRate *= 11185; /* Scale 48000 to 0x20002380 */
146 for (i = 31; i > 0; i--) {
147 if (sampleRate & 0x80000000) { /* Detect leading "1" */
148 return (u32) (((s32) (i - 15) << 20) +
149 logMagTable[0x7f & (sampleRate >> 24)] +
150 (0x7f & (sampleRate >> 17)) * logSlopeTable[0x7f & (sampleRate >> 24)]);
152 sampleRate = sampleRate << 1;
155 DPF(2, "srToPitch: BUG!\n");
156 return 0; /* Should never reach this point */
159 /* Returns an attenuation based upon a cumulative volume value */
161 /* Algorithm calculates 0x200 - 0x10 log2 (input) */
162 u8 sumVolumeToAttenuation(u32 value)
164 u16 count = 16;
165 s16 ans;
167 if (value == 0)
168 return 0xFF;
170 /* Find first SET bit. This is the integer part of the value */
171 while ((value & 0x10000) == 0) {
172 value <<= 1;
173 count--;
176 /* The REST of the data is the fractional part. */
177 ans = (s16) (0x110 - ((count << 4) + ((value & 0x0FFFFL) >> 12)));
178 if (ans > 0xFF)
179 ans = 0xFF;
181 return (u8) ans;
184 /*******************************************
185 * write/read PCI function 0 registers *
186 ********************************************/
187 void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data)
189 #ifndef AHI
190 unsigned long flags;
191 #endif
193 if (reg & 0xff000000) {
194 u32 mask;
195 u8 size, offset;
197 size = (reg >> 24) & 0x3f;
198 offset = (reg >> 16) & 0x1f;
199 mask = ((1 << size) - 1) << offset;
200 data = (data << offset) & mask;
201 reg &= 0x7f;
203 spin_lock_irqsave(&card->lock, flags);
204 data |= inl(card->iobase + reg) & ~mask;
205 outl(data, card->iobase + reg);
206 spin_unlock_irqrestore(&card->lock, flags);
207 } else {
208 spin_lock_irqsave(&card->lock, flags);
209 outl(data, card->iobase + reg);
210 spin_unlock_irqrestore(&card->lock, flags);
213 return;
216 void emu10k1_writefn0_2(struct emu10k1_card *card, u32 reg, u32 data, int size)
218 #ifndef AHI
219 unsigned long flags;
220 #endif
222 spin_lock_irqsave(&card->lock, flags);
224 if (size == 32)
225 outl(data, card->iobase + (reg & 0x1F));
226 else if (size == 16)
227 outw(data, card->iobase + (reg & 0x1F));
228 else
229 outb(data, card->iobase + (reg & 0x1F));
231 spin_unlock_irqrestore(&card->lock, flags);
233 return;
236 u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg)
238 u32 val;
239 #ifndef AHI
240 unsigned long flags;
241 #endif
243 if (reg & 0xff000000) {
244 u32 mask;
245 u8 size, offset;
247 size = (reg >> 24) & 0x3f;
248 offset = (reg >> 16) & 0x1f;
249 mask = ((1 << size) - 1) << offset;
250 reg &= 0x7f;
252 spin_lock_irqsave(&card->lock, flags);
253 val = inl(card->iobase + reg);
254 spin_unlock_irqrestore(&card->lock, flags);
256 return (val & mask) >> offset;
257 } else {
258 spin_lock_irqsave(&card->lock, flags);
259 val = inl(card->iobase + reg);
260 spin_unlock_irqrestore(&card->lock, flags);
261 return val;
265 void emu10k1_timer_set(struct emu10k1_card * card, u16 data)
267 #ifndef AHI
268 unsigned long flags;
269 #endif
271 spin_lock_irqsave(&card->lock, flags);
272 outw(data & TIMER_RATE_MASK, card->iobase + TIMER);
273 spin_unlock_irqrestore(&card->lock, flags);
277 /************************************************************************
278 * write/read Emu10k1 pointer-offset register set, accessed through *
279 * the PTR and DATA registers *
280 *************************************************************************/
281 #define A_PTR_ADDRESS_MASK 0x0fff0000
282 void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data)
284 u32 regptr;
285 #ifndef AHI
286 unsigned long flags;
287 #endif
289 regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
291 if (reg & 0xff000000) {
292 u32 mask;
293 u8 size, offset;
295 size = (reg >> 24) & 0x3f;
296 offset = (reg >> 16) & 0x1f;
297 mask = ((1 << size) - 1) << offset;
298 data = (data << offset) & mask;
300 spin_lock_irqsave(&card->lock, flags);
301 outl(regptr, card->iobase + PTR);
302 data |= inl(card->iobase + DATA) & ~mask;
303 outl(data, card->iobase + DATA);
304 spin_unlock_irqrestore(&card->lock, flags);
305 } else {
306 spin_lock_irqsave(&card->lock, flags);
307 outl(regptr, card->iobase + PTR);
308 outl(data, card->iobase + DATA);
309 spin_unlock_irqrestore(&card->lock, flags);
313 /* ... : data, reg, ... , TAGLIST_END */
314 void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...)
316 va_list args;
318 #ifndef AHI
319 unsigned long flags;
320 #endif
321 u32 reg;
323 va_start(args, channel);
325 spin_lock_irqsave(&card->lock, flags);
326 while ((reg = va_arg(args, u32)) != TAGLIST_END) {
327 u32 data = va_arg(args, u32);
328 u32 regptr = (((reg << 16) & A_PTR_ADDRESS_MASK)
329 | (channel & PTR_CHANNELNUM_MASK));
330 outl(regptr, card->iobase + PTR);
331 if (reg & 0xff000000) {
332 int size = (reg >> 24) & 0x3f;
333 int offset = (reg >> 16) & 0x1f;
334 u32 mask = ((1 << size) - 1) << offset;
335 data = (data << offset) & mask;
337 data |= inl(card->iobase + DATA) & ~mask;
339 outl(data, card->iobase + DATA);
341 spin_unlock_irqrestore(&card->lock, flags);
343 va_end(args);
345 return;
348 u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel)
350 u32 regptr, val;
351 #ifndef AHI
352 unsigned long flags;
353 #endif
355 regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
357 if (reg & 0xff000000) {
358 u32 mask;
359 u8 size, offset;
361 size = (reg >> 24) & 0x3f;
362 offset = (reg >> 16) & 0x1f;
363 mask = ((1 << size) - 1) << offset;
365 spin_lock_irqsave(&card->lock, flags);
366 outl(regptr, card->iobase + PTR);
367 val = inl(card->iobase + DATA);
368 spin_unlock_irqrestore(&card->lock, flags);
370 return (val & mask) >> offset;
371 } else {
372 spin_lock_irqsave(&card->lock, flags);
373 outl(regptr, card->iobase + PTR);
374 val = inl(card->iobase + DATA);
375 spin_unlock_irqrestore(&card->lock, flags);
377 return val;
381 void emu10k1_irq_enable(struct emu10k1_card *card, u32 irq_mask)
383 u32 val;
384 #ifndef AHI
385 unsigned long flags;
386 #endif
388 DPF(2,"emu10k1_irq_enable()\n");
390 spin_lock_irqsave(&card->lock, flags);
391 val = inl(card->iobase + INTE) | irq_mask;
392 outl(val, card->iobase + INTE);
393 spin_unlock_irqrestore(&card->lock, flags);
394 return;
397 void emu10k1_irq_disable(struct emu10k1_card *card, u32 irq_mask)
399 u32 val;
400 #ifndef AHI
401 unsigned long flags;
402 #endif
404 DPF(2,"emu10k1_irq_disable()\n");
406 spin_lock_irqsave(&card->lock, flags);
407 val = inl(card->iobase + INTE) & ~irq_mask;
408 outl(val, card->iobase + INTE);
409 spin_unlock_irqrestore(&card->lock, flags);
410 return;
413 void emu10k1_set_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
415 /* Voice interrupt */
416 if (voicenum >= 32)
417 sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 1);
418 else
419 sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 1);
421 return;
424 void emu10k1_clear_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
426 /* Voice interrupt */
427 if (voicenum >= 32)
428 sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0);
429 else
430 sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 0);
432 return;
435 static void sblive_wcwait(struct emu10k1_card *card, u32 wait)
437 volatile unsigned uCount;
438 u32 newtime = 0, curtime;
440 curtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER);
441 while (wait--) {
442 uCount = 0;
443 while (uCount++ < TIMEOUT) {
444 newtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER);
445 if (newtime != curtime)
446 break;
449 if (uCount >= TIMEOUT)
450 break;
452 curtime = newtime;
456 #ifndef AHI
457 u16 emu10k1_ac97_read(struct ac97_codec *codec, u8 reg)
459 struct emu10k1_card *card = codec->private_data;
460 u16 data;
461 #ifndef AHI
462 unsigned long flags;
463 #endif
465 spin_lock_irqsave(&card->lock, flags);
467 outb(reg, card->iobase + AC97ADDRESS);
468 data = inw(card->iobase + AC97DATA);
470 spin_unlock_irqrestore(&card->lock, flags);
472 printk( "emu10k1_ac97_read %02x->%08x\n", reg, data );
473 return data;
476 void emu10k1_ac97_write(struct ac97_codec *codec, u8 reg, u16 value)
478 struct emu10k1_card *card = codec->private_data;
479 unsigned long flags;
481 spin_lock_irqsave(&card->lock, flags);
483 outb(reg, card->iobase + AC97ADDRESS);
484 outw(value, card->iobase + AC97DATA);
485 outb( AC97_EXTENDED_ID, card->iobase + AC97ADDRESS);
487 spin_unlock_irqrestore(&card->lock, flags);
488 printk( "emu10k1_ac97_write %02x, %08x\n", reg, value );
491 #else // AHI
493 u16 emu10k1_readac97(struct emu10k1_card *card, u8 reg)
495 u16 data;
496 #ifndef AHI
497 unsigned long flags;
498 #endif
500 spin_lock_irqsave(&card->lock, flags);
502 outb(reg, card->iobase + AC97ADDRESS);
503 data = inw(card->iobase + AC97DATA);
505 spin_unlock_irqrestore(&card->lock, flags);
507 return data;
510 void emu10k1_writeac97(struct emu10k1_card *card, u8 reg, u16 value)
512 #ifndef AHI
513 unsigned long flags;
514 #endif
516 spin_lock_irqsave(&card->lock, flags);
518 outb(reg, card->iobase + AC97ADDRESS);
519 outw(value, card->iobase + AC97DATA);
521 spin_unlock_irqrestore(&card->lock, flags);
524 #endif // AHi
527 /*********************************************************
528 * MPU access functions *
529 **********************************************************/
531 int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data)
533 #ifndef AHI
534 unsigned long flags;
535 #endif
536 int ret;
538 if (card->is_audigy) {
539 if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_ORDYN) == 0) {
540 sblive_writeptr(card, A_MUDATA, 0, data);
541 ret = 0;
542 } else
543 ret = -1;
544 } else {
545 spin_lock_irqsave(&card->lock, flags);
547 if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
548 outb(data, card->iobase + MUDATA);
549 ret = 0;
550 } else
551 ret = -1;
553 spin_unlock_irqrestore(&card->lock, flags);
556 return ret;
559 int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data)
561 #ifndef AHI
562 unsigned long flags;
563 #endif
564 int ret;
566 if (card->is_audigy) {
567 if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_IRDYN) == 0) {
568 *data = sblive_readptr(card, A_MUDATA,0);
569 ret = 0;
570 } else
571 ret = -1;
572 } else {
573 spin_lock_irqsave(&card->lock, flags);
575 if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
576 *data = inb(card->iobase + MUDATA);
577 ret = 0;
578 } else
579 ret = -1;
581 spin_unlock_irqrestore(&card->lock, flags);
584 return ret;
587 int emu10k1_mpu_reset(struct emu10k1_card *card)
589 u8 status;
590 #ifndef AHI
591 unsigned long flags;
592 #endif
594 DPF(2, "emu10k1_mpu_reset()\n");
595 if (card->is_audigy) {
596 #ifndef AHI
597 if (card->mpuacqcount == 0) {
598 #endif
599 sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
600 sblive_wcwait(card, 8);
601 sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
602 sblive_wcwait(card, 8);
603 sblive_writeptr(card, A_MUCMD, 0, MUCMD_ENTERUARTMODE);
604 sblive_wcwait(card, 8);
605 status = sblive_readptr(card, A_MUDATA, 0);
606 if (status == 0xfe)
607 return 0;
608 else
609 return -1;
610 #ifndef AHI
612 #endif
614 return 0;
615 } else {
616 #ifndef AHI
617 if (card->mpuacqcount == 0) {
618 #endif
619 spin_lock_irqsave(&card->lock, flags);
620 outb(MUCMD_RESET, card->iobase + MUCMD);
621 spin_unlock_irqrestore(&card->lock, flags);
623 sblive_wcwait(card, 8);
625 spin_lock_irqsave(&card->lock, flags);
626 outb(MUCMD_RESET, card->iobase + MUCMD);
627 spin_unlock_irqrestore(&card->lock, flags);
629 sblive_wcwait(card, 8);
631 spin_lock_irqsave(&card->lock, flags);
632 outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD);
633 spin_unlock_irqrestore(&card->lock, flags);
635 sblive_wcwait(card, 8);
637 spin_lock_irqsave(&card->lock, flags);
638 status = inb(card->iobase + MUDATA);
639 spin_unlock_irqrestore(&card->lock, flags);
641 if (status == 0xfe)
642 return 0;
643 else
644 return -1;
645 #ifndef AHI
647 #endif
648 return 0;
652 #ifndef AHI
653 int emu10k1_mpu_acquire(struct emu10k1_card *card)
655 /* FIXME: This should be a macro */
656 ++card->mpuacqcount;
658 return 0;
661 int emu10k1_mpu_release(struct emu10k1_card *card)
663 /* FIXME: this should be a macro */
664 --card->mpuacqcount;
666 return 0;
669 #endif // AHI