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;
......
...@@ -681,7 +681,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) ...@@ -681,7 +681,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
struct hda_bus_unsolicited *unsol; struct hda_bus_unsolicited *unsol;
unsigned int wp; unsigned int wp;
if (!bus || !bus->workq) if (!bus)
return 0; return 0;
trace_hda_unsol_event(bus, res, res_ex); trace_hda_unsol_event(bus, res, res_ex);
...@@ -693,7 +693,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) ...@@ -693,7 +693,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
unsol->queue[wp] = res; unsol->queue[wp] = res;
unsol->queue[wp + 1] = res_ex; unsol->queue[wp + 1] = res_ex;
queue_work(bus->workq, &unsol->work); schedule_work(&unsol->work);
return 0; return 0;
} }
...@@ -732,13 +732,9 @@ static void snd_hda_bus_free(struct hda_bus *bus) ...@@ -732,13 +732,9 @@ static void snd_hda_bus_free(struct hda_bus *bus)
return; return;
WARN_ON(!list_empty(&bus->codec_list)); WARN_ON(!list_empty(&bus->codec_list));
if (bus->workq) cancel_work_sync(&bus->unsol.work);
flush_workqueue(bus->workq);
if (bus->ops.private_free) if (bus->ops.private_free)
bus->ops.private_free(bus); bus->ops.private_free(bus);
if (bus->workq)
destroy_workqueue(bus->workq);
kfree(bus); kfree(bus);
} }
...@@ -776,10 +772,8 @@ int snd_hda_bus_new(struct snd_card *card, ...@@ -776,10 +772,8 @@ int snd_hda_bus_new(struct snd_card *card,
*busp = NULL; *busp = NULL;
bus = kzalloc(sizeof(*bus), GFP_KERNEL); bus = kzalloc(sizeof(*bus), GFP_KERNEL);
if (bus == NULL) { if (!bus)
dev_err(card->dev, "can't allocate struct hda_bus\n");
return -ENOMEM; return -ENOMEM;
}
bus->card = card; bus->card = card;
mutex_init(&bus->cmd_mutex); mutex_init(&bus->cmd_mutex);
...@@ -787,16 +781,6 @@ int snd_hda_bus_new(struct snd_card *card, ...@@ -787,16 +781,6 @@ int snd_hda_bus_new(struct snd_card *card,
INIT_LIST_HEAD(&bus->codec_list); INIT_LIST_HEAD(&bus->codec_list);
INIT_WORK(&bus->unsol.work, process_unsol_events); INIT_WORK(&bus->unsol.work, process_unsol_events);
snprintf(bus->workq_name, sizeof(bus->workq_name),
"hd-audio%d", card->number);
bus->workq = create_singlethread_workqueue(bus->workq_name);
if (!bus->workq) {
dev_err(card->dev, "cannot create workqueue %s\n",
bus->workq_name);
kfree(bus);
return -ENOMEM;
}
err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops);
if (err < 0) { if (err < 0) {
snd_hda_bus_free(bus); snd_hda_bus_free(bus);
...@@ -1070,7 +1054,7 @@ static void hda_jackpoll_work(struct work_struct *work) ...@@ -1070,7 +1054,7 @@ static void hda_jackpoll_work(struct work_struct *work)
if (!codec->jackpoll_interval) if (!codec->jackpoll_interval)
return; return;
queue_delayed_work(codec->bus->workq, &codec->jackpoll_work, schedule_delayed_work(&codec->jackpoll_work,
codec->jackpoll_interval); codec->jackpoll_interval);
} }
...@@ -1118,36 +1102,93 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) ...@@ -1118,36 +1102,93 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid)
return p; return p;
} }
/*
* PCM device
*/
static void release_pcm(struct kref *kref)
{
struct hda_pcm *pcm = container_of(kref, struct hda_pcm, kref);
if (pcm->pcm)
snd_device_free(pcm->codec->card, pcm->pcm);
clear_bit(pcm->device, pcm->codec->bus->pcm_dev_bits);
kfree(pcm->name);
kfree(pcm);
}
void snd_hda_codec_pcm_put(struct hda_pcm *pcm)
{
kref_put(&pcm->kref, release_pcm);
}
EXPORT_SYMBOL_GPL(snd_hda_codec_pcm_put);
struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec,
const char *fmt, ...)
{
struct hda_pcm *pcm;
va_list args;
va_start(args, fmt);
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return NULL;
pcm->codec = codec;
kref_init(&pcm->kref);
pcm->name = kvasprintf(GFP_KERNEL, fmt, args);
if (!pcm->name) {
kfree(pcm);
return NULL;
}
list_add_tail(&pcm->list, &codec->pcm_list_head);
return pcm;
}
EXPORT_SYMBOL_GPL(snd_hda_codec_pcm_new);
/* /*
* codec destructor * codec destructor
*/ */
static void snd_hda_codec_free(struct hda_codec *codec) static void codec_release_pcms(struct hda_codec *codec)
{
struct hda_pcm *pcm, *n;
list_for_each_entry_safe(pcm, n, &codec->pcm_list_head, list) {
list_del_init(&pcm->list);
if (pcm->pcm)
snd_device_disconnect(codec->card, pcm->pcm);
snd_hda_codec_pcm_put(pcm);
}
}
void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
{ {
if (!codec)
return;
cancel_delayed_work_sync(&codec->jackpoll_work); cancel_delayed_work_sync(&codec->jackpoll_work);
if (device_is_registered(hda_codec_dev(codec))) if (!codec->in_freeing)
device_del(hda_codec_dev(codec)); snd_hda_ctls_clear(codec);
codec_release_pcms(codec);
snd_hda_detach_beep_device(codec);
memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
snd_hda_jack_tbl_clear(codec); snd_hda_jack_tbl_clear(codec);
free_init_pincfgs(codec); codec->proc_widget_hook = NULL;
flush_workqueue(codec->bus->workq); codec->spec = NULL;
list_del(&codec->list);
snd_array_free(&codec->mixers); free_hda_cache(&codec->amp_cache);
snd_array_free(&codec->nids); free_hda_cache(&codec->cmd_cache);
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
/* free only driver_pins so that init_pins + user_pins are restored */
snd_array_free(&codec->driver_pins);
snd_array_free(&codec->cvt_setups); snd_array_free(&codec->cvt_setups);
snd_array_free(&codec->spdif_out); snd_array_free(&codec->spdif_out);
snd_array_free(&codec->verbs);
codec->preset = NULL;
codec->slave_dig_outs = NULL;
codec->spdif_status_reset = 0;
snd_array_free(&codec->mixers);
snd_array_free(&codec->nids);
remove_conn_list(codec); remove_conn_list(codec);
codec->bus->caddr_tbl[codec->addr] = NULL;
clear_bit(codec->addr, &codec->bus->codec_powered);
snd_hda_sysfs_clear(codec);
free_hda_cache(&codec->amp_cache);
free_hda_cache(&codec->cmd_cache);
kfree(codec->vendor_name);
kfree(codec->chip_name);
kfree(codec->modelname);
kfree(codec->wcaps);
codec->bus->num_codecs--;
put_device(hda_codec_dev(codec));
} }
static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
...@@ -1178,14 +1219,32 @@ static int snd_hda_codec_dev_disconnect(struct snd_device *device) ...@@ -1178,14 +1219,32 @@ static int snd_hda_codec_dev_disconnect(struct snd_device *device)
static int snd_hda_codec_dev_free(struct snd_device *device) static int snd_hda_codec_dev_free(struct snd_device *device)
{ {
snd_hda_codec_free(device->device_data); struct hda_codec *codec = device->device_data;
codec->in_freeing = 1;
if (device_is_registered(hda_codec_dev(codec)))
device_del(hda_codec_dev(codec));
put_device(hda_codec_dev(codec));
return 0; return 0;
} }
/* just free the container */
static void snd_hda_codec_dev_release(struct device *dev) static void snd_hda_codec_dev_release(struct device *dev)
{ {
kfree(dev_to_hda_codec(dev)); struct hda_codec *codec = dev_to_hda_codec(dev);
free_init_pincfgs(codec);
list_del(&codec->list);
codec->bus->caddr_tbl[codec->addr] = NULL;
clear_bit(codec->addr, &codec->bus->codec_powered);
snd_hda_sysfs_clear(codec);
free_hda_cache(&codec->amp_cache);
free_hda_cache(&codec->cmd_cache);
kfree(codec->vendor_name);
kfree(codec->chip_name);
kfree(codec->modelname);
kfree(codec->wcaps);
codec->bus->num_codecs--;
kfree(codec);
} }
/** /**
...@@ -1196,9 +1255,8 @@ static void snd_hda_codec_dev_release(struct device *dev) ...@@ -1196,9 +1255,8 @@ static void snd_hda_codec_dev_release(struct device *dev)
* *
* Returns 0 if successful, or a negative error code. * Returns 0 if successful, or a negative error code.
*/ */
int snd_hda_codec_new(struct hda_bus *bus, int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
unsigned int codec_addr, unsigned int codec_addr, struct hda_codec **codecp)
struct hda_codec **codecp)
{ {
struct hda_codec *codec; struct hda_codec *codec;
struct device *dev; struct device *dev;
...@@ -1217,29 +1275,28 @@ int snd_hda_codec_new(struct hda_bus *bus, ...@@ -1217,29 +1275,28 @@ int snd_hda_codec_new(struct hda_bus *bus,
return -EINVAL; return -EINVAL;
if (bus->caddr_tbl[codec_addr]) { if (bus->caddr_tbl[codec_addr]) {
dev_err(bus->card->dev, dev_err(card->dev,
"address 0x%x is already occupied\n", "address 0x%x is already occupied\n",
codec_addr); codec_addr);
return -EBUSY; return -EBUSY;
} }
codec = kzalloc(sizeof(*codec), GFP_KERNEL); codec = kzalloc(sizeof(*codec), GFP_KERNEL);
if (codec == NULL) { if (!codec)
dev_err(bus->card->dev, "can't allocate struct hda_codec\n");
return -ENOMEM; return -ENOMEM;
}
dev = hda_codec_dev(codec); dev = hda_codec_dev(codec);
device_initialize(dev); device_initialize(dev);
dev->parent = bus->card->dev; dev->parent = card->dev;
dev->bus = &snd_hda_bus_type; dev->bus = &snd_hda_bus_type;
dev->release = snd_hda_codec_dev_release; dev->release = snd_hda_codec_dev_release;
dev->groups = snd_hda_dev_attr_groups; dev->groups = snd_hda_dev_attr_groups;
dev_set_name(dev, "hdaudioC%dD%d", bus->card->number, codec_addr); dev_set_name(dev, "hdaudioC%dD%d", card->number, codec_addr);
dev_set_drvdata(dev, codec); /* for sysfs */ dev_set_drvdata(dev, codec); /* for sysfs */
device_enable_async_suspend(dev); device_enable_async_suspend(dev);
codec->bus = bus; codec->bus = bus;
codec->card = card;
codec->addr = codec_addr; codec->addr = codec_addr;
mutex_init(&codec->spdif_mutex); mutex_init(&codec->spdif_mutex);
mutex_init(&codec->control_mutex); mutex_init(&codec->control_mutex);
...@@ -1255,6 +1312,7 @@ int snd_hda_codec_new(struct hda_bus *bus, ...@@ -1255,6 +1312,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16); snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16);
snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8); snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8);
INIT_LIST_HEAD(&codec->conn_list); INIT_LIST_HEAD(&codec->conn_list);
INIT_LIST_HEAD(&codec->pcm_list_head);
INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work); INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work);
codec->depop_delay = -1; codec->depop_delay = -1;
...@@ -1300,17 +1358,15 @@ int snd_hda_codec_new(struct hda_bus *bus, ...@@ -1300,17 +1358,15 @@ int snd_hda_codec_new(struct hda_bus *bus,
setup_fg_nodes(codec); setup_fg_nodes(codec);
if (!codec->afg && !codec->mfg) { if (!codec->afg && !codec->mfg) {
dev_err(bus->card->dev, "no AFG or MFG node found\n"); codec_err(codec, "no AFG or MFG node found\n");
err = -ENODEV; err = -ENODEV;
goto error; goto error;
} }
fg = codec->afg ? codec->afg : codec->mfg; fg = codec->afg ? codec->afg : codec->mfg;
err = read_widget_caps(codec, fg); err = read_widget_caps(codec, fg);
if (err < 0) { if (err < 0)
dev_err(bus->card->dev, "cannot malloc\n");
goto error; goto error;
}
err = read_pin_defaults(codec); err = read_pin_defaults(codec);
if (err < 0) if (err < 0)
goto error; goto error;
...@@ -1337,9 +1393,9 @@ int snd_hda_codec_new(struct hda_bus *bus, ...@@ -1337,9 +1393,9 @@ int snd_hda_codec_new(struct hda_bus *bus,
sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id,
codec->subsystem_id, codec->revision_id); codec->subsystem_id, codec->revision_id);
snd_component_add(codec->bus->card, component); snd_component_add(card, component);
err = snd_device_new(bus->card, SNDRV_DEV_CODEC, codec, &dev_ops); err = snd_device_new(card, SNDRV_DEV_CODEC, codec, &dev_ops);
if (err < 0) if (err < 0)
goto error; goto error;
...@@ -1348,7 +1404,7 @@ int snd_hda_codec_new(struct hda_bus *bus, ...@@ -1348,7 +1404,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
return 0; return 0;
error: error:
snd_hda_codec_free(codec); put_device(hda_codec_dev(codec));
return err; return err;
} }
EXPORT_SYMBOL_GPL(snd_hda_codec_new); EXPORT_SYMBOL_GPL(snd_hda_codec_new);
...@@ -1371,10 +1427,8 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec) ...@@ -1371,10 +1427,8 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec)
kfree(codec->wcaps); kfree(codec->wcaps);
fg = codec->afg ? codec->afg : codec->mfg; fg = codec->afg ? codec->afg : codec->mfg;
err = read_widget_caps(codec, fg); err = read_widget_caps(codec, fg);
if (err < 0) { if (err < 0)
codec_err(codec, "cannot malloc\n");
return err; return err;
}
snd_array_free(&codec->init_pins); snd_array_free(&codec->init_pins);
err = read_pin_defaults(codec); err = read_pin_defaults(codec);
...@@ -2237,7 +2291,7 @@ find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx) ...@@ -2237,7 +2291,7 @@ find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx)
if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) if (snd_BUG_ON(strlen(name) >= sizeof(id.name)))
return NULL; return NULL;
strcpy(id.name, name); strcpy(id.name, name);
return snd_ctl_find_id(codec->bus->card, &id); return snd_ctl_find_id(codec->card, &id);
} }
/** /**
...@@ -2301,7 +2355,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, ...@@ -2301,7 +2355,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
nid = kctl->id.subdevice & 0xffff; nid = kctl->id.subdevice & 0xffff;
if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG)) if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG))
kctl->id.subdevice = 0; kctl->id.subdevice = 0;
err = snd_ctl_add(codec->bus->card, kctl); err = snd_ctl_add(codec->card, kctl);
if (err < 0) if (err < 0)
return err; return err;
item = snd_array_new(&codec->mixers); item = snd_array_new(&codec->mixers);
...@@ -2354,7 +2408,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec) ...@@ -2354,7 +2408,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
int i; int i;
struct hda_nid_item *items = codec->mixers.list; struct hda_nid_item *items = codec->mixers.list;
for (i = 0; i < codec->mixers.used; i++) for (i = 0; i < codec->mixers.used; i++)
snd_ctl_remove(codec->bus->card, items[i].kctl); snd_ctl_remove(codec->card, items[i].kctl);
snd_array_free(&codec->mixers); snd_array_free(&codec->mixers);
snd_array_free(&codec->nids); snd_array_free(&codec->nids);
} }
...@@ -2378,9 +2432,8 @@ int snd_hda_lock_devices(struct hda_bus *bus) ...@@ -2378,9 +2432,8 @@ int snd_hda_lock_devices(struct hda_bus *bus)
goto err_clear; goto err_clear;
list_for_each_entry(codec, &bus->codec_list, list) { list_for_each_entry(codec, &bus->codec_list, list) {
int pcm; struct hda_pcm *cpcm;
for (pcm = 0; pcm < codec->num_pcms; pcm++) { list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
struct hda_pcm *cpcm = &codec->pcm_info[pcm];
if (!cpcm->pcm) if (!cpcm->pcm)
continue; continue;
if (cpcm->pcm->streams[0].substream_opened || if (cpcm->pcm->streams[0].substream_opened ||
...@@ -2407,7 +2460,6 @@ void snd_hda_unlock_devices(struct hda_bus *bus) ...@@ -2407,7 +2460,6 @@ void snd_hda_unlock_devices(struct hda_bus *bus)
{ {
struct snd_card *card = bus->card; struct snd_card *card = bus->card;
card = bus->card;
spin_lock(&card->files_lock); spin_lock(&card->files_lock);
card->shutdown = 0; card->shutdown = 0;
spin_unlock(&card->files_lock); spin_unlock(&card->files_lock);
...@@ -2427,47 +2479,14 @@ EXPORT_SYMBOL_GPL(snd_hda_unlock_devices); ...@@ -2427,47 +2479,14 @@ EXPORT_SYMBOL_GPL(snd_hda_unlock_devices);
int snd_hda_codec_reset(struct hda_codec *codec) int snd_hda_codec_reset(struct hda_codec *codec)
{ {
struct hda_bus *bus = codec->bus; struct hda_bus *bus = codec->bus;
struct snd_card *card = bus->card;
int i;
if (snd_hda_lock_devices(bus) < 0) if (snd_hda_lock_devices(bus) < 0)
return -EBUSY; return -EBUSY;
/* OK, let it free */ /* OK, let it free */
cancel_delayed_work_sync(&codec->jackpoll_work);
flush_workqueue(bus->workq);
snd_hda_ctls_clear(codec);
/* release PCMs */
for (i = 0; i < codec->num_pcms; i++) {
if (codec->pcm_info[i].pcm) {
snd_device_free(card, codec->pcm_info[i].pcm);
clear_bit(codec->pcm_info[i].device,
bus->pcm_dev_bits);
}
}
snd_hda_detach_beep_device(codec);
if (device_is_registered(hda_codec_dev(codec))) if (device_is_registered(hda_codec_dev(codec)))
device_del(hda_codec_dev(codec)); device_del(hda_codec_dev(codec));
memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
snd_hda_jack_tbl_clear(codec);
codec->proc_widget_hook = NULL;
codec->spec = NULL;
free_hda_cache(&codec->amp_cache);
free_hda_cache(&codec->cmd_cache);
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
/* free only driver_pins so that init_pins + user_pins are restored */
snd_array_free(&codec->driver_pins);
snd_array_free(&codec->cvt_setups);
snd_array_free(&codec->spdif_out);
snd_array_free(&codec->verbs);
codec->num_pcms = 0;
codec->pcm_info = NULL;
codec->preset = NULL;
codec->slave_dig_outs = NULL;
codec->spdif_status_reset = 0;
/* allow device access again */ /* allow device access again */
snd_hda_unlock_devices(bus); snd_hda_unlock_devices(bus);
return 0; return 0;
...@@ -3960,12 +3979,12 @@ static void hda_call_codec_resume(struct hda_codec *codec) ...@@ -3960,12 +3979,12 @@ static void hda_call_codec_resume(struct hda_codec *codec)
static int hda_codec_runtime_suspend(struct device *dev) static int hda_codec_runtime_suspend(struct device *dev)
{ {
struct hda_codec *codec = dev_to_hda_codec(dev); struct hda_codec *codec = dev_to_hda_codec(dev);
struct hda_pcm *pcm;
unsigned int state; unsigned int state;
int i;
cancel_delayed_work_sync(&codec->jackpoll_work); cancel_delayed_work_sync(&codec->jackpoll_work);
for (i = 0; i < codec->num_pcms; i++) list_for_each_entry(pcm, &codec->pcm_list_head, list)
snd_pcm_suspend_all(codec->pcm_info[i].pcm); snd_pcm_suspend_all(pcm->pcm);
state = hda_call_codec_suspend(codec); state = hda_call_codec_suspend(codec);
if (codec->d3_stop_clk && codec->epss && (state & AC_PWRST_CLK_STOP_OK)) if (codec->d3_stop_clk && codec->epss && (state & AC_PWRST_CLK_STOP_OK))
clear_bit(codec->addr, &codec->bus->codec_powered); clear_bit(codec->addr, &codec->bus->codec_powered);
...@@ -3991,57 +4010,26 @@ const struct dev_pm_ops hda_codec_driver_pm = { ...@@ -3991,57 +4010,26 @@ const struct dev_pm_ops hda_codec_driver_pm = {
NULL) NULL)
}; };
/**
* snd_hda_build_controls - build mixer controls
* @bus: the BUS
*
* Creates mixer controls for each codec included in the bus.
*
* Returns 0 if successful, otherwise a negative error code.
*/
int snd_hda_build_controls(struct hda_bus *bus)
{
struct hda_codec *codec;
list_for_each_entry(codec, &bus->codec_list, list) {
int err = snd_hda_codec_build_controls(codec);
if (err < 0) {
codec_err(codec,
"cannot build controls for #%d (error %d)\n",
codec->addr, err);
err = snd_hda_codec_reset(codec);
if (err < 0) {
codec_err(codec,
"cannot revert codec\n");
return err;
}
}
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_build_controls);
/* /*
* add standard channel maps if not specified * add standard channel maps if not specified
*/ */
static int add_std_chmaps(struct hda_codec *codec) static int add_std_chmaps(struct hda_codec *codec)
{ {
int i, str, err; struct hda_pcm *pcm;
int str, err;
for (i = 0; i < codec->num_pcms; i++) { list_for_each_entry(pcm, &codec->pcm_list_head, list) {
for (str = 0; str < 2; str++) { for (str = 0; str < 2; str++) {
struct snd_pcm *pcm = codec->pcm_info[i].pcm; struct hda_pcm_stream *hinfo = &pcm->stream[str];
struct hda_pcm_stream *hinfo =
&codec->pcm_info[i].stream[str];
struct snd_pcm_chmap *chmap; struct snd_pcm_chmap *chmap;
const struct snd_pcm_chmap_elem *elem; const struct snd_pcm_chmap_elem *elem;
if (codec->pcm_info[i].own_chmap) if (pcm->own_chmap)
continue; continue;
if (!pcm || !hinfo->substreams) if (!pcm || !hinfo->substreams)
continue; continue;
elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps; elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps;
err = snd_pcm_add_chmap_ctls(pcm, str, elem, err = snd_pcm_add_chmap_ctls(pcm->pcm, str, elem,
hinfo->channels_max, hinfo->channels_max,
0, &chmap); 0, &chmap);
if (err < 0) if (err < 0)
...@@ -4490,7 +4478,11 @@ int snd_hda_codec_prepare(struct hda_codec *codec, ...@@ -4490,7 +4478,11 @@ int snd_hda_codec_prepare(struct hda_codec *codec,
{ {
int ret; int ret;
mutex_lock(&codec->bus->prepare_mutex); mutex_lock(&codec->bus->prepare_mutex);
ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream); if (hinfo->ops.prepare)
ret = hinfo->ops.prepare(hinfo, codec, stream, format,
substream);
else
ret = -ENODEV;
if (ret >= 0) if (ret >= 0)
purify_inactive_streams(codec); purify_inactive_streams(codec);
mutex_unlock(&codec->bus->prepare_mutex); mutex_unlock(&codec->bus->prepare_mutex);
...@@ -4511,6 +4503,7 @@ void snd_hda_codec_cleanup(struct hda_codec *codec, ...@@ -4511,6 +4503,7 @@ void snd_hda_codec_cleanup(struct hda_codec *codec,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
mutex_lock(&codec->bus->prepare_mutex); mutex_lock(&codec->bus->prepare_mutex);
if (hinfo->ops.cleanup)
hinfo->ops.cleanup(hinfo, codec, substream); hinfo->ops.cleanup(hinfo, codec, substream);
mutex_unlock(&codec->bus->prepare_mutex); mutex_unlock(&codec->bus->prepare_mutex);
} }
...@@ -4569,63 +4562,74 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type) ...@@ -4569,63 +4562,74 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
return -EAGAIN; return -EAGAIN;
} }
/* /* call build_pcms ops of the given codec and set up the default parameters */
* attach a new PCM stream int snd_hda_codec_parse_pcms(struct hda_codec *codec)
*/
static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
{ {
struct hda_bus *bus = codec->bus; struct hda_pcm *cpcm;
struct hda_pcm_stream *info; int err;
int stream, err;
if (!list_empty(&codec->pcm_list_head))
return 0; /* already parsed */
if (!codec->patch_ops.build_pcms)
return 0;
err = codec->patch_ops.build_pcms(codec);
if (err < 0) {
codec_err(codec, "cannot build PCMs for #%d (error %d)\n",
codec->addr, err);
return err;
}
list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
int stream;
if (snd_BUG_ON(!pcm->name))
return -EINVAL;
for (stream = 0; stream < 2; stream++) { for (stream = 0; stream < 2; stream++) {
info = &pcm->stream[stream]; struct hda_pcm_stream *info = &cpcm->stream[stream];
if (info->substreams) {
if (!info->substreams)
continue;
err = set_pcm_default_values(codec, info); err = set_pcm_default_values(codec, info);
if (err < 0) if (err < 0) {
codec_warn(codec,
"fail to setup default for PCM %s\n",
cpcm->name);
return err; return err;
} }
} }
return bus->ops.attach_pcm(bus, codec, pcm); }
return 0;
} }
/* assign all PCMs of the given codec */ /* assign all PCMs of the given codec */
int snd_hda_codec_build_pcms(struct hda_codec *codec) int snd_hda_codec_build_pcms(struct hda_codec *codec)
{ {
unsigned int pcm; struct hda_bus *bus = codec->bus;
int err; struct hda_pcm *cpcm;
int dev, err;
if (!codec->num_pcms) { if (snd_BUG_ON(!bus->ops.attach_pcm))
if (!codec->patch_ops.build_pcms) return -EINVAL;
return 0;
err = codec->patch_ops.build_pcms(codec); err = snd_hda_codec_parse_pcms(codec);
if (err < 0) {
codec_err(codec,
"cannot build PCMs for #%d (error %d)\n",
codec->addr, err);
err = snd_hda_codec_reset(codec);
if (err < 0) { if (err < 0) {
codec_err(codec, snd_hda_codec_reset(codec);
"cannot revert codec\n");
return err; return err;
} }
}
}
for (pcm = 0; pcm < codec->num_pcms; pcm++) {
struct hda_pcm *cpcm = &codec->pcm_info[pcm];
int dev;
/* attach a new PCM streams */
list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
if (cpcm->pcm)
continue; /* already attached */
if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
continue; /* no substreams assigned */ continue; /* no substreams assigned */
if (!cpcm->pcm) { dev = get_empty_pcm_device(bus, cpcm->pcm_type);
dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type);
if (dev < 0) if (dev < 0)
continue; /* no fatal error */ continue; /* no fatal error */
cpcm->device = dev; cpcm->device = dev;
err = snd_hda_attach_pcm(codec, cpcm); err = bus->ops.attach_pcm(bus, codec, cpcm);
if (err < 0) { if (err < 0) {
codec_err(codec, codec_err(codec,
"cannot attach PCM stream %d for codec #%d\n", "cannot attach PCM stream %d for codec #%d\n",
...@@ -4633,48 +4637,9 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) ...@@ -4633,48 +4637,9 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
continue; /* no fatal error */ continue; /* no fatal error */
} }
} }
}
return 0;
}
/**
* snd_hda_build_pcms - build PCM information
* @bus: the BUS
*
* Create PCM information for each codec included in the bus.
*
* The build_pcms codec patch is requested to set up codec->num_pcms and
* codec->pcm_info properly. The array is referred by the top-level driver
* to create its PCM instances.
* The allocated codec->pcm_info should be released in codec->patch_ops.free
* callback.
*
* At least, substreams, channels_min and channels_max must be filled for
* each stream. substreams = 0 indicates that the stream doesn't exist.
* When rates and/or formats are zero, the supported values are queried
* from the given nid. The nid is used also by the default ops.prepare
* and ops.cleanup callbacks.
*
* The driver needs to call ops.open in its open callback. Similarly,
* ops.close is supposed to be called in the close callback.
* ops.prepare should be called in the prepare or hw_params callback
* with the proper parameters for set up.
* ops.cleanup should be called in hw_free for clean up of streams.
*
* This function returns 0 if successful, or a negative error code.
*/
int snd_hda_build_pcms(struct hda_bus *bus)
{
struct hda_codec *codec;
list_for_each_entry(codec, &bus->codec_list, list) {
int err = snd_hda_codec_build_pcms(codec);
if (err < 0)
return err;
}
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(snd_hda_build_pcms);
/** /**
* snd_hda_add_new_ctls - create controls from the array * snd_hda_add_new_ctls - create controls from the array
...@@ -4976,24 +4941,6 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) ...@@ -4976,24 +4941,6 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
} }
} }
/**
* snd_hda_bus_reboot_notify - call the reboot notifier of each codec
* @bus: HD-audio bus
*/
void snd_hda_bus_reboot_notify(struct hda_bus *bus)
{
struct hda_codec *codec;
if (!bus)
return;
list_for_each_entry(codec, &bus->codec_list, list) {
if (hda_codec_is_power_on(codec) &&
codec->patch_ops.reboot_notify)
codec->patch_ops.reboot_notify(codec);
}
}
EXPORT_SYMBOL_GPL(snd_hda_bus_reboot_notify);
/** /**
* snd_hda_multi_out_dig_open - open the digital out in the exclusive mode * snd_hda_multi_out_dig_open - open the digital out in the exclusive mode
* @codec: the HDA codec * @codec: the HDA codec
......
...@@ -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);
if (hinfo->ops.close)
hinfo->ops.close(hinfo, apcm->codec, substream); 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);
if (hinfo->ops.open)
err = hinfo->ops.open(hinfo, apcm->codec, substream); 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);
if (hinfo->ops.close)
hinfo->ops.close(hinfo, apcm->codec, substream); hinfo->ops.close(hinfo, apcm->codec, substream);
snd_hda_power_down(apcm->codec); err = -EINVAL;
mutex_unlock(&chip->open_mutex); goto powerdown;
return -EINVAL;
} }
/* 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,8 +1576,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) ...@@ -1578,8 +1576,7 @@ 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