mirror of https://gitee.com/openkylin/linux.git
Merge branch 'topic/hda-unbind' into for-next
This commit is contained in:
commit
2a557a861a
|
@ -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);
|
||||
int snd_device_register(struct snd_card *card, void *device_data);
|
||||
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_all(struct snd_card *card);
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type,
|
|||
}
|
||||
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->ops->dev_disconnect &&
|
||||
|
@ -79,7 +79,6 @@ static int __snd_device_disconnect(struct snd_device *dev)
|
|||
dev_err(dev->card->dev, "device disconnect failure\n");
|
||||
dev->state = SNDRV_DEV_DISCONNECTED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
|||
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
|
||||
* @card: the card instance
|
||||
|
@ -193,18 +220,14 @@ int snd_device_register_all(struct snd_card *card)
|
|||
* disconnect all the devices on the card.
|
||||
* 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;
|
||||
int err = 0;
|
||||
|
||||
if (snd_BUG_ON(!card))
|
||||
return -ENXIO;
|
||||
list_for_each_entry_reverse(dev, &card->devices, list) {
|
||||
if (__snd_device_disconnect(dev) < 0)
|
||||
err = -ENXIO;
|
||||
}
|
||||
return err;
|
||||
return;
|
||||
list_for_each_entry_reverse(dev, &card->devices, list)
|
||||
__snd_device_disconnect(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -400,7 +400,6 @@ static const struct file_operations snd_shutdown_f_ops =
|
|||
int snd_card_disconnect(struct snd_card *card)
|
||||
{
|
||||
struct snd_monitor_file *mfile;
|
||||
int err;
|
||||
|
||||
if (!card)
|
||||
return -EINVAL;
|
||||
|
@ -445,9 +444,7 @@ int snd_card_disconnect(struct snd_card *card)
|
|||
#endif
|
||||
|
||||
/* notify all devices that we are disconnected */
|
||||
err = 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_device_disconnect_all(card);
|
||||
|
||||
snd_info_card_disconnect(card);
|
||||
if (card->registered) {
|
||||
|
|
|
@ -160,7 +160,7 @@ static int snd_hda_do_attach(struct hda_beep *beep)
|
|||
input_dev->name = "HDA Digital PCBeep";
|
||||
input_dev->phys = beep->phys;
|
||||
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.product = codec->vendor_id & 0xffff;
|
||||
|
@ -224,7 +224,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
|
|||
if (beep == NULL)
|
||||
return -ENOMEM;
|
||||
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 */
|
||||
snd_hda_codec_write_cache(codec, nid, 0,
|
||||
AC_VERB_SET_DIGI_CONVERT_2, 0x01);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
|
@ -106,16 +107,28 @@ static int hda_codec_driver_probe(struct device *dev)
|
|||
}
|
||||
|
||||
err = codec->preset->patch(codec);
|
||||
if (err < 0) {
|
||||
module_put(owner);
|
||||
goto error;
|
||||
if (err < 0)
|
||||
goto error_module;
|
||||
|
||||
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;
|
||||
|
||||
error_module:
|
||||
module_put(owner);
|
||||
|
||||
error:
|
||||
codec->preset = NULL;
|
||||
memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
|
||||
snd_hda_codec_cleanup_for_unbind(codec);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -125,12 +138,19 @@ static int hda_codec_driver_remove(struct device *dev)
|
|||
|
||||
if (codec->patch_ops.free)
|
||||
codec->patch_ops.free(codec);
|
||||
codec->preset = NULL;
|
||||
memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
|
||||
snd_hda_codec_cleanup_for_unbind(codec);
|
||||
module_put(dev->driver->owner);
|
||||
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,
|
||||
struct module *owner)
|
||||
{
|
||||
|
@ -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.probe = hda_codec_driver_probe;
|
||||
drv->driver.remove = hda_codec_driver_remove;
|
||||
drv->driver.shutdown = hda_codec_driver_shutdown;
|
||||
drv->driver.pm = &hda_codec_driver_pm;
|
||||
return driver_register(&drv->driver);
|
||||
}
|
||||
|
@ -287,9 +308,9 @@ int snd_hda_codec_configure(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
/* audio codec should override the mixer name */
|
||||
if (codec->afg || !*codec->bus->card->mixername)
|
||||
snprintf(codec->bus->card->mixername,
|
||||
sizeof(codec->bus->card->mixername),
|
||||
if (codec->afg || !*codec->card->mixername)
|
||||
snprintf(codec->card->mixername,
|
||||
sizeof(codec->card->mixername),
|
||||
"%s %s", codec->vendor_name, codec->chip_name);
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -681,7 +681,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
|
|||
struct hda_bus_unsolicited *unsol;
|
||||
unsigned int wp;
|
||||
|
||||
if (!bus || !bus->workq)
|
||||
if (!bus)
|
||||
return 0;
|
||||
|
||||
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)
|
|||
unsol->queue[wp] = res;
|
||||
unsol->queue[wp + 1] = res_ex;
|
||||
|
||||
queue_work(bus->workq, &unsol->work);
|
||||
schedule_work(&unsol->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -732,13 +732,9 @@ static void snd_hda_bus_free(struct hda_bus *bus)
|
|||
return;
|
||||
|
||||
WARN_ON(!list_empty(&bus->codec_list));
|
||||
if (bus->workq)
|
||||
flush_workqueue(bus->workq);
|
||||
cancel_work_sync(&bus->unsol.work);
|
||||
if (bus->ops.private_free)
|
||||
bus->ops.private_free(bus);
|
||||
if (bus->workq)
|
||||
destroy_workqueue(bus->workq);
|
||||
|
||||
kfree(bus);
|
||||
}
|
||||
|
||||
|
@ -776,10 +772,8 @@ int snd_hda_bus_new(struct snd_card *card,
|
|||
*busp = NULL;
|
||||
|
||||
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
|
||||
if (bus == NULL) {
|
||||
dev_err(card->dev, "can't allocate struct hda_bus\n");
|
||||
if (!bus)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bus->card = card;
|
||||
mutex_init(&bus->cmd_mutex);
|
||||
|
@ -787,16 +781,6 @@ int snd_hda_bus_new(struct snd_card *card,
|
|||
INIT_LIST_HEAD(&bus->codec_list);
|
||||
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);
|
||||
if (err < 0) {
|
||||
snd_hda_bus_free(bus);
|
||||
|
@ -1070,8 +1054,8 @@ static void hda_jackpoll_work(struct work_struct *work)
|
|||
if (!codec->jackpoll_interval)
|
||||
return;
|
||||
|
||||
queue_delayed_work(codec->bus->workq, &codec->jackpoll_work,
|
||||
codec->jackpoll_interval);
|
||||
schedule_delayed_work(&codec->jackpoll_work,
|
||||
codec->jackpoll_interval);
|
||||
}
|
||||
|
||||
static void init_hda_cache(struct hda_cache_rec *cache,
|
||||
|
@ -1118,36 +1102,93 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid)
|
|||
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
|
||||
*/
|
||||
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);
|
||||
if (device_is_registered(hda_codec_dev(codec)))
|
||||
device_del(hda_codec_dev(codec));
|
||||
if (!codec->in_freeing)
|
||||
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);
|
||||
free_init_pincfgs(codec);
|
||||
flush_workqueue(codec->bus->workq);
|
||||
list_del(&codec->list);
|
||||
snd_array_free(&codec->mixers);
|
||||
snd_array_free(&codec->nids);
|
||||
snd_array_free(&codec->cvt_setups);
|
||||
snd_array_free(&codec->spdif_out);
|
||||
remove_conn_list(codec);
|
||||
codec->bus->caddr_tbl[codec->addr] = NULL;
|
||||
clear_bit(codec->addr, &codec->bus->codec_powered);
|
||||
snd_hda_sysfs_clear(codec);
|
||||
codec->proc_widget_hook = NULL;
|
||||
codec->spec = NULL;
|
||||
|
||||
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));
|
||||
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->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);
|
||||
}
|
||||
|
||||
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)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
/* just free the container */
|
||||
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)
|
|||
*
|
||||
* Returns 0 if successful, or a negative error code.
|
||||
*/
|
||||
int snd_hda_codec_new(struct hda_bus *bus,
|
||||
unsigned int codec_addr,
|
||||
struct hda_codec **codecp)
|
||||
int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
|
||||
unsigned int codec_addr, struct hda_codec **codecp)
|
||||
{
|
||||
struct hda_codec *codec;
|
||||
struct device *dev;
|
||||
|
@ -1217,29 +1275,28 @@ int snd_hda_codec_new(struct hda_bus *bus,
|
|||
return -EINVAL;
|
||||
|
||||
if (bus->caddr_tbl[codec_addr]) {
|
||||
dev_err(bus->card->dev,
|
||||
dev_err(card->dev,
|
||||
"address 0x%x is already occupied\n",
|
||||
codec_addr);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
codec = kzalloc(sizeof(*codec), GFP_KERNEL);
|
||||
if (codec == NULL) {
|
||||
dev_err(bus->card->dev, "can't allocate struct hda_codec\n");
|
||||
if (!codec)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev = hda_codec_dev(codec);
|
||||
device_initialize(dev);
|
||||
dev->parent = bus->card->dev;
|
||||
dev->parent = card->dev;
|
||||
dev->bus = &snd_hda_bus_type;
|
||||
dev->release = snd_hda_codec_dev_release;
|
||||
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 */
|
||||
device_enable_async_suspend(dev);
|
||||
|
||||
codec->bus = bus;
|
||||
codec->card = card;
|
||||
codec->addr = codec_addr;
|
||||
mutex_init(&codec->spdif_mutex);
|
||||
mutex_init(&codec->control_mutex);
|
||||
|
@ -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->verbs, sizeof(struct hda_verb *), 8);
|
||||
INIT_LIST_HEAD(&codec->conn_list);
|
||||
INIT_LIST_HEAD(&codec->pcm_list_head);
|
||||
|
||||
INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work);
|
||||
codec->depop_delay = -1;
|
||||
|
@ -1300,17 +1358,15 @@ int snd_hda_codec_new(struct hda_bus *bus,
|
|||
|
||||
setup_fg_nodes(codec);
|
||||
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;
|
||||
goto error;
|
||||
}
|
||||
|
||||
fg = codec->afg ? codec->afg : codec->mfg;
|
||||
err = read_widget_caps(codec, fg);
|
||||
if (err < 0) {
|
||||
dev_err(bus->card->dev, "cannot malloc\n");
|
||||
if (err < 0)
|
||||
goto error;
|
||||
}
|
||||
err = read_pin_defaults(codec);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
@ -1337,9 +1393,9 @@ int snd_hda_codec_new(struct hda_bus *bus,
|
|||
|
||||
sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_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)
|
||||
goto error;
|
||||
|
||||
|
@ -1348,7 +1404,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
|
|||
return 0;
|
||||
|
||||
error:
|
||||
snd_hda_codec_free(codec);
|
||||
put_device(hda_codec_dev(codec));
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_new);
|
||||
|
@ -1371,10 +1427,8 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec)
|
|||
kfree(codec->wcaps);
|
||||
fg = codec->afg ? codec->afg : codec->mfg;
|
||||
err = read_widget_caps(codec, fg);
|
||||
if (err < 0) {
|
||||
codec_err(codec, "cannot malloc\n");
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
snd_array_free(&codec->init_pins);
|
||||
err = read_pin_defaults(codec);
|
||||
|
@ -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)))
|
||||
return NULL;
|
||||
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,
|
|||
nid = kctl->id.subdevice & 0xffff;
|
||||
if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG))
|
||||
kctl->id.subdevice = 0;
|
||||
err = snd_ctl_add(codec->bus->card, kctl);
|
||||
err = snd_ctl_add(codec->card, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
item = snd_array_new(&codec->mixers);
|
||||
|
@ -2354,7 +2408,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
|
|||
int i;
|
||||
struct hda_nid_item *items = codec->mixers.list;
|
||||
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->nids);
|
||||
}
|
||||
|
@ -2378,9 +2432,8 @@ int snd_hda_lock_devices(struct hda_bus *bus)
|
|||
goto err_clear;
|
||||
|
||||
list_for_each_entry(codec, &bus->codec_list, list) {
|
||||
int pcm;
|
||||
for (pcm = 0; pcm < codec->num_pcms; pcm++) {
|
||||
struct hda_pcm *cpcm = &codec->pcm_info[pcm];
|
||||
struct hda_pcm *cpcm;
|
||||
list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
|
||||
if (!cpcm->pcm)
|
||||
continue;
|
||||
if (cpcm->pcm->streams[0].substream_opened ||
|
||||
|
@ -2407,7 +2460,6 @@ void snd_hda_unlock_devices(struct hda_bus *bus)
|
|||
{
|
||||
struct snd_card *card = bus->card;
|
||||
|
||||
card = bus->card;
|
||||
spin_lock(&card->files_lock);
|
||||
card->shutdown = 0;
|
||||
spin_unlock(&card->files_lock);
|
||||
|
@ -2427,47 +2479,14 @@ EXPORT_SYMBOL_GPL(snd_hda_unlock_devices);
|
|||
int snd_hda_codec_reset(struct hda_codec *codec)
|
||||
{
|
||||
struct hda_bus *bus = codec->bus;
|
||||
struct snd_card *card = bus->card;
|
||||
int i;
|
||||
|
||||
if (snd_hda_lock_devices(bus) < 0)
|
||||
return -EBUSY;
|
||||
|
||||
/* 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)))
|
||||
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 */
|
||||
snd_hda_unlock_devices(bus);
|
||||
return 0;
|
||||
|
@ -3960,12 +3979,12 @@ static void hda_call_codec_resume(struct hda_codec *codec)
|
|||
static int hda_codec_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct hda_codec *codec = dev_to_hda_codec(dev);
|
||||
struct hda_pcm *pcm;
|
||||
unsigned int state;
|
||||
int i;
|
||||
|
||||
cancel_delayed_work_sync(&codec->jackpoll_work);
|
||||
for (i = 0; i < codec->num_pcms; i++)
|
||||
snd_pcm_suspend_all(codec->pcm_info[i].pcm);
|
||||
list_for_each_entry(pcm, &codec->pcm_list_head, list)
|
||||
snd_pcm_suspend_all(pcm->pcm);
|
||||
state = hda_call_codec_suspend(codec);
|
||||
if (codec->d3_stop_clk && codec->epss && (state & AC_PWRST_CLK_STOP_OK))
|
||||
clear_bit(codec->addr, &codec->bus->codec_powered);
|
||||
|
@ -3991,57 +4010,26 @@ const struct dev_pm_ops hda_codec_driver_pm = {
|
|||
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
|
||||
*/
|
||||
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++) {
|
||||
struct snd_pcm *pcm = codec->pcm_info[i].pcm;
|
||||
struct hda_pcm_stream *hinfo =
|
||||
&codec->pcm_info[i].stream[str];
|
||||
struct hda_pcm_stream *hinfo = &pcm->stream[str];
|
||||
struct snd_pcm_chmap *chmap;
|
||||
const struct snd_pcm_chmap_elem *elem;
|
||||
|
||||
if (codec->pcm_info[i].own_chmap)
|
||||
if (pcm->own_chmap)
|
||||
continue;
|
||||
if (!pcm || !hinfo->substreams)
|
||||
continue;
|
||||
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,
|
||||
0, &chmap);
|
||||
if (err < 0)
|
||||
|
@ -4490,7 +4478,11 @@ int snd_hda_codec_prepare(struct hda_codec *codec,
|
|||
{
|
||||
int ret;
|
||||
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)
|
||||
purify_inactive_streams(codec);
|
||||
mutex_unlock(&codec->bus->prepare_mutex);
|
||||
|
@ -4511,7 +4503,8 @@ void snd_hda_codec_cleanup(struct hda_codec *codec,
|
|||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
mutex_lock(&codec->bus->prepare_mutex);
|
||||
hinfo->ops.cleanup(hinfo, codec, substream);
|
||||
if (hinfo->ops.cleanup)
|
||||
hinfo->ops.cleanup(hinfo, codec, substream);
|
||||
mutex_unlock(&codec->bus->prepare_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup);
|
||||
|
@ -4569,113 +4562,85 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
|
|||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* attach a new PCM stream
|
||||
*/
|
||||
static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
|
||||
/* call build_pcms ops of the given codec and set up the default parameters */
|
||||
int snd_hda_codec_parse_pcms(struct hda_codec *codec)
|
||||
{
|
||||
struct hda_bus *bus = codec->bus;
|
||||
struct hda_pcm_stream *info;
|
||||
int stream, err;
|
||||
struct hda_pcm *cpcm;
|
||||
int err;
|
||||
|
||||
if (snd_BUG_ON(!pcm->name))
|
||||
return -EINVAL;
|
||||
for (stream = 0; stream < 2; stream++) {
|
||||
info = &pcm->stream[stream];
|
||||
if (info->substreams) {
|
||||
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;
|
||||
|
||||
for (stream = 0; stream < 2; stream++) {
|
||||
struct hda_pcm_stream *info = &cpcm->stream[stream];
|
||||
|
||||
if (!info->substreams)
|
||||
continue;
|
||||
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 bus->ops.attach_pcm(bus, codec, pcm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* assign all PCMs of the given codec */
|
||||
int snd_hda_codec_build_pcms(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int pcm;
|
||||
int err;
|
||||
struct hda_bus *bus = codec->bus;
|
||||
struct hda_pcm *cpcm;
|
||||
int dev, err;
|
||||
|
||||
if (!codec->num_pcms) {
|
||||
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);
|
||||
err = snd_hda_codec_reset(codec);
|
||||
if (err < 0) {
|
||||
codec_err(codec,
|
||||
"cannot revert codec\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (snd_BUG_ON(!bus->ops.attach_pcm))
|
||||
return -EINVAL;
|
||||
|
||||
err = snd_hda_codec_parse_pcms(codec);
|
||||
if (err < 0) {
|
||||
snd_hda_codec_reset(codec);
|
||||
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)
|
||||
continue; /* no substreams assigned */
|
||||
|
||||
if (!cpcm->pcm) {
|
||||
dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type);
|
||||
if (dev < 0)
|
||||
continue; /* no fatal error */
|
||||
cpcm->device = dev;
|
||||
err = snd_hda_attach_pcm(codec, cpcm);
|
||||
if (err < 0) {
|
||||
codec_err(codec,
|
||||
"cannot attach PCM stream %d for codec #%d\n",
|
||||
dev, codec->addr);
|
||||
continue; /* no fatal error */
|
||||
}
|
||||
dev = get_empty_pcm_device(bus, cpcm->pcm_type);
|
||||
if (dev < 0)
|
||||
continue; /* no fatal error */
|
||||
cpcm->device = dev;
|
||||
err = bus->ops.attach_pcm(bus, codec, cpcm);
|
||||
if (err < 0) {
|
||||
codec_err(codec,
|
||||
"cannot attach PCM stream %d for codec #%d\n",
|
||||
dev, codec->addr);
|
||||
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;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_build_pcms);
|
||||
|
||||
/**
|
||||
* snd_hda_add_new_ctls - create controls from the array
|
||||
* @codec: the HDA codec
|
||||
|
@ -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
|
||||
* @codec: the HDA codec
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#ifndef __SOUND_HDA_CODEC_H
|
||||
#define __SOUND_HDA_CODEC_H
|
||||
|
||||
#include <linux/kref.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
|
@ -131,8 +132,6 @@ struct hda_bus {
|
|||
|
||||
/* unsolicited event queue */
|
||||
struct hda_bus_unsolicited unsol;
|
||||
char workq_name[16];
|
||||
struct workqueue_struct *workq; /* common workqueue for codecs */
|
||||
|
||||
/* assigned PCMs */
|
||||
DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
|
||||
|
@ -268,12 +267,17 @@ struct hda_pcm {
|
|||
int device; /* device number to assign */
|
||||
struct snd_pcm *pcm; /* assigned PCM instance */
|
||||
bool own_chmap; /* codec driver provides own channel maps */
|
||||
/* private: */
|
||||
struct hda_codec *codec;
|
||||
struct kref kref;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/* codec information */
|
||||
struct hda_codec {
|
||||
struct device dev;
|
||||
struct hda_bus *bus;
|
||||
struct snd_card *card;
|
||||
unsigned int addr; /* codec addr*/
|
||||
struct list_head list; /* list point */
|
||||
|
||||
|
@ -300,8 +304,7 @@ struct hda_codec {
|
|||
struct hda_codec_ops patch_ops;
|
||||
|
||||
/* PCM to create, set by patch_ops.build_pcms callback */
|
||||
unsigned int num_pcms;
|
||||
struct hda_pcm *pcm_info;
|
||||
struct list_head pcm_list_head;
|
||||
|
||||
/* codec specific info */
|
||||
void *spec;
|
||||
|
@ -345,6 +348,7 @@ struct hda_codec {
|
|||
#endif
|
||||
|
||||
/* misc flags */
|
||||
unsigned int in_freeing:1; /* being released */
|
||||
unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
|
||||
* status change
|
||||
* (e.g. Realtek codecs)
|
||||
|
@ -420,8 +424,8 @@ enum {
|
|||
* constructors
|
||||
*/
|
||||
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,
|
||||
struct hda_codec **codecp);
|
||||
int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
|
||||
unsigned int codec_addr, struct hda_codec **codecp);
|
||||
int snd_hda_codec_configure(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);
|
|||
/*
|
||||
* Mixer
|
||||
*/
|
||||
int snd_hda_build_controls(struct hda_bus *bus);
|
||||
int snd_hda_codec_build_controls(struct hda_codec *codec);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
__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,
|
||||
struct hda_pcm_stream *hinfo,
|
||||
unsigned int stream,
|
||||
|
@ -550,7 +563,6 @@ extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[];
|
|||
* Misc
|
||||
*/
|
||||
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,
|
||||
unsigned int power_state);
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include "hda_controller.h"
|
||||
|
@ -416,9 +415,11 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
|
|||
azx_dev->running = 0;
|
||||
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
||||
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);
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
snd_hda_codec_pcm_put(apcm->info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -805,11 +806,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
|
|||
int err;
|
||||
int buff_step;
|
||||
|
||||
snd_hda_codec_pcm_get(apcm->info);
|
||||
mutex_lock(&chip->open_mutex);
|
||||
azx_dev = azx_assign_device(chip, substream);
|
||||
if (azx_dev == NULL) {
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
return -EBUSY;
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
runtime->hw = azx_pcm_hw;
|
||||
runtime->hw.channels_min = hinfo->channels_min;
|
||||
|
@ -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,
|
||||
buff_step);
|
||||
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) {
|
||||
azx_release_device(azx_dev);
|
||||
snd_hda_power_down(apcm->codec);
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
return err;
|
||||
goto powerdown;
|
||||
}
|
||||
snd_pcm_limit_hw_rates(runtime);
|
||||
/* sanity check */
|
||||
|
@ -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.rates)) {
|
||||
azx_release_device(azx_dev);
|
||||
hinfo->ops.close(hinfo, apcm->codec, substream);
|
||||
snd_hda_power_down(apcm->codec);
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
return -EINVAL;
|
||||
if (hinfo->ops.close)
|
||||
hinfo->ops.close(hinfo, apcm->codec, substream);
|
||||
err = -EINVAL;
|
||||
goto powerdown;
|
||||
}
|
||||
|
||||
/* disable LINK_ATIME timestamps for capture streams
|
||||
|
@ -880,6 +883,13 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
|
|||
snd_pcm_set_sync(substream);
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
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,
|
||||
|
@ -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)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* single page (at least 4096 bytes) must suffice for both ringbuffes */
|
||||
err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
|
||||
PAGE_SIZE, &chip->rb);
|
||||
if (err < 0)
|
||||
dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n");
|
||||
return err;
|
||||
return chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
|
||||
PAGE_SIZE, &chip->rb);
|
||||
}
|
||||
|
||||
static void azx_init_cmd_io(struct azx *chip)
|
||||
|
@ -1467,7 +1472,6 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus,
|
|||
int azx_alloc_stream_pages(struct azx *chip)
|
||||
{
|
||||
int i, err;
|
||||
struct snd_card *card = chip->card;
|
||||
|
||||
for (i = 0; i < chip->num_streams; i++) {
|
||||
dsp_lock_init(&chip->azx_dev[i]);
|
||||
|
@ -1475,18 +1479,14 @@ int azx_alloc_stream_pages(struct azx *chip)
|
|||
err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
|
||||
BDL_SIZE,
|
||||
&chip->azx_dev[i].bdl);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "cannot allocate BDL\n");
|
||||
if (err < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
/* allocate memory for the position buffer */
|
||||
err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
|
||||
chip->num_streams * 8, &chip->posbuf);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "cannot allocate posbuf\n");
|
||||
if (err < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* allocate CORB/RIRB */
|
||||
err = azx_alloc_cmd_io(chip);
|
||||
|
@ -1893,7 +1893,7 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots)
|
|||
for (c = 0; c < max_slots; c++) {
|
||||
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
|
||||
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)
|
||||
continue;
|
||||
codec->jackpoll_interval = get_jackpoll_interval(chip);
|
||||
|
@ -1966,30 +1966,5 @@ int azx_init_stream(struct azx *chip)
|
|||
}
|
||||
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_DESCRIPTION("Common HDA driver functions");
|
||||
|
|
|
@ -362,9 +362,6 @@ struct azx {
|
|||
/* for debugging */
|
||||
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
|
||||
struct azx_dev saved_azx_dev;
|
||||
#endif
|
||||
|
@ -437,7 +434,4 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots);
|
|||
int azx_codec_configure(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 */
|
||||
|
|
|
@ -4675,7 +4675,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
|
|||
err = snd_hda_create_dig_out_ctls(codec,
|
||||
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)
|
||||
return err;
|
||||
if (!spec->no_analog) {
|
||||
|
@ -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)
|
||||
{
|
||||
struct hda_gen_spec *spec = codec->spec;
|
||||
struct hda_pcm *info = spec->pcm_rec;
|
||||
struct hda_pcm *info;
|
||||
const struct hda_pcm_stream *p;
|
||||
bool have_multi_adcs;
|
||||
|
||||
codec->num_pcms = 1;
|
||||
codec->pcm_info = info;
|
||||
|
||||
if (spec->no_analog)
|
||||
goto skip_analog;
|
||||
|
||||
fill_pcm_stream_name(spec->stream_name_analog,
|
||||
sizeof(spec->stream_name_analog),
|
||||
" 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) {
|
||||
p = spec->stream_analog_playback;
|
||||
|
@ -5192,10 +5192,12 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec)
|
|||
fill_pcm_stream_name(spec->stream_name_digital,
|
||||
sizeof(spec->stream_name_digital),
|
||||
" 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;
|
||||
info = spec->pcm_rec + 1;
|
||||
info->name = spec->stream_name_digital;
|
||||
spec->pcm_rec[1] = info;
|
||||
if (spec->dig_out_type)
|
||||
info->pcm_type = spec->dig_out_type;
|
||||
else
|
||||
|
@ -5229,9 +5231,11 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec)
|
|||
fill_pcm_stream_name(spec->stream_name_alt_analog,
|
||||
sizeof(spec->stream_name_alt_analog),
|
||||
" Alt Analog", codec->chip_name);
|
||||
codec->num_pcms = 3;
|
||||
info = spec->pcm_rec + 2;
|
||||
info->name = spec->stream_name_alt_analog;
|
||||
info = snd_hda_codec_pcm_new(codec, "%s",
|
||||
spec->stream_name_alt_analog);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
spec->pcm_rec[2] = info;
|
||||
if (spec->alt_dac_nid) {
|
||||
p = spec->stream_analog_alt_playback;
|
||||
if (!p)
|
||||
|
|
|
@ -144,7 +144,7 @@ struct hda_gen_spec {
|
|||
int const_channel_count; /* channel count for all */
|
||||
|
||||
/* 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 */
|
||||
struct auto_pin_cfg autocfg;
|
||||
|
|
|
@ -101,7 +101,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
|
|||
int err;
|
||||
|
||||
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)
|
||||
return err;
|
||||
codec->hwdep = hwdep;
|
||||
|
|
|
@ -528,10 +528,10 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
|
|||
if (ok == 1) {
|
||||
azx_dev->irq_pending = 0;
|
||||
return ok;
|
||||
} else if (ok == 0 && chip->bus && chip->bus->workq) {
|
||||
} else if (ok == 0) {
|
||||
/* bogus IRQ, process it later */
|
||||
azx_dev->irq_pending = 1;
|
||||
queue_work(chip->bus->workq, &hda->irq_pending_work);
|
||||
schedule_work(&hda->irq_pending_work);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -893,8 +893,8 @@ static int azx_runtime_resume(struct device *dev)
|
|||
if (status && bus) {
|
||||
list_for_each_entry(codec, &bus->codec_list, list)
|
||||
if (status & (1 << codec->addr))
|
||||
queue_delayed_work(codec->bus->workq,
|
||||
&codec->jackpoll_work, codec->jackpoll_interval);
|
||||
schedule_delayed_work(&codec->jackpoll_work,
|
||||
codec->jackpoll_interval);
|
||||
}
|
||||
|
||||
/* disable controller Wake Up event*/
|
||||
|
@ -1066,8 +1066,6 @@ static int azx_free(struct azx *chip)
|
|||
|
||||
azx_del_card_list(chip);
|
||||
|
||||
azx_notifier_unregister(chip);
|
||||
|
||||
hda->init_failed = 1; /* to be sure */
|
||||
complete_all(&hda->probe_wait);
|
||||
|
||||
|
@ -1383,7 +1381,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
|
|||
|
||||
hda = kzalloc(sizeof(*hda), GFP_KERNEL);
|
||||
if (!hda) {
|
||||
dev_err(card->dev, "Cannot allocate hda\n");
|
||||
pci_disable_device(pci);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -1564,10 +1561,8 @@ static int azx_first_init(struct azx *chip)
|
|||
chip->num_streams = chip->playback_streams + chip->capture_streams;
|
||||
chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
|
||||
GFP_KERNEL);
|
||||
if (!chip->azx_dev) {
|
||||
dev_err(card->dev, "cannot malloc azx_dev\n");
|
||||
if (!chip->azx_dev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = azx_alloc_stream_pages(chip);
|
||||
if (err < 0)
|
||||
|
@ -1898,22 +1893,11 @@ static int azx_probe_continue(struct azx *chip)
|
|||
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);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
|
||||
chip->running = 1;
|
||||
azx_notifier_register(chip);
|
||||
azx_add_card_list(chip);
|
||||
snd_hda_set_power_save(chip->bus, power_save * 1000);
|
||||
if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)
|
||||
|
@ -1934,6 +1918,18 @@ static void azx_remove(struct pci_dev *pci)
|
|||
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 */
|
||||
static const struct pci_device_id azx_ids[] = {
|
||||
/* CPT */
|
||||
|
@ -2156,6 +2152,7 @@ static struct pci_driver azx_driver = {
|
|||
.id_table = azx_ids,
|
||||
.probe = azx_probe,
|
||||
.remove = azx_remove,
|
||||
.shutdown = azx_shutdown,
|
||||
.driver = {
|
||||
.pm = AZX_PM_OPS,
|
||||
},
|
||||
|
|
|
@ -135,7 +135,7 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec)
|
|||
#ifdef CONFIG_SND_HDA_INPUT_JACK
|
||||
/* free jack instances manually when clearing/reconfiguring */
|
||||
if (!codec->bus->shutdown && jack->jack)
|
||||
snd_device_free(codec->bus->card, jack->jack);
|
||||
snd_device_free(codec->card, jack->jack);
|
||||
#endif
|
||||
for (cb = jack->callback; cb; cb = next) {
|
||||
next = cb->next;
|
||||
|
@ -340,7 +340,7 @@ void snd_hda_jack_report_sync(struct hda_codec *codec)
|
|||
if (!jack->kctl || jack->block_report)
|
||||
continue;
|
||||
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
|
||||
if (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,
|
|||
jack->phantom_jack = !!phantom_jack;
|
||||
|
||||
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
|
||||
if (!phantom_jack) {
|
||||
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);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
|
@ -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) \
|
||||
__snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL)
|
||||
int snd_hda_codec_reset(struct hda_codec *codec);
|
||||
void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec);
|
||||
|
||||
enum {
|
||||
HDA_VMUTE_OFF,
|
||||
|
|
|
@ -99,10 +99,10 @@ static void print_nid_array(struct snd_info_buffer *buffer,
|
|||
static void print_nid_pcms(struct snd_info_buffer *buffer,
|
||||
struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
int pcm, type;
|
||||
int type;
|
||||
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++) {
|
||||
if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
|
||||
continue;
|
||||
|
@ -861,7 +861,7 @@ int snd_hda_codec_proc_new(struct hda_codec *codec)
|
|||
int err;
|
||||
|
||||
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)
|
||||
return err;
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ static int reconfig_codec(struct hda_codec *codec)
|
|||
err = snd_hda_codec_build_controls(codec);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
err = snd_card_register(codec->bus->card);
|
||||
err = snd_card_register(codec->card);
|
||||
error:
|
||||
snd_hda_power_down(codec);
|
||||
return err;
|
||||
|
|
|
@ -290,8 +290,6 @@ static int hda_tegra_dev_free(struct snd_device *device)
|
|||
int i;
|
||||
struct azx *chip = device->device_data;
|
||||
|
||||
azx_notifier_unregister(chip);
|
||||
|
||||
if (chip->initialized) {
|
||||
for (i = 0; i < chip->num_streams; i++)
|
||||
azx_stream_stop(chip, &chip->azx_dev[i]);
|
||||
|
@ -497,22 +495,11 @@ static int hda_tegra_probe(struct platform_device *pdev)
|
|||
if (err < 0)
|
||||
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);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
|
||||
chip->running = 1;
|
||||
azx_notifier_register(chip);
|
||||
snd_hda_set_power_save(chip->bus, power_save * 1000);
|
||||
|
||||
return 0;
|
||||
|
@ -527,6 +514,18 @@ static int hda_tegra_remove(struct platform_device *pdev)
|
|||
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 = {
|
||||
.driver = {
|
||||
.name = "tegra-hda",
|
||||
|
@ -535,6 +534,7 @@ static struct platform_driver tegra_platform_hda = {
|
|||
},
|
||||
.probe = hda_tegra_probe,
|
||||
.remove = hda_tegra_remove,
|
||||
.shutdown = hda_tegra_shutdown,
|
||||
};
|
||||
module_platform_driver(tegra_platform_hda);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ DECLARE_EVENT_CLASS(hda_cmd,
|
|||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->card = (codec)->bus->card->number;
|
||||
__entry->card = (codec)->card->number;
|
||||
__entry->addr = (codec)->addr;
|
||||
__entry->val = (val);
|
||||
),
|
||||
|
@ -71,7 +71,7 @@ DECLARE_EVENT_CLASS(hda_power,
|
|||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->card = (codec)->bus->card->number;
|
||||
__entry->card = (codec)->card->number;
|
||||
__entry->addr = (codec)->addr;
|
||||
),
|
||||
|
||||
|
|
|
@ -719,7 +719,6 @@ struct ca0132_spec {
|
|||
unsigned int num_inputs;
|
||||
hda_nid_t shared_mic_nid;
|
||||
hda_nid_t shared_out_nid;
|
||||
struct hda_pcm pcm_rec[5]; /* PCM information */
|
||||
|
||||
/* chip access */
|
||||
struct mutex chipio_mutex; /* chip access mutex */
|
||||
|
@ -4036,12 +4035,11 @@ static struct hda_pcm_stream ca0132_pcm_digital_capture = {
|
|||
static int ca0132_build_pcms(struct hda_codec *codec)
|
||||
{
|
||||
struct ca0132_spec *spec = codec->spec;
|
||||
struct hda_pcm *info = spec->pcm_rec;
|
||||
struct hda_pcm *info;
|
||||
|
||||
codec->pcm_info = info;
|
||||
codec->num_pcms = 0;
|
||||
|
||||
info->name = "CA0132 Analog";
|
||||
info = snd_hda_codec_pcm_new(codec, "CA0132 Analog");
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
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].channels_max =
|
||||
|
@ -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].substreams = 1;
|
||||
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
|
||||
codec->num_pcms++;
|
||||
|
||||
info++;
|
||||
info->name = "CA0132 Analog Mic-In2";
|
||||
info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2");
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
|
||||
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
|
||||
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1];
|
||||
codec->num_pcms++;
|
||||
|
||||
info++;
|
||||
info->name = "CA0132 What U Hear";
|
||||
info = snd_hda_codec_pcm_new(codec, "CA0132 What U Hear");
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
|
||||
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
|
||||
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[2];
|
||||
codec->num_pcms++;
|
||||
|
||||
if (!spec->dig_out && !spec->dig_in)
|
||||
return 0;
|
||||
|
||||
info++;
|
||||
info->name = "CA0132 Digital";
|
||||
info = snd_hda_codec_pcm_new(codec, "CA0132 Digital");
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->pcm_type = HDA_PCM_TYPE_SPDIF;
|
||||
if (spec->dig_out) {
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
|
||||
|
@ -4081,7 +4079,6 @@ static int ca0132_build_pcms(struct hda_codec *codec)
|
|||
ca0132_pcm_digital_capture;
|
||||
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
|
||||
}
|
||||
codec->num_pcms++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4352,7 +4349,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
|
|||
const struct dsp_image_seg *dsp_os_image;
|
||||
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;
|
||||
|
||||
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)
|
|||
* state machine run.
|
||||
*/
|
||||
cancel_delayed_work_sync(&spec->unsol_hp_work);
|
||||
queue_delayed_work(codec->bus->workq, &spec->unsol_hp_work,
|
||||
msecs_to_jiffies(500));
|
||||
schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500));
|
||||
cb->tbl->block_report = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,6 @@ struct hdmi_spec_per_pin {
|
|||
bool non_pcm;
|
||||
bool chmap_set; /* channel-map override by ALSA API? */
|
||||
unsigned char chmap[8]; /* ALSA API channel-map */
|
||||
char pcm_name[8]; /* filled in build_pcm callbacks */
|
||||
#ifdef CONFIG_PROC_FS
|
||||
struct snd_info_entry *proc_entry;
|
||||
#endif
|
||||
|
@ -132,7 +131,7 @@ struct hdmi_spec {
|
|||
|
||||
int num_pins;
|
||||
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 */
|
||||
|
||||
struct hdmi_eld temp_eld;
|
||||
|
@ -355,8 +354,7 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
|
|||
((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
|
||||
#define get_cvt(spec, idx) \
|
||||
((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx))
|
||||
#define get_pcm_rec(spec, idx) \
|
||||
((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx))
|
||||
#define get_pcm_rec(spec, idx) ((spec)->pcm_rec[idx])
|
||||
|
||||
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)
|
|||
int err;
|
||||
|
||||
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)
|
||||
return err;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1578,9 +1576,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
|
|||
update_eld = true;
|
||||
}
|
||||
else if (repoll) {
|
||||
queue_delayed_work(codec->bus->workq,
|
||||
&per_pin->work,
|
||||
msecs_to_jiffies(300));
|
||||
schedule_delayed_work(&per_pin->work,
|
||||
msecs_to_jiffies(300));
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
@ -1624,7 +1621,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
|
|||
}
|
||||
|
||||
if (eld_changed)
|
||||
snd_ctl_notify(codec->bus->card,
|
||||
snd_ctl_notify(codec->card,
|
||||
SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
|
||||
&per_pin->eld_ctl->id);
|
||||
unlock:
|
||||
|
@ -2056,11 +2053,10 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
|
|||
struct hdmi_spec_per_pin *per_pin;
|
||||
|
||||
per_pin = get_pin(spec, pin_idx);
|
||||
sprintf(per_pin->pcm_name, "HDMI %d", pin_idx);
|
||||
info = snd_array_new(&spec->pcm_rec);
|
||||
info = snd_hda_codec_pcm_new(codec, "HDMI %d", pin_idx);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->name = per_pin->pcm_name;
|
||||
spec->pcm_rec[pin_idx] = info;
|
||||
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
||||
info->own_chmap = true;
|
||||
|
||||
|
@ -2070,9 +2066,6 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
|
|||
/* other pstr fields are set in open */
|
||||
}
|
||||
|
||||
codec->num_pcms = spec->num_pins;
|
||||
codec->pcm_info = spec->pcm_rec.list;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2125,13 +2118,15 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
|
|||
|
||||
/* add channel maps */
|
||||
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
||||
struct hda_pcm *pcm;
|
||||
struct snd_pcm_chmap *chmap;
|
||||
struct snd_kcontrol *kctl;
|
||||
int i;
|
||||
|
||||
if (!codec->pcm_info[pin_idx].pcm)
|
||||
pcm = spec->pcm_rec[pin_idx];
|
||||
if (!pcm || !pcm->pcm)
|
||||
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,
|
||||
NULL, 0, pin_idx, &chmap);
|
||||
if (err < 0)
|
||||
|
@ -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->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)
|
||||
{
|
||||
snd_array_free(&spec->pins);
|
||||
snd_array_free(&spec->cvts);
|
||||
snd_array_free(&spec->pcm_rec);
|
||||
}
|
||||
|
||||
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++) {
|
||||
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);
|
||||
}
|
||||
|
||||
flush_workqueue(codec->bus->workq);
|
||||
hdmi_array_free(spec);
|
||||
kfree(spec);
|
||||
}
|
||||
|
@ -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_channels(chans);
|
||||
|
||||
info = snd_array_new(&spec->pcm_rec);
|
||||
info = snd_hda_codec_pcm_new(codec, "HDMI 0");
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->name = get_pin(spec, 0)->pcm_name;
|
||||
sprintf(info->name, "HDMI 0");
|
||||
spec->pcm_rec[0] = info;
|
||||
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
||||
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
*pstr = spec->pcm_playback;
|
||||
|
@ -2393,9 +2384,6 @@ static int simple_playback_build_pcms(struct hda_codec *codec)
|
|||
if (pstr->channels_max <= 2 && chans && chans <= 16)
|
||||
pstr->channels_max = chans;
|
||||
|
||||
codec->num_pcms = 1;
|
||||
codec->pcm_info = info;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -5850,7 +5850,7 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec,
|
|||
{
|
||||
if (action == HDA_FIXUP_ACT_BUILD) {
|
||||
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 @@
|
|||
|
||||
struct si3054_spec {
|
||||
unsigned international;
|
||||
struct hda_pcm pcm;
|
||||
};
|
||||
|
||||
|
||||
|
@ -199,11 +198,11 @@ static const struct hda_pcm_stream si3054_pcm = {
|
|||
|
||||
static int si3054_build_pcms(struct hda_codec *codec)
|
||||
{
|
||||
struct si3054_spec *spec = codec->spec;
|
||||
struct hda_pcm *info = &spec->pcm;
|
||||
codec->num_pcms = 1;
|
||||
codec->pcm_info = info;
|
||||
info->name = "Si3054 Modem";
|
||||
struct hda_pcm *info;
|
||||
|
||||
info = snd_hda_codec_pcm_new(codec, "Si3054 Modem");
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
|
||||
info->stream[SNDRV_PCM_STREAM_CAPTURE] = si3054_pcm;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->mfg;
|
||||
|
|
|
@ -222,8 +222,7 @@ static void vt1708_update_hp_work(struct hda_codec *codec)
|
|||
if (!spec->hp_work_active) {
|
||||
codec->jackpoll_interval = msecs_to_jiffies(100);
|
||||
snd_hda_codec_write(codec, 0x1, 0, 0xf81, 0);
|
||||
queue_delayed_work(codec->bus->workq,
|
||||
&codec->jackpoll_work, 0);
|
||||
schedule_delayed_work(&codec->jackpoll_work, 0);
|
||||
spec->hp_work_active = true;
|
||||
}
|
||||
} else if (!hp_detect_with_aa(codec))
|
||||
|
@ -683,8 +682,10 @@ static int vt1708_build_pcms(struct hda_codec *codec)
|
|||
* 24bit samples are used. Until any workaround is found,
|
||||
* disable the 24bit format, so far.
|
||||
*/
|
||||
for (i = 0; i < codec->num_pcms; i++) {
|
||||
struct hda_pcm *info = &spec->gen.pcm_rec[i];
|
||||
for (i = 0; i < ARRAY_SIZE(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 ||
|
||||
info->pcm_type != HDA_PCM_TYPE_AUDIO)
|
||||
continue;
|
||||
|
@ -907,16 +908,16 @@ static int patch_vt1708S(struct hda_codec *codec)
|
|||
if (get_codec_type(codec) == VT1708BCE) {
|
||||
kfree(codec->chip_name);
|
||||
codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
|
||||
snprintf(codec->bus->card->mixername,
|
||||
sizeof(codec->bus->card->mixername),
|
||||
snprintf(codec->card->mixername,
|
||||
sizeof(codec->card->mixername),
|
||||
"%s %s", codec->vendor_name, codec->chip_name);
|
||||
}
|
||||
/* correct names for VT1705 */
|
||||
if (codec->vendor_id == 0x11064397) {
|
||||
kfree(codec->chip_name);
|
||||
codec->chip_name = kstrdup("VT1705", GFP_KERNEL);
|
||||
snprintf(codec->bus->card->mixername,
|
||||
sizeof(codec->bus->card->mixername),
|
||||
snprintf(codec->card->mixername,
|
||||
sizeof(codec->card->mixername),
|
||||
"%s %s", codec->vendor_name, codec->chip_name);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue