📄 mixart_core.c
字号:
spin_lock_irq(&mgr->msg_lock); /* send the message */ err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, ¬if_event); /* send and mark the notification event pending */ if(err) { spin_unlock_irq(&mgr->msg_lock); up(&mgr->msg_mutex); return err; } set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&mgr->msg_sleep, &wait); spin_unlock_irq(&mgr->msg_lock); timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); remove_wait_queue(&mgr->msg_sleep, &wait); if (! timeout) { /* error - no ack */ up(&mgr->msg_mutex); snd_printk(KERN_ERR "error: notification %x not received\n", notif_event); return -EIO; } up(&mgr->msg_mutex); return 0;}int snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request){ u32 message_frame; unsigned long flags; int err; /* just send the message (do not mark it as a pending one) */ spin_lock_irqsave(&mgr->msg_lock, flags); err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame); spin_unlock_irqrestore(&mgr->msg_lock, flags); /* the answer will be handled by snd_mixart_msg_tasklet() */ atomic_inc(&mgr->msg_processed); return err;}/* common buffer of tasklet and interrupt to send/receive messages */static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4];void snd_mixart_msg_tasklet( unsigned long arg){ mixart_mgr_t *mgr = ( mixart_mgr_t*)(arg); mixart_msg_t resp; u32 msg, addr, type; int err; spin_lock(&mgr->lock); while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) { msg = mgr->msg_fifo[mgr->msg_fifo_readptr]; mgr->msg_fifo_readptr++; mgr->msg_fifo_readptr %= MSG_FIFO_SIZE; /* process the message ... */ addr = msg & ~MSG_TYPE_MASK; type = msg & MSG_TYPE_MASK; switch (type) { case MSG_TYPE_ANSWER: /* answer to a message on that we did not wait for (send_msg_nonblock) */ resp.message_id = 0; resp.data = mixart_msg_data; resp.size = sizeof(mixart_msg_data); err = get_msg(mgr, &resp, addr); if( err < 0 ) { snd_printk(KERN_ERR "tasklet: error(%d) reading mf %x\n", err, msg); break; } switch(resp.message_id) { case MSG_STREAM_START_INPUT_STAGE_PACKET: case MSG_STREAM_START_OUTPUT_STAGE_PACKET: case MSG_STREAM_STOP_INPUT_STAGE_PACKET: case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET: if(mixart_msg_data[0]) snd_printk(KERN_ERR "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", mixart_msg_data[0]); break; default: snd_printdd("tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n", msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size); break; } break; case MSG_TYPE_NOTIFY: /* msg contains no address ! do not get_msg() ! */ case MSG_TYPE_COMMAND: /* get_msg() necessary */ default: snd_printk(KERN_ERR "tasklet doesn't know what to do with message %x\n", msg); } /* switch type */ /* decrement counter */ atomic_dec(&mgr->msg_processed); } /* while there is a msg in fifo */ spin_unlock(&mgr->lock);}irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs){ mixart_mgr_t *mgr = dev_id; int err; mixart_msg_t resp; u32 msg; u32 it_reg; spin_lock(&mgr->lock); it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET)); if( !(it_reg & MIXART_OIDI) ) { /* this device did not cause the interrupt */ spin_unlock(&mgr->lock); return IRQ_NONE; } /* mask all interrupts */ writel_le(MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG(mgr, MIXART_PCI_OMIMR_OFFSET)); /* outdoorbell register clear */ it_reg = readl(MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET)); writel(it_reg, MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET)); /* clear interrupt */ writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) ); /* process interrupt */ while (retrieve_msg_frame(mgr, &msg)) { switch (msg & MSG_TYPE_MASK) { case MSG_TYPE_COMMAND: resp.message_id = 0; resp.data = mixart_msg_data; resp.size = sizeof(mixart_msg_data); err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK); if( err < 0 ) { snd_printk(KERN_ERR "interrupt: error(%d) reading mf %x\n", err, msg); break; } if(resp.message_id == MSG_SERVICES_TIMER_NOTIFY) { int i; mixart_timer_notify_t *notify = (mixart_timer_notify_t*)mixart_msg_data; for(i=0; i<notify->stream_count; i++) { u32 buffer_id = notify->streams[i].buffer_id; unsigned int chip_number = (buffer_id & MIXART_NOTIFY_CARD_MASK) >> MIXART_NOTIFY_CARD_OFFSET; /* card0 to 3 */ unsigned int pcm_number = (buffer_id & MIXART_NOTIFY_PCM_MASK ) >> MIXART_NOTIFY_PCM_OFFSET; /* pcm0 to 3 */ unsigned int sub_number = buffer_id & MIXART_NOTIFY_SUBS_MASK; /* 0 to MIXART_PLAYBACK_STREAMS */ unsigned int is_capture = ((buffer_id & MIXART_NOTIFY_CAPT_MASK) != 0); /* playback == 0 / capture == 1 */ mixart_t *chip = mgr->chip[chip_number]; mixart_stream_t *stream; if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) { snd_printk(KERN_ERR "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n", buffer_id, notify->streams[i].sample_pos_low_part); break; } if (is_capture) stream = &chip->capture_stream[pcm_number]; else stream = &chip->playback_stream[pcm_number][sub_number]; if (stream->substream && (stream->status == MIXART_STREAM_STATUS_RUNNING)) { snd_pcm_runtime_t *runtime = stream->substream->runtime; int elapsed = 0; u64 sample_count = ((u64)notify->streams[i].sample_pos_high_part) << 32; sample_count |= notify->streams[i].sample_pos_low_part; while (1) { u64 new_elapse_pos = stream->abs_period_elapsed + runtime->period_size; if (new_elapse_pos > sample_count) { break; /* while */ } else { elapsed = 1; stream->buf_periods++; if (stream->buf_periods >= runtime->periods) stream->buf_periods = 0; stream->abs_period_elapsed = new_elapse_pos; } } stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed ); if(elapsed) { spin_unlock(&mgr->lock); snd_pcm_period_elapsed(stream->substream); spin_lock(&mgr->lock); } } } break; } if(resp.message_id == MSG_SERVICES_REPORT_TRACES) { if(resp.size > 1) {#ifndef __BIG_ENDIAN /* Traces are text: the swapped msg_data has to be swapped back ! */ int i; for(i=0; i<(resp.size/4); i++) { (mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]); }#endif ((char*)mixart_msg_data)[resp.size - 1] = 0; snd_printdd("MIXART TRACE : %s\n", (char*)mixart_msg_data); } break; } snd_printdd("command %x not handled\n", resp.message_id); break; case MSG_TYPE_NOTIFY: if(msg & MSG_CANCEL_NOTIFY_MASK) { msg &= ~MSG_CANCEL_NOTIFY_MASK; snd_printk(KERN_ERR "canceled notification %x !\n", msg); } /* no break, continue ! */ case MSG_TYPE_ANSWER: /* answer or notification to a message we are waiting for*/ spin_lock(&mgr->msg_lock); if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) { wake_up(&mgr->msg_sleep); mgr->pending_event = 0; } /* answer to a message we did't want to wait for */ else { mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg; mgr->msg_fifo_writeptr++; mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE; tasklet_hi_schedule(&mgr->msg_taskq); } spin_unlock(&mgr->msg_lock); break; case MSG_TYPE_REQUEST: default: snd_printdd("interrupt received request %x\n", msg); /* TODO : are there things to do here ? */ break; } /* switch on msg type */ } /* while there are msgs */ /* allow interrupt again */ writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); spin_unlock(&mgr->lock); return IRQ_HANDLED;}void snd_mixart_init_mailbox(mixart_mgr_t *mgr){ writel( 0, MIXART_MEM( mgr, MSG_HOST_RSC_PROTECTION ) ); writel( 0, MIXART_MEM( mgr, MSG_AGENT_RSC_PROTECTION ) ); /* allow outbound messagebox to generate interrupts */ if(mgr->irq >= 0) { writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); } return;}void snd_mixart_exit_mailbox(mixart_mgr_t *mgr){ /* no more interrupts on outbound messagebox */ writel_le( MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); return;}void snd_mixart_reset_board(mixart_mgr_t *mgr){ /* reset miXart */ writel_be( 1, MIXART_REG(mgr, MIXART_BA1_BRUTAL_RESET_OFFSET) ); return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -