📄 pcxhr_core.c
字号:
err = pcxhr_download_dsp(mgr, boot); if (err) return err; /* wait for hf5 bit */ return pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, PCXHR_MBOX0_HF5, PCXHR_MBOX0_HF5, PCXHR_TIMEOUT_DSP, &dummy);}/* * load the final dsp image */int pcxhr_load_dsp_binary(struct pcxhr_mgr *mgr, const struct firmware *dsp){ int err; unsigned char dummy; err = pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_BOARD_FUNC, 0); if (err) return err; err = pcxhr_send_it_dsp(mgr, PCXHR_IT_DOWNLOAD_DSP, 0); if (err) return err; err = pcxhr_download_dsp(mgr, dsp); if (err) return err; /* wait for chk bit */ return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK, PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &dummy);}struct pcxhr_cmd_info { u32 opcode; /* command word */ u16 st_length; /* status length */ u16 st_type; /* status type (RMH_SSIZE_XXX) */};/* RMH status type */enum { RMH_SSIZE_FIXED = 0, /* status size fix (st_length = 0..x) */ RMH_SSIZE_ARG = 1, /* status size given in the LSB byte (used with st_length = 1) */ RMH_SSIZE_MASK = 2, /* status size given in bitmask (used with st_length = 1) */};/* * Array of DSP commands */static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = {[CMD_VERSION] = { 0x010000, 1, RMH_SSIZE_FIXED },[CMD_SUPPORTED] = { 0x020000, 4, RMH_SSIZE_FIXED },[CMD_TEST_IT] = { 0x040000, 1, RMH_SSIZE_FIXED },[CMD_SEND_IRQA] = { 0x070001, 0, RMH_SSIZE_FIXED },[CMD_ACCESS_IO_WRITE] = { 0x090000, 1, RMH_SSIZE_ARG },[CMD_ACCESS_IO_READ] = { 0x094000, 1, RMH_SSIZE_ARG },[CMD_ASYNC] = { 0x0a0000, 1, RMH_SSIZE_ARG },[CMD_MODIFY_CLOCK] = { 0x0d0000, 0, RMH_SSIZE_FIXED },[CMD_RESYNC_AUDIO_INPUTS] = { 0x0e0000, 0, RMH_SSIZE_FIXED },[CMD_GET_DSP_RESOURCES] = { 0x100000, 4, RMH_SSIZE_FIXED },[CMD_SET_TIMER_INTERRUPT] = { 0x110000, 0, RMH_SSIZE_FIXED },[CMD_RES_PIPE] = { 0x400000, 0, RMH_SSIZE_FIXED },[CMD_FREE_PIPE] = { 0x410000, 0, RMH_SSIZE_FIXED },[CMD_CONF_PIPE] = { 0x422101, 0, RMH_SSIZE_FIXED },[CMD_STOP_PIPE] = { 0x470004, 0, RMH_SSIZE_FIXED },[CMD_PIPE_SAMPLE_COUNT] = { 0x49a000, 2, RMH_SSIZE_FIXED },[CMD_CAN_START_PIPE] = { 0x4b0000, 1, RMH_SSIZE_FIXED },[CMD_START_STREAM] = { 0x802000, 0, RMH_SSIZE_FIXED },[CMD_STREAM_OUT_LEVEL_ADJUST] = { 0x822000, 0, RMH_SSIZE_FIXED },[CMD_STOP_STREAM] = { 0x832000, 0, RMH_SSIZE_FIXED },[CMD_UPDATE_R_BUFFERS] = { 0x840000, 0, RMH_SSIZE_FIXED },[CMD_FORMAT_STREAM_OUT] = { 0x860000, 0, RMH_SSIZE_FIXED },[CMD_FORMAT_STREAM_IN] = { 0x870000, 0, RMH_SSIZE_FIXED },[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED }, /* stat_len = nb_streams * 2 */[CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED },};#ifdef CONFIG_SND_DEBUG_DETECTstatic char* cmd_names[] = {[CMD_VERSION] = "CMD_VERSION",[CMD_SUPPORTED] = "CMD_SUPPORTED",[CMD_TEST_IT] = "CMD_TEST_IT",[CMD_SEND_IRQA] = "CMD_SEND_IRQA",[CMD_ACCESS_IO_WRITE] = "CMD_ACCESS_IO_WRITE",[CMD_ACCESS_IO_READ] = "CMD_ACCESS_IO_READ",[CMD_ASYNC] = "CMD_ASYNC",[CMD_MODIFY_CLOCK] = "CMD_MODIFY_CLOCK",[CMD_RESYNC_AUDIO_INPUTS] = "CMD_RESYNC_AUDIO_INPUTS",[CMD_GET_DSP_RESOURCES] = "CMD_GET_DSP_RESOURCES",[CMD_SET_TIMER_INTERRUPT] = "CMD_SET_TIMER_INTERRUPT",[CMD_RES_PIPE] = "CMD_RES_PIPE",[CMD_FREE_PIPE] = "CMD_FREE_PIPE",[CMD_CONF_PIPE] = "CMD_CONF_PIPE",[CMD_STOP_PIPE] = "CMD_STOP_PIPE",[CMD_PIPE_SAMPLE_COUNT] = "CMD_PIPE_SAMPLE_COUNT",[CMD_CAN_START_PIPE] = "CMD_CAN_START_PIPE",[CMD_START_STREAM] = "CMD_START_STREAM",[CMD_STREAM_OUT_LEVEL_ADJUST] = "CMD_STREAM_OUT_LEVEL_ADJUST",[CMD_STOP_STREAM] = "CMD_STOP_STREAM",[CMD_UPDATE_R_BUFFERS] = "CMD_UPDATE_R_BUFFERS",[CMD_FORMAT_STREAM_OUT] = "CMD_FORMAT_STREAM_OUT",[CMD_FORMAT_STREAM_IN] = "CMD_FORMAT_STREAM_IN",[CMD_STREAM_SAMPLE_COUNT] = "CMD_STREAM_SAMPLE_COUNT",[CMD_AUDIO_LEVEL_ADJUST] = "CMD_AUDIO_LEVEL_ADJUST",};#endifstatic int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh){ int err; int i; u32 data; u32 size_mask; unsigned char reg; int max_stat_len; if (rmh->stat_len < PCXHR_SIZE_MAX_STATUS) max_stat_len = PCXHR_SIZE_MAX_STATUS; else max_stat_len = rmh->stat_len; for (i = 0; i < rmh->stat_len; i++) { /* wait for receiver full */ err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF, PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®); if (err) { snd_printk(KERN_ERR "ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n", reg, i); return err; } /* read data */ data = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL); /* need to update rmh->stat_len on the fly ?? */ if (i==0) { if (rmh->dsp_stat != RMH_SSIZE_FIXED) { if (rmh->dsp_stat == RMH_SSIZE_ARG) { rmh->stat_len = (u16)(data & 0x0000ff) + 1; data &= 0xffff00; } else { /* rmh->dsp_stat == RMH_SSIZE_MASK */ rmh->stat_len = 1; size_mask = data; while (size_mask) { if (size_mask & 1) rmh->stat_len++; size_mask >>= 1; } } } }#ifdef CONFIG_SND_DEBUG_DETECT if (rmh->cmd_idx < CMD_LAST_INDEX) snd_printdd(" stat[%d]=%x\n", i, data);#endif if (i < max_stat_len) rmh->stat[i] = data; } if (rmh->stat_len > max_stat_len) { snd_printdd("PCXHR : rmh->stat_len=%x too big\n", rmh->stat_len); rmh->stat_len = max_stat_len; } return 0;}static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh){ int err; int i; u32 data; unsigned char reg; snd_assert(rmh->cmd_len<PCXHR_SIZE_MAX_CMD, return -EINVAL); err = pcxhr_send_it_dsp(mgr, PCXHR_IT_MESSAGE, 1); if (err) { snd_printk(KERN_ERR "pcxhr_send_message : ED_DSP_CRASHED\n"); return err; } /* wait for chk bit */ err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK, PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, ®); if (err) return err; /* reset irq chk */ err = pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_CHK, 1); if (err) return err; /* wait for chk bit == 0*/ err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK, 0, PCXHR_TIMEOUT_DSP, ®); if (err) return err; data = rmh->cmd[0]; if (rmh->cmd_len > 1) data |= 0x008000; /* MASK_MORE_THAN_1_WORD_COMMAND */ else data &= 0xff7fff; /* MASK_1_WORD_COMMAND */#ifdef CONFIG_SND_DEBUG_DETECT if (rmh->cmd_idx < CMD_LAST_INDEX) snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]);#endif err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, ®); if (err) return err; PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF); PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF); PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF)); if (rmh->cmd_len > 1) { /* send length */ data = rmh->cmd_len - 1; err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, ®); if (err) return err; PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF); PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF); PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF)); for (i=1; i < rmh->cmd_len; i++) { /* send other words */ data = rmh->cmd[i];#ifdef CONFIG_SND_DEBUG_DETECT if (rmh->cmd_idx < CMD_LAST_INDEX) snd_printdd(" cmd[%d]=%x\n", i, data);#endif err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, ®); if (err) return err; PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF); PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, (data>>8)&0xFF); PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, (data&0xFF)); } } /* wait for chk bit */ err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK, PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, ®); if (err) return err; /* test status ISR */ if (reg & PCXHR_ISR_HI08_ERR) { /* ERROR, wait for receiver full */ err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF, PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®); if (err) { snd_printk(KERN_ERR "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg); return err; } /* read error code */ data = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL); snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n", rmh->cmd_idx, data); err = -EINVAL; } else { /* read the response data */ err = pcxhr_read_rmh_status(mgr, rmh); } /* reset semaphore */ if (pcxhr_send_it_dsp(mgr, PCXHR_IT_RESET_SEMAPHORE, 1) < 0) return -EIO; return err;}/** * pcxhr_init_rmh - initialize the RMH instance * @rmh: the rmh pointer to be initialized * @cmd: the rmh command to be set */void pcxhr_init_rmh(struct pcxhr_rmh *rmh, int cmd){ snd_assert(cmd < CMD_LAST_INDEX, return); rmh->cmd[0] = pcxhr_dsp_cmds[cmd].opcode; rmh->cmd_len = 1; rmh->stat_len = pcxhr_dsp_cmds[cmd].st_length; rmh->dsp_stat = pcxhr_dsp_cmds[cmd].st_type; rmh->cmd_idx = cmd;}void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh *rmh, int capture, unsigned int param1, unsigned int param2, unsigned int param3){ snd_assert(param1 <= MASK_FIRST_FIELD); if (capture) rmh->cmd[0] |= 0x800; /* COMMAND_RECORD_MASK */ if (param1) rmh->cmd[0] |= (param1 << FIELD_SIZE); if (param2) { snd_assert(param2 <= MASK_FIRST_FIELD); rmh->cmd[0] |= param2; } if(param3) { snd_assert(param3 <= MASK_DSP_WORD); rmh->cmd[1] = param3; rmh->cmd_len = 2; }}/* * pcxhr_send_msg - send a DSP message with spinlock * @rmh: the rmh record to send and receive * * returns 0 if successful, or a negative error code. */int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh){ unsigned long flags; int err; spin_lock_irqsave(&mgr->msg_lock, flags); err = pcxhr_send_msg_nolock(mgr, rmh); spin_unlock_irqrestore(&mgr->msg_lock, flags); return err;}static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr){ int start_mask = PCXHR_INPL(mgr, PCXHR_PLX_MBOX2); /* least segnificant 12 bits are the pipe states for the playback audios */ /* next 12 bits are the pipe states for the capture audios * (PCXHR_PIPE_STATE_CAPTURE_OFFSET) */ start_mask &= 0xffffff; snd_printdd("CMD_PIPE_STATE MBOX2=0x%06x\n", start_mask); return start_mask;}#define PCXHR_PIPE_STATE_CAPTURE_OFFSET 12#define MAX_WAIT_FOR_DSP 20static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int *retry){ struct pcxhr_rmh rmh; int err; int audio = 0; *retry = 0; while (audio_mask) { if (audio_mask & 1) { pcxhr_init_rmh(&rmh, CMD_CAN_START_PIPE); if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET) { /* can start playback pipe */ pcxhr_set_pipe_cmd_params(&rmh, 0, audio, 0, 0); } else { /* can start capture pipe */ pcxhr_set_pipe_cmd_params(&rmh, 1, audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET, 0, 0); } err = pcxhr_send_msg(mgr, &rmh); if (err) { snd_printk(KERN_ERR "error pipe start (CMD_CAN_START_PIPE) err=%x!\n", err); return err; } /* if the pipe couldn't be prepaired for start, retry it later */ if (rmh.stat[0] == 0) *retry |= (1<<audio); } audio_mask>>=1; audio++; } return 0;}static int pcxhr_stop_pipes(struct pcxhr_mgr *mgr, int audio_mask){ struct pcxhr_rmh rmh; int err; int audio = 0; while (audio_mask) { if (audio_mask & 1) { pcxhr_init_rmh(&rmh, CMD_STOP_PIPE); if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET) { /* stop playback pipe */ pcxhr_set_pipe_cmd_params(&rmh, 0, audio, 0, 0); } else { /* stop capture pipe */ pcxhr_set_pipe_cmd_params(&rmh, 1, audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET, 0, 0); } err = pcxhr_send_msg(mgr, &rmh); if (err) { snd_printk(KERN_ERR "error pipe stop (CMD_STOP_PIPE) err=%x!\n", err); return err; } } audio_mask>>=1; audio++; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -