diff options
Diffstat (limited to 'sound/pci/azt3328.c')
-rw-r--r-- | sound/pci/azt3328.c | 234 |
1 files changed, 172 insertions, 62 deletions
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 52a364524262..6e62dafb66cd 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
@@ -33,14 +33,21 @@ | |||
33 | * in the first place >:-P}), | 33 | * in the first place >:-P}), |
34 | * I was forced to base this driver on reverse engineering | 34 | * I was forced to base this driver on reverse engineering |
35 | * (3 weeks' worth of evenings filled with driver work). | 35 | * (3 weeks' worth of evenings filled with driver work). |
36 | * (and no, I did NOT go the easy way: to pick up a PCI128 for 9 Euros) | 36 | * (and no, I did NOT go the easy way: to pick up a SB PCI128 for 9 Euros) |
37 | * | 37 | * |
38 | * The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name | 38 | * The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name |
39 | * for compatibility reasons) has the following features: | 39 | * for compatibility reasons) has the following features: |
40 | * | 40 | * |
41 | * - builtin AC97 conformant codec (SNR over 80dB) | 41 | * - builtin AC97 conformant codec (SNR over 80dB) |
42 | * (really AC97 compliant?? I really doubt it when looking | 42 | * Note that "conformant" != "compliant"!! this chip's mixer register layout |
43 | * at the mixer register layout) | 43 | * *differs* from the standard AC97 layout: |
44 | * they chose to not implement the headphone register (which is not a | ||
45 | * problem since it's merely optional), yet when doing this, they committed | ||
46 | * the grave sin of letting other registers follow immediately instead of | ||
47 | * keeping a headphone dummy register, thereby shifting the mixer register | ||
48 | * addresses illegally. So far unfortunately it looks like the very flexible | ||
49 | * ALSA AC97 support is still not enough to easily compensate for such a | ||
50 | * grave layout violation despite all tweaks and quirks mechanisms it offers. | ||
44 | * - builtin genuine OPL3 | 51 | * - builtin genuine OPL3 |
45 | * - full duplex 16bit playback/record at independent sampling rate | 52 | * - full duplex 16bit playback/record at independent sampling rate |
46 | * - MPU401 (+ legacy address support) FIXME: how to enable legacy addr?? | 53 | * - MPU401 (+ legacy address support) FIXME: how to enable legacy addr?? |
@@ -90,10 +97,15 @@ | |||
90 | * | 97 | * |
91 | * TODO | 98 | * TODO |
92 | * - test MPU401 MIDI playback etc. | 99 | * - test MPU401 MIDI playback etc. |
93 | * - power management. See e.g. intel8x0 or cs4281. | 100 | * - add some power micro-management (disable various units of the card |
94 | * This would be nice since the chip runs a bit hot, and it's *required* | 101 | * as long as they're unused). However this requires I/O ports which I |
95 | * anyway for proper ACPI power management. | 102 | * haven't figured out yet and which thus might not even exist... |
103 | * The standard suspend/resume functionality could probably make use of | ||
104 | * some improvement, too... | ||
96 | * - figure out what all unknown port bits are responsible for | 105 | * - figure out what all unknown port bits are responsible for |
106 | * - figure out some cleverly evil scheme to possibly make ALSA AC97 code | ||
107 | * fully accept our quite incompatible ""AC97"" mixer and thus save some | ||
108 | * code (but I'm not too optimistic that doing this is possible at all) | ||
97 | */ | 109 | */ |
98 | 110 | ||
99 | #include <sound/driver.h> | 111 | #include <sound/driver.h> |
@@ -214,6 +226,16 @@ struct snd_azf3328 { | |||
214 | 226 | ||
215 | struct pci_dev *pci; | 227 | struct pci_dev *pci; |
216 | int irq; | 228 | int irq; |
229 | |||
230 | #ifdef CONFIG_PM | ||
231 | /* register value containers for power management | ||
232 | * Note: not always full I/O range preserved (just like Win driver!) */ | ||
233 | u16 saved_regs_codec [AZF_IO_SIZE_CODEC_PM / 2]; | ||
234 | u16 saved_regs_io2 [AZF_IO_SIZE_IO2_PM / 2]; | ||
235 | u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; | ||
236 | u16 saved_regs_synth[AZF_IO_SIZE_SYNTH_PM / 2]; | ||
237 | u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2]; | ||
238 | #endif | ||
217 | }; | 239 | }; |
218 | 240 | ||
219 | static const struct pci_device_id snd_azf3328_ids[] __devinitdata = { | 241 | static const struct pci_device_id snd_azf3328_ids[] __devinitdata = { |
@@ -317,10 +339,8 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg | |||
317 | else | 339 | else |
318 | dst_vol_left &= ~0x80; | 340 | dst_vol_left &= ~0x80; |
319 | 341 | ||
320 | do | 342 | do { |
321 | { | 343 | if (!left_done) { |
322 | if (!left_done) | ||
323 | { | ||
324 | if (curr_vol_left > dst_vol_left) | 344 | if (curr_vol_left > dst_vol_left) |
325 | curr_vol_left--; | 345 | curr_vol_left--; |
326 | else | 346 | else |
@@ -330,8 +350,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg | |||
330 | left_done = 1; | 350 | left_done = 1; |
331 | outb(curr_vol_left, portbase + 1); | 351 | outb(curr_vol_left, portbase + 1); |
332 | } | 352 | } |
333 | if (!right_done) | 353 | if (!right_done) { |
334 | { | ||
335 | if (curr_vol_right > dst_vol_right) | 354 | if (curr_vol_right > dst_vol_right) |
336 | curr_vol_right--; | 355 | curr_vol_right--; |
337 | else | 356 | else |
@@ -346,8 +365,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg | |||
346 | } | 365 | } |
347 | if (delay) | 366 | if (delay) |
348 | mdelay(delay); | 367 | mdelay(delay); |
349 | } | 368 | } while ((!left_done) || (!right_done)); |
350 | while ((!left_done) || (!right_done)); | ||
351 | snd_azf3328_dbgcallleave(); | 369 | snd_azf3328_dbgcallleave(); |
352 | } | 370 | } |
353 | 371 | ||
@@ -514,15 +532,18 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, | |||
514 | struct snd_ctl_elem_info *uinfo) | 532 | struct snd_ctl_elem_info *uinfo) |
515 | { | 533 | { |
516 | static const char * const texts1[] = { | 534 | static const char * const texts1[] = { |
517 | "ModemOut1", "ModemOut2" | 535 | "Mic1", "Mic2" |
518 | }; | 536 | }; |
519 | static const char * const texts2[] = { | 537 | static const char * const texts2[] = { |
520 | "MonoSelectSource1", "MonoSelectSource2" | 538 | "Mix", "Mic" |
521 | }; | 539 | }; |
522 | static const char * const texts3[] = { | 540 | static const char * const texts3[] = { |
523 | "Mic", "CD", "Video", "Aux", | 541 | "Mic", "CD", "Video", "Aux", |
524 | "Line", "Mix", "Mix Mono", "Phone" | 542 | "Line", "Mix", "Mix Mono", "Phone" |
525 | }; | 543 | }; |
544 | static const char * const texts4[] = { | ||
545 | "pre 3D", "post 3D" | ||
546 | }; | ||
526 | struct azf3328_mixer_reg reg; | 547 | struct azf3328_mixer_reg reg; |
527 | 548 | ||
528 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 549 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
@@ -531,14 +552,19 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, | |||
531 | uinfo->value.enumerated.items = reg.enum_c; | 552 | uinfo->value.enumerated.items = reg.enum_c; |
532 | if (uinfo->value.enumerated.item > reg.enum_c - 1U) | 553 | if (uinfo->value.enumerated.item > reg.enum_c - 1U) |
533 | uinfo->value.enumerated.item = reg.enum_c - 1U; | 554 | uinfo->value.enumerated.item = reg.enum_c - 1U; |
534 | if (reg.reg == IDX_MIXER_ADVCTL2) | 555 | if (reg.reg == IDX_MIXER_ADVCTL2) { |
535 | { | 556 | switch(reg.lchan_shift) { |
536 | if (reg.lchan_shift == 8) /* modem out sel */ | 557 | case 8: /* modem out sel */ |
537 | strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]); | 558 | strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]); |
538 | else /* mono sel source */ | 559 | break; |
560 | case 9: /* mono sel source */ | ||
539 | strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]); | 561 | strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]); |
540 | } | 562 | break; |
541 | else | 563 | case 15: /* PCM Out Path */ |
564 | strcpy(uinfo->value.enumerated.name, texts4[uinfo->value.enumerated.item]); | ||
565 | break; | ||
566 | } | ||
567 | } else | ||
542 | strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item] | 568 | strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item] |
543 | ); | 569 | ); |
544 | return 0; | 570 | return 0; |
@@ -554,12 +580,10 @@ snd_azf3328_get_mixer_enum(struct snd_kcontrol *kcontrol, | |||
554 | 580 | ||
555 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 581 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
556 | val = snd_azf3328_mixer_inw(chip, reg.reg); | 582 | val = snd_azf3328_mixer_inw(chip, reg.reg); |
557 | if (reg.reg == IDX_MIXER_REC_SELECT) | 583 | if (reg.reg == IDX_MIXER_REC_SELECT) { |
558 | { | ||
559 | ucontrol->value.enumerated.item[0] = (val >> 8) & (reg.enum_c - 1); | 584 | ucontrol->value.enumerated.item[0] = (val >> 8) & (reg.enum_c - 1); |
560 | ucontrol->value.enumerated.item[1] = (val >> 0) & (reg.enum_c - 1); | 585 | ucontrol->value.enumerated.item[1] = (val >> 0) & (reg.enum_c - 1); |
561 | } | 586 | } else |
562 | else | ||
563 | ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1); | 587 | ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1); |
564 | 588 | ||
565 | snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n", | 589 | snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n", |
@@ -579,16 +603,13 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, | |||
579 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 603 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
580 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); | 604 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); |
581 | val = oreg; | 605 | val = oreg; |
582 | if (reg.reg == IDX_MIXER_REC_SELECT) | 606 | if (reg.reg == IDX_MIXER_REC_SELECT) { |
583 | { | ||
584 | if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U || | 607 | if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U || |
585 | ucontrol->value.enumerated.item[1] > reg.enum_c - 1U) | 608 | ucontrol->value.enumerated.item[1] > reg.enum_c - 1U) |
586 | return -EINVAL; | 609 | return -EINVAL; |
587 | val = (ucontrol->value.enumerated.item[0] << 8) | | 610 | val = (ucontrol->value.enumerated.item[0] << 8) | |
588 | (ucontrol->value.enumerated.item[1] << 0); | 611 | (ucontrol->value.enumerated.item[1] << 0); |
589 | } | 612 | } else { |
590 | else | ||
591 | { | ||
592 | if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U) | 613 | if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U) |
593 | return -EINVAL; | 614 | return -EINVAL; |
594 | val &= ~((reg.enum_c - 1) << reg.lchan_shift); | 615 | val &= ~((reg.enum_c - 1) << reg.lchan_shift); |
@@ -629,13 +650,14 @@ static const struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata | |||
629 | AZF3328_MIXER_VOL_MONO("Modem Playback Volume", IDX_MIXER_MODEMOUT, 0x1f, 1), | 650 | AZF3328_MIXER_VOL_MONO("Modem Playback Volume", IDX_MIXER_MODEMOUT, 0x1f, 1), |
630 | AZF3328_MIXER_SWITCH("Modem Capture Switch", IDX_MIXER_MODEMIN, 15, 1), | 651 | AZF3328_MIXER_SWITCH("Modem Capture Switch", IDX_MIXER_MODEMIN, 15, 1), |
631 | AZF3328_MIXER_VOL_MONO("Modem Capture Volume", IDX_MIXER_MODEMIN, 0x1f, 1), | 652 | AZF3328_MIXER_VOL_MONO("Modem Capture Volume", IDX_MIXER_MODEMIN, 0x1f, 1), |
632 | AZF3328_MIXER_ENUM("Modem Out Select", IDX_MIXER_ADVCTL2, 2, 8), | 653 | AZF3328_MIXER_ENUM("Mic Select", IDX_MIXER_ADVCTL2, 2, 8), |
633 | AZF3328_MIXER_ENUM("Mono Select Source", IDX_MIXER_ADVCTL2, 2, 9), | 654 | AZF3328_MIXER_ENUM("Mono Output Select", IDX_MIXER_ADVCTL2, 2, 9), |
655 | AZF3328_MIXER_ENUM("PCM", IDX_MIXER_ADVCTL2, 2, 15), /* PCM Out Path, place in front since it controls *both* 3D and Bass/Treble! */ | ||
634 | AZF3328_MIXER_VOL_SPECIAL("Tone Control - Treble", IDX_MIXER_BASSTREBLE, 0x07, 1, 0), | 656 | AZF3328_MIXER_VOL_SPECIAL("Tone Control - Treble", IDX_MIXER_BASSTREBLE, 0x07, 1, 0), |
635 | AZF3328_MIXER_VOL_SPECIAL("Tone Control - Bass", IDX_MIXER_BASSTREBLE, 0x07, 9, 0), | 657 | AZF3328_MIXER_VOL_SPECIAL("Tone Control - Bass", IDX_MIXER_BASSTREBLE, 0x07, 9, 0), |
636 | AZF3328_MIXER_SWITCH("3D Control - Switch", IDX_MIXER_ADVCTL2, 13, 0), | 658 | AZF3328_MIXER_SWITCH("3D Control - Switch", IDX_MIXER_ADVCTL2, 13, 0), |
637 | AZF3328_MIXER_VOL_SPECIAL("3D Control - Wide", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */ | 659 | AZF3328_MIXER_VOL_SPECIAL("3D Control - Width", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */ |
638 | AZF3328_MIXER_VOL_SPECIAL("3D Control - Space", IDX_MIXER_ADVCTL1, 0x03, 8, 0), /* "Hifi 3D" */ | 660 | AZF3328_MIXER_VOL_SPECIAL("3D Control - Depth", IDX_MIXER_ADVCTL1, 0x03, 8, 0), /* "Hifi 3D" */ |
639 | #if MIXER_TESTING | 661 | #if MIXER_TESTING |
640 | AZF3328_MIXER_SWITCH("0", IDX_MIXER_ADVCTL2, 0, 0), | 662 | AZF3328_MIXER_SWITCH("0", IDX_MIXER_ADVCTL2, 0, 0), |
641 | AZF3328_MIXER_SWITCH("1", IDX_MIXER_ADVCTL2, 1, 0), | 663 | AZF3328_MIXER_SWITCH("1", IDX_MIXER_ADVCTL2, 1, 0), |
@@ -813,22 +835,18 @@ snd_azf3328_setdmaa(struct snd_azf3328 *chip, | |||
813 | unsigned int is_running; | 835 | unsigned int is_running; |
814 | 836 | ||
815 | snd_azf3328_dbgcallenter(); | 837 | snd_azf3328_dbgcallenter(); |
816 | if (do_recording) | 838 | if (do_recording) { |
817 | { | ||
818 | /* access capture registers, i.e. skip playback reg section */ | 839 | /* access capture registers, i.e. skip playback reg section */ |
819 | portbase = chip->codec_port + 0x20; | 840 | portbase = chip->codec_port + 0x20; |
820 | is_running = chip->is_recording; | 841 | is_running = chip->is_recording; |
821 | } | 842 | } else { |
822 | else | ||
823 | { | ||
824 | /* access the playback register section */ | 843 | /* access the playback register section */ |
825 | portbase = chip->codec_port + 0x00; | 844 | portbase = chip->codec_port + 0x00; |
826 | is_running = chip->is_playing; | 845 | is_running = chip->is_playing; |
827 | } | 846 | } |
828 | 847 | ||
829 | /* AZF3328 uses a two buffer pointer DMA playback approach */ | 848 | /* AZF3328 uses a two buffer pointer DMA playback approach */ |
830 | if (!is_running) | 849 | if (!is_running) { |
831 | { | ||
832 | unsigned long addr_area2; | 850 | unsigned long addr_area2; |
833 | unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */ | 851 | unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */ |
834 | count_areas = size/2; | 852 | count_areas = size/2; |
@@ -961,6 +979,13 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
961 | chip->is_playing = 1; | 979 | chip->is_playing = 1; |
962 | snd_azf3328_dbgplay("STARTED PLAYBACK\n"); | 980 | snd_azf3328_dbgplay("STARTED PLAYBACK\n"); |
963 | break; | 981 | break; |
982 | case SNDRV_PCM_TRIGGER_RESUME: | ||
983 | snd_azf3328_dbgplay("RESUME PLAYBACK\n"); | ||
984 | /* resume playback if we were active */ | ||
985 | if (chip->is_playing) | ||
986 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | ||
987 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME); | ||
988 | break; | ||
964 | case SNDRV_PCM_TRIGGER_STOP: | 989 | case SNDRV_PCM_TRIGGER_STOP: |
965 | snd_azf3328_dbgplay("STOP PLAYBACK\n"); | 990 | snd_azf3328_dbgplay("STOP PLAYBACK\n"); |
966 | 991 | ||
@@ -988,6 +1013,12 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
988 | chip->is_playing = 0; | 1013 | chip->is_playing = 0; |
989 | snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); | 1014 | snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); |
990 | break; | 1015 | break; |
1016 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1017 | snd_azf3328_dbgplay("SUSPEND PLAYBACK\n"); | ||
1018 | /* make sure playback is stopped */ | ||
1019 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | ||
1020 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) & ~DMA_RESUME); | ||
1021 | break; | ||
991 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1022 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
992 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); | 1023 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); |
993 | break; | 1024 | break; |
@@ -995,6 +1026,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
995 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); | 1026 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); |
996 | break; | 1027 | break; |
997 | default: | 1028 | default: |
1029 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | ||
998 | return -EINVAL; | 1030 | return -EINVAL; |
999 | } | 1031 | } |
1000 | 1032 | ||
@@ -1068,6 +1100,13 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1068 | chip->is_recording = 1; | 1100 | chip->is_recording = 1; |
1069 | snd_azf3328_dbgplay("STARTED CAPTURE\n"); | 1101 | snd_azf3328_dbgplay("STARTED CAPTURE\n"); |
1070 | break; | 1102 | break; |
1103 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1104 | snd_azf3328_dbgplay("RESUME CAPTURE\n"); | ||
1105 | /* resume recording if we were active */ | ||
1106 | if (chip->is_recording) | ||
1107 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | ||
1108 | snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME); | ||
1109 | break; | ||
1071 | case SNDRV_PCM_TRIGGER_STOP: | 1110 | case SNDRV_PCM_TRIGGER_STOP: |
1072 | snd_azf3328_dbgplay("STOP CAPTURE\n"); | 1111 | snd_azf3328_dbgplay("STOP CAPTURE\n"); |
1073 | 1112 | ||
@@ -1088,6 +1127,12 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1088 | chip->is_recording = 0; | 1127 | chip->is_recording = 0; |
1089 | snd_azf3328_dbgplay("STOPPED CAPTURE\n"); | 1128 | snd_azf3328_dbgplay("STOPPED CAPTURE\n"); |
1090 | break; | 1129 | break; |
1130 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1131 | snd_azf3328_dbgplay("SUSPEND CAPTURE\n"); | ||
1132 | /* make sure recording is stopped */ | ||
1133 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | ||
1134 | snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) & ~DMA_RESUME); | ||
1135 | break; | ||
1091 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1136 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1092 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); | 1137 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); |
1093 | break; | 1138 | break; |
@@ -1095,6 +1140,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1095 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); | 1140 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); |
1096 | break; | 1141 | break; |
1097 | default: | 1142 | default: |
1143 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | ||
1098 | return -EINVAL; | 1144 | return -EINVAL; |
1099 | } | 1145 | } |
1100 | 1146 | ||
@@ -1163,8 +1209,7 @@ snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
1163 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), | 1209 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), |
1164 | status); | 1210 | status); |
1165 | 1211 | ||
1166 | if (status & IRQ_TIMER) | 1212 | if (status & IRQ_TIMER) { |
1167 | { | ||
1168 | /* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */ | 1213 | /* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */ |
1169 | if (chip->timer) | 1214 | if (chip->timer) |
1170 | snd_timer_interrupt(chip->timer, chip->timer->sticks); | 1215 | snd_timer_interrupt(chip->timer, chip->timer->sticks); |
@@ -1174,50 +1219,43 @@ snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
1174 | spin_unlock(&chip->reg_lock); | 1219 | spin_unlock(&chip->reg_lock); |
1175 | snd_azf3328_dbgplay("azt3328: timer IRQ\n"); | 1220 | snd_azf3328_dbgplay("azt3328: timer IRQ\n"); |
1176 | } | 1221 | } |
1177 | if (status & IRQ_PLAYBACK) | 1222 | if (status & IRQ_PLAYBACK) { |
1178 | { | ||
1179 | spin_lock(&chip->reg_lock); | 1223 | spin_lock(&chip->reg_lock); |
1180 | which = snd_azf3328_codec_inb(chip, IDX_IO_PLAY_IRQTYPE); | 1224 | which = snd_azf3328_codec_inb(chip, IDX_IO_PLAY_IRQTYPE); |
1181 | /* ack all IRQ types immediately */ | 1225 | /* ack all IRQ types immediately */ |
1182 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); | 1226 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); |
1183 | spin_unlock(&chip->reg_lock); | 1227 | spin_unlock(&chip->reg_lock); |
1184 | 1228 | ||
1185 | if (chip->pcm && chip->playback_substream) | 1229 | if (chip->pcm && chip->playback_substream) { |
1186 | { | ||
1187 | snd_pcm_period_elapsed(chip->playback_substream); | 1230 | snd_pcm_period_elapsed(chip->playback_substream); |
1188 | snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", | 1231 | snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", |
1189 | which, | 1232 | which, |
1190 | inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); | 1233 | inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); |
1191 | } | 1234 | } else |
1192 | else | ||
1193 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); | 1235 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); |
1194 | if (which & IRQ_PLAY_SOMETHING) | 1236 | if (which & IRQ_PLAY_SOMETHING) |
1195 | snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n"); | 1237 | snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n"); |
1196 | } | 1238 | } |
1197 | if (status & IRQ_RECORDING) | 1239 | if (status & IRQ_RECORDING) { |
1198 | { | ||
1199 | spin_lock(&chip->reg_lock); | 1240 | spin_lock(&chip->reg_lock); |
1200 | which = snd_azf3328_codec_inb(chip, IDX_IO_REC_IRQTYPE); | 1241 | which = snd_azf3328_codec_inb(chip, IDX_IO_REC_IRQTYPE); |
1201 | /* ack all IRQ types immediately */ | 1242 | /* ack all IRQ types immediately */ |
1202 | snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); | 1243 | snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); |
1203 | spin_unlock(&chip->reg_lock); | 1244 | spin_unlock(&chip->reg_lock); |
1204 | 1245 | ||
1205 | if (chip->pcm && chip->capture_substream) | 1246 | if (chip->pcm && chip->capture_substream) { |
1206 | { | ||
1207 | snd_pcm_period_elapsed(chip->capture_substream); | 1247 | snd_pcm_period_elapsed(chip->capture_substream); |
1208 | snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", | 1248 | snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", |
1209 | which, | 1249 | which, |
1210 | inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); | 1250 | inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); |
1211 | } | 1251 | } else |
1212 | else | ||
1213 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); | 1252 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); |
1214 | if (which & IRQ_REC_SOMETHING) | 1253 | if (which & IRQ_REC_SOMETHING) |
1215 | snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n"); | 1254 | snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n"); |
1216 | } | 1255 | } |
1217 | /* MPU401 has less critical IRQ requirements | 1256 | /* MPU401 has less critical IRQ requirements |
1218 | * than timer and playback/recording, right? */ | 1257 | * than timer and playback/recording, right? */ |
1219 | if (status & IRQ_MPU401) | 1258 | if (status & IRQ_MPU401) { |
1220 | { | ||
1221 | snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); | 1259 | snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); |
1222 | 1260 | ||
1223 | /* hmm, do we have to ack the IRQ here somehow? | 1261 | /* hmm, do we have to ack the IRQ here somehow? |
@@ -1511,8 +1549,7 @@ snd_azf3328_timer_start(struct snd_timer *timer) | |||
1511 | snd_azf3328_dbgcallenter(); | 1549 | snd_azf3328_dbgcallenter(); |
1512 | chip = snd_timer_chip(timer); | 1550 | chip = snd_timer_chip(timer); |
1513 | delay = ((timer->sticks * seqtimer_scaling) - 1) & TIMER_VALUE_MASK; | 1551 | delay = ((timer->sticks * seqtimer_scaling) - 1) & TIMER_VALUE_MASK; |
1514 | if (delay < 49) | 1552 | if (delay < 49) { |
1515 | { | ||
1516 | /* uhoh, that's not good, since user-space won't know about | 1553 | /* uhoh, that's not good, since user-space won't know about |
1517 | * this timing tweak | 1554 | * this timing tweak |
1518 | * (we need to do it to avoid a lockup, though) */ | 1555 | * (we need to do it to avoid a lockup, though) */ |
@@ -1766,9 +1803,11 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
1766 | goto out_err; | 1803 | goto out_err; |
1767 | } | 1804 | } |
1768 | 1805 | ||
1806 | card->private_data = chip; | ||
1807 | |||
1769 | if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, | 1808 | if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, |
1770 | chip->mpu_port, 1, pci->irq, 0, | 1809 | chip->mpu_port, MPU401_INFO_INTEGRATED, |
1771 | &chip->rmidi)) < 0) { | 1810 | pci->irq, 0, &chip->rmidi)) < 0) { |
1772 | snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); | 1811 | snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); |
1773 | goto out_err; | 1812 | goto out_err; |
1774 | } | 1813 | } |
@@ -1791,6 +1830,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
1791 | } | 1830 | } |
1792 | } | 1831 | } |
1793 | 1832 | ||
1833 | opl3->private_data = chip; | ||
1834 | |||
1794 | sprintf(card->longname, "%s at 0x%lx, irq %i", | 1835 | sprintf(card->longname, "%s at 0x%lx, irq %i", |
1795 | card->shortname, chip->codec_port, chip->irq); | 1836 | card->shortname, chip->codec_port, chip->irq); |
1796 | 1837 | ||
@@ -1834,11 +1875,80 @@ snd_azf3328_remove(struct pci_dev *pci) | |||
1834 | snd_azf3328_dbgcallleave(); | 1875 | snd_azf3328_dbgcallleave(); |
1835 | } | 1876 | } |
1836 | 1877 | ||
1878 | #ifdef CONFIG_PM | ||
1879 | static int | ||
1880 | snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | ||
1881 | { | ||
1882 | struct snd_card *card = pci_get_drvdata(pci); | ||
1883 | struct snd_azf3328 *chip = card->private_data; | ||
1884 | int reg; | ||
1885 | |||
1886 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
1887 | |||
1888 | snd_pcm_suspend_all(chip->pcm); | ||
1889 | |||
1890 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) | ||
1891 | chip->saved_regs_mixer[reg] = inw(chip->mixer_port + reg * 2); | ||
1892 | |||
1893 | /* make sure to disable master volume etc. to prevent looping sound */ | ||
1894 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); | ||
1895 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | ||
1896 | |||
1897 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) | ||
1898 | chip->saved_regs_codec[reg] = inw(chip->codec_port + reg * 2); | ||
1899 | for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) | ||
1900 | chip->saved_regs_io2[reg] = inw(chip->io2_port + reg * 2); | ||
1901 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) | ||
1902 | chip->saved_regs_mpu[reg] = inw(chip->mpu_port + reg * 2); | ||
1903 | for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) | ||
1904 | chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2); | ||
1905 | |||
1906 | pci_set_power_state(pci, PCI_D3hot); | ||
1907 | pci_disable_device(pci); | ||
1908 | pci_save_state(pci); | ||
1909 | return 0; | ||
1910 | } | ||
1911 | |||
1912 | static int | ||
1913 | snd_azf3328_resume(struct pci_dev *pci) | ||
1914 | { | ||
1915 | struct snd_card *card = pci_get_drvdata(pci); | ||
1916 | struct snd_azf3328 *chip = card->private_data; | ||
1917 | int reg; | ||
1918 | |||
1919 | pci_restore_state(pci); | ||
1920 | pci_enable_device(pci); | ||
1921 | pci_set_power_state(pci, PCI_D0); | ||
1922 | pci_set_master(pci); | ||
1923 | |||
1924 | for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) | ||
1925 | outw(chip->saved_regs_io2[reg], chip->io2_port + reg * 2); | ||
1926 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) | ||
1927 | outw(chip->saved_regs_mpu[reg], chip->mpu_port + reg * 2); | ||
1928 | for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) | ||
1929 | outw(chip->saved_regs_synth[reg], chip->synth_port + reg * 2); | ||
1930 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) | ||
1931 | outw(chip->saved_regs_mixer[reg], chip->mixer_port + reg * 2); | ||
1932 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) | ||
1933 | outw(chip->saved_regs_codec[reg], chip->codec_port + reg * 2); | ||
1934 | |||
1935 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
1936 | return 0; | ||
1937 | } | ||
1938 | #endif | ||
1939 | |||
1940 | |||
1941 | |||
1942 | |||
1837 | static struct pci_driver driver = { | 1943 | static struct pci_driver driver = { |
1838 | .name = "AZF3328", | 1944 | .name = "AZF3328", |
1839 | .id_table = snd_azf3328_ids, | 1945 | .id_table = snd_azf3328_ids, |
1840 | .probe = snd_azf3328_probe, | 1946 | .probe = snd_azf3328_probe, |
1841 | .remove = __devexit_p(snd_azf3328_remove), | 1947 | .remove = __devexit_p(snd_azf3328_remove), |
1948 | #ifdef CONFIG_PM | ||
1949 | .suspend = snd_azf3328_suspend, | ||
1950 | .resume = snd_azf3328_resume, | ||
1951 | #endif | ||
1842 | }; | 1952 | }; |
1843 | 1953 | ||
1844 | static int __init | 1954 | static int __init |