* Line6 TonePort UX1 driver
@ 2006-05-08 17:16 Stefano D Angelo
2006-05-10 13:29 ` Takashi Iwai
0 siblings, 1 reply; 9+ messages in thread
From: Stefano D Angelo @ 2006-05-08 17:16 UTC (permalink / raw)
To: alsa-devel
Hello everyone,
I'm an italian university student and I'm developing an ALSA driver for Line6
TonePort UX1 USB sound card.
This is my first driver-writing experience, so maybe this is a dumb question
for you.
This soundcard supports 44.1/48 kHz 16/24-bits modes and full-duplex, but only
in one mode due to USB altesttings.
To be more precise if you are playing some audio stream at 44.1 kHz, 16-bits,
you can only capture data at 44.1 kHz and 16-bits, for example.
The Windows' driver uses some kind of implicit conversion for
playback/capture, so that it uses only 48 kHz, 24-bit mode (unless you use a
program to switch).
Do you think I should use such a compromise too or go on another way?
Stefano D'Angelo
-----------------
Registra il tuo nome di dominio su: http://www.oneonline.it/domini
One On Line ti offre domino + spazio web illimitato + 5 email + 5000 uscite banner + PHP + Link a soli Euro 15 iva compresa
-------------------------------------------------------
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] 9+ messages in thread
* Re: Line6 TonePort UX1 driver
2006-05-08 17:16 Line6 TonePort UX1 driver Stefano D Angelo
@ 2006-05-10 13:29 ` Takashi Iwai
[not found] ` <20060510165635.M757@oneonline.it>
0 siblings, 1 reply; 9+ messages in thread
From: Takashi Iwai @ 2006-05-10 13:29 UTC (permalink / raw)
To: Stefano D Angelo; +Cc: alsa-devel
At Mon, 8 May 2006 20:16:19 +0300,
Stefano D Angelo wrote:
>
> Hello everyone,
> I'm an italian university student and I'm developing an ALSA driver for Line6
> TonePort UX1 USB sound card.
> This is my first driver-writing experience, so maybe this is a dumb question
> for you.
> This soundcard supports 44.1/48 kHz 16/24-bits modes and full-duplex, but only
> in one mode due to USB altesttings.
> To be more precise if you are playing some audio stream at 44.1 kHz, 16-bits,
> you can only capture data at 44.1 kHz and 16-bits, for example.
> The Windows' driver uses some kind of implicit conversion for
> playback/capture, so that it uses only 48 kHz, 24-bit mode (unless you use a
> program to switch).
> Do you think I should use such a compromise too or go on another way?
The condition can be restricted via hw_constraints in ALSA.
When a playback (or a capture) is opened first, the driver remembers
the parameter. At the secondary open of another side, call
snd_pcm_hw_constraint_*() additionally to restrict the PCM
parameters to be accepted.
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] 9+ messages in thread
* Re: Line6 TonePort UX1 driver
[not found] ` <20060510165635.M757@oneonline.it>
@ 2006-05-10 15:34 ` Takashi Iwai
[not found] ` <20060512004915.M47766@oneonline.it>
0 siblings, 1 reply; 9+ messages in thread
From: Takashi Iwai @ 2006-05-10 15:34 UTC (permalink / raw)
To: Stefano D Angelo; +Cc: alsa-devel
At Wed, 10 May 2006 16:56:35 +0300,
Stefano D Angelo wrote:
>
> > At Mon, 8 May 2006 20:16:19 +0300,
> > Stefano D Angelo wrote:
> > >
> > > Hello everyone,
> > > I'm an italian university student and I'm developing an ALSA driver for Line6
> > > TonePort UX1 USB sound card.
> > > This is my first driver-writing experience, so maybe this is a dumb question
> > > for you.
> > > This soundcard supports 44.1/48 kHz 16/24-bits modes and full-duplex, but only
> > > in one mode due to USB altesttings.
> > > To be more precise if you are playing some audio stream at 44.1 kHz, 16-bits,
> > > you can only capture data at 44.1 kHz and 16-bits, for example.
> > > The Windows' driver uses some kind of implicit conversion for
> > > playback/capture, so that it uses only 48 kHz, 24-bit mode (unless you use a
> > > program to switch).
> > > Do you think I should use such a compromise too or go on another way?
> >
> > The condition can be restricted via hw_constraints in ALSA.
> > When a playback (or a capture) is opened first, the driver remembers
> > the parameter. At the secondary open of another side, call
> > snd_pcm_hw_constraint_*() additionally to restrict the PCM
> > parameters to be accepted.
> >
> > Takashi
[Added alsa-devel back to Cc]
> That's not the point of the question. Probably I'm not a good English speaker
> and writer, but I'll try to make you understand the same.
> Think about what happens perhaps in a recording studio: some output (a tick or
> something like that) is sent to a pair of hearphones and, while listening, you
> have to play your instrument for recording.
> Suppose that the tick is in 44.1 kHz 16-bits format. If you start playing it
> and then you want to record, this sound card lets you do it only at the
> current playback bit/sample-rate (this is due to altsettings of the card).
> So I noticed that the Windows' driver (or some other software built in
> Windows) converts every output sent to the card in 48 kHz 24-bits format, in
> order to be able to record always at the maximum rate. Then you can obviously
> do downsampling if you want.
> I was asking you whether I should do like Windows do (in the ALSA world I
> think it means "use 48 kHz 24-bits only format", then ALSA does the
> conversions) or not.
It's your choice, but I vote for allowing multiple formats.
The native support of 16 bit is preferred in some cases. The software
conversion of 24bit format may cost much on an old slow machine.
> Right now I did the first way, but now I've got another (strange) problem with
> ALSA.
> 48 kHz 24-bits output mostly works, but when I need a conversion (for example
> playing a 44.1 kHz 16-bits file), even using plughw:x it says me that no
> sample format is available. I used S24_3LE, 48 kHz, 24-bits, stereo as the
> only format supported in hw_params struct.
That's weird. Do you use the latest ALSA lib?
> But that's not all. I've got some strange underruns before the file is
> actually played, and I noticed that the trigger function is called many times
> before the actual data transfer (commands START and STOP alternated).
> However I'm going to put source files on sf.net as soon as they open a space
> for this project, so that such things can be better discussed.
> If, anyway, you know something about these things please let me know
Please _post_ your source code to ALSA devel ML if you want
debugs/reviews together with us. Keeping a forked stuff on sf really
sucks.
thanks,
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] 9+ messages in thread
* Re: Line6 TonePort UX1 driver
[not found] ` <20060512004915.M47766@oneonline.it>
@ 2006-05-12 8:15 ` Stefano D Angelo
0 siblings, 0 replies; 9+ messages in thread
From: Stefano D Angelo @ 2006-05-12 8:15 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1: Type: text/plain, Size: 667 bytes --]
Ok,
I attached the code to this e-mail.
I followed your suggestion, Takashi, and, as you can see, now I'm implementing
all supporte formats for playback.
But another problem arouses... I'm trying to set period/buffer sizes through a
rule_add, but now I can't make it work yet.
playback_copy works only for 24-bits 48000 outputs now, but now I'm going to
solve the problem I just told you first.
Please, let me know and thanks for your supporting.
Stefano
-----------------
Registra il tuo nome di dominio su: http://www.oneonline.it/domini
One On Line ti offre domino + spazio web illimitato + 5 email + 5000 uscite banner + PHP + Link a soli Euro 15 iva compresa
[-- Attachment #2: snd_line6_tp_ux1.c --]
[-- Type: application/octet-stream, Size: 25202 bytes --]
/*
* Line6 TonePort UX1 (and maybe TonePort UX2) USB driver for ALSA
*
*
* Copyright (c) 2006 by Stefano D'Angelo <daste@oneonline.it>
*
* Some code borrowed from
* USB Audio Driver for ALSA by Takashi Iwai <tiwai@suse.de>
* "Writing an ALSA Driver" by Takashi Iwai <tiwai@suse.de>
* "Linux USB Driver Basics" at http://www.linuxtecharticles.com
* and maybe, consequently, also from audio.c by
* Alan Cox <alan@lxorguk.ukuu.org.uk>
* Thomas Sailer <sailer@ife.ee.ethz.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/usb.h>
#include <linux/device.h>
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/control.h>
#include "snd_line6_tp_ux1.h"
/* urb list struct - TODO: maybe convert to list_head */
struct urb_list {
struct urb *urb;
struct urb_list *next;
};
/* chip struct */
struct snd_line6_tp_ux1 {
int index; /* device index */
struct usb_device *dev;
snd_card_t *card;
snd_pcm_t *pcm;
int altsetting; /* current altsetting */
unsigned int playback_pos; /* buffer position in frames */
unsigned int playback_lvol; /* master playback left volume */
unsigned int playback_rvol; /* master playback right volume */
struct urb_list *pending_playback_urbs;
struct urb_list *last_pending_playback_urb;
};
/* function prototypes */
static int snd_line6_tp_ux1_driver_init ();
static void snd_line6_tp_ux1_driver_exit ();
static int snd_line6_tp_ux1_probe (struct usb_interface *intf,
const struct usb_device_id *id);
static int snd_line6_tp_ux1_create (struct usb_device *dev, int idx);
static int snd_line6_tp_ux1_init_msgs (struct usb_device* dev);
static int snd_line6_tp_ux1_new_pcm (struct snd_line6_tp_ux1 *chip);
static void snd_line6_tp_ux1_disconnect (struct usb_interface *intf);
static int snd_line6_tp_ux1_free (struct snd_line6_tp_ux1 *chip_ptr);
static int snd_line6_tp_ux1_dev_free (snd_device_t *device);
static int snd_line6_tp_ux1_submit_control_transfer (struct usb_device* dev,
unsigned char* packet);
static void snd_line6_tp_ux1_complete_control_transfer (struct urb* urb,
struct pt_regs* regs);
static void snd_line6_tp_ux1_complete_playback_transfer (struct urb* urb,
struct pt_regs* regs);
static int snd_line6_tp_ux1_hw_period_by_rate (snd_pcm_hw_params_t *params,
snd_pcm_hw_rule_t *rule);
static int snd_line6_tp_ux1_playback_open (snd_pcm_substream_t *substream);
static int snd_line6_tp_ux1_playback_close (snd_pcm_substream_t *substream);
static int snd_line6_tp_ux1_pcm_hw_params (snd_pcm_substream_t *substream,
snd_pcm_hw_params_t *hw_params);
static int snd_line6_tp_ux1_pcm_hw_free (snd_pcm_substream_t *substream);
static int snd_line6_tp_ux1_pcm_prepare (snd_pcm_substream_t *substream);
static int snd_line6_tp_ux1_pcm_trigger (snd_pcm_substream_t *substream,
int cmd);
static snd_pcm_uframes_t snd_line6_tp_ux1_pcm_pointer (
snd_pcm_substream_t* substream);
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);
/* static int snd_line6_tp_ux1_playback_silence (snd_pcm_substream_t *substream,
int channel,
snd_pcm_uframes_t pos,
snd_pcm_uframes_t count); */
static inline s32 snd_line6_tp_ux1_volumize_24 (u8 byte1, u8 byte2, u8 byte3,
float norm_vol);
static int snd_line6_tp_ux1_playback_vol_info (snd_kcontrol_t *kcontrol,
snd_ctl_elem_info_t *uinfo);
static int snd_line6_tp_ux1_playback_vol_get (snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *ucontrol);
static int snd_line6_tp_ux1_playback_vol_put (snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *ucontrol);
/* global variables */
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
static struct snd_line6_tp_ux1 *chip[SNDRV_CARDS] = {NULL};
/* NOTE: add TonePort UX2 PID? */
static struct usb_device_id snd_line6_tp_ux1_id_table [] =
{
{ USB_DEVICE (LINE6_VENDOR_ID, LINE6_TP_UX1_PID) },
{ }
};
static struct usb_driver snd_line6_tp_ux1_driver = {
.owner = THIS_MODULE,
.name = "snd-line6-tp-ux1",
.id_table = snd_line6_tp_ux1_id_table,
.probe = snd_line6_tp_ux1_probe,
.disconnect = snd_line6_tp_ux1_disconnect
};
static snd_pcm_hardware_t snd_line6_tp_ux1_playback_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED,
.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,
/* double buffering */
.buffer_bytes_max = LINE6_TP_UX1_48000_24_PACKET_SIZE_OUT * 1024 * 2,
.period_bytes_min = LINE6_TP_UX1_44100_16_PACKET_SIZE_OUT * 2,
.period_bytes_max = LINE6_TP_UX1_48000_24_PACKET_SIZE_OUT * 2,
.periods_min = 1,
.periods_max = 1024
};
static snd_device_ops_t snd_line6_tp_ux1_ops =
{
.dev_free = snd_line6_tp_ux1_dev_free
};
static snd_pcm_ops_t snd_line6_tp_ux1_playback_ops = {
.open = snd_line6_tp_ux1_playback_open,
.close = snd_line6_tp_ux1_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_line6_tp_ux1_pcm_hw_params,
.hw_free = snd_line6_tp_ux1_pcm_hw_free,
.prepare = snd_line6_tp_ux1_pcm_prepare,
.trigger = snd_line6_tp_ux1_pcm_trigger,
.pointer = snd_line6_tp_ux1_pcm_pointer,
.copy = snd_line6_tp_ux1_playback_copy,
/* .silence = snd_line6_tp_ux1_playback_silence */
};
/* TODO: capture ops */
static snd_kcontrol_new_t snd_line6_tp_ux1_playback_vol = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Volume",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = snd_line6_tp_ux1_playback_vol_info,
.get = snd_line6_tp_ux1_playback_vol_get,
.put = snd_line6_tp_ux1_playback_vol_put
};
/* TODO: capture volume */
/* module related stuff */
module_param_array (index, int, NULL, 0444);
MODULE_PARM_DESC (index, "Index value for the Line6 TonePort UX1 adapter.");
module_param_array (id, charp, NULL, 0444);
MODULE_PARM_DESC (id, "ID string for the Line6 TonePort UX1 adapter.");
module_param_array (enable, bool, NULL, 0444);
MODULE_PARM_DESC (enable, "Enable Line6 TonePort UX1 adapter.");
MODULE_AUTHOR ("Stefano D'Angelo <daste@oneonline.it>");
MODULE_DESCRIPTION ("Line6 TonePort UX1 USB driver for ALSA");
MODULE_LICENSE ("GPL");
MODULE_SUPPORTED_DEVICE ("Line6 TonePort UX1 USB");
MODULE_DEVICE_TABLE (usb, snd_line6_tp_ux1_id_table);
/* functions */
/*
* driver's entry-point
*/
static int snd_line6_tp_ux1_driver_init ()
{
return usb_register (&snd_line6_tp_ux1_driver);
}
/*
* driver's exit-point
*/
static void snd_line6_tp_ux1_driver_exit ()
{
usb_deregister (&snd_line6_tp_ux1_driver);
}
/*
* probes the sound card
*
* checks whether the device is already registered or not and eventually inits
* it using the first avaible slot.
*
* it doesn't seem to happen that this function is executed multpile times for
* a single card, but we check the same
*/
static int snd_line6_tp_ux1_probe (struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev (intf);
int i, j;
j = -1;
for (i = 0; i < SNDRV_CARDS; i++) {
if (chip[i]) {
/* couldn't do the following check before */
if (dev == chip[i]->dev) {
/* yes, already registered */
return 0;
}
} else {
/* oh, we've got a slot */
if (j == -1)
j = i;
}
}
if (j == -1) {
snd_printk (KERN_ERR "no available USB audio device\n");
return -ENODEV;
}
return snd_line6_tp_ux1_create (dev, j);
}
/*
* inits the soundcard and the drivers' handles
*
* TODO: add capture volume
*/
static int snd_line6_tp_ux1_create (struct usb_device *dev, int idx)
{
snd_card_t* card;
int i;
chip[idx] = kzalloc (sizeof (struct snd_line6_tp_ux1), GFP_KERNEL);
/* create a card instance */
if (!(chip[idx]->card = snd_card_new (index[idx], id[idx], THIS_MODULE,
sizeof (struct snd_line6_tp_ux1*)))) {
snd_printk (KERN_ERR "cannot create card instance %d\n", idx);
kfree (chip[idx]);
chip[idx] = NULL;
return -ENOMEM;
}
card = chip[idx]->card;
card->private_data = chip[idx];
/* set the driver ID and name strings */
strlcat (card->driver, "Line6-TP-UX1", sizeof (card->driver));
strlcat (card->shortname, "Line6 TonePort UX1 USB",
sizeof (card->shortname));
i = strlcat (card->longname, "Line6 TonePort UX1 USB at ",
sizeof (card->longname));
if (i < sizeof (card->longname)) {
usb_make_path (dev, card->longname + i,
sizeof (card->longname) - i);
}
if (dev->speed == USB_SPEED_FULL) {
strlcat (card->longname, ", full speed",
sizeof (card->longname));
} else {
strlcat (card->longname, ", unknown speed",
sizeof (card->longname));
}
/* init USB messages */
if ((i = snd_line6_tp_ux1_init_msgs (dev))) {
snd_printk (KERN_ERR "failed to send init messages to the "
"sound card\n");
snd_card_free_in_thread (card);
kfree (chip[idx]);
chip[idx] = NULL;
return i;
}
/* create components, such as mixer, MIDI, etc. */
if ((i = snd_device_new (card, SNDRV_DEV_LOWLEVEL, chip[idx],
&snd_line6_tp_ux1_ops))) {
snd_printk (KERN_ERR "could not create a device handler for "
"the card\n");
snd_card_free_in_thread (card);
kfree (chip[idx]);
chip[idx] = NULL;
return i;
}
if ((i = snd_line6_tp_ux1_new_pcm (chip[idx]))) {
snd_printk (KERN_ERR "could not create a pcm stream for the "
"card\n");
} else {
if ((i = snd_ctl_add (card, snd_ctl_new1 (
&snd_line6_tp_ux1_playback_vol,
chip[idx]))) < 0) {
snd_printk (KERN_ERR "could not add the master playback "
"volume control to the card\n");
}
}
/* register the card instance */
if ((i = snd_card_register (card))) {
snd_printk (KERN_ERR "could not register the card's "
"instance!\n");
snd_card_free_in_thread (card);
kfree (chip[idx]);
chip[idx] = NULL;
return i;
}
/* set some other data */
chip[idx]->index = idx;
chip[idx]->dev = dev;
chip[idx]->altsetting = 0;
chip[idx]->playback_lvol = LINE6_TP_UX1_VOL_MAX;
chip[idx]->playback_rvol = LINE6_TP_UX1_VOL_MAX;
chip[idx]->pending_playback_urbs = NULL;
return 0;
}
/*
* sends vendor specific init messages to the card
*/
static int snd_line6_tp_ux1_init_msgs (struct usb_device* dev)
{
unsigned char msg1[] = LINE6_TP_UX1_MSG_1;
unsigned char msg2[] = LINE6_TP_UX1_MSG_2;
unsigned char msg3[] = LINE6_TP_UX1_MSG_3;
unsigned char msg4[] = LINE6_TP_UX1_MSG_4;
int i;
if ((i = snd_line6_tp_ux1_submit_control_transfer (dev, msg1)))
return i;
if ((i = snd_line6_tp_ux1_submit_control_transfer (dev, msg2)))
return i;
if ((i = snd_line6_tp_ux1_submit_control_transfer (dev, msg3)))
return i;
return snd_line6_tp_ux1_submit_control_transfer (dev, msg4);
}
/*
* creates a pcm stream for the device
*
* TODO: add capture
*/
static int snd_line6_tp_ux1_new_pcm (struct snd_line6_tp_ux1 *chip)
{
snd_pcm_t *pcm;
int err;
if ((err = snd_pcm_new (chip->card, "Line6 TonePort UX1", 0, 1, 0,
&pcm)) < 0)
return err;
pcm->private_data = chip;
strcpy (pcm->name, "Line6 TonePort UX1");
chip->pcm = pcm;
snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_PLAYBACK,
&snd_line6_tp_ux1_playback_ops);
snd_pcm_lib_preallocate_pages_for_all (pcm, SNDRV_DMA_TYPE_DEV,
chip->dev, 64*1024, 64*1024);
return 0;
}
/*
* handles the card's disconnection
*/
static void snd_line6_tp_ux1_disconnect (struct usb_interface *intf)
{
int i;
/* find the card */
for (i = 0; i < SNDRV_CARDS; i++) {
if (chip[i]) {
/* couldn't do this check before again */
if (chip[i]->dev == interface_to_usbdev(intf))
break;
}
}
if (i != SNDRV_CARDS)
snd_line6_tp_ux1_free (chip[i]);
}
/*
* fake component destructor
*/
static int snd_line6_tp_ux1_dev_free (snd_device_t *device)
{
return 0;
}
/*
* chip-specific destructor
*/
static int snd_line6_tp_ux1_free (struct snd_line6_tp_ux1 *chip_ptr)
{
int i;
if (!(i = snd_card_free_in_thread (chip_ptr->card))) {
chip[chip_ptr->index] = NULL;
kfree (chip_ptr);
}
return i;
}
/*
* submits an USB control transfer to the card with packet as setup_packet
*/
static int snd_line6_tp_ux1_submit_control_transfer (struct usb_device* dev,
unsigned char* packet)
{
struct urb* urb;
struct completion done;
int i;
urb = usb_alloc_urb (0, GFP_KERNEL);
init_completion (&done);
usb_fill_control_urb (urb, dev, usb_sndctrlpipe (dev, 0), packet, NULL,
0, snd_line6_tp_ux1_complete_control_transfer,
&done);
i = usb_submit_urb (urb, GFP_KERNEL);
wait_for_completion (&done);
return i;
}
/*
* control transfers' completition callback
*
* TODO: write some error handling
*/
static void snd_line6_tp_ux1_complete_control_transfer (struct urb* urb,
struct pt_regs* regs)
{
if (!urb->status) {
usb_free_urb (urb);
}
complete (urb->context);
}
/*
* playback transfers' completition callback
*
* TODO: error checking?
*/
static void snd_line6_tp_ux1_complete_playback_transfer (struct urb* urb,
struct pt_regs* regs)
{
struct urb_list** pend_urbs = &(chip[*((int*)(urb->context))]->
pending_playback_urbs);
struct urb_list *tmp;
if ((*pend_urbs)->next) {
tmp = *pend_urbs;
*pend_urbs = (*pend_urbs)->next;
kfree (tmp);
} else {
kfree (*pend_urbs);
*pend_urbs = NULL;
}
kfree (urb->transfer_buffer);
usb_free_urb (urb);
}
/*
* sets hw rules for playback at different rates
*/
static int snd_line6_tp_ux1_hw_period_by_rate (snd_pcm_hw_params_t *params,
snd_pcm_hw_rule_t *rule)
{
snd_interval_t *p = hw_param_interval (params,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
snd_interval_t *r = hw_param_interval (params,
SNDRV_PCM_HW_PARAM_RATE);
snd_interval_t *bs = hw_param_interval (params,
SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
snd_interval_t *bb = hw_param_interval (params,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
snd_interval_t p_size;
snd_interval_t b_size;
int i, j;
snd_interval_any (&p_size);
snd_interval_any (&b_size);
if (r->max == 48000) {
printk ("a\n");
p_size.min = p_size.max = 48 * 2;
b_size.min = 48 * 2;
b_size.max = 48 * 2 * 1024;
i = snd_interval_refine (bs, &b_size);
j = snd_interval_refine (p, &p_size);
printk ("%d %d %d %d %d %d %d %d\n", i, j, bs->min, bs->max, bb->min, bb->max, p->min, p->max);
return j;
} else if (r->max == 44100) {
printk ("b\n");
p_size.min = p_size.max = 45 * 2;
b_size.min = 45 * 2;
b_size.max = 45 * 2 * 1024;
printk ("%d %d %d %d %d %d %d %d\n", i, j, bs->min, bs->max, bb->min, bb->max, p->min, p->max);
i = snd_interval_refine (bs, &b_size);
j = snd_interval_refine (p, &p_size);
printk ("%d %d %d %d %d %d %d %d\n", i, j, bs->min, bs->max, bb->min, bb->max, p->min, p->max);
return j;
}
return 0;
}
/*
* sets the hw_params for a playback stream
*/
static int snd_line6_tp_ux1_playback_open (snd_pcm_substream_t *substream)
{
struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
if ((err = snd_pcm_hw_rule_add (runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
snd_line6_tp_ux1_hw_period_by_rate, 0,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1)))
return err;
runtime->hw = snd_line6_tp_ux1_playback_hw;
return 0;
}
/*
* resets the device to the "normal" (non-transfer) mode
*/
static int snd_line6_tp_ux1_playback_close (snd_pcm_substream_t *substream)
{
return 0;
}
/*
* hw_params callback
*
* TODO: capture
*/
static int snd_line6_tp_ux1_pcm_hw_params (snd_pcm_substream_t *substream,
snd_pcm_hw_params_t *hw_params)
{
struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
unsigned char msg[] = LINE6_TP_UX1_MSG_3;
int err, err2;
chip->playback_pos = 0;
if (chip->altsetting)
return snd_pcm_lib_malloc_pages (substream,
params_buffer_bytes (hw_params));
switch (params_rate (hw_params)) {
case 48000:
if (params_format (hw_params) == SNDRV_PCM_FMTBIT_S16_LE) {
chip->altsetting = LINE6_TP_UX1_48000_16_ALTSETTING;
} else {
chip->altsetting = LINE6_TP_UX1_48000_24_ALTSETTING;
}
break;
case 44100:
if (params_format (hw_params) == SNDRV_PCM_FMTBIT_S16_LE) {
chip->altsetting = LINE6_TP_UX1_44100_16_ALTSETTING;
} else {
chip->altsetting = LINE6_TP_UX1_44100_24_ALTSETTING;
}
break;
default:
chip->altsetting = LINE6_TP_UX1_48000_24_ALTSETTING;
break;
}
printk ("%d\n", params_period_size(hw_params));
if ((err = usb_set_interface (chip->dev, 0, chip->altsetting)) < 0) {
chip->altsetting = 0;
return err;
}
if ((err = snd_line6_tp_ux1_submit_control_transfer (chip->dev, msg)) <
0) {
chip->altsetting = 0;
if ((err2 = usb_set_interface (chip->dev, 0, 0)) < 0)
return err2;
return err;
}
return snd_pcm_lib_malloc_pages (substream,
params_buffer_bytes (hw_params));
}
/*
* hw_free callback
*
* TODO: unset playback/capture/both modes and relative parameters
*/
static int snd_line6_tp_ux1_pcm_hw_free (snd_pcm_substream_t *substream)
{
struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
struct urb_list *list;
int err;
if ((list = chip->pending_playback_urbs)) {
do {
usb_unlink_urb (list->urb);
} while ((list = list->next));
}
chip->altsetting = 0;
if ((err = usb_set_interface (chip->dev, 0 ,0)) < 0)
return err;
return snd_pcm_lib_free_pages (substream);
}
/*
* prepare callback
*
* TODO: write it
*/
static int snd_line6_tp_ux1_pcm_prepare (snd_pcm_substream_t *substream)
{
/* struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
snd_pcm_runtime_t *runtime = substream->runtime; */
/* set up the hardware with the current configuration (sample format,
sample rate, etc.) */
return 0;
}
/*
* trigger callback
*
* TODO: write it
*/
static int snd_line6_tp_ux1_pcm_trigger (snd_pcm_substream_t *substream, int cmd)
{
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
printk ("trigger start\n");
break;
case SNDRV_PCM_TRIGGER_STOP:
printk ("trigger stop\n");
break;
default:
return -EINVAL;
}
return 0;
}
/*
* pointer callback
*
* returns the position in frames of the buffer actually sent/received
*
* TODO: capture
*/
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);
return chip->playback_pos;
}
/*
* does the playback
*
* TODO: handle different formats, etc.
*/
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);
float norm_lvol = (float) chip->playback_lvol /
(float) LINE6_TP_UX1_VOL_MAX;
float norm_rvol = (float) chip->playback_rvol /
(float) LINE6_TP_UX1_VOL_MAX;
struct urb* urb;
u8* data = src;
u8* buf;
int val;
int i = 0;
urb = usb_alloc_urb (2, GFP_ATOMIC);
if (!chip->pending_playback_urbs) {
chip->last_pending_playback_urb = chip->pending_playback_urbs =
kmalloc (sizeof (struct urb_list), GFP_ATOMIC);
chip->pending_playback_urbs->urb = urb;
chip->pending_playback_urbs->next = NULL;
} else {
chip->last_pending_playback_urb =
chip->last_pending_playback_urb->next =
kmalloc (sizeof (struct urb_list), GFP_ATOMIC);
chip->last_pending_playback_urb->urb = urb;
chip->last_pending_playback_urb->next = NULL;
}
urb->dev = chip->dev;
urb->pipe = usb_sndisocpipe (urb->dev, 1);
urb->complete = snd_line6_tp_ux1_complete_playback_transfer;
urb->context = &chip->index;
buf = urb->transfer_buffer = kmalloc (
LINE6_TP_UX1_48000_24_PACKET_SIZE_OUT * 2, GFP_ATOMIC);
urb->transfer_buffer_length = LINE6_TP_UX1_48000_24_PACKET_SIZE_OUT *
2;
urb->transfer_flags = URB_ISO_ASAP;
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_24_PACKET_SIZE_OUT;
while (i < LINE6_TP_UX1_48000_24_PACKET_SIZE_OUT * 2) {
val = snd_line6_tp_ux1_volumize_24 (data[i + 2], data[i + 1], data[i], norm_lvol);
buf[i++] = val & 0x000000ff;
buf[i++] = (val & 0x0000ff00) >> 8;
buf[i++] = (val & 0x00ff0000) >> 16;
val = snd_line6_tp_ux1_volumize_24 (data[i + 2], data[i + 1], data[i], norm_rvol);
buf[i++] = val & 0x000000ff;
buf[i++] = (val & 0x0000ff00) >> 8;
buf[i++] = (val & 0x00ff0000) >> 16;
chip->playback_pos++;
}
usb_submit_urb (urb, GFP_ATOMIC);
return count;
}
/*
* 24-bit "volumizer" function
*/
static inline s32 snd_line6_tp_ux1_volumize_24 (u8 byte1, u8 byte2, u8 byte3,
float norm_vol)
{
s32 val = (byte1 << 16) + (byte2 << 8) + byte3;
if (byte1 & 0x80)
val |= 0xff000000;
return (s32) ((float) val * norm_vol);
}
/*
* sets master playback volume internal representation
*/
static int snd_line6_tp_ux1_playback_vol_info (snd_kcontrol_t *kcontrol,
snd_ctl_elem_info_t *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = LINE6_TP_UX1_VOL_MIN;
uinfo->value.integer.max = LINE6_TP_UX1_VOL_MAX;
return 0;
}
/*
* puts into ucontrol the current values of playback volumes
*/
static int snd_line6_tp_ux1_playback_vol_get (snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *ucontrol)
{
struct snd_line6_tp_ux1 *chip = snd_kcontrol_chip (kcontrol);
ucontrol->value.integer.value[0] = chip->playback_lvol;
ucontrol->value.integer.value[1] = chip->playback_rvol;
return 0;
}
/*
* sets values for playback volumes
*/
static int snd_line6_tp_ux1_playback_vol_put (snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *ucontrol)
{
struct snd_line6_tp_ux1 *chip = snd_kcontrol_chip (kcontrol);
int changed = 0;
if (chip->playback_lvol != ucontrol->value.integer.value[0]) {
chip->playback_lvol = ucontrol->value.integer.value[0];
changed = 1;
}
if (chip->playback_rvol != ucontrol->value.integer.value[1]) {
chip->playback_rvol = ucontrol->value.integer.value[1];
changed = 1;
}
return changed;
}
/* entry and exit-points of this driver */
module_init (snd_line6_tp_ux1_driver_init);
module_exit (snd_line6_tp_ux1_driver_exit);
[-- Attachment #3: snd_line6_tp_ux1.h --]
[-- Type: application/octet-stream, Size: 2563 bytes --]
/*
* Line6 TonePort UX1 (and maybe TonePort UX2) USB driver for ALSA
*
*
* Copyright (c) 2006 by Stefano D'Angelo <daste@oneonline.it>
*
* Some code borrowed from
* USB Audio Driver for ALSA by Takashi Iwai <tiwai@suse.de>
* "Writing an ALSA Driver" by Takashi Iwai <tiwai@suse.de>
* "Linux USB Driver Basics" at http://www.linuxtecharticles.com
* and maybe, consequently, also from audio.c by
* Alan Cox <alan@lxorguk.ukuu.org.uk>
* Thomas Sailer <sailer@ife.ee.ethz.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __LINE6_TP_UX1_H_
#define __LINE6_TP_UX1_H_
#define LINE6_VENDOR_ID 0x0e41
#define LINE6_TP_UX1_PID 0x4141
/* obscure control messages */
#define LINE6_TP_UX1_MSG_1 {0x40, 0x67, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00}
#define LINE6_TP_UX1_MSG_2 {0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
#define LINE6_TP_UX1_MSG_3 {0x40, 0x67, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00}
#define LINE6_TP_UX1_MSG_4 {0x40, 0x67, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00}
/* internal volume representation */
#define LINE6_TP_UX1_VOL_MIN 0x0000
#define LINE6_TP_UX1_VOL_MAX 0xffff
/* 48 kHz, 16-bits */
#define LINE6_TP_UX1_48000_16_ALTSETTING 1
#define LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT 192
#define LINE6_TP_UX1_48000_16_PACKET_SIZE_IN 200
/* 44.1 kHz, 16-bits */
#define LINE6_TP_UX1_44100_16_ALTSETTING 2
#define LINE6_TP_UX1_44100_16_PACKET_SIZE_OUT 180
#define LINE6_TP_UX1_44100_16_PACKET_SIZE_IN 188
/* 48 kHz, 24-bits */
#define LINE6_TP_UX1_48000_24_ALTSETTING 3
#define LINE6_TP_UX1_48000_24_PACKET_SIZE_OUT 288
#define LINE6_TP_UX1_48000_24_PACKET_SIZE_IN 300
/* 44.1 kHz, 24-bits */
#define LINE6_TP_UX1_44100_24_ALTSETTING 4
#define LINE6_TP_UX1_44100_24_PACKET_SIZE_OUT 270
#define LINE6_TP_UX1_44100_24_PACKET_SIZE_IN 282
#endif /* __LINE6_TP_UX1_H_ */
^ permalink raw reply [flat|nested] 9+ messages in thread
* Line6 TonePort UX1 driver
@ 2006-05-16 8:57 Stefano D Angelo
0 siblings, 0 replies; 9+ messages in thread
From: Stefano D Angelo @ 2006-05-16 8:57 UTC (permalink / raw)
To: alsa-devel
Hey,
are you still receiving my e-mails?
Stefano
-----------------
Registra il tuo nome di dominio su: http://www.oneonline.it/domini
One On Line ti offre domino + spazio web illimitato + 5 email + 5000 uscite banner + PHP + Link a soli Euro 15 iva compresa
-------------------------------------------------------
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] 9+ messages in thread
* Line6 Toneport UX1 driver
@ 2006-06-09 9:30 Stefano D'Angelo
2006-06-09 13:00 ` Clemens Ladisch
0 siblings, 1 reply; 9+ messages in thread
From: Stefano D'Angelo @ 2006-06-09 9:30 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1.1: Type: text/plain, Size: 1464 bytes --]
I just can't get it working... here's the code I've written:
static void snd_line6_tp_ux1_complete_playback_transfer (struct urb* urb,
struct pt_regs*
regs)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)(urb->context);
struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
snd_pcm_runtime_t *runtime = substream->runtime;
urb->dev = chip->dev;
urb->transfer_dma = runtime->dma_addr;
urb->transfer_buffer = usb_buffer_alloc (urb->dev,
LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2, GFP_KERNEL, &urb->transfer_dma);
memcpy (urb->transfer_buffer, runtime->dma_area + chip->playback_pos *
2, LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2);
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
usb_submit_urb (urb, GFP_ATOMIC);
chip->playback_pos += LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2 / 4;
snd_pcm_period_elapsed (substream);
}
don't care about freeing, etc. The problem is that it gives me a kind of
beep sound for anything I play. No underruns, etc., just that sound!
URBs' data seems to be correct and also the transfer seems to happen with no
particular problem. (no error checking right now however).
Another thing is this: I've seen that you decrement the hardware pointer
when it reaches the end of a period, but when I try to do this, it gives me
back garbage values, how is this possible?
What do you think I should do?
[-- Attachment #1.2: Type: text/html, Size: 2050 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
[-- 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] 9+ messages in thread
* Re: Line6 Toneport UX1 driver
2006-06-09 9:30 Line6 Toneport " Stefano D'Angelo
@ 2006-06-09 13:00 ` Clemens Ladisch
[not found] ` <160c13350606100338y63b73447t7e783f2709683e63@mail.gmail.com>
0 siblings, 1 reply; 9+ messages in thread
From: Clemens Ladisch @ 2006-06-09 13:00 UTC (permalink / raw)
To: Stefano D'Angelo; +Cc: alsa-devel
Stefano D'Angelo wrote:
> urb->transfer_dma = runtime->dma_addr;
This will always play the data at the beginning of the buffer.
> urb->transfer_buffer = usb_buffer_alloc (urb->dev,
> LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2, GFP_KERNEL, &urb->transfer_dma);
This buffer should be allocated when the URB is allocated.
> memcpy (urb->transfer_buffer, runtime->dma_area + chip->playback_pos *
> 2, LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2);
I hope the buffer size is a multiple of PACKET_SIZE_OUT * 2.
> urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
Why the NO_TRANSFER_DMA_MAP? You shouldn't need to do such
optimizations in the first version of the driver.
> snd_pcm_period_elapsed (substream);
What is the period size?
Regards,
Clemens
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Line6 Toneport UX1 driver
[not found] ` <160c13350606100338y63b73447t7e783f2709683e63@mail.gmail.com>
@ 2006-06-10 11:28 ` Stefano D'Angelo
0 siblings, 0 replies; 9+ messages in thread
From: Stefano D'Angelo @ 2006-06-10 11:28 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1.1: Type: text/plain, Size: 3695 bytes --]
2006/6/9, Clemens Ladisch <clemens@ladisch.de>:
>
> Stefano D'Angelo wrote:
> > urb->transfer_dma = runtime->dma_addr;
>
> This will always play the data at the beginning of the buffer.
fixed
> urb->transfer_buffer = usb_buffer_alloc (urb->dev,
> > LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2, GFP_KERNEL,
> &urb->transfer_dma);
>
> This buffer should be allocated when the URB is allocated.
fixed
> memcpy (urb->transfer_buffer, runtime->dma_area + chip->playback_pos *
> > 2, LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2);
>
> I hope the buffer size is a multiple of PACKET_SIZE_OUT * 2.
it is
> urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
>
> Why the NO_TRANSFER_DMA_MAP? You shouldn't need to do such
> optimizations in the first version of the driver.
ok
> snd_pcm_period_elapsed (substream);
>
> What is the period size?
period size is 96 = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2 (double
buffering) / 2 (16 bit data), so everytime an urb is sent a period is
elapsed.
Here is how I'm doing right now but I still got the same beep for everything
I play (when I used the copy () callback it kind of worked, is perphaps
possible that the soundcard doesn't support dma transfers?):
static void snd_line6_tp_ux1_complete_playback_transfer (struct urb* urb,
struct pt_regs*
regs)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)(urb->context);
struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
snd_pcm_runtime_t *runtime = substream->runtime;
chip->playback_pos += LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2 / 2;
if (chip->playback_pos == runtime->buffer_size) {
chip->playback_pos -= runtime->buffer_size;
}
memcpy (urb->transfer_buffer, runtime->dma_area + chip->playback_pos *
2, LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2);
snd_pcm_period_elapsed (substream);
usb_submit_urb (urb, GFP_ATOMIC);
}
static int snd_line6_tp_ux1_pcm_trigger (snd_pcm_substream_t *substream,
int cmd)
{
struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
snd_pcm_runtime_t *runtime = substream->runtime;
static struct urb* urb;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
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_dma = runtime->dma_addr;
urb->transfer_buffer = usb_buffer_alloc (urb->dev,
LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2, GFP_ATOMIC,
&urb->transfer_dma);
memcpy (urb->transfer_buffer, runtime->dma_area,
LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2);
urb->transfer_flags = URB_ISO_ASAP; // | URB_NO_TRANSFER_DMA_MAP;
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;
chip->playback_pos = 0;
usb_submit_urb (urb, GFP_KERNEL);
break;
case SNDRV_PCM_TRIGGER_STOP:
usb_buffer_free (chip->dev,
LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2,
urb->transfer_buffer, urb->transfer_dma);
usb_free_urb (urb);
break;
default:
return -EINVAL;
break;
}
return 0;
}
Thanks,
Stefano
[-- Attachment #1.2: Type: text/html, Size: 7938 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
[-- 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] 9+ messages in thread
* Line6 Toneport UX1 driver
@ 2006-06-12 8:54 Stefano D'Angelo
0 siblings, 0 replies; 9+ messages in thread
From: Stefano D'Angelo @ 2006-06-12 8:54 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1.1: Type: text/plain, Size: 3671 bytes --]
Hi,
> Stefano D'Angelo wrote:
> > urb->transfer_dma = runtime->dma_addr;
>
> This will always play the data at the beginning of the buffer.
fixed
> urb->transfer_buffer = usb_buffer_alloc (urb->dev,
> > LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2, GFP_KERNEL,
> &urb->transfer_dma);
>
> This buffer should be allocated when the URB is allocated.
fixed
> memcpy (urb->transfer_buffer, runtime->dma_area + chip->playback_pos *
> > 2, LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2);
>
> I hope the buffer size is a multiple of PACKET_SIZE_OUT * 2.
>
yes, it is
> urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
>
> Why the NO_TRANSFER_DMA_MAP? You shouldn't need to do such
> optimizations in the first version of the driver.
ok, put it out
> snd_pcm_period_elapsed (substream);
>
> What is the period size?
period size is 96 = LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2 (double
buffering) / 2 (16 bit data), so everytime an urb is sent a period elapses.
Here is how I'm doing right now but I still got the same beep for everything
I play (when I used the copy () callback it kind of worked, is perphaps
possible that this USB soundcard doesn't support dma transfers?):
static void snd_line6_tp_ux1_complete_playback_transfer (struct urb* urb,
struct pt_regs*
regs)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)(urb->context);
struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
snd_pcm_runtime_t *runtime = substream->runtime;
chip->playback_pos += LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2 / 2;
if (chip->playback_pos == runtime->buffer_size) {
chip->playback_pos -= runtime->buffer_size;
}
memcpy (urb->transfer_buffer, runtime->dma_area + chip->playback_pos *
2, LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2);
snd_pcm_period_elapsed (substream);
usb_submit_urb (urb, GFP_ATOMIC);
}
static int snd_line6_tp_ux1_pcm_trigger (snd_pcm_substream_t *substream,
int cmd)
{
struct snd_line6_tp_ux1 *chip = snd_pcm_substream_chip (substream);
snd_pcm_runtime_t *runtime = substream->runtime;
static struct urb* urb;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
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_dma = runtime->dma_addr;
urb->transfer_buffer = usb_buffer_alloc (urb->dev,
LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2, GFP_ATOMIC,
&urb->transfer_dma);
memcpy (urb->transfer_buffer, runtime->dma_area,
LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2);
urb->transfer_flags = URB_ISO_ASAP; // | URB_NO_TRANSFER_DMA_MAP;
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;
chip->playback_pos = 0;
usb_submit_urb (urb, GFP_KERNEL);
break;
case SNDRV_PCM_TRIGGER_STOP:
usb_buffer_free (chip->dev,
LINE6_TP_UX1_48000_16_PACKET_SIZE_OUT * 2,
urb->transfer_buffer, urb->transfer_dma);
usb_free_urb (urb);
break;
default:
return -EINVAL;
break;
}
return 0;
}
Thanks, Stefano
[-- Attachment #1.2: Type: text/html, Size: 7660 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
[-- 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] 9+ messages in thread
end of thread, other threads:[~2006-06-12 8:54 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-08 17:16 Line6 TonePort UX1 driver Stefano D Angelo
2006-05-10 13:29 ` Takashi Iwai
[not found] ` <20060510165635.M757@oneonline.it>
2006-05-10 15:34 ` Takashi Iwai
[not found] ` <20060512004915.M47766@oneonline.it>
2006-05-12 8:15 ` Stefano D Angelo
-- strict thread matches above, loose matches on Subject: below --
2006-05-16 8:57 Stefano D Angelo
2006-06-09 9:30 Line6 Toneport " Stefano D'Angelo
2006-06-09 13:00 ` Clemens Ladisch
[not found] ` <160c13350606100338y63b73447t7e783f2709683e63@mail.gmail.com>
2006-06-10 11:28 ` Stefano D'Angelo
2006-06-12 8:54 Stefano D'Angelo
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.