diff options
50 files changed, 354 insertions, 187 deletions
diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/hd-audio/models.rst index 773d2bfacc6c..1fee5a4f6660 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst @@ -82,6 +82,8 @@ tpt460 Lenovo Thinkpad T460/560 setup dual-codecs Lenovo laptops with dual codecs +alc700-ref + Intel reference board with ALC700 codec ALC66x/67x/892 ============== diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 47903d510955..8b800e34407b 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -187,6 +187,31 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); /*-------------------------------------------------------------------*/ +static const int pipetypes[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT +}; + +/** + * usb_urb_ep_type_check - sanity check of endpoint in the given urb + * @urb: urb to be checked + * + * This performs a light-weight sanity check for the endpoint in the + * given urb. It returns 0 if the urb contains a valid endpoint, otherwise + * a negative error code. + */ +int usb_urb_ep_type_check(const struct urb *urb) +{ + const struct usb_host_endpoint *ep; + + ep = usb_pipe_endpoint(urb->dev, urb->pipe); + if (!ep) + return -EINVAL; + if (usb_pipetype(urb->pipe) != pipetypes[usb_endpoint_type(&ep->desc)]) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL_GPL(usb_urb_ep_type_check); + /** * usb_submit_urb - issue an asynchronous transfer request for an endpoint * @urb: pointer to the urb describing the request @@ -326,9 +351,6 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { - static int pipetypes[4] = { - PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT - }; int xfertype, max; struct usb_device *dev; struct usb_host_endpoint *ep; @@ -444,7 +466,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) */ /* Check that the pipe's type matches the endpoint's type */ - if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) + if (usb_urb_ep_type_check(urb)) dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", usb_pipetype(urb->pipe), pipetypes[xfertype]); diff --git a/include/linux/usb.h b/include/linux/usb.h index cb9fbd54386e..2b861804fffa 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1728,6 +1728,8 @@ static inline int usb_urb_dir_out(struct urb *urb) return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT; } +int usb_urb_ep_type_check(const struct urb *urb); + void *usb_alloc_coherent(struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma); void usb_free_coherent(struct usb_device *dev, size_t size, diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 96546b30e900..6f1118545bb8 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -111,8 +111,7 @@ void snd_hdac_device_unregister(struct hdac_device *codec); int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name); int snd_hdac_codec_modalias(struct hdac_device *hdac, char *buf, size_t size); -int snd_hdac_refresh_widgets(struct hdac_device *codec); -int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec); +int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs); unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, unsigned int verb, unsigned int parm); diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h index a03acd0d398a..695257ae64ac 100644 --- a/include/sound/seq_virmidi.h +++ b/include/sound/seq_virmidi.h @@ -60,6 +60,7 @@ struct snd_virmidi_dev { int port; /* created/attached port */ unsigned int flags; /* SNDRV_VIRMIDI_* */ rwlock_t filelist_lock; + struct rw_semaphore filelist_sem; struct list_head filelist; }; diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c index 1ac0c423903e..5603e49f7bf7 100644 --- a/sound/core/hrtimer.c +++ b/sound/core/hrtimer.c @@ -127,7 +127,7 @@ static int snd_hrtimer_stop(struct snd_timer *t) return 0; } -static struct snd_timer_hardware hrtimer_hw = { +static const struct snd_timer_hardware hrtimer_hw __initconst = { .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_TASKLET, .open = snd_hrtimer_open, .close = snd_hrtimer_close, diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index a73baa1242be..8faae3d1455d 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -228,6 +228,8 @@ static int snd_hwdep_dsp_load(struct snd_hwdep *hw, memset(&info, 0, sizeof(info)); if (copy_from_user(&info, _info, sizeof(info))) return -EFAULT; + if (info.index >= 32) + return -EINVAL; /* check whether the dsp was already loaded */ if (hw->dsp_loaded & (1 << info.index)) return -EBUSY; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 2fec2feac387..a4d92e46c459 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -195,7 +195,6 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) { - struct snd_pcm_runtime *runtime; struct snd_pcm *pcm = substream->pcm; struct snd_pcm_str *pstr = substream->pstr; @@ -211,7 +210,6 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) info->subdevices_count = pstr->substream_count; info->subdevices_avail = pstr->substream_count - pstr->substream_opened; strlcpy(info->subname, substream->name, sizeof(info->subname)); - runtime = substream->runtime; return 0; } diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index ea2d0ae85bd3..84759d9c54bf 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -802,6 +802,10 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e return -EMLINK; } + if (snd_seq_ev_is_variable(event) && + snd_BUG_ON(atomic && (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR))) + return -EINVAL; + if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS || event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) result = deliver_to_subscribers(client, event, atomic, hop); @@ -1259,6 +1263,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg) struct snd_seq_port_info *info = arg; struct snd_seq_client_port *port; struct snd_seq_port_callback *callback; + int port_idx; /* it is not allowed to create the port for an another client */ if (info->addr.client != client->number) @@ -1269,7 +1274,9 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg) return -ENOMEM; if (client->type == USER_CLIENT && info->kernel) { - snd_seq_delete_port(client, port->addr.port); + port_idx = port->addr.port; + snd_seq_port_unlock(port); + snd_seq_delete_port(client, port_idx); return -EINVAL; } if (client->type == KERNEL_CLIENT) { @@ -1290,6 +1297,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg) snd_seq_set_port_info(port, info); snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port); + snd_seq_port_unlock(port); return 0; } diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 0a7020c82bfc..d21ece9f8d73 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -122,7 +122,9 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp) } -/* create a port, port number is returned (-1 on failure) */ +/* create a port, port number is returned (-1 on failure); + * the caller needs to unref the port via snd_seq_port_unlock() appropriately + */ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, int port) { @@ -151,6 +153,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, snd_use_lock_init(&new_port->use_lock); port_subs_info_init(&new_port->c_src); port_subs_info_init(&new_port->c_dest); + snd_use_lock_use(&new_port->use_lock); num = port >= 0 ? port : 0; mutex_lock(&client->ports_mutex); @@ -165,9 +168,9 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, list_add_tail(&new_port->list, &p->list); client->num_ports++; new_port->addr.port = num; /* store the port number in the port */ + sprintf(new_port->name, "port-%d", num); write_unlock_irqrestore(&client->ports_lock, flags); mutex_unlock(&client->ports_mutex); - sprintf(new_port->name, "port-%d", num); return new_port; } diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 8d93a4021c78..f48a4cd24ffc 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -77,13 +77,17 @@ static void snd_virmidi_init_event(struct snd_virmidi *vmidi, * decode input event and put to read buffer of each opened file */ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, - struct snd_seq_event *ev) + struct snd_seq_event *ev, + bool atomic) { struct snd_virmidi *vmidi; unsigned char msg[4]; int len; - read_lock(&rdev->filelist_lock); + if (atomic) + read_lock(&rdev->filelist_lock); + else + down_read(&rdev->filelist_sem); list_for_each_entry(vmidi, &rdev->filelist, list) { if (!vmidi->trigger) continue; @@ -97,7 +101,10 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, snd_rawmidi_receive(vmidi->substream, msg, len); } } - read_unlock(&rdev->filelist_lock); + if (atomic) + read_unlock(&rdev->filelist_lock); + else + up_read(&rdev->filelist_sem); return 0; } @@ -115,7 +122,7 @@ int snd_virmidi_receive(struct snd_rawmidi *rmidi, struct snd_seq_event *ev) struct snd_virmidi_dev *rdev; rdev = rmidi->private_data; - return snd_virmidi_dev_receive_event(rdev, ev); + return snd_virmidi_dev_receive_event(rdev, ev, true); } #endif /* 0 */ @@ -130,7 +137,7 @@ static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct, rdev = private_data; if (!(rdev->flags & SNDRV_VIRMIDI_USE)) return 0; /* ignored */ - return snd_virmidi_dev_receive_event(rdev, ev); + return snd_virmidi_dev_receive_event(rdev, ev, atomic); } /* @@ -209,7 +216,6 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream) struct snd_virmidi_dev *rdev = substream->rmidi->private_data; struct snd_rawmidi_runtime *runtime = substream->runtime; struct snd_virmidi *vmidi; - unsigned long flags; vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL); if (vmidi == NULL) @@ -223,9 +229,11 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream) vmidi->client = rdev->client; vmidi->port = rdev->port; runtime->private_data = vmidi; - write_lock_irqsave(&rdev->filelist_lock, flags); + down_write(&rdev->filelist_sem); + write_lock_irq(&rdev->filelist_lock); list_add_tail(&vmidi->list, &rdev->filelist); - write_unlock_irqrestore(&rdev->filelist_lock, flags); + write_unlock_irq(&rdev->filelist_lock); + up_write(&rdev->filelist_sem); vmidi->rdev = rdev; return 0; } @@ -264,9 +272,11 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) struct snd_virmidi_dev *rdev = substream->rmidi->private_data; struct snd_virmidi *vmidi = substream->runtime->private_data; + down_write(&rdev->filelist_sem); write_lock_irq(&rdev->filelist_lock); list_del(&vmidi->list); write_unlock_irq(&rdev->filelist_lock); + up_write(&rdev->filelist_sem); snd_midi_event_free(vmidi->parser); substream->runtime->private_data = NULL; kfree(vmidi); @@ -520,6 +530,7 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi rdev->rmidi = rmidi; rdev->device = device; rdev->client = -1; + init_rwsem(&rdev->filelist_sem); rwlock_init(&rdev->filelist_lock); INIT_LIST_HEAD(&rdev->filelist); rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH; diff --git a/sound/core/timer.c b/sound/core/timer.c index 6cdd04a45962..09acaf2b2e57 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1028,15 +1028,17 @@ EXPORT_SYMBOL(snd_timer_global_register); struct snd_timer_system_private { struct timer_list tlist; + struct snd_timer *snd_timer; unsigned long last_expires; unsigned long last_jiffies; unsigned long correction; }; -static void snd_timer_s_function(unsigned long data) +static void snd_timer_s_function(struct timer_list *t) { - struct snd_timer *timer = (struct snd_timer *)data; - struct snd_timer_system_private *priv = timer->private_data; + struct snd_timer_system_private *priv = from_timer(priv, t, + tlist); + struct snd_timer *timer = priv->snd_timer; unsigned long jiff = jiffies; if (time_after(jiff, priv->last_expires)) priv->correction += (long)jiff - (long)priv->last_expires; @@ -1118,7 +1120,8 @@ static int snd_timer_register_system(void) snd_timer_free(timer); return -ENOMEM; } - setup_timer(&priv->tlist, snd_timer_s_function, (unsigned long) timer); + priv->snd_timer = timer; + timer_setup(&priv->tlist, snd_timer_s_function, 0); timer->private_data = priv; timer->private_free = snd_timer_free_system; return snd_timer_global_register(timer); diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 978dc1801b3a..8f7d0d9ed762 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -314,7 +314,8 @@ int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus) break; default: - dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap); + dev_err(bus->dev, "Unknown capability %d\n", cur_cap); + cur_cap = 0; break; } diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index 19deb306facb..06f845e293cb 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -87,7 +87,7 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, fg = codec->afg ? codec->afg : codec->mfg; - err = snd_hdac_refresh_widgets(codec); + err = snd_hdac_refresh_widgets(codec, false); if (err < 0) goto error; @@ -388,11 +388,12 @@ static void setup_fg_nodes(struct hdac_device *codec) /** * snd_hdac_refresh_widgets - Reset the widget start/end nodes * @codec: the codec object + * @sysfs: re-initialize sysfs tree, too */ -int snd_hdac_refresh_widgets(struct hdac_device *codec) +int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs) { hda_nid_t start_nid; - int nums; + int nums, err; nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid); if (!start_nid || nums <= 0 || nums >= 0xff) { @@ -401,6 +402,12 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec) return -EINVAL; } + if (sysfs) { + err = hda_widget_sysfs_reinit(codec, start_nid, nums); + if (err < 0) + return err; + } + codec->num_nodes = nums; codec->start_nid = start_nid; codec->end_nid = start_nid + nums; @@ -408,36 +415,6 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec) } EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets); -/** - * snd_hdac_refresh_widget_sysfs - Reset the codec widgets and reinit the - * codec sysfs - * @codec: the codec object - * - * first we need to remove sysfs, then refresh widgets and lastly - * recreate it - */ -int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec) -{ - int ret; - - if (device_is_registered(&codec->dev)) - hda_widget_sysfs_exit(codec); - ret = snd_hdac_refresh_widgets(codec); - if (ret) { - dev_err(&codec->dev, "failed to refresh widget: %d\n", ret); - return ret; - } - if (device_is_registered(&codec->dev)) { - ret = hda_widget_sysfs_init(codec); - if (ret) { - dev_err(&codec->dev, "failed to init sysfs: %d\n", ret); - return ret; - } - } - return ret; -} -EXPORT_SYMBOL_GPL(snd_hdac_refresh_widget_sysfs); - /* return CONNLIST_LEN parameter of the given widget */ static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid) { diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c index 42d61bf41969..e123ba6b2e81 100644 --- a/sound/hda/hdac_sysfs.c +++ b/sound/hda/hdac_sysfs.c @@ -414,3 +414,50 @@ void hda_widget_sysfs_exit(struct hdac_device *codec) { widget_tree_free(codec); } + +int hda_widget_sysfs_reinit(struct hdac_device *codec, + hda_nid_t start_nid, int num_nodes) +{ + struct hdac_widget_tree *tree; + hda_nid_t end_nid = start_nid + num_nodes; + hda_nid_t nid; + int i; + + if (!codec->widgets) + return hda_widget_sysfs_init(codec); + + tree = kmemdup(codec->widgets, sizeof(*tree), GFP_KERNEL); + if (!tree) + return -ENOMEM; + + tree->nodes = kcalloc(num_nodes + 1, sizeof(*tree->nodes), GFP_KERNEL); + if (!tree->nodes) { + kfree(tree); + return -ENOMEM; + } + + /* prune non-existing nodes */ + for (i = 0, nid = codec->start_nid; i < codec->num_nodes; i++, nid++) { + if (nid < start_nid || nid >= end_nid) + free_widget_node(codec->widgets->nodes[i], + &widget_node_group); + } + + /* add new nodes */ + for (i = 0, nid = start_nid; i < num_nodes; i++, nid++) { + if (nid < codec->start_nid || nid >= codec->end_nid) + add_widget_node(tree->root, nid, &widget_node_group, + &tree->nodes[i]); + else + tree->nodes[i] = + codec->widgets->nodes[nid - codec->start_nid]; + } + + /* replace with the new tree */ + kfree(codec->widgets->nodes); + kfree(codec->widgets); + codec->widgets = tree; + + kobject_uevent(tree->root, KOBJ_CHANGE); + return 0; +} diff --git a/sound/hda/local.h b/sound/hda/local.h index 0d5bb159d538..c586ea62d49e 100644 --- a/sound/hda/local.h +++ b/sound/hda/local.h @@ -28,6 +28,8 @@ static inline unsigned int get_wcaps_channels(u32 wcaps) extern const struct attribute_group *hdac_dev_attr_groups[]; int hda_widget_sysfs_init(struct hdac_device *codec); +int hda_widget_sysfs_reinit(struct hdac_device *codec, hda_nid_t start_nid, + int num_nodes); void hda_widget_sysfs_exit(struct hdac_device *codec); #endif /* __HDAC_LOCAL_H */ diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 70d023a85bf5..720361455c60 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -573,10 +573,8 @@ static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream) static void snd_card_asihpi_pcm_int_stop(struct snd_pcm_substream *substream) { - struct snd_card_asihpi_pcm *dpcm; struct snd_card_asihpi *card; - dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data; card = snd_pcm_substream_chip(substream); hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index, @@ -749,9 +747,9 @@ static inline unsigned int modulo_min(unsigned int a, unsigned int b, /** Timer function, equivalent to interrupt service routine for cards */ -static void snd_card_asihpi_timer_function(unsigned long data) +static void snd_card_asihpi_timer_function(struct timer_list *t) { - struct snd_card_asihpi_pcm *dpcm = (struct snd_card_asihpi_pcm *)data; + struct snd_card_asihpi_pcm *dpcm = from_timer(dpcm, t, timer); struct snd_pcm_substream *substream = dpcm->substream; struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime; @@ -863,7 +861,6 @@ static void snd_card_asihpi_timer_function(unsigned long data) snd_pcm_group_for_each_entry(s, substream) { struct snd_card_asihpi_pcm *ds = s->runtime->private_data; - runtime = s->runtime; /* don't link Cap and Play */ if (substream->stream != s->stream) @@ -948,7 +945,7 @@ static void snd_card_asihpi_int_task(unsigned long data) asihpi = (struct snd_card_asihpi *)a->snd_card->private_data; if (asihpi->llmode_streampriv) snd_card_asihpi_timer_function( - (unsigned long)asihpi->llmode_streampriv); + &asihpi->llmode_streampriv->timer); } static void snd_card_asihpi_isr(struct hpi_adapter *a) @@ -1059,8 +1056,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) If internal and other stream playing, can't switch */ - setup_timer(&dpcm->timer, snd_card_asihpi_timer_function, - (unsigned long) dpcm); + timer_setup(&dpcm->timer, snd_card_asihpi_timer_function, 0); dpcm->substream = substream; runtime->private_data = dpcm; runtime->private_free = snd_card_asihpi_runtime_free; @@ -1240,8 +1236,7 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) if (err) return -EIO; - setup_timer(&dpcm->timer, snd_card_asihpi_timer_function, - (unsigned long) dpcm); + timer_setup(&dpcm->timer, snd_card_asihpi_timer_function, 0); dpcm->substream = substream; runtime->private_data = dpcm; runtime->private_free = snd_card_asihpi_runtime_free; diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index c308a4f70550..4083c8b01619 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -2628,7 +2628,7 @@ static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode) else edi = 0x1ffff; } else { - i = edi = 0x800; + edi = 0x800; } /* this_04 and this_08 are the CASp4Src's (samplerate converters) */ vortex_src_setupchannel(vortex, this_04, edi, 0, 1, diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index cf05229b569b..bde0d1954f56 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -280,7 +280,6 @@ static void snd_emu10k1_proc_rates_read(struct snd_info_entry *entry, struct snd_emu10k1 *emu = entry->private_data; unsigned int val, tmp, n; val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0); - tmp = (val >> 16) & 0x8; for (n = 0; n < 4; n++) { tmp = val >> (16 + (n*4)); if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]); diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index d4cd6451fdca..39f79a6b5283 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -732,7 +732,7 @@ static void snd_es1371_codec_wait(struct snd_ac97 *ac97) static void snd_es1371_adc_rate(struct ensoniq * ensoniq, unsigned int rate) { - unsigned int n, truncm, freq, result; + unsigned int n, truncm, freq; mutex_lock(&ensoniq->src_mutex); n = rate / 3000; @@ -740,7 +740,6 @@ static void snd_es1371_adc_rate(struct ensoniq * ensoniq, unsigned int rate) n--; truncm = (21 * n - 1) | 1; freq = ((48000UL << 15) / rate) * n; - result = (48000UL << 15) / (freq / n); if (rate >= 24000) { if (truncm > 239) truncm = 239; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3db26c451837..bb086665c3e0 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -977,7 +977,7 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec) hda_nid_t fg; int err; - err = snd_hdac_refresh_widget_sysfs(&codec->core); + err = snd_hdac_refresh_widgets(&codec->core, true); if (err < 0) return err; diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 28e265a88383..5cc65093d941 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -795,6 +795,8 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, hda_nid_t nid = path->path[i]; nums = snd_hda_get_conn_list(codec, nid, &conn); + if (nums < 0) + return; type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_PIN || (type == AC_WID_AUD_IN && codec->single_adc_amp)) { diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 3e73d5c6ccfc..768ea8651993 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -27,6 +27,7 @@ #include <linux/mutex.h> #include <linux/module.h> #include <linux/firmware.h> +#include <linux/kernel.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" @@ -3605,8 +3606,7 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, static int ca0132_voicefx_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - unsigned int items = sizeof(ca0132_voicefx_presets) - / sizeof(struct ct_voicefx_preset); + unsigned int items = ARRAY_SIZE(ca0132_voicefx_presets); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -3635,10 +3635,8 @@ static int ca0132_voicefx_put(struct snd_kcontrol *kcontrol, struct ca0132_spec *spec = codec->spec; int i, err = 0; int sel = ucontrol->value.enumerated.item[0]; - unsigned int items = sizeof(ca0132_voicefx_presets) - / sizeof(struct ct_voicefx_preset); - if (sel >= items) + if (sel >= ARRAY_SIZE(ca0132_voicefx_presets)) return 0; codec_dbg(codec, "ca0132_voicefx_put: sel=%d, preset=%s\n", diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0ce71111b4e3..1a0163b81f5b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6357,6 +6357,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC292_FIXUP_TPT440, .name = "tpt440"}, {.id = ALC292_FIXUP_TPT460, .name = "tpt460"}, {.id = ALC233_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"}, + {.id = ALC700_FIXUP_INTEL_REFERENCE, .name = "alc700-ref"}, {} }; #define ALC225_STANDARD_PINS \ diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h index d461df357aa1..5a07cda011b3 100644 --- a/sound/pci/oxygen/xonar_dg.h +++ b/sound/pci/oxygen/xonar_dg.h @@ -51,6 +51,6 @@ void dg_suspend(struct oxygen *chip); void dg_resume(struct oxygen *chip); void dg_cleanup(struct oxygen *chip); -extern struct oxygen_model model_xonar_dg; +extern const struct oxygen_model model_xonar_dg; #endif diff --git a/sound/pci/oxygen/xonar_dg_mixer.c b/sound/pci/oxygen/xonar_dg_mixer.c index b885dac28a09..d22fbe8aebd0 100644 --- a/sound/pci/oxygen/xonar_dg_mixer.c +++ b/sound/pci/oxygen/xonar_dg_mixer.c @@ -449,7 +449,7 @@ static int dg_mixer_init(struct oxygen *chip) return 0; } -struct oxygen_model model_xonar_dg = { +const struct oxygen_model model_xonar_dg = { .longname = "C-Media Oxygen HD Audio", .chip = "CMI8786", .init = dg_init, diff --git a/sound/sh/aica.c b/sound/sh/aica.c index fdc680ae8aa0..2b26311405a4 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -299,14 +299,14 @@ static void run_spu_dma(struct work_struct *work) } } -static void aica_period_elapsed(unsigned long timer_var) +static void aica_period_elapsed(struct timer_list *t) { + struct snd_card_aica *dreamcastcard = from_timer(dreamcastcard, + t, timer); + struct snd_pcm_substream *substream = dreamcastcard->timer_substream; /*timer function - so cannot sleep */ int play_period; struct snd_pcm_runtime *runtime; - struct snd_pcm_substream *substream; - struct snd_card_aica *dreamcastcard; - substream = (struct snd_pcm_substream *) timer_var; runtime = substream->runtime; dreamcastcard = substream->pcm->private_data; /* Have we played out an additional period? */ @@ -336,12 +336,12 @@ static void spu_begin_dma(struct snd_pcm_substream *substream) /*get the queue to do the work */ schedule_work(&(dreamcastcard->spu_dma_work)); /* Timer may already be running */ - if (unlikely(dreamcastcard->timer.data)) { + if (unlikely(dreamcastcard->timer_substream)) { mod_timer(&dreamcastcard->timer, jiffies + 4); return; } - setup_timer(&dreamcastcard->timer, aica_period_elapsed, - (unsigned long) substream); + timer_setup(&dreamcastcard->timer, aica_period_elapsed, 0); + dreamcastcard->timer_substream = substream; mod_timer(&dreamcastcard->timer, jiffies + 4); } @@ -379,7 +379,7 @@ static int snd_aicapcm_pcm_close(struct snd_pcm_substream { struct snd_card_aica *dreamcastcard = substream->pcm->private_data; flush_work(&(dreamcastcard->spu_dma_work)); - if (dreamcastcard->timer.data) + if (dreamcastcard->timer_substream) del_timer(&dreamcastcard->timer); kfree(dreamcastcard->channel); spu_disable(); @@ -600,7 +600,7 @@ static int snd_aica_probe(struct platform_device *devptr) { int err; struct snd_card_aica *dreamcastcard; - dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL); + dreamcastcard = kzalloc(sizeof(struct snd_card_aica), GFP_KERNEL); if (unlikely(!dreamcastcard)) return -ENOMEM; err = snd_card_new(&devptr->dev, index, SND_AICA_DRIVER, @@ -619,8 +619,6 @@ static int snd_aica_probe(struct platform_device *devptr) err = snd_aicapcmchip(dreamcastcard, 0); if (unlikely(err < 0)) goto freedreamcast; - dreamcastcard->timer.data = 0; - dreamcastcard->channel = NULL; /* Add basic controls */ err = add_aicamixer_controls(dreamcastcard); if (unlikely(err < 0)) diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c index de19e108974a..764ff4bc2089 100644 --- a/sound/synth/emux/emux_oss.c +++ b/sound/synth/emux/emux_oss.c @@ -430,7 +430,6 @@ gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, { int voice; unsigned short p1; - short p2; int plong; struct snd_midi_channel *chan; @@ -445,7 +444,6 @@ gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, chan = &port->chset.channels[voice]; p1 = *(unsigned short *) &event[4]; - p2 = *(short *) &event[6]; plong = *(int*) &event[4]; switch (cmd) { diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index c7641cb50616..17d5e3ee6d73 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c @@ -174,11 +174,9 @@ destroy_chip: static void usb6fire_chip_disconnect(struct usb_interface *intf) { struct sfire_chip *chip; - struct snd_card *card; chip = usb_get_intfdata(intf); if (chip) { /* if !chip, fw upload has been performed */ - card = chip->card; chip->intf_count--; if (!chip->intf_count) { mutex_lock(®ister_mutex); diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c index 7371e5b06035..a6408209d7f1 100644 --- a/sound/usb/bcd2000/bcd2000.c +++ b/sound/usb/bcd2000/bcd2000.c @@ -342,6 +342,13 @@ static int bcd2000_init_midi(struct bcd2000 *bcd2k) bcd2k->midi_out_buf, BUFSIZE, bcd2000_output_complete, bcd2k, 1); + /* sanity checks of EPs before actually submitting */ + if (usb_urb_ep_type_check(bcd2k->midi_in_urb) || + usb_urb_ep_type_check(bcd2k->midi_out_urb)) { + dev_err(&bcd2k->dev->dev, "invalid MIDI EP\n"); + return -EINVAL; + } + bcd2000_init_device(bcd2k); return 0; diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index 0fb6b1b79261..d55ca48de3ea 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -461,6 +461,13 @@ static int init_card(struct snd_usb_caiaqdev *cdev) cdev->midi_out_buf, EP1_BUFSIZE, snd_usb_caiaq_midi_output_done, cdev); + /* sanity checks of EPs before actually submitting */ + if (usb_urb_ep_type_check(&cdev->ep1_in_urb) || + usb_urb_ep_type_check(&cdev->midi_out_urb)) { + dev_err(dev, "invalid EPs\n"); + return -EINVAL; + } + init_waitqueue_head(&cdev->ep1_wait_queue); init_waitqueue_head(&cdev->prepare_wait_queue); @@ -469,10 +476,12 @@ static int init_card(struct snd_usb_caiaqdev *cdev) err = snd_usb_caiaq_send_command(cdev, EP1_CMD_GET_DEVICE_INFO, NULL, 0); if (err) - return err; + goto err_kill_urb; - if (!wait_event_timeout(cdev->ep1_wait_queue, cdev->spec_received, HZ)) - return -ENODEV; + if (!wait_event_timeout(cdev->ep1_wait_queue, cdev->spec_received, HZ)) { + err = -ENODEV; + goto err_kill_urb; + } usb_string(usb_dev, usb_dev->descriptor.iManufacturer, cdev->vendor_name, CAIAQ_USB_STR_LEN); @@ -507,6 +516,10 @@ static int init_card(struct snd_usb_caiaqdev *cdev) setup_card(cdev); return 0; + + err_kill_urb: + usb_kill_urb(&cdev->ep1_in_urb); + return err; } static int snd_probe(struct usb_interface *intf, diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index 4b3fb91deecd..e883659ea6e7 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c @@ -718,6 +718,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev) usb_rcvbulkpipe(usb_dev, 0x4), cdev->ep4_in_buf, EP4_BUFSIZE, snd_usb_caiaq_ep4_reply_dispatch, cdev); + ret = usb_urb_ep_type_check(cdev->ep4_in_urb); + if (ret < 0) + goto exit_free_idev; snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5); @@ -757,6 +760,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev) usb_rcvbulkpipe(usb_dev, 0x4), cdev->ep4_in_buf, EP4_BUFSIZE, snd_usb_caiaq_ep4_reply_dispatch, cdev); + ret = usb_urb_ep_type_check(cdev->ep4_in_urb); + if (ret < 0) + goto exit_free_idev; snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5); @@ -802,6 +808,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev) usb_rcvbulkpipe(usb_dev, 0x4), cdev->ep4_in_buf, EP4_BUFSIZE, snd_usb_caiaq_ep4_reply_dispatch, cdev); + ret = usb_urb_ep_type_check(cdev->ep4_in_urb); + if (ret < 0) + goto exit_free_idev; snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5); break; diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c index 175d8d6b7f59..396c317115b1 100644 --- a/sound/usb/hiface/pcm.c +++ b/sound/usb/hiface/pcm.c @@ -541,6 +541,8 @@ static int hiface_pcm_init_urb(struct pcm_urb *urb, usb_fill_bulk_urb(&urb->instance, chip->dev, usb_sndbulkpipe(chip->dev, ep), (void *)urb->buffer, PCM_PACKET_SIZE, handler, urb); + if (usb_urb_ep_type_check(&urb->instance)) + return -EINVAL; init_usb_anchor(&urb->submitted); return 0; @@ -599,9 +601,12 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq) mutex_init(&rt->stream_mutex); spin_lock_init(&rt->playback.lock); - for (i = 0; i < PCM_N_URBS; i++) - hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP, + for (i = 0; i < PCM_N_URBS; i++) { + ret = hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP, hiface_pcm_out_urb_handler); + if (ret < 0) + return ret; + } ret = snd_pcm_new(chip->card, "USB-SPDIF Audio", 0, 1, 0, &pcm); if (ret < 0) { diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 7c812565f90d..947d6168f24a 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -248,7 +248,7 @@ static int snd_line6_capture_close(struct snd_pcm_substream *substream) } /* capture operators */ -struct snd_pcm_ops snd_line6_capture_ops = { +const struct snd_pcm_ops snd_line6_capture_ops = { .open = snd_line6_capture_open, .close = snd_line6_capture_close, .ioctl = snd_pcm_lib_ioctl, diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h index 890b21bff18c..b67ccc39fd25 100644 --- a/sound/usb/line6/capture.h +++ b/sound/usb/line6/capture.h @@ -17,7 +17,7 @@ #include "driver.h" #include "pcm.h" -extern struct snd_pcm_ops snd_line6_capture_ops; +extern const struct snd_pcm_ops snd_line6_capture_ops; extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize); diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index 0ff5a7d2e19f..4f9613e5fc9e 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -78,6 +78,13 @@ static int line6_start_listen(struct usb_line6 *line6) line6->buffer_listen, LINE6_BUFSIZE_LISTEN, line6_data_received, line6); } + + /* sanity checks of EP before actually submitting */ + if (usb_urb_ep_type_check(line6->urb_listen)) { + dev_err(line6->ifcdev, "invalid control EP\n"); + return -EINVAL; + } + line6->urb_listen->actual_length = 0; err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC); return err; @@ -168,26 +175,33 @@ static int line6_send_raw_message_async_part(struct message *msg, } msg->done += bytes; - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval < 0) { - dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", - __func__, retval); - usb_free_urb(urb); - kfree(msg); - return retval; - } + /* sanity checks of EP before actually submitting */ + retval = usb_urb_ep_type_check(urb); + if (retval < 0) + goto error; + + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval < 0) + goto error; return 0; + + error: + dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", + __func__, retval); + usb_free_urb(urb); + kfree(msg); + return retval; } /* Setup and start timer. */ void line6_start_timer(struct timer_list *timer, unsigned long msecs, - void (*function)(unsigned long), unsigned long data) + void (*function)(struct timer_list *t)) { - setup_timer(timer, function, data); + timer->function = (TIMER_FUNC_TYPE)function; mod_timer(timer, jiffies + msecs_to_jiffies(msecs)); } EXPORT_SYMBOL_GPL(line6_start_timer); @@ -779,9 +793,10 @@ int line6_probe(struct usb_interface *interface, return 0; error: - if (line6->disconnect) - line6->disconnect(line6); - snd_card_free(card); + /* we can call disconnect callback here because no close-sync is + * needed yet at this point + */ + line6_disconnect(interface); return ret; } EXPORT_SYMBOL_GPL(line6_probe); diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h index dc97895547be..61425597eb61 100644 --- a/sound/usb/line6/driver.h +++ b/sound/usb/line6/driver.h @@ -198,8 +198,7 @@ extern int line6_send_sysex_message(struct usb_line6 *line6, extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); extern void line6_start_timer(struct timer_list *timer, unsigned long msecs, - void (*function)(unsigned long), - unsigned long data); + void (*function)(struct timer_list *t)); extern int line6_version_request_async(struct usb_line6 *line6); extern int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, unsigned datalen); diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c index 1d3a23b02d68..6d7cde56a355 100644 --- a/sound/usb/line6/midi.c +++ b/sound/usb/line6/midi.c @@ -130,16 +130,21 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, transfer_buffer, length, midi_sent, line6, line6->interval); urb->actual_length = 0; - retval = usb_submit_urb(urb, GFP_ATOMIC); + retval = usb_urb_ep_type_check(urb); + if (retval < 0) + goto error; - if (retval < 0) { - dev_err(line6->ifcdev, "usb_submit_urb failed\n"); - usb_free_urb(urb); - return retval; - } + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval < 0) + goto error; ++line6->line6midi->num_active_send_urbs; return 0; + + error: + dev_err(line6->ifcdev, "usb_submit_urb failed\n"); + usb_free_urb(urb); + return retval; } static int line6_midi_output_open(struct snd_rawmidi_substream *substream) diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 812d18191e01..819e9b2d1d6e 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -393,7 +393,7 @@ static int snd_line6_playback_close(struct snd_pcm_substream *substream) } /* playback operators */ -struct snd_pcm_ops snd_line6_playback_ops = { +const struct snd_pcm_ops snd_line6_playback_ops = { .open = snd_line6_playback_open, .close = snd_line6_playback_close, .ioctl = snd_pcm_lib_ioctl, diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h index 51fce29e8726..d8d3b8a07a72 100644 --- a/sound/usb/line6/playback.h +++ b/sound/usb/line6/playback.h @@ -27,7 +27,7 @@ */ #define USE_CLEAR_BUFFER_WORKAROUND 1 -extern struct snd_pcm_ops snd_line6_playback_ops; +extern const struct snd_pcm_ops snd_line6_playback_ops; extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c index 358224cc5638..020c81818951 100644 --- a/sound/usb/line6/pod.c +++ b/sound/usb/line6/pod.c @@ -174,7 +174,7 @@ static const char pod_version_header[] = { }; /* forward declarations: */ -static void pod_startup2(unsigned long data); +static void pod_startup2(struct timer_list *t); static void pod_startup3(struct usb_line6_pod *pod); static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, @@ -286,13 +286,12 @@ static void pod_startup1(struct usb_line6_pod *pod) CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT); /* delay startup procedure: */ - line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2, - (unsigned long)pod); + line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2); } -static void pod_startup2(unsigned long data) +static void pod_startup2(struct timer_list *t) { - struct usb_line6_pod *pod = (struct usb_line6_pod *)data; + struct usb_line6_pod *pod = from_timer(pod, t, startup_timer); struct usb_line6 *line6 = &pod->line6; CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ); @@ -413,7 +412,7 @@ static int pod_init(struct usb_line6 *line6, line6->process_message = line6_pod_process_message; line6->disconnect = line6_pod_disconnect; - init_timer(&pod->startup_timer); + timer_setup(&pod->startup_timer, NULL, 0); INIT_WORK(&pod->startup_work, pod_startup4); /* create sysfs entries: */ diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 956f847a96e4..36ed9c85c0eb 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -39,7 +39,8 @@ enum { LINE6_PODHD500_1, LINE6_PODX3, LINE6_PODX3LIVE, - LINE6_PODHD500X + LINE6_PODHD500X, + LINE6_PODHDDESKTOP }; struct usb_line6_podhd { @@ -157,7 +158,7 @@ static struct line6_pcm_properties podx3_pcm_properties = { }; static struct usb_driver podhd_driver; -static void podhd_startup_start_workqueue(unsigned long data); +static void podhd_startup_start_workqueue(struct timer_list *t); static void podhd_startup_workqueue(struct work_struct *work); static int podhd_startup_finalize(struct usb_line6_podhd *pod); @@ -207,12 +208,12 @@ static void podhd_startup(struct usb_line6_podhd *pod) /* delay startup procedure: */ line6_start_timer(&pod->startup_timer, PODHD_STARTUP_DELAY, - podhd_startup_start_workqueue, (unsigned long)pod); + podhd_startup_start_workqueue); } -static void podhd_startup_start_workqueue(unsigned long data) +static void podhd_startup_start_workqueue(struct timer_list *t) { - struct usb_line6_podhd *pod = (struct usb_line6_podhd *)data; + struct usb_line6_podhd *pod = from_timer(pod, t, startup_timer); CHECK_STARTUP_PROGRESS(pod->startup_progress, PODHD_STARTUP_SCHEDULE_WORKQUEUE); @@ -301,7 +302,8 @@ static void podhd_disconnect(struct usb_line6 *line6) intf = usb_ifnum_to_if(line6->usbdev, pod->line6.properties->ctrl_if); - usb_driver_release_interface(&podhd_driver, intf); + if (intf) + usb_driver_release_interface(&podhd_driver, intf); } } @@ -317,6 +319,9 @@ static int podhd_init(struct usb_line6 *line6, line6->disconnect = podhd_disconnect; + timer_setup(&pod->startup_timer, NULL, 0); + INIT_WORK(&pod->startup_work, podhd_startup_workqueue); + if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { /* claim the data interface */ intf = usb_ifnum_to_if(line6->usbdev, @@ -358,8 +363,6 @@ static int podhd_init(struct usb_line6 *line6, } /* init device and delay registering */ - init_timer(&pod->startup_timer); - INIT_WORK(&pod->startup_work, podhd_startup_workqueue); podhd_startup(pod); return 0; } @@ -377,6 +380,7 @@ static const struct usb_device_id podhd_id_table[] = { { LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 }, { LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE }, { LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X }, + { LINE6_IF_NUM(0x4156, 0), .driver_info = LINE6_PODHDDESKTOP }, {} }; @@ -463,6 +467,18 @@ static const struct line6_properties podhd_properties_table[] = { .ep_audio_r = 0x86, .ep_audio_w = 0x02, }, + [LINE6_PODHDDESKTOP] = { + .id = "PODHDDESKTOP", + .name = "POD HDDESKTOP", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x81, + .ep_ctrl_w = 0x01, + .ctrl_if = 1, + .ep_audio_r = 0x86, + .ep_audio_w = 0x02, + }, }; /* diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index ba7975c0d03d..750467fb95db 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -241,9 +241,9 @@ static int snd_toneport_source_put(struct snd_kcontrol *kcontrol, return 1; } -static void toneport_start_pcm(unsigned long arg) +static void toneport_start_pcm(struct timer_list *t) { - struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; + struct usb_line6_toneport *toneport = from_timer(toneport, t, timer); struct usb_line6 *line6 = &toneport->line6; line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true); @@ -415,8 +415,7 @@ static int toneport_init(struct usb_line6 *line6, struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; toneport->type = id->driver_info; - setup_timer(&toneport->timer, toneport_start_pcm, - (unsigned long)toneport); + timer_setup(&toneport->timer, toneport_start_pcm, 0); line6->disconnect = line6_toneport_disconnect; diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c index 0c4512d0382e..e8c852b2ce35 100644 --- a/sound/usb/line6/variax.c +++ b/sound/usb/line6/variax.c @@ -82,9 +82,9 @@ static const char variax_activate[] = { }; /* forward declarations: */ -static void variax_startup2(unsigned long data); -static void variax_startup4(unsigned long data); -static void variax_startup5(unsigned long data); +static void variax_startup2(struct timer_list *t); +static void variax_startup4(struct timer_list *t); +static void variax_startup5(struct timer_list *t); static void variax_activate_async(struct usb_line6_variax *variax, int a) { @@ -106,12 +106,12 @@ static void variax_startup1(struct usb_line6_variax *variax) /* delay startup procedure: */ line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, - variax_startup2, (unsigned long)variax); + variax_startup2); } -static void variax_startup2(unsigned long data) +static void variax_startup2(struct timer_list *t) { - struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + struct usb_line6_variax *variax = from_timer(variax, t, startup_timer1); struct usb_line6 *line6 = &variax->line6; /* schedule another startup procedure until startup is complete: */ @@ -120,7 +120,7 @@ static void variax_startup2(unsigned long data) variax->startup_progress = VARIAX_STARTUP_VERSIONREQ; line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, - variax_startup2, (unsigned long)variax); + variax_startup2); /* request firmware version: */ line6_version_request_async(line6); @@ -132,12 +132,12 @@ static void variax_startup3(struct usb_line6_variax *variax) /* delay startup procedure: */ line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3, - variax_startup4, (unsigned long)variax); + variax_startup4); } -static void variax_startup4(unsigned long data) +static void variax_startup4(struct timer_list *t) { - struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2); CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_ACTIVATE); @@ -145,12 +145,12 @@ static void variax_startup4(unsigned long data) /* activate device: */ variax_activate_async(variax, 1); line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, - variax_startup5, (unsigned long)variax); + variax_startup5); } -static void variax_startup5(unsigned long data) +static void variax_startup5(struct timer_list *t) { - struct usb_line6_variax *variax = (struct usb_line6_variax *)data; + struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2); CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WORKQUEUE); @@ -190,7 +190,7 @@ static void line6_variax_process_message(struct usb_line6 *line6) } else if (memcmp(buf + 1, variax_init_done + 1, sizeof(variax_init_done) - 1) == 0) { /* notify of complete initialization: */ - variax_startup4((unsigned long)variax); + variax_startup4(&variax->startup_timer2); } break; } @@ -222,8 +222,8 @@ static int variax_init(struct usb_line6 *line6, line6->process_message = line6_variax_process_message; line6->disconnect = line6_variax_disconnect; - init_timer(&variax->startup_timer1); - init_timer(&variax->startup_timer2); + timer_setup(&variax->startup_timer1, NULL, 0); + timer_setup(&variax->startup_timer2, NULL, 0); INIT_WORK(&variax->startup_work, variax_startup6); /* initialize USB buffers: */ diff --git a/sound/usb/midi.c b/sound/usb/midi.c index a92e2b2a91ec..2c1aaa3292bf 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -352,9 +352,9 @@ static void snd_usbmidi_out_tasklet(unsigned long data) } /* called after transfers had been interrupted due to some USB error */ -static void snd_usbmidi_error_timer(unsigned long data) +static void snd_usbmidi_error_timer(struct timer_list *t) { - struct snd_usb_midi *umidi = (struct snd_usb_midi *)data; + struct snd_usb_midi *umidi = from_timer(umidi, t, error_timer); unsigned int i, j; spin_lock(&umidi->disc_lock); @@ -1282,6 +1282,7 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi, unsigned int pipe; int length; unsigned int i; + int err; rep->in = NULL; ep = kzalloc(sizeof(*ep), GFP_KERNEL); @@ -1292,8 +1293,8 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi, 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; + err = -ENOMEM; + goto error; } } if (ep_info->in_interval) @@ -1305,8 +1306,8 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi, buffer = usb_alloc_coherent(umidi->dev, length, GFP_KERNEL, &ep->urbs[i]->transfer_dma); if (!buffer) { - snd_usbmidi_in_endpoint_delete(ep); - return -ENOMEM; + err = -ENOMEM; + goto error; } if (ep_info->in_interval) usb_fill_int_urb(ep->urbs[i], umidi->dev, @@ -1318,10 +1319,20 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi, pipe, buffer, length, snd_usbmidi_in_urb_complete, ep); ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + err = usb_urb_ep_type_check(ep->urbs[i]); + if (err < 0) { + dev_err(&umidi->dev->dev, "invalid MIDI in EP %x\n", + ep_info->in_ep); + goto error; + } } rep->in = ep; return 0; + + error: + snd_usbmidi_in_endpoint_delete(ep); + return -ENOMEM; } /* @@ -1357,6 +1368,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, unsigned int i; unsigned int pipe; void *buffer; + int err; rep->out = NULL; ep = kzalloc(sizeof(*ep), GFP_KERNEL); @@ -1367,8 +1379,8 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, 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; + err = -ENOMEM; + goto error; } ep->urbs[i].ep = ep; } @@ -1406,8 +1418,8 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, ep->max_transfer, GFP_KERNEL, &ep->urbs[i].urb->transfer_dma); if (!buffer) { - snd_usbmidi_out_endpoint_delete(ep); - return -ENOMEM; + err = -ENOMEM; + goto error; } if (ep_info->out_interval) usb_fill_int_urb(ep->urbs[i].urb, umidi->dev, @@ -1419,6 +1431,12 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, pipe, buffer, ep->max_transfer, snd_usbmidi_out_urb_complete, &ep->urbs[i]); + err = usb_urb_ep_type_check(ep->urbs[i].urb); + if (err < 0) { + dev_err(&umidi->dev->dev, "invalid MIDI out EP %x\n", + ep_info->out_ep); + goto error; + } ep->urbs[i].urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; } @@ -1437,6 +1455,10 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, rep->out = ep; return 0; + + error: + snd_usbmidi_out_endpoint_delete(ep); + return err; } /* @@ -2347,8 +2369,7 @@ int __snd_usbmidi_create(struct snd_card *card, usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), le16_to_cpu(umidi->dev->descriptor.idProduct)); umidi->usb_id = usb_id; - setup_timer(&umidi->error_timer, snd_usbmidi_error_timer, - (unsigned long)umidi); + timer_setup(&umidi->error_timer, snd_usbmidi_error_timer, 0); /* detect the endpoint(s) to use */ memset(endpoints, 0, sizeof(endpoints)); diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 9732edf77f86..91bc8f18791e 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2234,6 +2234,9 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) { + /* kill pending URBs */ + snd_usb_mixer_disconnect(mixer); + kfree(mixer->id_elems); if (mixer->urb) { kfree(mixer->urb->transfer_buffer); @@ -2584,8 +2587,13 @@ _error: void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer) { - usb_kill_urb(mixer->urb); - usb_kill_urb(mixer->rc_urb); + if (mixer->disconnected) + return; + if (mixer->urb) + usb_kill_urb(mixer->urb); + if (mixer->rc_urb) + usb_kill_urb(mixer->rc_urb); + mixer->disconnected = true; } #ifdef CONFIG_PM diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 2b4b067646ab..545d99b09706 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -22,6 +22,8 @@ struct usb_mixer_interface { struct urb *rc_urb; struct usb_ctrlrequest *rc_setup_packet; u8 rc_buffer[6]; + + bool disconnected; }; #define MAX_CHANNELS 16 /* max logical channels */ diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index b8cb57aeec77..9aeb05f61f78 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1128,29 +1128,24 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) /* devices which do not support reading the sample rate. */ switch (chip->usb_id) { case USB_ID(0x041E, 0x4080): /* Creative Live Cam VF0610 */ - case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema */ - case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */ - case USB_ID(0x045E, 0x076E): /* MS Lifecam HD-5001 */ - case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */ - case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ - case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ - case USB_ID(0x047F, 0x02F7): /* Plantronics BT-600 */ - case USB_ID(0x047F, 0x0415): /* Plantronics BT-300 */ - case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */ - case USB_ID(0x047F, 0xC022): /* Plantronics C310 */ - case USB_ID(0x047F, 0xC036): /* Plantronics C520-M */ case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */ case USB_ID(0x05A3, 0x9420): /* ELP HD USB Camera */ case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */ case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */ - case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */ - case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */ - case USB_ID(0x1de7, 0x0114): /* Phoenix Audio MT202pcs */ case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */ return true; } + + /* devices of these vendors don't support reading rate, either */ + switch (USB_ID_VENDOR(chip->usb_id)) { + case 0x045E: /* MS Lifecam */ + case 0x047F: /* Plantronics */ + case 0x1de7: /* Phoenix Audio */ + return true; + } + return false; } diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 4569c0efac0a..0ddf29267d70 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -279,6 +279,9 @@ int usX2Y_AsyncSeq04_init(struct usX2Ydev *usX2Y) usX2Y->AS04.buffer + URB_DataLen_AsyncSeq*i, 0, i_usX2Y_Out04Int, usX2Y ); + err = usb_urb_ep_type_check(usX2Y->AS04.urb[i]); + if (err < 0) + break; } return err; } @@ -298,6 +301,8 @@ int usX2Y_In04_init(struct usX2Ydev *usX2Y) usX2Y->In04Buf, 21, i_usX2Y_In04Int, usX2Y, 10); + if (usb_urb_ep_type_check(usX2Y->In04urb)) + return -EINVAL; return usb_submit_urb(usX2Y->In04urb, GFP_KERNEL); } diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index f93b355756e6..345e439aa95b 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -677,6 +677,9 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate) usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4), usbdata + i, 2, i_usX2Y_04Int, usX2Y); } + err = usb_urb_ep_type_check(us->urb[0]); + if (err < 0) + goto cleanup; us->submitted = 0; us->len = NOOF_SETRATE_URBS; usX2Y->US04 = us; |