Index: core/misc.c =================================================================== --- core/misc.c (revision 8635) +++ core/misc.c (working copy) @@ -1,6 +1,6 @@ /* * Misc and compatibility things - * Copyright (c) by Jaroslav Kysela + * Copyright (c) by Jaroslav Kysela * * * This program is free software; you can redistribute it and/or modify @@ -19,7 +19,6 @@ * */ -#include #include #include #include @@ -35,7 +34,7 @@ EXPORT_SYMBOL(release_and_free_resource); -#ifdef CONFIG_SND_VERBOSE_PRINTK +/* #ifdef CONFIG_SND_VERBOSE_PRINTK */ void snd_verbose_printk(const char *file, int line, const char *format, ...) { va_list args; @@ -54,7 +53,7 @@ } EXPORT_SYMBOL(snd_verbose_printk); -#endif +/* #endif */ #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK) void snd_verbose_printd(const char *file, int line, const char *format, ...) Index: usb/usbmixer.c =================================================================== --- usb/usbmixer.c (revision 8635) +++ usb/usbmixer.c (working copy) @@ -1,3 +1,18 @@ +#include "config.h" +#ifdef CONFIG_HAVE_DEPRECATED_CONFIG_H +#include +#else +#include +#endif +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#define SND_NEED_USB_WRAPPER +#define __NO_VERSION__ +#endif +#include "adriver.h" +#include "usbcompat.h" + /* * (Tentative) USB Audio Driver for ALSA * @@ -26,7 +41,6 @@ * */ -#include #include #include #include @@ -41,6 +55,14 @@ #include "usbaudio.h" +#ifndef USB_DT_CS_DEVICE +#define USB_DT_CS_DEVICE 0x21 +#define USB_DT_CS_CONFIG 0x22 +#define USB_DT_CS_STRING 0x23 +#define USB_DT_CS_INTERFACE 0x24 +#define USB_DT_CS_ENDPOINT 0x25 +#endif + /* */ @@ -60,12 +82,14 @@ u8 offset; u8 length; u8 packet_length; + u8 min_packet_length; /* minimum accepted length of the URB result */ u8 mute_mixer_id; u32 mute_code; } rc_configs[] = { - { USB_ID(0x041e, 0x3000), 0, 1, 2, 18, 0x0013 }, /* Extigy */ - { USB_ID(0x041e, 0x3020), 2, 1, 6, 18, 0x0013 }, /* Audigy 2 NX */ - { USB_ID(0x041e, 0x3040), 2, 2, 6, 2, 0x6e91 }, /* Live! 24-bit */ + { 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 +102,6 @@ /* 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; @@ -86,6 +109,7 @@ u8 rc_buffer[6]; u8 audigy2nx_leds[3]; + u8 xonar_u1_status; }; @@ -110,6 +134,8 @@ 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 +146,8 @@ int channels; int val_type; int min, max, res; + int cached; + int cache_val[MAX_CHANNELS]; u8 initialized; }; @@ -181,9 +209,22 @@ USB_PROC_DCR_RELEASE = 6, }; -#define MAX_CHANNELS 10 /* max logical channels */ +/*E-mu 0202(0404) eXtension Unit(XU) control*/ +enum { + USB_XU_CLOCK_RATE = 0xe301, + USB_XU_CLOCK_SOURCE = 0xe302, + USB_XU_DIGITAL_IO_STATUS = 0xe303, + USB_XU_DEVICE_OPTIONS = 0xe304, + USB_XU_DIRECT_MONITORING = 0xe305, + USB_XU_METERING = 0xe306 +}; +enum { + USB_XU_CLOCK_SOURCE_SELECTOR = 0x02, /* clock source*/ + USB_XU_CLOCK_RATE_SELECTOR = 0x03, /* clock rate */ + USB_XU_DIGITAL_FORMAT_SELECTOR = 0x01, /* the spdif format */ + USB_XU_SOFT_LIMIT_SELECTOR = 0x03 /* soft limiter */ +}; - /* * manual mapping of mixer names * if the mixer topology is too complicated and the parsed names are @@ -219,7 +260,10 @@ 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 +420,35 @@ } /* 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 */ @@ -394,7 +462,7 @@ value_set = convert_bytes_value(cval, value_set); buf[0] = value_set & 0xff; buf[1] = (value_set >> 8) & 0xff; - while (timeout -- > 0) + while (timeout-- > 0) if (snd_usb_ctl_msg(cval->mixer->chip->dev, usb_sndctrlpipe(cval->mixer->chip->dev, 0), request, @@ -412,9 +480,17 @@ 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; } /* @@ -424,15 +500,24 @@ unsigned int size, unsigned int __user *_tlv) { struct usb_mixer_elem_info *cval = kcontrol->private_data; - DECLARE_TLV_DB_SCALE(scale, 0, 0, 0); - +/* DECLARE_TLV_DB_MINMAX(scale, 0, 0); */ + DECLARE_TLV_DB_SCALE(scale, 0, 0, 0); if (size < sizeof(scale)) return -ENOMEM; /* USB descriptions contain the dB scale in 1/256 dB unit * while ALSA TLV contains in 1/100 dB unit */ scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; - scale[3] = (convert_signed_value(cval, cval->res) * 100) / 256; + scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256; + if (scale[3] <= scale[2]) { + /* something is wrong; assume it's either from/to 0dB */ + if (scale[2] < 0) + scale[3] = 0; + else if (scale[2] > 0) + scale[2] = 0; + else /* totally crap, return an error */ + return -EINVAL; + } if (copy_to_user(_tlv, scale, sizeof(scale))) return -EFAULT; return 0; @@ -718,7 +803,7 @@ 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 +811,8 @@ 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 +820,7 @@ break; cval->res *= 2; } - set_cur_mix_value(cval, minchn, saved); + set_cur_mix_value(cval, minchn, 0, saved); } cval->initialized = 1; @@ -775,35 +860,25 @@ 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 +895,28 @@ 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; } } @@ -867,6 +936,11 @@ * build a feature control */ +static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str) +{ + return strlcat(kctl->id.name, str, sizeof(kctl->id.name)); +} + static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, unsigned int ctl_mask, int control, struct usb_audio_term *iterm, int unitid) @@ -947,13 +1021,13 @@ */ if (! mapped_name && ! (state->oterm.type >> 16)) { if ((state->oterm.type & 0xff00) == 0x0100) { - len = strlcat(kctl->id.name, " Capture", sizeof(kctl->id.name)); + len = append_ctl_name(kctl, " Capture"); } else { - len = strlcat(kctl->id.name + len, " Playback", sizeof(kctl->id.name)); + len = append_ctl_name(kctl, " Playback"); } } - strlcat(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume", - sizeof(kctl->id.name)); + append_ctl_name(kctl, control == USB_FEATURE_MUTE ? + " Switch" : " Volume"); if (control == USB_FEATURE_VOLUME) { kctl->tlv.c = mixer_vol_tlv; kctl->vd[0].access |= @@ -969,20 +1043,35 @@ break; } - /* quirk for UDA1321/N101 */ - /* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */ - /* is not very clear from datasheets */ - /* I hope that the min value is -15360 for newer firmware --jk */ + /* volume control quirks */ switch (state->chip->usb_id) { case USB_ID(0x0471, 0x0101): case USB_ID(0x0471, 0x0104): case USB_ID(0x0471, 0x0105): case USB_ID(0x0672, 0x1041): + /* quirk for UDA1321/N101. + * note that detection between firmware 2.1.1.7 (N101) + * and later 2.1.1.21 is not very clear from datasheets. + * I hope that the min value is -15360 for newer firmware --jk + */ if (!strcmp(kctl->id.name, "PCM Playback Volume") && cval->min == -15616) { - snd_printk(KERN_INFO "using volume control quirk for the UDA1321/N101 chip\n"); + snd_printk(KERN_INFO + "set volume quirk for UDA1321/N101 chip\n"); cval->max = -256; } + break; + + case USB_ID(0x046d, 0x09a4): + if (!strcmp(kctl->id.name, "Mic Capture Volume")) { + snd_printk(KERN_INFO + "set volume quirk for QuickCam E3500\n"); + cval->min = 6080; + cval->max = 8768; + cval->res = 192; + } + break; + } snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", @@ -1020,6 +1109,15 @@ channels = (ftr[0] - 7) / csize - 1; master_bits = snd_usb_combine_bytes(ftr + 6, csize); + /* master configuration quirks */ + switch (state->chip->usb_id) { + case USB_ID(0x08bb, 0x2702): + snd_printk(KERN_INFO + "usbmixer: master volume quirk for PCM2702 chip\n"); + /* disable non-functional volume control */ + master_bits &= ~(1 << (USB_FEATURE_VOLUME - 1)); + break; + } if (channels > 0) first_ch_bits = snd_usb_combine_bytes(ftr + 6 + csize, csize); else @@ -1097,7 +1195,7 @@ len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); if (! len) len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1); - strlcat(kctl->id.name + len, " Volume", sizeof(kctl->id.name)); + append_ctl_name(kctl, " Volume"); snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); @@ -1270,8 +1368,33 @@ { USB_PROC_DCR, "DCR", dcr_proc_info }, { 0 }, }; - /* + * predefined data for extension units + */ +static struct procunit_value_info clock_rate_xu_info[] = { + { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 }, + { 0 } +}; +static struct procunit_value_info clock_source_xu_info[] = { + { USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN }, + { 0 } +}; +static struct procunit_value_info spdif_format_xu_info[] = { + { USB_XU_DIGITAL_FORMAT_SELECTOR, "SPDIF/AC3", USB_MIXER_BOOLEAN }, + { 0 } +}; +static struct procunit_value_info soft_limit_xu_info[] = { + { USB_XU_SOFT_LIMIT_SELECTOR, " ", USB_MIXER_BOOLEAN }, + { 0 } +}; +static struct procunit_info extunits[] = { + { USB_XU_CLOCK_RATE, "Clock rate", clock_rate_xu_info }, + { USB_XU_CLOCK_SOURCE, "DigitalIn CLK source", clock_source_xu_info }, + { USB_XU_DIGITAL_IO_STATUS, "DigitalOut format:", spdif_format_xu_info }, + { USB_XU_DEVICE_OPTIONS, "AnalogueIn Soft Limit", soft_limit_xu_info }, + { 0 } +}; +/* * build a processing/extension unit */ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned char *dsc, struct procunit_info *list, char *name) @@ -1331,8 +1454,18 @@ cval->max = dsc[15]; cval->res = 1; cval->initialized = 1; - } else - get_min_max(cval, valinfo->min_value); + } else { + if (type == USB_XU_CLOCK_RATE) { + /* E-Mu USB 0404/0202/TrackerPre + * samplerate control quirk + */ + cval->min = 0; + cval->max = 5; + cval->res = 1; + cval->initialized = 1; + } else + get_min_max(cval, valinfo->min_value); + } kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); if (! kctl) { @@ -1354,8 +1487,8 @@ if (! len) strlcpy(kctl->id.name, name, sizeof(kctl->id.name)); } - strlcat(kctl->id.name, " ", sizeof(kctl->id.name)); - strlcat(kctl->id.name, valinfo->suffix, sizeof(kctl->id.name)); + append_ctl_name(kctl, " "); + append_ctl_name(kctl, valinfo->suffix); snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); @@ -1373,7 +1506,7 @@ static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) { - return build_audio_procunit(state, unitid, desc, NULL, "Extension Unit"); + return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit"); } @@ -1389,6 +1522,9 @@ struct usb_mixer_elem_info *cval = kcontrol->private_data; char **itemlist = (char **)kcontrol->private_value; +/* if (snd_BUG_ON(!itemlist)) + return -EINVAL; +*/ snd_assert(itemlist, return -EINVAL); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -1483,7 +1619,7 @@ struct snd_kcontrol *kctl; char **namelist; - if (! num_ins || desc[0] < 6 + num_ins) { + if (! num_ins || desc[0] < 5 + num_ins) { snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid); return -EINVAL; } @@ -1563,9 +1699,9 @@ strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); if ((state->oterm.type & 0xff00) == 0x0100) - strlcat(kctl->id.name, " Capture Source", sizeof(kctl->id.name)); + append_ctl_name(kctl, " Capture Source"); else - strlcat(kctl->id.name, " Playback Source", sizeof(kctl->id.name)); + append_ctl_name(kctl, " Playback Source"); } snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", @@ -1703,13 +1839,23 @@ case 19: /* speaker out jacks */ case 20: /* headphones out jack */ break; + /* live24ext: 4 = line-in jack */ + case 3: /* hp-out jack (may actuate Mute) */ + 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: snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); break; } } +#if !defined(OLD_USB) && !defined(CONFIG_SND_NEW_IRQ_HANDLER) +static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) +#else static void snd_usb_mixer_status_complete(struct urb *urb) +#endif { struct usb_mixer_interface *mixer = urb->context; @@ -1749,12 +1895,15 @@ if (get_iface_desc(hostif)->bNumEndpoints < 1) return 0; ep = get_endpoint(hostif, 0); - if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN || - (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_int(ep)) return 0; - epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + epnum = usb_endpoint_num(ep); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) buffer_length = le16_to_cpu(ep->wMaxPacketSize); +#else + buffer_length = ep->wMaxPacketSize; +#endif transfer_buffer = kmalloc(buffer_length, GFP_KERNEL); if (!transfer_buffer) return -ENOMEM; @@ -1771,13 +1920,18 @@ return 0; } +#if !defined(OLD_USB) && !defined(CONFIG_SND_NEW_IRQ_HANDLER) +static void snd_usb_soundblaster_remote_complete(struct urb *urb, + struct pt_regs *regs) +#else static void snd_usb_soundblaster_remote_complete(struct urb *urb) +#endif { struct usb_mixer_interface *mixer = urb->context; const struct rc_config *rc = mixer->rc_cfg; u32 code; - if (urb->status < 0 || urb->actual_length < rc->packet_length) + if (urb->status < 0 || urb->actual_length < rc->min_packet_length) return; code = mixer->rc_buffer[rc->offset]; @@ -1792,24 +1946,6 @@ 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) { @@ -1862,9 +1998,8 @@ 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) @@ -1888,14 +2023,7 @@ return 0; } -static int snd_audigy2nx_led_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_audigy2nx_led_info snd_ctl_boolean_mono_info static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1958,6 +2086,10 @@ 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) || + mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) + break; err = snd_ctl_add(mixer->chip->card, snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); if (err < 0) @@ -1970,36 +2102,121 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - static const struct { + static const struct sb_jack { int unitid; const char *name; - } jacks[] = { + } jacks_audigy2nx[] = { {4, "dig in "}, {7, "line in"}, {19, "spk out"}, {20, "hph out"}, + {-1, NULL} + }, jacks_live24ext[] = { + {4, "line in"}, /* &1=Line, &2=Mic*/ + {3, "hph out"}, /* headphones */ + {0, "RC "}, /* last command, 6 bytes see rc_config above */ + {-1, NULL} }; + const struct sb_jack *jacks; struct usb_mixer_interface *mixer = entry->private_data; int i, err; u8 buf[3]; snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); - for (i = 0; i < ARRAY_SIZE(jacks); ++i) { + if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) + jacks = jacks_audigy2nx; + else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || + mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) + jacks = jacks_live24ext; + else + return; + + for (i = 0; jacks[i].name; ++i) { snd_iprintf(buffer, "%s: ", jacks[i].name); err = snd_usb_ctl_msg(mixer->chip->dev, usb_rcvctrlpipe(mixer->chip->dev, 0), GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, jacks[i].unitid << 8, buf, 3, 100); - if (err == 3 && buf[0] == 3) + if (err == 3 && (buf[0] == 3 || buf[0] == 6)) snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); else snd_iprintf(buffer, "?\n"); } } -int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif) +static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02); + return 0; +} + +static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + u8 old_status, new_status; + int err, changed; + + old_status = mixer->xonar_u1_status; + if (ucontrol->value.integer.value[0]) + new_status = old_status | 0x02; + else + new_status = old_status & ~0x02; + changed = new_status != old_status; + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 50, 0, &new_status, 1, 100); + if (err < 0) + return err; + mixer->xonar_u1_status = new_status; + return changed; +} + +static struct snd_kcontrol_new snd_xonar_u1_output_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = snd_xonar_u1_switch_get, + .put = snd_xonar_u1_switch_put, +}; + +static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) +{ + int err; + + err = snd_ctl_add(mixer->chip->card, + snd_ctl_new1(&snd_xonar_u1_output_switch, mixer)); + if (err < 0) + return err; + mixer->xonar_u1_status = 0x05; + return 0; +} + +void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, + unsigned char samplerate_id) +{ + struct usb_mixer_interface *mixer; + struct usb_mixer_elem_info *cval; + int unitid = 12; /* SamleRate ExtensionUnit ID */ + + list_for_each_entry(mixer, &chip->mixer_list, list) { + cval = mixer->id_elems[unitid]; + if (cval) { + set_cur_ctl_value(cval, cval->control << 8, samplerate_id); + snd_usb_mixer_notify_id(mixer, unitid); + } + break; + } +} + +int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, + int ignore_error) +{ static struct snd_device_ops dev_ops = { .dev_free = snd_usb_mixer_dev_free }; @@ -2013,9 +2230,7 @@ return -ENOMEM; mixer->chip = chip; mixer->ctrlif = ctrlif; -#ifdef IGNORE_CTL_ERROR - mixer->ignore_ctl_error = 1; -#endif + mixer->ignore_ctl_error = ignore_error; mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL); if (!mixer->id_elems) { kfree(mixer); @@ -2029,7 +2244,9 @@ if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) 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, 0x3048)) { struct snd_info_entry *entry; if ((err = snd_audigy2nx_controls_create(mixer)) < 0) @@ -2039,6 +2256,13 @@ snd_audigy2nx_proc_read); } + if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) || + mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) { + err = snd_xonar_u1_controls_create(mixer); + if (err < 0) + goto _error; + } + err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); if (err < 0) goto _error; Index: usb/usbmixer_maps.c =================================================================== --- usb/usbmixer_maps.c (revision 8635) +++ usb/usbmixer_maps.c (working copy) @@ -187,6 +187,13 @@ { 0 } /* terminator */ }; +/* Creative SoundBlaster Live! 24-bit External */ +static struct usbmix_name_map live24ext_map[] = { + /* 2: PCM Playback Volume */ + { 5, "Mic Capture" }, /* FU, default PCM Capture Volume */ + { 0 } /* terminator */ +}; + /* LineX FM Transmitter entry - needed to bypass controls bug */ static struct usbmix_name_map linex_map[] = { /* 1: IT pcm */ @@ -254,6 +261,38 @@ {} /* 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 */ +}; + +/* "Gamesurround Muse Pocket LT" looks same like "Sound Blaster MP3+" + * most importand difference is SU[8], it should be set to "Capture Source" + * to make alsamixer and PA working properly. + * FIXME: or mp3plus_map should use "Capture Source" too, + * so this maps can be merget + */ +static struct usbmix_name_map hercules_usb51_map[] = { + { 8, "Capture Source" }, /* SU, default "PCM Capture Source" */ + { 9, "Master Playback" }, /* FU, default "Speaker Playback" */ + { 10, "Mic Boost", 7 }, /* FU, default "Auto Gain Input" */ + { 11, "Line Capture" }, /* FU, default "PCM Capture" */ + { 13, "Mic Bypass Playback" }, /* FU, default "Mic Playback" */ + { 14, "Line Bypass Playback" }, /* FU, default "Line Playback" */ + { 0 } /* terminator */ +}; + /* * Control map entries */ @@ -273,7 +312,16 @@ .map = audigy2nx_map, .selector_map = audigy2nx_selectors, }, + { + .id = USB_ID(0x041e, 0x3040), + .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, @@ -284,6 +332,13 @@ .ignore_ctl_error = 1, }, { + /* Hercules Gamesurround Muse Pocket LT + * (USB 5.1 Channel Audio Adapter) + */ + .id = USB_ID(0x06f8, 0xc000), + .map = hercules_usb51_map, + }, + { .id = USB_ID(0x08bb, 0x2702), .map = linex_map, .ignore_ctl_error = 1, @@ -300,6 +355,11 @@ .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 */ }; Index: usb/Kconfig =================================================================== --- usb/Kconfig (revision 8635) +++ usb/Kconfig (working copy) @@ -31,16 +31,18 @@ config SND_USB_CAIAQ tristate "Native Instruments USB audio devices" - depends on SND && USB - select SND_HWDEP - select SND_RAWMIDI - select SND_PCM - help + depends on SND && USB + select SND_HWDEP + select SND_RAWMIDI + select SND_PCM + help Say Y here to include support for caiaq USB audio interfaces, namely: * Native Instruments RigKontrol2 + * Native Instruments RigKontrol3 * Native Instruments Kore Controller + * Native Instruments Kore Controller 2 * Native Instruments Audio Kontrol 1 * Native Instruments Audio 8 DJ @@ -50,11 +52,15 @@ config SND_USB_CAIAQ_INPUT bool "enable input device for controllers" depends on SND_USB_CAIAQ + depends on INPUT=y || INPUT=SND_USB_CAIAQ help Say Y here to support input controllers like buttons, knobs, alpha dials and analog pedals on the following products: * Native Instruments RigKontrol2 + * Native Instruments RigKontrol3 + * Native Instruments Kore Controller + * Native Instruments Kore Controller 2 * Native Instruments Audio Kontrol 1 endmenu Index: usb/usbaudio.h =================================================================== --- usb/usbaudio.h (revision 8635) +++ usb/usbaudio.h (working copy) @@ -125,13 +125,14 @@ struct snd_card *card; u32 usb_id; int shutdown; + unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ int num_interfaces; + int num_suspended_intf; struct list_head pcm_list; /* list of pcm streams */ int pcm_devs; struct list_head midi_list; /* list of midi interfaces */ - int next_midi_device; struct list_head mixer_list; /* list of mixer interfaces */ }; @@ -152,14 +153,15 @@ QUIRK_MIDI_YAMAHA, QUIRK_MIDI_MIDIMAN, QUIRK_MIDI_NOVATION, - QUIRK_MIDI_RAW, + QUIRK_MIDI_FASTLANE, QUIRK_MIDI_EMAGIC, QUIRK_MIDI_CME, + QUIRK_MIDI_US122L, QUIRK_AUDIO_STANDARD_INTERFACE, QUIRK_AUDIO_FIXED_ENDPOINT, - QUIRK_AUDIO_EDIROL_UA700_UA25, QUIRK_AUDIO_EDIROL_UA1000, - QUIRK_AUDIO_EDIROL_UA101, + QUIRK_AUDIO_EDIROL_UAXX, + QUIRK_AUDIO_ALIGN_TRANSFER, QUIRK_TYPE_COUNT }; @@ -208,7 +210,17 @@ /* */ -#define combine_word(s) ((*s) | ((unsigned int)(s)[1] << 8)) +/*E-mu USB samplerate control quirk*/ +enum { + EMU_QUIRK_SR_44100HZ = 0, + EMU_QUIRK_SR_48000HZ, + EMU_QUIRK_SR_88200HZ, + EMU_QUIRK_SR_96000HZ, + EMU_QUIRK_SR_176400HZ, + EMU_QUIRK_SR_192000HZ +}; + +#define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) @@ -221,15 +233,21 @@ __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout); -int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif); +int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, + int ignore_error); void snd_usb_mixer_disconnect(struct list_head *p); -int snd_usb_create_midi_interface(struct snd_usb_audio *chip, struct usb_interface *iface, - const struct snd_usb_audio_quirk *quirk); +int snd_usbmidi_create(struct snd_card *card, + struct usb_interface *iface, + struct list_head *midi_list, + const struct snd_usb_audio_quirk *quirk); void snd_usbmidi_input_stop(struct list_head* p); void snd_usbmidi_input_start(struct list_head* p); void snd_usbmidi_disconnect(struct list_head *p); +void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, + unsigned char samplerate_id); + /* * retrieve usb_interface descriptor from the host interface * (conditional for compatibility with the older API) Index: usb/usx2y/usX2Yhwdep.c =================================================================== --- usb/usx2y/usX2Yhwdep.c (revision 8635) +++ usb/usx2y/usX2Yhwdep.c (working copy) @@ -20,7 +20,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include @@ -31,37 +30,31 @@ #include "usbusx2y.h" #include "usX2Yhwdep.h" -int usX2Y_hwdep_pcm_new(struct snd_card *card); - - -static struct page * snd_us428ctls_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type) +static int snd_us428ctls_vm_fault(struct vm_area_struct *area, + struct vm_fault *vmf) { unsigned long offset; struct page * page; void *vaddr; - snd_printdd("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh\n", + snd_printdd("ENTER, start %lXh, pgoff %ld\n", area->vm_start, - address - area->vm_start, - (address - area->vm_start) >> PAGE_SHIFT, - address); + vmf->pgoff); - offset = area->vm_pgoff << PAGE_SHIFT; - offset += address - area->vm_start; - snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_SIGBUS); + offset = vmf->pgoff << PAGE_SHIFT; vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->us428ctls_sharedmem + offset; page = virt_to_page(vaddr); get_page(page); - snd_printdd( "vaddr=%p made us428ctls_vm_nopage() return %p; offset=%lX\n", vaddr, page, offset); + vmf->page = page; - if (type) - *type = VM_FAULT_MINOR; + snd_printdd("vaddr=%p made us428ctls_vm_fault() page %p\n", + vaddr, page); - return page; + return 0; } -static struct vm_operations_struct us428ctls_vm_ops = { - .nopage = snd_us428ctls_vm_nopage, +static const struct vm_operations_struct us428ctls_vm_ops = { + .fault = snd_us428ctls_vm_fault, }; static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area) @@ -88,7 +81,7 @@ us428->us428ctls_sharedmem->CtlSnapShotLast = -2; } area->vm_ops = &us428ctls_vm_ops; - area->vm_flags |= VM_RESERVED; + area->vm_flags |= VM_RESERVED | VM_DONTEXPAND; area->vm_private_data = hw->private_data; return 0; } @@ -110,16 +103,6 @@ } -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) { @@ -131,7 +114,7 @@ struct usX2Ydev *us428 = hw->private_data; int id = -1; - switch (le16_to_cpu(us428->chip.dev->descriptor.idProduct)) { + switch (le16_to_cpu(us428->dev->descriptor.idProduct)) { case USB_ID_US122: id = USX2Y_TYPE_122; break; @@ -181,14 +164,14 @@ .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &quirk_data_2 }; - struct usb_device *dev = usX2Y(card)->chip.dev; + struct usb_device *dev = usX2Y(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 0); struct snd_usb_audio_quirk *quirk = le16_to_cpu(dev->descriptor.idProduct) == USB_ID_US428 ? &quirk_2 : &quirk_1; snd_printdd("usX2Y_create_usbmidi \n"); - return snd_usb_create_midi_interface(&usX2Y(card)->chip, iface, quirk); + return snd_usbmidi_create(card, iface, &usX2Y(card)->midi_list, quirk); } static int usX2Y_create_alsa_devices(struct snd_card *card) @@ -219,14 +202,16 @@ snd_printdd( "dsp_load %s\n", dsp->name); if (access_ok(VERIFY_READ, dsp->image, dsp->length)) { - struct usb_device* dev = priv->chip.dev; + struct usb_device* dev = priv->dev; +/* char *buf; */ + +/* buf = memdup_user(dsp->image, dsp->length); + if (IS_ERR(buf)) + return PTR_ERR(buf); +*/ char *buf = kmalloc(dsp->length, GFP_KERNEL); if (!buf) return -ENOMEM; - if (copy_from_user(buf, dsp->image, dsp->length)) { - kfree(buf); - return -EFAULT; - } err = usb_set_interface(dev, 0, 1); if (err) snd_printk(KERN_ERR "usb_set_interface error \n"); @@ -271,8 +256,6 @@ 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; Index: usb/usx2y/usx2yhwdeppcm.c =================================================================== --- usb/usx2y/usx2yhwdeppcm.c (revision 8635) +++ usb/usx2y/usx2yhwdeppcm.c (working copy) @@ -234,7 +234,7 @@ if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; @@ -318,7 +318,7 @@ int i; unsigned int pipe; int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->chip.dev; + struct usb_device *dev = subs->usX2Y->dev; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -441,7 +441,7 @@ unsigned long pack; if (0 == u) atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; urb->transfer_flags = URB_ISO_ASAP; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs()); @@ -683,30 +683,24 @@ } -static struct page * snd_usX2Y_hwdep_pcm_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type) +static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct *area, + struct vm_fault *vmf) { unsigned long offset; - struct page *page; void *vaddr; - offset = area->vm_pgoff << PAGE_SHIFT; - offset += address - area->vm_start; - snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM); + offset = vmf->pgoff << PAGE_SHIFT; vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset; - page = virt_to_page(vaddr); - get_page(page); - - if (type) - *type = VM_FAULT_MINOR; - - return page; + vmf->page = virt_to_page(vaddr); + get_page(vmf->page); + return 0; } -static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = { +static const struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = { .open = snd_usX2Y_hwdep_pcm_vm_open, .close = snd_usX2Y_hwdep_pcm_vm_close, - .nopage = snd_usX2Y_hwdep_pcm_vm_nopage, + .fault = snd_usX2Y_hwdep_pcm_vm_fault, }; @@ -728,7 +722,7 @@ return -ENODEV; } area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops; - area->vm_flags |= VM_RESERVED; + area->vm_flags |= VM_RESERVED | VM_DONTEXPAND; area->vm_private_data = hw->private_data; return 0; } @@ -747,7 +741,7 @@ int err; struct snd_hwdep *hw; struct snd_pcm *pcm; - struct usb_device *dev = usX2Y(card)->chip.dev; + struct usb_device *dev = usX2Y(card)->dev; if (1 != nr_of_packs()) return 0; Index: usb/usx2y/usbusx2y.c =================================================================== --- usb/usx2y/usbusx2y.c (revision 8635) +++ usb/usx2y/usbusx2y.c (working copy) @@ -130,7 +130,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include @@ -228,9 +227,9 @@ 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) { @@ -239,9 +238,9 @@ send = 0; for (j = 0; j < URBS_AsyncSeq && !err; ++j) if (0 == usX2Y->AS04.urb[j]->status) { - struct us428_p4out *p4out = us428ctls->p4out + send; // FIXME if more then 1 p4out is new, 1 gets lost. - usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->chip.dev, - usb_sndbulkpipe(usX2Y->chip.dev, 0x04), &p4out->val.vol, + struct us428_p4out *p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost. + usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->dev, + usb_sndbulkpipe(usX2Y->dev, 0x04), &p4out->val.vol, p4out->type == eLT_Light ? sizeof(struct us428_lights) : 5, i_usX2Y_Out04Int, usX2Y); err = usb_submit_urb(usX2Y->AS04.urb[j], GFP_ATOMIC); @@ -254,7 +253,7 @@ if (err) snd_printk(KERN_ERR "In04Int() usb_submit_urb err=%i\n", err); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; usb_submit_urb(urb, GFP_ATOMIC); } @@ -274,8 +273,8 @@ err = -ENOMEM; break; } - usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->chip.dev, - usb_sndbulkpipe(usX2Y->chip.dev, 0x04), + usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->dev, + usb_sndbulkpipe(usX2Y->dev, 0x04), usX2Y->AS04.buffer + URB_DataLen_AsyncSeq*i, 0, i_usX2Y_Out04Int, usX2Y ); @@ -294,7 +293,7 @@ } init_waitqueue_head(&usX2Y->In04WaitQueue); - usb_fill_int_urb(usX2Y->In04urb, usX2Y->chip.dev, usb_rcvintpipe(usX2Y->chip.dev, 0x4), + usb_fill_int_urb(usX2Y->In04urb, usX2Y->dev, usb_rcvintpipe(usX2Y->dev, 0x4), usX2Y->In04Buf, 21, i_usX2Y_In04Int, usX2Y, 10); @@ -334,25 +333,31 @@ { /* 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)); + return -ENODEV; +/* err = snd_card_create(index[dev], id[dev], THIS_MODULE, + sizeof(struct usX2Ydev), &card); + if (err < 0) + return err; +*/ + card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct usX2Ydev)); if (!card) return NULL; - snd_usX2Y_card_used[usX2Y(card)->chip.index = dev] = 1; + snd_usX2Y_card_used[usX2Y(card)->card_index = dev] = 1; card->private_free = snd_usX2Y_card_private_free; - usX2Y(card)->chip.dev = device; - usX2Y(card)->chip.card = card; + usX2Y(card)->dev = device; init_waitqueue_head(&usX2Y(card)->prepare_wait_queue); mutex_init(&usX2Y(card)->prepare_mutex); - INIT_LIST_HEAD(&usX2Y(card)->chip.midi_list); + INIT_LIST_HEAD(&usX2Y(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", @@ -360,29 +365,39 @@ le16_to_cpu(device->descriptor.idVendor), le16_to_cpu(device->descriptor.idProduct), 0,//us428(card)->usbmidi.ifnum, - usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum + usX2Y(card)->dev->bus->busnum, usX2Y(card)->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; + snd_card_set_dev(card, &intf->dev); 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; } /* @@ -390,19 +405,20 @@ */ 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) { - dev_set_drvdata(&intf->dev, 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) { usX2Y_usb_disconnect(interface_to_usbdev(intf), - dev_get_drvdata(&intf->dev)); + usb_get_intfdata(intf)); } MODULE_DEVICE_TABLE(usb, snd_usX2Y_usb_id_table); @@ -419,8 +435,8 @@ usb_free_urb(usX2Y(card)->In04urb); if (usX2Y(card)->us428ctls_sharedmem) snd_free_pages(usX2Y(card)->us428ctls_sharedmem, sizeof(*usX2Y(card)->us428ctls_sharedmem)); - if (usX2Y(card)->chip.index >= 0 && usX2Y(card)->chip.index < SNDRV_CARDS) - snd_usX2Y_card_used[usX2Y(card)->chip.index] = 0; + if (usX2Y(card)->card_index >= 0 && usX2Y(card)->card_index < SNDRV_CARDS) + snd_usX2Y_card_used[usX2Y(card)->card_index] = 0; } /* @@ -432,13 +448,12 @@ struct snd_card *card = ptr; struct usX2Ydev *usX2Y = usX2Y(card); struct list_head *p; - usX2Y->chip.shutdown = 1; usX2Y->chip_status = USX2Y_STAT_CHIP_HUP; usX2Y_unlinkSeq(&usX2Y->AS04); usb_kill_urb(usX2Y->In04urb); snd_card_disconnect(card); /* release the midi resources */ - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_disconnect(p); } if (usX2Y->us428ctls_sharedmem) Index: usb/usx2y/usbusx2yaudio.c =================================================================== --- usb/usx2y/usbusx2yaudio.c (revision 8635) +++ usb/usx2y/usbusx2yaudio.c (working copy) @@ -31,7 +31,6 @@ */ -#include #include #include #include @@ -200,7 +199,7 @@ return -ENODEV; urb->start_frame = (frame + NRURBS * nr_of_packs()); // let hcd do rollover sanity checks urb->hcpriv = NULL; - urb->dev = subs->usX2Y->chip.dev; /* we need to set this at each time */ + urb->dev = subs->usX2Y->dev; /* we need to set this at each time */ if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { snd_printk(KERN_ERR "usb_submit_urb() returned %i\n", err); return err; @@ -297,10 +296,11 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y, struct snd_usX2Y_substream *subs, struct urb *urb) { - snd_printk(KERN_ERR "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" - KERN_ERR "Most propably some urb of usb-frame %i is still missing.\n" - KERN_ERR "Cause could be too long delays in usb-hcd interrupt handling.\n", - usb_get_current_frame_number(usX2Y->chip.dev), + snd_printk(KERN_ERR +"Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" +"Most propably some urb of usb-frame %i is still missing.\n" +"Cause could be too long delays in usb-hcd interrupt handling.\n", + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame); usX2Y_clients_stop(usX2Y); @@ -313,7 +313,7 @@ if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; @@ -424,7 +424,7 @@ int i; unsigned int pipe; int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->chip.dev; + struct usb_device *dev = subs->usX2Y->dev; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -500,7 +500,7 @@ unsigned long pack; if (0 == i) atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; urb->transfer_flags = URB_ISO_ASAP; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack; @@ -692,7 +692,7 @@ } ((char*)(usbdata + i))[0] = ra[i].c1; ((char*)(usbdata + i))[1] = ra[i].c2; - usb_fill_bulk_urb(us->urb[i], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 4), + usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4), usbdata + i, 2, i_usX2Y_04Int, usX2Y); #ifdef OLD_USB us->urb[i]->transfer_flags = USB_QUEUE_BULK; @@ -740,17 +740,17 @@ alternate = 1; usX2Y->stride = 4; } - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_stop(p); } usb_kill_urb(usX2Y->In04urb); - if ((err = usb_set_interface(usX2Y->chip.dev, 0, alternate))) { + if ((err = usb_set_interface(usX2Y->dev, 0, alternate))) { snd_printk(KERN_ERR "usb_set_interface error \n"); return err; } - usX2Y->In04urb->dev = usX2Y->chip.dev; + usX2Y->In04urb->dev = usX2Y->dev; err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL); - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_start(p); } usX2Y->format = format; @@ -871,7 +871,8 @@ { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH), .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE, .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .rate_min = 44100, @@ -935,10 +936,9 @@ */ static void usX2Y_audio_stream_free(struct snd_usX2Y_substream **usX2Y_substream) { - if (NULL != usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]) { - kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]); - usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL; - } + kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]); + usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL; + kfree(usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]); usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE] = NULL; } @@ -955,7 +955,7 @@ struct snd_pcm *pcm; int err, i; struct snd_usX2Y_substream **usX2Y_substream = - usX2Y(card)->subs + 2 * usX2Y(card)->chip.pcm_devs; + usX2Y(card)->subs + 2 * usX2Y(card)->pcm_devs; for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; i <= SNDRV_PCM_STREAM_CAPTURE; ++i) { @@ -971,7 +971,7 @@ usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint; usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint; - err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->chip.pcm_devs, + err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->pcm_devs, playback_endpoint ? 1 : 0, 1, &pcm); if (err < 0) { @@ -987,7 +987,7 @@ pcm->private_free = snd_usX2Y_pcm_private_free; pcm->info_flags = 0; - sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->chip.pcm_devs); + sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->pcm_devs); if ((playback_endpoint && 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, @@ -1001,7 +1001,7 @@ snd_usX2Y_pcm_private_free(pcm); return err; } - usX2Y(card)->chip.pcm_devs++; + usX2Y(card)->pcm_devs++; return 0; } @@ -1013,14 +1013,14 @@ { int err = 0; - INIT_LIST_HEAD(&usX2Y(card)->chip.pcm_list); + INIT_LIST_HEAD(&usX2Y(card)->pcm_list); if (0 > (err = usX2Y_audio_stream_new(card, 0xA, 0x8))) return err; - if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) == USB_ID_US428) + if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) == USB_ID_US428) if (0 > (err = usX2Y_audio_stream_new(card, 0, 0xA))) return err; - if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) != USB_ID_US122) + if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) != USB_ID_US122) err = usX2Y_rate_set(usX2Y(card), 44100); // Lets us428 recognize output-volume settings, disturbs us122. return err; } Index: usb/usx2y/usx2yhwdeppcm.h =================================================================== --- usb/usx2y/usx2yhwdeppcm.h (revision 8635) +++ usb/usx2y/usx2yhwdeppcm.h (working copy) @@ -18,3 +18,5 @@ volatile unsigned captured_iso_frames; int capture_iso_start; }; + +int usX2Y_hwdep_pcm_new(struct snd_card *card); Index: usb/usx2y/usbusx2y.h =================================================================== --- usb/usx2y/usbusx2y.h (revision 8635) +++ usb/usx2y/usbusx2y.h (working copy) @@ -22,7 +22,8 @@ #include "usx2yhwdeppcm.h" struct usX2Ydev { - struct snd_usb_audio chip; + struct usb_device *dev; + int card_index; int stride; struct urb *In04urb; void *In04Buf; @@ -42,6 +43,9 @@ struct snd_usX2Y_substream *subs[4]; struct snd_usX2Y_substream * volatile prepare_subs; wait_queue_head_t prepare_wait_queue; + struct list_head midi_list; + struct list_head pcm_list; + int pcm_devs; }; Index: usb/usx2y/Makefile =================================================================== --- usb/usx2y/Makefile (revision 8635) +++ usb/usx2y/Makefile (working copy) @@ -1,3 +1,5 @@ snd-usb-usx2y-objs := usbusx2y.o usX2Yhwdep.o usx2yhwdeppcm.o +snd-usb-us122l-objs := us122l.o obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-usx2y.o +obj-$(CONFIG_SND_USB_US122L) += snd-usb-us122l.o Index: usb/usbaudio.c =================================================================== --- usb/usbaudio.c (revision 8635) +++ usb/usbaudio.c (working copy) @@ -1,3 +1,4 @@ +#include "usbaudio.inc" /* * (Tentative) USB Audio Driver for ALSA * @@ -38,7 +39,6 @@ */ -#include #include #include #include @@ -65,12 +65,19 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */ -static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ +/* Vendor/product IDs for this card */ +static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; +static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; static int nrpacks = 8; /* max. number of packets per urb */ -static int async_unlink = 1; +static int async_unlink = +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +1; +#else +0; /* disabled as default for buggy async-unlink handling */ +#endif static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/ +static int ignore_ctl_error; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); @@ -88,8 +95,10 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); module_param_array(device_setup, int, NULL, 0444); MODULE_PARM_DESC(device_setup, "Specific device setup (if needed)."); +module_param(ignore_ctl_error, bool, 0444); +MODULE_PARM_DESC(ignore_ctl_error, + "Ignore errors from USB controller for mixer interfaces."); - /* * debug the h/w constraints */ @@ -104,7 +113,7 @@ #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; @@ -118,12 +127,12 @@ unsigned char attributes; /* corresponding attributes of cs endpoint */ unsigned char endpoint; /* endpoint */ unsigned char ep_attr; /* endpoint attributes */ + unsigned char datainterval; /* log_2 of data packet interval */ unsigned int maxpacksize; /* max. packet size */ unsigned int rates; /* rate bitmasks */ unsigned int rate_min, rate_max; /* min/max rates */ unsigned int nr_rates; /* number of rate table entries */ unsigned int *rate_table; /* rate table */ - unsigned int needs_knot; /* any unusual rates? */ }; struct snd_usb_substream; @@ -167,12 +176,12 @@ unsigned int curpacksize; /* current packet size in bytes (for capture) */ unsigned int curframesize; /* current packet size in frames (for capture) */ unsigned int fill_max: 1; /* fill max packet size always */ + unsigned int txfr_quirk:1; /* allow sub-frame alignment */ unsigned int fmt_type; /* USB audio format type (1-3) */ - unsigned int packs_per_ms; /* packets per millisecond (for playback) */ unsigned int running: 1; /* running status */ - unsigned int hwptr_done; /* processed frame position in the buffer */ + unsigned int hwptr_done; /* processed byte position in the buffer */ unsigned int transfer_done; /* processed frames since last period update */ unsigned long active_mask; /* bitmask of active urbs */ unsigned long unlink_mask; /* bitmask of unlinked urbs */ @@ -341,7 +350,7 @@ unsigned long flags; unsigned char *cp; int i; - unsigned int stride, len, oldptr; + unsigned int stride, frames, bytes, oldptr; int period_elapsed = 0; stride = runtime->frame_bits >> 3; @@ -352,29 +361,39 @@ snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); // continue; } - len = urb->iso_frame_desc[i].actual_length / stride; - if (! len) - continue; + bytes = urb->iso_frame_desc[i].actual_length; + frames = bytes / stride; + if (!subs->txfr_quirk) + bytes = frames * stride; + if (bytes % (runtime->sample_bits >> 3) != 0) { +#ifdef CONFIG_SND_DEBUG_VERBOSE + int oldbytes = bytes; +#endif + bytes = frames * stride; + snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", + oldbytes, bytes); + } /* update the current pointer */ spin_lock_irqsave(&subs->lock, flags); oldptr = subs->hwptr_done; - subs->hwptr_done += len; - if (subs->hwptr_done >= runtime->buffer_size) - subs->hwptr_done -= runtime->buffer_size; - subs->transfer_done += len; + subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; + frames = (bytes + (oldptr % stride)) / stride; + subs->transfer_done += frames; if (subs->transfer_done >= runtime->period_size) { subs->transfer_done -= runtime->period_size; period_elapsed = 1; } spin_unlock_irqrestore(&subs->lock, flags); /* copy a data chunk */ - if (oldptr + len > runtime->buffer_size) { - unsigned int cnt = runtime->buffer_size - oldptr; - unsigned int blen = cnt * stride; - memcpy(runtime->dma_area + oldptr * stride, cp, blen); - memcpy(runtime->dma_area, cp + blen, len * stride - blen); + if (oldptr + bytes > runtime->buffer_size * stride) { + unsigned int bytes1 = + runtime->buffer_size * stride - oldptr; + memcpy(runtime->dma_area + oldptr, cp, bytes1); + memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); } else { - memcpy(runtime->dma_area + oldptr * stride, cp, len * stride); + memcpy(runtime->dma_area + oldptr, cp, bytes); } } if (period_elapsed) @@ -481,6 +500,33 @@ return 0; } +/* + * process after E-Mu 0202/0404/Tracker Pre high speed playback sync complete + * + * These devices return the number of samples per packet instead of the number + * of samples per microframe. + */ +static int retire_playback_sync_urb_hs_emu(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + unsigned int f; + unsigned long flags; + + if (urb->iso_frame_desc[0].status == 0 && + urb->iso_frame_desc[0].actual_length == 4) { + f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; + f >>= subs->datainterval; + if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { + spin_lock_irqsave(&subs->lock, flags); + subs->freqm = f; + spin_unlock_irqrestore(&subs->lock, flags); + } + } + + return 0; +} + /* determine the number of frames in the next packet */ static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs) { @@ -496,7 +542,7 @@ /* * 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, @@ -508,13 +554,13 @@ 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, @@ -534,24 +580,24 @@ struct snd_pcm_runtime *runtime, struct urb *urb) { - int i, stride, offs; - unsigned int counts; + int i, stride; + unsigned int counts, frames, bytes; unsigned long flags; int period_elapsed = 0; struct snd_urb_ctx *ctx = urb->context; stride = runtime->frame_bits >> 3; - offs = 0; + frames = 0; urb->dev = ctx->subs->dev; /* we need to set this at each time */ urb->number_of_packets = 0; spin_lock_irqsave(&subs->lock, flags); for (i = 0; i < ctx->packets; i++) { counts = snd_usb_audio_next_packet_size(subs); /* set up descriptor */ - urb->iso_frame_desc[i].offset = offs * stride; + urb->iso_frame_desc[i].offset = frames * stride; urb->iso_frame_desc[i].length = counts * stride; - offs += counts; + frames += counts; urb->number_of_packets++; subs->transfer_done += counts; if (subs->transfer_done >= runtime->period_size) { @@ -561,7 +607,7 @@ if (subs->transfer_done > 0) { /* FIXME: fill-max mode is not * supported yet */ - offs -= subs->transfer_done; + frames -= subs->transfer_done; counts -= subs->transfer_done; urb->iso_frame_desc[i].length = counts * stride; @@ -571,37 +617,35 @@ if (i < ctx->packets) { /* add a transfer delimiter */ urb->iso_frame_desc[i].offset = - offs * stride; + frames * stride; urb->iso_frame_desc[i].length = 0; urb->number_of_packets++; } break; } } - /* finish at the frame boundary at/after the period boundary */ - if (period_elapsed && - (i & (subs->packs_per_ms - 1)) == subs->packs_per_ms - 1) + if (period_elapsed) /* finish at the period boundary */ break; } - if (subs->hwptr_done + offs > runtime->buffer_size) { + bytes = frames * stride; + if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { /* err, the transferred area goes over buffer boundary. */ - unsigned int len = runtime->buffer_size - subs->hwptr_done; + unsigned int bytes1 = + runtime->buffer_size * stride - subs->hwptr_done; memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done * stride, - len * stride); - memcpy(urb->transfer_buffer + len * stride, - runtime->dma_area, - (offs - len) * stride); + runtime->dma_area + subs->hwptr_done, bytes1); + memcpy(urb->transfer_buffer + bytes1, + runtime->dma_area, bytes - bytes1); } else { memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done * stride, - offs * stride); + runtime->dma_area + subs->hwptr_done, bytes); } - subs->hwptr_done += offs; - if (subs->hwptr_done >= runtime->buffer_size) - subs->hwptr_done -= runtime->buffer_size; + subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; +/* runtime->delay += frames; */ spin_unlock_irqrestore(&subs->lock, flags); - urb->transfer_buffer_length = offs * stride; + urb->transfer_buffer_length = bytes; if (period_elapsed) snd_pcm_period_elapsed(subs->pcm_substream); return 0; @@ -609,12 +653,23 @@ /* * process after playback data complete - * - nothing to do + * - decrease the delay count again */ static int retire_playback_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb) { + unsigned long flags; + int stride = runtime->frame_bits >> 3; + int processed = urb->transfer_buffer_length / stride; + + spin_lock_irqsave(&subs->lock, flags); +/* if (processed > runtime->delay) + runtime->delay = 0; + else + runtime->delay -= processed; +*/ + spin_unlock_irqrestore(&subs->lock, flags); return 0; } @@ -654,7 +709,11 @@ /* * complete callback from data urb */ +#if !defined(OLD_USB) && !defined(CONFIG_SND_NEW_IRQ_HANDLER) +static void snd_complete_urb(struct urb *urb, struct pt_regs *regs) +#else static void snd_complete_urb(struct urb *urb) +#endif { struct snd_urb_ctx *ctx = urb->context; struct snd_usb_substream *subs = ctx->subs; @@ -662,7 +721,7 @@ int err = 0; if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) || - ! subs->running || /* can be stopped during retire callback */ + !subs->running || /* can be stopped during retire callback */ (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 || (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { clear_bit(ctx->index, &subs->active_mask); @@ -672,31 +731,6 @@ } } } - - -/* - * complete callback from sync urb - */ -static void snd_complete_sync_urb(struct urb *urb) -{ - struct snd_urb_ctx *ctx = urb->context; - struct snd_usb_substream *subs = ctx->subs; - struct snd_pcm_substream *substream = ctx->subs->pcm_substream; - int err = 0; - - if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) || - ! subs->running || /* can be stopped during retire callback */ - (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 || - (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - clear_bit(ctx->index + 16, &subs->active_mask); - if (err < 0) { - snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - } - } -} - - /* get the physical page pointer at the given offset */ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, unsigned long offset) @@ -733,6 +767,33 @@ /* + * complete callback from sync urb + */ +#if !defined(OLD_USB) && !defined(CONFIG_SND_NEW_IRQ_HANDLER) +static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs) +#else +static void snd_complete_sync_urb(struct urb *urb) +#endif +{ + struct snd_urb_ctx *ctx = urb->context; + struct snd_usb_substream *subs = ctx->subs; + struct snd_pcm_substream *substream = ctx->subs->pcm_substream; + int err = 0; + + if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) || + !subs->running || /* can be stopped during retire callback */ + (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 || + (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + clear_bit(ctx->index + 16, &subs->active_mask); + if (err < 0) { + snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + } + } +} + + +/* * unlink active urbs. */ static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep) @@ -747,16 +808,19 @@ async = !can_sleep && async_unlink; - if (! async && in_interrupt()) + if (!async && in_interrupt()) return 0; for (i = 0; i < subs->nurbs; i++) { if (test_bit(i, &subs->active_mask)) { - if (! test_and_set_bit(i, &subs->unlink_mask)) { + if (!test_and_set_bit(i, &subs->unlink_mask)) { struct urb *u = subs->dataurb[i].urb; - if (async) + if (async) { +#ifdef URB_ASYNC_UNLINK + u->transfer_flags |= URB_ASYNC_UNLINK; +#endif usb_unlink_urb(u); - else + } else usb_kill_urb(u); } } @@ -764,11 +828,14 @@ if (subs->syncpipe) { for (i = 0; i < SYNC_URBS; i++) { if (test_bit(i+16, &subs->active_mask)) { - if (! test_and_set_bit(i+16, &subs->unlink_mask)) { + if (!test_and_set_bit(i+16, &subs->unlink_mask)) { struct urb *u = subs->syncurb[i].urb; - if (async) + if (async) { +#ifdef URB_ASYNC_UNLINK + u->transfer_flags |= URB_ASYNC_UNLINK; +#endif usb_unlink_urb(u); - else + } else usb_kill_urb(u); } } @@ -793,10 +860,6 @@ return "device disabled"; case -EHOSTUNREACH: return "device suspended"; -#ifndef CONFIG_USB_EHCI_SPLIT_ISO - case -ENOSYS: - return "enable CONFIG_USB_EHCI_SPLIT_ISO to play through a hub"; -#endif case -EINVAL: case -EAGAIN: case -EFBIG: @@ -901,18 +964,18 @@ /* - * return the current pcm pointer. just return the hwptr_done value. + * return the current pcm pointer. just based on the hwptr_done value. */ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_usb_substream *subs; - snd_pcm_uframes_t hwptr_done; + unsigned int hwptr_done; subs = (struct snd_usb_substream *)substream->runtime->private_data; spin_lock(&subs->lock); hwptr_done = subs->hwptr_done; spin_unlock(&subs->lock); - return hwptr_done; + return hwptr_done / (substream->runtime->frame_bits >> 3); } @@ -1007,9 +1070,9 @@ 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) @@ -1040,19 +1103,19 @@ packs_per_ms = 8 >> subs->datainterval; else packs_per_ms = 1; - 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; urb_packs *= packs_per_ms; + if (subs->syncpipe) + urb_packs = min(urb_packs, 1U << subs->syncinterval); /* 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); @@ -1061,13 +1124,17 @@ minsize -= minsize >> 3; minsize = max(minsize, 1u); total_packs = (period_bytes + minsize - 1) / minsize; - /* round up to multiple of packs_per_ms */ - 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) { + total_packs = 2; + } 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 { + while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) + urb_packs >>= 1; total_packs = MAX_URBS * urb_packs; } subs->nurbs = (total_packs + urb_packs - 1) / urb_packs; @@ -1075,31 +1142,11 @@ /* 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 */ @@ -1107,17 +1154,18 @@ 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 */ u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); - if (! u->urb) + if (!u->urb) goto out_of_memory; u->urb->transfer_buffer = usb_buffer_alloc(subs->dev, u->buffer_size, GFP_KERNEL, &u->urb->transfer_dma); - if (! u->urb->transfer_buffer) + if (!u->urb->transfer_buffer) goto out_of_memory; u->urb->pipe = subs->datapipe; u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; @@ -1130,7 +1178,7 @@ /* allocate and initialize sync urbs */ subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4, GFP_KERNEL, &subs->sync_dma); - if (! subs->syncbuf) + if (!subs->syncbuf) goto out_of_memory; for (i = 0; i < SYNC_URBS; i++) { struct snd_urb_ctx *u = &subs->syncurb[i]; @@ -1138,10 +1186,12 @@ u->subs = subs; u->packets = 1; u->urb = usb_alloc_urb(1, GFP_KERNEL); - if (! u->urb) + if (!u->urb) goto out_of_memory; u->urb->transfer_buffer = subs->syncbuf + i * 4; +#ifdef HAVE_USB_BUFFERS u->urb->transfer_dma = subs->sync_dma + i * 4; +#endif u->urb->transfer_buffer_length = 4; u->urb->pipe = subs->syncpipe; u->urb->transfer_flags = URB_ISO_ASAP | @@ -1265,14 +1315,14 @@ 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 */ } @@ -1286,6 +1336,47 @@ } /* + * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device, + * not for interface. + */ +static void set_format_emu_quirk(struct snd_usb_substream *subs, + struct audioformat *fmt) +{ + unsigned char emu_samplerate_id = 0; + + /* When capture is active + * sample rate shouldn't be changed + * by playback substream + */ + if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { + if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1) + return; + } + + switch (fmt->rate_min) { + case 48000: + emu_samplerate_id = EMU_QUIRK_SR_48000HZ; + break; + case 88200: + emu_samplerate_id = EMU_QUIRK_SR_88200HZ; + break; + case 96000: + emu_samplerate_id = EMU_QUIRK_SR_96000HZ; + break; + case 176400: + emu_samplerate_id = EMU_QUIRK_SR_176400HZ; + break; + case 192000: + emu_samplerate_id = EMU_QUIRK_SR_192000HZ; + break; + default: + emu_samplerate_id = EMU_QUIRK_SR_44100HZ; + break; + } + snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id); +} + +/* * find a matching format and set up the interface */ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) @@ -1299,17 +1390,23 @@ int err; iface = usb_ifnum_to_if(dev, fmt->iface); - snd_assert(iface, return -EINVAL); + if (WARN_ON(!iface)) + return -EINVAL; alts = &iface->altsetting[fmt->altset_idx]; altsd = get_iface_desc(alts); - snd_assert(altsd->bAlternateSetting == fmt->altsetting, return -EINVAL); + if (WARN_ON(altsd->bAlternateSetting != fmt->altsetting)) + return -EINVAL; if (fmt == subs->cur_audiofmt) return 0; /* close the old interface */ if (subs->interface >= 0 && subs->interface != fmt->iface) { - usb_set_interface(subs->dev, subs->interface, 0); + if (usb_set_interface(subs->dev, subs->interface, 0) < 0) { + snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n", + dev->devnum, fmt->iface, fmt->altsetting); + return -EIO; + } subs->interface = -1; subs->format = 0; } @@ -1332,12 +1429,7 @@ subs->datapipe = usb_sndisocpipe(dev, ep); else subs->datapipe = usb_rcvisocpipe(dev, ep); - if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH && - get_endpoint(alts, 0)->bInterval >= 1 && - get_endpoint(alts, 0)->bInterval <= 4) - subs->datainterval = get_endpoint(alts, 0)->bInterval - 1; - else - subs->datainterval = 0; + subs->datainterval = fmt->datainterval; subs->syncpipe = subs->syncinterval = 0; subs->maxpacksize = fmt->maxpacksize; subs->fill_max = 0; @@ -1397,10 +1489,20 @@ subs->cur_audiofmt = fmt; + switch (subs->stream->chip->usb_id) { + case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ + case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ + case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ + set_format_emu_quirk(subs, fmt); + break; + } + #if 0 - printk("setting done: format = %d, rate = %d, channels = %d\n", - fmt->format, fmt->rate, fmt->channels); - printk(" datapipe = 0x%0x, syncpipe = 0x%0x\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(KERN_DEBUG + " datapipe = 0x%0x, syncpipe = 0x%0x\n", subs->datapipe, subs->syncpipe); #endif @@ -1425,8 +1527,12 @@ unsigned int channels, rate, format; int ret, changed; +/* ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); +*/ ret = snd_pcm_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); + if (ret < 0) return ret; @@ -1434,8 +1540,8 @@ rate = params_rate(hw_params); 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", + if (!fmt) { + snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n", format, rate, channels); return -EINVAL; } @@ -1483,7 +1589,9 @@ subs->period_bytes = 0; if (!subs->stream->chip->shutdown) release_substream_urbs(subs, 0); +/* return snd_pcm_lib_free_vmalloc_buffer(substream); */ return snd_pcm_free_vmalloc_buffer(substream); + } /* @@ -1509,6 +1617,7 @@ subs->hwptr_done = 0; subs->transfer_done = 0; subs->phase = 0; +/* runtime->delay = 0; */ /* clear urbs (to be sure) */ deactivate_urbs(subs, 0, 1); @@ -1548,14 +1657,18 @@ #define hwc_debug(fmt, args...) /**/ #endif -static int hw_check_valid_format(struct snd_pcm_hw_params *params, struct audioformat *fp) +static int hw_check_valid_format(struct snd_usb_substream *subs, + struct snd_pcm_hw_params *params, + struct audioformat *fp) { struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_mask *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_interval *pt = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME); + unsigned int ptime; /* check the format */ - if (! snd_mask_test(fmts, fp->format)) { + if (!snd_mask_test(fmts, fp->format)) { hwc_debug(" > check: no supported format %d\n", fp->format); return 0; } @@ -1573,6 +1686,14 @@ hwc_debug(" > check: rate_max %d < min %d\n", fp->rate_max, it->min); return 0; } + /* check whether the period time is >= the data packet interval */ + if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) { + ptime = 125 * (1 << fp->datainterval); + if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { + hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); + return 0; + } + } return 1; } @@ -1591,7 +1712,7 @@ list_for_each(p, &subs->fmt_list) { struct audioformat *fp; fp = list_entry(p, struct audioformat, list); - if (! hw_check_valid_format(params, fp)) + if (!hw_check_valid_format(subs, params, fp)) continue; if (changed++) { if (rmin > fp->rate_min) @@ -1604,7 +1725,7 @@ } } - if (! changed) { + if (!changed) { hwc_debug(" --> get empty\n"); it->empty = 1; return -EINVAL; @@ -1645,7 +1766,7 @@ list_for_each(p, &subs->fmt_list) { struct audioformat *fp; fp = list_entry(p, struct audioformat, list); - if (! hw_check_valid_format(params, fp)) + if (!hw_check_valid_format(subs, params, fp)) continue; if (changed++) { if (rmin > fp->channels) @@ -1658,7 +1779,7 @@ } } - if (! changed) { + if (!changed) { hwc_debug(" --> get empty\n"); it->empty = 1; return -EINVAL; @@ -1698,7 +1819,7 @@ list_for_each(p, &subs->fmt_list) { struct audioformat *fp; fp = list_entry(p, struct audioformat, list); - if (! hw_check_valid_format(params, fp)) + if (!hw_check_valid_format(subs, params, fp)) continue; fbits |= (1ULL << fp->format); } @@ -1707,7 +1828,7 @@ oldbits[1] = fmt->bits[1]; fmt->bits[0] &= (u32)fbits; fmt->bits[1] &= (u32)(fbits >> 32); - if (! fmt->bits[0] && ! fmt->bits[1]) { + if (!fmt->bits[0] && !fmt->bits[1]) { hwc_debug(" --> get empty\n"); return -EINVAL; } @@ -1716,91 +1837,42 @@ return changed; } -#define MAX_MASK 64 - -/* - * check whether the registered audio formats need special hw-constraints - */ -static int check_hw_params_convention(struct snd_usb_substream *subs) +static int hw_rule_period_time(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { - int i; - u32 *channels; - u32 *rates; - u32 cmaster, rmaster; - u32 rate_min = 0, rate_max = 0; - struct list_head *p; - int err = 1; + struct snd_usb_substream *subs = rule->private; + struct audioformat *fp; + struct snd_interval *it; + unsigned char min_datainterval; + unsigned int pmin; + int changed; - channels = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL); - rates = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL); - - list_for_each(p, &subs->fmt_list) { - struct audioformat *f; - f = list_entry(p, struct audioformat, list); - /* unconventional channels? */ - if (f->channels > 32) - goto __out; - /* continuous rate min/max matches? */ - if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) { - if (rate_min && f->rate_min != rate_min) - goto __out; - if (rate_max && f->rate_max != rate_max) - goto __out; - rate_min = f->rate_min; - rate_max = f->rate_max; - } - /* combination of continuous rates and fixed rates? */ - if (rates[f->format] & SNDRV_PCM_RATE_CONTINUOUS) { - if (f->rates != rates[f->format]) - goto __out; - } - if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) { - if (rates[f->format] && rates[f->format] != f->rates) - goto __out; - } - channels[f->format] |= (1 << f->channels); - rates[f->format] |= f->rates; - /* needs knot? */ - if (f->needs_knot) - goto __out; + it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME); + hwc_debug("hw_rule_period_time: (%u,%u)\n", it->min, it->max); + min_datainterval = 0xff; + list_for_each_entry(fp, &subs->fmt_list, list) { + if (!hw_check_valid_format(subs, params, fp)) + continue; + min_datainterval = min(min_datainterval, fp->datainterval); } - /* check whether channels and rates match for all formats */ - cmaster = rmaster = 0; - for (i = 0; i < MAX_MASK; i++) { - if (cmaster != channels[i] && cmaster && channels[i]) - goto __out; - if (rmaster != rates[i] && rmaster && rates[i]) - goto __out; - if (channels[i]) - cmaster = channels[i]; - if (rates[i]) - rmaster = rates[i]; + if (min_datainterval == 0xff) { + hwc_debug(" --> get emtpy\n"); + it->empty = 1; + return -EINVAL; } - /* check whether channels match for all distinct rates */ - memset(channels, 0, MAX_MASK * sizeof(u32)); - list_for_each(p, &subs->fmt_list) { - struct audioformat *f; - f = list_entry(p, struct audioformat, list); - if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) - continue; - for (i = 0; i < 32; i++) { - if (f->rates & (1 << i)) - channels[i] |= (1 << f->channels); - } + pmin = 125 * (1 << min_datainterval); + changed = 0; + if (it->min < pmin) { + it->min = pmin; + it->openmin = 0; + changed = 1; } - cmaster = 0; - for (i = 0; i < 32; i++) { - if (cmaster != channels[i] && cmaster && channels[i]) - goto __out; - if (channels[i]) - cmaster = channels[i]; + if (snd_interval_checkempty(it)) { + it->empty = 1; + return -EINVAL; } - err = 0; - - __out: - kfree(channels); - kfree(rates); - return err; + hwc_debug(" --> (%u,%u) (changed = %d)\n", it->min, it->max, changed); + return changed; } /* @@ -1817,7 +1889,7 @@ if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) return 0; count += fp->nr_rates; - if (fp->needs_knot) + if (fp->rates & SNDRV_PCM_RATE_KNOT) needs_knot = 1; } if (!needs_knot) @@ -1848,6 +1920,8 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) { struct list_head *p; + unsigned int pt, ptmin; + int param_period_time_if_needed; int err; runtime->hw.formats = subs->formats; @@ -1857,6 +1931,7 @@ runtime->hw.channels_min = 256; runtime->hw.channels_max = 0; runtime->hw.rates = 0; + ptmin = UINT_MAX; /* check min/max rates and channels */ list_for_each(p, &subs->fmt_list) { struct audioformat *fp; @@ -1875,39 +1950,54 @@ runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = fp->frame_size; } + pt = 125 * (1 << fp->datainterval); + ptmin = min(ptmin, pt); } - /* set the period time minimum 1ms */ - /* FIXME: high-speed mode allows 125us minimum period, but many parts - * in the current code assume the 1ms period. - */ + param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; + if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH) + /* full speed devices have fixed data packet interval */ + ptmin = 1000; + if (ptmin == 1000) + /* if period time doesn't go below 1 ms, no rules needed */ + param_period_time_if_needed = -1; snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, - 1000 * MIN_PACKS_URB, - /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX); + ptmin, UINT_MAX); - if (check_hw_params_convention(subs)) { - hwc_debug("setting extra hw constraints...\n"); - if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - hw_rule_rate, subs, - SNDRV_PCM_HW_PARAM_FORMAT, - SNDRV_PCM_HW_PARAM_CHANNELS, - -1)) < 0) + if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + hw_rule_rate, subs, + SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_HW_PARAM_CHANNELS, + param_period_time_if_needed, + -1)) < 0) + return err; + if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + hw_rule_channels, subs, + SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_HW_PARAM_RATE, + param_period_time_if_needed, + -1)) < 0) + return err; + if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, + hw_rule_format, subs, + SNDRV_PCM_HW_PARAM_RATE, + SNDRV_PCM_HW_PARAM_CHANNELS, + param_period_time_if_needed, + -1)) < 0) + return err; + if (param_period_time_if_needed >= 0) { + err = snd_pcm_hw_rule_add(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_TIME, + hw_rule_period_time, subs, + SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_RATE, + -1); + if (err < 0) return err; - if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - hw_rule_channels, subs, - SNDRV_PCM_HW_PARAM_FORMAT, - SNDRV_PCM_HW_PARAM_RATE, - -1)) < 0) - return err; - if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, - hw_rule_format, subs, - SNDRV_PCM_HW_PARAM_RATE, - SNDRV_PCM_HW_PARAM_CHANNELS, - -1)) < 0) - return err; - if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) - return err; } + if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) + return err; return 0; } @@ -1930,7 +2020,7 @@ struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_usb_substream *subs = &as->substream[direction]; - if (subs->interface >= 0) { + if (!as->chip->shutdown && subs->interface >= 0) { usb_set_interface(subs->dev, subs->interface, 0); subs->interface = -1; } @@ -1967,6 +2057,7 @@ .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_pcm_playback_trigger, .pointer = snd_usb_pcm_pointer, +/* .page = snd_pcm_lib_get_vmalloc_page, */ .page = snd_pcm_get_vmalloc_page, }; @@ -1979,6 +2070,7 @@ .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_pcm_capture_trigger, .pointer = snd_usb_pcm_pointer, + /*.page = snd_pcm_lib_get_vmalloc_page, */ .page = snd_pcm_get_vmalloc_page, }; @@ -2057,8 +2149,13 @@ if (!buf) return -ENOMEM; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) err = usb_control_msg(dev, pipe, request, requesttype, value, index, buf, size, timeout); +#else + err = usb_control_msg(dev, pipe, request, requesttype, + value, index, buf, size, timeout * HZ / 1000); +#endif if (size > 0) { memcpy(data, buf, size); kfree(buf); @@ -2071,10 +2168,20 @@ * entry point for linux usb interface */ +#ifndef OLD_USB static int usb_audio_probe(struct usb_interface *intf, const struct usb_device_id *id); static void usb_audio_disconnect(struct usb_interface *intf); +#ifdef CONFIG_PM +static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message); +static int usb_audio_resume(struct usb_interface *intf); +#else +#define usb_audio_suspend NULL +#define usb_audio_resume NULL +#endif +#endif + static struct usb_device_id usb_audio_ids [] = { #include "usbquirks.h" { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), @@ -2086,9 +2193,19 @@ MODULE_DEVICE_TABLE (usb, usb_audio_ids); static struct usb_driver usb_audio_driver = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70) && LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) /* FIXME: find right number */ + .owner = THIS_MODULE, +#endif .name = "snd-usb-audio", .probe = usb_audio_probe, .disconnect = usb_audio_disconnect, +#ifndef OLD_USB + .suspend = usb_audio_suspend, + .resume = usb_audio_resume, +#endif +#ifdef OLD_USB + .driver_list = LIST_HEAD_INIT(usb_audio_driver.driver_list), +#endif .id_table = usb_audio_ids, }; @@ -2110,6 +2227,8 @@ 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: %s\n", + snd_pcm_format_name(fp->format)); */ snd_iprintf(buffer, " Format: 0x%x\n", fp->format); snd_iprintf(buffer, " Channels: %d\n", fp->channels); snd_iprintf(buffer, " Endpoint: %d %s (%s)\n", @@ -2129,8 +2248,11 @@ } snd_iprintf(buffer, "\n"); } + if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) + snd_iprintf(buffer, " Data packet interval: %d us\n", + 125 * (1 << fp->datainterval)); // 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); } } @@ -2181,7 +2303,7 @@ struct snd_card *card = stream->chip->card; sprintf(name, "stream%d", stream->pcm_index); - if (! snd_card_proc_new(card, name, &entry)) + if (!snd_card_proc_new(card, name, &entry)) snd_info_set_text_ops(entry, stream, proc_pcm_format_read); } @@ -2207,10 +2329,19 @@ subs->stream = as; subs->direction = stream; subs->dev = as->chip->dev; - if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) + subs->txfr_quirk = as->chip->txfr_quirk; + if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { subs->ops = audio_urb_ops[stream]; - else + } else { subs->ops = audio_urb_ops_high_speed[stream]; + switch (as->chip->usb_id) { + case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ + case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ + case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ + subs->ops.retire_sync = retire_playback_sync_urb_hs_emu; + break; + } + } snd_pcm_set_ops(as->pcm, stream, stream == SNDRV_PCM_STREAM_PLAYBACK ? &snd_usb_playback_ops : &snd_usb_capture_ops); @@ -2230,7 +2361,7 @@ { struct list_head *p, *n; - if (! subs->num_formats) + if (!subs->num_formats) return; /* not initialized */ list_for_each_safe(p, n, &subs->fmt_list) { struct audioformat *fp = list_entry(p, struct audioformat, list); @@ -2280,7 +2411,7 @@ if (as->fmt_type != fp->fmt_type) continue; subs = &as->substream[stream]; - if (! subs->endpoint) + if (!subs->endpoint) continue; if (subs->endpoint == fp->endpoint) { list_add_tail(&fp->list, &subs->fmt_list); @@ -2306,7 +2437,7 @@ /* create a new pcm */ as = kzalloc(sizeof(*as), GFP_KERNEL); - if (! as) + if (!as) return -ENOMEM; as->pcm_index = chip->pcm_devs; as->chip = chip; @@ -2350,7 +2481,9 @@ return 1; break; case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ - return 1; + if (device_setup[chip->index] == 0x00 || + fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3) + return 1; } return 0; } @@ -2413,11 +2546,12 @@ } break; case USB_AUDIO_FORMAT_PCM8: - /* Dallas DS4201 workaround */ + pcm_format = SNDRV_PCM_FORMAT_U8; + + /* Dallas DS4201 workaround: it advertises U8 format, but really + supports S8. */ if (chip->usb_id == USB_ID(0x04fa, 0x4201)) pcm_format = SNDRV_PCM_FORMAT_S8; - else - pcm_format = SNDRV_PCM_FORMAT_U8; break; case USB_AUDIO_FORMAT_IEEE_FLOAT: pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE; @@ -2451,7 +2585,7 @@ unsigned char *fmt, int offset) { int nr_rates = fmt[offset]; - int found; + if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", chip->dev->devnum, fp->iface, fp->altsetting); @@ -2462,52 +2596,38 @@ /* * build the rate table and bitmap flags */ - int r, idx, c; - unsigned int nonzero_rates = 0; - /* this table corresponds to the SNDRV_PCM_RATE_XXX bit */ - static unsigned int conv_rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, - 64000, 88200, 96000, 176400, 192000 - }; + int r, idx; + fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); if (fp->rate_table == NULL) { snd_printk(KERN_ERR "cannot malloc\n"); return -1; } - fp->needs_knot = 0; - fp->nr_rates = nr_rates; - fp->rate_min = fp->rate_max = combine_triple(&fmt[8]); + fp->nr_rates = 0; + fp->rate_min = fp->rate_max = 0; for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { unsigned int rate = combine_triple(&fmt[idx]); + if (!rate) + continue; /* C-Media CM6501 mislabels its 96 kHz altsetting */ if (rate == 48000 && nr_rates == 1 && - chip->usb_id == USB_ID(0x0d8c, 0x0201) && + (chip->usb_id == USB_ID(0x0d8c, 0x0201) || + chip->usb_id == USB_ID(0x0d8c, 0x0102)) && fp->altsetting == 5 && fp->maxpacksize == 392) rate = 96000; - fp->rate_table[r] = rate; - nonzero_rates |= rate; - if (rate < fp->rate_min) + fp->rate_table[fp->nr_rates] = rate; + if (!fp->rate_min || rate < fp->rate_min) fp->rate_min = rate; - else if (rate > fp->rate_max) + if (!fp->rate_max || rate > fp->rate_max) fp->rate_max = rate; - found = 0; - for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) { - if (rate == conv_rates[c]) { - found = 1; - fp->rates |= (1 << c); - break; - } - } - if (!found) - fp->needs_knot = 1; + fp->rates |= snd_pcm_rate_to_rate_bit(rate); + fp->nr_rates++; } - if (!nonzero_rates) { + if (!fp->nr_rates) { hwc_debug("All rates were zero. Skipping format!\n"); return -1; } - if (fp->needs_knot) - fp->rates |= SNDRV_PCM_RATE_KNOT; } else { /* continuous rates */ fp->rates = SNDRV_PCM_RATE_CONTINUOUS; @@ -2530,7 +2650,18 @@ * but we give normal PCM format to get the existing * apps working... */ - pcm_format = SNDRV_PCM_FORMAT_S16_LE; + switch (chip->usb_id) { + + case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ + if (device_setup[chip->index] == 0x00 && + fp->altsetting == 6) + pcm_format = SNDRV_PCM_FORMAT_S16_BE; + else + pcm_format = SNDRV_PCM_FORMAT_S16_LE; + break; + default: + pcm_format = SNDRV_PCM_FORMAT_S16_LE; + } } else { pcm_format = parse_audio_format_i_type(chip, fp, format, fmt); if (pcm_format < 0) @@ -2563,7 +2694,7 @@ 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; @@ -2614,6 +2745,17 @@ return 0; } +static unsigned char parse_datainterval(struct snd_usb_audio *chip, + struct usb_host_interface *alts) +{ + if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH && + get_endpoint(alts, 0)->bInterval >= 1 && + get_endpoint(alts, 0)->bInterval <= 4) + return get_endpoint(alts, 0)->bInterval - 1; + else + return 0; +} + static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, int iface, int altno); static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) @@ -2624,14 +2766,25 @@ struct usb_interface_descriptor *altsd; int i, altno, err, stream; int format; - struct audioformat *fp; + struct audioformat *fp = NULL; unsigned char *fmt, *csep; + int num; dev = chip->dev; /* parse the interface's altsettings */ iface = usb_ifnum_to_if(dev, iface_no); - for (i = 0; i < iface->num_altsetting; i++) { + + num = iface->num_altsetting; + + /* + * Dallas DS4201 workaround: It presents 5 altsettings, but the last + * one misses syncpipe, and does not produce any sound. + */ + if (chip->usb_id == USB_ID(0x04fa, 0x4201)) + num = 4; + + for (i = 0; i < num; i++) { alts = &iface->altsetting[i]; altsd = get_iface_desc(alts); /* skip invalid one */ @@ -2640,7 +2793,11 @@ (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING && altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) || altsd->bNumEndpoints < 1 || +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0) +#else + get_endpoint(alts, 0)->wMaxPacketSize == 0) +#endif continue; /* must be isochronous */ if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != @@ -2686,6 +2843,22 @@ continue; } + /* + * Blue Microphones workaround: The last altsetting is identical + * with the previous one, except for a larger packet size, but + * is actually a mislabeled two-channel setting; ignore it. + */ + if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 && + fp && fp->altsetting == 1 && fp->channels == 1 && + fp->format == SNDRV_PCM_FORMAT_S16_LE && +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) + le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == +#else + get_endpoint(alts, 0)->wMaxPacketSize == +#endif + fp->maxpacksize * 2) + continue; + csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT); /* Creamware Noah has this descriptor after the 2nd endpoint */ if (!csep && altsd->bNumEndpoints >= 2) @@ -2708,7 +2881,12 @@ fp->altset_idx = i; fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; + fp->datainterval = parse_datainterval(chip, alts); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); +#else + fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize; +#endif if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) * (fp->maxpacksize & 0x7ff); @@ -2750,7 +2928,7 @@ 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); @@ -2830,7 +3008,9 @@ if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) { - if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) { + int err = snd_usbmidi_create(chip->card, iface, + &chip->midi_list, NULL); + if (err < 0) { snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j); continue; } @@ -2844,6 +3024,10 @@ /* skip non-supported classes */ continue; } + if (snd_usb_get_speed(dev) == USB_SPEED_LOW) { + snd_printk(KERN_ERR "low speed audio streaming not supported\n"); + continue; + } if (! parse_audio_endpoints(chip, j)) { usb_set_interface(dev, j, 0); /* reset the current interface */ usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); @@ -2863,7 +3047,7 @@ struct audioformat *fp; struct usb_host_interface *alts; int stream, err; - int *rate_table = NULL; + unsigned *rate_table = NULL; fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL); if (! fp) { @@ -2895,6 +3079,12 @@ return -EINVAL; } alts = &iface->altsetting[fp->altset_idx]; + fp->datainterval = parse_datainterval(chip, alts); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) + fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); +#else + fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize; +#endif usb_set_interface(chip->dev, fp->iface, 0); init_usb_pitch(chip->dev, fp->iface, alts, fp); init_usb_sample_rate(chip->dev, fp->iface, alts, fp, fp->rate_max); @@ -2926,12 +3116,12 @@ } /* - * Create a stream for an Edirol UA-700/UA-25 interface. The only way - * to detect the sample rate is by looking at wMaxPacketSize. + * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface. + * The only way to detect the sample rate is by looking at wMaxPacketSize. */ -static int create_ua700_ua25_quirk(struct snd_usb_audio *chip, - struct usb_interface *iface, - const struct snd_usb_audio_quirk *quirk) +static int create_uaxx_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk) { static const struct audioformat ua_format = { .format = SNDRV_PCM_FORMAT_S24_3LE, @@ -2946,8 +3136,8 @@ struct audioformat *fp; int stream, err; - /* both PCM and MIDI interfaces have 2 altsettings */ - if (iface->num_altsetting != 2) + /* both PCM and MIDI interfaces have 2 or more altsettings */ + if (iface->num_altsetting < 2) return -ENXIO; alts = &iface->altsetting[1]; altsd = get_iface_desc(alts); @@ -2961,20 +3151,19 @@ .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &ua700_ep }; - static const struct snd_usb_midi_endpoint_info ua25_ep = { + static const struct snd_usb_midi_endpoint_info uaxx_ep = { .out_cables = 0x0001, .in_cables = 0x0001 }; - static const struct snd_usb_audio_quirk ua25_quirk = { + static const struct snd_usb_audio_quirk uaxx_quirk = { .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = &ua25_ep + .data = &uaxx_ep }; - if (chip->usb_id == USB_ID(0x0582, 0x002b)) - return snd_usb_create_midi_interface(chip, iface, - &ua700_quirk); - else - return snd_usb_create_midi_interface(chip, iface, - &ua25_quirk); + const struct snd_usb_audio_quirk *quirk = + chip->usb_id == USB_ID(0x0582, 0x002b) + ? &ua700_quirk : &uaxx_quirk; + return snd_usbmidi_create(chip->card, iface, + &chip->midi_list, quirk); } if (altsd->bNumEndpoints != 1) @@ -2988,7 +3177,12 @@ fp->iface = altsd->bInterfaceNumber; fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; + fp->datainterval = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); +#else + fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize; +#endif switch (fp->maxpacksize) { case 0x120: @@ -3055,7 +3249,12 @@ fp->iface = altsd->bInterfaceNumber; fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; + fp->datainterval = parse_datainterval(chip, alts); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); +#else + fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize; +#endif fp->rate_max = fp->rate_min = combine_triple(&alts->extra[8]); stream = (fp->endpoint & USB_DIR_IN) @@ -3070,58 +3269,6 @@ return 0; } -/* - * Create a stream for an Edirol UA-101 interface. - * Copy, paste and modify from Edirol UA-1000 - */ -static int create_ua101_quirk(struct snd_usb_audio *chip, - struct usb_interface *iface, - const struct snd_usb_audio_quirk *quirk) -{ - static const struct audioformat ua101_format = { - .format = SNDRV_PCM_FORMAT_S32_LE, - .fmt_type = USB_FORMAT_TYPE_I, - .altsetting = 1, - .altset_idx = 1, - .attributes = 0, - .rates = SNDRV_PCM_RATE_CONTINUOUS, - }; - struct usb_host_interface *alts; - struct usb_interface_descriptor *altsd; - struct audioformat *fp; - int stream, err; - - if (iface->num_altsetting != 2) - return -ENXIO; - alts = &iface->altsetting[1]; - altsd = get_iface_desc(alts); - if (alts->extralen != 18 || alts->extra[1] != USB_DT_CS_INTERFACE || - altsd->bNumEndpoints != 1) - return -ENXIO; - - fp = kmemdup(&ua101_format, sizeof(*fp), GFP_KERNEL); - if (!fp) - return -ENOMEM; - - fp->channels = alts->extra[11]; - fp->iface = altsd->bInterfaceNumber; - fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; - fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; - fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); - fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]); - - stream = (fp->endpoint & USB_DIR_IN) - ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - err = add_audio_endpoint(chip, stream, fp); - if (err < 0) { - kfree(fp); - return err; - } - /* FIXME: playback must be synchronized to capture */ - usb_set_interface(chip->dev, fp->iface, 0); - return 0; -} - static int snd_usb_create_quirk(struct snd_usb_audio *chip, struct usb_interface *iface, const struct snd_usb_audio_quirk *quirk); @@ -3159,7 +3306,19 @@ return 0; } +/* + * Allow alignment on audio sub-slot (channel samples) rather than + * on audio slots (audio frames) + */ +static int create_align_transfer_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk) +{ + chip->txfr_quirk = 1; + return 1; /* Continue with creating streams and mixer */ +} + /* * boot quirks */ @@ -3172,8 +3331,13 @@ struct usb_host_config *config = dev->actconfig; int err; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD || le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_NEW) { +#else + if (get_cfg_desc(config)->wTotalLength == EXTIGY_FIRMWARE_SIZE_OLD || + get_cfg_desc(config)->wTotalLength == EXTIGY_FIRMWARE_SIZE_NEW) { +#endif snd_printdd("sending Extigy boot sequence...\n"); /* Send message to force it to reconnect with full interface. */ err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0), @@ -3185,8 +3349,13 @@ if (err < 0) snd_printdd("error usb_get_descriptor: %d\n", err); err = usb_reset_configuration(dev); if (err < 0) snd_printdd("error usb_reset_configuration: %d\n", err); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) snd_printdd("extigy_boot: new boot length = %d\n", le16_to_cpu(get_cfg_desc(config)->wTotalLength)); +#else + snd_printdd("extigy_boot: new boot length = %d\n", + get_cfg_desc(config)->wTotalLength); +#endif return -ENODEV; /* quit this anyway */ } return 0; @@ -3194,6 +3363,8 @@ static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) { +/* The pre-2.6.13 EHCI driver blows up when doing high speed iso transfers */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) u8 buf = 1; snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a, @@ -3205,6 +3376,7 @@ 1, 2000, NULL, 0, 1000); return -ENODEV; } +#endif return 0; } @@ -3233,7 +3405,26 @@ return snd_usb_cm106_write_int_reg(dev, 2, 0x8004); } +/* + * C-Media CM6206 is based on CM106 with two additional + * registers that are not documented in the data sheet. + * Values here are chosen based on sniffing USB traffic + * under Windows. + */ +static int snd_usb_cm6206_boot_quirk(struct usb_device *dev) +{ + int err, reg; + int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000}; + for (reg = 0; reg < ARRAY_SIZE(val); reg++) { + err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]); + if (err < 0) + return err; + } + + return err; +} + /* * Setup quirks */ @@ -3251,6 +3442,11 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, int iface, int altno) { + /* Reset ALL ifaces to 0 altsetting. + * Call it for every possible altsetting of every interface. + */ + usb_set_interface(chip->dev, iface, 0); + if (device_setup[chip->index] & AUDIOPHILE_SET) { if ((device_setup[chip->index] & AUDIOPHILE_SET_DTS) && altno != 6) @@ -3274,6 +3470,13 @@ return 0; /* keep this altsetting */ } +static int create_any_midi_quirk(struct snd_usb_audio *chip, + struct usb_interface *intf, + const struct snd_usb_audio_quirk *quirk) +{ + return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk); +} + /* * audio-interface quirks * @@ -3291,19 +3494,19 @@ static const quirk_func_t quirk_funcs[] = { [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk, [QUIRK_COMPOSITE] = create_composite_quirk, - [QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface, - [QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface, - [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface, - [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface, - [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface, - [QUIRK_MIDI_RAW] = snd_usb_create_midi_interface, - [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, - [QUIRK_MIDI_CME] = snd_usb_create_midi_interface, + [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk, + [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk, + [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, + [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, + [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, + [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, + [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, + [QUIRK_MIDI_CME] = create_any_midi_quirk, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, - [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk, [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, - [QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk, + [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, + [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk }; if (quirk->type < QUIRK_TYPE_COUNT) { @@ -3321,14 +3524,14 @@ static void proc_audio_usbbus_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_usb_audio *chip = entry->private_data; - if (! chip->shutdown) + if (!chip->shutdown) snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum); } static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_usb_audio *chip = entry->private_data; - if (! chip->shutdown) + if (!chip->shutdown) snd_iprintf(buffer, "%04x:%04x\n", USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); @@ -3337,9 +3540,9 @@ static void snd_usb_audio_create_proc(struct snd_usb_audio *chip) { struct snd_info_entry *entry; - if (! snd_card_proc_new(chip->card, "usbbus", &entry)) + if (!snd_card_proc_new(chip->card, "usbbus", &entry)) snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read); - if (! snd_card_proc_new(chip->card, "usbid", &entry)) + if (!snd_card_proc_new(chip->card, "usbid", &entry)) snd_info_set_text_ops(entry, chip, proc_audio_usbid_read); } @@ -3352,7 +3555,6 @@ static int snd_usb_audio_free(struct snd_usb_audio *chip) { - usb_chip[chip->index] = NULL; kfree(chip); return 0; } @@ -3381,12 +3583,19 @@ *rchip = NULL; - if (snd_usb_get_speed(dev) != USB_SPEED_FULL && + if (snd_usb_get_speed(dev) != USB_SPEED_LOW && + snd_usb_get_speed(dev) != USB_SPEED_FULL && snd_usb_get_speed(dev) != USB_SPEED_HIGH) { snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); return -ENXIO; } +/* 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 err; + } +*/ card = snd_card_new(index[idx], id[idx], THIS_MODULE, 0); if (card == NULL) { snd_printk(KERN_ERR "cannot create card instance %d\n", idx); @@ -3402,8 +3611,13 @@ chip->index = idx; chip->dev = dev; chip->card = card; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); +#else + chip->usb_id = USB_ID(dev->descriptor.idVendor, + dev->descriptor.idProduct); +#endif INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->midi_list); INIT_LIST_HEAD(&chip->mixer_list); @@ -3455,7 +3669,9 @@ usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); strlcat(card->longname, - snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : ", high speed", + snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" : + snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : + ", high speed", sizeof(card->longname)); snd_usb_audio_create_proc(chip); @@ -3488,8 +3704,12 @@ alts = &intf->altsetting[0]; ifnum = get_iface_desc(alts)->bInterfaceNumber; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); +#else + id = USB_ID(dev->descriptor.idVendor, dev->descriptor.idProduct); +#endif if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) goto __err_val; @@ -3512,6 +3732,12 @@ goto __err_val; } + /* C-Media CM6206 / CM106-Like Sound Device */ + if (id == USB_ID(0x0d8c, 0x0102)) { + if (snd_usb_cm6206_boot_quirk(dev) < 0) + goto __err_val; + } + /* * found a config. now register to ALSA */ @@ -3543,12 +3769,13 @@ snd_card_set_dev(chip->card, &intf->dev); break; } - if (! chip) { - snd_printk(KERN_ERR "no available usb audio device\n"); + if (!chip) { + printk(KERN_ERR "no available usb audio device\n"); goto __error; } } + chip->txfr_quirk = 0; err = 1; /* continue */ if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { /* need some special handlings */ @@ -3559,7 +3786,7 @@ if (err > 0) { /* create normal USB audio interfaces */ if (snd_usb_create_streams(chip, ifnum) < 0 || - snd_usb_create_mixer(chip, ifnum) < 0) { + snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) { goto __error; } } @@ -3614,6 +3841,7 @@ list_for_each(p, &chip->mixer_list) { snd_usb_mixer_disconnect(p); } + usb_chip[chip->index] = NULL; mutex_unlock(®ister_mutex); snd_card_free_when_closed(card); } else { @@ -3621,6 +3849,7 @@ } } +#ifndef OLD_USB /* * new 2.5 USB kernel API */ @@ -3630,7 +3859,7 @@ void *chip; chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id); if (chip) { - dev_set_drvdata(&intf->dev, chip); + usb_set_intfdata(intf, chip); return 0; } else return -EIO; @@ -3639,13 +3868,53 @@ static void usb_audio_disconnect(struct usb_interface *intf) { snd_usb_audio_disconnect(interface_to_usbdev(intf), - dev_get_drvdata(&intf->dev)); + usb_get_intfdata(intf)); } +#ifdef CONFIG_PM +static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct snd_usb_audio *chip = usb_get_intfdata(intf); + struct list_head *p; + struct snd_usb_stream *as; + if (chip == (void *)-1L) + return 0; + + snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); + if (!chip->num_suspended_intf++) { + list_for_each(p, &chip->pcm_list) { + as = list_entry(p, struct snd_usb_stream, list); + snd_pcm_suspend_all(as->pcm); + } + } + + return 0; +} + +static int usb_audio_resume(struct usb_interface *intf) +{ + struct snd_usb_audio *chip = usb_get_intfdata(intf); + + if (chip == (void *)-1L) + return 0; + if (--chip->num_suspended_intf) + return 0; + /* + * ALSA leaves material resumption to user space + * we just notify + */ + + snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); + + return 0; +} +#endif /* CONFIG_PM */ +#endif /* OLD_USB */ + 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; } @@ -3660,3 +3929,5 @@ module_init(snd_usb_audio_init); module_exit(snd_usb_audio_cleanup); + +#include "usbaudio.inc1" Index: usb/usbmidi.c =================================================================== --- usb/usbmidi.c (revision 8635) +++ usb/usbmidi.c (working copy) @@ -1,7 +1,9 @@ +#include "usbmidi.inc" + /* * usbmidi.c - ALSA USB MIDI driver * - * Copyright (c) 2002-2007 Clemens Ladisch + * Copyright (c) 2002-2009 Clemens Ladisch * All rights reserved. * * Based on the OSS usb-midi driver by NAGANO Daisuke, @@ -35,7 +37,6 @@ * SUCH DAMAGE. */ -#include #include #include #include @@ -46,7 +47,9 @@ #include #include #include +#include #include +#include #include #include #include "usbaudio.h" @@ -63,7 +66,10 @@ */ #define ERROR_DELAY_JIFFIES (HZ / 10) +#define OUTPUT_URBS 7 +#define INPUT_URBS 7 + MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("USB Audio/MIDI helper module"); MODULE_LICENSE("Dual BSD/GPL"); @@ -91,35 +97,48 @@ struct usb_protocol_ops { void (*input)(struct snd_usb_midi_in_endpoint*, uint8_t*, int); - void (*output)(struct snd_usb_midi_out_endpoint*); + void (*output)(struct snd_usb_midi_out_endpoint *ep, struct urb *urb); void (*output_packet)(struct urb*, uint8_t, uint8_t, uint8_t, uint8_t); void (*init_out_endpoint)(struct snd_usb_midi_out_endpoint*); void (*finish_out_endpoint)(struct snd_usb_midi_out_endpoint*); }; struct snd_usb_midi { - struct snd_usb_audio *chip; + struct usb_device *dev; + struct snd_card *card; struct usb_interface *iface; const struct snd_usb_audio_quirk *quirk; struct snd_rawmidi *rmidi; struct usb_protocol_ops* usb_protocol_ops; struct list_head list; struct timer_list error_timer; + spinlock_t disc_lock; + struct mutex mutex; + u32 usb_id; + int next_midi_device; struct snd_usb_midi_endpoint { struct snd_usb_midi_out_endpoint *out; struct snd_usb_midi_in_endpoint *in; } endpoints[MIDI_MAX_ENDPOINTS]; unsigned long input_triggered; + unsigned int opened; + unsigned char disconnected; + + struct snd_kcontrol *roland_load_ctl; }; struct snd_usb_midi_out_endpoint { struct snd_usb_midi* umidi; - struct urb* urb; - int urb_active; + struct out_urb_context { + struct urb *urb; + struct snd_usb_midi_out_endpoint *ep; + } urbs[OUTPUT_URBS]; + unsigned int active_urbs; + unsigned int drain_urbs; int max_transfer; /* size of urb buffer */ struct tasklet_struct tasklet; - + unsigned int next_urb; spinlock_t buffer_lock; struct usbmidi_out_port { @@ -138,11 +157,13 @@ uint8_t data[2]; } ports[0x10]; int current_port; + + wait_queue_head_t drain_wait; }; struct snd_usb_midi_in_endpoint { struct snd_usb_midi* umidi; - struct urb* urb; + struct urb* urbs[INPUT_URBS]; struct usbmidi_in_port { struct snd_rawmidi_substream *substream; u8 running_status_length; @@ -224,7 +245,11 @@ /* * Processes the data read from the device. */ +#if !defined(OLD_USB) && !defined(CONFIG_SND_NEW_IRQ_HANDLER) +static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs) +#else static void snd_usbmidi_in_urb_complete(struct urb* urb) +#endif { struct snd_usb_midi_in_endpoint* ep = urb->context; @@ -244,16 +269,27 @@ } } - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_ATOMIC); } +#if !defined(OLD_USB) && !defined(CONFIG_SND_NEW_IRQ_HANDLER) +static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs) +#else static void snd_usbmidi_out_urb_complete(struct urb* urb) +#endif { - struct snd_usb_midi_out_endpoint* ep = urb->context; + struct out_urb_context *context = urb->context; + struct snd_usb_midi_out_endpoint* ep = context->ep; + unsigned int urb_index; spin_lock(&ep->buffer_lock); - ep->urb_active = 0; + urb_index = context - ep->urbs; + ep->active_urbs &= ~(1 << urb_index); + if (unlikely(ep->drain_urbs)) { + ep->drain_urbs &= ~(1 << urb_index); + wake_up(&ep->drain_wait); + } spin_unlock(&ep->buffer_lock); if (urb->status < 0) { int err = snd_usbmidi_urb_error(urb->status); @@ -273,24 +309,38 @@ */ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) { - struct urb* urb = ep->urb; + unsigned int urb_index; + struct urb* urb; unsigned long flags; spin_lock_irqsave(&ep->buffer_lock, flags); - if (ep->urb_active || ep->umidi->chip->shutdown) { + if (ep->umidi->disconnected) { spin_unlock_irqrestore(&ep->buffer_lock, flags); return; } - urb->transfer_buffer_length = 0; - ep->umidi->usb_protocol_ops->output(ep); + urb_index = ep->next_urb; + for (;;) { + if (!(ep->active_urbs & (1 << urb_index))) { + urb = ep->urbs[urb_index].urb; + urb->transfer_buffer_length = 0; + ep->umidi->usb_protocol_ops->output(ep, urb); + if (urb->transfer_buffer_length == 0) + break; - if (urb->transfer_buffer_length > 0) { - dump_urb("sending", urb->transfer_buffer, - urb->transfer_buffer_length); - urb->dev = ep->umidi->chip->dev; - ep->urb_active = snd_usbmidi_submit_urb(urb, GFP_ATOMIC) >= 0; + dump_urb("sending", urb->transfer_buffer, + urb->transfer_buffer_length); + urb->dev = ep->umidi->dev; + if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0) + break; + ep->active_urbs |= 1 << urb_index; + } + if (++urb_index >= OUTPUT_URBS) + urb_index = 0; + if (urb_index == ep->next_urb) + break; } + ep->next_urb = urb_index; spin_unlock_irqrestore(&ep->buffer_lock, flags); } @@ -305,31 +355,45 @@ static void snd_usbmidi_error_timer(unsigned long data) { struct snd_usb_midi *umidi = (struct snd_usb_midi *)data; - int i; + unsigned int i, j; + spin_lock(&umidi->disc_lock); + if (umidi->disconnected) { + spin_unlock(&umidi->disc_lock); + return; + } for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_in_endpoint *in = umidi->endpoints[i].in; if (in && in->error_resubmit) { in->error_resubmit = 0; - in->urb->dev = umidi->chip->dev; - snd_usbmidi_submit_urb(in->urb, GFP_ATOMIC); + for (j = 0; j < INPUT_URBS; ++j) { + in->urbs[j]->dev = umidi->dev; + snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC); + } } if (umidi->endpoints[i].out) snd_usbmidi_do_output(umidi->endpoints[i].out); } + spin_unlock(&umidi->disc_lock); } /* helper function to send static data that may not DMA-able */ static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep, const void *data, int len) { - int err; + int err = 0; void *buf = kmemdup(data, len, GFP_KERNEL); if (!buf) return -ENOMEM; dump_urb("sending", buf, len); - err = usb_bulk_msg(ep->umidi->chip->dev, ep->urb->pipe, buf, len, - NULL, 250); + if (ep->urbs[0].urb) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) + err = usb_bulk_msg(ep->umidi->dev, ep->urbs[0].urb->pipe, + buf, len, NULL, 250); +#else + err = usb_bulk_msg(ep->umidi->dev, ep->urbs[0].urb->pipe, + buf, len, NULL, HZ); +#endif kfree(buf); return err; } @@ -407,6 +471,20 @@ } /* + * CME protocol: like the standard protocol, but SysEx commands are sent as a + * single USB packet preceded by a 0x0F byte. + */ +static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) +{ + if (buffer_length < 2 || (buffer[0] & 0x0f) != 0x0f) + snd_usbmidi_standard_input(ep, buffer, buffer_length); + else + snd_usbmidi_input_data(ep, buffer[0] >> 4, + &buffer[1], buffer_length - 1); +} + +/* * Adds one USB MIDI packet to the output buffer. */ static void snd_usbmidi_output_standard_packet(struct urb* urb, uint8_t p0, @@ -533,9 +611,9 @@ } } -static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { - struct urb* urb = ep->urb; int p; /* FIXME: lower-numbered ports can starve higher-numbered ports */ @@ -572,6 +650,12 @@ .output_packet = snd_usbmidi_output_standard_packet, }; +static struct usb_protocol_ops snd_usbmidi_cme_ops = { + .input = snd_usbmidi_cme_input, + .output = snd_usbmidi_standard_output, + .output_packet = snd_usbmidi_output_standard_packet, +}; + /* * Novation USB MIDI protocol: number of data bytes is in the first byte * (when receiving) (+1!) or in the second byte (when sending); data begins @@ -586,14 +670,15 @@ snd_usbmidi_input_data(ep, 0, &buffer[2], buffer[0] - 1); } -static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { uint8_t* transfer_buffer; int count; if (!ep->ports[0].active) return; - transfer_buffer = ep->urb->transfer_buffer; + transfer_buffer = urb->transfer_buffer; count = snd_rawmidi_transmit(ep->ports[0].substream, &transfer_buffer[2], ep->max_transfer - 2); @@ -603,7 +688,7 @@ } transfer_buffer[0] = 0; transfer_buffer[1] = count; - ep->urb->transfer_buffer_length = 2 + count; + urb->transfer_buffer_length = 2 + count; } static struct usb_protocol_ops snd_usbmidi_novation_ops = { @@ -621,20 +706,21 @@ snd_usbmidi_input_data(ep, 0, buffer, buffer_length); } -static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { int count; if (!ep->ports[0].active) return; count = snd_rawmidi_transmit(ep->ports[0].substream, - ep->urb->transfer_buffer, + urb->transfer_buffer, ep->max_transfer); if (count < 1) { ep->ports[0].active = 0; return; } - ep->urb->transfer_buffer_length = count; + urb->transfer_buffer_length = count; } static struct usb_protocol_ops snd_usbmidi_raw_ops = { @@ -642,6 +728,43 @@ .output = snd_usbmidi_raw_output, }; +static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) +{ + if (buffer_length != 9) + return; + buffer_length = 8; + while (buffer_length && buffer[buffer_length - 1] == 0xFD) + buffer_length--; + if (buffer_length) + snd_usbmidi_input_data(ep, 0, buffer, buffer_length); +} + +static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, + struct urb *urb) +{ + int count; + + if (!ep->ports[0].active) + return; + count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2; + count = snd_rawmidi_transmit(ep->ports[0].substream, + urb->transfer_buffer, + count); + if (count < 1) { + ep->ports[0].active = 0; + return; + } + + memset(urb->transfer_buffer + count, 0xFD, 9 - count); + urb->transfer_buffer_length = count; +} + +static struct usb_protocol_ops snd_usbmidi_122l_ops = { + .input = snd_usbmidi_us122l_input, + .output = snd_usbmidi_us122l_output, +}; + /* * Emagic USB MIDI protocol: raw MIDI with "F5 xx" port switching. */ @@ -723,10 +846,11 @@ } } -static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { int port0 = ep->current_port; - uint8_t* buf = ep->urb->transfer_buffer; + uint8_t* buf = urb->transfer_buffer; int buf_free = ep->max_transfer; int length, i; @@ -766,7 +890,7 @@ *buf = 0xff; --buf_free; } - ep->urb->transfer_buffer_length = ep->max_transfer - buf_free; + urb->transfer_buffer_length = ep->max_transfer - buf_free; } static struct usb_protocol_ops snd_usbmidi_emagic_ops = { @@ -777,6 +901,55 @@ }; +static void update_roland_altsetting(struct snd_usb_midi* umidi) +{ + struct usb_interface *intf; + struct usb_host_interface *hostif; + struct usb_interface_descriptor *intfd; + int is_light_load; + + intf = umidi->iface; +#ifndef OLD_USB + is_light_load = intf->cur_altsetting != intf->altsetting; +#else + is_light_load = &intf->altsetting[intf->act_altsetting] != + intf->altsetting; +#endif + if (umidi->roland_load_ctl->private_value == is_light_load) + return; + hostif = &intf->altsetting[umidi->roland_load_ctl->private_value]; + intfd = get_iface_desc(hostif); + snd_usbmidi_input_stop(&umidi->list); + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, + intfd->bAlternateSetting); + snd_usbmidi_input_start(&umidi->list); +} + +static void substream_open(struct snd_rawmidi_substream *substream, int open) +{ + struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct snd_kcontrol *ctl; + + mutex_lock(&umidi->mutex); + if (open) { + if (umidi->opened++ == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + update_roland_altsetting(umidi); + } + } else { + if (--umidi->opened == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + } + } + mutex_unlock(&umidi->mutex); +} + static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) { struct snd_usb_midi* umidi = substream->rmidi->private_data; @@ -796,11 +969,13 @@ } substream->runtime->private_data = port; port->state = STATE_UNKNOWN; + substream_open(substream, 1); return 0; } static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -810,24 +985,72 @@ port->active = up; if (up) { - if (port->ep->umidi->chip->shutdown) { + if (port->ep->umidi->disconnected) { /* gobble up remaining bytes to prevent wait in * snd_rawmidi_drain_output */ while (!snd_rawmidi_transmit_empty(substream)) snd_rawmidi_transmit_ack(substream, 1); return; } - tasklet_hi_schedule(&port->ep->tasklet); + tasklet_schedule(&port->ep->tasklet); } } +static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream) +{ + struct usbmidi_out_port* port = substream->runtime->private_data; + struct snd_usb_midi_out_endpoint *ep = port->ep; + unsigned int drain_urbs; +#ifndef OLD_USB + DEFINE_WAIT(wait); +#else + wait_queue_t wait; +#endif + long timeout = msecs_to_jiffies(50); + + /* + * The substream buffer is empty, but some data might still be in the + * currently active URBs, so we have to wait for those to complete. + */ + spin_lock_irq(&ep->buffer_lock); + drain_urbs = ep->active_urbs; + if (drain_urbs) { + ep->drain_urbs |= drain_urbs; +#ifndef OLD_USB + do { + prepare_to_wait(&ep->drain_wait, &wait, + TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&ep->buffer_lock); + timeout = schedule_timeout(timeout); + spin_lock_irq(&ep->buffer_lock); + drain_urbs &= ep->drain_urbs; + } while (drain_urbs && timeout); + finish_wait(&ep->drain_wait, &wait); +#else + do { + init_waitqueue_entry(&wait, current); + add_wait_queue(&ep->drain_wait, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&ep->buffer_lock); + timeout = schedule_timeout(timeout); + spin_lock_irq(&ep->buffer_lock); + drain_urbs &= ep->drain_urbs; + remove_wait_queue(&ep->drain_wait, &wait); + } while (drain_urbs && timeout); +#endif + } + spin_unlock_irq(&ep->buffer_lock); +} + static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) { + substream_open(substream, 1); return 0; } static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -845,6 +1068,7 @@ .open = snd_usbmidi_output_open, .close = snd_usbmidi_output_close, .trigger = snd_usbmidi_output_trigger, + .drain = snd_usbmidi_output_drain, }; static struct snd_rawmidi_ops snd_usbmidi_input_ops = { @@ -853,19 +1077,26 @@ .trigger = snd_usbmidi_input_trigger }; +static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb, + unsigned int buffer_length) +{ + usb_buffer_free(umidi->dev, buffer_length, + urb->transfer_buffer, urb->transfer_dma); + usb_free_urb(urb); +} + /* * Frees an input endpoint. * May be called when ep hasn't been initialized completely. */ static void snd_usbmidi_in_endpoint_delete(struct snd_usb_midi_in_endpoint* ep) { - if (ep->urb) { - usb_buffer_free(ep->umidi->chip->dev, - ep->urb->transfer_buffer_length, - ep->urb->transfer_buffer, - ep->urb->transfer_dma); - usb_free_urb(ep->urb); - } + unsigned int i; + + for (i = 0; i < INPUT_URBS; ++i) + if (ep->urbs[i]) + free_urb_and_buffer(ep->umidi, ep->urbs[i], + ep->urbs[i]->transfer_buffer_length); kfree(ep); } @@ -880,6 +1111,7 @@ void* buffer; unsigned int pipe; int length; + unsigned int i; rep->in = NULL; ep = kzalloc(sizeof(*ep), GFP_KERNEL); @@ -887,56 +1119,53 @@ return -ENOMEM; ep->umidi = umidi; - ep->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ep->urb) { - snd_usbmidi_in_endpoint_delete(ep); - return -ENOMEM; + for (i = 0; i < INPUT_URBS; ++i) { + ep->urbs[i] = usb_alloc_urb(0, GFP_KERNEL); + if (!ep->urbs[i]) { + snd_usbmidi_in_endpoint_delete(ep); + return -ENOMEM; + } } if (ep_info->in_interval) - pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep); + pipe = usb_rcvintpipe(umidi->dev, ep_info->in_ep); else - pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep); - length = usb_maxpacket(umidi->chip->dev, pipe, 0); - buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL, - &ep->urb->transfer_dma); - if (!buffer) { - snd_usbmidi_in_endpoint_delete(ep); - return -ENOMEM; + pipe = usb_rcvbulkpipe(umidi->dev, ep_info->in_ep); + length = usb_maxpacket(umidi->dev, pipe, 0); + for (i = 0; i < INPUT_URBS; ++i) { + buffer = usb_buffer_alloc(umidi->dev, length, GFP_KERNEL, + &ep->urbs[i]->transfer_dma); + if (!buffer) { + snd_usbmidi_in_endpoint_delete(ep); + return -ENOMEM; + } + if (ep_info->in_interval) + usb_fill_int_urb(ep->urbs[i], umidi->dev, + pipe, buffer, length, + snd_usbmidi_in_urb_complete, + ep, ep_info->in_interval); + else + usb_fill_bulk_urb(ep->urbs[i], umidi->dev, + pipe, buffer, length, + snd_usbmidi_in_urb_complete, ep); + ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; } - if (ep_info->in_interval) - usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer, - length, snd_usbmidi_in_urb_complete, ep, - ep_info->in_interval); - else - usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, - length, snd_usbmidi_in_urb_complete, ep); - ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; rep->in = ep; return 0; } -static unsigned int snd_usbmidi_count_bits(unsigned int x) -{ - unsigned int bits; - - for (bits = 0; x; ++bits) - x &= x - 1; - return bits; -} - /* * Frees an output endpoint. * May be called when ep hasn't been initialized completely. */ static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint* ep) { - if (ep->urb) { - usb_buffer_free(ep->umidi->chip->dev, ep->max_transfer, - ep->urb->transfer_buffer, - ep->urb->transfer_dma); - usb_free_urb(ep->urb); - } + unsigned int i; + + for (i = 0; i < OUTPUT_URBS; ++i) + if (ep->urbs[i].urb) + free_urb_and_buffer(ep->umidi, ep->urbs[i].urb, + ep->max_transfer); kfree(ep); } @@ -948,7 +1177,7 @@ struct snd_usb_midi_endpoint* rep) { struct snd_usb_midi_out_endpoint* ep; - int i; + unsigned int i; unsigned int pipe; void* buffer; @@ -958,30 +1187,46 @@ return -ENOMEM; ep->umidi = umidi; - ep->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ep->urb) { - snd_usbmidi_out_endpoint_delete(ep); - return -ENOMEM; + for (i = 0; i < OUTPUT_URBS; ++i) { + ep->urbs[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ep->urbs[i].urb) { + snd_usbmidi_out_endpoint_delete(ep); + return -ENOMEM; + } + ep->urbs[i].ep = ep; } - /* we never use interrupt output pipes */ - pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); - if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ - /* FIXME: we need more URBs to get reasonable bandwidth here: */ + if (ep_info->out_interval) + pipe = usb_sndintpipe(umidi->dev, ep_info->out_ep); + else + pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep); + if (umidi->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ ep->max_transfer = 4; else - ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1); - buffer = usb_buffer_alloc(umidi->chip->dev, ep->max_transfer, - GFP_KERNEL, &ep->urb->transfer_dma); - if (!buffer) { - snd_usbmidi_out_endpoint_delete(ep); - return -ENOMEM; + ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1); + for (i = 0; i < OUTPUT_URBS; ++i) { + buffer = usb_buffer_alloc(umidi->dev, + ep->max_transfer, GFP_KERNEL, + &ep->urbs[i].urb->transfer_dma); + if (!buffer) { + snd_usbmidi_out_endpoint_delete(ep); + return -ENOMEM; + } + if (ep_info->out_interval) + usb_fill_int_urb(ep->urbs[i].urb, umidi->dev, + pipe, buffer, ep->max_transfer, + snd_usbmidi_out_urb_complete, + &ep->urbs[i], ep_info->out_interval); + else + usb_fill_bulk_urb(ep->urbs[i].urb, umidi->dev, + pipe, buffer, ep->max_transfer, + snd_usbmidi_out_urb_complete, + &ep->urbs[i]); + ep->urbs[i].urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; } - usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, - ep->max_transfer, snd_usbmidi_out_urb_complete, ep); - ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; spin_lock_init(&ep->buffer_lock); tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep); + init_waitqueue_head(&ep->drain_wait); for (i = 0; i < 0x10; ++i) if (ep_info->out_cables & (1 << i)) { @@ -1010,6 +1255,7 @@ if (ep->in) snd_usbmidi_in_endpoint_delete(ep->in); } + mutex_destroy(&umidi->mutex); kfree(umidi); } @@ -1019,22 +1265,41 @@ void snd_usbmidi_disconnect(struct list_head* p) { struct snd_usb_midi* umidi; - int i; + unsigned int i, j; umidi = list_entry(p, struct snd_usb_midi, list); - del_timer_sync(&umidi->error_timer); + /* + * an URB's completion handler may start the timer and + * a timer may submit an URB. To reliably break the cycle + * a flag under lock must be used + */ + spin_lock_irq(&umidi->disc_lock); + umidi->disconnected = 1; + spin_unlock_irq(&umidi->disc_lock); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; if (ep->out) tasklet_kill(&ep->out->tasklet); - if (ep->out && ep->out->urb) { - usb_kill_urb(ep->out->urb); + if (ep->out) { + for (j = 0; j < OUTPUT_URBS; ++j) + usb_kill_urb(ep->out->urbs[j].urb); if (umidi->usb_protocol_ops->finish_out_endpoint) umidi->usb_protocol_ops->finish_out_endpoint(ep->out); } if (ep->in) - usb_kill_urb(ep->in->urb); + for (j = 0; j < INPUT_URBS; ++j) + usb_kill_urb(ep->in->urbs[j]); + /* free endpoints here; later call can result in Oops */ + if (ep->out) { + snd_usbmidi_out_endpoint_delete(ep->out); + ep->out = NULL; + } + if (ep->in) { + snd_usbmidi_in_endpoint_delete(ep->in); + ep->in = NULL; + } } + del_timer_sync(&umidi->error_timer); } static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi) @@ -1186,7 +1451,7 @@ int i; for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) { - if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id && + if (snd_usbmidi_port_info[i].id == umidi->usb_id && snd_usbmidi_port_info[i].port == number) return &snd_usbmidi_port_info[i]; } @@ -1224,7 +1489,7 @@ port_info = find_port_info(umidi, number); name_format = port_info ? port_info->name : "%s MIDI %d"; snprintf(substream->name, sizeof(substream->name), - name_format, umidi->chip->card->shortname, number + 1); + name_format, umidi->card->shortname, number + 1); *rsubstream = substream; } @@ -1304,8 +1569,7 @@ for (i = 0; i < intfd->bNumEndpoints; ++i) { hostep = &hostif->endpoint[i]; ep = get_ep_desc(hostep); - if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK && - (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_xfer_bulk(ep) && !usb_endpoint_xfer_int(ep)) continue; ms_ep = (struct usb_ms_endpoint_descriptor*)hostep->extra; if (hostep->extralen < 4 || @@ -1313,16 +1577,23 @@ ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT || ms_ep->bDescriptorSubtype != MS_GENERAL) continue; - if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { + if (usb_endpoint_dir_out(ep)) { if (endpoints[epidx].out_ep) { if (++epidx >= MIDI_MAX_ENDPOINTS) { snd_printk(KERN_WARNING "too many endpoints\n"); break; } } - endpoints[epidx].out_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + endpoints[epidx].out_ep = usb_endpoint_num(ep); + if (usb_endpoint_xfer_int(ep)) endpoints[epidx].out_interval = ep->bInterval; + else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW) + /* + * Low speed bulk transfers don't exist, so + * force interrupt transfers for devices like + * ESI MIDI Mate that try to use them anyway. + */ + endpoints[epidx].out_interval = 1; endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); @@ -1333,9 +1604,11 @@ break; } } - endpoints[epidx].in_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + endpoints[epidx].in_ep = usb_endpoint_num(ep); + if (usb_endpoint_xfer_int(ep)) endpoints[epidx].in_interval = ep->bInterval; + else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW) + endpoints[epidx].in_interval = 1; endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); @@ -1344,6 +1617,52 @@ return 0; } +static int roland_load_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + static const char *const names[] = { "High Load", "Light Load" }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item > 1) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int roland_load_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + value->value.enumerated.item[0] = kcontrol->private_value; + return 0; +} + +static int roland_load_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_usb_midi* umidi = kcontrol->private_data; + int changed; + + if (value->value.enumerated.item[0] > 1) + return -EINVAL; + mutex_lock(&umidi->mutex); + changed = value->value.enumerated.item[0] != kcontrol->private_value; + if (changed) + kcontrol->private_value = value->value.enumerated.item[0]; + mutex_unlock(&umidi->mutex); + return changed; +} + +static struct snd_kcontrol_new roland_load_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "MIDI Input Mode", + .info = roland_load_info, + .get = roland_load_get, + .put = roland_load_put, + .private_value = 1, +}; + /* * On Roland devices, use the second alternate setting to be able to use * the interrupt input endpoint. @@ -1367,8 +1686,12 @@ snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n", intfd->bAlternateSetting); - usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, intfd->bAlternateSetting); + + umidi->roland_load_ctl = snd_ctl_new1(&roland_load_ctl, umidi); + if (snd_ctl_add(umidi->card, umidi->roland_load_ctl) < 0) + umidi->roland_load_ctl = NULL; } /* @@ -1384,7 +1707,7 @@ struct usb_endpoint_descriptor* epd; int i, out_eps = 0, in_eps = 0; - if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582) + if (USB_ID_VENDOR(umidi->usb_id) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); if (endpoint[0].out_ep || endpoint[0].in_ep) @@ -1393,25 +1716,29 @@ intf = umidi->iface; if (!intf || intf->num_altsetting < 1) return -ENOENT; +#ifndef OLD_USB hostif = intf->cur_altsetting; +#else + hostif = &intf->altsetting[intf->act_altsetting]; +#endif intfd = get_iface_desc(hostif); for (i = 0; i < intfd->bNumEndpoints; ++i) { epd = get_endpoint(hostif, i); - if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK && - (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_xfer_bulk(epd) && + !usb_endpoint_xfer_int(epd)) continue; if (out_eps < max_endpoints && - (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { - endpoint[out_eps].out_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + usb_endpoint_dir_out(epd)) { + endpoint[out_eps].out_ep = usb_endpoint_num(epd); + if (usb_endpoint_xfer_int(epd)) endpoint[out_eps].out_interval = epd->bInterval; ++out_eps; } if (in_eps < max_endpoints && - (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - endpoint[in_eps].in_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + usb_endpoint_dir_in(epd)) { + endpoint[in_eps].in_ep = usb_endpoint_num(epd); + if (usb_endpoint_xfer_int(epd)) endpoint[in_eps].in_interval = epd->bInterval; ++in_eps; } @@ -1510,27 +1837,26 @@ } epd = get_endpoint(hostif, 0); - if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN || - (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) { + if (!usb_endpoint_dir_in(epd) || !usb_endpoint_xfer_int(epd)) { snd_printdd(KERN_ERR "endpoint[0] isn't interrupt\n"); return -ENXIO; } epd = get_endpoint(hostif, 2); - if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT || - (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { + if (!usb_endpoint_dir_out(epd) || !usb_endpoint_xfer_bulk(epd)) { snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n"); return -ENXIO; } if (endpoint->out_cables > 0x0001) { epd = get_endpoint(hostif, 4); - if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT || - (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { + if (!usb_endpoint_dir_out(epd) || + !usb_endpoint_xfer_bulk(epd)) { snd_printdd(KERN_ERR "endpoint[4] isn't bulk output\n"); return -ENXIO; } } ep_info.out_ep = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep_info.out_interval = 0; ep_info.out_cables = endpoint->out_cables & 0x5555; err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]); if (err < 0) @@ -1572,12 +1898,12 @@ struct snd_rawmidi *rmidi; int err; - err = snd_rawmidi_new(umidi->chip->card, "USB MIDI", - umidi->chip->next_midi_device++, + err = snd_rawmidi_new(umidi->card, "USB MIDI", + umidi->next_midi_device++, out_ports, in_ports, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, umidi->chip->card->shortname); + strcpy(rmidi->name, umidi->card->shortname); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; @@ -1597,21 +1923,26 @@ void snd_usbmidi_input_stop(struct list_head* p) { struct snd_usb_midi* umidi; - int i; + unsigned int i, j; umidi = list_entry(p, struct snd_usb_midi, list); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; if (ep->in) - usb_kill_urb(ep->in->urb); + for (j = 0; j < INPUT_URBS; ++j) + usb_kill_urb(ep->in->urbs[j]); } } static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) { - if (ep) { - struct urb* urb = ep->urb; - urb->dev = ep->umidi->chip->dev; + unsigned int i; + + if (!ep) + return; + for (i = 0; i < INPUT_URBS; ++i) { + struct urb* urb = ep->urbs[i]; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_KERNEL); } } @@ -1632,9 +1963,10 @@ /* * Creates and registers everything needed for a MIDI streaming interface. */ -int snd_usb_create_midi_interface(struct snd_usb_audio* chip, - struct usb_interface* iface, - const struct snd_usb_audio_quirk* quirk) +int snd_usbmidi_create(struct snd_card *card, + struct usb_interface* iface, + struct list_head *midi_list, + const struct snd_usb_audio_quirk* quirk) { struct snd_usb_midi* umidi; struct snd_usb_midi_endpoint_info endpoints[MIDI_MAX_ENDPOINTS]; @@ -1644,11 +1976,16 @@ umidi = kzalloc(sizeof(*umidi), GFP_KERNEL); if (!umidi) return -ENOMEM; - umidi->chip = chip; + umidi->dev = interface_to_usbdev(iface); + umidi->card = card; umidi->iface = iface; umidi->quirk = quirk; umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); + spin_lock_init(&umidi->disc_lock); + mutex_init(&umidi->mutex); + umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), + le16_to_cpu(umidi->dev->descriptor.idProduct)); umidi->error_timer.function = snd_usbmidi_error_timer; umidi->error_timer.data = (unsigned long)umidi; @@ -1657,10 +1994,13 @@ switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) { case QUIRK_MIDI_STANDARD_INTERFACE: err = snd_usbmidi_get_ms_info(umidi, endpoints); - if (chip->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ + if (umidi->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ umidi->usb_protocol_ops = &snd_usbmidi_maudio_broken_running_status_ops; break; + case QUIRK_MIDI_US122L: + umidi->usb_protocol_ops = &snd_usbmidi_122l_ops; + /* fall through */ case QUIRK_MIDI_FIXED_ENDPOINT: memcpy(&endpoints[0], quirk->data, sizeof(struct snd_usb_midi_endpoint_info)); @@ -1679,8 +2019,18 @@ umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; - case QUIRK_MIDI_RAW: + case QUIRK_MIDI_FASTLANE: umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; + /* + * Interface 1 contains isochronous endpoints, but with the same + * numbers as in interface 0. Since it is interface 1 that the + * USB core has most recently seen, these descriptors are now + * associated with the endpoint numbers. This will foul up our + * attempts to submit bulk/interrupt URBs to the endpoints in + * interface 0, so we have to make sure that the USB core looks + * again at interface 0 by calling usb_set_interface() on it. + */ + usb_set_interface(umidi->dev, 0, 0); err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; case QUIRK_MIDI_EMAGIC: @@ -1690,6 +2040,7 @@ err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1); break; case QUIRK_MIDI_CME: + umidi->usb_protocol_ops = &snd_usbmidi_cme_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; default: @@ -1706,8 +2057,8 @@ out_ports = 0; in_ports = 0; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { - out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables); - in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables); + out_ports += hweight16(endpoints[i].out_cables); + in_ports += hweight16(endpoints[i].in_cables); } err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports); if (err < 0) { @@ -1725,14 +2076,16 @@ return err; } - list_add(&umidi->list, &umidi->chip->midi_list); + list_add_tail(&umidi->list, midi_list); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) snd_usbmidi_input_start_ep(umidi->endpoints[i].in); return 0; } -EXPORT_SYMBOL(snd_usb_create_midi_interface); +EXPORT_SYMBOL(snd_usbmidi_create); EXPORT_SYMBOL(snd_usbmidi_input_stop); EXPORT_SYMBOL(snd_usbmidi_input_start); EXPORT_SYMBOL(snd_usbmidi_disconnect); + +#include "usbmidi.inc1" Index: usb/caiaq/caiaq-midi.c =================================================================== --- usb/caiaq/caiaq-midi.c (revision 8635) +++ usb/caiaq/caiaq-midi.c (working copy) @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -124,7 +123,7 @@ snd_rawmidi_receive(dev->midi_receive_substream, buf, len); } -int __devinit snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) +int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) { int ret; struct snd_rawmidi *rmidi; Index: usb/caiaq/caiaq-device.h =================================================================== --- usb/caiaq/caiaq-device.h (revision 8635) +++ usb/caiaq/caiaq-device.h (working copy) @@ -6,7 +6,9 @@ #define USB_VID_NATIVEINSTRUMENTS 0x17cc #define USB_PID_RIGKONTROL2 0x1969 -#define USB_PID_KORECONTROLLER 0x4711 +#define USB_PID_RIGKONTROL3 0x1940 +#define USB_PID_KORECONTROLLER 0x4711 +#define USB_PID_KORECONTROLLER2 0x4712 #define USB_PID_AK1 0x0815 #define USB_PID_AUDIO8DJ 0x1978 @@ -34,6 +36,7 @@ #define EP1_CMD_MIDI_WRITE 0x7 #define EP1_CMD_AUDIO_PARAMS 0x9 #define EP1_CMD_AUTO_MSG 0xb +#define EP1_CMD_DIMM_LEDS 0xc struct caiaq_device_spec { unsigned short fw_version; @@ -61,7 +64,7 @@ struct urb **data_urbs_in; struct urb **data_urbs_out; struct snd_usb_caiaq_cb_info *data_cb_info; - + unsigned char ep1_in_buf[EP1_BUFSIZE]; unsigned char ep1_out_buf[EP1_BUFSIZE]; unsigned char midi_out_buf[EP1_BUFSIZE]; @@ -71,7 +74,7 @@ wait_queue_head_t ep1_wait_queue; wait_queue_head_t prepare_wait_queue; int spec_received, audio_parm_answer; - + char vendor_name[CAIAQ_USB_STR_LEN]; char product_name[CAIAQ_USB_STR_LEN]; char serial[CAIAQ_USB_STR_LEN]; @@ -89,11 +92,16 @@ struct snd_pcm_substream *sub_playback[MAX_STREAMS]; struct snd_pcm_substream *sub_capture[MAX_STREAMS]; + /* Controls */ + unsigned char control_state[64]; + /* Linux input */ #ifdef CONFIG_SND_USB_CAIAQ_INPUT struct input_dev *input_dev; + char phys[64]; /* physical device path */ + unsigned short keycode[64]; #endif - + /* ALSA */ struct snd_pcm *pcm; struct snd_pcm_hardware pcm_info; @@ -111,6 +119,9 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, int rate, int depth, int bbp); int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, int digital, int analog, int erp); +int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev, + unsigned char command, + const unsigned char *buffer, + int len); - #endif /* CAIAQ_DEVICE_H */ Index: usb/caiaq/caiaq-device.c =================================================================== --- usb/caiaq/caiaq-device.c (revision 8635) +++ usb/caiaq/caiaq-device.c (working copy) @@ -26,25 +26,28 @@ #include #include #include -#include #include #include #include #include +#include #include "caiaq-device.h" #include "caiaq-audio.h" #include "caiaq-midi.h" +#include "caiaq-control.h" #ifdef CONFIG_SND_USB_CAIAQ_INPUT #include "caiaq-input.h" #endif MODULE_AUTHOR("Daniel Mack "); -MODULE_DESCRIPTION("caiaq USB audio, version 1.1.0"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.3.2"); 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 8 DJ}}"); @@ -85,9 +88,19 @@ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = USB_VID_NATIVEINSTRUMENTS, + .idProduct = USB_PID_RIGKONTROL3 + }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = USB_VID_NATIVEINSTRUMENTS, .idProduct = USB_PID_KORECONTROLLER }, { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = USB_VID_NATIVEINSTRUMENTS, + .idProduct = USB_PID_KORECONTROLLER2 + }, + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = USB_VID_NATIVEINSTRUMENTS, .idProduct = USB_PID_AK1 @@ -134,14 +147,21 @@ case EP1_CMD_MIDI_READ: snd_usb_caiaq_midi_handle_input(dev, buf[1], buf + 3, buf[2]); break; - + case EP1_CMD_READ_IO: + if (dev->chip.usb_id == + USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)) { + if (urb->actual_length > sizeof(dev->control_state)) + urb->actual_length = sizeof(dev->control_state); + memcpy(dev->control_state, buf + 1, urb->actual_length); + wake_up(&dev->ep1_wait_queue); + break; + } #ifdef CONFIG_SND_USB_CAIAQ_INPUT case EP1_CMD_READ_ERP: case EP1_CMD_READ_ANALOG: - case EP1_CMD_READ_IO: snd_usb_caiaq_input_dispatch(dev, buf, urb->actual_length); +#endif break; -#endif } dev->ep1_in_urb.actual_length = 0; @@ -150,10 +170,10 @@ log("unable to submit urb. OOM!?\n"); } -static int send_command (struct snd_usb_caiaqdev *dev, - unsigned char command, - const unsigned char *buffer, - int len) +int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev, + unsigned char command, + const unsigned char *buffer, + int len) { int actual_len; struct usb_device *usb_dev = dev->chip.dev; @@ -201,7 +221,8 @@ rate, depth, bpp); dev->audio_parm_answer = -1; - ret = send_command(dev, EP1_CMD_AUDIO_PARAMS, tmp, sizeof(tmp)); + ret = snd_usb_caiaq_send_command(dev, EP1_CMD_AUDIO_PARAMS, + tmp, sizeof(tmp)); if (ret) return ret; @@ -220,13 +241,14 @@ int digital, int analog, int erp) { char tmp[3] = { digital, analog, erp }; - return send_command(dev, EP1_CMD_AUTO_MSG, tmp, sizeof(tmp)); + return snd_usb_caiaq_send_command(dev, EP1_CMD_AUTO_MSG, + tmp, sizeof(tmp)); } -static void setup_card(struct snd_usb_caiaqdev *dev) +static void __devinit setup_card(struct snd_usb_caiaqdev *dev) { int ret; - char val[3]; + char val[4]; /* device-specific startup specials */ switch (dev->chip.usb_id) { @@ -235,22 +257,60 @@ val[0] = 0x00; val[1] = 0x00; val[2] = 0x01; - send_command(dev, EP1_CMD_WRITE_IO, val, 3); + snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 3); break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): + /* RigKontrol2 - display two centered dashes ('--') */ + val[0] = 0x00; + val[1] = 0x40; + val[2] = 0x40; + val[3] = 0x00; + snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 4); + break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): /* Audio Kontrol 1 - make USB-LED stop blinking */ val[0] = 0x00; - send_command(dev, EP1_CMD_WRITE_IO, val, 1); + snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 1); break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): + /* Audio 8 DJ - trigger read of current settings */ + dev->control_state[0] = 0xff; + snd_usb_caiaq_set_auto_msg(dev, 1, 0, 0); + snd_usb_caiaq_send_command(dev, EP1_CMD_READ_IO, NULL, 0); + + if (!wait_event_timeout(dev->ep1_wait_queue, + dev->control_state[0] != 0xff, HZ)) + return; + + /* fix up some defaults */ + if ((dev->control_state[1] != 2) || + (dev->control_state[2] != 3) || + (dev->control_state[4] != 2)) { + dev->control_state[1] = 2; + dev->control_state[2] = 3; + dev->control_state[4] = 2; + snd_usb_caiaq_send_command(dev, + EP1_CMD_WRITE_IO, dev->control_state, 6); + } + + break; } - ret = snd_usb_caiaq_audio_init(dev); - if (ret < 0) - log("Unable to set up audio system (ret=%d)\n", ret); + if (dev->spec.num_analog_audio_out + + dev->spec.num_analog_audio_in + + dev->spec.num_digital_audio_out + + dev->spec.num_digital_audio_in > 0) { + ret = snd_usb_caiaq_audio_init(dev); + if (ret < 0) + log("Unable to set up audio system (ret=%d)\n", ret); + } - ret = snd_usb_caiaq_midi_init(dev); - if (ret < 0) - log("Unable to set up MIDI system (ret=%d)\n", ret); + if (dev->spec.num_midi_in + + dev->spec.num_midi_out > 0) { + ret = snd_usb_caiaq_midi_init(dev); + if (ret < 0) + log("Unable to set up MIDI system (ret=%d)\n", ret); + } #ifdef CONFIG_SND_USB_CAIAQ_INPUT ret = snd_usb_caiaq_input_init(dev); @@ -264,6 +324,10 @@ log("snd_card_register() returned %d\n", ret); snd_card_free(dev->chip.card); } + + ret = snd_usb_caiaq_control_init(dev); + if (ret < 0) + log("Unable to set up control system (ret=%d)\n", ret); } static struct snd_card* create_card(struct usb_device* usb_dev) @@ -295,7 +359,7 @@ return card; } -static int init_card(struct snd_usb_caiaqdev *dev) +static int __devinit init_card(struct snd_usb_caiaqdev *dev) { char *c; struct usb_device *usb_dev = dev->chip.dev; @@ -326,7 +390,7 @@ if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0) return -EIO; - err = send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0); + err = snd_usb_caiaq_send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0); if (err) return err; @@ -364,7 +428,7 @@ return 0; } -static int snd_probe(struct usb_interface *intf, +static int __devinit snd_probe(struct usb_interface *intf, const struct usb_device_id *id) { int ret; Index: usb/caiaq/caiaq-input.c =================================================================== --- usb/caiaq/caiaq-input.c (revision 8635) +++ usb/caiaq/caiaq-input.c (working copy) @@ -21,26 +21,61 @@ #include #include #include +#include #include -#include #include #include #include #include "caiaq-device.h" #include "caiaq-input.h" -#ifdef CONFIG_SND_USB_CAIAQ_INPUT +static unsigned short keycode_ak1[] = { KEY_C, KEY_B, KEY_A }; +static unsigned short keycode_rk2[] = { KEY_1, KEY_2, KEY_3, KEY_4, + KEY_5, KEY_6, KEY_7 }; +static unsigned short keycode_rk3[] = { KEY_1, KEY_2, KEY_3, KEY_4, + KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 }; -static unsigned char keycode_ak1[] = { KEY_C, KEY_B, KEY_A }; -static unsigned char keycode_rk2[] = { KEY_1, KEY_2, KEY_3, KEY_4, - KEY_5, KEY_6, KEY_7 }; +static unsigned short keycode_kore[] = { + KEY_FN_F1, /* "menu" */ + KEY_FN_F7, /* "lcd backlight */ + KEY_FN_F2, /* "control" */ + KEY_FN_F3, /* "enter" */ + KEY_FN_F4, /* "view" */ + KEY_FN_F5, /* "esc" */ + KEY_FN_F6, /* "sound" */ + KEY_FN_F8, /* array spacer, never triggered. */ + KEY_RIGHT, + KEY_DOWN, + KEY_UP, + KEY_LEFT, + KEY_SOUND, /* "listen" */ + KEY_RECORD, + KEY_PLAYPAUSE, + KEY_STOP, + BTN_4, /* 8 softkeys */ + BTN_3, + BTN_2, + BTN_1, + BTN_8, + BTN_7, + BTN_6, + BTN_5, + KEY_BRL_DOT4, /* touch sensitive knobs */ + KEY_BRL_DOT3, + KEY_BRL_DOT2, + KEY_BRL_DOT1, + KEY_BRL_DOT8, + KEY_BRL_DOT7, + KEY_BRL_DOT6, + KEY_BRL_DOT5 +}; -#define DEG90 (range/2) -#define DEG180 (range) -#define DEG270 (DEG90 + DEG180) -#define DEG360 (DEG180 * 2) -#define HIGH_PEAK (268) -#define LOW_PEAK (-7) +#define DEG90 (range / 2) +#define DEG180 (range) +#define DEG270 (DEG90 + DEG180) +#define DEG360 (DEG180 * 2) +#define HIGH_PEAK (268) +#define LOW_PEAK (-7) /* some of these devices have endless rotation potentiometers * built in which use two tapers, 90 degrees phase shifted. @@ -54,8 +89,8 @@ int range = HIGH_PEAK - LOW_PEAK; int mid_value = (HIGH_PEAK + LOW_PEAK) / 2; - weight_b = abs(mid_value-a) - (range/2 - 100)/2; - + weight_b = abs(mid_value - a) - (range / 2 - 100) / 2; + if (weight_b < 0) weight_b = 0; @@ -91,7 +126,7 @@ if (ret < 0) ret += 1000; - + if (ret >= 1000) ret -= 1000; @@ -106,69 +141,113 @@ #undef LOW_PEAK -static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, - const char *buf, unsigned int len) +static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, + const unsigned char *buf, + unsigned int len) { - switch(dev->input_dev->id.product) { - case USB_PID_RIGKONTROL2: - input_report_abs(dev->input_dev, ABS_X, (buf[4] << 8) |buf[5]); - input_report_abs(dev->input_dev, ABS_Y, (buf[0] << 8) |buf[1]); - input_report_abs(dev->input_dev, ABS_Z, (buf[2] << 8) |buf[3]); - input_sync(dev->input_dev); + struct input_dev *input_dev = dev->input_dev; + + switch (dev->chip.usb_id) { + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): + input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]); + input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]); + input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]); + input_sync(input_dev); break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): + input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); + input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); + input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); + input_sync(input_dev); + break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): + input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); + input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); + input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); + input_sync(input_dev); + break; } } -static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, +static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, const char *buf, unsigned int len) { + struct input_dev *input_dev = dev->input_dev; int i; - switch(dev->input_dev->id.product) { - case USB_PID_AK1: + switch (dev->chip.usb_id) { + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): i = decode_erp(buf[0], buf[1]); - input_report_abs(dev->input_dev, ABS_X, i); - input_sync(dev->input_dev); + input_report_abs(input_dev, ABS_X, i); + input_sync(input_dev); break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): + i = decode_erp(buf[7], buf[5]); + input_report_abs(input_dev, ABS_HAT0X, i); + i = decode_erp(buf[12], buf[14]); + input_report_abs(input_dev, ABS_HAT0Y, i); + i = decode_erp(buf[15], buf[13]); + input_report_abs(input_dev, ABS_HAT1X, i); + i = decode_erp(buf[0], buf[2]); + input_report_abs(input_dev, ABS_HAT1Y, i); + i = decode_erp(buf[3], buf[1]); + input_report_abs(input_dev, ABS_HAT2X, i); + i = decode_erp(buf[8], buf[10]); + input_report_abs(input_dev, ABS_HAT2Y, i); + i = decode_erp(buf[11], buf[9]); + input_report_abs(input_dev, ABS_HAT3X, i); + i = decode_erp(buf[4], buf[6]); + input_report_abs(input_dev, ABS_HAT3Y, i); + input_sync(input_dev); + break; } } -static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, +static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, char *buf, unsigned int len) { + struct input_dev *input_dev = dev->input_dev; + unsigned short *keycode = input_dev->keycode; int i; - unsigned char *keycode = dev->input_dev->keycode; if (!keycode) return; - if (dev->input_dev->id.product == USB_PID_RIGKONTROL2) - for (i=0; iid.product == USB_PID_RIGKONTROL2) + for (i = 0; i < len; i++) buf[i] = ~buf[i]; - for (i=0; (iinput_dev->keycodemax) && (i < len); i++) - input_report_key(dev->input_dev, keycode[i], - buf[i/8] & (1 << (i%8))); + for (i = 0; i < input_dev->keycodemax && i < len * 8; i++) + input_report_key(input_dev, keycode[i], + buf[i / 8] & (1 << (i % 8))); - input_sync(dev->input_dev); + if (dev->chip.usb_id == + USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER) || + dev->chip.usb_id == + USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2)) + input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]); + + input_sync(input_dev); } -void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, - char *buf, +void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, + char *buf, unsigned int len) { - if (!dev->input_dev || (len < 1)) + if (!dev->input_dev || len < 1) return; switch (buf[0]) { case EP1_CMD_READ_ANALOG: - snd_caiaq_input_read_analog(dev, buf+1, len-1); + snd_caiaq_input_read_analog(dev, buf + 1, len - 1); break; case EP1_CMD_READ_ERP: - snd_caiaq_input_read_erp(dev, buf+1, len-1); + snd_caiaq_input_read_erp(dev, buf + 1, len - 1); break; case EP1_CMD_READ_IO: - snd_caiaq_input_read_io(dev, buf+1, len-1); + snd_caiaq_input_read_io(dev, buf + 1, len - 1); break; } } @@ -183,45 +262,86 @@ if (!input) return -ENOMEM; + usb_make_path(usb_dev, dev->phys, sizeof(dev->phys)); + strlcat(dev->phys, "/input0", sizeof(dev->phys)); + input->name = dev->product_name; - input->id.bustype = BUS_USB; - input->id.vendor = usb_dev->descriptor.idVendor; - input->id.product = usb_dev->descriptor.idProduct; - input->id.version = usb_dev->descriptor.bcdDevice; + input->phys = dev->phys; + usb_to_input_id(usb_dev, &input->id); + input->dev.parent = &usb_dev->dev; switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): - input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_Z); - input->keycode = keycode_rk2; - input->keycodesize = sizeof(char); + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | + BIT_MASK(ABS_Z); + BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk2)); + memcpy(dev->keycode, keycode_rk2, sizeof(keycode_rk2)); input->keycodemax = ARRAY_SIZE(keycode_rk2); - for (i=0; ikeybit); - input_set_abs_params(input, ABS_X, 0, 4096, 0, 10); input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10); input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10); snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0); break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | + BIT_MASK(ABS_Z); + BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk3)); + memcpy(dev->keycode, keycode_rk3, sizeof(keycode_rk3)); + input->keycodemax = ARRAY_SIZE(keycode_rk3); + input_set_abs_params(input, ABS_X, 0, 1024, 0, 10); + input_set_abs_params(input, ABS_Y, 0, 1024, 0, 10); + input_set_abs_params(input, ABS_Z, 0, 1024, 0, 10); + snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0); + break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): - input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - input->absbit[0] = BIT(ABS_X); - input->keycode = keycode_ak1; - input->keycodesize = sizeof(char); + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input->absbit[0] = BIT_MASK(ABS_X); + BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_ak1)); + memcpy(dev->keycode, keycode_ak1, sizeof(keycode_ak1)); input->keycodemax = ARRAY_SIZE(keycode_ak1); - for (i=0; ikeybit); - input_set_abs_params(input, ABS_X, 0, 999, 0, 10); snd_usb_caiaq_set_auto_msg(dev, 1, 0, 5); break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) | + BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) | + BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) | + BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) | + BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | + BIT_MASK(ABS_Z); + input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); + BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_kore)); + memcpy(dev->keycode, keycode_kore, sizeof(keycode_kore)); + input->keycodemax = ARRAY_SIZE(keycode_kore); + input_set_abs_params(input, ABS_HAT0X, 0, 999, 0, 10); + input_set_abs_params(input, ABS_HAT0Y, 0, 999, 0, 10); + input_set_abs_params(input, ABS_HAT1X, 0, 999, 0, 10); + input_set_abs_params(input, ABS_HAT1Y, 0, 999, 0, 10); + input_set_abs_params(input, ABS_HAT2X, 0, 999, 0, 10); + input_set_abs_params(input, ABS_HAT2Y, 0, 999, 0, 10); + input_set_abs_params(input, ABS_HAT3X, 0, 999, 0, 10); + input_set_abs_params(input, ABS_HAT3Y, 0, 999, 0, 10); + input_set_abs_params(input, ABS_X, 0, 4096, 0, 10); + input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10); + input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10); + input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1); + snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); + break; default: /* no input methods supported on this device */ input_free_device(input); return 0; } + input->keycode = dev->keycode; + input->keycodesize = sizeof(unsigned short); + for (i = 0; i < input->keycodemax; i++) + __set_bit(dev->keycode[i], input->keybit); + ret = input_register_device(input); if (ret < 0) { input_free_device(input); @@ -238,9 +358,6 @@ return; input_unregister_device(dev->input_dev); - input_free_device(dev->input_dev); dev->input_dev = NULL; } -#endif /* CONFIG_SND_USB_CAIAQ_INPUT */ - Index: usb/caiaq/Makefile =================================================================== --- usb/caiaq/Makefile (revision 8635) +++ usb/caiaq/Makefile (working copy) @@ -1,3 +1,4 @@ -snd-usb-caiaq-objs := caiaq-device.o caiaq-audio.o caiaq-midi.o caiaq-input.o +snd-usb-caiaq-y := caiaq-device.o caiaq-audio.o caiaq-midi.o caiaq-control.o +snd-usb-caiaq-$(CONFIG_SND_USB_CAIAQ_INPUT) += caiaq-input.o obj-$(CONFIG_SND_USB_CAIAQ) += snd-usb-caiaq.o Index: usb/caiaq/caiaq-audio.c =================================================================== --- usb/caiaq/caiaq-audio.c (revision 8635) +++ usb/caiaq/caiaq-audio.c (working copy) @@ -16,7 +16,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include @@ -27,9 +26,7 @@ #include #include #include -#ifdef CONFIG_SND_USB_CAIAQ_INPUT #include -#endif #include "caiaq-device.h" #include "caiaq-audio.h" @@ -60,7 +57,7 @@ .channels_min = CHANNELS_PER_STREAM, .channels_max = CHANNELS_PER_STREAM, .buffer_bytes_max = MAX_BUFFER_SIZE, - .period_bytes_min = 4096, + .period_bytes_min = 128, .period_bytes_max = MAX_BUFFER_SIZE, .periods_min = 1, .periods_max = 1024, @@ -606,7 +603,7 @@ kfree(urbs); } -int __devinit snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) +int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) { int i, ret; @@ -648,6 +645,7 @@ dev->samplerates = dev->pcm_info.rates; switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): dev->samplerates |= SNDRV_PCM_RATE_88200; dev->samplerates |= SNDRV_PCM_RATE_192000; break; Index: usb/usbquirks.h =================================================================== --- usb/usbquirks.h (revision 8635) +++ usb/usbquirks.h (working copy) @@ -39,6 +39,47 @@ .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), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Creative Labs", + .product_name = "Sound Blaster MP3+", + .ifnum = QUIRK_NO_INTERFACE + } +}, +{ + /* E-Mu 0202 USB */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x041e, + .idProduct = 0x3f02, + .bInterfaceClass = USB_CLASS_AUDIO, +}, +{ + /* E-Mu 0404 USB */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x041e, + .idProduct = 0x3f04, + .bInterfaceClass = USB_CLASS_AUDIO, +}, +{ + /* E-Mu Tracker Pre */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x041e, + .idProduct = 0x3f0a, + .bInterfaceClass = USB_CLASS_AUDIO, +}, + /* * Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface * class matches do not take effect without an explicit ID match. @@ -57,6 +98,24 @@ USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS, .idVendor = 0x046d, + .idProduct = 0x08ae, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL +}, +{ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .idVendor = 0x046d, + .idProduct = 0x08c6, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL +}, +{ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .idVendor = 0x046d, .idProduct = 0x08f0, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL @@ -66,10 +125,27 @@ USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS, .idVendor = 0x046d, + .idProduct = 0x08f5, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL +}, +{ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .idVendor = 0x046d, .idProduct = 0x08f6, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL }, +{ + USB_DEVICE(0x046d, 0x0990), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Logitech, Inc.", + .product_name = "QuickCam Pro 9000", + .ifnum = QUIRK_NO_INTERFACE + } +}, /* * Yamaha devices @@ -159,6 +235,11 @@ YAMAHA_DEVICE(0x1043, NULL), YAMAHA_DEVICE(0x1044, NULL), YAMAHA_DEVICE(0x1045, NULL), +YAMAHA_INTERFACE(0x104e, 0, NULL), +YAMAHA_DEVICE(0x104f, NULL), +YAMAHA_DEVICE(0x1050, NULL), +YAMAHA_DEVICE(0x1051, NULL), +YAMAHA_DEVICE(0x1052, NULL), YAMAHA_DEVICE(0x2000, "DGP-7"), YAMAHA_DEVICE(0x2001, "DGP-5"), YAMAHA_DEVICE(0x2002, NULL), @@ -799,15 +880,15 @@ .data = (const struct snd_usb_audio_quirk[]) { { .ifnum = 1, - .type = QUIRK_AUDIO_EDIROL_UA700_UA25 + .type = QUIRK_AUDIO_EDIROL_UAXX }, { .ifnum = 2, - .type = QUIRK_AUDIO_EDIROL_UA700_UA25 + .type = QUIRK_AUDIO_EDIROL_UAXX }, { .ifnum = 3, - .type = QUIRK_AUDIO_EDIROL_UA700_UA25 + .type = QUIRK_AUDIO_EDIROL_UAXX }, { .ifnum = -1 @@ -965,11 +1046,35 @@ } }, { + /* has ID 0x0049 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0047), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "EDIROL", */ + /* .product_name = "UR-80", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + /* in the 96 kHz modes, only interface 1 is there */ + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, +{ /* has ID 0x004a when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0048), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "EDIROL", - .product_name = "UR-80", + /* .vendor_name = "EDIROL", */ + /* .product_name = "UR-80", */ .ifnum = 0, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = & (const struct snd_usb_midi_endpoint_info) { @@ -1051,8 +1156,16 @@ .type = QUIRK_MIDI_STANDARD_INTERFACE } }, - /* TODO: add Roland EXR support */ { + USB_DEVICE(0x0582, 0x0060), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Roland", + .product_name = "EXR Series", + .ifnum = 0, + .type = QUIRK_MIDI_STANDARD_INTERFACE + } +}, +{ /* has ID 0x0067 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0065), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { @@ -1109,15 +1222,15 @@ .data = (const struct snd_usb_audio_quirk[]) { { .ifnum = 0, - .type = QUIRK_AUDIO_EDIROL_UA700_UA25 + .type = QUIRK_AUDIO_EDIROL_UAXX }, { .ifnum = 1, - .type = QUIRK_AUDIO_EDIROL_UA700_UA25 + .type = QUIRK_AUDIO_EDIROL_UAXX }, { .ifnum = 2, - .type = QUIRK_AUDIO_EDIROL_UA700_UA25 + .type = QUIRK_AUDIO_EDIROL_UAXX }, { .ifnum = -1 @@ -1153,38 +1266,7 @@ } } }, -/* Roland UA-101 in High-Speed Mode only */ { - USB_DEVICE(0x0582, 0x007d), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Roland", - .product_name = "UA-101", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_COMPOSITE, - .data = (const struct snd_usb_audio_quirk[]) { - { - .ifnum = 0, - .type = QUIRK_AUDIO_EDIROL_UA101 - }, - { - .ifnum = 1, - .type = QUIRK_AUDIO_EDIROL_UA101 - }, - { - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const struct snd_usb_midi_endpoint_info) { - .out_cables = 0x0001, - .in_cables = 0x0001 - } - }, - { - .ifnum = -1 - } - } - } -}, -{ /* has ID 0x0081 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0080), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { @@ -1215,8 +1297,29 @@ } }, /* TODO: add Edirol PC-80 support */ - /* TODO: add Edirol UA-1EX support */ { + USB_DEVICE(0x0582, 0x0096), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "EDIROL", + .product_name = "UA-1EX", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, +{ USB_DEVICE(0x0582, 0x009a), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { .vendor_name = "EDIROL", @@ -1229,7 +1332,229 @@ } } }, +{ + /* + * This quirk is for the "Advanced Driver" mode. If off, the UA-4FX + * is standard compliant, but has only 16-bit PCM and no MIDI. + */ + USB_DEVICE(0x0582, 0x00a3), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "EDIROL", + .product_name = "UA-4FX", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_EDIROL_UAXX + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_EDIROL_UAXX + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_EDIROL_UAXX + }, + { + .ifnum = -1 + } + } + } +}, /* TODO: add Edirol MD-P1 support */ +{ + USB_DEVICE(0x582, 0x00a6), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Roland", + .product_name = "Juno-G", + .ifnum = 0, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + } +}, +{ + /* Roland SH-201 */ + USB_DEVICE(0x0582, 0x00ad), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Roland", + .product_name = "SH-201", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, +{ + /* Roland SonicCell */ + USB_DEVICE(0x0582, 0x00c2), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Roland", + .product_name = "SonicCell", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, +{ + /* Edirol M-16DX */ + /* FIXME: This quirk gives a good-working capture stream but the + * playback seems problematic because of lacking of sync + * with capture stream. It needs to sync with the capture + * clock. As now, you'll get frequent sound distortions + * via the playback. + */ + USB_DEVICE(0x0582, 0x00c4), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, +{ + /* BOSS GT-10 */ + USB_DEVICE(0x0582, 0x00da), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, +{ + /* Advanced modes of the Edirol UA-25EX. + * For the standard mode, UA-25EX has ID 0582:00e7, which + * offers only 16-bit PCM at 44.1 kHz and no MIDI. + */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e6), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "EDIROL", + .product_name = "UA-25EX", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_EDIROL_UAXX + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_EDIROL_UAXX + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_EDIROL_UAXX + }, + { + .ifnum = -1 + } + } + } +}, +{ + /* has ID 0x00ea when not in Advanced Driver mode */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Roland", */ + /* .product_name = "UA-1G", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, /* Guillemot devices */ { @@ -1497,6 +1822,40 @@ } } }, +{ + USB_DEVICE(0x0763, 0x2019), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Ozone Academic", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 3, + .type = QUIRK_MIDI_MIDIMAN, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, /* Casio devices */ { @@ -1536,7 +1895,7 @@ .data = & (const struct snd_usb_audio_quirk[]) { { .ifnum = 0, - .type = QUIRK_MIDI_RAW + .type = QUIRK_MIDI_FASTLANE }, { .ifnum = 1, @@ -1549,17 +1908,6 @@ } }, -{ - /* Creative Sound Blaster MP3+ */ - USB_DEVICE(0x041e, 0x3010), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Creative Labs", - .product_name = "Sound Blaster MP3+", - .ifnum = QUIRK_NO_INTERFACE - } - -}, - /* Emagic devices */ { USB_DEVICE(0x086a, 0x0001), @@ -1630,6 +1978,14 @@ } }, { + USB_DEVICE(0x0ccd, 0x0028), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "TerraTec", + .product_name = "Aureon5.1MkII", + .ifnum = QUIRK_NO_INTERFACE + } +}, +{ USB_DEVICE(0x0ccd, 0x0035), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { .vendor_name = "Miditech", @@ -1639,6 +1995,24 @@ } }, +/* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */ +{ + USB_DEVICE(0x103d, 0x0100), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Stanton", + .product_name = "ScratchAmp", + .ifnum = QUIRK_NO_INTERFACE + } +}, +{ + USB_DEVICE(0x103d, 0x0101), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Stanton", + .product_name = "ScratchAmp", + .ifnum = QUIRK_NO_INTERFACE + } +}, + /* Novation EMS devices */ { USB_DEVICE_VENDOR_SPEC(0x1235, 0x0001), @@ -1668,6 +2042,17 @@ } }, +/* */ +{ + /* aka. Serato Scratch Live DJ Box */ + USB_DEVICE(0x13e5, 0x0001), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Rane", + .product_name = "SL-1", + .ifnum = QUIRK_NO_INTERFACE + } +}, + /* Miditech devices */ { USB_DEVICE(0x4752, 0x0011), @@ -1689,7 +2074,121 @@ } }, +/* Hauppauge HVR-950Q and HVR-850 */ { + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7200), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7201), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7202), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7203), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7204), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7205), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7250), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7230), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-850", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, + +{ /* * Some USB MIDI devices don't have an audio control interface, * so we have to grab MIDI streaming interfaces here.