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.
95 #define mach_heartbeat ppc_md.heartbeat
98 static void (*saved_heartbeat
)(int) = NULL
;
100 static inline void disable_heartbeat(void)
102 if (mach_heartbeat
) {
103 saved_heartbeat
= mach_heartbeat
;
104 mach_heartbeat
= NULL
;
106 AmiSetTreble(dmasound
.treble
);
109 static inline void enable_heartbeat(void)
112 mach_heartbeat
= saved_heartbeat
;
114 #else /* !CONFIG_HEARTBEAT */
115 #define disable_heartbeat() do { } while (0)
116 #define enable_heartbeat() do { } while (0)
117 #endif /* !CONFIG_HEARTBEAT */
120 /*** Mid level stuff *********************************************************/
122 static void AmiMixerInit(void);
123 static int AmiMixerIoctl(u_int cmd
, u_long arg
);
124 static int AmiWriteSqSetup(void);
125 static int AmiStateInfo(char *buffer
, size_t space
);
128 /*** Translations ************************************************************/
130 /* ++TeSche: radically changed for new expanding purposes...
132 * These two routines now deal with copying/expanding/translating the samples
133 * from user space into our buffer at the right frequency. They take care about
134 * how much data there's actually to read, how much buffer space there is and
135 * to convert samples into the right frequency/encoding. They will only work on
136 * complete samples so it may happen they leave some bytes in the input stream
137 * if the user didn't write a multiple of the current sample size. They both
138 * return the number of bytes they've used from both streams so you may detect
139 * such a situation. Luckily all programs should be able to cope with that.
141 * I think I've optimized anything as far as one can do in plain C, all
142 * variables should fit in registers and the loops are really short. There's
143 * one loop for every possible situation. Writing a more generalized and thus
144 * parameterized loop would only produce slower code. Feel free to optimize
145 * this in assembler if you like. :)
147 * I think these routines belong here because they're not yet really hardware
148 * independent, especially the fact that the Falcon can play 16bit samples
149 * only in stereo is hardcoded in both of them!
151 * ++geert: split in even more functions (one per format)
159 static ssize_t
ami_ct_s8(const u_char __user
*userPtr
, size_t userCount
,
160 u_char frame
[], ssize_t
*frameUsed
, ssize_t frameLeft
)
164 if (!dmasound
.soft
.stereo
) {
165 void *p
= &frame
[*frameUsed
];
166 count
= min_t(unsigned long, userCount
, frameLeft
) & ~1;
168 if (copy_from_user(p
, userPtr
, count
))
171 u_char
*left
= &frame
[*frameUsed
>>1];
172 u_char
*right
= left
+write_sq_block_size_half
;
173 count
= min_t(unsigned long, userCount
, frameLeft
)>>1 & ~1;
176 if (get_user(*left
++, userPtr
++)
177 || get_user(*right
++, userPtr
++))
188 * Copy and convert 8 bit data
191 #define GENERATE_AMI_CT8(funcname, convsample) \
192 static ssize_t funcname(const u_char __user *userPtr, size_t userCount, \
193 u_char frame[], ssize_t *frameUsed, \
196 ssize_t count, used; \
198 if (!dmasound.soft.stereo) { \
199 u_char *p = &frame[*frameUsed]; \
200 count = min_t(size_t, userCount, frameLeft) & ~1; \
202 while (count > 0) { \
204 if (get_user(data, userPtr++)) \
206 *p++ = convsample(data); \
210 u_char *left = &frame[*frameUsed>>1]; \
211 u_char *right = left+write_sq_block_size_half; \
212 count = min_t(size_t, userCount, frameLeft)>>1 & ~1; \
214 while (count > 0) { \
216 if (get_user(data, userPtr++)) \
218 *left++ = convsample(data); \
219 if (get_user(data, userPtr++)) \
221 *right++ = convsample(data); \
225 *frameUsed += used; \
229 #define AMI_CT_ULAW(x) (dmasound_ulaw2dma8[(x)])
230 #define AMI_CT_ALAW(x) (dmasound_alaw2dma8[(x)])
231 #define AMI_CT_U8(x) ((x) ^ 0x80)
233 GENERATE_AMI_CT8(ami_ct_ulaw
, AMI_CT_ULAW
)
234 GENERATE_AMI_CT8(ami_ct_alaw
, AMI_CT_ALAW
)
235 GENERATE_AMI_CT8(ami_ct_u8
, AMI_CT_U8
)
239 * Copy and convert 16 bit data
242 #define GENERATE_AMI_CT_16(funcname, convsample) \
243 static ssize_t funcname(const u_char __user *userPtr, size_t userCount, \
244 u_char frame[], ssize_t *frameUsed, \
247 const u_short __user *ptr = (const u_short __user *)userPtr; \
248 ssize_t count, used; \
251 if (!dmasound.soft.stereo) { \
252 u_char *high = &frame[*frameUsed>>1]; \
253 u_char *low = high+write_sq_block_size_half; \
254 count = min_t(size_t, userCount, frameLeft)>>1 & ~1; \
256 while (count > 0) { \
257 if (get_user(data, ptr++)) \
259 data = convsample(data); \
261 *low++ = (data>>2) & 0x3f; \
265 u_char *lefth = &frame[*frameUsed>>2]; \
266 u_char *leftl = lefth+write_sq_block_size_quarter; \
267 u_char *righth = lefth+write_sq_block_size_half; \
268 u_char *rightl = righth+write_sq_block_size_quarter; \
269 count = min_t(size_t, userCount, frameLeft)>>2 & ~1; \
271 while (count > 0) { \
272 if (get_user(data, ptr++)) \
274 data = convsample(data); \
275 *lefth++ = data>>8; \
276 *leftl++ = (data>>2) & 0x3f; \
277 if (get_user(data, ptr++)) \
279 data = convsample(data); \
280 *righth++ = data>>8; \
281 *rightl++ = (data>>2) & 0x3f; \
285 *frameUsed += used; \
289 #define AMI_CT_S16BE(x) (x)
290 #define AMI_CT_U16BE(x) ((x) ^ 0x8000)
291 #define AMI_CT_S16LE(x) (le2be16((x)))
292 #define AMI_CT_U16LE(x) (le2be16((x)) ^ 0x8000)
294 GENERATE_AMI_CT_16(ami_ct_s16be
, AMI_CT_S16BE
)
295 GENERATE_AMI_CT_16(ami_ct_u16be
, AMI_CT_U16BE
)
296 GENERATE_AMI_CT_16(ami_ct_s16le
, AMI_CT_S16LE
)
297 GENERATE_AMI_CT_16(ami_ct_u16le
, AMI_CT_U16LE
)
300 static TRANS transAmiga
= {
301 .ct_ulaw
= ami_ct_ulaw
,
302 .ct_alaw
= ami_ct_alaw
,
305 .ct_s16be
= ami_ct_s16be
,
306 .ct_u16be
= ami_ct_u16be
,
307 .ct_s16le
= ami_ct_s16le
,
308 .ct_u16le
= ami_ct_u16le
,
311 /*** Low level stuff *********************************************************/
313 static inline void StopDMA(void)
315 custom
.aud
[0].audvol
= custom
.aud
[1].audvol
= 0;
316 custom
.aud
[2].audvol
= custom
.aud
[3].audvol
= 0;
317 custom
.dmacon
= AMI_AUDIO_OFF
;
321 static void *AmiAlloc(unsigned int size
, gfp_t flags
)
323 return amiga_chip_alloc((long)size
, "dmasound [Paula]");
326 static void AmiFree(void *obj
, unsigned int size
)
328 amiga_chip_free (obj
);
331 static int __init
AmiIrqInit(void)
333 /* turn off DMA for audio channels */
336 /* Register interrupt handler. */
337 if (request_irq(IRQ_AMIGA_AUD0
, AmiInterrupt
, 0, "DMA sound",
344 static void AmiIrqCleanUp(void)
346 /* turn off DMA for audio channels */
348 /* release the interrupt */
349 free_irq(IRQ_AMIGA_AUD0
, AmiInterrupt
);
353 static void AmiSilence(void)
355 /* turn off DMA for audio channels */
360 static void AmiInit(void)
366 if (dmasound
.soft
.speed
)
367 period
= amiga_colorclock
/dmasound
.soft
.speed
-1;
369 period
= amiga_audio_min_period
;
370 dmasound
.hard
= dmasound
.soft
;
371 dmasound
.trans_write
= &transAmiga
;
373 if (period
< amiga_audio_min_period
) {
374 /* we would need to squeeze the sound, but we won't do that */
375 period
= amiga_audio_min_period
;
376 } else if (period
> 65535) {
379 dmasound
.hard
.speed
= amiga_colorclock
/(period
+1);
381 for (i
= 0; i
< 4; i
++)
382 custom
.aud
[i
].audper
= period
;
383 amiga_audio_period
= period
;
387 static int AmiSetFormat(int format
)
391 /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
395 return dmasound
.soft
.format
;
413 dmasound
.soft
.format
= format
;
414 dmasound
.soft
.size
= size
;
415 if (dmasound
.minDev
== SND_DEV_DSP
) {
416 dmasound
.dsp
.format
= format
;
417 dmasound
.dsp
.size
= dmasound
.soft
.size
;
425 #define VOLUME_VOXWARE_TO_AMI(v) \
426 (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
427 #define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
429 static int AmiSetVolume(int volume
)
431 dmasound
.volume_left
= VOLUME_VOXWARE_TO_AMI(volume
& 0xff);
432 custom
.aud
[0].audvol
= dmasound
.volume_left
;
433 dmasound
.volume_right
= VOLUME_VOXWARE_TO_AMI((volume
& 0xff00) >> 8);
434 custom
.aud
[1].audvol
= dmasound
.volume_right
;
435 if (dmasound
.hard
.size
== 16) {
436 if (dmasound
.volume_left
== 64 && dmasound
.volume_right
== 64) {
437 custom
.aud
[2].audvol
= 1;
438 custom
.aud
[3].audvol
= 1;
440 custom
.aud
[2].audvol
= 0;
441 custom
.aud
[3].audvol
= 0;
444 return VOLUME_AMI_TO_VOXWARE(dmasound
.volume_left
) |
445 (VOLUME_AMI_TO_VOXWARE(dmasound
.volume_right
) << 8);
448 static int AmiSetTreble(int treble
)
450 dmasound
.treble
= treble
;
459 #define AMI_PLAY_LOADED 1
460 #define AMI_PLAY_PLAYING 2
461 #define AMI_PLAY_MASK 3
464 static void AmiPlayNextFrame(int index
)
466 u_char
*start
, *ch0
, *ch1
, *ch2
, *ch3
;
469 /* used by AmiPlay() if all doubts whether there really is something
470 * to be played are already wiped out.
472 start
= write_sq
.buffers
[write_sq
.front
];
473 size
= (write_sq
.count
== index
? write_sq
.rear_size
474 : write_sq
.block_size
)>>1;
476 if (dmasound
.hard
.stereo
) {
478 ch1
= start
+write_sq_block_size_half
;
486 custom
.aud
[0].audvol
= dmasound
.volume_left
;
487 custom
.aud
[1].audvol
= dmasound
.volume_right
;
488 if (dmasound
.hard
.size
== 8) {
489 custom
.aud
[0].audlc
= (u_short
*)ZTWO_PADDR(ch0
);
490 custom
.aud
[0].audlen
= size
;
491 custom
.aud
[1].audlc
= (u_short
*)ZTWO_PADDR(ch1
);
492 custom
.aud
[1].audlen
= size
;
493 custom
.dmacon
= AMI_AUDIO_8
;
496 custom
.aud
[0].audlc
= (u_short
*)ZTWO_PADDR(ch0
);
497 custom
.aud
[0].audlen
= size
;
498 custom
.aud
[1].audlc
= (u_short
*)ZTWO_PADDR(ch1
);
499 custom
.aud
[1].audlen
= size
;
500 if (dmasound
.volume_left
== 64 && dmasound
.volume_right
== 64) {
501 /* We can play pseudo 14-bit only with the maximum volume */
502 ch3
= ch0
+write_sq_block_size_quarter
;
503 ch2
= ch1
+write_sq_block_size_quarter
;
504 custom
.aud
[2].audvol
= 1; /* we are being affected by the beeps */
505 custom
.aud
[3].audvol
= 1; /* restoring volume here helps a bit */
506 custom
.aud
[2].audlc
= (u_short
*)ZTWO_PADDR(ch2
);
507 custom
.aud
[2].audlen
= size
;
508 custom
.aud
[3].audlc
= (u_short
*)ZTWO_PADDR(ch3
);
509 custom
.aud
[3].audlen
= size
;
510 custom
.dmacon
= AMI_AUDIO_14
;
512 custom
.aud
[2].audvol
= 0;
513 custom
.aud
[3].audvol
= 0;
514 custom
.dmacon
= AMI_AUDIO_8
;
517 write_sq
.front
= (write_sq
.front
+1) % write_sq
.max_count
;
518 write_sq
.active
|= AMI_PLAY_LOADED
;
522 static void AmiPlay(void)
526 custom
.intena
= IF_AUD0
;
528 if (write_sq
.active
& AMI_PLAY_LOADED
) {
529 /* There's already a frame loaded */
530 custom
.intena
= IF_SETCLR
| IF_AUD0
;
534 if (write_sq
.active
& AMI_PLAY_PLAYING
)
535 /* Increase threshold: frame 1 is already being played */
538 if (write_sq
.count
< minframes
) {
540 custom
.intena
= IF_SETCLR
| IF_AUD0
;
544 if (write_sq
.count
<= minframes
&&
545 write_sq
.rear_size
< write_sq
.block_size
&& !write_sq
.syncing
) {
546 /* hmmm, the only existing frame is not
547 * yet filled and we're not syncing?
549 custom
.intena
= IF_SETCLR
| IF_AUD0
;
553 AmiPlayNextFrame(minframes
);
555 custom
.intena
= IF_SETCLR
| IF_AUD0
;
559 static irqreturn_t
AmiInterrupt(int irq
, void *dummy
)
563 custom
.intena
= IF_AUD0
;
565 if (!write_sq
.active
) {
566 /* Playing was interrupted and sq_reset() has already cleared
567 * the sq variables, so better don't do anything here.
569 WAKE_UP(write_sq
.sync_queue
);
573 if (write_sq
.active
& AMI_PLAY_PLAYING
) {
574 /* We've just finished a frame */
576 WAKE_UP(write_sq
.action_queue
);
579 if (write_sq
.active
& AMI_PLAY_LOADED
)
580 /* Increase threshold: frame 1 is already being played */
583 /* Shift the flags */
584 write_sq
.active
= (write_sq
.active
<<1) & AMI_PLAY_MASK
;
586 if (!write_sq
.active
)
587 /* No frame is playing, disable audio DMA */
590 custom
.intena
= IF_SETCLR
| IF_AUD0
;
592 if (write_sq
.count
>= minframes
)
593 /* Try to play the next frame */
596 if (!write_sq
.active
)
597 /* Nothing to play anymore.
598 Wake up a process waiting for audio output to drain. */
599 WAKE_UP(write_sq
.sync_queue
);
603 /*** Mid level stuff *********************************************************/
607 * /dev/mixer abstraction
610 static void __init
AmiMixerInit(void)
612 dmasound
.volume_left
= 64;
613 dmasound
.volume_right
= 64;
614 custom
.aud
[0].audvol
= dmasound
.volume_left
;
615 custom
.aud
[3].audvol
= 1; /* For pseudo 14bit */
616 custom
.aud
[1].audvol
= dmasound
.volume_right
;
617 custom
.aud
[2].audvol
= 1; /* For pseudo 14bit */
618 dmasound
.treble
= 50;
621 static int AmiMixerIoctl(u_int cmd
, u_long arg
)
625 case SOUND_MIXER_READ_DEVMASK
:
626 return IOCTL_OUT(arg
, SOUND_MASK_VOLUME
| SOUND_MASK_TREBLE
);
627 case SOUND_MIXER_READ_RECMASK
:
628 return IOCTL_OUT(arg
, 0);
629 case SOUND_MIXER_READ_STEREODEVS
:
630 return IOCTL_OUT(arg
, SOUND_MASK_VOLUME
);
631 case SOUND_MIXER_READ_VOLUME
:
632 return IOCTL_OUT(arg
,
633 VOLUME_AMI_TO_VOXWARE(dmasound
.volume_left
) |
634 VOLUME_AMI_TO_VOXWARE(dmasound
.volume_right
) << 8);
635 case SOUND_MIXER_WRITE_VOLUME
:
637 return IOCTL_OUT(arg
, dmasound_set_volume(data
));
638 case SOUND_MIXER_READ_TREBLE
:
639 return IOCTL_OUT(arg
, dmasound
.treble
);
640 case SOUND_MIXER_WRITE_TREBLE
:
642 return IOCTL_OUT(arg
, dmasound_set_treble(data
));
648 static int AmiWriteSqSetup(void)
650 write_sq_block_size_half
= write_sq
.block_size
>>1;
651 write_sq_block_size_quarter
= write_sq_block_size_half
>>1;
656 static int AmiStateInfo(char *buffer
, size_t space
)
659 len
+= sprintf(buffer
+len
, "\tsound.volume_left = %d [0...64]\n",
660 dmasound
.volume_left
);
661 len
+= sprintf(buffer
+len
, "\tsound.volume_right = %d [0...64]\n",
662 dmasound
.volume_right
);
664 printk(KERN_ERR
"dmasound_paula: overlowed state buffer alloc.\n") ;
671 /*** Machine definitions *****************************************************/
673 static SETTINGS def_hard
= {
680 static SETTINGS def_soft
= {
687 static MACHINE machAmiga
= {
690 .owner
= THIS_MODULE
,
691 .dma_alloc
= AmiAlloc
,
693 .irqinit
= AmiIrqInit
,
695 .irqcleanup
= AmiIrqCleanUp
,
698 .silence
= AmiSilence
,
699 .setFormat
= AmiSetFormat
,
700 .setVolume
= AmiSetVolume
,
701 .setTreble
= AmiSetTreble
,
703 .mixer_init
= AmiMixerInit
,
704 .mixer_ioctl
= AmiMixerIoctl
,
705 .write_sq_setup
= AmiWriteSqSetup
,
706 .state_info
= AmiStateInfo
,
707 .min_dsp_speed
= 8000,
708 .version
= ((DMASOUND_PAULA_REVISION
<<8) | DMASOUND_PAULA_EDITION
),
709 .hardware_afmts
= (AFMT_S8
| AFMT_S16_BE
), /* h'ware-supported formats *only* here */
710 .capabilities
= DSP_CAP_BATCH
/* As per SNDCTL_DSP_GETCAPS */
714 /*** Config & Setup **********************************************************/
717 int __init
dmasound_paula_init(void)
721 if (MACH_IS_AMIGA
&& AMIGAHW_PRESENT(AMI_AUDIO
)) {
722 if (!request_mem_region(CUSTOM_PHYSADDR
+0xa0, 0x40,
725 dmasound
.mach
= machAmiga
;
726 dmasound
.mach
.default_hard
= def_hard
;
727 dmasound
.mach
.default_soft
= def_soft
;
728 err
= dmasound_init();
730 release_mem_region(CUSTOM_PHYSADDR
+0xa0, 0x40);
736 static void __exit
dmasound_paula_cleanup(void)
739 release_mem_region(CUSTOM_PHYSADDR
+0xa0, 0x40);
742 module_init(dmasound_paula_init
);
743 module_exit(dmasound_paula_cleanup
);
744 MODULE_LICENSE("GPL");