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 void __exit amiga_audio_remove(struct platform_device *pdev) 724 { 725 dmasound_deinit(); 726 } 727 728 /* 729 * amiga_audio_remove() lives in .exit.text. For drivers registered via 730 * module_platform_driver_probe() this is ok because they cannot get unbound at 731 * runtime. So mark the driver struct with __refdata to prevent modpost 732 * triggering a section mismatch warning. 733 */ 734 static struct platform_driver amiga_audio_driver __refdata = { 735 .remove = __exit_p(amiga_audio_remove), 736 .driver = { 737 .name = "amiga-audio", 738 }, 739 }; 740 741 module_platform_driver_probe(amiga_audio_driver, amiga_audio_probe); 742 743 MODULE_DESCRIPTION("Amiga Paula DMA Sound Driver"); 744 MODULE_LICENSE("GPL"); 745 MODULE_ALIAS("platform:amiga-audio"); 746