However the problem remains... I really don't know what's wrong with my code so I post the "interesting parts" here. Please help, I DO need this card to work!
static snd_pcm_hardware_t snd_toneport_playback_hw = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_3LE,
.rates = SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000,
.rate_min = 44100,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = TONEPORT_48000_24_PACKET_SIZE_OUT * 2 * 2,
.period_bytes_min = TONEPORT_48000_24_PACKET_SIZE_OUT * 2,
.period_bytes_max = TONEPORT_48000_24_PACKET_SIZE_OUT * 2,
.periods_min = 1,
.periods_max = 2
};
Here period_bytes_min are is as the maximum period size to use just one PCM.
#define snd_toneport_period_elapsed(old, new) \
(new >= TONEPORT_48000_24_PACKET_SIZE_OUT * 2 * 2) || \
((old < TONEPORT_48000_24_PACKET_SIZE_OUT * 2) && \
(new >= TONEPORT_48000_24_PACKET_SIZE_OUT * 2))
This one should test if a period is elapsed based on the old playback position (I see other drivers call such pointers hwptr) and the new one (before this last is "normalized").
/*
* null urb trasfer's completition callback
*/
static void snd_toneport_playback_complete_first(struct urb* urb,
struct pt_regs* regs)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)(urb->context);
snd_pcm_runtime_t *runtime = substream->runtime;
struct snd_toneport *chip = snd_pcm_substream_chip(substream);
memcpy(urb->transfer_buffer, runtime->dma_area,
chip->playback_packet_size * 2);
urb->complete = snd_toneport_playback_complete;
usb_submit_urb(urb, GFP_ATOMIC);
}
/*
* playback transfers' completition callback
*/
static void snd_toneport_playback_complete(struct urb* urb,
struct pt_regs* regs)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)(urb->context);
snd_pcm_runtime_t *runtime = substream->runtime;
struct snd_toneport *chip = snd_pcm_substream_chip(substream);
int new_pos = chip->playback_pos + chip->playback_packet_size * 2;
int offs;
if (new_pos <= TONEPORT_48000_24_PACKET_SIZE_OUT * 2 * 2) {
memcpy(urb->transfer_buffer,
runtime->dma_area + chip->playback_pos,
chip->playback_packet_size * 2);
} else {
offs = TONEPORT_48000_24_PACKET_SIZE_OUT * 2 * 2 -
chip->playback_pos;
memcpy(urb->transfer_buffer,
runtime->dma_area + chip->playback_pos,
offs);
memcpy(urb->transfer_buffer + new_pos,
runtime->dma_area,
chip->playback_packet_size * 2 - offs);
}
if (snd_toneport_period_elapsed(chip->playback_pos, new_pos)) {
if (new_pos >= TONEPORT_48000_24_PACKET_SIZE_OUT * 2 * 2)
new_pos -= TONEPORT_48000_24_PACKET_SIZE_OUT * 2 * 2;
chip->playback_pos = new_pos;
snd_pcm_period_elapsed(substream);
} else {
chip->playback_pos = new_pos;
}
if (chip->status & TONEPORT_STATUS_PLAYBACK)
usb_submit_urb(urb, GFP_ATOMIC);
}
/*
* hw_params callback
*
* TODO: capture and full duplex
*/
static int snd_toneport_pcm_hw_params(snd_pcm_substream_t *substream,
snd_pcm_hw_params_t *hw_params)
{
struct snd_toneport *chip = snd_pcm_substream_chip(substream);
unsigned char msg[] = TONEPORT_MSG_3;
int alt, err;
alt = (params_format(hw_params) == SNDRV_PCM_FORMAT_S16_LE) ? 1 : 3;
if ((params_rate(hw_params) == 44100))
alt++;
if ((err = usb_set_interface(chip->dev, 0, alt)) < 0)
return err;
chip->altsetting = alt;
if ((err = snd_toneport_submit_control_transfer(chip->dev, msg)) < 0)
return err;
chip->playback_packet_size = out_sizes[alt - 1];
if (!chip->playback_urb) {
chip->playback_urb = usb_alloc_urb(2, GFP_KERNEL);
chip->playback_urb->dev = chip->dev;
chip->playback_urb->pipe = usb_sndisocpipe(chip->dev, 1);
chip->playback_urb->context = substream;
chip->playback_urb->transfer_flags = URB_ISO_ASAP |
URB_NO_TRANSFER_DMA_MAP;
chip->playback_urb->interval = 1;
chip->playback_urb->number_of_packets = 2;
chip->playback_urb->iso_frame_desc[0].offset = 0;
} else {
usb_buffer_free(chip->dev, chip->playback_packet_size * 2,
chip->playback_urb->transfer_buffer,
chip->playback_urb->transfer_dma);
}
if (!(chip->playback_urb->transfer_buffer =
usb_buffer_alloc(chip->dev, chip->playback_packet_size * 2,
GFP_KERNEL, &chip->playback_urb->transfer_dma)))
return -ENOMEM;
chip->playback_urb->transfer_buffer_length =
chip->playback_packet_size * 2;
chip->playback_urb->iso_frame_desc[0].length =
chip->playback_urb->iso_frame_desc[1].offset =
chip->playback_urb->iso_frame_desc[1].length =
chip->playback_packet_size;
return snd_pcm_lib_malloc_pages(substream,
TONEPORT_48000_24_PACKET_SIZE_OUT * 2 * 2);
}
/*
* trigger callback
*/
static int snd_toneport_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
{
struct snd_toneport *chip = snd_pcm_substream_chip(substream);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
memset(chip->playback_urb->transfer_buffer, 0,
chip->playback_packet_size * 2);
chip->playback_pos = 0;
chip->status |= TONEPORT_STATUS_PLAYBACK;
chip->playback_urb->complete =
snd_toneport_playback_complete_first;
return usb_submit_urb(chip->playback_urb, GFP_ATOMIC);
break;
case SNDRV_PCM_TRIGGER_STOP:
chip->status &= ~TONEPORT_STATUS_PLAYBACK;
break;
default:
return -EINVAL;
break;
}
return 0;
}
/*
* pointer callback
*/
static snd_pcm_uframes_t snd_toneport_pcm_pointer(
snd_pcm_substream_t* substream)
{
struct snd_toneport *chip = snd_pcm_substream_chip(substream);
return bytes_to_frames(substream->runtime, chip->playback_pos);
}
As you can see I chose to store the playback position in bytes instead of frames because I have 6-bytes frames and 4-bytes frames (depends on the format).
Also TONEPORT_48000_24_PACKET_SIZE_OUT * 2 * 2 is the alsa buffer size.
Thanks,
Stefano
------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.sourceforge.net/lists/listinfo/alsa-devel