use the function names directly
[AROS.git] / workbench / devs / AHI / Drivers / EMU10kx / hwaccess.c
blob413a7fc725667bb3a7b94842070c2dcb3d70e595
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 unsigned long flags;
191 if (reg & 0xff000000) {
192 u32 mask;
193 u8 size, offset;
195 size = (reg >> 24) & 0x3f;
196 offset = (reg >> 16) & 0x1f;
197 mask = ((1 << size) - 1) << offset;
198 data = (data << offset) & mask;
199 reg &= 0x7f;
201 spin_lock_irqsave(&card->lock, flags);
202 data |= inl(card->iobase + reg) & ~mask;
203 outl(data, card->iobase + reg);
204 spin_unlock_irqrestore(&card->lock, flags);
205 } else {
206 spin_lock_irqsave(&card->lock, flags);
207 outl(data, card->iobase + reg);
208 spin_unlock_irqrestore(&card->lock, flags);
211 return;
214 void emu10k1_writefn0_2(struct emu10k1_card *card, u32 reg, u32 data, int size)
216 unsigned long flags;
218 spin_lock_irqsave(&card->lock, flags);
220 if (size == 32)
221 outl(data, card->iobase + (reg & 0x1F));
222 else if (size == 16)
223 outw(data, card->iobase + (reg & 0x1F));
224 else
225 outb(data, card->iobase + (reg & 0x1F));
227 spin_unlock_irqrestore(&card->lock, flags);
229 return;
232 u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg)
234 u32 val;
235 unsigned long flags;
237 if (reg & 0xff000000) {
238 u32 mask;
239 u8 size, offset;
241 size = (reg >> 24) & 0x3f;
242 offset = (reg >> 16) & 0x1f;
243 mask = ((1 << size) - 1) << offset;
244 reg &= 0x7f;
246 spin_lock_irqsave(&card->lock, flags);
247 val = inl(card->iobase + reg);
248 spin_unlock_irqrestore(&card->lock, flags);
250 return (val & mask) >> offset;
251 } else {
252 spin_lock_irqsave(&card->lock, flags);
253 val = inl(card->iobase + reg);
254 spin_unlock_irqrestore(&card->lock, flags);
255 return val;
259 void emu10k1_timer_set(struct emu10k1_card * card, u16 data)
261 unsigned long flags;
263 spin_lock_irqsave(&card->lock, flags);
264 outw(data & TIMER_RATE_MASK, card->iobase + TIMER);
265 spin_unlock_irqrestore(&card->lock, flags);
269 /************************************************************************
270 * write/read Emu10k1 pointer-offset register set, accessed through *
271 * the PTR and DATA registers *
272 *************************************************************************/
273 #define A_PTR_ADDRESS_MASK 0x0fff0000
274 void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data)
276 u32 regptr;
277 unsigned long flags;
279 regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
281 if (reg & 0xff000000) {
282 u32 mask;
283 u8 size, offset;
285 size = (reg >> 24) & 0x3f;
286 offset = (reg >> 16) & 0x1f;
287 mask = ((1 << size) - 1) << offset;
288 data = (data << offset) & mask;
290 spin_lock_irqsave(&card->lock, flags);
291 outl(regptr, card->iobase + PTR);
292 data |= inl(card->iobase + DATA) & ~mask;
293 outl(data, card->iobase + DATA);
294 spin_unlock_irqrestore(&card->lock, flags);
295 } else {
296 spin_lock_irqsave(&card->lock, flags);
297 outl(regptr, card->iobase + PTR);
298 outl(data, card->iobase + DATA);
299 spin_unlock_irqrestore(&card->lock, flags);
303 /* ... : data, reg, ... , TAGLIST_END */
304 void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...)
306 va_list args;
308 unsigned long flags;
309 u32 reg;
311 va_start(args, channel);
313 spin_lock_irqsave(&card->lock, flags);
314 while ((reg = va_arg(args, u32)) != TAGLIST_END) {
315 u32 data = va_arg(args, u32);
316 u32 regptr = (((reg << 16) & A_PTR_ADDRESS_MASK)
317 | (channel & PTR_CHANNELNUM_MASK));
318 outl(regptr, card->iobase + PTR);
319 if (reg & 0xff000000) {
320 int size = (reg >> 24) & 0x3f;
321 int offset = (reg >> 16) & 0x1f;
322 u32 mask = ((1 << size) - 1) << offset;
323 data = (data << offset) & mask;
325 data |= inl(card->iobase + DATA) & ~mask;
327 outl(data, card->iobase + DATA);
329 spin_unlock_irqrestore(&card->lock, flags);
331 va_end(args);
333 return;
336 u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel)
338 u32 regptr, val;
339 unsigned long flags;
341 regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
343 if (reg & 0xff000000) {
344 u32 mask;
345 u8 size, offset;
347 size = (reg >> 24) & 0x3f;
348 offset = (reg >> 16) & 0x1f;
349 mask = ((1 << size) - 1) << offset;
351 spin_lock_irqsave(&card->lock, flags);
352 outl(regptr, card->iobase + PTR);
353 val = inl(card->iobase + DATA);
354 spin_unlock_irqrestore(&card->lock, flags);
356 return (val & mask) >> offset;
357 } else {
358 spin_lock_irqsave(&card->lock, flags);
359 outl(regptr, card->iobase + PTR);
360 val = inl(card->iobase + DATA);
361 spin_unlock_irqrestore(&card->lock, flags);
363 return val;
367 void emu10k1_irq_enable(struct emu10k1_card *card, u32 irq_mask)
369 u32 val;
370 unsigned long flags;
372 DPF(2,"emu10k1_irq_enable()\n");
374 spin_lock_irqsave(&card->lock, flags);
375 val = inl(card->iobase + INTE) | irq_mask;
376 outl(val, card->iobase + INTE);
377 spin_unlock_irqrestore(&card->lock, flags);
378 return;
381 void emu10k1_irq_disable(struct emu10k1_card *card, u32 irq_mask)
383 u32 val;
384 unsigned long flags;
386 DPF(2,"emu10k1_irq_disable()\n");
388 spin_lock_irqsave(&card->lock, flags);
389 val = inl(card->iobase + INTE) & ~irq_mask;
390 outl(val, card->iobase + INTE);
391 spin_unlock_irqrestore(&card->lock, flags);
392 return;
395 void emu10k1_set_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
397 /* Voice interrupt */
398 if (voicenum >= 32)
399 sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 1);
400 else
401 sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 1);
403 return;
406 void emu10k1_clear_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
408 /* Voice interrupt */
409 if (voicenum >= 32)
410 sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0);
411 else
412 sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 0);
414 return;
417 static void sblive_wcwait(struct emu10k1_card *card, u32 wait)
419 volatile unsigned uCount;
420 u32 newtime = 0, curtime;
422 curtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER);
423 while (wait--) {
424 uCount = 0;
425 while (uCount++ < TIMEOUT) {
426 newtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER);
427 if (newtime != curtime)
428 break;
431 if (uCount >= TIMEOUT)
432 break;
434 curtime = newtime;
438 #ifndef AHI
439 u16 emu10k1_ac97_read(struct ac97_codec *codec, u8 reg)
441 struct emu10k1_card *card = codec->private_data;
442 u16 data;
443 unsigned long flags;
445 spin_lock_irqsave(&card->lock, flags);
447 outb(reg, card->iobase + AC97ADDRESS);
448 data = inw(card->iobase + AC97DATA);
450 spin_unlock_irqrestore(&card->lock, flags);
452 printk( "emu10k1_ac97_read %02x->%08x\n", reg, data );
453 return data;
456 void emu10k1_ac97_write(struct ac97_codec *codec, u8 reg, u16 value)
458 struct emu10k1_card *card = codec->private_data;
459 unsigned long flags;
461 spin_lock_irqsave(&card->lock, flags);
463 outb(reg, card->iobase + AC97ADDRESS);
464 outw(value, card->iobase + AC97DATA);
465 outb( AC97_EXTENDED_ID, card->iobase + AC97ADDRESS);
467 spin_unlock_irqrestore(&card->lock, flags);
468 printk( "emu10k1_ac97_write %02x, %08x\n", reg, value );
471 #else // AHI
473 u16 emu10k1_readac97(struct emu10k1_card *card, u8 reg)
475 u16 data;
476 unsigned long flags;
478 spin_lock_irqsave(&card->lock, flags);
480 outb(reg, card->iobase + AC97ADDRESS);
481 data = inw(card->iobase + AC97DATA);
483 spin_unlock_irqrestore(&card->lock, flags);
485 return data;
488 void emu10k1_writeac97(struct emu10k1_card *card, u8 reg, u16 value)
490 unsigned long flags;
492 spin_lock_irqsave(&card->lock, flags);
494 outb(reg, card->iobase + AC97ADDRESS);
495 outw(value, card->iobase + AC97DATA);
497 spin_unlock_irqrestore(&card->lock, flags);
500 #endif // AHi
503 /*********************************************************
504 * MPU access functions *
505 **********************************************************/
507 int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data)
509 unsigned long flags;
510 int ret;
512 if (card->is_audigy) {
513 if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_ORDYN) == 0) {
514 sblive_writeptr(card, A_MUDATA, 0, data);
515 ret = 0;
516 } else
517 ret = -1;
518 } else {
519 spin_lock_irqsave(&card->lock, flags);
521 if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
522 outb(data, card->iobase + MUDATA);
523 ret = 0;
524 } else
525 ret = -1;
527 spin_unlock_irqrestore(&card->lock, flags);
530 return ret;
533 int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data)
535 unsigned long flags;
536 int ret;
538 if (card->is_audigy) {
539 if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_IRDYN) == 0) {
540 *data = sblive_readptr(card, A_MUDATA,0);
541 ret = 0;
542 } else
543 ret = -1;
544 } else {
545 spin_lock_irqsave(&card->lock, flags);
547 if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
548 *data = inb(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_reset(struct emu10k1_card *card)
561 u8 status;
562 unsigned long flags;
564 DPF(2, "emu10k1_mpu_reset()\n");
565 if (card->is_audigy) {
566 #ifndef AHI
567 if (card->mpuacqcount == 0) {
568 #endif
569 sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
570 sblive_wcwait(card, 8);
571 sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
572 sblive_wcwait(card, 8);
573 sblive_writeptr(card, A_MUCMD, 0, MUCMD_ENTERUARTMODE);
574 sblive_wcwait(card, 8);
575 status = sblive_readptr(card, A_MUDATA, 0);
576 if (status == 0xfe)
577 return 0;
578 else
579 return -1;
580 #ifndef AHI
582 #endif
584 return 0;
585 } else {
586 #ifndef AHI
587 if (card->mpuacqcount == 0) {
588 #endif
589 spin_lock_irqsave(&card->lock, flags);
590 outb(MUCMD_RESET, card->iobase + MUCMD);
591 spin_unlock_irqrestore(&card->lock, flags);
593 sblive_wcwait(card, 8);
595 spin_lock_irqsave(&card->lock, flags);
596 outb(MUCMD_RESET, card->iobase + MUCMD);
597 spin_unlock_irqrestore(&card->lock, flags);
599 sblive_wcwait(card, 8);
601 spin_lock_irqsave(&card->lock, flags);
602 outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD);
603 spin_unlock_irqrestore(&card->lock, flags);
605 sblive_wcwait(card, 8);
607 spin_lock_irqsave(&card->lock, flags);
608 status = inb(card->iobase + MUDATA);
609 spin_unlock_irqrestore(&card->lock, flags);
611 if (status == 0xfe)
612 return 0;
613 else
614 return -1;
615 #ifndef AHI
617 #endif
618 return 0;
622 #ifndef AHI
623 int emu10k1_mpu_acquire(struct emu10k1_card *card)
625 /* FIXME: This should be a macro */
626 ++card->mpuacqcount;
628 return 0;
631 int emu10k1_mpu_release(struct emu10k1_card *card)
633 /* FIXME: this should be a macro */
634 --card->mpuacqcount;
636 return 0;
639 #endif // AHI