* 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
* Re: Line6 Toneport UX1 driver again
2006-07-08 16:14 Stefano D'Angelo
@ 2006-07-11 11:12 ` Takashi Iwai
0 siblings, 0 replies; 11+ messages in thread
From: Takashi Iwai @ 2006-07-11 11:12 UTC (permalink / raw)
To: Stefano D'Angelo; +Cc: alsa-devel
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
-------------------------------------------------------------------------
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
^ permalink raw reply [flat|nested] 11+ messages in thread
* 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
* Re: Line6 Toneport UX1 driver again
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
0 siblings, 1 reply; 11+ messages in thread
From: Takashi Iwai @ 2006-07-11 13:15 UTC (permalink / raw)
To: Stefano D'Angelo; +Cc: alsa-devel
At Tue, 11 Jul 2006 14:59:40 +0200,
Stefano D'Angelo wrote:
>
> 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!
Did you allocate the ring-buffer in hw_params callback, not only the
urbs?
You could implement using copy callback, but in that case, the driver
won't work with mmap mode. So, a ring-buffer as the primary buffer
and manual copy to urbs would be a more flexible option.
Anyway, the copy callback shouldn't submit urbs by itself. The copy
callback is to copy the data. That's all. The copy can be operated
even before starting the stream (filling the buffer first, then
start). Hence, the urbs should be submitted in the trigger-start
callback.
Also, kmalloc/kfree at each time is inefficient. You can reuse the
urbs and packet data buffers.
Takashi
-------------------------------------------------------------------------
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
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Line6 Toneport UX1 driver again
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
0 siblings, 2 replies; 11+ messages in thread
From: Stefano D'Angelo @ 2006-07-11 15:15 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1.1: Type: text/plain, Size: 11229 bytes --]
2006/7/11, Takashi Iwai <tiwai@suse.de>:
>
> At Tue, 11 Jul 2006 14:59:40 +0200,
> Stefano D'Angelo wrote:
> >
> > 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!
>
> Did you allocate the ring-buffer in hw_params callback, not only the
> urbs?
>
> You could implement using copy callback, but in that case, the driver
> won't work with mmap mode. So, a ring-buffer as the primary buffer
> and manual copy to urbs would be a more flexible option.
>
> Anyway, the copy callback shouldn't submit urbs by itself. The copy
> callback is to copy the data. That's all. The copy can be operated
> even before starting the stream (filling the buffer first, then
> start). Hence, the urbs should be submitted in the trigger-start
> callback.
>
> Also, kmalloc/kfree at each time is inefficient. You can reuse the
> urbs and packet data buffers.
>
>
> Takashi
No, I didn't allocate the ring-buffer, but isn't the data to copy just
present in the buffer pointed by src in the copy callback parameters?
However, I read in "Writing an ALSA driver" by you that if a sound card does
not support DMA a copy callback is necessary. I tried without... but it
didn't work, just heard long beeps, but maybe I did wrong.
But maybe there's another solution to the problem: since this card has just
some differences at initialization and playback start with normal USB cards,
maybe usb-snd-audio could be used. (To be honest I still don't know about
capture, but I suppose it is quite similar).
What do you think about that?
[-- Attachment #1.2: Type: text/html, Size: 19172 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
* Re: Line6 Toneport UX1 driver again
2006-07-11 15:15 ` Stefano D'Angelo
@ 2006-07-11 16:26 ` Takashi Iwai
2006-07-12 9:43 ` Clemens Ladisch
1 sibling, 0 replies; 11+ messages in thread
From: Takashi Iwai @ 2006-07-11 16:26 UTC (permalink / raw)
To: Stefano D'Angelo; +Cc: alsa-devel
At Tue, 11 Jul 2006 17:15:00 +0200,
Stefano D'Angelo wrote:
>
> 2006/7/11, Takashi Iwai <tiwai@suse.de>:
>
> At Tue, 11 Jul 2006 14:59:40 +0200,
> Stefano D'Angelo wrote:
> >
> > 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!
>
> Did you allocate the ring-buffer in hw_params callback, not only the
> urbs?
>
> You could implement using copy callback, but in that case, the driver
> won't work with mmap mode. So, a ring-buffer as the primary buffer
> and manual copy to urbs would be a more flexible option.
>
> Anyway, the copy callback shouldn't submit urbs by itself. The copy
> callback is to copy the data. That's all. The copy can be operated
> even before starting the stream (filling the buffer first, then
> start). Hence, the urbs should be submitted in the trigger-start
> callback.
>
> Also, kmalloc/kfree at each time is inefficient. You can reuse the
> urbs and packet data buffers.
>
> Takashi
>
> No, I didn't allocate the ring-buffer, but isn't the data to copy just present in the
> buffer pointed by src in the copy callback parameters? However, I read in "Writing an
> ALSA driver" by you that if a sound card does not support DMA a copy callback is
> necessary. I tried without... but it didn't work, just heard long beeps, but maybe I
> did wrong.
The copy callback doesn't always pass the pointer aligned to the
period size. For descrete buffers like URB, you really need some
intermediate buffer to make the driver work robustly.
The beep symptom sounds like you didn't copy the data properly to the
URBs.
> But maybe there's another solution to the problem: since this card has just some
> differences at initialization and playback start with normal USB cards, maybe
> usb-snd-audio could be used. (To be honest I still don't know about capture, but I
> suppose it is quite similar).
> What do you think about that?
Integrating to snd-usb-audio would be a wise option, especially if you
consider about the maintenance.
Takashi
-------------------------------------------------------------------------
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
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Line6 Toneport UX1 driver again
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
1 sibling, 1 reply; 11+ messages in thread
From: Clemens Ladisch @ 2006-07-12 9:43 UTC (permalink / raw)
To: Stefano D'Angelo; +Cc: alsa-devel
Stefano D'Angelo wrote:
> But maybe there's another solution to the problem: since this card has just
> some differences at initialization and playback start with normal USB cards,
> maybe usb-snd-audio could be used.
This would be preferrable.
What are the differences?
Regards,
Clemens
-------------------------------------------------------------------------
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
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Line6 Toneport UX1 driver again
2006-07-12 9:43 ` Clemens Ladisch
@ 2006-07-12 10:29 ` Stefano D'Angelo
2006-07-12 16:05 ` Lee Revell
0 siblings, 1 reply; 11+ messages in thread
From: Stefano D'Angelo @ 2006-07-12 10:29 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1.1: Type: text/plain, Size: 5731 bytes --]
2006/7/12, Clemens Ladisch <clemens@ladisch.de>:
> Stefano D'Angelo wrote:
> > But maybe there's another solution to the problem: since this card has
just
> > some differences at initialization and playback start with normal USB
cards,
> > maybe usb-snd-audio could be used.
>
> This would be preferrable.
>
> What are the differences?
>
>
> Regards,
> Clemens
Well, I'm already working on it. Yesterday night I starting modifying
snd-usb-audio (and I have to admit that it is a great piece of code) and
what I did is adding the quirk in usbquirks.h this way:
/* Line6 TonePort devices */
{
USB_DEVICE(0x0e41, 0x4141),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
.vendor_name = "Line6",
.product_name = "TonePort UX1",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_COMPOSITE,
.data = & (const struct snd_usb_audio_quirk[]) {
{
.ifnum = 0,
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
.data = & (const struct audioformat) {
.format = SNDRV_PCM_FORMAT_S16_LE,
.channels = 2,
.iface = 0,
.altsetting = 1,
.altset_idx = 1,
.attributes = 0,
.endpoint = 0x01,
.ep_attr = 0x01,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000
}
},
{
.ifnum = 0,
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
.data = & (const struct audioformat) {
.format = SNDRV_PCM_FORMAT_S16_LE,
.channels = 2,
.iface = 0,
.altsetting = 2,
.altset_idx = 2,
.attributes = 0,
.endpoint = 0x01,
.ep_attr = 0x01,
.rates = SNDRV_PCM_RATE_44100,
.rate_min = 44100,
.rate_max = 44100
}
},
{
.ifnum = 0,
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
.data = & (const struct audioformat) {
.format = SNDRV_PCM_FORMAT_S24_3LE,
.channels = 2,
.iface = 0,
.altsetting = 3,
.altset_idx = 3,
.attributes = 0,
.endpoint = 0x01,
.ep_attr = 0x01,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000
}
},
{
.ifnum = 0,
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
.data = & (const struct audioformat) {
.format = SNDRV_PCM_FORMAT_S24_3LE,
.channels = 2,
.iface = 0,
.altsetting = 4,
.altset_idx = 4,
.attributes = 0,
.endpoint = 0x01,
.ep_attr = 0x01,
.rates = SNDRV_PCM_RATE_44100,
.rate_min = 44100,
.rate_max = 44100
}
},
{
.ifnum = -1
}
}
}
},
Practically the sound card uses just one interface (# 0) and has 4
alsettings which work (for playback) at this parameters (playback endpoint
is always 0x01):
altsetting 0, control msgs
altsetting 1, 48000 Hz, 16 bits LE, stereo, 192 bytes max packet size
altsetting 2, 44100 Hz, 16 bits LE, stereo, 180 bytes max packet size
altsetting 3, 48000 Hz, 24 bits 3LE, stereo, 288 bytes max packet size
altsetting 4, 44100 Hz, 24 bits 3LE, stereo, 270 bytes max packet size
For each altsetting the Windows' driver works by sending in every URB 2
packets long as the endpoints' max packet size. The card responds also by
continuously sending data on the endpoint 0x82, and that is how capture is
done (when you just want to capture you can send 0-filled URBs to the card).
I haven't investigated yet, but this card should only do mono capture and
maybe at different rates on the same altsetting (they claim it can do 96 kHz
capture).
Then at init time some control msgs are sent to the card to init it, and I
tried to do this way:
/* ugly incomprehensible messages in here, snd_usb_ctl_msg does not work */
static int snd_usb_line6_tp_boot_quirk(struct usb_device *dev)
{
int pipe = usb_sndctrlpipe(dev, 0);
int err = 0;
if ((err = snd_usb_ctl_msg(dev, pipe, 0x67, 0x40, 0x0102, 0x0200, NULL,
0, 0)) < 0)
return err;
if ((err = snd_usb_ctl_msg(dev, pipe, 0x03, 0x00, 0x0100, 0x0000, NULL,
0, 0)) < 0)
return err;
if ((err = snd_usb_ctl_msg(dev, pipe, 0x67, 0x40, 0x0108, 0x0000, NULL,
0, 0)) < 0)
return err;
err = snd_usb_ctl_msg(dev, pipe, 0x67, 0x40, 0x0103, 0x0000, NULL, 0,
0);
return err;
}
But it doesn't work... after the first msg is sent the second (whatever it
is), when sent, brings to a -EPIPE error, and I still don't know why (I
checked the driver I was writing and the usb_control_msg code and they're
basically similar, expect that I submit urbs with GFP_KERNEL and it does
with GFP_NOIO). What should I do with then?
Then also when starting the playback another msg is to be sent (before
playback and after altsetting is set). This is the same msg as the third in
the previous function I wrote.
Do you think it could be mergeable?
[-- Attachment #1.2: Type: text/html, Size: 11882 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
* Re: Line6 Toneport UX1 driver again
2006-07-12 10:29 ` Stefano D'Angelo
@ 2006-07-12 16:05 ` Lee Revell
2006-07-12 16:23 ` Stefano D'Angelo
0 siblings, 1 reply; 11+ messages in thread
From: Lee Revell @ 2006-07-12 16:05 UTC (permalink / raw)
To: Stefano D'Angelo; +Cc: alsa-devel
On Wed, 2006-07-12 at 12:29 +0200, Stefano D'Angelo wrote:
> Well, I'm already working on it. Yesterday night I starting modifying
> snd-usb-audio (and I have to admit that it is a great piece of code)
> and what I did is adding the quirk in usbquirks.h this way:
>
Please, please don't post HTML to this list, it makes your code very
difficult to review.
Lee
-------------------------------------------------------------------------
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
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Line6 Toneport UX1 driver again
2006-07-12 16:05 ` Lee Revell
@ 2006-07-12 16:23 ` Stefano D'Angelo
2006-07-12 16:31 ` Lee Revell
0 siblings, 1 reply; 11+ messages in thread
From: Stefano D'Angelo @ 2006-07-12 16:23 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1.1: Type: text/plain, Size: 68 bytes --]
Lee, sorry, it's because of gmail... I have to delete this account!
[-- Attachment #1.2: Type: text/html, Size: 72 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
* Re: Line6 Toneport UX1 driver again
2006-07-12 16:23 ` Stefano D'Angelo
@ 2006-07-12 16:31 ` Lee Revell
0 siblings, 0 replies; 11+ messages in thread
From: Lee Revell @ 2006-07-12 16:31 UTC (permalink / raw)
To: Stefano D'Angelo; +Cc: alsa-devel
On Wed, 2006-07-12 at 18:23 +0200, Stefano D'Angelo wrote:
> Lee, sorry, it's because of gmail... I have to delete this account!
gmail can send in plain text. It only defaults to HTML.
Lee
-------------------------------------------------------------------------
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
^ 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.