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/config.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 26 #include <asm/uaccess.h> 27 #include <asm/setup.h> 28 #include <asm/amigahw.h> 29 #include <asm/amigaints.h> 30 #include <asm/machdep.h> 31 32 #include "dmasound.h" 33 34 #define DMASOUND_PAULA_REVISION 0 35 #define DMASOUND_PAULA_EDITION 4 36 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, int 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, struct pt_regs *fp); 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 #ifdef CONFIG_APUS 95 #define mach_heartbeat ppc_md.heartbeat 96 #endif 97 98 static void (*saved_heartbeat)(int) = NULL; 99 100 static inline void disable_heartbeat(void) 101 { 102 if (mach_heartbeat) { 103 saved_heartbeat = mach_heartbeat; 104 mach_heartbeat = NULL; 105 } 106 AmiSetTreble(dmasound.treble); 107 } 108 109 static inline void enable_heartbeat(void) 110 { 111 if (saved_heartbeat) 112 mach_heartbeat = saved_heartbeat; 113 } 114 #else /* !CONFIG_HEARTBEAT */ 115 #define disable_heartbeat() do { } while (0) 116 #define enable_heartbeat() do { } while (0) 117 #endif /* !CONFIG_HEARTBEAT */ 118 119 120 /*** Mid level stuff *********************************************************/ 121 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); 126 127 128 /*** Translations ************************************************************/ 129 130 /* ++TeSche: radically changed for new expanding purposes... 131 * 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. 140 * 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. :) 146 * 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! 150 * 151 * ++geert: split in even more functions (one per format) 152 */ 153 154 155 /* 156 * Native format 157 */ 158 159 static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount, 160 u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) 161 { 162 ssize_t count, used; 163 164 if (!dmasound.soft.stereo) { 165 void *p = &frame[*frameUsed]; 166 count = min_t(unsigned long, userCount, frameLeft) & ~1; 167 used = count; 168 if (copy_from_user(p, userPtr, count)) 169 return -EFAULT; 170 } else { 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; 174 used = count*2; 175 while (count > 0) { 176 if (get_user(*left++, userPtr++) 177 || get_user(*right++, userPtr++)) 178 return -EFAULT; 179 count--; 180 } 181 } 182 *frameUsed += used; 183 return used; 184 } 185 186 187 /* 188 * Copy and convert 8 bit data 189 */ 190 191 #define GENERATE_AMI_CT8(funcname, convsample) \ 192 static ssize_t funcname(const u_char *userPtr, size_t userCount, \ 193 u_char frame[], ssize_t *frameUsed, \ 194 ssize_t frameLeft) \ 195 { \ 196 ssize_t count, used; \ 197 \ 198 if (!dmasound.soft.stereo) { \ 199 u_char *p = &frame[*frameUsed]; \ 200 count = min_t(size_t, userCount, frameLeft) & ~1; \ 201 used = count; \ 202 while (count > 0) { \ 203 u_char data; \ 204 if (get_user(data, userPtr++)) \ 205 return -EFAULT; \ 206 *p++ = convsample(data); \ 207 count--; \ 208 } \ 209 } else { \ 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; \ 213 used = count*2; \ 214 while (count > 0) { \ 215 u_char data; \ 216 if (get_user(data, userPtr++)) \ 217 return -EFAULT; \ 218 *left++ = convsample(data); \ 219 if (get_user(data, userPtr++)) \ 220 return -EFAULT; \ 221 *right++ = convsample(data); \ 222 count--; \ 223 } \ 224 } \ 225 *frameUsed += used; \ 226 return used; \ 227 } 228 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) 232 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) 236 237 238 /* 239 * Copy and convert 16 bit data 240 */ 241 242 #define GENERATE_AMI_CT_16(funcname, convsample) \ 243 static ssize_t funcname(const u_char *userPtr, size_t userCount, \ 244 u_char frame[], ssize_t *frameUsed, \ 245 ssize_t frameLeft) \ 246 { \ 247 ssize_t count, used; \ 248 u_short data; \ 249 \ 250 if (!dmasound.soft.stereo) { \ 251 u_char *high = &frame[*frameUsed>>1]; \ 252 u_char *low = high+write_sq_block_size_half; \ 253 count = min_t(size_t, userCount, frameLeft)>>1 & ~1; \ 254 used = count*2; \ 255 while (count > 0) { \ 256 if (get_user(data, ((u_short *)userPtr)++)) \ 257 return -EFAULT; \ 258 data = convsample(data); \ 259 *high++ = data>>8; \ 260 *low++ = (data>>2) & 0x3f; \ 261 count--; \ 262 } \ 263 } else { \ 264 u_char *lefth = &frame[*frameUsed>>2]; \ 265 u_char *leftl = lefth+write_sq_block_size_quarter; \ 266 u_char *righth = lefth+write_sq_block_size_half; \ 267 u_char *rightl = righth+write_sq_block_size_quarter; \ 268 count = min_t(size_t, userCount, frameLeft)>>2 & ~1; \ 269 used = count*4; \ 270 while (count > 0) { \ 271 if (get_user(data, ((u_short *)userPtr)++)) \ 272 return -EFAULT; \ 273 data = convsample(data); \ 274 *lefth++ = data>>8; \ 275 *leftl++ = (data>>2) & 0x3f; \ 276 if (get_user(data, ((u_short *)userPtr)++)) \ 277 return -EFAULT; \ 278 data = convsample(data); \ 279 *righth++ = data>>8; \ 280 *rightl++ = (data>>2) & 0x3f; \ 281 count--; \ 282 } \ 283 } \ 284 *frameUsed += used; \ 285 return used; \ 286 } 287 288 #define AMI_CT_S16BE(x) (x) 289 #define AMI_CT_U16BE(x) ((x) ^ 0x8000) 290 #define AMI_CT_S16LE(x) (le2be16((x))) 291 #define AMI_CT_U16LE(x) (le2be16((x)) ^ 0x8000) 292 293 GENERATE_AMI_CT_16(ami_ct_s16be, AMI_CT_S16BE) 294 GENERATE_AMI_CT_16(ami_ct_u16be, AMI_CT_U16BE) 295 GENERATE_AMI_CT_16(ami_ct_s16le, AMI_CT_S16LE) 296 GENERATE_AMI_CT_16(ami_ct_u16le, AMI_CT_U16LE) 297 298 299 static TRANS transAmiga = { 300 .ct_ulaw = ami_ct_ulaw, 301 .ct_alaw = ami_ct_alaw, 302 .ct_s8 = ami_ct_s8, 303 .ct_u8 = ami_ct_u8, 304 .ct_s16be = ami_ct_s16be, 305 .ct_u16be = ami_ct_u16be, 306 .ct_s16le = ami_ct_s16le, 307 .ct_u16le = ami_ct_u16le, 308 }; 309 310 /*** Low level stuff *********************************************************/ 311 312 static inline void StopDMA(void) 313 { 314 custom.aud[0].audvol = custom.aud[1].audvol = 0; 315 custom.aud[2].audvol = custom.aud[3].audvol = 0; 316 custom.dmacon = AMI_AUDIO_OFF; 317 enable_heartbeat(); 318 } 319 320 static void *AmiAlloc(unsigned int size, int flags) 321 { 322 return amiga_chip_alloc((long)size, "dmasound [Paula]"); 323 } 324 325 static void AmiFree(void *obj, unsigned int size) 326 { 327 amiga_chip_free (obj); 328 } 329 330 static int __init AmiIrqInit(void) 331 { 332 /* turn off DMA for audio channels */ 333 StopDMA(); 334 335 /* Register interrupt handler. */ 336 if (request_irq(IRQ_AMIGA_AUD0, AmiInterrupt, 0, "DMA sound", 337 AmiInterrupt)) 338 return 0; 339 return 1; 340 } 341 342 #ifdef MODULE 343 static void AmiIrqCleanUp(void) 344 { 345 /* turn off DMA for audio channels */ 346 StopDMA(); 347 /* release the interrupt */ 348 free_irq(IRQ_AMIGA_AUD0, AmiInterrupt); 349 } 350 #endif /* MODULE */ 351 352 static void AmiSilence(void) 353 { 354 /* turn off DMA for audio channels */ 355 StopDMA(); 356 } 357 358 359 static void AmiInit(void) 360 { 361 int period, i; 362 363 AmiSilence(); 364 365 if (dmasound.soft.speed) 366 period = amiga_colorclock/dmasound.soft.speed-1; 367 else 368 period = amiga_audio_min_period; 369 dmasound.hard = dmasound.soft; 370 dmasound.trans_write = &transAmiga; 371 372 if (period < amiga_audio_min_period) { 373 /* we would need to squeeze the sound, but we won't do that */ 374 period = amiga_audio_min_period; 375 } else if (period > 65535) { 376 period = 65535; 377 } 378 dmasound.hard.speed = amiga_colorclock/(period+1); 379 380 for (i = 0; i < 4; i++) 381 custom.aud[i].audper = period; 382 amiga_audio_period = period; 383 } 384 385 386 static int AmiSetFormat(int format) 387 { 388 int size; 389 390 /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */ 391 392 switch (format) { 393 case AFMT_QUERY: 394 return dmasound.soft.format; 395 case AFMT_MU_LAW: 396 case AFMT_A_LAW: 397 case AFMT_U8: 398 case AFMT_S8: 399 size = 8; 400 break; 401 case AFMT_S16_BE: 402 case AFMT_U16_BE: 403 case AFMT_S16_LE: 404 case AFMT_U16_LE: 405 size = 16; 406 break; 407 default: /* :-) */ 408 size = 8; 409 format = AFMT_S8; 410 } 411 412 dmasound.soft.format = format; 413 dmasound.soft.size = size; 414 if (dmasound.minDev == SND_DEV_DSP) { 415 dmasound.dsp.format = format; 416 dmasound.dsp.size = dmasound.soft.size; 417 } 418 AmiInit(); 419 420 return format; 421 } 422 423 424 #define VOLUME_VOXWARE_TO_AMI(v) \ 425 (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100) 426 #define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64) 427 428 static int AmiSetVolume(int volume) 429 { 430 dmasound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff); 431 custom.aud[0].audvol = dmasound.volume_left; 432 dmasound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8); 433 custom.aud[1].audvol = dmasound.volume_right; 434 if (dmasound.hard.size == 16) { 435 if (dmasound.volume_left == 64 && dmasound.volume_right == 64) { 436 custom.aud[2].audvol = 1; 437 custom.aud[3].audvol = 1; 438 } else { 439 custom.aud[2].audvol = 0; 440 custom.aud[3].audvol = 0; 441 } 442 } 443 return VOLUME_AMI_TO_VOXWARE(dmasound.volume_left) | 444 (VOLUME_AMI_TO_VOXWARE(dmasound.volume_right) << 8); 445 } 446 447 static int AmiSetTreble(int treble) 448 { 449 dmasound.treble = treble; 450 if (treble < 50) 451 ciaa.pra &= ~0x02; 452 else 453 ciaa.pra |= 0x02; 454 return treble; 455 } 456 457 458 #define AMI_PLAY_LOADED 1 459 #define AMI_PLAY_PLAYING 2 460 #define AMI_PLAY_MASK 3 461 462 463 static void AmiPlayNextFrame(int index) 464 { 465 u_char *start, *ch0, *ch1, *ch2, *ch3; 466 u_long size; 467 468 /* used by AmiPlay() if all doubts whether there really is something 469 * to be played are already wiped out. 470 */ 471 start = write_sq.buffers[write_sq.front]; 472 size = (write_sq.count == index ? write_sq.rear_size 473 : write_sq.block_size)>>1; 474 475 if (dmasound.hard.stereo) { 476 ch0 = start; 477 ch1 = start+write_sq_block_size_half; 478 size >>= 1; 479 } else { 480 ch0 = start; 481 ch1 = start; 482 } 483 484 disable_heartbeat(); 485 custom.aud[0].audvol = dmasound.volume_left; 486 custom.aud[1].audvol = dmasound.volume_right; 487 if (dmasound.hard.size == 8) { 488 custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); 489 custom.aud[0].audlen = size; 490 custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); 491 custom.aud[1].audlen = size; 492 custom.dmacon = AMI_AUDIO_8; 493 } else { 494 size >>= 1; 495 custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); 496 custom.aud[0].audlen = size; 497 custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); 498 custom.aud[1].audlen = size; 499 if (dmasound.volume_left == 64 && dmasound.volume_right == 64) { 500 /* We can play pseudo 14-bit only with the maximum volume */ 501 ch3 = ch0+write_sq_block_size_quarter; 502 ch2 = ch1+write_sq_block_size_quarter; 503 custom.aud[2].audvol = 1; /* we are being affected by the beeps */ 504 custom.aud[3].audvol = 1; /* restoring volume here helps a bit */ 505 custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2); 506 custom.aud[2].audlen = size; 507 custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3); 508 custom.aud[3].audlen = size; 509 custom.dmacon = AMI_AUDIO_14; 510 } else { 511 custom.aud[2].audvol = 0; 512 custom.aud[3].audvol = 0; 513 custom.dmacon = AMI_AUDIO_8; 514 } 515 } 516 write_sq.front = (write_sq.front+1) % write_sq.max_count; 517 write_sq.active |= AMI_PLAY_LOADED; 518 } 519 520 521 static void AmiPlay(void) 522 { 523 int minframes = 1; 524 525 custom.intena = IF_AUD0; 526 527 if (write_sq.active & AMI_PLAY_LOADED) { 528 /* There's already a frame loaded */ 529 custom.intena = IF_SETCLR | IF_AUD0; 530 return; 531 } 532 533 if (write_sq.active & AMI_PLAY_PLAYING) 534 /* Increase threshold: frame 1 is already being played */ 535 minframes = 2; 536 537 if (write_sq.count < minframes) { 538 /* Nothing to do */ 539 custom.intena = IF_SETCLR | IF_AUD0; 540 return; 541 } 542 543 if (write_sq.count <= minframes && 544 write_sq.rear_size < write_sq.block_size && !write_sq.syncing) { 545 /* hmmm, the only existing frame is not 546 * yet filled and we're not syncing? 547 */ 548 custom.intena = IF_SETCLR | IF_AUD0; 549 return; 550 } 551 552 AmiPlayNextFrame(minframes); 553 554 custom.intena = IF_SETCLR | IF_AUD0; 555 } 556 557 558 static irqreturn_t AmiInterrupt(int irq, void *dummy, struct pt_regs *fp) 559 { 560 int minframes = 1; 561 562 custom.intena = IF_AUD0; 563 564 if (!write_sq.active) { 565 /* Playing was interrupted and sq_reset() has already cleared 566 * the sq variables, so better don't do anything here. 567 */ 568 WAKE_UP(write_sq.sync_queue); 569 return IRQ_HANDLED; 570 } 571 572 if (write_sq.active & AMI_PLAY_PLAYING) { 573 /* We've just finished a frame */ 574 write_sq.count--; 575 WAKE_UP(write_sq.action_queue); 576 } 577 578 if (write_sq.active & AMI_PLAY_LOADED) 579 /* Increase threshold: frame 1 is already being played */ 580 minframes = 2; 581 582 /* Shift the flags */ 583 write_sq.active = (write_sq.active<<1) & AMI_PLAY_MASK; 584 585 if (!write_sq.active) 586 /* No frame is playing, disable audio DMA */ 587 StopDMA(); 588 589 custom.intena = IF_SETCLR | IF_AUD0; 590 591 if (write_sq.count >= minframes) 592 /* Try to play the next frame */ 593 AmiPlay(); 594 595 if (!write_sq.active) 596 /* Nothing to play anymore. 597 Wake up a process waiting for audio output to drain. */ 598 WAKE_UP(write_sq.sync_queue); 599 return IRQ_HANDLED; 600 } 601 602 /*** Mid level stuff *********************************************************/ 603 604 605 /* 606 * /dev/mixer abstraction 607 */ 608 609 static void __init AmiMixerInit(void) 610 { 611 dmasound.volume_left = 64; 612 dmasound.volume_right = 64; 613 custom.aud[0].audvol = dmasound.volume_left; 614 custom.aud[3].audvol = 1; /* For pseudo 14bit */ 615 custom.aud[1].audvol = dmasound.volume_right; 616 custom.aud[2].audvol = 1; /* For pseudo 14bit */ 617 dmasound.treble = 50; 618 } 619 620 static int AmiMixerIoctl(u_int cmd, u_long arg) 621 { 622 int data; 623 switch (cmd) { 624 case SOUND_MIXER_READ_DEVMASK: 625 return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE); 626 case SOUND_MIXER_READ_RECMASK: 627 return IOCTL_OUT(arg, 0); 628 case SOUND_MIXER_READ_STEREODEVS: 629 return IOCTL_OUT(arg, SOUND_MASK_VOLUME); 630 case SOUND_MIXER_READ_VOLUME: 631 return IOCTL_OUT(arg, 632 VOLUME_AMI_TO_VOXWARE(dmasound.volume_left) | 633 VOLUME_AMI_TO_VOXWARE(dmasound.volume_right) << 8); 634 case SOUND_MIXER_WRITE_VOLUME: 635 IOCTL_IN(arg, data); 636 return IOCTL_OUT(arg, dmasound_set_volume(data)); 637 case SOUND_MIXER_READ_TREBLE: 638 return IOCTL_OUT(arg, dmasound.treble); 639 case SOUND_MIXER_WRITE_TREBLE: 640 IOCTL_IN(arg, data); 641 return IOCTL_OUT(arg, dmasound_set_treble(data)); 642 } 643 return -EINVAL; 644 } 645 646 647 static int AmiWriteSqSetup(void) 648 { 649 write_sq_block_size_half = write_sq.block_size>>1; 650 write_sq_block_size_quarter = write_sq_block_size_half>>1; 651 return 0; 652 } 653 654 655 static int AmiStateInfo(char *buffer, size_t space) 656 { 657 int len = 0; 658 len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n", 659 dmasound.volume_left); 660 len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n", 661 dmasound.volume_right); 662 if (len >= space) { 663 printk(KERN_ERR "dmasound_paula: overlowed state buffer alloc.\n") ; 664 len = space ; 665 } 666 return len; 667 } 668 669 670 /*** Machine definitions *****************************************************/ 671 672 static SETTINGS def_hard = { 673 .format = AFMT_S8, 674 .stereo = 0, 675 .size = 8, 676 .speed = 8000 677 } ; 678 679 static SETTINGS def_soft = { 680 .format = AFMT_U8, 681 .stereo = 0, 682 .size = 8, 683 .speed = 8000 684 } ; 685 686 static MACHINE machAmiga = { 687 .name = "Amiga", 688 .name2 = "AMIGA", 689 .owner = THIS_MODULE, 690 .dma_alloc = AmiAlloc, 691 .dma_free = AmiFree, 692 .irqinit = AmiIrqInit, 693 #ifdef MODULE 694 .irqcleanup = AmiIrqCleanUp, 695 #endif /* MODULE */ 696 .init = AmiInit, 697 .silence = AmiSilence, 698 .setFormat = AmiSetFormat, 699 .setVolume = AmiSetVolume, 700 .setTreble = AmiSetTreble, 701 .play = AmiPlay, 702 .mixer_init = AmiMixerInit, 703 .mixer_ioctl = AmiMixerIoctl, 704 .write_sq_setup = AmiWriteSqSetup, 705 .state_info = AmiStateInfo, 706 .min_dsp_speed = 8000, 707 .version = ((DMASOUND_PAULA_REVISION<<8) | DMASOUND_PAULA_EDITION), 708 .hardware_afmts = (AFMT_S8 | AFMT_S16_BE), /* h'ware-supported formats *only* here */ 709 .capabilities = DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */ 710 }; 711 712 713 /*** Config & Setup **********************************************************/ 714 715 716 int __init dmasound_paula_init(void) 717 { 718 int err; 719 720 if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_AUDIO)) { 721 if (!request_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40, 722 "dmasound [Paula]")) 723 return -EBUSY; 724 dmasound.mach = machAmiga; 725 dmasound.mach.default_hard = def_hard ; 726 dmasound.mach.default_soft = def_soft ; 727 err = dmasound_init(); 728 if (err) 729 release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40); 730 return err; 731 } else 732 return -ENODEV; 733 } 734 735 static void __exit dmasound_paula_cleanup(void) 736 { 737 dmasound_deinit(); 738 release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40); 739 } 740 741 module_init(dmasound_paula_init); 742 module_exit(dmasound_paula_cleanup); 743 MODULE_LICENSE("GPL"); 744