@@ -335,95 +335,98 @@ typedef struct {
335335 struct virtq_desc vq_desc ;
336336 struct list_head q ;
337337} virtq_desc_queue_node_t ;
338- #define VSND_GEN_TX_QUEUE_HANDLER (NAME_SUFFIX , WRITE ) \
339- static int virtio_snd_tx_desc_##NAME_SUFFIX##_handler( \
340- virtio_snd_state_t *vsnd, const virtio_snd_queue_t *queue, \
341- uint32_t desc_idx, uint32_t *plen) \
342- { \
343- /* A PCM I/O message uses at least 3 virtqueue descriptors to \
344- * represent a PCM data of a period size. \
345- * The first part contains one descriptor as follows: \
346- * struct virtio_snd_pcm_xfer \
347- * The second part contains one or more descriptors \
348- * representing PCM frames. \
349- * the last part contains one descriptor as follows: \
350- * struct virtio_snd_pcm_status \
351- */ \
352- virtq_desc_queue_node_t * node ; \
353- struct list_head q ; \
354- INIT_LIST_HEAD (& q ); \
355- \
356- /* Collect the descriptors */ \
357- int cnt = 0 ; \
358- for (;;) { \
359- /* The size of the `struct virtq_desc` is 4 words */ \
360- const uint32_t * desc = \
361- & vsnd -> ram [queue -> QueueDesc + desc_idx * 4 ]; \
362- \
363- /* Retrieve the fields of current descriptor */ \
364- node = (virtq_desc_queue_node_t * ) malloc (sizeof (* node )); \
365- node -> vq_desc .addr = desc [0 ]; \
366- node -> vq_desc .len = desc [2 ]; \
367- node -> vq_desc .flags = desc [3 ]; \
368- list_push (& node -> q , & q ); \
369- desc_idx = desc [3 ] >> 16 ; /* vq_desc[desc_cnt].next */ \
370- \
371- cnt ++ ; \
372- \
373- /* Leave the loop if next-flag is not set */ \
374- if (!(desc [3 ] & VIRTIO_DESC_F_NEXT )) \
375- break ; \
376- } \
377- \
378- int idx = 0 ; \
379- uint32_t stream_id = 0 ; /* Explicitly set the stream_id */ \
380- uintptr_t base = (uintptr_t ) vsnd -> ram ; \
381- uint32_t ret_len = 0 ; \
382- list_for_each_entry (node , & q , q ) { \
383- uint32_t addr = node -> vq_desc .addr ; \
384- uint32_t len = node -> vq_desc .len ; \
385- if (idx == 0 ) { /* the first descriptor */ \
386- const virtio_snd_pcm_xfer_t * request = \
387- (virtio_snd_pcm_xfer_t * ) (base + addr ); \
388- stream_id = request -> stream_id ; \
389- goto early_continue ; \
390- } else if (idx == cnt - 1 ) { /* the last descriptor */ \
391- virtio_snd_pcm_status_t * response = \
392- (virtio_snd_pcm_status_t * ) (base + addr ); \
393- response -> status = VIRTIO_SND_S_OK ; \
394- response -> latency_bytes = ret_len ; \
395- * plen = sizeof (* response ); \
396- goto early_continue ; \
397- } \
398- \
399- if (WRITE ) { \
400- void * payload = (void * ) (base + addr ); \
401- __virtio_snd_frame_enqueue (payload , len , stream_id ); \
402- } \
403- ret_len += len ; \
404- \
405- early_continue : \
406- idx ++ ; \
407- } \
408- \
409- if (WRITE ) { \
410- virtio_snd_prop_t * props = & vsnd_props [stream_id ]; \
411- props -> lock .buf_ev_notity ++ ; \
412- pthread_cond_signal (& props -> lock .readable ); \
413- } \
414- \
415- /* Tear down the descriptor list and free space. */ \
416- virtq_desc_queue_node_t * tmp = NULL ; \
417- list_for_each_entry_safe (node , tmp , & q , q ) { \
418- list_del (& node -> q ); \
419- free (node ); \
420- } \
421- \
422- return 0 ; \
338+ #define VSND_GEN_TX_QUEUE_HANDLER (NAME_SUFFIX , WRITE ) \
339+ static int virtio_snd_tx_desc_##NAME_SUFFIX##_handler( \
340+ virtio_snd_state_t *vsnd, const virtio_snd_queue_t *queue, \
341+ uint32_t desc_idx, uint32_t *plen) \
342+ { \
343+ /* A PCM I/O message uses at least 3 virtqueue descriptors to \
344+ * represent a PCM data of a period size. \
345+ * The first part contains one descriptor as follows: \
346+ * struct virtio_snd_pcm_xfer \
347+ * The second part contains one or more descriptors \
348+ * representing PCM frames. \
349+ * the last part contains one descriptor as follows: \
350+ * struct virtio_snd_pcm_status \
351+ */ \
352+ virtq_desc_queue_node_t * node ; \
353+ struct list_head q ; \
354+ INIT_LIST_HEAD (& q ); \
355+ \
356+ /* Collect the descriptors */ \
357+ int cnt = 0 ; \
358+ for (;;) { \
359+ /* The size of the `struct virtq_desc` is 4 words */ \
360+ const uint32_t * desc = \
361+ & vsnd -> ram [queue -> QueueDesc + desc_idx * 4 ]; \
362+ \
363+ /* Retrieve the fields of current descriptor */ \
364+ node = (virtq_desc_queue_node_t * ) malloc (sizeof (* node )); \
365+ node -> vq_desc .addr = desc [0 ]; \
366+ node -> vq_desc .len = desc [2 ]; \
367+ node -> vq_desc .flags = desc [3 ]; \
368+ list_push (& node -> q , & q ); \
369+ desc_idx = desc [3 ] >> 16 ; /* vq_desc[desc_cnt].next */ \
370+ \
371+ cnt ++ ; \
372+ \
373+ /* Leave the loop if next-flag is not set */ \
374+ if (!(desc [3 ] & VIRTIO_DESC_F_NEXT )) \
375+ break ; \
376+ } \
377+ \
378+ int idx = 0 ; \
379+ uint32_t stream_id = 0 ; /* Explicitly set the stream_id */ \
380+ uintptr_t base = (uintptr_t ) vsnd -> ram ; \
381+ uint32_t ret_len = 0 ; \
382+ list_for_each_entry (node , & q , q ) { \
383+ uint32_t addr = node -> vq_desc .addr ; \
384+ uint32_t len = node -> vq_desc .len ; \
385+ if (idx == 0 ) { /* the first descriptor */ \
386+ const virtio_snd_pcm_xfer_t * request = \
387+ (virtio_snd_pcm_xfer_t * ) (base + addr ); \
388+ stream_id = request -> stream_id ; \
389+ goto early_continue ; \
390+ } else if (idx == cnt - 1 ) { /* the last descriptor */ \
391+ virtio_snd_pcm_status_t * response = \
392+ (virtio_snd_pcm_status_t * ) (base + addr ); \
393+ response -> status = VIRTIO_SND_S_OK ; \
394+ response -> latency_bytes = ret_len ; \
395+ * plen = sizeof (* response ); \
396+ goto early_continue ; \
397+ } \
398+ \
399+ IIF (WRITE ) \
400+ (/* enqueue frames */ \
401+ void * payload = (void * ) (base + addr ); \
402+ __virtio_snd_frame_enqueue (payload , len , stream_id ); \
403+ , /* flush queue */ \
404+ (void ) stream_id ; \
405+ /* Suppress unused variable warning. */ ) ret_len += len ; \
406+ \
407+ early_continue : \
408+ idx ++ ; \
409+ } \
410+ \
411+ IIF (WRITE ) \
412+ (/* enque frames */ \
413+ virtio_snd_prop_t * props = & vsnd_props [stream_id ]; \
414+ props -> lock .buf_ev_notity ++ ; \
415+ pthread_cond_signal (& props -> lock .readable );, /* flush queue */ \
416+ ) \
417+ \
418+ /* Tear down the descriptor list and free space. */ \
419+ virtq_desc_queue_node_t * tmp = NULL ; \
420+ list_for_each_entry_safe (node , tmp , & q , q ) { \
421+ list_del (& node -> q ); \
422+ free (node ); \
423+ } \
424+ \
425+ return 0 ; \
423426 }
424427
425- VSND_GEN_TX_QUEUE_HANDLER (normal , true );
426- VSND_GEN_TX_QUEUE_HANDLER (flush , false );
428+ VSND_GEN_TX_QUEUE_HANDLER (normal , 1 );
429+ VSND_GEN_TX_QUEUE_HANDLER (flush , 0 );
427430
428431static void virtio_snd_set_fail (virtio_snd_state_t * vsnd )
429432{
0 commit comments