2 * linux/sound/oss/dmasound/dmasound_paula.c
4 * Amiga `Paula' DMA Sound Driver
6 * See linux/sound/oss/dmasound/dmasound_core.c for copyright and credits
9 * 28/01/2001 [0.1] Iain Sandoe
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
18 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/ioport.h>
22 #include <linux/soundcard.h>
23 #include <linux/interrupt.h>
25 #include <asm/uaccess.h>
26 #include <asm/setup.h>
27 #include <asm/amigahw.h>
28 #include <asm/amigaints.h>
29 #include <asm/machdep.h>
33 #define DMASOUND_PAULA_REVISION 0
34 #define DMASOUND_PAULA_EDITION 4
36 #define custom amiga_custom
38 * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
39 * (Imported from arch/m68k/amiga/amisound.c)
42 extern volatile u_short amiga_audio_min_period
;
46 * amiga_mksound() should be able to restore the period after beeping
47 * (Imported from arch/m68k/amiga/amisound.c)
50 extern u_short amiga_audio_period
;
57 #define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)
58 #define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)
59 #define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)
63 * Helper pointers for 16(14)-bit sound
66 static int write_sq_block_size_half
, write_sq_block_size_quarter
;
69 /*** Low level stuff *********************************************************/
72 static void *AmiAlloc(unsigned int size
, gfp_t flags
);
73 static void AmiFree(void *obj
, unsigned int size
);
74 static int AmiIrqInit(void);
76 static void AmiIrqCleanUp(void);
78 static void AmiSilence(void);
79 static void AmiInit(void);
80 static int AmiSetFormat(int format
);
81 static int AmiSetVolume(int volume
);
82 static int AmiSetTreble(int treble
);
83 static void AmiPlayNextFrame(int index
);
84 static void AmiPlay(void);
85 static irqreturn_t
AmiInterrupt(int irq
, void *dummy
);
87 #ifdef CONFIG_HEARTBEAT
90 * Heartbeat interferes with sound since the 7 kHz low-pass filter and the
91 * power LED are controlled by the same line.
94 static void (*saved_heartbeat
)(int) = NULL
;
96 static inline void disable_heartbeat(void)
99 saved_heartbeat
= mach_heartbeat
;
100 mach_heartbeat
= NULL
;
102 AmiSetTreble(dmasound
.treble
);
105 static inline void enable_heartbeat(void)
108 mach_heartbeat
= saved_heartbeat
;
110 #else /* !CONFIG_HEARTBEAT */
111 #define disable_heartbeat() do { } while (0)
112 #define enable_heartbeat() do { } while (0)
113 #endif /* !CONFIG_HEARTBEAT */
116 /*** Mid level stuff *********************************************************/
118 static void AmiMixerInit(void);
119 static int AmiMixerIoctl(u_int cmd
, u_long arg
);
120 static int AmiWriteSqSetup(void);
121 static int AmiStateInfo(char *buffer
, size_t space
);
124 /*** Translations ************************************************************/
126 /* ++TeSche: radically changed for new expanding purposes...
128 * These two routines now deal with copying/expanding/translating the samples
129 * from user space into our buffer at the right frequency. They take care about
130 * how much data there's actually to read, how much buffer space there is and
131 * to convert samples into the right frequency/encoding. They will only work on
132 * complete samples so it may happen they leave some bytes in the input stream
133 * if the user didn't write a multiple of the current sample size. They both
134 * return the number of bytes they've used from both streams so you may detect
135 * such a situation. Luckily all programs should be able to cope with that.
137 * I think I've optimized anything as far as one can do in plain C, all
138 * variables should fit in registers and the loops are really short. There's
139 * one loop for every possible situation. Writing a more generalized and thus
140 * parameterized loop would only produce slower code. Feel free to optimize
141 * this in assembler if you like. :)
143 * I think these routines belong here because they're not yet really hardware
144 * independent, especially the fact that the Falcon can play 16bit samples
145 * only in stereo is hardcoded in both of them!
147 * ++geert: split in even more functions (one per format)
155 static ssize_t
ami_ct_s8(const u_char __user
*userPtr
, size_t userCount
,
156 u_char frame
[], ssize_t
*frameUsed
, ssize_t frameLeft
)
160 if (!dmasound
.soft
.stereo
) {
161 void *p
= &frame
[*frameUsed
];
162 count
= min_t(unsigned long, userCount
, frameLeft
) & ~1;
164 if (copy_from_user(p
, userPtr
, count
))
167 u_char
*left
= &frame
[*frameUsed
>>1];
168 u_char
*right
= left
+write_sq_block_size_half
;
169 count
= min_t(unsigned long, userCount
, frameLeft
)>>1 & ~1;
172 if (get_user(*left
++, userPtr
++)
173 || get_user(*right
++, userPtr
++))
184 * Copy and convert 8 bit data
187 #define GENERATE_AMI_CT8(funcname, convsample) \
188 static ssize_t funcname(const u_char __user *userPtr, size_t userCount, \
189 u_char frame[], ssize_t *frameUsed, \
192 ssize_t count, used; \
194 if (!dmasound.soft.stereo) { \
195 u_char *p = &frame[*frameUsed]; \
196 count = min_t(size_t, userCount, frameLeft) & ~1; \
198 while (count > 0) { \
200 if (get_user(data, userPtr++)) \
202 *p++ = convsample(data); \
206 u_char *left = &frame[*frameUsed>>1]; \
207 u_char *right = left+write_sq_block_size_half; \
208 count = min_t(size_t, userCount, frameLeft)>>1 & ~1; \
210 while (count > 0) { \
212 if (get_user(data, userPtr++)) \
214 *left++ = convsample(data); \
215 if (get_user(data, userPtr++)) \
217 *right++ = convsample(data); \
221 *frameUsed += used; \
225 #define AMI_CT_ULAW(x) (dmasound_ulaw2dma8[(x)])
226 #define AMI_CT_ALAW(x) (dmasound_alaw2dma8[(x)])
227 #define AMI_CT_U8(x) ((x) ^ 0x80)
229 GENERATE_AMI_CT8(ami_ct_ulaw
, AMI_CT_ULAW
)
230 GENERATE_AMI_CT8(ami_ct_alaw
, AMI_CT_ALAW
)
231 GENERATE_AMI_CT8(ami_ct_u8
, AMI_CT_U8
)
235 * Copy and convert 16 bit data
238 #define GENERATE_AMI_CT_16(funcname, convsample) \
239 static ssize_t funcname(const u_char __user *userPtr, size_t userCount, \
240 u_char frame[], ssize_t *frameUsed, \
243 const u_short __user *ptr = (const u_short __user *)userPtr; \
244 ssize_t count, used; \
247 if (!dmasound.soft.stereo) { \
248 u_char *high = &frame[*frameUsed>>1]; \
249 u_char *low = high+write_sq_block_size_half; \
250 count = min_t(size_t, userCount, frameLeft)>>1 & ~1; \
252 while (count > 0) { \
253 if (get_user(data, ptr++)) \
255 data = convsample(data); \
257 *low++ = (data>>2) & 0x3f; \
261 u_char *lefth = &frame[*frameUsed>>2]; \
262 u_char *leftl = lefth+write_sq_block_size_quarter; \
263 u_char *righth = lefth+write_sq_block_size_half; \
264 u_char *rightl = righth+write_sq_block_size_quarter; \
265 count = min_t(size_t, userCount, frameLeft)>>2 & ~1; \
267 while (count > 0) { \
268 if (get_user(data, ptr++)) \
270 data = convsample(data); \
271 *lefth++ = data>>8; \
272 *leftl++ = (data>>2) & 0x3f; \
273 if (get_user(data, ptr++)) \
275 data = convsample(data); \
276 *righth++ = data>>8; \
277 *rightl++ = (data>>2) & 0x3f; \
281 *frameUsed += used; \
285 #define AMI_CT_S16BE(x) (x)
286 #define AMI_CT_U16BE(x) ((x) ^ 0x8000)
287 #define AMI_CT_S16LE(x) (le2be16((x)))
288 #define AMI_CT_U16LE(x) (le2be16((x)) ^ 0x8000)
290 GENERATE_AMI_CT_16(ami_ct_s16be
, AMI_CT_S16BE
)
291 GENERATE_AMI_CT_16(ami_ct_u16be
, AMI_CT_U16BE
)
292 GENERATE_AMI_CT_16(ami_ct_s16le
, AMI_CT_S16LE
)
293 GENERATE_AMI_CT_16(ami_ct_u16le
, AMI_CT_U16LE
)
296 static TRANS transAmiga
= {
297 .ct_ulaw
= ami_ct_ulaw
,
298 .ct_alaw
= ami_ct_alaw
,
301 .ct_s16be
= ami_ct_s16be
,
302 .ct_u16be
= ami_ct_u16be
,
303 .ct_s16le
= ami_ct_s16le
,
304 .ct_u16le
= ami_ct_u16le
,
307 /*** Low level stuff *********************************************************/
309 static inline void StopDMA(void)
311 custom
.aud
[0].audvol
= custom
.aud
[1].audvol
= 0;
312 custom
.aud
[2].audvol
= custom
.aud
[3].audvol
= 0;
313 custom
.dmacon
= AMI_AUDIO_OFF
;
317 static void *AmiAlloc(unsigned int size
, gfp_t flags
)
319 return amiga_chip_alloc((long)size
, "dmasound [Paula]");
322 static void AmiFree(void *obj
, unsigned int size
)
324 amiga_chip_free (obj
);
327 static int __init
AmiIrqInit(void)
329 /* turn off DMA for audio channels */
332 /* Register interrupt handler. */
333 if (request_irq(IRQ_AMIGA_AUD0
, AmiInterrupt
, 0, "DMA sound",
340 static void AmiIrqCleanUp(void)
342 /* turn off DMA for audio channels */
344 /* release the interrupt */
345 free_irq(IRQ_AMIGA_AUD0
, AmiInterrupt
);
349 static void AmiSilence(void)
351 /* turn off DMA for audio channels */
356 static void AmiInit(void)
362 if (dmasound
.soft
.speed
)
363 period
= amiga_colorclock
/dmasound
.soft
.speed
-1;
365 period
= amiga_audio_min_period
;
366 dmasound
.hard
= dmasound
.soft
;
367 dmasound
.trans_write
= &transAmiga
;
369 if (period
< amiga_audio_min_period
) {
370 /* we would need to squeeze the sound, but we won't do that */
371 period
= amiga_audio_min_period
;
372 } else if (period
> 65535) {
375 dmasound
.hard
.speed
= amiga_colorclock
/(period
+1);
377 for (i
= 0; i
< 4; i
++)
378 custom
.aud
[i
].audper
= period
;
379 amiga_audio_period
= period
;
383 static int AmiSetFormat(int format
)
387 /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
391 return dmasound
.soft
.format
;
409 dmasound
.soft
.format
= format
;
410 dmasound
.soft
.size
= size
;
411 if (dmasound
.minDev
== SND_DEV_DSP
) {
412 dmasound
.dsp
.format
= format
;
413 dmasound
.dsp
.size
= dmasound
.soft
.size
;
421 #define VOLUME_VOXWARE_TO_AMI(v) \
422 (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
423 #define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
425 static int AmiSetVolume(int volume
)
427 dmasound
.volume_left
= VOLUME_VOXWARE_TO_AMI(volume
& 0xff);
428 custom
.aud
[0].audvol
= dmasound
.volume_left
;
429 dmasound
.volume_right
= VOLUME_VOXWARE_TO_AMI((volume
& 0xff00) >> 8);
430 custom
.aud
[1].audvol
= dmasound
.volume_right
;
431 if (dmasound
.hard
.size
== 16) {
432 if (dmasound
.volume_left
== 64 && dmasound
.volume_right
== 64) {
433 custom
.aud
[2].audvol
= 1;
434 custom
.aud
[3].audvol
= 1;
436 custom
.aud
[2].audvol
= 0;
437 custom
.aud
[3].audvol
= 0;
440 return VOLUME_AMI_TO_VOXWARE(dmasound
.volume_left
) |
441 (VOLUME_AMI_TO_VOXWARE(dmasound
.volume_right
) << 8);
444 static int AmiSetTreble(int treble
)
446 dmasound
.treble
= treble
;
455 #define AMI_PLAY_LOADED 1
456 #define AMI_PLAY_PLAYING 2
457 #define AMI_PLAY_MASK 3
460 static void AmiPlayNextFrame(int index
)
462 u_char
*start
, *ch0
, *ch1
, *ch2
, *ch3
;
465 /* used by AmiPlay() if all doubts whether there really is something
466 * to be played are already wiped out.
468 start
= write_sq
.buffers
[write_sq
.front
];
469 size
= (write_sq
.count
== index
? write_sq
.rear_size
470 : write_sq
.block_size
)>>1;
472 if (dmasound
.hard
.stereo
) {
474 ch1
= start
+write_sq_block_size_half
;
482 custom
.aud
[0].audvol
= dmasound
.volume_left
;
483 custom
.aud
[1].audvol
= dmasound
.volume_right
;
484 if (dmasound
.hard
.size
== 8) {
485 custom
.aud
[0].audlc
= (u_short
*)ZTWO_PADDR(ch0
);
486 custom
.aud
[0].audlen
= size
;
487 custom
.aud
[1].audlc
= (u_short
*)ZTWO_PADDR(ch1
);
488 custom
.aud
[1].audlen
= size
;
489 custom
.dmacon
= AMI_AUDIO_8
;
492 custom
.aud
[0].audlc
= (u_short
*)ZTWO_PADDR(ch0
);
493 custom
.aud
[0].audlen
= size
;
494 custom
.aud
[1].audlc
= (u_short
*)ZTWO_PADDR(ch1
);
495 custom
.aud
[1].audlen
= size
;
496 if (dmasound
.volume_left
== 64 && dmasound
.volume_right
== 64) {
497 /* We can play pseudo 14-bit only with the maximum volume */
498 ch3
= ch0
+write_sq_block_size_quarter
;
499 ch2
= ch1
+write_sq_block_size_quarter
;
500 custom
.aud
[2].audvol
= 1; /* we are being affected by the beeps */
501 custom
.aud
[3].audvol
= 1; /* restoring volume here helps a bit */
502 custom
.aud
[2].audlc
= (u_short
*)ZTWO_PADDR(ch2
);
503 custom
.aud
[2].audlen
= size
;
504 custom
.aud
[3].audlc
= (u_short
*)ZTWO_PADDR(ch3
);
505 custom
.aud
[3].audlen
= size
;
506 custom
.dmacon
= AMI_AUDIO_14
;
508 custom
.aud
[2].audvol
= 0;
509 custom
.aud
[3].audvol
= 0;
510 custom
.dmacon
= AMI_AUDIO_8
;
513 write_sq
.front
= (write_sq
.front
+1) % write_sq
.max_count
;
514 write_sq
.active
|= AMI_PLAY_LOADED
;
518 static void AmiPlay(void)
522 custom
.intena
= IF_AUD0
;
524 if (write_sq
.active
& AMI_PLAY_LOADED
) {
525 /* There's already a frame loaded */
526 custom
.intena
= IF_SETCLR
| IF_AUD0
;
530 if (write_sq
.active
& AMI_PLAY_PLAYING
)
531 /* Increase threshold: frame 1 is already being played */
534 if (write_sq
.count
< minframes
) {
536 custom
.intena
= IF_SETCLR
| IF_AUD0
;
540 if (write_sq
.count
<= minframes
&&
541 write_sq
.rear_size
< write_sq
.block_size
&& !write_sq
.syncing
) {
542 /* hmmm, the only existing frame is not
543 * yet filled and we're not syncing?
545 custom
.intena
= IF_SETCLR
| IF_AUD0
;
549 AmiPlayNextFrame(minframes
);
551 custom
.intena
= IF_SETCLR
| IF_AUD0
;
555 static irqreturn_t
AmiInterrupt(int irq
, void *dummy
)
559 custom
.intena
= IF_AUD0
;
561 if (!write_sq
.active
) {
562 /* Playing was interrupted and sq_reset() has already cleared
563 * the sq variables, so better don't do anything here.
565 WAKE_UP(write_sq
.sync_queue
);
569 if (write_sq
.active
& AMI_PLAY_PLAYING
) {
570 /* We've just finished a frame */
572 WAKE_UP(write_sq
.action_queue
);
575 if (write_sq
.active
& AMI_PLAY_LOADED
)
576 /* Increase threshold: frame 1 is already being played */
579 /* Shift the flags */
580 write_sq
.active
= (write_sq
.active
<<1) & AMI_PLAY_MASK
;
582 if (!write_sq
.active
)
583 /* No frame is playing, disable audio DMA */
586 custom
.intena
= IF_SETCLR
| IF_AUD0
;
588 if (write_sq
.count
>= minframes
)
589 /* Try to play the next frame */
592 if (!write_sq
.active
)
593 /* Nothing to play anymore.
594 Wake up a process waiting for audio output to drain. */
595 WAKE_UP(write_sq
.sync_queue
);
599 /*** Mid level stuff *********************************************************/
603 * /dev/mixer abstraction
606 static void __init
AmiMixerInit(void)
608 dmasound
.volume_left
= 64;
609 dmasound
.volume_right
= 64;
610 custom
.aud
[0].audvol
= dmasound
.volume_left
;
611 custom
.aud
[3].audvol
= 1; /* For pseudo 14bit */
612 custom
.aud
[1].audvol
= dmasound
.volume_right
;
613 custom
.aud
[2].audvol
= 1; /* For pseudo 14bit */
614 dmasound
.treble
= 50;
617 static int AmiMixerIoctl(u_int cmd
, u_long arg
)
621 case SOUND_MIXER_READ_DEVMASK
:
622 return IOCTL_OUT(arg
, SOUND_MASK_VOLUME
| SOUND_MASK_TREBLE
);
623 case SOUND_MIXER_READ_RECMASK
:
624 return IOCTL_OUT(arg
, 0);
625 case SOUND_MIXER_READ_STEREODEVS
:
626 return IOCTL_OUT(arg
, SOUND_MASK_VOLUME
);
627 case SOUND_MIXER_READ_VOLUME
:
628 return IOCTL_OUT(arg
,
629 VOLUME_AMI_TO_VOXWARE(dmasound
.volume_left
) |
630 VOLUME_AMI_TO_VOXWARE(dmasound
.volume_right
) << 8);
631 case SOUND_MIXER_WRITE_VOLUME
:
633 return IOCTL_OUT(arg
, dmasound_set_volume(data
));
634 case SOUND_MIXER_READ_TREBLE
:
635 return IOCTL_OUT(arg
, dmasound
.treble
);
636 case SOUND_MIXER_WRITE_TREBLE
:
638 return IOCTL_OUT(arg
, dmasound_set_treble(data
));
644 static int AmiWriteSqSetup(void)
646 write_sq_block_size_half
= write_sq
.block_size
>>1;
647 write_sq_block_size_quarter
= write_sq_block_size_half
>>1;
652 static int AmiStateInfo(char *buffer
, size_t space
)
655 len
+= sprintf(buffer
+len
, "\tsound.volume_left = %d [0...64]\n",
656 dmasound
.volume_left
);
657 len
+= sprintf(buffer
+len
, "\tsound.volume_right = %d [0...64]\n",
658 dmasound
.volume_right
);
660 printk(KERN_ERR
"dmasound_paula: overlowed state buffer alloc.\n") ;
667 /*** Machine definitions *****************************************************/
669 static SETTINGS def_hard
= {
676 static SETTINGS def_soft
= {
683 static MACHINE machAmiga
= {
686 .owner
= THIS_MODULE
,
687 .dma_alloc
= AmiAlloc
,
689 .irqinit
= AmiIrqInit
,
691 .irqcleanup
= AmiIrqCleanUp
,
694 .silence
= AmiSilence
,
695 .setFormat
= AmiSetFormat
,
696 .setVolume
= AmiSetVolume
,
697 .setTreble
= AmiSetTreble
,
699 .mixer_init
= AmiMixerInit
,
700 .mixer_ioctl
= AmiMixerIoctl
,
701 .write_sq_setup
= AmiWriteSqSetup
,
702 .state_info
= AmiStateInfo
,
703 .min_dsp_speed
= 8000,
704 .version
= ((DMASOUND_PAULA_REVISION
<<8) | DMASOUND_PAULA_EDITION
),
705 .hardware_afmts
= (AFMT_S8
| AFMT_S16_BE
), /* h'ware-supported formats *only* here */
706 .capabilities
= DSP_CAP_BATCH
/* As per SNDCTL_DSP_GETCAPS */
710 /*** Config & Setup **********************************************************/
713 static int __init
dmasound_paula_init(void)
717 if (MACH_IS_AMIGA
&& AMIGAHW_PRESENT(AMI_AUDIO
)) {
718 if (!request_mem_region(CUSTOM_PHYSADDR
+0xa0, 0x40,
721 dmasound
.mach
= machAmiga
;
722 dmasound
.mach
.default_hard
= def_hard
;
723 dmasound
.mach
.default_soft
= def_soft
;
724 err
= dmasound_init();
726 release_mem_region(CUSTOM_PHYSADDR
+0xa0, 0x40);
732 static void __exit
dmasound_paula_cleanup(void)
735 release_mem_region(CUSTOM_PHYSADDR
+0xa0, 0x40);
738 module_init(dmasound_paula_init
);
739 module_exit(dmasound_paula_cleanup
);
740 MODULE_LICENSE("GPL");