📄 dmasound_awacs.c
字号:
pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_headphone_detect, val | 0x80); /* Trigger it */ headphone_intr(0,NULL,NULL); } } if (!gpio_headphone_irq) { /* Some machine enter this case ? */ printk(KERN_WARNING "tumbler: Headphone detect IRQ not found, enabling all outputs !\n"); write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol); write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol); } return 0;}static inttas_dmasound_cleanup(void){ if (gpio_headphone_irq) free_irq(gpio_headphone_irq, NULL); return 0;}/* We don't support 48k yet */static int tas_freqs[1] = { 44100 } ;static int tas_freqs_ok[1] = { 1 } ;/* don't know what to do really - just have to leave it where * OF left things*/static inttas_set_frame_rate(void){ if (i2s) { out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000); out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200); } dmasound.hard.speed = 44100 ; awacs_rate_index = 0 ; return 44100 ;}static inttas_mixer_ioctl(u_int cmd, u_long arg){ int __user *argp = (int __user *)arg; int data; int rc; rc=tas_device_ioctl(cmd, arg); if (rc != -EINVAL) { return rc; } if ((cmd & ~0xff) == MIXER_WRITE(0) && tas_supported_mixers() & (1<<(cmd & 0xff))) { rc = get_user(data, argp); if (rc<0) return rc; tas_set_mixer_level(cmd & 0xff, data); tas_get_mixer_level(cmd & 0xff, &data); return ioctl_return2(argp, data); } if ((cmd & ~0xff) == MIXER_READ(0) && tas_supported_mixers() & (1<<(cmd & 0xff))) { tas_get_mixer_level(cmd & 0xff, &data); return ioctl_return2(argp, data); } switch(cmd) { case SOUND_MIXER_READ_DEVMASK: data = tas_supported_mixers() | SOUND_MASK_SPEAKER; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_STEREODEVS: data = tas_stereo_mixers(); rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_CAPS: rc = IOCTL_OUT(arg, 0); break; case SOUND_MIXER_READ_RECMASK: // XXX FIXME: find a way to check what is really available */ data = SOUND_MASK_LINE | SOUND_MASK_MIC; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_RECSRC: if (awacs_reg[0] & MASK_MUX_AUDIN) data |= SOUND_MASK_LINE; if (awacs_reg[0] & MASK_MUX_MIC) data |= SOUND_MASK_MIC; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_RECSRC: IOCTL_IN(arg, data); data =0; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_SPEAKER: /* really bell volume */ IOCTL_IN(arg, data); beep_vol = data & 0xff; /* fall through */ case SOUND_MIXER_READ_SPEAKER: rc = IOCTL_OUT(arg, (beep_vol<<8) | beep_vol); break; case SOUND_MIXER_OUTMASK: case SOUND_MIXER_OUTSRC: default: rc = -EINVAL; } return rc;}static void __inittas_init_frame_rates(unsigned int *prop, unsigned int l){ int i ; if (prop) { for (i=0; i<1; i++) tas_freqs_ok[i] = 0; for (l /= sizeof(int); l > 0; --l) { unsigned int r = *prop++; /* Apple 'Fixed' format */ if (r >= 0x10000) r >>= 16; for (i = 0; i < 1; ++i) { if (r == tas_freqs[i]) { tas_freqs_ok[i] = 1; break; } } } } /* else we assume that all the rates are available */}/*** AE - TUMBLER / SNAPPER END ************************************************//*** Low level stuff *********************************************************//* * PCI PowerMac, with AWACS, Screamer, Burgundy, DACA or Tumbler and DBDMA. */static void *PMacAlloc(unsigned int size, int flags){ return kmalloc(size, flags);}static void PMacFree(void *ptr, unsigned int size){ kfree(ptr);}static int __init PMacIrqInit(void){ if (awacs) if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", NULL)) return 0; if (request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", NULL) || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "Built-in Sound in", NULL)) return 0; return 1;}#ifdef MODULEstatic void PMacIrqCleanup(void){ /* turn off input & output dma */ DBDMA_DO_STOP(awacs_txdma); DBDMA_DO_STOP(awacs_rxdma); if (awacs) /* disable interrupts from awacs interface */ out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff); /* Switch off the sound clock */ pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); /* Make sure proper bits are set on pismo & tipb */ if ((machine_is_compatible("PowerBook3,1") || machine_is_compatible("PowerBook3,2")) && awacs) { awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; awacs_write(MASK_ADDR1 | awacs_reg[1]); msleep(200); } if (awacs) free_irq(awacs_irq, NULL); free_irq(awacs_tx_irq, NULL); free_irq(awacs_rx_irq, NULL); if (awacs) iounmap(awacs); if (i2s) iounmap(i2s); iounmap(awacs_txdma); iounmap(awacs_rxdma); release_OF_resource(awacs_node, 0); release_OF_resource(awacs_node, 1); release_OF_resource(awacs_node, 2); if (awacs_tx_cmd_space) kfree(awacs_tx_cmd_space); if (awacs_rx_cmd_space) kfree(awacs_rx_cmd_space); if (beep_dbdma_cmd_space) kfree(beep_dbdma_cmd_space); if (beep_buf) kfree(beep_buf);#ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier(&awacs_sleep_notifier);#endif}#endif /* MODULE */static void PMacSilence(void){ /* turn off output dma */ DBDMA_DO_STOP(awacs_txdma);}/* don't know what to do really - just have to leave it where * OF left things*/static int daca_set_frame_rate(void){ if (i2s) { out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000); out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200); } dmasound.hard.speed = 44100 ; awacs_rate_index = 0 ; return 44100 ;}static int awacs_freqs[8] = { 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350};static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };static intawacs_set_frame_rate(int desired, int catch_r){ int tolerance, i = 8 ; /* * If we have a sample rate which is within catchRadius percent * of the requested value, we don't have to expand the samples. * Otherwise choose the next higher rate. * N.B.: burgundy awacs only works at 44100 Hz. */ do { tolerance = catch_r * awacs_freqs[--i] / 100; if (awacs_freqs_ok[i] && dmasound.soft.speed <= awacs_freqs[i] + tolerance) break; } while (i > 0); dmasound.hard.speed = awacs_freqs[i]; awacs_rate_index = i; out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 ); awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3); awacs_write(awacs_reg[1] | MASK_ADDR1); return dmasound.hard.speed;}static intburgundy_set_frame_rate(void){ awacs_rate_index = 0 ; awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) ; /* XXX disable error interrupt on burgundy for now */ out_le32(&awacs->control, MASK_IEPC | 0 | 0x11 | MASK_IEE); return 44100 ;}static intset_frame_rate(int desired, int catch_r){ switch (awacs_revision) { case AWACS_BURGUNDY: dmasound.hard.speed = burgundy_set_frame_rate(); break ; case AWACS_TUMBLER: case AWACS_SNAPPER: dmasound.hard.speed = tas_set_frame_rate(); break ; case AWACS_DACA: dmasound.hard.speed = daca_set_frame_rate(); break ; default: dmasound.hard.speed = awacs_set_frame_rate(desired, catch_r); break ; } return dmasound.hard.speed ;}static voidawacs_recalibrate(void){ /* Sorry for the horrible delays... I hope to get that improved * by making the whole PM process asynchronous in a future version */ msleep(750); awacs_reg[1] |= MASK_CMUTE | MASK_AMUTE; awacs_write(awacs_reg[1] | MASK_RECALIBRATE | MASK_ADDR1); msleep(1000); awacs_write(awacs_reg[1] | MASK_ADDR1);}static void PMacInit(void){ int tolerance; switch (dmasound.soft.format) { case AFMT_S16_LE: case AFMT_U16_LE: if (hw_can_byteswap) dmasound.hard.format = AFMT_S16_LE; else dmasound.hard.format = AFMT_S16_BE; break; default: dmasound.hard.format = AFMT_S16_BE; break; } dmasound.hard.stereo = 1; dmasound.hard.size = 16; /* set dmasound.hard.speed - on the basis of what we want (soft) * and the tolerance we'll allow. */ set_frame_rate(dmasound.soft.speed, catchRadius) ; tolerance = (catchRadius * dmasound.hard.speed) / 100; if (dmasound.soft.speed >= dmasound.hard.speed - tolerance) { dmasound.trans_write = &transAwacsNormal; dmasound.trans_read = &transAwacsNormalRead; } else { dmasound.trans_write = &transAwacsExpand; dmasound.trans_read = &transAwacsExpandRead; } if (awacs) { if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) out_le32(&awacs->byteswap, BS_VAL); else out_le32(&awacs->byteswap, 0); } expand_bal = -dmasound.soft.speed; expand_read_bal = -dmasound.soft.speed;}static int PMacSetFormat(int format){ int size; int req_format = format; switch (format) { case AFMT_QUERY: return dmasound.soft.format; case AFMT_MU_LAW: case AFMT_A_LAW: case AFMT_U8: case AFMT_S8: size = 8; break; case AFMT_S16_LE: if(!hw_can_byteswap) format = AFMT_S16_BE; case AFMT_S16_BE: size = 16; break; case AFMT_U16_LE: if(!hw_can_byteswap) format = AFMT_U16_BE; case AFMT_U16_BE: size = 16; break; default: /* :-) */ printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n", format); size = 8; format = AFMT_U8; } if (req_format == format) { dmasound.soft.format = format; dmasound.soft.size = size; if (dmasound.minDev == SND_DEV_DSP) { dmasound.dsp.format = format; dmasound.dsp.size = size; } } return format;}#define AWACS_VOLUME_TO_MASK(x) (15 - ((((x) - 1) * 15) / 99))#define AWACS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 15))static int awacs_get_volume(int reg, int lshift){ int volume; volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf); volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8; return volume;}static int awacs_volume_setter(int volume, int n, int mute, int lshift){ int r1, rn; if (mute && volume == 0) { r1 = awacs_reg[1] | mute; } else { r1 = awacs_reg[1] & ~mute; rn = awacs_reg[n] & ~(0xf | (0xf << lshift)); rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift); rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf; awacs_reg[n] = rn; awacs_write((n << 12) | rn); volume = awacs_get_volume(rn, lshift); } if (r1 != awacs_reg[1]) { awacs_reg[1] = r1; awacs_write(r1 | MASK_ADDR1); } return volume;}static int PMacSetVolume(int volume){ printk(KERN_WARNING "Bogus call to PMacSetVolume !\n"); return 0;}static void awacs_setup_for_beep(int speed){ out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) | ((speed > 0 ? speed : awacs_rate_index) << 8)); if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE) && speed == -1) out_le32(&awacs->byteswap, BS_VAL); else out_le32(&awacs->byteswap, 0);}/* CHECK: how much of this *really* needs IRQs masked? */static void __PMacPlay(void){ volatile struct dbdma_cmd *cp; int next_frg, count; count = 300 ; /* > two cycles at the lowest sample rate */ /* what we want to send next */ next_frg = (write_sq.front + write_sq.active) % write_sq.max_count; if (awacs_beep_state) { /* sound takes precedence over beeps */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -