#define MSG_TYPE_MASK 0x00000003 /* mask for following types */ #define MSG_TYPE_NOTIFY 0 /* embedded -> driver (only notification, do not get_msg() !) */ #define MSG_TYPE_COMMAND 1 /* driver <-> embedded (a command has no answer) */ #define MSG_TYPE_REQUEST 2 /* driver -> embedded (request will get an answer back) */ #define MSG_TYPE_ANSWER 3 /* embedded -> driver */ #define MSG_CANCEL_NOTIFY_MASK 0x80000000 /* this bit is set for a notification that has been canceled */
/* * send a message to miXart. return: the msg_frame used for this message
*/ /* call with mgr->msg_lock held! */ staticint send_msg( struct mixart_mgr *mgr, struct mixart_msg *msg, int max_answersize, int mark_pending,
u32 *msg_event)
{
u32 headptr, tailptr;
u32 msg_frame_address; int i;
/* copy message data to card memory */ for( i=0; i < msg->size; i+=4 ) {
writel_be( *(u32*)(msg->data + i), MIXART_MEM(mgr, MSG_HEADER_SIZE + msg_frame_address + i) );
}
if( mark_pending ) { if( *msg_event ) { /* the pending event is the notification we wait for ! */
mgr->pending_event = *msg_event;
} else { /* the pending event is the answer we wait for (same address than the request)! */
mgr->pending_event = msg_frame_address;
/* copy address back to caller */
*msg_event = msg_frame_address;
}
}
/* mark the frame as a request (will have an answer) */
msg_frame_address |= MSG_TYPE_REQUEST;
/* post the frame */
headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD));
int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int max_resp_size, void *resp_data)
{ struct mixart_msg resp;
u32 msg_frame = 0; /* set to 0, so it's no notification to wait for, but the answer */ int err;
wait_queue_entry_t wait; long timeout;
init_waitqueue_entry(&wait, current);
mutex_lock(&mgr->msg_lock); /* send the message */
err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */ if (err) {
mutex_unlock(&mgr->msg_lock); return err;
}
if (! timeout) { /* error - no ack */
dev_err(&mgr->pci->dev, "error: notification %x not received\n", notif_event); return -EIO;
}
return 0;
}
int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request)
{
u32 message_frame; int err;
/* just send the message (do not mark it as a pending one) */
mutex_lock(&mgr->msg_lock);
err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame);
mutex_unlock(&mgr->msg_lock);
/* the answer will be handled by snd_struct mixart_msgasklet() */
atomic_inc(&mgr->msg_processed);
return err;
}
/* common buffer of interrupt to send/receive messages */ static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4];
/* 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 ) {
dev_err(&mgr->pci->dev, "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])
dev_err(&mgr->pci->dev, "error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n",
mixart_msg_data[0]); break; default:
dev_dbg(&mgr->pci->dev, "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:
dev_err(&mgr->pci->dev, "doesn't know what to do with message %x\n",
msg);
} /* switch type */
it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET)); if( !(it_reg & MIXART_OIDI) ) { /* this device did not cause the interrupt */ return IRQ_NONE;
}
/* mask all interrupts */
writel_le(MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG(mgr, MIXART_PCI_OMIMR_OFFSET));
if(elapsed) {
mutex_unlock(&mgr->lock);
snd_pcm_period_elapsed(stream->substream);
mutex_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++) {
((__be32*)mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]);
} #endif
((char*)mixart_msg_data)[resp.size - 1] = 0;
dev_dbg(&mgr->pci->dev, "MIXART TRACE : %s\n",
(char *)mixart_msg_data);
} break;
}
dev_dbg(&mgr->pci->dev, "command %x not handled\n",
resp.message_id); break;
case MSG_TYPE_NOTIFY: if(msg & MSG_CANCEL_NOTIFY_MASK) {
msg &= ~MSG_CANCEL_NOTIFY_MASK;
dev_err(&mgr->pci->dev, "canceled notification %x !\n", msg);
}
fallthrough; case MSG_TYPE_ANSWER: /* answer or notification to a message we are waiting for*/
mutex_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;
snd_mixart_process_msg(mgr);
}
mutex_unlock(&mgr->msg_lock); break; case MSG_TYPE_REQUEST: default:
dev_dbg(&mgr->pci->dev, "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));
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.1Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.