All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: Line6 Toneport UX1 driver again
@ 2006-07-11 12:59 Stefano D'Angelo
  2006-07-11 13:15 ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: Stefano D'Angelo @ 2006-07-11 12:59 UTC (permalink / raw)
  To: alsa-devel


[-- Attachment #1.1: Type: text/plain, Size: 8612 bytes --]

2006/7/11, Takashi Iwai <tiwai@suse.de>:

> At Sat, 8 Jul 2006 18:14:15 +0200,
> Stefano D'Angelo wrote:
> >
> > Excuse me if I'm repeatedly asking the same things, but I still can't
> understand how
> > some stuff works probably.
> > I have these lines of code:
> >
> > static snd_pcm_hardware_t snd_line6_tp_ux1_playback_hw = {
> >     .info             = SNDRV_PCM_INFO_INTERLEAVED |
> >                         SNDRV_PCM_INFO_BLOCK_TRANSFER,
> >     .formats          = SNDRV_PCM_FMTBIT_S16_LE,
> >     .rates            = SNDRV_PCM_RATE_48000,
> >     .rate_min         = 48000,
> >     .rate_max         = 48000,
> >     .channels_min     = 2,
> >     .channels_max     = 2,
> >     /* double buffering */
> >     .buffer_bytes_max = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2 * 2,
> >     .period_bytes_min = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2,
> >     .period_bytes_max = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2,
> >     .periods_min      = 1,
> >     .periods_max      = 2
> > };
> >
> > and then also:
> >
> > static snd_pcm_uframes_t snd_line6_tp_ux1_pcm_pointer (
> >                                                snd_pcm_substream_t*
> substream)
> > {
> >     struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
> >
> >     printk ("pos: %d\n", chip->playback_pos);
> >     return chip->playback_pos;
> > }
> >
> > static int snd_line6_tp_ux1_playback_copy (snd_pcm_substream_t
> *substream,
> >                                            int channel,
> snd_pcm_uframes_t pos,
> >                                            void *src, snd_pcm_uframes_t
> count)
> > {
> >     struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
> >     snd_pcm_runtime_t *runtime = substream->runtime;
> >     static struct urb* urb;
> >
> >     int i = 0;
> >     static int j = 0;
> >
> >     urb = usb_alloc_urb (2, GFP_ATOMIC);
> >     urb->dev = chip->dev;
> >     urb->pipe = usb_sndisocpipe (urb->dev, 1);
> >     urb->complete = snd_line6_tp_ux1_complete_playback_transfer;
> >     urb->context = substream;
> >     urb->transfer_buffer = kmalloc
> (LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2,
> > GFP_ATOMIC);
> >     urb->transfer_buffer_length = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT
> * 2;
> >     urb->transfer_flags = URB_ISO_ASAP;
> >
> >     memcpy (urb->transfer_buffer, src, count * 2 * 2);
> >
> >     for (; i < LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT; i++) {
> >         printk ("%d\n", ((s16*)urb->transfer_buffer)[i]);
> >     }
> >     printk ("---------\n");
> >
> >     urb->interval = 1;
> >     urb->number_of_packets = 2;
> >     urb->iso_frame_desc[0].offset = 0;
> >     urb->iso_frame_desc[0].length = urb->iso_frame_desc[1].offset =
> >     urb->iso_frame_desc[1].length =
> LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT;
> >     if (chip->playback_pos)
> >         chip->playback_pos = 0;
> >     else
> >         chip->playback_pos = count;
> >     j++;
> >     printk (":: %d %d %d\n", j, chip->playback_pos,
> runtime->buffer_size);
> >     snd_pcm_period_elapsed (substream);
> >     usb_submit_urb (urb, GFP_KERNEL);
> >
> >     return count;
> > }
> >
> > Don't care about printk()s and codying style, count in the copy callback
> is always 96,
> > which is the # of frames of a period, so everytime the copy callback is
> called, a
> > period is elapsed. Since the buffer is long 2 periods, the playback
> position pointer
> > should be either 0 or 96, I think (beginning or half of the buffer).
> > Now, instead of working as expected, the copy callback just works twice,
> for the first
> > two periods (one buffer length). Then the pointer becomes 0 and I can't
> understand why
> > the playback stops.
> > Please help! I have some people who keep on asking me about the driver,
> and it's a
> > pity that I can't overcome such simple problems and let them use their
> sound card!
>
> Calling snd_pcm_period_elapsed() in copy callback doesn't make sense.
> The copy callback is called when the PCM core requires something to
> copy.
>
> In general, all PCM driver callbacks are passive.  They need to do
> only what they are requested.   The role of copy callback is to copy
> the given user-space data to the hardware buffer.  The role of pointer
> callback is to return the current (DMA) transfer position in the ring
> buffer.  The role of trigger callback is to start or stop the PCM
> stream...
>
> In the ALSA PCM model, there are some assumptions:
>
> 1. You have a ring buffer containing PCM data.
> 2. DMA is running at constant rate, transferring the data in
>    background and updating the position.
>
> Usually, the DMA controller issues an interrupt when a given size of
> data ("period" in ALSA term) is processed.  The driver calls
> snd_pcm_period_elapsed() in the interrupt handler, then.
>
> However, in the case of USB devices, it's a bit tricky, because the
> transfer is done via non-continuous packets.  To overcome this,
> snd-usb-audio allocates a ring-buffer via vmalloc() in hw_params
> callback.  The PCM core copies the user-space data to the ring-buffer,
> and the driver copies the data from the ring-buffer to each urb
> appropriately.
>
> The first trigger-start callback prepares the urbs (with data copy
> from ring-buffer) and submit them.  When urb-complete callback is
> called, the driver updates the current position, then *here* calls
> snd_pcm_period_elapsed() if the pre-given period size was already
> processed.  Then, copy the data to urb, and re-submit it.
>
>
> Takashi
>

Thanks a lot, however I realized that just yesterday and I think I fixed the
whole thing, 48kHz 16-bits stereo output works properly now (just a little
problem occours, some overruns at the beginning of the output, but I think I
know how to fix it).
Since I've got a person who owns a Line6 TonePort UX2 sound card and its'
likely that these sound cards share the same protocol, I sent him the driver
code and he will test it in the next days. So I renamed it as snd_toneport.
However I did this way (tell me if it is correct - just 48kHz 16-bits stereo
support now):

[...]

static snd_pcm_hardware_t snd_toneport_playback_hw = {

    .info             = SNDRV_PCM_INFO_INTERLEAVED |
                        SNDRV_PCM_INFO_BLOCK_TRANSFER,
    .formats          = SNDRV_PCM_FMTBIT_S16_LE,
    .rates            = SNDRV_PCM_RATE_48000,
    .rate_min         = 48000,
    .rate_max         = 48000,
    .channels_min     = 2,
    .channels_max     = 2,
    .buffer_bytes_max = TONEPORT_48000_16_PACKET_SIZE_OUT * 2 * 10,
    .period_bytes_min = TONEPORT_48000_16_PACKET_SIZE_OUT * 2,
    .period_bytes_max = TONEPORT_48000_16_PACKET_SIZE_OUT * 2,
    .periods_min      = 1,
    .periods_max      = 10
};

[...]

/*
 * playback transfers' completition callback
 *
 * TODO: error handling and full duplex
 */
static void snd_toneport_complete_playback_transfer (struct urb* urb,
    struct pt_regs* regs)
{
    snd_pcm_substream_t *substream = (snd_pcm_substream_t *)(urb->context);
    struct snd_toneport *chip = snd_pcm_substream_chip (substream);

    chip->playback_pos += TONEPORT_48000_16_PACKET_SIZE_OUT / 2;
    if (chip->playback_pos >= TONEPORT_48000_16_PACKET_SIZE_OUT / 2 * 10)
        chip->playback_pos -= TONEPORT_48000_16_PACKET_SIZE_OUT / 2 *
            10;

    snd_pcm_period_elapsed (substream);

    kfree (urb->transfer_buffer);
    usb_free_urb (urb);
}

[...]

/*
 * copy callback
 */
static int snd_toneport_playback_copy (snd_pcm_substream_t *substream,

    int channel, snd_pcm_uframes_t pos, void *src, snd_pcm_uframes_t count)
{
    struct snd_toneport *chip = snd_pcm_substream_chip (substream);
    struct urb* urb;


    urb = usb_alloc_urb (2, GFP_ATOMIC);
    urb->dev = chip->dev;
    urb->pipe = usb_sndisocpipe (urb->dev, 1);
    urb->complete = snd_toneport_complete_playback_transfer;
    urb->context = substream;
    urb->transfer_buffer = kmalloc (TONEPORT_48000_16_PACKET_SIZE_OUT * 2,
        GFP_ATOMIC);
    urb->transfer_buffer_length = TONEPORT_48000_16_PACKET_SIZE_OUT * 2;

    urb->transfer_flags = URB_ISO_ASAP;
    memcpy (urb->transfer_buffer, src, count * 2 * 2);
    urb->interval = 1;
    urb->number_of_packets = 2;
    urb->iso_frame_desc[0].offset = 0;
    urb->iso_frame_desc[0].length = urb->iso_frame_desc[1].offset =
    urb->iso_frame_desc[1].length = TONEPORT_48000_16_PACKET_SIZE_OUT;
    usb_submit_urb (urb, GFP_ATOMIC);

    return count;
}

[...]

I tried without a copy callback via DMA transfers (if I'm not wrong also
snd-usb-audio does this way) but it just didn't work (maybe the card does
not support DMA?)
However thanks a lot again!

