forked from Minki/linux
Merge branch 'topic/usb-audio' into for-linus
This commit is contained in:
commit
afad17c0ae
@ -107,7 +107,7 @@ MODULE_PARM_DESC(ignore_ctl_error,
|
|||||||
#define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
|
#define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
|
||||||
#define MAX_URBS 8
|
#define MAX_URBS 8
|
||||||
#define SYNC_URBS 4 /* always four urbs for sync */
|
#define SYNC_URBS 4 /* always four urbs for sync */
|
||||||
#define MIN_PACKS_URB 1 /* minimum 1 packet per urb */
|
#define MAX_QUEUE 24 /* try not to exceed this queue length, in ms */
|
||||||
|
|
||||||
struct audioformat {
|
struct audioformat {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
@ -525,7 +525,7 @@ static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
|
|||||||
/*
|
/*
|
||||||
* Prepare urb for streaming before playback starts or when paused.
|
* Prepare urb for streaming before playback starts or when paused.
|
||||||
*
|
*
|
||||||
* We don't have any data, so we send a frame of silence.
|
* We don't have any data, so we send silence.
|
||||||
*/
|
*/
|
||||||
static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
|
static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
|
||||||
struct snd_pcm_runtime *runtime,
|
struct snd_pcm_runtime *runtime,
|
||||||
@ -537,13 +537,13 @@ static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
|
|||||||
|
|
||||||
offs = 0;
|
offs = 0;
|
||||||
urb->dev = ctx->subs->dev;
|
urb->dev = ctx->subs->dev;
|
||||||
urb->number_of_packets = subs->packs_per_ms;
|
for (i = 0; i < ctx->packets; ++i) {
|
||||||
for (i = 0; i < subs->packs_per_ms; ++i) {
|
|
||||||
counts = snd_usb_audio_next_packet_size(subs);
|
counts = snd_usb_audio_next_packet_size(subs);
|
||||||
urb->iso_frame_desc[i].offset = offs * stride;
|
urb->iso_frame_desc[i].offset = offs * stride;
|
||||||
urb->iso_frame_desc[i].length = counts * stride;
|
urb->iso_frame_desc[i].length = counts * stride;
|
||||||
offs += counts;
|
offs += counts;
|
||||||
}
|
}
|
||||||
|
urb->number_of_packets = ctx->packets;
|
||||||
urb->transfer_buffer_length = offs * stride;
|
urb->transfer_buffer_length = offs * stride;
|
||||||
memset(urb->transfer_buffer,
|
memset(urb->transfer_buffer,
|
||||||
subs->cur_audiofmt->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0,
|
subs->cur_audiofmt->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0,
|
||||||
@ -1034,9 +1034,9 @@ static void release_substream_urbs(struct snd_usb_substream *subs, int force)
|
|||||||
static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int period_bytes,
|
static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int period_bytes,
|
||||||
unsigned int rate, unsigned int frame_bits)
|
unsigned int rate, unsigned int frame_bits)
|
||||||
{
|
{
|
||||||
unsigned int maxsize, n, i;
|
unsigned int maxsize, i;
|
||||||
int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
|
int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
|
||||||
unsigned int npacks[MAX_URBS], urb_packs, total_packs, packs_per_ms;
|
unsigned int urb_packs, total_packs, packs_per_ms;
|
||||||
|
|
||||||
/* calculate the frequency in 16.16 format */
|
/* calculate the frequency in 16.16 format */
|
||||||
if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
|
if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
|
||||||
@ -1070,8 +1070,7 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
|
|||||||
subs->packs_per_ms = packs_per_ms;
|
subs->packs_per_ms = packs_per_ms;
|
||||||
|
|
||||||
if (is_playback) {
|
if (is_playback) {
|
||||||
urb_packs = nrpacks;
|
urb_packs = max(nrpacks, 1);
|
||||||
urb_packs = max(urb_packs, (unsigned int)MIN_PACKS_URB);
|
|
||||||
urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
|
urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
|
||||||
} else
|
} else
|
||||||
urb_packs = 1;
|
urb_packs = 1;
|
||||||
@ -1079,7 +1078,7 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
|
|||||||
|
|
||||||
/* decide how many packets to be used */
|
/* decide how many packets to be used */
|
||||||
if (is_playback) {
|
if (is_playback) {
|
||||||
unsigned int minsize;
|
unsigned int minsize, maxpacks;
|
||||||
/* determine how small a packet can be */
|
/* determine how small a packet can be */
|
||||||
minsize = (subs->freqn >> (16 - subs->datainterval))
|
minsize = (subs->freqn >> (16 - subs->datainterval))
|
||||||
* (frame_bits >> 3);
|
* (frame_bits >> 3);
|
||||||
@ -1092,8 +1091,13 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
|
|||||||
total_packs = (total_packs + packs_per_ms - 1)
|
total_packs = (total_packs + packs_per_ms - 1)
|
||||||
& ~(packs_per_ms - 1);
|
& ~(packs_per_ms - 1);
|
||||||
/* we need at least two URBs for queueing */
|
/* we need at least two URBs for queueing */
|
||||||
if (total_packs < 2 * MIN_PACKS_URB * packs_per_ms)
|
if (total_packs < 2 * packs_per_ms) {
|
||||||
total_packs = 2 * MIN_PACKS_URB * packs_per_ms;
|
total_packs = 2 * packs_per_ms;
|
||||||
|
} else {
|
||||||
|
/* and we don't want too long a queue either */
|
||||||
|
maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
|
||||||
|
total_packs = min(total_packs, maxpacks);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
total_packs = MAX_URBS * urb_packs;
|
total_packs = MAX_URBS * urb_packs;
|
||||||
}
|
}
|
||||||
@ -1102,31 +1106,11 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
|
|||||||
/* too much... */
|
/* too much... */
|
||||||
subs->nurbs = MAX_URBS;
|
subs->nurbs = MAX_URBS;
|
||||||
total_packs = MAX_URBS * urb_packs;
|
total_packs = MAX_URBS * urb_packs;
|
||||||
}
|
} else if (subs->nurbs < 2) {
|
||||||
n = total_packs;
|
|
||||||
for (i = 0; i < subs->nurbs; i++) {
|
|
||||||
npacks[i] = n > urb_packs ? urb_packs : n;
|
|
||||||
n -= urb_packs;
|
|
||||||
}
|
|
||||||
if (subs->nurbs <= 1) {
|
|
||||||
/* too little - we need at least two packets
|
/* too little - we need at least two packets
|
||||||
* to ensure contiguous playback/capture
|
* to ensure contiguous playback/capture
|
||||||
*/
|
*/
|
||||||
subs->nurbs = 2;
|
subs->nurbs = 2;
|
||||||
npacks[0] = (total_packs + 1) / 2;
|
|
||||||
npacks[1] = total_packs - npacks[0];
|
|
||||||
} else if (npacks[subs->nurbs-1] < MIN_PACKS_URB * packs_per_ms) {
|
|
||||||
/* the last packet is too small.. */
|
|
||||||
if (subs->nurbs > 2) {
|
|
||||||
/* merge to the first one */
|
|
||||||
npacks[0] += npacks[subs->nurbs - 1];
|
|
||||||
subs->nurbs--;
|
|
||||||
} else {
|
|
||||||
/* divide to two */
|
|
||||||
subs->nurbs = 2;
|
|
||||||
npacks[0] = (total_packs + 1) / 2;
|
|
||||||
npacks[1] = total_packs - npacks[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate and initialize data urbs */
|
/* allocate and initialize data urbs */
|
||||||
@ -1134,7 +1118,8 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
|
|||||||
struct snd_urb_ctx *u = &subs->dataurb[i];
|
struct snd_urb_ctx *u = &subs->dataurb[i];
|
||||||
u->index = i;
|
u->index = i;
|
||||||
u->subs = subs;
|
u->subs = subs;
|
||||||
u->packets = npacks[i];
|
u->packets = (i + 1) * total_packs / subs->nurbs
|
||||||
|
- i * total_packs / subs->nurbs;
|
||||||
u->buffer_size = maxsize * u->packets;
|
u->buffer_size = maxsize * u->packets;
|
||||||
if (subs->fmt_type == USB_FORMAT_TYPE_II)
|
if (subs->fmt_type == USB_FORMAT_TYPE_II)
|
||||||
u->packets++; /* for transfer delimiter */
|
u->packets++; /* for transfer delimiter */
|
||||||
@ -1292,14 +1277,14 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface,
|
|||||||
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
|
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
|
||||||
USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
|
USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
|
||||||
SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
|
SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
|
||||||
snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep 0x%x\n",
|
snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
|
||||||
dev->devnum, iface, fmt->altsetting, rate, ep);
|
dev->devnum, iface, fmt->altsetting, rate, ep);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR,
|
if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR,
|
||||||
USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
|
USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
|
||||||
SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
|
SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
|
||||||
snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep 0x%x\n",
|
snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
|
||||||
dev->devnum, iface, fmt->altsetting, ep);
|
dev->devnum, iface, fmt->altsetting, ep);
|
||||||
return 0; /* some devices don't support reading */
|
return 0; /* some devices don't support reading */
|
||||||
}
|
}
|
||||||
@ -1431,9 +1416,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
|
|||||||
subs->cur_audiofmt = fmt;
|
subs->cur_audiofmt = fmt;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
printk("setting done: format = %d, rate = %d..%d, channels = %d\n",
|
printk(KERN_DEBUG
|
||||||
|
"setting done: format = %d, rate = %d..%d, channels = %d\n",
|
||||||
fmt->format, fmt->rate_min, fmt->rate_max, fmt->channels);
|
fmt->format, fmt->rate_min, fmt->rate_max, fmt->channels);
|
||||||
printk(" datapipe = 0x%0x, syncpipe = 0x%0x\n",
|
printk(KERN_DEBUG
|
||||||
|
" datapipe = 0x%0x, syncpipe = 0x%0x\n",
|
||||||
subs->datapipe, subs->syncpipe);
|
subs->datapipe, subs->syncpipe);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1468,7 +1455,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
|
|||||||
channels = params_channels(hw_params);
|
channels = params_channels(hw_params);
|
||||||
fmt = find_format(subs, format, rate, channels);
|
fmt = find_format(subs, format, rate, channels);
|
||||||
if (!fmt) {
|
if (!fmt) {
|
||||||
snd_printd(KERN_DEBUG "cannot set format: format = 0x%x, rate = %d, channels = %d\n",
|
snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n",
|
||||||
format, rate, channels);
|
format, rate, channels);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -1795,7 +1782,7 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
|
|||||||
if (rates[f->format] && rates[f->format] != f->rates)
|
if (rates[f->format] && rates[f->format] != f->rates)
|
||||||
goto __out;
|
goto __out;
|
||||||
}
|
}
|
||||||
channels[f->format] |= (1 << f->channels);
|
channels[f->format] |= 1 << (f->channels - 1);
|
||||||
rates[f->format] |= f->rates;
|
rates[f->format] |= f->rates;
|
||||||
/* needs knot? */
|
/* needs knot? */
|
||||||
if (f->rates & SNDRV_PCM_RATE_KNOT)
|
if (f->rates & SNDRV_PCM_RATE_KNOT)
|
||||||
@ -1822,7 +1809,7 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
|
|||||||
continue;
|
continue;
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
if (f->rates & (1 << i))
|
if (f->rates & (1 << i))
|
||||||
channels[i] |= (1 << f->channels);
|
channels[i] |= 1 << (f->channels - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmaster = 0;
|
cmaster = 0;
|
||||||
@ -1919,7 +1906,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
|
|||||||
* in the current code assume the 1ms period.
|
* in the current code assume the 1ms period.
|
||||||
*/
|
*/
|
||||||
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
|
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
|
||||||
1000 * MIN_PACKS_URB,
|
1000,
|
||||||
/*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX);
|
/*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX);
|
||||||
|
|
||||||
err = check_hw_params_convention(subs);
|
err = check_hw_params_convention(subs);
|
||||||
@ -2160,7 +2147,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
|
|||||||
fp = list_entry(p, struct audioformat, list);
|
fp = list_entry(p, struct audioformat, list);
|
||||||
snd_iprintf(buffer, " Interface %d\n", fp->iface);
|
snd_iprintf(buffer, " Interface %d\n", fp->iface);
|
||||||
snd_iprintf(buffer, " Altset %d\n", fp->altsetting);
|
snd_iprintf(buffer, " Altset %d\n", fp->altsetting);
|
||||||
snd_iprintf(buffer, " Format: 0x%x\n", fp->format);
|
snd_iprintf(buffer, " Format: %#x\n", fp->format);
|
||||||
snd_iprintf(buffer, " Channels: %d\n", fp->channels);
|
snd_iprintf(buffer, " Channels: %d\n", fp->channels);
|
||||||
snd_iprintf(buffer, " Endpoint: %d %s (%s)\n",
|
snd_iprintf(buffer, " Endpoint: %d %s (%s)\n",
|
||||||
fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
|
fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
|
||||||
@ -2180,7 +2167,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
|
|||||||
snd_iprintf(buffer, "\n");
|
snd_iprintf(buffer, "\n");
|
||||||
}
|
}
|
||||||
// snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize);
|
// snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize);
|
||||||
// snd_iprintf(buffer, " EP Attribute = 0x%x\n", fp->attributes);
|
// snd_iprintf(buffer, " EP Attribute = %#x\n", fp->attributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2621,7 +2608,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, struct audioformat
|
|||||||
fp->format = SNDRV_PCM_FORMAT_MPEG;
|
fp->format = SNDRV_PCM_FORMAT_MPEG;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
snd_printd(KERN_INFO "%d:%u:%d : unknown format tag 0x%x is detected. processed as MPEG.\n",
|
snd_printd(KERN_INFO "%d:%u:%d : unknown format tag %#x is detected. processed as MPEG.\n",
|
||||||
chip->dev->devnum, fp->iface, fp->altsetting, format);
|
chip->dev->devnum, fp->iface, fp->altsetting, format);
|
||||||
fp->format = SNDRV_PCM_FORMAT_MPEG;
|
fp->format = SNDRV_PCM_FORMAT_MPEG;
|
||||||
break;
|
break;
|
||||||
@ -2819,7 +2806,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, altno, fp->endpoint);
|
snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
|
||||||
err = add_audio_endpoint(chip, stream, fp);
|
err = add_audio_endpoint(chip, stream, fp);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
kfree(fp->rate_table);
|
kfree(fp->rate_table);
|
||||||
@ -3766,7 +3753,7 @@ static int usb_audio_resume(struct usb_interface *intf)
|
|||||||
|
|
||||||
static int __init snd_usb_audio_init(void)
|
static int __init snd_usb_audio_init(void)
|
||||||
{
|
{
|
||||||
if (nrpacks < MIN_PACKS_URB || nrpacks > MAX_PACKS) {
|
if (nrpacks < 1 || nrpacks > MAX_PACKS) {
|
||||||
printk(KERN_WARNING "invalid nrpacks value.\n");
|
printk(KERN_WARNING "invalid nrpacks value.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@ static const struct rc_config {
|
|||||||
{ USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */
|
{ USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */
|
||||||
{ USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */
|
{ USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */
|
||||||
{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */
|
{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */
|
||||||
|
{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct usb_mixer_interface {
|
struct usb_mixer_interface {
|
||||||
@ -109,6 +110,8 @@ struct mixer_build {
|
|||||||
const struct usbmix_selector_map *selector_map;
|
const struct usbmix_selector_map *selector_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAX_CHANNELS 10 /* max logical channels */
|
||||||
|
|
||||||
struct usb_mixer_elem_info {
|
struct usb_mixer_elem_info {
|
||||||
struct usb_mixer_interface *mixer;
|
struct usb_mixer_interface *mixer;
|
||||||
struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */
|
struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */
|
||||||
@ -119,6 +122,8 @@ struct usb_mixer_elem_info {
|
|||||||
int channels;
|
int channels;
|
||||||
int val_type;
|
int val_type;
|
||||||
int min, max, res;
|
int min, max, res;
|
||||||
|
int cached;
|
||||||
|
int cache_val[MAX_CHANNELS];
|
||||||
u8 initialized;
|
u8 initialized;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -180,8 +185,6 @@ enum {
|
|||||||
USB_PROC_DCR_RELEASE = 6,
|
USB_PROC_DCR_RELEASE = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_CHANNELS 10 /* max logical channels */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* manual mapping of mixer names
|
* manual mapping of mixer names
|
||||||
@ -218,7 +221,10 @@ static int check_ignored_ctl(struct mixer_build *state, int unitid, int control)
|
|||||||
for (p = state->map; p->id; p++) {
|
for (p = state->map; p->id; p++) {
|
||||||
if (p->id == unitid && ! p->name &&
|
if (p->id == unitid && ! p->name &&
|
||||||
(! control || ! p->control || control == p->control)) {
|
(! control || ! p->control || control == p->control)) {
|
||||||
// printk("ignored control %d:%d\n", unitid, control);
|
/*
|
||||||
|
printk(KERN_DEBUG "ignored control %d:%d\n",
|
||||||
|
unitid, control);
|
||||||
|
*/
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,11 +381,35 @@ static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* channel = 0: master, 1 = first channel */
|
/* channel = 0: master, 1 = first channel */
|
||||||
static inline int get_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int *value)
|
static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval,
|
||||||
|
int channel, int *value)
|
||||||
{
|
{
|
||||||
return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value);
|
return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
|
||||||
|
int channel, int index, int *value)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (cval->cached & (1 << channel)) {
|
||||||
|
*value = cval->cache_val[index];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
err = get_cur_mix_raw(cval, channel, value);
|
||||||
|
if (err < 0) {
|
||||||
|
if (!cval->mixer->ignore_ctl_error)
|
||||||
|
snd_printd(KERN_ERR "cannot get current value for "
|
||||||
|
"control %d ch %d: err = %d\n",
|
||||||
|
cval->control, channel, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
cval->cached |= 1 << channel;
|
||||||
|
cval->cache_val[index] = *value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set a mixer value
|
* set a mixer value
|
||||||
*/
|
*/
|
||||||
@ -411,9 +441,17 @@ static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int v
|
|||||||
return set_ctl_value(cval, SET_CUR, validx, value);
|
return set_ctl_value(cval, SET_CUR, validx, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int value)
|
static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
|
||||||
|
int index, int value)
|
||||||
{
|
{
|
||||||
return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value);
|
int err;
|
||||||
|
err = set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel,
|
||||||
|
value);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
cval->cached |= 1 << channel;
|
||||||
|
cval->cache_val[index] = value;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -717,7 +755,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
|
|||||||
if (cval->min + cval->res < cval->max) {
|
if (cval->min + cval->res < cval->max) {
|
||||||
int last_valid_res = cval->res;
|
int last_valid_res = cval->res;
|
||||||
int saved, test, check;
|
int saved, test, check;
|
||||||
get_cur_mix_value(cval, minchn, &saved);
|
get_cur_mix_raw(cval, minchn, &saved);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
test = saved;
|
test = saved;
|
||||||
if (test < cval->max)
|
if (test < cval->max)
|
||||||
@ -725,8 +763,8 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
|
|||||||
else
|
else
|
||||||
test -= cval->res;
|
test -= cval->res;
|
||||||
if (test < cval->min || test > cval->max ||
|
if (test < cval->min || test > cval->max ||
|
||||||
set_cur_mix_value(cval, minchn, test) ||
|
set_cur_mix_value(cval, minchn, 0, test) ||
|
||||||
get_cur_mix_value(cval, minchn, &check)) {
|
get_cur_mix_raw(cval, minchn, &check)) {
|
||||||
cval->res = last_valid_res;
|
cval->res = last_valid_res;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -734,7 +772,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
|
|||||||
break;
|
break;
|
||||||
cval->res *= 2;
|
cval->res *= 2;
|
||||||
}
|
}
|
||||||
set_cur_mix_value(cval, minchn, saved);
|
set_cur_mix_value(cval, minchn, 0, saved);
|
||||||
}
|
}
|
||||||
|
|
||||||
cval->initialized = 1;
|
cval->initialized = 1;
|
||||||
@ -774,35 +812,25 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
|||||||
struct usb_mixer_elem_info *cval = kcontrol->private_data;
|
struct usb_mixer_elem_info *cval = kcontrol->private_data;
|
||||||
int c, cnt, val, err;
|
int c, cnt, val, err;
|
||||||
|
|
||||||
|
ucontrol->value.integer.value[0] = cval->min;
|
||||||
if (cval->cmask) {
|
if (cval->cmask) {
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
for (c = 0; c < MAX_CHANNELS; c++) {
|
for (c = 0; c < MAX_CHANNELS; c++) {
|
||||||
if (cval->cmask & (1 << c)) {
|
if (!(cval->cmask & (1 << c)))
|
||||||
err = get_cur_mix_value(cval, c + 1, &val);
|
continue;
|
||||||
if (err < 0) {
|
err = get_cur_mix_value(cval, c + 1, cnt, &val);
|
||||||
if (cval->mixer->ignore_ctl_error) {
|
if (err < 0)
|
||||||
ucontrol->value.integer.value[0] = cval->min;
|
return cval->mixer->ignore_ctl_error ? 0 : err;
|
||||||
return 0;
|
val = get_relative_value(cval, val);
|
||||||
}
|
ucontrol->value.integer.value[cnt] = val;
|
||||||
snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err);
|
cnt++;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
val = get_relative_value(cval, val);
|
|
||||||
ucontrol->value.integer.value[cnt] = val;
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
/* master channel */
|
/* master channel */
|
||||||
err = get_cur_mix_value(cval, 0, &val);
|
err = get_cur_mix_value(cval, 0, 0, &val);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
if (cval->mixer->ignore_ctl_error) {
|
return cval->mixer->ignore_ctl_error ? 0 : err;
|
||||||
ucontrol->value.integer.value[0] = cval->min;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
snd_printd(KERN_ERR "cannot get current value for control %d master ch: err = %d\n", cval->control, err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
val = get_relative_value(cval, val);
|
val = get_relative_value(cval, val);
|
||||||
ucontrol->value.integer.value[0] = val;
|
ucontrol->value.integer.value[0] = val;
|
||||||
}
|
}
|
||||||
@ -819,34 +847,28 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
|||||||
if (cval->cmask) {
|
if (cval->cmask) {
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
for (c = 0; c < MAX_CHANNELS; c++) {
|
for (c = 0; c < MAX_CHANNELS; c++) {
|
||||||
if (cval->cmask & (1 << c)) {
|
if (!(cval->cmask & (1 << c)))
|
||||||
err = get_cur_mix_value(cval, c + 1, &oval);
|
continue;
|
||||||
if (err < 0) {
|
err = get_cur_mix_value(cval, c + 1, cnt, &oval);
|
||||||
if (cval->mixer->ignore_ctl_error)
|
if (err < 0)
|
||||||
return 0;
|
return cval->mixer->ignore_ctl_error ? 0 : err;
|
||||||
return err;
|
val = ucontrol->value.integer.value[cnt];
|
||||||
}
|
val = get_abs_value(cval, val);
|
||||||
val = ucontrol->value.integer.value[cnt];
|
if (oval != val) {
|
||||||
val = get_abs_value(cval, val);
|
set_cur_mix_value(cval, c + 1, cnt, val);
|
||||||
if (oval != val) {
|
changed = 1;
|
||||||
set_cur_mix_value(cval, c + 1, val);
|
|
||||||
changed = 1;
|
|
||||||
}
|
|
||||||
get_cur_mix_value(cval, c + 1, &val);
|
|
||||||
cnt++;
|
|
||||||
}
|
}
|
||||||
|
cnt++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* master channel */
|
/* master channel */
|
||||||
err = get_cur_mix_value(cval, 0, &oval);
|
err = get_cur_mix_value(cval, 0, 0, &oval);
|
||||||
if (err < 0 && cval->mixer->ignore_ctl_error)
|
|
||||||
return 0;
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return cval->mixer->ignore_ctl_error ? 0 : err;
|
||||||
val = ucontrol->value.integer.value[0];
|
val = ucontrol->value.integer.value[0];
|
||||||
val = get_abs_value(cval, val);
|
val = get_abs_value(cval, val);
|
||||||
if (val != oval) {
|
if (val != oval) {
|
||||||
set_cur_mix_value(cval, 0, val);
|
set_cur_mix_value(cval, 0, 0, val);
|
||||||
changed = 1;
|
changed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1705,7 +1727,8 @@ static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer,
|
|||||||
break;
|
break;
|
||||||
/* live24ext: 4 = line-in jack */
|
/* live24ext: 4 = line-in jack */
|
||||||
case 3: /* hp-out jack (may actuate Mute) */
|
case 3: /* hp-out jack (may actuate Mute) */
|
||||||
if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
|
if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
|
||||||
|
mixer->chip->usb_id == USB_ID(0x041e, 0x3048))
|
||||||
snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id);
|
snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1936,8 +1959,9 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
|
|||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
|
for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
|
||||||
if (i > 1 && /* Live24ext has 2 LEDs only */
|
if (i > 1 && /* Live24ext has 2 LEDs only */
|
||||||
mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
|
(mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
|
||||||
|
mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
|
||||||
break;
|
break;
|
||||||
err = snd_ctl_add(mixer->chip->card,
|
err = snd_ctl_add(mixer->chip->card,
|
||||||
snd_ctl_new1(&snd_audigy2nx_controls[i], mixer));
|
snd_ctl_new1(&snd_audigy2nx_controls[i], mixer));
|
||||||
@ -1974,7 +1998,8 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
|
|||||||
snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname);
|
snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname);
|
||||||
if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020))
|
if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020))
|
||||||
jacks = jacks_audigy2nx;
|
jacks = jacks_audigy2nx;
|
||||||
else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
|
else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
|
||||||
|
mixer->chip->usb_id == USB_ID(0x041e, 0x3048))
|
||||||
jacks = jacks_live24ext;
|
jacks = jacks_live24ext;
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
@ -2024,7 +2049,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
|
|||||||
goto _error;
|
goto _error;
|
||||||
|
|
||||||
if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
|
if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
|
||||||
mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) {
|
mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
|
||||||
|
mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) {
|
||||||
struct snd_info_entry *entry;
|
struct snd_info_entry *entry;
|
||||||
|
|
||||||
if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
|
if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
|
||||||
|
@ -261,6 +261,22 @@ static struct usbmix_name_map aureon_51_2_map[] = {
|
|||||||
{} /* terminator */
|
{} /* terminator */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct usbmix_name_map scratch_live_map[] = {
|
||||||
|
/* 1: IT Line 1 (USB streaming) */
|
||||||
|
/* 2: OT Line 1 (Speaker) */
|
||||||
|
/* 3: IT Line 1 (Line connector) */
|
||||||
|
{ 4, "Line 1 In" }, /* FU */
|
||||||
|
/* 5: OT Line 1 (USB streaming) */
|
||||||
|
/* 6: IT Line 2 (USB streaming) */
|
||||||
|
/* 7: OT Line 2 (Speaker) */
|
||||||
|
/* 8: IT Line 2 (Line connector) */
|
||||||
|
{ 9, "Line 2 In" }, /* FU */
|
||||||
|
/* 10: OT Line 2 (USB streaming) */
|
||||||
|
/* 11: IT Mic (Line connector) */
|
||||||
|
/* 12: OT Mic (USB streaming) */
|
||||||
|
{ 0 } /* terminator */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Control map entries
|
* Control map entries
|
||||||
*/
|
*/
|
||||||
@ -284,6 +300,11 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
|
|||||||
.id = USB_ID(0x041e, 0x3040),
|
.id = USB_ID(0x041e, 0x3040),
|
||||||
.map = live24ext_map,
|
.map = live24ext_map,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.id = USB_ID(0x041e, 0x3048),
|
||||||
|
.map = audigy2nx_map,
|
||||||
|
.selector_map = audigy2nx_selectors,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
/* Hercules DJ Console (Windows Edition) */
|
/* Hercules DJ Console (Windows Edition) */
|
||||||
.id = USB_ID(0x06f8, 0xb000),
|
.id = USB_ID(0x06f8, 0xb000),
|
||||||
@ -311,6 +332,11 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
|
|||||||
.id = USB_ID(0x0ccd, 0x0028),
|
.id = USB_ID(0x0ccd, 0x0028),
|
||||||
.map = aureon_51_2_map,
|
.map = aureon_51_2_map,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.id = USB_ID(0x13e5, 0x0001),
|
||||||
|
.map = scratch_live_map,
|
||||||
|
.ignore_ctl_error = 1,
|
||||||
|
},
|
||||||
{ 0 } /* terminator */
|
{ 0 } /* terminator */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,6 +39,16 @@
|
|||||||
.idProduct = prod, \
|
.idProduct = prod, \
|
||||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC
|
.bInterfaceClass = USB_CLASS_VENDOR_SPEC
|
||||||
|
|
||||||
|
/* Creative/Toshiba Multimedia Center SB-0500 */
|
||||||
|
{
|
||||||
|
USB_DEVICE(0x041e, 0x3048),
|
||||||
|
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||||
|
.vendor_name = "Toshiba",
|
||||||
|
.product_name = "SB-0500",
|
||||||
|
.ifnum = QUIRK_NO_INTERFACE
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/* Creative/E-Mu devices */
|
/* Creative/E-Mu devices */
|
||||||
{
|
{
|
||||||
USB_DEVICE(0x041e, 0x3010),
|
USB_DEVICE(0x041e, 0x3010),
|
||||||
|
@ -557,7 +557,7 @@ static void stream_start(struct usb_stream_kernel *sk,
|
|||||||
s->idle_insize -= max_diff - max_diff_0;
|
s->idle_insize -= max_diff - max_diff_0;
|
||||||
s->idle_insize += urb_size - s->period_size;
|
s->idle_insize += urb_size - s->period_size;
|
||||||
if (s->idle_insize < 0) {
|
if (s->idle_insize < 0) {
|
||||||
snd_printk("%i %i %i\n",
|
snd_printk(KERN_WARNING "%i %i %i\n",
|
||||||
s->idle_insize, urb_size, s->period_size);
|
s->idle_insize, urb_size, s->period_size);
|
||||||
return;
|
return;
|
||||||
} else if (s->idle_insize == 0) {
|
} else if (s->idle_insize == 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user