Эх сурвалжийг харах

Merge branch 'topic/usb-audio' into for-linus

Takashi Iwai 16 жил өмнө
parent
commit
afad17c0ae

+ 33 - 46
sound/usb/usbaudio.c

@@ -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 < subs->packs_per_ms; ++i) {
+	for (i = 0; i < ctx->packets; ++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(urb_packs, (unsigned int)MIN_PACKS_URB);
+		urb_packs = max(nrpacks, 1);
 		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)
-			total_packs = 2 * MIN_PACKS_URB * packs_per_ms;
+		if (total_packs < 2 * 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;
-	}
-	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) {
+	} else if (subs->nurbs < 2) {
 		/* 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;
 	}
 	}

+ 84 - 58
sound/usb/usbmixer.c

@@ -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) ||
-				    get_cur_mix_value(cval, minchn, &check)) {
+				    set_cur_mix_value(cval, minchn, 0, test) ||
+				    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)) {
-				err = get_cur_mix_value(cval, c + 1, &val);
-				if (err < 0) {
-					if (cval->mixer->ignore_ctl_error) {
-						ucontrol->value.integer.value[0] = cval->min;
-						return 0;
-					}
-					snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err);
-					return err;
-				}
-				val = get_relative_value(cval, val);
-				ucontrol->value.integer.value[cnt] = val;
-				cnt++;
-			}
+			if (!(cval->cmask & (1 << c)))
+				continue;
+			err = get_cur_mix_value(cval, c + 1, cnt, &val);
+			if (err < 0)
+				return cval->mixer->ignore_ctl_error ? 0 : 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);
-		if (err < 0) {
-			if (cval->mixer->ignore_ctl_error) {
-				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;
-		}
+		err = get_cur_mix_value(cval, 0, 0, &val);
+		if (err < 0)
+			return cval->mixer->ignore_ctl_error ? 0 : 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)) {
-				err = get_cur_mix_value(cval, c + 1, &oval);
-				if (err < 0) {
-					if (cval->mixer->ignore_ctl_error)
-						return 0;
-					return err;
-				}
-				val = ucontrol->value.integer.value[cnt];
-				val = get_abs_value(cval, val);
-				if (oval != val) {
-					set_cur_mix_value(cval, c + 1, val);
-					changed = 1;
-				}
-				get_cur_mix_value(cval, c + 1, &val);
-				cnt++;
+			if (!(cval->cmask & (1 << c)))
+				continue;
+			err = get_cur_mix_value(cval, c + 1, cnt, &oval);
+			if (err < 0)
+				return cval->mixer->ignore_ctl_error ? 0 : err;
+			val = ucontrol->value.integer.value[cnt];
+			val = get_abs_value(cval, val);
+			if (oval != val) {
+				set_cur_mix_value(cval, c + 1, cnt, val);
+				changed = 1;
 			}
 			}
+			cnt++;
 		}
 		}
 	} else {
 	} else {
 		/* master channel */
 		/* master channel */
-		err = get_cur_mix_value(cval, 0, &oval);
-		if (err < 0 && cval->mixer->ignore_ctl_error)
-			return 0;
+		err = get_cur_mix_value(cval, 0, 0, &oval);
 		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 */
-			mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
+		if (i > 1 && /* Live24ext has 2 LEDs only */
+			(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)

+ 26 - 0
sound/usb/usbmixer_maps.c

@@ -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 */
 };
 };
 
 

+ 10 - 0
sound/usb/usbquirks.h

@@ -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),

+ 1 - 1
sound/usb/usx2y/usb_stream.c

@@ -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) {