Re: Line6 TonePort

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Clemens you were right of course, what I was saying was just bull shit (and I'm sorry).
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

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux