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: overflowed 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"); 741