Re: [Alsa-devel] [RFC 4/8] snd-aoa: add i2sbus
From: Takashi Iwai <hidden>
Date: 2006-06-02 14:23:26
Also in:
alsa-devel
At Thu, 01 Jun 2006 13:58:48 +0200, Johannes Berg wrote:
quoted hunk ↗ jump to hunk
--- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c +static int clock_and_divisors(int mclk, int sclk, int rate, int *out) +{ + /* sclk must be derived from mclk! */ + if (mclk % sclk) + return -1; + /* derive sclk register value */ + if (i2s_sf_sclkdiv(mclk / sclk, out)) + return -1; + + if (I2S_CLOCK_SPEED_18MHz % rate == 0) { + if ((I2S_CLOCK_SPEED_18MHz / rate) % mclk == 0) {
Equivalent with "I2S_CLOCK_SPEED_18MHZ % (rate * mclk) == 0" ?
+static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
+{(snip)
+ list_for_each_entry(cii, &sdev->codec_list, list) {
+ if (cii->codec->open) {
+ err = cii->codec->open(cii, pi->substream);
+ if (err) {
+ result = err;
+ goto out_unlock;What happens if the first code is opened but fail the secondary? No need to close the first?
+static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in)
+{
+ struct pcm_info *pi;
+ u32 fc;
+
+ get_pcm_info(i2sdev, in, &pi, NULL);
+
+ fc = in_le32(&i2sdev->intfregs->frame_count);
+ fc = fc - pi->frame_count;
+
+ return (bytes_to_frames(pi->substream->runtime,
+ pi->current_period *
+ snd_pcm_lib_period_bytes(pi->substream)) + fc) % pi->substream->runtime->buffer_size;
+}
+
+static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
+{
+ struct pcm_info *pi;
+ u32 fc;
+ u32 delta;
+
+ spin_lock(&i2sdev->low_lock);
+ get_pcm_info(i2sdev, in, &pi, NULL);
+ if (!pi->substream) {
+ printk(KERN_INFO "i2sbus: got %s irq while not active!\n",
+ in ? "rx" : "tx");
+ goto out_unlock;
+ }
+
+ fc = in_le32(&i2sdev->intfregs->frame_count);
+ /* a counter overflow does not change the calculation. */
+ delta = fc - pi->frame_count;
+
+ /* update current_period */
+ while (delta >= pi->substream->runtime->period_size) {
+ pi->current_period++;
+ delta = delta - pi->substream->runtime->period_size;
+ }
+
+ if (unlikely(delta)) {
+ /* Some interrupt came late, so check the dbdma.
+ * This special case exists to syncronize the frame_count with the
+ * dbdma transfers, but is hit every once in a while. */
+ int period;
+
+ period = (in_le32(&pi->dbdma->cmdptr) - pi->dbdma_ring.bus_cmd_start) / sizeof(struct dbdma_cmd);
+ pi->current_period = pi->current_period % pi->substream->runtime->periods;
+
+ while (pi->current_period != period) {
+ pi->current_period = (pi->current_period + 1) % pi->substream->runtime->periods;
+ /* Set delta to zero, as the frame_count value is too high (otherwise the code path
+ * will not be executed).
+ * This is to correct the fact that the frame_count is too low at the beginning
+ * due to the dbdma's buffer. */
+ delta = 0;Too long lines...
+/* FIXME: this function needs an error handling strategy with labels */
+int
+i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
+ struct codec_info *ci, void *data)
+{
+ int err, in = 0, out = 0;
+ struct transfer_info *tmp;
+ struct i2sbus_dev *i2sdev = soundbus_dev_to_i2sbus_dev(dev);
+ struct codec_info_item *cii;
+
+ if (!dev->pcmname || dev->pcmid == -1) {
+ printk(KERN_ERR "i2sbus: pcm name and id must be set!\n");No error return?
+ /* well, we really should support scatter/gather DMA */ + /* FIXME FIXME FIXME: If this fails, we BUG() when the alsa layer + * later tries to allocate memory. Apparently we should be setting + * some device pointer for that ... + */ + snd_pcm_lib_preallocate_pages_for_all( + dev->pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(macio_get_pci_dev(i2sdev->macio)), + 64 * 1024, 64 * 1024);
Is the comment true? Yes, you have to set the device pointer via snd_pcm_lib_preallocate*(). But it must be OK even if preallocate fails.
quoted hunk ↗ jump to hunk
--- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c +static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, + struct dbdma_command_mem *r, + int numcmds) +{ + /* one more for rounding */ + r->size = (numcmds+1) * sizeof(struct dbdma_cmd); + /* We use the PCI APIs for now until the generic one gets fixed + * enough or until we get some macio-specific versions + */ + r->space = pci_alloc_consistent(macio_get_pci_dev(i2sdev->macio), + r->size, + &r->bus_addr);
Better to use dma_alloc_coherent(). pci_alloc_consistent() implies GFP_ATOMIC.
+static irqreturn_t i2sbus_bus_intr(int irq, void *devid, struct pt_regs *regs)
+{
+ struct i2sbus_dev *dev = devid;
+ u32 intreg;
+
+ spin_lock(&dev->low_lock);
+ intreg = in_le32(&dev->intfregs->intr_ctl);
+
+ printk(KERN_INFO "i2sbus: interrupt, intr reg is 0x%x!\n", intreg);Should this be really always printed? Takashi