linux/sound/oss/dmasound/dmasound_paula.c
<<
>>
Prefs
   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
  42extern 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
  50extern 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
  66static int write_sq_block_size_half, write_sq_block_size_quarter;
  67
  68
  69/*** Low level stuff *********************************************************/
  70
  71
  72static void *AmiAlloc(unsigned int size, gfp_t flags);
  73static void AmiFree(void *obj, unsigned int size);
  74static int AmiIrqInit(void);
  75#ifdef MODULE
  76static void AmiIrqCleanUp(void);
  77#endif
  78static void AmiSilence(void);
  79static void AmiInit(void);
  80static int AmiSetFormat(int format);
  81static int AmiSetVolume(int volume);
  82static int AmiSetTreble(int treble);
  83static void AmiPlayNextFrame(int index);
  84static void AmiPlay(void);
  85static 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
  94static void (*saved_heartbeat)(int) = NULL;
  95
  96static 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
 105static 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
 118static void AmiMixerInit(void);
 119static int AmiMixerIoctl(u_int cmd, u_long arg);
 120static int AmiWriteSqSetup(void);
 121static 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
 155static 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)                          \
 188static 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
 229GENERATE_AMI_CT8(ami_ct_ulaw, AMI_CT_ULAW)
 230GENERATE_AMI_CT8(ami_ct_alaw, AMI_CT_ALAW)
 231GENERATE_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)                        \
 239static 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
 290GENERATE_AMI_CT_16(ami_ct_s16be, AMI_CT_S16BE)
 291GENERATE_AMI_CT_16(ami_ct_u16be, AMI_CT_U16BE)
 292GENERATE_AMI_CT_16(ami_ct_s16le, AMI_CT_S16LE)
 293GENERATE_AMI_CT_16(ami_ct_u16le, AMI_CT_U16LE)
 294
 295
 296static 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
 309static 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
 317static void *AmiAlloc(unsigned int size, gfp_t flags)
 318{
 319        return amiga_chip_alloc((long)size, "dmasound [Paula]");
 320}
 321
 322static void AmiFree(void *obj, unsigned int size)
 323{
 324        amiga_chip_free (obj);
 325}
 326
 327static 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
 340static 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
 349static void AmiSilence(void)
 350{
 351        /* turn off DMA for audio channels */
 352        StopDMA();
 353}
 354
 355
 356static 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
 383static 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
 425static 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
 444static 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
 460static 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
 518static 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
 555static 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
 606static 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
 617static 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
 644static 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
 652static 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
 669static SETTINGS def_hard = {
 670        .format = AFMT_S8,
 671        .stereo = 0,
 672        .size   = 8,
 673        .speed  = 8000
 674} ;
 675
 676static SETTINGS def_soft = {
 677        .format = AFMT_U8,
 678        .stereo = 0,
 679        .size   = 8,
 680        .speed  = 8000
 681} ;
 682
 683static 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
 713static 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
 732static void __exit dmasound_paula_cleanup(void)
 733{
 734        dmasound_deinit();
 735        release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
 736}
 737
 738module_init(dmasound_paula_init);
 739module_exit(dmasound_paula_cleanup);
 740MODULE_LICENSE("GPL");
 741