Commit 2a557a86 authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/hda-unbind' into for-next

parents 8f88f025 b2a0bafa
...@@ -278,7 +278,8 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type, ...@@ -278,7 +278,8 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type,
void *device_data, struct snd_device_ops *ops); void *device_data, struct snd_device_ops *ops);
int snd_device_register(struct snd_card *card, void *device_data); int snd_device_register(struct snd_card *card, void *device_data);
int snd_device_register_all(struct snd_card *card); int snd_device_register_all(struct snd_card *card);
int snd_device_disconnect_all(struct snd_card *card); void snd_device_disconnect(struct snd_card *card, void *device_data);
void snd_device_disconnect_all(struct snd_card *card);
void snd_device_free(struct snd_card *card, void *device_data); void snd_device_free(struct snd_card *card, void *device_data);
void snd_device_free_all(struct snd_card *card); void snd_device_free_all(struct snd_card *card);
......
...@@ -71,7 +71,7 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type, ...@@ -71,7 +71,7 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type,
} }
EXPORT_SYMBOL(snd_device_new); EXPORT_SYMBOL(snd_device_new);
static int __snd_device_disconnect(struct snd_device *dev) static void __snd_device_disconnect(struct snd_device *dev)
{ {
if (dev->state == SNDRV_DEV_REGISTERED) { if (dev->state == SNDRV_DEV_REGISTERED) {
if (dev->ops->dev_disconnect && if (dev->ops->dev_disconnect &&
...@@ -79,7 +79,6 @@ static int __snd_device_disconnect(struct snd_device *dev) ...@@ -79,7 +79,6 @@ static int __snd_device_disconnect(struct snd_device *dev)
dev_err(dev->card->dev, "device disconnect failure\n"); dev_err(dev->card->dev, "device disconnect failure\n");
dev->state = SNDRV_DEV_DISCONNECTED; dev->state = SNDRV_DEV_DISCONNECTED;
} }
return 0;
} }
static void __snd_device_free(struct snd_device *dev) static void __snd_device_free(struct snd_device *dev)
...@@ -106,6 +105,34 @@ static struct snd_device *look_for_dev(struct snd_card *card, void *device_data) ...@@ -106,6 +105,34 @@ static struct snd_device *look_for_dev(struct snd_card *card, void *device_data)
return NULL; return NULL;
} }
/**
* snd_device_disconnect - disconnect the device
* @card: the card instance
* @device_data: the data pointer to disconnect
*
* Turns the device into the disconnection state, invoking
* dev_disconnect callback, if the device was already registered.
*
* Usually called from snd_card_disconnect().
*
* Return: Zero if successful, or a negative error code on failure or if the
* device not found.
*/
void snd_device_disconnect(struct snd_card *card, void *device_data)
{
struct snd_device *dev;
if (snd_BUG_ON(!card || !device_data))
return;
dev = look_for_dev(card, device_data);
if (dev)
__snd_device_disconnect(dev);
else
dev_dbg(card->dev, "device disconnect %p (from %pF), not found\n",
device_data, __builtin_return_address(0));
}
EXPORT_SYMBOL_GPL(snd_device_disconnect);
/** /**
* snd_device_free - release the device from the card * snd_device_free - release the device from the card
* @card: the card instance * @card: the card instance
...@@ -193,18 +220,14 @@ int snd_device_register_all(struct snd_card *card) ...@@ -193,18 +220,14 @@ int snd_device_register_all(struct snd_card *card)
* disconnect all the devices on the card. * disconnect all the devices on the card.
* called from init.c * called from init.c
*/ */
int snd_device_disconnect_all(struct snd_card *card) void snd_device_disconnect_all(struct snd_card *card)
{ {
struct snd_device *dev; struct snd_device *dev;
int err = 0;
if (snd_BUG_ON(!card)) if (snd_BUG_ON(!card))
return -ENXIO; return;
list_for_each_entry_reverse(dev, &card->devices, list) { list_for_each_entry_reverse(dev, &card->devices, list)
if (__snd_device_disconnect(dev) < 0) __snd_device_disconnect(dev);
err = -ENXIO;
}
return err;
} }
/* /*
......
...@@ -400,7 +400,6 @@ static const struct file_operations snd_shutdown_f_ops = ...@@ -400,7 +400,6 @@ static const struct file_operations snd_shutdown_f_ops =
int snd_card_disconnect(struct snd_card *card) int snd_card_disconnect(struct snd_card *card)
{ {
struct snd_monitor_file *mfile; struct snd_monitor_file *mfile;
int err;
if (!card) if (!card)
return -EINVAL; return -EINVAL;
...@@ -445,9 +444,7 @@ int snd_card_disconnect(struct snd_card *card) ...@@ -445,9 +444,7 @@ int snd_card_disconnect(struct snd_card *card)
#endif #endif
/* notify all devices that we are disconnected */ /* notify all devices that we are disconnected */
err = snd_device_disconnect_all(card); snd_device_disconnect_all(card);
if (err < 0)
dev_err(card->dev, "not all devices for card %i can be disconnected\n", card->number);
snd_info_card_disconnect(card); snd_info_card_disconnect(card);
if (card->registered) { if (card->registered) {
......
...@@ -160,7 +160,7 @@ static int snd_hda_do_attach(struct hda_beep *beep) ...@@ -160,7 +160,7 @@ static int snd_hda_do_attach(struct hda_beep *beep)
input_dev->name = "HDA Digital PCBeep"; input_dev->name = "HDA Digital PCBeep";
input_dev->phys = beep->phys; input_dev->phys = beep->phys;
input_dev->id.bustype = BUS_PCI; input_dev->id.bustype = BUS_PCI;
input_dev->dev.parent = &codec->bus->card->card_dev; input_dev->dev.parent = &codec->card->card_dev;
input_dev->id.vendor = codec->vendor_id >> 16; input_dev->id.vendor = codec->vendor_id >> 16;
input_dev->id.product = codec->vendor_id & 0xffff; input_dev->id.product = codec->vendor_id & 0xffff;
...@@ -224,7 +224,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) ...@@ -224,7 +224,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
if (beep == NULL) if (beep == NULL)
return -ENOMEM; return -ENOMEM;
snprintf(beep->phys, sizeof(beep->phys), snprintf(beep->phys, sizeof(beep->phys),
"card%d/codec#%d/beep0", codec->bus->card->number, codec->addr); "card%d/codec#%d/beep0", codec->card->number, codec->addr);
/* enable linear scale */ /* enable linear scale */
snd_hda_codec_write_cache(codec, nid, 0, snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_DIGI_CONVERT_2, 0x01); AC_VERB_SET_DIGI_CONVERT_2, 0x01);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <sound/core.h> #include <sound/core.h>
#include "hda_codec.h" #include "hda_codec.h"
#include "hda_local.h" #include "hda_local.h"
...@@ -106,16 +107,28 @@ static int hda_codec_driver_probe(struct device *dev) ...@@ -106,16 +107,28 @@ static int hda_codec_driver_probe(struct device *dev)
} }
err = codec->preset->patch(codec); err = codec->preset->patch(codec);
if (err < 0) { if (err < 0)
module_put(owner); goto error_module;
goto error;
err = snd_hda_codec_build_pcms(codec);
if (err < 0)
goto error_module;
err = snd_hda_codec_build_controls(codec);
if (err < 0)
goto error_module;
if (codec->card->registered) {
err = snd_card_register(codec->card);
if (err < 0)
goto error_module;
} }
return 0; return 0;
error_module:
module_put(owner);
error: error:
codec->preset = NULL; snd_hda_codec_cleanup_for_unbind(codec);
memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
return err; return err;
} }
...@@ -125,12 +138,19 @@ static int hda_codec_driver_remove(struct device *dev) ...@@ -125,12 +138,19 @@ static int hda_codec_driver_remove(struct device *dev)
if (codec->patch_ops.free) if (codec->patch_ops.free)
codec->patch_ops.free(codec); codec->patch_ops.free(codec);
codec->preset = NULL; snd_hda_codec_cleanup_for_unbind(codec);
memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
module_put(dev->driver->owner); module_put(dev->driver->owner);
return 0; return 0;
} }
static void hda_codec_driver_shutdown(struct device *dev)
{
struct hda_codec *codec = dev_to_hda_codec(dev);
if (!pm_runtime_suspended(dev) && codec->patch_ops.reboot_notify)
codec->patch_ops.reboot_notify(codec);
}
int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
struct module *owner) struct module *owner)
{ {
...@@ -139,6 +159,7 @@ int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, ...@@ -139,6 +159,7 @@ int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
drv->driver.bus = &snd_hda_bus_type; drv->driver.bus = &snd_hda_bus_type;
drv->driver.probe = hda_codec_driver_probe; drv->driver.probe = hda_codec_driver_probe;
drv->driver.remove = hda_codec_driver_remove; drv->driver.remove = hda_codec_driver_remove;
drv->driver.shutdown = hda_codec_driver_shutdown;
drv->driver.pm = &hda_codec_driver_pm; drv->driver.pm = &hda_codec_driver_pm;
return driver_register(&drv->driver); return driver_register(&drv->driver);
} }
...@@ -287,9 +308,9 @@ int snd_hda_codec_configure(struct hda_codec *codec) ...@@ -287,9 +308,9 @@ int snd_hda_codec_configure(struct hda_codec *codec)
} }
/* audio codec should override the mixer name */ /* audio codec should override the mixer name */
if (codec->afg || !*codec->bus->card->mixername) if (codec->afg || !*codec->card->mixername)
snprintf(codec->bus->card->mixername, snprintf(codec->card->mixername,
sizeof(codec->bus->card->mixername), sizeof(codec->card->mixername),
"%s %s", codec->vendor_name, codec->chip_name); "%s %s", codec->vendor_name, codec->chip_name);
return 0; return 0;
......
This diff is collapsed.
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#ifndef __SOUND_HDA_CODEC_H #ifndef __SOUND_HDA_CODEC_H
#define __SOUND_HDA_CODEC_H #define __SOUND_HDA_CODEC_H
#include <linux/kref.h>
#include <sound/info.h> #include <sound/info.h>
#include <sound/control.h> #include <sound/control.h>
#include <sound/pcm.h> #include <sound/pcm.h>
...@@ -131,8 +132,6 @@ struct hda_bus { ...@@ -131,8 +132,6 @@ struct hda_bus {
/* unsolicited event queue */ /* unsolicited event queue */
struct hda_bus_unsolicited unsol; struct hda_bus_unsolicited unsol;
char workq_name[16];
struct workqueue_struct *workq; /* common workqueue for codecs */
/* assigned PCMs */ /* assigned PCMs */
DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
...@@ -268,12 +267,17 @@ struct hda_pcm { ...@@ -268,12 +267,17 @@ struct hda_pcm {
int device; /* device number to assign */ int device; /* device number to assign */
struct snd_pcm *pcm; /* assigned PCM instance */ struct snd_pcm *pcm; /* assigned PCM instance */
bool own_chmap; /* codec driver provides own channel maps */ bool own_chmap; /* codec driver provides own channel maps */
/* private: */
struct hda_codec *codec;
struct kref kref;
struct list_head list;
}; };
/* codec information */ /* codec information */
struct hda_codec { struct hda_codec {
struct device dev; struct device dev;
struct hda_bus *bus; struct hda_bus *bus;
struct snd_card *card;
unsigned int addr; /* codec addr*/ unsigned int addr; /* codec addr*/
struct list_head list; /* list point */ struct list_head list; /* list point */
...@@ -300,8 +304,7 @@ struct hda_codec { ...@@ -300,8 +304,7 @@ struct hda_codec {
struct hda_codec_ops patch_ops; struct hda_codec_ops patch_ops;
/* PCM to create, set by patch_ops.build_pcms callback */ /* PCM to create, set by patch_ops.build_pcms callback */
unsigned int num_pcms; struct list_head pcm_list_head;
struct hda_pcm *pcm_info;
/* codec specific info */ /* codec specific info */
void *spec; void *spec;
...@@ -345,6 +348,7 @@ struct hda_codec { ...@@ -345,6 +348,7 @@ struct hda_codec {
#endif #endif
/* misc flags */ /* misc flags */
unsigned int in_freeing:1; /* being released */
unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
* status change * status change
* (e.g. Realtek codecs) * (e.g. Realtek codecs)
...@@ -420,8 +424,8 @@ enum { ...@@ -420,8 +424,8 @@ enum {
* constructors * constructors
*/ */
int snd_hda_bus_new(struct snd_card *card, struct hda_bus **busp); int snd_hda_bus_new(struct snd_card *card, struct hda_bus **busp);
int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
struct hda_codec **codecp); unsigned int codec_addr, struct hda_codec **codecp);
int snd_hda_codec_configure(struct hda_codec *codec); int snd_hda_codec_configure(struct hda_codec *codec);
int snd_hda_codec_update_widgets(struct hda_codec *codec); int snd_hda_codec_update_widgets(struct hda_codec *codec);
...@@ -510,15 +514,24 @@ void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid); ...@@ -510,15 +514,24 @@ void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid);
/* /*
* Mixer * Mixer
*/ */
int snd_hda_build_controls(struct hda_bus *bus);
int snd_hda_codec_build_controls(struct hda_codec *codec); int snd_hda_codec_build_controls(struct hda_codec *codec);
/* /*
* PCM * PCM
*/ */
int snd_hda_build_pcms(struct hda_bus *bus); int snd_hda_codec_parse_pcms(struct hda_codec *codec);
int snd_hda_codec_build_pcms(struct hda_codec *codec); int snd_hda_codec_build_pcms(struct hda_codec *codec);
__printf(2, 3)
struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec,
const char *fmt, ...);
static inline void snd_hda_codec_pcm_get(struct hda_pcm *pcm)
{
kref_get(&pcm->kref);
}
void snd_hda_codec_pcm_put(struct hda_pcm *pcm);
int snd_hda_codec_prepare(struct hda_codec *codec, int snd_hda_codec_prepare(struct hda_codec *codec,
struct hda_pcm_stream *hinfo, struct hda_pcm_stream *hinfo,
unsigned int stream, unsigned int stream,
...@@ -550,7 +563,6 @@ extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[]; ...@@ -550,7 +563,6 @@ extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[];
* Misc * Misc
*/ */
void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
void snd_hda_bus_reboot_notify(struct hda_bus *bus);
void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state); unsigned int power_state);
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/reboot.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/initval.h> #include <sound/initval.h>
#include "hda_controller.h" #include "hda_controller.h"
...@@ -416,9 +415,11 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) ...@@ -416,9 +415,11 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
azx_dev->running = 0; azx_dev->running = 0;
spin_unlock_irqrestore(&chip->reg_lock, flags); spin_unlock_irqrestore(&chip->reg_lock, flags);
azx_release_device(azx_dev); azx_release_device(azx_dev);
hinfo->ops.close(hinfo, apcm->codec, substream); if (hinfo->ops.close)
hinfo->ops.close(hinfo, apcm->codec, substream);
snd_hda_power_down(apcm->codec); snd_hda_power_down(apcm->codec);
mutex_unlock(&chip->open_mutex); mutex_unlock(&chip->open_mutex);
snd_hda_codec_pcm_put(apcm->info);
return 0; return 0;
} }
...@@ -805,11 +806,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) ...@@ -805,11 +806,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
int err; int err;
int buff_step; int buff_step;
snd_hda_codec_pcm_get(apcm->info);
mutex_lock(&chip->open_mutex); mutex_lock(&chip->open_mutex);
azx_dev = azx_assign_device(chip, substream); azx_dev = azx_assign_device(chip, substream);
if (azx_dev == NULL) { if (azx_dev == NULL) {
mutex_unlock(&chip->open_mutex); err = -EBUSY;
return -EBUSY; goto unlock;
} }
runtime->hw = azx_pcm_hw; runtime->hw = azx_pcm_hw;
runtime->hw.channels_min = hinfo->channels_min; runtime->hw.channels_min = hinfo->channels_min;
...@@ -844,12 +846,13 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) ...@@ -844,12 +846,13 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
buff_step); buff_step);
snd_hda_power_up(apcm->codec); snd_hda_power_up(apcm->codec);
err = hinfo->ops.open(hinfo, apcm->codec, substream); if (hinfo->ops.open)
err = hinfo->ops.open(hinfo, apcm->codec, substream);
else
err = -ENODEV;
if (err < 0) { if (err < 0) {
azx_release_device(azx_dev); azx_release_device(azx_dev);
snd_hda_power_down(apcm->codec); goto powerdown;
mutex_unlock(&chip->open_mutex);
return err;
} }
snd_pcm_limit_hw_rates(runtime); snd_pcm_limit_hw_rates(runtime);
/* sanity check */ /* sanity check */
...@@ -858,10 +861,10 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) ...@@ -858,10 +861,10 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
snd_BUG_ON(!runtime->hw.formats) || snd_BUG_ON(!runtime->hw.formats) ||
snd_BUG_ON(!runtime->hw.rates)) { snd_BUG_ON(!runtime->hw.rates)) {
azx_release_device(azx_dev); azx_release_device(azx_dev);
hinfo->ops.close(hinfo, apcm->codec, substream); if (hinfo->ops.close)
snd_hda_power_down(apcm->codec); hinfo->ops.close(hinfo, apcm->codec, substream);
mutex_unlock(&chip->open_mutex); err = -EINVAL;
return -EINVAL; goto powerdown;
} }
/* disable LINK_ATIME timestamps for capture streams /* disable LINK_ATIME timestamps for capture streams
...@@ -880,6 +883,13 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) ...@@ -880,6 +883,13 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
snd_pcm_set_sync(substream); snd_pcm_set_sync(substream);
mutex_unlock(&chip->open_mutex); mutex_unlock(&chip->open_mutex);
return 0; return 0;
powerdown:
snd_hda_power_down(apcm->codec);
unlock:
mutex_unlock(&chip->open_mutex);
snd_hda_codec_pcm_put(apcm->info);
return err;
} }
static int azx_pcm_mmap(struct snd_pcm_substream *substream, static int azx_pcm_mmap(struct snd_pcm_substream *substream,
...@@ -974,14 +984,9 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, ...@@ -974,14 +984,9 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
*/ */
static int azx_alloc_cmd_io(struct azx *chip) static int azx_alloc_cmd_io(struct azx *chip)
{ {
int err;
/* single page (at least 4096 bytes) must suffice for both ringbuffes */ /* single page (at least 4096 bytes) must suffice for both ringbuffes */
err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, return chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
PAGE_SIZE, &chip->rb); PAGE_SIZE, &chip->rb);
if (err < 0)
dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n");
return err;
} }
static void azx_init_cmd_io(struct azx *chip) static void azx_init_cmd_io(struct azx *chip)
...@@ -1467,7 +1472,6 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus, ...@@ -1467,7 +1472,6 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus,
int azx_alloc_stream_pages(struct azx *chip) int azx_alloc_stream_pages(struct azx *chip)
{ {
int i, err; int i, err;
struct snd_card *card = chip->card;
for (i = 0; i < chip->num_streams; i++) { for (i = 0; i < chip->num_streams; i++) {
dsp_lock_init(&chip->azx_dev[i]); dsp_lock_init(&chip->azx_dev[i]);
...@@ -1475,18 +1479,14 @@ int azx_alloc_stream_pages(struct azx *chip) ...@@ -1475,18 +1479,14 @@ int azx_alloc_stream_pages(struct azx *chip)
err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
BDL_SIZE, BDL_SIZE,
&chip->azx_dev[i].bdl); &chip->azx_dev[i].bdl);
if (err < 0) { if (err < 0)
dev_err(card->dev, "cannot allocate BDL\n");
return -ENOMEM; return -ENOMEM;
}
} }
/* allocate memory for the position buffer */ /* allocate memory for the position buffer */
err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
chip->num_streams * 8, &chip->posbuf); chip->num_streams * 8, &chip->posbuf);
if (err < 0) { if (err < 0)
dev_err(card->dev, "cannot allocate posbuf\n");
return -ENOMEM; return -ENOMEM;
}
/* allocate CORB/RIRB */ /* allocate CORB/RIRB */
err = azx_alloc_cmd_io(chip); err = azx_alloc_cmd_io(chip);
...@@ -1893,7 +1893,7 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots) ...@@ -1893,7 +1893,7 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots)
for (c = 0; c < max_slots; c++) { for (c = 0; c < max_slots; c++) {
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
struct hda_codec *codec; struct hda_codec *codec;
err = snd_hda_codec_new(bus, c, &codec); err = snd_hda_codec_new(bus, bus->card, c, &codec);
if (err < 0) if (err < 0)
continue; continue;
codec->jackpoll_interval = get_jackpoll_interval(chip); codec->jackpoll_interval = get_jackpoll_interval(chip);
...@@ -1966,30 +1966,5 @@ int azx_init_stream(struct azx *chip) ...@@ -1966,30 +1966,5 @@ int azx_init_stream(struct azx *chip)
} }
EXPORT_SYMBOL_GPL(azx_init_stream); EXPORT_SYMBOL_GPL(azx_init_stream);
/*
* reboot notifier for hang-up problem at power-down
*/
static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf)
{
struct azx *chip = container_of(nb, struct azx, reboot_notifier);
snd_hda_bus_reboot_notify(chip->bus);
azx_stop_chip(chip);
return NOTIFY_OK;
}
void azx_notifier_register(struct azx *chip)
{
chip->reboot_notifier.notifier_call = azx_halt;
register_reboot_notifier(&chip->reboot_notifier);
}
EXPORT_SYMBOL_GPL(azx_notifier_register);
void azx_notifier_unregister(struct azx *chip)
{
if (chip->reboot_notifier.notifier_call)
unregister_reboot_notifier(&chip->reboot_notifier);
}
EXPORT_SYMBOL_GPL(azx_notifier_unregister);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Common HDA driver functions"); MODULE_DESCRIPTION("Common HDA driver functions");
...@@ -362,9 +362,6 @@ struct azx { ...@@ -362,9 +362,6 @@ struct azx {
/* for debugging */ /* for debugging */
unsigned int last_cmd[AZX_MAX_CODECS]; unsigned int last_cmd[AZX_MAX_CODECS];
/* reboot notifier (for mysterious hangup problem at power-down) */
struct notifier_block reboot_notifier;
#ifdef CONFIG_SND_HDA_DSP_LOADER #ifdef CONFIG_SND_HDA_DSP_LOADER
struct azx_dev saved_azx_dev; struct azx_dev saved_azx_dev;
#endif #endif
...@@ -437,7 +434,4 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots); ...@@ -437,7 +434,4 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots);
int azx_codec_configure(struct azx *chip); int azx_codec_configure(struct azx *chip);
int azx_init_stream(struct azx *chip); int azx_init_stream(struct azx *chip);
void azx_notifier_register(struct azx *chip);
void azx_notifier_unregister(struct azx *chip);
#endif /* __SOUND_HDA_CONTROLLER_H */ #endif /* __SOUND_HDA_CONTROLLER_H */
...@@ -4675,7 +4675,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec) ...@@ -4675,7 +4675,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
err = snd_hda_create_dig_out_ctls(codec, err = snd_hda_create_dig_out_ctls(codec,
spec->multiout.dig_out_nid, spec->multiout.dig_out_nid,
spec->multiout.dig_out_nid, spec->multiout.dig_out_nid,
spec->pcm_rec[1].pcm_type); spec->pcm_rec[1]->pcm_type);
if (err < 0) if (err < 0)
return err; return err;
if (!spec->no_analog) { if (!spec->no_analog) {
...@@ -5146,20 +5146,20 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, ...@@ -5146,20 +5146,20 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
int snd_hda_gen_build_pcms(struct hda_codec *codec) int snd_hda_gen_build_pcms(struct hda_codec *codec)
{ {
struct hda_gen_spec *spec = codec->spec; struct hda_gen_spec *spec = codec->spec;
struct hda_pcm *info = spec->pcm_rec; struct hda_pcm *info;
const struct hda_pcm_stream *p; const struct hda_pcm_stream *p;
bool have_multi_adcs; bool have_multi_adcs;
codec->num_pcms = 1;
codec->pcm_info = info;
if (spec->no_analog) if (spec->no_analog)
goto skip_analog; goto skip_analog;
fill_pcm_stream_name(spec->stream_name_analog, fill_pcm_stream_name(spec->stream_name_analog,
sizeof(spec->stream_name_analog), sizeof(spec->stream_name_analog),
" Analog", codec->chip_name); " Analog", codec->chip_name);
info->name = spec->stream_name_analog; info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog);
if (!info)
return -ENOMEM;
spec->pcm_rec[0] = info;
if (spec->multiout.num_dacs > 0) { if (spec->multiout.num_dacs > 0) {
p = spec->stream_analog_playback; p = spec->stream_analog_playback;
...@@ -5192,10 +5192,12 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec) ...@@ -5192,10 +5192,12 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec)
fill_pcm_stream_name(spec->stream_name_digital, fill_pcm_stream_name(spec->stream_name_digital,
sizeof(spec->stream_name_digital), sizeof(spec->stream_name_digital),
" Digital", codec->chip_name); " Digital", codec->chip_name);
codec->num_pcms = 2; info = snd_hda_codec_pcm_new(codec, "%s",
spec->stream_name_digital);
if (!info)
return -ENOMEM;
codec->slave_dig_outs = spec->multiout.slave_dig_outs; codec->slave_dig_outs = spec->multiout.slave_dig_outs;
info = spec->pcm_rec + 1; spec->pcm_rec[1] = info;
info->name = spec->stream_name_digital;
if (spec->dig_out_type) if (spec->dig_out_type)
info->pcm_type = spec->dig_out_type; info->pcm_type = spec->dig_out_type;
else else
...@@ -5229,9 +5231,11 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec) ...@@ -5229,9 +5231,11 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec)
fill_pcm_stream_name(spec->stream_name_alt_analog, fill_pcm_stream_name(spec->stream_name_alt_analog,
sizeof(spec->stream_name_alt_analog), sizeof(spec->stream_name_alt_analog),
" Alt Analog", codec->chip_name); " Alt Analog", codec->chip_name);
codec->num_pcms = 3; info = snd_hda_codec_pcm_new(codec, "%s",
info = spec->pcm_rec + 2; spec->stream_name_alt_analog);
info->name = spec->stream_name_alt_analog; if (!info)
return -ENOMEM;
spec->pcm_rec[2] = info;
if (spec->alt_dac_nid) { if (spec->alt_dac_nid) {
p = spec->stream_analog_alt_playback; p = spec->stream_analog_alt_playback;
if (!p) if (!p)
......
...@@ -144,7 +144,7 @@ struct hda_gen_spec { ...@@ -144,7 +144,7 @@ struct hda_gen_spec {
int const_channel_count; /* channel count for all */ int const_channel_count; /* channel count for all */
/* PCM information */ /* PCM information */
struct hda_pcm pcm_rec[3]; /* used in build_pcms() */ struct hda_pcm *pcm_rec[3]; /* used in build_pcms() */
/* dynamic controls, init_verbs and input_mux */ /* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg; struct auto_pin_cfg autocfg;
......
...@@ -101,7 +101,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec) ...@@ -101,7 +101,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
int err; int err;
sprintf(hwname, "HDA Codec %d", codec->addr); sprintf(hwname, "HDA Codec %d", codec->addr);
err = snd_hwdep_new(codec->bus->card, hwname, codec->addr, &hwdep); err = snd_hwdep_new(codec->card, hwname, codec->addr, &hwdep);
if (err < 0) if (err < 0)
return err; return err;
codec->hwdep = hwdep; codec->hwdep = hwdep;
......
...@@ -528,10 +528,10 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) ...@@ -528,10 +528,10 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
if (ok == 1) { if (ok == 1) {
azx_dev->irq_pending = 0; azx_dev->irq_pending = 0;
return ok; return ok;
} else if (ok == 0 && chip->bus && chip->bus->workq) { } else if (ok == 0) {
/* bogus IRQ, process it later */ /* bogus IRQ, process it later */
azx_dev->irq_pending = 1; azx_dev->irq_pending = 1;
queue_work(chip->bus->workq, &hda->irq_pending_work); schedule_work(&hda->irq_pending_work);
} }
return 0; return 0;
} }
...@@ -893,8 +893,8 @@ static int azx_runtime_resume(struct device *dev) ...@@ -893,8 +893,8 @@ static int azx_runtime_resume(struct device *dev)
if (status && bus) { if (status && bus) {
list_for_each_entry(codec, &bus->codec_list, list) list_for_each_entry(codec, &bus->codec_list, list)
if (status & (1 << codec->addr)) if (status & (1 << codec->addr))
queue_delayed_work(codec->bus->workq, schedule_delayed_work(&codec->jackpoll_work,
&codec->jackpoll_work, codec->jackpoll_interval); codec->jackpoll_interval);
} }
/* disable controller Wake Up event*/ /* disable controller Wake Up event*/
...@@ -1066,8 +1066,6 @@ static int azx_free(struct azx *chip) ...@@ -1066,8 +1066,6 @@ static int azx_free(struct azx *chip)
azx_del_card_list(chip); azx_del_card_list(chip);
azx_notifier_unregister(chip);
hda->init_failed = 1; /* to be sure */ hda->init_failed = 1; /* to be sure */
complete_all(&hda->probe_wait); complete_all(&hda->probe_wait);
...@@ -1383,7 +1381,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, ...@@ -1383,7 +1381,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
hda = kzalloc(sizeof(*hda), GFP_KERNEL); hda = kzalloc(sizeof(*hda), GFP_KERNEL);
if (!hda) { if (!hda) {
dev_err(card->dev, "Cannot allocate hda\n");
pci_disable_device(pci); pci_disable_device(pci);
return -ENOMEM; return -ENOMEM;
} }
...@@ -1564,10 +1561,8 @@ static int azx_first_init(struct azx *chip) ...@@ -1564,10 +1561,8 @@ static int azx_first_init(struct azx *chip)
chip->num_streams = chip->playback_streams + chip->capture_streams; chip->num_streams = chip->playback_streams + chip->capture_streams;
chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
GFP_KERNEL); GFP_KERNEL);
if (!chip->azx_dev) { if (!chip->azx_dev)
dev_err(card->dev, "cannot malloc azx_dev\n");
return -ENOMEM; return -ENOMEM;
}
err = azx_alloc_stream_pages(chip); err = azx_alloc_stream_pages(chip);
if (err < 0) if (err < 0)
...@@ -1898,22 +1893,11 @@ static int azx_probe_continue(struct azx *chip) ...@@ -1898,22 +1893,11 @@ static int azx_probe_continue(struct azx *chip)
goto out_free; goto out_free;
} }
/* create PCM streams */
err = snd_hda_build_pcms(chip->bus);
if (err < 0)
goto out_free;
/* create mixer controls */
err = snd_hda_build_controls(chip->bus);
if (err < 0)
goto out_free;
err = snd_card_register(chip->card); err = snd_card_register(chip->card);
if (err < 0) if (err < 0)
goto out_free; goto out_free;
chip->running = 1; chip->running = 1;
azx_notifier_register(chip);
azx_add_card_list(chip); azx_add_card_list(chip);
snd_hda_set_power_save(chip->bus, power_save * 1000); snd_hda_set_power_save(chip->bus, power_save * 1000);
if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo) if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)
...@@ -1934,6 +1918,18 @@ static void azx_remove(struct pci_dev *pci) ...@@ -1934,6 +1918,18 @@ static void azx_remove(struct pci_dev *pci)
snd_card_free(card); snd_card_free(card);
} }
static void azx_shutdown(struct pci_dev *pci)
{
struct snd_card *card = pci_get_drvdata(pci);
struct azx *chip;
if (!card)
return;
chip = card->private_data;
if (chip && chip->running)
azx_stop_chip(chip);
}
/* PCI IDs */ /* PCI IDs */
static const struct pci_device_id azx_ids[] = { static const struct pci_device_id azx_ids[] = {
/* CPT */ /* CPT */
...@@ -2156,6 +2152,7 @@ static struct pci_driver azx_driver = { ...@@ -2156,6 +2152,7 @@ static struct pci_driver azx_driver = {
.id_table = azx_ids, .id_table = azx_ids,
.probe = azx_probe, .probe = azx_probe,
.remove = azx_remove, .remove = azx_remove,
.shutdown = azx_shutdown,
.driver = { .driver = {
.pm = AZX_PM_OPS, .pm = AZX_PM_OPS,
}, },
......
...@@ -135,7 +135,7 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec) ...@@ -135,7 +135,7 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec)
#ifdef CONFIG_SND_HDA_INPUT_JACK #ifdef CONFIG_SND_HDA_INPUT_JACK
/* free jack instances manually when clearing/reconfiguring */ /* free jack instances manually when clearing/reconfiguring */
if (!codec->bus->shutdown && jack->jack) if (!codec->bus->shutdown && jack->jack)
snd_device_free(codec->bus->card, jack->jack); snd_device_free(codec->card, jack->jack);
#endif #endif
for (cb = jack->callback; cb; cb = next) { for (cb = jack->callback; cb; cb = next) {
next = cb->next; next = cb->next;
...@@ -340,7 +340,7 @@ void snd_hda_jack_report_sync(struct hda_codec *codec) ...@@ -340,7 +340,7 @@ void snd_hda_jack_report_sync(struct hda_codec *codec)
if (!jack->kctl || jack->block_report) if (!jack->kctl || jack->block_report)
continue; continue;
state = get_jack_plug_state(jack->pin_sense); state = get_jack_plug_state(jack->pin_sense);
snd_kctl_jack_report(codec->bus->card, jack->kctl, state); snd_kctl_jack_report(codec->card, jack->kctl, state);
#ifdef CONFIG_SND_HDA_INPUT_JACK #ifdef CONFIG_SND_HDA_INPUT_JACK
if (jack->jack) if (jack->jack)
snd_jack_report(jack->jack, snd_jack_report(jack->jack,
...@@ -412,11 +412,11 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, ...@@ -412,11 +412,11 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
jack->phantom_jack = !!phantom_jack; jack->phantom_jack = !!phantom_jack;
state = snd_hda_jack_detect(codec, nid); state = snd_hda_jack_detect(codec, nid);
snd_kctl_jack_report(codec->bus->card, kctl, state); snd_kctl_jack_report(codec->card, kctl, state);
#ifdef CONFIG_SND_HDA_INPUT_JACK #ifdef CONFIG_SND_HDA_INPUT_JACK
if (!phantom_jack) { if (!phantom_jack) {
jack->type = get_input_jack_type(codec, nid); jack->type = get_input_jack_type(codec, nid);
err = snd_jack_new(codec->bus->card, name, jack->type, err = snd_jack_new(codec->card, name, jack->type,
&jack->jack); &jack->jack);
if (err < 0) if (err < 0)
return err; return err;
......
...@@ -150,6 +150,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, ...@@ -150,6 +150,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
#define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \ #define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \
__snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL) __snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL)
int snd_hda_codec_reset(struct hda_codec *codec); int snd_hda_codec_reset(struct hda_codec *codec);
void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec);
enum { enum {
HDA_VMUTE_OFF, HDA_VMUTE_OFF,
......
...@@ -99,10 +99,10 @@ static void print_nid_array(struct snd_info_buffer *buffer, ...@@ -99,10 +99,10 @@ static void print_nid_array(struct snd_info_buffer *buffer,
static void print_nid_pcms(struct snd_info_buffer *buffer, static void print_nid_pcms(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid) struct hda_codec *codec, hda_nid_t nid)
{ {
int pcm, type; int type;
struct hda_pcm *cpcm; struct hda_pcm *cpcm;
for (pcm = 0; pcm < codec->num_pcms; pcm++) {
cpcm = &codec->pcm_info[pcm]; list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
for (type = 0; type < 2; type++) { for (type = 0; type < 2; type++) {
if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL) if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
continue; continue;
...@@ -861,7 +861,7 @@ int snd_hda_codec_proc_new(struct hda_codec *codec) ...@@ -861,7 +861,7 @@ int snd_hda_codec_proc_new(struct hda_codec *codec)
int err; int err;
snprintf(name, sizeof(name), "codec#%d", codec->addr); snprintf(name, sizeof(name), "codec#%d", codec->addr);
err = snd_card_proc_new(codec->bus->card, name, &entry); err = snd_card_proc_new(codec->card, name, &entry);
if (err < 0) if (err < 0)
return err; return err;
......
...@@ -149,7 +149,7 @@ static int reconfig_codec(struct hda_codec *codec) ...@@ -149,7 +149,7 @@ static int reconfig_codec(struct hda_codec *codec)
err = snd_hda_codec_build_controls(codec); err = snd_hda_codec_build_controls(codec);
if (err < 0) if (err < 0)
goto error; goto error;
err = snd_card_register(codec->bus->card); err = snd_card_register(codec->card);
error: error:
snd_hda_power_down(codec); snd_hda_power_down(codec);
return err; return err;
......
...@@ -290,8 +290,6 @@ static int hda_tegra_dev_free(struct snd_device *device) ...@@ -290,8 +290,6 @@ static int hda_tegra_dev_free(struct snd_device *device)
int i; int i;
struct azx *chip = device->device_data; struct azx *chip = device->device_data;
azx_notifier_unregister(chip);
if (chip->initialized) { if (chip->initialized) {
for (i = 0; i < chip->num_streams; i++) for (i = 0; i < chip->num_streams; i++)
azx_stream_stop(chip, &chip->azx_dev[i]); azx_stream_stop(chip, &chip->azx_dev[i]);
...@@ -497,22 +495,11 @@ static int hda_tegra_probe(struct platform_device *pdev) ...@@ -497,22 +495,11 @@ static int hda_tegra_probe(struct platform_device *pdev)
if (err < 0) if (err < 0)
goto out_free; goto out_free;
/* create PCM streams */
err = snd_hda_build_pcms(chip->bus);
if (err < 0)
goto out_free;
/* create mixer controls */
err = snd_hda_build_controls(chip->bus);
if (err < 0)
goto out_free;
err = snd_card_register(chip->card); err = snd_card_register(chip->card);
if (err < 0) if (err < 0)
goto out_free; goto out_free;
chip->running = 1; chip->running = 1;
azx_notifier_register(chip);
snd_hda_set_power_save(chip->bus, power_save * 1000); snd_hda_set_power_save(chip->bus, power_save * 1000);
return 0; return 0;
...@@ -527,6 +514,18 @@ static int hda_tegra_remove(struct platform_device *pdev) ...@@ -527,6 +514,18 @@ static int hda_tegra_remove(struct platform_device *pdev)
return snd_card_free(dev_get_drvdata(&pdev->dev)); return snd_card_free(dev_get_drvdata(&pdev->dev));
} }
static void hda_tegra_shutdown(struct platform_device *pdev)
{
struct snd_card *card = dev_get_drvdata(&pdev->dev);
struct azx *chip;
if (!card)
return;
chip = card->private_data;
if (chip && chip->running)
azx_stop_chip(chip);
}
static struct platform_driver tegra_platform_hda = { static struct platform_driver tegra_platform_hda = {
.driver = { .driver = {
.name = "tegra-hda", .name = "tegra-hda",
...@@ -535,6 +534,7 @@ static struct platform_driver tegra_platform_hda = { ...@@ -535,6 +534,7 @@ static struct platform_driver tegra_platform_hda = {
}, },
.probe = hda_tegra_probe, .probe = hda_tegra_probe,
.remove = hda_tegra_remove, .remove = hda_tegra_remove,
.shutdown = hda_tegra_shutdown,
}; };
module_platform_driver(tegra_platform_hda); module_platform_driver(tegra_platform_hda);
......
...@@ -23,7 +23,7 @@ DECLARE_EVENT_CLASS(hda_cmd, ...@@ -23,7 +23,7 @@ DECLARE_EVENT_CLASS(hda_cmd,
), ),
TP_fast_assign( TP_fast_assign(
__entry->card = (codec)->bus->card->number; __entry->card = (codec)->card->number;
__entry->addr = (codec)->addr; __entry->addr = (codec)->addr;
__entry->val = (val); __entry->val = (val);
), ),
...@@ -71,7 +71,7 @@ DECLARE_EVENT_CLASS(hda_power, ...@@ -71,7 +71,7 @@ DECLARE_EVENT_CLASS(hda_power,
), ),
TP_fast_assign( TP_fast_assign(
__entry->card = (codec)->bus->card->number; __entry->card = (codec)->card->number;
__entry->addr = (codec)->addr; __entry->addr = (codec)->addr;
), ),
......
...@@ -719,7 +719,6 @@ struct ca0132_spec { ...@@ -719,7 +719,6 @@ struct ca0132_spec {
unsigned int num_inputs; unsigned int num_inputs;
hda_nid_t shared_mic_nid; hda_nid_t shared_mic_nid;
hda_nid_t shared_out_nid; hda_nid_t shared_out_nid;
struct hda_pcm pcm_rec[5]; /* PCM information */
/* chip access */ /* chip access */
struct mutex chipio_mutex; /* chip access mutex */ struct mutex chipio_mutex; /* chip access mutex */
...@@ -4036,12 +4035,11 @@ static struct hda_pcm_stream ca0132_pcm_digital_capture = { ...@@ -4036,12 +4035,11 @@ static struct hda_pcm_stream ca0132_pcm_digital_capture = {
static int ca0132_build_pcms(struct hda_codec *codec) static int ca0132_build_pcms(struct hda_codec *codec)
{ {
struct ca0132_spec *spec = codec->spec; struct ca0132_spec *spec = codec->spec;
struct hda_pcm *info = spec->pcm_rec; struct hda_pcm *info;
codec->pcm_info = info; info = snd_hda_codec_pcm_new(codec, "CA0132 Analog");
codec->num_pcms = 0; if (!info)
return -ENOMEM;
info->name = "CA0132 Analog";
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
...@@ -4049,27 +4047,27 @@ static int ca0132_build_pcms(struct hda_codec *codec) ...@@ -4049,27 +4047,27 @@ static int ca0132_build_pcms(struct hda_codec *codec)
info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
codec->num_pcms++;
info++; info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2");
info->name = "CA0132 Analog Mic-In2"; if (!info)
return -ENOMEM;
info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1]; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1];
codec->num_pcms++;
info++; info = snd_hda_codec_pcm_new(codec, "CA0132 What U Hear");
info->name = "CA0132 What U Hear"; if (!info)
return -ENOMEM;
info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[2]; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[2];
codec->num_pcms++;
if (!spec->dig_out && !spec->dig_in) if (!spec->dig_out && !spec->dig_in)
return 0; return 0;
info++; info = snd_hda_codec_pcm_new(codec, "CA0132 Digital");
info->name = "CA0132 Digital"; if (!info)
return -ENOMEM;
info->pcm_type = HDA_PCM_TYPE_SPDIF; info->pcm_type = HDA_PCM_TYPE_SPDIF;
if (spec->dig_out) { if (spec->dig_out) {
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
...@@ -4081,7 +4079,6 @@ static int ca0132_build_pcms(struct hda_codec *codec) ...@@ -4081,7 +4079,6 @@ static int ca0132_build_pcms(struct hda_codec *codec)
ca0132_pcm_digital_capture; ca0132_pcm_digital_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
} }
codec->num_pcms++;
return 0; return 0;
} }
...@@ -4352,7 +4349,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec) ...@@ -4352,7 +4349,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
const struct dsp_image_seg *dsp_os_image; const struct dsp_image_seg *dsp_os_image;
const struct firmware *fw_entry; const struct firmware *fw_entry;
if (request_firmware(&fw_entry, EFX_FILE, codec->bus->card->dev) != 0) if (request_firmware(&fw_entry, EFX_FILE, codec->card->dev) != 0)
return false; return false;
dsp_os_image = (struct dsp_image_seg *)(fw_entry->data); dsp_os_image = (struct dsp_image_seg *)(fw_entry->data);
...@@ -4413,8 +4410,7 @@ static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb) ...@@ -4413,8 +4410,7 @@ static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
* state machine run. * state machine run.
*/ */
cancel_delayed_work_sync(&spec->unsol_hp_work); cancel_delayed_work_sync(&spec->unsol_hp_work);
queue_delayed_work(codec->bus->workq, &spec->unsol_hp_work, schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500));
msecs_to_jiffies(500));
cb->tbl->block_report = 1; cb->tbl->block_report = 1;
} }
......
...@@ -86,7 +86,6 @@ struct hdmi_spec_per_pin { ...@@ -86,7 +86,6 @@ struct hdmi_spec_per_pin {
bool non_pcm; bool non_pcm;
bool chmap_set; /* channel-map override by ALSA API? */ bool chmap_set; /* channel-map override by ALSA API? */
unsigned char chmap[8]; /* ALSA API channel-map */ unsigned char chmap[8]; /* ALSA API channel-map */
char pcm_name[8]; /* filled in build_pcm callbacks */
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
struct snd_info_entry *proc_entry; struct snd_info_entry *proc_entry;
#endif #endif
...@@ -132,7 +131,7 @@ struct hdmi_spec { ...@@ -132,7 +131,7 @@ struct hdmi_spec {
int num_pins; int num_pins;
struct snd_array pins; /* struct hdmi_spec_per_pin */ struct snd_array pins; /* struct hdmi_spec_per_pin */
struct snd_array pcm_rec; /* struct hda_pcm */ struct hda_pcm *pcm_rec[16];
unsigned int channels_max; /* max over all cvts */ unsigned int channels_max; /* max over all cvts */
struct hdmi_eld temp_eld; struct hdmi_eld temp_eld;
...@@ -355,8 +354,7 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { ...@@ -355,8 +354,7 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx)) ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
#define get_cvt(spec, idx) \ #define get_cvt(spec, idx) \
((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx)) ((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx))
#define get_pcm_rec(spec, idx) \ #define get_pcm_rec(spec, idx) ((spec)->pcm_rec[idx])
((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx))
static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid) static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid)
{ {
...@@ -579,7 +577,7 @@ static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index) ...@@ -579,7 +577,7 @@ static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index)
int err; int err;
snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index); snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
err = snd_card_proc_new(codec->bus->card, name, &entry); err = snd_card_proc_new(codec->card, name, &entry);
if (err < 0) if (err < 0)
return err; return err;
...@@ -594,7 +592,7 @@ static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index) ...@@ -594,7 +592,7 @@ static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index)
static void eld_proc_free(struct hdmi_spec_per_pin *per_pin) static void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
{ {
if (!per_pin->codec->bus->shutdown && per_pin->proc_entry) { if (!per_pin->codec->bus->shutdown && per_pin->proc_entry) {
snd_device_free(per_pin->codec->bus->card, per_pin->proc_entry); snd_device_free(per_pin->codec->card, per_pin->proc_entry);
per_pin->proc_entry = NULL; per_pin->proc_entry = NULL;
} }
} }
...@@ -1578,9 +1576,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) ...@@ -1578,9 +1576,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
update_eld = true; update_eld = true;
} }
else if (repoll) { else if (repoll) {
queue_delayed_work(codec->bus->workq, schedule_delayed_work(&per_pin->work,
&per_pin->work, msecs_to_jiffies(300));
msecs_to_jiffies(300));
goto unlock; goto unlock;
} }
} }
...@@ -1624,7 +1621,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) ...@@ -1624,7 +1621,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
} }
if (eld_changed) if (eld_changed)
snd_ctl_notify(codec->bus->card, snd_ctl_notify(codec->card,
SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
&per_pin->eld_ctl->id); &per_pin->eld_ctl->id);
unlock: unlock:
...@@ -2056,11 +2053,10 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) ...@@ -2056,11 +2053,10 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
struct hdmi_spec_per_pin *per_pin; struct hdmi_spec_per_pin *per_pin;
per_pin = get_pin(spec, pin_idx); per_pin = get_pin(spec, pin_idx);
sprintf(per_pin->pcm_name, "HDMI %d", pin_idx); info = snd_hda_codec_pcm_new(codec, "HDMI %d", pin_idx);
info = snd_array_new(&spec->pcm_rec);
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
info->name = per_pin->pcm_name; spec->pcm_rec[pin_idx] = info;
info->pcm_type = HDA_PCM_TYPE_HDMI; info->pcm_type = HDA_PCM_TYPE_HDMI;
info->own_chmap = true; info->own_chmap = true;
...@@ -2070,9 +2066,6 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) ...@@ -2070,9 +2066,6 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
/* other pstr fields are set in open */ /* other pstr fields are set in open */
} }
codec->num_pcms = spec->num_pins;
codec->pcm_info = spec->pcm_rec.list;
return 0; return 0;
} }
...@@ -2125,13 +2118,15 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) ...@@ -2125,13 +2118,15 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
/* add channel maps */ /* add channel maps */
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hda_pcm *pcm;
struct snd_pcm_chmap *chmap; struct snd_pcm_chmap *chmap;
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
int i; int i;
if (!codec->pcm_info[pin_idx].pcm) pcm = spec->pcm_rec[pin_idx];
if (!pcm || !pcm->pcm)
break; break;
err = snd_pcm_add_chmap_ctls(codec->pcm_info[pin_idx].pcm, err = snd_pcm_add_chmap_ctls(pcm->pcm,
SNDRV_PCM_STREAM_PLAYBACK, SNDRV_PCM_STREAM_PLAYBACK,
NULL, 0, pin_idx, &chmap); NULL, 0, pin_idx, &chmap);
if (err < 0) if (err < 0)
...@@ -2186,14 +2181,12 @@ static void hdmi_array_init(struct hdmi_spec *spec, int nums) ...@@ -2186,14 +2181,12 @@ static void hdmi_array_init(struct hdmi_spec *spec, int nums)
{ {
snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums); snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums);
snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums); snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums);
snd_array_init(&spec->pcm_rec, sizeof(struct hda_pcm), nums);
} }
static void hdmi_array_free(struct hdmi_spec *spec) static void hdmi_array_free(struct hdmi_spec *spec)
{ {
snd_array_free(&spec->pins); snd_array_free(&spec->pins);
snd_array_free(&spec->cvts); snd_array_free(&spec->cvts);
snd_array_free(&spec->pcm_rec);
} }
static void generic_hdmi_free(struct hda_codec *codec) static void generic_hdmi_free(struct hda_codec *codec)
...@@ -2204,11 +2197,10 @@ static void generic_hdmi_free(struct hda_codec *codec) ...@@ -2204,11 +2197,10 @@ static void generic_hdmi_free(struct hda_codec *codec)
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
cancel_delayed_work(&per_pin->work); cancel_delayed_work_sync(&per_pin->work);
eld_proc_free(per_pin); eld_proc_free(per_pin);
} }
flush_workqueue(codec->bus->workq);
hdmi_array_free(spec); hdmi_array_free(spec);
kfree(spec); kfree(spec);
} }
...@@ -2381,11 +2373,10 @@ static int simple_playback_build_pcms(struct hda_codec *codec) ...@@ -2381,11 +2373,10 @@ static int simple_playback_build_pcms(struct hda_codec *codec)
chans = get_wcaps(codec, per_cvt->cvt_nid); chans = get_wcaps(codec, per_cvt->cvt_nid);
chans = get_wcaps_channels(chans); chans = get_wcaps_channels(chans);
info = snd_array_new(&spec->pcm_rec); info = snd_hda_codec_pcm_new(codec, "HDMI 0");
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
info->name = get_pin(spec, 0)->pcm_name; spec->pcm_rec[0] = info;
sprintf(info->name, "HDMI 0");
info->pcm_type = HDA_PCM_TYPE_HDMI; info->pcm_type = HDA_PCM_TYPE_HDMI;
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
*pstr = spec->pcm_playback; *pstr = spec->pcm_playback;
...@@ -2393,9 +2384,6 @@ static int simple_playback_build_pcms(struct hda_codec *codec) ...@@ -2393,9 +2384,6 @@ static int simple_playback_build_pcms(struct hda_codec *codec)
if (pstr->channels_max <= 2 && chans && chans <= 16) if (pstr->channels_max <= 2 && chans && chans <= 16)
pstr->channels_max = chans; pstr->channels_max = chans;
codec->num_pcms = 1;
codec->pcm_info = info;
return 0; return 0;
} }
......
...@@ -5850,7 +5850,7 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec, ...@@ -5850,7 +5850,7 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec,
{ {
if (action == HDA_FIXUP_ACT_BUILD) { if (action == HDA_FIXUP_ACT_BUILD) {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
spec->gen.pcm_rec[0].stream[0].chmap = asus_pcm_2_1_chmaps; spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps;
} }
} }
......
...@@ -83,7 +83,6 @@ ...@@ -83,7 +83,6 @@
struct si3054_spec { struct si3054_spec {
unsigned international; unsigned international;
struct hda_pcm pcm;
}; };
...@@ -199,11 +198,11 @@ static const struct hda_pcm_stream si3054_pcm = { ...@@ -199,11 +198,11 @@ static const struct hda_pcm_stream si3054_pcm = {
static int si3054_build_pcms(struct hda_codec *codec) static int si3054_build_pcms(struct hda_codec *codec)
{ {
struct si3054_spec *spec = codec->spec; struct hda_pcm *info;
struct hda_pcm *info = &spec->pcm;
codec->num_pcms = 1; info = snd_hda_codec_pcm_new(codec, "Si3054 Modem");
codec->pcm_info = info; if (!info)
info->name = "Si3054 Modem"; return -ENOMEM;
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
info->stream[SNDRV_PCM_STREAM_CAPTURE] = si3054_pcm; info->stream[SNDRV_PCM_STREAM_CAPTURE] = si3054_pcm;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->mfg; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->mfg;
......
...@@ -222,8 +222,7 @@ static void vt1708_update_hp_work(struct hda_codec *codec) ...@@ -222,8 +222,7 @@ static void vt1708_update_hp_work(struct hda_codec *codec)
if (!spec->hp_work_active) { if (!spec->hp_work_active) {
codec->jackpoll_interval = msecs_to_jiffies(100); codec->jackpoll_interval = msecs_to_jiffies(100);
snd_hda_codec_write(codec, 0x1, 0, 0xf81, 0); snd_hda_codec_write(codec, 0x1, 0, 0xf81, 0);
queue_delayed_work(codec->bus->workq, schedule_delayed_work(&codec->jackpoll_work, 0);
&codec->jackpoll_work, 0);
spec->hp_work_active = true; spec->hp_work_active = true;
} }
} else if (!hp_detect_with_aa(codec)) } else if (!hp_detect_with_aa(codec))
...@@ -683,8 +682,10 @@ static int vt1708_build_pcms(struct hda_codec *codec) ...@@ -683,8 +682,10 @@ static int vt1708_build_pcms(struct hda_codec *codec)
* 24bit samples are used. Until any workaround is found, * 24bit samples are used. Until any workaround is found,
* disable the 24bit format, so far. * disable the 24bit format, so far.
*/ */
for (i = 0; i < codec->num_pcms; i++) { for (i = 0; i < ARRAY_SIZE(spec->gen.pcm_rec); i++) {
struct hda_pcm *info = &spec->gen.pcm_rec[i]; struct hda_pcm *info = spec->gen.pcm_rec[i];
if (!info)
continue;
if (!info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams || if (!info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams ||
info->pcm_type != HDA_PCM_TYPE_AUDIO) info->pcm_type != HDA_PCM_TYPE_AUDIO)
continue; continue;
...@@ -907,16 +908,16 @@ static int patch_vt1708S(struct hda_codec *codec) ...@@ -907,16 +908,16 @@ static int patch_vt1708S(struct hda_codec *codec)
if (get_codec_type(codec) == VT1708BCE) { if (get_codec_type(codec) == VT1708BCE) {
kfree(codec->chip_name); kfree(codec->chip_name);
codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL); codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
snprintf(codec->bus->card->mixername, snprintf(codec->card->mixername,
sizeof(codec->bus->card->mixername), sizeof(codec->card->mixername),
"%s %s", codec->vendor_name, codec->chip_name); "%s %s", codec->vendor_name, codec->chip_name);
} }
/* correct names for VT1705 */ /* correct names for VT1705 */
if (codec->vendor_id == 0x11064397) { if (codec->vendor_id == 0x11064397) {
kfree(codec->chip_name); kfree(codec->chip_name);
codec->chip_name = kstrdup("VT1705", GFP_KERNEL); codec->chip_name = kstrdup("VT1705", GFP_KERNEL);
snprintf(codec->bus->card->mixername, snprintf(codec->card->mixername,
sizeof(codec->bus->card->mixername), sizeof(codec->card->mixername),
"%s %s", codec->vendor_name, codec->chip_name); "%s %s", codec->vendor_name, codec->chip_name);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment