dmasound_paula.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. /*
  2. * linux/sound/oss/dmasound/dmasound_paula.c
  3. *
  4. * Amiga `Paula' DMA Sound Driver
  5. *
  6. * See linux/sound/oss/dmasound/dmasound_core.c for copyright and credits
  7. * prior to 28/01/2001
  8. *
  9. * 28/01/2001 [0.1] Iain Sandoe
  10. * - added versioning
  11. * - put in and populated the hardware_afmts field.
  12. * [0.2] - put in SNDCTL_DSP_GETCAPS value.
  13. * [0.3] - put in constraint on state buffer usage.
  14. * [0.4] - put in default hard/soft settings
  15. */
  16. #include <linux/module.h>
  17. #include <linux/mm.h>
  18. #include <linux/init.h>
  19. #include <linux/ioport.h>
  20. #include <linux/soundcard.h>
  21. #include <linux/interrupt.h>
  22. #include <asm/uaccess.h>
  23. #include <asm/setup.h>
  24. #include <asm/amigahw.h>
  25. #include <asm/amigaints.h>
  26. #include <asm/machdep.h>
  27. #include "dmasound.h"
  28. #define DMASOUND_PAULA_REVISION 0
  29. #define DMASOUND_PAULA_EDITION 4
  30. #define custom amiga_custom
  31. /*
  32. * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
  33. * (Imported from arch/m68k/amiga/amisound.c)
  34. */
  35. extern volatile u_short amiga_audio_min_period;
  36. /*
  37. * amiga_mksound() should be able to restore the period after beeping
  38. * (Imported from arch/m68k/amiga/amisound.c)
  39. */
  40. extern u_short amiga_audio_period;
  41. /*
  42. * Audio DMA masks
  43. */
  44. #define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)
  45. #define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)
  46. #define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)
  47. /*
  48. * Helper pointers for 16(14)-bit sound
  49. */
  50. static int write_sq_block_size_half, write_sq_block_size_quarter;
  51. /*** Low level stuff *********************************************************/
  52. static void *AmiAlloc(unsigned int size, gfp_t flags);
  53. static void AmiFree(void *obj, unsigned int size);
  54. static int AmiIrqInit(void);
  55. #ifdef MODULE
  56. static void AmiIrqCleanUp(void);
  57. #endif
  58. static void AmiSilence(void);
  59. static void AmiInit(void);
  60. static int AmiSetFormat(int format);
  61. static int AmiSetVolume(int volume);
  62. static int AmiSetTreble(int treble);
  63. static void AmiPlayNextFrame(int index);
  64. static void AmiPlay(void);
  65. static irqreturn_t AmiInterrupt(int irq, void *dummy);
  66. #ifdef CONFIG_HEARTBEAT
  67. /*
  68. * Heartbeat interferes with sound since the 7 kHz low-pass filter and the
  69. * power LED are controlled by the same line.
  70. */
  71. static void (*saved_heartbeat)(int) = NULL;
  72. static inline void disable_heartbeat(void)
  73. {
  74. if (mach_heartbeat) {
  75. saved_heartbeat = mach_heartbeat;
  76. mach_heartbeat = NULL;
  77. }
  78. AmiSetTreble(dmasound.treble);
  79. }
  80. static inline void enable_heartbeat(void)
  81. {
  82. if (saved_heartbeat)
  83. mach_heartbeat = saved_heartbeat;
  84. }
  85. #else /* !CONFIG_HEARTBEAT */
  86. #define disable_heartbeat() do { } while (0)
  87. #define enable_heartbeat() do { } while (0)
  88. #endif /* !CONFIG_HEARTBEAT */
  89. /*** Mid level stuff *********************************************************/
  90. static void AmiMixerInit(void);
  91. static int AmiMixerIoctl(u_int cmd, u_long arg);
  92. static int AmiWriteSqSetup(void);
  93. static int AmiStateInfo(char *buffer, size_t space);
  94. /*** Translations ************************************************************/
  95. /* ++TeSche: radically changed for new expanding purposes...
  96. *
  97. * These two routines now deal with copying/expanding/translating the samples
  98. * from user space into our buffer at the right frequency. They take care about
  99. * how much data there's actually to read, how much buffer space there is and
  100. * to convert samples into the right frequency/encoding. They will only work on
  101. * complete samples so it may happen they leave some bytes in the input stream
  102. * if the user didn't write a multiple of the current sample size. They both
  103. * return the number of bytes they've used from both streams so you may detect
  104. * such a situation. Luckily all programs should be able to cope with that.
  105. *
  106. * I think I've optimized anything as far as one can do in plain C, all
  107. * variables should fit in registers and the loops are really short. There's
  108. * one loop for every possible situation. Writing a more generalized and thus
  109. * parameterized loop would only produce slower code. Feel free to optimize
  110. * this in assembler if you like. :)
  111. *
  112. * I think these routines belong here because they're not yet really hardware
  113. * independent, especially the fact that the Falcon can play 16bit samples
  114. * only in stereo is hardcoded in both of them!
  115. *
  116. * ++geert: split in even more functions (one per format)
  117. */
  118. /*
  119. * Native format
  120. */
  121. static ssize_t ami_ct_s8(const u_char __user *userPtr, size_t userCount,
  122. u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
  123. {
  124. ssize_t count, used;
  125. if (!dmasound.soft.stereo) {
  126. void *p = &frame[*frameUsed];
  127. count = min_t(unsigned long, userCount, frameLeft) & ~1;
  128. used = count;
  129. if (copy_from_user(p, userPtr, count))
  130. return -EFAULT;
  131. } else {
  132. u_char *left = &frame[*frameUsed>>1];
  133. u_char *right = left+write_sq_block_size_half;
  134. count = min_t(unsigned long, userCount, frameLeft)>>1 & ~1;
  135. used = count*2;
  136. while (count > 0) {
  137. if (get_user(*left++, userPtr++)
  138. || get_user(*right++, userPtr++))
  139. return -EFAULT;
  140. count--;
  141. }
  142. }
  143. *frameUsed += used;
  144. return used;
  145. }
  146. /*
  147. * Copy and convert 8 bit data
  148. */
  149. #define GENERATE_AMI_CT8(funcname, convsample) \
  150. static ssize_t funcname(const u_char __user *userPtr, size_t userCount, \
  151. u_char frame[], ssize_t *frameUsed, \
  152. ssize_t frameLeft) \
  153. { \
  154. ssize_t count, used; \
  155. \
  156. if (!dmasound.soft.stereo) { \
  157. u_char *p = &frame[*frameUsed]; \
  158. count = min_t(size_t, userCount, frameLeft) & ~1; \
  159. used = count; \
  160. while (count > 0) { \
  161. u_char data; \
  162. if (get_user(data, userPtr++)) \
  163. return -EFAULT; \
  164. *p++ = convsample(data); \
  165. count--; \
  166. } \
  167. } else { \
  168. u_char *left = &frame[*frameUsed>>1]; \
  169. u_char *right = left+write_sq_block_size_half; \
  170. count = min_t(size_t, userCount, frameLeft)>>1 & ~1; \
  171. used = count*2; \
  172. while (count > 0) { \
  173. u_char data; \
  174. if (get_user(data, userPtr++)) \
  175. return -EFAULT; \
  176. *left++ = convsample(data); \
  177. if (get_user(data, userPtr++)) \
  178. return -EFAULT; \
  179. *right++ = convsample(data); \
  180. count--; \
  181. } \
  182. } \
  183. *frameUsed += used; \
  184. return used; \
  185. }
  186. #define AMI_CT_ULAW(x) (dmasound_ulaw2dma8[(x)])
  187. #define AMI_CT_ALAW(x) (dmasound_alaw2dma8[(x)])
  188. #define AMI_CT_U8(x) ((x) ^ 0x80)
  189. GENERATE_AMI_CT8(ami_ct_ulaw, AMI_CT_ULAW)
  190. GENERATE_AMI_CT8(ami_ct_alaw, AMI_CT_ALAW)
  191. GENERATE_AMI_CT8(ami_ct_u8, AMI_CT_U8)
  192. /*
  193. * Copy and convert 16 bit data
  194. */
  195. #define GENERATE_AMI_CT_16(funcname, convsample) \
  196. static ssize_t funcname(const u_char __user *userPtr, size_t userCount, \
  197. u_char frame[], ssize_t *frameUsed, \
  198. ssize_t frameLeft) \
  199. { \
  200. const u_short __user *ptr = (const u_short __user *)userPtr; \
  201. ssize_t count, used; \
  202. u_short data; \
  203. \
  204. if (!dmasound.soft.stereo) { \
  205. u_char *high = &frame[*frameUsed>>1]; \
  206. u_char *low = high+write_sq_block_size_half; \
  207. count = min_t(size_t, userCount, frameLeft)>>1 & ~1; \
  208. used = count*2; \
  209. while (count > 0) { \
  210. if (get_user(data, ptr++)) \
  211. return -EFAULT; \
  212. data = convsample(data); \
  213. *high++ = data>>8; \
  214. *low++ = (data>>2) & 0x3f; \
  215. count--; \
  216. } \
  217. } else { \
  218. u_char *lefth = &frame[*frameUsed>>2]; \
  219. u_char *leftl = lefth+write_sq_block_size_quarter; \
  220. u_char *righth = lefth+write_sq_block_size_half; \
  221. u_char *rightl = righth+write_sq_block_size_quarter; \
  222. count = min_t(size_t, userCount, frameLeft)>>2 & ~1; \
  223. used = count*4; \
  224. while (count > 0) { \
  225. if (get_user(data, ptr++)) \
  226. return -EFAULT; \
  227. data = convsample(data); \
  228. *lefth++ = data>>8; \
  229. *leftl++ = (data>>2) & 0x3f; \
  230. if (get_user(data, ptr++)) \
  231. return -EFAULT; \
  232. data = convsample(data); \
  233. *righth++ = data>>8; \
  234. *rightl++ = (data>>2) & 0x3f; \
  235. count--; \
  236. } \
  237. } \
  238. *frameUsed += used; \
  239. return used; \
  240. }
  241. #define AMI_CT_S16BE(x) (x)
  242. #define AMI_CT_U16BE(x) ((x) ^ 0x8000)
  243. #define AMI_CT_S16LE(x) (le2be16((x)))
  244. #define AMI_CT_U16LE(x) (le2be16((x)) ^ 0x8000)
  245. GENERATE_AMI_CT_16(ami_ct_s16be, AMI_CT_S16BE)
  246. GENERATE_AMI_CT_16(ami_ct_u16be, AMI_CT_U16BE)
  247. GENERATE_AMI_CT_16(ami_ct_s16le, AMI_CT_S16LE)
  248. GENERATE_AMI_CT_16(ami_ct_u16le, AMI_CT_U16LE)
  249. static TRANS transAmiga = {
  250. .ct_ulaw = ami_ct_ulaw,
  251. .ct_alaw = ami_ct_alaw,
  252. .ct_s8 = ami_ct_s8,
  253. .ct_u8 = ami_ct_u8,
  254. .ct_s16be = ami_ct_s16be,
  255. .ct_u16be = ami_ct_u16be,
  256. .ct_s16le = ami_ct_s16le,
  257. .ct_u16le = ami_ct_u16le,
  258. };
  259. /*** Low level stuff *********************************************************/
  260. static inline void StopDMA(void)
  261. {
  262. custom.aud[0].audvol = custom.aud[1].audvol = 0;
  263. custom.aud[2].audvol = custom.aud[3].audvol = 0;
  264. custom.dmacon = AMI_AUDIO_OFF;
  265. enable_heartbeat();
  266. }
  267. static void *AmiAlloc(unsigned int size, gfp_t flags)
  268. {
  269. return amiga_chip_alloc((long)size, "dmasound [Paula]");
  270. }
  271. static void AmiFree(void *obj, unsigned int size)
  272. {
  273. amiga_chip_free (obj);
  274. }
  275. static int __init AmiIrqInit(void)
  276. {
  277. /* turn off DMA for audio channels */
  278. StopDMA();
  279. /* Register interrupt handler. */
  280. if (request_irq(IRQ_AMIGA_AUD0, AmiInterrupt, 0, "DMA sound",
  281. AmiInterrupt))
  282. return 0;
  283. return 1;
  284. }
  285. #ifdef MODULE
  286. static void AmiIrqCleanUp(void)
  287. {
  288. /* turn off DMA for audio channels */
  289. StopDMA();
  290. /* release the interrupt */
  291. free_irq(IRQ_AMIGA_AUD0, AmiInterrupt);
  292. }
  293. #endif /* MODULE */
  294. static void AmiSilence(void)
  295. {
  296. /* turn off DMA for audio channels */
  297. StopDMA();
  298. }
  299. static void AmiInit(void)
  300. {
  301. int period, i;
  302. AmiSilence();
  303. if (dmasound.soft.speed)
  304. period = amiga_colorclock/dmasound.soft.speed-1;
  305. else
  306. period = amiga_audio_min_period;
  307. dmasound.hard = dmasound.soft;
  308. dmasound.trans_write = &transAmiga;
  309. if (period < amiga_audio_min_period) {
  310. /* we would need to squeeze the sound, but we won't do that */
  311. period = amiga_audio_min_period;
  312. } else if (period > 65535) {
  313. period = 65535;
  314. }
  315. dmasound.hard.speed = amiga_colorclock/(period+1);
  316. for (i = 0; i < 4; i++)
  317. custom.aud[i].audper = period;
  318. amiga_audio_period = period;
  319. }
  320. static int AmiSetFormat(int format)
  321. {
  322. int size;
  323. /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
  324. switch (format) {
  325. case AFMT_QUERY:
  326. return dmasound.soft.format;
  327. case AFMT_MU_LAW:
  328. case AFMT_A_LAW:
  329. case AFMT_U8:
  330. case AFMT_S8:
  331. size = 8;
  332. break;
  333. case AFMT_S16_BE:
  334. case AFMT_U16_BE:
  335. case AFMT_S16_LE:
  336. case AFMT_U16_LE:
  337. size = 16;
  338. break;
  339. default: /* :-) */
  340. size = 8;
  341. format = AFMT_S8;
  342. }
  343. dmasound.soft.format = format;
  344. dmasound.soft.size = size;
  345. if (dmasound.minDev == SND_DEV_DSP) {
  346. dmasound.dsp.format = format;
  347. dmasound.dsp.size = dmasound.soft.size;
  348. }
  349. AmiInit();
  350. return format;
  351. }
  352. #define VOLUME_VOXWARE_TO_AMI(v) \
  353. (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
  354. #define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
  355. static int AmiSetVolume(int volume)
  356. {
  357. dmasound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
  358. custom.aud[0].audvol = dmasound.volume_left;
  359. dmasound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
  360. custom.aud[1].audvol = dmasound.volume_right;
  361. if (dmasound.hard.size == 16) {
  362. if (dmasound.volume_left == 64 && dmasound.volume_right == 64) {
  363. custom.aud[2].audvol = 1;
  364. custom.aud[3].audvol = 1;
  365. } else {
  366. custom.aud[2].audvol = 0;
  367. custom.aud[3].audvol = 0;
  368. }
  369. }
  370. return VOLUME_AMI_TO_VOXWARE(dmasound.volume_left) |
  371. (VOLUME_AMI_TO_VOXWARE(dmasound.volume_right) << 8);
  372. }
  373. static int AmiSetTreble(int treble)
  374. {
  375. dmasound.treble = treble;
  376. if (treble < 50)
  377. ciaa.pra &= ~0x02;
  378. else
  379. ciaa.pra |= 0x02;
  380. return treble;
  381. }
  382. #define AMI_PLAY_LOADED 1
  383. #define AMI_PLAY_PLAYING 2
  384. #define AMI_PLAY_MASK 3
  385. static void AmiPlayNextFrame(int index)
  386. {
  387. u_char *start, *ch0, *ch1, *ch2, *ch3;
  388. u_long size;
  389. /* used by AmiPlay() if all doubts whether there really is something
  390. * to be played are already wiped out.
  391. */
  392. start = write_sq.buffers[write_sq.front];
  393. size = (write_sq.count == index ? write_sq.rear_size
  394. : write_sq.block_size)>>1;
  395. if (dmasound.hard.stereo) {
  396. ch0 = start;
  397. ch1 = start+write_sq_block_size_half;
  398. size >>= 1;
  399. } else {
  400. ch0 = start;
  401. ch1 = start;
  402. }
  403. disable_heartbeat();
  404. custom.aud[0].audvol = dmasound.volume_left;
  405. custom.aud[1].audvol = dmasound.volume_right;
  406. if (dmasound.hard.size == 8) {
  407. custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
  408. custom.aud[0].audlen = size;
  409. custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
  410. custom.aud[1].audlen = size;
  411. custom.dmacon = AMI_AUDIO_8;
  412. } else {
  413. size >>= 1;
  414. custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
  415. custom.aud[0].audlen = size;
  416. custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
  417. custom.aud[1].audlen = size;
  418. if (dmasound.volume_left == 64 && dmasound.volume_right == 64) {
  419. /* We can play pseudo 14-bit only with the maximum volume */
  420. ch3 = ch0+write_sq_block_size_quarter;
  421. ch2 = ch1+write_sq_block_size_quarter;
  422. custom.aud[2].audvol = 1; /* we are being affected by the beeps */
  423. custom.aud[3].audvol = 1; /* restoring volume here helps a bit */
  424. custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
  425. custom.aud[2].audlen = size;
  426. custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
  427. custom.aud[3].audlen = size;
  428. custom.dmacon = AMI_AUDIO_14;
  429. } else {
  430. custom.aud[2].audvol = 0;
  431. custom.aud[3].audvol = 0;
  432. custom.dmacon = AMI_AUDIO_8;
  433. }
  434. }
  435. write_sq.front = (write_sq.front+1) % write_sq.max_count;
  436. write_sq.active |= AMI_PLAY_LOADED;
  437. }
  438. static void AmiPlay(void)
  439. {
  440. int minframes = 1;
  441. custom.intena = IF_AUD0;
  442. if (write_sq.active & AMI_PLAY_LOADED) {
  443. /* There's already a frame loaded */
  444. custom.intena = IF_SETCLR | IF_AUD0;
  445. return;
  446. }
  447. if (write_sq.active & AMI_PLAY_PLAYING)
  448. /* Increase threshold: frame 1 is already being played */
  449. minframes = 2;
  450. if (write_sq.count < minframes) {
  451. /* Nothing to do */
  452. custom.intena = IF_SETCLR | IF_AUD0;
  453. return;
  454. }
  455. if (write_sq.count <= minframes &&
  456. write_sq.rear_size < write_sq.block_size && !write_sq.syncing) {
  457. /* hmmm, the only existing frame is not
  458. * yet filled and we're not syncing?
  459. */
  460. custom.intena = IF_SETCLR | IF_AUD0;
  461. return;
  462. }
  463. AmiPlayNextFrame(minframes);
  464. custom.intena = IF_SETCLR | IF_AUD0;
  465. }
  466. static irqreturn_t AmiInterrupt(int irq, void *dummy)
  467. {
  468. int minframes = 1;
  469. custom.intena = IF_AUD0;
  470. if (!write_sq.active) {
  471. /* Playing was interrupted and sq_reset() has already cleared
  472. * the sq variables, so better don't do anything here.
  473. */
  474. WAKE_UP(write_sq.sync_queue);
  475. return IRQ_HANDLED;
  476. }
  477. if (write_sq.active & AMI_PLAY_PLAYING) {
  478. /* We've just finished a frame */
  479. write_sq.count--;
  480. WAKE_UP(write_sq.action_queue);
  481. }
  482. if (write_sq.active & AMI_PLAY_LOADED)
  483. /* Increase threshold: frame 1 is already being played */
  484. minframes = 2;
  485. /* Shift the flags */
  486. write_sq.active = (write_sq.active<<1) & AMI_PLAY_MASK;
  487. if (!write_sq.active)
  488. /* No frame is playing, disable audio DMA */
  489. StopDMA();
  490. custom.intena = IF_SETCLR | IF_AUD0;
  491. if (write_sq.count >= minframes)
  492. /* Try to play the next frame */
  493. AmiPlay();
  494. if (!write_sq.active)
  495. /* Nothing to play anymore.
  496. Wake up a process waiting for audio output to drain. */
  497. WAKE_UP(write_sq.sync_queue);
  498. return IRQ_HANDLED;
  499. }
  500. /*** Mid level stuff *********************************************************/
  501. /*
  502. * /dev/mixer abstraction
  503. */
  504. static void __init AmiMixerInit(void)
  505. {
  506. dmasound.volume_left = 64;
  507. dmasound.volume_right = 64;
  508. custom.aud[0].audvol = dmasound.volume_left;
  509. custom.aud[3].audvol = 1; /* For pseudo 14bit */
  510. custom.aud[1].audvol = dmasound.volume_right;
  511. custom.aud[2].audvol = 1; /* For pseudo 14bit */
  512. dmasound.treble = 50;
  513. }
  514. static int AmiMixerIoctl(u_int cmd, u_long arg)
  515. {
  516. int data;
  517. switch (cmd) {
  518. case SOUND_MIXER_READ_DEVMASK:
  519. return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE);
  520. case SOUND_MIXER_READ_RECMASK:
  521. return IOCTL_OUT(arg, 0);
  522. case SOUND_MIXER_READ_STEREODEVS:
  523. return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
  524. case SOUND_MIXER_READ_VOLUME:
  525. return IOCTL_OUT(arg,
  526. VOLUME_AMI_TO_VOXWARE(dmasound.volume_left) |
  527. VOLUME_AMI_TO_VOXWARE(dmasound.volume_right) << 8);
  528. case SOUND_MIXER_WRITE_VOLUME:
  529. IOCTL_IN(arg, data);
  530. return IOCTL_OUT(arg, dmasound_set_volume(data));
  531. case SOUND_MIXER_READ_TREBLE:
  532. return IOCTL_OUT(arg, dmasound.treble);
  533. case SOUND_MIXER_WRITE_TREBLE:
  534. IOCTL_IN(arg, data);
  535. return IOCTL_OUT(arg, dmasound_set_treble(data));
  536. }
  537. return -EINVAL;
  538. }
  539. static int AmiWriteSqSetup(void)
  540. {
  541. write_sq_block_size_half = write_sq.block_size>>1;
  542. write_sq_block_size_quarter = write_sq_block_size_half>>1;
  543. return 0;
  544. }
  545. static int AmiStateInfo(char *buffer, size_t space)
  546. {
  547. int len = 0;
  548. len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
  549. dmasound.volume_left);
  550. len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
  551. dmasound.volume_right);
  552. if (len >= space) {
  553. printk(KERN_ERR "dmasound_paula: overlowed state buffer alloc.\n") ;
  554. len = space ;
  555. }
  556. return len;
  557. }
  558. /*** Machine definitions *****************************************************/
  559. static SETTINGS def_hard = {
  560. .format = AFMT_S8,
  561. .stereo = 0,
  562. .size = 8,
  563. .speed = 8000
  564. } ;
  565. static SETTINGS def_soft = {
  566. .format = AFMT_U8,
  567. .stereo = 0,
  568. .size = 8,
  569. .speed = 8000
  570. } ;
  571. static MACHINE machAmiga = {
  572. .name = "Amiga",
  573. .name2 = "AMIGA",
  574. .owner = THIS_MODULE,
  575. .dma_alloc = AmiAlloc,
  576. .dma_free = AmiFree,
  577. .irqinit = AmiIrqInit,
  578. #ifdef MODULE
  579. .irqcleanup = AmiIrqCleanUp,
  580. #endif /* MODULE */
  581. .init = AmiInit,
  582. .silence = AmiSilence,
  583. .setFormat = AmiSetFormat,
  584. .setVolume = AmiSetVolume,
  585. .setTreble = AmiSetTreble,
  586. .play = AmiPlay,
  587. .mixer_init = AmiMixerInit,
  588. .mixer_ioctl = AmiMixerIoctl,
  589. .write_sq_setup = AmiWriteSqSetup,
  590. .state_info = AmiStateInfo,
  591. .min_dsp_speed = 8000,
  592. .version = ((DMASOUND_PAULA_REVISION<<8) | DMASOUND_PAULA_EDITION),
  593. .hardware_afmts = (AFMT_S8 | AFMT_S16_BE), /* h'ware-supported formats *only* here */
  594. .capabilities = DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */
  595. };
  596. /*** Config & Setup **********************************************************/
  597. static int __init dmasound_paula_init(void)
  598. {
  599. int err;
  600. if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_AUDIO)) {
  601. if (!request_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40,
  602. "dmasound [Paula]"))
  603. return -EBUSY;
  604. dmasound.mach = machAmiga;
  605. dmasound.mach.default_hard = def_hard ;
  606. dmasound.mach.default_soft = def_soft ;
  607. err = dmasound_init();
  608. if (err)
  609. release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
  610. return err;
  611. } else
  612. return -ENODEV;
  613. }
  614. static void __exit dmasound_paula_cleanup(void)
  615. {
  616. dmasound_deinit();
  617. release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
  618. }
  619. module_init(dmasound_paula_init);
  620. module_exit(dmasound_paula_cleanup);
  621. MODULE_LICENSE("GPL");