root/sound/oss/dmasound/dmasound_paula.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. disable_heartbeat
  2. enable_heartbeat
  3. ami_ct_s8
  4. StopDMA
  5. AmiAlloc
  6. AmiFree
  7. AmiIrqInit
  8. AmiIrqCleanUp
  9. AmiSilence
  10. AmiInit
  11. AmiSetFormat
  12. AmiSetVolume
  13. AmiSetTreble
  14. AmiPlayNextFrame
  15. AmiPlay
  16. AmiInterrupt
  17. AmiMixerInit
  18. AmiMixerIoctl
  19. AmiWriteSqSetup
  20. AmiStateInfo
  21. amiga_audio_probe
  22. amiga_audio_remove

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

/* [<][>][^][v][top][bottom][index][help] */