📄 dmasound_awacs.c
字号:
#ifdef DEBUG_DMASOUNDprintk("dmasound_pmac: tx-irq: xfer died - patching it up...\n") ;#endif /* to clear DEAD status we must first clear RUN set it to quiescent to be on the safe side */ (void)in_le32(&awacs_txdma->status); out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); write_sq.died++ ; if (!emergency_in_use) { /* new problem */ memcpy((void *)emergency_dbdma_cmd, (void *)cp, sizeof(struct dbdma_cmd)); emergency_in_use = 1; cp = emergency_dbdma_cmd; } /* now bump the values to reflect the amount we haven't yet shifted */ req = ld_le16(&cp->req_count); res = ld_le16(&cp->res_count); phy = ld_le32(&cp->phy_addr); phy += (req - res); st_le16(&cp->req_count, res); st_le16(&cp->res_count, 0); st_le16(&cp->xfer_status, 0); st_le32(&cp->phy_addr, phy); st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS); /* point at our patched up command block */ out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp)); /* we must re-start the controller */ (void)in_le32(&awacs_txdma->status); /* should complete clearing the DEAD status */ out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); break; /* this block is still going */ } if ((stat & ACTIVE) == 0) break; /* this frame is still going */ if (emergency_in_use) emergency_in_use = 0 ; /* done that */ --write_sq.count; --write_sq.active; if (++i >= write_sq.max_count) i = 0; } /* if we stopped and we were not sync-ing - then we under-ran */ if( write_sq.syncing == 0 ){ stat = in_le32(&awacs_txdma->status) ; /* we hit the dbdma_stop */ if( (stat & ACTIVE) == 0 ) write_sq.xruns++ ; } /* if we used some data up then wake the writer to supply some more*/ if (i != write_sq.front) WAKE_UP(write_sq.action_queue); write_sq.front = i; /* but make sure we funnel what we've already got */\ if (!awacs_sleeping) __PMacPlay(); /* make the wake-on-empty conditional on syncing */ if (!write_sq.active && (write_sq.syncing & 1)) WAKE_UP(write_sq.sync_queue); /* any time we're empty */}static voidpmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs){ int stat ; /* For some reason on my PowerBook G3, I get one interrupt * when the interrupt vector is installed (like something is * pending). This happens before the dbdma is initialized by * us, so I just check the command pointer and if it is zero, * just blow it off. */ if (in_le32(&awacs_rxdma->cmdptr) == 0) return; /* We also want to blow 'em off when shutting down. */ if (read_sq.active == 0) return; /* Check multiple buffers in case we were held off from * interrupt processing for a long time. Geeze, I really hope * this doesn't happen. */ while ((stat=awacs_rx_cmds[read_sq.rear].xfer_status)) { /* if we got a "DEAD" status then just log it for now. and try to restart dma. TODO: figure out how best to fix it up */ if (stat & DEAD){#ifdef DEBUG_DMASOUNDprintk("dmasound_pmac: rx-irq: DIED - attempting resurection\n");#endif /* to clear DEAD status we must first clear RUN set it to quiescent to be on the safe side */ (void)in_le32(&awacs_txdma->status); out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); awacs_rx_cmds[read_sq.rear].xfer_status = 0; awacs_rx_cmds[read_sq.rear].res_count = 0; read_sq.died++ ; (void)in_le32(&awacs_txdma->status); /* re-start the same block */ out_le32(&awacs_rxdma->cmdptr, virt_to_bus(&awacs_rx_cmds[read_sq.rear])); /* we must re-start the controller */ (void)in_le32(&awacs_rxdma->status); /* should complete clearing the DEAD status */ out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); return; /* try this block again */ } /* Clear status and move on to next buffer. */ awacs_rx_cmds[read_sq.rear].xfer_status = 0; read_sq.rear++; /* Wrap the buffer ring. */ if (read_sq.rear >= read_sq.max_active) read_sq.rear = 0; /* If we have caught up to the front buffer, bump it. * This will cause weird (but not fatal) results if the * read loop is currently using this buffer. The user is * behind in this case anyway, so weird things are going * to happen. */ if (read_sq.rear == read_sq.front) { read_sq.front++; read_sq.xruns++ ; /* we overan */ if (read_sq.front >= read_sq.max_active) read_sq.front = 0; } } WAKE_UP(read_sq.action_queue);}static voidpmac_awacs_intr(int irq, void *devid, struct pt_regs *regs){ int ctrl = in_le32(&awacs->control); if (ctrl & MASK_PORTCHG) { /* do something when headphone is plugged/unplugged? */ } if (ctrl & MASK_CNTLERR) { int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16; /* CHECK: we just swallow burgundy errors at the moment..*/ if (err != 0 && awacs_revision != AWACS_BURGUNDY) printk(KERN_ERR "dmasound_pmac: error %x\n", err); } /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */ out_le32(&awacs->control, ctrl);}static voidawacs_write(int val){ int count = 300 ; if (awacs_revision >= AWACS_DACA) return ; while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--) udelay(1) ; /* timeout is > 2 samples at lowest rate */ out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22)); (void)in_le32(&awacs->byteswap);}/* this is called when the beep timer expires... it will be called even if the beep has been overidden by other sound output.*/static void awacs_nosound(unsigned long xx){ unsigned long flags; int count = 600 ; /* > four samples at lowest rate */ save_flags(flags); cli(); if (beep_playing) { st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); while ((in_le32(&awacs_txdma->status) & RUN) && count--) udelay(1); /* FIXME: check this is OK for DACA, Tumbler */ out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) | (awacs_rate_index << 8)); if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) out_le32(&awacs->byteswap, BS_VAL); else out_le32(&awacs->byteswap, 0); beep_playing = 0; } restore_flags(flags);}static struct timer_list beep_timer = { function: awacs_nosound};/* we generate the beep with a single dbdma command that loops a buffer forever - without generating interrupts. So, to stop it you have to stop dma output as per awacs_nosound.*/static void awacs_mksound(unsigned int hz, unsigned int ticks){ unsigned long flags; int beep_speed = 0; int srate; int period, ncycles, nsamples; int i, j, f; short *p; static int beep_hz_cache; static int beep_nsamples_cache; static int beep_volume_cache; if (beep_buf == NULL) return; /* quick-hack fix for DACA, Burgundy & Tumbler */ if (awacs_revision >= AWACS_DACA){ srate = 44100 ; } else { for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i) if (awacs_freqs_ok[i]) beep_speed = i; srate = awacs_freqs[beep_speed]; } if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {#if 1 /* this is a hack for broken X server code */ hz = 750; ticks = 12;#else /* cancel beep currently playing */ awacs_nosound(0); return;#endif } save_flags(flags); cli(); del_timer(&beep_timer); if (ticks) { beep_timer.expires = jiffies + ticks; add_timer(&beep_timer); } if (beep_playing || write_sq.active || beep_buf == NULL) { restore_flags(flags); return; /* too hard, sorry :-( */ } beep_playing = 1; st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS); restore_flags(flags); if (hz == beep_hz_cache && beep_vol == beep_volume_cache) { nsamples = beep_nsamples_cache; } else { period = srate * 256 / hz; /* fixed point */ ncycles = BEEP_BUFLEN * 256 / period; nsamples = (period * ncycles) >> 8; f = ncycles * 65536 / nsamples; j = 0; p = beep_buf; for (i = 0; i < nsamples; ++i, p += 2) { p[0] = p[1] = beep_wform[j >> 8] * beep_vol; j = (j + f) & 0xffff; } beep_hz_cache = hz; beep_volume_cache = beep_vol; beep_nsamples_cache = nsamples; } st_le16(&beep_dbdma_cmd->req_count, nsamples*4); st_le16(&beep_dbdma_cmd->xfer_status, 0); st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd)); st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf)); awacs_beep_state = 1; save_flags(flags); cli(); if (beep_playing) { /* i.e. haven't been terminated already */ int count = 300 ; out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); while ((in_le32(&awacs_txdma->status) & RUN) && count--) udelay(1); /* timeout > 2 samples at lowest rate*/ /* FIXME: check this is OK on DACA, Tumbler */ out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) | (beep_speed << 8)); out_le32(&awacs->byteswap, 0); /* force BE */ out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); (void)in_le32(&awacs_txdma->status); out_le32(&awacs_txdma->control, RUN | (RUN << 16)); } restore_flags(flags);}/* used in init and for wake-up */static voidload_awacs(void){ awacs_write(awacs_reg[0] + MASK_ADDR0); awacs_write(awacs_reg[1] + MASK_ADDR1); awacs_write(awacs_reg[2] + MASK_ADDR2); awacs_write(awacs_reg[4] + MASK_ADDR4); if (awacs_revision == AWACS_SCREAMER) { awacs_write(awacs_reg[5] + MASK_ADDR5); wait_ms(100); awacs_write(awacs_reg[6] + MASK_ADDR6); wait_ms(2); awacs_write(awacs_reg[1] + MASK_ADDR1); awacs_write(awacs_reg[7] + MASK_ADDR7); } if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) out_le32(&awacs->byteswap, BS_VAL); else out_le32(&awacs->byteswap, 0);}#ifdef CONFIG_PMAC_PBOOK/* * Save state when going to sleep, restore it afterwards. *//* FIXME: sort out disabling/re-enabling of read stuff as well */static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when){ switch (when) { case PBOOK_SLEEP_NOW: LOCK(); awacs_sleeping = 1; /* Tell the rest of the driver we are now going to sleep */ mb(); if (awacs_revision == AWACS_SCREAMER || awacs_revision == AWACS_AWACS) { awacs_reg1_save = awacs_reg[1]; awacs_reg[1] |= MASK_AMUTE | MASK_CMUTE; awacs_write(MASK_ADDR1 | awacs_reg[1]); } PMacSilence(); /* stop rx - if going - a bit of a daft user... but */ out_le32(&awacs_rxdma->control, (RUN|WAKE|FLUSH << 16)); /* deny interrupts */ switch (awacs_revision) { case AWACS_TUMBLER: tumbler_enter_sleep(); /* Stub for now */ break ; case AWACS_DACA: daca_enter_sleep(); break ; case AWACS_BURGUNDY: break ; case AWACS_SCREAMER: case AWACS_AWACS: default: out_le32(&awacs->control, 0x11) ; break ; } disable_irq(awacs_irq); disable_irq(awacs_tx_irq); disable_irq(awacs_rx_irq); /* Disable sound clock */ pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); /* According to Darwin, we do that after turning off the sound * chip clock. All this will have to be cleaned up once we properly * parse the OF sound-objects */ if (machine_is_compatible("PowerBook3,1") || machine_is_compatible("PowerBook3,2")) { awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; awacs_write(MASK_ADDR1 | awacs_reg[1]); wait_ms(200); } break; case PBOOK_WAKE: /* Enable sound clock */ pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 1); if (machine_is_compatible("PowerBook3,1") || machine_is_compatible("PowerBook3,2")) { wait_ms(100); awacs_reg[1] &= ~(MASK_PAROUT0 | MASK_PAROUT1); awacs_write(MASK_ADDR1 | awacs_reg[1]); wait_ms(300); } else wait_ms(1000); /* restore settings */ switch (awacs_revision) { case AWACS_TUMBLER: headphone_intr(0,0,0); tumbler_leave_sleep(); /* Stub for now */ break; case AWACS_DACA: wait_ms(10); /* Check this !!! */ daca_leave_sleep(); break ; /* dont know how yet */ case AWACS_BURGUNDY: break ; case AWACS_SCREAMER: case AWACS_AWACS: default: load_awacs() ; break ; } /* Recalibrate chip */ if (awacs_revision == AWACS_SCREAMER) awacs_recalibrate(); /* Make sure dma is stopped */ PMacSilence(); enable_irq(awacs_irq); enable_irq(awacs_tx_irq); enable_irq(awacs_rx_irq); /* OK, allow ints back again */ out_le32(&awacs->control, MASK_IEPC | (awacs_rate_index << 8) | 0x11 | (awacs_revision < AWACS_DACA ? MASK_IEE: 0)); if (macio_base && is_pbook_g3) { /* FIXME: should restore the setup we had...*/ out_8(macio_base + 0x37, 3); } else if (is_pbook_3X00) { in_8(latch_base + 0x190); } /* Remove mute */ if (awacs_revision == AWACS_SCREAMER || awacs_revision == AWACS_AWACS) { awacs_reg[1] = awacs_reg1_save; awacs_write(MASK_ADDR1 | awacs_reg[1]); } awacs_sleeping = 0; /* Resume pending sounds. */ /* we don't try to restart input... */ __PMacPlay(); UNLOCK(); } return PBOOK_SLEEP_OK;}#endif /* CONFIG_PMAC_PBOOK *//* All the burgundy functions: *//* Waits for busy flag to clear */inline static voidawacs_burgundy_busy_wait(void){ int count = 50; /* > 2 samples at 44k1 */ while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--) udelay(1) ;}inline static voidawacs_burgundy_extend_wait(void){ int count = 50 ; /* > 2 samples at 44k1 */ while ((!(in_le32(&awacs->codec_stat) & MASK_EXTEND)) && count--) udelay(1) ; count = 50; while ((in_le32(&awacs->codec_stat) & MASK_EXTEND) && count--) udelay(1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -