1/* 2 ********************************************************************** 3 * hwaccess.c -- Hardware access layer 4 * Copyright 1999, 2000 Creative Labs, Inc. 5 * 6 ********************************************************************** 7 * 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 12 * 13 ********************************************************************** 14 * 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. 19 * 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. 24 * 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. 29 * 30 ********************************************************************** 31 */ 32 33#include <asm/io.h> 34 35#include "hwaccess.h" 36#include "8010.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 static u32 logMagTable[128] = { 52 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2, 53 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5, 54 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081, 55 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191, 56 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7, 57 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829, 58 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e, 59 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26, 60 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d, 61 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885, 62 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899, 63 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c, 64 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3, 65 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3, 66 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83, 67 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df 68 }; 69 70 static char logSlopeTable[128] = { 71 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58, 72 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53, 73 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, 74 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, 75 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47, 76 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, 77 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, 78 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 79 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 80 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 81 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, 82 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35, 83 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34, 84 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32, 85 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 86 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f 87 }; 88 89 if (sampleRate == 0) 90 return 0; /* Bail out if no leading "1" */ 91 92 sampleRate *= 11185; /* Scale 48000 to 0x20002380 */ 93 94 for (i = 31; i > 0; i--) { 95 if (sampleRate & 0x80000000) { /* Detect leading "1" */ 96 return (u32) (((s32) (i - 15) << 20) + 97 logMagTable[0x7f & (sampleRate >> 24)] + 98 (0x7f & (sampleRate >> 17)) * logSlopeTable[0x7f & (sampleRate >> 24)]); 99 } 100 sampleRate = sampleRate << 1; 101 } 102 103 DPF(2, "srToPitch: BUG!\n"); 104 return 0; /* Should never reach this point */ 105} 106 107/******************************************* 108* write/read PCI function 0 registers * 109********************************************/ 110void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data) 111{ 112 unsigned long flags; 113 114 if (reg & 0xff000000) { 115 u32 mask; 116 u8 size, offset; 117 118 size = (reg >> 24) & 0x3f; 119 offset = (reg >> 16) & 0x1f; 120 mask = ((1 << size) - 1) << offset; 121 data = (data << offset) & mask; 122 reg &= 0x7f; 123 124 spin_lock_irqsave(&card->lock, flags); 125 data |= inl(card->iobase + reg) & ~mask; 126 outl(data, card->iobase + reg); 127 spin_unlock_irqrestore(&card->lock, flags); 128 } else { 129 spin_lock_irqsave(&card->lock, flags); 130 outl(data, card->iobase + reg); 131 spin_unlock_irqrestore(&card->lock, flags); 132 } 133 134 return; 135} 136 137#ifdef DBGEMU 138void emu10k1_writefn0_2(struct emu10k1_card *card, u32 reg, u32 data, int size) 139{ 140 unsigned long flags; 141 142 spin_lock_irqsave(&card->lock, flags); 143 144 if (size == 32) 145 outl(data, card->iobase + (reg & 0x1F)); 146 else if (size == 16) 147 outw(data, card->iobase + (reg & 0x1F)); 148 else 149 outb(data, card->iobase + (reg & 0x1F)); 150 151 spin_unlock_irqrestore(&card->lock, flags); 152 153 return; 154} 155#endif /* DBGEMU */ 156 157u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg) 158{ 159 u32 val; 160 unsigned long flags; 161 162 if (reg & 0xff000000) { 163 u32 mask; 164 u8 size, offset; 165 166 size = (reg >> 24) & 0x3f; 167 offset = (reg >> 16) & 0x1f; 168 mask = ((1 << size) - 1) << offset; 169 reg &= 0x7f; 170 171 spin_lock_irqsave(&card->lock, flags); 172 val = inl(card->iobase + reg); 173 spin_unlock_irqrestore(&card->lock, flags); 174 175 return (val & mask) >> offset; 176 } else { 177 spin_lock_irqsave(&card->lock, flags); 178 val = inl(card->iobase + reg); 179 spin_unlock_irqrestore(&card->lock, flags); 180 return val; 181 } 182} 183 184void emu10k1_timer_set(struct emu10k1_card * card, u16 data) 185{ 186 unsigned long flags; 187 188 spin_lock_irqsave(&card->lock, flags); 189 outw(data & TIMER_RATE_MASK, card->iobase + TIMER); 190 spin_unlock_irqrestore(&card->lock, flags); 191} 192 193/************************************************************************ 194* write/read Emu10k1 pointer-offset register set, accessed through * 195* the PTR and DATA registers * 196*************************************************************************/ 197#define A_PTR_ADDRESS_MASK 0x0fff0000 198void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data) 199{ 200 u32 regptr; 201 unsigned long flags; 202 203 regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); 204 205 if (reg & 0xff000000) { 206 u32 mask; 207 u8 size, offset; 208 209 size = (reg >> 24) & 0x3f; 210 offset = (reg >> 16) & 0x1f; 211 mask = ((1 << size) - 1) << offset; 212 data = (data << offset) & mask; 213 214 spin_lock_irqsave(&card->lock, flags); 215 outl(regptr, card->iobase + PTR); 216 data |= inl(card->iobase + DATA) & ~mask; 217 outl(data, card->iobase + DATA); 218 spin_unlock_irqrestore(&card->lock, flags); 219 } else { 220 spin_lock_irqsave(&card->lock, flags); 221 outl(regptr, card->iobase + PTR); 222 outl(data, card->iobase + DATA); 223 spin_unlock_irqrestore(&card->lock, flags); 224 } 225} 226 227/* ... : data, reg, ... , TAGLIST_END */ 228void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...) 229{ 230 va_list args; 231 232 unsigned long flags; 233 u32 reg; 234 235 va_start(args, channel); 236 237 spin_lock_irqsave(&card->lock, flags); 238 while ((reg = va_arg(args, u32)) != TAGLIST_END) { 239 u32 data = va_arg(args, u32); 240 u32 regptr = (((reg << 16) & A_PTR_ADDRESS_MASK) 241 | (channel & PTR_CHANNELNUM_MASK)); 242 outl(regptr, card->iobase + PTR); 243 if (reg & 0xff000000) { 244 int size = (reg >> 24) & 0x3f; 245 int offset = (reg >> 16) & 0x1f; 246 u32 mask = ((1 << size) - 1) << offset; 247 data = (data << offset) & mask; 248 249 data |= inl(card->iobase + DATA) & ~mask; 250 } 251 outl(data, card->iobase + DATA); 252 } 253 spin_unlock_irqrestore(&card->lock, flags); 254 255 va_end(args); 256 257 return; 258} 259 260u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel) 261{ 262 u32 regptr, val; 263 unsigned long flags; 264 265 regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); 266 267 if (reg & 0xff000000) { 268 u32 mask; 269 u8 size, offset; 270 271 size = (reg >> 24) & 0x3f; 272 offset = (reg >> 16) & 0x1f; 273 mask = ((1 << size) - 1) << offset; 274 275 spin_lock_irqsave(&card->lock, flags); 276 outl(regptr, card->iobase + PTR); 277 val = inl(card->iobase + DATA); 278 spin_unlock_irqrestore(&card->lock, flags); 279 280 return (val & mask) >> offset; 281 } else { 282 spin_lock_irqsave(&card->lock, flags); 283 outl(regptr, card->iobase + PTR); 284 val = inl(card->iobase + DATA); 285 spin_unlock_irqrestore(&card->lock, flags); 286 287 return val; 288 } 289} 290 291void emu10k1_irq_enable(struct emu10k1_card *card, u32 irq_mask) 292{ 293 u32 val; 294 unsigned long flags; 295 296 DPF(2,"emu10k1_irq_enable()\n"); 297 298 spin_lock_irqsave(&card->lock, flags); 299 val = inl(card->iobase + INTE) | irq_mask; 300 outl(val, card->iobase + INTE); 301 spin_unlock_irqrestore(&card->lock, flags); 302 return; 303} 304 305void emu10k1_irq_disable(struct emu10k1_card *card, u32 irq_mask) 306{ 307 u32 val; 308 unsigned long flags; 309 310 DPF(2,"emu10k1_irq_disable()\n"); 311 312 spin_lock_irqsave(&card->lock, flags); 313 val = inl(card->iobase + INTE) & ~irq_mask; 314 outl(val, card->iobase + INTE); 315 spin_unlock_irqrestore(&card->lock, flags); 316 return; 317} 318 319void emu10k1_clear_stop_on_loop(struct emu10k1_card *card, u32 voicenum) 320{ 321 /* Voice interrupt */ 322 if (voicenum >= 32) 323 sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0); 324 else 325 sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 0); 326 327 return; 328} 329 330static void sblive_wcwait(struct emu10k1_card *card, u32 wait) 331{ 332 volatile unsigned uCount; 333 u32 newtime = 0, curtime; 334 335 curtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER); 336 while (wait--) { 337 uCount = 0; 338 while (uCount++ < TIMEOUT) { 339 newtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER); 340 if (newtime != curtime) 341 break; 342 } 343 344 if (uCount >= TIMEOUT) 345 break; 346 347 curtime = newtime; 348 } 349} 350 351u16 emu10k1_ac97_read(struct ac97_codec *codec, u8 reg) 352{ 353 struct emu10k1_card *card = codec->private_data; 354 u16 data; 355 unsigned long flags; 356 357 spin_lock_irqsave(&card->lock, flags); 358 359 outb(reg, card->iobase + AC97ADDRESS); 360 data = inw(card->iobase + AC97DATA); 361 362 spin_unlock_irqrestore(&card->lock, flags); 363 364 return data; 365} 366 367void emu10k1_ac97_write(struct ac97_codec *codec, u8 reg, u16 value) 368{ 369 struct emu10k1_card *card = codec->private_data; 370 unsigned long flags; 371 372 spin_lock_irqsave(&card->lock, flags); 373 374 outb(reg, card->iobase + AC97ADDRESS); 375 outw(value, card->iobase + AC97DATA); 376 outb( AC97_EXTENDED_ID, card->iobase + AC97ADDRESS); 377 spin_unlock_irqrestore(&card->lock, flags); 378} 379 380/********************************************************* 381* MPU access functions * 382**********************************************************/ 383 384int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data) 385{ 386 unsigned long flags; 387 int ret; 388 389 if (card->is_audigy) { 390 if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_ORDYN) == 0) { 391 sblive_writeptr(card, A_MUDATA, 0, data); 392 ret = 0; 393 } else 394 ret = -1; 395 } else { 396 spin_lock_irqsave(&card->lock, flags); 397 398 if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) { 399 outb(data, card->iobase + MUDATA); 400 ret = 0; 401 } else 402 ret = -1; 403 404 spin_unlock_irqrestore(&card->lock, flags); 405 } 406 407 return ret; 408} 409 410int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data) 411{ 412 unsigned long flags; 413 int ret; 414 415 if (card->is_audigy) { 416 if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_IRDYN) == 0) { 417 *data = sblive_readptr(card, A_MUDATA,0); 418 ret = 0; 419 } else 420 ret = -1; 421 } else { 422 spin_lock_irqsave(&card->lock, flags); 423 424 if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) { 425 *data = inb(card->iobase + MUDATA); 426 ret = 0; 427 } else 428 ret = -1; 429 430 spin_unlock_irqrestore(&card->lock, flags); 431 } 432 433 return ret; 434} 435 436int emu10k1_mpu_reset(struct emu10k1_card *card) 437{ 438 u8 status; 439 unsigned long flags; 440 441 DPF(2, "emu10k1_mpu_reset()\n"); 442 if (card->is_audigy) { 443 if (card->mpuacqcount == 0) { 444 sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET); 445 sblive_wcwait(card, 8); 446 sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET); 447 sblive_wcwait(card, 8); 448 sblive_writeptr(card, A_MUCMD, 0, MUCMD_ENTERUARTMODE); 449 sblive_wcwait(card, 8); 450 status = sblive_readptr(card, A_MUDATA, 0); 451 if (status == 0xfe) 452 return 0; 453 else 454 return -1; 455 } 456 457 return 0; 458 } else { 459 if (card->mpuacqcount == 0) { 460 spin_lock_irqsave(&card->lock, flags); 461 outb(MUCMD_RESET, card->iobase + MUCMD); 462 spin_unlock_irqrestore(&card->lock, flags); 463 464 sblive_wcwait(card, 8); 465 466 spin_lock_irqsave(&card->lock, flags); 467 outb(MUCMD_RESET, card->iobase + MUCMD); 468 spin_unlock_irqrestore(&card->lock, flags); 469 470 sblive_wcwait(card, 8); 471 472 spin_lock_irqsave(&card->lock, flags); 473 outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD); 474 spin_unlock_irqrestore(&card->lock, flags); 475 476 sblive_wcwait(card, 8); 477 478 spin_lock_irqsave(&card->lock, flags); 479 status = inb(card->iobase + MUDATA); 480 spin_unlock_irqrestore(&card->lock, flags); 481 482 if (status == 0xfe) 483 return 0; 484 else 485 return -1; 486 } 487 488 return 0; 489 } 490} 491 492int emu10k1_mpu_acquire(struct emu10k1_card *card) 493{ 494 ++card->mpuacqcount; 495 496 return 0; 497} 498 499int emu10k1_mpu_release(struct emu10k1_card *card) 500{ 501 --card->mpuacqcount; 502 503 return 0; 504} 505