hwaccess.c 14 KB

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