diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-03-29 01:05:50 +0300 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-03-29 01:05:50 +0300 |
commit | b0d44c0dbbd52effb731b1c0af9afd56215c48de (patch) | |
tree | 3237c0087d91a5390aed05689b9f610ba16fa116 /sound/usb | |
parent | 9537a48ed4b9e4b738943d6da0a0fd4278adf905 (diff) | |
parent | 7c730ccdc1188b97f5c8cb690906242c7ed75c22 (diff) | |
download | linux-b0d44c0dbbd52effb731b1c0af9afd56215c48de.tar.xz |
Merge branch 'linus' into core/iommu
Conflicts:
arch/x86/Kconfig
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/Kconfig | 3 | ||||
-rw-r--r-- | sound/usb/caiaq/caiaq-audio.c | 15 | ||||
-rw-r--r-- | sound/usb/caiaq/caiaq-control.c | 42 | ||||
-rw-r--r-- | sound/usb/caiaq/caiaq-device.c | 46 | ||||
-rw-r--r-- | sound/usb/caiaq/caiaq-device.h | 6 | ||||
-rw-r--r-- | sound/usb/usbaudio.c | 85 | ||||
-rw-r--r-- | sound/usb/usbmixer.c | 164 | ||||
-rw-r--r-- | sound/usb/usbmixer_maps.c | 26 | ||||
-rw-r--r-- | sound/usb/usbquirks.h | 10 | ||||
-rw-r--r-- | sound/usb/usx2y/us122l.c | 59 | ||||
-rw-r--r-- | sound/usb/usx2y/usX2Yhwdep.c | 15 | ||||
-rw-r--r-- | sound/usb/usx2y/usb_stream.c | 2 | ||||
-rw-r--r-- | sound/usb/usx2y/usbusx2y.c | 56 | ||||
-rw-r--r-- | sound/usb/usx2y/usx2yhwdeppcm.h | 2 |
14 files changed, 322 insertions, 209 deletions
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 4f0eac9bff1e..523aec188ccf 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -48,7 +48,10 @@ config SND_USB_CAIAQ * Native Instruments Kore Controller * Native Instruments Kore Controller 2 * Native Instruments Audio Kontrol 1 + * Native Instruments Audio 4 DJ * Native Instruments Audio 8 DJ + * Native Instruments Guitar Rig Session I/O + * Native Instruments Guitar Rig mobile To compile this driver as a module, choose M here: the module will be called snd-usb-caiaq. diff --git a/sound/usb/caiaq/caiaq-audio.c b/sound/usb/caiaq/caiaq-audio.c index b3a603325835..08d51e0c9fea 100644 --- a/sound/usb/caiaq/caiaq-audio.c +++ b/sound/usb/caiaq/caiaq-audio.c @@ -114,6 +114,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev) dev->output_panic = 0; dev->first_packet = 1; dev->streaming = 1; + dev->warned = 0; for (i = 0; i < N_URBS; i++) { ret = usb_submit_urb(dev->data_urbs_in[i], GFP_ATOMIC); @@ -376,6 +377,9 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, for (stream = 0; stream < dev->n_streams; stream++, i++) { sub = dev->sub_capture[stream]; + if (dev->input_panic) + usb_buf[i] = 0; + if (sub) { struct snd_pcm_runtime *rt = sub->runtime; char *audio_buf = rt->dma_area; @@ -397,6 +401,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, if (!dev->streaming) return; + if (iso->actual_length < dev->bpp) + return; + switch (dev->spec.data_alignment) { case 0: read_in_urb_mode0(dev, urb, iso); @@ -406,10 +413,11 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, break; } - if (dev->input_panic || dev->output_panic) { + if ((dev->input_panic || dev->output_panic) && !dev->warned) { debug("streaming error detected %s %s\n", dev->input_panic ? "(input)" : "", dev->output_panic ? "(output)" : ""); + dev->warned = 1; } } @@ -638,9 +646,10 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO): - dev->samplerates |= SNDRV_PCM_RATE_88200; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_GUITARRIGMOBILE): dev->samplerates |= SNDRV_PCM_RATE_192000; - break; + /* fall thru */ + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): dev->samplerates |= SNDRV_PCM_RATE_88200; break; diff --git a/sound/usb/caiaq/caiaq-control.c b/sound/usb/caiaq/caiaq-control.c index ccd763dd7167..e92c2bbf4fe9 100644 --- a/sound/usb/caiaq/caiaq-control.c +++ b/sound/usb/caiaq/caiaq-control.c @@ -39,12 +39,12 @@ static int control_info(struct snd_kcontrol *kcontrol, struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); int pos = kcontrol->private_value; int is_intval = pos & CNT_INTVAL; + unsigned int id = dev->chip.usb_id; uinfo->count = 1; pos &= ~CNT_INTVAL; - if (dev->chip.usb_id == - USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ) + if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ) && (pos == 0)) { /* current input mode of A8DJ */ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; @@ -53,6 +53,15 @@ static int control_info(struct snd_kcontrol *kcontrol, return 0; } + if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ) + && (pos == 0)) { + /* current input mode of A4DJ */ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; + } + if (is_intval) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->value.integer.min = 0; @@ -73,6 +82,14 @@ static int control_get(struct snd_kcontrol *kcontrol, struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); int pos = kcontrol->private_value; + if (dev->chip.usb_id == + USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) { + /* A4DJ has only one control */ + /* do not expose hardware input mode 0 */ + ucontrol->value.integer.value[0] = dev->control_state[0] - 1; + return 0; + } + if (pos & CNT_INTVAL) ucontrol->value.integer.value[0] = dev->control_state[pos & ~CNT_INTVAL]; @@ -90,10 +107,20 @@ static int control_put(struct snd_kcontrol *kcontrol, struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); int pos = kcontrol->private_value; + if (dev->chip.usb_id == + USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) { + /* A4DJ has only one control */ + /* do not expose hardware input mode 0 */ + dev->control_state[0] = ucontrol->value.integer.value[0] + 1; + snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, + dev->control_state, sizeof(dev->control_state)); + return 1; + } + if (pos & CNT_INTVAL) { dev->control_state[pos & ~CNT_INTVAL] = ucontrol->value.integer.value[0]; - snd_usb_caiaq_send_command(dev, EP1_CMD_DIMM_LEDS, + snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, dev->control_state, sizeof(dev->control_state)); } else { if (ucontrol->value.integer.value[0]) @@ -243,10 +270,13 @@ static struct caiaq_controller a8dj_controller[] = { { "GND lift for TC Vinyl mode", 24 + 0 }, { "GND lift for TC CD/Line mode", 24 + 1 }, { "GND lift for phono mode", 24 + 2 }, - { "GND lift for TC Vinyl mode", 24 + 3 }, { "Software lock", 40 } }; +static struct caiaq_controller a4dj_controller[] = { + { "Current input mode", 0 | CNT_INTVAL } +}; + static int __devinit add_controls(struct caiaq_controller *c, int num, struct snd_usb_caiaqdev *dev) { @@ -295,6 +325,10 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) ret = add_controls(a8dj_controller, ARRAY_SIZE(a8dj_controller), dev); break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): + ret = add_controls(a4dj_controller, + ARRAY_SIZE(a4dj_controller), dev); + break; } return ret; diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c index 41c36b055f6b..cf573a982fdc 100644 --- a/sound/usb/caiaq/caiaq-device.c +++ b/sound/usb/caiaq/caiaq-device.c @@ -42,15 +42,17 @@ #endif MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); -MODULE_DESCRIPTION("caiaq USB audio, version 1.3.10"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.3.13"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, RigKontrol3}," "{Native Instruments, Kore Controller}," "{Native Instruments, Kore Controller 2}," "{Native Instruments, Audio Kontrol 1}," + "{Native Instruments, Audio 4 DJ}," "{Native Instruments, Audio 8 DJ}," - "{Native Instruments, Session I/O}}"); + "{Native Instruments, Session I/O}," + "{Native Instruments, GuitarRig mobile}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ @@ -116,6 +118,16 @@ static struct usb_device_id snd_usb_id_table[] = { .idVendor = USB_VID_NATIVEINSTRUMENTS, .idProduct = USB_PID_SESSIONIO }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = USB_VID_NATIVEINSTRUMENTS, + .idProduct = USB_PID_GUITARRIGMOBILE + }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = USB_VID_NATIVEINSTRUMENTS, + .idProduct = USB_PID_AUDIO4DJ + }, { /* terminator */ } }; @@ -239,6 +251,8 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, if (dev->audio_parm_answer != 1) debug("unable to set the device's audio params\n"); + else + dev->bpp = bpp; return dev->audio_parm_answer == 1 ? 0 : -EINVAL; } @@ -300,6 +314,12 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev) } break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): + /* Audio 4 DJ - default input mode to phono */ + dev->control_state[0] = 2; + snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, + dev->control_state, 1); + break; } if (dev->spec.num_analog_audio_out + @@ -336,9 +356,10 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev) log("Unable to set up control system (ret=%d)\n", ret); } -static struct snd_card* create_card(struct usb_device* usb_dev) +static int create_card(struct usb_device* usb_dev, struct snd_card **cardp) { int devnum; + int err; struct snd_card *card; struct snd_usb_caiaqdev *dev; @@ -347,12 +368,12 @@ static struct snd_card* create_card(struct usb_device* usb_dev) break; if (devnum >= SNDRV_CARDS) - return NULL; + return -ENODEV; - card = snd_card_new(index[devnum], id[devnum], THIS_MODULE, - sizeof(struct snd_usb_caiaqdev)); - if (!card) - return NULL; + err = snd_card_create(index[devnum], id[devnum], THIS_MODULE, + sizeof(struct snd_usb_caiaqdev), &card); + if (err < 0) + return err; dev = caiaqdev(card); dev->chip.dev = usb_dev; @@ -362,7 +383,8 @@ static struct snd_card* create_card(struct usb_device* usb_dev) spin_lock_init(&dev->spinlock); snd_card_set_dev(card, &usb_dev->dev); - return card; + *cardp = card; + return 0; } static int __devinit init_card(struct snd_usb_caiaqdev *dev) @@ -441,10 +463,10 @@ static int __devinit snd_probe(struct usb_interface *intf, struct snd_card *card; struct usb_device *device = interface_to_usbdev(intf); - card = create_card(device); + ret = create_card(device, &card); - if (!card) - return -ENOMEM; + if (ret < 0) + return ret; usb_set_intfdata(intf, card); ret = init_card(caiaqdev(card)); diff --git a/sound/usb/caiaq/caiaq-device.h b/sound/usb/caiaq/caiaq-device.h index ab56e738c5fc..4cce1ad7493d 100644 --- a/sound/usb/caiaq/caiaq-device.h +++ b/sound/usb/caiaq/caiaq-device.h @@ -10,8 +10,10 @@ #define USB_PID_KORECONTROLLER 0x4711 #define USB_PID_KORECONTROLLER2 0x4712 #define USB_PID_AK1 0x0815 +#define USB_PID_AUDIO4DJ 0x0839 #define USB_PID_AUDIO8DJ 0x1978 #define USB_PID_SESSIONIO 0x1915 +#define USB_PID_GUITARRIGMOBILE 0x0d8d #define EP1_BUFSIZE 64 #define CAIAQ_USB_STR_LEN 0xff @@ -87,9 +89,9 @@ struct snd_usb_caiaqdev { int audio_out_buf_pos[MAX_STREAMS]; int period_in_count[MAX_STREAMS]; int period_out_count[MAX_STREAMS]; - int input_panic, output_panic; + int input_panic, output_panic, warned; char *audio_in_buf, *audio_out_buf; - unsigned int samplerates; + unsigned int samplerates, bpp; struct snd_pcm_substream *sub_playback[MAX_STREAMS]; struct snd_pcm_substream *sub_capture[MAX_STREAMS]; diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 19e37451c216..c2db0f959681 100644 --- a/sound/usb/usbaudio.c +++ b/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_URBS 8 #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 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. * - * 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, struct snd_pcm_runtime *runtime, @@ -537,13 +537,13 @@ static int prepare_nodata_playback_urb(struct snd_usb_substream *subs, offs = 0; 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); urb->iso_frame_desc[i].offset = offs * stride; urb->iso_frame_desc[i].length = counts * stride; offs += counts; } + urb->number_of_packets = ctx->packets; urb->transfer_buffer_length = offs * stride; memset(urb->transfer_buffer, 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, 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; - 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 */ 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; 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); } else 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 */ if (is_playback) { - unsigned int minsize; + unsigned int minsize, maxpacks; /* determine how small a packet can be */ minsize = (subs->freqn >> (16 - subs->datainterval)) * (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) & ~(packs_per_ms - 1); /* 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 { 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... */ subs->nurbs = MAX_URBS; 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 * to ensure contiguous playback/capture */ 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 */ @@ -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]; u->index = i; 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; if (subs->fmt_type == USB_FORMAT_TYPE_II) 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, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 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); return err; } if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, 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); 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; #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); - printk(" datapipe = 0x%0x, syncpipe = 0x%0x\n", + printk(KERN_DEBUG + " datapipe = 0x%0x, syncpipe = 0x%0x\n", subs->datapipe, subs->syncpipe); #endif @@ -1468,7 +1455,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, channels = params_channels(hw_params); fmt = find_format(subs, format, rate, channels); 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); 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) goto __out; } - channels[f->format] |= (1 << f->channels); + channels[f->format] |= 1 << (f->channels - 1); rates[f->format] |= f->rates; /* needs knot? */ if (f->rates & SNDRV_PCM_RATE_KNOT) @@ -1822,7 +1809,7 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) continue; for (i = 0; i < 32; i++) { if (f->rates & (1 << i)) - channels[i] |= (1 << f->channels); + channels[i] |= 1 << (f->channels - 1); } } 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. */ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, - 1000 * MIN_PACKS_URB, + 1000, /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX); 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); snd_iprintf(buffer, " Interface %d\n", fp->iface); 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, " Endpoint: %d %s (%s)\n", 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, " 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; break; 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); fp->format = SNDRV_PCM_FORMAT_MPEG; break; @@ -2819,7 +2806,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) 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); if (err < 0) { kfree(fp->rate_table); @@ -3466,10 +3453,10 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, return -ENXIO; } - card = snd_card_new(index[idx], id[idx], THIS_MODULE, 0); - if (card == NULL) { + err = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card); + if (err < 0) { snd_printk(KERN_ERR "cannot create card instance %d\n", idx); - return -ENOMEM; + return err; } chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -3766,7 +3753,7 @@ static int usb_audio_resume(struct usb_interface *intf) 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"); return -EINVAL; } diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 00397c8a765b..ecb58e7a6245 100644 --- a/sound/usb/usbmixer.c +++ b/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, 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, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ }; struct usb_mixer_interface { @@ -78,7 +79,6 @@ struct usb_mixer_interface { /* Sound Blaster remote control stuff */ const struct rc_config *rc_cfg; - unsigned long rc_hwdep_open; u32 rc_code; wait_queue_head_t rc_waitq; struct urb *rc_urb; @@ -110,6 +110,8 @@ struct mixer_build { const struct usbmix_selector_map *selector_map; }; +#define MAX_CHANNELS 10 /* max logical channels */ + struct usb_mixer_elem_info { struct usb_mixer_interface *mixer; struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */ @@ -120,6 +122,8 @@ struct usb_mixer_elem_info { int channels; int val_type; int min, max, res; + int cached; + int cache_val[MAX_CHANNELS]; u8 initialized; }; @@ -181,8 +185,6 @@ enum { USB_PROC_DCR_RELEASE = 6, }; -#define MAX_CHANNELS 10 /* max logical channels */ - /* * manual mapping of mixer names @@ -219,7 +221,10 @@ static int check_ignored_ctl(struct mixer_build *state, int unitid, int control) for (p = state->map; p->id; p++) { if (p->id == unitid && ! p->name && (! 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; } } @@ -376,11 +381,35 @@ static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int * } /* 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); } +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 */ @@ -412,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); } -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; } /* @@ -718,7 +755,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) if (cval->min + cval->res < cval->max) { int last_valid_res = cval->res; int saved, test, check; - get_cur_mix_value(cval, minchn, &saved); + get_cur_mix_raw(cval, minchn, &saved); for (;;) { test = saved; if (test < cval->max) @@ -726,8 +763,8 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) else test -= cval->res; 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; break; } @@ -735,7 +772,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) break; cval->res *= 2; } - set_cur_mix_value(cval, minchn, saved); + set_cur_mix_value(cval, minchn, 0, saved); } cval->initialized = 1; @@ -775,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; int c, cnt, val, err; + ucontrol->value.integer.value[0] = cval->min; if (cval->cmask) { cnt = 0; 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 { /* 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); ucontrol->value.integer.value[0] = val; } @@ -820,34 +847,28 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e if (cval->cmask) { cnt = 0; 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 { /* 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) - return err; + return cval->mixer->ignore_ctl_error ? 0 : err; val = ucontrol->value.integer.value[0]; val = get_abs_value(cval, val); if (val != oval) { - set_cur_mix_value(cval, 0, val); + set_cur_mix_value(cval, 0, 0, val); changed = 1; } } @@ -1706,7 +1727,8 @@ static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, break; /* live24ext: 4 = line-in jack */ 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); break; default: @@ -1797,24 +1819,6 @@ static void snd_usb_soundblaster_remote_complete(struct urb *urb) wake_up(&mixer->rc_waitq); } -static int snd_usb_sbrc_hwdep_open(struct snd_hwdep *hw, struct file *file) -{ - struct usb_mixer_interface *mixer = hw->private_data; - - if (test_and_set_bit(0, &mixer->rc_hwdep_open)) - return -EBUSY; - return 0; -} - -static int snd_usb_sbrc_hwdep_release(struct snd_hwdep *hw, struct file *file) -{ - struct usb_mixer_interface *mixer = hw->private_data; - - clear_bit(0, &mixer->rc_hwdep_open); - smp_mb__after_clear_bit(); - return 0; -} - static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf, long count, loff_t *offset) { @@ -1867,9 +1871,8 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC; hwdep->private_data = mixer; hwdep->ops.read = snd_usb_sbrc_hwdep_read; - hwdep->ops.open = snd_usb_sbrc_hwdep_open; - hwdep->ops.release = snd_usb_sbrc_hwdep_release; hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; + hwdep->exclusive = 1; mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); if (!mixer->rc_urb) @@ -1956,8 +1959,9 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) int i, err; 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; err = snd_ctl_add(mixer->chip->card, snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); @@ -1994,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); if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) 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; else return; @@ -2044,7 +2049,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, goto _error; 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; if ((err = snd_audigy2nx_controls_create(mixer)) < 0) diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index d755be0ad811..3e5d66cf1f5a 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -261,6 +261,22 @@ static struct usbmix_name_map aureon_51_2_map[] = { {} /* 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 */ @@ -285,6 +301,11 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .map = live24ext_map, }, { + .id = USB_ID(0x041e, 0x3048), + .map = audigy2nx_map, + .selector_map = audigy2nx_selectors, + }, + { /* Hercules DJ Console (Windows Edition) */ .id = USB_ID(0x06f8, 0xb000), .ignore_ctl_error = 1, @@ -311,6 +332,11 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x0ccd, 0x0028), .map = aureon_51_2_map, }, + { + .id = USB_ID(0x13e5, 0x0001), + .map = scratch_live_map, + .ignore_ctl_error = 1, + }, { 0 } /* terminator */ }; diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 5d8ef09b9dcc..647ef5029651 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -39,6 +39,16 @@ .idProduct = prod, \ .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 */ { USB_DEVICE(0x041e, 0x3010), diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 73e59f4403a4..98276aafefe6 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -478,19 +478,21 @@ static bool us122l_create_card(struct snd_card *card) return true; } -static struct snd_card *usx2y_create_card(struct usb_device *device) +static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) { int dev; struct snd_card *card; + int err; + for (dev = 0; dev < SNDRV_CARDS; ++dev) if (enable[dev] && !snd_us122l_card_used[dev]) break; if (dev >= SNDRV_CARDS) - return NULL; - card = snd_card_new(index[dev], id[dev], THIS_MODULE, - sizeof(struct us122l)); - if (!card) - return NULL; + return -ENODEV; + err = snd_card_create(index[dev], id[dev], THIS_MODULE, + sizeof(struct us122l), &card); + if (err < 0) + return err; snd_us122l_card_used[US122L(card)->chip.index = dev] = 1; US122L(card)->chip.dev = device; @@ -509,46 +511,57 @@ static struct snd_card *usx2y_create_card(struct usb_device *device) US122L(card)->chip.dev->devnum ); snd_card_set_dev(card, &device->dev); - return card; + *cardp = card; + return 0; } -static void *us122l_usb_probe(struct usb_interface *intf, - const struct usb_device_id *device_id) +static int us122l_usb_probe(struct usb_interface *intf, + const struct usb_device_id *device_id, + struct snd_card **cardp) { struct usb_device *device = interface_to_usbdev(intf); - struct snd_card *card = usx2y_create_card(device); + struct snd_card *card; + int err; - if (!card) - return NULL; + err = usx2y_create_card(device, &card); + if (err < 0) + return err; - if (!us122l_create_card(card) || - snd_card_register(card) < 0) { + if (!us122l_create_card(card)) { snd_card_free(card); - return NULL; + return -EINVAL; + } + + err = snd_card_register(card); + if (err < 0) { + snd_card_free(card); + return err; } usb_get_dev(device); - return card; + *cardp = card; + return 0; } static int snd_us122l_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct snd_card *card; + int err; + snd_printdd(KERN_DEBUG"%p:%i\n", intf, intf->cur_altsetting->desc.bInterfaceNumber); if (intf->cur_altsetting->desc.bInterfaceNumber != 1) return 0; - card = us122l_usb_probe(usb_get_intf(intf), id); - - if (card) { - usb_set_intfdata(intf, card); - return 0; + err = us122l_usb_probe(usb_get_intf(intf), id, &card); + if (err < 0) { + usb_put_intf(intf); + return err; } - usb_put_intf(intf); - return -EIO; + usb_set_intfdata(intf, card); + return 0; } static void snd_us122l_disconnect(struct usb_interface *intf) diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 1558a5c4094f..4af8740db717 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -30,9 +30,6 @@ #include "usbusx2y.h" #include "usX2Yhwdep.h" -int usX2Y_hwdep_pcm_new(struct snd_card *card); - - static int snd_us428ctls_vm_fault(struct vm_area_struct *area, struct vm_fault *vmf) { @@ -106,16 +103,6 @@ static unsigned int snd_us428ctls_poll(struct snd_hwdep *hw, struct file *file, } -static int snd_usX2Y_hwdep_open(struct snd_hwdep *hw, struct file *file) -{ - return 0; -} - -static int snd_usX2Y_hwdep_release(struct snd_hwdep *hw, struct file *file) -{ - return 0; -} - static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, struct snd_hwdep_dsp_status *info) { @@ -267,8 +254,6 @@ int usX2Y_hwdep_new(struct snd_card *card, struct usb_device* device) hw->iface = SNDRV_HWDEP_IFACE_USX2Y; hw->private_data = usX2Y(card); - hw->ops.open = snd_usX2Y_hwdep_open; - hw->ops.release = snd_usX2Y_hwdep_release; hw->ops.dsp_status = snd_usX2Y_hwdep_dsp_status; hw->ops.dsp_load = snd_usX2Y_hwdep_dsp_load; hw->ops.mmap = snd_us428ctls_mmap; diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index 70b96355ca4c..24393dafcb6e 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/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 += urb_size - s->period_size; 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); return; } else if (s->idle_insize == 0) { diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 11639bd72a51..5ce0da23ee96 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -227,9 +227,9 @@ static void i_usX2Y_In04Int(struct urb *urb) if (usX2Y->US04) { if (0 == usX2Y->US04->submitted) - do + do { err = usb_submit_urb(usX2Y->US04->urb[usX2Y->US04->submitted++], GFP_ATOMIC); - while (!err && usX2Y->US04->submitted < usX2Y->US04->len); + } while (!err && usX2Y->US04->submitted < usX2Y->US04->len); } else if (us428ctls && us428ctls->p4outLast >= 0 && us428ctls->p4outLast < N_us428_p4out_BUFS) { if (us428ctls->p4outLast != us428ctls->p4outSent) { @@ -333,18 +333,21 @@ static struct usb_device_id snd_usX2Y_usb_id_table[] = { { /* terminator */ } }; -static struct snd_card *usX2Y_create_card(struct usb_device *device) +static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) { int dev; struct snd_card * card; + int err; + for (dev = 0; dev < SNDRV_CARDS; ++dev) if (enable[dev] && !snd_usX2Y_card_used[dev]) break; if (dev >= SNDRV_CARDS) - return NULL; - card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct usX2Ydev)); - if (!card) - return NULL; + return -ENODEV; + err = snd_card_create(index[dev], id[dev], THIS_MODULE, + sizeof(struct usX2Ydev), &card); + if (err < 0) + return err; snd_usX2Y_card_used[usX2Y(card)->chip.index = dev] = 1; card->private_free = snd_usX2Y_card_private_free; usX2Y(card)->chip.dev = device; @@ -362,26 +365,36 @@ static struct snd_card *usX2Y_create_card(struct usb_device *device) usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum ); snd_card_set_dev(card, &device->dev); - return card; + *cardp = card; + return 0; } -static void *usX2Y_usb_probe(struct usb_device *device, struct usb_interface *intf, const struct usb_device_id *device_id) +static int usX2Y_usb_probe(struct usb_device *device, + struct usb_interface *intf, + const struct usb_device_id *device_id, + struct snd_card **cardp) { int err; struct snd_card * card; + + *cardp = NULL; if (le16_to_cpu(device->descriptor.idVendor) != 0x1604 || (le16_to_cpu(device->descriptor.idProduct) != USB_ID_US122 && le16_to_cpu(device->descriptor.idProduct) != USB_ID_US224 && - le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428) || - !(card = usX2Y_create_card(device))) - return NULL; + le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428)) + return -EINVAL; + + err = usX2Y_create_card(device, &card); + if (err < 0) + return err; if ((err = usX2Y_hwdep_new(card, device)) < 0 || (err = snd_card_register(card)) < 0) { snd_card_free(card); - return NULL; + return err; } - return card; + *cardp = card; + return 0; } /* @@ -389,13 +402,14 @@ static void *usX2Y_usb_probe(struct usb_device *device, struct usb_interface *in */ static int snd_usX2Y_probe(struct usb_interface *intf, const struct usb_device_id *id) { - void *chip; - chip = usX2Y_usb_probe(interface_to_usbdev(intf), intf, id); - if (chip) { - usb_set_intfdata(intf, chip); - return 0; - } else - return -EIO; + struct snd_card *card; + int err; + + err = usX2Y_usb_probe(interface_to_usbdev(intf), intf, id, &card); + if (err < 0) + return err; + dev_set_drvdata(&intf->dev, card); + return 0; } static void snd_usX2Y_disconnect(struct usb_interface *intf) diff --git a/sound/usb/usx2y/usx2yhwdeppcm.h b/sound/usb/usx2y/usx2yhwdeppcm.h index c3382fdc386b..9c4fb84b2aa0 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.h +++ b/sound/usb/usx2y/usx2yhwdeppcm.h @@ -18,3 +18,5 @@ struct snd_usX2Y_hwdep_pcm_shm { volatile unsigned captured_iso_frames; int capture_iso_start; }; + +int usX2Y_hwdep_pcm_new(struct snd_card *card); |