static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_pcm_substream *substream) { struct cygnus_aio_port *aio; unsigned int res = 0, cur = 0, base = 0; struct ringbuf_regs *p_rbuf = NULL; aio = cygnus_dai_get_dma_data(substream); /* * Get the offset of the current read (for playack) or write * index (for capture). Report this value back to the asoc framework. */ p_rbuf = get_ringbuf(substream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) cur = readl(aio->cygaud->audio + p_rbuf->rdaddr); else cur = readl(aio->cygaud->audio + p_rbuf->wraddr); base = readl(aio->cygaud->audio + p_rbuf->baseaddr); /* * Mask off the MSB of the rdaddr,wraddr and baseaddr * since MSB is not part of the address */ res = (cur & 0x7fffffff) - (base & 0x7fffffff); return bytes_to_frames(substream->runtime, res); }
static void cygnus_pcm_period_elapsed(struct snd_pcm_substream *substream) { struct cygnus_aio_port *aio; struct ringbuf_regs *p_rbuf = NULL; u32 regval; aio = cygnus_dai_get_dma_data(substream); p_rbuf = get_ringbuf(substream); /* * If free/full mark interrupt occurs, provide timestamp * to ALSA and update appropriate idx by period_bytes */ snd_pcm_period_elapsed(substream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* Set the ring buffer to full */ regval = readl(aio->cygaud->audio + p_rbuf->rdaddr); regval = regval ^ BIT(31); writel(regval, aio->cygaud->audio + p_rbuf->wraddr); } else { /* Set the ring buffer to empty */ regval = readl(aio->cygaud->audio + p_rbuf->wraddr); writel(regval, aio->cygaud->audio + p_rbuf->rdaddr); } }
static int cygnus_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct cygnus_aio_port *aio; unsigned long bufsize, periodsize; int ret = 0; bool is_play; u32 start; struct ringbuf_regs *p_rbuf = NULL; aio = cygnus_dai_get_dma_data(substream); dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum); bufsize = snd_pcm_lib_buffer_bytes(substream); periodsize = snd_pcm_lib_period_bytes(substream); dev_dbg(rtd->cpu_dai->dev, "%s (buf_size %lu) (period_size %lu)\n", __func__, bufsize, periodsize); configure_ringbuf_regs(substream); p_rbuf = get_ringbuf(substream); start = runtime->dma_addr; is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 1 : 0; ringbuf_set_initial(aio->cygaud->audio, p_rbuf, is_play, start, periodsize, bufsize); return ret; }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(rx_data_process, ev, data) { PROCESS_BEGIN(); /* Process is polled whenever data is available from uart isr */ uint8_t c; while(1) { PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL); /* Read RX ringbuffer. ASCII chars Output when LF is seen. If overflowed, strings are skipped */ do { if (get_ringbuf(&c) == -1) { break; /* No more rx char's in ringbuffer */ } else { if (rx_buf_index == RX_BUFFER_SIZE) { /* Skip current content if buffer full */ rx_buf_index = 0; } rx_buf[rx_buf_index++] = c; if ((c == '\n')||(c == '\r')) { rx_buf[rx_buf_index] = '\0'; printf("RX on UART1: %s", rx_buf); /* Signal event to coap clients. Demo assumes data is consumed before new data comes in */ event_coap_rx_uart1_handler(); rx_buf_index = 0; } } } while (1); } PROCESS_END(); }
/* get data from ring buffer and then write to usb bus */ static void spcp8x5_send(struct usb_serial_port *port) { int count, result; struct spcp8x5_private *priv = usb_get_serial_port_data(port); unsigned long flags; spin_lock_irqsave(&priv->lock, flags); if (priv->write_urb_in_use) { dev_dbg(&port->dev, "write urb still used\n"); spin_unlock_irqrestore(&priv->lock, flags); return; } /* send the 1st urb for writting */ memset(port->write_urb->transfer_buffer , 0x00 , port->bulk_out_size); count = get_ringbuf(priv->buf, port->write_urb->transfer_buffer, port->bulk_out_size); if (count == 0) { spin_unlock_irqrestore(&priv->lock, flags); return; } /* update the urb status */ priv->write_urb_in_use = 1; spin_unlock_irqrestore(&priv->lock, flags); port->write_urb->transfer_buffer_length = count; port->write_urb->dev = port->serial->dev; result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { dev_dbg(&port->dev, "failed submitting write urb, error %d\n", result); priv->write_urb_in_use = 0; /* TODO: reschedule spcp8x5_send */ } schedule_work(&port->work); }