On Fri, Nov 12, 2010 at 1:35 PM, Jaroslav Kysela perex@perex.cz wrote:
On Fri, 12 Nov 2010, Manu Abraham wrote:
On Thu, Nov 11, 2010 at 6:04 PM, Manu Abraham abraham.manu@gmail.com wrote:
On Thu, Nov 11, 2010 at 4:00 PM, Jaroslav Kysela perex@perex.cz wrote:
On Thu, 11 Nov 2010, Manu Abraham wrote:
On Wed, Nov 10, 2010 at 11:35 PM, Jaroslav Kysela perex@perex.cz wrote:
I adapted the whole thing to make the buffersize divided amongst the XS2D_BUFFERS (8):
Probably yes.
I hope the mapping of the buffers is okay ? It looks thus, now ..
From information you sent me about hw privately, I think that the period_bytes must be 4096 or multiple of this value with minumum count of periods 8 (or multiple of 8). Otherwise you get a non-continuous memory area (the hw uses only portion of system memory page, thus there'll be gaps). The problem is that we have MMAP_COMPLEX mode, but no application can handle (does not implement) this mmap mode and I'm not sure, if we can even describe the DMA buffer size layout for this case for your specific hw.
I would use:
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4096);
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, 8);
And define periods_min = 8 (max to multiple 8 - choose your max limit) and period_bytes_min to 4096 (max to multiple 4096 - choose your max limit).
Note that -EIO means that your driver does not called snd_pcm_period_elapsed() and/or the pointer callback returns wrong position to the audio ring buffer.
Ok, modified it, also added in code to acquire the stream, It's a bit more complete now. The crazy part that I do see now, is that I see an inconsistent lock state with the hda_intel driver which is the soundcard on my system. But I don't understand why the locking on it has to become inconsistent on loading this driver.
Ok, I found the reason: I was passing a single page for the page_table, which I guess corrupted the whole stack !!
Eventually, I fixed the same. but ran into another issue ? Should trigger not sleep or something that way ? Currently, I see the issue as follows in the log, but if the ops->run() callback is commented out I don't get that weird message/error about lock states.
Now, ops->run(), ie xs2dtl_run() is called with other other streams, such as an MPEG stream, where it doesn't show any issues.
Any idea, why uncommenting ops->run() produces that message ? Should trigger not sleep ? Confused ...
Trigger must be fast without any sleeping. Only fast spinlocks are allowed. If you need sleep, just activate a tasklet and do the start job in the tasklet or a thread.
Ok, I have now a tasklet to handle the commands. But still I do have the same issue. if i comment out ops->run() things do look sane. But with the tasklet, also added in, I can see the same error, but almost immediately, the machine freezes completely. I see quite a lot of junk in the syslog, looks like there has been memory corruption. Any idea, what could be going wrong ?
static int saa7231_hw_params(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params) { struct saa7231_audio *audio = snd_pcm_substream_chip(pcm); struct saa7231_dev *saa7231 = audio->saa7231; struct snd_pcm_runtime *rt = pcm->runtime;
struct saa7231_dmabuf *buffer; struct saa7231_stream *stream; struct saa7231_dmabuf *dmabuf;
struct page **ptable;
void *mem; void *dma_area;
int i, j, pages, bytes, periods, bufsiz, idx;
#define MAX_ENTRIES_PER_PAGE (PAGE_SIZE / 8) #define PAGES_PER_XS2D(__pages) (__pages / XS2D_BUFFERS) #define BUFSIZE_PER_XS2D(__size) (__size / XS2D_BUFFERS)
dprintk(SAA7231_DEBUG, 1, "DEBUG: ()");
periods = params_periods(params); bytes = params_period_bytes(params); bufsiz = params_buffer_bytes(params); pages = snd_sgbuf_aligned_pages(bufsiz);
audio->bufsize = bufsiz;
dprintk(SAA7231_DEBUG, 1, "bufsiz=%d periods=%d bytes=%d pages=%d", bufsiz, periods, bytes, pages);
/* enable stream */ /* initializing 8 buffer with "pages" pages each .. */ stream = saa7231_stream_init(saa7231, AUDIO_CAPTURE, ADAPTER_INT, 0, (pages / XS2D_BUFFERS)); if (!stream) { dprintk(SAA7231_ERROR, 1, "ERROR: Registering stream"); return -ENOMEM; } audio->stream = stream; buffer = stream->dmabuf; saa7231_add_irqevent(saa7231, 43, SAA7231_EDGE_RISING, saa7231_audio_evhandler, "AS2D_AVIS"); dprintk(SAA7231_DEBUG, 1, "Mapping %d buffers with %d pages each", XS2D_BUFFERS, PAGES_PER_XS2D(pages));
dprintk(SAA7231_DEBUG, 1, "Page Table array size=%d", pages); ptable = kzalloc((sizeof (struct page) * pages), GFP_KERNEL); if (!ptable) { dprintk(SAA7231_ERROR, 1, "ERROR: No memory to allocate virtual map"); return -ENOMEM; } audio->ptable = ptable; idx = 0;
for (i = 0; i < XS2D_BUFFERS; i ++) { dmabuf = &buffer[i]; mem = dmabuf->vmalloc; for (j = 0; j < PAGES_PER_XS2D(pages); j++) { BUG_ON(idx > pages); dprintk(SAA7231_DEBUG, 1, "Mapping Page:%d from XS2D_BUFFER:%d to PTA Offset:%d", j, i, idx); ptable[idx] = virt_to_page(mem); mem += PAGE_SIZE; idx += 1; } }
dma_area = vmap(ptable, pages, VM_MAP, PAGE_KERNEL); rt->dma_area = dma_area; rt->dma_bytes = pages * PAGE_SIZE; rt->dma_addr = 0;
return 0; }
static void saa7231_cmd_tasklet(unsigned long data) { struct saa7231_audio *audio = (struct saa7231_audio *) data; struct saa7231_dev *saa7231 = audio->saa7231; struct saa7231_stream *stream = audio->stream; struct stream_ops *ops = &stream->ops; int cmd = audio->cmd;
int err = 0;
switch (cmd) { case SNDRV_PCM_TRIGGER_START: dprintk(SAA7231_DEBUG, 1, "Trying to START stream, cmd=%d", cmd); if (ops->run) { err = ops->run(stream); if (err) { dprintk(SAA7231_ERROR, 1, "ERROR: starting stream, err=%d", err); // return -EIO; } } break; case SNDRV_PCM_TRIGGER_STOP: dprintk(SAA7231_DEBUG, 1, "Trying to STOP stream, cmd=%d", cmd); if (ops->stop) { err = ops->stop(stream); if (err) { dprintk(SAA7231_ERROR, 1, "ERROR: stopping stream, err=%d", err); // return -EIO; } } break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_SUSPEND: dprintk(SAA7231_DEBUG, 1, "Trying to PAUSE stream, cmd=%d", cmd); if (ops->pause) { err = ops->pause(stream); if (err) { dprintk(SAA7231_ERROR, 1, "ERROR: pausing stream, err=%d", err); // return -EIO; } } break; default: dprintk(SAA7231_DEBUG, 1, "Unknown command, cmd=%d", cmd); snd_BUG(); // return -EINVAL; } }
/* * saa7231_capture_trigger() * * This callback is called when the PCM is started, stoppped or paused. */ static int saa7231_capture_trigger(struct snd_pcm_substream *pcm, int cmd) { struct saa7231_audio *audio = snd_pcm_substream_chip(pcm); struct saa7231_dev *saa7231 = audio->saa7231;
dprintk(SAA7231_DEBUG, 1, "Scheduling cmd tasklet with cmd=%d", cmd); audio->cmd = cmd; tasklet_schedule(&audio->cmd_tasklet); return 0; }
static snd_pcm_uframes_t saa7231_capture_pointer(struct snd_pcm_substream *pcm) { struct saa7231_audio *audio = snd_pcm_substream_chip(pcm); struct saa7231_dev *saa7231 = audio->saa7231;
dprintk(SAA7231_DEBUG, 1, "DEBUG:()");
return 0; //bytes_to_frames(rt, played); }
int saa7231_alsa_init(struct saa7231_dev *saa7231) { int err; struct snd_card *card; struct saa7231_audio *audio;
struct saa7231_config *config = saa7231->config; struct card_desc *desc = config->desc;
dprintk(SAA7231_DEBUG, 1, "Initializing Audio ..");
audio = kzalloc(sizeof (struct saa7231_audio), GFP_KERNEL); if (!audio) { dprintk(SAA7231_ERROR, 1, "ERROR: Out of memory, audio=NULL"); return -ENOMEM; }
err = snd_card_create(index[saa7231->num], id[saa7231->num], THIS_MODULE, 0, &card); if (err < 0) { dprintk(SAA7231_ERROR, 1, "snd_card_create() failed, err=%d", err); return err; } saa7231->audio = audio; audio->saa7231 = saa7231; audio->card = card;
err = snd_saa7231_pcm_init(audio); if (err) { dprintk(SAA7231_ERROR, 1, "PCM Initialization failed, err=%d", err); return err; } err = snd_saa7231_mixer_init(audio); if (err) { dprintk(SAA7231_ERROR, 1, "Mixer initialization failed, err=%d", err); return err; }
snd_card_set_dev(card, &saa7231->pdev->dev); strcpy(card->driver, "SAA7231"); sprintf(card->shortname, "%s-%d", desc->product, saa7231->num); sprintf(card->mixername, "%s", saa7231->name); sprintf(card->longname, "%s %s (%s) @ 0x%p, irq %i", desc->vendor, desc->product, card->shortname, saa7231->mmio1, saa7231->pdev->irq);
err = snd_card_register(card); if (err) { dprintk(SAA7231_ERROR, 1, "Sound Card registration failed, err=%d", err); return err; } tasklet_init(&audio->cmd_tasklet, saa7231_cmd_tasklet, (unsigned long) audio); return 0; }
testbox ~ # cat /var/log/messages ginInfo-AllowEmptySettings.X-KDE-PluginInfo-Author 2X-KDE-PluginInfo-Category 0X-KDE-PluginInfo-Depends ,X-KDE-PluginInfo-Email BX-KDE-PluginInfo-EnabledByDefault4X-KDE-PluginInfo-Immutable0X-KDE-PluginInfo-License *X-KDE-PluginInfo-Name 0X-KDE-PluginInfo-Version 0X-KDE-PluginInfo-Website X-KDE-PriorityX-KDE-Protocol X-KDE-Protocols X-KDE-Read(X-KDE-ResourceFamily $X-KDE-ResourceType <X-KDE-SolidBackendInfo-Version &X-KDE-StartupNotify&X-KDE-SubstituteUID<X-KDE-System-Settings-Category JX-KDE-System-Settings-Parent-Category X-KDE-Type ,X-KDE-UA-DYNAMIC-ENTRY▒X-KDE-UA-FULL ▒X-KDE-UA-NAME X-KDE-UA-SYSNAME &X-KDE-UA-SYSRELEASE ▒X-KDE-UA-TAG X-KDE-UA-VERSION X-KDE-Username ▒X-KDE-Version▒X-KDE-WMClass ▒X-KDE-WeightX-KDE-Write,X-KDE-okularAPIVersion>X-KDE-okularHasInternalSettingsX-KIPI-Id "X-KIPI-Interfaces X-KIPI-Mimetypes $X-KIPI-ReqFeatures
(X-Kate-MajorProfiles
Thanks, Manu