Index: cmpci.c =================================================================== RCS file: /home/cltien/cvs/cmpci/cmpci.c,v retrieving revision 6.67 retrieving revision 6.72 diff -a -u -r6.67 -r6.72 --- linux-2.4.25/drivers/sound/cmpci.c 31 Mar 2004 17:56:11 -0000 6.67 +++ linux-2.4.25new/drivers/sound/cmpci.c 2 Apr 2004 04:17:24 -0000 6.72 @@ -447,6 +447,8 @@ #define DO_SPDIF_OUT 0x00000100 #define DO_SPDIF_IN 0x00000200 #define DO_SPDIF_LOOP 0x00000400 +#define DO_BIGENDIAN_W 0x00001000 /* used in PowerPC */ +#define DO_BIGENDIAN_R 0x00002000 /* used in PowerPC */ static LIST_HEAD(devs); @@ -1258,6 +1260,8 @@ static int set_dac_channels(struct cm_state *s, int channels) { unsigned long flags; + static unsigned int fmmute = 0; + spin_lock_irqsave(&s->lock, flags); if ((channels > 2) && (channels <= s->max_channels) @@ -1280,9 +1284,11 @@ // ENDBDAC, turn on double DAC mode // XCHGDAC, CH0 -> back, CH1->front maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, ENDBDAC|XCHGDAC); + // mute FM + fmmute = inb(s->iobase + CODEC_CMI_MIXER1) & FMMUTE; + maskb(s->iobase + CODEC_CMI_MIXER1, ~0, FMMUTE); s->status |= DO_DUAL_DAC; // prepare secondary buffer - spin_unlock_irqrestore(&s->lock, flags); ret = prog_dmabuf(s, 1); if (ret) return ret; @@ -1299,9 +1305,7 @@ set_fmt_unlocked(s, fmtm, fmts); set_adc_rate_unlocked(s, s->ratedac); - } - // disable 4 speaker mode (analog duplicate) set_hw_copy(s, 0); s->curr_channels = channels; @@ -1312,7 +1316,6 @@ set_line_as_bass(s, use_line_as_bass); set_mic_as_bass(s, use_mic_as_bass); } - } else { if (s->status & DO_MULTI_CH_HW) { maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~NXCHG, 0); @@ -1320,6 +1323,7 @@ maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, 0); } else if (s->status & DO_DUAL_DAC) { maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~ENDBDAC, 0); + maskb(s->iobase + CODEC_CMI_MIXER1, ~FMMUTE, fmmute); } // enable 4 speaker mode (analog duplicate) set_hw_copy(s, hw_copy); @@ -1330,7 +1334,6 @@ set_line_as_bass(s, 0); set_mic_as_bass(s, 0); } - spin_unlock_irqrestore(&s->lock, flags); return s->curr_channels; } @@ -1977,7 +1980,28 @@ } continue; } - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { + if (s->status & DO_BIGENDIAN_R) { + int i, err; + unsigned char *src, *dst; + unsigned char data[2]; + + src = (unsigned char *) (s->dma_adc.rawbuf + swptr); + dst = (unsigned char *) buffer; + // copy left/right sample at one time + for (i = 0; i < cnt / 2; i++) { + data[0] = src[1]; + data[1] = src[0]; + if ((err = __put_user(data[0], dst++))) { + ret = err; + goto out; + } + if ((err = __put_user(data[1], dst++))) { + ret = err; + goto out; + } + src += 2; + } + } else if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { if (!ret) ret = -EFAULT; goto out; @@ -2097,6 +2121,60 @@ goto out; } swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize; + } else if ((s->status & DO_DUAL_DAC) && (s->status & DO_BIGENDIAN_W)) { + int i, err; + unsigned char *src, *dst0, *dst1; + unsigned char data[8]; + + src = (unsigned char *) buffer; + dst0 = (unsigned char *) (s->dma_dac.rawbuf + swptr); + dst1 = (unsigned char *) (s->dma_adc.rawbuf + swptr); + // copy left/right sample at one time + for (i = 0; i < cnt / 4; i++) { + if ((err = __get_user(data[0], src++))) { + ret = err; + goto out; + } + if ((err = __get_user(data[1], src++))) { + ret = err; + goto out; + } + if ((err = __get_user(data[2], src++))) { + ret = err; + goto out; + } + if ((err = __get_user(data[3], src++))) { + ret = err; + goto out; + } + if ((err = __get_user(data[4], src++))) { + ret = err; + goto out; + } + if ((err = __get_user(data[5], src++))) { + ret = err; + goto out; + } + if ((err = __get_user(data[6], src++))) { + ret = err; + goto out; + } + if ((err = __get_user(data[7], src++))) { + ret = err; + goto out; + } + dst0[0] = data[1]; + dst0[1] = data[0]; + dst0[2] = data[3]; + dst0[3] = data[2]; + dst1[0] = data[5]; + dst1[1] = data[4]; + dst1[2] = data[7]; + dst1[3] = data[6]; + dst0 += 4; + dst1 += 4; + } + swptr = (swptr + cnt) % s->dma_dac.dmasize; } else if (s->status & DO_DUAL_DAC) { int i, err; unsigned long *src, *dst0, *dst1; @@ -2105,7 +2183,7 @@ dst0 = (unsigned long *) (s->dma_dac.rawbuf + swptr); dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr); // copy left/right sample at one time - for (i = 0; i <= cnt / 4; i++) { + for (i = 0; i < cnt / 4; i++) { if ((err = __get_user(*dst0++, src++))) { ret = err; goto out; @@ -2116,6 +2194,28 @@ } } swptr = (swptr + cnt) % s->dma_dac.dmasize; + } else if (s->status & DO_BIGENDIAN_W) { + int i, err; + unsigned char *src, *dst; + unsigned char data[2]; + + src = (unsigned char *) buffer; + dst = (unsigned char *) (s->dma_dac.rawbuf + swptr); + // swap hi/lo bytes for each sample + for (i = 0; i < cnt / 2; i++) { + if ((err = __get_user(data[0], src++))) { + ret = err; + goto out; + } + if ((err = __get_user(data[1], src++))) { + ret = err; + goto out; + } + dst[0] = data[1]; + dst[1] = data[0]; + dst += 2; + } + swptr = (swptr + cnt) % s->dma_dac.dmasize; } else { if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { if (!ret) @@ -2363,7 +2463,7 @@ : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, (int *)arg); case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE|AFMT_U8| + return put_user(AFMT_S16_BE|AFMT_S16_LE|AFMT_U8| ((s->capability & CAN_AC3) ? AFMT_AC3 : 0), (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ @@ -2375,15 +2475,19 @@ if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ready = 0; - if (val == AFMT_S16_LE) + if (val == AFMT_S16_BE || val == AFMT_S16_LE) fmtd |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT; else fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_ADCSHIFT); + if (val == AFMT_S16_BE) + s->status |= DO_BIGENDIAN_R; + else + s->status &= ~DO_BIGENDIAN_R; } if (file->f_mode & FMODE_WRITE) { stop_dac(s); s->dma_dac.ready = 0; - if (val == AFMT_S16_LE || val == AFMT_AC3) + if (val == AFMT_S16_BE || val == AFMT_S16_LE || val == AFMT_AC3) fmtd |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT; else fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_DACSHIFT); @@ -2394,17 +2498,21 @@ set_ac3(s, 0); if (s->status & DO_DUAL_DAC) { s->dma_adc.ready = 0; - if (val == AFMT_S16_LE) + if (val == AFMT_S16_BE || val == AFMT_S16_LE) fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT; else fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT); } + if (val == AFMT_S16_BE) + s->status |= DO_BIGENDIAN_W; + else + s->status &= ~DO_BIGENDIAN_W; } set_fmt(s, fmtm, fmtd); } if (s->status & DO_AC3) return put_user(AFMT_AC3, (int *)arg); return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) - : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? AFMT_S16_LE : AFMT_U8, (int *)arg); + : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? val : AFMT_U8, (int *)arg); case SNDCTL_DSP_POST: return 0; @@ -2747,6 +2855,7 @@ down(&s->open_sem); } if (file->f_mode & FMODE_READ) { + s->status &= ~DO_BIGENDIAN_R; fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT); if ((minor & 0xf) == SND_DEV_DSP16) fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT; @@ -2757,6 +2866,7 @@ set_spdifin(s, 0); } if (file->f_mode & FMODE_WRITE) { + s->status &= ~DO_BIGENDIAN_W; fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT); if ((minor & 0xf) == SND_DEV_DSP16) fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT; @@ -2798,10 +2908,12 @@ set_spdifout(s, 0); /* enable SPDIF loop */ set_spdif_loop(s, spdif_loop); + s->status &= ~DO_BIGENDIAN_W; } if (file->f_mode & FMODE_READ) { stop_adc(s); dealloc_dmabuf(s, &s->dma_adc); + s->status &= ~DO_BIGENDIAN_R; } s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE)); up(&s->open_sem); @@ -2941,6 +3053,9 @@ s->iobase = pci_resource_start(pcidev, 0); s->iosynth = fmio; s->iomidi = mpuio; +#ifdef CONFIG_SOUND_CMPCI_MIDI + s->midi_devc = 0; +#endif s->status = 0; if (s->iobase == 0) return -ENODEV; @@ -3067,12 +3182,15 @@ maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8); if (opl3_detect(s->iosynth, NULL)) ret = opl3_init(s->iosynth, NULL, THIS_MODULE); + else { + maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0); + s->iosynth = 0; + } } } } #endif #ifdef CONFIG_SOUND_CMPCI_MIDI - s->midi_devc = 0; /* disable MPU-401 */ maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0); s->mpu_data.name = "cmpci mpu"; @@ -3100,10 +3218,20 @@ maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x60, reg_mask); /* enable MPU-401 */ if (s->iomidi) { + int timeout; + maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04); - if (!probe_mpu401(&s->mpu_data)) + /* clear all previously received interrupt */ + for (timeout = 900000; timeout > 0; timeout--) { + if ((inb(s->iomidi + 1) && 0x80) == 0) + inb(s->iomidi); + else + break; + } + if (!probe_mpu401(&s->mpu_data)) { s->iomidi = 0; - else { + maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04); + } else { attach_mpu401(&s->mpu_data, THIS_MODULE); s->midi_devc = s->mpu_data.slots[1]; } @@ -3163,11 +3291,14 @@ if (s->gameport.io) { gameport_unregister_port(&s->gameport); release_region(s->gameport.io, CM_EXTENT_GAME); + maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0); } #endif #ifdef CONFIG_SOUND_CMPCI_FM - /* disable FM */ - maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0); + if (s->iosynth) { + /* disable FM */ + maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0); + } #endif #ifdef CONFIG_SOUND_CMPCI_MIDI if (s->iomidi) { @@ -3212,7 +3343,7 @@ static int __init init_cmpci(void) { - printk(KERN_INFO "cmpci: version $Revision: 6.67 $ time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "cmpci: version $Revision: 6.72 $ time " __TIME__ " " __DATE__ "\n"); return pci_module_init(&cm_driver); }