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/* Returns an attenuation based upon a cumulative volume value */ 108 109/* Algorithm calculates 0x200 - 0x10 log2 (input) */ 110u8 sumVolumeToAttenuation(u32 value) 111{ 112 u16 count = 16; 113 s16 ans; 114 115 if (value == 0) 116 return 0xFF; 117 118 /* Find first SET bit. This is the integer part of the value */ 119 while ((value & 0x10000) == 0) { 120 value <<= 1; 121 count--; 122 } 123 124 /* The REST of the data is the fractional part. */ 125 ans = (s16) (0x110 - ((count << 4) + ((value & 0x0FFFFL) >> 12))); 126 if (ans > 0xFF) 127 ans = 0xFF; 128 129 return (u8) ans; 130} 131 132/******************************************* 133* write/read PCI function 0 registers * 134********************************************/ 135void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data) 136{ 137 unsigned long flags; 138 139 if (reg & 0xff000000) { 140 u32 mask; 141 u8 size, offset; 142 143 size = (reg >> 24) & 0x3f; 144 offset = (reg >> 16) & 0x1f; 145 mask = ((1 << size) - 1) << offset; 146 data = (data << offset) & mask; 147 reg &= 0x7f; 148 149 spin_lock_irqsave(&card->lock, flags); 150 data |= inl(card->iobase + reg) & ~mask; 151 outl(data, card->iobase + reg); 152 spin_unlock_irqrestore(&card->lock, flags); 153 } else { 154 spin_lock_irqsave(&card->lock, flags); 155 outl(data, card->iobase + reg); 156 spin_unlock_irqrestore(&card->lock, flags); 157 } 158 159 return; 160} 161 162u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg) 163{ 164 u32 val; 165 unsigned long flags; 166 167 if (reg & 0xff000000) { 168 u32 mask; 169 u8 size, offset; 170 171 size = (reg >> 24) & 0x3f; 172 offset = (reg >> 16) & 0x1f; 173 mask = ((1 << size) - 1) << offset; 174 reg &= 0x7f; 175 176 spin_lock_irqsave(&card->lock, flags); 177 val = inl(card->iobase + reg); 178 spin_unlock_irqrestore(&card->lock, flags); 179 180 return (val & mask) >> offset; 181 } else { 182 spin_lock_irqsave(&card->lock, flags); 183 val = inl(card->iobase + reg); 184 spin_unlock_irqrestore(&card->lock, flags); 185 return val; 186 } 187} 188 189void emu10k1_timer_set(struct emu10k1_card * card, u16 data) 190{ 191 unsigned long flags; 192 193 spin_lock_irqsave(&card->lock, flags); 194 outw(data & TIMER_RATE_MASK, card->iobase + TIMER); 195 spin_unlock_irqrestore(&card->lock, flags); 196} 197 198/************************************************************************ 199* write/read Emu10k1 pointer-offset register set, accessed through * 200* the PTR and DATA registers * 201*************************************************************************/ 202void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data) 203{ 204 u32 regptr; 205 unsigned long flags; 206 207 regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); 208 209 if (reg & 0xff000000) { 210 u32 mask; 211 u8 size, offset; 212 213 size = (reg >> 24) & 0x3f; 214 offset = (reg >> 16) & 0x1f; 215 mask = ((1 << size) - 1) << offset; 216 data = (data << offset) & mask; 217 218 spin_lock_irqsave(&card->lock, flags); 219 outl(regptr, card->iobase + PTR); 220 data |= inl(card->iobase + DATA) & ~mask; 221 outl(data, card->iobase + DATA); 222 spin_unlock_irqrestore(&card->lock, flags); 223 } else { 224 spin_lock_irqsave(&card->lock, flags); 225 outl(regptr, card->iobase + PTR); 226 outl(data, card->iobase + DATA); 227 spin_unlock_irqrestore(&card->lock, flags); 228 } 229} 230 231/* ... : data, reg, ... , TAGLIST_END */ 232void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...) 233{ 234 va_list args; 235 236 unsigned long flags; 237 u32 reg; 238 239 va_start(args, channel); 240 241 spin_lock_irqsave(&card->lock, flags); 242 while ((reg = va_arg(args, u32)) != TAGLIST_END) { 243 u32 data = va_arg(args, u32); 244 u32 regptr = (((reg << 16) & PTR_ADDRESS_MASK) 245 | (channel & PTR_CHANNELNUM_MASK)); 246 outl(regptr, card->iobase + PTR); 247 if (reg & 0xff000000) { 248 int size = (reg >> 24) & 0x3f; 249 int offset = (reg >> 16) & 0x1f; 250 u32 mask = ((1 << size) - 1) << offset; 251 data = (data << offset) & mask; 252 253 data |= inl(card->iobase + DATA) & ~mask; 254 } 255 outl(data, card->iobase + DATA); 256 } 257 spin_unlock_irqrestore(&card->lock, flags); 258 259 va_end(args); 260 261 return; 262} 263 264u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel) 265{ 266 u32 regptr, val; 267 unsigned long flags; 268 269 regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK); 270 271 if (reg & 0xff000000) { 272 u32 mask; 273 u8 size, offset; 274 275 size = (reg >> 24) & 0x3f; 276 offset = (reg >> 16) & 0x1f; 277 mask = ((1 << size) - 1) << offset; 278 279 spin_lock_irqsave(&card->lock, flags); 280 outl(regptr, card->iobase + PTR); 281 val = inl(card->iobase + DATA); 282 spin_unlock_irqrestore(&card->lock, flags); 283 284 return (val & mask) >> offset; 285 } else { 286 spin_lock_irqsave(&card->lock, flags); 287 outl(regptr, card->iobase + PTR); 288 val = inl(card->iobase + DATA); 289 spin_unlock_irqrestore(&card->lock, flags); 290 291 return val; 292 } 293} 294 295void emu10k1_irq_enable(struct emu10k1_card *card, u32 irq_mask) 296{ 297 u32 val; 298 unsigned long flags; 299 300 DPF(2,"emu10k1_irq_enable()\n"); 301 302 spin_lock_irqsave(&card->lock, flags); 303 val = inl(card->iobase + INTE) | irq_mask; 304 outl(val, card->iobase + INTE); 305 spin_unlock_irqrestore(&card->lock, flags); 306 return; 307} 308 309void emu10k1_irq_disable(struct emu10k1_card *card, u32 irq_mask) 310{ 311 u32 val; 312 unsigned long flags; 313 314 DPF(2,"emu10k1_irq_disable()\n"); 315 316 spin_lock_irqsave(&card->lock, flags); 317 val = inl(card->iobase + INTE) & ~irq_mask; 318 outl(val, card->iobase + INTE); 319 spin_unlock_irqrestore(&card->lock, flags); 320 return; 321} 322 323void emu10k1_set_stop_on_loop(struct emu10k1_card *card, u32 voicenum) 324{ 325 /* Voice interrupt */ 326 if (voicenum >= 32) 327 sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 1); 328 else 329 sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 1); 330 331 return; 332} 333 334void emu10k1_clear_stop_on_loop(struct emu10k1_card *card, u32 voicenum) 335{ 336 /* Voice interrupt */ 337 if (voicenum >= 32) 338 sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0); 339 else 340 sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 0); 341 342 return; 343} 344 345static void sblive_wcwait(struct emu10k1_card *card, u32 wait) 346{ 347 volatile unsigned uCount; 348 u32 newtime = 0, curtime; 349 350 curtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER); 351 while (wait--) { 352 uCount = 0; 353 while (uCount++ < TIMEOUT) { 354 newtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER); 355 if (newtime != curtime) 356 break; 357 } 358 359 if (uCount >= TIMEOUT) 360 break; 361 362 curtime = newtime; 363 } 364} 365 366u16 emu10k1_ac97_read(struct ac97_codec *codec, u8 reg) 367{ 368 struct emu10k1_card *card = codec->private_data; 369 u16 data; 370 unsigned long flags; 371 372 spin_lock_irqsave(&card->lock, flags); 373 374 outb(reg, card->iobase + AC97ADDRESS); 375 data = inw(card->iobase + AC97DATA); 376 377 spin_unlock_irqrestore(&card->lock, flags); 378 379 return data; 380} 381 382void emu10k1_ac97_write(struct ac97_codec *codec, u8 reg, u16 value) 383{ 384 struct emu10k1_card *card = codec->private_data; 385 unsigned long flags; 386 387 spin_lock_irqsave(&card->lock, flags); 388 389 outb(reg, card->iobase + AC97ADDRESS); 390 outw(value, card->iobase + AC97DATA); 391 392 spin_unlock_irqrestore(&card->lock, flags); 393} 394 395/********************************************************* 396* MPU access functions * 397**********************************************************/ 398 399int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data) 400{ 401 unsigned long flags; 402 int ret; 403 404 spin_lock_irqsave(&card->lock, flags); 405 406 if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) { 407 outb(data, card->iobase + MUDATA); 408 ret = 0; 409 } else 410 ret = -1; 411 412 spin_unlock_irqrestore(&card->lock, flags); 413 414 return ret; 415} 416 417int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data) 418{ 419 unsigned long flags; 420 int ret; 421 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 return ret; 433} 434 435int emu10k1_mpu_reset(struct emu10k1_card *card) 436{ 437 u8 status; 438 unsigned long flags; 439 440 DPF(2, "emu10k1_mpu_reset()\n"); 441 442 if (card->mpuacqcount == 0) { 443 spin_lock_irqsave(&card->lock, flags); 444 outb(MUCMD_RESET, card->iobase + MUCMD); 445 spin_unlock_irqrestore(&card->lock, flags); 446 447 sblive_wcwait(card, 8); 448 449 spin_lock_irqsave(&card->lock, flags); 450 outb(MUCMD_RESET, card->iobase + MUCMD); 451 spin_unlock_irqrestore(&card->lock, flags); 452 453 sblive_wcwait(card, 8); 454 455 spin_lock_irqsave(&card->lock, flags); 456 outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD); 457 spin_unlock_irqrestore(&card->lock, flags); 458 459 sblive_wcwait(card, 8); 460 461 spin_lock_irqsave(&card->lock, flags); 462 status = inb(card->iobase + MUDATA); 463 spin_unlock_irqrestore(&card->lock, flags); 464 465 if (status == 0xfe) 466 return 0; 467 else 468 return -1; 469 } 470 471 return 0; 472} 473 474int emu10k1_mpu_acquire(struct emu10k1_card *card) 475{ 476 ++card->mpuacqcount; 477 478 return 0; 479} 480 481int emu10k1_mpu_release(struct emu10k1_card *card) 482{ 483 --card->mpuacqcount; 484 485 return 0; 486} 487