symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/virtio-audio.c
changeset 71 d00bf4f57250
parent 1 2fb8b9db1c86
equal deleted inserted replaced
70:5158c0d3bde3 71:d00bf4f57250
    37 do { fprintf(stderr, "virtio-audio: error: " fmt , ##args);} while (0)
    37 do { fprintf(stderr, "virtio-audio: error: " fmt , ##args);} while (0)
    38 #endif
    38 #endif
    39 
    39 
    40 #define NUM_STREAMS 2
    40 #define NUM_STREAMS 2
    41 
    41 
       
    42 #define VIRT_CONTROL_QUEUE_SIZE 0x40
       
    43 #define VIRT_DATA_QUEUE_SIZE 0x80
       
    44 
    42 typedef struct {
    45 typedef struct {
    43     struct VirtIOAudio *dev;
    46     struct VirtIOAudio *dev;
    44     VirtQueue *data_vq;
    47     VirtQueue *data_vq;
    45     struct audsettings fmt;
    48     struct audsettings fmt;
    46     SWVoiceOut *out_voice;
    49     SWVoiceOut *out_voice;
    95     int iov_len;
    98     int iov_len;
    96 
    99 
    97     if (stream->in_voice) {
   100     if (stream->in_voice) {
    98         iov_len = stream->elem.in_num;
   101         iov_len = stream->elem.in_num;
    99         iov = stream->elem.in_sg;
   102         iov = stream->elem.in_sg;
   100     } else {
   103     } else if (stream->out_voice) {
   101         iov_len = stream->elem.out_num;
   104         iov_len = stream->elem.out_num;
   102         iov = stream->elem.out_sg;
   105         iov = stream->elem.out_sg;
       
   106     } else
       
   107     {
       
   108         DPRINTF("No voice selected skipping block\n");
       
   109         return 0;
   103     }
   110     }
   104     written = 0;
   111     written = 0;
   105     for (n = 0; total_len > 0 && n < iov_len; n++) {
   112     for (n = 0; total_len > 0 && n < iov_len; n++) {
   106         p = iov[n].iov_base;
   113         p = iov[n].iov_base;
   107         to_write = iov[n].iov_len;
   114         to_write = iov[n].iov_len;
   117         if (to_write > total_len)
   124         if (to_write > total_len)
   118             to_write = total_len;
   125             to_write = total_len;
   119         while (to_write) {
   126         while (to_write) {
   120             if (stream->in_voice) {
   127             if (stream->in_voice) {
   121                 size = AUD_read(stream->in_voice, p, to_write);
   128                 size = AUD_read(stream->in_voice, p, to_write);
       
   129             } else if (stream->out_voice) {
       
   130                 size = AUD_write(stream->out_voice, p, to_write);
   122             } else {
   131             } else {
   123                 size = AUD_write(stream->out_voice, p, to_write);
   132                 size = 0;
   124             }
   133             }
   125             DPRINTF("Copied %d/%d\n", size, to_write);
   134             DPRINTF("Copied %d/%d\n", size, to_write);
   126             if (size == 0) {
   135             if (size == 0) {
   127                 total_len = 0;
   136                 total_len = 0;
   128                 break;
   137                 break;
   139 {
   148 {
   140     VirtIOAudioStream *stream = opaque;
   149     VirtIOAudioStream *stream = opaque;
   141     int n;
   150     int n;
   142 
   151 
   143     DPRINTF("Callback (%d)\n", avail);
   152     DPRINTF("Callback (%d)\n", avail);
       
   153     if ((!stream->in_voice)&&(!stream->out_voice))
       
   154     {
       
   155         DPRINTF("Skipping callback as no voice is selected!\n");
       
   156     }
   144     while (avail) {
   157     while (avail) {
   145         while (stream->data_left == 0) {
   158         while (stream->data_left == 0) {
   146             if (stream->has_buffer) {
   159             if (stream->has_buffer) {
   147                 virtqueue_push(stream->data_vq, &stream->elem, 0);
   160                 virtqueue_push(stream->data_vq, &stream->elem, stream->data_offset);
   148                 virtio_notify(&stream->dev->vdev, stream->data_vq);
   161                 virtio_notify(&stream->dev->vdev, stream->data_vq);
   149                 stream->has_buffer = 0;
   162                 stream->has_buffer = 0;
   150             }
   163             }
   151             if (!virtqueue_pop(stream->data_vq, &stream->elem)) {
   164             if (!virtqueue_pop(stream->data_vq, &stream->elem)) {
   152                 /* Buffer underrun.  */
   165                 /* Buffer underrun.  */
   158             stream->data_left = 0;
   171             stream->data_left = 0;
   159             stream->has_buffer = 1;
   172             stream->has_buffer = 1;
   160             if (stream->in_voice) {
   173             if (stream->in_voice) {
   161                 for (n = 0; n < stream->elem.in_num; n++)
   174                 for (n = 0; n < stream->elem.in_num; n++)
   162                     stream->data_left += stream->elem.in_sg[n].iov_len;
   175                     stream->data_left += stream->elem.in_sg[n].iov_len;
   163             } else {
   176             } else if (stream->out_voice) {
   164                 for (n = 0; n < stream->elem.out_num; n++)
   177                 for (n = 0; n < stream->elem.out_num; n++)
   165                     stream->data_left += stream->elem.out_sg[n].iov_len;
   178                     stream->data_left += stream->elem.out_sg[n].iov_len;
   166             }
   179             }
   167         }
   180         }
   168         if (stream->data_left == 0)
   181         if (stream->data_left == 0)
   173         avail -= n;
   186         avail -= n;
   174         if (!n)
   187         if (!n)
   175             break;
   188             break;
   176     }
   189     }
   177     if (stream->data_left == 0 && stream->has_buffer) {
   190     if (stream->data_left == 0 && stream->has_buffer) {
   178         virtqueue_push(stream->data_vq, &stream->elem, 0);
   191         virtqueue_push(stream->data_vq, &stream->elem, stream->data_offset);
   179         virtio_notify(&stream->dev->vdev, stream->data_vq);
   192         virtio_notify(&stream->dev->vdev, stream->data_vq);
   180         stream->has_buffer = 0;
   193         stream->has_buffer = 0;
   181     }
   194     }
   182 }
   195 }
   183 
   196 
   218     int len;
   231     int len;
   219     size_t out_bytes;
   232     size_t out_bytes;
   220     uint32_t value;
   233     uint32_t value;
   221 
   234 
   222     while (virtqueue_pop(s->cmd_vq, &elem)) {
   235     while (virtqueue_pop(s->cmd_vq, &elem)) {
       
   236         size_t bytes_transferred = 0;
   223         for (out_n = 0; out_n < elem.out_num; out_n++) {
   237         for (out_n = 0; out_n < elem.out_num; out_n++) {
   224             p = (uint32_t *)elem.out_sg[out_n].iov_base;
   238             p = (uint32_t *)elem.out_sg[out_n].iov_base;
   225             len = elem.out_sg[out_n].iov_len;
   239             len = elem.out_sg[out_n].iov_len;
   226             while (len > 0) {
   240             while (len > 0) {
   227                 if (len < 12) {
   241                 if (len < 12) {
   247                     break;
   261                     break;
   248                 case VIRTIO_AUDIO_CMD_SET_FREQ:
   262                 case VIRTIO_AUDIO_CMD_SET_FREQ:
   249                     stream->fmt.freq = value;
   263                     stream->fmt.freq = value;
   250                     break;
   264                     break;
   251                 case VIRTIO_AUDIO_CMD_INIT:
   265                 case VIRTIO_AUDIO_CMD_INIT:
   252                     if (value & 1) {
   266                     out_bytes = 0;
       
   267                     if (value == 1) {
   253                         if (stream->out_voice) {
   268                         if (stream->out_voice) {
   254                             AUD_close_out(&s->card, stream->out_voice);
   269                             AUD_close_out(&s->card, stream->out_voice);
   255                             stream->out_voice = NULL;
   270                             stream->out_voice = NULL;
   256                         }
   271                         }
   257                         stream->in_voice =
   272                         stream->in_voice =
   259                                       "virtio-audio.in",
   274                                       "virtio-audio.in",
   260                                       stream,
   275                                       stream,
   261                                       virtio_audio_callback,
   276                                       virtio_audio_callback,
   262                                       &stream->fmt);
   277                                       &stream->fmt);
   263                         virtio_audio_cmd_result(0, &elem, &out_bytes);
   278                         virtio_audio_cmd_result(0, &elem, &out_bytes);
   264                     } else {
   279                     } else if (value == 0) {
   265                         if (stream->out_voice) {
   280                         if (stream->in_voice) {
   266                             AUD_close_in(&s->card, stream->in_voice);
   281                             AUD_close_in(&s->card, stream->in_voice);
   267                             stream->in_voice = NULL;
   282                             stream->in_voice = NULL;
   268                         }
   283                         }
   269                         stream->out_voice =
   284                         stream->out_voice =
   270                           AUD_open_out(&s->card, stream->out_voice,
   285                           AUD_open_out(&s->card, stream->out_voice,
   272                                        stream,
   287                                        stream,
   273                                        virtio_audio_callback,
   288                                        virtio_audio_callback,
   274                                        &stream->fmt);
   289                                        &stream->fmt);
   275                         value = AUD_get_buffer_size_out(stream->out_voice);
   290                         value = AUD_get_buffer_size_out(stream->out_voice);
   276                         virtio_audio_cmd_result(value, &elem, &out_bytes);
   291                         virtio_audio_cmd_result(value, &elem, &out_bytes);
       
   292                     } else { // let us close all down
       
   293                         if (stream->out_voice) {
       
   294                             AUD_close_out(&s->card, stream->out_voice);
       
   295                             stream->out_voice = NULL;
       
   296                         }
       
   297                         if (stream->in_voice) {
       
   298                             AUD_close_in(&s->card, stream->in_voice);
       
   299                             stream->in_voice = NULL;
       
   300                         }                        
   277                     }
   301                     }
       
   302                     bytes_transferred += out_bytes;
   278                     break;
   303                     break;
   279                 case VIRTIO_AUDIO_CMD_RUN:
   304                 case VIRTIO_AUDIO_CMD_RUN:
   280                     if (stream->in_voice) {
   305                     if (stream->in_voice) {
   281                         AUD_set_active_in(stream->in_voice, value);
   306                         AUD_set_active_in(stream->in_voice, value);
   282                     } else {
   307                     } else if (stream->out_voice) {
   283                         AUD_set_active_out(stream->out_voice, value);
   308                         AUD_set_active_out(stream->out_voice, value);
       
   309                     } else
       
   310                     {
       
   311                         DPRINTF("Cannot execute CMD_RUN as no voice is active\n");
   284                     }
   312                     }
   285                     break;
   313                     break;
   286                 }
   314                 }
   287                 p += 3;
   315                 p += 3;
   288                 len -= 12;
   316                 len -= 12;
   289             }
   317                 bytes_transferred += 12;
   290         }
   318             }
   291         virtqueue_push(s->cmd_vq, &elem, out_bytes);
   319         }
       
   320         virtqueue_push(s->cmd_vq, &elem, bytes_transferred);
       
   321         virtio_notify(vdev, s->cmd_vq);		
   292     }
   322     }
   293 }
   323 }
   294 
   324 
   295 static void virtio_audio_handle_data(VirtIODevice *vdev, VirtQueue *vq)
   325 static void virtio_audio_handle_data(VirtIODevice *vdev, VirtQueue *vq)
   296 {
   326 {
   312         if (stream->in_voice) {
   342         if (stream->in_voice) {
   313             mode = 2;
   343             mode = 2;
   314             if (AUD_is_active_in(stream->in_voice))
   344             if (AUD_is_active_in(stream->in_voice))
   315                 mode |= 1;
   345                 mode |= 1;
   316         } else if (stream->out_voice) {
   346         } else if (stream->out_voice) {
   317             mode |= 4;
   347             mode = 4;
   318             if (AUD_is_active_out(stream->out_voice))
   348             if (AUD_is_active_out(stream->out_voice))
   319                 mode |= 1;
   349                 mode |= 1;
   320         } else {
   350         } else {
   321             mode = 0;
   351             mode = 0;
   322         }
   352         }
   392         return;
   422         return;
   393 
   423 
   394     s->vdev.get_config = virtio_audio_get_config;
   424     s->vdev.get_config = virtio_audio_get_config;
   395     s->vdev.get_features = virtio_audio_get_features;
   425     s->vdev.get_features = virtio_audio_get_features;
   396     s->vdev.set_features = virtio_audio_set_features;
   426     s->vdev.set_features = virtio_audio_set_features;
   397     s->cmd_vq = virtio_add_queue(&s->vdev, 64, virtio_audio_handle_cmd);
   427     s->cmd_vq = virtio_add_queue(&s->vdev, VIRT_CONTROL_QUEUE_SIZE, virtio_audio_handle_cmd);
   398     for (i = 0; i < NUM_STREAMS; i++) {
   428     for (i = 0; i < NUM_STREAMS; i++) {
   399         s->stream[i].data_vq = virtio_add_queue(&s->vdev, 128,
   429         s->stream[i].data_vq = virtio_add_queue(&s->vdev, VIRT_DATA_QUEUE_SIZE,
   400                                                 virtio_audio_handle_data);
   430                                                 virtio_audio_handle_data);
   401         s->stream[i].dev = s;
   431         s->stream[i].dev = s;
   402     }
   432     }
   403 
   433 
   404     AUD_register_card(audio, "virtio-audio", &s->card);
   434     AUD_register_card(audio, "virtio-audio", &s->card);