Stefano

[-- Attachment #1.2: Type: text/html, Size: 13549 bytes --]

[-- Attachment #2: Type: text/plain, Size: 375 bytes --]


-------------------------------------------------------------------------
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

[-- Attachment #3: Type: text/plain, Size: 161 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 11+ messages in thread
* Line6 Toneport UX1 driver again
@ 2006-07-08 16:14 Stefano D'Angelo
  2006-07-11 11:12 ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: Stefano D'Angelo @ 2006-07-08 16:14 UTC (permalink / raw)
  To: alsa-devel


[-- Attachment #1.1: Type: text/plain, Size: 3395 bytes --]

Excuse me if I'm repeatedly asking the same things, but I still can't
understand how some stuff works probably.
I have these lines of code:

static snd_pcm_hardware_t snd_line6_tp_ux1_playback_hw = {
    .info             = SNDRV_PCM_INFO_INTERLEAVED |
                        SNDRV_PCM_INFO_BLOCK_TRANSFER,
    .formats          = SNDRV_PCM_FMTBIT_S16_LE,
    .rates            = SNDRV_PCM_RATE_48000,
    .rate_min         = 48000,
    .rate_max         = 48000,
    .channels_min     = 2,
    .channels_max     = 2,
    /* double buffering */
    .buffer_bytes_max = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2 * 2,
    .period_bytes_min = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2,
    .period_bytes_max = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2,
    .periods_min      = 1,
    .periods_max      = 2
};

and then also:

static snd_pcm_uframes_t snd_line6_tp_ux1_pcm_pointer (
                                               snd_pcm_substream_t*
substream)
{
    struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);

    printk ("pos: %d\n", chip->playback_pos);
    return chip->playback_pos;
}

static int snd_line6_tp_ux1_playback_copy (snd_pcm_substream_t *substream,
                                           int channel, snd_pcm_uframes_t
pos,
                                           void *src, snd_pcm_uframes_t
count)
{
    struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
    snd_pcm_runtime_t *runtime = substream->runtime;
    static struct urb* urb;

    int i = 0;
    static int j = 0;

    urb = usb_alloc_urb (2, GFP_ATOMIC);
    urb->dev = chip->dev;
    urb->pipe = usb_sndisocpipe (urb->dev, 1);
    urb->complete = snd_line6_tp_ux1_complete_playback_transfer;
    urb->context = substream;
    urb->transfer_buffer = kmalloc (LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT *
2, GFP_ATOMIC);
    urb->transfer_buffer_length = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2;
    urb->transfer_flags = URB_ISO_ASAP;

    memcpy (urb->transfer_buffer, src, count * 2 * 2);

    for (; i < LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT; i++) {
        printk ("%d\n", ((s16*)urb->transfer_buffer)[i]);
    }
    printk ("---------\n");

    urb->interval = 1;
    urb->number_of_packets = 2;
    urb->iso_frame_desc[0].offset = 0;
    urb->iso_frame_desc[0].length = urb->iso_frame_desc[1].offset =
    urb->iso_frame_desc[1].length = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT;
    if (chip->playback_pos)
        chip->playback_pos = 0;
    else
        chip->playback_pos = count;
    j++;
    printk (":: %d %d %d\n", j, chip->playback_pos, runtime->buffer_size);
    snd_pcm_period_elapsed (substream);
    usb_submit_urb (urb, GFP_KERNEL);

    return count;
}

Don't care about printk()s and codying style, count in the copy callback is
always 96, which is the # of frames of a period, so everytime the copy
callback is called, a period is elapsed. Since the buffer is long 2 periods,
the playback position pointer should be either 0 or 96, I think (beginning
or half of the buffer).
Now, instead of working as expected, the copy callback just works twice, for
the first two periods (one buffer length). Then the pointer becomes 0 and I
can't understand why the playback stops.
Please help! I have some people who keep on asking me about the driver, and
it's a pity that I can't overcome such simple problems and let them use
their sound card!
Thanks,
Stefano

[-- Attachment #1.2: Type: text/html, Size: 5623 bytes --]

[-- Attachment #2: Type: text/plain, Size: 299 bytes --]

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

[-- Attachment #3: Type: text/plain, Size: 161 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2006-07-12 16:31 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-11 12:59 Line6 Toneport UX1 driver again Stefano D'Angelo
2006-07-11 13:15 ` Takashi Iwai
2006-07-11 15:15   ` Stefano D'Angelo
2006-07-11 16:26     ` Takashi Iwai
2006-07-12  9:43     ` Clemens Ladisch
2006-07-12 10:29       ` Stefano D'Angelo
2006-07-12 16:05         ` Lee Revell
2006-07-12 16:23           ` Stefano D'Angelo
2006-07-12 16:31             ` Lee Revell
  -- strict thread matches above, loose matches on Subject: below --
2006-07-08 16:14 Stefano D'Angelo
2006-07-11 11:12 ` Takashi Iwai

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.