source: cmedia/trunk/Sblive/hwaccess.c@ 354

Last change on this file since 354 was 354, checked in by stevenhl, 17 years ago

Import untested baseline cmedia sources, work products and binaries
Binaries and work products should be deleted from repository.
once new builds are verified to work.

File size: 12.3 KB
Line 
1/* $Id: hwaccess.c,v 1.1 2000/04/23 14:55:43 ktk Exp $ */
2
3
4/*
5 **********************************************************************
6 * hwaccess.c -- Hardware access layer
7 * Copyright 1999, 2000 Creative Labs, Inc.
8 *
9 **********************************************************************
10 *
11 * Date Author Summary of changes
12 * ---- ------ ------------------
13 * October 20, 1999 Bertrand Lee base code release
14 * December 9, 1999 Jon Taylor rewrote the I/O subsystem
15 *
16 **********************************************************************
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License as
20 * published by the Free Software Foundation; either version 2 of
21 * the License, or (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public
29 * License along with this program; if not, write to the Free
30 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
31 * USA.
32 *
33 **********************************************************************
34 */
35
36#include "hwaccess.h"
37#include "icardmid.h"
38
39/*************************************************************************
40* Function : srToPitch *
41* Input : sampleRate - sampling rate *
42* Return : pitch value *
43* About : convert sampling rate to pitch *
44* Note : for 8010, sampling rate is at 48kHz, this function should *
45* be changed. *
46*************************************************************************/
47u32 srToPitch(u32 sampleRate)
48{
49 int i;
50
51 /* FIXME: These tables should be defined in a headerfile */
52 static u32 logMagTable[128] = {
53 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
54 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
55 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
56 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
57 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
58 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
59 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
60 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
61 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
62 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
63 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
64 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
65 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
66 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
67 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
68 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
69 };
70
71 static char logSlopeTable[128] = {
72 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
73 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
74 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
75 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
76 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
77 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
78 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
79 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
80 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
81 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
82 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
83 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
84 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
85 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
86 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
87 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
88 };
89
90 if (sampleRate == 0)
91 return (0); /* Bail out if no leading "1" */
92
93 sampleRate *= 11185; /* Scale 48000 to 0x20002380 */
94
95 for (i = 31; i > 0; i--) {
96 if (sampleRate & 0x80000000) { /* Detect leading "1" */
97 return (u32) (((s32) (i - 15) << 20) +
98 logMagTable[0x7f & (sampleRate >> 24)] +
99 (0x7f & (sampleRate >> 17)) * logSlopeTable[0x7f & (sampleRate >> 24)]);
100 }
101 sampleRate = sampleRate << 1;
102 }
103
104 DPF(2, "srToPitch: BUG!\n");
105 return 0; /* Should never reach this point */
106}
107
108/* Returns an attenuation based upon a cumulative volume value */
109
110/* Algorithm calculates 0x200 - 0x10 log2 (input) */
111u8 sumVolumeToAttenuation(u32 value)
112{
113 u16 count = 16;
114 s16 ans;
115
116 if (value == 0)
117 return 0xFF;
118
119 /* Find first SET bit. This is the integer part of the value */
120 while ((value & 0x10000) == 0) {
121 value <<= 1;
122 count--;
123 }
124
125 /* The REST of the data is the fractional part. */
126 ans = (s16) (0x110 - ((count << 4) + ((value & 0x0FFFFL) >> 12)));
127 if (ans > 0xFF)
128 ans = 0xFF;
129
130 return (u8) ans;
131}
132
133/*******************************************
134* write/read PCI function 0 registers *
135********************************************/
136void sblive_writefn0(struct emu10k1_card *card, u8 reg, u32 data)
137{
138 unsigned long flags;
139
140 spin_lock_irqsave(&card->lock, flags);
141 outl(data, card->iobase + reg);
142 spin_unlock_irqrestore(&card->lock, flags);
143
144 return;
145}
146
147void sblive_wrtmskfn0(struct emu10k1_card *card, u8 reg, u32 mask, u32 data)
148{
149 unsigned long flags;
150
151 data &= mask;
152
153 spin_lock_irqsave(&card->lock, flags);
154 data |= inl(card->iobase + reg) & ~mask;
155 outl(data, card->iobase + reg);
156 spin_unlock_irqrestore(&card->lock, flags);
157
158 return;
159}
160
161u32 sblive_readfn0(struct emu10k1_card * card, u8 reg)
162{
163 u32 val;
164 unsigned long flags;
165
166 spin_lock_irqsave(&card->lock, flags);
167 val = inl(card->iobase + reg);
168 spin_unlock_irqrestore(&card->lock, flags);
169 return val;
170}
171
172u32 sblive_rdmskfn0(struct emu10k1_card * card, u8 reg, u32 mask)
173{
174 u32 val;
175 unsigned long flags;
176
177 spin_lock_irqsave(&card->lock, flags);
178 val = inl(card->iobase + reg);
179 spin_unlock_irqrestore(&card->lock, flags);
180 return val & mask;
181}
182
183/************************************************************************
184* write/read Emu10k1 pointer-offset register set, accessed through *
185* the PTR and DATA registers *
186*************************************************************************/
187void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data)
188{
189 u32 regptr;
190 unsigned long flags;
191
192 regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
193
194 if (reg & 0xff000000) {
195 u32 mask;
196 u8 size, offset;
197
198 size = (reg >> 24) & 0x3f;
199 offset = (reg >> 16) & 0x1f;
200 mask = ((1 << size) - 1) << offset;
201 data = (data << offset) & mask;
202
203 spin_lock_irqsave(&card->lock, flags);
204 outl(regptr, card->iobase + PTR);
205 data |= inl(card->iobase + DATA) & ~mask;
206 outl(data, card->iobase + DATA);
207 spin_unlock_irqrestore(&card->lock, flags);
208 } else {
209 spin_lock_irqsave(&card->lock, flags);
210 outl(regptr, card->iobase + PTR);
211 outl(data, card->iobase + DATA);
212 spin_unlock_irqrestore(&card->lock, flags);
213 }
214
215 return;
216}
217
218u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel)
219{
220 u32 regptr, val;
221 unsigned long flags;
222
223 regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
224
225 if (reg & 0xff000000) {
226 u32 mask;
227 u8 size, offset;
228
229 size = (reg >> 24) & 0x3f;
230 offset = (reg >> 16) & 0x1f;
231 mask = ((1 << size) - 1) << offset;
232
233 spin_lock_irqsave(&card->lock, flags);
234 outl(regptr, card->iobase + PTR);
235 val = inl(card->iobase + DATA);
236 spin_unlock_irqrestore(&card->lock, flags);
237
238 return (val & mask) >> offset;
239 } else {
240 spin_lock_irqsave(&card->lock, flags);
241 outl(regptr, card->iobase + PTR);
242 val = inl(card->iobase + DATA);
243 spin_unlock_irqrestore(&card->lock, flags);
244
245 return val;
246 }
247}
248
249void emu10k1_set_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
250{
251 /* Voice interrupt */
252 if (voicenum >= 32)
253 sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 1);
254 else
255 sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 1);
256
257 return;
258}
259
260void emu10k1_clear_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
261{
262 /* Voice interrupt */
263 if (voicenum >= 32)
264 sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0);
265 else
266 sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 0);
267
268 return;
269}
270
271static void sblive_wcwait(struct emu10k1_card *card, u32 wait)
272{
273 volatile unsigned uCount;
274 u32 newtime = 0, curtime;
275
276 curtime = READ_FN0(card, WC_SAMPLECOUNTER);
277 while (wait--) {
278 uCount = 0;
279 while (uCount++ < TIMEOUT) {
280 newtime = READ_FN0(card, WC_SAMPLECOUNTER);
281 if (newtime != curtime)
282 break;
283 }
284
285 if (uCount >= TIMEOUT)
286 break;
287
288 curtime = newtime;
289 }
290}
291
292int sblive_readac97(struct emu10k1_card *card, u8 index, u16 * data)
293{
294 unsigned long flags;
295
296 spin_lock_irqsave(&card->lock, flags);
297
298 outb(index, card->mixeraddx + 2);
299 *data = inw(card->mixeraddx);
300
301 spin_unlock_irqrestore(&card->lock, flags);
302
303 return CTSTATUS_SUCCESS;
304}
305
306int sblive_writeac97(struct emu10k1_card *card, u8 index, u16 data)
307{
308 unsigned long flags;
309
310 spin_lock_irqsave(&card->lock, flags);
311
312 outb(index, card->mixeraddx + 2);
313 outw(data, card->mixeraddx);
314
315 spin_unlock_irqrestore(&card->lock, flags);
316
317 return CTSTATUS_SUCCESS;
318}
319
320int sblive_rmwac97(struct emu10k1_card *card, u8 index, u16 data, u16 mask)
321{
322 u16 temp;
323 unsigned long flags;
324
325 spin_lock_irqsave(&card->lock, flags);
326
327 outb(index, card->mixeraddx + 2);
328 temp = inw(card->mixeraddx);
329 temp &= ~mask;
330 data &= mask;
331 temp |= data;
332 outw(temp, card->mixeraddx);
333
334 spin_unlock_irqrestore(&card->lock, flags);
335
336 return CTSTATUS_SUCCESS;
337}
338
339/*********************************************************
340* MPU access functions *
341**********************************************************/
342
343int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data)
344{
345 unsigned long flags;
346 int ret;
347
348 spin_lock_irqsave(&card->lock, flags);
349
350 if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
351 outb(data, card->iobase + MUDATA);
352 ret = CTSTATUS_SUCCESS;
353 } else
354 ret = CTSTATUS_BUSY;
355
356 spin_unlock_irqrestore(&card->lock, flags);
357
358 return ret;
359}
360
361int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data)
362{
363 unsigned long flags;
364 int ret;
365
366 spin_lock_irqsave(&card->lock, flags);
367
368 if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
369 *data = inb(card->iobase + MUDATA);
370 ret = CTSTATUS_SUCCESS;
371 } else
372 ret = CTSTATUS_NODATA;
373
374 spin_unlock_irqrestore(&card->lock, flags);
375
376 return ret;
377}
378
379int emu10k1_mpu_reset(struct emu10k1_card *card)
380{
381 u8 status;
382 unsigned long flags;
383
384 DPF(2, "emu10k1_mpu_reset()\n");
385
386 if (card->mpuacqcount == 0) {
387 spin_lock_irqsave(&card->lock, flags);
388 outb(MUCMD_RESET, card->iobase + MUCMD);
389 spin_unlock_irqrestore(&card->lock, flags);
390
391 sblive_wcwait(card, 8);
392
393 spin_lock_irqsave(&card->lock, flags);
394 outb(MUCMD_RESET, card->iobase + MUCMD);
395 spin_unlock_irqrestore(&card->lock, flags);
396
397 sblive_wcwait(card, 8);
398
399 spin_lock_irqsave(&card->lock, flags);
400 outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD);
401 spin_unlock_irqrestore(&card->lock, flags);
402
403 sblive_wcwait(card, 8);
404
405 spin_lock_irqsave(&card->lock, flags);
406 status = inb(card->iobase + MUDATA);
407 spin_unlock_irqrestore(&card->lock, flags);
408
409 if (status == 0xfe)
410 return CTSTATUS_SUCCESS;
411 else
412 return CTSTATUS_ERROR;
413 }
414
415 return CTSTATUS_SUCCESS;
416}
417
418int emu10k1_mpu_acquire(struct emu10k1_card *card)
419{
420 /* FIXME: This should be a macro */
421 ++card->mpuacqcount;
422
423 return CTSTATUS_SUCCESS;
424}
425
426int emu10k1_mpu_release(struct emu10k1_card *card)
427{
428 /* FIXME: this should be a macro */
429 --card->mpuacqcount;
430
431 return CTSTATUS_SUCCESS;
432}
Note: See TracBrowser for help on using the repository browser.