Merge branch 'sched/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip...
[pandora-kernel.git] / sound / oss / dmasound / dmasound_paula.c
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
17
18 #include <linux/module.h>
19 #include <linux/mm.h>
20 #include <linux/init.h>
21 #include <linux/ioport.h>
22 #include <linux/soundcard.h>
23 #include <linux/interrupt.h>
24
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>
30
31 #include "dmasound.h"
32
33 #define DMASOUND_PAULA_REVISION 0
34 #define DMASOUND_PAULA_EDITION 4
35
36 #define custom amiga_custom
37    /*
38     *   The minimum period for audio depends on htotal (for OCS/ECS/AGA)
39     *   (Imported from arch/m68k/amiga/amisound.c)
40     */
41
42 extern volatile u_short amiga_audio_min_period;
43
44
45    /*
46     *   amiga_mksound() should be able to restore the period after beeping
47     *   (Imported from arch/m68k/amiga/amisound.c)
48     */
49
50 extern u_short amiga_audio_period;
51
52
53    /*
54     *   Audio DMA masks
55     */
56
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)
60
61
62     /*
63      *  Helper pointers for 16(14)-bit sound
64      */
65
66 static int write_sq_block_size_half, write_sq_block_size_quarter;
67
68
69 /*** Low level stuff *********************************************************/
70
71
72 static void *AmiAlloc(unsigned int size, gfp_t flags);
73 static void AmiFree(void *obj, unsigned int size);
74 static int AmiIrqInit(void);
75 #ifdef MODULE
76 static void AmiIrqCleanUp(void);
77 #endif
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);
86
87 #ifdef CONFIG_HEARTBEAT
88
89     /*
90      *  Heartbeat interferes with sound since the 7 kHz low-pass filter and the
91      *  power LED are controlled by the same line.
92      */
93
94 static void (*saved_heartbeat)(int) = NULL;
95
96 static inline void disable_heartbeat(void)
97 {
98         if (mach_heartbeat) {
99             saved_heartbeat = mach_heartbeat;
100             mach_heartbeat = NULL;
101         }
102         AmiSetTreble(dmasound.treble);
103 }
104
105 static inline void enable_heartbeat(void)
106 {
107         if (saved_heartbeat)
108             mach_heartbeat = saved_heartbeat;
109 }
110 #else /* !CONFIG_HEARTBEAT */
111 #define disable_heartbeat()     do { } while (0)
112 #define enable_heartbeat()      do { } while (0)
113 #endif /* !CONFIG_HEARTBEAT */
114
115
116 /*** Mid level stuff *********************************************************/
117
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);
122
123
124 /*** Translations ************************************************************/
125
126 /* ++TeSche: radically changed for new expanding purposes...
127  *
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.
136  *
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. :)
142  *
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!
146  *
147  * ++geert: split in even more functions (one per format)
148  */
149
150
151     /*
152      *  Native format
153      */
154
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)
157 {
158         ssize_t count, used;
159
160         if (!dmasound.soft.stereo) {
161                 void *p = &frame[*frameUsed];
162                 count = min_t(unsigned long, userCount, frameLeft) & ~1;
163                 used = count;
164                 if (copy_from_user(p, userPtr, count))
165                         return -EFAULT;
166         } else {
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;
170                 used = count*2;
171                 while (count > 0) {
172                         if (get_user(*left++, userPtr++)
173                             || get_user(*right++, userPtr++))
174                                 return -EFAULT;
175                         count--;
176                 }
177         }
178         *frameUsed += used;
179         return used;
180 }
181
182
183     /*
184      *  Copy and convert 8 bit data
185      */
186
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,             \
190                         ssize_t frameLeft)                              \
191 {                                                                       \
192         ssize_t count, used;                                            \
193                                                                         \
194         if (!dmasound.soft.stereo) {                                    \
195                 u_char *p = &frame[*frameUsed];                         \
196                 count = min_t(size_t, userCount, frameLeft) & ~1;       \
197                 used = count;                                           \
198                 while (count > 0) {                                     \
199                         u_char data;                                    \
200                         if (get_user(data, userPtr++))                  \
201                                 return -EFAULT;                         \
202                         *p++ = convsample(data);                        \
203                         count--;                                        \
204                 }                                                       \
205         } else {                                                        \
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;    \
209                 used = count*2;                                         \
210                 while (count > 0) {                                     \
211                         u_char data;                                    \
212                         if (get_user(data, userPtr++))                  \
213                                 return -EFAULT;                         \
214                         *left++ = convsample(data);                     \
215                         if (get_user(data, userPtr++))                  \
216                                 return -EFAULT;                         \
217                         *right++ = convsample(data);                    \
218                         count--;                                        \
219                 }                                                       \
220         }                                                               \
221         *frameUsed += used;                                             \
222         return used;                                                    \
223 }
224
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)
228
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)
232
233
234     /*
235      *  Copy and convert 16 bit data
236      */
237
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,             \
241                         ssize_t frameLeft)                              \
242 {                                                                       \
243         const u_short __user *ptr = (const u_short __user *)userPtr;    \
244         ssize_t count, used;                                            \
245         u_short data;                                                   \
246                                                                         \
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;    \
251                 used = count*2;                                         \
252                 while (count > 0) {                                     \
253                         if (get_user(data, ptr++))                      \
254                                 return -EFAULT;                         \
255                         data = convsample(data);                        \
256                         *high++ = data>>8;                              \
257                         *low++ = (data>>2) & 0x3f;                      \
258                         count--;                                        \
259                 }                                                       \
260         } else {                                                        \
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;    \
266                 used = count*4;                                         \
267                 while (count > 0) {                                     \
268                         if (get_user(data, ptr++))                      \
269                                 return -EFAULT;                         \
270                         data = convsample(data);                        \
271                         *lefth++ = data>>8;                             \
272                         *leftl++ = (data>>2) & 0x3f;                    \
273                         if (get_user(data, ptr++))                      \
274                                 return -EFAULT;                         \
275                         data = convsample(data);                        \
276                         *righth++ = data>>8;                            \
277                         *rightl++ = (data>>2) & 0x3f;                   \
278                         count--;                                        \
279                 }                                                       \
280         }                                                               \
281         *frameUsed += used;                                             \
282         return used;                                                    \
283 }
284
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)
289
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)
294
295
296 static TRANS transAmiga = {
297         .ct_ulaw        = ami_ct_ulaw,
298         .ct_alaw        = ami_ct_alaw,
299         .ct_s8          = ami_ct_s8,
300         .ct_u8          = ami_ct_u8,
301         .ct_s16be       = ami_ct_s16be,
302         .ct_u16be       = ami_ct_u16be,
303         .ct_s16le       = ami_ct_s16le,
304         .ct_u16le       = ami_ct_u16le,
305 };
306
307 /*** Low level stuff *********************************************************/
308
309 static inline void StopDMA(void)
310 {
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;
314         enable_heartbeat();
315 }
316
317 static void *AmiAlloc(unsigned int size, gfp_t flags)
318 {
319         return amiga_chip_alloc((long)size, "dmasound [Paula]");
320 }
321
322 static void AmiFree(void *obj, unsigned int size)
323 {
324         amiga_chip_free (obj);
325 }
326
327 static int __init AmiIrqInit(void)
328 {
329         /* turn off DMA for audio channels */
330         StopDMA();
331
332         /* Register interrupt handler. */
333         if (request_irq(IRQ_AMIGA_AUD0, AmiInterrupt, 0, "DMA sound",
334                         AmiInterrupt))
335                 return 0;
336         return 1;
337 }
338
339 #ifdef MODULE
340 static void AmiIrqCleanUp(void)
341 {
342         /* turn off DMA for audio channels */
343         StopDMA();
344         /* release the interrupt */
345         free_irq(IRQ_AMIGA_AUD0, AmiInterrupt);
346 }
347 #endif /* MODULE */
348
349 static void AmiSilence(void)
350 {
351         /* turn off DMA for audio channels */
352         StopDMA();
353 }
354
355
356 static void AmiInit(void)
357 {
358         int period, i;
359
360         AmiSilence();
361
362         if (dmasound.soft.speed)
363                 period = amiga_colorclock/dmasound.soft.speed-1;
364         else
365                 period = amiga_audio_min_period;
366         dmasound.hard = dmasound.soft;
367         dmasound.trans_write = &transAmiga;
368
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) {
373                 period = 65535;
374         }
375         dmasound.hard.speed = amiga_colorclock/(period+1);
376
377         for (i = 0; i < 4; i++)
378                 custom.aud[i].audper = period;
379         amiga_audio_period = period;
380 }
381
382
383 static int AmiSetFormat(int format)
384 {
385         int size;
386
387         /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
388
389         switch (format) {
390         case AFMT_QUERY:
391                 return dmasound.soft.format;
392         case AFMT_MU_LAW:
393         case AFMT_A_LAW:
394         case AFMT_U8:
395         case AFMT_S8:
396                 size = 8;
397                 break;
398         case AFMT_S16_BE:
399         case AFMT_U16_BE:
400         case AFMT_S16_LE:
401         case AFMT_U16_LE:
402                 size = 16;
403                 break;
404         default: /* :-) */
405                 size = 8;
406                 format = AFMT_S8;
407         }
408
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;
414         }
415         AmiInit();
416
417         return format;
418 }
419
420
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)
424
425 static int AmiSetVolume(int volume)
426 {
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;
435                 } else {
436                         custom.aud[2].audvol = 0;
437                         custom.aud[3].audvol = 0;
438                 }
439         }
440         return VOLUME_AMI_TO_VOXWARE(dmasound.volume_left) |
441                (VOLUME_AMI_TO_VOXWARE(dmasound.volume_right) << 8);
442 }
443
444 static int AmiSetTreble(int treble)
445 {
446         dmasound.treble = treble;
447         if (treble < 50)
448                 ciaa.pra &= ~0x02;
449         else
450                 ciaa.pra |= 0x02;
451         return treble;
452 }
453
454
455 #define AMI_PLAY_LOADED         1
456 #define AMI_PLAY_PLAYING        2
457 #define AMI_PLAY_MASK           3
458
459
460 static void AmiPlayNextFrame(int index)
461 {
462         u_char *start, *ch0, *ch1, *ch2, *ch3;
463         u_long size;
464
465         /* used by AmiPlay() if all doubts whether there really is something
466          * to be played are already wiped out.
467          */
468         start = write_sq.buffers[write_sq.front];
469         size = (write_sq.count == index ? write_sq.rear_size
470                                         : write_sq.block_size)>>1;
471
472         if (dmasound.hard.stereo) {
473                 ch0 = start;
474                 ch1 = start+write_sq_block_size_half;
475                 size >>= 1;
476         } else {
477                 ch0 = start;
478                 ch1 = start;
479         }
480
481         disable_heartbeat();
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;
490         } else {
491                 size >>= 1;
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;
507                 } else {
508                         custom.aud[2].audvol = 0;
509                         custom.aud[3].audvol = 0;
510                         custom.dmacon = AMI_AUDIO_8;
511                 }
512         }
513         write_sq.front = (write_sq.front+1) % write_sq.max_count;
514         write_sq.active |= AMI_PLAY_LOADED;
515 }
516
517
518 static void AmiPlay(void)
519 {
520         int minframes = 1;
521
522         custom.intena = IF_AUD0;
523
524         if (write_sq.active & AMI_PLAY_LOADED) {
525                 /* There's already a frame loaded */
526                 custom.intena = IF_SETCLR | IF_AUD0;
527                 return;
528         }
529
530         if (write_sq.active & AMI_PLAY_PLAYING)
531                 /* Increase threshold: frame 1 is already being played */
532                 minframes = 2;
533
534         if (write_sq.count < minframes) {
535                 /* Nothing to do */
536                 custom.intena = IF_SETCLR | IF_AUD0;
537                 return;
538         }
539
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?
544                  */
545                 custom.intena = IF_SETCLR | IF_AUD0;
546                 return;
547         }
548
549         AmiPlayNextFrame(minframes);
550
551         custom.intena = IF_SETCLR | IF_AUD0;
552 }
553
554
555 static irqreturn_t AmiInterrupt(int irq, void *dummy)
556 {
557         int minframes = 1;
558
559         custom.intena = IF_AUD0;
560
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.
564                  */
565                 WAKE_UP(write_sq.sync_queue);
566                 return IRQ_HANDLED;
567         }
568
569         if (write_sq.active & AMI_PLAY_PLAYING) {
570                 /* We've just finished a frame */
571                 write_sq.count--;
572                 WAKE_UP(write_sq.action_queue);
573         }
574
575         if (write_sq.active & AMI_PLAY_LOADED)
576                 /* Increase threshold: frame 1 is already being played */
577                 minframes = 2;
578
579         /* Shift the flags */
580         write_sq.active = (write_sq.active<<1) & AMI_PLAY_MASK;
581
582         if (!write_sq.active)
583                 /* No frame is playing, disable audio DMA */
584                 StopDMA();
585
586         custom.intena = IF_SETCLR | IF_AUD0;
587
588         if (write_sq.count >= minframes)
589                 /* Try to play the next frame */
590                 AmiPlay();
591
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);
596         return IRQ_HANDLED;
597 }
598
599 /*** Mid level stuff *********************************************************/
600
601
602 /*
603  * /dev/mixer abstraction
604  */
605
606 static void __init AmiMixerInit(void)
607 {
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;
615 }
616
617 static int AmiMixerIoctl(u_int cmd, u_long arg)
618 {
619         int data;
620         switch (cmd) {
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:
632                     IOCTL_IN(arg, data);
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:
637                     IOCTL_IN(arg, data);
638                     return IOCTL_OUT(arg, dmasound_set_treble(data));
639         }
640         return -EINVAL;
641 }
642
643
644 static int AmiWriteSqSetup(void)
645 {
646         write_sq_block_size_half = write_sq.block_size>>1;
647         write_sq_block_size_quarter = write_sq_block_size_half>>1;
648         return 0;
649 }
650
651
652 static int AmiStateInfo(char *buffer, size_t space)
653 {
654         int len = 0;
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);
659         if (len >= space) {
660                 printk(KERN_ERR "dmasound_paula: overlowed state buffer alloc.\n") ;
661                 len = space ;
662         }
663         return len;
664 }
665
666
667 /*** Machine definitions *****************************************************/
668
669 static SETTINGS def_hard = {
670         .format = AFMT_S8,
671         .stereo = 0,
672         .size   = 8,
673         .speed  = 8000
674 } ;
675
676 static SETTINGS def_soft = {
677         .format = AFMT_U8,
678         .stereo = 0,
679         .size   = 8,
680         .speed  = 8000
681 } ;
682
683 static MACHINE machAmiga = {
684         .name           = "Amiga",
685         .name2          = "AMIGA",
686         .owner          = THIS_MODULE,
687         .dma_alloc      = AmiAlloc,
688         .dma_free       = AmiFree,
689         .irqinit        = AmiIrqInit,
690 #ifdef MODULE
691         .irqcleanup     = AmiIrqCleanUp,
692 #endif /* MODULE */
693         .init           = AmiInit,
694         .silence        = AmiSilence,
695         .setFormat      = AmiSetFormat,
696         .setVolume      = AmiSetVolume,
697         .setTreble      = AmiSetTreble,
698         .play           = AmiPlay,
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 */
707 };
708
709
710 /*** Config & Setup **********************************************************/
711
712
713 static int __init dmasound_paula_init(void)
714 {
715         int err;
716
717         if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_AUDIO)) {
718             if (!request_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40,
719                                     "dmasound [Paula]"))
720                 return -EBUSY;
721             dmasound.mach = machAmiga;
722             dmasound.mach.default_hard = def_hard ;
723             dmasound.mach.default_soft = def_soft ;
724             err = dmasound_init();
725             if (err)
726                 release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
727             return err;
728         } else
729             return -ENODEV;
730 }
731
732 static void __exit dmasound_paula_cleanup(void)
733 {
734         dmasound_deinit();
735         release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
736 }
737
738 module_init(dmasound_paula_init);
739 module_exit(dmasound_paula_cleanup);
740 MODULE_LICENSE("GPL");