📄 dmasound_awacs.c
字号:
}static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft){ unsigned int *p = (unsigned int *) &frame[*frameUsed]; unsigned int data = expand_data; unsigned short *up = (unsigned short *) userPtr; int bal = expand_bal; int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; int stereo = dmasound.soft.stereo; int utotal, ftotal; frameLeft >>= 2; userCount >>= (stereo? 2: 1); ftotal = frameLeft; utotal = userCount; while (frameLeft) { unsigned short c; if (bal < 0) { if (userCount == 0) break; if (get_user(data, up++)) return -EFAULT; if (stereo) { if (get_user(c, up++)) return -EFAULT; data = (data << 16) + c; } else data = (data << 16) + data; userCount--; bal += hSpeed; } *p++ = data; frameLeft--; bal -= sSpeed; } expand_bal = bal; expand_data = data; *frameUsed += (ftotal - frameLeft) * 4; utotal -= userCount; return stereo? utotal * 4: utotal * 2;}static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft){ int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); unsigned int *p = (unsigned int *) &frame[*frameUsed]; unsigned int data = expand_data; unsigned short *up = (unsigned short *) userPtr; int bal = expand_bal; int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; int stereo = dmasound.soft.stereo; int utotal, ftotal; frameLeft >>= 2; userCount >>= (stereo? 2: 1); ftotal = frameLeft; utotal = userCount; while (frameLeft) { unsigned short c; if (bal < 0) { if (userCount == 0) break; if (get_user(data, up++)) return -EFAULT; data ^= mask; if (stereo) { if (get_user(c, up++)) return -EFAULT; data = (data << 16) + (c ^ mask); } else data = (data << 16) + data; userCount--; bal += hSpeed; } *p++ = data; frameLeft--; bal -= sSpeed; } expand_bal = bal; expand_data = data; *frameUsed += (ftotal - frameLeft) * 4; utotal -= userCount; return stereo? utotal * 4: utotal * 2;}static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft){ ssize_t count, used; short *p = (short *) &frame[*frameUsed]; int val, stereo = dmasound.soft.stereo; frameLeft >>= 2; if (stereo) userCount >>= 1; used = count = min(userCount, frameLeft); while (count > 0) { u_char data; val = *p++; data = val >> 8; if (put_user(data, (u_char *)userPtr++)) return -EFAULT; if (stereo) { val = *p; data = val >> 8; if (put_user(data, (u_char *)userPtr++)) return -EFAULT; } p++; count--; } *frameUsed += used * 4; return stereo? used * 2: used;}static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft){ ssize_t count, used; short *p = (short *) &frame[*frameUsed]; int val, stereo = dmasound.soft.stereo; frameLeft >>= 2; if (stereo) userCount >>= 1; used = count = min(userCount, frameLeft); while (count > 0) { u_char data; val = *p++; data = (val >> 8) ^ 0x80; if (put_user(data, (u_char *)userPtr++)) return -EFAULT; if (stereo) { val = *p; data = (val >> 8) ^ 0x80; if (put_user(data, (u_char *)userPtr++)) return -EFAULT; } p++; count--; } *frameUsed += used * 4; return stereo? used * 2: used;}static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft){ ssize_t count, used; int stereo = dmasound.soft.stereo; short *fp = (short *) &frame[*frameUsed]; frameLeft >>= 2; userCount >>= (stereo? 2: 1); used = count = min(userCount, frameLeft); if (!stereo) { short *up = (short *) userPtr; while (count > 0) { short data; data = *fp; if (put_user(data, up++)) return -EFAULT; fp+=2; count--; } } else { if (copy_to_user((u_char *)userPtr, fp, count * 4)) return -EFAULT; } *frameUsed += used * 4; return stereo? used * 4: used * 2;}static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft){ ssize_t count, used; int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); int stereo = dmasound.soft.stereo; short *fp = (short *) &frame[*frameUsed]; short *up = (short *) userPtr; frameLeft >>= 2; userCount >>= (stereo? 2: 1); used = count = min(userCount, frameLeft); while (count > 0) { int data; data = *fp++; data ^= mask; if (put_user(data, up++)) return -EFAULT; if (stereo) { data = *fp; data ^= mask; if (put_user(data, up++)) return -EFAULT; } fp++; count--; } *frameUsed += used * 4; return stereo? used * 4: used * 2;}static TRANS transAwacsNormal = { ct_ulaw: pmac_ct_law, ct_alaw: pmac_ct_law, ct_s8: pmac_ct_s8, ct_u8: pmac_ct_u8, ct_s16be: pmac_ct_s16, ct_u16be: pmac_ct_u16, ct_s16le: pmac_ct_s16, ct_u16le: pmac_ct_u16,};static TRANS transAwacsExpand = { ct_ulaw: pmac_ctx_law, ct_alaw: pmac_ctx_law, ct_s8: pmac_ctx_s8, ct_u8: pmac_ctx_u8, ct_s16be: pmac_ctx_s16, ct_u16be: pmac_ctx_u16, ct_s16le: pmac_ctx_s16, ct_u16le: pmac_ctx_u16,};static TRANS transAwacsNormalRead = { ct_s8: pmac_ct_s8_read, ct_u8: pmac_ct_u8_read, ct_s16be: pmac_ct_s16_read, ct_u16be: pmac_ct_u16_read, ct_s16le: pmac_ct_s16_read, ct_u16le: pmac_ct_u16_read,};/*** Low level stuff *********************************************************//* * PCI PowerMac, with AWACS and DBDMA. */static void PMacOpen(void){ MOD_INC_USE_COUNT;}static void PMacRelease(void){ MOD_DEC_USE_COUNT;}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 (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0) || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0) || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0)) return 0; return 1;}#ifdef MODULEstatic void PMacIrqCleanup(void){ /* turn off output dma */ out_le32(&awacs_txdma->control, RUN<<16); /* disable interrupts from awacs interface */ out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);#ifdef CONFIG_PMAC_PBOOK if (is_pbook_G3) { feature_clear(awacs_node, FEATURE_Sound_power); feature_clear(awacs_node, FEATURE_Sound_CLK_enable); }#endif free_irq(awacs_irq, 0); free_irq(awacs_tx_irq, 0); free_irq(awacs_rx_irq, 0); kfree(awacs_tx_cmd_space); if (awacs_rx_cmd_space) kfree(awacs_rx_cmd_space); if (beep_buf) kfree(beep_buf); kd_mksound = orig_mksound;#ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier(&awacs_sleep_notifier);#endif}#endif /* MODULE */static void PMacSilence(void){ /* turn off output dma */ out_le32(&awacs_txdma->control, RUN<<16);}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 void PMacInit(void){ int i, tolerance; switch (dmasound.soft.format) { case AFMT_S16_LE: case AFMT_U16_LE: dmasound.hard.format = AFMT_S16_LE; break; default: dmasound.hard.format = AFMT_S16_BE; break; } dmasound.hard.stereo = 1; dmasound.hard.size = 16; /* * 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 (iMac and later) only works at 44100 Hz. */ i = 8; do { tolerance = catchRadius * awacs_freqs[--i] / 100; if (awacs_freqs_ok[i] && dmasound.soft.speed <= awacs_freqs[i] + tolerance) break; } while (i > 0); if (dmasound.soft.speed >= awacs_freqs[i] - tolerance) dmasound.trans_write = &transAwacsNormal; else dmasound.trans_write = &transAwacsExpand; dmasound.trans_read = &transAwacsNormalRead; dmasound.hard.speed = awacs_freqs[i]; awacs_rate_index = i; /* XXX disable error interrupt on burgundy for now */ out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0)); awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3); awacs_write(awacs_reg[1] | MASK_ADDR1); out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE); /* We really want to execute a DMA stop command, after the AWACS * is initialized. * For reasons I don't understand, it stops the hissing noise * common to many PowerBook G3 systems (like mine :-). */ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); out_le32(&awacs_txdma->control, RUN | (RUN << 16)); expand_bal = -dmasound.soft.speed;}static int PMacSetFormat(int format){ int size; 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_BE: case AFMT_U16_BE: case AFMT_S16_LE: case AFMT_U16_LE: size = 16; break; default: /* :-) */ printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n", format); size = 8; format = AFMT_U8; } dmasound.soft.format = format; dmasound.soft.size = size; if (dmasound.minDev == SND_DEV_DSP) { dmasound.dsp.format = format; dmasound.dsp.size = size; } PMacInit(); 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){ return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);}static void PMacPlay(void){ volatile struct dbdma_cmd *cp; int i, count; unsigned long flags; save_flags(flags); cli(); if (awacs_beep_state) { /* sound takes precedence over beeps */ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) | (awacs_rate_index << 8)); out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE); out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(write_sq.front+write_sq.active) % write_sq.max_count]))); beep_playing = 0; awacs_beep_state = 0; } i = write_sq.front + write_sq.active; if (i >= write_sq.max_count) i -= write_sq.max_count; while (write_sq.active < 2 && write_sq.active < write_sq.count) { count = (write_sq.count == write_sq.active + 1)?write_sq.rear_size:write_sq.block_size; if (count < write_sq.block_size && !write_sq.syncing) /* last block not yet filled, and we're not syncing. */ break; cp = &awacs_tx_cmds[i]; st_le16(&cp->req_count, count); st_le16(&cp->xfer_status, 0); if (++i >= write_sq.max_count) i = 0; out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP); out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS); if (write_sq.active == 0) out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp)); out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); ++write_sq.active; } restore_flags(flags);}static void PMacRecord(void){ unsigned long flags; if (read_sq.active) return; save_flags(flags); cli(); /* This is all we have to do......Just start it up. */ out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); read_sq.active = 1; restore_flags(flags);}static voidpmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs){ int i = write_sq.front; int stat; volatile struct dbdma_cmd *cp; while (write_sq.active > 0) { cp = &awacs_tx_cmds[i]; stat = ld_le16(&cp->xfer_status); if ((stat & ACTIVE) == 0) break; /* this frame is still going */ --write_sq.count; --write_sq.active; if (++i >= write_sq.max_count) i = 0; } if (i != write_sq.front) WAKE_UP(write_sq.action_queue); write_sq.front = i; PMacPlay();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -