diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-06-06 12:26:02 +0100 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-06-06 12:26:02 +0100 |
commit | aa72f6899b9fb3dc824c458234ae3507a60e462d (patch) | |
tree | 97480a3cefc3d864ffd6eb994ec09ab5d680eabe /sound | |
parent | e6a9be0bb018466896632969ba4b496d1a7caea9 (diff) | |
parent | 05d3962cc921c51059df69488c7f70ab8b6a5d88 (diff) |
Merge branch 'for-3.0' into for-3.1
Diffstat (limited to 'sound')
93 files changed, 9620 insertions, 7854 deletions
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index 58804c7acfc..fd2188c3df2 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c @@ -170,7 +170,7 @@ static void tas_set_volume(struct tas *tas) /* analysing the volume and mixer tables shows * that they are similar enough when we shift * the mixer table down by 4 bits. The error - * is minuscule, in just one item the error + * is miniscule, in just one item the error * is 1, at a value of 0x07f17b (mixer table * value is 0x07f17a) */ tmp = tas_gaintable[left]; diff --git a/sound/core/control.c b/sound/core/control.c index a08ad57c49b..f8c5be46451 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -366,6 +366,70 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) EXPORT_SYMBOL(snd_ctl_add); /** + * snd_ctl_replace - replace the control instance of the card + * @card: the card instance + * @kcontrol: the control instance to replace + * @add_on_replace: add the control if not already added + * + * Replaces the given control. If the given control does not exist + * and the add_on_replace flag is set, the control is added. If the + * control exists, it is destroyed first. + * + * Returns zero if successful, or a negative error code on failure. + * + * It frees automatically the control which cannot be added or replaced. + */ +int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, + bool add_on_replace) +{ + struct snd_ctl_elem_id id; + unsigned int idx; + struct snd_kcontrol *old; + int ret; + + if (!kcontrol) + return -EINVAL; + if (snd_BUG_ON(!card || !kcontrol->info)) { + ret = -EINVAL; + goto error; + } + id = kcontrol->id; + down_write(&card->controls_rwsem); + old = snd_ctl_find_id(card, &id); + if (!old) { + if (add_on_replace) + goto add; + up_write(&card->controls_rwsem); + ret = -EINVAL; + goto error; + } + ret = snd_ctl_remove(card, old); + if (ret < 0) { + up_write(&card->controls_rwsem); + goto error; + } +add: + if (snd_ctl_find_hole(card, kcontrol->count) < 0) { + up_write(&card->controls_rwsem); + ret = -ENOMEM; + goto error; + } + list_add_tail(&kcontrol->list, &card->controls); + card->controls_count += kcontrol->count; + kcontrol->id.numid = card->last_numid + 1; + card->last_numid += kcontrol->count; + up_write(&card->controls_rwsem); + for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); + return 0; + +error: + snd_ctl_free_one(kcontrol); + return ret; +} +EXPORT_SYMBOL(snd_ctl_replace); + +/** * snd_ctl_remove - remove the control from the card and release it * @card: the card instance * @kcontrol: the control instance to remove @@ -640,13 +704,12 @@ static int snd_ctl_elem_list(struct snd_card *card, struct snd_ctl_elem_list list; struct snd_kcontrol *kctl; struct snd_ctl_elem_id *dst, *id; - unsigned int offset, space, first, jidx; + unsigned int offset, space, jidx; if (copy_from_user(&list, _list, sizeof(list))) return -EFAULT; offset = list.offset; space = list.space; - first = 0; /* try limit maximum space */ if (space > 16384) return -ENOMEM; diff --git a/sound/core/init.c b/sound/core/init.c index a0080aa45ae..2c041bb36ab 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -342,7 +342,6 @@ static const struct file_operations snd_shutdown_f_ops = int snd_card_disconnect(struct snd_card *card) { struct snd_monitor_file *mfile; - struct file *file; int err; if (!card) @@ -366,8 +365,6 @@ int snd_card_disconnect(struct snd_card *card) spin_lock(&card->files_lock); list_for_each_entry(mfile, &card->files_list, list) { - file = mfile->file; - /* it's critical part, use endless loop */ /* we have no room to fail */ mfile->disconnected_f_op = mfile->file->f_op; @@ -514,7 +511,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid) id = card->id; if (*id == '\0') - strcpy(id, "default"); + strcpy(id, "Default"); while (1) { if (loops-- == 0) { diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c index 13b3f6f49fa..2045697f449 100644 --- a/sound/core/oss/linear.c +++ b/sound/core/oss/linear.c @@ -90,11 +90,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin, struct snd_pcm_plugin_channel *dst_channels, snd_pcm_uframes_t frames) { - struct linear_priv *data; - if (snd_BUG_ON(!plugin || !src_channels || !dst_channels)) return -ENXIO; - data = (struct linear_priv *)plugin->extra_data; if (frames == 0) return 0; #ifdef CONFIG_SND_DEBUG diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 64449cb8f87..f1341308bed 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -189,6 +189,7 @@ static void xrun(struct snd_pcm_substream *substream) #define XRUN_LOG_CNT 10 struct hwptr_log_entry { + unsigned int in_interrupt; unsigned long jiffies; snd_pcm_uframes_t pos; snd_pcm_uframes_t period_size; @@ -204,7 +205,7 @@ struct snd_pcm_hwptr_log { }; static void xrun_log(struct snd_pcm_substream *substream, - snd_pcm_uframes_t pos) + snd_pcm_uframes_t pos, int in_interrupt) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hwptr_log *log = runtime->hwptr_log; @@ -220,6 +221,7 @@ static void xrun_log(struct snd_pcm_substream *substream, return; } entry = &log->entries[log->idx]; + entry->in_interrupt = in_interrupt; entry->jiffies = jiffies; entry->pos = pos; entry->period_size = runtime->period_size; @@ -246,9 +248,11 @@ static void xrun_log_show(struct snd_pcm_substream *substream) entry = &log->entries[idx]; if (entry->period_size == 0) break; - snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, " + snd_printd("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, " "hwptr=%ld/%ld\n", - name, entry->jiffies, (unsigned long)entry->pos, + name, entry->in_interrupt ? "[Q] " : "", + entry->jiffies, + (unsigned long)entry->pos, (unsigned long)entry->period_size, (unsigned long)entry->buffer_size, (unsigned long)entry->old_hw_ptr, @@ -262,7 +266,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream) #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ #define hw_ptr_error(substream, fmt, args...) do { } while (0) -#define xrun_log(substream, pos) do { } while (0) +#define xrun_log(substream, pos, in_interrupt) do { } while (0) #define xrun_log_show(substream) do { } while (0) #endif @@ -326,7 +330,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, } pos -= pos % runtime->min_align; if (xrun_debug(substream, XRUN_DEBUG_LOG)) - xrun_log(substream, pos); + xrun_log(substream, pos, in_interrupt); hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; if (in_interrupt) { @@ -1752,8 +1756,18 @@ static int wait_for_avail(struct snd_pcm_substream *substream, wait_queue_t wait; int err = 0; snd_pcm_uframes_t avail = 0; - long tout; - + long wait_time, tout; + + if (runtime->no_period_wakeup) + wait_time = MAX_SCHEDULE_TIMEOUT; + else { + wait_time = 10; + if (runtime->rate) { + long t = runtime->period_size * 2 / runtime->rate; + wait_time = max(t, wait_time); + } + wait_time = msecs_to_jiffies(wait_time * 1000); + } init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->tsleep, &wait); for (;;) { @@ -1761,9 +1775,8 @@ static int wait_for_avail(struct snd_pcm_substream *substream, err = -ERESTARTSYS; break; } - set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); - tout = schedule_timeout(msecs_to_jiffies(10000)); + tout = schedule_timeout_interruptible(wait_time); snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_SUSPENDED: diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 1a07750f383..1c6be91dfb9 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1481,11 +1481,20 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, break; /* all drained */ init_waitqueue_entry(&wait, current); add_wait_queue(&to_check->sleep, &wait); - set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); up_read(&snd_pcm_link_rwsem); snd_power_unlock(card); - tout = schedule_timeout(10 * HZ); + if (runtime->no_period_wakeup) + tout = MAX_SCHEDULE_TIMEOUT; + else { + tout = 10; + if (runtime->rate) { + long t = runtime->period_size * 2 / runtime->rate; + tout = max(t, tout); + } + tout = msecs_to_jiffies(tout * 1000); + } + tout = schedule_timeout_interruptible(tout); snd_power_lock(card); down_read(&snd_pcm_link_rwsem); snd_pcm_stream_lock_irq(substream); @@ -1518,13 +1527,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, static int snd_pcm_drop(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime; - struct snd_card *card; int result = 0; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - card = substream->pcm->card; if (runtime->status->state == SNDRV_PCM_STATE_OPEN || runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED || @@ -2056,7 +2063,6 @@ static int snd_pcm_open_file(struct file *file, { struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream; - struct snd_pcm_str *str; int err; if (rpcm_file) @@ -2073,7 +2079,6 @@ static int snd_pcm_open_file(struct file *file, } pcm_file->substream = substream; if (substream->ref_count == 1) { - str = substream->pstr; substream->file = pcm_file; substream->pcm_release = pcm_release_private; } @@ -3015,11 +3020,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_status = static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area) { - struct snd_pcm_runtime *runtime; long size; if (!(area->vm_flags & VM_READ)) return -EINVAL; - runtime = substream->runtime; size = area->vm_end - area->vm_start; if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status))) return -EINVAL; @@ -3054,11 +3057,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_control = static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area) { - struct snd_pcm_runtime *runtime; long size; if (!(area->vm_flags & VM_READ)) return -EINVAL; - runtime = substream->runtime; size = area->vm_end - area->vm_start; if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))) return -EINVAL; diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index e7a8e9e4edb..f9077361c11 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -467,13 +467,11 @@ int snd_seq_queue_timer_open(int queueid) int snd_seq_queue_timer_close(int queueid) { struct snd_seq_queue *queue; - struct snd_seq_timer *tmr; int result = 0; queue = queueptr(queueid); if (queue == NULL) return -EINVAL; - tmr = queue->timer; snd_seq_timer_close(queue); queuefree(queue); return result; diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index e486f48660f..26071489970 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -22,4 +22,15 @@ config SND_FIREWIRE_SPEAKERS To compile this driver as a module, choose M here: the module will be called snd-firewire-speakers. +config SND_ISIGHT + tristate "Apple iSight microphone" + select SND_PCM + select SND_FIREWIRE_LIB + help + Say Y here to include support for the front and rear microphones + of the Apple iSight web camera. + + To compile this driver as a module, choose M here: the module + will be called snd-isight. + endif # SND_FIREWIRE diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index e5b1634d9ad..d71ed8935f7 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -1,6 +1,8 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ fcp.o cmp.o amdtp.o snd-firewire-speakers-objs := speakers.o +snd-isight-objs := isight.o obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o +obj-$(CONFIG_SND_ISIGHT) += snd-isight.o diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index b18140ff2b9..87657dd7714 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -396,6 +396,7 @@ static void out_packet_callback(struct fw_iso_context *context, u32 cycle, for (i = 0; i < packets; ++i) queue_out_packet(s, ++cycle); + fw_iso_context_queue_flush(s->context); } static int queue_initial_skip_packets(struct amdtp_out_stream *s) diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c index 4a37f3a6fab..14cacbc655d 100644 --- a/sound/firewire/cmp.c +++ b/sound/firewire/cmp.c @@ -49,10 +49,9 @@ static int pcr_modify(struct cmp_connection *c, enum bus_reset_handling bus_reset_handling) { struct fw_device *device = fw_parent_device(c->resources.unit); - __be32 *buffer = c->resources.buffer; int generation = c->resources.generation; int rcode, errors = 0; - __be32 old_arg; + __be32 old_arg, buffer[2]; int err; buffer[0] = c->last_pcr_value; diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c new file mode 100644 index 00000000000..86ee16ca365 --- /dev/null +++ b/sound/firewire/isight.c @@ -0,0 +1,755 @@ +/* + * Apple iSight audio driver + * + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include <asm/byteorder.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/firewire.h> +#include <linux/firewire-constants.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/mutex.h> +#include <linux/string.h> +#include <sound/control.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/tlv.h> +#include "lib.h" +#include "iso-resources.h" +#include "packets-buffer.h" + +#define OUI_APPLE 0x000a27 +#define MODEL_APPLE_ISIGHT 0x000008 +#define SW_ISIGHT_AUDIO 0x000010 + +#define REG_AUDIO_ENABLE 0x000 +#define AUDIO_ENABLE 0x80000000 +#define REG_DEF_AUDIO_GAIN 0x204 +#define REG_GAIN_RAW_START 0x210 +#define REG_GAIN_RAW_END 0x214 +#define REG_GAIN_DB_START 0x218 +#define REG_GAIN_DB_END 0x21c +#define REG_SAMPLE_RATE_INQUIRY 0x280 +#define REG_ISO_TX_CONFIG 0x300 +#define SPEED_SHIFT 16 +#define REG_SAMPLE_RATE 0x400 +#define RATE_48000 0x80000000 +#define REG_GAIN 0x500 +#define REG_MUTE 0x504 + +#define MAX_FRAMES_PER_PACKET 475 + +#define QUEUE_LENGTH 20 + +struct isight { + struct snd_card *card; + struct fw_unit *unit; + struct fw_device *device; + u64 audio_base; + struct fw_address_handler iris_handler; + struct snd_pcm_substream *pcm; + struct mutex mutex; + struct iso_packets_buffer buffer; + struct fw_iso_resources resources; + struct fw_iso_context *context; + bool pcm_active; + bool pcm_running; + bool first_packet; + int packet_index; + u32 total_samples; + unsigned int buffer_pointer; + unsigned int period_counter; + s32 gain_min, gain_max; + unsigned int gain_tlv[4]; +}; + +struct audio_payload { + __be32 sample_count; + __be32 signature; + __be32 sample_total; + __be32 reserved; + __be16 samples[2 * MAX_FRAMES_PER_PACKET]; +}; + +MODULE_DESCRIPTION("iSight audio driver"); +MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); +MODULE_LICENSE("GPL v2"); + +static struct fw_iso_packet audio_packet = { + .payload_length = sizeof(struct audio_payload), + .interrupt = 1, + .header_length = 4, +}; + +static void isight_update_pointers(struct isight *isight, unsigned int count) +{ + struct snd_pcm_runtime *runtime = isight->pcm->runtime; + unsigned int ptr; + + smp_wmb(); /* update buffer data before buffer pointer */ + + ptr = isight->buffer_pointer; + ptr += count; + if (ptr >= runtime->buffer_size) + ptr -= runtime->buffer_size; + ACCESS_ONCE(isight->buffer_pointer) = ptr; + + isight->period_counter += count; + if (isight->period_counter >= runtime->period_size) { + isight->period_counter -= runtime->period_size; + snd_pcm_period_elapsed(isight->pcm); + } +} + +static void isight_samples(struct isight *isight, + const __be16 *samples, unsigned int count) +{ + struct snd_pcm_runtime *runtime; + unsigned int count1; + + if (!ACCESS_ONCE(isight->pcm_running)) + return; + + runtime = isight->pcm->runtime; + if (isight->buffer_pointer + count <= runtime->buffer_size) { + memcpy(runtime->dma_area + isight->buffer_pointer * 4, + samples, count * 4); + } else { + count1 = runtime->buffer_size - isight->buffer_pointer; + memcpy(runtime->dma_area + isight->buffer_pointer * 4, + samples, count1 * 4); + samples += count1 * 2; + memcpy(runtime->dma_area, samples, (count - count1) * 4); + } + + isight_update_pointers(isight, count); +} + +static void isight_pcm_abort(struct isight *isight) +{ + unsigned long flags; + + if (ACCESS_ONCE(isight->pcm_active)) { + snd_pcm_stream_lock_irqsave(isight->pcm, flags); + if (snd_pcm_running(isight->pcm)) + snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock_irqrestore(isight->pcm, flags); + } +} + +static void isight_dropped_samples(struct isight *isight, unsigned int total) +{ + struct snd_pcm_runtime *runtime; + u32 dropped; + unsigned int count1; + + if (!ACCESS_ONCE(isight->pcm_running)) + return; + + runtime = isight->pcm->runtime; + dropped = total - isight->total_samples; + if (dropped < runtime->buffer_size) { + if (isight->buffer_pointer + dropped <= runtime->buffer_size) { + memset(runtime->dma_area + isight->buffer_pointer * 4, + 0, dropped * 4); + } else { + count1 = runtime->buffer_size - isight->buffer_pointer; + memset(runtime->dma_area + isight->buffer_pointer * 4, + 0, count1 * 4); + memset(runtime->dma_area, 0, (dropped - count1) * 4); + } + isight_update_pointers(isight, dropped); + } else { + isight_pcm_abort(isight); + } +} + +static void isight_packet(struct fw_iso_context *context, u32 cycle, + size_t header_length, void *header, void *data) +{ + struct isight *isight = data; + const struct audio_payload *payload; + unsigned int index, length, count, total; + int err; + + if (isight->packet_index < 0) + return; + index = isight->packet_index; + payload = isight->buffer.packets[index].buffer; + length = be32_to_cpup(header) >> 16; + + if (likely(length >= 16 && + payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) { + count = be32_to_cpu(payload->sample_count); + if (likely(count <= (length - 16) / 4)) { + total = be32_to_cpu(payload->sample_total); + if (unlikely(total != isight->total_samples)) { + if (!isight->first_packet) + isight_dropped_samples(isight, total); + isight->first_packet = false; + isight->total_samples = total; + } + + isight_samples(isight, payload->samples, count); + isight->total_samples += count; + } + } + + err = fw_iso_context_queue(isight->context, &audio_packet, + &isight->buffer.iso_buffer, + isight->buffer.packets[index].offset); + if (err < 0) { + dev_err(&isight->unit->device, "queueing error: %d\n", err); + isight_pcm_abort(isight); + isight->packet_index = -1; + return; + } + + if (++index >= QUEUE_LENGTH) + index = 0; + isight->packet_index = index; +} + +static int isight_connect(struct isight *isight) +{ + int ch, err, rcode, errors = 0; + __be32 value; + +retry_after_bus_reset: + ch = fw_iso_resources_allocate(&isight->resources, + sizeof(struct audio_payload), + isight->device->max_speed); + if (ch < 0) { + err = ch; + goto error; + } + + value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT)); + for (;;) { + rcode = fw_run_transaction( + isight->device->card, + TCODE_WRITE_QUADLET_REQUEST, + isight->device->node_id, + isight->resources.generation, + isight->device->max_speed, + isight->audio_base + REG_ISO_TX_CONFIG, + &value, 4); + if (rcode == RCODE_COMPLETE) { + return 0; + } else if (rcode == RCODE_GENERATION) { + fw_iso_resources_free(&isight->resources); + goto retry_after_bus_reset; + } else if (rcode_is_permanent_error(rcode) || ++errors >= 3) { + err = -EIO; + goto err_resources; + } + msleep(5); + } + +err_resources: + fw_iso_resources_free(&isight->resources); +error: + return err; +} + +static int isight_open(struct snd_pcm_substream *substream) +{ + static const struct snd_pcm_hardware hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_BE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 4 * 1024 * 1024, + .period_bytes_min = MAX_FRAMES_PER_PACKET * 4, + .period_bytes_max = 1024 * 1024, + .periods_min = 2, + .periods_max = UINT_MAX, + }; + struct isight *isight = substream->private_data; + + substream->runtime->hw = hardware; + + return iso_packets_buffer_init(&isight->buffer, isight->unit, + QUEUE_LENGTH, + sizeof(struct audio_payload), + DMA_FROM_DEVICE); +} + +static int isight_close(struct snd_pcm_substream *substream) +{ + struct isight *isight = substream->private_data; + + iso_packets_buffer_destroy(&isight->buffer, isight->unit); + + return 0; +} + +static int isight_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct isight *isight = substream->private_data; + int err; + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; + + ACCESS_ONCE(isight->pcm_active) = true; + + return 0; +} + +static int reg_read(struct isight *isight, int offset, __be32 *value) +{ + return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST, + isight->audio_base + offset, value, 4); +} + +static int reg_write(struct isight *isight, int offset, __be32 value) +{ + return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST, + isight->audio_base + offset, &value, 4); +} + +static void isight_stop_streaming(struct isight *isight) +{ + if (!isight->context) + return; + + fw_iso_context_stop(isight->context); + fw_iso_context_destroy(isight->context); + isight->context = NULL; + fw_iso_resources_free(&isight->resources); + reg_write(isight, REG_AUDIO_ENABLE, 0); +} + +static int isight_hw_free(struct snd_pcm_substream *substream) +{ + struct isight *isight = substream->private_data; + + ACCESS_ONCE(isight->pcm_active) = false; + + mutex_lock(&isight->mutex); + isight_stop_streaming(isight); + mutex_unlock(&isight->mutex); + + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static int isight_start_streaming(struct isight *isight) +{ + unsigned int i; + int err; + + if (isight->context) { + if (isight->packet_index < 0) + isight_stop_streaming(isight); + else + return 0; + } + + err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000)); + if (err < 0) + goto error; + + err = isight_connect(isight); + if (err < 0) + goto error; + + err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE)); + if (err < 0) + goto err_resources; + + isight->context = fw_iso_context_create(isight->device->card, + FW_ISO_CONTEXT_RECEIVE, + isight->resources.channel, + isight->device->max_speed, + 4, isight_packet, isight); + if (IS_ERR(isight->context)) { + err = PTR_ERR(isight->context); + isight->context = NULL; + goto err_resources; + } + + for (i = 0; i < QUEUE_LENGTH; ++i) { + err = fw_iso_context_queue(isight->context, &audio_packet, + &isight->buffer.iso_buffer, + isight->buffer.packets[i].offset); + if (err < 0) + goto err_context; + } + + isight->first_packet = true; + isight->packet_index = 0; + + err = fw_iso_context_start(isight->context, -1, 0, + FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/); + if (err < 0) + goto err_context; + + return 0; + +err_context: + fw_iso_context_destroy(isight->context); + isight->context = NULL; +err_resources: + fw_iso_resources_free(&isight->resources); + reg_write(isight, REG_AUDIO_ENABLE, 0); +error: + return err; +} + +static int isight_prepare(struct snd_pcm_substream *substream) +{ + struct isight *isight = substream->private_data; + int err; + + isight->buffer_pointer = 0; + isight->period_counter = 0; + + mutex_lock(&isight->mutex); + err = isight_start_streaming(isight); + mutex_unlock(&isight->mutex); + + return err; +} + +static int isight_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct isight *isight = substream->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + ACCESS_ONCE(isight->pcm_running) = true; + break; + case SNDRV_PCM_TRIGGER_STOP: + ACCESS_ONCE(isight->pcm_running) = false; + break; + default: + return -EINVAL; + } + return 0; +} + +static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream) +{ + struct isight *isight = substream->private_data; + + return ACCESS_ONCE(isight->buffer_pointer); +} + +static int isight_create_pcm(struct isight *isight) +{ + static struct snd_pcm_ops ops = { + .open = isight_open, + .close = isight_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = isight_hw_params, + .hw_free = isight_hw_free, + .prepare = isight_prepare, + .trigger = isight_trigger, + .pointer = isight_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm); + if (err < 0) + return err; + pcm->private_data = isight; + strcpy(pcm->name, "iSight"); + isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + isight->pcm->ops = &ops; + + return 0; +} + +static int isight_gain_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + struct isight *isight = ctl->private_data; + + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 1; + info->value.integer.min = isight->gain_min; + info->value.integer.max = isight->gain_max; + + return 0; +} + +static int isight_gain_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct isight *isight = ctl->private_data; + __be32 gain; + int err; + + err = reg_read(isight, REG_GAIN, &gain); + if (err < 0) + return err; + + value->value.integer.value[0] = (s32)be32_to_cpu(gain); + + return 0; +} + +static int isight_gain_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct isight *isight = ctl->private_data; + + if (value->value.integer.value[0] < isight->gain_min || + value->value.integer.value[0] > isight->gain_max) + return -EINVAL; + + return reg_write(isight, REG_GAIN, + cpu_to_be32(value->value.integer.value[0])); +} + +static int isight_mute_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct isight *isight = ctl->private_data; + __be32 mute; + int err; + + err = reg_read(isight, REG_MUTE, &mute); + if (err < 0) + return err; + + value->value.integer.value[0] = !mute; + + return 0; +} + +static int isight_mute_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct isight *isight = ctl->private_data; + + return reg_write(isight, REG_MUTE, + (__force __be32)!value->value.integer.value[0]); +} + +static int isight_create_mixer(struct isight *isight) +{ + static const struct snd_kcontrol_new gain_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Capture Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = isight_gain_info, + .get = isight_gain_get, + .put = isight_gain_put, + }; + static const struct snd_kcontrol_new mute_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Capture Switch", + .info = snd_ctl_boolean_mono_info, + .get = isight_mute_get, + .put = isight_mute_put, + }; + __be32 value; + struct snd_kcontrol *ctl; + int err; + + err = reg_read(isight, REG_GAIN_RAW_START, &value); + if (err < 0) + return err; + isight->gain_min = be32_to_cpu(value); + + err = reg_read(isight, REG_GAIN_RAW_END, &value); + if (err < 0) + return err; + isight->gain_max = be32_to_cpu(value); + + isight->gain_tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX; + isight->gain_tlv[1] = 2 * sizeof(unsigned int); + + err = reg_read(isight, REG_GAIN_DB_START, &value); + if (err < 0) + return err; + isight->gain_tlv[2] = (s32)be32_to_cpu(value) * 100; + + err = reg_read(isight, REG_GAIN_DB_END, &value); + if (err < 0) + return err; + isight->gain_tlv[3] = (s32)be32_to_cpu(value) * 100; + + ctl = snd_ctl_new1(&gain_control, isight); + if (ctl) + ctl->tlv.p = isight->gain_tlv; + err = snd_ctl_add(isight->card, ctl); + if (err < 0) + return err; + + err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight)); + if (err < 0) + return err; + + return 0; +} + +static void isight_card_free(struct snd_card *card) +{ + struct isight *isight = card->private_data; + + fw_iso_resources_destroy(&isight->resources); + fw_unit_put(isight->unit); + fw_device_put(isight->device); + mutex_destroy(&isight->mutex); +} + +static u64 get_unit_base(struct fw_unit *unit) +{ + struct fw_csr_iterator i; + int key, value; + + fw_csr_iterator_init(&i, unit->directory); + while (fw_csr_iterator_next(&i, &key, &value)) + if (key == CSR_OFFSET) + return CSR_REGISTER_BASE + value * 4; + return 0; +} + +static int isight_probe(struct device *unit_dev) +{ + struct fw_unit *unit = fw_unit(unit_dev); + struct fw_device *fw_dev = fw_parent_device(unit); + struct snd_card *card; + struct isight *isight; + int err; + + err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card); + if (err < 0) + return err; + snd_card_set_dev(card, unit_dev); + + isight = card->private_data; + isight->card = card; + mutex_init(&isight->mutex); + isight->unit = fw_unit_get(unit); + isight->device = fw_device_get(fw_dev); + isight->audio_base = get_unit_base(unit); + if (!isight->audio_base) { + dev_err(&unit->device, "audio unit base not found\n"); + err = -ENXIO; + goto err_unit; + } + fw_iso_resources_init(&isight->resources, unit); + + card->private_free = isight_card_free; + + strcpy(card->driver, "iSight"); + strcpy(card->shortname, "Apple iSight"); + snprintf(card->longname, sizeof(card->longname), + "Apple iSight (GUID %08x%08x) at %s, S%d", + fw_dev->config_rom[3], fw_dev->config_rom[4], + dev_name(&unit->device), 100 << fw_dev->max_speed); + strcpy(card->mixername, "iSight"); + + err = isight_create_pcm(isight); + if (err < 0) + goto error; + + err = isight_create_mixer(isight); + if (err < 0) + goto error; + + err = snd_card_register(card); + if (err < 0) + goto error; + + dev_set_drvdata(unit_dev, isight); + + return 0; + +err_unit: + fw_unit_put(isight->unit); + fw_device_put(isight->device); + mutex_destroy(&isight->mutex); +error: + snd_card_free(card); + return err; +} + +static int isight_remove(struct device *dev) +{ + struct isight *isight = dev_get_drvdata(dev); + + isight_pcm_abort(isight); + + snd_card_disconnect(isight->card); + + mutex_lock(&isight->mutex); + isight_stop_streaming(isight); + mutex_unlock(&isight->mutex); + + snd_card_free_when_closed(isight->card); + + return 0; +} + +static void isight_bus_reset(struct fw_unit *unit) +{ + struct isight *isight = dev_get_drvdata(&unit->device); + + if (fw_iso_resources_update(&isight->resources) < 0) { + isight_pcm_abort(isight); + + mutex_lock(&isight->mutex); + isight_stop_streaming(isight); + mutex_unlock(&isight->mutex); + } +} + +static const struct ieee1394_device_id isight_id_table[] = { + { + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + .specifier_id = OUI_APPLE, + .version = SW_ISIGHT_AUDIO, + }, + { } +}; +MODULE_DEVICE_TABLE(ieee1394, isight_id_table); + +static struct fw_driver isight_driver = { + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .bus = &fw_bus_type, + .probe = isight_probe, + .remove = isight_remove, + }, + .update = isight_bus_reset, + .id_table = isight_id_table, +}; + +static int __init alsa_isight_init(void) +{ + return driver_register(&isight_driver.driver); +} + +static void __exit alsa_isight_exit(void) +{ + driver_unregister(&isight_driver.driver); +} + +module_init(alsa_isight_init); +module_exit(alsa_isight_exit); diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c index 775dbd5f344..ffe20b877e9 100644 --- a/sound/firewire/iso-resources.c +++ b/sound/firewire/iso-resources.c @@ -11,7 +11,6 @@ #include <linux/jiffies.h> #include <linux/mutex.h> #include <linux/sched.h> -#include <linux/slab.h> #include <linux/spinlock.h> #include "iso-resources.h" @@ -25,10 +24,6 @@ */ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) { - r->buffer = kmalloc(2 * 4, GFP_KERNEL); - if (!r->buffer) - return -ENOMEM; - r->channels_mask = ~0uLL; r->unit = fw_unit_get(unit); mutex_init(&r->mutex); @@ -36,6 +31,7 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) return 0; } +EXPORT_SYMBOL(fw_iso_resources_init); /** * fw_iso_resources_destroy - destroy a resource manager @@ -44,10 +40,10 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) void fw_iso_resources_destroy(struct fw_iso_resources *r) { WARN_ON(r->allocated); - kfree(r->buffer); mutex_destroy(&r->mutex); fw_unit_put(r->unit); } +EXPORT_SYMBOL(fw_iso_resources_destroy); static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed) { @@ -131,7 +127,7 @@ retry_after_bus_reset: bandwidth = r->bandwidth + r->bandwidth_overhead; fw_iso_resource_manage(card, r->generation, r->channels_mask, - &channel, &bandwidth, true, r->buffer); + &channel, &bandwidth, true); if (channel == -EAGAIN) { mutex_unlock(&r->mutex); goto retry_after_bus_reset; @@ -152,6 +148,7 @@ retry_after_bus_reset: return channel; } +EXPORT_SYMBOL(fw_iso_resources_allocate); /** * fw_iso_resources_update - update resource allocations after a bus reset @@ -184,7 +181,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r) bandwidth = r->bandwidth + r->bandwidth_overhead; fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, - &channel, &bandwidth, true, r->buffer); + &channel, &bandwidth, true); /* * When another bus reset happens, pretend that the allocation * succeeded; we will try again for the new generation later. @@ -203,6 +200,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r) return channel; } +EXPORT_SYMBOL(fw_iso_resources_update); /** * fw_iso_resources_free - frees allocated resources @@ -220,7 +218,7 @@ void fw_iso_resources_free(struct fw_iso_resources *r) if (r->allocated) { bandwidth = r->bandwidth + r->bandwidth_overhead; fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, - &channel, &bandwidth, false, r->buffer); + &channel, &bandwidth, false); if (channel < 0) dev_err(&r->unit->device, "isochronous resource deallocation failed\n"); @@ -230,3 +228,4 @@ void fw_iso_resources_free(struct fw_iso_resources *r) mutex_unlock(&r->mutex); } +EXPORT_SYMBOL(fw_iso_resources_free); diff --git a/sound/firewire/iso-resources.h b/sound/firewire/iso-resources.h index 3f0730e4d84..5a9af7c6165 100644 --- a/sound/firewire/iso-resources.h +++ b/sound/firewire/iso-resources.h @@ -24,7 +24,6 @@ struct fw_iso_resources { unsigned int bandwidth_overhead; int generation; /* in which allocation is valid */ bool allocated; - __be32 *buffer; }; int fw_iso_resources_init(struct fw_iso_resources *r, diff --git a/sound/firewire/packets-buffer.c b/sound/firewire/packets-buffer.c index 1e20e60ba6a..3c61ca2e615 100644 --- a/sound/firewire/packets-buffer.c +++ b/sound/firewire/packets-buffer.c @@ -60,6 +60,7 @@ err_packets: error: return err; } +EXPORT_SYMBOL(iso_packets_buffer_init); /** * iso_packets_buffer_destroy - frees packet buffer resources @@ -72,3 +73,4 @@ void iso_packets_buffer_destroy(struct iso_packets_buffer *b, fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card); kfree(b->packets); } +EXPORT_SYMBOL(iso_packets_buffer_destroy); diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile index 2dad40f3f62..c95d8f1aae8 100644 --- a/sound/i2c/other/Makefile +++ b/sound/i2c/other/Makefile @@ -14,4 +14,4 @@ snd-tea575x-tuner-objs := tea575x-tuner.o obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o -obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o +obj-$(CONFIG_SND_TEA575X) += snd-tea575x-tuner.o diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index ee538f1ae84..4831800239d 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -37,8 +37,8 @@ static int radio_nr = -1; module_param(radio_nr, int, 0); #define RADIO_VERSION KERNEL_VERSION(0, 0, 2) -#define FREQ_LO (87 * 16000) -#define FREQ_HI (108 * 16000) +#define FREQ_LO (50UL * 16000) +#define FREQ_HI (150UL * 16000) /* * definitions @@ -77,27 +77,95 @@ static struct v4l2_queryctrl radio_qctrl[] = { * lowlevel part */ +static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val) +{ + u16 l; + u8 data; + + tea->ops->set_direction(tea, 1); + udelay(16); + + for (l = 25; l > 0; l--) { + data = (val >> 24) & TEA575X_DATA; + val <<= 1; /* shift data */ + tea->ops->set_pins(tea, data | TEA575X_WREN); + udelay(2); + tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK); + udelay(2); + tea->ops->set_pins(tea, data | TEA575X_WREN); + udelay(2); + } + + if (!tea->mute) + tea->ops->set_pins(tea, 0); +} + +static unsigned int snd_tea575x_read(struct snd_tea575x *tea) +{ + u16 l, rdata; + u32 data = 0; + + tea->ops->set_direction(tea, 0); + tea->ops->set_pins(tea, 0); + udelay(16); + + for (l = 24; l--;) { + tea->ops->set_pins(tea, TEA575X_CLK); + udelay(2); + if (!l) + tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1; + tea->ops->set_pins(tea, 0); + udelay(2); + data <<= 1; /* shift data */ + rdata = tea->ops->get_pins(tea); + if (!l) + tea->stereo = (rdata & TEA575X_MOST) ? 0 : 1; + if (rdata & TEA575X_DATA) + data++; + udelay(2); + } + + if (tea->mute) + tea->ops->set_pins(tea, TEA575X_WREN); + + return data; +} + +static void snd_tea575x_get_freq(struct snd_tea575x *tea) +{ + unsigned long freq; + + freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK; + /* freq *= 12.5 */ + freq *= 125; + freq /= 10; + /* crystal fixup */ + if (tea->tea5759) + freq += TEA575X_FMIF; + else + freq -= TEA575X_FMIF; + + tea->freq = freq * 16; /* from kHz */ +} + static void snd_tea575x_set_freq(struct snd_tea575x *tea) { unsigned long freq; - freq = tea->freq / 16; /* to kHz */ - if (freq > 108000) - freq = 108000; - if (freq < 87000) - freq = 87000; + freq = clamp(tea->freq, FREQ_LO, FREQ_HI); + freq /= 16; /* to kHz */ /* crystal fixup */ if (tea->tea5759) - freq -= tea->freq_fixup; + freq -= TEA575X_FMIF; else - freq += tea->freq_fixup; + freq += TEA575X_FMIF; /* freq /= 12.5 */ freq *= 10; freq /= 125; tea->val &= ~TEA575X_BIT_FREQ_MASK; tea->val |= freq & TEA575X_BIT_FREQ_MASK; - tea->ops->write(tea, tea->val); + snd_tea575x_write(tea, tea->val); } /* @@ -109,29 +177,34 @@ static int vidioc_querycap(struct file *file, void *priv, { struct snd_tea575x *tea = video_drvdata(file); - strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757"); strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver)); - strlcpy(v->card, "Maestro Radio", sizeof(v->card)); - sprintf(v->bus_info, "PCI"); + strlcpy(v->card, tea->card, sizeof(v->card)); + strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card)); + strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { + struct snd_tea575x *tea = video_drvdata(file); + if (v->index > 0) return -EINVAL; + snd_tea575x_read(tea); + strcpy(v->name, "FM"); v->type = V4L2_TUNER_RADIO; + v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; v->rangelow = FREQ_LO; v->rangehigh = FREQ_HI; - v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; + v->signal = tea->tuned ? 0xffff : 0; + return 0; } @@ -148,7 +221,10 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct snd_tea575x *tea = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; + snd_tea575x_get_freq(tea); f->frequency = tea->freq; return 0; } @@ -158,6 +234,9 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct snd_tea575x *tea = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) return -EINVAL; @@ -209,10 +288,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv, switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - if (tea->ops->mute) { - ctrl->value = tea->mute; - return 0; - } + ctrl->value = tea->mute; + return 0; } return -EINVAL; } @@ -224,11 +301,11 @@ static int vidioc_s_ctrl(struct file *file, void *priv, switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - if (tea->ops->mute) { - tea->ops->mute(tea, ctrl->value); + if (tea->mute != ctrl->value) { tea->mute = ctrl->value; - return 0; + snd_tea575x_set_freq(tea); } + return 0; } return -EINVAL; } @@ -293,18 +370,16 @@ static struct video_device tea575x_radio = { /* * initialize all the tea575x chips */ -void snd_tea575x_init(struct snd_tea575x *tea) +int snd_tea575x_init(struct snd_tea575x *tea) { int retval; - unsigned int val; struct video_device *tea575x_radio_inst; - val = tea->ops->read(tea); - if (val == 0x1ffffff || val == 0) { - snd_printk(KERN_ERR - "tea575x-tuner: Cannot find TEA575x chip\n"); - return; - } + tea->mute = 1; + + snd_tea575x_write(tea, 0x55AA); + if (snd_tea575x_read(tea) != 0x55AA) + return -ENODEV; tea->in_use = 0; tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; @@ -313,7 +388,7 @@ void snd_tea575x_init(struct snd_tea575x *tea) tea575x_radio_inst = video_device_alloc(); if (tea575x_radio_inst == NULL) { printk(KERN_ERR "tea575x-tuner: not enough memory\n"); - return; + return -ENOMEM; } memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio)); @@ -328,17 +403,13 @@ void snd_tea575x_init(struct snd_tea575x *tea) if (retval) { printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); kfree(tea575x_radio_inst); - return; + return retval; } snd_tea575x_set_freq(tea); - - /* mute on init */ - if (tea->ops->mute) { - tea->ops->mute(tea, 1); - tea->mute = 1; - } tea->vd = tea575x_radio_inst; + + return 0; } void snd_tea575x_exit(struct snd_tea575x *tea) diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index 76c09021807..6c93e051f9a 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -22,10 +22,6 @@ config SOUND_VWSND <file:Documentation/sound/oss/vwsnd> for more info on this driver's capabilities. -config SOUND_AU1550_AC97 - tristate "Au1550/Au1200 AC97 Sound" - depends on SOC_AU1550 || SOC_AU1200 - config SOUND_MSNDCLAS tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" depends on (m || !STANDALONE) && ISA diff --git a/sound/oss/Makefile b/sound/oss/Makefile index 90ffb99c6b1..77f21b68bf0 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -25,7 +25,6 @@ obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o obj-$(CONFIG_SOUND_VWSND) += vwsnd.o -obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o obj-$(CONFIG_DMASOUND) += dmasound/ diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c deleted file mode 100644 index 0cd23d94888..00000000000 --- a/sound/oss/ac97_codec.c +++ /dev/null @@ -1,1203 +0,0 @@ -/* - * ac97_codec.c: Generic AC97 mixer/modem module - * - * Derived from ac97 mixer in maestro and trident driver. - * - * Copyright 2000 Silicon Integrated System Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ************************************************************************** - * - * The Intel Audio Codec '97 specification is available at: - * http://download.intel.com/support/motherboards/desktop/sb/ac97_r23.pdf - * - ************************************************************************** - * - * History - * May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk> - * Removed non existent WM9700 - * Added support for WM9705, WM9708, WM9709, WM9710, WM9711 - * WM9712 and WM9717 - * Mar 28, 2002 Randolph Bentson <bentson@holmsjoen.com> - * corrections to support WM9707 in ViewPad 1000 - * v0.4 Mar 15 2000 Ollie Lho - * dual codecs support verified with 4 channels output - * v0.3 Feb 22 2000 Ollie Lho - * bug fix for record mask setting - * v0.2 Feb 10 2000 Ollie Lho - * add ac97_read_proc for /proc/driver/{vendor}/ac97 - * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw> - * Isolated from trident.c to support multiple ac97 codec - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/bitops.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <linux/ac97_codec.h> -#include <asm/uaccess.h> -#include <linux/mutex.h> - -#define CODEC_ID_BUFSZ 14 - -static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel); -static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, - unsigned int left, unsigned int right); -static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ); -static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask); -static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg); - -static int ac97_init_mixer(struct ac97_codec *codec); - -static int wolfson_init03(struct ac97_codec * codec); -static int wolfson_init04(struct ac97_codec * codec); -static int wolfson_init05(struct ac97_codec * codec); -static int wolfson_init11(struct ac97_codec * codec); -static int wolfson_init13(struct ac97_codec * codec); -static int tritech_init(struct ac97_codec * codec); -static int tritech_maestro_init(struct ac97_codec * codec); -static int sigmatel_9708_init(struct ac97_codec *codec); -static int sigmatel_9721_init(struct ac97_codec *codec); -static int sigmatel_9744_init(struct ac97_codec *codec); -static int ad1886_init(struct ac97_codec *codec); -static int eapd_control(struct ac97_codec *codec, int); -static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode); -static int cmedia_init(struct ac97_codec * codec); -static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode); -static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode); - - -/* - * AC97 operations. - * - * If you are adding a codec then you should be able to use - * eapd_ops - any codec that supports EAPD amp control (most) - * null_ops - any ancient codec that supports nothing - * - * The three functions are - * init - used for non AC97 standard initialisation - * amplifier - used to do amplifier control (1=on 0=off) - * digital - switch to digital modes (0 = analog) - * - * Not all codecs support all features, not all drivers use all the - * operations yet - */ - -static struct ac97_ops null_ops = { NULL, NULL, NULL }; -static struct ac97_ops default_ops = { NULL, eapd_control, NULL }; -static struct ac97_ops default_digital_ops = { NULL, eapd_control, generic_digital_control}; -static struct ac97_ops wolfson_ops03 = { wolfson_init03, NULL, NULL }; -static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL }; -static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL }; -static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL }; -static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL }; -static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL }; -static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL }; -static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL }; -static struct ac97_ops sigmatel_9721_ops = { sigmatel_9721_init, NULL, NULL }; -static struct ac97_ops sigmatel_9744_ops = { sigmatel_9744_init, NULL, NULL }; -static struct ac97_ops crystal_digital_ops = { NULL, eapd_control, crystal_digital_control }; -static struct ac97_ops ad1886_ops = { ad1886_init, eapd_control, NULL }; -static struct ac97_ops cmedia_ops = { NULL, eapd_control, NULL}; -static struct ac97_ops cmedia_digital_ops = { cmedia_init, eapd_control, cmedia_digital_control}; - -/* sorted by vendor/device id */ -static const struct { - u32 id; - char *name; - struct ac97_ops *ops; - int flags; -} ac97_codec_ids[] = { - {0x41445303, "Analog Devices AD1819", &null_ops}, - {0x41445340, "Analog Devices AD1881", &null_ops}, - {0x41445348, "Analog Devices AD1881A", &null_ops}, - {0x41445360, "Analog Devices AD1885", &default_ops}, - {0x41445361, "Analog Devices AD1886", &ad1886_ops}, - {0x41445370, "Analog Devices AD1981", &null_ops}, - {0x41445372, "Analog Devices AD1981A", &null_ops}, - {0x41445374, "Analog Devices AD1981B", &null_ops}, - {0x41445460, "Analog Devices AD1885", &default_ops}, - {0x41445461, "Analog Devices AD1886", &ad1886_ops}, - {0x414B4D00, "Asahi Kasei AK4540", &null_ops}, - {0x414B4D01, "Asahi Kasei AK4542", &null_ops}, - {0x414B4D02, "Asahi Kasei AK4543", &null_ops}, - {0x414C4326, "ALC100P", &null_ops}, - {0x414C4710, "ALC200/200P", &null_ops}, - {0x414C4720, "ALC650", &default_digital_ops}, - {0x434D4941, "CMedia", &cmedia_ops, AC97_NO_PCM_VOLUME }, - {0x434D4942, "CMedia", &cmedia_ops, AC97_NO_PCM_VOLUME }, - {0x434D4961, "CMedia", &cmedia_digital_ops, AC97_NO_PCM_VOLUME }, - {0x43525900, "Cirrus Logic CS4297", &default_ops}, - {0x43525903, "Cirrus Logic CS4297", &default_ops}, - {0x43525913, "Cirrus Logic CS4297A rev A", &default_ops}, - {0x43525914, "Cirrus Logic CS4297A rev B", &default_ops}, - {0x43525923, "Cirrus Logic CS4298", &null_ops}, - {0x4352592B, "Cirrus Logic CS4294", &null_ops}, - {0x4352592D, "Cirrus Logic CS4294", &null_ops}, - {0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops}, - {0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops}, - {0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops}, - {0x43585430, "CXT48", &default_ops, AC97_DELUDED_MODEM }, - {0x43585442, "CXT66", &default_ops, AC97_DELUDED_MODEM }, - {0x44543031, "Diamond Technology DT0893", &default_ops}, - {0x45838308, "ESS Allegro ES1988", &null_ops}, - {0x49434511, "ICE1232", &null_ops}, /* I hope --jk */ - {0x4e534331, "National Semiconductor LM4549", &null_ops}, - {0x53494c22, "Silicon Laboratory Si3036", &null_ops}, - {0x53494c23, "Silicon Laboratory Si3038", &null_ops}, - {0x545200FF, "TriTech TR?????", &tritech_m_ops}, - {0x54524102, "TriTech TR28022", &null_ops}, - {0x54524103, "TriTech TR28023", &null_ops}, - {0x54524106, "TriTech TR28026", &null_ops}, - {0x54524108, "TriTech TR28028", &tritech_ops}, - {0x54524123, "TriTech TR A5", &null_ops}, - {0x574D4C03, "Wolfson WM9703/07/08/17", &wolfson_ops03}, - {0x574D4C04, "Wolfson WM9704M/WM9704Q", &wolfson_ops04}, - {0x574D4C05, "Wolfson WM9705/WM9710", &wolfson_ops05}, - {0x574D4C09, "Wolfson WM9709", &null_ops}, - {0x574D4C12, "Wolfson WM9711/9712", &wolfson_ops11}, - {0x574D4C13, "Wolfson WM9713", &wolfson_ops13, AC97_DEFAULT_POWER_OFF}, - {0x83847600, "SigmaTel STAC????", &null_ops}, - {0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops}, - {0x83847605, "SigmaTel STAC9704", &null_ops}, - {0x83847608, "SigmaTel STAC9708", &sigmatel_9708_ops}, - {0x83847609, "SigmaTel STAC9721/23", &sigmatel_9721_ops}, - {0x83847644, "SigmaTel STAC9744/45", &sigmatel_9744_ops}, - {0x83847652, "SigmaTel STAC9752/53", &default_ops}, - {0x83847656, "SigmaTel STAC9756/57", &sigmatel_9744_ops}, - {0x83847666, "SigmaTel STAC9750T", &sigmatel_9744_ops}, - {0x83847684, "SigmaTel STAC9783/84?", &null_ops}, - {0x57454301, "Winbond 83971D", &null_ops}, -}; - -/* this table has default mixer values for all OSS mixers. */ -static struct mixer_defaults { - int mixer; - unsigned int value; -} mixer_defaults[SOUND_MIXER_NRDEVICES] = { - /* all values 0 -> 100 in bytes */ - {SOUND_MIXER_VOLUME, 0x4343}, - {SOUND_MIXER_BASS, 0x4343}, - {SOUND_MIXER_TREBLE, 0x4343}, - {SOUND_MIXER_PCM, 0x4343}, - {SOUND_MIXER_SPEAKER, 0x4343}, - {SOUND_MIXER_LINE, 0x4343}, - {SOUND_MIXER_MIC, 0x0000}, - {SOUND_MIXER_CD, 0x4343}, - {SOUND_MIXER_ALTPCM, 0x4343}, - {SOUND_MIXER_IGAIN, 0x4343}, - {SOUND_MIXER_LINE1, 0x4343}, - {SOUND_MIXER_PHONEIN, 0x4343}, - {SOUND_MIXER_PHONEOUT, 0x4343}, - {SOUND_MIXER_VIDEO, 0x4343}, - {-1,0} -}; - -/* table to scale scale from OSS mixer value to AC97 mixer register value */ -static struct ac97_mixer_hw { - unsigned char offset; - int scale; -} ac97_hw[SOUND_MIXER_NRDEVICES]= { - [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,64}, - [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 16}, - [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 16}, - [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 32}, - [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 16}, - [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 32}, - [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 32}, - [SOUND_MIXER_CD] = {AC97_CD_VOL, 32}, - [SOUND_MIXER_ALTPCM] = {AC97_HEADPHONE_VOL, 64}, - [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 16}, - [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 32}, - [SOUND_MIXER_PHONEIN] = {AC97_PHONE_VOL, 32}, - [SOUND_MIXER_PHONEOUT] = {AC97_MASTER_VOL_MONO, 64}, - [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 32}, -}; - -/* the following tables allow us to go from OSS <-> ac97 quickly. */ -enum ac97_recsettings { - AC97_REC_MIC=0, - AC97_REC_CD, - AC97_REC_VIDEO, - AC97_REC_AUX, - AC97_REC_LINE, - AC97_REC_STEREO, /* combination of all enabled outputs.. */ - AC97_REC_MONO, /*.. or the mono equivalent */ - AC97_REC_PHONE -}; - -static const unsigned int ac97_rm2oss[] = { - [AC97_REC_MIC] = SOUND_MIXER_MIC, - [AC97_REC_CD] = SOUND_MIXER_CD, - [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, - [AC97_REC_AUX] = SOUND_MIXER_LINE1, - [AC97_REC_LINE] = SOUND_MIXER_LINE, - [AC97_REC_STEREO]= SOUND_MIXER_IGAIN, - [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN -}; - -/* indexed by bit position */ -static const unsigned int ac97_oss_rm[] = { - [SOUND_MIXER_MIC] = AC97_REC_MIC, - [SOUND_MIXER_CD] = AC97_REC_CD, - [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, - [SOUND_MIXER_LINE1] = AC97_REC_AUX, - [SOUND_MIXER_LINE] = AC97_REC_LINE, - [SOUND_MIXER_IGAIN] = AC97_REC_STEREO, - [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE -}; - -static LIST_HEAD(codecs); -static LIST_HEAD(codec_drivers); -static DEFINE_MUTEX(codec_mutex); - -/* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows - about that given mixer, and should be holding a spinlock for the card */ -static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel) -{ - u16 val; - int ret = 0; - int scale; - struct ac97_mixer_hw *mh = &ac97_hw[oss_channel]; - - val = codec->codec_read(codec , mh->offset); - - if (val & AC97_MUTE) { - ret = 0; - } else if (AC97_STEREO_MASK & (1 << oss_channel)) { - /* nice stereo mixers .. */ - int left,right; - - left = (val >> 8) & 0x7f; - right = val & 0x7f; - - if (oss_channel == SOUND_MIXER_IGAIN) { - right = (right * 100) / mh->scale; - left = (left * 100) / mh->scale; - } else { - /* these may have 5 or 6 bit resolution */ - if(oss_channel == SOUND_MIXER_VOLUME || oss_channel == SOUND_MIXER_ALTPCM) - scale = (1 << codec->bit_resolution); - else - scale = mh->scale; - - right = 100 - ((right * 100) / scale); - left = 100 - ((left * 100) / scale); - } - ret = left | (right << 8); - } else if (oss_channel == SOUND_MIXER_SPEAKER) { - ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale); - } else if (oss_channel == SOUND_MIXER_PHONEIN) { - ret = 100 - (((val & 0x1f) * 100) / mh->scale); - } else if (oss_channel == SOUND_MIXER_PHONEOUT) { - scale = (1 << codec->bit_resolution); - ret = 100 - (((val & 0x1f) * 100) / scale); - } else if (oss_channel == SOUND_MIXER_MIC) { - ret = 100 - (((val & 0x1f) * 100) / mh->scale); - /* the low bit is optional in the tone sliders and masking - it lets us avoid the 0xf 'bypass'.. */ - } else if (oss_channel == SOUND_MIXER_BASS) { - ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale); - } else if (oss_channel == SOUND_MIXER_TREBLE) { - ret = 100 - (((val & 0xe) * 100) / mh->scale); - } - -#ifdef DEBUG - printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), " - "0x%04x -> 0x%04x\n", - oss_channel, codec->id ? "Secondary" : "Primary", - mh->offset, val, ret); -#endif - - return ret; -} - -/* write the OSS encoded volume to the given OSS encoded mixer, again caller's job to - make sure all is well in arg land, call with spinlock held */ -static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, - unsigned int left, unsigned int right) -{ - u16 val = 0; - int scale; - struct ac97_mixer_hw *mh = &ac97_hw[oss_channel]; - -#ifdef DEBUG - printk("ac97_codec: wrote OSS mixer %2d (%s ac97 register 0x%02x), " - "left vol:%2d, right vol:%2d:", - oss_channel, codec->id ? "Secondary" : "Primary", - mh->offset, left, right); -#endif - - if (AC97_STEREO_MASK & (1 << oss_channel)) { - /* stereo mixers */ - if (left == 0 && right == 0) { - val = AC97_MUTE; - } else { - if (oss_channel == SOUND_MIXER_IGAIN) { - right = (right * mh->scale) / 100; - left = (left * mh->scale) / 100; - if (right >= mh->scale) - right = mh->scale-1; - if (left >= mh->scale) - left = mh->scale-1; - } else { - /* these may have 5 or 6 bit resolution */ - if (oss_channel == SOUND_MIXER_VOLUME || - oss_channel == SOUND_MIXER_ALTPCM) - scale = (1 << codec->bit_resolution); - else - scale = mh->scale; - - right = ((100 - right) * scale) / 100; - left = ((100 - left) * scale) / 100; - if (right >= scale) - right = scale-1; - if (left >= scale) - left = scale-1; - } - val = (left << 8) | right; - } - } else if (oss_channel == SOUND_MIXER_BASS) { - val = codec->codec_read(codec , mh->offset) & ~0x0f00; - left = ((100 - left) * mh->scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val |= (left << 8) & 0x0e00; - } else if (oss_channel == SOUND_MIXER_TREBLE) { - val = codec->codec_read(codec , mh->offset) & ~0x000f; - left = ((100 - left) * mh->scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val |= left & 0x000e; - } else if(left == 0) { - val = AC97_MUTE; - } else if (oss_channel == SOUND_MIXER_SPEAKER) { - left = ((100 - left) * mh->scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val = left << 1; - } else if (oss_channel == SOUND_MIXER_PHONEIN) { - left = ((100 - left) * mh->scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val = left; - } else if (oss_channel == SOUND_MIXER_PHONEOUT) { - scale = (1 << codec->bit_resolution); - left = ((100 - left) * scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val = left; - } else if (oss_channel == SOUND_MIXER_MIC) { - val = codec->codec_read(codec , mh->offset) & ~0x801f; - left = ((100 - left) * mh->scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val |= left; - /* the low bit is optional in the tone sliders and masking - it lets us avoid the 0xf 'bypass'.. */ - } -#ifdef DEBUG - printk(" 0x%04x", val); -#endif - - codec->codec_write(codec, mh->offset, val); - -#ifdef DEBUG - val = codec->codec_read(codec, mh->offset); - printk(" -> 0x%04x\n", val); -#endif -} - -/* a thin wrapper for write_mixer */ -static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ) -{ - unsigned int left,right; - - /* cleanse input a little */ - right = ((val >> 8) & 0xff) ; - left = (val & 0xff) ; - - if (right > 100) right = 100; - if (left > 100) left = 100; - - codec->mixer_state[oss_mixer] = (right << 8) | left; - codec->write_mixer(codec, oss_mixer, left, right); -} - -/* read or write the recmask, the ac97 can really have left and right recording - inputs independently set, but OSS doesn't seem to want us to express that to - the user. the caller guarantees that we have a supported bit set, and they - must be holding the card's spinlock */ -static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask) -{ - unsigned int val; - - if (rw) { - /* read it from the card */ - val = codec->codec_read(codec, AC97_RECORD_SELECT); -#ifdef DEBUG - printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val); -#endif - return (1 << ac97_rm2oss[val & 0x07]); - } - - /* else, write the first set in the mask as the - output */ - /* clear out current set value first (AC97 supports only 1 input!) */ - val = (1 << ac97_rm2oss[codec->codec_read(codec, AC97_RECORD_SELECT) & 0x07]); - if (mask != val) - mask &= ~val; - - val = ffs(mask); - val = ac97_oss_rm[val-1]; - val |= val << 8; /* set both channels */ - -#ifdef DEBUG - printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val); -#endif - - codec->codec_write(codec, AC97_RECORD_SELECT, val); - - return 0; -}; - -static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg) -{ - int i, val = 0; - - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, codec->name, sizeof(info.id)); - strlcpy(info.name, codec->name, sizeof(info.name)); - info.modify_counter = codec->modcnt; - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, codec->name, sizeof(info.id)); - strlcpy(info.name, codec->name, sizeof(info.name)); - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - - if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, (int __user *)arg); - - if (_SIOC_DIR(cmd) == _SIOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* give them the current record source */ - if (!codec->recmask_io) { - val = 0; - } else { - val = codec->recmask_io(codec, 1, 0); - } - break; - - case SOUND_MIXER_DEVMASK: /* give them the supported mixers */ - val = codec->supported_mixers; - break; - - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - val = codec->record_sources; - break; - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - val = codec->stereo_mixers; - break; - - case SOUND_MIXER_CAPS: - val = SOUND_CAP_EXCL_INPUT; - break; - - default: /* read a specific mixer */ - i = _IOC_NR(cmd); - - if (!supported_mixer(codec, i)) - return -EINVAL; - - /* do we ever want to touch the hardware? */ - /* val = codec->read_mixer(codec, i); */ - val = codec->mixer_state[i]; - break; - } - return put_user(val, (int __user *)arg); - } - - if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) { - codec->modcnt++; - if (get_user(val, (int __user *)arg)) - return -EFAULT; - - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - if (!codec->recmask_io) return -EINVAL; - if (!val) return 0; - if (!(val &= codec->record_sources)) return -EINVAL; - - codec->recmask_io(codec, 0, val); - - return 0; - default: /* write a specific mixer */ - i = _IOC_NR(cmd); - - if (!supported_mixer(codec, i)) - return -EINVAL; - - ac97_set_mixer(codec, i, val); - - return 0; - } - } - return -EINVAL; -} - -/** - * codec_id - Turn id1/id2 into a PnP string - * @id1: Vendor ID1 - * @id2: Vendor ID2 - * @buf: CODEC_ID_BUFSZ byte buffer - * - * Fills buf with a zero terminated PnP ident string for the id1/id2 - * pair. For convenience the return is the passed in buffer pointer. - */ - -static char *codec_id(u16 id1, u16 id2, char *buf) -{ - if(id1&0x8080) { - snprintf(buf, CODEC_ID_BUFSZ, "0x%04x:0x%04x", id1, id2); - } else { - buf[0] = (id1 >> 8); - buf[1] = (id1 & 0xFF); - buf[2] = (id2 >> 8); - snprintf(buf+3, CODEC_ID_BUFSZ - 3, "%d", id2&0xFF); - } - return buf; -} - -/** - * ac97_check_modem - Check if the Codec is a modem - * @codec: codec to check - * - * Return true if the device is an AC97 1.0 or AC97 2.0 modem - */ - -static int ac97_check_modem(struct ac97_codec *codec) -{ - /* Check for an AC97 1.0 soft modem (ID1) */ - if(codec->codec_read(codec, AC97_RESET) & 2) - return 1; - /* Check for an AC97 2.x soft modem */ - codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L); - if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1) - return 1; - return 0; -} - - -/** - * ac97_alloc_codec - Allocate an AC97 codec - * - * Returns a new AC97 codec structure. AC97 codecs may become - * refcounted soon so this interface is needed. Returns with - * one reference taken. - */ - -struct ac97_codec *ac97_alloc_codec(void) -{ - struct ac97_codec *codec = kzalloc(sizeof(struct ac97_codec), GFP_KERNEL); - if(!codec) - return NULL; - - spin_lock_init(&codec->lock); - INIT_LIST_HEAD(&codec->list); - return codec; -} - -EXPORT_SYMBOL(ac97_alloc_codec); - -/** - * ac97_release_codec - Release an AC97 codec - * @codec: codec to release - * - * Release an allocated AC97 codec. This will be refcounted in - * time but for the moment is trivial. Calls the unregister - * handler if the codec is now defunct. - */ - -void ac97_release_codec(struct ac97_codec *codec) -{ - /* Remove from the list first, we don't want to be - "rediscovered" */ - mutex_lock(&codec_mutex); - list_del(&codec->list); - mutex_unlock(&codec_mutex); - /* - * The driver needs to deal with internal - * locking to avoid accidents here. - */ - if(codec->driver) - codec->driver->remove(codec, codec->driver); - kfree(codec); -} - -EXPORT_SYMBOL(ac97_release_codec); - -/** - * ac97_probe_codec - Initialize and setup AC97-compatible codec - * @codec: (in/out) Kernel info for a single AC97 codec - * - * Reset the AC97 codec, then initialize the mixer and - * the rest of the @codec structure. - * - * The codec_read and codec_write fields of @codec are - * required to be setup and working when this function - * is called. All other fields are set by this function. - * - * codec_wait field of @codec can optionally be provided - * when calling this function. If codec_wait is not %NULL, - * this function will call codec_wait any time it is - * necessary to wait for the audio chip to reach the - * codec-ready state. If codec_wait is %NULL, then - * the default behavior is to call schedule_timeout. - * Currently codec_wait is used to wait for AC97 codec - * reset to complete. - * - * Some codecs will power down when a register reset is - * performed. We now check for such codecs. - * - * Returns 1 (true) on success, or 0 (false) on failure. - */ - -int ac97_probe_codec(struct ac97_codec *codec) -{ - u16 id1, id2; - u16 audio; - int i; - char cidbuf[CODEC_ID_BUFSZ]; - u16 f; - struct list_head *l; - struct ac97_driver *d; - - /* wait for codec-ready state */ - if (codec->codec_wait) - codec->codec_wait(codec); - else - udelay(10); - - /* will the codec power down if register reset ? */ - id1 = codec->codec_read(codec, AC97_VENDOR_ID1); - id2 = codec->codec_read(codec, AC97_VENDOR_ID2); - codec->name = NULL; - codec->codec_ops = &null_ops; - for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) { - if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) { - codec->type = ac97_codec_ids[i].id; - codec->name = ac97_codec_ids[i].name; - codec->codec_ops = ac97_codec_ids[i].ops; - codec->flags = ac97_codec_ids[i].flags; - break; - } - } - - codec->model = (id1 << 16) | id2; - if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) { - /* reset codec and wait for the ready bit before we continue */ - codec->codec_write(codec, AC97_RESET, 0L); - if (codec->codec_wait) - codec->codec_wait(codec); - else - udelay(10); - } - - /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should - * be read zero. - * - * FIXME: is the following comment outdated? -jgarzik - * Probing of AC97 in this way is not reliable, it is not even SAFE !! - */ - if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) { - printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n", - (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") - : (codec->id&1 ? "Secondary": "Primary")); - return 0; - } - - /* probe for Modem Codec */ - codec->modem = ac97_check_modem(codec); - - /* enable SPDIF */ - f = codec->codec_read(codec, AC97_EXTENDED_STATUS); - if((codec->codec_ops == &null_ops) && (f & 4)) - codec->codec_ops = &default_digital_ops; - - /* A device which thinks its a modem but isn't */ - if(codec->flags & AC97_DELUDED_MODEM) - codec->modem = 0; - - if (codec->name == NULL) - codec->name = "Unknown"; - printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s (%s)\n", - codec->modem ? "Modem" : (audio ? "Audio" : ""), - codec_id(id1, id2, cidbuf), codec->name); - - if(!ac97_init_mixer(codec)) - return 0; - - /* - * Attach last so the caller can override the mixer - * callbacks. - */ - - mutex_lock(&codec_mutex); - list_add(&codec->list, &codecs); - - list_for_each(l, &codec_drivers) { - d = list_entry(l, struct ac97_driver, list); - if ((codec->model ^ d->codec_id) & d->codec_mask) - continue; - if(d->probe(codec, d) == 0) - { - codec->driver = d; - break; - } - } - - mutex_unlock(&codec_mutex); - return 1; -} - -static int ac97_init_mixer(struct ac97_codec *codec) -{ - u16 cap; - int i; - - cap = codec->codec_read(codec, AC97_RESET); - - /* mixer masks */ - codec->supported_mixers = AC97_SUPPORTED_MASK; - codec->stereo_mixers = AC97_STEREO_MASK; - codec->record_sources = AC97_RECORD_MASK; - if (!(cap & 0x04)) - codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE); - if (!(cap & 0x10)) - codec->supported_mixers &= ~SOUND_MASK_ALTPCM; - - - /* detect bit resolution */ - codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0x2020); - if(codec->codec_read(codec, AC97_MASTER_VOL_STEREO) == 0x2020) - codec->bit_resolution = 6; - else - codec->bit_resolution = 5; - - /* generic OSS to AC97 wrapper */ - codec->read_mixer = ac97_read_mixer; - codec->write_mixer = ac97_write_mixer; - codec->recmask_io = ac97_recmask_io; - codec->mixer_ioctl = ac97_mixer_ioctl; - - /* initialize mixer channel volumes */ - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - struct mixer_defaults *md = &mixer_defaults[i]; - if (md->mixer == -1) - break; - if (!supported_mixer(codec, md->mixer)) - continue; - ac97_set_mixer(codec, md->mixer, md->value); - } - - /* codec specific initialization for 4-6 channel output or secondary codec stuff */ - if (codec->codec_ops->init != NULL) { - codec->codec_ops->init(codec); - } - - /* - * Volume is MUTE only on this device. We have to initialise - * it but its useless beyond that. - */ - if(codec->flags & AC97_NO_PCM_VOLUME) - { - codec->supported_mixers &= ~SOUND_MASK_PCM; - printk(KERN_WARNING "AC97 codec does not have proper volume support.\n"); - } - return 1; -} - -#define AC97_SIGMATEL_ANALOG 0x6c /* Analog Special */ -#define AC97_SIGMATEL_DAC2INVERT 0x6e -#define AC97_SIGMATEL_BIAS1 0x70 -#define AC97_SIGMATEL_BIAS2 0x72 -#define AC97_SIGMATEL_MULTICHN 0x74 /* Multi-Channel programming */ -#define AC97_SIGMATEL_CIC1 0x76 -#define AC97_SIGMATEL_CIC2 0x78 - - -static int sigmatel_9708_init(struct ac97_codec * codec) -{ - u16 codec72, codec6c; - - codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000; - codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG); - - if ((codec72==0) && (codec6c==0)) { - codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); - codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000); - codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); - codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007); - } else if ((codec72==0x8000) && (codec6c==0)) { - codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); - codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001); - codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008); - } else if ((codec72==0x8000) && (codec6c==0x0080)) { - /* nothing */ - } - codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); - return 0; -} - - -static int sigmatel_9721_init(struct ac97_codec * codec) -{ - /* Only set up secondary codec */ - if (codec->id == 0) - return 0; - - codec->codec_write(codec, AC97_SURROUND_MASTER, 0L); - - /* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link - sloc 3,4 = 0x01, slot 7,8 = 0x00, */ - codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00); - - /* we don't have the crystal when we are on an AMR card, so use - BIT_CLK as our clock source. Write the magic word ABBA and read - back to enable register 0x78 */ - codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); - codec->codec_read(codec, AC97_SIGMATEL_CIC1); - - /* sync all the clocks*/ - codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802); - - return 0; -} - - -static int sigmatel_9744_init(struct ac97_codec * codec) -{ - // patch for SigmaTel - codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); - codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk - codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); - codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002); - codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); - return 0; -} - -static int cmedia_init(struct ac97_codec *codec) -{ - /* Initialise the CMedia 9739 */ - /* - We could set various options here - Register 0x20 bit 0x100 sets mic as center bass - Also do multi_channel_ctrl &=~0x3000 |=0x1000 - - For now we set up the GPIO and PC beep - */ - - u16 v; - - /* MIC */ - codec->codec_write(codec, 0x64, 0x3000); - v = codec->codec_read(codec, 0x64); - v &= ~0x8000; - codec->codec_write(codec, 0x64, v); - codec->codec_write(codec, 0x70, 0x0100); - codec->codec_write(codec, 0x72, 0x0020); - return 0; -} - -#define AC97_WM97XX_FMIXER_VOL 0x72 -#define AC97_WM97XX_RMIXER_VOL 0x74 -#define AC97_WM97XX_TEST 0x5a -#define AC97_WM9704_RPCM_VOL 0x70 -#define AC97_WM9711_OUT3VOL 0x16 - -static int wolfson_init03(struct ac97_codec * codec) -{ - /* this is known to work for the ViewSonic ViewPad 1000 */ - codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808); - codec->codec_write(codec, AC97_GENERAL_PURPOSE, 0x8000); - return 0; -} - -static int wolfson_init04(struct ac97_codec * codec) -{ - codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808); - codec->codec_write(codec, AC97_WM97XX_RMIXER_VOL, 0x0808); - - // patch for DVD noise - codec->codec_write(codec, AC97_WM97XX_TEST, 0x0200); - - // init vol as PCM vol - codec->codec_write(codec, AC97_WM9704_RPCM_VOL, - codec->codec_read(codec, AC97_PCMOUT_VOL)); - - /* set rear surround volume */ - codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); - return 0; -} - -/* WM9705, WM9710 */ -static int wolfson_init05(struct ac97_codec * codec) -{ - /* set front mixer volume */ - codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808); - return 0; -} - -/* WM9711, WM9712 */ -static int wolfson_init11(struct ac97_codec * codec) -{ - /* stop pop's during suspend/resume */ - codec->codec_write(codec, AC97_WM97XX_TEST, - codec->codec_read(codec, AC97_WM97XX_TEST) & 0xffbf); - - /* set out3 volume */ - codec->codec_write(codec, AC97_WM9711_OUT3VOL, 0x0808); - return 0; -} - -/* WM9713 */ -static int wolfson_init13(struct ac97_codec * codec) -{ - codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0); - codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000); - codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00); - codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810); - codec->codec_write(codec, AC97_PHONE_VOL, 0x0808); - codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808); - - return 0; -} - -static int tritech_init(struct ac97_codec * codec) -{ - codec->codec_write(codec, 0x26, 0x0300); - codec->codec_write(codec, 0x26, 0x0000); - codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); - codec->codec_write(codec, AC97_RESERVED_3A, 0x0000); - return 0; -} - - -/* copied from drivers/sound/maestro.c */ -static int tritech_maestro_init(struct ac97_codec * codec) -{ - /* no idea what this does */ - codec->codec_write(codec, 0x2A, 0x0001); - codec->codec_write(codec, 0x2C, 0x0000); - codec->codec_write(codec, 0x2C, 0XFFFF); - return 0; -} - - - -/* - * Presario700 workaround - * for Jack Sense/SPDIF Register mis-setting causing - * no audible output - * by Santiago Nullo 04/05/2002 - */ - -#define AC97_AD1886_JACK_SENSE 0x72 - -static int ad1886_init(struct ac97_codec * codec) -{ - /* from AD1886 Specs */ - codec->codec_write(codec, AC97_AD1886_JACK_SENSE, 0x0010); - return 0; -} - - - - -/* - * This is basically standard AC97. It should work as a default for - * almost all modern codecs. Note that some cards wire EAPD *backwards* - * That side of it is up to the card driver not us to cope with. - * - */ - -static int eapd_control(struct ac97_codec * codec, int on) -{ - if(on) - codec->codec_write(codec, AC97_POWER_CONTROL, - codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000); - else - codec->codec_write(codec, AC97_POWER_CONTROL, - codec->codec_read(codec, AC97_POWER_CONTROL)&~0x8000); - return 0; -} - -static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode) -{ - u16 reg; - - reg = codec->codec_read(codec, AC97_SPDIF_CONTROL); - - switch(rate) - { - /* Off by default */ - default: - case 0: - reg = codec->codec_read(codec, AC97_EXTENDED_STATUS); - codec->codec_write(codec, AC97_EXTENDED_STATUS, (reg & ~AC97_EA_SPDIF)); - if(rate == 0) - return 0; - return -EINVAL; - case 1: - reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K; - break; - case 2: - reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K; - break; - case 3: - reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K; - break; - } - - reg &= ~AC97_SC_CC_MASK; - reg |= (mode & AUDIO_CCMASK) << 6; - - if(mode & AUDIO_DIGITAL) - reg |= 2; - if(mode & AUDIO_PRO) - reg |= 1; - if(mode & AUDIO_DRS) - reg |= 0x4000; - - codec->codec_write(codec, AC97_SPDIF_CONTROL, reg); - - reg = codec->codec_read(codec, AC97_EXTENDED_STATUS); - reg &= (AC97_EA_SLOT_MASK); - reg |= AC97_EA_VRA | AC97_EA_SPDIF | slots; - codec->codec_write(codec, AC97_EXTENDED_STATUS, reg); - - reg = codec->codec_read(codec, AC97_EXTENDED_STATUS); - if(!(reg & 0x0400)) - { - codec->codec_write(codec, AC97_EXTENDED_STATUS, reg & ~ AC97_EA_SPDIF); - return -EINVAL; - } - return 0; -} - -/* - * Crystal digital audio control (CS4299) - */ - -static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode) -{ - u16 cv; - - if(mode & AUDIO_DIGITAL) - return -EINVAL; - - switch(rate) - { - case 0: cv = 0x0; break; /* SPEN off */ - case 48000: cv = 0x8004; break; /* 48KHz digital */ - case 44100: cv = 0x8104; break; /* 44.1KHz digital */ - case 32768: /* 32Khz */ - default: - return -EINVAL; - } - codec->codec_write(codec, 0x68, cv); - return 0; -} - -/* - * CMedia digital audio control - * Needs more work. - */ - -static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode) -{ - u16 cv; - - if(mode & AUDIO_DIGITAL) - return -EINVAL; - - switch(rate) - { - case 0: cv = 0x0001; break; /* SPEN off */ - case 48000: cv = 0x0009; break; /* 48KHz digital */ - default: - return -EINVAL; - } - codec->codec_write(codec, 0x2A, 0x05c4); - codec->codec_write(codec, 0x6C, cv); - - /* Switch on mix to surround */ - cv = codec->codec_read(codec, 0x64); - cv &= ~0x0200; - if(mode) - cv |= 0x0200; - codec->codec_write(codec, 0x64, cv); - return 0; -} - - -/* copied from drivers/sound/maestro.c */ -#if 0 /* there has been 1 person on the planet with a pt101 that we - know of. If they care, they can put this back in :) */ -static int pt101_init(struct ac97_codec * codec) -{ - printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n"); - /* who knows.. */ - codec->codec_write(codec, 0x2A, 0x0001); - codec->codec_write(codec, 0x2C, 0x0000); - codec->codec_write(codec, 0x2C, 0xFFFF); - codec->codec_write(codec, 0x10, 0x9F1F); - codec->codec_write(codec, 0x12, 0x0808); - codec->codec_write(codec, 0x14, 0x9F1F); - codec->codec_write(codec, 0x16, 0x9F1F); - codec->codec_write(codec, 0x18, 0x0404); - codec->codec_write(codec, 0x1A, 0x0000); - codec->codec_write(codec, 0x1C, 0x0000); - codec->codec_write(codec, 0x02, 0x0404); - codec->codec_write(codec, 0x04, 0x0808); - codec->codec_write(codec, 0x0C, 0x801F); - codec->codec_write(codec, 0x0E, 0x801F); - return 0; -} -#endif - - -EXPORT_SYMBOL(ac97_probe_codec); - -MODULE_LICENSE("GPL"); - diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c deleted file mode 100644 index a8f626d99c5..00000000000 --- a/sound/oss/au1550_ac97.c +++ /dev/null @@ -1,2147 +0,0 @@ -/* - * au1550_ac97.c -- Sound driver for Alchemy Au1550 MIPS Internet Edge - * Processor. - * - * Copyright 2004 Embedded Edge, LLC - * dan@embeddededge.com - * - * Mostly copied from the au1000.c driver and some from the - * PowerMac dbdma driver. - * We assume the processor can do memory coherent DMA. - * - * Ported to 2.6 by Matt Porter <mporter@kernel.crashing.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#undef DEBUG - -#include <linux/module.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/sound.h> -#include <linux/slab.h> -#include <linux/soundcard.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/poll.h> -#include <linux/bitops.h> -#include <linux/spinlock.h> -#include <linux/ac97_codec.h> -#include <linux/mutex.h> - -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/hardirq.h> -#include <asm/mach-au1x00/au1xxx_psc.h> -#include <asm/mach-au1x00/au1xxx_dbdma.h> -#include <asm/mach-au1x00/au1xxx.h> - -#undef OSS_DOCUMENTED_MIXER_SEMANTICS - -/* misc stuff */ -#define POLL_COUNT 0x50000 -#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC) - -/* The number of DBDMA ring descriptors to allocate. No sense making - * this too large....if you can't keep up with a few you aren't likely - * to be able to with lots of them, either. - */ -#define NUM_DBDMA_DESCRIPTORS 4 - -#define err(format, arg...) printk(KERN_ERR format "\n" , ## arg) - -/* Boot options - * 0 = no VRA, 1 = use VRA if codec supports it - */ -static DEFINE_MUTEX(au1550_ac97_mutex); -static int vra = 1; -module_param(vra, bool, 0); -MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); - -static struct au1550_state { - /* soundcore stuff */ - int dev_audio; - - struct ac97_codec *codec; - unsigned codec_base_caps; /* AC'97 reg 00h, "Reset Register" */ - unsigned codec_ext_caps; /* AC'97 reg 28h, "Extended Audio ID" */ - int no_vra; /* do not use VRA */ - - spinlock_t lock; - struct mutex open_mutex; - struct mutex sem; - fmode_t open_mode; - wait_queue_head_t open_wait; - - struct dmabuf { - u32 dmanr; - unsigned sample_rate; - unsigned src_factor; - unsigned sample_size; - int num_channels; - int dma_bytes_per_sample; - int user_bytes_per_sample; - int cnt_factor; - - void *rawbuf; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - void *nextIn; - void *nextOut; - int count; - unsigned total_bytes; - unsigned error; - wait_queue_head_t wait; - - /* redundant, but makes calculations easier */ - unsigned fragsize; - unsigned dma_fragsize; - unsigned dmasize; - unsigned dma_qcount; - - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned stopped:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac, dma_adc; -} au1550_state; - -static unsigned -ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -static void -au1550_delay(int msec) -{ - if (in_interrupt()) - return; - - schedule_timeout_uninterruptible(msecs_to_jiffies(msec)); -} - -static u16 -rdcodec(struct ac97_codec *codec, u8 addr) -{ - struct au1550_state *s = codec->private_data; - unsigned long flags; - u32 cmd, val; - u16 data; - int i; - - spin_lock_irqsave(&s->lock, flags); - - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (!(val & PSC_AC97STAT_CP)) - break; - } - if (i == POLL_COUNT) - err("rdcodec: codec cmd pending expired!"); - - cmd = (u32)PSC_AC97CDC_INDX(addr); - cmd |= PSC_AC97CDC_RD; /* read command */ - au_writel(cmd, PSC_AC97CDC); - au_sync(); - - /* now wait for the data - */ - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (!(val & PSC_AC97STAT_CP)) - break; - } - if (i == POLL_COUNT) { - err("rdcodec: read poll expired!"); - data = 0; - goto out; - } - - /* wait for command done? - */ - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97EVNT); - au_sync(); - if (val & PSC_AC97EVNT_CD) - break; - } - if (i == POLL_COUNT) { - err("rdcodec: read cmdwait expired!"); - data = 0; - goto out; - } - - data = au_readl(PSC_AC97CDC) & 0xffff; - au_sync(); - - /* Clear command done event. - */ - au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT); - au_sync(); - - out: - spin_unlock_irqrestore(&s->lock, flags); - - return data; -} - - -static void -wrcodec(struct ac97_codec *codec, u8 addr, u16 data) -{ - struct au1550_state *s = codec->private_data; - unsigned long flags; - u32 cmd, val; - int i; - - spin_lock_irqsave(&s->lock, flags); - - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (!(val & PSC_AC97STAT_CP)) - break; - } - if (i == POLL_COUNT) - err("wrcodec: codec cmd pending expired!"); - - cmd = (u32)PSC_AC97CDC_INDX(addr); - cmd |= (u32)data; - au_writel(cmd, PSC_AC97CDC); - au_sync(); - - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (!(val & PSC_AC97STAT_CP)) - break; - } - if (i == POLL_COUNT) - err("wrcodec: codec cmd pending expired!"); - - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97EVNT); - au_sync(); - if (val & PSC_AC97EVNT_CD) - break; - } - if (i == POLL_COUNT) - err("wrcodec: read cmdwait expired!"); - - /* Clear command done event. - */ - au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT); - au_sync(); - - spin_unlock_irqrestore(&s->lock, flags); -} - -static void -waitcodec(struct ac97_codec *codec) -{ - u16 temp; - u32 val; - int i; - - /* codec_wait is used to wait for a ready state after - * an AC97C_RESET. - */ - au1550_delay(10); - - /* first poll the CODEC_READY tag bit - */ - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (val & PSC_AC97STAT_CR) - break; - } - if (i == POLL_COUNT) { - err("waitcodec: CODEC_READY poll expired!"); - return; - } - - /* get AC'97 powerdown control/status register - */ - temp = rdcodec(codec, AC97_POWER_CONTROL); - - /* If anything is powered down, power'em up - */ - if (temp & 0x7f00) { - /* Power on - */ - wrcodec(codec, AC97_POWER_CONTROL, 0); - au1550_delay(100); - - /* Reread - */ - temp = rdcodec(codec, AC97_POWER_CONTROL); - } - - /* Check if Codec REF,ANL,DAC,ADC ready - */ - if ((temp & 0x7f0f) != 0x000f) - err("codec reg 26 status (0x%x) not ready!!", temp); -} - -/* stop the ADC before calling */ -static void -set_adc_rate(struct au1550_state *s, unsigned rate) -{ - struct dmabuf *adc = &s->dma_adc; - struct dmabuf *dac = &s->dma_dac; - unsigned adc_rate, dac_rate; - u16 ac97_extstat; - - if (s->no_vra) { - /* calc SRC factor - */ - adc->src_factor = ((96000 / rate) + 1) >> 1; - adc->sample_rate = 48000 / adc->src_factor; - return; - } - - adc->src_factor = 1; - - ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS); - - rate = rate > 48000 ? 48000 : rate; - - /* enable VRA - */ - wrcodec(s->codec, AC97_EXTENDED_STATUS, - ac97_extstat | AC97_EXTSTAT_VRA); - - /* now write the sample rate - */ - wrcodec(s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate); - - /* read it back for actual supported rate - */ - adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE); - - pr_debug("set_adc_rate: set to %d Hz\n", adc_rate); - - /* some codec's don't allow unequal DAC and ADC rates, in which case - * writing one rate reg actually changes both. - */ - dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE); - if (dac->num_channels > 2) - wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate); - if (dac->num_channels > 4) - wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate); - - adc->sample_rate = adc_rate; - dac->sample_rate = dac_rate; -} - -/* stop the DAC before calling */ -static void -set_dac_rate(struct au1550_state *s, unsigned rate) -{ - struct dmabuf *dac = &s->dma_dac; - struct dmabuf *adc = &s->dma_adc; - unsigned adc_rate, dac_rate; - u16 ac97_extstat; - - if (s->no_vra) { - /* calc SRC factor - */ - dac->src_factor = ((96000 / rate) + 1) >> 1; - dac->sample_rate = 48000 / dac->src_factor; - return; - } - - dac->src_factor = 1; - - ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS); - - rate = rate > 48000 ? 48000 : rate; - - /* enable VRA - */ - wrcodec(s->codec, AC97_EXTENDED_STATUS, - ac97_extstat | AC97_EXTSTAT_VRA); - - /* now write the sample rate - */ - wrcodec(s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate); - - /* I don't support different sample rates for multichannel, - * so make these channels the same. - */ - if (dac->num_channels > 2) - wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate); - if (dac->num_channels > 4) - wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate); - /* read it back for actual supported rate - */ - dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE); - - pr_debug("set_dac_rate: set to %d Hz\n", dac_rate); - - /* some codec's don't allow unequal DAC and ADC rates, in which case - * writing one rate reg actually changes both. - */ - adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE); - - dac->sample_rate = dac_rate; - adc->sample_rate = adc_rate; -} - -static void -stop_dac(struct au1550_state *s) -{ - struct dmabuf *db = &s->dma_dac; - u32 stat; - unsigned long flags; - - if (db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - au_writel(PSC_AC97PCR_TP, PSC_AC97PCR); - au_sync(); - - /* Wait for Transmit Busy to show disabled. - */ - do { - stat = au_readl(PSC_AC97STAT); - au_sync(); - } while ((stat & PSC_AC97STAT_TB) != 0); - - au1xxx_dbdma_reset(db->dmanr); - - db->stopped = 1; - - spin_unlock_irqrestore(&s->lock, flags); -} - -static void -stop_adc(struct au1550_state *s) -{ - struct dmabuf *db = &s->dma_adc; - unsigned long flags; - u32 stat; - - if (db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - au_writel(PSC_AC97PCR_RP, PSC_AC97PCR); - au_sync(); - - /* Wait for Receive Busy to show disabled. - */ - do { - stat = au_readl(PSC_AC97STAT); - au_sync(); - } while ((stat & PSC_AC97STAT_RB) != 0); - - au1xxx_dbdma_reset(db->dmanr); - - db->stopped = 1; - - spin_unlock_irqrestore(&s->lock, flags); -} - - -static void -set_xmit_slots(int num_channels) -{ - u32 ac97_config, stat; - - ac97_config = au_readl(PSC_AC97CFG); - au_sync(); - ac97_config &= ~(PSC_AC97CFG_TXSLOT_MASK | PSC_AC97CFG_DE_ENABLE); - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - switch (num_channels) { - case 6: /* stereo with surround and center/LFE, - * slots 3,4,6,7,8,9 - */ - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(6); - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(9); - - case 4: /* stereo with surround, slots 3,4,7,8 */ - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(7); - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(8); - - case 2: /* stereo, slots 3,4 */ - case 1: /* mono */ - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(3); - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(4); - } - - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - ac97_config |= PSC_AC97CFG_DE_ENABLE; - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - /* Wait for Device ready. - */ - do { - stat = au_readl(PSC_AC97STAT); - au_sync(); - } while ((stat & PSC_AC97STAT_DR) == 0); -} - -static void -set_recv_slots(int num_channels) -{ - u32 ac97_config, stat; - - ac97_config = au_readl(PSC_AC97CFG); - au_sync(); - ac97_config &= ~(PSC_AC97CFG_RXSLOT_MASK | PSC_AC97CFG_DE_ENABLE); - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - /* Always enable slots 3 and 4 (stereo). Slot 6 is - * optional Mic ADC, which we don't support yet. - */ - ac97_config |= PSC_AC97CFG_RXSLOT_ENA(3); - ac97_config |= PSC_AC97CFG_RXSLOT_ENA(4); - - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - ac97_config |= PSC_AC97CFG_DE_ENABLE; - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - /* Wait for Device ready. - */ - do { - stat = au_readl(PSC_AC97STAT); - au_sync(); - } while ((stat & PSC_AC97STAT_DR) == 0); -} - -/* Hold spinlock for both start_dac() and start_adc() calls */ -static void -start_dac(struct au1550_state *s) -{ - struct dmabuf *db = &s->dma_dac; - - if (!db->stopped) - return; - - set_xmit_slots(db->num_channels); - au_writel(PSC_AC97PCR_TC, PSC_AC97PCR); - au_sync(); - au_writel(PSC_AC97PCR_TS, PSC_AC97PCR); - au_sync(); - - au1xxx_dbdma_start(db->dmanr); - - db->stopped = 0; -} - -static void -start_adc(struct au1550_state *s) -{ - struct dmabuf *db = &s->dma_adc; - int i; - - if (!db->stopped) - return; - - /* Put two buffers on the ring to get things started. - */ - for (i=0; i<2; i++) { - au1xxx_dbdma_put_dest(db->dmanr, virt_to_phys(db->nextIn), - db->dma_fragsize, DDMA_FLAGS_IE); - - db->nextIn += db->dma_fragsize; - if (db->nextIn >= db->rawbuf + db->dmasize) - db->nextIn -= db->dmasize; - } - - set_recv_slots(db->num_channels); - au1xxx_dbdma_start(db->dmanr); - au_writel(PSC_AC97PCR_RC, PSC_AC97PCR); - au_sync(); - au_writel(PSC_AC97PCR_RS, PSC_AC97PCR); - au_sync(); - - db->stopped = 0; -} - -static int -prog_dmabuf(struct au1550_state *s, struct dmabuf *db) -{ - unsigned user_bytes_per_sec; - unsigned bufs; - unsigned rate = db->sample_rate; - - if (!db->rawbuf) { - db->ready = db->mapped = 0; - db->buforder = 5; /* 32 * PAGE_SIZE */ - db->rawbuf = kmalloc((PAGE_SIZE << db->buforder), GFP_KERNEL); - if (!db->rawbuf) - return -ENOMEM; - } - - db->cnt_factor = 1; - if (db->sample_size == 8) - db->cnt_factor *= 2; - if (db->num_channels == 1) - db->cnt_factor *= 2; - db->cnt_factor *= db->src_factor; - - db->count = 0; - db->dma_qcount = 0; - db->nextIn = db->nextOut = db->rawbuf; - - db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels; - db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ? - 2 : db->num_channels); - - user_bytes_per_sec = rate * db->user_bytes_per_sample; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < user_bytes_per_sec) - db->fragshift = ld2(user_bytes_per_sec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(user_bytes_per_sec / 100 / - (db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - - db->fragsize = 1 << db->fragshift; - db->dma_fragsize = db->fragsize * db->cnt_factor; - db->numfrag = bufs / db->dma_fragsize; - - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->fragsize = 1 << db->fragshift; - db->dma_fragsize = db->fragsize * db->cnt_factor; - db->numfrag = bufs / db->dma_fragsize; - } - - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - - db->dmasize = db->dma_fragsize * db->numfrag; - memset(db->rawbuf, 0, bufs); - - pr_debug("prog_dmabuf: rate=%d, samplesize=%d, channels=%d\n", - rate, db->sample_size, db->num_channels); - pr_debug("prog_dmabuf: fragsize=%d, cnt_factor=%d, dma_fragsize=%d\n", - db->fragsize, db->cnt_factor, db->dma_fragsize); - pr_debug("prog_dmabuf: numfrag=%d, dmasize=%d\n", db->numfrag, db->dmasize); - - db->ready = 1; - return 0; -} - -static int -prog_dmabuf_adc(struct au1550_state *s) -{ - stop_adc(s); - return prog_dmabuf(s, &s->dma_adc); - -} - -static int -prog_dmabuf_dac(struct au1550_state *s) -{ - stop_dac(s); - return prog_dmabuf(s, &s->dma_dac); -} - - -static void dac_dma_interrupt(int irq, void *dev_id) -{ - struct au1550_state *s = (struct au1550_state *) dev_id; - struct dmabuf *db = &s->dma_dac; - u32 ac97c_stat; - - spin_lock(&s->lock); - - ac97c_stat = au_readl(PSC_AC97STAT); - if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE)) - pr_debug("AC97C status = 0x%08x\n", ac97c_stat); - db->dma_qcount--; - - if (db->count >= db->fragsize) { - if (au1xxx_dbdma_put_source(db->dmanr, - virt_to_phys(db->nextOut), db->fragsize, - DDMA_FLAGS_IE) == 0) { - err("qcount < 2 and no ring room!"); - } - db->nextOut += db->fragsize; - if (db->nextOut >= db->rawbuf + db->dmasize) - db->nextOut -= db->dmasize; - db->count -= db->fragsize; - db->total_bytes += db->dma_fragsize; - db->dma_qcount++; - } - - /* wake up anybody listening */ - if (waitqueue_active(&db->wait)) - wake_up(&db->wait); - - spin_unlock(&s->lock); -} - - -static void adc_dma_interrupt(int irq, void *dev_id) -{ - struct au1550_state *s = (struct au1550_state *)dev_id; - struct dmabuf *dp = &s->dma_adc; - u32 obytes; - char *obuf; - - spin_lock(&s->lock); - - /* Pull the buffer from the dma queue. - */ - au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes); - - if ((dp->count + obytes) > dp->dmasize) { - /* Overrun. Stop ADC and log the error - */ - spin_unlock(&s->lock); - stop_adc(s); - dp->error++; - err("adc overrun"); - return; - } - - /* Put a new empty buffer on the destination DMA. - */ - au1xxx_dbdma_put_dest(dp->dmanr, virt_to_phys(dp->nextIn), - dp->dma_fragsize, DDMA_FLAGS_IE); - - dp->nextIn += dp->dma_fragsize; - if (dp->nextIn >= dp->rawbuf + dp->dmasize) - dp->nextIn -= dp->dmasize; - - dp->count += obytes; - dp->total_bytes += obytes; - - /* wake up anybody listening - */ - if (waitqueue_active(&dp->wait)) - wake_up(&dp->wait); - - spin_unlock(&s->lock); -} - -static loff_t -au1550_llseek(struct file *file, loff_t offset, int origin) -{ - return -ESPIPE; -} - - -static int -au1550_open_mixdev(struct inode *inode, struct file *file) -{ - mutex_lock(&au1550_ac97_mutex); - file->private_data = &au1550_state; - mutex_unlock(&au1550_ac97_mutex); - return 0; -} - -static int -au1550_release_mixdev(struct inode *inode, struct file *file) -{ - return 0; -} - -static int -mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, - unsigned long arg) -{ - return codec->mixer_ioctl(codec, cmd, arg); -} - -static long -au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct au1550_state *s = file->private_data; - struct ac97_codec *codec = s->codec; - int ret; - - mutex_lock(&au1550_ac97_mutex); - ret = mixdev_ioctl(codec, cmd, arg); - mutex_unlock(&au1550_ac97_mutex); - - return ret; -} - -static /*const */ struct file_operations au1550_mixer_fops = { - .owner = THIS_MODULE, - .llseek = au1550_llseek, - .unlocked_ioctl = au1550_ioctl_mixdev, - .open = au1550_open_mixdev, - .release = au1550_release_mixdev, -}; - -static int -drain_dac(struct au1550_state *s, int nonblock) -{ - unsigned long flags; - int count, tmo; - - if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped) - return 0; - - for (;;) { - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= s->dma_dac.fragsize) - break; - if (signal_pending(current)) - break; - if (nonblock) - return -EBUSY; - tmo = 1000 * count / (s->no_vra ? - 48000 : s->dma_dac.sample_rate); - tmo /= s->dma_dac.dma_bytes_per_sample; - au1550_delay(tmo); - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -static inline u8 S16_TO_U8(s16 ch) -{ - return (u8) (ch >> 8) + 0x80; -} -static inline s16 U8_TO_S16(u8 ch) -{ - return (s16) (ch - 0x80) << 8; -} - -/* - * Translates user samples to dma buffer suitable for AC'97 DAC data: - * If mono, copy left channel to right channel in dma buffer. - * If 8 bit samples, cvt to 16-bit before writing to dma buffer. - * If interpolating (no VRA), duplicate every audio frame src_factor times. - */ -static int -translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf, - int dmacount) -{ - int sample, i; - int interp_bytes_per_sample; - int num_samples; - int mono = (db->num_channels == 1); - char usersample[12]; - s16 ch, dmasample[6]; - - if (db->sample_size == 16 && !mono && db->src_factor == 1) { - /* no translation necessary, just copy - */ - if (copy_from_user(dmabuf, userbuf, dmacount)) - return -EFAULT; - return dmacount; - } - - interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor; - num_samples = dmacount / interp_bytes_per_sample; - - for (sample = 0; sample < num_samples; sample++) { - if (copy_from_user(usersample, userbuf, - db->user_bytes_per_sample)) { - return -EFAULT; - } - - for (i = 0; i < db->num_channels; i++) { - if (db->sample_size == 8) - ch = U8_TO_S16(usersample[i]); - else - ch = *((s16 *) (&usersample[i * 2])); - dmasample[i] = ch; - if (mono) - dmasample[i + 1] = ch; /* right channel */ - } - - /* duplicate every audio frame src_factor times - */ - for (i = 0; i < db->src_factor; i++) - memcpy(dmabuf, dmasample, db->dma_bytes_per_sample); - - userbuf += db->user_bytes_per_sample; - dmabuf += interp_bytes_per_sample; - } - - return num_samples * interp_bytes_per_sample; -} - -/* - * Translates AC'97 ADC samples to user buffer: - * If mono, send only left channel to user buffer. - * If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer. - * If decimating (no VRA), skip over src_factor audio frames. - */ -static int -translate_to_user(struct dmabuf *db, char* userbuf, char* dmabuf, - int dmacount) -{ - int sample, i; - int interp_bytes_per_sample; - int num_samples; - int mono = (db->num_channels == 1); - char usersample[12]; - - if (db->sample_size == 16 && !mono && db->src_factor == 1) { - /* no translation necessary, just copy - */ - if (copy_to_user(userbuf, dmabuf, dmacount)) - return -EFAULT; - return dmacount; - } - - interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor; - num_samples = dmacount / interp_bytes_per_sample; - - for (sample = 0; sample < num_samples; sample++) { - for (i = 0; i < db->num_channels; i++) { - if (db->sample_size == 8) - usersample[i] = - S16_TO_U8(*((s16 *) (&dmabuf[i * 2]))); - else - *((s16 *) (&usersample[i * 2])) = - *((s16 *) (&dmabuf[i * 2])); - } - - if (copy_to_user(userbuf, usersample, - db->user_bytes_per_sample)) { - return -EFAULT; - } - - userbuf += db->user_bytes_per_sample; - dmabuf += interp_bytes_per_sample; - } - - return num_samples * interp_bytes_per_sample; -} - -/* - * Copy audio data to/from user buffer from/to dma buffer, taking care - * that we wrap when reading/writing the dma buffer. Returns actual byte - * count written to or read from the dma buffer. - */ -static int -copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user) -{ - char *bufptr = to_user ? db->nextOut : db->nextIn; - char *bufend = db->rawbuf + db->dmasize; - int cnt, ret; - - if (bufptr + count > bufend) { - int partial = (int) (bufend - bufptr); - if (to_user) { - if ((cnt = translate_to_user(db, userbuf, - bufptr, partial)) < 0) - return cnt; - ret = cnt; - if ((cnt = translate_to_user(db, userbuf + partial, - db->rawbuf, - count - partial)) < 0) - return cnt; - ret += cnt; - } else { - if ((cnt = translate_from_user(db, bufptr, userbuf, - partial)) < 0) - return cnt; - ret = cnt; - if ((cnt = translate_from_user(db, db->rawbuf, - userbuf + partial, - count - partial)) < 0) - return cnt; - ret += cnt; - } - } else { - if (to_user) - ret = translate_to_user(db, userbuf, bufptr, count); - else - ret = translate_from_user(db, bufptr, userbuf, count); - } - - return ret; -} - - -static ssize_t -au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -{ - struct au1550_state *s = file->private_data; - struct dmabuf *db = &s->dma_adc; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - int cnt, usercnt, avail; - - if (db->mapped) - return -ENXIO; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - - count *= db->cnt_factor; - - mutex_lock(&s->sem); - add_wait_queue(&db->wait, &wait); - - while (count > 0) { - /* wait for samples in ADC dma buffer - */ - do { - spin_lock_irqsave(&s->lock, flags); - if (db->stopped) - start_adc(s); - avail = db->count; - if (avail <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (avail <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->sem); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out2; - } - mutex_lock(&s->sem); - } - } while (avail <= 0); - - /* copy from nextOut to user - */ - if ((cnt = copy_dmabuf_user(db, buffer, - count > avail ? - avail : count, 1)) < 0) { - if (!ret) - ret = -EFAULT; - goto out; - } - - spin_lock_irqsave(&s->lock, flags); - db->count -= cnt; - db->nextOut += cnt; - if (db->nextOut >= db->rawbuf + db->dmasize) - db->nextOut -= db->dmasize; - spin_unlock_irqrestore(&s->lock, flags); - - count -= cnt; - usercnt = cnt / db->cnt_factor; - buffer += usercnt; - ret += usercnt; - } /* while (count > 0) */ - -out: - mutex_unlock(&s->sem); -out2: - remove_wait_queue(&db->wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -static ssize_t -au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) -{ - struct au1550_state *s = file->private_data; - struct dmabuf *db = &s->dma_dac; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - int cnt, usercnt, avail; - - pr_debug("write: count=%d\n", count); - - if (db->mapped) - return -ENXIO; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - - count *= db->cnt_factor; - - mutex_lock(&s->sem); - add_wait_queue(&db->wait, &wait); - - while (count > 0) { - /* wait for space in playback buffer - */ - do { - spin_lock_irqsave(&s->lock, flags); - avail = (int) db->dmasize - db->count; - if (avail <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (avail <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->sem); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out2; - } - mutex_lock(&s->sem); - } - } while (avail <= 0); - - /* copy from user to nextIn - */ - if ((cnt = copy_dmabuf_user(db, (char *) buffer, - count > avail ? - avail : count, 0)) < 0) { - if (!ret) - ret = -EFAULT; - goto out; - } - - spin_lock_irqsave(&s->lock, flags); - db->count += cnt; - db->nextIn += cnt; - if (db->nextIn >= db->rawbuf + db->dmasize) - db->nextIn -= db->dmasize; - - /* If the data is available, we want to keep two buffers - * on the dma queue. If the queue count reaches zero, - * we know the dma has stopped. - */ - while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) { - if (au1xxx_dbdma_put_source(db->dmanr, - virt_to_phys(db->nextOut), db->fragsize, - DDMA_FLAGS_IE) == 0) { - err("qcount < 2 and no ring room!"); - } - db->nextOut += db->fragsize; - if (db->nextOut >= db->rawbuf + db->dmasize) - db->nextOut -= db->dmasize; - db->total_bytes += db->dma_fragsize; - if (db->dma_qcount == 0) - start_dac(s); - db->dma_qcount++; - } - spin_unlock_irqrestore(&s->lock, flags); - - count -= cnt; - usercnt = cnt / db->cnt_factor; - buffer += usercnt; - ret += usercnt; - } /* while (count > 0) */ - -out: - mutex_unlock(&s->sem); -out2: - remove_wait_queue(&db->wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - - -/* No kernel lock - we have our own spinlock */ -static unsigned int -au1550_poll(struct file *file, struct poll_table_struct *wait) -{ - struct au1550_state *s = file->private_data; - unsigned long flags; - unsigned int mask = 0; - - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac.ready) - return 0; - poll_wait(file, &s->dma_dac.wait, wait); - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - - spin_lock_irqsave(&s->lock, flags); - - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= - (signed)s->dma_dac.dma_fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed) s->dma_dac.dmasize >= - s->dma_dac.count + (signed)s->dma_dac.dma_fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int -au1550_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct au1550_state *s = file->private_data; - struct dmabuf *db; - unsigned long size; - int ret = 0; - - mutex_lock(&au1550_ac97_mutex); - mutex_lock(&s->sem); - if (vma->vm_flags & VM_WRITE) - db = &s->dma_dac; - else if (vma->vm_flags & VM_READ) - db = &s->dma_adc; - else { - ret = -EINVAL; - goto out; - } - if (vma->vm_pgoff != 0) { - ret = -EINVAL; - goto out; - } - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) { - ret = -EINVAL; - goto out; - } - if (remap_pfn_range(vma, vma->vm_start, page_to_pfn(virt_to_page(db->rawbuf)), - size, vma->vm_page_prot)) { - ret = -EAGAIN; - goto out; - } - vma->vm_flags &= ~VM_IO; - db->mapped = 1; -out: - mutex_unlock(&s->sem); - mutex_unlock(&au1550_ac97_mutex); - return ret; -} - -#ifdef DEBUG -static struct ioctl_str_t { - unsigned int cmd; - const char *str; -} ioctl_str[] = { - {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"}, - {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"}, - {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"}, - {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"}, - {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"}, - {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"}, - {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"}, - {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"}, - {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"}, - {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"}, - {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"}, - {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"}, - {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"}, - {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"}, - {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"}, - {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"}, - {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"}, - {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"}, - {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"}, - {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"}, - {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"}, - {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"}, - {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"}, - {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"}, - {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"}, - {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"}, - {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"}, - {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"}, - {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"}, - {OSS_GETVERSION, "OSS_GETVERSION"}, - {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"}, - {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"}, - {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"}, - {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"} -}; -#endif - -static int -dma_count_done(struct dmabuf *db) -{ - if (db->stopped) - return 0; - - return db->dma_fragsize - au1xxx_get_dma_residue(db->dmanr); -} - - -static int -au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct au1550_state *s = file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val, mapped, ret, diff; - - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - -#ifdef DEBUG - for (count = 0; count < ARRAY_SIZE(ioctl_str); count++) { - if (ioctl_str[count].cmd == cmd) - break; - } - if (count < ARRAY_SIZE(ioctl_str)) - pr_debug("ioctl %s, arg=0x%lxn", ioctl_str[count].str, arg); - else - pr_debug("ioctl 0x%x unknown, arg=0x%lx\n", cmd, arg); -#endif - - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, (int *) arg); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac(s, file->f_flags & O_NONBLOCK); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | - DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(); - s->dma_dac.count = s->dma_dac.total_bytes = 0; - s->dma_dac.nextIn = s->dma_dac.nextOut = - s->dma_dac.rawbuf; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(); - s->dma_adc.count = s->dma_adc.total_bytes = 0; - s->dma_adc.nextIn = s->dma_adc.nextOut = - s->dma_adc.rawbuf; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - set_adc_rate(s, val); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - set_dac_rate(s, val); - } - if (s->open_mode & FMODE_READ) - if ((ret = prog_dmabuf_adc(s))) - return ret; - if (s->open_mode & FMODE_WRITE) - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return put_user((file->f_mode & FMODE_READ) ? - s->dma_adc.sample_rate : - s->dma_dac.sample_rate, - (int *)arg); - - case SNDCTL_DSP_STEREO: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.num_channels = val ? 2 : 1; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.num_channels = val ? 2 : 1; - if (s->codec_ext_caps & AC97_EXT_DACS) { - /* disable surround and center/lfe in AC'97 - */ - u16 ext_stat = rdcodec(s->codec, - AC97_EXTENDED_STATUS); - wrcodec(s->codec, AC97_EXTENDED_STATUS, - ext_stat | (AC97_EXTSTAT_PRI | - AC97_EXTSTAT_PRJ | - AC97_EXTSTAT_PRK)); - } - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != 0) { - if (file->f_mode & FMODE_READ) { - if (val < 0 || val > 2) - return -EINVAL; - stop_adc(s); - s->dma_adc.num_channels = val; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - switch (val) { - case 1: - case 2: - break; - case 3: - case 5: - return -EINVAL; - case 4: - if (!(s->codec_ext_caps & - AC97_EXTID_SDAC)) - return -EINVAL; - break; - case 6: - if ((s->codec_ext_caps & - AC97_EXT_DACS) != AC97_EXT_DACS) - return -EINVAL; - break; - default: - return -EINVAL; - } - - stop_dac(s); - if (val <= 2 && - (s->codec_ext_caps & AC97_EXT_DACS)) { - /* disable surround and center/lfe - * channels in AC'97 - */ - u16 ext_stat = - rdcodec(s->codec, - AC97_EXTENDED_STATUS); - wrcodec(s->codec, - AC97_EXTENDED_STATUS, - ext_stat | (AC97_EXTSTAT_PRI | - AC97_EXTSTAT_PRJ | - AC97_EXTSTAT_PRK)); - } else if (val >= 4) { - /* enable surround, center/lfe - * channels in AC'97 - */ - u16 ext_stat = - rdcodec(s->codec, - AC97_EXTENDED_STATUS); - ext_stat &= ~AC97_EXTSTAT_PRJ; - if (val == 6) - ext_stat &= - ~(AC97_EXTSTAT_PRI | - AC97_EXTSTAT_PRK); - wrcodec(s->codec, - AC97_EXTENDED_STATUS, - ext_stat); - } - - s->dma_dac.num_channels = val; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } - return put_user(val, (int *) arg); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - if (val == AFMT_S16_LE) - s->dma_adc.sample_size = 16; - else { - val = AFMT_U8; - s->dma_adc.sample_size = 8; - } - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - if (val == AFMT_S16_LE) - s->dma_dac.sample_size = 16; - else { - val = AFMT_U8; - s->dma_dac.sample_size = 8; - } - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } else { - if (file->f_mode & FMODE_READ) - val = (s->dma_adc.sample_size == 16) ? - AFMT_S16_LE : AFMT_U8; - else - val = (s->dma_dac.sample_size == 16) ? - AFMT_S16_LE : AFMT_U8; - } - return put_user(val, (int *) arg); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ && !s->dma_adc.stopped) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped) - val |= PCM_ENABLE_OUTPUT; - spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *) arg); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - spin_lock_irqsave(&s->lock, flags); - start_adc(s); - spin_unlock_irqrestore(&s->lock, flags); - } else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - spin_lock_irqsave(&s->lock, flags); - start_dac(s); - spin_unlock_irqrestore(&s->lock, flags); - } else - stop_dac(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - abinfo.fragsize = s->dma_dac.fragsize; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - count -= dma_count_done(&s->dma_dac); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - abinfo.bytes = (s->dma_dac.dmasize - count) / - s->dma_dac.cnt_factor; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - pr_debug("ioctl SNDCTL_DSP_GETOSPACE: bytes=%d, fragments=%d\n", abinfo.bytes, abinfo.fragments); - return copy_to_user((void *) arg, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - abinfo.fragsize = s->dma_adc.fragsize; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_adc.count; - count += dma_count_done(&s->dma_adc); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - abinfo.bytes = count / s->dma_adc.cnt_factor; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - return copy_to_user((void *) arg, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - spin_lock(&file->f_lock); - file->f_flags |= O_NONBLOCK; - spin_unlock(&file->f_lock); - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - count -= dma_count_done(&s->dma_dac); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - count /= s->dma_dac.cnt_factor; - return put_user(count, (int *) arg); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cinfo.bytes = s->dma_adc.total_bytes; - count = s->dma_adc.count; - if (!s->dma_adc.stopped) { - diff = dma_count_done(&s->dma_adc); - count += diff; - cinfo.bytes += diff; - cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) + diff - - virt_to_phys(s->dma_adc.rawbuf); - } else - cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) - - virt_to_phys(s->dma_adc.rawbuf); - if (s->dma_adc.mapped) - s->dma_adc.count &= (s->dma_adc.dma_fragsize-1); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_adc.fragshift; - return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cinfo.bytes = s->dma_dac.total_bytes; - count = s->dma_dac.count; - if (!s->dma_dac.stopped) { - diff = dma_count_done(&s->dma_dac); - count -= diff; - cinfo.bytes += diff; - cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff - - virt_to_phys(s->dma_dac.rawbuf); - } else - cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) - - virt_to_phys(s->dma_dac.rawbuf); - if (s->dma_dac.mapped) - s->dma_dac.count &= (s->dma_dac.dma_fragsize-1); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac.fragshift; - return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) - return put_user(s->dma_dac.fragsize, (int *) arg); - else - return put_user(s->dma_adc.fragsize, (int *) arg); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) - return -EINVAL; - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.subdivision = val; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.subdivision = val; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? - s->dma_adc.sample_rate : - s->dma_dac.sample_rate, - (int *)arg); - - case SOUND_PCM_READ_CHANNELS: - if (file->f_mode & FMODE_READ) - return put_user(s->dma_adc.num_channels, (int *)arg); - else - return put_user(s->dma_dac.num_channels, (int *)arg); - - case SOUND_PCM_READ_BITS: - if (file->f_mode & FMODE_READ) - return put_user(s->dma_adc.sample_size, (int *)arg); - else - return put_user(s->dma_dac.sample_size, (int *)arg); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - } - - return mixdev_ioctl(s->codec, cmd, arg); -} - -static long -au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int ret; - - mutex_lock(&au1550_ac97_mutex); - ret = au1550_ioctl(file, cmd, arg); - mutex_unlock(&au1550_ac97_mutex); - - return ret; -} - -static int -au1550_open(struct inode *inode, struct file *file) -{ - int minor = MINOR(inode->i_rdev); - DECLARE_WAITQUEUE(wait, current); - struct au1550_state *s = &au1550_state; - int ret; - -#ifdef DEBUG - if (file->f_flags & O_NONBLOCK) - pr_debug("open: non-blocking\n"); - else - pr_debug("open: blocking\n"); -#endif - - file->private_data = s; - mutex_lock(&au1550_ac97_mutex); - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - ret = -EBUSY; - if (file->f_flags & O_NONBLOCK) - goto out; - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - ret = -ERESTARTSYS; - if (signal_pending(current)) - goto out2; - mutex_lock(&s->open_mutex); - } - - stop_dac(s); - stop_adc(s); - - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = - s->dma_adc.subdivision = s->dma_adc.total_bytes = 0; - s->dma_adc.num_channels = 1; - s->dma_adc.sample_size = 8; - set_adc_rate(s, 8000); - if ((minor & 0xf) == SND_DEV_DSP16) - s->dma_adc.sample_size = 16; - } - - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = - s->dma_dac.subdivision = s->dma_dac.total_bytes = 0; - s->dma_dac.num_channels = 1; - s->dma_dac.sample_size = 8; - set_dac_rate(s, 8000); - if ((minor & 0xf) == SND_DEV_DSP16) - s->dma_dac.sample_size = 16; - } - - if (file->f_mode & FMODE_READ) { - if ((ret = prog_dmabuf_adc(s))) - goto out; - } - if (file->f_mode & FMODE_WRITE) { - if ((ret = prog_dmabuf_dac(s))) - goto out; - } - - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - mutex_init(&s->sem); - ret = 0; -out: - mutex_unlock(&s->open_mutex); -out2: - mutex_unlock(&au1550_ac97_mutex); - return ret; -} - -static int -au1550_release(struct inode *inode, struct file *file) -{ - struct au1550_state *s = file->private_data; - - mutex_lock(&au1550_ac97_mutex); - - if (file->f_mode & FMODE_WRITE) { - mutex_unlock(&au1550_ac97_mutex); - drain_dac(s, file->f_flags & O_NONBLOCK); - mutex_lock(&au1550_ac97_mutex); - } - - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - kfree(s->dma_dac.rawbuf); - s->dma_dac.rawbuf = NULL; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - kfree(s->dma_adc.rawbuf); - s->dma_adc.rawbuf = NULL; - } - s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - mutex_unlock(&au1550_ac97_mutex); - return 0; -} - -static /*const */ struct file_operations au1550_audio_fops = { - .owner = THIS_MODULE, - .llseek = au1550_llseek, - .read = au1550_read, - .write = au1550_write, - .poll = au1550_poll, - .unlocked_ioctl = au1550_unlocked_ioctl, - .mmap = au1550_mmap, - .open = au1550_open, - .release = au1550_release, -}; - -MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com"); -MODULE_DESCRIPTION("Au1550 AC97 Audio Driver"); -MODULE_LICENSE("GPL"); - - -static int __devinit -au1550_probe(void) -{ - struct au1550_state *s = &au1550_state; - int val; - - memset(s, 0, sizeof(struct au1550_state)); - - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - mutex_init(&s->open_mutex); - spin_lock_init(&s->lock); - - s->codec = ac97_alloc_codec(); - if(s->codec == NULL) { - err("Out of memory"); - return -1; - } - s->codec->private_data = s; - s->codec->id = 0; - s->codec->codec_read = rdcodec; - s->codec->codec_write = wrcodec; - s->codec->codec_wait = waitcodec; - - if (!request_mem_region(CPHYSADDR(AC97_PSC_SEL), - 0x30, "Au1550 AC97")) { - err("AC'97 ports in use"); - } - - /* Allocate the DMA Channels - */ - if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_MEM_CHAN, - DBDMA_AC97_TX_CHAN, dac_dma_interrupt, (void *)s)) == 0) { - err("Can't get DAC DMA"); - goto err_dma1; - } - au1xxx_dbdma_set_devwidth(s->dma_dac.dmanr, 16); - if (au1xxx_dbdma_ring_alloc(s->dma_dac.dmanr, - NUM_DBDMA_DESCRIPTORS) == 0) { - err("Can't get DAC DMA descriptors"); - goto err_dma1; - } - - if ((s->dma_adc.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_AC97_RX_CHAN, - DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) { - err("Can't get ADC DMA"); - goto err_dma2; - } - au1xxx_dbdma_set_devwidth(s->dma_adc.dmanr, 16); - if (au1xxx_dbdma_ring_alloc(s->dma_adc.dmanr, - NUM_DBDMA_DESCRIPTORS) == 0) { - err("Can't get ADC DMA descriptors"); - goto err_dma2; - } - - pr_info("DAC: DMA%d, ADC: DMA%d", DBDMA_AC97_TX_CHAN, DBDMA_AC97_RX_CHAN); - - /* register devices */ - - if ((s->dev_audio = register_sound_dsp(&au1550_audio_fops, -1)) < 0) - goto err_dev1; - if ((s->codec->dev_mixer = - register_sound_mixer(&au1550_mixer_fops, -1)) < 0) - goto err_dev2; - - /* The GPIO for the appropriate PSC was configured by the - * board specific start up. - * - * configure PSC for AC'97 - */ - au_writel(0, AC97_PSC_CTRL); /* Disable PSC */ - au_sync(); - au_writel((PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE), AC97_PSC_SEL); - au_sync(); - - /* cold reset the AC'97 - */ - au_writel(PSC_AC97RST_RST, PSC_AC97RST); - au_sync(); - au1550_delay(10); - au_writel(0, PSC_AC97RST); - au_sync(); - - /* need to delay around 500msec(bleech) to give - some CODECs enough time to wakeup */ - au1550_delay(500); - - /* warm reset the AC'97 to start the bitclk - */ - au_writel(PSC_AC97RST_SNC, PSC_AC97RST); - au_sync(); - udelay(100); - au_writel(0, PSC_AC97RST); - au_sync(); - - /* Enable PSC - */ - au_writel(PSC_CTRL_ENABLE, AC97_PSC_CTRL); - au_sync(); - - /* Wait for PSC ready. - */ - do { - val = au_readl(PSC_AC97STAT); - au_sync(); - } while ((val & PSC_AC97STAT_SR) == 0); - - /* Configure AC97 controller. - * Deep FIFO, 16-bit sample, DMA, make sure DMA matches fifo size. - */ - val = PSC_AC97CFG_SET_LEN(16); - val |= PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8; - - /* Enable device so we can at least - * talk over the AC-link. - */ - au_writel(val, PSC_AC97CFG); - au_writel(PSC_AC97MSK_ALLMASK, PSC_AC97MSK); - au_sync(); - val |= PSC_AC97CFG_DE_ENABLE; - au_writel(val, PSC_AC97CFG); - au_sync(); - - /* Wait for Device ready. - */ - do { - val = au_readl(PSC_AC97STAT); - au_sync(); - } while ((val & PSC_AC97STAT_DR) == 0); - - /* codec init */ - if (!ac97_probe_codec(s->codec)) - goto err_dev3; - - s->codec_base_caps = rdcodec(s->codec, AC97_RESET); - s->codec_ext_caps = rdcodec(s->codec, AC97_EXTENDED_ID); - pr_info("AC'97 Base/Extended ID = %04x/%04x", - s->codec_base_caps, s->codec_ext_caps); - - if (!(s->codec_ext_caps & AC97_EXTID_VRA)) { - /* codec does not support VRA - */ - s->no_vra = 1; - } else if (!vra) { - /* Boot option says disable VRA - */ - u16 ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS); - wrcodec(s->codec, AC97_EXTENDED_STATUS, - ac97_extstat & ~AC97_EXTSTAT_VRA); - s->no_vra = 1; - } - if (s->no_vra) - pr_info("no VRA, interpolating and decimating"); - - /* set mic to be the recording source */ - val = SOUND_MASK_MIC; - mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_RECSRC, - (unsigned long) &val); - - return 0; - - err_dev3: - unregister_sound_mixer(s->codec->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - au1xxx_dbdma_chan_free(s->dma_adc.dmanr); - err_dma2: - au1xxx_dbdma_chan_free(s->dma_dac.dmanr); - err_dma1: - release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30); - - ac97_release_codec(s->codec); - return -1; -} - -static void __devinit -au1550_remove(void) -{ - struct au1550_state *s = &au1550_state; - - if (!s) - return; - synchronize_irq(); - au1xxx_dbdma_chan_free(s->dma_adc.dmanr); - au1xxx_dbdma_chan_free(s->dma_dac.dmanr); - release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->codec->dev_mixer); - ac97_release_codec(s->codec); -} - -static int __init -init_au1550(void) -{ - return au1550_probe(); -} - -static void __exit -cleanup_au1550(void) -{ - au1550_remove(); -} - -module_init(init_au1550); -module_exit(cleanup_au1550); - -#ifndef MODULE - -static int __init -au1550_setup(char *options) -{ - char *this_opt; - - if (!options || !*options) - return 0; - - while ((this_opt = strsep(&options, ","))) { - if (!*this_opt) - continue; - if (!strncmp(this_opt, "vra", 3)) { - vra = 1; - } - } - - return 1; -} - -__setup("au1550_audio=", au1550_setup); - -#endif /* MODULE */ diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 389cd793166..e90d103e177 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -534,6 +534,14 @@ config SND_ES1968_INPUT If you say N the buttons will directly control the master volume. It is recommended to say Y. +config SND_ES1968_RADIO + bool "Enable TEA5757 radio tuner support for es1968" + depends on SND_ES1968 + depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_ES1968 + help + Say Y here to include support for TEA5757 radio tuner integrated on + some MediaForte cards (e.g. SF64-PCE2). + config SND_FM801 tristate "ForteMedia FM801" select SND_OPL3_LIB @@ -552,13 +560,13 @@ config SND_FM801_TEA575X_BOOL depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801 help Say Y here to include support for soundcards based on the ForteMedia - FM801 chip with a TEA5757 tuner connected to GPIO1-3 pins (Media - Forte SF256-PCS-02) into the snd-fm801 driver. + FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and + SF64-PCR) into the snd-fm801 driver. -config SND_FM801_TEA575X +config SND_TEA575X tristate - depends on SND_FM801_TEA575X_BOOL - default SND_FM801 + depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO + default SND_FM801 || SND_ES1968 source "sound/pci/hda/Kconfig" @@ -658,6 +666,15 @@ config SND_KORG1212 To compile this driver as a module, choose M here: the module will be called snd-korg1212. +config SND_LOLA + tristate "Digigram Lola" + select SND_PCM + help + Say Y to include support for Digigram Lola boards. + + To compile this driver as a module, choose M here: the module + will be called snd-lola. + config SND_LX6464ES tristate "Digigram LX6464ES" select SND_PCM diff --git a/sound/pci/Makefile b/sound/pci/Makefile index 9cf4348ec13..54fe325e3aa 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_SND) += \ ca0106/ \ cs46xx/ \ cs5535audio/ \ + lola/ \ lx6464es/ \ echoaudio/ \ emu10k1/ \ diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index f8ccc9677c6..2ca6f4f85b4 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -42,10 +42,29 @@ #include <sound/tlv.h> #include <sound/hwdep.h> + MODULE_LICENSE("GPL"); MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>"); MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); +#if defined CONFIG_SND_DEBUG +/* copied from pcm_lib.c, hope later patch will make that version public +and this copy can be removed */ +static void pcm_debug_name(struct snd_pcm_substream *substream, + char *name, size_t len) +{ + snprintf(name, len, "pcmC%dD%d%c:%d", + substream->pcm->card->number, + substream->pcm->device, + substream->stream ? 'c' : 'p', + substream->number); +} +#define DEBUG_NAME(substream, name) char name[16]; pcm_debug_name(substream, name, sizeof(name)) +#else +#define pcm_debug_name(s, n, l) do { } while (0) +#define DEBUG_NAME(name, substream) do { } while (0) +#endif + #if defined CONFIG_SND_DEBUG_VERBOSE /** * snd_printddd - very verbose debug printk @@ -58,7 +77,7 @@ MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); #define snd_printddd(format, args...) \ __snd_printk(3, __FILE__, __LINE__, format, ##args) #else -#define snd_printddd(format, args...) do { } while (0) +#define snd_printddd(format, args...) do { } while (0) #endif static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */ @@ -101,13 +120,6 @@ static int adapter_fs = DEFAULT_SAMPLERATE; #define PERIOD_BYTES_MIN 2048 #define BUFFER_BYTES_MAX (512 * 1024) -/* convert stream to character */ -#define SCHR(s) ((s == SNDRV_PCM_STREAM_PLAYBACK) ? 'P' : 'C') - -/*#define TIMER_MILLISECONDS 20 -#define FORCE_TIMER_JIFFIES ((TIMER_MILLISECONDS * HZ + 999)/1000) -*/ - #define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7) struct clk_source { @@ -136,7 +148,7 @@ struct snd_card_asihpi { u32 h_mixer; struct clk_cache cc; - u16 support_mmap; + u16 can_dma; u16 support_grouping; u16 support_mrx; u16 update_interval_frames; @@ -155,6 +167,7 @@ struct snd_card_asihpi_pcm { unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */ unsigned int pcm_buf_dma_ofs; /* DMA R/W offset in buffer */ unsigned int pcm_buf_elapsed_dma_ofs; /* DMA R/W offset in buffer */ + unsigned int drained_count; struct snd_pcm_substream *substream; u32 h_stream; struct hpi_format format; @@ -288,19 +301,26 @@ static u16 handle_error(u16 err, int line, char *filename) #define hpi_handle_error(x) handle_error(x, __LINE__, __FILE__) /***************************** GENERAL PCM ****************/ -static void print_hwparams(struct snd_pcm_hw_params *p) + +static void print_hwparams(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *p) { - snd_printd("HWPARAMS \n"); - snd_printd("samplerate %d \n", params_rate(p)); - snd_printd("Channels %d \n", params_channels(p)); - snd_printd("Format %d \n", params_format(p)); - snd_printd("subformat %d \n", params_subformat(p)); - snd_printd("Buffer bytes %d \n", params_buffer_bytes(p)); - snd_printd("Period bytes %d \n", params_period_bytes(p)); - snd_printd("access %d \n", params_access(p)); - snd_printd("period_size %d \n", params_period_size(p)); - snd_printd("periods %d \n", params_periods(p)); - snd_printd("buffer_size %d \n", params_buffer_size(p)); + DEBUG_NAME(substream, name); + snd_printd("%s HWPARAMS\n", name); + snd_printd(" samplerate %d Hz\n", params_rate(p)); + snd_printd(" channels %d\n", params_channels(p)); + snd_printd(" format %d\n", params_format(p)); + snd_printd(" subformat %d\n", params_subformat(p)); + snd_printd(" buffer %d B\n", params_buffer_bytes(p)); + snd_printd(" period %d B\n", params_period_bytes(p)); + snd_printd(" access %d\n", params_access(p)); + snd_printd(" period_size %d\n", params_period_size(p)); + snd_printd(" periods %d\n", params_periods(p)); + snd_printd(" buffer_size %d\n", params_buffer_size(p)); + snd_printd(" %d B/s\n", params_rate(p) * + params_channels(p) * + snd_pcm_format_width(params_format(p)) / 8); + } static snd_pcm_format_t hpi_to_alsa_formats[] = { @@ -451,7 +471,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, int width; unsigned int bytes_per_sec; - print_hwparams(params); + print_hwparams(substream, params); err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); if (err < 0) return err; @@ -459,10 +479,6 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, if (err) return err; - snd_printdd("format %d, %d chans, %d_hz\n", - format, params_channels(params), - params_rate(params)); - hpi_handle_error(hpi_format_create(&dpcm->format, params_channels(params), format, params_rate(params), 0, 0)); @@ -477,8 +493,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, } dpcm->hpi_buffer_attached = 0; - if (card->support_mmap) { - + if (card->can_dma) { err = hpi_stream_host_buffer_attach(dpcm->h_stream, params_buffer_bytes(params), runtime->dma_addr); if (err == 0) { @@ -509,8 +524,6 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, dpcm->bytes_per_sec = bytes_per_sec; dpcm->buffer_bytes = params_buffer_bytes(params); dpcm->period_bytes = params_period_bytes(params); - snd_printdd("buffer_bytes=%d, period_bytes=%d, bps=%d\n", - dpcm->buffer_bytes, dpcm->period_bytes, bytes_per_sec); return 0; } @@ -564,9 +577,10 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); struct snd_pcm_substream *s; u16 e; + DEBUG_NAME(substream, name); + + snd_printdd("%s trigger\n", name); - snd_printdd("%c%d trigger\n", - SCHR(substream->stream), substream->number); switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_pcm_group_for_each_entry(s, substream) { @@ -580,8 +594,8 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, if (substream->stream != s->stream) continue; - if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) && - (card->support_mmap)) { + ds->drained_count = 0; + if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* How do I know how much valid data is present * in buffer? Must be at least one period! * Guessing 2 periods, but if @@ -599,9 +613,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, } if (card->support_grouping) { - snd_printdd("\t%c%d group\n", - SCHR(s->stream), - s->number); + snd_printdd("%d group\n", s->number); e = hpi_stream_group_add( dpcm->h_stream, ds->h_stream); @@ -618,7 +630,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, /* start the master stream */ snd_card_asihpi_pcm_timer_start(substream); if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) || - !card->support_mmap) + !card->can_dma) hpi_handle_error(hpi_stream_start(dpcm->h_stream)); break; @@ -636,9 +648,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, s->runtime->status->state = SNDRV_PCM_STATE_SETUP; if (card->support_grouping) { - snd_printdd("\t%c%d group\n", - SCHR(s->stream), - s->number); + snd_printdd("%d group\n", s->number); snd_pcm_trigger_done(s, substream); } else break; @@ -732,9 +742,9 @@ static void snd_card_asihpi_timer_function(unsigned long data) int loops = 0; u16 state; u32 buffer_size, bytes_avail, samples_played, on_card_bytes; + DEBUG_NAME(substream, name); - snd_printdd("%c%d snd_card_asihpi_timer_function\n", - SCHR(substream->stream), substream->number); + snd_printdd("%s snd_card_asihpi_timer_function\n", name); /* find minimum newdata and buffer pos in group */ snd_pcm_group_for_each_entry(s, substream) { @@ -756,6 +766,9 @@ static void snd_card_asihpi_timer_function(unsigned long data) /* number of bytes in on-card buffer */ runtime->delay = on_card_bytes; + if (!card->can_dma) + on_card_bytes = bytes_avail; + if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail; if (state == HPI_STATE_STOPPED) { @@ -763,12 +776,18 @@ static void snd_card_asihpi_timer_function(unsigned long data) (on_card_bytes < ds->pcm_buf_host_rw_ofs)) { hpi_handle_error(hpi_stream_start(ds->h_stream)); snd_printdd("P%d start\n", s->number); + ds->drained_count = 0; } } else if (state == HPI_STATE_DRAINED) { snd_printd(KERN_WARNING "P%d drained\n", s->number); - /*snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN); - continue; */ + ds->drained_count++; + if (ds->drained_count > 2) { + snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN); + continue; + } + } else { + ds->drained_count = 0; } } else pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs; @@ -786,16 +805,18 @@ static void snd_card_asihpi_timer_function(unsigned long data) newdata); } - snd_printdd("hw_ptr x%04lX, appl_ptr x%04lX\n", + snd_printdd("hw_ptr 0x%04lX, appl_ptr 0x%04lX\n", (unsigned long)frames_to_bytes(runtime, runtime->status->hw_ptr), (unsigned long)frames_to_bytes(runtime, runtime->control->appl_ptr)); - snd_printdd("%d %c%d S=%d, rw=%04X, dma=x%04X, left=x%04X," - " aux=x%04X space=x%04X\n", - loops, SCHR(s->stream), s->number, - state, ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, (int)bytes_avail, + snd_printdd("%d S=%d, " + "rw=0x%04X, dma=0x%04X, left=0x%04X, " + "aux=0x%04X space=0x%04X\n", + s->number, state, + ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, + (int)bytes_avail, (int)on_card_bytes, buffer_size-bytes_avail); loops++; } @@ -814,7 +835,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) next_jiffies = max(next_jiffies, 1U); dpcm->timer.expires = jiffies + next_jiffies; - snd_printdd("jif %d buf pos x%04X newdata x%04X xfer x%04X\n", + snd_printdd("jif %d buf pos 0x%04X newdata 0x%04X xfer 0x%04X\n", next_jiffies, pcm_buf_dma_ofs, newdata, xfercount); snd_pcm_group_for_each_entry(s, substream) { @@ -826,30 +847,63 @@ static void snd_card_asihpi_timer_function(unsigned long data) ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs; - if (xfercount && (on_card_bytes <= ds->period_bytes)) { - if (card->support_mmap) { - if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { - snd_printddd("P%d write x%04x\n", + if (xfercount && + /* Limit use of on card fifo for playback */ + ((on_card_bytes <= ds->period_bytes) || + (s->stream == SNDRV_PCM_STREAM_CAPTURE))) + + { + + unsigned int buf_ofs = ds->pcm_buf_host_rw_ofs % ds->buffer_bytes; + unsigned int xfer1, xfer2; + char *pd = &s->runtime->dma_area[buf_ofs]; + + if (card->can_dma) { /* buffer wrap is handled at lower level */ + xfer1 = xfercount; + xfer2 = 0; + } else { + xfer1 = min(xfercount, ds->buffer_bytes - buf_ofs); + xfer2 = xfercount - xfer1; + } + + if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { + snd_printddd("P%d write1 0x%04X 0x%04X\n", + s->number, xfer1, buf_ofs); + hpi_handle_error( + hpi_outstream_write_buf( + ds->h_stream, pd, xfer1, + &ds->format)); + + if (xfer2) { + pd = s->runtime->dma_area; + + snd_printddd("P%d write2 0x%04X 0x%04X\n", s->number, - ds->period_bytes); + xfercount - xfer1, buf_ofs); hpi_handle_error( hpi_outstream_write_buf( - ds->h_stream, - &s->runtime-> - dma_area[0], - xfercount, + ds->h_stream, pd, + xfercount - xfer1, &ds->format)); - } else { - snd_printddd("C%d read x%04x\n", - s->number, - xfercount); + } + } else { + snd_printddd("C%d read1 0x%04x\n", + s->number, xfer1); + hpi_handle_error( + hpi_instream_read_buf( + ds->h_stream, + pd, xfer1)); + if (xfer2) { + pd = s->runtime->dma_area; + snd_printddd("C%d read2 0x%04x\n", + s->number, xfer2); hpi_handle_error( hpi_instream_read_buf( ds->h_stream, - NULL, xfercount)); + pd, xfer2)); } - ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount; - } /* else R/W will be handled by read/write callbacks */ + } + ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount; ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs; snd_pcm_period_elapsed(s); } @@ -863,7 +917,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { - snd_printdd(KERN_INFO "Playback ioctl %d\n", cmd); + snd_printddd(KERN_INFO "P%d ioctl %d\n", substream->number, cmd); return snd_pcm_lib_ioctl(substream, cmd, arg); } @@ -873,7 +927,7 @@ static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream * struct snd_pcm_runtime *runtime = substream->runtime; struct snd_card_asihpi_pcm *dpcm = runtime->private_data; - snd_printdd("playback prepare %d\n", substream->number); + snd_printdd("P%d prepare\n", substream->number); hpi_handle_error(hpi_outstream_reset(dpcm->h_stream)); dpcm->pcm_buf_host_rw_ofs = 0; @@ -890,7 +944,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t ptr; ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes); - snd_printddd("playback_pointer=x%04lx\n", (unsigned long)ptr); + snd_printddd("P%d pointer = 0x%04lx\n", substream->number, (unsigned long)ptr); return ptr; } @@ -986,11 +1040,9 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) SNDRV_PCM_INFO_DOUBLE | SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_PAUSE; - - if (card->support_mmap) - snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID; + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID; if (card->support_grouping) snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START; @@ -998,7 +1050,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) /* struct is copied, so can create initializer dynamically */ runtime->hw = snd_card_asihpi_playback; - if (card->support_mmap) + if (card->can_dma) err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); if (err < 0) @@ -1028,58 +1080,6 @@ static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream) return 0; } -static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream, - int channel, - snd_pcm_uframes_t pos, - void __user *src, - snd_pcm_uframes_t count) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_card_asihpi_pcm *dpcm = runtime->private_data; - unsigned int len; - - len = frames_to_bytes(runtime, count); - - if (copy_from_user(runtime->dma_area, src, len)) - return -EFAULT; - - snd_printddd("playback copy%d %u bytes\n", - substream->number, len); - - hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream, - runtime->dma_area, len, &dpcm->format)); - - dpcm->pcm_buf_host_rw_ofs += len; - - return 0; -} - -static int snd_card_asihpi_playback_silence(struct snd_pcm_substream * - substream, int channel, - snd_pcm_uframes_t pos, - snd_pcm_uframes_t count) -{ - /* Usually writes silence to DMA buffer, which should be overwritten - by real audio later. Our fifos cannot be overwritten, and are not - free-running DMAs. Silence is output on fifo underflow. - This callback is still required to allow the copy callback to be used. - */ - return 0; -} - -static struct snd_pcm_ops snd_card_asihpi_playback_ops = { - .open = snd_card_asihpi_playback_open, - .close = snd_card_asihpi_playback_close, - .ioctl = snd_card_asihpi_playback_ioctl, - .hw_params = snd_card_asihpi_pcm_hw_params, - .hw_free = snd_card_asihpi_hw_free, - .prepare = snd_card_asihpi_playback_prepare, - .trigger = snd_card_asihpi_trigger, - .pointer = snd_card_asihpi_playback_pointer, - .copy = snd_card_asihpi_playback_copy, - .silence = snd_card_asihpi_playback_silence, -}; - static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = { .open = snd_card_asihpi_playback_open, .close = snd_card_asihpi_playback_close, @@ -1211,18 +1211,16 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) snd_card_asihpi_capture_format(card, dpcm->h_stream, &snd_card_asihpi_capture); snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture); - snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED; - - if (card->support_mmap) - snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID; + snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID; if (card->support_grouping) snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START; runtime->hw = snd_card_asihpi_capture; - if (card->support_mmap) + if (card->can_dma) err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); if (err < 0) @@ -1246,28 +1244,6 @@ static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream) return 0; } -static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream, - int channel, snd_pcm_uframes_t pos, - void __user *dst, snd_pcm_uframes_t count) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_card_asihpi_pcm *dpcm = runtime->private_data; - u32 len; - - len = frames_to_bytes(runtime, count); - - snd_printddd("capture copy%d %d bytes\n", substream->number, len); - hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream, - runtime->dma_area, len)); - - dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len; - - if (copy_to_user(dst, runtime->dma_area, len)) - return -EFAULT; - - return 0; -} - static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = { .open = snd_card_asihpi_capture_open, .close = snd_card_asihpi_capture_close, @@ -1279,18 +1255,6 @@ static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = { .pointer = snd_card_asihpi_capture_pointer, }; -static struct snd_pcm_ops snd_card_asihpi_capture_ops = { - .open = snd_card_asihpi_capture_open, - .close = snd_card_asihpi_capture_close, - .ioctl = snd_card_asihpi_capture_ioctl, - .hw_params = snd_card_asihpi_pcm_hw_params, - .hw_free = snd_card_asihpi_hw_free, - .prepare = snd_card_asihpi_capture_prepare, - .trigger = snd_card_asihpi_trigger, - .pointer = snd_card_asihpi_capture_pointer, - .copy = snd_card_asihpi_capture_copy -}; - static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device, int substreams) { @@ -1303,17 +1267,10 @@ static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, if (err < 0) return err; /* pointer to ops struct is stored, dont change ops afterwards! */ - if (asihpi->support_mmap) { snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_asihpi_playback_mmap_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_asihpi_capture_mmap_ops); - } else { - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_card_asihpi_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - &snd_card_asihpi_capture_ops); - } pcm->private_data = asihpi; pcm->info_flags = 0; @@ -1413,14 +1370,16 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, struct hpi_control *hpi_ctl, char *name) { - char *dir = ""; + char *dir; memset(snd_control, 0, sizeof(*snd_control)); snd_control->name = hpi_ctl->name; snd_control->private_value = hpi_ctl->h_control; snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER; snd_control->index = 0; - if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM) + if (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE == HPI_SOURCENODE_CLOCK_SOURCE) + dir = ""; /* clock is neither capture nor playback */ + else if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM) dir = "Capture "; /* On or towards a PCM capture destination*/ else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) && (!hpi_ctl->dst_node_type)) @@ -1433,7 +1392,7 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, dir = "Playback "; /* PCM Playback source, or output node */ if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type) - sprintf(hpi_ctl->name, "%s%d %s%d %s%s", + sprintf(hpi_ctl->name, "%s %d %s %d %s%s", asihpi_src_names[hpi_ctl->src_node_type], hpi_ctl->src_node_index, asihpi_dst_names[hpi_ctl->dst_node_type], @@ -2875,14 +2834,14 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, if (err) asihpi->update_interval_frames = 512; - if (!asihpi->support_mmap) + if (!asihpi->can_dma) asihpi->update_interval_frames *= 2; hpi_handle_error(hpi_instream_open(asihpi->adapter_index, 0, &h_stream)); err = hpi_instream_host_buffer_free(h_stream); - asihpi->support_mmap = (!err); + asihpi->can_dma = (!err); hpi_handle_error(hpi_instream_close(h_stream)); @@ -2894,8 +2853,8 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, asihpi->out_max_chans = 2; } - snd_printk(KERN_INFO "supports mmap:%d grouping:%d mrx:%d\n", - asihpi->support_mmap, + snd_printk(KERN_INFO "has dma:%d, grouping:%d, mrx:%d\n", + asihpi->can_dma, asihpi->support_grouping, asihpi->support_mrx ); @@ -2925,10 +2884,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, by enable_hwdep module param*/ snd_asihpi_hpi_new(asihpi, 0, NULL); - if (asihpi->support_mmap) - strcpy(card->driver, "ASIHPI-MMAP"); - else - strcpy(card->driver, "ASIHPI"); + strcpy(card->driver, "ASIHPI"); sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type); sprintf(card->longname, "%s %i", diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c index 8c8aac4c567..df4aed5295d 100644 --- a/sound/pci/asihpi/hpi6000.c +++ b/sound/pci/asihpi/hpi6000.c @@ -200,8 +200,8 @@ static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata, static void subsys_create_adapter(struct hpi_message *phm, struct hpi_response *phr); -static void subsys_delete_adapter(struct hpi_message *phm, - struct hpi_response *phr); +static void adapter_delete(struct hpi_adapter_obj *pao, + struct hpi_message *phm, struct hpi_response *phr); static void adapter_get_asserts(struct hpi_adapter_obj *pao, struct hpi_message *phm, struct hpi_response *phr); @@ -222,9 +222,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) case HPI_SUBSYS_CREATE_ADAPTER: subsys_create_adapter(phm, phr); break; - case HPI_SUBSYS_DELETE_ADAPTER: - subsys_delete_adapter(phm, phr); - break; default: phr->error = HPI_ERROR_INVALID_FUNC; break; @@ -279,6 +276,10 @@ static void adapter_message(struct hpi_adapter_obj *pao, adapter_get_asserts(pao, phm, phr); break; + case HPI_ADAPTER_DELETE: + adapter_delete(pao, phm, phr); + break; + default: hw_message(pao, phm, phr); break; @@ -333,26 +334,22 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr) { struct hpi_adapter_obj *pao = NULL; - /* subsytem messages get executed by every HPI. */ - /* All other messages are ignored unless the adapter index matches */ - /* an adapter in the HPI */ - /*HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->wObject, phm->wFunction); */ - - /* if Dsp has crashed then do not communicate with it any more */ if (phm->object != HPI_OBJ_SUBSYSTEM) { pao = hpi_find_adapter(phm->adapter_index); if (!pao) { - HPI_DEBUG_LOG(DEBUG, - " %d,%d refused, for another HPI?\n", - phm->object, phm->function); + hpi_init_response(phr, phm->object, phm->function, + HPI_ERROR_BAD_ADAPTER_NUMBER); + HPI_DEBUG_LOG(DEBUG, "invalid adapter index: %d \n", + phm->adapter_index); return; } + /* Don't even try to communicate with crashed DSP */ if (pao->dsp_crashed >= 10) { hpi_init_response(phr, phm->object, phm->function, HPI_ERROR_DSP_HARDWARE); - HPI_DEBUG_LOG(DEBUG, " %d,%d dsp crashed.\n", - phm->object, phm->function); + HPI_DEBUG_LOG(DEBUG, "adapter %d dsp crashed\n", + phm->adapter_index); return; } } @@ -463,15 +460,9 @@ static void subsys_create_adapter(struct hpi_message *phm, phr->error = 0; } -static void subsys_delete_adapter(struct hpi_message *phm, - struct hpi_response *phr) +static void adapter_delete(struct hpi_adapter_obj *pao, + struct hpi_message *phm, struct hpi_response *phr) { - struct hpi_adapter_obj *pao = NULL; - - pao = hpi_find_adapter(phm->obj_index); - if (!pao) - return; - delete_adapter_obj(pao); hpi_delete_adapter(pao); phr->error = 0; diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c index 22e9f08dea6..9d5df54a6b4 100644 --- a/sound/pci/asihpi/hpi6205.c +++ b/sound/pci/asihpi/hpi6205.c @@ -152,8 +152,8 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, static void subsys_create_adapter(struct hpi_message *phm, struct hpi_response *phr); -static void subsys_delete_adapter(struct hpi_message *phm, - struct hpi_response *phr); +static void adapter_delete(struct hpi_adapter_obj *pao, + struct hpi_message *phm, struct hpi_response *phr); static u16 create_adapter_obj(struct hpi_adapter_obj *pao, u32 *pos_error_code); @@ -223,15 +223,13 @@ static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index); /*****************************************************************************/ -static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) +static void subsys_message(struct hpi_adapter_obj *pao, + struct hpi_message *phm, struct hpi_response *phr) { switch (phm->function) { case HPI_SUBSYS_CREATE_ADAPTER: subsys_create_adapter(phm, phr); break; - case HPI_SUBSYS_DELETE_ADAPTER: - subsys_delete_adapter(phm, phr); - break; default: phr->error = HPI_ERROR_INVALID_FUNC; break; @@ -279,6 +277,10 @@ static void adapter_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, struct hpi_response *phr) { switch (phm->function) { + case HPI_ADAPTER_DELETE: + adapter_delete(pao, phm, phr); + break; + default: hw_message(pao, phm, phr); break; @@ -371,36 +373,17 @@ static void instream_message(struct hpi_adapter_obj *pao, /** Entry point to this HPI backend * All calls to the HPI start here */ -void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) +void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm, + struct hpi_response *phr) { - struct hpi_adapter_obj *pao = NULL; - - /* subsytem messages are processed by every HPI. - * All other messages are ignored unless the adapter index matches - * an adapter in the HPI - */ - /* HPI_DEBUG_LOG(DEBUG, "HPI Obj=%d, Func=%d\n", phm->wObject, - phm->wFunction); */ - - /* if Dsp has crashed then do not communicate with it any more */ - if (phm->object != HPI_OBJ_SUBSYSTEM) { - pao = hpi_find_adapter(phm->adapter_index); - if (!pao) { - HPI_DEBUG_LOG(DEBUG, - " %d,%d refused, for another HPI?\n", - phm->object, phm->function); - return; - } - - if ((pao->dsp_crashed >= 10) - && (phm->function != HPI_ADAPTER_DEBUG_READ)) { - /* allow last resort debug read even after crash */ - hpi_init_response(phr, phm->object, phm->function, - HPI_ERROR_DSP_HARDWARE); - HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", - phm->object, phm->function); - return; - } + if (pao && (pao->dsp_crashed >= 10) + && (phm->function != HPI_ADAPTER_DEBUG_READ)) { + /* allow last resort debug read even after crash */ + hpi_init_response(phr, phm->object, phm->function, + HPI_ERROR_DSP_HARDWARE); + HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", phm->object, + phm->function); + return; } /* Init default response */ @@ -412,7 +395,7 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) case HPI_TYPE_MESSAGE: switch (phm->object) { case HPI_OBJ_SUBSYSTEM: - subsys_message(phm, phr); + subsys_message(pao, phm, phr); break; case HPI_OBJ_ADAPTER: @@ -444,6 +427,26 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) } } +void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) +{ + struct hpi_adapter_obj *pao = NULL; + + if (phm->object != HPI_OBJ_SUBSYSTEM) { + /* normal messages must have valid adapter index */ + pao = hpi_find_adapter(phm->adapter_index); + } else { + /* subsys messages don't address an adapter */ + _HPI_6205(NULL, phm, phr); + return; + } + + if (pao) + _HPI_6205(pao, phm, phr); + else + hpi_init_response(phr, phm->object, phm->function, + HPI_ERROR_BAD_ADAPTER_NUMBER); +} + /*****************************************************************************/ /* SUBSYSTEM */ @@ -491,13 +494,11 @@ static void subsys_create_adapter(struct hpi_message *phm, } /** delete an adapter - required by WDM driver */ -static void subsys_delete_adapter(struct hpi_message *phm, - struct hpi_response *phr) +static void adapter_delete(struct hpi_adapter_obj *pao, + struct hpi_message *phm, struct hpi_response *phr) { - struct hpi_adapter_obj *pao; struct hpi_hw_obj *phw; - pao = hpi_find_adapter(phm->obj_index); if (!pao) { phr->error = HPI_ERROR_INVALID_OBJ_INDEX; return; @@ -563,11 +564,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, } err = adapter_boot_load_dsp(pao, pos_error_code); - if (err) + if (err) { + HPI_DEBUG_LOG(ERROR, "DSP code load failed\n"); /* no need to clean up as SubSysCreateAdapter */ /* calls DeleteAdapter on error. */ return err; - + } HPI_DEBUG_LOG(INFO, "load DSP code OK\n"); /* allow boot load even if mem alloc wont work */ @@ -604,6 +606,7 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, control_cache.number_of_controls, interface->control_cache.size_in_bytes, p_control_cache_virtual); + if (!phw->p_cache) err = HPI_ERROR_MEMORY_ALLOC; } @@ -675,16 +678,14 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, } /** Free memory areas allocated by adapter - * this routine is called from SubSysDeleteAdapter, + * this routine is called from AdapterDelete, * and SubSysCreateAdapter if duplicate index */ static void delete_adapter_obj(struct hpi_adapter_obj *pao) { - struct hpi_hw_obj *phw; + struct hpi_hw_obj *phw = pao->priv; int i; - phw = pao->priv; - if (hpios_locked_mem_valid(&phw->h_control_cache)) { hpios_locked_mem_free(&phw->h_control_cache); hpi_free_control_cache(phw->p_cache); @@ -1275,6 +1276,7 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao, case HPI_ADAPTER_FAMILY_ASI(0x6300): boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6400); break; + case HPI_ADAPTER_FAMILY_ASI(0x5500): case HPI_ADAPTER_FAMILY_ASI(0x5600): case HPI_ADAPTER_FAMILY_ASI(0x6500): boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6600); @@ -2059,7 +2061,6 @@ static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us) static void send_dsp_command(struct hpi_hw_obj *phw, int cmd) { struct bus_master_interface *interface = phw->p_interface_buffer; - u32 r; interface->host_cmd = cmd; diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h index 3b9fd115da3..bf5eced76ba 100644 --- a/sound/pci/asihpi/hpi_internal.h +++ b/sound/pci/asihpi/hpi_internal.h @@ -294,7 +294,7 @@ enum HPI_CONTROL_ATTRIBUTES { /* These defines are used to fill in protocol information for an Ethernet packet sent using HMI on CS18102 */ -/** ID supplied by Cirrius for ASI packets. */ +/** ID supplied by Cirrus for ASI packets. */ #define HPI_ETHERNET_PACKET_ID 0x85 /** Simple packet - no special routing required */ #define HPI_ETHERNET_PACKET_V1 0x01 @@ -307,7 +307,7 @@ enum HPI_CONTROL_ATTRIBUTES { /** This packet must make its way to the host across the HPI interface */ #define HPI_ETHERNET_PACKET_HOSTED_VIA_HPI_V1 0x41 -#define HPI_ETHERNET_UDP_PORT (44600) /*!< UDP messaging port */ +#define HPI_ETHERNET_UDP_PORT 44600 /**< HPI UDP service */ /** Default network timeout in milli-seconds. */ #define HPI_ETHERNET_TIMEOUT_MS 500 @@ -397,14 +397,14 @@ enum HPI_FUNCTION_IDS { HPI_SUBSYS_OPEN = HPI_FUNC_ID(SUBSYSTEM, 1), HPI_SUBSYS_GET_VERSION = HPI_FUNC_ID(SUBSYSTEM, 2), HPI_SUBSYS_GET_INFO = HPI_FUNC_ID(SUBSYSTEM, 3), - HPI_SUBSYS_FIND_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 4), + /* HPI_SUBSYS_FIND_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 4), */ HPI_SUBSYS_CREATE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 5), HPI_SUBSYS_CLOSE = HPI_FUNC_ID(SUBSYSTEM, 6), - HPI_SUBSYS_DELETE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 7), + /* HPI_SUBSYS_DELETE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 7), */ HPI_SUBSYS_DRIVER_LOAD = HPI_FUNC_ID(SUBSYSTEM, 8), HPI_SUBSYS_DRIVER_UNLOAD = HPI_FUNC_ID(SUBSYSTEM, 9), - HPI_SUBSYS_READ_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 10), - HPI_SUBSYS_WRITE_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 11), + /* HPI_SUBSYS_READ_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 10), */ + /* HPI_SUBSYS_WRITE_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 11), */ HPI_SUBSYS_GET_NUM_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 12), HPI_SUBSYS_GET_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 13), HPI_SUBSYS_SET_NETWORK_INTERFACE = HPI_FUNC_ID(SUBSYSTEM, 14), @@ -433,7 +433,8 @@ enum HPI_FUNCTION_IDS { HPI_ADAPTER_DEBUG_READ = HPI_FUNC_ID(ADAPTER, 18), HPI_ADAPTER_IRQ_QUERY_AND_CLEAR = HPI_FUNC_ID(ADAPTER, 19), HPI_ADAPTER_IRQ_CALLBACK = HPI_FUNC_ID(ADAPTER, 20), -#define HPI_ADAPTER_FUNCTION_COUNT 20 + HPI_ADAPTER_DELETE = HPI_FUNC_ID(ADAPTER, 21), +#define HPI_ADAPTER_FUNCTION_COUNT 21 HPI_OSTREAM_OPEN = HPI_FUNC_ID(OSTREAM, 1), HPI_OSTREAM_CLOSE = HPI_FUNC_ID(OSTREAM, 2), @@ -1561,8 +1562,6 @@ void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr); u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource, u16 *pw_adapter_index); -u16 hpi_subsys_delete_adapter(u16 adapter_index); - u16 hpi_outstream_host_buffer_get_info(u32 h_outstream, u8 **pp_buffer, struct hpi_hostbuffer_status **pp_status); @@ -1584,9 +1583,7 @@ void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR); /*////////////////////////////////////////////////////////////////////////// */ /* declarations for individual HPI entry points */ -hpi_handler_func HPI_1000; hpi_handler_func HPI_6000; hpi_handler_func HPI_6205; -hpi_handler_func HPI_COMMON; #endif /* _HPI_INTERNAL_H_ */ diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c index 3e9c5c28976..b15a02e91f8 100644 --- a/sound/pci/asihpi/hpicmn.c +++ b/sound/pci/asihpi/hpicmn.c @@ -227,8 +227,9 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC) if (info->control_type) { pC->p_info[info->control_index] = info; cached++; - } else /* dummy cache entry */ + } else { /* dummy cache entry */ pC->p_info[info->control_index] = NULL; + } byte_count += info->size_in32bit_words * 4; @@ -298,7 +299,7 @@ struct pad_ofs_size { unsigned int field_size; }; -static struct pad_ofs_size pad_desc[] = { +static const struct pad_ofs_size pad_desc[] = { HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */ HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */ HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */ @@ -617,6 +618,10 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, } } +/** Allocate control cache. + +\return Cache pointer, or NULL if allocation fails. +*/ struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count, const u32 size_in_bytes, u8 *p_dsp_control_buffer) { @@ -667,7 +672,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) phr->u.s.num_adapters = adapters.gw_num_adapters; break; case HPI_SUBSYS_CREATE_ADAPTER: - case HPI_SUBSYS_DELETE_ADAPTER: break; default: phr->error = HPI_ERROR_INVALID_FUNC; diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h index 590f0b69e65..d53cdf6e535 100644 --- a/sound/pci/asihpi/hpicmn.h +++ b/sound/pci/asihpi/hpicmn.h @@ -60,3 +60,5 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC, struct hpi_message *phm, struct hpi_response *phr); u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr); + +hpi_handler_func HPI_COMMON; diff --git a/sound/pci/asihpi/hpifunc.c b/sound/pci/asihpi/hpifunc.c index c38fc948756..7397b169b89 100644 --- a/sound/pci/asihpi/hpifunc.c +++ b/sound/pci/asihpi/hpifunc.c @@ -105,33 +105,6 @@ u16 hpi_subsys_get_version_ex(u32 *pversion_ex) return hr.error; } -u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource, - u16 *pw_adapter_index) -{ - struct hpi_message hm; - struct hpi_response hr; - - hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, - HPI_SUBSYS_CREATE_ADAPTER); - hm.u.s.resource = *p_resource; - - hpi_send_recv(&hm, &hr); - - *pw_adapter_index = hr.u.s.adapter_index; - return hr.error; -} - -u16 hpi_subsys_delete_adapter(u16 adapter_index) -{ - struct hpi_message hm; - struct hpi_response hr; - hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, - HPI_SUBSYS_DELETE_ADAPTER); - hm.obj_index = adapter_index; - hpi_send_recv(&hm, &hr); - return hr.error; -} - u16 hpi_subsys_get_num_adapters(int *pn_num_adapters) { struct hpi_message hm; diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c index 360028b9abf..7352a5f7b4f 100644 --- a/sound/pci/asihpi/hpimsgx.c +++ b/sound/pci/asihpi/hpimsgx.c @@ -211,24 +211,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr, HPIMSGX__init(phm, phr); break; - case HPI_SUBSYS_DELETE_ADAPTER: - HPIMSGX__cleanup(phm->obj_index, h_owner); - { - struct hpi_message hm; - struct hpi_response hr; - hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, - HPI_ADAPTER_CLOSE); - hm.adapter_index = phm->obj_index; - hw_entry_point(&hm, &hr); - } - if ((phm->obj_index < HPI_MAX_ADAPTERS) - && hpi_entry_points[phm->obj_index]) { - hpi_entry_points[phm->obj_index] (phm, phr); - hpi_entry_points[phm->obj_index] = NULL; - } else - phr->error = HPI_ERROR_INVALID_OBJ_INDEX; - - break; default: /* Must explicitly handle every subsys message in this switch */ hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, @@ -247,6 +229,19 @@ static void adapter_message(struct hpi_message *phm, struct hpi_response *phr, case HPI_ADAPTER_CLOSE: adapter_close(phm, phr); break; + case HPI_ADAPTER_DELETE: + HPIMSGX__cleanup(phm->adapter_index, h_owner); + { + struct hpi_message hm; + struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, + HPI_ADAPTER_CLOSE); + hm.adapter_index = phm->adapter_index; + hw_entry_point(&hm, &hr); + } + hw_entry_point(phm, phr); + break; + default: hw_entry_point(phm, phr); break; diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index cd624f13ff8..d8e7047512f 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -25,6 +25,7 @@ Common Linux HPI ioctl and module probe/remove functions #include "hpidebug.h" #include "hpimsgx.h" #include "hpioctl.h" +#include "hpicmn.h" #include <linux/fs.h> #include <linux/slab.h> @@ -161,26 +162,24 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto out; } - pa = &adapters[hm->h.adapter_index]; + switch (hm->h.function) { + case HPI_SUBSYS_CREATE_ADAPTER: + case HPI_ADAPTER_DELETE: + /* Application must not use these functions! */ + hr->h.size = sizeof(hr->h); + hr->h.error = HPI_ERROR_INVALID_OPERATION; + hr->h.function = hm->h.function; + uncopied_bytes = copy_to_user(puhr, hr, hr->h.size); + if (uncopied_bytes) + err = -EFAULT; + else + err = 0; + goto out; + } + hr->h.size = res_max_size; if (hm->h.object == HPI_OBJ_SUBSYSTEM) { - switch (hm->h.function) { - case HPI_SUBSYS_CREATE_ADAPTER: - case HPI_SUBSYS_DELETE_ADAPTER: - /* Application must not use these functions! */ - hr->h.size = sizeof(hr->h); - hr->h.error = HPI_ERROR_INVALID_OPERATION; - hr->h.function = hm->h.function; - uncopied_bytes = copy_to_user(puhr, hr, hr->h.size); - if (uncopied_bytes) - err = -EFAULT; - else - err = 0; - goto out; - - default: - hpi_send_recv_f(&hm->m0, &hr->r0, file); - } + hpi_send_recv_f(&hm->m0, &hr->r0, file); } else { u16 __user *ptr = NULL; u32 size = 0; @@ -188,8 +187,9 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* -1=no data 0=read from user mem, 1=write to user mem */ int wrflag = -1; u32 adapter = hm->h.adapter_index; + pa = &adapters[adapter]; - if ((hm->h.adapter_index > HPI_MAX_ADAPTERS) || (!pa->type)) { + if ((adapter > HPI_MAX_ADAPTERS) || (!pa->type)) { hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER, HPI_ADAPTER_OPEN, HPI_ERROR_BAD_ADAPTER_NUMBER); @@ -317,7 +317,7 @@ out: int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { - int err, idx, nm; + int idx, nm; unsigned int memlen; struct hpi_message hm; struct hpi_response hr; @@ -351,11 +351,8 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, nm = HPI_MAX_ADAPTER_MEM_SPACES; for (idx = 0; idx < nm; idx++) { - HPI_DEBUG_LOG(INFO, "resource %d %s %08llx-%08llx %04llx\n", - idx, pci_dev->resource[idx].name, - (unsigned long long)pci_resource_start(pci_dev, idx), - (unsigned long long)pci_resource_end(pci_dev, idx), - (unsigned long long)pci_resource_flags(pci_dev, idx)); + HPI_DEBUG_LOG(INFO, "resource %d %pR\n", idx, + &pci_dev->resource[idx]); if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) { memlen = pci_resource_len(pci_dev, idx); @@ -395,17 +392,20 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, adapter.index = hr.u.s.adapter_index; adapter.type = hr.u.s.adapter_type; + + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, + HPI_ADAPTER_OPEN); hm.adapter_index = adapter.index; + hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); - err = hpi_adapter_open(adapter.index); - if (err) + if (hr.error) goto err; adapter.snd_card_asihpi = NULL; /* WARNING can't init mutex in 'adapter' * and then copy it to adapters[] ?!?! */ - adapters[hr.u.s.adapter_index] = adapter; + adapters[adapter.index] = adapter; mutex_init(&adapters[adapter.index].mutex); pci_set_drvdata(pci_dev, &adapters[adapter.index]); @@ -440,10 +440,9 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev) struct hpi_adapter *pa; pa = pci_get_drvdata(pci_dev); - hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, - HPI_SUBSYS_DELETE_ADAPTER); - hm.obj_index = pa->index; - hm.adapter_index = HPI_ADAPTER_INDEX_INVALID; + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, + HPI_ADAPTER_DELETE); + hm.adapter_index = pa->index; hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); /* unmap PCI memory space, mapped during device init. */ diff --git a/sound/pci/au88x0/au8810.h b/sound/pci/au88x0/au8810.h index 5d69c31fe3f..79fbee3845e 100644 --- a/sound/pci/au88x0/au8810.h +++ b/sound/pci/au88x0/au8810.h @@ -4,7 +4,7 @@ #define CHIP_AU8810 -#define CARD_NAME "Aureal Advantage 3D Sound Processor" +#define CARD_NAME "Aureal Advantage" #define CARD_NAME_SHORT "au8810" #define NR_ADB 0x10 diff --git a/sound/pci/au88x0/au8820.h b/sound/pci/au88x0/au8820.h index abbe85e4f7a..cafdb9668a3 100644 --- a/sound/pci/au88x0/au8820.h +++ b/sound/pci/au88x0/au8820.h @@ -11,7 +11,7 @@ #define CHIP_AU8820 -#define CARD_NAME "Aureal Vortex 3D Sound Processor" +#define CARD_NAME "Aureal Vortex" #define CARD_NAME_SHORT "au8820" /* Number of ADB and WT channels */ diff --git a/sound/pci/au88x0/au8830.h b/sound/pci/au88x0/au8830.h index 04ece1b1c21..999b29ab34a 100644 --- a/sound/pci/au88x0/au8830.h +++ b/sound/pci/au88x0/au8830.h @@ -11,7 +11,7 @@ #define CHIP_AU8830 -#define CARD_NAME "Aureal Vortex 2 3D Sound Processor" +#define CARD_NAME "Aureal Vortex 2" #define CARD_NAME_SHORT "au8830" #define NR_ADB 0x20 diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 33f0ba5559a..c5f7ae46afe 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -44,10 +44,10 @@ static struct snd_pcm_hardware snd_vortex_playback_hw_adb = { .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 0x10000, - .period_bytes_min = 0x1, + .period_bytes_min = 0x20, .period_bytes_max = 0x1000, .periods_min = 2, - .periods_max = 32, + .periods_max = 1024, }; #ifndef CHIP_AU8820 @@ -140,6 +140,9 @@ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0) return err; + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 64); + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { #ifndef CHIP_AU8820 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) { @@ -423,11 +426,11 @@ static struct snd_pcm_ops snd_vortex_playback_ops = { */ static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = { - "AU88x0 ADB", - "AU88x0 SPDIF", - "AU88x0 A3D", - "AU88x0 WT", - "AU88x0 I2S", + CARD_NAME " ADB", + CARD_NAME " SPDIF", + CARD_NAME " A3D", + CARD_NAME " WT", + CARD_NAME " I2S", }; static char *vortex_pcm_name[VORTEX_PCM_LAST] = { "adb", @@ -524,7 +527,8 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) nr_capt, &pcm); if (err < 0) return err; - strcpy(pcm->name, vortex_pcm_name[idx]); + snprintf(pcm->name, sizeof(pcm->name), + "%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]); chip->pcm[idx] = pcm; // This is an evil hack, but it saves a lot of duplicated code. VORTEX_PCM_TYPE(pcm) = idx; diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 7a9401462c1..dae4050ede5 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -303,6 +303,9 @@ static const u32 db_table[101] = { static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0); +/* EMU10K1 bass/treble db gain */ +static const DECLARE_TLV_DB_SCALE(snd_emu10k1_bass_treble_db_scale, -1200, 60, 0); + static const u32 onoff_table[2] = { 0x00000000, 0x00000001 }; @@ -2163,6 +2166,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) ctl->min = 0; ctl->max = 40; ctl->value[0] = ctl->value[1] = 20; + ctl->tlv = snd_emu10k1_bass_treble_db_scale; ctl->translation = EMU10K1_GPR_TRANSLATION_BASS; ctl = &controls[i + 1]; ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; @@ -2172,6 +2176,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) ctl->min = 0; ctl->max = 40; ctl->value[0] = ctl->value[1] = 20; + ctl->tlv = snd_emu10k1_bass_treble_db_scale; ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE; #define BASS_GPR 0x8c diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 05afe06e353..9d890a5aec5 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1729,8 +1729,6 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, "Master Mono Playback Volume", "PCM Out Path & Mute", "Mono Output Select", - "Front Playback Switch", - "Front Playback Volume", "Surround Playback Switch", "Surround Playback Volume", "Center Playback Switch", @@ -1879,6 +1877,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, emu->rear_ac97 = 1; snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); + remove_ctl(card,"Front Playback Volume"); + remove_ctl(card,"Front Playback Switch"); } /* remove unused AC97 controls */ snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); @@ -1913,6 +1913,12 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, for (; *c; c += 2) rename_ctl(card, c[0], c[1]); + if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */ + remove_ctl(card, "Center Playback Volume"); + remove_ctl(card, "LFE Playback Volume"); + remove_ctl(card, "Wave Center Playback Volume"); + remove_ctl(card, "Wave LFE Playback Volume"); + } if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 7c17f45d876..ab0a6156a70 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -112,6 +112,10 @@ #include <sound/ac97_codec.h> #include <sound/initval.h> +#ifdef CONFIG_SND_ES1968_RADIO +#include <sound/tea575x-tuner.h> +#endif + #define CARD_NAME "ESS Maestro1/2" #define DRIVER_NAME "ES1968" @@ -553,6 +557,10 @@ struct es1968 { spinlock_t ac97_lock; struct tasklet_struct hwvol_tq; #endif + +#ifdef CONFIG_SND_ES1968_RADIO + struct snd_tea575x tea; +#endif }; static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); @@ -2571,6 +2579,63 @@ static int __devinit snd_es1968_input_register(struct es1968 *chip) } #endif /* CONFIG_SND_ES1968_INPUT */ +#ifdef CONFIG_SND_ES1968_RADIO +#define GPIO_DATA 0x60 +#define IO_MASK 4 /* mask register offset from GPIO_DATA + bits 1=unmask write to given bit */ +#define IO_DIR 8 /* direction register offset from GPIO_DATA + bits 0/1=read/write direction */ +/* mask bits for GPIO lines */ +#define STR_DATA 0x0040 /* GPIO6 */ +#define STR_CLK 0x0080 /* GPIO7 */ +#define STR_WREN 0x0100 /* GPIO8 */ +#define STR_MOST 0x0200 /* GPIO9 */ + +static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) +{ + struct es1968 *chip = tea->private_data; + unsigned long io = chip->io_port + GPIO_DATA; + u16 val = 0; + + val |= (pins & TEA575X_DATA) ? STR_DATA : 0; + val |= (pins & TEA575X_CLK) ? STR_CLK : 0; + val |= (pins & TEA575X_WREN) ? STR_WREN : 0; + + outw(val, io); +} + +static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea) +{ + struct es1968 *chip = tea->private_data; + unsigned long io = chip->io_port + GPIO_DATA; + u16 val = inw(io); + + return (val & STR_DATA) ? TEA575X_DATA : 0 | + (val & STR_MOST) ? TEA575X_MOST : 0; +} + +static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool output) +{ + struct es1968 *chip = tea->private_data; + unsigned long io = chip->io_port + GPIO_DATA; + u16 odir = inw(io + IO_DIR); + + if (output) { + outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK); + outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR); + } else { + outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK); + outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR); + } +} + +static struct snd_tea575x_ops snd_es1968_tea_ops = { + .set_pins = snd_es1968_tea575x_set_pins, + .get_pins = snd_es1968_tea575x_get_pins, + .set_direction = snd_es1968_tea575x_set_direction, +}; +#endif + static int snd_es1968_free(struct es1968 *chip) { #ifdef CONFIG_SND_ES1968_INPUT @@ -2585,6 +2650,10 @@ static int snd_es1968_free(struct es1968 *chip) outw(0, chip->io_port + ESM_PORT_HOST_IRQ); /* disable IRQ */ } +#ifdef CONFIG_SND_ES1968_RADIO + snd_tea575x_exit(&chip->tea); +#endif + if (chip->irq >= 0) free_irq(chip->irq, chip); snd_es1968_free_gameport(chip); @@ -2723,6 +2792,15 @@ static int __devinit snd_es1968_create(struct snd_card *card, snd_card_set_dev(card, &pci->dev); +#ifdef CONFIG_SND_ES1968_RADIO + chip->tea.private_data = chip; + chip->tea.ops = &snd_es1968_tea_ops; + strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card)); + sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); + if (!snd_tea575x_init(&chip->tea)) + printk(KERN_INFO "es1968: detected TEA575x radio\n"); +#endif + *chip_ret = chip; return 0; diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index e1baad74ea4..eacd4901a30 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -38,7 +38,6 @@ #ifdef CONFIG_SND_FM801_TEA575X_BOOL #include <sound/tea575x-tuner.h> -#define TEA575X_RADIO 1 #endif MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); @@ -53,7 +52,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * /* * Enable TEA575x tuner * 1 = MediaForte 256-PCS - * 2 = MediaForte 256-PCPR + * 2 = MediaForte 256-PCP * 3 = MediaForte 64-PCR * 16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card * High 16-bits are video (radio) device number + 1 @@ -67,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable FM801 soundcard."); module_param_array(tea575x_tuner, int, NULL, 0444); -MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only)."); +MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only)."); #define TUNER_ONLY (1<<4) #define TUNER_TYPE_MASK (~TUNER_ONLY & 0xFFFF) @@ -196,7 +195,7 @@ struct fm801 { spinlock_t reg_lock; struct snd_info_entry *proc_entry; -#ifdef TEA575X_RADIO +#ifdef CONFIG_SND_FM801_TEA575X_BOOL struct snd_tea575x tea; #endif @@ -715,310 +714,89 @@ static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pc * TEA5757 radio */ -#ifdef TEA575X_RADIO - -/* 256PCS GPIO numbers */ -#define TEA_256PCS_DATA 1 -#define TEA_256PCS_WRITE_ENABLE 2 /* inverted */ -#define TEA_256PCS_BUS_CLOCK 3 - -static void snd_fm801_tea575x_256pcs_write(struct snd_tea575x *tea, unsigned int val) -{ - struct fm801 *chip = tea->private_data; - unsigned short reg; - int i = 25; +#ifdef CONFIG_SND_FM801_TEA575X_BOOL - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); - /* use GPIO lines and set write enable bit */ - reg |= FM801_GPIO_GS(TEA_256PCS_DATA) | - FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK); - /* all of lines are in the write direction */ - /* clear data and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_256PCS_DATA) | - FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCS_DATA) | - FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE)); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - - while (i--) { - if (val & (1 << i)) - reg |= FM801_GPIO_GP(TEA_256PCS_DATA); - else - reg &= ~FM801_GPIO_GP(TEA_256PCS_DATA); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - } +/* GPIO to TEA575x maps */ +struct snd_fm801_tea575x_gpio { + u8 data, clk, wren, most; + char *name; +}; - /* and reset the write enable bit */ - reg |= FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE) | - FM801_GPIO_GP(TEA_256PCS_DATA); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - spin_unlock_irq(&chip->reg_lock); -} +static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = { + { .data = 1, .clk = 3, .wren = 2, .most = 0, .name = "SF256-PCS" }, + { .data = 1, .clk = 0, .wren = 2, .most = 3, .name = "SF256-PCP" }, + { .data = 2, .clk = 0, .wren = 1, .most = 3, .name = "SF64-PCR" }, +}; -static unsigned int snd_fm801_tea575x_256pcs_read(struct snd_tea575x *tea) +static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) { struct fm801 *chip = tea->private_data; - unsigned short reg; - unsigned int val = 0; - int i; - - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); - /* use GPIO lines, set data direction to input */ - reg |= FM801_GPIO_GS(TEA_256PCS_DATA) | - FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK) | - FM801_GPIO_GD(TEA_256PCS_DATA) | - FM801_GPIO_GP(TEA_256PCS_DATA) | - FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE); - /* all of lines are in the write direction, except data */ - /* clear data, write enable and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK)); - - for (i = 0; i < 24; i++) { - reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - val <<= 1; - if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCS_DATA)) - val |= 1; - } + unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; - spin_unlock_irq(&chip->reg_lock); + reg &= ~(FM801_GPIO_GP(gpio.data) | + FM801_GPIO_GP(gpio.clk) | + FM801_GPIO_GP(gpio.wren)); - return val; -} + reg |= (pins & TEA575X_DATA) ? FM801_GPIO_GP(gpio.data) : 0; + reg |= (pins & TEA575X_CLK) ? FM801_GPIO_GP(gpio.clk) : 0; + /* WRITE_ENABLE is inverted */ + reg |= (pins & TEA575X_WREN) ? 0 : FM801_GPIO_GP(gpio.wren); -/* 256PCPR GPIO numbers */ -#define TEA_256PCPR_BUS_CLOCK 0 -#define TEA_256PCPR_DATA 1 -#define TEA_256PCPR_WRITE_ENABLE 2 /* inverted */ - -static void snd_fm801_tea575x_256pcpr_write(struct snd_tea575x *tea, unsigned int val) -{ - struct fm801 *chip = tea->private_data; - unsigned short reg; - int i = 25; - - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); - /* use GPIO lines and set write enable bit */ - reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) | - FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK); - /* all of lines are in the write direction */ - /* clear data and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_256PCPR_DATA) | - FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCPR_DATA) | - FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE)); outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - - while (i--) { - if (val & (1 << i)) - reg |= FM801_GPIO_GP(TEA_256PCPR_DATA); - else - reg &= ~FM801_GPIO_GP(TEA_256PCPR_DATA); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - } - - /* and reset the write enable bit */ - reg |= FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE) | - FM801_GPIO_GP(TEA_256PCPR_DATA); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - spin_unlock_irq(&chip->reg_lock); } -static unsigned int snd_fm801_tea575x_256pcpr_read(struct snd_tea575x *tea) +static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea) { struct fm801 *chip = tea->private_data; - unsigned short reg; - unsigned int val = 0; - int i; - - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); - /* use GPIO lines, set data direction to input */ - reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) | - FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK) | - FM801_GPIO_GD(TEA_256PCPR_DATA) | - FM801_GPIO_GP(TEA_256PCPR_DATA) | - FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE); - /* all of lines are in the write direction, except data */ - /* clear data, write enable and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK)); - - for (i = 0; i < 24; i++) { - reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - val <<= 1; - if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCPR_DATA)) - val |= 1; - } + unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; - spin_unlock_irq(&chip->reg_lock); - - return val; + return (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 | + (reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0; } -/* 64PCR GPIO numbers */ -#define TEA_64PCR_BUS_CLOCK 0 -#define TEA_64PCR_WRITE_ENABLE 1 /* inverted */ -#define TEA_64PCR_DATA 2 - -static void snd_fm801_tea575x_64pcr_write(struct snd_tea575x *tea, unsigned int val) +static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output) { struct fm801 *chip = tea->private_data; - unsigned short reg; - int i = 25; + unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); /* use GPIO lines and set write enable bit */ - reg |= FM801_GPIO_GS(TEA_64PCR_DATA) | - FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK); - /* all of lines are in the write direction */ - /* clear data and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_64PCR_DATA) | - FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_64PCR_DATA) | - FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE)); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - - while (i--) { - if (val & (1 << i)) - reg |= FM801_GPIO_GP(TEA_64PCR_DATA); - else - reg &= ~FM801_GPIO_GP(TEA_64PCR_DATA); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); + reg |= FM801_GPIO_GS(gpio.data) | + FM801_GPIO_GS(gpio.wren) | + FM801_GPIO_GS(gpio.clk) | + FM801_GPIO_GS(gpio.most); + if (output) { + /* all of lines are in the write direction */ + /* clear data and clock lines */ + reg &= ~(FM801_GPIO_GD(gpio.data) | + FM801_GPIO_GD(gpio.wren) | + FM801_GPIO_GD(gpio.clk) | + FM801_GPIO_GP(gpio.data) | + FM801_GPIO_GP(gpio.clk) | + FM801_GPIO_GP(gpio.wren)); + } else { + /* use GPIO lines, set data direction to input */ + reg |= FM801_GPIO_GD(gpio.data) | + FM801_GPIO_GD(gpio.most) | + FM801_GPIO_GP(gpio.data) | + FM801_GPIO_GP(gpio.most) | + FM801_GPIO_GP(gpio.wren); + /* all of lines are in the write direction, except data */ + /* clear data, write enable and clock lines */ + reg &= ~(FM801_GPIO_GD(gpio.wren) | + FM801_GPIO_GD(gpio.clk) | + FM801_GPIO_GP(gpio.clk)); } - /* and reset the write enable bit */ - reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE) | - FM801_GPIO_GP(TEA_64PCR_DATA); outw(reg, FM801_REG(chip, GPIO_CTRL)); - spin_unlock_irq(&chip->reg_lock); -} - -static unsigned int snd_fm801_tea575x_64pcr_read(struct snd_tea575x *tea) -{ - struct fm801 *chip = tea->private_data; - unsigned short reg; - unsigned int val = 0; - int i; - - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); - /* use GPIO lines, set data direction to input */ - reg |= FM801_GPIO_GS(TEA_64PCR_DATA) | - FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK) | - FM801_GPIO_GD(TEA_64PCR_DATA) | - FM801_GPIO_GP(TEA_64PCR_DATA) | - FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE); - /* all of lines are in the write direction, except data */ - /* clear data, write enable and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK)); - - for (i = 0; i < 24; i++) { - reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - val <<= 1; - if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_64PCR_DATA)) - val |= 1; - } - - spin_unlock_irq(&chip->reg_lock); - - return val; } -static void snd_fm801_tea575x_64pcr_mute(struct snd_tea575x *tea, - unsigned int mute) -{ - struct fm801 *chip = tea->private_data; - unsigned short reg; - - spin_lock_irq(&chip->reg_lock); - - reg = inw(FM801_REG(chip, GPIO_CTRL)); - if (mute) - /* 0xf800 (mute) */ - reg &= ~FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE); - else - /* 0xf802 (unmute) */ - reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - - spin_unlock_irq(&chip->reg_lock); -} - -static struct snd_tea575x_ops snd_fm801_tea_ops[3] = { - { - /* 1 = MediaForte 256-PCS */ - .write = snd_fm801_tea575x_256pcs_write, - .read = snd_fm801_tea575x_256pcs_read, - }, - { - /* 2 = MediaForte 256-PCPR */ - .write = snd_fm801_tea575x_256pcpr_write, - .read = snd_fm801_tea575x_256pcpr_read, - }, - { - /* 3 = MediaForte 64-PCR */ - .write = snd_fm801_tea575x_64pcr_write, - .read = snd_fm801_tea575x_64pcr_read, - .mute = snd_fm801_tea575x_64pcr_mute, - } +static struct snd_tea575x_ops snd_fm801_tea_ops = { + .set_pins = snd_fm801_tea575x_set_pins, + .get_pins = snd_fm801_tea575x_get_pins, + .set_direction = snd_fm801_tea575x_set_direction, }; #endif @@ -1371,7 +1149,7 @@ static int snd_fm801_free(struct fm801 *chip) outw(cmdw, FM801_REG(chip, IRQ_MASK)); __end_hw: -#ifdef TEA575X_RADIO +#ifdef CONFIG_SND_FM801_TEA575X_BOOL snd_tea575x_exit(&chip->tea); #endif if (chip->irq >= 0) @@ -1450,16 +1228,25 @@ static int __devinit snd_fm801_create(struct snd_card *card, snd_card_set_dev(card, &pci->dev); -#ifdef TEA575X_RADIO +#ifdef CONFIG_SND_FM801_TEA575X_BOOL + chip->tea.private_data = chip; + chip->tea.ops = &snd_fm801_tea_ops; + sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 && (tea575x_tuner & TUNER_TYPE_MASK) < 4) { - chip->tea.dev_nr = tea575x_tuner >> 16; - chip->tea.card = card; - chip->tea.freq_fixup = 10700; - chip->tea.private_data = chip; - chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1]; - snd_tea575x_init(&chip->tea); - } + if (snd_tea575x_init(&chip->tea)) + snd_printk(KERN_ERR "TEA575x radio not found\n"); + } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) + /* autodetect tuner connection */ + for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) { + chip->tea575x_tuner = tea575x_tuner; + if (!snd_tea575x_init(&chip->tea)) { + snd_printk(KERN_INFO "detected TEA575x radio type %s\n", + snd_fm801_tea575x_gpios[tea575x_tuner - 1].name); + break; + } + } + strlcpy(chip->tea.card, snd_fm801_tea575x_gpios[(tea575x_tuner & TUNER_TYPE_MASK) - 1].name, sizeof(chip->tea.card)); #endif *rchip = chip; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 430f41db604..45b4a8d70e0 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -307,6 +307,12 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns); +static bool add_conn_list(struct snd_array *array, hda_nid_t nid); +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst, + hda_nid_t *src, int len); + /** * snd_hda_get_connections - get connection list * @codec: the HDA codec @@ -320,7 +326,44 @@ EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); * Returns the number of connections, or a negative error code. */ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *conn_list, int max_conns) + hda_nid_t *conn_list, int max_conns) +{ + struct snd_array *array = &codec->conn_lists; + int i, len, old_used; + hda_nid_t list[HDA_MAX_CONNECTIONS]; + + /* look up the cached results */ + for (i = 0; i < array->used; ) { + hda_nid_t *p = snd_array_elem(array, i); + len = p[1]; + if (nid == *p) + return copy_conn_list(nid, conn_list, max_conns, + p + 2, len); + i += len + 2; + } + + len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS); + if (len < 0) + return len; + + /* add to the cache */ + old_used = array->used; + if (!add_conn_list(array, nid) || !add_conn_list(array, len)) + goto error_add; + for (i = 0; i < len; i++) + if (!add_conn_list(array, list[i])) + goto error_add; + + return copy_conn_list(nid, conn_list, max_conns, list, len); + + error_add: + array->used = old_used; + return -ENOMEM; +} +EXPORT_SYMBOL_HDA(snd_hda_get_connections); + +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns) { unsigned int parm; int i, conn_len, conns; @@ -417,8 +460,28 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, } return conns; } -EXPORT_SYMBOL_HDA(snd_hda_get_connections); +static bool add_conn_list(struct snd_array *array, hda_nid_t nid) +{ + hda_nid_t *p = snd_array_new(array); + if (!p) + return false; + *p = nid; + return true; +} + +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst, + hda_nid_t *src, int len) +{ + if (len > max_dst) { + snd_printk(KERN_ERR "hda_codec: " + "Too many connections %d for NID 0x%x\n", + len, nid); + return -EINVAL; + } + memcpy(dst, src, len * sizeof(hda_nid_t)); + return len; +} /** * snd_hda_queue_unsol_event - add an unsolicited event to queue @@ -937,6 +1000,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec) } EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); +#ifdef SND_HDA_NEEDS_RESUME /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ static void restore_shutup_pins(struct hda_codec *codec) { @@ -953,6 +1017,7 @@ static void restore_shutup_pins(struct hda_codec *codec) } codec->pins_shutup = 0; } +#endif static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size); @@ -1017,6 +1082,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) list_del(&codec->list); snd_array_free(&codec->mixers); snd_array_free(&codec->nids); + snd_array_free(&codec->conn_lists); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); @@ -1077,6 +1143,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); + snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64); if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { @@ -1329,6 +1396,7 @@ static void purify_inactive_streams(struct hda_codec *codec) } } +#ifdef SND_HDA_NEEDS_RESUME /* clean up all streams; called from suspend */ static void hda_cleanup_all_streams(struct hda_codec *codec) { @@ -1340,6 +1408,7 @@ static void hda_cleanup_all_streams(struct hda_codec *codec) really_cleanup_stream(codec, p); } } +#endif /* * amp access functions @@ -2552,7 +2621,7 @@ static unsigned int convert_to_spdif_status(unsigned short val) static void set_dig_out(struct hda_codec *codec, hda_nid_t nid, int verb, int val) { - hda_nid_t *d; + const hda_nid_t *d; snd_hda_codec_write_cache(codec, nid, 0, verb, val); d = codec->slave_dig_outs; @@ -3803,7 +3872,8 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config); * * Returns 0 if successful, or a negative error code. */ -int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) +int snd_hda_add_new_ctls(struct hda_codec *codec, + const struct snd_kcontrol_new *knew) { int err; @@ -3946,7 +4016,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, hda_nid_t nid) { - struct hda_amp_list *p; + const struct hda_amp_list *p; int ch, v; if (!check->amplist) @@ -4114,7 +4184,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, -1); snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); if (codec->slave_dig_outs) { - hda_nid_t *d; + const hda_nid_t *d; for (d = codec->slave_dig_outs; *d; d++) snd_hda_codec_setup_stream(codec, *d, stream_tag, 0, format); @@ -4129,7 +4199,7 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) { snd_hda_codec_cleanup_stream(codec, nid); if (codec->slave_dig_outs) { - hda_nid_t *d; + const hda_nid_t *d; for (d = codec->slave_dig_outs; *d; d++) snd_hda_codec_cleanup_stream(codec, *d); } @@ -4276,7 +4346,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, unsigned int format, struct snd_pcm_substream *substream) { - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; int chs = substream->runtime->channels; int i; @@ -4331,7 +4401,7 @@ EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare); int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout) { - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; int i; for (i = 0; i < mout->num_dacs; i++) @@ -4356,7 +4426,7 @@ EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup); * Helper for automatic pin configuration */ -static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) +static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) { for (; *list; list++) if (*list == nid) @@ -4437,7 +4507,7 @@ static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) */ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg, - hda_nid_t *ignore_nids) + const hda_nid_t *ignore_nids) { hda_nid_t nid, end_nid; short seq, assoc_line_out, assoc_speaker; @@ -4628,10 +4698,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, /* * debug prints of the parsed results */ - snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], cfg->line_out_pins[2], cfg->line_out_pins[3], - cfg->line_out_pins[4]); + cfg->line_out_pins[4], + cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : + (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? + "speaker" : "line")); snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", cfg->speaker_outs, cfg->speaker_pins[0], cfg->speaker_pins[1], cfg->speaker_pins[2], @@ -4646,7 +4719,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, cfg->dig_out_pins[0], cfg->dig_out_pins[1]); snd_printd(" inputs:"); for (i = 0; i < cfg->num_inputs; i++) { - snd_printdd(" %s=0x%x", + snd_printd(" %s=0x%x", hda_get_autocfg_input_label(codec, cfg, i), cfg->inputs[i].pin); } @@ -4982,6 +5055,8 @@ static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid, return "Line-out"; case SND_JACK_HEADSET: return "Headset"; + case SND_JACK_VIDEOOUT: + return "HDMI/DP"; default: return "Misc"; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index e46d5420a9f..59c97306c1d 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -825,12 +825,14 @@ struct hda_codec { struct hda_cache_rec amp_cache; /* cache for amp access */ struct hda_cache_rec cmd_cache; /* cache for other commands */ + struct snd_array conn_lists; /* connection-list array */ + struct mutex spdif_mutex; struct mutex control_mutex; unsigned int spdif_status; /* IEC958 status bits */ unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ - hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ + const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ struct snd_array init_pins; /* initial (BIOS) pin configurations */ struct snd_array driver_pins; /* pin configs set by codec parser */ struct snd_array cvt_setups; /* audio convert setups */ diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 74b0560289c..b05f7be9dc1 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -312,23 +312,6 @@ out_fail: return -EINVAL; } -static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid) -{ - int eldv; - int present; - - present = snd_hda_pin_sense(codec, nid); - eldv = (present & AC_PINSENSE_ELDV); - present = (present & AC_PINSENSE_PRESENCE); - -#ifdef CONFIG_SND_DEBUG_VERBOSE - printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n", - !!present, !!eldv); -#endif - - return eldv && present; -} - int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) { return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, @@ -343,7 +326,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, int size; unsigned char *buf; - if (!hdmi_eld_valid(codec, nid)) + if (!eld->eld_valid) return -ENOENT; size = snd_hdmi_get_eld_size(codec, nid); @@ -477,6 +460,8 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, snd_iprintf(buffer, "monitor_present\t\t%d\n", e->monitor_present); snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid); + if (!e->eld_valid) + return; snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); snd_iprintf(buffer, "connection_type\t\t%s\n", eld_connection_type_names[e->conn_type]); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 70a9d32f0e9..486f6deb3ee 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -126,6 +126,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH10}," "{Intel, PCH}," "{Intel, CPT}," + "{Intel, PPT}," "{Intel, PBG}," "{Intel, SCH}," "{ATI, SB450}," @@ -390,6 +391,7 @@ struct azx { /* chip type specific */ int driver_type; + unsigned int driver_caps; int playback_streams; int playback_index_offset; int capture_streams; @@ -463,6 +465,34 @@ enum { AZX_NUM_DRIVERS, /* keep this as last entry */ }; +/* driver quirks (capabilities) */ +/* bits 0-7 are used for indicating driver type */ +#define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */ +#define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */ +#define AZX_DCAPS_ATI_SNOOP (1 << 10) /* ATI snoop enable */ +#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11) /* Nvidia snoop enable */ +#define AZX_DCAPS_SCH_SNOOP (1 << 12) /* SCH/PCH snoop enable */ +#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */ +#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */ +#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ +#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ +#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */ +#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ +#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ + +/* quirks for ATI SB / AMD Hudson */ +#define AZX_DCAPS_PRESET_ATI_SB \ + (AZX_DCAPS_ATI_SNOOP | AZX_DCAPS_NO_TCSEL | \ + AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB) + +/* quirks for ATI/AMD HDMI */ +#define AZX_DCAPS_PRESET_ATI_HDMI \ + (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB) + +/* quirks for Nvidia */ +#define AZX_DCAPS_PRESET_NVIDIA \ + (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI) + static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_ICH] = "HDA Intel", [AZX_DRIVER_PCH] = "HDA Intel PCH", @@ -565,7 +595,7 @@ static void azx_init_cmd_io(struct azx *chip) /* reset the rirb hw write pointer */ azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); /* set N=1, get RIRB response interrupt for new entry */ - if (chip->driver_type == AZX_DRIVER_CTX) + if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) azx_writew(chip, RINTCNT, 0xc0); else azx_writew(chip, RINTCNT, 1); @@ -1055,19 +1085,24 @@ static void azx_init_pci(struct azx *chip) * codecs. * The PCI register TCSEL is defined in the Intel manuals. */ - if (chip->driver_type != AZX_DRIVER_ATI && - chip->driver_type != AZX_DRIVER_ATIHDMI) + if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) { + snd_printdd(SFX "Clearing TCSEL\n"); update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); + } - switch (chip->driver_type) { - case AZX_DRIVER_ATI: - /* For ATI SB450 azalia HD audio, we need to enable snoop */ + /* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio, + * we need to enable snoop. + */ + if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) { + snd_printdd(SFX "Enabling ATI snoop\n"); update_pci_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP); - break; - case AZX_DRIVER_NVIDIA: - /* For NVIDIA HDA, enable snoop */ + } + + /* For NVIDIA HDA, enable snoop */ + if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) { + snd_printdd(SFX "Enabling Nvidia snoop\n"); update_pci_byte(chip->pci, NVIDIA_HDA_TRANSREG_ADDR, 0x0f, NVIDIA_HDA_ENABLE_COHBITS); @@ -1077,9 +1112,10 @@ static void azx_init_pci(struct azx *chip) update_pci_byte(chip->pci, NVIDIA_HDA_OSTRM_COH, 0x01, NVIDIA_HDA_ENABLE_COHBIT); - break; - case AZX_DRIVER_SCH: - case AZX_DRIVER_PCH: + } + + /* Enable SCH/PCH snoop if needed */ + if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) { pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) { pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, @@ -1090,8 +1126,6 @@ static void azx_init_pci(struct azx *chip) (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) ? "Failed" : "OK"); } - break; - } } @@ -1145,7 +1179,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) status = azx_readb(chip, RIRBSTS); if (status & RIRB_INT_MASK) { if (status & RIRB_INT_RESPONSE) { - if (chip->driver_type == AZX_DRIVER_CTX) + if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY) udelay(80); azx_update_rirb(chip); } @@ -1414,8 +1448,10 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) if (err < 0) return err; - if (chip->driver_type == AZX_DRIVER_NVIDIA) + if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { + snd_printd(SFX "Enable delay in RIRB handling\n"); chip->bus->needs_damn_long_delay = 1; + } codecs = 0; max_slots = azx_max_codecs[chip->driver_type]; @@ -1446,6 +1482,16 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) } } + /* AMD chipsets often cause the communication stalls upon certain + * sequence like the pin-detection. It seems that forcing the synced + * access works around the stall. Grrr... + */ + if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) { + snd_printd(SFX "Enable sync_write for stable communication\n"); + chip->bus->sync_write = 1; + chip->bus->allow_bus_reset = 1; + } + /* Then create codec instances */ for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { @@ -1702,7 +1748,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) stream_tag = azx_dev->stream_tag; /* CA-IBG chips need the playback stream starting from 1 */ - if (chip->driver_type == AZX_DRIVER_CTX && + if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) && stream_tag > chip->capture_streams) stream_tag -= chip->capture_streams; return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag, @@ -2347,13 +2393,14 @@ static int __devinit check_position_fix(struct azx *chip, int fix) } /* Check VIA/ATI HD Audio Controller exist */ - switch (chip->driver_type) { - case AZX_DRIVER_VIA: - case AZX_DRIVER_ATI: - /* Use link position directly, avoid any transfer problem. */ + if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) { + snd_printd(SFX "Using VIACOMBO position fix\n"); return POS_FIX_VIACOMBO; } - + if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) { + snd_printd(SFX "Using LPIB position fix\n"); + return POS_FIX_LPIB; + } return POS_FIX_AUTO; } @@ -2435,8 +2482,8 @@ static void __devinit check_msi(struct azx *chip) } /* NVidia chipsets seem to cause troubles with MSI */ - if (chip->driver_type == AZX_DRIVER_NVIDIA) { - printk(KERN_INFO "hda_intel: Disable MSI for Nvidia chipset\n"); + if (chip->driver_caps & AZX_DCAPS_NO_MSI) { + printk(KERN_INFO "hda_intel: Disabling MSI\n"); chip->msi = 0; } } @@ -2446,7 +2493,7 @@ static void __devinit check_msi(struct azx *chip) * constructor */ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, - int dev, int driver_type, + int dev, unsigned int driver_caps, struct azx **rchip) { struct azx *chip; @@ -2474,7 +2521,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->card = card; chip->pci = pci; chip->irq = -1; - chip->driver_type = driver_type; + chip->driver_caps = driver_caps; + chip->driver_type = driver_caps & 0xff; check_msi(chip); chip->dev_index = dev; INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); @@ -2538,8 +2586,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap); /* disable SB600 64bit support for safety */ - if ((chip->driver_type == AZX_DRIVER_ATI) || - (chip->driver_type == AZX_DRIVER_ATIHDMI)) { + if (chip->pci->vendor == PCI_VENDOR_ID_ATI) { struct pci_dev *p_smbus; p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, @@ -2551,10 +2598,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } } - /* disable 64bit DMA address for Teradici */ - /* it does not work with device 6549:1200 subsys e4a2:040b */ - if (chip->driver_type == AZX_DRIVER_TERA) + /* disable 64bit DMA address on some devices */ + if (chip->driver_caps & AZX_DCAPS_NO_64BIT) { + snd_printd(SFX "Disabling 64bit DMA\n"); gcap &= ~ICH6_GCAP_64OK; + } /* allow 64bit DMA address if supported by H/W */ if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) @@ -2756,36 +2804,62 @@ static void __devexit azx_remove(struct pci_dev *pci) /* PCI IDs */ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* CPT */ - { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH }, + { PCI_DEVICE(0x8086, 0x1c20), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, /* PBG */ - { PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH }, + { PCI_DEVICE(0x8086, 0x1d20), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, + /* Panther Point */ + { PCI_DEVICE(0x8086, 0x1e20), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, /* SCH */ - { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH }, + { PCI_DEVICE(0x8086, 0x811b), + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP }, /* Generic Intel */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, .driver_data = AZX_DRIVER_ICH }, - /* ATI SB 450/600 */ - { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI }, - { PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI }, + /* ATI SB 450/600/700/800/900 */ + { PCI_DEVICE(0x1002, 0x437b), + .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, + { PCI_DEVICE(0x1002, 0x4383), + .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, + /* AMD Hudson */ + { PCI_DEVICE(0x1022, 0x780d), + .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB }, /* ATI HDMI */ - { PCI_DEVICE(0x1002, 0x793b), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0x7919), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0x960f), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0x970f), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa00), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa08), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa10), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa18), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa20), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa28), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa30), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa38), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa40), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa48), .driver_data = AZX_DRIVER_ATIHDMI }, + { PCI_DEVICE(0x1002, 0x793b), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0x7919), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0x960f), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0x970f), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa00), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa08), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa10), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa18), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa20), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa28), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa30), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa38), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa40), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa48), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, /* VIA VT8251/VT8237A */ - { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA }, + { PCI_DEVICE(0x1106, 0x3288), + .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA }, /* SIS966 */ { PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS }, /* ULI M5461 */ @@ -2794,9 +2868,10 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_NVIDIA }, + .driver_data = AZX_DRIVER_NVIDIA | AZX_DCAPS_PRESET_NVIDIA }, /* Teradici */ - { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, + { PCI_DEVICE(0x6549, 0x1200), + .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT }, /* Creative X-Fi (CA0110-IBG) */ #if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE) /* the following entry conflicts with snd-ctxfi driver, @@ -2806,10 +2881,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_CTX }, + .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | + AZX_DCAPS_RIRB_PRE_DELAY }, #else /* this entry seems still valid -- i.e. without emu20kx chip */ - { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX }, + { PCI_DEVICE(0x1102, 0x0009), + .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | + AZX_DCAPS_RIRB_PRE_DELAY }, #endif /* Vortex86MX */ { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, @@ -2819,11 +2897,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_GENERIC }, + .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_GENERIC }, + .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI }, { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index ff5e2ac2239..08ec073444e 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -267,11 +267,11 @@ enum { HDA_DIG_NONE, HDA_DIG_EXCLUSIVE, HDA_DIG_ANALOG_DUP }; /* dig_out_used */ struct hda_multi_out { int num_dacs; /* # of DACs, must be more than 1 */ - hda_nid_t *dac_nids; /* DAC list */ + const hda_nid_t *dac_nids; /* DAC list */ hda_nid_t hp_nid; /* optional DAC for HP, 0 when not exists */ hda_nid_t extra_out_nid[3]; /* optional DACs, 0 when not exists */ hda_nid_t dig_out_nid; /* digital out audio widget */ - hda_nid_t *slave_dig_outs; + const hda_nid_t *slave_dig_outs; int max_channels; /* currently supported analog channels */ int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ int no_share_stream; /* don't share a stream with multiple pins */ @@ -347,7 +347,7 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, int num_configs, const char * const *models, const struct snd_pci_quirk *tbl); int snd_hda_add_new_ctls(struct hda_codec *codec, - struct snd_kcontrol_new *knew); + const struct snd_kcontrol_new *knew); /* * unsolicited event handler @@ -443,7 +443,7 @@ struct auto_pin_cfg { int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg, - hda_nid_t *ignore_nids); + const hda_nid_t *ignore_nids); /* amp values */ #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) @@ -493,6 +493,12 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); +static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) +{ + return (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT) && + (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP); +} + /* flags for hda_nid_item */ #define HDA_NID_ITEM_AMP (1<<0) @@ -567,7 +573,7 @@ struct hda_amp_list { }; struct hda_loopback_check { - struct hda_amp_list *amplist; + const struct hda_amp_list *amplist; int power_on; }; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2942d2a9ea1..696ac259030 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -30,7 +30,7 @@ #include "hda_beep.h" struct ad198x_spec { - struct snd_kcontrol_new *mixers[6]; + const struct snd_kcontrol_new *mixers[6]; int num_mixers; unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ const struct hda_verb *init_verbs[6]; /* initialization verbs @@ -46,17 +46,17 @@ struct ad198x_spec { unsigned int cur_eapd; unsigned int need_dac_fix; - hda_nid_t *alt_dac_nid; - struct hda_pcm_stream *stream_analog_alt_playback; + const hda_nid_t *alt_dac_nid; + const struct hda_pcm_stream *stream_analog_alt_playback; /* capture */ unsigned int num_adc_nids; - hda_nid_t *adc_nids; + const hda_nid_t *adc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ /* capture source */ const struct hda_input_mux *input_mux; - hda_nid_t *capsrc_nids; + const hda_nid_t *capsrc_nids; unsigned int cur_mux[3]; /* channel model */ @@ -182,13 +182,13 @@ static void ad198x_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP /* additional beep mixers; the actual parameters are overwritten at build */ -static struct snd_kcontrol_new ad_beep_mixer[] = { +static const struct snd_kcontrol_new ad_beep_mixer[] = { HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT), HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT), { } /* end */ }; -static struct snd_kcontrol_new ad_beep2_mixer[] = { +static const struct snd_kcontrol_new ad_beep2_mixer[] = { HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT), HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT), { } /* end */ @@ -231,7 +231,7 @@ static int ad198x_build_controls(struct hda_codec *codec) /* create beep controls if needed */ #ifdef CONFIG_SND_HDA_INPUT_BEEP if (spec->beep_amp) { - struct snd_kcontrol_new *knew; + const struct snd_kcontrol_new *knew; knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer; for ( ; knew->name; knew++) { struct snd_kcontrol *kctl; @@ -331,7 +331,7 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); } -static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { +static const struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -403,7 +403,7 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, /* */ -static struct hda_pcm_stream ad198x_pcm_analog_playback = { +static const struct hda_pcm_stream ad198x_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 6, /* changed later */ @@ -415,7 +415,7 @@ static struct hda_pcm_stream ad198x_pcm_analog_playback = { }, }; -static struct hda_pcm_stream ad198x_pcm_analog_capture = { +static const struct hda_pcm_stream ad198x_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -426,7 +426,7 @@ static struct hda_pcm_stream ad198x_pcm_analog_capture = { }, }; -static struct hda_pcm_stream ad198x_pcm_digital_playback = { +static const struct hda_pcm_stream ad198x_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -439,7 +439,7 @@ static struct hda_pcm_stream ad198x_pcm_digital_playback = { }, }; -static struct hda_pcm_stream ad198x_pcm_digital_capture = { +static const struct hda_pcm_stream ad198x_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -489,11 +489,6 @@ static int ad198x_build_pcms(struct hda_codec *codec) return 0; } -static inline void ad198x_shutup(struct hda_codec *codec) -{ - snd_hda_shutup_pins(codec); -} - static void ad198x_free_kctls(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; @@ -547,6 +542,12 @@ static void ad198x_power_eapd(struct hda_codec *codec) } } +static void ad198x_shutup(struct hda_codec *codec) +{ + snd_hda_shutup_pins(codec); + ad198x_power_eapd(codec); +} + static void ad198x_free(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; @@ -564,12 +565,11 @@ static void ad198x_free(struct hda_codec *codec) static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) { ad198x_shutup(codec); - ad198x_power_eapd(codec); return 0; } #endif -static struct hda_codec_ops ad198x_patch_ops = { +static const struct hda_codec_ops ad198x_patch_ops = { .build_controls = ad198x_build_controls, .build_pcms = ad198x_build_pcms, .init = ad198x_init, @@ -639,13 +639,13 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, #define AD1986A_CLFE_DAC 0x05 #define AD1986A_ADC 0x06 -static hda_nid_t ad1986a_dac_nids[3] = { +static const hda_nid_t ad1986a_dac_nids[3] = { AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC }; -static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; -static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 }; +static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; +static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 }; -static struct hda_input_mux ad1986a_capture_source = { +static const struct hda_input_mux ad1986a_capture_source = { .num_items = 7, .items = { { "Mic", 0x0 }, @@ -659,7 +659,7 @@ static struct hda_input_mux ad1986a_capture_source = { }; -static struct hda_bind_ctls ad1986a_bind_pcm_vol = { +static const struct hda_bind_ctls ad1986a_bind_pcm_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), @@ -669,7 +669,7 @@ static struct hda_bind_ctls ad1986a_bind_pcm_vol = { }, }; -static struct hda_bind_ctls ad1986a_bind_pcm_sw = { +static const struct hda_bind_ctls ad1986a_bind_pcm_sw = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), @@ -682,7 +682,7 @@ static struct hda_bind_ctls ad1986a_bind_pcm_sw = { /* * mixers */ -static struct snd_kcontrol_new ad1986a_mixers[] = { +static const struct snd_kcontrol_new ad1986a_mixers[] = { /* * bind volumes/mutes of 3 DACs as a single PCM control for simplicity */ @@ -723,7 +723,7 @@ static struct snd_kcontrol_new ad1986a_mixers[] = { }; /* additional mixers for 3stack mode */ -static struct snd_kcontrol_new ad1986a_3st_mixers[] = { +static const struct snd_kcontrol_new ad1986a_3st_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -735,10 +735,10 @@ static struct snd_kcontrol_new ad1986a_3st_mixers[] = { }; /* laptop model - 2ch only */ -static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; +static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; /* master controls both pins 0x1a and 0x1b */ -static struct hda_bind_ctls ad1986a_laptop_master_vol = { +static const struct hda_bind_ctls ad1986a_laptop_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), @@ -747,7 +747,7 @@ static struct hda_bind_ctls ad1986a_laptop_master_vol = { }, }; -static struct hda_bind_ctls ad1986a_laptop_master_sw = { +static const struct hda_bind_ctls ad1986a_laptop_master_sw = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), @@ -756,7 +756,7 @@ static struct hda_bind_ctls ad1986a_laptop_master_sw = { }, }; -static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { +static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), @@ -787,7 +787,7 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { /* laptop-eapd model - 2ch only */ -static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { +static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -796,7 +796,7 @@ static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { }, }; -static struct hda_input_mux ad1986a_automic_capture_source = { +static const struct hda_input_mux ad1986a_automic_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -804,13 +804,13 @@ static struct hda_input_mux ad1986a_automic_capture_source = { }, }; -static struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = { +static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = { HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), { } /* end */ }; -static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { +static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), @@ -837,7 +837,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { +static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT), { } /* end */ @@ -931,7 +931,7 @@ static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { +static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -949,7 +949,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { /* * initialization verbs */ -static struct hda_verb ad1986a_init_verbs[] = { +static const struct hda_verb ad1986a_init_verbs[] = { /* Front, Surround, CLFE DAC; mute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, @@ -1004,7 +1004,7 @@ static struct hda_verb ad1986a_init_verbs[] = { { } /* end */ }; -static struct hda_verb ad1986a_ch2_init[] = { +static const struct hda_verb ad1986a_ch2_init[] = { /* Surround out -> Line In */ { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line-in selectors */ @@ -1016,7 +1016,7 @@ static struct hda_verb ad1986a_ch2_init[] = { { } /* end */ }; -static struct hda_verb ad1986a_ch4_init[] = { +static const struct hda_verb ad1986a_ch4_init[] = { /* Surround out -> Surround */ { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, @@ -1026,7 +1026,7 @@ static struct hda_verb ad1986a_ch4_init[] = { { } /* end */ }; -static struct hda_verb ad1986a_ch6_init[] = { +static const struct hda_verb ad1986a_ch6_init[] = { /* Surround out -> Surround out */ { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, @@ -1036,19 +1036,19 @@ static struct hda_verb ad1986a_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode ad1986a_modes[3] = { +static const struct hda_channel_mode ad1986a_modes[3] = { { 2, ad1986a_ch2_init }, { 4, ad1986a_ch4_init }, { 6, ad1986a_ch6_init }, }; /* eapd initialization */ -static struct hda_verb ad1986a_eapd_init_verbs[] = { +static const struct hda_verb ad1986a_eapd_init_verbs[] = { {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, {} }; -static struct hda_verb ad1986a_automic_verbs[] = { +static const struct hda_verb ad1986a_automic_verbs[] = { {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/ @@ -1058,7 +1058,7 @@ static struct hda_verb ad1986a_automic_verbs[] = { }; /* Ultra initialization */ -static struct hda_verb ad1986a_ultra_init[] = { +static const struct hda_verb ad1986a_ultra_init[] = { /* eapd initialization */ { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* CLFE -> Mic in */ @@ -1069,7 +1069,7 @@ static struct hda_verb ad1986a_ultra_init[] = { }; /* pin sensing on HP jack */ -static struct hda_verb ad1986a_hp_init_verbs[] = { +static const struct hda_verb ad1986a_hp_init_verbs[] = { {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, {} }; @@ -1120,7 +1120,7 @@ static const char * const ad1986a_models[AD1986A_MODELS] = { [AD1986A_SAMSUNG_P50] = "samsung-p50", }; -static struct snd_pci_quirk ad1986a_cfg_tbl[] = { +static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), @@ -1152,7 +1152,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1986a_loopbacks[] = { +static const struct hda_amp_list ad1986a_loopbacks[] = { { 0x13, HDA_OUTPUT, 0 }, /* Mic */ { 0x14, HDA_OUTPUT, 0 }, /* Phone */ { 0x15, HDA_OUTPUT, 0 }, /* CD */ @@ -1329,11 +1329,11 @@ static int patch_ad1986a(struct hda_codec *codec) #define AD1983_DAC 0x03 #define AD1983_ADC 0x04 -static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; -static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; -static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 }; +static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; +static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; +static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 }; -static struct hda_input_mux ad1983_capture_source = { +static const struct hda_input_mux ad1983_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -1348,7 +1348,7 @@ static struct hda_input_mux ad1983_capture_source = { */ static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "PCM", "ADC" }; + static const char * const texts[] = { "PCM", "ADC" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -1385,7 +1385,7 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ return 0; } -static struct snd_kcontrol_new ad1983_mixers[] = { +static const struct snd_kcontrol_new ad1983_mixers[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), @@ -1418,7 +1418,7 @@ static struct snd_kcontrol_new ad1983_mixers[] = { { } /* end */ }; -static struct hda_verb ad1983_init_verbs[] = { +static const struct hda_verb ad1983_init_verbs[] = { /* Front, HP, Mono; mute as default */ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, @@ -1458,7 +1458,7 @@ static struct hda_verb ad1983_init_verbs[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1983_loopbacks[] = { +static const struct hda_amp_list ad1983_loopbacks[] = { { 0x12, HDA_OUTPUT, 0 }, /* Mic */ { 0x13, HDA_OUTPUT, 0 }, /* Line */ { } /* end */ @@ -1518,12 +1518,12 @@ static int patch_ad1983(struct hda_codec *codec) #define AD1981_DAC 0x03 #define AD1981_ADC 0x04 -static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; -static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; -static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 }; +static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; +static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; +static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 }; /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ -static struct hda_input_mux ad1981_capture_source = { +static const struct hda_input_mux ad1981_capture_source = { .num_items = 7, .items = { { "Front Mic", 0x0 }, @@ -1536,7 +1536,7 @@ static struct hda_input_mux ad1981_capture_source = { }, }; -static struct snd_kcontrol_new ad1981_mixers[] = { +static const struct snd_kcontrol_new ad1981_mixers[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), @@ -1577,7 +1577,7 @@ static struct snd_kcontrol_new ad1981_mixers[] = { { } /* end */ }; -static struct hda_verb ad1981_init_verbs[] = { +static const struct hda_verb ad1981_init_verbs[] = { /* Front, HP, Mono; mute as default */ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, @@ -1625,7 +1625,7 @@ static struct hda_verb ad1981_init_verbs[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1981_loopbacks[] = { +static const struct hda_amp_list ad1981_loopbacks[] = { { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ { 0x13, HDA_OUTPUT, 0 }, /* Line */ { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ @@ -1645,7 +1645,7 @@ static struct hda_amp_list ad1981_loopbacks[] = { #define AD1981_HP_EVENT 0x37 #define AD1981_MIC_EVENT 0x38 -static struct hda_verb ad1981_hp_init_verbs[] = { +static const struct hda_verb ad1981_hp_init_verbs[] = { {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */ /* pin sensing on HP and Mic jacks */ {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, @@ -1674,7 +1674,7 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, } /* bind volumes of both NID 0x05 and 0x06 */ -static struct hda_bind_ctls ad1981_hp_bind_master_vol = { +static const struct hda_bind_ctls ad1981_hp_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), @@ -1696,12 +1696,12 @@ static void ad1981_hp_automute(struct hda_codec *codec) /* toggle input of built-in and mic jack appropriately */ static void ad1981_hp_automic(struct hda_codec *codec) { - static struct hda_verb mic_jack_on[] = { + static const struct hda_verb mic_jack_on[] = { {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, {} }; - static struct hda_verb mic_jack_off[] = { + static const struct hda_verb mic_jack_off[] = { {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, {} @@ -1730,7 +1730,7 @@ static void ad1981_hp_unsol_event(struct hda_codec *codec, } } -static struct hda_input_mux ad1981_hp_capture_source = { +static const struct hda_input_mux ad1981_hp_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -1739,7 +1739,7 @@ static struct hda_input_mux ad1981_hp_capture_source = { }, }; -static struct snd_kcontrol_new ad1981_hp_mixers[] = { +static const struct snd_kcontrol_new ad1981_hp_mixers[] = { HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1790,7 +1790,7 @@ static int ad1981_hp_init(struct hda_codec *codec) } /* configuration for Toshiba Laptops */ -static struct hda_verb ad1981_toshiba_init_verbs[] = { +static const struct hda_verb ad1981_toshiba_init_verbs[] = { {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */ /* pin sensing on HP and Mic jacks */ {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, @@ -1798,14 +1798,14 @@ static struct hda_verb ad1981_toshiba_init_verbs[] = { {} }; -static struct snd_kcontrol_new ad1981_toshiba_mixers[] = { +static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = { HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT), { } }; /* configuration for Lenovo Thinkpad T60 */ -static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { +static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), @@ -1835,7 +1835,7 @@ static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { { } /* end */ }; -static struct hda_input_mux ad1981_thinkpad_capture_source = { +static const struct hda_input_mux ad1981_thinkpad_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -1860,7 +1860,7 @@ static const char * const ad1981_models[AD1981_MODELS] = { [AD1981_TOSHIBA] = "toshiba" }; -static struct snd_pci_quirk ad1981_cfg_tbl[] = { +static const struct snd_pci_quirk ad1981_cfg_tbl[] = { SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD), /* All HP models */ @@ -2075,32 +2075,32 @@ enum { * mixers */ -static hda_nid_t ad1988_6stack_dac_nids[4] = { +static const hda_nid_t ad1988_6stack_dac_nids[4] = { 0x04, 0x06, 0x05, 0x0a }; -static hda_nid_t ad1988_3stack_dac_nids[3] = { +static const hda_nid_t ad1988_3stack_dac_nids[3] = { 0x04, 0x05, 0x0a }; /* for AD1988A revision-2, DAC2-4 are swapped */ -static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { +static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { 0x04, 0x05, 0x0a, 0x06 }; -static hda_nid_t ad1988_alt_dac_nid[1] = { +static const hda_nid_t ad1988_alt_dac_nid[1] = { 0x03 }; -static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { +static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { 0x04, 0x0a, 0x06 }; -static hda_nid_t ad1988_adc_nids[3] = { +static const hda_nid_t ad1988_adc_nids[3] = { 0x08, 0x09, 0x0f }; -static hda_nid_t ad1988_capsrc_nids[3] = { +static const hda_nid_t ad1988_capsrc_nids[3] = { 0x0c, 0x0d, 0x0e }; @@ -2108,11 +2108,11 @@ static hda_nid_t ad1988_capsrc_nids[3] = { #define AD1988_SPDIF_OUT_HDMI 0x0b #define AD1988_SPDIF_IN 0x07 -static hda_nid_t ad1989b_slave_dig_outs[] = { +static const hda_nid_t ad1989b_slave_dig_outs[] = { AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0 }; -static struct hda_input_mux ad1988_6stack_capture_source = { +static const struct hda_input_mux ad1988_6stack_capture_source = { .num_items = 5, .items = { { "Front Mic", 0x1 }, /* port-B */ @@ -2123,7 +2123,7 @@ static struct hda_input_mux ad1988_6stack_capture_source = { }, }; -static struct hda_input_mux ad1988_laptop_capture_source = { +static const struct hda_input_mux ad1988_laptop_capture_source = { .num_items = 3, .items = { { "Mic/Line", 0x1 }, /* port-B */ @@ -2166,7 +2166,7 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, } /* 6-stack mode */ -static struct snd_kcontrol_new ad1988_6stack_mixers1[] = { +static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), @@ -2175,7 +2175,7 @@ static struct snd_kcontrol_new ad1988_6stack_mixers1[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { +static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), @@ -2184,7 +2184,7 @@ static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_6stack_mixers2[] = { +static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = { HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), @@ -2211,14 +2211,14 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = { +static const struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), { } /* end */ }; /* 3-stack mode */ -static struct snd_kcontrol_new ad1988_3stack_mixers1[] = { +static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), @@ -2226,7 +2226,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers1[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { +static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT), @@ -2234,7 +2234,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_3stack_mixers2[] = { +static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = { HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT), HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT), @@ -2268,7 +2268,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers2[] = { }; /* laptop mode */ -static struct snd_kcontrol_new ad1988_laptop_mixers[] = { +static const struct snd_kcontrol_new ad1988_laptop_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT), HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), @@ -2299,7 +2299,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { }; /* capture */ -static struct snd_kcontrol_new ad1988_capture_mixers[] = { +static const struct snd_kcontrol_new ad1988_capture_mixers[] = { HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), @@ -2324,7 +2324,7 @@ static struct snd_kcontrol_new ad1988_capture_mixers[] = { static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "PCM", "ADC1", "ADC2", "ADC3" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -2405,7 +2405,7 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { +static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -2418,12 +2418,12 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { +static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT), { } /* end */ }; -static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { +static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT), { } /* end */ @@ -2436,7 +2436,7 @@ static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { /* * for 6-stack (+dig) */ -static struct hda_verb ad1988_6stack_init_verbs[] = { +static const struct hda_verb ad1988_6stack_init_verbs[] = { /* Front, Surround, CLFE, side DAC; unmute as default */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -2496,7 +2496,7 @@ static struct hda_verb ad1988_6stack_init_verbs[] = { { } }; -static struct hda_verb ad1988_6stack_fp_init_verbs[] = { +static const struct hda_verb ad1988_6stack_fp_init_verbs[] = { /* Headphone; unmute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Port-A front headphon path */ @@ -2509,7 +2509,7 @@ static struct hda_verb ad1988_6stack_fp_init_verbs[] = { { } }; -static struct hda_verb ad1988_capture_init_verbs[] = { +static const struct hda_verb ad1988_capture_init_verbs[] = { /* mute analog mix */ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, @@ -2527,7 +2527,7 @@ static struct hda_verb ad1988_capture_init_verbs[] = { { } }; -static struct hda_verb ad1988_spdif_init_verbs[] = { +static const struct hda_verb ad1988_spdif_init_verbs[] = { /* SPDIF out sel */ {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ @@ -2539,14 +2539,14 @@ static struct hda_verb ad1988_spdif_init_verbs[] = { { } }; -static struct hda_verb ad1988_spdif_in_init_verbs[] = { +static const struct hda_verb ad1988_spdif_in_init_verbs[] = { /* unmute SPDIF input pin */ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { } }; /* AD1989 has no ADC -> SPDIF route */ -static struct hda_verb ad1989_spdif_init_verbs[] = { +static const struct hda_verb ad1989_spdif_init_verbs[] = { /* SPDIF-1 out pin */ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ @@ -2559,7 +2559,7 @@ static struct hda_verb ad1989_spdif_init_verbs[] = { /* * verbs for 3stack (+dig) */ -static struct hda_verb ad1988_3stack_ch2_init[] = { +static const struct hda_verb ad1988_3stack_ch2_init[] = { /* set port-C to line-in */ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, @@ -2569,7 +2569,7 @@ static struct hda_verb ad1988_3stack_ch2_init[] = { { } /* end */ }; -static struct hda_verb ad1988_3stack_ch6_init[] = { +static const struct hda_verb ad1988_3stack_ch6_init[] = { /* set port-C to surround out */ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -2579,12 +2579,12 @@ static struct hda_verb ad1988_3stack_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode ad1988_3stack_modes[2] = { +static const struct hda_channel_mode ad1988_3stack_modes[2] = { { 2, ad1988_3stack_ch2_init }, { 6, ad1988_3stack_ch6_init }, }; -static struct hda_verb ad1988_3stack_init_verbs[] = { +static const struct hda_verb ad1988_3stack_init_verbs[] = { /* Front, Surround, CLFE, side DAC; unmute as default */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -2644,13 +2644,13 @@ static struct hda_verb ad1988_3stack_init_verbs[] = { /* * verbs for laptop mode (+dig) */ -static struct hda_verb ad1988_laptop_hp_on[] = { +static const struct hda_verb ad1988_laptop_hp_on[] = { /* unmute port-A and mute port-D */ { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { } /* end */ }; -static struct hda_verb ad1988_laptop_hp_off[] = { +static const struct hda_verb ad1988_laptop_hp_off[] = { /* mute port-A and unmute port-D */ { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -2659,7 +2659,7 @@ static struct hda_verb ad1988_laptop_hp_off[] = { #define AD1988_HP_EVENT 0x01 -static struct hda_verb ad1988_laptop_init_verbs[] = { +static const struct hda_verb ad1988_laptop_init_verbs[] = { /* Front, Surround, CLFE, side DAC; unmute as default */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -2723,7 +2723,7 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1988_loopbacks[] = { +static const struct hda_amp_list ad1988_loopbacks[] = { { 0x20, HDA_INPUT, 0 }, /* Front Mic */ { 0x20, HDA_INPUT, 1 }, /* Line */ { 0x20, HDA_INPUT, 4 }, /* Mic */ @@ -2741,7 +2741,7 @@ enum { AD_CTL_WIDGET_MUTE, AD_CTL_BIND_MUTE, }; -static struct snd_kcontrol_new ad1988_control_templates[] = { +static const struct snd_kcontrol_new ad1988_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), HDA_BIND_MUTE(NULL, 0, 0, 0), @@ -2770,18 +2770,18 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, #define AD1988_PIN_CD_NID 0x18 #define AD1988_PIN_BEEP_NID 0x10 -static hda_nid_t ad1988_mixer_nids[8] = { +static const hda_nid_t ad1988_mixer_nids[8] = { /* A B C D E F G H */ 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28 }; static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx) { - static hda_nid_t idx_to_dac[8] = { + static const hda_nid_t idx_to_dac[8] = { /* A B C D E F G H */ 0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a }; - static hda_nid_t idx_to_dac_rev2[8] = { + static const hda_nid_t idx_to_dac_rev2[8] = { /* A B C D E F G H */ 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06 }; @@ -2791,13 +2791,13 @@ static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx) return idx_to_dac[idx]; } -static hda_nid_t ad1988_boost_nids[8] = { +static const hda_nid_t ad1988_boost_nids[8] = { 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0 }; static int ad1988_pin_idx(hda_nid_t nid) { - static hda_nid_t ad1988_io_pins[8] = { + static const hda_nid_t ad1988_io_pins[8] = { 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25 }; int i; @@ -2809,7 +2809,7 @@ static int ad1988_pin_idx(hda_nid_t nid) static int ad1988_pin_to_loopback_idx(hda_nid_t nid) { - static int loopback_idx[8] = { + static const int loopback_idx[8] = { 2, 0, 1, 3, 4, 5, 1, 4 }; switch (nid) { @@ -2822,7 +2822,7 @@ static int ad1988_pin_to_loopback_idx(hda_nid_t nid) static int ad1988_pin_to_adc_idx(hda_nid_t nid) { - static int adc_idx[8] = { + static const int adc_idx[8] = { 0, 1, 2, 8, 4, 3, 6, 7 }; switch (nid) { @@ -2845,7 +2845,7 @@ static int ad1988_auto_fill_dac_nids(struct hda_codec *codec, /* check the pins hardwired to audio widget */ for (i = 0; i < cfg->line_outs; i++) { idx = ad1988_pin_idx(cfg->line_out_pins[i]); - spec->multiout.dac_nids[i] = ad1988_idx_to_dac(codec, idx); + spec->private_dac_nids[i] = ad1988_idx_to_dac(codec, idx); } spec->multiout.num_dacs = cfg->line_outs; return 0; @@ -3070,6 +3070,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; + int type = cfg->inputs[i].type; switch (nid) { case 0x15: /* port-C */ snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0); @@ -3079,7 +3080,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec) break; } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN); + type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN); if (nid != AD1988_PIN_CD_NID) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); @@ -3154,10 +3155,11 @@ static const char * const ad1988_models[AD1988_MODEL_LAST] = { [AD1988_AUTO] = "auto", }; -static struct snd_pci_quirk ad1988_cfg_tbl[] = { +static const struct snd_pci_quirk ad1988_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG), + SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG), {} }; @@ -3342,21 +3344,21 @@ static int patch_ad1988(struct hda_codec *codec) * but no build-up framework is given, so far. */ -static hda_nid_t ad1884_dac_nids[1] = { +static const hda_nid_t ad1884_dac_nids[1] = { 0x04, }; -static hda_nid_t ad1884_adc_nids[2] = { +static const hda_nid_t ad1884_adc_nids[2] = { 0x08, 0x09, }; -static hda_nid_t ad1884_capsrc_nids[2] = { +static const hda_nid_t ad1884_capsrc_nids[2] = { 0x0c, 0x0d, }; #define AD1884_SPDIF_OUT 0x02 -static struct hda_input_mux ad1884_capture_source = { +static const struct hda_input_mux ad1884_capture_source = { .num_items = 4, .items = { { "Front Mic", 0x0 }, @@ -3366,7 +3368,7 @@ static struct hda_input_mux ad1884_capture_source = { }, }; -static struct snd_kcontrol_new ad1884_base_mixers[] = { +static const struct snd_kcontrol_new ad1884_base_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), @@ -3410,7 +3412,7 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1984_dmic_mixers[] = { +static const struct snd_kcontrol_new ad1984_dmic_mixers[] = { HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0, @@ -3423,7 +3425,7 @@ static struct snd_kcontrol_new ad1984_dmic_mixers[] = { /* * initialization verbs */ -static struct hda_verb ad1884_init_verbs[] = { +static const struct hda_verb ad1884_init_verbs[] = { /* DACs; mute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, @@ -3469,7 +3471,7 @@ static struct hda_verb ad1884_init_verbs[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1884_loopbacks[] = { +static const struct hda_amp_list ad1884_loopbacks[] = { { 0x20, HDA_INPUT, 0 }, /* Front Mic */ { 0x20, HDA_INPUT, 1 }, /* Mic */ { 0x20, HDA_INPUT, 2 }, /* CD */ @@ -3541,7 +3543,7 @@ static int patch_ad1884(struct hda_codec *codec) /* * Lenovo Thinkpad T61/X61 */ -static struct hda_input_mux ad1984_thinkpad_capture_source = { +static const struct hda_input_mux ad1984_thinkpad_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -3555,7 +3557,7 @@ static struct hda_input_mux ad1984_thinkpad_capture_source = { /* * Dell Precision T3400 */ -static struct hda_input_mux ad1984_dell_desktop_capture_source = { +static const struct hda_input_mux ad1984_dell_desktop_capture_source = { .num_items = 3, .items = { { "Front Mic", 0x0 }, @@ -3565,7 +3567,7 @@ static struct hda_input_mux ad1984_dell_desktop_capture_source = { }; -static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { +static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), @@ -3611,7 +3613,7 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { }; /* additional verbs */ -static struct hda_verb ad1984_thinkpad_init_verbs[] = { +static const struct hda_verb ad1984_thinkpad_init_verbs[] = { /* Port-E (docking station mic) pin */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, @@ -3629,7 +3631,7 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = { /* * Dell Precision T3400 */ -static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { +static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), @@ -3680,7 +3682,7 @@ static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream ad1984_pcm_dmic_capture = { +static const struct hda_pcm_stream ad1984_pcm_dmic_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -3722,7 +3724,7 @@ static const char * const ad1984_models[AD1984_MODELS] = { [AD1984_DELL_DESKTOP] = "dell_desktop", }; -static struct snd_pci_quirk ad1984_cfg_tbl[] = { +static const struct snd_pci_quirk ad1984_cfg_tbl[] = { /* Lenovo Thinkpad T61/X61 */ SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD), SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), @@ -3787,7 +3789,7 @@ static int patch_ad1984(struct hda_codec *codec) * We share the single DAC for both HP and line-outs (see AD1884/1984). */ -static hda_nid_t ad1884a_dac_nids[1] = { +static const hda_nid_t ad1884a_dac_nids[1] = { 0x03, }; @@ -3796,7 +3798,7 @@ static hda_nid_t ad1884a_dac_nids[1] = { #define AD1884A_SPDIF_OUT 0x02 -static struct hda_input_mux ad1884a_capture_source = { +static const struct hda_input_mux ad1884a_capture_source = { .num_items = 5, .items = { { "Front Mic", 0x0 }, @@ -3807,7 +3809,7 @@ static struct hda_input_mux ad1884a_capture_source = { }, }; -static struct snd_kcontrol_new ad1884a_base_mixers[] = { +static const struct snd_kcontrol_new ad1884a_base_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), @@ -3859,7 +3861,7 @@ static struct snd_kcontrol_new ad1884a_base_mixers[] = { /* * initialization verbs */ -static struct hda_verb ad1884a_init_verbs[] = { +static const struct hda_verb ad1884a_init_verbs[] = { /* DACs; unmute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ @@ -3914,7 +3916,7 @@ static struct hda_verb ad1884a_init_verbs[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1884a_loopbacks[] = { +static const struct hda_amp_list ad1884a_loopbacks[] = { { 0x20, HDA_INPUT, 0 }, /* Front Mic */ { 0x20, HDA_INPUT, 1 }, /* Mic */ { 0x20, HDA_INPUT, 2 }, /* CD */ @@ -3947,7 +3949,7 @@ static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, return ret; } -static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { +static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -3975,7 +3977,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { +static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ { @@ -4095,7 +4097,7 @@ static int ad1884a_laptop_init(struct hda_codec *codec) } /* additional verbs for laptop model */ -static struct hda_verb ad1884a_laptop_verbs[] = { +static const struct hda_verb ad1884a_laptop_verbs[] = { /* Port-A (HP) pin - always unmuted */ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Port-F (int speaker) mixer - route only from analog mixer */ @@ -4126,7 +4128,7 @@ static struct hda_verb ad1884a_laptop_verbs[] = { { } /* end */ }; -static struct hda_verb ad1884a_mobile_verbs[] = { +static const struct hda_verb ad1884a_mobile_verbs[] = { /* DACs; unmute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ @@ -4181,7 +4183,7 @@ static struct hda_verb ad1884a_mobile_verbs[] = { * 0x17 - built-in mic */ -static struct hda_verb ad1984a_thinkpad_verbs[] = { +static const struct hda_verb ad1984a_thinkpad_verbs[] = { /* HP unmute */ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* analog mix */ @@ -4198,7 +4200,7 @@ static struct hda_verb ad1984a_thinkpad_verbs[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { +static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), @@ -4219,7 +4221,7 @@ static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { { } /* end */ }; -static struct hda_input_mux ad1984a_thinkpad_capture_source = { +static const struct hda_input_mux ad1984a_thinkpad_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -4262,7 +4264,7 @@ static int ad1984a_thinkpad_init(struct hda_codec *codec) * 0x15 - mic-in */ -static struct hda_verb ad1984a_precision_verbs[] = { +static const struct hda_verb ad1984a_precision_verbs[] = { /* Unmute main output path */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */ @@ -4288,7 +4290,7 @@ static struct hda_verb ad1984a_precision_verbs[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1984a_precision_mixers[] = { +static const struct snd_kcontrol_new ad1984a_precision_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), @@ -4344,7 +4346,7 @@ static int ad1984a_precision_init(struct hda_codec *codec) * digital-mic (0x17) - Internal mic */ -static struct hda_verb ad1984a_touchsmart_verbs[] = { +static const struct hda_verb ad1984a_touchsmart_verbs[] = { /* DACs; unmute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ @@ -4396,7 +4398,7 @@ static struct hda_verb ad1984a_touchsmart_verbs[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { +static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ { @@ -4475,7 +4477,7 @@ static const char * const ad1884a_models[AD1884A_MODELS] = { [AD1984A_PRECISION] = "precision", }; -static struct snd_pci_quirk ad1884a_cfg_tbl[] = { +static const struct snd_pci_quirk ad1884a_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION), SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), @@ -4614,22 +4616,22 @@ static int patch_ad1884a(struct hda_codec *codec) * port-G - rear clfe-out (6stack) */ -static hda_nid_t ad1882_dac_nids[3] = { +static const hda_nid_t ad1882_dac_nids[3] = { 0x04, 0x03, 0x05 }; -static hda_nid_t ad1882_adc_nids[2] = { +static const hda_nid_t ad1882_adc_nids[2] = { 0x08, 0x09, }; -static hda_nid_t ad1882_capsrc_nids[2] = { +static const hda_nid_t ad1882_capsrc_nids[2] = { 0x0c, 0x0d, }; #define AD1882_SPDIF_OUT 0x02 /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */ -static struct hda_input_mux ad1882_capture_source = { +static const struct hda_input_mux ad1882_capture_source = { .num_items = 5, .items = { { "Front Mic", 0x1 }, @@ -4641,7 +4643,7 @@ static struct hda_input_mux ad1882_capture_source = { }; /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */ -static struct hda_input_mux ad1882a_capture_source = { +static const struct hda_input_mux ad1882a_capture_source = { .num_items = 5, .items = { { "Front Mic", 0x1 }, @@ -4652,7 +4654,7 @@ static struct hda_input_mux ad1882a_capture_source = { }, }; -static struct snd_kcontrol_new ad1882_base_mixers[] = { +static const struct snd_kcontrol_new ad1882_base_mixers[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), @@ -4694,7 +4696,7 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1882_loopback_mixers[] = { +static const struct snd_kcontrol_new ad1882_loopback_mixers[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), @@ -4706,7 +4708,7 @@ static struct snd_kcontrol_new ad1882_loopback_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1882a_loopback_mixers[] = { +static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), @@ -4719,7 +4721,7 @@ static struct snd_kcontrol_new ad1882a_loopback_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1882_3stack_mixers[] = { +static const struct snd_kcontrol_new ad1882_3stack_mixers[] = { HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT), @@ -4733,14 +4735,14 @@ static struct snd_kcontrol_new ad1882_3stack_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1882_6stack_mixers[] = { +static const struct snd_kcontrol_new ad1882_6stack_mixers[] = { HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT), { } /* end */ }; -static struct hda_verb ad1882_ch2_init[] = { +static const struct hda_verb ad1882_ch2_init[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, @@ -4750,7 +4752,7 @@ static struct hda_verb ad1882_ch2_init[] = { { } /* end */ }; -static struct hda_verb ad1882_ch4_init[] = { +static const struct hda_verb ad1882_ch4_init[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -4760,7 +4762,7 @@ static struct hda_verb ad1882_ch4_init[] = { { } /* end */ }; -static struct hda_verb ad1882_ch6_init[] = { +static const struct hda_verb ad1882_ch6_init[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -4770,7 +4772,7 @@ static struct hda_verb ad1882_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode ad1882_modes[3] = { +static const struct hda_channel_mode ad1882_modes[3] = { { 2, ad1882_ch2_init }, { 4, ad1882_ch4_init }, { 6, ad1882_ch6_init }, @@ -4779,7 +4781,7 @@ static struct hda_channel_mode ad1882_modes[3] = { /* * initialization verbs */ -static struct hda_verb ad1882_init_verbs[] = { +static const struct hda_verb ad1882_init_verbs[] = { /* DACs; mute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, @@ -4848,7 +4850,7 @@ static struct hda_verb ad1882_init_verbs[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1882_loopbacks[] = { +static const struct hda_amp_list ad1882_loopbacks[] = { { 0x20, HDA_INPUT, 0 }, /* Front Mic */ { 0x20, HDA_INPUT, 1 }, /* Mic */ { 0x20, HDA_INPUT, 4 }, /* Line */ @@ -4945,7 +4947,7 @@ static int patch_ad1882(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_analog[] = { +static const struct hda_codec_preset snd_hda_preset_analog[] = { { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index 46c8bf48c31..61b92634b16 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -134,7 +134,7 @@ static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, /* */ -static char *dirstr[2] = { "Playback", "Capture" }; +static const char * const dirstr[2] = { "Playback", "Capture" }; static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, int chan, int dir) @@ -171,7 +171,7 @@ static int ca0110_build_controls(struct hda_codec *codec) { struct ca0110_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - static char *prefix[AUTO_CFG_MAX_OUTS] = { + static const char * const prefix[AUTO_CFG_MAX_OUTS] = { "Front", "Surround", NULL, "Side", "Multi" }; hda_nid_t mutenid; @@ -259,7 +259,7 @@ static int ca0110_build_controls(struct hda_codec *codec) /* */ -static struct hda_pcm_stream ca0110_pcm_analog_playback = { +static const struct hda_pcm_stream ca0110_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -270,7 +270,7 @@ static struct hda_pcm_stream ca0110_pcm_analog_playback = { }, }; -static struct hda_pcm_stream ca0110_pcm_analog_capture = { +static const struct hda_pcm_stream ca0110_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -280,7 +280,7 @@ static struct hda_pcm_stream ca0110_pcm_analog_capture = { }, }; -static struct hda_pcm_stream ca0110_pcm_digital_playback = { +static const struct hda_pcm_stream ca0110_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -291,7 +291,7 @@ static struct hda_pcm_stream ca0110_pcm_digital_playback = { }, }; -static struct hda_pcm_stream ca0110_pcm_digital_capture = { +static const struct hda_pcm_stream ca0110_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -389,7 +389,7 @@ static void ca0110_free(struct hda_codec *codec) kfree(codec->spec); } -static struct hda_codec_ops ca0110_patch_ops = { +static const struct hda_codec_ops ca0110_patch_ops = { .build_controls = ca0110_build_controls, .build_pcms = ca0110_build_pcms, .init = ca0110_init, @@ -539,7 +539,7 @@ static int patch_ca0110(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_ca0110[] = { +static const struct hda_codec_preset snd_hda_preset_ca0110[] = { { .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 }, { .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 }, { .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 }, diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 067982f4f18..26a1521045b 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -51,7 +51,7 @@ struct cs_spec { unsigned int cur_adc_format; hda_nid_t dig_in; - struct hda_bind_ctls *capture_bind[2]; + const struct hda_bind_ctls *capture_bind[2]; unsigned int gpio_mask; unsigned int gpio_dir; @@ -231,7 +231,7 @@ static int cs_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, /* */ -static struct hda_pcm_stream cs_pcm_analog_playback = { +static const struct hda_pcm_stream cs_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -242,7 +242,7 @@ static struct hda_pcm_stream cs_pcm_analog_playback = { }, }; -static struct hda_pcm_stream cs_pcm_analog_capture = { +static const struct hda_pcm_stream cs_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -252,7 +252,7 @@ static struct hda_pcm_stream cs_pcm_analog_capture = { }, }; -static struct hda_pcm_stream cs_pcm_digital_playback = { +static const struct hda_pcm_stream cs_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -264,7 +264,7 @@ static struct hda_pcm_stream cs_pcm_digital_playback = { }, }; -static struct hda_pcm_stream cs_pcm_digital_capture = { +static const struct hda_pcm_stream cs_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -331,8 +331,8 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx) struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t pin = cfg->inputs[idx].pin; - unsigned int val = snd_hda_query_pin_caps(codec, pin); - if (!(val & AC_PINCAP_PRES_DETECT)) + unsigned int val; + if (!is_jack_detectable(codec, pin)) return 0; val = snd_hda_codec_get_pincfg(codec, pin); return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT); @@ -349,8 +349,7 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, hda_nid_t pins[2]; unsigned int type; int j, nums; - type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) - >> AC_WCAP_TYPE_SHIFT; + type = get_wcaps_type(get_wcaps(codec, nid)); if (type != AC_WID_AUD_IN) continue; nums = snd_hda_get_connections(codec, nid, pins, @@ -559,10 +558,10 @@ static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx, const char *name; int err, index; struct snd_kcontrol *kctl; - static char *speakers[] = { + static const char * const speakers[] = { "Front Speaker", "Surround Speaker", "Bass Speaker" }; - static char *line_outs[] = { + static const char * const line_outs[] = { "Front Line-Out", "Surround Line-Out", "Bass Line-Out" }; @@ -642,7 +641,7 @@ static int build_output(struct hda_codec *codec) /* */ -static struct snd_kcontrol_new cs_capture_ctls[] = { +static const struct snd_kcontrol_new cs_capture_ctls[] = { HDA_BIND_SW("Capture Switch", 0), HDA_BIND_VOL("Capture Volume", 0), }; @@ -710,7 +709,7 @@ static int cs_capture_source_put(struct snd_kcontrol *kcontrol, return change_cur_input(codec, idx, 0); } -static struct snd_kcontrol_new cs_capture_source = { +static const struct snd_kcontrol_new cs_capture_source = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -719,7 +718,7 @@ static struct snd_kcontrol_new cs_capture_source = { .put = cs_capture_source_put, }; -static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, +static const struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, struct hda_ctl_ops *ops) { struct cs_spec *spec = codec->spec; @@ -847,15 +846,14 @@ static void cs_automute(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int caps, hp_present; + unsigned int hp_present; hda_nid_t nid; int i; hp_present = 0; for (i = 0; i < cfg->hp_outs; i++) { nid = cfg->hp_pins[i]; - caps = snd_hda_query_pin_caps(codec, nid); - if (!(caps & AC_PINCAP_PRES_DETECT)) + if (!is_jack_detectable(codec, nid)) continue; hp_present = snd_hda_jack_detect(codec, nid); if (hp_present) @@ -924,7 +922,7 @@ static void init_output(struct hda_codec *codec) AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); if (!cfg->speaker_outs) continue; - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { + if (is_jack_detectable(codec, nid)) { snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | HP_EVENT); @@ -983,7 +981,7 @@ static void init_input(struct hda_codec *codec) cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); } -static struct hda_verb cs_coef_init_verbs[] = { +static const struct hda_verb cs_coef_init_verbs[] = { {0x11, AC_VERB_SET_PROC_STATE, 1}, {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG}, {0x11, AC_VERB_SET_PROC_COEF, @@ -1017,7 +1015,7 @@ static struct hda_verb cs_coef_init_verbs[] = { * blocks, which will alleviate the issue. */ -static struct hda_verb cs_errata_init_verbs[] = { +static const struct hda_verb cs_errata_init_verbs[] = { {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */ {0x11, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ @@ -1126,7 +1124,7 @@ static void cs_unsol_event(struct hda_codec *codec, unsigned int res) } } -static struct hda_codec_ops cs_patch_ops = { +static const struct hda_codec_ops cs_patch_ops = { .build_controls = cs_build_controls, .build_pcms = cs_build_pcms, .init = cs_init, @@ -1166,7 +1164,7 @@ static const char * const cs420x_models[CS420X_MODELS] = { }; -static struct snd_pci_quirk cs420x_cfg_tbl[] = { +static const struct snd_pci_quirk cs420x_cfg_tbl[] = { SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53), SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55), SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), @@ -1180,7 +1178,7 @@ struct cs_pincfg { u32 val; }; -static struct cs_pincfg mbp53_pincfgs[] = { +static const struct cs_pincfg mbp53_pincfgs[] = { { 0x09, 0x012b4050 }, { 0x0a, 0x90100141 }, { 0x0b, 0x90100140 }, @@ -1194,7 +1192,7 @@ static struct cs_pincfg mbp53_pincfgs[] = { {} /* terminator */ }; -static struct cs_pincfg mbp55_pincfgs[] = { +static const struct cs_pincfg mbp55_pincfgs[] = { { 0x09, 0x012b4030 }, { 0x0a, 0x90100121 }, { 0x0b, 0x90100120 }, @@ -1208,7 +1206,7 @@ static struct cs_pincfg mbp55_pincfgs[] = { {} /* terminator */ }; -static struct cs_pincfg imac27_pincfgs[] = { +static const struct cs_pincfg imac27_pincfgs[] = { { 0x09, 0x012b4050 }, { 0x0a, 0x90100140 }, { 0x0b, 0x90100142 }, @@ -1222,7 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = { {} /* terminator */ }; -static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { +static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { [CS420X_MBP53] = mbp53_pincfgs, [CS420X_MBP55] = mbp55_pincfgs, [CS420X_IMAC27] = imac27_pincfgs, @@ -1283,7 +1281,7 @@ static int patch_cs420x(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_cirrus[] = { +static const struct hda_codec_preset snd_hda_preset_cirrus[] = { { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, {} /* terminator */ diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 1f8bbcd0f80..ab3308daa96 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -53,7 +53,7 @@ struct cmi_spec { int num_dacs; /* capture */ - hda_nid_t *adc_nids; + const hda_nid_t *adc_nids; hda_nid_t dig_in_nid; /* capture source */ @@ -110,7 +110,7 @@ static int cmi_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v */ /* 3-stack / 2 channel */ -static struct hda_verb cmi9880_ch2_init[] = { +static const struct hda_verb cmi9880_ch2_init[] = { /* set line-in PIN for input */ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* set mic PIN for input, also enable vref */ @@ -121,7 +121,7 @@ static struct hda_verb cmi9880_ch2_init[] = { }; /* 3-stack / 6 channel */ -static struct hda_verb cmi9880_ch6_init[] = { +static const struct hda_verb cmi9880_ch6_init[] = { /* set line-in PIN for output */ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* set mic PIN for output */ @@ -132,7 +132,7 @@ static struct hda_verb cmi9880_ch6_init[] = { }; /* 3-stack+front / 8 channel */ -static struct hda_verb cmi9880_ch8_init[] = { +static const struct hda_verb cmi9880_ch8_init[] = { /* set line-in PIN for output */ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* set mic PIN for output */ @@ -142,7 +142,7 @@ static struct hda_verb cmi9880_ch8_init[] = { {} }; -static struct hda_channel_mode cmi9880_channel_modes[3] = { +static const struct hda_channel_mode cmi9880_channel_modes[3] = { { 2, cmi9880_ch2_init }, { 6, cmi9880_ch6_init }, { 8, cmi9880_ch8_init }, @@ -174,7 +174,7 @@ static int cmi_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va /* */ -static struct snd_kcontrol_new cmi9880_basic_mixer[] = { +static const struct snd_kcontrol_new cmi9880_basic_mixer[] = { /* CMI9880 has no playback volumes! */ HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */ HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT), @@ -205,7 +205,7 @@ static struct snd_kcontrol_new cmi9880_basic_mixer[] = { /* * shared I/O pins */ -static struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = { +static const struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -219,7 +219,7 @@ static struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = { /* AUD-in selections: * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20 */ -static struct hda_input_mux cmi9880_basic_mux = { +static const struct hda_input_mux cmi9880_basic_mux = { .num_items = 4, .items = { { "Front Mic", 0x5 }, @@ -229,7 +229,7 @@ static struct hda_input_mux cmi9880_basic_mux = { } }; -static struct hda_input_mux cmi9880_no_line_mux = { +static const struct hda_input_mux cmi9880_no_line_mux = { .num_items = 3, .items = { { "Front Mic", 0x5 }, @@ -239,11 +239,11 @@ static struct hda_input_mux cmi9880_no_line_mux = { }; /* front, rear, clfe, rear_surr */ -static hda_nid_t cmi9880_dac_nids[4] = { +static const hda_nid_t cmi9880_dac_nids[4] = { 0x03, 0x04, 0x05, 0x06 }; /* ADC0, ADC1 */ -static hda_nid_t cmi9880_adc_nids[2] = { +static const hda_nid_t cmi9880_adc_nids[2] = { 0x08, 0x09 }; @@ -252,7 +252,7 @@ static hda_nid_t cmi9880_adc_nids[2] = { /* */ -static struct hda_verb cmi9880_basic_init[] = { +static const struct hda_verb cmi9880_basic_init[] = { /* port-D for line out (rear panel) */ { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-E for HP out (front panel) */ @@ -281,7 +281,7 @@ static struct hda_verb cmi9880_basic_init[] = { {} /* terminator */ }; -static struct hda_verb cmi9880_allout_init[] = { +static const struct hda_verb cmi9880_allout_init[] = { /* port-D for line out (rear panel) */ { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-E for HP out (front panel) */ @@ -528,7 +528,7 @@ static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, /* */ -static struct hda_pcm_stream cmi9880_pcm_analog_playback = { +static const struct hda_pcm_stream cmi9880_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -540,7 +540,7 @@ static struct hda_pcm_stream cmi9880_pcm_analog_playback = { }, }; -static struct hda_pcm_stream cmi9880_pcm_analog_capture = { +static const struct hda_pcm_stream cmi9880_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -551,7 +551,7 @@ static struct hda_pcm_stream cmi9880_pcm_analog_capture = { }, }; -static struct hda_pcm_stream cmi9880_pcm_digital_playback = { +static const struct hda_pcm_stream cmi9880_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -563,7 +563,7 @@ static struct hda_pcm_stream cmi9880_pcm_digital_playback = { }, }; -static struct hda_pcm_stream cmi9880_pcm_digital_capture = { +static const struct hda_pcm_stream cmi9880_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -617,14 +617,14 @@ static const char * const cmi9880_models[CMI_MODELS] = { [CMI_AUTO] = "auto", }; -static struct snd_pci_quirk cmi9880_cfg_tbl[] = { +static const struct snd_pci_quirk cmi9880_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG), SND_PCI_QUIRK(0x1854, 0x002b, "LG LS75", CMI_MINIMAL), SND_PCI_QUIRK(0x1854, 0x0032, "LG", CMI_FULL_DIG), {} /* terminator */ }; -static struct hda_codec_ops cmi9880_patch_ops = { +static const struct hda_codec_ops cmi9880_patch_ops = { .build_controls = cmi9880_build_controls, .build_pcms = cmi9880_build_pcms, .init = cmi9880_init, @@ -745,7 +745,7 @@ static int patch_cmi9880(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_cmedia[] = { +static const struct hda_codec_preset snd_hda_preset_cmedia[] = { { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 }, { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 }, {} /* terminator */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ad97d937d3a..3e6b9a8539c 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -39,6 +39,7 @@ #define CONEXANT_HP_EVENT 0x37 #define CONEXANT_MIC_EVENT 0x38 +#define CONEXANT_LINE_EVENT 0x39 /* Conexant 5051 specific */ @@ -55,9 +56,16 @@ struct pin_dac_pair { int type; }; +struct imux_info { + hda_nid_t pin; /* input pin NID */ + hda_nid_t adc; /* connected ADC NID */ + hda_nid_t boost; /* optional boost volume NID */ + int index; /* corresponding to autocfg.input */ +}; + struct conexant_spec { - struct snd_kcontrol_new *mixers[5]; + const struct snd_kcontrol_new *mixers[5]; int num_mixers; hda_nid_t vmaster_nid; @@ -74,14 +82,17 @@ struct conexant_spec { */ unsigned int cur_eapd; unsigned int hp_present; + unsigned int line_present; unsigned int auto_mic; - int auto_mic_ext; /* autocfg.inputs[] index for ext mic */ + int auto_mic_ext; /* imux_pins[] index for ext mic */ + int auto_mic_dock; /* imux_pins[] index for dock mic */ + int auto_mic_int; /* imux_pins[] index for int mic */ unsigned int need_dac_fix; hda_nid_t slave_dig_outs[2]; /* capture */ unsigned int num_adc_nids; - hda_nid_t *adc_nids; + const hda_nid_t *adc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ unsigned int cur_adc_idx; @@ -89,9 +100,11 @@ struct conexant_spec { unsigned int cur_adc_stream_tag; unsigned int cur_adc_format; + const struct hda_pcm_stream *capture_stream; + /* capture source */ const struct hda_input_mux *input_mux; - hda_nid_t *capsrc_nids; + const hda_nid_t *capsrc_nids; unsigned int cur_mux[3]; /* channel model */ @@ -106,12 +119,17 @@ struct conexant_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; struct hda_input_mux private_imux; + struct imux_info imux_info[HDA_MAX_NUM_INPUTS]; + hda_nid_t private_adc_nids[HDA_MAX_NUM_INPUTS]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; struct pin_dac_pair dac_info[8]; int dac_info_filled; unsigned int port_d_mode; unsigned int auto_mute:1; /* used in auto-parser */ + unsigned int detect_line:1; /* Line-out detection enabled */ + unsigned int automute_lines:1; /* automute line-out as well */ + unsigned int automute_hp_lo:1; /* both HP and LO available */ unsigned int dell_automute:1; unsigned int dell_vostro:1; unsigned int ideapad:1; @@ -119,6 +137,8 @@ struct conexant_spec { unsigned int hp_laptop:1; unsigned int asus:1; + unsigned int adc_switching:1; + unsigned int ext_mic_present; unsigned int recording; void (*capture_prepare)(struct hda_codec *codec); @@ -227,7 +247,7 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, -static struct hda_pcm_stream conexant_pcm_analog_playback = { +static const struct hda_pcm_stream conexant_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -239,7 +259,7 @@ static struct hda_pcm_stream conexant_pcm_analog_playback = { }, }; -static struct hda_pcm_stream conexant_pcm_analog_capture = { +static const struct hda_pcm_stream conexant_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -251,7 +271,7 @@ static struct hda_pcm_stream conexant_pcm_analog_capture = { }; -static struct hda_pcm_stream conexant_pcm_digital_playback = { +static const struct hda_pcm_stream conexant_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -263,7 +283,7 @@ static struct hda_pcm_stream conexant_pcm_digital_playback = { }, }; -static struct hda_pcm_stream conexant_pcm_digital_capture = { +static const struct hda_pcm_stream conexant_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -294,7 +314,7 @@ static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream cx5051_pcm_analog_capture = { +static const struct hda_pcm_stream cx5051_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -319,13 +339,19 @@ static int conexant_build_pcms(struct hda_codec *codec) spec->multiout.max_channels; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; - if (codec->vendor_id == 0x14f15051) - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - cx5051_pcm_analog_capture; - else - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - conexant_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; + if (spec->capture_stream) + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; + else { + if (codec->vendor_id == 0x14f15051) + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + cx5051_pcm_analog_capture; + else { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + conexant_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = + spec->num_adc_nids; + } + } info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; if (spec->multiout.dig_out_nid) { @@ -433,7 +459,7 @@ static void conexant_free(struct hda_codec *codec) kfree(codec->spec); } -static struct snd_kcontrol_new cxt_capture_mixers[] = { +static const struct snd_kcontrol_new cxt_capture_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", @@ -446,7 +472,7 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = { #ifdef CONFIG_SND_HDA_INPUT_BEEP /* additional beep mixers; the actual parameters are overwritten at build */ -static struct snd_kcontrol_new cxt_beep_mixer[] = { +static const struct snd_kcontrol_new cxt_beep_mixer[] = { HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), { } /* end */ @@ -456,12 +482,18 @@ static struct snd_kcontrol_new cxt_beep_mixer[] = { static const char * const slave_vols[] = { "Headphone Playback Volume", "Speaker Playback Volume", + "Front Playback Volume", + "Surround Playback Volume", + "CLFE Playback Volume", NULL }; static const char * const slave_sws[] = { "Headphone Playback Switch", "Speaker Playback Switch", + "Front Playback Switch", + "Surround Playback Switch", + "CLFE Playback Switch", NULL }; @@ -521,7 +553,7 @@ static int conexant_build_controls(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_INPUT_BEEP /* create beep controls if needed */ if (spec->beep_amp) { - struct snd_kcontrol_new *knew; + const struct snd_kcontrol_new *knew; for (knew = cxt_beep_mixer; knew->name; knew++) { struct snd_kcontrol *kctl; kctl = snd_ctl_new1(knew, codec); @@ -546,7 +578,7 @@ static int conexant_suspend(struct hda_codec *codec, pm_message_t state) } #endif -static struct hda_codec_ops conexant_patch_ops = { +static const struct hda_codec_ops conexant_patch_ops = { .build_controls = conexant_build_controls, .build_pcms = conexant_build_pcms, .init = conexant_init, @@ -564,6 +596,7 @@ static struct hda_codec_ops conexant_patch_ops = { #define set_beep_amp(spec, nid, idx, dir) /* NOP */ #endif +static int patch_conexant_auto(struct hda_codec *codec); /* * EAPD control * the private value = nid | (invert << 8) @@ -662,16 +695,16 @@ static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, /* Conexant 5045 specific */ -static hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; -static hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; -static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; +static const hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; +static const hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; +static const hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; #define CXT5045_SPDIF_OUT 0x18 -static struct hda_channel_mode cxt5045_modes[1] = { +static const struct hda_channel_mode cxt5045_modes[1] = { { 2, NULL }, }; -static struct hda_input_mux cxt5045_capture_source = { +static const struct hda_input_mux cxt5045_capture_source = { .num_items = 2, .items = { { "IntMic", 0x1 }, @@ -679,7 +712,7 @@ static struct hda_input_mux cxt5045_capture_source = { } }; -static struct hda_input_mux cxt5045_capture_source_benq = { +static const struct hda_input_mux cxt5045_capture_source_benq = { .num_items = 5, .items = { { "IntMic", 0x1 }, @@ -690,7 +723,7 @@ static struct hda_input_mux cxt5045_capture_source_benq = { } }; -static struct hda_input_mux cxt5045_capture_source_hp530 = { +static const struct hda_input_mux cxt5045_capture_source_hp530 = { .num_items = 2, .items = { { "ExtMic", 0x1 }, @@ -723,7 +756,7 @@ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, } /* bind volumes of both NID 0x10 and 0x11 */ -static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { +static const struct hda_bind_ctls cxt5045_hp_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), @@ -735,12 +768,12 @@ static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { /* toggle input of built-in and mic jack appropriately */ static void cxt5045_hp_automic(struct hda_codec *codec) { - static struct hda_verb mic_jack_on[] = { + static const struct hda_verb mic_jack_on[] = { {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, {} }; - static struct hda_verb mic_jack_off[] = { + static const struct hda_verb mic_jack_off[] = { {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, {} @@ -784,7 +817,7 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec, } } -static struct snd_kcontrol_new cxt5045_mixers[] = { +static const struct snd_kcontrol_new cxt5045_mixers[] = { HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), @@ -808,7 +841,7 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5045_benq_mixers[] = { +static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT), @@ -825,7 +858,7 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { +static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = { HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), @@ -849,7 +882,7 @@ static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { {} }; -static struct hda_verb cxt5045_init_verbs[] = { +static const struct hda_verb cxt5045_init_verbs[] = { /* Line in, Mic */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, @@ -875,7 +908,7 @@ static struct hda_verb cxt5045_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5045_benq_init_verbs[] = { +static const struct hda_verb cxt5045_benq_init_verbs[] = { /* Internal Mic, Mic */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, @@ -901,13 +934,13 @@ static struct hda_verb cxt5045_benq_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5045_hp_sense_init_verbs[] = { +static const struct hda_verb cxt5045_hp_sense_init_verbs[] = { /* pin sensing on HP jack */ {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, { } /* end */ }; -static struct hda_verb cxt5045_mic_sense_init_verbs[] = { +static const struct hda_verb cxt5045_mic_sense_init_verbs[] = { /* pin sensing on HP jack */ {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, { } /* end */ @@ -917,7 +950,7 @@ static struct hda_verb cxt5045_mic_sense_init_verbs[] = { /* Test configuration for debugging, modelled after the ALC260 test * configuration. */ -static struct hda_input_mux cxt5045_test_capture_source = { +static const struct hda_input_mux cxt5045_test_capture_source = { .num_items = 5, .items = { { "MIXER", 0x0 }, @@ -928,7 +961,7 @@ static struct hda_input_mux cxt5045_test_capture_source = { }, }; -static struct snd_kcontrol_new cxt5045_test_mixer[] = { +static const struct snd_kcontrol_new cxt5045_test_mixer[] = { /* Output controls */ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), @@ -978,7 +1011,7 @@ static struct snd_kcontrol_new cxt5045_test_mixer[] = { { } /* end */ }; -static struct hda_verb cxt5045_test_init_verbs[] = { +static const struct hda_verb cxt5045_test_init_verbs[] = { /* Set connections */ { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, { 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 }, @@ -1047,6 +1080,7 @@ enum { #ifdef CONFIG_SND_DEBUG CXT5045_TEST, #endif + CXT5045_AUTO, CXT5045_MODELS }; @@ -1059,9 +1093,10 @@ static const char * const cxt5045_models[CXT5045_MODELS] = { #ifdef CONFIG_SND_DEBUG [CXT5045_TEST] = "test", #endif + [CXT5045_AUTO] = "auto", }; -static struct snd_pci_quirk cxt5045_cfg_tbl[] = { +static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", CXT5045_LAPTOP_HPSENSE), @@ -1085,6 +1120,16 @@ static int patch_cxt5045(struct hda_codec *codec) struct conexant_spec *spec; int board_config; + board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, + cxt5045_models, + cxt5045_cfg_tbl); +#if 0 /* use the old method just for safety */ + if (board_config < 0) + board_config = CXT5045_AUTO; +#endif + if (board_config == CXT5045_AUTO) + return patch_conexant_auto(codec); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; @@ -1111,9 +1156,6 @@ static int patch_cxt5045(struct hda_codec *codec) codec->patch_ops = conexant_patch_ops; - board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, - cxt5045_models, - cxt5045_cfg_tbl); switch (board_config) { case CXT5045_LAPTOP_HPSENSE: codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; @@ -1196,15 +1238,15 @@ static int patch_cxt5045(struct hda_codec *codec) /* Conexant 5047 specific */ #define CXT5047_SPDIF_OUT 0x11 -static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ -static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; -static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; +static const hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ +static const hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; +static const hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; -static struct hda_channel_mode cxt5047_modes[1] = { +static const struct hda_channel_mode cxt5047_modes[1] = { { 2, NULL }, }; -static struct hda_input_mux cxt5047_toshiba_capture_source = { +static const struct hda_input_mux cxt5047_toshiba_capture_source = { .num_items = 2, .items = { { "ExtMic", 0x2 }, @@ -1256,12 +1298,12 @@ static void cxt5047_hp_automute(struct hda_codec *codec) /* toggle input of built-in and mic jack appropriately */ static void cxt5047_hp_automic(struct hda_codec *codec) { - static struct hda_verb mic_jack_on[] = { + static const struct hda_verb mic_jack_on[] = { {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {} }; - static struct hda_verb mic_jack_off[] = { + static const struct hda_verb mic_jack_off[] = { {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {} @@ -1289,7 +1331,7 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec, } } -static struct snd_kcontrol_new cxt5047_base_mixers[] = { +static const struct snd_kcontrol_new cxt5047_base_mixers[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), @@ -1309,19 +1351,19 @@ static struct snd_kcontrol_new cxt5047_base_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { +static const struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { /* See the note in cxt5047_hp_master_sw_put */ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), {} }; -static struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { +static const struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), { } /* end */ }; -static struct hda_verb cxt5047_init_verbs[] = { +static const struct hda_verb cxt5047_init_verbs[] = { /* Line in, Mic, Built-in Mic */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, @@ -1348,7 +1390,7 @@ static struct hda_verb cxt5047_init_verbs[] = { }; /* configuration for Toshiba Laptops */ -static struct hda_verb cxt5047_toshiba_init_verbs[] = { +static const struct hda_verb cxt5047_toshiba_init_verbs[] = { {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ {} }; @@ -1357,7 +1399,7 @@ static struct hda_verb cxt5047_toshiba_init_verbs[] = { * configuration. */ #ifdef CONFIG_SND_DEBUG -static struct hda_input_mux cxt5047_test_capture_source = { +static const struct hda_input_mux cxt5047_test_capture_source = { .num_items = 4, .items = { { "LINE1 pin", 0x0 }, @@ -1367,7 +1409,7 @@ static struct hda_input_mux cxt5047_test_capture_source = { }, }; -static struct snd_kcontrol_new cxt5047_test_mixer[] = { +static const struct snd_kcontrol_new cxt5047_test_mixer[] = { /* Output only controls */ HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), @@ -1420,7 +1462,7 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = { { } /* end */ }; -static struct hda_verb cxt5047_test_init_verbs[] = { +static const struct hda_verb cxt5047_test_init_verbs[] = { /* Enable retasking pins as output, initially without power amp */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -1492,6 +1534,7 @@ enum { #ifdef CONFIG_SND_DEBUG CXT5047_TEST, #endif + CXT5047_AUTO, CXT5047_MODELS }; @@ -1502,9 +1545,10 @@ static const char * const cxt5047_models[CXT5047_MODELS] = { #ifdef CONFIG_SND_DEBUG [CXT5047_TEST] = "test", #endif + [CXT5047_AUTO] = "auto", }; -static struct snd_pci_quirk cxt5047_cfg_tbl[] = { +static const struct snd_pci_quirk cxt5047_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", CXT5047_LAPTOP), @@ -1517,6 +1561,16 @@ static int patch_cxt5047(struct hda_codec *codec) struct conexant_spec *spec; int board_config; + board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, + cxt5047_models, + cxt5047_cfg_tbl); +#if 0 /* not enabled as default, as BIOS often broken for this codec */ + if (board_config < 0) + board_config = CXT5047_AUTO; +#endif + if (board_config == CXT5047_AUTO) + return patch_conexant_auto(codec); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; @@ -1540,9 +1594,6 @@ static int patch_cxt5047(struct hda_codec *codec) codec->patch_ops = conexant_patch_ops; - board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, - cxt5047_models, - cxt5047_cfg_tbl); switch (board_config) { case CXT5047_LAPTOP: spec->num_mixers = 2; @@ -1591,10 +1642,10 @@ static int patch_cxt5047(struct hda_codec *codec) } /* Conexant 5051 specific */ -static hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; -static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; +static const hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; +static const hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; -static struct hda_channel_mode cxt5051_modes[1] = { +static const struct hda_channel_mode cxt5051_modes[1] = { { 2, NULL }, }; @@ -1696,7 +1747,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec, snd_hda_input_jack_report(codec, nid); } -static struct snd_kcontrol_new cxt5051_playback_mixers[] = { +static const struct snd_kcontrol_new cxt5051_playback_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1709,7 +1760,7 @@ static struct snd_kcontrol_new cxt5051_playback_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5051_capture_mixers[] = { +static const struct snd_kcontrol_new cxt5051_capture_mixers[] = { HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), @@ -1719,7 +1770,7 @@ static struct snd_kcontrol_new cxt5051_capture_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5051_hp_mixers[] = { +static const struct snd_kcontrol_new cxt5051_hp_mixers[] = { HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT), @@ -1727,19 +1778,19 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { +static const struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), {} }; -static struct snd_kcontrol_new cxt5051_f700_mixers[] = { +static const struct snd_kcontrol_new cxt5051_f700_mixers[] = { HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), {} }; -static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { +static const struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), @@ -1747,7 +1798,7 @@ static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { {} }; -static struct hda_verb cxt5051_init_verbs[] = { +static const struct hda_verb cxt5051_init_verbs[] = { /* Line in, Mic */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, @@ -1776,7 +1827,7 @@ static struct hda_verb cxt5051_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { +static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { /* Line in, Mic */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, @@ -1801,7 +1852,7 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { +static const struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { /* Line in, Mic */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, @@ -1834,7 +1885,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5051_f700_init_verbs[] = { +static const struct hda_verb cxt5051_f700_init_verbs[] = { /* Line in, Mic */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, @@ -1869,7 +1920,7 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, snd_hda_input_jack_report(codec, nid); } -static struct hda_verb cxt5051_ideapad_init_verbs[] = { +static const struct hda_verb cxt5051_ideapad_init_verbs[] = { /* Subwoofer */ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -1906,6 +1957,7 @@ enum { CXT5051_F700, /* HP Compaq Presario F700 */ CXT5051_TOSHIBA, /* Toshiba M300 & co */ CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ + CXT5051_AUTO, /* auto-parser */ CXT5051_MODELS }; @@ -1917,9 +1969,10 @@ static const char *const cxt5051_models[CXT5051_MODELS] = { [CXT5051_F700] = "hp-700", [CXT5051_TOSHIBA] = "toshiba", [CXT5051_IDEAPAD] = "ideapad", + [CXT5051_AUTO] = "auto", }; -static struct snd_pci_quirk cxt5051_cfg_tbl[] = { +static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), @@ -1937,6 +1990,16 @@ static int patch_cxt5051(struct hda_codec *codec) struct conexant_spec *spec; int board_config; + board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, + cxt5051_models, + cxt5051_cfg_tbl); +#if 0 /* use the old method just for safety */ + if (board_config < 0) + board_config = CXT5051_AUTO; +#endif + if (board_config == CXT5051_AUTO) + return patch_conexant_auto(codec); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; @@ -1967,9 +2030,6 @@ static int patch_cxt5051(struct hda_codec *codec) codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; - board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, - cxt5051_models, - cxt5051_cfg_tbl); spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; switch (board_config) { case CXT5051_HP: @@ -2011,17 +2071,17 @@ static int patch_cxt5051(struct hda_codec *codec) /* Conexant 5066 specific */ -static hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; -static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; -static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; -static hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; +static const hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; +static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; +static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; +static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; /* OLPC's microphone port is DC coupled for use with external sensors, * therefore we use a 50% mic bias in order to center the input signal with * the DC input range of the codec. */ #define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 -static struct hda_channel_mode cxt5066_modes[1] = { +static const struct hda_channel_mode cxt5066_modes[1] = { { 2, NULL }, }; @@ -2176,7 +2236,7 @@ static void cxt5066_vostro_automic(struct hda_codec *codec) {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {} }; - static struct hda_verb ext_mic_absent[] = { + static const struct hda_verb ext_mic_absent[] = { /* enable internal mic, port C */ {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -2209,7 +2269,7 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {} }; - static struct hda_verb ext_mic_absent[] = { + static const struct hda_verb ext_mic_absent[] = { {0x14, AC_VERB_SET_CONNECT_SEL, 2}, {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, @@ -2257,7 +2317,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) { unsigned int ext_present, dock_present; - static struct hda_verb ext_mic_present[] = { + static const struct hda_verb ext_mic_present[] = { {0x14, AC_VERB_SET_CONNECT_SEL, 0}, {0x17, AC_VERB_SET_CONNECT_SEL, 1}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, @@ -2265,7 +2325,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {} }; - static struct hda_verb dock_mic_present[] = { + static const struct hda_verb dock_mic_present[] = { {0x14, AC_VERB_SET_CONNECT_SEL, 0}, {0x17, AC_VERB_SET_CONNECT_SEL, 0}, {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, @@ -2273,7 +2333,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {} }; - static struct hda_verb ext_mic_absent[] = { + static const struct hda_verb ext_mic_absent[] = { {0x14, AC_VERB_SET_CONNECT_SEL, 2}, {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, @@ -2537,7 +2597,7 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) } static void conexant_check_dig_outs(struct hda_codec *codec, - hda_nid_t *dig_pins, + const hda_nid_t *dig_pins, int num_pins) { struct conexant_spec *spec = codec->spec; @@ -2557,7 +2617,7 @@ static void conexant_check_dig_outs(struct hda_codec *codec, } } -static struct hda_input_mux cxt5066_capture_source = { +static const struct hda_input_mux cxt5066_capture_source = { .num_items = 4, .items = { { "Mic B", 0 }, @@ -2567,7 +2627,7 @@ static struct hda_input_mux cxt5066_capture_source = { }, }; -static struct hda_bind_ctls cxt5066_bind_capture_vol_others = { +static const struct hda_bind_ctls cxt5066_bind_capture_vol_others = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), @@ -2576,7 +2636,7 @@ static struct hda_bind_ctls cxt5066_bind_capture_vol_others = { }, }; -static struct hda_bind_ctls cxt5066_bind_capture_sw_others = { +static const struct hda_bind_ctls cxt5066_bind_capture_sw_others = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), @@ -2585,12 +2645,12 @@ static struct hda_bind_ctls cxt5066_bind_capture_sw_others = { }, }; -static struct snd_kcontrol_new cxt5066_mixer_master[] = { +static const struct snd_kcontrol_new cxt5066_mixer_master[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), {} }; -static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { +static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", @@ -2609,7 +2669,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { {} }; -static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { +static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DC Mode Enable Switch", @@ -2627,7 +2687,7 @@ static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { {} }; -static struct snd_kcontrol_new cxt5066_mixers[] = { +static const struct snd_kcontrol_new cxt5066_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -2650,7 +2710,7 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { +static const struct snd_kcontrol_new cxt5066_vostro_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Internal Mic Boost Capture Enum", @@ -2662,7 +2722,7 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { {} }; -static struct hda_verb cxt5066_init_verbs[] = { +static const struct hda_verb cxt5066_init_verbs[] = { {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ @@ -2717,7 +2777,7 @@ static struct hda_verb cxt5066_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_olpc[] = { +static const struct hda_verb cxt5066_init_verbs_olpc[] = { /* Port A: headphones */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ @@ -2778,7 +2838,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_vostro[] = { +static const struct hda_verb cxt5066_init_verbs_vostro[] = { /* Port A: headphones */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ @@ -2839,7 +2899,7 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = { { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_ideapad[] = { +static const struct hda_verb cxt5066_init_verbs_ideapad[] = { {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ @@ -2889,7 +2949,7 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = { { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_thinkpad[] = { +static const struct hda_verb cxt5066_init_verbs_thinkpad[] = { {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ @@ -2947,13 +3007,13 @@ static struct hda_verb cxt5066_init_verbs_thinkpad[] = { { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_portd_lo[] = { +static const struct hda_verb cxt5066_init_verbs_portd_lo[] = { {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_hp_laptop[] = { +static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = { {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, @@ -2997,6 +3057,7 @@ enum { CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */ CXT5066_HP_LAPTOP, /* HP Laptop */ + CXT5066_AUTO, /* BIOS auto-parser */ CXT5066_MODELS }; @@ -3009,9 +3070,10 @@ static const char * const cxt5066_models[CXT5066_MODELS] = { [CXT5066_THINKPAD] = "thinkpad", [CXT5066_ASUS] = "asus", [CXT5066_HP_LAPTOP] = "hp-laptop", + [CXT5066_AUTO] = "auto", }; -static struct snd_pci_quirk cxt5066_cfg_tbl[] = { +static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), @@ -3036,7 +3098,9 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), + SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO), SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */ {} }; @@ -3046,6 +3110,15 @@ static int patch_cxt5066(struct hda_codec *codec) struct conexant_spec *spec; int board_config; + board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, + cxt5066_models, cxt5066_cfg_tbl); +#if 0 /* use the old method just for safety */ + if (board_config < 0) + board_config = CXT5066_AUTO; +#endif + if (board_config == CXT5066_AUTO) + return patch_conexant_auto(codec); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; @@ -3076,8 +3149,6 @@ static int patch_cxt5066(struct hda_codec *codec) set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); - board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, - cxt5066_models, cxt5066_cfg_tbl); switch (board_config) { default: case CXT5066_LAPTOP: @@ -3195,7 +3266,45 @@ static int patch_cxt5066(struct hda_codec *codec) * Automatic parser for CX20641 & co */ -static hda_nid_t cx_auto_adc_nids[] = { 0x14 }; +static int cx_auto_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct conexant_spec *spec = codec->spec; + hda_nid_t adc = spec->imux_info[spec->cur_mux[0]].adc; + if (spec->adc_switching) { + spec->cur_adc = adc; + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + } + snd_hda_codec_setup_stream(codec, adc, stream_tag, 0, format); + return 0; +} + +static int cx_auto_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct conexant_spec *spec = codec->spec; + snd_hda_codec_cleanup_stream(codec, spec->cur_adc); + spec->cur_adc = 0; + return 0; +} + +static const struct hda_pcm_stream cx_auto_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .prepare = cx_auto_capture_pcm_prepare, + .cleanup = cx_auto_capture_pcm_cleanup + }, +}; + +static const hda_nid_t cx_auto_adc_nids[] = { 0x14 }; /* get the connection index of @nid in the widget @mux */ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, @@ -3320,61 +3429,349 @@ static void cx_auto_parse_output(struct hda_codec *codec) spec->multiout.dac_nids = spec->private_dac_nids; spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (cfg->hp_outs > 0) - spec->auto_mute = 1; + for (i = 0; i < cfg->hp_outs; i++) { + if (is_jack_detectable(codec, cfg->hp_pins[i])) { + spec->auto_mute = 1; + break; + } + } + if (spec->auto_mute && + cfg->line_out_pins[0] && + cfg->line_out_type != AUTO_PIN_SPEAKER_OUT && + cfg->line_out_pins[0] != cfg->hp_pins[0] && + cfg->line_out_pins[0] != cfg->speaker_pins[0]) { + for (i = 0; i < cfg->line_outs; i++) { + if (is_jack_detectable(codec, cfg->line_out_pins[i])) { + spec->detect_line = 1; + break; + } + } + spec->automute_lines = spec->detect_line; + } + spec->vmaster_nid = spec->private_dac_nids[0]; } +static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, + hda_nid_t *pins, bool on); + +static void do_automute(struct hda_codec *codec, int num_pins, + hda_nid_t *pins, bool on) +{ + int i; + for (i = 0; i < num_pins; i++) + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + on ? PIN_OUT : 0); + cx_auto_turn_eapd(codec, num_pins, pins, on); +} + +static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) +{ + int i, present = 0; + + for (i = 0; i < num_pins; i++) { + hda_nid_t nid = pins[i]; + if (!nid || !is_jack_detectable(codec, nid)) + break; + snd_hda_input_jack_report(codec, nid); + present |= snd_hda_jack_detect(codec, nid); + } + return present; +} + /* auto-mute/unmute speaker and line outs according to headphone jack */ +static void cx_auto_update_speakers(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int on = 1; + + /* turn on HP EAPD when HP jacks are present */ + if (spec->auto_mute) + on = spec->hp_present; + cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); + /* mute speakers in auto-mode if HP or LO jacks are plugged */ + if (spec->auto_mute) + on = !(spec->hp_present || + (spec->detect_line && spec->line_present)); + do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, on); + + /* toggle line-out mutes if needed, too */ + /* if LO is a copy of either HP or Speaker, don't need to handle it */ + if (cfg->line_out_pins[0] == cfg->hp_pins[0] || + cfg->line_out_pins[0] == cfg->speaker_pins[0]) + return; + if (spec->auto_mute) { + /* mute LO in auto-mode when HP jack is present */ + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT || + spec->automute_lines) + on = !spec->hp_present; + else + on = 1; + } + do_automute(codec, cfg->line_outs, cfg->line_out_pins, on); +} + static void cx_auto_hp_automute(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i, present; if (!spec->auto_mute) return; - present = 0; - for (i = 0; i < cfg->hp_outs; i++) { - if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) { - present = 1; - break; - } + spec->hp_present = detect_jacks(codec, cfg->hp_outs, cfg->hp_pins); + cx_auto_update_speakers(codec); +} + +static void cx_auto_line_automute(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (!spec->auto_mute || !spec->detect_line) + return; + spec->line_present = detect_jacks(codec, cfg->line_outs, + cfg->line_out_pins); + cx_auto_update_speakers(codec); +} + +static int cx_automute_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + static const char * const texts2[] = { + "Disabled", "Enabled" + }; + static const char * const texts3[] = { + "Disabled", "Speaker Only", "Line-Out+Speaker" + }; + const char * const *texts; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + if (spec->automute_hp_lo) { + uinfo->value.enumerated.items = 3; + texts = texts3; + } else { + uinfo->value.enumerated.items = 2; + texts = texts2; } - for (i = 0; i < cfg->line_outs; i++) { - snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - present ? 0 : PIN_OUT); + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int cx_automute_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + unsigned int val; + if (!spec->auto_mute) + val = 0; + else if (!spec->automute_lines) + val = 1; + else + val = 2; + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int cx_automute_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + + switch (ucontrol->value.enumerated.item[0]) { + case 0: + if (!spec->auto_mute) + return 0; + spec->auto_mute = 0; + break; + case 1: + if (spec->auto_mute && !spec->automute_lines) + return 0; + spec->auto_mute = 1; + spec->automute_lines = 0; + break; + case 2: + if (!spec->automute_hp_lo) + return -EINVAL; + if (spec->auto_mute && spec->automute_lines) + return 0; + spec->auto_mute = 1; + spec->automute_lines = 1; + break; + default: + return -EINVAL; } - for (i = 0; !present && i < cfg->line_outs; i++) - if (snd_hda_jack_detect(codec, cfg->line_out_pins[i])) - present = 1; - for (i = 0; i < cfg->speaker_outs; i++) { - snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - present ? 0 : PIN_OUT); + cx_auto_update_speakers(codec); + return 1; +} + +static const struct snd_kcontrol_new cx_automute_mode_enum[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Auto-Mute Mode", + .info = cx_automute_mode_info, + .get = cx_automute_mode_get, + .put = cx_automute_mode_put, + }, + { } +}; + +static int cx_auto_mux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + + return snd_hda_input_mux_info(&spec->private_imux, uinfo); +} + +static int cx_auto_mux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->cur_mux[0]; + return 0; +} + +/* look for the route the given pin from mux and return the index; + * if do_select is set, actually select the route. + */ +static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t pin, hda_nid_t *srcp, + bool do_select, int depth) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int i, nums; + + switch (get_wcaps_type(get_wcaps(codec, mux))) { + case AC_WID_AUD_IN: + case AC_WID_AUD_SEL: + case AC_WID_AUD_MIX: + break; + default: + return -1; + } + + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + for (i = 0; i < nums; i++) + if (conn[i] == pin) { + if (do_select) + snd_hda_codec_write(codec, mux, 0, + AC_VERB_SET_CONNECT_SEL, i); + if (srcp) + *srcp = mux; + return i; + } + depth++; + if (depth == 2) + return -1; + for (i = 0; i < nums; i++) { + int ret = __select_input_connection(codec, conn[i], pin, srcp, + do_select, depth); + if (ret >= 0) { + if (do_select) + snd_hda_codec_write(codec, mux, 0, + AC_VERB_SET_CONNECT_SEL, i); + return i; + } } + return -1; +} + +static void select_input_connection(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t pin) +{ + __select_input_connection(codec, mux, pin, NULL, true, 0); +} + +static int get_input_connection(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t pin) +{ + return __select_input_connection(codec, mux, pin, NULL, false, 0); +} + +static int cx_auto_mux_enum_update(struct hda_codec *codec, + const struct hda_input_mux *imux, + unsigned int idx) +{ + struct conexant_spec *spec = codec->spec; + hda_nid_t adc; + int changed = 1; + + if (!imux->num_items) + return 0; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (spec->cur_mux[0] == idx) + changed = 0; + adc = spec->imux_info[idx].adc; + select_input_connection(codec, spec->imux_info[idx].adc, + spec->imux_info[idx].pin); + if (spec->cur_adc && spec->cur_adc != adc) { + /* stream is running, let's swap the current ADC */ + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); + spec->cur_adc = adc; + snd_hda_codec_setup_stream(codec, adc, + spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); + } + spec->cur_mux[0] = idx; + return changed; +} + +static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct conexant_spec *spec = codec->spec; + + return cx_auto_mux_enum_update(codec, &spec->private_imux, + ucontrol->value.enumerated.item[0]); +} + +static const struct snd_kcontrol_new cx_auto_capture_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = cx_auto_mux_enum_info, + .get = cx_auto_mux_enum_get, + .put = cx_auto_mux_enum_put + }, + {} +}; + +static bool select_automic(struct hda_codec *codec, int idx, bool detect) +{ + struct conexant_spec *spec = codec->spec; + if (idx < 0) + return false; + if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin)) + return false; + cx_auto_mux_enum_update(codec, &spec->private_imux, idx); + return true; } /* automatic switch internal and external mic */ static void cx_auto_automic(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct hda_input_mux *imux = &spec->private_imux; - int ext_idx = spec->auto_mic_ext; if (!spec->auto_mic) return; - if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) { - snd_hda_codec_write(codec, spec->adc_nids[0], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[ext_idx].index); - } else { - snd_hda_codec_write(codec, spec->adc_nids[0], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[!ext_idx].index); - } + if (!select_automic(codec, spec->auto_mic_ext, true)) + if (!select_automic(codec, spec->auto_mic_dock, true)) + select_automic(codec, spec->auto_mic_int, false); } static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) @@ -3383,7 +3780,9 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) switch (res >> 26) { case CONEXANT_HP_EVENT: cx_auto_hp_automute(codec); - snd_hda_input_jack_report(codec, nid); + break; + case CONEXANT_LINE_EVENT: + cx_auto_line_automute(codec); break; case CONEXANT_MIC_EVENT: cx_auto_automic(codec); @@ -3392,43 +3791,45 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) } } -/* return true if it's an internal-mic pin */ -static int is_int_mic(struct hda_codec *codec, hda_nid_t pin) -{ - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); - return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && - snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT; -} - -/* return true if it's an external-mic pin */ -static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin) -{ - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); - return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && - snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL && - (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT); -} - /* check whether the pin config is suitable for auto-mic switching; - * auto-mic is enabled only when one int-mic and one-ext mic exist + * auto-mic is enabled only when one int-mic and one ext- and/or + * one dock-mic exist */ static void cx_auto_check_auto_mic(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; + int pset[INPUT_PIN_ATTR_NORMAL + 1]; + int i; - if (is_ext_mic(codec, cfg->inputs[0].pin) && - is_int_mic(codec, cfg->inputs[1].pin)) { - spec->auto_mic = 1; - spec->auto_mic_ext = 1; - return; - } - if (is_int_mic(codec, cfg->inputs[1].pin) && - is_ext_mic(codec, cfg->inputs[0].pin)) { - spec->auto_mic = 1; - spec->auto_mic_ext = 0; - return; + for (i = 0; i < ARRAY_SIZE(pset); i++) + pset[i] = -1; + for (i = 0; i < spec->private_imux.num_items; i++) { + hda_nid_t pin = spec->imux_info[i].pin; + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); + int type, attr; + attr = snd_hda_get_input_pin_attr(def_conf); + if (attr == INPUT_PIN_ATTR_UNUSED) + return; /* invalid entry */ + if (attr > INPUT_PIN_ATTR_NORMAL) + attr = INPUT_PIN_ATTR_NORMAL; + if (attr != INPUT_PIN_ATTR_INT && + !is_jack_detectable(codec, pin)) + return; /* non-detectable pin */ + type = get_defcfg_device(def_conf); + if (type != AC_JACK_MIC_IN && + (attr != INPUT_PIN_ATTR_DOCK || type != AC_JACK_LINE_IN)) + return; /* no valid input type */ + if (pset[attr] >= 0) + return; /* already occupied */ + pset[attr] = i; } + if (pset[INPUT_PIN_ATTR_INT] < 0 || + (pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK])) + return; /* no input to switch*/ + spec->auto_mic = 1; + spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL]; + spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK]; + spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT]; } static void cx_auto_parse_input(struct hda_codec *codec) @@ -3436,22 +3837,37 @@ static void cx_auto_parse_input(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; struct hda_input_mux *imux; - int i; + int i, j; imux = &spec->private_imux; for (i = 0; i < cfg->num_inputs; i++) { - int idx = get_connection_index(codec, spec->adc_nids[0], - cfg->inputs[i].pin); - if (idx >= 0) { - const char *label; - label = hda_get_autocfg_input_label(codec, cfg, i); - snd_hda_add_imux_item(imux, label, idx, NULL); + for (j = 0; j < spec->num_adc_nids; j++) { + hda_nid_t adc = spec->adc_nids[j]; + int idx = get_input_connection(codec, adc, + cfg->inputs[i].pin); + if (idx >= 0) { + const char *label; + label = hda_get_autocfg_input_label(codec, cfg, i); + spec->imux_info[imux->num_items].index = i; + spec->imux_info[imux->num_items].boost = 0; + spec->imux_info[imux->num_items].adc = adc; + spec->imux_info[imux->num_items].pin = + cfg->inputs[i].pin; + snd_hda_add_imux_item(imux, label, idx, NULL); + break; + } } } - if (imux->num_items == 2 && cfg->num_inputs == 2) + if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items) cx_auto_check_auto_mic(codec); - if (imux->num_items > 1 && !spec->auto_mic) - spec->input_mux = imux; + if (imux->num_items > 1 && !spec->auto_mic) { + for (i = 1; i < imux->num_items; i++) { + if (spec->imux_info[i].adc != spec->imux_info[0].adc) { + spec->adc_switching = 1; + break; + } + } + } } /* get digital-input audio widget corresponding to the given pin */ @@ -3517,14 +3933,15 @@ static int cx_auto_parse_auto_config(struct hda_codec *codec) return 0; } -static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins, - hda_nid_t *pins) +static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, + hda_nid_t *pins, bool on) { int i; for (i = 0; i < num_pins; i++) { if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD) snd_hda_codec_write(codec, pins[i], 0, - AC_VERB_SET_EAPD_BTLENABLE, 0x02); + AC_VERB_SET_EAPD_BTLENABLE, + on ? 0x02 : 0); } } @@ -3537,6 +3954,34 @@ static void select_connection(struct hda_codec *codec, hda_nid_t pin, AC_VERB_SET_CONNECT_SEL, idx); } +static void mute_outputs(struct hda_codec *codec, int num_nids, + const hda_nid_t *nids) +{ + int i, val; + + for (i = 0; i < num_nids; i++) { + hda_nid_t nid = nids[i]; + if (!(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + continue; + if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE) + val = AMP_OUT_MUTE; + else + val = AMP_OUT_ZERO; + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, val); + } +} + +static void enable_unsol_pins(struct hda_codec *codec, int num_pins, + hda_nid_t *pins, unsigned int tag) +{ + int i; + for (i = 0; i < num_pins; i++) + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | tag); +} + static void cx_auto_init_output(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -3544,51 +3989,53 @@ static void cx_auto_init_output(struct hda_codec *codec) hda_nid_t nid; int i; - for (i = 0; i < spec->multiout.num_dacs; i++) - snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - + mute_outputs(codec, spec->multiout.num_dacs, spec->multiout.dac_nids); for (i = 0; i < cfg->hp_outs; i++) snd_hda_codec_write(codec, cfg->hp_pins[i], 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); - if (spec->auto_mute) { - for (i = 0; i < cfg->hp_outs; i++) { - snd_hda_codec_write(codec, cfg->hp_pins[i], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | CONEXANT_HP_EVENT); - } - cx_auto_hp_automute(codec); - } else { - for (i = 0; i < cfg->line_outs; i++) - snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - for (i = 0; i < cfg->speaker_outs; i++) - snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - } - + mute_outputs(codec, cfg->hp_outs, cfg->hp_pins); + mute_outputs(codec, cfg->line_outs, cfg->line_out_pins); + mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins); for (i = 0; i < spec->dac_info_filled; i++) { nid = spec->dac_info[i].dac; if (!nid) nid = spec->multiout.dac_nids[0]; select_connection(codec, spec->dac_info[i].pin, nid); } - - /* turn on EAPD */ - cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins); - cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins); - cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins); + if (spec->auto_mute) { + enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins, + CONEXANT_HP_EVENT); + spec->hp_present = detect_jacks(codec, cfg->hp_outs, + cfg->hp_pins); + if (spec->detect_line) { + enable_unsol_pins(codec, cfg->line_outs, + cfg->line_out_pins, + CONEXANT_LINE_EVENT); + spec->line_present = + detect_jacks(codec, cfg->line_outs, + cfg->line_out_pins); + } + } + cx_auto_update_speakers(codec); } static void cx_auto_init_input(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i; + int i, val; - for (i = 0; i < spec->num_adc_nids; i++) - snd_hda_codec_write(codec, spec->adc_nids[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)); + for (i = 0; i < spec->num_adc_nids; i++) { + hda_nid_t nid = spec->adc_nids[i]; + if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) + continue; + if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE) + val = AMP_IN_MUTE(0); + else + val = AMP_IN_UNMUTE(0); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + val); + } for (i = 0; i < cfg->num_inputs; i++) { unsigned int type; @@ -3601,17 +4048,22 @@ static void cx_auto_init_input(struct hda_codec *codec) } if (spec->auto_mic) { - int ext_idx = spec->auto_mic_ext; - snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | CONEXANT_MIC_EVENT); + if (spec->auto_mic_ext >= 0) { + snd_hda_codec_write(codec, + cfg->inputs[spec->auto_mic_ext].pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | CONEXANT_MIC_EVENT); + } + if (spec->auto_mic_dock >= 0) { + snd_hda_codec_write(codec, + cfg->inputs[spec->auto_mic_dock].pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | CONEXANT_MIC_EVENT); + } cx_auto_automic(codec); } else { - for (i = 0; i < spec->num_adc_nids; i++) { - snd_hda_codec_write(codec, spec->adc_nids[i], 0, - AC_VERB_SET_CONNECT_SEL, - spec->private_imux.items[0].index); - } + select_input_connection(codec, spec->imux_info[0].adc, + spec->imux_info[0].pin); } } @@ -3646,7 +4098,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, HDA_CODEC_VOLUME(name, 0, 0, 0), HDA_CODEC_MUTE(name, 0, 0, 0), }; - static char *sfx[2] = { "Volume", "Switch" }; + static const char * const sfx[2] = { "Volume", "Switch" }; int i, err; for (i = 0; i < 2; i++) { @@ -3674,6 +4126,19 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, #define cx_auto_add_pb_volume(codec, nid, str, idx) \ cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) +static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac, + hda_nid_t pin, const char *name, int idx) +{ + unsigned int caps; + caps = query_amp_caps(codec, dac, HDA_OUTPUT); + if (caps & AC_AMPCAP_NUM_STEPS) + return cx_auto_add_pb_volume(codec, dac, name, idx); + caps = query_amp_caps(codec, pin, HDA_OUTPUT); + if (caps & AC_AMPCAP_NUM_STEPS) + return cx_auto_add_pb_volume(codec, pin, name, idx); + return 0; +} + static int cx_auto_build_output_controls(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -3682,8 +4147,10 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) static const char * const texts[3] = { "Front", "Surround", "CLFE" }; if (spec->dac_info_filled == 1) - return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac, - "Master", 0); + return try_add_pb_volume(codec, spec->dac_info[0].dac, + spec->dac_info[0].pin, + "Master", 0); + for (i = 0; i < spec->dac_info_filled; i++) { const char *label; int idx, type; @@ -3707,74 +4174,123 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) idx = num_spk++; break; } - err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac, - label, idx); + err = try_add_pb_volume(codec, spec->dac_info[i].dac, + spec->dac_info[i].pin, + label, idx); if (err < 0) return err; } + + if (spec->auto_mute) { + err = snd_hda_add_new_ctls(codec, cx_automute_mode_enum); + if (err < 0) + return err; + } + + return 0; +} + +static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, + const char *label, const char *pfx, + int cidx) +{ + struct conexant_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_adc_nids; i++) { + hda_nid_t adc_nid = spec->adc_nids[i]; + int idx = get_input_connection(codec, adc_nid, nid); + if (idx < 0) + continue; + return cx_auto_add_volume_idx(codec, label, pfx, + cidx, adc_nid, HDA_INPUT, idx); + } + return 0; +} + +static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx, + const char *label, int cidx) +{ + struct conexant_spec *spec = codec->spec; + hda_nid_t mux, nid; + int i, con; + + nid = spec->imux_info[idx].pin; + if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) + return cx_auto_add_volume(codec, label, " Boost", cidx, + nid, HDA_INPUT); + con = __select_input_connection(codec, spec->imux_info[idx].adc, nid, + &mux, false, 0); + if (con < 0) + return 0; + for (i = 0; i < idx; i++) { + if (spec->imux_info[i].boost == mux) + return 0; /* already present */ + } + + if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP) { + spec->imux_info[idx].boost = mux; + return cx_auto_add_volume(codec, label, " Boost", 0, + mux, HDA_OUTPUT); + } return 0; } static int cx_auto_build_input_controls(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - static const char *prev_label; - int i, err, cidx, conn_len; - hda_nid_t conn[HDA_MAX_CONNECTIONS]; - - int multi_adc_volume = 0; /* If the ADC nid has several input volumes */ - int adc_nid = spec->adc_nids[0]; - - conn_len = snd_hda_get_connections(codec, adc_nid, conn, - HDA_MAX_CONNECTIONS); - if (conn_len < 0) - return conn_len; - - multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1; - if (!multi_adc_volume) { - err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid, - HDA_INPUT); - if (err < 0) - return err; + struct hda_input_mux *imux = &spec->private_imux; + const char *prev_label; + int input_conn[HDA_MAX_NUM_INPUTS]; + int i, err, cidx; + int multi_connection; + + multi_connection = 0; + for (i = 0; i < imux->num_items; i++) { + cidx = get_input_connection(codec, spec->imux_info[i].adc, + spec->imux_info[i].pin); + input_conn[i] = (spec->imux_info[i].adc << 8) | cidx; + if (i > 0 && input_conn[i] != input_conn[0]) + multi_connection = 1; } prev_label = NULL; cidx = 0; - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; + for (i = 0; i < imux->num_items; i++) { + hda_nid_t nid = spec->imux_info[i].pin; const char *label; - int j; - int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP; - if (!pin_amp && !multi_adc_volume) - continue; - label = hda_get_autocfg_input_label(codec, cfg, i); + label = hda_get_autocfg_input_label(codec, &spec->autocfg, + spec->imux_info[i].index); if (label == prev_label) cidx++; else cidx = 0; prev_label = label; - if (pin_amp) { - err = cx_auto_add_volume(codec, label, " Boost", cidx, - nid, HDA_INPUT); - if (err < 0) - return err; - } + err = cx_auto_add_boost_volume(codec, i, label, cidx); + if (err < 0) + return err; - if (!multi_adc_volume) - continue; - for (j = 0; j < conn_len; j++) { - if (conn[j] == nid) { - err = cx_auto_add_volume_idx(codec, label, - " Capture", cidx, adc_nid, HDA_INPUT, j); - if (err < 0) - return err; - break; - } + if (!multi_connection) { + if (i > 0) + continue; + err = cx_auto_add_capture_volume(codec, nid, + "Capture", "", cidx); + } else { + err = cx_auto_add_capture_volume(codec, nid, + label, " Capture", cidx); } + if (err < 0) + return err; + } + + if (spec->private_imux.num_items > 1 && !spec->auto_mic) { + err = snd_hda_add_new_ctls(codec, cx_auto_capture_mixers); + if (err < 0) + return err; } + return 0; } @@ -3791,7 +4307,29 @@ static int cx_auto_build_controls(struct hda_codec *codec) return conexant_build_controls(codec); } -static struct hda_codec_ops cx_auto_patch_ops = { +static int cx_auto_search_adcs(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + hda_nid_t nid, end_nid; + + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) { + unsigned int caps = get_wcaps(codec, nid); + if (get_wcaps_type(caps) != AC_WID_AUD_IN) + continue; + if (caps & AC_WCAP_DIGITAL) + continue; + if (snd_BUG_ON(spec->num_adc_nids >= + ARRAY_SIZE(spec->private_adc_nids))) + break; + spec->private_adc_nids[spec->num_adc_nids++] = nid; + } + spec->adc_nids = spec->private_adc_nids; + return 0; +} + + +static const struct hda_codec_ops cx_auto_patch_ops = { .build_controls = cx_auto_build_controls, .build_pcms = conexant_build_pcms, .init = cx_auto_init, @@ -3808,19 +4346,24 @@ static int patch_conexant_auto(struct hda_codec *codec) struct conexant_spec *spec; int err; + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; codec->spec = spec; - spec->adc_nids = cx_auto_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids); - spec->capsrc_nids = spec->adc_nids; + codec->pin_amp_workaround = 1; + err = cx_auto_search_adcs(codec); + if (err < 0) + return err; err = cx_auto_parse_auto_config(codec); if (err < 0) { kfree(codec->spec); codec->spec = NULL; return err; } + spec->capture_stream = &cx_auto_pcm_analog_capture; codec->patch_ops = cx_auto_patch_ops; if (spec->beep_amp) snd_hda_attach_beep_device(codec, spec->beep_amp); @@ -3830,7 +4373,7 @@ static int patch_conexant_auto(struct hda_codec *codec) /* */ -static struct hda_codec_preset snd_hda_preset_conexant[] = { +static const struct hda_codec_preset snd_hda_preset_conexant[] = { { .id = 0x14f15045, .name = "CX20549 (Venice)", .patch = patch_cxt5045 }, { .id = 0x14f15047, .name = "CX20551 (Waikiki)", diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 715615a88a8..bd0ae697f9c 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -33,6 +33,7 @@ #include <linux/slab.h> #include <linux/moduleparam.h> #include <sound/core.h> +#include <sound/jack.h> #include "hda_codec.h" #include "hda_local.h" @@ -47,8 +48,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); * * The HDA correspondence of pipes/ports are converter/pin nodes. */ -#define MAX_HDMI_CVTS 3 -#define MAX_HDMI_PINS 3 +#define MAX_HDMI_CVTS 4 +#define MAX_HDMI_PINS 4 struct hdmi_spec { int num_cvts; @@ -76,11 +77,7 @@ struct hdmi_spec { * ati/nvhdmi specific */ struct hda_multi_out multiout; - struct hda_pcm_stream *pcm_playback; - - /* misc flags */ - /* PD bit indicates only the update, not the current state */ - unsigned int old_pin_detect:1; + const struct hda_pcm_stream *pcm_playback; }; @@ -299,13 +296,6 @@ static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) return -EINVAL; } -static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid, - struct hdmi_eld *eld) -{ - if (!snd_hdmi_get_eld(eld, codec, pin_nid)) - snd_hdmi_show_eld(eld); -} - #ifdef BE_PARANOID static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, int *packet_index, int *byte_index) @@ -693,33 +683,20 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) { struct hdmi_spec *spec = codec->spec; - int tag = res >> AC_UNSOL_RES_TAG_SHIFT; - int pind = !!(res & AC_UNSOL_RES_PD); + int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT; + int pd = !!(res & AC_UNSOL_RES_PD); int eldv = !!(res & AC_UNSOL_RES_ELDV); int index; printk(KERN_INFO "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - tag, pind, eldv); + pin_nid, pd, eldv); - index = hda_node_index(spec->pin, tag); + index = hda_node_index(spec->pin, pin_nid); if (index < 0) return; - if (spec->old_pin_detect) { - if (pind) - hdmi_present_sense(codec, tag, &spec->sink_eld[index]); - pind = spec->sink_eld[index].monitor_present; - } - - spec->sink_eld[index].monitor_present = pind; - spec->sink_eld[index].eld_valid = eldv; - - if (pind && eldv) { - hdmi_get_show_eld(codec, spec->pin[index], - &spec->sink_eld[index]); - /* TODO: do real things about ELD */ - } + hdmi_present_sense(codec, pin_nid, &spec->sink_eld[index]); } static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) @@ -900,18 +877,39 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, struct hdmi_eld *eld) { + /* + * Always execute a GetPinSense verb here, even when called from + * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited + * response's PD bit is not the real PD value, but indicates that + * the real PD value changed. An older version of the HD-audio + * specification worked this way. Hence, we just ignore the data in + * the unsolicited response to avoid custom WARs. + */ int present = snd_hda_pin_sense(codec, pin_nid); + memset(eld, 0, sizeof(*eld)); + eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); - eld->eld_valid = !!(present & AC_PINSENSE_ELDV); + if (eld->monitor_present) + eld->eld_valid = !!(present & AC_PINSENSE_ELDV); + else + eld->eld_valid = 0; + + printk(KERN_INFO + "HDMI status: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", + pin_nid, eld->monitor_present, eld->eld_valid); + + if (eld->eld_valid) + if (!snd_hdmi_get_eld(eld, codec, pin_nid)) + snd_hdmi_show_eld(eld); - if (present & AC_PINSENSE_ELDV) - hdmi_get_show_eld(codec, pin_nid, eld); + snd_hda_input_jack_report(codec, pin_nid); } static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) { struct hdmi_spec *spec = codec->spec; + int err; if (spec->num_pins >= MAX_HDMI_PINS) { snd_printk(KERN_WARNING @@ -919,6 +917,11 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) return -E2BIG; } + err = snd_hda_input_jack_add(codec, pin_nid, + SND_JACK_VIDEOOUT, NULL); + if (err < 0) + return err; + hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); spec->pin[spec->num_pins] = pin_nid; @@ -1024,6 +1027,7 @@ static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = { "HDMI 0", "HDMI 1", "HDMI 2", + "HDMI 3", }; /* @@ -1044,7 +1048,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); } -static struct hda_pcm_stream generic_hdmi_pcm_playback = { +static const struct hda_pcm_stream generic_hdmi_pcm_playback = { .substreams = 1, .channels_min = 2, .ops = { @@ -1120,11 +1124,12 @@ static void generic_hdmi_free(struct hda_codec *codec) for (i = 0; i < spec->num_pins; i++) snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); + snd_hda_input_jack_free(codec); kfree(spec); } -static struct hda_codec_ops generic_hdmi_patch_ops = { +static const struct hda_codec_ops generic_hdmi_patch_ops = { .init = generic_hdmi_init, .free = generic_hdmi_free, .build_pcms = generic_hdmi_build_pcms, @@ -1169,12 +1174,12 @@ static int patch_generic_hdmi(struct hda_codec *codec) #define nvhdmi_master_con_nid_7x 0x04 #define nvhdmi_master_pin_nid_7x 0x05 -static hda_nid_t nvhdmi_con_nids_7x[4] = { +static const hda_nid_t nvhdmi_con_nids_7x[4] = { /*front, rear, clfe, rear_surr */ 0x6, 0x8, 0xa, 0xc, }; -static struct hda_verb nvhdmi_basic_init_7x[] = { +static const struct hda_verb nvhdmi_basic_init_7x[] = { /* set audio protect on */ { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, /* enable digital output on pin widget */ @@ -1435,7 +1440,7 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = { +static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -1450,7 +1455,7 @@ static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = { }, }; -static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = { +static const struct hda_pcm_stream nvhdmi_pcm_playback_2ch = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1465,32 +1470,20 @@ static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = { }, }; -static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = { +static const struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = { .build_controls = generic_hdmi_build_controls, .build_pcms = generic_hdmi_build_pcms, .init = nvhdmi_7x_init, .free = generic_hdmi_free, }; -static struct hda_codec_ops nvhdmi_patch_ops_2ch = { +static const struct hda_codec_ops nvhdmi_patch_ops_2ch = { .build_controls = generic_hdmi_build_controls, .build_pcms = generic_hdmi_build_pcms, .init = nvhdmi_7x_init, .free = generic_hdmi_free, }; -static int patch_nvhdmi_8ch_89(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int err = patch_generic_hdmi(codec); - - if (err < 0) - return err; - spec = codec->spec; - spec->old_pin_detect = 1; - return 0; -} - static int patch_nvhdmi_2ch(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -1504,7 +1497,6 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 2; spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; - spec->old_pin_detect = 1; spec->num_cvts = 1; spec->cvt[0] = nvhdmi_master_con_nid_7x; spec->pcm_playback = &nvhdmi_pcm_playback_2ch; @@ -1568,7 +1560,7 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream atihdmi_pcm_digital_playback = { +static const struct hda_pcm_stream atihdmi_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1580,7 +1572,7 @@ static struct hda_pcm_stream atihdmi_pcm_digital_playback = { }, }; -static struct hda_verb atihdmi_basic_init[] = { +static const struct hda_verb atihdmi_basic_init[] = { /* enable digital output on pin widget */ { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, {} /* terminator */ @@ -1599,7 +1591,7 @@ static int atihdmi_init(struct hda_codec *codec) return 0; } -static struct hda_codec_ops atihdmi_patch_ops = { +static const struct hda_codec_ops atihdmi_patch_ops = { .build_controls = generic_hdmi_build_controls, .build_pcms = generic_hdmi_build_pcms, .init = atihdmi_init, @@ -1634,7 +1626,7 @@ static int patch_atihdmi(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_hdmi[] = { +static const struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, @@ -1647,28 +1639,28 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, -{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_generic_hdmi }, /* 17 is known to be absent */ -{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi }, @@ -1677,6 +1669,7 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi }, { .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi }, {} /* terminator */ }; @@ -1722,6 +1715,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862802"); MODULE_ALIAS("snd-hda-codec-id:80862803"); MODULE_ALIAS("snd-hda-codec-id:80862804"); MODULE_ALIAS("snd-hda-codec-id:80862805"); +MODULE_ALIAS("snd-hda-codec-id:80862806"); MODULE_ALIAS("snd-hda-codec-id:808629fb"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 52928d9a72d..7a4e10002f5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -299,11 +299,23 @@ struct alc_customize_define { struct alc_fixup; +struct alc_multi_io { + hda_nid_t pin; /* multi-io widget pin NID */ + hda_nid_t dac; /* DAC to be connected */ + unsigned int ctl_in; /* cached input-pin control value */ +}; + +enum { + ALC_AUTOMUTE_PIN, /* change the pin control */ + ALC_AUTOMUTE_AMP, /* mute/unmute the pin AMP */ + ALC_AUTOMUTE_MIXER, /* mute/unmute mixer widget AMP */ +}; + struct alc_spec { /* codec parameterization */ - struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ + const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ unsigned int num_mixers; - struct snd_kcontrol_new *cap_mixer; /* capture mixer */ + const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ const struct hda_verb *init_verbs[10]; /* initialization verbs @@ -313,14 +325,14 @@ struct alc_spec { unsigned int num_init_verbs; char stream_name_analog[32]; /* analog PCM stream */ - struct hda_pcm_stream *stream_analog_playback; - struct hda_pcm_stream *stream_analog_capture; - struct hda_pcm_stream *stream_analog_alt_playback; - struct hda_pcm_stream *stream_analog_alt_capture; + const struct hda_pcm_stream *stream_analog_playback; + const struct hda_pcm_stream *stream_analog_capture; + const struct hda_pcm_stream *stream_analog_alt_playback; + const struct hda_pcm_stream *stream_analog_alt_capture; char stream_name_digital[32]; /* digital PCM stream */ - struct hda_pcm_stream *stream_digital_playback; - struct hda_pcm_stream *stream_digital_capture; + const struct hda_pcm_stream *stream_digital_playback; + const struct hda_pcm_stream *stream_digital_capture; /* playback */ struct hda_multi_out multiout; /* playback set-up @@ -333,8 +345,8 @@ struct alc_spec { /* capture */ unsigned int num_adc_nids; - hda_nid_t *adc_nids; - hda_nid_t *capsrc_nids; + const hda_nid_t *adc_nids; + const hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ /* capture setup for dynamic dual-adc switch */ @@ -348,6 +360,7 @@ struct alc_spec { const struct hda_input_mux *input_mux; unsigned int cur_mux[3]; struct alc_mic_route ext_mic; + struct alc_mic_route dock_mic; struct alc_mic_route int_mic; /* channel model */ @@ -375,17 +388,27 @@ struct alc_spec { #ifdef CONFIG_SND_HDA_POWER_SAVE void (*power_hook)(struct hda_codec *codec); #endif + void (*shutup)(struct hda_codec *codec); /* for pin sensing */ - unsigned int sense_updated: 1; unsigned int jack_present: 1; - unsigned int master_sw: 1; + unsigned int line_jack_present:1; + unsigned int master_mute:1; unsigned int auto_mic:1; + unsigned int automute:1; /* HP automute enabled */ + unsigned int detect_line:1; /* Line-out detection enabled */ + unsigned int automute_lines:1; /* automute line-out as well */ + unsigned int automute_hp_lo:1; /* both HP and LO available */ /* other flags */ unsigned int no_analog :1; /* digital I/O only */ unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */ unsigned int single_input_src:1; + + /* auto-mute control */ + int automute_mode; + hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS]; + int init_amp; int codec_variant; /* flag for other variants */ @@ -403,25 +426,29 @@ struct alc_spec { int fixup_id; const struct alc_fixup *fixup_list; const char *fixup_name; + + /* multi-io */ + int multi_ios; + struct alc_multi_io multi_io[4]; }; /* * configuration template - to be copied to the spec instance */ struct alc_config_preset { - struct snd_kcontrol_new *mixers[5]; /* should be identical size + const struct snd_kcontrol_new *mixers[5]; /* should be identical size * with spec */ - struct snd_kcontrol_new *cap_mixer; /* capture mixer */ + const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ const struct hda_verb *init_verbs[5]; unsigned int num_dacs; - hda_nid_t *dac_nids; + const hda_nid_t *dac_nids; hda_nid_t dig_out_nid; /* optional */ hda_nid_t hp_nid; /* optional */ - hda_nid_t *slave_dig_outs; + const hda_nid_t *slave_dig_outs; unsigned int num_adc_nids; - hda_nid_t *adc_nids; - hda_nid_t *capsrc_nids; + const hda_nid_t *adc_nids; + const hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; unsigned int num_channel_mode; const struct hda_channel_mode *channel_mode; @@ -433,7 +460,7 @@ struct alc_config_preset { void (*setup)(struct hda_codec *); void (*init_hook)(struct hda_codec *); #ifdef CONFIG_SND_HDA_POWER_SAVE - struct hda_amp_list *loopbacks; + const struct hda_amp_list *loopbacks; void (*power_hook)(struct hda_codec *codec); #endif }; @@ -560,11 +587,11 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, * NIDs 0x0f and 0x10 have been observed to have this behaviour as of * March 2006. */ -static char *alc_pin_mode_names[] = { +static const char * const alc_pin_mode_names[] = { "Mic 50pc bias", "Mic 80pc bias", "Line in", "Line out", "Headphone out", }; -static unsigned char alc_pin_mode_values[] = { +static const unsigned char alc_pin_mode_values[] = { PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP, }; /* The control can present all 5 options, or it can limit the options based @@ -583,7 +610,7 @@ static unsigned char alc_pin_mode_values[] = { /* Info about the pin modes supported by the different pin direction modes. * For each direction the minimum and maximum values are given. */ -static signed char alc_pin_mode_dir_info[5][2] = { +static const signed char alc_pin_mode_dir_info[5][2] = { { 0, 2 }, /* ALC_PIN_DIR_IN */ { 3, 4 }, /* ALC_PIN_DIR_OUT */ { 0, 4 }, /* ALC_PIN_DIR_INOUT */ @@ -900,7 +927,7 @@ static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec) /* */ -static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix) +static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix) { if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers))) return; @@ -971,21 +998,21 @@ static void setup_preset(struct hda_codec *codec, } /* Enable GPIO mask and set output */ -static struct hda_verb alc_gpio1_init_verbs[] = { +static const struct hda_verb alc_gpio1_init_verbs[] = { {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, { } }; -static struct hda_verb alc_gpio2_init_verbs[] = { +static const struct hda_verb alc_gpio2_init_verbs[] = { {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, { } }; -static struct hda_verb alc_gpio3_init_verbs[] = { +static const struct hda_verb alc_gpio3_init_verbs[] = { {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03}, {0x01, AC_VERB_SET_GPIO_DATA, 0x03}, @@ -1031,6 +1058,7 @@ static int alc_init_jacks(struct hda_codec *codec) int err; unsigned int hp_nid = spec->autocfg.hp_pins[0]; unsigned int mic_nid = spec->ext_mic.pin; + unsigned int dock_nid = spec->dock_mic.pin; if (hp_nid) { err = snd_hda_input_jack_add(codec, hp_nid, @@ -1047,46 +1075,116 @@ static int alc_init_jacks(struct hda_codec *codec) return err; snd_hda_input_jack_report(codec, mic_nid); } + if (dock_nid) { + err = snd_hda_input_jack_add(codec, dock_nid, + SND_JACK_MICROPHONE, NULL); + if (err < 0) + return err; + snd_hda_input_jack_report(codec, dock_nid); + } #endif /* CONFIG_SND_HDA_INPUT_JACK */ return 0; } -static void alc_automute_speaker(struct hda_codec *codec, int pinctl) +static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) { - struct alc_spec *spec = codec->spec; - unsigned int mute; - hda_nid_t nid; - int i; + int i, present = 0; - spec->jack_present = 0; - for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { - nid = spec->autocfg.hp_pins[i]; + for (i = 0; i < num_pins; i++) { + hda_nid_t nid = pins[i]; if (!nid) break; snd_hda_input_jack_report(codec, nid); - spec->jack_present |= snd_hda_jack_detect(codec, nid); + present |= snd_hda_jack_detect(codec, nid); } + return present; +} - mute = spec->jack_present ? HDA_AMP_MUTE : 0; - /* Toggle internal speakers muting */ - for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { - nid = spec->autocfg.speaker_pins[i]; +static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, + bool mute, bool hp_out) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0; + unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT); + int i; + + for (i = 0; i < num_pins; i++) { + hda_nid_t nid = pins[i]; if (!nid) break; - if (pinctl) { + switch (spec->automute_mode) { + case ALC_AUTOMUTE_PIN: snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - spec->jack_present ? 0 : PIN_OUT); - } else { + AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_bits); + break; + case ALC_AUTOMUTE_AMP: snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); + HDA_AMP_MUTE, mute_bits); + break; + case ALC_AUTOMUTE_MIXER: + nid = spec->automute_mixer_nid[i]; + if (!nid) + break; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, mute_bits); + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1, + HDA_AMP_MUTE, mute_bits); + break; } } } -static void alc_automute_pin(struct hda_codec *codec) +/* Toggle internal speakers muting */ +static void update_speakers(struct hda_codec *codec) { - alc_automute_speaker(codec, 1); + struct alc_spec *spec = codec->spec; + int on; + + if (!spec->automute) + on = 0; + else + on = spec->jack_present | spec->line_jack_present; + on |= spec->master_mute; + do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), + spec->autocfg.speaker_pins, on, false); + + /* toggle line-out mutes if needed, too */ + /* if LO is a copy of either HP or Speaker, don't need to handle it */ + if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || + spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) + return; + if (!spec->automute_lines || !spec->automute) + on = 0; + else + on = spec->jack_present; + on |= spec->master_mute; + do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), + spec->autocfg.line_out_pins, on, false); +} + +static void alc_hp_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec->automute) + return; + spec->jack_present = + detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), + spec->autocfg.hp_pins); + update_speakers(codec); +} + +static void alc_line_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec->automute || !spec->detect_line) + return; + spec->line_jack_present = + detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), + spec->autocfg.line_out_pins); + update_speakers(codec); } static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, @@ -1128,7 +1226,7 @@ static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec) static void alc_mic_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - struct alc_mic_route *dead, *alive; + struct alc_mic_route *dead1, *dead2, *alive; unsigned int present, type; hda_nid_t cap_nid; @@ -1146,13 +1244,24 @@ static void alc_mic_automute(struct hda_codec *codec) cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; + alive = &spec->int_mic; + dead1 = &spec->ext_mic; + dead2 = &spec->dock_mic; + present = snd_hda_jack_detect(codec, spec->ext_mic.pin); if (present) { alive = &spec->ext_mic; - dead = &spec->int_mic; - } else { - alive = &spec->int_mic; - dead = &spec->ext_mic; + dead1 = &spec->int_mic; + dead2 = &spec->dock_mic; + } + if (!present && spec->dock_mic.pin > 0) { + present = snd_hda_jack_detect(codec, spec->dock_mic.pin); + if (present) { + alive = &spec->dock_mic; + dead1 = &spec->int_mic; + dead2 = &spec->ext_mic; + } + snd_hda_input_jack_report(codec, spec->dock_mic.pin); } type = get_wcaps_type(get_wcaps(codec, cap_nid)); @@ -1161,9 +1270,14 @@ static void alc_mic_automute(struct hda_codec *codec) snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, alive->mux_idx, HDA_AMP_MUTE, 0); - snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, - dead->mux_idx, - HDA_AMP_MUTE, HDA_AMP_MUTE); + if (dead1->pin > 0) + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + dead1->mux_idx, + HDA_AMP_MUTE, HDA_AMP_MUTE); + if (dead2->pin > 0) + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + dead2->mux_idx, + HDA_AMP_MUTE, HDA_AMP_MUTE); } else { /* MUX style (e.g. ALC880) */ snd_hda_codec_write_cache(codec, cap_nid, 0, @@ -1184,7 +1298,10 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) res >>= 26; switch (res) { case ALC880_HP_EVENT: - alc_automute_pin(codec); + alc_hp_automute(codec); + break; + case ALC880_FRONT_EVENT: + alc_line_automute(codec); break; case ALC880_MIC_EVENT: alc_mic_automute(codec); @@ -1194,7 +1311,8 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) static void alc_inithook(struct hda_codec *codec) { - alc_automute_pin(codec); + alc_hp_automute(codec); + alc_line_automute(codec); alc_mic_automute(codec); } @@ -1236,6 +1354,43 @@ static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on) on ? 2 : 0); } +/* turn on/off EAPD controls of the codec */ +static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) +{ + /* We currently only handle front, HP */ + switch (codec->vendor_id) { + case 0x10ec0260: + set_eapd(codec, 0x0f, on); + set_eapd(codec, 0x10, on); + break; + case 0x10ec0262: + case 0x10ec0267: + case 0x10ec0268: + case 0x10ec0269: + case 0x10ec0270: + case 0x10ec0272: + case 0x10ec0660: + case 0x10ec0662: + case 0x10ec0663: + case 0x10ec0665: + case 0x10ec0862: + case 0x10ec0889: + case 0x10ec0892: + set_eapd(codec, 0x14, on); + set_eapd(codec, 0x15, on); + break; + } +} + +/* generic shutup callback; + * just turning off EPAD and a little pause for avoiding pop-noise + */ +static void alc_eapd_shutup(struct hda_codec *codec) +{ + alc_auto_setup_eapd(codec, false); + msleep(200); +} + static void alc_auto_init_amp(struct hda_codec *codec, int type) { unsigned int tmp; @@ -1251,27 +1406,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) snd_hda_sequence_write(codec, alc_gpio3_init_verbs); break; case ALC_INIT_DEFAULT: - switch (codec->vendor_id) { - case 0x10ec0260: - set_eapd(codec, 0x0f, 1); - set_eapd(codec, 0x10, 1); - break; - case 0x10ec0262: - case 0x10ec0267: - case 0x10ec0268: - case 0x10ec0269: - case 0x10ec0270: - case 0x10ec0272: - case 0x10ec0660: - case 0x10ec0662: - case 0x10ec0663: - case 0x10ec0665: - case 0x10ec0862: - case 0x10ec0889: - set_eapd(codec, 0x14, 1); - set_eapd(codec, 0x15, 1); - break; - } + alc_auto_setup_eapd(codec, true); switch (codec->vendor_id) { case 0x10ec0260: snd_hda_codec_write(codec, 0x1a, 0, @@ -1315,20 +1450,128 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) } } +static int alc_automute_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + static const char * const texts2[] = { + "Disabled", "Enabled" + }; + static const char * const texts3[] = { + "Disabled", "Speaker Only", "Line-Out+Speaker" + }; + const char * const *texts; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + if (spec->automute_hp_lo) { + uinfo->value.enumerated.items = 3; + texts = texts3; + } else { + uinfo->value.enumerated.items = 2; + texts = texts2; + } + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_automute_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + unsigned int val; + if (!spec->automute) + val = 0; + else if (!spec->automute_lines) + val = 1; + else + val = 2; + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int alc_automute_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + + switch (ucontrol->value.enumerated.item[0]) { + case 0: + if (!spec->automute) + return 0; + spec->automute = 0; + break; + case 1: + if (spec->automute && !spec->automute_lines) + return 0; + spec->automute = 1; + spec->automute_lines = 0; + break; + case 2: + if (!spec->automute_hp_lo) + return -EINVAL; + if (spec->automute && spec->automute_lines) + return 0; + spec->automute = 1; + spec->automute_lines = 1; + break; + default: + return -EINVAL; + } + update_speakers(codec); + return 1; +} + +static const struct snd_kcontrol_new alc_automute_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Auto-Mute Mode", + .info = alc_automute_mode_info, + .get = alc_automute_mode_get, + .put = alc_automute_mode_put, +}; + +static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec); + +static int alc_add_automute_mode_enum(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; + + knew = alc_kcontrol_new(spec); + if (!knew) + return -ENOMEM; + *knew = alc_automute_mode_enum; + knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL); + if (!knew->name) + return -ENOMEM; + return 0; +} + static void alc_init_auto_hp(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; + int present = 0; int i; - if (!cfg->hp_pins[0]) { - if (cfg->line_out_type != AUTO_PIN_HP_OUT) - return; - } + if (cfg->hp_pins[0]) + present++; + if (cfg->line_out_pins[0]) + present++; + if (cfg->speaker_pins[0]) + present++; + if (present < 2) /* need two different output types */ + return; + if (present == 3) + spec->automute_hp_lo = 1; /* both HP and LO automute */ if (!cfg->speaker_pins[0]) { - if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) - return; memcpy(cfg->speaker_pins, cfg->line_out_pins, sizeof(cfg->speaker_pins)); cfg->speaker_outs = cfg->line_outs; @@ -1341,28 +1584,49 @@ static void alc_init_auto_hp(struct hda_codec *codec) } for (i = 0; i < cfg->hp_outs; i++) { + hda_nid_t nid = cfg->hp_pins[i]; + if (!is_jack_detectable(codec, nid)) + continue; snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n", - cfg->hp_pins[i]); - snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0, + nid); + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + } + if (spec->automute && cfg->line_out_pins[0] && + cfg->line_out_pins[0] != cfg->hp_pins[0] && + cfg->line_out_pins[0] != cfg->speaker_pins[0]) { + for (i = 0; i < cfg->line_outs; i++) { + hda_nid_t nid = cfg->line_out_pins[i]; + if (!is_jack_detectable(codec, nid)) + continue; + snd_printdd("realtek: Enable Line-Out auto-muting " + "on NID 0x%x\n", nid); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_FRONT_EVENT); + spec->detect_line = 1; + } + spec->automute_lines = spec->detect_line; + } + + if (spec->automute) { + /* create a control for automute mode */ + alc_add_automute_mode_enum(codec); + spec->unsol_event = alc_sku_unsol_event; } - spec->unsol_event = alc_sku_unsol_event; } static void alc_init_auto_mic(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t fixed, ext; + hda_nid_t fixed, ext, dock; int i; - /* there must be only two mic inputs exclusively */ - for (i = 0; i < cfg->num_inputs; i++) - if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN) - return; - - fixed = ext = 0; + fixed = ext = dock = 0; for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; unsigned int defcfg; @@ -1371,26 +1635,45 @@ static void alc_init_auto_mic(struct hda_codec *codec) case INPUT_PIN_ATTR_INT: if (fixed) return; /* already occupied */ + if (cfg->inputs[i].type != AUTO_PIN_MIC) + return; /* invalid type */ fixed = nid; break; case INPUT_PIN_ATTR_UNUSED: return; /* invalid entry */ + case INPUT_PIN_ATTR_DOCK: + if (dock) + return; /* already occupied */ + if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) + return; /* invalid type */ + dock = nid; + break; default: if (ext) return; /* already occupied */ + if (cfg->inputs[i].type != AUTO_PIN_MIC) + return; /* invalid type */ ext = nid; break; } } + if (!ext && dock) { + ext = dock; + dock = 0; + } if (!ext || !fixed) return; - if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP)) + if (!is_jack_detectable(codec, ext)) return; /* no unsol support */ - snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n", - ext, fixed); + if (dock && !is_jack_detectable(codec, dock)) + return; /* no unsol support */ + snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", + ext, fixed, dock); spec->ext_mic.pin = ext; + spec->dock_mic.pin = dock; spec->int_mic.pin = fixed; spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ + spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ spec->auto_mic = 1; snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0, @@ -1583,9 +1866,6 @@ do_sku: return 1; spec->autocfg.hp_pins[0] = nid; } - - alc_init_auto_hp(codec); - alc_init_auto_mic(codec); return 1; } @@ -1598,9 +1878,10 @@ static void alc_ssid_check(struct hda_codec *codec, snd_printd("realtek: " "Enable default setup for auto mode as fallback\n"); spec->init_amp = ALC_INIT_DEFAULT; - alc_init_auto_hp(codec); - alc_init_auto_mic(codec); } + + alc_init_auto_hp(codec); + alc_init_auto_mic(codec); } /* @@ -1704,11 +1985,11 @@ static void alc_apply_fixup(struct hda_codec *codec, int action) codec->chip_name, fix->type); break; } - if (!fix[id].chained) + if (!fix->chained) break; if (++depth > 10) break; - id = fix[id].chain_id; + id = fix->chain_id; } } @@ -1842,7 +2123,7 @@ static void alc_auto_parse_digital(struct hda_codec *codec) /* * 2ch mode */ -static struct hda_verb alc888_4ST_ch2_intel_init[] = { +static const struct hda_verb alc888_4ST_ch2_intel_init[] = { /* Mic-in jack as mic in */ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -1857,7 +2138,7 @@ static struct hda_verb alc888_4ST_ch2_intel_init[] = { /* * 4ch mode */ -static struct hda_verb alc888_4ST_ch4_intel_init[] = { +static const struct hda_verb alc888_4ST_ch4_intel_init[] = { /* Mic-in jack as mic in */ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -1872,7 +2153,7 @@ static struct hda_verb alc888_4ST_ch4_intel_init[] = { /* * 6ch mode */ -static struct hda_verb alc888_4ST_ch6_intel_init[] = { +static const struct hda_verb alc888_4ST_ch6_intel_init[] = { /* Mic-in jack as CLFE */ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -1887,7 +2168,7 @@ static struct hda_verb alc888_4ST_ch6_intel_init[] = { /* * 8ch mode */ -static struct hda_verb alc888_4ST_ch8_intel_init[] = { +static const struct hda_verb alc888_4ST_ch8_intel_init[] = { /* Mic-in jack as CLFE */ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -1899,7 +2180,7 @@ static struct hda_verb alc888_4ST_ch8_intel_init[] = { { } /* end */ }; -static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { +static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { { 2, alc888_4ST_ch2_intel_init }, { 4, alc888_4ST_ch4_intel_init }, { 6, alc888_4ST_ch6_intel_init }, @@ -1910,7 +2191,7 @@ static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { * ALC888 Fujitsu Siemens Amillo xa3530 */ -static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { +static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = { /* Front Mic: set to PIN_IN (empty by default) */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Connect Internal HP to Front */ @@ -1943,22 +2224,6 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { {} }; -static void alc_automute_amp(struct hda_codec *codec) -{ - alc_automute_speaker(codec, 0); -} - -static void alc_automute_amp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if (codec->vendor_id == 0x10ec0880) - res >>= 28; - else - res >>= 26; - if (res == ALC880_HP_EVENT) - alc_automute_amp(codec); -} - static void alc889_automute_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1969,12 +2234,14 @@ static void alc889_automute_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x17; spec->autocfg.speaker_pins[3] = 0x19; spec->autocfg.speaker_pins[4] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc889_intel_init_hook(struct hda_codec *codec) { alc889_coef_init(codec); - alc_automute_amp(codec); + alc_hp_automute(codec); } static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) @@ -1985,13 +2252,15 @@ static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) spec->autocfg.hp_pins[1] = 0x1b; /* hp */ spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ spec->autocfg.speaker_pins[1] = 0x15; /* bass */ + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* * ALC888 Acer Aspire 4930G model */ -static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { +static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = { /* Front Mic: set to PIN_IN (empty by default) */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Unselect Front Mic by default in input mixer 3 */ @@ -2014,7 +2283,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { * ALC888 Acer Aspire 6530G model */ -static struct hda_verb alc888_acer_aspire_6530g_verbs[] = { +static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = { /* Route to built-in subwoofer as well as speakers */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -2044,7 +2313,7 @@ static struct hda_verb alc888_acer_aspire_6530g_verbs[] = { *ALC888 Acer Aspire 7730G model */ -static struct hda_verb alc888_acer_aspire_7730G_verbs[] = { +static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = { /* Bias voltage on for external mic port */ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, /* Front Mic: set to PIN_IN (empty by default) */ @@ -2074,7 +2343,7 @@ static struct hda_verb alc888_acer_aspire_7730G_verbs[] = { * ALC889 Acer Aspire 8930G model */ -static struct hda_verb alc889_acer_aspire_8930g_verbs[] = { +static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = { /* Front Mic: set to PIN_IN (empty by default) */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Unselect Front Mic by default in input mixer 3 */ @@ -2120,7 +2389,7 @@ static struct hda_verb alc889_acer_aspire_8930g_verbs[] = { { } }; -static struct hda_input_mux alc888_2_capture_sources[2] = { +static const struct hda_input_mux alc888_2_capture_sources[2] = { /* Front mic only available on one ADC */ { .num_items = 4, @@ -2141,7 +2410,7 @@ static struct hda_input_mux alc888_2_capture_sources[2] = { } }; -static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { +static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { /* Interal mic only available on one ADC */ { .num_items = 5, @@ -2164,7 +2433,7 @@ static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { } }; -static struct hda_input_mux alc889_capture_sources[3] = { +static const struct hda_input_mux alc889_capture_sources[3] = { /* Digital mic only available on first "ADC" */ { .num_items = 5, @@ -2196,7 +2465,7 @@ static struct hda_input_mux alc889_capture_sources[3] = { } }; -static struct snd_kcontrol_new alc888_base_mixer[] = { +static const struct snd_kcontrol_new alc888_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2218,7 +2487,7 @@ static struct snd_kcontrol_new alc888_base_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { +static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2240,7 +2509,7 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = { +static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2267,6 +2536,8 @@ static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) @@ -2277,6 +2548,8 @@ static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) @@ -2287,6 +2560,8 @@ static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) @@ -2297,6 +2572,8 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* @@ -2307,12 +2584,12 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) * F-Mic = 0x1b, HP = 0x19 */ -static hda_nid_t alc880_dac_nids[4] = { +static const hda_nid_t alc880_dac_nids[4] = { /* front, rear, clfe, rear_surr */ 0x02, 0x05, 0x04, 0x03 }; -static hda_nid_t alc880_adc_nids[3] = { +static const hda_nid_t alc880_adc_nids[3] = { /* ADC0-2 */ 0x07, 0x08, 0x09, }; @@ -2321,7 +2598,7 @@ static hda_nid_t alc880_adc_nids[3] = { * but it shows zero connection in the real implementation on some devices. * Note: this is a 915GAV bug, fixed on 915GLV */ -static hda_nid_t alc880_adc_nids_alt[2] = { +static const hda_nid_t alc880_adc_nids_alt[2] = { /* ADC1-2 */ 0x08, 0x09, }; @@ -2329,7 +2606,7 @@ static hda_nid_t alc880_adc_nids_alt[2] = { #define ALC880_DIGOUT_NID 0x06 #define ALC880_DIGIN_NID 0x0a -static struct hda_input_mux alc880_capture_source = { +static const struct hda_input_mux alc880_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -2341,7 +2618,7 @@ static struct hda_input_mux alc880_capture_source = { /* channel source setting (2/6 channel selection for 3-stack) */ /* 2ch mode */ -static struct hda_verb alc880_threestack_ch2_init[] = { +static const struct hda_verb alc880_threestack_ch2_init[] = { /* set line-in to input, mute it */ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -2352,7 +2629,7 @@ static struct hda_verb alc880_threestack_ch2_init[] = { }; /* 6ch mode */ -static struct hda_verb alc880_threestack_ch6_init[] = { +static const struct hda_verb alc880_threestack_ch6_init[] = { /* set line-in to output, unmute it */ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -2362,12 +2639,12 @@ static struct hda_verb alc880_threestack_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc880_threestack_modes[2] = { +static const struct hda_channel_mode alc880_threestack_modes[2] = { { 2, alc880_threestack_ch2_init }, { 6, alc880_threestack_ch6_init }, }; -static struct snd_kcontrol_new alc880_three_stack_mixer[] = { +static const struct snd_kcontrol_new alc880_three_stack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), @@ -2512,14 +2789,14 @@ static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, } #define DEFINE_CAPMIX(num) \ -static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ +static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ _DEFINE_CAPMIX(num), \ _DEFINE_CAPSRC(num), \ { } /* end */ \ } #define DEFINE_CAPMIX_NOSRC(num) \ -static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \ +static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \ _DEFINE_CAPMIX(num), \ { } /* end */ \ } @@ -2542,7 +2819,7 @@ DEFINE_CAPMIX_NOSRC(3); */ /* additional mixers to alc880_three_stack_mixer */ -static struct snd_kcontrol_new alc880_five_stack_mixer[] = { +static const struct snd_kcontrol_new alc880_five_stack_mixer[] = { HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), { } /* end */ @@ -2550,7 +2827,7 @@ static struct snd_kcontrol_new alc880_five_stack_mixer[] = { /* channel source setting (6/8 channel selection for 5-stack) */ /* 6ch mode */ -static struct hda_verb alc880_fivestack_ch6_init[] = { +static const struct hda_verb alc880_fivestack_ch6_init[] = { /* set line-in to input, mute it */ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -2558,14 +2835,14 @@ static struct hda_verb alc880_fivestack_ch6_init[] = { }; /* 8ch mode */ -static struct hda_verb alc880_fivestack_ch8_init[] = { +static const struct hda_verb alc880_fivestack_ch8_init[] = { /* set line-in to output, unmute it */ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { } /* end */ }; -static struct hda_channel_mode alc880_fivestack_modes[2] = { +static const struct hda_channel_mode alc880_fivestack_modes[2] = { { 6, alc880_fivestack_ch6_init }, { 8, alc880_fivestack_ch8_init }, }; @@ -2580,12 +2857,12 @@ static struct hda_channel_mode alc880_fivestack_modes[2] = { * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b */ -static hda_nid_t alc880_6st_dac_nids[4] = { +static const hda_nid_t alc880_6st_dac_nids[4] = { /* front, rear, clfe, rear_surr */ 0x02, 0x03, 0x04, 0x05 }; -static struct hda_input_mux alc880_6stack_capture_source = { +static const struct hda_input_mux alc880_6stack_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -2596,11 +2873,11 @@ static struct hda_input_mux alc880_6stack_capture_source = { }; /* fixed 8-channels */ -static struct hda_channel_mode alc880_sixstack_modes[1] = { +static const struct hda_channel_mode alc880_sixstack_modes[1] = { { 8, NULL }, }; -static struct snd_kcontrol_new alc880_six_stack_mixer[] = { +static const struct snd_kcontrol_new alc880_six_stack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2655,18 +2932,18 @@ static struct snd_kcontrol_new alc880_six_stack_mixer[] = { * haven't setup any initialization verbs for these yet... */ -static hda_nid_t alc880_w810_dac_nids[3] = { +static const hda_nid_t alc880_w810_dac_nids[3] = { /* front, rear/surround, clfe */ 0x02, 0x03, 0x04 }; /* fixed 6 channels */ -static struct hda_channel_mode alc880_w810_modes[1] = { +static const struct hda_channel_mode alc880_w810_modes[1] = { { 6, NULL } }; /* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ -static struct snd_kcontrol_new alc880_w810_base_mixer[] = { +static const struct snd_kcontrol_new alc880_w810_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2688,17 +2965,17 @@ static struct snd_kcontrol_new alc880_w810_base_mixer[] = { * Line = 0x1a */ -static hda_nid_t alc880_z71v_dac_nids[1] = { +static const hda_nid_t alc880_z71v_dac_nids[1] = { 0x02 }; #define ALC880_Z71V_HP_DAC 0x03 /* fixed 2 channels */ -static struct hda_channel_mode alc880_2_jack_modes[1] = { +static const struct hda_channel_mode alc880_2_jack_modes[1] = { { 2, NULL } }; -static struct snd_kcontrol_new alc880_z71v_mixer[] = { +static const struct snd_kcontrol_new alc880_z71v_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2718,12 +2995,12 @@ static struct snd_kcontrol_new alc880_z71v_mixer[] = { * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 */ -static hda_nid_t alc880_f1734_dac_nids[1] = { +static const hda_nid_t alc880_f1734_dac_nids[1] = { 0x03 }; #define ALC880_F1734_HP_DAC 0x02 -static struct snd_kcontrol_new alc880_f1734_mixer[] = { +static const struct snd_kcontrol_new alc880_f1734_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2735,7 +3012,7 @@ static struct snd_kcontrol_new alc880_f1734_mixer[] = { { } /* end */ }; -static struct hda_input_mux alc880_f1734_capture_source = { +static const struct hda_input_mux alc880_f1734_capture_source = { .num_items = 2, .items = { { "Mic", 0x1 }, @@ -2755,7 +3032,7 @@ static struct hda_input_mux alc880_f1734_capture_source = { #define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ #define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ -static struct snd_kcontrol_new alc880_asus_mixer[] = { +static const struct snd_kcontrol_new alc880_asus_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2789,14 +3066,14 @@ static struct snd_kcontrol_new alc880_asus_mixer[] = { */ /* additional mixers to alc880_asus_mixer */ -static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = { +static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = { HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), { } /* end */ }; /* TCL S700 */ -static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { +static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -2810,7 +3087,7 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { }; /* Uniwill */ -static struct snd_kcontrol_new alc880_uniwill_mixer[] = { +static const struct snd_kcontrol_new alc880_uniwill_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2837,7 +3114,7 @@ static struct snd_kcontrol_new alc880_uniwill_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc880_fujitsu_mixer[] = { +static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2851,7 +3128,7 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { +static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2878,7 +3155,6 @@ static const char * const alc_slave_vols[] = { "Speaker Playback Volume", "Mono Playback Volume", "Line-Out Playback Volume", - "PCM Playback Volume", NULL, }; @@ -2893,7 +3169,6 @@ static const char * const alc_slave_sws[] = { "Mono Playback Switch", "IEC958 Playback Switch", "Line-Out Playback Switch", - "PCM Playback Switch", NULL, }; @@ -2914,7 +3189,7 @@ static void alc_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP /* additional beep mixers; the actual parameters are overwritten at build */ -static struct snd_kcontrol_new alc_beep_mixer[] = { +static const struct snd_kcontrol_new alc_beep_mixer[] = { HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT), { } /* end */ @@ -2925,7 +3200,7 @@ static int alc_build_controls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct snd_kcontrol *kctl = NULL; - struct snd_kcontrol_new *knew; + const struct snd_kcontrol_new *knew; int i, j, err; unsigned int u; hda_nid_t nid; @@ -2962,7 +3237,7 @@ static int alc_build_controls(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_INPUT_BEEP /* create beep controls if needed */ if (spec->beep_amp) { - struct snd_kcontrol_new *knew; + const struct snd_kcontrol_new *knew; for (knew = alc_beep_mixer; knew->name; knew++) { struct snd_kcontrol *kctl; kctl = snd_ctl_new1(knew, codec); @@ -3001,7 +3276,7 @@ static int alc_build_controls(struct hda_codec *codec) if (!kctl) kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); for (i = 0; kctl && i < kctl->count; i++) { - hda_nid_t *nids = spec->capsrc_nids; + const hda_nid_t *nids = spec->capsrc_nids; if (!nids) nids = spec->adc_nids; err = snd_hda_add_nid(codec, kctl, i, nids[i]); @@ -3079,7 +3354,7 @@ static int alc_build_controls(struct hda_codec *codec) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc880_volume_init_verbs[] = { +static const struct hda_verb alc880_volume_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -3130,7 +3405,7 @@ static struct hda_verb alc880_volume_init_verbs[] = { * 3-stack pin configuration: * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b */ -static struct hda_verb alc880_pin_3stack_init_verbs[] = { +static const struct hda_verb alc880_pin_3stack_init_verbs[] = { /* * preset connection lists of input pins * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround @@ -3168,7 +3443,7 @@ static struct hda_verb alc880_pin_3stack_init_verbs[] = { * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, * line-in/side = 0x1a, f-mic = 0x1b */ -static struct hda_verb alc880_pin_5stack_init_verbs[] = { +static const struct hda_verb alc880_pin_5stack_init_verbs[] = { /* * preset connection lists of input pins * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround @@ -3212,7 +3487,7 @@ static struct hda_verb alc880_pin_5stack_init_verbs[] = { * W810 pin configuration: * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b */ -static struct hda_verb alc880_pin_w810_init_verbs[] = { +static const struct hda_verb alc880_pin_w810_init_verbs[] = { /* hphone/speaker input selector: front DAC */ {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, @@ -3233,7 +3508,7 @@ static struct hda_verb alc880_pin_w810_init_verbs[] = { * Z71V pin configuration: * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) */ -static struct hda_verb alc880_pin_z71v_init_verbs[] = { +static const struct hda_verb alc880_pin_z71v_init_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -3252,7 +3527,7 @@ static struct hda_verb alc880_pin_z71v_init_verbs[] = { * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, * f-mic = 0x19, line = 0x1a, HP = 0x1b */ -static struct hda_verb alc880_pin_6stack_init_verbs[] = { +static const struct hda_verb alc880_pin_6stack_init_verbs[] = { {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -3282,7 +3557,7 @@ static struct hda_verb alc880_pin_6stack_init_verbs[] = { * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19, * line = 0x1a */ -static struct hda_verb alc880_uniwill_init_verbs[] = { +static const struct hda_verb alc880_uniwill_init_verbs[] = { {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -3320,7 +3595,7 @@ static struct hda_verb alc880_uniwill_init_verbs[] = { * Uniwill P53 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, */ -static struct hda_verb alc880_uniwill_p53_init_verbs[] = { +static const struct hda_verb alc880_uniwill_p53_init_verbs[] = { {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -3349,7 +3624,7 @@ static struct hda_verb alc880_uniwill_p53_init_verbs[] = { { } }; -static struct hda_verb alc880_beep_init_verbs[] = { +static const struct hda_verb alc880_beep_init_verbs[] = { { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) }, { } }; @@ -3372,11 +3647,13 @@ static void alc880_uniwill_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc880_uniwill_init_hook(struct hda_codec *codec) { - alc_automute_amp(codec); + alc_hp_automute(codec); alc88x_simple_mic_automute(codec); } @@ -3391,7 +3668,7 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec, alc88x_simple_mic_automute(codec); break; default: - alc_automute_amp_unsol_event(codec, res); + alc_sku_unsol_event(codec, res); break; } } @@ -3402,6 +3679,8 @@ static void alc880_uniwill_p53_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -3426,14 +3705,14 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, if ((res >> 28) == ALC880_DCVOL_EVENT) alc880_uniwill_p53_dcvol_automute(codec); else - alc_automute_amp_unsol_event(codec, res); + alc_sku_unsol_event(codec, res); } /* * F1734 pin configuration: * HP = 0x14, speaker-out = 0x15, mic = 0x18 */ -static struct hda_verb alc880_pin_f1734_init_verbs[] = { +static const struct hda_verb alc880_pin_f1734_init_verbs[] = { {0x07, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -3465,7 +3744,7 @@ static struct hda_verb alc880_pin_f1734_init_verbs[] = { * ASUS pin configuration: * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a */ -static struct hda_verb alc880_pin_asus_init_verbs[] = { +static const struct hda_verb alc880_pin_asus_init_verbs[] = { {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, @@ -3499,7 +3778,7 @@ static struct hda_verb alc880_pin_asus_init_verbs[] = { #define alc880_gpio3_init_verbs alc_gpio3_init_verbs /* Clevo m520g init */ -static struct hda_verb alc880_pin_clevo_init_verbs[] = { +static const struct hda_verb alc880_pin_clevo_init_verbs[] = { /* headphone output */ {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line-out */ @@ -3527,7 +3806,7 @@ static struct hda_verb alc880_pin_clevo_init_verbs[] = { { } }; -static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { +static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { /* change to EAPD mode */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, @@ -3565,12 +3844,12 @@ static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { */ /* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */ -static hda_nid_t alc880_lg_dac_nids[3] = { +static const hda_nid_t alc880_lg_dac_nids[3] = { 0x05, 0x02, 0x03 }; /* seems analog CD is not working */ -static struct hda_input_mux alc880_lg_capture_source = { +static const struct hda_input_mux alc880_lg_capture_source = { .num_items = 3, .items = { { "Mic", 0x1 }, @@ -3580,34 +3859,34 @@ static struct hda_input_mux alc880_lg_capture_source = { }; /* 2,4,6 channel modes */ -static struct hda_verb alc880_lg_ch2_init[] = { +static const struct hda_verb alc880_lg_ch2_init[] = { /* set line-in and mic-in to input */ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { } }; -static struct hda_verb alc880_lg_ch4_init[] = { +static const struct hda_verb alc880_lg_ch4_init[] = { /* set line-in to out and mic-in to input */ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { } }; -static struct hda_verb alc880_lg_ch6_init[] = { +static const struct hda_verb alc880_lg_ch6_init[] = { /* set line-in and mic-in to output */ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { } }; -static struct hda_channel_mode alc880_lg_ch_modes[3] = { +static const struct hda_channel_mode alc880_lg_ch_modes[3] = { { 2, alc880_lg_ch2_init }, { 4, alc880_lg_ch4_init }, { 6, alc880_lg_ch6_init }, }; -static struct snd_kcontrol_new alc880_lg_mixer[] = { +static const struct snd_kcontrol_new alc880_lg_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), @@ -3632,7 +3911,7 @@ static struct snd_kcontrol_new alc880_lg_mixer[] = { { } /* end */ }; -static struct hda_verb alc880_lg_init_verbs[] = { +static const struct hda_verb alc880_lg_init_verbs[] = { /* set capture source to mic-in */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -3670,6 +3949,8 @@ static void alc880_lg_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* @@ -3684,7 +3965,7 @@ static void alc880_lg_setup(struct hda_codec *codec) * SPDIF-Out: 0x1e */ -static struct hda_input_mux alc880_lg_lw_capture_source = { +static const struct hda_input_mux alc880_lg_lw_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -3695,7 +3976,7 @@ static struct hda_input_mux alc880_lg_lw_capture_source = { #define alc880_lg_lw_modes alc880_threestack_modes -static struct snd_kcontrol_new alc880_lg_lw_mixer[] = { +static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), @@ -3720,7 +4001,7 @@ static struct snd_kcontrol_new alc880_lg_lw_mixer[] = { { } /* end */ }; -static struct hda_verb alc880_lg_lw_init_verbs[] = { +static const struct hda_verb alc880_lg_lw_init_verbs[] = { {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ @@ -3754,9 +4035,11 @@ static void alc880_lg_lw_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { +static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -3766,7 +4049,7 @@ static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { { } /* end */ }; -static struct hda_input_mux alc880_medion_rim_capture_source = { +static const struct hda_input_mux alc880_medion_rim_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -3774,7 +4057,7 @@ static struct hda_input_mux alc880_medion_rim_capture_source = { }, }; -static struct hda_verb alc880_medion_rim_init_verbs[] = { +static const struct hda_verb alc880_medion_rim_init_verbs[] = { {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -3801,7 +4084,7 @@ static struct hda_verb alc880_medion_rim_init_verbs[] = { static void alc880_medion_rim_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - alc_automute_amp(codec); + alc_hp_automute(codec); /* toggle EAPD */ if (spec->jack_present) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); @@ -3825,10 +4108,12 @@ static void alc880_medion_rim_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list alc880_loopbacks[] = { +static const struct hda_amp_list alc880_loopbacks[] = { { 0x0b, HDA_INPUT, 0 }, { 0x0b, HDA_INPUT, 1 }, { 0x0b, HDA_INPUT, 2 }, @@ -3837,7 +4122,7 @@ static struct hda_amp_list alc880_loopbacks[] = { { } /* end */ }; -static struct hda_amp_list alc880_lg_loopbacks[] = { +static const struct hda_amp_list alc880_lg_loopbacks[] = { { 0x0b, HDA_INPUT, 1 }, { 0x0b, HDA_INPUT, 6 }, { 0x0b, HDA_INPUT, 7 }, @@ -4009,7 +4294,7 @@ static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream dualmic_pcm_analog_capture = { +static const struct hda_pcm_stream dualmic_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -4022,7 +4307,7 @@ static struct hda_pcm_stream dualmic_pcm_analog_capture = { /* */ -static struct hda_pcm_stream alc880_pcm_analog_playback = { +static const struct hda_pcm_stream alc880_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -4034,21 +4319,21 @@ static struct hda_pcm_stream alc880_pcm_analog_playback = { }, }; -static struct hda_pcm_stream alc880_pcm_analog_capture = { +static const struct hda_pcm_stream alc880_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, /* NID is set in alc_build_pcms */ }; -static struct hda_pcm_stream alc880_pcm_analog_alt_playback = { +static const struct hda_pcm_stream alc880_pcm_analog_alt_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, /* NID is set in alc_build_pcms */ }; -static struct hda_pcm_stream alc880_pcm_analog_alt_capture = { +static const struct hda_pcm_stream alc880_pcm_analog_alt_capture = { .substreams = 2, /* can be overridden */ .channels_min = 2, .channels_max = 2, @@ -4059,7 +4344,7 @@ static struct hda_pcm_stream alc880_pcm_analog_alt_capture = { }, }; -static struct hda_pcm_stream alc880_pcm_digital_playback = { +static const struct hda_pcm_stream alc880_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -4072,7 +4357,7 @@ static struct hda_pcm_stream alc880_pcm_digital_playback = { }, }; -static struct hda_pcm_stream alc880_pcm_digital_capture = { +static const struct hda_pcm_stream alc880_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -4080,7 +4365,7 @@ static struct hda_pcm_stream alc880_pcm_digital_capture = { }; /* Used by alc_build_pcms to flag that a PCM has no playback stream */ -static struct hda_pcm_stream alc_pcm_null_stream = { +static const struct hda_pcm_stream alc_pcm_null_stream = { .substreams = 0, .channels_min = 0, .channels_max = 0, @@ -4174,7 +4459,7 @@ static int alc_build_pcms(struct hda_codec *codec) alc_pcm_null_stream; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; } - if (spec->num_adc_nids > 1) { + if (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture) { info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->stream_analog_alt_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = @@ -4193,6 +4478,10 @@ static int alc_build_pcms(struct hda_codec *codec) static inline void alc_shutup(struct hda_codec *codec) { + struct alc_spec *spec = codec->spec; + + if (spec && spec->shutup) + spec->shutup(codec); snd_hda_shutup_pins(codec); } @@ -4226,28 +4515,7 @@ static void alc_free(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_POWER_SAVE static void alc_power_eapd(struct hda_codec *codec) { - /* We currently only handle front, HP */ - switch (codec->vendor_id) { - case 0x10ec0260: - set_eapd(codec, 0x0f, 0); - set_eapd(codec, 0x10, 0); - break; - case 0x10ec0262: - case 0x10ec0267: - case 0x10ec0268: - case 0x10ec0269: - case 0x10ec0270: - case 0x10ec0272: - case 0x10ec0660: - case 0x10ec0662: - case 0x10ec0663: - case 0x10ec0665: - case 0x10ec0862: - case 0x10ec0889: - set_eapd(codec, 0x14, 0); - set_eapd(codec, 0x15, 0); - break; - } + alc_auto_setup_eapd(codec, false); } static int alc_suspend(struct hda_codec *codec, pm_message_t state) @@ -4263,6 +4531,7 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state) #ifdef SND_HDA_NEEDS_RESUME static int alc_resume(struct hda_codec *codec) { + msleep(150); /* to avoid pop noise */ codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); @@ -4273,7 +4542,7 @@ static int alc_resume(struct hda_codec *codec) /* */ -static struct hda_codec_ops alc_patch_ops = { +static const struct hda_codec_ops alc_patch_ops = { .build_controls = alc_build_controls, .build_pcms = alc_build_pcms, .init = alc_init, @@ -4308,11 +4577,11 @@ static int alc_codec_rename(struct hda_codec *codec, const char *name) * enum controls. */ #ifdef CONFIG_SND_DEBUG -static hda_nid_t alc880_test_dac_nids[4] = { +static const hda_nid_t alc880_test_dac_nids[4] = { 0x02, 0x03, 0x04, 0x05 }; -static struct hda_input_mux alc880_test_capture_source = { +static const struct hda_input_mux alc880_test_capture_source = { .num_items = 7, .items = { { "In-1", 0x0 }, @@ -4325,7 +4594,7 @@ static struct hda_input_mux alc880_test_capture_source = { }, }; -static struct hda_channel_mode alc880_test_modes[4] = { +static const struct hda_channel_mode alc880_test_modes[4] = { { 2, NULL }, { 4, NULL }, { 6, NULL }, @@ -4335,7 +4604,7 @@ static struct hda_channel_mode alc880_test_modes[4] = { static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "N/A", "Line Out", "HP Out", "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" }; @@ -4380,7 +4649,7 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - static unsigned int ctls[] = { + static const unsigned int ctls[] = { 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, @@ -4410,7 +4679,7 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "Front", "Surround", "CLFE", "Side" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -4471,7 +4740,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, .private_value = nid \ } -static struct snd_kcontrol_new alc880_test_mixer[] = { +static const struct snd_kcontrol_new alc880_test_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), @@ -4512,7 +4781,7 @@ static struct snd_kcontrol_new alc880_test_mixer[] = { { } /* end */ }; -static struct hda_verb alc880_test_init_verbs[] = { +static const struct hda_verb alc880_test_init_verbs[] = { /* Unmute inputs of 0x0c - 0x0f */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -4596,7 +4865,7 @@ static const char * const alc880_models[ALC880_MODEL_LAST] = { [ALC880_AUTO] = "auto", }; -static struct snd_pci_quirk alc880_cfg_tbl[] = { +static const struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), @@ -4676,7 +4945,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { /* * ALC880 codec presets */ -static struct alc_config_preset alc880_presets[] = { +static const struct alc_config_preset alc880_presets[] = { [ALC880_3ST] = { .mixers = { alc880_three_stack_mixer }, .init_verbs = { alc880_volume_init_verbs, @@ -4794,7 +5063,7 @@ static struct alc_config_preset alc880_presets[] = { .input_mux = &alc880_f1734_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, .setup = alc880_uniwill_p53_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC880_ASUS] = { .mixers = { alc880_asus_mixer }, @@ -4885,7 +5154,7 @@ static struct alc_config_preset alc880_presets[] = { .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, .setup = alc880_uniwill_p53_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC880_FUJITSU] = { .mixers = { alc880_fujitsu_mixer }, @@ -4900,7 +5169,7 @@ static struct alc_config_preset alc880_presets[] = { .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, .setup = alc880_uniwill_p53_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC880_CLEVO] = { .mixers = { alc880_three_stack_mixer }, @@ -4925,9 +5194,9 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_lg_ch_modes, .need_dac_fix = 1, .input_mux = &alc880_lg_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc880_lg_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, #ifdef CONFIG_SND_HDA_POWER_SAVE .loopbacks = alc880_lg_loopbacks, #endif @@ -4942,9 +5211,9 @@ static struct alc_config_preset alc880_presets[] = { .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes), .channel_mode = alc880_lg_lw_modes, .input_mux = &alc880_lg_lw_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc880_lg_lw_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC880_MEDION_RIM] = { .mixers = { alc880_medion_rim_mixer }, @@ -4984,20 +5253,25 @@ enum { ALC_CTL_WIDGET_MUTE, ALC_CTL_BIND_MUTE, }; -static struct snd_kcontrol_new alc880_control_templates[] = { +static const struct snd_kcontrol_new alc880_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), HDA_BIND_MUTE(NULL, 0, 0, 0), }; +static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec) +{ + snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); + return snd_array_new(&spec->kctls); +} + /* add dynamic controls */ static int add_control(struct alc_spec *spec, int type, const char *name, int cidx, unsigned long val) { struct snd_kcontrol_new *knew; - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); + knew = alc_kcontrol_new(spec); if (!knew) return -ENOMEM; *knew = alc880_control_templates[type]; @@ -5055,7 +5329,7 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec, nid = cfg->line_out_pins[i]; if (alc880_is_fixed_pin(nid)) { int idx = alc880_fixed_pin_idx(nid); - spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx); + spec->private_dac_nids[i] = alc880_idx_to_dac(idx); assigned[idx] = 1; } } @@ -5067,7 +5341,7 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec, /* search for an empty channel */ for (j = 0; j < cfg->line_outs; j++) { if (!assigned[j]) { - spec->multiout.dac_nids[i] = + spec->private_dac_nids[i] = alc880_idx_to_dac(j); assigned[j] = 1; break; @@ -5078,10 +5352,13 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec, return 0; } -static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg, +static const char *alc_get_line_out_pfx(struct alc_spec *spec, bool can_be_master) { - if (!cfg->hp_outs && !cfg->speaker_outs && can_be_master) + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (cfg->line_outs == 1 && !spec->multi_ios && + !cfg->hp_outs && !cfg->speaker_outs && can_be_master) return "Master"; switch (cfg->line_out_type) { @@ -5092,7 +5369,7 @@ static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg, case AUTO_PIN_HP_OUT: return "Headphone"; default: - if (cfg->line_outs == 1) + if (cfg->line_outs == 1 && !spec->multi_ios) return "PCM"; break; } @@ -5106,11 +5383,15 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, static const char * const chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; - const char *pfx = alc_get_line_out_pfx(cfg, false); + const char *pfx = alc_get_line_out_pfx(spec, false); hda_nid_t nid; - int i, err; + int i, err, noutputs; - for (i = 0; i < cfg->line_outs; i++) { + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { if (!spec->multiout.dac_nids[i]) continue; nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); @@ -5376,6 +5657,8 @@ static void alc880_auto_init_input_src(struct hda_codec *codec) } } +static int alc_auto_add_multi_channel_mode(struct hda_codec *codec); + /* parse the BIOS configuration and set up the alc_spec */ /* return 1 if successful, 0 if the proper config is not found, * or a negative error code @@ -5384,7 +5667,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc880_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc880_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc880_ignore); @@ -5396,6 +5679,9 @@ static int alc880_parse_auto_config(struct hda_codec *codec) err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); if (err < 0) return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; @@ -5467,6 +5753,12 @@ static void fixup_automic_adc(struct hda_codec *codec) spec->capsrc_nids += i; spec->adc_nids += i; spec->num_adc_nids = 1; + /* optional dock-mic */ + eidx = get_connection_index(codec, cap, spec->dock_mic.pin); + if (eidx < 0) + spec->dock_mic.pin = 0; + else + spec->dock_mic.mux_idx = eidx; return; } snd_printd(KERN_INFO "hda_codec: %s: " @@ -5494,6 +5786,8 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) struct alc_spec *spec = codec->spec; int i; + if (!pin) + return 0; for (i = 0; i < spec->num_adc_nids; i++) { hda_nid_t cap = spec->capsrc_nids ? spec->capsrc_nids[i] : spec->adc_nids[i]; @@ -5534,6 +5828,7 @@ static void fixup_dual_adc_switch(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; init_capsrc_for_pin(codec, spec->ext_mic.pin); + init_capsrc_for_pin(codec, spec->dock_mic.pin); init_capsrc_for_pin(codec, spec->int_mic.pin); } @@ -5550,7 +5845,7 @@ static void alc_init_special_input_src(struct hda_codec *codec) static void set_capture_mixer(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - static struct snd_kcontrol_new *caps[2][3] = { + static const struct snd_kcontrol_new *caps[2][3] = { { alc_capture_mixer_nosrc1, alc_capture_mixer_nosrc2, alc_capture_mixer_nosrc3 }, @@ -5576,7 +5871,7 @@ static void set_capture_mixer(struct hda_codec *codec) } /* fill adc_nids (and capsrc_nids) containing all active input pins */ -static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, +static void fillup_priv_adc_nids(struct hda_codec *codec, const hda_nid_t *nids, int num_nids) { struct alc_spec *spec = codec->spec; @@ -5642,9 +5937,11 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, #define set_beep_amp(spec, nid, idx, dir) \ ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) -static struct snd_pci_quirk beep_white_list[] = { +static const struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), {} }; @@ -5752,17 +6049,17 @@ static int patch_alc880(struct hda_codec *codec) * ALC260 support */ -static hda_nid_t alc260_dac_nids[1] = { +static const hda_nid_t alc260_dac_nids[1] = { /* front */ 0x02, }; -static hda_nid_t alc260_adc_nids[1] = { +static const hda_nid_t alc260_adc_nids[1] = { /* ADC0 */ 0x04, }; -static hda_nid_t alc260_adc_nids_alt[1] = { +static const hda_nid_t alc260_adc_nids_alt[1] = { /* ADC1 */ 0x05, }; @@ -5770,7 +6067,7 @@ static hda_nid_t alc260_adc_nids_alt[1] = { /* NIDs used when simultaneous access to both ADCs makes sense. Note that * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. */ -static hda_nid_t alc260_dual_adc_nids[2] = { +static const hda_nid_t alc260_dual_adc_nids[2] = { /* ADC0, ADC1 */ 0x04, 0x05 }; @@ -5778,7 +6075,7 @@ static hda_nid_t alc260_dual_adc_nids[2] = { #define ALC260_DIGOUT_NID 0x03 #define ALC260_DIGIN_NID 0x06 -static struct hda_input_mux alc260_capture_source = { +static const struct hda_input_mux alc260_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -5794,7 +6091,7 @@ static struct hda_input_mux alc260_capture_source = { * recording the mixer output on the second ADC (ADC0 doesn't have a * connection to the mixer output). */ -static struct hda_input_mux alc260_fujitsu_capture_sources[2] = { +static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = { { .num_items = 3, .items = { @@ -5818,7 +6115,7 @@ static struct hda_input_mux alc260_fujitsu_capture_sources[2] = { /* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to * the Fujitsu S702x, but jacks are marked differently. */ -static struct hda_input_mux alc260_acer_capture_sources[2] = { +static const struct hda_input_mux alc260_acer_capture_sources[2] = { { .num_items = 4, .items = { @@ -5841,7 +6138,7 @@ static struct hda_input_mux alc260_acer_capture_sources[2] = { }; /* Maxdata Favorit 100XS */ -static struct hda_input_mux alc260_favorit100_capture_sources[2] = { +static const struct hda_input_mux alc260_favorit100_capture_sources[2] = { { .num_items = 2, .items = { @@ -5865,7 +6162,7 @@ static struct hda_input_mux alc260_favorit100_capture_sources[2] = { * element which allows changing the channel mode, so the verb list is * never used. */ -static struct hda_channel_mode alc260_modes[1] = { +static const struct hda_channel_mode alc260_modes[1] = { { 2, NULL }, }; @@ -5879,7 +6176,7 @@ static struct hda_channel_mode alc260_modes[1] = { * acer: acer + capture */ -static struct snd_kcontrol_new alc260_base_output_mixer[] = { +static const struct snd_kcontrol_new alc260_base_output_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), @@ -5889,7 +6186,7 @@ static struct snd_kcontrol_new alc260_base_output_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc260_input_mixer[] = { +static const struct snd_kcontrol_new alc260_input_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), @@ -5902,21 +6199,14 @@ static struct snd_kcontrol_new alc260_input_mixer[] = { }; /* update HP, line and mono out pins according to the master switch */ -static void alc260_hp_master_update(struct hda_codec *codec, - hda_nid_t hp, hda_nid_t line, - hda_nid_t mono) +static void alc260_hp_master_update(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int val = spec->master_sw ? PIN_HP : 0; - /* change HP and line-out pins */ - snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - val); - snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - val); - /* mono (speaker) depending on the HP jack sense */ - val = (val && !spec->jack_present) ? PIN_OUT : 0; - snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - val); + + /* change HP pins */ + do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), + spec->autocfg.hp_pins, spec->master_mute, true); + update_speakers(codec); } static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, @@ -5924,7 +6214,7 @@ static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - *ucontrol->value.integer.value = spec->master_sw; + *ucontrol->value.integer.value = !spec->master_mute; return 0; } @@ -5933,20 +6223,16 @@ static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - int val = !!*ucontrol->value.integer.value; - hda_nid_t hp, line, mono; + int val = !*ucontrol->value.integer.value; - if (val == spec->master_sw) + if (val == spec->master_mute) return 0; - spec->master_sw = val; - hp = (kcontrol->private_value >> 16) & 0xff; - line = (kcontrol->private_value >> 8) & 0xff; - mono = kcontrol->private_value & 0xff; - alc260_hp_master_update(codec, hp, line, mono); + spec->master_mute = val; + alc260_hp_master_update(codec); return 1; } -static struct snd_kcontrol_new alc260_hp_output_mixer[] = { +static const struct snd_kcontrol_new alc260_hp_output_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -5954,7 +6240,6 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = { .info = snd_ctl_boolean_mono_info, .get = alc260_hp_master_sw_get, .put = alc260_hp_master_sw_put, - .private_value = (0x0f << 16) | (0x10 << 8) | 0x11 }, HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), @@ -5966,26 +6251,23 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = { { } /* end */ }; -static struct hda_verb alc260_hp_unsol_verbs[] = { +static const struct hda_verb alc260_hp_unsol_verbs[] = { {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {}, }; -static void alc260_hp_automute(struct hda_codec *codec) +static void alc260_hp_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->jack_present = snd_hda_jack_detect(codec, 0x10); - alc260_hp_master_update(codec, 0x0f, 0x10, 0x11); -} - -static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc260_hp_automute(codec); + spec->autocfg.hp_pins[0] = 0x0f; + spec->autocfg.speaker_pins[0] = 0x10; + spec->autocfg.speaker_pins[1] = 0x11; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } -static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { +static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -5993,7 +6275,6 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { .info = snd_ctl_boolean_mono_info, .get = alc260_hp_master_sw_get, .put = alc260_hp_master_sw_put, - .private_value = (0x15 << 16) | (0x10 << 8) | 0x11 }, HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), @@ -6006,7 +6287,18 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc260_dc7600_bind_master_vol = { +static void alc260_hp_3013_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x10; + spec->autocfg.speaker_pins[1] = 0x11; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT), @@ -6016,7 +6308,7 @@ static struct hda_bind_ctls alc260_dc7600_bind_master_vol = { }, }; -static struct hda_bind_ctls alc260_dc7600_bind_switch = { +static const struct hda_bind_ctls alc260_dc7600_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), @@ -6025,7 +6317,7 @@ static struct hda_bind_ctls alc260_dc7600_bind_switch = { }, }; -static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { +static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol), HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch), HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT), @@ -6033,49 +6325,27 @@ static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { { } /* end */ }; -static struct hda_verb alc260_hp_3013_unsol_verbs[] = { +static const struct hda_verb alc260_hp_3013_unsol_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {}, }; -static void alc260_hp_3013_automute(struct hda_codec *codec) +static void alc260_hp_3012_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->jack_present = snd_hda_jack_detect(codec, 0x15); - alc260_hp_master_update(codec, 0x15, 0x10, 0x11); -} - -static void alc260_hp_3013_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc260_hp_3013_automute(codec); -} - -static void alc260_hp_3012_automute(struct hda_codec *codec) -{ - unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT; - - snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - bits); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - bits); - snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - bits); -} - -static void alc260_hp_3012_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc260_hp_3012_automute(codec); + spec->autocfg.hp_pins[0] = 0x10; + spec->autocfg.speaker_pins[0] = 0x0f; + spec->autocfg.speaker_pins[1] = 0x11; + spec->autocfg.speaker_pins[2] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } /* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. */ -static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { +static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT), @@ -6112,7 +6382,7 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { * controls for such models. On models without a "mono speaker" the control * won't do anything. */ -static struct snd_kcontrol_new alc260_acer_mixer[] = { +static const struct snd_kcontrol_new alc260_acer_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), @@ -6133,7 +6403,7 @@ static struct snd_kcontrol_new alc260_acer_mixer[] = { /* Maxdata Favorit 100XS: one output and one input (0x12) jack */ -static struct snd_kcontrol_new alc260_favorit100_mixer[] = { +static const struct snd_kcontrol_new alc260_favorit100_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), @@ -6146,7 +6416,7 @@ static struct snd_kcontrol_new alc260_favorit100_mixer[] = { /* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12, * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17. */ -static struct snd_kcontrol_new alc260_will_mixer[] = { +static const struct snd_kcontrol_new alc260_will_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), @@ -6163,7 +6433,7 @@ static struct snd_kcontrol_new alc260_will_mixer[] = { /* Replacer 672V ALC260 pin usage: Mic jack = 0x12, * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f. */ -static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { +static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), @@ -6180,7 +6450,7 @@ static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { /* * initialization verbs */ -static struct hda_verb alc260_init_verbs[] = { +static const struct hda_verb alc260_init_verbs[] = { /* Line In pin widget for input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ @@ -6244,7 +6514,7 @@ static struct hda_verb alc260_init_verbs[] = { }; #if 0 /* should be identical with alc260_init_verbs? */ -static struct hda_verb alc260_hp_init_verbs[] = { +static const struct hda_verb alc260_hp_init_verbs[] = { /* Headphone and output */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, /* mono output */ @@ -6294,7 +6564,7 @@ static struct hda_verb alc260_hp_init_verbs[] = { }; #endif -static struct hda_verb alc260_hp_3013_init_verbs[] = { +static const struct hda_verb alc260_hp_3013_init_verbs[] = { /* Line out and output */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* mono output */ @@ -6347,7 +6617,7 @@ static struct hda_verb alc260_hp_3013_init_verbs[] = { * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD * audio = 0x16, internal speaker = 0x10. */ -static struct hda_verb alc260_fujitsu_init_verbs[] = { +static const struct hda_verb alc260_fujitsu_init_verbs[] = { /* Disable all GPIOs */ {0x01, AC_VERB_SET_GPIO_MASK, 0}, /* Internal speaker is connected to headphone pin */ @@ -6429,7 +6699,7 @@ static struct hda_verb alc260_fujitsu_init_verbs[] = { /* Initialisation sequence for ALC260 as configured in Acer TravelMate and * similar laptops (adapted from Fujitsu init verbs). */ -static struct hda_verb alc260_acer_init_verbs[] = { +static const struct hda_verb alc260_acer_init_verbs[] = { /* On TravelMate laptops, GPIO 0 enables the internal speaker and * the headphone jack. Turn this on and rely on the standard mute * methods whenever the user wants to turn these outputs off. @@ -6517,7 +6787,7 @@ static struct hda_verb alc260_acer_init_verbs[] = { /* Initialisation sequence for Maxdata Favorit 100XS * (adapted from Acer init verbs). */ -static struct hda_verb alc260_favorit100_init_verbs[] = { +static const struct hda_verb alc260_favorit100_init_verbs[] = { /* GPIO 0 enables the output jack. * Turn this on and rely on the standard mute * methods whenever the user wants to turn these outputs off. @@ -6597,7 +6867,7 @@ static struct hda_verb alc260_favorit100_init_verbs[] = { { } }; -static struct hda_verb alc260_will_verbs[] = { +static const struct hda_verb alc260_will_verbs[] = { {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -6607,7 +6877,7 @@ static struct hda_verb alc260_will_verbs[] = { {} }; -static struct hda_verb alc260_replacer_672v_verbs[] = { +static const struct hda_verb alc260_replacer_672v_verbs[] = { {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, {0x1a, AC_VERB_SET_PROC_COEF, 0x3050}, @@ -6649,7 +6919,7 @@ static void alc260_replacer_672v_unsol_event(struct hda_codec *codec, alc260_replacer_672v_automute(codec); } -static struct hda_verb alc260_hp_dc7600_verbs[] = { +static const struct hda_verb alc260_hp_dc7600_verbs[] = { {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -6667,17 +6937,17 @@ static struct hda_verb alc260_hp_dc7600_verbs[] = { * configuration. */ #ifdef CONFIG_SND_DEBUG -static hda_nid_t alc260_test_dac_nids[1] = { +static const hda_nid_t alc260_test_dac_nids[1] = { 0x02, }; -static hda_nid_t alc260_test_adc_nids[2] = { +static const hda_nid_t alc260_test_adc_nids[2] = { 0x04, 0x05, }; /* For testing the ALC260, each input MUX needs its own definition since * the signal assignments are different. This assumes that the first ADC * is NID 0x04. */ -static struct hda_input_mux alc260_test_capture_sources[2] = { +static const struct hda_input_mux alc260_test_capture_sources[2] = { { .num_items = 7, .items = { @@ -6704,7 +6974,7 @@ static struct hda_input_mux alc260_test_capture_sources[2] = { }, }, }; -static struct snd_kcontrol_new alc260_test_mixer[] = { +static const struct snd_kcontrol_new alc260_test_mixer[] = { /* Output driver widgets */ HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), @@ -6768,7 +7038,7 @@ static struct snd_kcontrol_new alc260_test_mixer[] = { { } /* end */ }; -static struct hda_verb alc260_test_init_verbs[] = { +static const struct hda_verb alc260_test_init_verbs[] = { /* Enable all GPIOs as outputs with an initial value of 0 */ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, @@ -6906,7 +7176,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, spec->multiout.num_dacs = 1; spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.dac_nids[0] = 0x02; + spec->private_dac_nids[0] = 0x02; nid = cfg->line_out_pins[0]; if (nid) { @@ -7004,7 +7274,7 @@ static void alc260_auto_init_analog_input(struct hda_codec *codec) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc260_volume_init_verbs[] = { +static const struct hda_verb alc260_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -7049,7 +7319,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc260_ignore[] = { 0x17, 0 }; + static const hda_nid_t alc260_ignore[] = { 0x17, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc260_ignore); @@ -7094,7 +7364,7 @@ static void alc260_auto_init(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list alc260_loopbacks[] = { +static const struct hda_amp_list alc260_loopbacks[] = { { 0x07, HDA_INPUT, 0 }, { 0x07, HDA_INPUT, 1 }, { 0x07, HDA_INPUT, 2 }, @@ -7121,7 +7391,7 @@ static const struct alc_fixup alc260_fixups[] = { }, }; -static struct snd_pci_quirk alc260_fixup_tbl[] = { +static const struct snd_pci_quirk alc260_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750), {} }; @@ -7145,7 +7415,7 @@ static const char * const alc260_models[ALC260_MODEL_LAST] = { [ALC260_AUTO] = "auto", }; -static struct snd_pci_quirk alc260_cfg_tbl[] = { +static const struct snd_pci_quirk alc260_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), @@ -7169,7 +7439,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { {} }; -static struct alc_config_preset alc260_presets[] = { +static const struct alc_config_preset alc260_presets[] = { [ALC260_BASIC] = { .mixers = { alc260_base_output_mixer, alc260_input_mixer }, @@ -7194,8 +7464,9 @@ static struct alc_config_preset alc260_presets[] = { .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, - .unsol_event = alc260_hp_unsol_event, - .init_hook = alc260_hp_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_setup, + .init_hook = alc_inithook, }, [ALC260_HP_DC7600] = { .mixers = { alc260_hp_dc7600_mixer, @@ -7209,8 +7480,9 @@ static struct alc_config_preset alc260_presets[] = { .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, - .unsol_event = alc260_hp_3012_unsol_event, - .init_hook = alc260_hp_3012_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_3012_setup, + .init_hook = alc_inithook, }, [ALC260_HP_3013] = { .mixers = { alc260_hp_3013_mixer, @@ -7224,8 +7496,9 @@ static struct alc_config_preset alc260_presets[] = { .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, - .unsol_event = alc260_hp_3013_unsol_event, - .init_hook = alc260_hp_3013_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_3013_setup, + .init_hook = alc_inithook, }, [ALC260_FUJITSU_S702X] = { .mixers = { alc260_fujitsu_mixer }, @@ -7383,6 +7656,7 @@ static int patch_alc260(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC260_AUTO) spec->init_hook = alc260_auto_init; + spec->shutup = alc_eapd_shutup; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc260_loopbacks; @@ -7410,12 +7684,12 @@ static int patch_alc260(struct hda_codec *codec) #define ALC1200_DIGOUT_NID 0x10 -static struct hda_channel_mode alc882_ch_modes[1] = { +static const struct hda_channel_mode alc882_ch_modes[1] = { { 8, NULL } }; /* DACs */ -static hda_nid_t alc882_dac_nids[4] = { +static const hda_nid_t alc882_dac_nids[4] = { /* front, rear, clfe, rear_surr */ 0x02, 0x03, 0x04, 0x05 }; @@ -7425,20 +7699,20 @@ static hda_nid_t alc882_dac_nids[4] = { #define alc882_adc_nids alc880_adc_nids #define alc882_adc_nids_alt alc880_adc_nids_alt #define alc883_adc_nids alc882_adc_nids_alt -static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 }; -static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 }; +static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 }; +static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 }; #define alc889_adc_nids alc880_adc_nids -static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 }; -static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 }; +static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 }; +static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 }; #define alc883_capsrc_nids alc882_capsrc_nids_alt -static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; +static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; #define alc889_capsrc_nids alc882_capsrc_nids /* input MUX */ /* FIXME: should be a matrix-type input source selection */ -static struct hda_input_mux alc882_capture_source = { +static const struct hda_input_mux alc882_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -7450,7 +7724,7 @@ static struct hda_input_mux alc882_capture_source = { #define alc883_capture_source alc882_capture_source -static struct hda_input_mux alc889_capture_source = { +static const struct hda_input_mux alc889_capture_source = { .num_items = 3, .items = { { "Front Mic", 0x0 }, @@ -7459,7 +7733,7 @@ static struct hda_input_mux alc889_capture_source = { }, }; -static struct hda_input_mux mb5_capture_source = { +static const struct hda_input_mux mb5_capture_source = { .num_items = 3, .items = { { "Mic", 0x1 }, @@ -7468,7 +7742,7 @@ static struct hda_input_mux mb5_capture_source = { }, }; -static struct hda_input_mux macmini3_capture_source = { +static const struct hda_input_mux macmini3_capture_source = { .num_items = 2, .items = { { "Line", 0x2 }, @@ -7476,7 +7750,7 @@ static struct hda_input_mux macmini3_capture_source = { }, }; -static struct hda_input_mux alc883_3stack_6ch_intel = { +static const struct hda_input_mux alc883_3stack_6ch_intel = { .num_items = 4, .items = { { "Mic", 0x1 }, @@ -7486,7 +7760,7 @@ static struct hda_input_mux alc883_3stack_6ch_intel = { }, }; -static struct hda_input_mux alc883_lenovo_101e_capture_source = { +static const struct hda_input_mux alc883_lenovo_101e_capture_source = { .num_items = 2, .items = { { "Mic", 0x1 }, @@ -7494,7 +7768,7 @@ static struct hda_input_mux alc883_lenovo_101e_capture_source = { }, }; -static struct hda_input_mux alc883_lenovo_nb0763_capture_source = { +static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -7504,7 +7778,7 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = { }, }; -static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { +static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -7512,7 +7786,7 @@ static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { }, }; -static struct hda_input_mux alc883_lenovo_sky_capture_source = { +static const struct hda_input_mux alc883_lenovo_sky_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -7521,7 +7795,7 @@ static struct hda_input_mux alc883_lenovo_sky_capture_source = { }, }; -static struct hda_input_mux alc883_asus_eee1601_capture_source = { +static const struct hda_input_mux alc883_asus_eee1601_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -7529,7 +7803,7 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = { }, }; -static struct hda_input_mux alc889A_mb31_capture_source = { +static const struct hda_input_mux alc889A_mb31_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -7540,7 +7814,7 @@ static struct hda_input_mux alc889A_mb31_capture_source = { }, }; -static struct hda_input_mux alc889A_imac91_capture_source = { +static const struct hda_input_mux alc889A_imac91_capture_source = { .num_items = 2, .items = { { "Mic", 0x01 }, @@ -7551,14 +7825,14 @@ static struct hda_input_mux alc889A_imac91_capture_source = { /* * 2ch mode */ -static struct hda_channel_mode alc883_3ST_2ch_modes[1] = { +static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = { { 2, NULL } }; /* * 2ch mode */ -static struct hda_verb alc882_3ST_ch2_init[] = { +static const struct hda_verb alc882_3ST_ch2_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, @@ -7569,7 +7843,7 @@ static struct hda_verb alc882_3ST_ch2_init[] = { /* * 4ch mode */ -static struct hda_verb alc882_3ST_ch4_init[] = { +static const struct hda_verb alc882_3ST_ch4_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7581,7 +7855,7 @@ static struct hda_verb alc882_3ST_ch4_init[] = { /* * 6ch mode */ -static struct hda_verb alc882_3ST_ch6_init[] = { +static const struct hda_verb alc882_3ST_ch6_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -7591,7 +7865,7 @@ static struct hda_verb alc882_3ST_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc882_3ST_6ch_modes[3] = { +static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = { { 2, alc882_3ST_ch2_init }, { 4, alc882_3ST_ch4_init }, { 6, alc882_3ST_ch6_init }, @@ -7602,7 +7876,7 @@ static struct hda_channel_mode alc882_3ST_6ch_modes[3] = { /* * 2ch mode */ -static struct hda_verb alc883_3ST_ch2_clevo_init[] = { +static const struct hda_verb alc883_3ST_ch2_clevo_init[] = { { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -7614,7 +7888,7 @@ static struct hda_verb alc883_3ST_ch2_clevo_init[] = { /* * 4ch mode */ -static struct hda_verb alc883_3ST_ch4_clevo_init[] = { +static const struct hda_verb alc883_3ST_ch4_clevo_init[] = { { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -7627,7 +7901,7 @@ static struct hda_verb alc883_3ST_ch4_clevo_init[] = { /* * 6ch mode */ -static struct hda_verb alc883_3ST_ch6_clevo_init[] = { +static const struct hda_verb alc883_3ST_ch6_clevo_init[] = { { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -7638,7 +7912,7 @@ static struct hda_verb alc883_3ST_ch6_clevo_init[] = { { } /* end */ }; -static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = { +static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = { { 2, alc883_3ST_ch2_clevo_init }, { 4, alc883_3ST_ch4_clevo_init }, { 6, alc883_3ST_ch6_clevo_init }, @@ -7648,7 +7922,7 @@ static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = { /* * 6ch mode */ -static struct hda_verb alc882_sixstack_ch6_init[] = { +static const struct hda_verb alc882_sixstack_ch6_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7659,7 +7933,7 @@ static struct hda_verb alc882_sixstack_ch6_init[] = { /* * 8ch mode */ -static struct hda_verb alc882_sixstack_ch8_init[] = { +static const struct hda_verb alc882_sixstack_ch8_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7667,7 +7941,7 @@ static struct hda_verb alc882_sixstack_ch8_init[] = { { } /* end */ }; -static struct hda_channel_mode alc882_sixstack_modes[2] = { +static const struct hda_channel_mode alc882_sixstack_modes[2] = { { 6, alc882_sixstack_ch6_init }, { 8, alc882_sixstack_ch8_init }, }; @@ -7675,7 +7949,7 @@ static struct hda_channel_mode alc882_sixstack_modes[2] = { /* Macbook Air 2,1 */ -static struct hda_channel_mode alc885_mba21_ch_modes[1] = { +static const struct hda_channel_mode alc885_mba21_ch_modes[1] = { { 2, NULL }, }; @@ -7686,7 +7960,7 @@ static struct hda_channel_mode alc885_mba21_ch_modes[1] = { /* * 2ch mode */ -static struct hda_verb alc885_mbp_ch2_init[] = { +static const struct hda_verb alc885_mbp_ch2_init[] = { { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, @@ -7696,7 +7970,7 @@ static struct hda_verb alc885_mbp_ch2_init[] = { /* * 4ch mode */ -static struct hda_verb alc885_mbp_ch4_init[] = { +static const struct hda_verb alc885_mbp_ch4_init[] = { { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, @@ -7705,7 +7979,7 @@ static struct hda_verb alc885_mbp_ch4_init[] = { { } /* end */ }; -static struct hda_channel_mode alc885_mbp_4ch_modes[2] = { +static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = { { 2, alc885_mbp_ch2_init }, { 4, alc885_mbp_ch4_init }, }; @@ -7715,7 +7989,7 @@ static struct hda_channel_mode alc885_mbp_4ch_modes[2] = { * Speakers/Woofer/HP = Front * LineIn = Input */ -static struct hda_verb alc885_mb5_ch2_init[] = { +static const struct hda_verb alc885_mb5_ch2_init[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, { } /* end */ @@ -7727,14 +8001,14 @@ static struct hda_verb alc885_mb5_ch2_init[] = { * Woofer = LFE * LineIn = Surround */ -static struct hda_verb alc885_mb5_ch6_init[] = { +static const struct hda_verb alc885_mb5_ch6_init[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, { } /* end */ }; -static struct hda_channel_mode alc885_mb5_6ch_modes[2] = { +static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = { { 2, alc885_mb5_ch2_init }, { 6, alc885_mb5_ch6_init }, }; @@ -7744,7 +8018,7 @@ static struct hda_channel_mode alc885_mb5_6ch_modes[2] = { /* * 2ch mode */ -static struct hda_verb alc883_4ST_ch2_init[] = { +static const struct hda_verb alc883_4ST_ch2_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, @@ -7757,7 +8031,7 @@ static struct hda_verb alc883_4ST_ch2_init[] = { /* * 4ch mode */ -static struct hda_verb alc883_4ST_ch4_init[] = { +static const struct hda_verb alc883_4ST_ch4_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, @@ -7771,7 +8045,7 @@ static struct hda_verb alc883_4ST_ch4_init[] = { /* * 6ch mode */ -static struct hda_verb alc883_4ST_ch6_init[] = { +static const struct hda_verb alc883_4ST_ch6_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7786,7 +8060,7 @@ static struct hda_verb alc883_4ST_ch6_init[] = { /* * 8ch mode */ -static struct hda_verb alc883_4ST_ch8_init[] = { +static const struct hda_verb alc883_4ST_ch8_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, @@ -7799,7 +8073,7 @@ static struct hda_verb alc883_4ST_ch8_init[] = { { } /* end */ }; -static struct hda_channel_mode alc883_4ST_8ch_modes[4] = { +static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = { { 2, alc883_4ST_ch2_init }, { 4, alc883_4ST_ch4_init }, { 6, alc883_4ST_ch6_init }, @@ -7810,7 +8084,7 @@ static struct hda_channel_mode alc883_4ST_8ch_modes[4] = { /* * 2ch mode */ -static struct hda_verb alc883_3ST_ch2_intel_init[] = { +static const struct hda_verb alc883_3ST_ch2_intel_init[] = { { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, @@ -7821,7 +8095,7 @@ static struct hda_verb alc883_3ST_ch2_intel_init[] = { /* * 4ch mode */ -static struct hda_verb alc883_3ST_ch4_intel_init[] = { +static const struct hda_verb alc883_3ST_ch4_intel_init[] = { { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7833,7 +8107,7 @@ static struct hda_verb alc883_3ST_ch4_intel_init[] = { /* * 6ch mode */ -static struct hda_verb alc883_3ST_ch6_intel_init[] = { +static const struct hda_verb alc883_3ST_ch6_intel_init[] = { { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -7843,7 +8117,7 @@ static struct hda_verb alc883_3ST_ch6_intel_init[] = { { } /* end */ }; -static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { +static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { { 2, alc883_3ST_ch2_intel_init }, { 4, alc883_3ST_ch4_intel_init }, { 6, alc883_3ST_ch6_intel_init }, @@ -7852,7 +8126,7 @@ static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { /* * 2ch mode */ -static struct hda_verb alc889_ch2_intel_init[] = { +static const struct hda_verb alc889_ch2_intel_init[] = { { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 }, { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 }, @@ -7865,7 +8139,7 @@ static struct hda_verb alc889_ch2_intel_init[] = { /* * 6ch mode */ -static struct hda_verb alc889_ch6_intel_init[] = { +static const struct hda_verb alc889_ch6_intel_init[] = { { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -7878,7 +8152,7 @@ static struct hda_verb alc889_ch6_intel_init[] = { /* * 8ch mode */ -static struct hda_verb alc889_ch8_intel_init[] = { +static const struct hda_verb alc889_ch8_intel_init[] = { { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -7889,7 +8163,7 @@ static struct hda_verb alc889_ch8_intel_init[] = { { } /* end */ }; -static struct hda_channel_mode alc889_8ch_intel_modes[3] = { +static const struct hda_channel_mode alc889_8ch_intel_modes[3] = { { 2, alc889_ch2_intel_init }, { 6, alc889_ch6_intel_init }, { 8, alc889_ch8_intel_init }, @@ -7898,7 +8172,7 @@ static struct hda_channel_mode alc889_8ch_intel_modes[3] = { /* * 6ch mode */ -static struct hda_verb alc883_sixstack_ch6_init[] = { +static const struct hda_verb alc883_sixstack_ch6_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7909,7 +8183,7 @@ static struct hda_verb alc883_sixstack_ch6_init[] = { /* * 8ch mode */ -static struct hda_verb alc883_sixstack_ch8_init[] = { +static const struct hda_verb alc883_sixstack_ch8_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7917,7 +8191,7 @@ static struct hda_verb alc883_sixstack_ch8_init[] = { { } /* end */ }; -static struct hda_channel_mode alc883_sixstack_modes[2] = { +static const struct hda_channel_mode alc883_sixstack_modes[2] = { { 6, alc883_sixstack_ch6_init }, { 8, alc883_sixstack_ch8_init }, }; @@ -7926,7 +8200,7 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = { /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ -static struct snd_kcontrol_new alc882_base_mixer[] = { +static const struct snd_kcontrol_new alc882_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -7953,14 +8227,14 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { /* Macbook Air 2,1 same control for HP and internal Speaker */ -static struct snd_kcontrol_new alc885_mba21_mixer[] = { +static const struct snd_kcontrol_new alc885_mba21_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT), { } }; -static struct snd_kcontrol_new alc885_mbp3_mixer[] = { +static const struct snd_kcontrol_new alc885_mbp3_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT), @@ -7975,7 +8249,7 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc885_mb5_mixer[] = { +static const struct snd_kcontrol_new alc885_mb5_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), @@ -7993,7 +8267,7 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc885_macmini3_mixer[] = { +static const struct snd_kcontrol_new alc885_macmini3_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), @@ -8008,14 +8282,14 @@ static struct snd_kcontrol_new alc885_macmini3_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc885_imac91_mixer[] = { +static const struct snd_kcontrol_new alc885_imac91_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), { } /* end */ }; -static struct snd_kcontrol_new alc882_w2jc_mixer[] = { +static const struct snd_kcontrol_new alc882_w2jc_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -8028,7 +8302,7 @@ static struct snd_kcontrol_new alc882_w2jc_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc882_targa_mixer[] = { +static const struct snd_kcontrol_new alc882_targa_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -8048,7 +8322,7 @@ static struct snd_kcontrol_new alc882_targa_mixer[] = { /* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ??? * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c */ -static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { +static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -8065,7 +8339,7 @@ static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { +static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -8079,7 +8353,7 @@ static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc882_chmode_mixer[] = { +static const struct snd_kcontrol_new alc882_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -8090,7 +8364,7 @@ static struct snd_kcontrol_new alc882_chmode_mixer[] = { { } /* end */ }; -static struct hda_verb alc882_base_init_verbs[] = { +static const struct hda_verb alc882_base_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, @@ -8152,7 +8426,7 @@ static struct hda_verb alc882_base_init_verbs[] = { { } }; -static struct hda_verb alc882_adc1_init_verbs[] = { +static const struct hda_verb alc882_adc1_init_verbs[] = { /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, @@ -8164,26 +8438,26 @@ static struct hda_verb alc882_adc1_init_verbs[] = { { } }; -static struct hda_verb alc882_eapd_verbs[] = { +static const struct hda_verb alc882_eapd_verbs[] = { /* change to EAPD mode */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, { } }; -static struct hda_verb alc889_eapd_verbs[] = { +static const struct hda_verb alc889_eapd_verbs[] = { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -static struct hda_verb alc_hp15_unsol_verbs[] = { +static const struct hda_verb alc_hp15_unsol_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {} }; -static struct hda_verb alc885_init_verbs[] = { +static const struct hda_verb alc885_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -8242,7 +8516,7 @@ static struct hda_verb alc885_init_verbs[] = { { } }; -static struct hda_verb alc885_init_input_verbs[] = { +static const struct hda_verb alc885_init_input_verbs[] = { {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, @@ -8251,7 +8525,7 @@ static struct hda_verb alc885_init_input_verbs[] = { /* Unmute Selector 24h and set the default input to front mic */ -static struct hda_verb alc889_init_input_verbs[] = { +static const struct hda_verb alc889_init_input_verbs[] = { {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, { } @@ -8261,7 +8535,7 @@ static struct hda_verb alc889_init_input_verbs[] = { #define alc883_init_verbs alc882_base_init_verbs /* Mac Pro test */ -static struct snd_kcontrol_new alc882_macpro_mixer[] = { +static const struct snd_kcontrol_new alc882_macpro_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT), @@ -8274,7 +8548,7 @@ static struct snd_kcontrol_new alc882_macpro_mixer[] = { { } /* end */ }; -static struct hda_verb alc882_macpro_init_verbs[] = { +static const struct hda_verb alc882_macpro_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -8326,7 +8600,7 @@ static struct hda_verb alc882_macpro_init_verbs[] = { }; /* Macbook 5,1 */ -static struct hda_verb alc885_mb5_init_verbs[] = { +static const struct hda_verb alc885_mb5_init_verbs[] = { /* DACs */ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -8375,7 +8649,7 @@ static struct hda_verb alc885_mb5_init_verbs[] = { }; /* Macmini 3,1 */ -static struct hda_verb alc885_macmini3_init_verbs[] = { +static const struct hda_verb alc885_macmini3_init_verbs[] = { /* DACs */ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -8422,7 +8696,7 @@ static struct hda_verb alc885_macmini3_init_verbs[] = { }; -static struct hda_verb alc885_mba21_init_verbs[] = { +static const struct hda_verb alc885_mba21_init_verbs[] = { /*Internal and HP Speaker Mixer*/ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -8445,7 +8719,7 @@ static struct hda_verb alc885_mba21_init_verbs[] = { /* Macbook Pro rev3 */ -static struct hda_verb alc885_mbp3_init_verbs[] = { +static const struct hda_verb alc885_mbp3_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -8509,7 +8783,7 @@ static struct hda_verb alc885_mbp3_init_verbs[] = { }; /* iMac 9,1 */ -static struct hda_verb alc885_imac91_init_verbs[] = { +static const struct hda_verb alc885_imac91_init_verbs[] = { /* Internal Speaker Pin (0x0c) */ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -8564,14 +8838,14 @@ static struct hda_verb alc885_imac91_init_verbs[] = { }; /* iMac 24 mixer. */ -static struct snd_kcontrol_new alc885_imac24_mixer[] = { +static const struct snd_kcontrol_new alc885_imac24_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT), { } /* end */ }; /* iMac 24 init verbs. */ -static struct hda_verb alc885_imac24_init_verbs[] = { +static const struct hda_verb alc885_imac24_init_verbs[] = { /* Internal speakers: output 0 (0x0c) */ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -8599,6 +8873,8 @@ static void alc885_imac24_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x18; spec->autocfg.speaker_pins[1] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } #define alc885_mb5_setup alc885_imac24_setup @@ -8611,6 +8887,8 @@ static void alc885_mba21_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x18; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } @@ -8621,6 +8899,8 @@ static void alc885_mbp3_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc885_imac91_setup(struct hda_codec *codec) @@ -8630,9 +8910,11 @@ static void alc885_imac91_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x18; spec->autocfg.speaker_pins[1] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc882_targa_verbs[] = { +static const struct hda_verb alc882_targa_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -8651,7 +8933,7 @@ static struct hda_verb alc882_targa_verbs[] = { static void alc882_targa_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - alc_automute_amp(codec); + alc_hp_automute(codec); snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, spec->jack_present ? 1 : 3); } @@ -8662,6 +8944,8 @@ static void alc882_targa_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) @@ -8670,7 +8954,7 @@ static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) alc882_targa_automute(codec); } -static struct hda_verb alc882_asus_a7j_verbs[] = { +static const struct hda_verb alc882_asus_a7j_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -8688,7 +8972,7 @@ static struct hda_verb alc882_asus_a7j_verbs[] = { { } /* end */ }; -static struct hda_verb alc882_asus_a7m_verbs[] = { +static const struct hda_verb alc882_asus_a7m_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -8749,13 +9033,13 @@ static void alc885_macpro_init_hook(struct hda_codec *codec) static void alc885_imac24_init_hook(struct hda_codec *codec) { alc885_macpro_init_hook(codec); - alc_automute_amp(codec); + alc_hp_automute(codec); } /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc883_auto_init_verbs[] = { +static const struct hda_verb alc883_auto_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -8795,7 +9079,7 @@ static struct hda_verb alc883_auto_init_verbs[] = { }; /* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ -static struct hda_verb alc889A_mb31_ch2_init[] = { +static const struct hda_verb alc889A_mb31_ch2_init[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ @@ -8804,7 +9088,7 @@ static struct hda_verb alc889A_mb31_ch2_init[] = { }; /* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */ -static struct hda_verb alc889A_mb31_ch4_init[] = { +static const struct hda_verb alc889A_mb31_ch4_init[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ @@ -8813,7 +9097,7 @@ static struct hda_verb alc889A_mb31_ch4_init[] = { }; /* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */ -static struct hda_verb alc889A_mb31_ch5_init[] = { +static const struct hda_verb alc889A_mb31_ch5_init[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ @@ -8822,7 +9106,7 @@ static struct hda_verb alc889A_mb31_ch5_init[] = { }; /* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */ -static struct hda_verb alc889A_mb31_ch6_init[] = { +static const struct hda_verb alc889A_mb31_ch6_init[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ @@ -8830,14 +9114,14 @@ static struct hda_verb alc889A_mb31_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { +static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { { 2, alc889A_mb31_ch2_init }, { 4, alc889A_mb31_ch4_init }, { 5, alc889A_mb31_ch5_init }, { 6, alc889A_mb31_ch6_init }, }; -static struct hda_verb alc883_medion_eapd_verbs[] = { +static const struct hda_verb alc883_medion_eapd_verbs[] = { /* eanable EAPD on medion laptop */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, @@ -8846,7 +9130,7 @@ static struct hda_verb alc883_medion_eapd_verbs[] = { #define alc883_base_mixer alc882_base_mixer -static struct snd_kcontrol_new alc883_mitac_mixer[] = { +static const struct snd_kcontrol_new alc883_mitac_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), @@ -8863,7 +9147,7 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { +static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -8877,7 +9161,7 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { +static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -8891,7 +9175,7 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { +static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -8908,7 +9192,7 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { +static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -8931,7 +9215,7 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { +static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -8955,7 +9239,7 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = { +static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -8979,7 +9263,7 @@ static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_fivestack_mixer[] = { +static const struct snd_kcontrol_new alc883_fivestack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -9002,7 +9286,7 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_targa_mixer[] = { +static const struct snd_kcontrol_new alc883_targa_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -9023,7 +9307,7 @@ static struct snd_kcontrol_new alc883_targa_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { +static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -9039,7 +9323,7 @@ static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = { +static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = { HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), @@ -9048,7 +9332,7 @@ static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { +static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -9060,7 +9344,7 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { +static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -9073,7 +9357,7 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = { +static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -9083,7 +9367,7 @@ static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = { { } /* end */ }; -static struct hda_verb alc883_medion_wim2160_verbs[] = { +static const struct hda_verb alc883_medion_wim2160_verbs[] = { /* Unmute front mixer */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -9107,9 +9391,11 @@ static void alc883_medion_wim2160_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1a; spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { +static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -9121,7 +9407,7 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { +static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -9134,7 +9420,7 @@ static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { +static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT), @@ -9159,7 +9445,7 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc889A_mb31_mixer[] = { +static const struct snd_kcontrol_new alc889A_mb31_mixer[] = { /* Output mixers */ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), @@ -9185,7 +9471,7 @@ static struct snd_kcontrol_new alc889A_mb31_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_vaiott_mixer[] = { +static const struct snd_kcontrol_new alc883_vaiott_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -9195,7 +9481,7 @@ static struct snd_kcontrol_new alc883_vaiott_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc883_bind_cap_vol = { +static const struct hda_bind_ctls alc883_bind_cap_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), @@ -9204,7 +9490,7 @@ static struct hda_bind_ctls alc883_bind_cap_vol = { }, }; -static struct hda_bind_ctls alc883_bind_cap_switch = { +static const struct hda_bind_ctls alc883_bind_cap_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), @@ -9213,7 +9499,7 @@ static struct hda_bind_ctls alc883_bind_cap_switch = { }, }; -static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { +static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -9225,7 +9511,7 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { +static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), { @@ -9240,7 +9526,7 @@ static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_chmode_mixer[] = { +static const struct snd_kcontrol_new alc883_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -9259,9 +9545,11 @@ static void alc883_mitac_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc883_mitac_verbs[] = { +static const struct hda_verb alc883_mitac_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -9276,7 +9564,7 @@ static struct hda_verb alc883_mitac_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_clevo_m540r_verbs[] = { +static const struct hda_verb alc883_clevo_m540r_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -9292,7 +9580,7 @@ static struct hda_verb alc883_clevo_m540r_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_clevo_m720_verbs[] = { +static const struct hda_verb alc883_clevo_m720_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -9307,7 +9595,7 @@ static struct hda_verb alc883_clevo_m720_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { +static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { /* HP */ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -9321,7 +9609,7 @@ static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_targa_verbs[] = { +static const struct hda_verb alc883_targa_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -9350,14 +9638,14 @@ static struct hda_verb alc883_targa_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_lenovo_101e_verbs[] = { +static const struct hda_verb alc883_lenovo_101e_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN}, { } /* end */ }; -static struct hda_verb alc883_lenovo_nb0763_verbs[] = { +static const struct hda_verb alc883_lenovo_nb0763_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, @@ -9365,7 +9653,7 @@ static struct hda_verb alc883_lenovo_nb0763_verbs[] = { { } /* end */ }; -static struct hda_verb alc888_lenovo_ms7195_verbs[] = { +static const struct hda_verb alc888_lenovo_ms7195_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -9374,7 +9662,7 @@ static struct hda_verb alc888_lenovo_ms7195_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_haier_w66_verbs[] = { +static const struct hda_verb alc883_haier_w66_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -9387,7 +9675,7 @@ static struct hda_verb alc883_haier_w66_verbs[] = { { } /* end */ }; -static struct hda_verb alc888_lenovo_sky_verbs[] = { +static const struct hda_verb alc888_lenovo_sky_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -9399,12 +9687,12 @@ static struct hda_verb alc888_lenovo_sky_verbs[] = { { } /* end */ }; -static struct hda_verb alc888_6st_dell_verbs[] = { +static const struct hda_verb alc888_6st_dell_verbs[] = { {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, { } }; -static struct hda_verb alc883_vaiott_verbs[] = { +static const struct hda_verb alc883_vaiott_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -9423,9 +9711,11 @@ static void alc888_3st_hp_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x18; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc888_3st_hp_verbs[] = { +static const struct hda_verb alc888_3st_hp_verbs[] = { {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */ {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */ @@ -9436,7 +9726,7 @@ static struct hda_verb alc888_3st_hp_verbs[] = { /* * 2ch mode */ -static struct hda_verb alc888_3st_hp_2ch_init[] = { +static const struct hda_verb alc888_3st_hp_2ch_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, @@ -9447,7 +9737,7 @@ static struct hda_verb alc888_3st_hp_2ch_init[] = { /* * 4ch mode */ -static struct hda_verb alc888_3st_hp_4ch_init[] = { +static const struct hda_verb alc888_3st_hp_4ch_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -9459,7 +9749,7 @@ static struct hda_verb alc888_3st_hp_4ch_init[] = { /* * 6ch mode */ -static struct hda_verb alc888_3st_hp_6ch_init[] = { +static const struct hda_verb alc888_3st_hp_6ch_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -9469,39 +9759,21 @@ static struct hda_verb alc888_3st_hp_6ch_init[] = { { } /* end */ }; -static struct hda_channel_mode alc888_3st_hp_modes[3] = { +static const struct hda_channel_mode alc888_3st_hp_modes[3] = { { 2, alc888_3st_hp_2ch_init }, { 4, alc888_3st_hp_4ch_init }, { 6, alc888_3st_hp_6ch_init }, }; -/* toggle front-jack and RCA according to the hp-jack state */ -static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec) +static void alc888_lenovo_ms7195_setup(struct hda_codec *codec) { - unsigned int present = snd_hda_jack_detect(codec, 0x1b); - - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - -/* toggle RCA according to the front-jack state */ -static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec) -{ - unsigned int present = snd_hda_jack_detect(codec, 0x14); - - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} + struct alc_spec *spec = codec->spec; -static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc888_lenovo_ms7195_front_automute(codec); - if ((res >> 26) == ALC880_FRONT_EVENT) - alc888_lenovo_ms7195_rca_automute(codec); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* toggle speaker-output according to the hp-jack state */ @@ -9511,6 +9783,8 @@ static void alc883_lenovo_nb0763_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* toggle speaker-output according to the hp-jack state */ @@ -9523,11 +9797,13 @@ static void alc883_clevo_m720_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc883_clevo_m720_init_hook(struct hda_codec *codec) { - alc_automute_amp(codec); + alc_hp_automute(codec); alc88x_simple_mic_automute(codec); } @@ -9539,7 +9815,7 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, alc88x_simple_mic_automute(codec); break; default: - alc_automute_amp_unsol_event(codec, res); + alc_sku_unsol_event(codec, res); break; } } @@ -9551,6 +9827,8 @@ static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc883_haier_w66_setup(struct hda_codec *codec) @@ -9559,33 +9837,21 @@ static void alc883_haier_w66_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) -{ - int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0; - - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) +static void alc883_lenovo_101e_setup(struct hda_codec *codec) { - int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0; - - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} + struct alc_spec *spec = codec->spec; -static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc883_lenovo_101e_all_automute(codec); - if ((res >> 26) == ALC880_FRONT_EVENT) - alc883_lenovo_101e_ispeaker_automute(codec); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* toggle speaker-output according to the hp-jack state */ @@ -9596,9 +9862,11 @@ static void alc883_acer_aspire_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; spec->autocfg.speaker_pins[1] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc883_acer_eapd_verbs[] = { +static const struct hda_verb alc883_acer_eapd_verbs[] = { /* HP Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -9625,6 +9893,8 @@ static void alc888_6st_dell_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[1] = 0x15; spec->autocfg.speaker_pins[2] = 0x16; spec->autocfg.speaker_pins[3] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc888_lenovo_sky_setup(struct hda_codec *codec) @@ -9637,6 +9907,8 @@ static void alc888_lenovo_sky_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x16; spec->autocfg.speaker_pins[3] = 0x17; spec->autocfg.speaker_pins[4] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc883_vaiott_setup(struct hda_codec *codec) @@ -9646,9 +9918,11 @@ static void alc883_vaiott_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc888_asus_m90v_verbs[] = { +static const struct hda_verb alc888_asus_m90v_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -9671,9 +9945,11 @@ static void alc883_mode2_setup(struct hda_codec *codec) spec->ext_mic.mux_idx = 0; spec->int_mic.mux_idx = 1; spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc888_asus_eee1601_verbs[] = { +static const struct hda_verb alc888_asus_eee1601_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -9692,10 +9968,10 @@ static void alc883_eee1601_inithook(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; - alc_automute_pin(codec); + alc_hp_automute(codec); } -static struct hda_verb alc889A_mb31_verbs[] = { +static const struct hda_verb alc889A_mb31_verbs[] = { /* Init rear pin (used as headphone output) */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */ @@ -9741,11 +10017,11 @@ static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) #define alc882_pcm_digital_playback alc880_pcm_digital_playback #define alc882_pcm_digital_capture alc880_pcm_digital_capture -static hda_nid_t alc883_slave_dig_outs[] = { +static const hda_nid_t alc883_slave_dig_outs[] = { ALC1200_DIGOUT_NID, 0, }; -static hda_nid_t alc1200_slave_dig_outs[] = { +static const hda_nid_t alc1200_slave_dig_outs[] = { ALC883_DIGOUT_NID, 0, }; @@ -9804,7 +10080,7 @@ static const char * const alc882_models[ALC882_MODEL_LAST] = { [ALC882_AUTO] = "auto", }; -static struct snd_pci_quirk alc882_cfg_tbl[] = { +static const struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), @@ -9863,6 +10139,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL), SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), @@ -9930,7 +10207,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { }; /* codec SSID table for Intel Mac */ -static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { +static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3), @@ -9957,7 +10234,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { {} /* terminator */ }; -static struct alc_config_preset alc882_presets[] = { +static const struct alc_config_preset alc882_presets[] = { [ALC882_3ST_DIG] = { .mixers = { alc882_base_mixer }, .init_verbs = { alc882_base_init_verbs, @@ -10013,9 +10290,9 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc885_mba21_ch_modes, .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), .input_mux = &alc882_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_mba21_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC885_MBP3] = { .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, @@ -10029,9 +10306,9 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &alc882_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_mbp3_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC885_MB5] = { .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, @@ -10044,9 +10321,9 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &mb5_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_mb5_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC885_MACMINI3] = { .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer }, @@ -10059,9 +10336,9 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &macmini3_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_macmini3_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC885_MACPRO] = { .mixers = { alc882_macpro_mixer }, @@ -10085,7 +10362,7 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_imac24_setup, .init_hook = alc885_imac24_init_hook, }, @@ -10100,9 +10377,9 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &alc889A_imac91_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_imac91_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC882_TARGA] = { .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, @@ -10118,7 +10395,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc882_3ST_6ch_modes, .need_dac_fix = 1, .input_mux = &alc882_capture_source, - .unsol_event = alc882_targa_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc882_targa_setup, .init_hook = alc882_targa_automute, }, @@ -10212,8 +10489,8 @@ static struct alc_config_preset alc882_presets[] = { .capsrc_nids = alc889_capsrc_nids, .input_mux = &alc889_capture_source, .setup = alc889_automute_setup, - .init_hook = alc_automute_amp, - .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc_hp_automute, + .unsol_event = alc_sku_unsol_event, .need_dac_fix = 1, }, [ALC889_INTEL] = { @@ -10233,7 +10510,7 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &alc889_capture_source, .setup = alc889_automute_setup, .init_hook = alc889_intel_init_hook, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .need_dac_fix = 1, }, [ALC883_6ST_DIG] = { @@ -10322,9 +10599,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_acer_aspire_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_ACER_ASPIRE_4930G] = { .mixers = { alc888_acer_aspire_4930g_mixer, @@ -10344,9 +10621,9 @@ static struct alc_config_preset alc882_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_acer_aspire_4930g_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_ACER_ASPIRE_6530G] = { .mixers = { alc888_acer_aspire_6530_mixer }, @@ -10363,9 +10640,9 @@ static struct alc_config_preset alc882_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_acer_aspire_6530_sources, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_acer_aspire_6530g_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_ACER_ASPIRE_8930G] = { .mixers = { alc889_acer_aspire_8930g_mixer, @@ -10386,9 +10663,9 @@ static struct alc_config_preset alc882_presets[] = { .num_mux_defs = ARRAY_SIZE(alc889_capture_sources), .input_mux = alc889_capture_sources, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc889_acer_aspire_8930g_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, #ifdef CONFIG_SND_HDA_POWER_SAVE .power_hook = alc_power_eapd, #endif @@ -10409,9 +10686,9 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .const_channel_count = 6, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_acer_aspire_7730g_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, @@ -10438,9 +10715,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_medion_wim2160_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC883_LAPTOP_EAPD] = { .mixers = { alc883_base_mixer }, @@ -10490,8 +10767,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_lenovo_101e_capture_source, - .unsol_event = alc883_lenovo_101e_unsol_event, - .init_hook = alc883_lenovo_101e_all_automute, + .setup = alc883_lenovo_101e_setup, + .unsol_event = alc_sku_unsol_event, + .init_hook = alc_inithook, }, [ALC883_LENOVO_NB0763] = { .mixers = { alc883_lenovo_nb0763_mixer }, @@ -10502,9 +10780,9 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .need_dac_fix = 1, .input_mux = &alc883_lenovo_nb0763_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_lenovo_nb0763_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_LENOVO_MS7195_DIG] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -10516,8 +10794,9 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_6ch_modes, .need_dac_fix = 1, .input_mux = &alc883_capture_source, - .unsol_event = alc883_lenovo_ms7195_unsol_event, - .init_hook = alc888_lenovo_ms7195_front_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_lenovo_ms7195_setup, + .init_hook = alc_inithook, }, [ALC883_HAIER_W66] = { .mixers = { alc883_targa_2ch_mixer}, @@ -10528,9 +10807,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_haier_w66_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_3ST_HP] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -10541,9 +10820,9 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc888_3st_hp_modes, .need_dac_fix = 1, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_3st_hp_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_6ST_DELL] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, @@ -10555,9 +10834,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_6st_dell_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC883_MITAC] = { .mixers = { alc883_mitac_mixer }, @@ -10567,9 +10846,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_mitac_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC883_FUJITSU_PI2515] = { .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, @@ -10581,9 +10860,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_fujitsu_pi2515_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_2ch_fujitsu_pi2515_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_FUJITSU_XA3530] = { .mixers = { alc888_base_mixer, alc883_chmode_mixer }, @@ -10600,9 +10879,9 @@ static struct alc_config_preset alc882_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_fujitsu_xa3530_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_LENOVO_SKY] = { .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, @@ -10614,9 +10893,9 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_sixstack_modes, .need_dac_fix = 1, .input_mux = &alc883_lenovo_sky_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_lenovo_sky_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_ASUS_M90V] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -10684,9 +10963,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_vaiott_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, }; @@ -10699,7 +10978,6 @@ enum { PINFIX_LENOVO_Y530, PINFIX_PB_M5210, PINFIX_ACER_ASPIRE_7736, - PINFIX_GIGABYTE_880GM, }; static const struct alc_fixup alc882_fixups[] = { @@ -10731,21 +11009,13 @@ static const struct alc_fixup alc882_fixups[] = { .type = ALC_FIXUP_SKU, .v.sku = ALC_FIXUP_SKU_IGNORE, }, - [PINFIX_GIGABYTE_880GM] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x1114410 }, /* set as speaker */ - { } - } - }, }; -static struct snd_pci_quirk alc882_fixup_tbl[] = { +static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte", PINFIX_GIGABYTE_880GM), {} }; @@ -10849,6 +11119,11 @@ static void alc882_auto_init_input_src(struct hda_codec *codec) const struct hda_input_mux *imux; int conns, mute, idx, item; + /* mute ADC */ + snd_hda_codec_write(codec, spec->adc_nids[c], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(0)); + conns = snd_hda_get_connections(codec, nid, conn_list, ARRAY_SIZE(conn_list)); if (conns < 0) @@ -10928,7 +11203,7 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) static int alc882_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - static hda_nid_t alc882_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc882_ignore[] = { 0x1d, 0 }; int err; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, @@ -10941,6 +11216,9 @@ static int alc882_parse_auto_config(struct hda_codec *codec) err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); if (err < 0) return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; @@ -11142,14 +11420,14 @@ static int patch_alc882(struct hda_codec *codec) #define alc262_modes alc260_modes #define alc262_capture_source alc882_capture_source -static hda_nid_t alc262_dmic_adc_nids[1] = { +static const hda_nid_t alc262_dmic_adc_nids[1] = { /* ADC0 */ 0x09 }; -static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 }; +static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 }; -static struct snd_kcontrol_new alc262_base_mixer[] = { +static const struct snd_kcontrol_new alc262_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -11170,71 +11448,30 @@ static struct snd_kcontrol_new alc262_base_mixer[] = { }; /* update HP, line and mono-out pins according to the master switch */ -static void alc262_hp_master_update(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int val = spec->master_sw; - - /* HP & line-out */ - snd_hda_codec_write_cache(codec, 0x1b, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - val ? PIN_HP : 0); - snd_hda_codec_write_cache(codec, 0x15, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - val ? PIN_HP : 0); - /* mono (speaker) depending on the HP jack sense */ - val = val && !spec->jack_present; - snd_hda_codec_write_cache(codec, 0x16, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - val ? PIN_OUT : 0); -} +#define alc262_hp_master_update alc260_hp_master_update -static void alc262_hp_bpc_automute(struct hda_codec *codec) +static void alc262_hp_bpc_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->jack_present = snd_hda_jack_detect(codec, 0x1b); - alc262_hp_master_update(codec); -} - -static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hp_bpc_automute(codec); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } -static void alc262_hp_wildwest_automute(struct hda_codec *codec) +static void alc262_hp_wildwest_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->jack_present = snd_hda_jack_detect(codec, 0x15); - alc262_hp_master_update(codec); -} - -static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hp_wildwest_automute(codec); + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } #define alc262_hp_master_sw_get alc260_hp_master_sw_get - -static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int val = !!*ucontrol->value.integer.value; - - if (val == spec->master_sw) - return 0; - spec->master_sw = val; - alc262_hp_master_update(codec); - return 1; -} +#define alc262_hp_master_sw_put alc260_hp_master_sw_put #define ALC262_HP_MASTER_SWITCH \ { \ @@ -11251,7 +11488,7 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, } -static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { +static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { ALC262_HP_MASTER_SWITCH, HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -11275,7 +11512,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { +static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { ALC262_HP_MASTER_SWITCH, HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -11295,7 +11532,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { +static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT), @@ -11309,9 +11546,11 @@ static void alc262_hp_t5735_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } -static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { +static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -11322,7 +11561,7 @@ static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_hp_t5735_verbs[] = { +static const struct hda_verb alc262_hp_t5735_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -11330,7 +11569,7 @@ static struct hda_verb alc262_hp_t5735_verbs[] = { { } }; -static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { +static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT), @@ -11340,7 +11579,7 @@ static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_hp_rp5700_verbs[] = { +static const struct hda_verb alc262_hp_rp5700_verbs[] = { {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -11354,7 +11593,7 @@ static struct hda_verb alc262_hp_rp5700_verbs[] = { {} }; -static struct hda_input_mux alc262_hp_rp5700_capture_source = { +static const struct hda_input_mux alc262_hp_rp5700_capture_source = { .num_items = 1, .items = { { "Line", 0x1 }, @@ -11362,44 +11601,9 @@ static struct hda_input_mux alc262_hp_rp5700_capture_source = { }; /* bind hp and internal speaker mute (with plug check) as master switch */ -static void alc262_hippo_master_update(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; - hda_nid_t line_nid = spec->autocfg.line_out_pins[0]; - hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0]; - unsigned int mute; - - /* HP */ - mute = spec->master_sw ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - /* mute internal speaker per jack sense */ - if (spec->jack_present) - mute = HDA_AMP_MUTE; - if (line_nid) - snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - if (speaker_nid && speaker_nid != line_nid) - snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); -} - +#define alc262_hippo_master_update alc262_hp_master_update #define alc262_hippo_master_sw_get alc262_hp_master_sw_get - -static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int val = !!*ucontrol->value.integer.value; - - if (val == spec->master_sw) - return 0; - spec->master_sw = val; - alc262_hippo_master_update(codec); - return 1; -} +#define alc262_hippo_master_sw_put alc262_hp_master_sw_put #define ALC262_HIPPO_MASTER_SWITCH \ { \ @@ -11416,7 +11620,7 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, (SUBDEV_SPEAKER(0) << 16), \ } -static struct snd_kcontrol_new alc262_hippo_mixer[] = { +static const struct snd_kcontrol_new alc262_hippo_mixer[] = { ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -11433,7 +11637,7 @@ static struct snd_kcontrol_new alc262_hippo_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_hippo1_mixer[] = { +static const struct snd_kcontrol_new alc262_hippo1_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -11450,28 +11654,14 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hippo_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; - - spec->jack_present = snd_hda_jack_detect(codec, hp_nid); - alc262_hippo_master_update(codec); -} - -static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hippo_automute(codec); -} - static void alc262_hippo_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc262_hippo1_setup(struct hda_codec *codec) @@ -11480,10 +11670,12 @@ static void alc262_hippo1_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct snd_kcontrol_new alc262_sony_mixer[] = { +static const struct snd_kcontrol_new alc262_sony_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -11493,7 +11685,7 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_benq_t31_mixer[] = { +static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -11504,7 +11696,7 @@ static struct snd_kcontrol_new alc262_benq_t31_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_tyan_mixer[] = { +static const struct snd_kcontrol_new alc262_tyan_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT), @@ -11520,7 +11712,7 @@ static struct snd_kcontrol_new alc262_tyan_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_tyan_verbs[] = { +static const struct hda_verb alc262_tyan_verbs[] = { /* Headphone automute */ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -11542,6 +11734,8 @@ static void alc262_tyan_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } @@ -11551,7 +11745,7 @@ static void alc262_tyan_setup(struct hda_codec *codec) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc262_init_verbs[] = { +static const struct hda_verb alc262_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -11627,13 +11821,13 @@ static struct hda_verb alc262_init_verbs[] = { { } }; -static struct hda_verb alc262_eapd_verbs[] = { +static const struct hda_verb alc262_eapd_verbs[] = { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -static struct hda_verb alc262_hippo1_unsol_verbs[] = { +static const struct hda_verb alc262_hippo1_unsol_verbs[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, @@ -11643,7 +11837,7 @@ static struct hda_verb alc262_hippo1_unsol_verbs[] = { {} }; -static struct hda_verb alc262_sony_unsol_verbs[] = { +static const struct hda_verb alc262_sony_unsol_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic @@ -11653,7 +11847,7 @@ static struct hda_verb alc262_sony_unsol_verbs[] = { {} }; -static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { +static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -11662,7 +11856,7 @@ static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_toshiba_s06_verbs[] = { +static const struct hda_verb alc262_toshiba_s06_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -11685,6 +11879,8 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec) spec->int_mic.pin = 0x12; spec->int_mic.mux_idx = 9; spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } /* @@ -11694,7 +11890,7 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec) * 0x18 = external mic */ -static struct snd_kcontrol_new alc262_nec_mixer[] = { +static const struct snd_kcontrol_new alc262_nec_mixer[] = { HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT), @@ -11707,7 +11903,7 @@ static struct snd_kcontrol_new alc262_nec_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_nec_verbs[] = { +static const struct hda_verb alc262_nec_verbs[] = { /* Unmute Speaker */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -11730,7 +11926,7 @@ static struct hda_verb alc262_nec_verbs[] = { #define ALC_HP_EVENT 0x37 -static struct hda_verb alc262_fujitsu_unsol_verbs[] = { +static const struct hda_verb alc262_fujitsu_unsol_verbs[] = { {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, @@ -11738,20 +11934,20 @@ static struct hda_verb alc262_fujitsu_unsol_verbs[] = { {} }; -static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = { +static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = { {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {} }; -static struct hda_verb alc262_lenovo_3000_init_verbs[] = { +static const struct hda_verb alc262_lenovo_3000_init_verbs[] = { /* Front Mic pin: input vref at 50% */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {} }; -static struct hda_input_mux alc262_fujitsu_capture_source = { +static const struct hda_input_mux alc262_fujitsu_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -11760,7 +11956,7 @@ static struct hda_input_mux alc262_fujitsu_capture_source = { }, }; -static struct hda_input_mux alc262_HP_capture_source = { +static const struct hda_input_mux alc262_HP_capture_source = { .num_items = 5, .items = { { "Mic", 0x0 }, @@ -11771,7 +11967,7 @@ static struct hda_input_mux alc262_HP_capture_source = { }, }; -static struct hda_input_mux alc262_HP_D7000_capture_source = { +static const struct hda_input_mux alc262_HP_D7000_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -11781,44 +11977,19 @@ static struct hda_input_mux alc262_HP_D7000_capture_source = { }, }; -/* mute/unmute internal speaker according to the hp jacks and mute state */ -static void alc262_fujitsu_automute(struct hda_codec *codec, int force) +static void alc262_fujitsu_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int mute; - if (force || !spec->sense_updated) { - spec->jack_present = snd_hda_jack_detect(codec, 0x14) || - snd_hda_jack_detect(codec, 0x1b); - spec->sense_updated = 1; - } - /* unmute internal speaker only if both HPs are unplugged and - * master switch is on - */ - if (spec->jack_present) - mute = HDA_AMP_MUTE; - else - mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); -} - -/* unsolicited event for HP jack sensing */ -static void alc262_fujitsu_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC_HP_EVENT) - return; - alc262_fujitsu_automute(codec, 1); -} - -static void alc262_fujitsu_init_hook(struct hda_codec *codec) -{ - alc262_fujitsu_automute(codec, 1); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.hp_pins[1] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* bind volumes of both NID 0x0c and 0x0d */ -static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { +static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), @@ -11827,78 +11998,15 @@ static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { }, }; -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force) -{ - struct alc_spec *spec = codec->spec; - unsigned int mute; - - if (force || !spec->sense_updated) { - spec->jack_present = snd_hda_jack_detect(codec, 0x1b); - spec->sense_updated = 1; - } - if (spec->jack_present) { - /* mute internal speaker */ - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - } else { - /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - } -} - -/* unsolicited event for HP jack sensing */ -static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC_HP_EVENT) - return; - alc262_lenovo_3000_automute(codec, 1); -} - -static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid, - int dir, int idx, long *valp) -{ - int i, change = 0; - - for (i = 0; i < 2; i++, valp++) - change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx, - HDA_AMP_MUTE, - *valp ? 0 : HDA_AMP_MUTE); - return change; -} - -/* bind hp and internal speaker mute (with plug check) */ -static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp); - change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp); - if (change) - alc262_fujitsu_automute(codec, 0); - return change; -} - -static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { +static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc262_fujitsu_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, }, { .iface = NID_MAPPING, @@ -11916,30 +12024,26 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { { } /* end */ }; -/* bind hp and internal speaker mute (with plug check) */ -static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc262_lenovo_3000_setup(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; + struct alc_spec *spec = codec->spec; - change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp); - if (change) - alc262_lenovo_3000_automute(codec, 0); - return change; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { +static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc262_lenovo_3000_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, }, HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), @@ -11952,7 +12056,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { +static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -11965,13 +12069,13 @@ static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { }; /* additional init verbs for Benq laptops */ -static struct hda_verb alc262_EAPD_verbs[] = { +static const struct hda_verb alc262_EAPD_verbs[] = { {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, {} }; -static struct hda_verb alc262_benq_t31_EAPD_verbs[] = { +static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, @@ -11981,7 +12085,7 @@ static struct hda_verb alc262_benq_t31_EAPD_verbs[] = { }; /* Samsung Q1 Ultra Vista model setup */ -static struct snd_kcontrol_new alc262_ultra_mixer[] = { +static const struct snd_kcontrol_new alc262_ultra_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), @@ -11991,7 +12095,7 @@ static struct snd_kcontrol_new alc262_ultra_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_ultra_verbs[] = { +static const struct hda_verb alc262_ultra_verbs[] = { /* output mixer */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, @@ -12054,7 +12158,7 @@ static void alc262_ultra_unsol_event(struct hda_codec *codec, alc262_ultra_automute(codec); } -static struct hda_input_mux alc262_ultra_capture_source = { +static const struct hda_input_mux alc262_ultra_capture_source = { .num_items = 2, .items = { { "Mic", 0x1 }, @@ -12080,7 +12184,7 @@ static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol, return ret; } -static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { +static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), { @@ -12155,9 +12259,9 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, spec->multiout.num_dacs = 1; /* only use one dac */ spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.dac_nids[0] = 2; + spec->private_dac_nids[0] = 2; - pfx = alc_get_line_out_pfx(cfg, true); + pfx = alc_get_line_out_pfx(spec, true); if (!pfx) pfx = "Front"; for (i = 0; i < 2; i++) { @@ -12211,7 +12315,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc262_volume_init_verbs[] = { +static const struct hda_verb alc262_volume_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -12272,7 +12376,7 @@ static struct hda_verb alc262_volume_init_verbs[] = { { } }; -static struct hda_verb alc262_HP_BPC_init_verbs[] = { +static const struct hda_verb alc262_HP_BPC_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -12376,7 +12480,7 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { { } }; -static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { +static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -12472,7 +12576,7 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { { } }; -static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { +static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -12508,7 +12612,7 @@ static const struct alc_fixup alc262_fixups[] = { }, }; -static struct snd_pci_quirk alc262_fixup_tbl[] = { +static const struct snd_pci_quirk alc262_fixup_tbl[] = { SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270), {} }; @@ -12531,7 +12635,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc262_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc262_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc262_ignore); @@ -12616,7 +12720,7 @@ static const char * const alc262_models[ALC262_MODEL_LAST] = { [ALC262_AUTO] = "auto", }; -static struct snd_pci_quirk alc262_cfg_tbl[] = { +static const struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC), SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series", @@ -12668,7 +12772,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { {} }; -static struct alc_config_preset alc262_presets[] = { +static const struct alc_config_preset alc262_presets[] = { [ALC262_BASIC] = { .mixers = { alc262_base_mixer }, .init_verbs = { alc262_init_verbs }, @@ -12689,9 +12793,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc_inithook, }, [ALC262_HIPPO_1] = { .mixers = { alc262_hippo1_mixer }, @@ -12703,9 +12807,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_hippo1_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc_inithook, }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, @@ -12718,8 +12822,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_fujitsu_capture_source, - .unsol_event = alc262_fujitsu_unsol_event, - .init_hook = alc262_fujitsu_init_hook, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_fujitsu_setup, + .init_hook = alc_inithook, }, [ALC262_HP_BPC] = { .mixers = { alc262_HP_BPC_mixer }, @@ -12730,8 +12835,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_HP_capture_source, - .unsol_event = alc262_hp_bpc_unsol_event, - .init_hook = alc262_hp_bpc_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_bpc_setup, + .init_hook = alc_inithook, }, [ALC262_HP_BPC_D7000_WF] = { .mixers = { alc262_HP_BPC_WildWest_mixer }, @@ -12742,8 +12848,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_HP_D7000_capture_source, - .unsol_event = alc262_hp_wildwest_unsol_event, - .init_hook = alc262_hp_wildwest_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_wildwest_setup, + .init_hook = alc_inithook, }, [ALC262_HP_BPC_D7000_WL] = { .mixers = { alc262_HP_BPC_WildWest_mixer, @@ -12755,8 +12862,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_HP_D7000_capture_source, - .unsol_event = alc262_hp_wildwest_unsol_event, - .init_hook = alc262_hp_wildwest_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_wildwest_setup, + .init_hook = alc_inithook, }, [ALC262_HP_TC_T5735] = { .mixers = { alc262_hp_t5735_mixer }, @@ -12799,9 +12907,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc_inithook, }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, @@ -12813,9 +12921,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc_inithook, }, [ALC262_ULTRA] = { .mixers = { alc262_ultra_mixer }, @@ -12844,7 +12952,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_fujitsu_capture_source, - .unsol_event = alc262_lenovo_3000_unsol_event, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_lenovo_3000_setup, + .init_hook = alc_inithook, }, [ALC262_NEC] = { .mixers = { alc262_nec_mixer }, @@ -12881,9 +12991,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc_inithook, }, [ALC262_TYAN] = { .mixers = { alc262_tyan_mixer }, @@ -12895,9 +13005,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_tyan_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, }; @@ -13018,6 +13128,7 @@ static int patch_alc262(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC262_AUTO) spec->init_hook = alc262_auto_init; + spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -13034,24 +13145,24 @@ static int patch_alc262(struct hda_codec *codec) #define ALC268_DIGOUT_NID ALC880_DIGOUT_NID #define alc268_modes alc260_modes -static hda_nid_t alc268_dac_nids[2] = { +static const hda_nid_t alc268_dac_nids[2] = { /* front, hp */ 0x02, 0x03 }; -static hda_nid_t alc268_adc_nids[2] = { +static const hda_nid_t alc268_adc_nids[2] = { /* ADC0-1 */ 0x08, 0x07 }; -static hda_nid_t alc268_adc_nids_alt[1] = { +static const hda_nid_t alc268_adc_nids_alt[1] = { /* ADC0 */ 0x08 }; -static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 }; +static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 }; -static struct snd_kcontrol_new alc268_base_mixer[] = { +static const struct snd_kcontrol_new alc268_base_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -13063,7 +13174,7 @@ static struct snd_kcontrol_new alc268_base_mixer[] = { { } }; -static struct snd_kcontrol_new alc268_toshiba_mixer[] = { +static const struct snd_kcontrol_new alc268_toshiba_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), @@ -13075,7 +13186,7 @@ static struct snd_kcontrol_new alc268_toshiba_mixer[] = { }; /* bind Beep switches of both NID 0x0f and 0x10 */ -static struct hda_bind_ctls alc268_bind_beep_sw = { +static const struct hda_bind_ctls alc268_bind_beep_sw = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT), @@ -13084,27 +13195,27 @@ static struct hda_bind_ctls alc268_bind_beep_sw = { }, }; -static struct snd_kcontrol_new alc268_beep_mixer[] = { +static const struct snd_kcontrol_new alc268_beep_mixer[] = { HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT), HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw), { } }; -static struct hda_verb alc268_eapd_verbs[] = { +static const struct hda_verb alc268_eapd_verbs[] = { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; /* Toshiba specific */ -static struct hda_verb alc268_toshiba_verbs[] = { +static const struct hda_verb alc268_toshiba_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, { } /* end */ }; /* Acer specific */ /* bind volumes of both NID 0x02 and 0x03 */ -static struct hda_bind_ctls alc268_acer_bind_master_vol = { +static const struct hda_bind_ctls alc268_acer_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), @@ -13113,66 +13224,44 @@ static struct hda_bind_ctls alc268_acer_bind_master_vol = { }, }; -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc268_acer_automute(struct hda_codec *codec, int force) +static void alc268_acer_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int mute; - if (force || !spec->sense_updated) { - spec->jack_present = snd_hda_jack_detect(codec, 0x14); - spec->sense_updated = 1; - } - if (spec->jack_present) - mute = HDA_AMP_MUTE; /* mute internal speaker */ - else /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } +#define alc268_acer_master_sw_get alc262_hp_master_sw_get +#define alc268_acer_master_sw_put alc262_hp_master_sw_put -/* bind hp and internal speaker mute (with plug check) */ -static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp); - if (change) - alc268_acer_automute(codec, 0); - return change; -} - -static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { +static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { /* output mixer control */ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, + .subdevice = HDA_SUBDEV_NID_FLAG | 0x15, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }, HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT), { } }; -static struct snd_kcontrol_new alc268_acer_mixer[] = { +static const struct snd_kcontrol_new alc268_acer_mixer[] = { /* output mixer control */ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }, HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), @@ -13180,24 +13269,23 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { { } }; -static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { +static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { /* output mixer control */ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }, HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), { } }; -static struct hda_verb alc268_acer_aspire_one_verbs[] = { +static const struct hda_verb alc268_acer_aspire_one_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, @@ -13207,7 +13295,7 @@ static struct hda_verb alc268_acer_aspire_one_verbs[] = { { } }; -static struct hda_verb alc268_acer_verbs[] = { +static const struct hda_verb alc268_acer_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -13219,53 +13307,16 @@ static struct hda_verb alc268_acer_verbs[] = { }; /* unsolicited event for HP jack sensing */ -#define alc268_toshiba_unsol_event alc262_hippo_unsol_event #define alc268_toshiba_setup alc262_hippo_setup -#define alc268_toshiba_automute alc262_hippo_automute - -static void alc268_acer_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc268_acer_automute(codec, 1); -} - -static void alc268_acer_init_hook(struct hda_codec *codec) -{ - alc268_acer_automute(codec, 1); -} - -/* toggle speaker-output according to the hp-jack state */ -static void alc268_aspire_one_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x15); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); -} - -static void alc268_acer_lc_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc268_aspire_one_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} static void alc268_acer_lc_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0f; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; @@ -13273,13 +13324,7 @@ static void alc268_acer_lc_setup(struct hda_codec *codec) spec->auto_mic = 1; } -static void alc268_acer_lc_init_hook(struct hda_codec *codec) -{ - alc268_aspire_one_speaker_automute(codec); - alc_mic_automute(codec); -} - -static struct snd_kcontrol_new alc268_dell_mixer[] = { +static const struct snd_kcontrol_new alc268_dell_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -13290,7 +13335,7 @@ static struct snd_kcontrol_new alc268_dell_mixer[] = { { } }; -static struct hda_verb alc268_dell_verbs[] = { +static const struct hda_verb alc268_dell_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, @@ -13310,9 +13355,11 @@ static void alc268_dell_setup(struct hda_codec *codec) spec->int_mic.pin = 0x19; spec->int_mic.mux_idx = 1; spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } -static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { +static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), @@ -13324,7 +13371,7 @@ static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { { } }; -static struct hda_verb alc267_quanta_il1_verbs[] = { +static const struct hda_verb alc267_quanta_il1_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, { } @@ -13340,12 +13387,14 @@ static void alc267_quanta_il1_setup(struct hda_codec *codec) spec->int_mic.pin = 0x19; spec->int_mic.mux_idx = 1; spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc268_base_init_verbs[] = { +static const struct hda_verb alc268_base_init_verbs[] = { /* Unmute DAC0-1 and set vol = 0 */ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, @@ -13393,7 +13442,7 @@ static struct hda_verb alc268_base_init_verbs[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc268_volume_init_verbs[] = { +static const struct hda_verb alc268_volume_init_verbs[] = { /* set output DAC */ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, @@ -13419,20 +13468,20 @@ static struct hda_verb alc268_volume_init_verbs[] = { { } }; -static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = { +static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), { } /* end */ }; -static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { +static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), _DEFINE_CAPSRC(1), { } /* end */ }; -static struct snd_kcontrol_new alc268_capture_mixer[] = { +static const struct snd_kcontrol_new alc268_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT), @@ -13441,7 +13490,7 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = { { } /* end */ }; -static struct hda_input_mux alc268_capture_source = { +static const struct hda_input_mux alc268_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -13451,7 +13500,7 @@ static struct hda_input_mux alc268_capture_source = { }, }; -static struct hda_input_mux alc268_acer_capture_source = { +static const struct hda_input_mux alc268_acer_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -13460,7 +13509,7 @@ static struct hda_input_mux alc268_acer_capture_source = { }, }; -static struct hda_input_mux alc268_acer_dmic_capture_source = { +static const struct hda_input_mux alc268_acer_dmic_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -13470,7 +13519,7 @@ static struct hda_input_mux alc268_acer_dmic_capture_source = { }; #ifdef CONFIG_SND_DEBUG -static struct snd_kcontrol_new alc268_test_mixer[] = { +static const struct snd_kcontrol_new alc268_test_mixer[] = { /* Volume widgets */ HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -13549,7 +13598,7 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, HDA_OUTPUT)); if (err < 0) return err; - spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } if (nid != 0x16) @@ -13722,7 +13771,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc268_ignore[] = { 0 }; + static const hda_nid_t alc268_ignore[] = { 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc268_ignore); @@ -13802,7 +13851,7 @@ static const char * const alc268_models[ALC268_MODEL_LAST] = { [ALC268_AUTO] = "auto", }; -static struct snd_pci_quirk alc268_cfg_tbl[] = { +static const struct snd_pci_quirk alc268_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER), SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER), @@ -13827,7 +13876,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { }; /* Toshiba laptops have no unique PCI SSID but only codec SSID */ -static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { +static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO), SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO), SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05", @@ -13835,7 +13884,7 @@ static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { {} }; -static struct alc_config_preset alc268_presets[] = { +static const struct alc_config_preset alc268_presets[] = { [ALC267_QUANTA_IL1] = { .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer, alc268_capture_nosrc_mixer }, @@ -13881,9 +13930,9 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, - .unsol_event = alc268_toshiba_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc268_toshiba_setup, - .init_hook = alc268_toshiba_automute, + .init_hook = alc_inithook, }, [ALC268_ACER] = { .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, @@ -13899,8 +13948,9 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_acer_capture_source, - .unsol_event = alc268_acer_unsol_event, - .init_hook = alc268_acer_init_hook, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_setup, + .init_hook = alc_inithook, }, [ALC268_ACER_DMIC] = { .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, @@ -13916,8 +13966,9 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_acer_dmic_capture_source, - .unsol_event = alc268_acer_unsol_event, - .init_hook = alc268_acer_init_hook, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_setup, + .init_hook = alc_inithook, }, [ALC268_ACER_ASPIRE_ONE] = { .mixers = { alc268_acer_aspire_one_mixer, @@ -13933,9 +13984,9 @@ static struct alc_config_preset alc268_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, - .unsol_event = alc268_acer_lc_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc268_acer_lc_setup, - .init_hook = alc268_acer_lc_init_hook, + .init_hook = alc_inithook, }, [ALC268_DELL] = { .mixers = { alc268_dell_mixer, alc268_beep_mixer, @@ -13969,8 +14020,9 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, + .unsol_event = alc_sku_unsol_event, .setup = alc268_toshiba_setup, - .init_hook = alc268_toshiba_automute, + .init_hook = alc_inithook, }, #ifdef CONFIG_SND_DEBUG [ALC268_TEST] = { @@ -14092,6 +14144,7 @@ static int patch_alc268(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC268_AUTO) spec->init_hook = alc268_auto_init; + spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); @@ -14105,32 +14158,32 @@ static int patch_alc268(struct hda_codec *codec) #define alc269_dac_nids alc260_dac_nids -static hda_nid_t alc269_adc_nids[1] = { +static const hda_nid_t alc269_adc_nids[1] = { /* ADC1 */ 0x08, }; -static hda_nid_t alc269_capsrc_nids[1] = { +static const hda_nid_t alc269_capsrc_nids[1] = { 0x23, }; -static hda_nid_t alc269vb_adc_nids[1] = { +static const hda_nid_t alc269vb_adc_nids[1] = { /* ADC1 */ 0x09, }; -static hda_nid_t alc269vb_capsrc_nids[1] = { +static const hda_nid_t alc269vb_capsrc_nids[1] = { 0x22, }; -static hda_nid_t alc269_adc_candidates[] = { +static const hda_nid_t alc269_adc_candidates[] = { 0x08, 0x09, 0x07, 0x11, }; #define alc269_modes alc260_modes #define alc269_capture_source alc880_lg_lw_capture_source -static struct snd_kcontrol_new alc269_base_mixer[] = { +static const struct snd_kcontrol_new alc269_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -14146,7 +14199,7 @@ static struct snd_kcontrol_new alc269_base_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { +static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { /* output mixer control */ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), { @@ -14167,7 +14220,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { { } }; -static struct snd_kcontrol_new alc269_lifebook_mixer[] = { +static const struct snd_kcontrol_new alc269_lifebook_mixer[] = { /* output mixer control */ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), { @@ -14191,7 +14244,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { { } }; -static struct snd_kcontrol_new alc269_laptop_mixer[] = { +static const struct snd_kcontrol_new alc269_laptop_mixer[] = { HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -14199,7 +14252,7 @@ static struct snd_kcontrol_new alc269_laptop_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc269vb_laptop_mixer[] = { +static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = { HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), @@ -14207,14 +14260,14 @@ static struct snd_kcontrol_new alc269vb_laptop_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc269_asus_mixer[] = { +static const struct snd_kcontrol_new alc269_asus_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT), { } /* end */ }; /* capture mixer elements */ -static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { +static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), @@ -14222,14 +14275,14 @@ static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { +static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), { } /* end */ }; -static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { +static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), @@ -14237,7 +14290,7 @@ static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { +static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), @@ -14247,7 +14300,7 @@ static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { /* FSC amilo */ #define alc269_fujitsu_mixer alc269_laptop_mixer -static struct hda_verb alc269_quanta_fl1_verbs[] = { +static const struct hda_verb alc269_quanta_fl1_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -14257,7 +14310,7 @@ static struct hda_verb alc269_quanta_fl1_verbs[] = { { } }; -static struct hda_verb alc269_lifebook_verbs[] = { +static const struct hda_verb alc269_lifebook_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -14274,15 +14327,7 @@ static struct hda_verb alc269_lifebook_verbs[] = { /* toggle speaker-output according to the hp-jack state */ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x15); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); + alc_hp_automute(codec); snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x0c); @@ -14295,34 +14340,8 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x480); } -/* toggle speaker-output according to the hp-jacks state */ -static void alc269_lifebook_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - /* Check laptop headphone socket */ - present = snd_hda_jack_detect(codec, 0x15); - - /* Check port replicator headphone socket */ - present |= snd_hda_jack_detect(codec, 0x1a); - - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x680); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x480); -} +#define alc269_lifebook_speaker_automute \ + alc269_quanta_fl1_speaker_automute static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) { @@ -14371,6 +14390,9 @@ static void alc269_quanta_fl1_setup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; @@ -14384,13 +14406,24 @@ static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) alc_mic_automute(codec); } +static void alc269_lifebook_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.hp_pins[1] = 0x1a; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; +} + static void alc269_lifebook_init_hook(struct hda_codec *codec) { alc269_lifebook_speaker_automute(codec); alc269_lifebook_mic_autoswitch(codec); } -static struct hda_verb alc269_laptop_dmic_init_verbs[] = { +static const struct hda_verb alc269_laptop_dmic_init_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, @@ -14401,7 +14434,7 @@ static struct hda_verb alc269_laptop_dmic_init_verbs[] = { {} }; -static struct hda_verb alc269_laptop_amic_init_verbs[] = { +static const struct hda_verb alc269_laptop_amic_init_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, @@ -14411,7 +14444,7 @@ static struct hda_verb alc269_laptop_amic_init_verbs[] = { {} }; -static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { +static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x22, AC_VERB_SET_CONNECT_SEL, 0x06}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, @@ -14422,7 +14455,7 @@ static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { {} }; -static struct hda_verb alc269vb_laptop_amic_init_verbs[] = { +static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = { {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, @@ -14433,7 +14466,7 @@ static struct hda_verb alc269vb_laptop_amic_init_verbs[] = { {} }; -static struct hda_verb alc271_acer_dmic_verbs[] = { +static const struct hda_verb alc271_acer_dmic_verbs[] = { {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -14447,42 +14480,14 @@ static struct hda_verb alc271_acer_dmic_verbs[] = { { } }; -/* toggle speaker-output according to the hp-jack state */ -static void alc269_speaker_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - unsigned int nid = spec->autocfg.hp_pins[0]; - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, nid); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); - snd_hda_input_jack_report(codec, nid); -} - -/* unsolicited event for HP jack sensing */ -static void alc269_laptop_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc269_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - static void alc269_laptop_amic_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; @@ -14495,6 +14500,9 @@ static void alc269_laptop_dmic_setup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; @@ -14507,6 +14515,9 @@ static void alc269vb_laptop_amic_setup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x21; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; @@ -14519,6 +14530,9 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x21; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; @@ -14526,16 +14540,10 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) spec->auto_mic = 1; } -static void alc269_laptop_inithook(struct hda_codec *codec) -{ - alc269_speaker_automute(codec); - alc_mic_automute(codec); -} - /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc269_init_verbs[] = { +static const struct hda_verb alc269_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -14578,7 +14586,7 @@ static struct hda_verb alc269_init_verbs[] = { { } }; -static struct hda_verb alc269vb_init_verbs[] = { +static const struct hda_verb alc269vb_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -14636,7 +14644,7 @@ static struct hda_verb alc269vb_init_verbs[] = { #define alc269_pcm_digital_playback alc880_pcm_digital_playback #define alc269_pcm_digital_capture alc880_pcm_digital_capture -static struct hda_pcm_stream alc269_44k_pcm_analog_playback = { +static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -14649,7 +14657,7 @@ static struct hda_pcm_stream alc269_44k_pcm_analog_playback = { }, }; -static struct hda_pcm_stream alc269_44k_pcm_analog_capture = { +static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -14733,7 +14741,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc269_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc269_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc269_ignore); @@ -14803,7 +14811,6 @@ static void alc269_auto_init(struct hda_codec *codec) alc_inithook(codec); } -#ifdef SND_HDA_NEEDS_RESUME static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) { int val = alc_read_coef_idx(codec, 0x04); @@ -14814,25 +14821,17 @@ static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) alc_write_coef_idx(codec, 0x04, val); } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static int alc269_suspend(struct hda_codec *codec, pm_message_t state) +static void alc269_shutup(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) alc269_toggle_power_output(codec, 0); if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { alc269_toggle_power_output(codec, 0); msleep(150); } - - alc_shutup(codec); - if (spec && spec->power_hook) - spec->power_hook(codec); - return 0; } -#endif /* CONFIG_SND_HDA_POWER_SAVE */ +#ifdef SND_HDA_NEEDS_RESUME static int alc269_resume(struct hda_codec *codec) { if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { @@ -14868,6 +14867,23 @@ static void alc269_fixup_hweq(struct hda_codec *codec, alc_write_coef_idx(codec, 0x1e, coef | 0x80); } +static void alc271_fixup_dmic(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + static const struct hda_verb verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, + {} + }; + unsigned int cfg; + + if (strcmp(codec->chip_name, "ALC271X")) + return; + cfg = snd_hda_codec_get_pincfg(codec, 0x12); + if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED) + snd_hda_sequence_write(codec, verbs); +} + enum { ALC269_FIXUP_SONY_VAIO, ALC275_FIXUP_SONY_VAIO_GPIO2, @@ -14876,6 +14892,7 @@ enum { ALC269_FIXUP_ASUS_G73JW, ALC269_FIXUP_LENOVO_EAPD, ALC275_FIXUP_SONY_HWEQ, + ALC271_FIXUP_DMIC, }; static const struct alc_fixup alc269_fixups[] = { @@ -14929,15 +14946,20 @@ static const struct alc_fixup alc269_fixups[] = { .v.func = alc269_fixup_hweq, .chained = true, .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 - } + }, + [ALC271_FIXUP_DMIC] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc271_fixup_dmic, + }, }; -static struct snd_pci_quirk alc269_fixup_tbl[] = { +static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), @@ -14962,7 +14984,7 @@ static const char * const alc269_models[ALC269_MODEL_LAST] = { [ALC269_AUTO] = "auto", }; -static struct snd_pci_quirk alc269_cfg_tbl[] = { +static const struct snd_pci_quirk alc269_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER), SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", @@ -15020,7 +15042,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = { {} }; -static struct alc_config_preset alc269_presets[] = { +static const struct alc_config_preset alc269_presets[] = { [ALC269_BASIC] = { .mixers = { alc269_base_mixer }, .init_verbs = { alc269_init_verbs }, @@ -15054,9 +15076,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_laptop_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc269_laptop_amic_setup, - .init_hook = alc269_laptop_inithook, + .init_hook = alc_inithook, }, [ALC269_DMIC] = { .mixers = { alc269_laptop_mixer }, @@ -15068,9 +15090,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_laptop_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc269_laptop_dmic_setup, - .init_hook = alc269_laptop_inithook, + .init_hook = alc_inithook, }, [ALC269VB_AMIC] = { .mixers = { alc269vb_laptop_mixer }, @@ -15082,9 +15104,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_laptop_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc269vb_laptop_amic_setup, - .init_hook = alc269_laptop_inithook, + .init_hook = alc_inithook, }, [ALC269VB_DMIC] = { .mixers = { alc269vb_laptop_mixer }, @@ -15096,9 +15118,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_laptop_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc269vb_laptop_dmic_setup, - .init_hook = alc269_laptop_inithook, + .init_hook = alc_inithook, }, [ALC269_FUJITSU] = { .mixers = { alc269_fujitsu_mixer }, @@ -15110,9 +15132,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_laptop_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc269_laptop_dmic_setup, - .init_hook = alc269_laptop_inithook, + .init_hook = alc_inithook, }, [ALC269_LIFEBOOK] = { .mixers = { alc269_lifebook_mixer }, @@ -15124,6 +15146,7 @@ static struct alc_config_preset alc269_presets[] = { .channel_mode = alc269_modes, .input_mux = &alc269_capture_source, .unsol_event = alc269_lifebook_unsol_event, + .setup = alc269_lifebook_setup, .init_hook = alc269_lifebook_init_hook, }, [ALC271_ACER] = { @@ -15169,14 +15192,21 @@ static int alc269_fill_coef(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0xd); if ((val & 0x0c00) >> 10 != 0x1) { /* Capless ramp up clock control */ - alc_write_coef_idx(codec, 0xd, val | 1<<10); + alc_write_coef_idx(codec, 0xd, val | (1<<10)); } val = alc_read_coef_idx(codec, 0x17); if ((val & 0x01c0) >> 6 != 0x4) { /* Class D power on reset */ - alc_write_coef_idx(codec, 0x17, val | 1<<7); + alc_write_coef_idx(codec, 0x17, val | (1<<7)); } } + + val = alc_read_coef_idx(codec, 0xd); /* Class D */ + alc_write_coef_idx(codec, 0xd, val | (1<<14)); + + val = alc_read_coef_idx(codec, 0x4); /* HP */ + alc_write_coef_idx(codec, 0x4, val | (1<<11)); + return 0; } @@ -15297,14 +15327,12 @@ static int patch_alc269(struct hda_codec *codec) spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; -#ifdef CONFIG_SND_HDA_POWER_SAVE - codec->patch_ops.suspend = alc269_suspend; -#endif #ifdef SND_HDA_NEEDS_RESUME codec->patch_ops.resume = alc269_resume; #endif if (board_config == ALC269_AUTO) spec->init_hook = alc269_auto_init; + spec->shutup = alc269_shutup; alc_init_jacks(codec); #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -15325,7 +15353,7 @@ static int patch_alc269(struct hda_codec *codec) * set the path ways for 2 channel output * need to set the codec line out and mic 1 pin widgets to inputs */ -static struct hda_verb alc861_threestack_ch2_init[] = { +static const struct hda_verb alc861_threestack_ch2_init[] = { /* set pin widget 1Ah (line in) for input */ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, /* set pin widget 18h (mic1/2) for input, for mic also enable @@ -15344,7 +15372,7 @@ static struct hda_verb alc861_threestack_ch2_init[] = { * 6ch mode * need to set the codec line out and mic 1 pin widgets to outputs */ -static struct hda_verb alc861_threestack_ch6_init[] = { +static const struct hda_verb alc861_threestack_ch6_init[] = { /* set pin widget 1Ah (line in) for output (Back Surround)*/ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, /* set pin widget 18h (mic1) for output (CLFE)*/ @@ -15361,30 +15389,30 @@ static struct hda_verb alc861_threestack_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc861_threestack_modes[2] = { +static const struct hda_channel_mode alc861_threestack_modes[2] = { { 2, alc861_threestack_ch2_init }, { 6, alc861_threestack_ch6_init }, }; /* Set mic1 as input and unmute the mixer */ -static struct hda_verb alc861_uniwill_m31_ch2_init[] = { +static const struct hda_verb alc861_uniwill_m31_ch2_init[] = { { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ { } /* end */ }; /* Set mic1 as output and mute mixer */ -static struct hda_verb alc861_uniwill_m31_ch4_init[] = { +static const struct hda_verb alc861_uniwill_m31_ch4_init[] = { { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ { } /* end */ }; -static struct hda_channel_mode alc861_uniwill_m31_modes[2] = { +static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = { { 2, alc861_uniwill_m31_ch2_init }, { 4, alc861_uniwill_m31_ch4_init }, }; /* Set mic1 and line-in as input and unmute the mixer */ -static struct hda_verb alc861_asus_ch2_init[] = { +static const struct hda_verb alc861_asus_ch2_init[] = { /* set pin widget 1Ah (line in) for input */ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, /* set pin widget 18h (mic1/2) for input, for mic also enable @@ -15400,7 +15428,7 @@ static struct hda_verb alc861_asus_ch2_init[] = { { } /* end */ }; /* Set mic1 nad line-in as output and mute mixer */ -static struct hda_verb alc861_asus_ch6_init[] = { +static const struct hda_verb alc861_asus_ch6_init[] = { /* set pin widget 1Ah (line in) for output (Back Surround)*/ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ @@ -15418,14 +15446,14 @@ static struct hda_verb alc861_asus_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc861_asus_modes[2] = { +static const struct hda_channel_mode alc861_asus_modes[2] = { { 2, alc861_asus_ch2_init }, { 6, alc861_asus_ch6_init }, }; /* patch-ALC861 */ -static struct snd_kcontrol_new alc861_base_mixer[] = { +static const struct snd_kcontrol_new alc861_base_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), @@ -15448,7 +15476,7 @@ static struct snd_kcontrol_new alc861_base_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861_3ST_mixer[] = { +static const struct snd_kcontrol_new alc861_3ST_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), @@ -15479,7 +15507,7 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861_toshiba_mixer[] = { +static const struct snd_kcontrol_new alc861_toshiba_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), @@ -15488,7 +15516,7 @@ static struct snd_kcontrol_new alc861_toshiba_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { +static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), @@ -15519,7 +15547,7 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861_asus_mixer[] = { +static const struct snd_kcontrol_new alc861_asus_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), @@ -15551,7 +15579,7 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = { }; /* additional mixer */ -static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { +static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), { } @@ -15560,7 +15588,7 @@ static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc861_base_init_verbs[] = { +static const struct hda_verb alc861_base_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -15626,7 +15654,7 @@ static struct hda_verb alc861_base_init_verbs[] = { { } }; -static struct hda_verb alc861_threestack_init_verbs[] = { +static const struct hda_verb alc861_threestack_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -15687,7 +15715,7 @@ static struct hda_verb alc861_threestack_init_verbs[] = { { } }; -static struct hda_verb alc861_uniwill_m31_init_verbs[] = { +static const struct hda_verb alc861_uniwill_m31_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -15749,7 +15777,7 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = { { } }; -static struct hda_verb alc861_asus_init_verbs[] = { +static const struct hda_verb alc861_asus_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -15815,7 +15843,7 @@ static struct hda_verb alc861_asus_init_verbs[] = { }; /* additional init verbs for ASUS laptops */ -static struct hda_verb alc861_asus_laptop_init_verbs[] = { +static const struct hda_verb alc861_asus_laptop_init_verbs[] = { { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */ { } @@ -15824,7 +15852,7 @@ static struct hda_verb alc861_asus_laptop_init_verbs[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc861_auto_init_verbs[] = { +static const struct hda_verb alc861_auto_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -15873,7 +15901,7 @@ static struct hda_verb alc861_auto_init_verbs[] = { { } }; -static struct hda_verb alc861_toshiba_init_verbs[] = { +static const struct hda_verb alc861_toshiba_init_verbs[] = { {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, { } @@ -15906,26 +15934,26 @@ static void alc861_toshiba_unsol_event(struct hda_codec *codec, #define ALC861_DIGOUT_NID 0x07 -static struct hda_channel_mode alc861_8ch_modes[1] = { +static const struct hda_channel_mode alc861_8ch_modes[1] = { { 8, NULL } }; -static hda_nid_t alc861_dac_nids[4] = { +static const hda_nid_t alc861_dac_nids[4] = { /* front, surround, clfe, side */ 0x03, 0x06, 0x05, 0x04 }; -static hda_nid_t alc660_dac_nids[3] = { +static const hda_nid_t alc660_dac_nids[3] = { /* front, clfe, surround */ 0x03, 0x05, 0x06 }; -static hda_nid_t alc861_adc_nids[1] = { +static const hda_nid_t alc861_adc_nids[1] = { /* ADC0-2 */ 0x08, }; -static struct hda_input_mux alc861_capture_source = { +static const struct hda_input_mux alc861_capture_source = { .num_items = 5, .items = { { "Mic", 0x0 }, @@ -15975,7 +16003,7 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec, dac = alc861_look_for_dac(codec, nid); if (!dac) continue; - spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } return 0; } @@ -15998,11 +16026,15 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec, static const char * const chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; - const char *pfx = alc_get_line_out_pfx(cfg, true); + const char *pfx = alc_get_line_out_pfx(spec, true); hda_nid_t nid; - int i, err; + int i, err, noutputs; - for (i = 0; i < cfg->line_outs; i++) { + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { nid = spec->multiout.dac_nids[i]; if (!nid) continue; @@ -16135,7 +16167,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc861_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc861_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc861_ignore); @@ -16147,6 +16179,9 @@ static int alc861_parse_auto_config(struct hda_codec *codec) err = alc861_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -16191,7 +16226,7 @@ static void alc861_auto_init(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list alc861_loopbacks[] = { +static const struct hda_amp_list alc861_loopbacks[] = { { 0x15, HDA_INPUT, 0 }, { 0x15, HDA_INPUT, 1 }, { 0x15, HDA_INPUT, 2 }, @@ -16216,7 +16251,7 @@ static const char * const alc861_models[ALC861_MODEL_LAST] = { [ALC861_AUTO] = "auto", }; -static struct snd_pci_quirk alc861_cfg_tbl[] = { +static const struct snd_pci_quirk alc861_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), @@ -16240,7 +16275,7 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = { {} }; -static struct alc_config_preset alc861_presets[] = { +static const struct alc_config_preset alc861_presets[] = { [ALC861_3ST] = { .mixers = { alc861_3ST_mixer }, .init_verbs = { alc861_threestack_init_verbs }, @@ -16363,7 +16398,7 @@ static const struct alc_fixup alc861_fixups[] = { }, }; -static struct snd_pci_quirk alc861_fixup_tbl[] = { +static const struct snd_pci_quirk alc861_fixup_tbl[] = { SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), {} }; @@ -16456,7 +16491,7 @@ static int patch_alc861(struct hda_codec *codec) */ #define ALC861VD_DIGOUT_NID 0x06 -static hda_nid_t alc861vd_dac_nids[4] = { +static const hda_nid_t alc861vd_dac_nids[4] = { /* front, surr, clfe, side surr */ 0x02, 0x03, 0x04, 0x05 }; @@ -16468,21 +16503,21 @@ static hda_nid_t alc861vd_dac_nids[4] = { * - and it is the same as in 861vd. * adc_nids in ALC660vd are (is) the same as in 861vd */ -static hda_nid_t alc660vd_dac_nids[3] = { +static const hda_nid_t alc660vd_dac_nids[3] = { /* front, rear, clfe, rear_surr */ 0x02, 0x04, 0x03 }; -static hda_nid_t alc861vd_adc_nids[1] = { +static const hda_nid_t alc861vd_adc_nids[1] = { /* ADC0 */ 0x09, }; -static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 }; +static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 }; /* input MUX */ /* FIXME: should be a matrix-type input source selection */ -static struct hda_input_mux alc861vd_capture_source = { +static const struct hda_input_mux alc861vd_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -16492,7 +16527,7 @@ static struct hda_input_mux alc861vd_capture_source = { }, }; -static struct hda_input_mux alc861vd_dallas_capture_source = { +static const struct hda_input_mux alc861vd_dallas_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -16500,7 +16535,7 @@ static struct hda_input_mux alc861vd_dallas_capture_source = { }, }; -static struct hda_input_mux alc861vd_hp_capture_source = { +static const struct hda_input_mux alc861vd_hp_capture_source = { .num_items = 2, .items = { { "Front Mic", 0x0 }, @@ -16511,14 +16546,14 @@ static struct hda_input_mux alc861vd_hp_capture_source = { /* * 2ch mode */ -static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { +static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { { 2, NULL } }; /* * 6ch mode */ -static struct hda_verb alc861vd_6stack_ch6_init[] = { +static const struct hda_verb alc861vd_6stack_ch6_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -16529,7 +16564,7 @@ static struct hda_verb alc861vd_6stack_ch6_init[] = { /* * 8ch mode */ -static struct hda_verb alc861vd_6stack_ch8_init[] = { +static const struct hda_verb alc861vd_6stack_ch8_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -16537,12 +16572,12 @@ static struct hda_verb alc861vd_6stack_ch8_init[] = { { } /* end */ }; -static struct hda_channel_mode alc861vd_6stack_modes[2] = { +static const struct hda_channel_mode alc861vd_6stack_modes[2] = { { 6, alc861vd_6stack_ch6_init }, { 8, alc861vd_6stack_ch8_init }, }; -static struct snd_kcontrol_new alc861vd_chmode_mixer[] = { +static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -16556,7 +16591,7 @@ static struct snd_kcontrol_new alc861vd_chmode_mixer[] = { /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ -static struct snd_kcontrol_new alc861vd_6st_mixer[] = { +static const struct snd_kcontrol_new alc861vd_6st_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -16592,7 +16627,7 @@ static struct snd_kcontrol_new alc861vd_6st_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861vd_3st_mixer[] = { +static const struct snd_kcontrol_new alc861vd_3st_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -16615,7 +16650,7 @@ static struct snd_kcontrol_new alc861vd_3st_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { +static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/ HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -16639,7 +16674,7 @@ static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { /* Pin assignment: Speaker=0x14, HP = 0x15, * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d */ -static struct snd_kcontrol_new alc861vd_dallas_mixer[] = { +static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -16656,7 +16691,7 @@ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = { /* Pin assignment: Speaker=0x14, Line-out = 0x15, * Front Mic=0x18, ATAPI Mic = 0x19, */ -static struct snd_kcontrol_new alc861vd_hp_mixer[] = { +static const struct snd_kcontrol_new alc861vd_hp_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -16672,7 +16707,7 @@ static struct snd_kcontrol_new alc861vd_hp_mixer[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc861vd_volume_init_verbs[] = { +static const struct hda_verb alc861vd_volume_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -16722,7 +16757,7 @@ static struct hda_verb alc861vd_volume_init_verbs[] = { * 3-stack pin configuration: * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b */ -static struct hda_verb alc861vd_3stack_init_verbs[] = { +static const struct hda_verb alc861vd_3stack_init_verbs[] = { /* * Set pin mode and muting */ @@ -16753,7 +16788,7 @@ static struct hda_verb alc861vd_3stack_init_verbs[] = { /* * 6-stack pin configuration: */ -static struct hda_verb alc861vd_6stack_init_verbs[] = { +static const struct hda_verb alc861vd_6stack_init_verbs[] = { /* * Set pin mode and muting */ @@ -16794,18 +16829,18 @@ static struct hda_verb alc861vd_6stack_init_verbs[] = { { } }; -static struct hda_verb alc861vd_eapd_verbs[] = { +static const struct hda_verb alc861vd_eapd_verbs[] = { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -static struct hda_verb alc660vd_eapd_verbs[] = { +static const struct hda_verb alc660vd_eapd_verbs[] = { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { +static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, @@ -16819,11 +16854,13 @@ static void alc861vd_lenovo_setup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc861vd_lenovo_init_hook(struct hda_codec *codec) { - alc_automute_amp(codec); + alc_hp_automute(codec); alc88x_simple_mic_automute(codec); } @@ -16835,12 +16872,12 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, alc88x_simple_mic_automute(codec); break; default: - alc_automute_amp_unsol_event(codec, res); + alc_sku_unsol_event(codec, res); break; } } -static struct hda_verb alc861vd_dallas_verbs[] = { +static const struct hda_verb alc861vd_dallas_verbs[] = { {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, @@ -16892,6 +16929,8 @@ static void alc861vd_dallas_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -16920,7 +16959,7 @@ static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = { [ALC861VD_AUTO] = "auto", }; -static struct snd_pci_quirk alc861vd_cfg_tbl[] = { +static const struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), @@ -16939,7 +16978,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { {} }; -static struct alc_config_preset alc861vd_presets[] = { +static const struct alc_config_preset alc861vd_presets[] = { [ALC660VD_3ST] = { .mixers = { alc861vd_3st_mixer }, .init_verbs = { alc861vd_volume_init_verbs, @@ -17016,9 +17055,9 @@ static struct alc_config_preset alc861vd_presets[] = { .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_dallas_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc861vd_dallas_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC861VD_HP] = { .mixers = { alc861vd_hp_mixer }, @@ -17029,9 +17068,9 @@ static struct alc_config_preset alc861vd_presets[] = { .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_hp_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc861vd_dallas_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC660VD_ASUS_V1S] = { .mixers = { alc861vd_lenovo_mixer }, @@ -17130,11 +17169,15 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, static const char * const chname[4] = { "Front", "Surround", "CLFE", "Side" }; - const char *pfx = alc_get_line_out_pfx(cfg, true); + const char *pfx = alc_get_line_out_pfx(spec, true); hda_nid_t nid_v, nid_s; - int i, err; + int i, err, noutputs; - for (i = 0; i < cfg->line_outs; i++) { + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { if (!spec->multiout.dac_nids[i]) continue; nid_v = alc861vd_idx_to_mixer_vol( @@ -17247,7 +17290,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc861vd_ignore); @@ -17259,6 +17302,9 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); if (err < 0) return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; @@ -17327,7 +17373,7 @@ static const struct alc_fixup alc861vd_fixups[] = { }, }; -static struct snd_pci_quirk alc861vd_fixup_tbl[] = { +static const struct snd_pci_quirk alc861vd_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), {} }; @@ -17410,6 +17456,7 @@ static int patch_alc861vd(struct hda_codec *codec) if (board_config == ALC861VD_AUTO) spec->init_hook = alc861vd_auto_init; + spec->shutup = alc_eapd_shutup; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc861vd_loopbacks; @@ -17432,32 +17479,32 @@ static int patch_alc861vd(struct hda_codec *codec) #define ALC662_DIGOUT_NID 0x06 #define ALC662_DIGIN_NID 0x0a -static hda_nid_t alc662_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ +static const hda_nid_t alc662_dac_nids[3] = { + /* front, rear, clfe */ 0x02, 0x03, 0x04 }; -static hda_nid_t alc272_dac_nids[2] = { +static const hda_nid_t alc272_dac_nids[2] = { 0x02, 0x03 }; -static hda_nid_t alc662_adc_nids[2] = { +static const hda_nid_t alc662_adc_nids[2] = { /* ADC1-2 */ 0x09, 0x08 }; -static hda_nid_t alc272_adc_nids[1] = { +static const hda_nid_t alc272_adc_nids[1] = { /* ADC1-2 */ 0x08, }; -static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; -static hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; +static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; +static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; /* input MUX */ /* FIXME: should be a matrix-type input source selection */ -static struct hda_input_mux alc662_capture_source = { +static const struct hda_input_mux alc662_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -17467,7 +17514,7 @@ static struct hda_input_mux alc662_capture_source = { }, }; -static struct hda_input_mux alc662_lenovo_101e_capture_source = { +static const struct hda_input_mux alc662_lenovo_101e_capture_source = { .num_items = 2, .items = { { "Mic", 0x1 }, @@ -17475,7 +17522,7 @@ static struct hda_input_mux alc662_lenovo_101e_capture_source = { }, }; -static struct hda_input_mux alc663_capture_source = { +static const struct hda_input_mux alc663_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -17485,7 +17532,7 @@ static struct hda_input_mux alc663_capture_source = { }; #if 0 /* set to 1 for testing other input sources below */ -static struct hda_input_mux alc272_nc10_capture_source = { +static const struct hda_input_mux alc272_nc10_capture_source = { .num_items = 16, .items = { { "Autoselect Mic", 0x0 }, @@ -17511,14 +17558,14 @@ static struct hda_input_mux alc272_nc10_capture_source = { /* * 2ch mode */ -static struct hda_channel_mode alc662_3ST_2ch_modes[1] = { +static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = { { 2, NULL } }; /* * 2ch mode */ -static struct hda_verb alc662_3ST_ch2_init[] = { +static const struct hda_verb alc662_3ST_ch2_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, @@ -17529,7 +17576,7 @@ static struct hda_verb alc662_3ST_ch2_init[] = { /* * 6ch mode */ -static struct hda_verb alc662_3ST_ch6_init[] = { +static const struct hda_verb alc662_3ST_ch6_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -17539,7 +17586,7 @@ static struct hda_verb alc662_3ST_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc662_3ST_6ch_modes[2] = { +static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = { { 2, alc662_3ST_ch2_init }, { 6, alc662_3ST_ch6_init }, }; @@ -17547,7 +17594,7 @@ static struct hda_channel_mode alc662_3ST_6ch_modes[2] = { /* * 2ch mode */ -static struct hda_verb alc662_sixstack_ch6_init[] = { +static const struct hda_verb alc662_sixstack_ch6_init[] = { { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -17557,14 +17604,14 @@ static struct hda_verb alc662_sixstack_ch6_init[] = { /* * 6ch mode */ -static struct hda_verb alc662_sixstack_ch8_init[] = { +static const struct hda_verb alc662_sixstack_ch8_init[] = { { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { } /* end */ }; -static struct hda_channel_mode alc662_5stack_modes[2] = { +static const struct hda_channel_mode alc662_5stack_modes[2] = { { 2, alc662_sixstack_ch6_init }, { 6, alc662_sixstack_ch8_init }, }; @@ -17573,7 +17620,7 @@ static struct hda_channel_mode alc662_5stack_modes[2] = { * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ -static struct snd_kcontrol_new alc662_base_mixer[] = { +static const struct snd_kcontrol_new alc662_base_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), @@ -17597,7 +17644,7 @@ static struct snd_kcontrol_new alc662_base_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { +static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -17612,7 +17659,7 @@ static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { +static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -17633,7 +17680,7 @@ static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { +static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -17646,7 +17693,7 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { +static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, @@ -17660,7 +17707,7 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { +static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -17674,7 +17721,7 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc663_asus_bind_master_vol = { +static const struct hda_bind_ctls alc663_asus_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), @@ -17683,7 +17730,7 @@ static struct hda_bind_ctls alc663_asus_bind_master_vol = { }, }; -static struct hda_bind_ctls alc663_asus_one_bind_switch = { +static const struct hda_bind_ctls alc663_asus_one_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17692,7 +17739,7 @@ static struct hda_bind_ctls alc663_asus_one_bind_switch = { }, }; -static struct snd_kcontrol_new alc663_m51va_mixer[] = { +static const struct snd_kcontrol_new alc663_m51va_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -17700,7 +17747,7 @@ static struct snd_kcontrol_new alc663_m51va_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc663_asus_tree_bind_switch = { +static const struct hda_bind_ctls alc663_asus_tree_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17710,7 +17757,7 @@ static struct hda_bind_ctls alc663_asus_tree_bind_switch = { }, }; -static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { +static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -17721,7 +17768,7 @@ static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc663_asus_four_bind_switch = { +static const struct hda_bind_ctls alc663_asus_four_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17731,7 +17778,7 @@ static struct hda_bind_ctls alc663_asus_four_bind_switch = { }, }; -static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { +static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -17741,7 +17788,7 @@ static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_1bjd_mixer[] = { +static const struct snd_kcontrol_new alc662_1bjd_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -17752,7 +17799,7 @@ static struct snd_kcontrol_new alc662_1bjd_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc663_asus_two_bind_master_vol = { +static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), @@ -17761,7 +17808,7 @@ static struct hda_bind_ctls alc663_asus_two_bind_master_vol = { }, }; -static struct hda_bind_ctls alc663_asus_two_bind_switch = { +static const struct hda_bind_ctls alc663_asus_two_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17770,7 +17817,7 @@ static struct hda_bind_ctls alc663_asus_two_bind_switch = { }, }; -static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { +static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc663_asus_two_bind_master_vol), HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), @@ -17781,7 +17828,7 @@ static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { +static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -17791,7 +17838,7 @@ static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc663_g71v_mixer[] = { +static const struct snd_kcontrol_new alc663_g71v_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -17805,7 +17852,7 @@ static struct snd_kcontrol_new alc663_g71v_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc663_g50v_mixer[] = { +static const struct snd_kcontrol_new alc663_g50v_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), @@ -17819,7 +17866,7 @@ static struct snd_kcontrol_new alc663_g50v_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { +static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17831,7 +17878,7 @@ static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { }, }; -static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { +static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17840,7 +17887,7 @@ static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { }, }; -static struct snd_kcontrol_new alc663_mode7_mixer[] = { +static const struct snd_kcontrol_new alc663_mode7_mixer[] = { HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), @@ -17853,7 +17900,7 @@ static struct snd_kcontrol_new alc663_mode7_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc663_mode8_mixer[] = { +static const struct snd_kcontrol_new alc663_mode8_mixer[] = { HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), @@ -17865,7 +17912,7 @@ static struct snd_kcontrol_new alc663_mode8_mixer[] = { }; -static struct snd_kcontrol_new alc662_chmode_mixer[] = { +static const struct snd_kcontrol_new alc662_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -17876,7 +17923,7 @@ static struct snd_kcontrol_new alc662_chmode_mixer[] = { { } /* end */ }; -static struct hda_verb alc662_init_verbs[] = { +static const struct hda_verb alc662_init_verbs[] = { /* ADC: mute amp left and right */ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -17922,55 +17969,36 @@ static struct hda_verb alc662_init_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* always trun on EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - - { } -}; - -static struct hda_verb alc663_init_verbs[] = { - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, { } }; -static struct hda_verb alc272_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +static const struct hda_verb alc662_eapd_init_verbs[] = { + /* always trun on EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -static struct hda_verb alc662_sue_init_verbs[] = { +static const struct hda_verb alc662_sue_init_verbs[] = { {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, {} }; -static struct hda_verb alc662_eeepc_sue_init_verbs[] = { +static const struct hda_verb alc662_eeepc_sue_init_verbs[] = { {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {} }; /* Set Unsolicited Event*/ -static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { +static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {} }; -static struct hda_verb alc663_m51va_init_verbs[] = { +static const struct hda_verb alc663_m51va_init_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -17983,7 +18011,7 @@ static struct hda_verb alc663_m51va_init_verbs[] = { {} }; -static struct hda_verb alc663_21jd_amic_init_verbs[] = { +static const struct hda_verb alc663_21jd_amic_init_verbs[] = { {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ @@ -17994,7 +18022,7 @@ static struct hda_verb alc663_21jd_amic_init_verbs[] = { {} }; -static struct hda_verb alc662_1bjd_amic_init_verbs[] = { +static const struct hda_verb alc662_1bjd_amic_init_verbs[] = { {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -18006,7 +18034,7 @@ static struct hda_verb alc662_1bjd_amic_init_verbs[] = { {} }; -static struct hda_verb alc663_15jd_amic_init_verbs[] = { +static const struct hda_verb alc663_15jd_amic_init_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ @@ -18017,7 +18045,7 @@ static struct hda_verb alc663_15jd_amic_init_verbs[] = { {} }; -static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { +static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -18033,7 +18061,7 @@ static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { {} }; -static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { +static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -18049,7 +18077,7 @@ static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { {} }; -static struct hda_verb alc663_g71v_init_verbs[] = { +static const struct hda_verb alc663_g71v_init_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */ @@ -18064,7 +18092,7 @@ static struct hda_verb alc663_g71v_init_verbs[] = { {} }; -static struct hda_verb alc663_g50v_init_verbs[] = { +static const struct hda_verb alc663_g50v_init_verbs[] = { {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ @@ -18074,7 +18102,7 @@ static struct hda_verb alc663_g50v_init_verbs[] = { {} }; -static struct hda_verb alc662_ecs_init_verbs[] = { +static const struct hda_verb alc662_ecs_init_verbs[] = { {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, @@ -18082,7 +18110,7 @@ static struct hda_verb alc662_ecs_init_verbs[] = { {} }; -static struct hda_verb alc272_dell_zm1_init_verbs[] = { +static const struct hda_verb alc272_dell_zm1_init_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -18097,7 +18125,7 @@ static struct hda_verb alc272_dell_zm1_init_verbs[] = { {} }; -static struct hda_verb alc272_dell_init_verbs[] = { +static const struct hda_verb alc272_dell_init_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -18112,7 +18140,7 @@ static struct hda_verb alc272_dell_init_verbs[] = { {} }; -static struct hda_verb alc663_mode7_init_verbs[] = { +static const struct hda_verb alc663_mode7_init_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -18131,7 +18159,7 @@ static struct hda_verb alc663_mode7_init_verbs[] = { {} }; -static struct hda_verb alc663_mode8_init_verbs[] = { +static const struct hda_verb alc663_mode8_init_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -18151,61 +18179,29 @@ static struct hda_verb alc663_mode8_init_verbs[] = { {} }; -static struct snd_kcontrol_new alc662_auto_capture_mixer[] = { +static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), { } /* end */ }; -static struct snd_kcontrol_new alc272_auto_capture_mixer[] = { +static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), { } /* end */ }; -static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec) +static void alc662_lenovo_101e_setup(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x14); - bits = present ? HDA_AMP_MUTE : 0; - - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x1b); - bits = present ? HDA_AMP_MUTE : 0; - - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc662_lenovo_101e_all_automute(codec); - if ((res >> 26) == ALC880_FRONT_EVENT) - alc662_lenovo_101e_ispeaker_automute(codec); -} + struct alc_spec *spec = codec->spec; -/* unsolicited event for HP jack sensing */ -static void alc662_eeepc_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_MIC_EVENT) - alc_mic_automute(codec); - else - alc262_hippo_unsol_event(codec, res); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc662_eeepc_setup(struct hda_codec *codec) @@ -18220,180 +18216,24 @@ static void alc662_eeepc_setup(struct hda_codec *codec) spec->auto_mic = 1; } -static void alc662_eeepc_inithook(struct hda_codec *codec) -{ - alc262_hippo_automute(codec); - alc_mic_automute(codec); -} - static void alc662_eeepc_ep20_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; -} - -#define alc662_eeepc_ep20_inithook alc262_hippo_master_update - -static void alc663_m51va_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x21); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); -} - -static void alc663_21jd_two_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x21); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); -} - -static void alc663_15jd_two_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x15); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); -} - -static void alc662_f5z_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x1b); - bits = present ? 0 : PIN_OUT; - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, bits); -} - -static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec) -{ - unsigned int present1, present2; - - present1 = snd_hda_jack_detect(codec, 0x21); - present2 = snd_hda_jack_detect(codec, 0x15); - - if (present1 || present2) { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - } else { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - } -} - -static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec) -{ - unsigned int present1, present2; - - present1 = snd_hda_jack_detect(codec, 0x1b); - present2 = snd_hda_jack_detect(codec, 0x15); - - if (present1 || present2) { - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, HDA_AMP_MUTE); - } else { - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, 0); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, 0); - } -} - -static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec) -{ - unsigned int present1, present2; - - present1 = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - present2 = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - - if (present1 || present2) { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - } else { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - } -} - -static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec) -{ - unsigned int present1, present2; - - present1 = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - present2 = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - - if (present1 || present2) { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - } else { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - } -} - -static void alc663_m51va_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_m51va_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc663_m51va_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; @@ -18401,18 +18241,15 @@ static void alc663_m51va_setup(struct hda_codec *codec) spec->auto_mic = 1; } -static void alc663_m51va_inithook(struct hda_codec *codec) -{ - alc663_m51va_speaker_automute(codec); - alc_mic_automute(codec); -} - /* ***************** Mode1 ******************************/ -#define alc663_mode1_unsol_event alc663_m51va_unsol_event - static void alc663_mode1_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; @@ -18420,229 +18257,144 @@ static void alc663_mode1_setup(struct hda_codec *codec) spec->auto_mic = 1; } -#define alc663_mode1_inithook alc663_m51va_inithook - /* ***************** Mode2 ******************************/ -static void alc662_mode2_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc662_mode2_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc662_f5z_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#define alc662_mode2_setup alc663_mode1_setup - -static void alc662_mode2_inithook(struct hda_codec *codec) -{ - alc662_f5z_speaker_automute(codec); - alc_mic_automute(codec); -} /* ***************** Mode3 ******************************/ -static void alc663_mode3_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc663_mode3_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_two_hp_m1_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#define alc663_mode3_setup alc663_mode1_setup - -static void alc663_mode3_inithook(struct hda_codec *codec) -{ - alc663_two_hp_m1_speaker_automute(codec); - alc_mic_automute(codec); -} /* ***************** Mode4 ******************************/ -static void alc663_mode4_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc663_mode4_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_21jd_two_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute_mixer_nid[1] = 0x0e; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#define alc663_mode4_setup alc663_mode1_setup - -static void alc663_mode4_inithook(struct hda_codec *codec) -{ - alc663_21jd_two_speaker_automute(codec); - alc_mic_automute(codec); -} /* ***************** Mode5 ******************************/ -static void alc663_mode5_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc663_mode5_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_15jd_two_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute_mixer_nid[1] = 0x0e; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#define alc663_mode5_setup alc663_mode1_setup - -static void alc663_mode5_inithook(struct hda_codec *codec) -{ - alc663_15jd_two_speaker_automute(codec); - alc_mic_automute(codec); -} /* ***************** Mode6 ******************************/ -static void alc663_mode6_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_two_hp_m2_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - -#define alc663_mode6_setup alc663_mode1_setup - -static void alc663_mode6_inithook(struct hda_codec *codec) +static void alc663_mode6_setup(struct hda_codec *codec) { - alc663_two_hp_m2_speaker_automute(codec); - alc_mic_automute(codec); + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } /* ***************** Mode7 ******************************/ -static void alc663_mode7_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc663_mode7_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_two_hp_m7_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - -#define alc663_mode7_setup alc663_mode1_setup - -static void alc663_mode7_inithook(struct hda_codec *codec) -{ - alc663_two_hp_m7_speaker_automute(codec); - alc_mic_automute(codec); + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } /* ***************** Mode8 ******************************/ -static void alc663_mode8_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_two_hp_m8_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - -#define alc663_mode8_setup alc663_m51va_setup - -static void alc663_mode8_inithook(struct hda_codec *codec) -{ - alc663_two_hp_m8_speaker_automute(codec); - alc_mic_automute(codec); -} - -static void alc663_g71v_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x21); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc663_g71v_front_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x15); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc663_g71v_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_g71v_hp_automute(codec); - break; - case ALC880_FRONT_EVENT: - alc663_g71v_front_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - -#define alc663_g71v_setup alc663_m51va_setup - -static void alc663_g71v_inithook(struct hda_codec *codec) +static void alc663_mode8_setup(struct hda_codec *codec) { - alc663_g71v_front_automute(codec); - alc663_g71v_hp_automute(codec); - alc_mic_automute(codec); + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.hp_pins[1] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; } -static void alc663_g50v_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc663_g71v_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_m51va_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.line_out_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; } #define alc663_g50v_setup alc663_m51va_setup -static void alc663_g50v_inithook(struct hda_codec *codec) -{ - alc663_m51va_speaker_automute(codec); - alc_mic_automute(codec); -} - -static struct snd_kcontrol_new alc662_ecs_mixer[] = { +static const struct snd_kcontrol_new alc662_ecs_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, @@ -18656,7 +18408,7 @@ static struct snd_kcontrol_new alc662_ecs_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc272_nc10_mixer[] = { +static const struct snd_kcontrol_new alc272_nc10_mixer[] = { /* Master Playback automatically created from Speaker and Headphone */ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -18691,7 +18443,7 @@ static const char * const alc662_models[ALC662_MODEL_LAST] = { [ALC662_3ST_2ch_DIG] = "3stack-dig", [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig", [ALC662_3ST_6ch] = "3stack-6ch", - [ALC662_5ST_DIG] = "6stack-dig", + [ALC662_5ST_DIG] = "5stack-dig", [ALC662_LENOVO_101E] = "lenovo-101e", [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", @@ -18714,7 +18466,7 @@ static const char * const alc662_models[ALC662_MODEL_LAST] = { [ALC662_AUTO] = "auto", }; -static struct snd_pci_quirk alc662_cfg_tbl[] = { +static const struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL), SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1), @@ -18782,6 +18534,8 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { ALC662_3ST_6ch_DIG), SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO), SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", + ALC662_3ST_6ch_DIG), SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13), SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA), @@ -18794,10 +18548,10 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { {} }; -static struct alc_config_preset alc662_presets[] = { +static const struct alc_config_preset alc662_presets[] = { [ALC662_3ST_2ch_DIG] = { .mixers = { alc662_3ST_2ch_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18808,7 +18562,7 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_3ST_6ch_DIG] = { .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18820,7 +18574,7 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_3ST_6ch] = { .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), @@ -18830,7 +18584,7 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_5ST_DIG] = { .mixers = { alc662_base_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18841,104 +18595,120 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_LENOVO_101E] = { .mixers = { alc662_lenovo_101e_mixer }, - .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc662_lenovo_101e_unsol_event, - .init_hook = alc662_lenovo_101e_all_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_lenovo_101e_setup, + .init_hook = alc_inithook, }, [ALC662_ASUS_EEEPC_P701] = { .mixers = { alc662_eeepc_p701_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_eeepc_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc662_eeepc_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc662_eeepc_setup, - .init_hook = alc662_eeepc_inithook, + .init_hook = alc_inithook, }, [ALC662_ASUS_EEEPC_EP20] = { .mixers = { alc662_eeepc_ep20_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_eeepc_ep20_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), .channel_mode = alc662_3ST_6ch_modes, .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc662_eeepc_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc662_eeepc_ep20_setup, - .init_hook = alc662_eeepc_ep20_inithook, + .init_hook = alc_inithook, }, [ALC662_ECS] = { .mixers = { alc662_ecs_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_ecs_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc662_eeepc_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc662_eeepc_setup, - .init_hook = alc662_eeepc_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_M51VA] = { .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_m51va_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_m51va_setup, - .init_hook = alc663_m51va_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_G71V] = { .mixers = { alc663_g71v_mixer }, - .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g71v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_g71v_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_g71v_setup, - .init_hook = alc663_g71v_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_H13] = { .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_m51va_unsol_event, - .init_hook = alc663_m51va_inithook, + .setup = alc663_m51va_setup, + .unsol_event = alc_sku_unsol_event, + .init_hook = alc_inithook, }, [ALC663_ASUS_G50V] = { .mixers = { alc663_g50v_mixer }, - .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g50v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), .channel_mode = alc662_3ST_6ch_modes, .input_mux = &alc663_capture_source, - .unsol_event = alc663_g50v_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_g50v_setup, - .init_hook = alc663_g50v_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE1] = { .mixers = { alc663_m51va_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_21jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -18946,28 +18716,30 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode1_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode1_setup, - .init_hook = alc663_mode1_inithook, + .init_hook = alc_inithook, }, [ALC662_ASUS_MODE2] = { .mixers = { alc662_1bjd_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_1bjd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc662_mode2_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc662_mode2_setup, - .init_hook = alc662_mode2_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE3] = { .mixers = { alc663_two_hp_m1_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_two_hp_amic_m1_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -18975,14 +18747,15 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode3_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode3_setup, - .init_hook = alc663_mode3_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE4] = { .mixers = { alc663_asus_21jd_clfe_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_21jd_amic_init_verbs}, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -18990,14 +18763,15 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode4_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode4_setup, - .init_hook = alc663_mode4_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE5] = { .mixers = { alc663_asus_15jd_clfe_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_15jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19005,14 +18779,15 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode5_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode5_setup, - .init_hook = alc663_mode5_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE6] = { .mixers = { alc663_two_hp_m2_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_two_hp_amic_m2_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19020,14 +18795,15 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode6_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode6_setup, - .init_hook = alc663_mode6_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE7] = { .mixers = { alc663_mode7_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_mode7_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19035,14 +18811,15 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode7_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode7_setup, - .init_hook = alc663_mode7_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE8] = { .mixers = { alc663_mode8_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_mode8_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19050,52 +18827,57 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode8_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode8_setup, - .init_hook = alc663_mode8_inithook, + .init_hook = alc_inithook, }, [ALC272_DELL] = { .mixers = { alc663_m51va_mixer }, .cap_mixer = alc272_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_init_verbs }, .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc662_dac_nids, + .dac_nids = alc272_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .adc_nids = alc272_adc_nids, .num_adc_nids = ARRAY_SIZE(alc272_adc_nids), .capsrc_nids = alc272_capsrc_nids, .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_m51va_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_m51va_setup, - .init_hook = alc663_m51va_inithook, + .init_hook = alc_inithook, }, [ALC272_DELL_ZM1] = { .mixers = { alc663_m51va_mixer }, .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_zm1_init_verbs }, .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc662_dac_nids, + .dac_nids = alc272_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .adc_nids = alc662_adc_nids, .num_adc_nids = 1, .capsrc_nids = alc662_capsrc_nids, .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_m51va_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_m51va_setup, - .init_hook = alc663_m51va_inithook, + .init_hook = alc_inithook, }, [ALC272_SAMSUNG_NC10] = { .mixers = { alc272_nc10_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_21jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc272_dac_nids), .dac_nids = alc272_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, /*.input_mux = &alc272_nc10_capture_source,*/ - .unsol_event = alc663_mode4_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode4_setup, - .init_hook = alc663_mode4_inithook, + .init_hook = alc_inithook, }, }; @@ -19105,45 +18887,79 @@ static struct alc_config_preset alc662_presets[] = { */ /* convert from MIX nid to DAC */ -static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid) -{ - if (nid == 0x0f) - return 0x02; - else if (nid >= 0x0c && nid <= 0x0e) - return nid - 0x0c + 0x02; - else if (nid == 0x26) /* ALC887-VD has this DAC too */ - return 0x25; - else - return 0; +static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid) +{ + hda_nid_t list[5]; + int i, num; + + num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list)); + for (i = 0; i < num; i++) { + if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT) + return list[i]; + } + return 0; +} + +/* go down to the selector widget before the mixer */ +static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin) +{ + hda_nid_t srcs[5]; + int num = snd_hda_get_connections(codec, pin, srcs, + ARRAY_SIZE(srcs)); + if (num != 1 || + get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL) + return pin; + return srcs[0]; } /* get MIX nid connected to the given pin targeted to DAC */ -static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, +static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) { hda_nid_t mix[5]; int i, num; + pin = alc_go_down_to_selector(codec, pin); num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); for (i = 0; i < num; i++) { - if (alc662_mix_to_dac(mix[i]) == dac) + if (alc_auto_mix_to_dac(codec, mix[i]) == dac) return mix[i]; } return 0; } +/* select the connection from pin to DAC if needed */ +static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, + hda_nid_t dac) +{ + hda_nid_t mix[5]; + int i, num; + + pin = alc_go_down_to_selector(codec, pin); + num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); + if (num < 2) + return 0; + for (i = 0; i < num; i++) { + if (alc_auto_mix_to_dac(codec, mix[i]) == dac) { + snd_hda_codec_update_cache(codec, pin, 0, + AC_VERB_SET_CONNECT_SEL, i); + return 0; + } + } + return 0; +} + /* look for an empty DAC slot */ -static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin) +static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) { struct alc_spec *spec = codec->spec; hda_nid_t srcs[5]; int i, j, num; + pin = alc_go_down_to_selector(codec, pin); num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); - if (num < 0) - return 0; for (i = 0; i < num; i++) { - hda_nid_t nid = alc662_mix_to_dac(srcs[i]); + hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); if (!nid) continue; for (j = 0; j < spec->multiout.num_dacs; j++) @@ -19165,10 +18981,10 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec, spec->multiout.dac_nids = spec->private_dac_nids; for (i = 0; i < cfg->line_outs; i++) { - dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]); + dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]); if (!dac) continue; - spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } return 0; } @@ -19204,15 +19020,23 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, static const char * const chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; - const char *pfx = alc_get_line_out_pfx(cfg, true); - hda_nid_t nid, mix; - int i, err; + const char *pfx = alc_get_line_out_pfx(spec, true); + hda_nid_t nid, mix, pin; + int i, err, noutputs; - for (i = 0; i < cfg->line_outs; i++) { + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { nid = spec->multiout.dac_nids[i]; if (!nid) continue; - mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid); + if (i >= cfg->line_outs) + pin = spec->multi_io[i - 1].pin; + else + pin = cfg->line_out_pins[i]; + mix = alc_auto_dac_to_mix(codec, pin, nid); if (!mix) continue; if (!pfx && i == 2) { @@ -19258,7 +19082,7 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, if (!pin) return 0; - nid = alc662_look_for_dac(codec, pin); + nid = alc_auto_look_for_dac(codec, pin); if (!nid) { /* the corresponding DAC is already occupied */ if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) @@ -19268,7 +19092,7 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); } - mix = alc662_dac_to_mix(codec, pin, nid); + mix = alc_auto_dac_to_mix(codec, pin, nid); if (!mix) return 0; err = alc662_add_vol_ctl(spec, pfx, nid, 3); @@ -19292,14 +19116,21 @@ static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t srcs[HDA_MAX_CONNECTIONS]; alc_set_pin_output(codec, nid, pin_type); - /* need the manual connection? */ num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs)); - if (num <= 1) - return; for (i = 0; i < num; i++) { - if (alc662_mix_to_dac(srcs[i]) != dac) + if (alc_auto_mix_to_dac(codec, srcs[i]) != dac) continue; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i); + /* need the manual connection? */ + if (num > 1) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, i); + /* unmute mixer widget inputs */ + snd_hda_codec_write(codec, srcs[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + snd_hda_codec_write(codec, srcs[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); return; } } @@ -19356,11 +19187,164 @@ static void alc662_auto_init_analog_input(struct hda_codec *codec) #define alc662_auto_init_input_src alc882_auto_init_input_src +/* + * multi-io helper + */ +static int alc_auto_fill_multi_ios(struct hda_codec *codec, + unsigned int location) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int type, i, num_pins = 0; + + for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + hda_nid_t dac; + unsigned int defcfg, caps; + if (cfg->inputs[i].type != type) + continue; + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) + continue; + if (location && get_defcfg_location(defcfg) != location) + continue; + caps = snd_hda_query_pin_caps(codec, nid); + if (!(caps & AC_PINCAP_OUT)) + continue; + dac = alc_auto_look_for_dac(codec, nid); + if (!dac) + continue; + spec->multi_io[num_pins].pin = nid; + spec->multi_io[num_pins].dac = dac; + num_pins++; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; + } + } + spec->multiout.num_dacs = 1; + if (num_pins < 2) + return 0; + return num_pins; +} + +static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = spec->multi_ios + 1; + if (uinfo->value.enumerated.item > spec->multi_ios) + uinfo->value.enumerated.item = spec->multi_ios; + sprintf(uinfo->value.enumerated.name, "%dch", + (uinfo->value.enumerated.item + 1) * 2); + return 0; +} + +static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2; + return 0; +} + +static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid = spec->multi_io[idx].pin; + + if (!spec->multi_io[idx].ctl_in) + spec->multi_io[idx].ctl_in = + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (output) { + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); + alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac); + } else { + if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->multi_io[idx].ctl_in); + } + return 0; +} + +static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int i, ch; + + ch = ucontrol->value.enumerated.item[0]; + if (ch < 0 || ch > spec->multi_ios) + return -EINVAL; + if (ch == (spec->ext_channel_count - 1) / 2) + return 0; + spec->ext_channel_count = (ch + 1) * 2; + for (i = 0; i < spec->multi_ios; i++) + alc_set_multi_io(codec, i, i < ch); + spec->multiout.max_channels = spec->ext_channel_count; + return 1; +} + +static const struct snd_kcontrol_new alc_auto_channel_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_auto_ch_mode_info, + .get = alc_auto_ch_mode_get, + .put = alc_auto_ch_mode_put, +}; + +static int alc_auto_add_multi_channel_mode(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int location, defcfg; + int num_pins; + + if (cfg->line_outs != 1 || + cfg->line_out_type != AUTO_PIN_LINE_OUT) + return 0; + + defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); + location = get_defcfg_location(defcfg); + + num_pins = alc_auto_fill_multi_ios(codec, location); + if (num_pins > 0) { + struct snd_kcontrol_new *knew; + + knew = alc_kcontrol_new(spec); + if (!knew) + return -ENOMEM; + *knew = alc_auto_channel_mode_enum; + knew->name = kstrdup("Channel Mode", GFP_KERNEL); + if (!knew->name) + return -ENOMEM; + + spec->multi_ios = num_pins; + spec->ext_channel_count = 2; + spec->multiout.num_dacs = num_pins + 1; + } + return 0; +} + static int alc662_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc662_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc662_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc662_ignore); @@ -19372,6 +19356,9 @@ static int alc662_parse_auto_config(struct hda_codec *codec) err = alc662_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -19402,14 +19389,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; - add_verb(spec, alc662_init_verbs); - if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || - codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) - add_verb(spec, alc663_init_verbs); - - if (codec->vendor_id == 0x10ec0272) - add_verb(spec, alc272_init_verbs); - err = alc_auto_add_mic_boost(codec); if (err < 0) return err; @@ -19455,7 +19434,7 @@ enum { ALC662_FIXUP_IDEAPAD, ALC272_FIXUP_MARIO, ALC662_FIXUP_CZC_P10T, - ALC662_FIXUP_GIGABYTE, + ALC662_FIXUP_SKU_IGNORE, }; static const struct alc_fixup alc662_fixups[] = { @@ -19484,20 +19463,17 @@ static const struct alc_fixup alc662_fixups[] = { {} } }, - [ALC662_FIXUP_GIGABYTE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x1114410 }, /* set as speaker */ - { } - } + [ALC662_FIXUP_SKU_IGNORE] = { + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, }, }; -static struct snd_pci_quirk alc662_fixup_tbl[] = { +static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte", ALC662_FIXUP_GIGABYTE), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), @@ -19611,6 +19587,7 @@ static int patch_alc662(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC662_AUTO) spec->init_hook = alc662_auto_init; + spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); @@ -19639,6 +19616,15 @@ static int patch_alc888(struct hda_codec *codec) return patch_alc882(codec); } +static int patch_alc899(struct hda_codec *codec) +{ + if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) { + kfree(codec->chip_name); + codec->chip_name = kstrdup("ALC898", GFP_KERNEL); + } + return patch_alc882(codec); +} + /* * ALC680 support */ @@ -19646,12 +19632,12 @@ static int patch_alc888(struct hda_codec *codec) #define ALC680_DIGOUT_NID ALC880_DIGOUT_NID #define alc680_modes alc260_modes -static hda_nid_t alc680_dac_nids[3] = { +static const hda_nid_t alc680_dac_nids[3] = { /* Lout1, Lout2, hp */ 0x02, 0x03, 0x04 }; -static hda_nid_t alc680_adc_nids[3] = { +static const hda_nid_t alc680_adc_nids[3] = { /* ADC0-2 */ /* DMIC, MIC, Line-in*/ 0x07, 0x08, 0x09 @@ -19671,8 +19657,7 @@ static void alc680_rec_autoswitch(struct hda_codec *codec) for (i = 0; i < cfg->num_inputs; i++) { nid = cfg->inputs[i].pin; - if (!(snd_hda_query_pin_caps(codec, nid) & - AC_PINCAP_PRES_DETECT)) + if (!is_jack_detectable(codec, nid)) continue; if (snd_hda_jack_detect(codec, nid)) { if (cfg->inputs[i].type < type_found) { @@ -19719,7 +19704,7 @@ static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream alc680_pcm_analog_auto_capture = { +static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = { .substreams = 1, /* can be overridden */ .channels_min = 2, .channels_max = 2, @@ -19730,7 +19715,7 @@ static struct hda_pcm_stream alc680_pcm_analog_auto_capture = { }, }; -static struct snd_kcontrol_new alc680_base_mixer[] = { +static const struct snd_kcontrol_new alc680_base_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -19742,7 +19727,7 @@ static struct snd_kcontrol_new alc680_base_mixer[] = { { } }; -static struct hda_bind_ctls alc680_bind_cap_vol = { +static const struct hda_bind_ctls alc680_bind_cap_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), @@ -19752,7 +19737,7 @@ static struct hda_bind_ctls alc680_bind_cap_vol = { }, }; -static struct hda_bind_ctls alc680_bind_cap_switch = { +static const struct hda_bind_ctls alc680_bind_cap_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), @@ -19762,7 +19747,7 @@ static struct hda_bind_ctls alc680_bind_cap_switch = { }, }; -static struct snd_kcontrol_new alc680_master_capture_mixer[] = { +static const struct snd_kcontrol_new alc680_master_capture_mixer[] = { HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), { } /* end */ @@ -19771,7 +19756,7 @@ static struct snd_kcontrol_new alc680_master_capture_mixer[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc680_init_verbs[] = { +static const struct hda_verb alc680_init_verbs[] = { {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -19809,20 +19794,22 @@ static void alc680_base_setup(struct hda_codec *codec) spec->autocfg.inputs[0].type = AUTO_PIN_MIC; spec->autocfg.inputs[1].pin = 0x19; spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc680_unsol_event(struct hda_codec *codec, unsigned int res) { if ((res >> 26) == ALC880_HP_EVENT) - alc_automute_amp(codec); + alc_hp_automute(codec); if ((res >> 26) == ALC880_MIC_EVENT) alc680_rec_autoswitch(codec); } static void alc680_inithook(struct hda_codec *codec) { - alc_automute_amp(codec); + alc_hp_automute(codec); alc680_rec_autoswitch(codec); } @@ -19859,7 +19846,7 @@ static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid, if (err < 0) return err; - spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } return 0; @@ -19945,7 +19932,7 @@ static int alc680_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc680_ignore[] = { 0 }; + static const hda_nid_t alc680_ignore[] = { 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc680_ignore); @@ -20003,12 +19990,12 @@ static const char * const alc680_models[ALC680_MODEL_LAST] = { [ALC680_AUTO] = "auto", }; -static struct snd_pci_quirk alc680_cfg_tbl[] = { +static const struct snd_pci_quirk alc680_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), {} }; -static struct alc_config_preset alc680_presets[] = { +static const struct alc_config_preset alc680_presets[] = { [ALC680_BASE] = { .mixers = { alc680_base_mixer }, .cap_mixer = alc680_master_capture_mixer, @@ -20089,7 +20076,8 @@ static int patch_alc680(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_realtek[] = { +static const struct hda_codec_preset snd_hda_preset_realtek[] = { + { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 }, { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, @@ -20098,6 +20086,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 }, { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 }, { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 }, + { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, @@ -20125,6 +20114,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 }, { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 }, { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 }, + { .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 }, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index f419ee8d75f..2f55f32876f 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -130,7 +130,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol, } -static struct snd_kcontrol_new si3054_modem_mixer[] = { +static const struct snd_kcontrol_new si3054_modem_mixer[] = { SI3054_KCONTROL("Off-hook Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_OH), SI3054_KCONTROL("Caller ID Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_CID), {} @@ -181,7 +181,7 @@ static int si3054_pcm_open(struct hda_pcm_stream *hinfo, } -static struct hda_pcm_stream si3054_pcm = { +static const struct hda_pcm_stream si3054_pcm = { .substreams = 1, .channels_min = 1, .channels_max = 1, @@ -200,12 +200,13 @@ static int si3054_build_pcms(struct hda_codec *codec) { struct si3054_spec *spec = codec->spec; struct hda_pcm *info = &spec->pcm; - si3054_pcm.nid = codec->mfg; codec->num_pcms = 1; codec->pcm_info = info; info->name = "Si3054 Modem"; 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; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = codec->mfg; info->pcm_type = HDA_PCM_TYPE_MODEM; return 0; } @@ -263,7 +264,7 @@ static void si3054_free(struct hda_codec *codec) /* */ -static struct hda_codec_ops si3054_patch_ops = { +static const struct hda_codec_ops si3054_patch_ops = { .build_controls = si3054_build_controls, .build_pcms = si3054_build_pcms, .init = si3054_init, @@ -283,7 +284,7 @@ static int patch_si3054(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_si3054[] = { +static const struct hda_codec_preset snd_hda_preset_si3054[] = { { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 94d19c03a7f..7f81cc2274f 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -217,15 +217,15 @@ struct sigmatel_spec { unsigned int stream_delay; /* analog loopback */ - struct snd_kcontrol_new *aloopback_ctl; + const struct snd_kcontrol_new *aloopback_ctl; unsigned char aloopback_mask; unsigned char aloopback_shift; /* power management */ unsigned int num_pwrs; - unsigned int *pwr_mapping; - hda_nid_t *pwr_nids; - hda_nid_t *dac_list; + const unsigned int *pwr_mapping; + const hda_nid_t *pwr_nids; + const hda_nid_t *dac_list; /* events */ struct snd_array events; @@ -241,20 +241,20 @@ struct sigmatel_spec { int volume_offset; /* capture */ - hda_nid_t *adc_nids; + const hda_nid_t *adc_nids; unsigned int num_adcs; - hda_nid_t *mux_nids; + const hda_nid_t *mux_nids; unsigned int num_muxes; - hda_nid_t *dmic_nids; + const hda_nid_t *dmic_nids; unsigned int num_dmics; - hda_nid_t *dmux_nids; + const hda_nid_t *dmux_nids; unsigned int num_dmuxes; - hda_nid_t *smux_nids; + const hda_nid_t *smux_nids; unsigned int num_smuxes; unsigned int num_analog_muxes; - unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */ - unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ + const unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */ + const unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ unsigned int num_caps; /* number of capture volume/switch elements */ struct sigmatel_mic_route ext_mic; @@ -269,12 +269,12 @@ struct sigmatel_spec { hda_nid_t digbeep_nid; /* pin widgets */ - hda_nid_t *pin_nids; + const hda_nid_t *pin_nids; unsigned int num_pins; /* codec specific stuff */ - struct hda_verb *init; - struct snd_kcontrol_new *mixer; + const struct hda_verb *init; + const struct snd_kcontrol_new *mixer; /* capture source */ struct hda_input_mux *dinput_mux; @@ -317,52 +317,52 @@ struct sigmatel_spec { hda_nid_t auto_dmic_nids[MAX_DMICS_NUM]; }; -static hda_nid_t stac9200_adc_nids[1] = { +static const hda_nid_t stac9200_adc_nids[1] = { 0x03, }; -static hda_nid_t stac9200_mux_nids[1] = { +static const hda_nid_t stac9200_mux_nids[1] = { 0x0c, }; -static hda_nid_t stac9200_dac_nids[1] = { +static const hda_nid_t stac9200_dac_nids[1] = { 0x02, }; -static hda_nid_t stac92hd73xx_pwr_nids[8] = { +static const hda_nid_t stac92hd73xx_pwr_nids[8] = { 0x0a, 0x0b, 0x0c, 0xd, 0x0e, 0x0f, 0x10, 0x11 }; -static hda_nid_t stac92hd73xx_slave_dig_outs[2] = { +static const hda_nid_t stac92hd73xx_slave_dig_outs[2] = { 0x26, 0, }; -static hda_nid_t stac92hd73xx_adc_nids[2] = { +static const hda_nid_t stac92hd73xx_adc_nids[2] = { 0x1a, 0x1b }; #define STAC92HD73XX_NUM_DMICS 2 -static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { +static const hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { 0x13, 0x14, 0 }; #define STAC92HD73_DAC_COUNT 5 -static hda_nid_t stac92hd73xx_mux_nids[2] = { +static const hda_nid_t stac92hd73xx_mux_nids[2] = { 0x20, 0x21, }; -static hda_nid_t stac92hd73xx_dmux_nids[2] = { +static const hda_nid_t stac92hd73xx_dmux_nids[2] = { 0x20, 0x21, }; -static hda_nid_t stac92hd73xx_smux_nids[2] = { +static const hda_nid_t stac92hd73xx_smux_nids[2] = { 0x22, 0x23, }; #define STAC92HD73XX_NUM_CAPS 2 -static unsigned long stac92hd73xx_capvols[] = { +static const unsigned long stac92hd73xx_capvols[] = { HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), }; @@ -370,137 +370,141 @@ static unsigned long stac92hd73xx_capvols[] = { #define STAC92HD83_DAC_COUNT 3 -static hda_nid_t stac92hd83xxx_pwr_nids[4] = { +static const hda_nid_t stac92hd83xxx_pwr_nids[4] = { 0xa, 0xb, 0xd, 0xe, }; -static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = { +static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = { 0x1e, 0, }; -static unsigned int stac92hd83xxx_pwr_mapping[4] = { +static const unsigned int stac92hd83xxx_pwr_mapping[4] = { 0x03, 0x0c, 0x20, 0x40, }; -static hda_nid_t stac92hd83xxx_dmic_nids[] = { +static const hda_nid_t stac92hd83xxx_dmic_nids[] = { 0x11, 0x20, }; -static hda_nid_t stac92hd71bxx_pwr_nids[3] = { +static const hda_nid_t stac92hd71bxx_pwr_nids[3] = { 0x0a, 0x0d, 0x0f }; -static hda_nid_t stac92hd71bxx_adc_nids[2] = { +static const hda_nid_t stac92hd71bxx_adc_nids[2] = { 0x12, 0x13, }; -static hda_nid_t stac92hd71bxx_mux_nids[2] = { +static const hda_nid_t stac92hd71bxx_mux_nids[2] = { 0x1a, 0x1b }; -static hda_nid_t stac92hd71bxx_dmux_nids[2] = { +static const hda_nid_t stac92hd71bxx_dmux_nids[2] = { 0x1c, 0x1d, }; -static hda_nid_t stac92hd71bxx_smux_nids[2] = { +static const hda_nid_t stac92hd71bxx_smux_nids[2] = { 0x24, 0x25, }; #define STAC92HD71BXX_NUM_DMICS 2 -static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = { +static const hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = { 0x18, 0x19, 0 }; -static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = { +static const hda_nid_t stac92hd71bxx_dmic_5port_nids[STAC92HD71BXX_NUM_DMICS] = { + 0x18, 0 +}; + +static const hda_nid_t stac92hd71bxx_slave_dig_outs[2] = { 0x22, 0 }; #define STAC92HD71BXX_NUM_CAPS 2 -static unsigned long stac92hd71bxx_capvols[] = { +static const unsigned long stac92hd71bxx_capvols[] = { HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), }; #define stac92hd71bxx_capsws stac92hd71bxx_capvols -static hda_nid_t stac925x_adc_nids[1] = { +static const hda_nid_t stac925x_adc_nids[1] = { 0x03, }; -static hda_nid_t stac925x_mux_nids[1] = { +static const hda_nid_t stac925x_mux_nids[1] = { 0x0f, }; -static hda_nid_t stac925x_dac_nids[1] = { +static const hda_nid_t stac925x_dac_nids[1] = { 0x02, }; #define STAC925X_NUM_DMICS 1 -static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = { +static const hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = { 0x15, 0 }; -static hda_nid_t stac925x_dmux_nids[1] = { +static const hda_nid_t stac925x_dmux_nids[1] = { 0x14, }; -static unsigned long stac925x_capvols[] = { +static const unsigned long stac925x_capvols[] = { HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), }; -static unsigned long stac925x_capsws[] = { +static const unsigned long stac925x_capsws[] = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }; -static hda_nid_t stac922x_adc_nids[2] = { +static const hda_nid_t stac922x_adc_nids[2] = { 0x06, 0x07, }; -static hda_nid_t stac922x_mux_nids[2] = { +static const hda_nid_t stac922x_mux_nids[2] = { 0x12, 0x13, }; #define STAC922X_NUM_CAPS 2 -static unsigned long stac922x_capvols[] = { +static const unsigned long stac922x_capvols[] = { HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT), HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), }; #define stac922x_capsws stac922x_capvols -static hda_nid_t stac927x_slave_dig_outs[2] = { +static const hda_nid_t stac927x_slave_dig_outs[2] = { 0x1f, 0, }; -static hda_nid_t stac927x_adc_nids[3] = { +static const hda_nid_t stac927x_adc_nids[3] = { 0x07, 0x08, 0x09 }; -static hda_nid_t stac927x_mux_nids[3] = { +static const hda_nid_t stac927x_mux_nids[3] = { 0x15, 0x16, 0x17 }; -static hda_nid_t stac927x_smux_nids[1] = { +static const hda_nid_t stac927x_smux_nids[1] = { 0x21, }; -static hda_nid_t stac927x_dac_nids[6] = { +static const hda_nid_t stac927x_dac_nids[6] = { 0x02, 0x03, 0x04, 0x05, 0x06, 0 }; -static hda_nid_t stac927x_dmux_nids[1] = { +static const hda_nid_t stac927x_dmux_nids[1] = { 0x1b, }; #define STAC927X_NUM_DMICS 2 -static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = { +static const hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = { 0x13, 0x14, 0 }; #define STAC927X_NUM_CAPS 3 -static unsigned long stac927x_capvols[] = { +static const unsigned long stac927x_capvols[] = { HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT), HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT), }; -static unsigned long stac927x_capsws[] = { +static const unsigned long stac927x_capsws[] = { HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), @@ -511,77 +515,77 @@ static const char * const stac927x_spdif_labels[5] = { "Analog Mux 2", "Analog Mux 3" }; -static hda_nid_t stac9205_adc_nids[2] = { +static const hda_nid_t stac9205_adc_nids[2] = { 0x12, 0x13 }; -static hda_nid_t stac9205_mux_nids[2] = { +static const hda_nid_t stac9205_mux_nids[2] = { 0x19, 0x1a }; -static hda_nid_t stac9205_dmux_nids[1] = { +static const hda_nid_t stac9205_dmux_nids[1] = { 0x1d, }; -static hda_nid_t stac9205_smux_nids[1] = { +static const hda_nid_t stac9205_smux_nids[1] = { 0x21, }; #define STAC9205_NUM_DMICS 2 -static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { +static const hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { 0x17, 0x18, 0 }; #define STAC9205_NUM_CAPS 2 -static unsigned long stac9205_capvols[] = { +static const unsigned long stac9205_capvols[] = { HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT), HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT), }; -static unsigned long stac9205_capsws[] = { +static const unsigned long stac9205_capsws[] = { HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT), }; -static hda_nid_t stac9200_pin_nids[8] = { +static const hda_nid_t stac9200_pin_nids[8] = { 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, }; -static hda_nid_t stac925x_pin_nids[8] = { +static const hda_nid_t stac925x_pin_nids[8] = { 0x07, 0x08, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x11, }; -static hda_nid_t stac922x_pin_nids[10] = { +static const hda_nid_t stac922x_pin_nids[10] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x15, 0x1b, }; -static hda_nid_t stac92hd73xx_pin_nids[13] = { +static const hda_nid_t stac92hd73xx_pin_nids[13] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x22, 0x23 }; #define STAC92HD71BXX_NUM_PINS 13 -static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { +static const hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x14, 0x18, 0x19, 0x1e, 0x1f, 0x20, 0x27 }; -static hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = { +static const hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x14, 0x18, 0x19, 0x1e, 0x1f, 0x20, 0x27 }; -static hda_nid_t stac927x_pin_nids[14] = { +static const hda_nid_t stac927x_pin_nids[14] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x21, 0x22, 0x23, }; -static hda_nid_t stac9205_pin_nids[12] = { +static const hda_nid_t stac9205_pin_nids[12] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x14, 0x16, 0x17, 0x18, 0x21, 0x22, @@ -841,45 +845,45 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, return 1; } -static struct hda_verb stac9200_core_init[] = { +static const struct hda_verb stac9200_core_init[] = { /* set dac0mux for dac converter */ { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, {} }; -static struct hda_verb stac9200_eapd_init[] = { +static const struct hda_verb stac9200_eapd_init[] = { /* set dac0mux for dac converter */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, {} }; -static struct hda_verb dell_eq_core_init[] = { +static const struct hda_verb dell_eq_core_init[] = { /* set master volume to max value without distortion * and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec}, {} }; -static struct hda_verb stac92hd73xx_core_init[] = { +static const struct hda_verb stac92hd73xx_core_init[] = { /* set master volume and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, {} }; -static struct hda_verb stac92hd83xxx_core_init[] = { +static const struct hda_verb stac92hd83xxx_core_init[] = { /* power state controls amps */ { 0x01, AC_VERB_SET_EAPD, 1 << 2}, {} }; -static struct hda_verb stac92hd71bxx_core_init[] = { +static const struct hda_verb stac92hd71bxx_core_init[] = { /* set master volume and direct control */ { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, {} }; -static struct hda_verb stac92hd71bxx_unmute_core_init[] = { +static const struct hda_verb stac92hd71bxx_unmute_core_init[] = { /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */ { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -887,7 +891,7 @@ static struct hda_verb stac92hd71bxx_unmute_core_init[] = { {} }; -static struct hda_verb stac925x_core_init[] = { +static const struct hda_verb stac925x_core_init[] = { /* set dac0mux for dac converter */ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, /* mute the master volume */ @@ -895,13 +899,13 @@ static struct hda_verb stac925x_core_init[] = { {} }; -static struct hda_verb stac922x_core_init[] = { +static const struct hda_verb stac922x_core_init[] = { /* set master volume and direct control */ { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, {} }; -static struct hda_verb d965_core_init[] = { +static const struct hda_verb d965_core_init[] = { /* set master volume and direct control */ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* unmute node 0x1b */ @@ -911,7 +915,7 @@ static struct hda_verb d965_core_init[] = { {} }; -static struct hda_verb dell_3st_core_init[] = { +static const struct hda_verb dell_3st_core_init[] = { /* don't set delta bit */ {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f}, /* unmute node 0x1b */ @@ -921,7 +925,7 @@ static struct hda_verb dell_3st_core_init[] = { {} }; -static struct hda_verb stac927x_core_init[] = { +static const struct hda_verb stac927x_core_init[] = { /* set master volume and direct control */ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* enable analog pc beep path */ @@ -929,7 +933,7 @@ static struct hda_verb stac927x_core_init[] = { {} }; -static struct hda_verb stac927x_volknob_core_init[] = { +static const struct hda_verb stac927x_volknob_core_init[] = { /* don't set delta bit */ {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f}, /* enable analog pc beep path */ @@ -937,7 +941,7 @@ static struct hda_verb stac927x_volknob_core_init[] = { {} }; -static struct hda_verb stac9205_core_init[] = { +static const struct hda_verb stac9205_core_init[] = { /* set master volume and direct control */ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* enable analog pc beep path */ @@ -977,7 +981,7 @@ static struct hda_verb stac9205_core_init[] = { .private_value = nid, \ } -static struct snd_kcontrol_new stac9200_mixer[] = { +static const struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), @@ -985,38 +989,38 @@ static struct snd_kcontrol_new stac9200_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = { +static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3), {} }; -static struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = { +static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4), {} }; -static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = { +static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5), {} }; -static struct snd_kcontrol_new stac92hd71bxx_loopback[] = { +static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2) }; -static struct snd_kcontrol_new stac925x_mixer[] = { +static const struct snd_kcontrol_new stac925x_mixer[] = { HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT), { } /* end */ }; -static struct snd_kcontrol_new stac9205_loopback[] = { +static const struct snd_kcontrol_new stac9205_loopback[] = { STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1), {} }; -static struct snd_kcontrol_new stac927x_loopback[] = { +static const struct snd_kcontrol_new stac927x_loopback[] = { STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1), {} }; @@ -1182,16 +1186,16 @@ static int stac92xx_build_controls(struct hda_codec *codec) return 0; } -static unsigned int ref9200_pin_configs[8] = { +static const unsigned int ref9200_pin_configs[8] = { 0x01c47010, 0x01447010, 0x0221401f, 0x01114010, 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; -static unsigned int gateway9200_m4_pin_configs[8] = { +static const unsigned int gateway9200_m4_pin_configs[8] = { 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, }; -static unsigned int gateway9200_m4_2_pin_configs[8] = { +static const unsigned int gateway9200_m4_2_pin_configs[8] = { 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, }; @@ -1202,7 +1206,7 @@ static unsigned int gateway9200_m4_2_pin_configs[8] = { 102801DE 102801E8 */ -static unsigned int dell9200_d21_pin_configs[8] = { +static const unsigned int dell9200_d21_pin_configs[8] = { 0x400001f0, 0x400001f1, 0x02214030, 0x01014010, 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; @@ -1212,7 +1216,7 @@ static unsigned int dell9200_d21_pin_configs[8] = { 102801C0 102801C1 */ -static unsigned int dell9200_d22_pin_configs[8] = { +static const unsigned int dell9200_d22_pin_configs[8] = { 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, 0x01813020, 0x02a19021, 0x90100140, 0x400001f2, }; @@ -1226,7 +1230,7 @@ static unsigned int dell9200_d22_pin_configs[8] = { 102801DA 102801E3 */ -static unsigned int dell9200_d23_pin_configs[8] = { +static const unsigned int dell9200_d23_pin_configs[8] = { 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, 0x01813020, 0x01a19021, 0x90100140, 0x400001f2, }; @@ -1237,7 +1241,7 @@ static unsigned int dell9200_d23_pin_configs[8] = { 102801B5 (Dell Inspiron 630m) 102801D8 (Dell Inspiron 640m) */ -static unsigned int dell9200_m21_pin_configs[8] = { +static const unsigned int dell9200_m21_pin_configs[8] = { 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310, 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd, }; @@ -1250,7 +1254,7 @@ static unsigned int dell9200_m21_pin_configs[8] = { 102801D4 102801D6 */ -static unsigned int dell9200_m22_pin_configs[8] = { +static const unsigned int dell9200_m22_pin_configs[8] = { 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc, }; @@ -1260,7 +1264,7 @@ static unsigned int dell9200_m22_pin_configs[8] = { 102801CE (Dell XPS M1710) 102801CF (Dell Precision M90) */ -static unsigned int dell9200_m23_pin_configs[8] = { +static const unsigned int dell9200_m23_pin_configs[8] = { 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310, 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc, }; @@ -1272,7 +1276,7 @@ static unsigned int dell9200_m23_pin_configs[8] = { 102801CB (Dell Latitude 120L) 102801D3 */ -static unsigned int dell9200_m24_pin_configs[8] = { +static const unsigned int dell9200_m24_pin_configs[8] = { 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, }; @@ -1283,7 +1287,7 @@ static unsigned int dell9200_m24_pin_configs[8] = { 102801EE 102801EF */ -static unsigned int dell9200_m25_pin_configs[8] = { +static const unsigned int dell9200_m25_pin_configs[8] = { 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd, }; @@ -1293,7 +1297,7 @@ static unsigned int dell9200_m25_pin_configs[8] = { 102801F5 (Dell Inspiron 1501) 102801F6 */ -static unsigned int dell9200_m26_pin_configs[8] = { +static const unsigned int dell9200_m26_pin_configs[8] = { 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe, }; @@ -1302,18 +1306,18 @@ static unsigned int dell9200_m26_pin_configs[8] = { STAC 9200-32 102801CD (Dell Inspiron E1705/9400) */ -static unsigned int dell9200_m27_pin_configs[8] = { +static const unsigned int dell9200_m27_pin_configs[8] = { 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc, }; -static unsigned int oqo9200_pin_configs[8] = { +static const unsigned int oqo9200_pin_configs[8] = { 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210, 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3, }; -static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { +static const unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { [STAC_REF] = ref9200_pin_configs, [STAC_9200_OQO] = oqo9200_pin_configs, [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, @@ -1350,7 +1354,7 @@ static const char * const stac9200_models[STAC_9200_MODELS] = { [STAC_9200_PANASONIC] = "panasonic", }; -static struct snd_pci_quirk stac9200_cfg_tbl[] = { +static const struct snd_pci_quirk stac9200_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), @@ -1426,47 +1430,47 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref925x_pin_configs[8] = { +static const unsigned int ref925x_pin_configs[8] = { 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, 0x90a70320, 0x02214210, 0x01019020, 0x9033032e, }; -static unsigned int stac925xM1_pin_configs[8] = { +static const unsigned int stac925xM1_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; -static unsigned int stac925xM1_2_pin_configs[8] = { +static const unsigned int stac925xM1_2_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; -static unsigned int stac925xM2_pin_configs[8] = { +static const unsigned int stac925xM2_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; -static unsigned int stac925xM2_2_pin_configs[8] = { +static const unsigned int stac925xM2_2_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; -static unsigned int stac925xM3_pin_configs[8] = { +static const unsigned int stac925xM3_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3, }; -static unsigned int stac925xM5_pin_configs[8] = { +static const unsigned int stac925xM5_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; -static unsigned int stac925xM6_pin_configs[8] = { +static const unsigned int stac925xM6_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x90330320, }; -static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { +static const unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { [STAC_REF] = ref925x_pin_configs, [STAC_M1] = stac925xM1_pin_configs, [STAC_M1_2] = stac925xM1_2_pin_configs, @@ -1489,7 +1493,7 @@ static const char * const stac925x_models[STAC_925x_MODELS] = { [STAC_M6] = "m6", }; -static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { +static const struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2), SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5), SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1), @@ -1503,7 +1507,7 @@ static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { {} /* terminator */ }; -static struct snd_pci_quirk stac925x_cfg_tbl[] = { +static const struct snd_pci_quirk stac925x_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), @@ -1515,33 +1519,33 @@ static struct snd_pci_quirk stac925x_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref92hd73xx_pin_configs[13] = { +static const unsigned int ref92hd73xx_pin_configs[13] = { 0x02214030, 0x02a19040, 0x01a19020, 0x02214030, 0x0181302e, 0x01014010, 0x01014020, 0x01014030, 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050, 0x01452050, }; -static unsigned int dell_m6_pin_configs[13] = { +static const unsigned int dell_m6_pin_configs[13] = { 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110, 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0, }; -static unsigned int alienware_m17x_pin_configs[13] = { +static const unsigned int alienware_m17x_pin_configs[13] = { 0x0321101f, 0x0321101f, 0x03a11020, 0x03014020, 0x90170110, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0, 0x904601b0, }; -static unsigned int intel_dg45id_pin_configs[13] = { +static const unsigned int intel_dg45id_pin_configs[13] = { 0x02214230, 0x02A19240, 0x01013214, 0x01014210, 0x01A19250, 0x01011212, 0x01016211 }; -static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { +static const unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs, [STAC_DELL_M6_AMIC] = dell_m6_pin_configs, [STAC_DELL_M6_DMIC] = dell_m6_pin_configs, @@ -1563,7 +1567,7 @@ static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = { [STAC_ALIENWARE_M17X] = "alienware", }; -static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD73XX_REF), @@ -1600,11 +1604,11 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe, "Dell Studio XPS 1645", STAC_DELL_M6_BOTH), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413, - "Dell Studio 1558", STAC_DELL_M6_BOTH), + "Dell Studio 1558", STAC_DELL_M6_DMIC), {} /* terminator */ }; -static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1, "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a, @@ -1612,25 +1616,25 @@ static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref92hd83xxx_pin_configs[10] = { +static const unsigned int ref92hd83xxx_pin_configs[10] = { 0x02214030, 0x02211010, 0x02a19020, 0x02170130, 0x01014050, 0x01819040, 0x01014020, 0x90a3014e, 0x01451160, 0x98560170, }; -static unsigned int dell_s14_pin_configs[10] = { +static const unsigned int dell_s14_pin_configs[10] = { 0x0221403f, 0x0221101f, 0x02a19020, 0x90170110, 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a60160, 0x40f000f0, 0x40f000f0, }; -static unsigned int hp_dv7_4000_pin_configs[10] = { +static const unsigned int hp_dv7_4000_pin_configs[10] = { 0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110, 0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140, 0x40f000f0, 0x40f000f0, }; -static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { +static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, [STAC_DELL_S14] = dell_s14_pin_configs, @@ -1646,7 +1650,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_HP_DV7_4000] = "hp-dv7-4000", }; -static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD83XXX_REF), @@ -1659,35 +1663,35 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = { +static const unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = { 0x02214030, 0x02a19040, 0x01a19020, 0x01014010, 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0, 0x90a000f0, 0x01452050, 0x01452050, 0x00000000, 0x00000000 }; -static unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = { +static const unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = { 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110, 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0, 0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000, 0x00000000 }; -static unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = { +static const unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = { 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000, 0x00000000 }; -static unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = { +static const unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = { 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0, 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000, 0x00000000 }; -static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { +static const unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs, [STAC_DELL_M4_1] = dell_m4_1_pin_configs, [STAC_DELL_M4_2] = dell_m4_2_pin_configs, @@ -1712,7 +1716,7 @@ static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr", }; -static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD71BXX_REF), @@ -1769,7 +1773,7 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref922x_pin_configs[10] = { +static const unsigned int ref922x_pin_configs[10] = { 0x01014010, 0x01016011, 0x01012012, 0x0221401f, 0x01813122, 0x01011014, 0x01441030, 0x01c41030, 0x40000100, 0x40000100, @@ -1783,7 +1787,7 @@ static unsigned int ref922x_pin_configs[10] = { 102801D1 102801D2 */ -static unsigned int dell_922x_d81_pin_configs[10] = { +static const unsigned int dell_922x_d81_pin_configs[10] = { 0x02214030, 0x01a19021, 0x01111012, 0x01114010, 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1, 0x01813122, 0x400001f2, @@ -1794,7 +1798,7 @@ static unsigned int dell_922x_d81_pin_configs[10] = { 102801AC 102801D0 */ -static unsigned int dell_922x_d82_pin_configs[10] = { +static const unsigned int dell_922x_d82_pin_configs[10] = { 0x02214030, 0x01a19021, 0x01111012, 0x01114010, 0x02a19020, 0x01117011, 0x01451140, 0x400001f0, 0x01813122, 0x400001f1, @@ -1804,7 +1808,7 @@ static unsigned int dell_922x_d82_pin_configs[10] = { STAC 922X pin configs for 102801BF */ -static unsigned int dell_922x_m81_pin_configs[10] = { +static const unsigned int dell_922x_m81_pin_configs[10] = { 0x0321101f, 0x01112024, 0x01111222, 0x91174220, 0x03a11050, 0x01116221, 0x90a70330, 0x01452340, 0x40C003f1, 0x405003f0, @@ -1814,61 +1818,61 @@ static unsigned int dell_922x_m81_pin_configs[10] = { STAC 9221 A1 pin configs for 102801D7 (Dell XPS M1210) */ -static unsigned int dell_922x_m82_pin_configs[10] = { +static const unsigned int dell_922x_m82_pin_configs[10] = { 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310, 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2, 0x508003f3, 0x405003f4, }; -static unsigned int d945gtp3_pin_configs[10] = { +static const unsigned int d945gtp3_pin_configs[10] = { 0x0221401f, 0x01a19022, 0x01813021, 0x01014010, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x02a19120, 0x40000100, }; -static unsigned int d945gtp5_pin_configs[10] = { +static const unsigned int d945gtp5_pin_configs[10] = { 0x0221401f, 0x01011012, 0x01813024, 0x01014010, 0x01a19021, 0x01016011, 0x01452130, 0x40000100, 0x02a19320, 0x40000100, }; -static unsigned int intel_mac_v1_pin_configs[10] = { +static const unsigned int intel_mac_v1_pin_configs[10] = { 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd, 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240, 0x400000fc, 0x400000fb, }; -static unsigned int intel_mac_v2_pin_configs[10] = { +static const unsigned int intel_mac_v2_pin_configs[10] = { 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd, 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa, 0x400000fc, 0x400000fb, }; -static unsigned int intel_mac_v3_pin_configs[10] = { +static const unsigned int intel_mac_v3_pin_configs[10] = { 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd, 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240, 0x400000fc, 0x400000fb, }; -static unsigned int intel_mac_v4_pin_configs[10] = { +static const unsigned int intel_mac_v4_pin_configs[10] = { 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f, 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240, 0x400000fc, 0x400000fb, }; -static unsigned int intel_mac_v5_pin_configs[10] = { +static const unsigned int intel_mac_v5_pin_configs[10] = { 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f, 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240, 0x400000fc, 0x400000fb, }; -static unsigned int ecs202_pin_configs[10] = { +static const unsigned int ecs202_pin_configs[10] = { 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010, 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1, 0x9037012e, 0x40e000f2, }; -static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { +static const unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { [STAC_D945_REF] = ref922x_pin_configs, [STAC_D945GTP3] = d945gtp3_pin_configs, [STAC_D945GTP5] = d945gtp5_pin_configs, @@ -1917,7 +1921,7 @@ static const char * const stac922x_models[STAC_922X_MODELS] = { [STAC_922X_DELL_M82] = "dell-m82", }; -static struct snd_pci_quirk stac922x_cfg_tbl[] = { +static const struct snd_pci_quirk stac922x_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D945_REF), @@ -2008,42 +2012,42 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref927x_pin_configs[14] = { +static const unsigned int ref927x_pin_configs[14] = { 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, 0x01a19040, 0x01011012, 0x01016011, 0x0101201f, 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070, 0x01c42190, 0x40000100, }; -static unsigned int d965_3st_pin_configs[14] = { +static const unsigned int d965_3st_pin_configs[14] = { 0x0221401f, 0x02a19120, 0x40000100, 0x01014011, 0x01a19021, 0x01813024, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x40000100 }; -static unsigned int d965_5st_pin_configs[14] = { +static const unsigned int d965_5st_pin_configs[14] = { 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, 0x01a19040, 0x01011012, 0x01016011, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x01442070, 0x40000100, 0x40000100 }; -static unsigned int d965_5st_no_fp_pin_configs[14] = { +static const unsigned int d965_5st_no_fp_pin_configs[14] = { 0x40000100, 0x40000100, 0x0181304e, 0x01014010, 0x01a19040, 0x01011012, 0x01016011, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x01442070, 0x40000100, 0x40000100 }; -static unsigned int dell_3st_pin_configs[14] = { +static const unsigned int dell_3st_pin_configs[14] = { 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, 0x01111212, 0x01116211, 0x01813050, 0x01112214, 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb, 0x40c003fc, 0x40000100 }; -static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { +static const unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { [STAC_D965_REF_NO_JD] = ref927x_pin_configs, [STAC_D965_REF] = ref927x_pin_configs, [STAC_D965_3ST] = d965_3st_pin_configs, @@ -2066,7 +2070,7 @@ static const char * const stac927x_models[STAC_927X_MODELS] = { [STAC_927X_VOLKNOB] = "volknob", }; -static struct snd_pci_quirk stac927x_cfg_tbl[] = { +static const struct snd_pci_quirk stac927x_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D965_REF), @@ -2104,7 +2108,7 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref9205_pin_configs[12] = { +static const unsigned int ref9205_pin_configs[12] = { 0x40000100, 0x40000100, 0x01016011, 0x01014010, 0x01813122, 0x01a19021, 0x01019020, 0x40000100, 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 @@ -2121,7 +2125,7 @@ static unsigned int ref9205_pin_configs[12] = { 10280228 (Dell Vostro 1500) 10280229 (Dell Vostro 1700) */ -static unsigned int dell_9205_m42_pin_configs[12] = { +static const unsigned int dell_9205_m42_pin_configs[12] = { 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9, 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE, @@ -2137,19 +2141,19 @@ static unsigned int dell_9205_m42_pin_configs[12] = { 10280200 10280201 */ -static unsigned int dell_9205_m43_pin_configs[12] = { +static const unsigned int dell_9205_m43_pin_configs[12] = { 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310, 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9, 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8, }; -static unsigned int dell_9205_m44_pin_configs[12] = { +static const unsigned int dell_9205_m44_pin_configs[12] = { 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310, 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9, 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe, }; -static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { +static const unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { [STAC_9205_REF] = ref9205_pin_configs, [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs, [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs, @@ -2166,7 +2170,7 @@ static const char * const stac9205_models[STAC_9205_MODELS] = { [STAC_9205_EAPD] = "eapd", }; -static struct snd_pci_quirk stac9205_cfg_tbl[] = { +static const struct snd_pci_quirk stac9205_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_9205_REF), @@ -2214,7 +2218,7 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { }; static void stac92xx_set_config_regs(struct hda_codec *codec, - unsigned int *pincfgs) + const unsigned int *pincfgs) { int i; struct sigmatel_spec *spec = codec->spec; @@ -2334,7 +2338,7 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream stac92xx_pcm_digital_playback = { +static const struct hda_pcm_stream stac92xx_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -2347,14 +2351,14 @@ static struct hda_pcm_stream stac92xx_pcm_digital_playback = { }, }; -static struct hda_pcm_stream stac92xx_pcm_digital_capture = { +static const struct hda_pcm_stream stac92xx_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, /* NID is set in stac92xx_build_pcms */ }; -static struct hda_pcm_stream stac92xx_pcm_analog_playback = { +static const struct hda_pcm_stream stac92xx_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -2366,7 +2370,7 @@ static struct hda_pcm_stream stac92xx_pcm_analog_playback = { }, }; -static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { +static const struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -2378,7 +2382,7 @@ static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { }, }; -static struct hda_pcm_stream stac92xx_pcm_analog_capture = { +static const struct hda_pcm_stream stac92xx_pcm_analog_capture = { .channels_min = 2, .channels_max = 2, /* NID + .substreams is set in stac92xx_build_pcms */ @@ -2487,7 +2491,7 @@ static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { int i; - static char *texts[] = { + static const char * const texts[] = { "Mic In", "Line In", "Line Out" }; @@ -2556,7 +2560,7 @@ static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2]; + char *texts[2]; struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; @@ -2687,7 +2691,7 @@ enum { STAC_CTL_WIDGET_DC_BIAS }; -static struct snd_kcontrol_new stac92xx_control_templates[] = { +static const struct snd_kcontrol_new stac92xx_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0), @@ -2701,7 +2705,7 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = { /* add dynamic controls */ static struct snd_kcontrol_new * stac_control_new(struct sigmatel_spec *spec, - struct snd_kcontrol_new *ktemp, + const struct snd_kcontrol_new *ktemp, const char *name, unsigned int subdev) { @@ -2724,7 +2728,7 @@ stac_control_new(struct sigmatel_spec *spec, } static int stac92xx_add_control_temp(struct sigmatel_spec *spec, - struct snd_kcontrol_new *ktemp, + const struct snd_kcontrol_new *ktemp, int idx, const char *name, unsigned long val) { @@ -2754,7 +2758,7 @@ static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type, return stac92xx_add_control_idx(spec, type, 0, name, val); } -static struct snd_kcontrol_new stac_input_src_temp = { +static const struct snd_kcontrol_new stac_input_src_temp = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Source", .info = stac92xx_mux_enum_info, @@ -3072,7 +3076,8 @@ static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); return 1; } else { - spec->multiout.dac_nids[spec->multiout.num_dacs] = nid; + snd_BUG_ON(spec->multiout.dac_nids != spec->dac_nids); + spec->dac_nids[spec->multiout.num_dacs] = nid; spec->multiout.num_dacs++; } return 0; @@ -3109,8 +3114,7 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) { if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) { - wid_caps = get_wcaps(codec, pins[i]); - if (wid_caps & AC_WCAP_UNSOL_CAP) + if (is_jack_detectable(codec, pins[i])) spec->hp_detect = 1; } nid = dac_nids[i]; @@ -3309,7 +3313,7 @@ static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol, return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]); } -static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { +static const struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = stac92xx_dig_beep_switch_info, .get = stac92xx_dig_beep_switch_get, @@ -3516,14 +3520,18 @@ static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock) { unsigned int cfg; + unsigned int type; if (!nid) return 0; cfg = snd_hda_codec_get_pincfg(codec, nid); + type = get_defcfg_device(cfg); switch (snd_hda_get_input_pin_attr(cfg)) { case INPUT_PIN_ATTR_INT: if (*fixed) return 1; /* already occupied */ + if (type != AC_JACK_MIC_IN) + return 1; /* invalid type */ *fixed = nid; break; case INPUT_PIN_ATTR_UNUSED: @@ -3531,11 +3539,15 @@ static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid, case INPUT_PIN_ATTR_DOCK: if (*dock) return 1; /* already occupied */ + if (type != AC_JACK_MIC_IN && type != AC_JACK_LINE_IN) + return 1; /* invalid type */ *dock = nid; break; default: if (*ext) return 1; /* already occupied */ + if (type != AC_JACK_MIC_IN) + return 1; /* invalid type */ *ext = nid; break; } @@ -3591,10 +3603,6 @@ static int stac_check_auto_mic(struct hda_codec *codec) hda_nid_t fixed, ext, dock; int i; - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN) - return 0; /* must be exclusively mics */ - } fixed = ext = dock = 0; for (i = 0; i < cfg->num_inputs; i++) if (check_mic_pin(codec, cfg->inputs[i].pin, @@ -3606,7 +3614,7 @@ static int stac_check_auto_mic(struct hda_codec *codec) return 0; if (!fixed || (!ext && !dock)) return 0; /* no input to switch */ - if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP)) + if (!is_jack_detectable(codec, ext)) return 0; /* no unsol support */ if (set_mic_route(codec, &spec->ext_mic, ext) || set_mic_route(codec, &spec->int_mic, fixed) || @@ -3921,13 +3929,11 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, { struct sigmatel_spec *spec = codec->spec; hda_nid_t pin = cfg->hp_pins[0]; - unsigned int wid_caps; if (! pin) return 0; - wid_caps = get_wcaps(codec, pin); - if (wid_caps & AC_WCAP_UNSOL_CAP) + if (is_jack_detectable(codec, pin)) spec->hp_detect = 1; return 0; @@ -4138,7 +4144,7 @@ static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, struct sigmatel_event *event; int tag; - if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) + if (!is_jack_detectable(codec, nid)) return 0; event = stac_get_event(codec, nid); if (event) { @@ -4171,7 +4177,7 @@ static void stac92xx_power_down(struct hda_codec *codec) struct sigmatel_spec *spec = codec->spec; /* power down inactive DACs */ - hda_nid_t *dac; + const hda_nid_t *dac; for (dac = spec->dac_list; *dac; dac++) if (!check_all_dac_nids(spec, *dac)) snd_hda_codec_write(codec, *dac, 0, @@ -4644,7 +4650,7 @@ static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) } static int stac92xx_connected_ports(struct hda_codec *codec, - hda_nid_t *nids, int num_nids) + const hda_nid_t *nids, int num_nids) { struct sigmatel_spec *spec = codec->spec; int idx, num; @@ -4968,7 +4974,7 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) } #endif -static struct hda_codec_ops stac92xx_patch_ops = { +static const struct hda_codec_ops stac92xx_patch_ops = { .build_controls = stac92xx_build_controls, .build_pcms = stac92xx_build_pcms, .init = stac92xx_init, @@ -5588,7 +5594,7 @@ static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { +static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = stac_hp_bass_gpio_info, .get = stac_hp_bass_gpio_get, @@ -5612,7 +5618,7 @@ static int stac_add_hp_bass_switch(struct hda_codec *codec) static int patch_stac92hd71bxx(struct hda_codec *codec) { struct sigmatel_spec *spec; - struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; + const struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; unsigned int pin_cfg; int err = 0; @@ -5705,9 +5711,9 @@ again: unmute_init++; snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0); snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3); - stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0; + spec->dmic_nids = stac92hd71bxx_dmic_5port_nids; spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd71bxx_dmic_nids, + stac92hd71bxx_dmic_5port_nids, STAC92HD71BXX_NUM_DMICS - 1); break; case 0x111d7603: /* 6 Port with Analog Mixer */ @@ -5729,15 +5735,6 @@ again: if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) snd_hda_sequence_write_cache(codec, unmute_init); - /* Some HP machines seem to have unstable codec communications - * especially with ATI fglrx driver. For recovering from the - * CORB/RIRB stall, allow the BUS reset and keep always sync - */ - if (spec->board_config == STAC_HP_DV5) { - codec->bus->sync_write = 1; - codec->bus->allow_bus_reset = 1; - } - spec->aloopback_ctl = stac92hd71bxx_loopback; spec->aloopback_mask = 0x50; spec->aloopback_shift = 0; @@ -6223,31 +6220,31 @@ static int patch_stac9205(struct hda_codec *codec) * STAC9872 hack */ -static struct hda_verb stac9872_core_init[] = { +static const struct hda_verb stac9872_core_init[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */ {} }; -static hda_nid_t stac9872_pin_nids[] = { +static const hda_nid_t stac9872_pin_nids[] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x13, 0x14, }; -static hda_nid_t stac9872_adc_nids[] = { +static const hda_nid_t stac9872_adc_nids[] = { 0x8 /*,0x6*/ }; -static hda_nid_t stac9872_mux_nids[] = { +static const hda_nid_t stac9872_mux_nids[] = { 0x15 }; -static unsigned long stac9872_capvols[] = { +static const unsigned long stac9872_capvols[] = { HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), }; #define stac9872_capsws stac9872_capvols -static unsigned int stac9872_vaio_pin_configs[9] = { +static const unsigned int stac9872_vaio_pin_configs[9] = { 0x03211020, 0x411111f0, 0x411111f0, 0x03a15030, 0x411111f0, 0x90170110, 0x411111f0, 0x411111f0, 0x90a7013e @@ -6258,11 +6255,11 @@ static const char * const stac9872_models[STAC_9872_MODELS] = { [STAC_9872_VAIO] = "vaio", }; -static unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = { +static const unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = { [STAC_9872_VAIO] = stac9872_vaio_pin_configs, }; -static struct snd_pci_quirk stac9872_cfg_tbl[] = { +static const struct snd_pci_quirk stac9872_cfg_tbl[] = { SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0, "Sony VAIO F/S", STAC_9872_VAIO), {} /* terminator */ @@ -6316,7 +6313,7 @@ static int patch_stac9872(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_sigmatel[] = { +static const struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 }, { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x }, { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x }, diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 1371b57c11e..605c99e1e52 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -98,24 +98,30 @@ enum VIA_HDA_CODEC { VT1716S, VT2002P, VT1812, + VT1802, CODEC_TYPES, }; +#define VT2002P_COMPATIBLE(spec) \ + ((spec)->codec_type == VT2002P ||\ + (spec)->codec_type == VT1812 ||\ + (spec)->codec_type == VT1802) + struct via_spec { /* codec parameterization */ - struct snd_kcontrol_new *mixers[6]; + const struct snd_kcontrol_new *mixers[6]; unsigned int num_mixers; - struct hda_verb *init_verbs[5]; + const struct hda_verb *init_verbs[5]; unsigned int num_iverbs; char *stream_name_analog; - struct hda_pcm_stream *stream_analog_playback; - struct hda_pcm_stream *stream_analog_capture; + const struct hda_pcm_stream *stream_analog_playback; + const struct hda_pcm_stream *stream_analog_capture; char *stream_name_digital; - struct hda_pcm_stream *stream_digital_playback; - struct hda_pcm_stream *stream_digital_capture; + const struct hda_pcm_stream *stream_digital_playback; + const struct hda_pcm_stream *stream_digital_capture; /* playback */ struct hda_multi_out multiout; @@ -123,7 +129,7 @@ struct via_spec { /* capture */ unsigned int num_adc_nids; - hda_nid_t *adc_nids; + const hda_nid_t *adc_nids; hda_nid_t mux_nids[3]; hda_nid_t dig_in_nid; hda_nid_t dig_in_pin; @@ -154,6 +160,9 @@ struct via_spec { struct delayed_work vt1708_hp_work; int vt1708_jack_detectect; int vt1708_hp_present; + + void (*set_widgets_power_state)(struct hda_codec *codec); + #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; #endif @@ -218,17 +227,19 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) codec_type = VT1812; else if (dev_id == 0x0440) codec_type = VT1708S; + else if ((dev_id & 0xfff) == 0x446) + codec_type = VT1802; else codec_type = UNKNOWN; return codec_type; }; +#define VIA_JACK_EVENT 0x20 #define VIA_HP_EVENT 0x01 #define VIA_GPIO_EVENT 0x02 -#define VIA_JACK_EVENT 0x04 -#define VIA_MONO_EVENT 0x08 -#define VIA_SPEAKER_EVENT 0x10 -#define VIA_BIND_HP_EVENT 0x20 +#define VIA_MONO_EVENT 0x03 +#define VIA_SPEAKER_EVENT 0x04 +#define VIA_BIND_HP_EVENT 0x05 enum { VIA_CTL_WIDGET_VOL, @@ -245,7 +256,6 @@ enum { }; static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); -static void set_jack_power_state(struct hda_codec *codec); static int is_aa_path_mute(struct hda_codec *codec); static void vt1708_start_hp_work(struct via_spec *spec) @@ -271,6 +281,12 @@ static void vt1708_stop_hp_work(struct via_spec *spec) cancel_delayed_work_sync(&spec->vt1708_hp_work); } +static void set_widgets_power_state(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + if (spec->set_widgets_power_state) + spec->set_widgets_power_state(codec); +} static int analog_input_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -278,7 +294,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - set_jack_power_state(codec); + set_widgets_power_state(codec); analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { if (is_aa_path_mute(codec)) @@ -394,54 +410,54 @@ static int bind_pin_switch_put(struct snd_kcontrol *kcontrol, .put = bind_pin_switch_put, \ .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } -static struct snd_kcontrol_new via_control_templates[] = { +static const struct snd_kcontrol_new via_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), ANALOG_INPUT_MUTE, BIND_PIN_MUTE, }; -static hda_nid_t vt1708_adc_nids[2] = { +static const hda_nid_t vt1708_adc_nids[2] = { /* ADC1-2 */ 0x15, 0x27 }; -static hda_nid_t vt1709_adc_nids[3] = { +static const hda_nid_t vt1709_adc_nids[3] = { /* ADC1-2 */ 0x14, 0x15, 0x16 }; -static hda_nid_t vt1708B_adc_nids[2] = { +static const hda_nid_t vt1708B_adc_nids[2] = { /* ADC1-2 */ 0x13, 0x14 }; -static hda_nid_t vt1708S_adc_nids[2] = { +static const hda_nid_t vt1708S_adc_nids[2] = { /* ADC1-2 */ 0x13, 0x14 }; -static hda_nid_t vt1702_adc_nids[3] = { +static const hda_nid_t vt1702_adc_nids[3] = { /* ADC1-2 */ 0x12, 0x20, 0x1F }; -static hda_nid_t vt1718S_adc_nids[2] = { +static const hda_nid_t vt1718S_adc_nids[2] = { /* ADC1-2 */ 0x10, 0x11 }; -static hda_nid_t vt1716S_adc_nids[2] = { +static const hda_nid_t vt1716S_adc_nids[2] = { /* ADC1-2 */ 0x13, 0x14 }; -static hda_nid_t vt2002P_adc_nids[2] = { +static const hda_nid_t vt2002P_adc_nids[2] = { /* ADC1-2 */ 0x10, 0x11 }; -static hda_nid_t vt1812_adc_nids[2] = { +static const hda_nid_t vt1812_adc_nids[2] = { /* ADC1-2 */ 0x10, 0x11 }; @@ -471,7 +487,7 @@ static int __via_add_control(struct via_spec *spec, int type, const char *name, __via_add_control(spec, type, name, 0, val) static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec, - struct snd_kcontrol_new *tmpl) + const struct snd_kcontrol_new *tmpl) { struct snd_kcontrol_new *knew; @@ -602,482 +618,6 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); } -static void set_jack_power_state(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int imux_is_smixer; - unsigned int parm; - - if (spec->codec_type == VT1702) { - imux_is_smixer = snd_hda_codec_read( - codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; - /* inputs */ - /* PW 1/2/5 (14h/15h/18h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x14, &parm); - set_pin_power_state(codec, 0x15, &parm); - set_pin_power_state(codec, 0x18, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */ - /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */ - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW 3/4 (16h/17h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x16, &parm); - set_pin_power_state(codec, 0x17, &parm); - /* MW0 (1ah), AOW 0/1 (10h/1dh) */ - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, - parm); - } else if (spec->codec_type == VT1708B_8CH - || spec->codec_type == VT1708B_4CH - || spec->codec_type == VT1708S) { - /* SW0 (17h) = stereo mixer */ - int is_8ch = spec->codec_type != VT1708B_4CH; - imux_is_smixer = snd_hda_codec_read( - codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) - == ((spec->codec_type == VT1708S) ? 5 : 0); - /* inputs */ - /* PW 1/2/5 (1ah/1bh/1eh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1a, &parm); - set_pin_power_state(codec, 0x1b, &parm); - set_pin_power_state(codec, 0x1e, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* SW0 (17h), AIW 0/1 (13h/14h) */ - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW0 (19h), SW1 (18h), AOW1 (11h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x19, &parm); - if (spec->smart51_enabled) - parm = AC_PWRST_D0; - snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW6 (22h), SW2 (26h), AOW2 (24h) */ - if (is_8ch) { - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x22, &parm); - if (spec->smart51_enabled) - parm = AC_PWRST_D0; - snd_hda_codec_write(codec, 0x26, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x24, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* PW 3/4/7 (1ch/1dh/23h) */ - parm = AC_PWRST_D3; - /* force to D0 for internal Speaker */ - set_pin_power_state(codec, 0x1c, &parm); - set_pin_power_state(codec, 0x1d, &parm); - if (is_8ch) - set_pin_power_state(codec, 0x23, &parm); - /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - if (is_8ch) { - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x27, 0, - AC_VERB_SET_POWER_STATE, parm); - } - } else if (spec->codec_type == VT1718S) { - /* MUX6 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x27, &parm); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW2 (26h), AOW2 (ah) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x26, &parm); - snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW0/1 (24h/25h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - set_pin_power_state(codec, 0x25, &parm); - if (!spec->hp_independent_mode) /* check for redirected HP */ - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, - parm); - /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ - snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - if (spec->hp_independent_mode) { - /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x1b, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0xc, 0, - AC_VERB_SET_POWER_STATE, parm); - } - } else if (spec->codec_type == VT1716S) { - unsigned int mono_out, present; - /* SW0 (17h) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 1/2/5 (1ah/1bh/1eh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1a, &parm); - set_pin_power_state(codec, 0x1b, &parm); - set_pin_power_state(codec, 0x1e, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* SW0 (17h), AIW0(13h) */ - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1e, &parm); - /* PW11 (22h) */ - if (spec->dmic_enabled) - set_pin_power_state(codec, 0x22, &parm); - else - snd_hda_codec_write( - codec, 0x22, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - - /* SW2(26h), AIW1(14h) */ - snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW0 (19h), SW1 (18h), AOW1 (11h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x19, &parm); - /* Smart 5.1 PW2(1bh) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1b, &parm); - snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW7 (23h), SW3 (27h), AOW3 (25h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x23, &parm); - /* Smart 5.1 PW1(1ah) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1a, &parm); - snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* Smart 5.1 PW5(1eh) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1e, &parm); - snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* Mono out */ - /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ - present = snd_hda_jack_detect(codec, 0x1c); - if (present) - mono_out = 0; - else { - present = snd_hda_jack_detect(codec, 0x1d); - if (!spec->hp_independent_mode && present) - mono_out = 0; - else - mono_out = 1; - } - parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; - snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW 3/4 (1ch/1dh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1c, &parm); - set_pin_power_state(codec, 0x1d, &parm); - /* HP Independent Mode, power on AOW3 */ - if (spec->hp_independent_mode) - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* force to D0 for internal Speaker */ - /* MW0 (16h), AOW0 (10h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - mono_out ? AC_PWRST_D0 : parm); - } else if (spec->codec_type == VT2002P) { - unsigned int present; - /* MUX9 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x10, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* outputs */ - /* AOW0 (8h)*/ - snd_hda_codec_write(codec, 0x8, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - - /* PW4 (26h), MW4 (1ch), MUX4(37h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x26, &parm); - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x37, - 0, AC_VERB_SET_POWER_STATE, parm); - - /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x25, &parm); - snd_hda_codec_write(codec, 0x19, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x35, 0, - AC_VERB_SET_POWER_STATE, parm); - if (spec->hp_independent_mode) { - snd_hda_codec_write(codec, 0x9, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* Class-D */ - /* PW0 (24h), MW0(18h), MUX0(34h) */ - present = snd_hda_jack_detect(codec, 0x25); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - if (present) { - snd_hda_codec_write( - codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write( - codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else { - snd_hda_codec_write( - codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write( - codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - } - - /* Mono Out */ - /* PW15 (31h), MW8(17h), MUX8(3bh) */ - present = snd_hda_jack_detect(codec, 0x26); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x31, &parm); - if (present) { - snd_hda_codec_write( - codec, 0x17, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write( - codec, 0x3b, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else { - snd_hda_codec_write( - codec, 0x17, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write( - codec, 0x3b, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - } - - /* MW9 (21h) */ - if (imux_is_smixer || !is_aa_path_mute(codec)) - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - else - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else if (spec->codec_type == VT1812) { - unsigned int present; - /* MUX10 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x10, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* outputs */ - /* AOW0 (8h)*/ - snd_hda_codec_write(codec, 0x8, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - - /* PW4 (28h), MW4 (18h), MUX4(38h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x38, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x25, &parm); - snd_hda_codec_write(codec, 0x15, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x35, 0, - AC_VERB_SET_POWER_STATE, parm); - if (spec->hp_independent_mode) { - snd_hda_codec_write(codec, 0x9, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* Internal Speaker */ - /* PW0 (24h), MW0(14h), MUX0(34h) */ - present = snd_hda_jack_detect(codec, 0x25); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - if (present) { - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - } else { - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - } - /* Mono Out */ - /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */ - present = snd_hda_jack_detect(codec, 0x28); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x31, &parm); - if (present) { - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x3c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x3e, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - } else { - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x3c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x3e, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - } - - /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x33, &parm); - snd_hda_codec_write(codec, 0x1d, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x3d, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* MW9 (21h) */ - if (imux_is_smixer || !is_aa_path_mute(codec)) - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - else - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } -} - /* * input MUX handling */ @@ -1120,7 +660,7 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); /* update jack power state */ - set_jack_power_state(codec); + set_widgets_power_state(codec); return ret; } @@ -1168,6 +708,9 @@ static hda_nid_t side_mute_channel(struct via_spec *spec) case VT1709_10CH: return 0x29; case VT1708B_8CH: /* fall thru */ case VT1708S: return 0x27; + case VT2002P: return 0x19; + case VT1802: return 0x15; + case VT1812: return 0x15; default: return 0; } } @@ -1176,13 +719,22 @@ static int update_side_mute_status(struct hda_codec *codec) { /* mute side channel */ struct via_spec *spec = codec->spec; - unsigned int parm = spec->hp_independent_mode - ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; + unsigned int parm; hda_nid_t sw3 = side_mute_channel(spec); - if (sw3) - snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, - parm); + if (sw3) { + if (VT2002P_COMPATIBLE(spec)) + parm = spec->hp_independent_mode ? + AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1); + else + parm = spec->hp_independent_mode ? + AMP_OUT_MUTE : AMP_OUT_UNMUTE; + snd_hda_codec_write(codec, sw3, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); + if (spec->codec_type == VT1812) + snd_hda_codec_write(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); + } return 0; } @@ -1217,19 +769,18 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, || spec->codec_type == VT1702 || spec->codec_type == VT1718S || spec->codec_type == VT1716S - || spec->codec_type == VT2002P - || spec->codec_type == VT1812) { + || VT2002P_COMPATIBLE(spec)) { activate_ctl(codec, "Headphone Playback Volume", spec->hp_independent_mode); activate_ctl(codec, "Headphone Playback Switch", spec->hp_independent_mode); } /* update jack power state */ - set_jack_power_state(codec); + set_widgets_power_state(codec); return 0; } -static struct snd_kcontrol_new via_hp_mixer[2] = { +static const struct snd_kcontrol_new via_hp_mixer[2] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Independent HP", @@ -1256,6 +807,7 @@ static int via_hp_build(struct hda_codec *codec) nid = 0x34; break; case VT2002P: + case VT1802: nid = 0x35; break; case VT1812: @@ -1292,14 +844,18 @@ static void notify_aa_path_ctls(struct hda_codec *codec) { int i; struct snd_ctl_elem_id id; - const char *labels[] = {"Mic", "Front Mic", "Line"}; + const char *labels[] = {"Mic", "Front Mic", "Line", "Rear Mic"}; + struct snd_kcontrol *ctl; memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; for (i = 0; i < ARRAY_SIZE(labels); i++) { sprintf(id.name, "%s Playback Volume", labels[i]); - snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, - &id); + ctl = snd_hda_find_mixer_ctl(codec, id.name); + if (ctl) + snd_ctl_notify(codec->bus->card, + SNDRV_CTL_EVENT_MASK_VALUE, + &ctl->id); } } @@ -1443,11 +999,11 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, } } spec->smart51_enabled = *ucontrol->value.integer.value; - set_jack_power_state(codec); + set_widgets_power_state(codec); return 1; } -static struct snd_kcontrol_new via_smart51_mixer[2] = { +static const struct snd_kcontrol_new via_smart51_mixer[2] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Smart 5.1", @@ -1469,6 +1025,11 @@ static int via_smart51_build(struct via_spec *spec) hda_nid_t nid; int i; + if (!cfg) + return 0; + if (cfg->line_outs > 2) + return 0; + knew = via_clone_control(spec, &via_smart51_mixer[0]); if (knew == NULL) return -ENOMEM; @@ -1488,7 +1049,7 @@ static int via_smart51_build(struct via_spec *spec) } /* capture mixer elements */ -static struct snd_kcontrol_new vt1708_capture_mixer[] = { +static const struct snd_kcontrol_new vt1708_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT), @@ -1539,6 +1100,7 @@ static int is_aa_path_mute(struct hda_codec *codec) break; case VT2002P: case VT1812: + case VT1802: nid_mixer = 0x21; start_idx = 0; end_idx = 2; @@ -1603,6 +1165,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) break; case VT2002P: case VT1812: + case VT1802: verb = 0xf93; parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ break; @@ -1616,7 +1179,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb vt1708_volume_init_verbs[] = { +static const struct hda_verb vt1708_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -1646,6 +1209,8 @@ static struct hda_verb vt1708_volume_init_verbs[] = { {0x20, AC_VERB_SET_CONNECT_SEL, 0}, /* PW9 Output enable */ {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* power down jack detect function */ + {0x1, 0xf81, 0x1}, { } }; @@ -1668,7 +1233,7 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec, { struct via_spec *spec = codec->spec; struct hda_multi_out *mout = &spec->multiout; - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; int chs = substream->runtime->channels; int i; @@ -1737,7 +1302,7 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, { struct via_spec *spec = codec->spec; struct hda_multi_out *mout = &spec->multiout; - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; if (substream->number == 0) playback_multi_pcm_prep_0(codec, stream_tag, format, @@ -1758,7 +1323,7 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, { struct via_spec *spec = codec->spec; struct hda_multi_out *mout = &spec->multiout; - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; int i; if (substream->number == 0) { @@ -1856,7 +1421,7 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream vt1708_pcm_analog_playback = { +static const struct hda_pcm_stream vt1708_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 8, @@ -1868,7 +1433,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { +static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { .substreams = 2, .channels_min = 2, .channels_max = 8, @@ -1885,7 +1450,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { }, }; -static struct hda_pcm_stream vt1708_pcm_analog_capture = { +static const struct hda_pcm_stream vt1708_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -1896,7 +1461,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1708_pcm_digital_playback = { +static const struct hda_pcm_stream vt1708_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1909,7 +1474,7 @@ static struct hda_pcm_stream vt1708_pcm_digital_playback = { }, }; -static struct hda_pcm_stream vt1708_pcm_digital_capture = { +static const struct hda_pcm_stream vt1708_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1919,7 +1484,7 @@ static int via_build_controls(struct hda_codec *codec) { struct via_spec *spec = codec->spec; struct snd_kcontrol *kctl; - struct snd_kcontrol_new *knew; + const struct snd_kcontrol_new *knew; int err, i; for (i = 0; i < spec->num_mixers; i++) { @@ -1967,7 +1532,7 @@ static int via_build_controls(struct hda_codec *codec) } /* init power states */ - set_jack_power_state(codec); + set_widgets_power_state(codec); analog_low_current_mode(codec, 1); via_free_kctls(codec); /* no longer needed */ @@ -2131,7 +1696,7 @@ static void via_speaker_automute(struct hda_codec *codec) unsigned int hp_present; struct via_spec *spec = codec->spec; - if (spec->codec_type != VT2002P && spec->codec_type != VT1812) + if (!VT2002P_COMPATIBLE(spec)) return; hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); @@ -2190,17 +1755,21 @@ static void via_unsol_event(struct hda_codec *codec, unsigned int res) { res >>= 26; - if (res & VIA_HP_EVENT) + + if (res & VIA_JACK_EVENT) + set_widgets_power_state(codec); + + res &= ~VIA_JACK_EVENT; + + if (res == VIA_HP_EVENT) via_hp_automute(codec); - if (res & VIA_GPIO_EVENT) + else if (res == VIA_GPIO_EVENT) via_gpio_control(codec); - if (res & VIA_JACK_EVENT) - set_jack_power_state(codec); - if (res & VIA_MONO_EVENT) + else if (res == VIA_MONO_EVENT) via_mono_automute(codec); - if (res & VIA_SPEAKER_EVENT) + else if (res == VIA_SPEAKER_EVENT) via_speaker_automute(codec); - if (res & VIA_BIND_HP_EVENT) + else if (res == VIA_BIND_HP_EVENT) via_hp_bind_automute(codec); } @@ -2250,7 +1819,7 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) /* */ -static struct hda_codec_ops via_patch_ops = { +static const struct hda_codec_ops via_patch_ops = { .build_controls = via_build_controls, .build_pcms = via_build_pcms, .init = via_init, @@ -2280,16 +1849,16 @@ static int vt1708_auto_fill_dac_nids(struct via_spec *spec, /* config dac list */ switch (i) { case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0x12; + spec->private_dac_nids[i] = 0x12; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0x13; + spec->private_dac_nids[i] = 0x13; break; } } @@ -2433,7 +2002,8 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg, hda_nid_t cap_nid, - hda_nid_t pin_idxs[], int num_idxs) + const hda_nid_t pin_idxs[], + int num_idxs) { struct via_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; @@ -2479,13 +2049,13 @@ static int vt_auto_create_analog_input_ctls(struct hda_codec *codec, static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 }; + static const hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs, ARRAY_SIZE(pin_idxs)); } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1708_loopbacks[] = { +static const struct hda_amp_list vt1708_loopbacks[] = { { 0x17, HDA_INPUT, 1 }, { 0x17, HDA_INPUT, 2 }, { 0x17, HDA_INPUT, 3 }, @@ -2544,7 +2114,7 @@ static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new vt1708_jack_detectect[] = { +static const struct snd_kcontrol_new vt1708_jack_detectect[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Jack Detect", @@ -2619,7 +2189,8 @@ static int via_auto_init(struct hda_codec *codec) via_auto_init_multi_out(codec); via_auto_init_hp_out(codec); via_auto_init_analog_input(codec); - if (spec->codec_type == VT2002P || spec->codec_type == VT1812) { + + if (VT2002P_COMPATIBLE(spec)) { via_hp_bind_automute(codec); } else { via_hp_automute(codec); @@ -2723,7 +2294,7 @@ static int patch_vt1708(struct hda_codec *codec) } /* capture mixer elements */ -static struct snd_kcontrol_new vt1709_capture_mixer[] = { +static const struct snd_kcontrol_new vt1709_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT), @@ -2745,7 +2316,7 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt1709_uniwill_init_verbs[] = { +static const struct hda_verb vt1709_uniwill_init_verbs[] = { {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, { } @@ -2754,7 +2325,7 @@ static struct hda_verb vt1709_uniwill_init_verbs[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb vt1709_10ch_volume_init_verbs[] = { +static const struct hda_verb vt1709_10ch_volume_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -2794,7 +2365,7 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { +static const struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 10, @@ -2806,7 +2377,7 @@ static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { +static const struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 6, @@ -2818,7 +2389,7 @@ static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1709_pcm_analog_capture = { +static const struct hda_pcm_stream vt1709_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -2829,7 +2400,7 @@ static struct hda_pcm_stream vt1709_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1709_pcm_digital_playback = { +static const struct hda_pcm_stream vt1709_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -2840,7 +2411,7 @@ static struct hda_pcm_stream vt1709_pcm_digital_playback = { }, }; -static struct hda_pcm_stream vt1709_pcm_digital_capture = { +static const struct hda_pcm_stream vt1709_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -2867,26 +2438,26 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec, switch (i) { case AUTO_SEQ_FRONT: /* AOW0 */ - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: /* AOW2 */ - spec->multiout.dac_nids[i] = 0x12; + spec->private_dac_nids[i] = 0x12; break; case AUTO_SEQ_SURROUND: /* AOW3 */ - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: /* AOW1 */ - spec->multiout.dac_nids[i] = 0x27; + spec->private_dac_nids[i] = 0x27; break; default: break; } } } - spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ + spec->private_dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ } else if (cfg->line_outs == 3) { /* 6 channels */ for (i = 0; i < cfg->line_outs; i++) { @@ -2896,15 +2467,15 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec, switch (i) { case AUTO_SEQ_FRONT: /* AOW0 */ - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: /* AOW2 */ - spec->multiout.dac_nids[i] = 0x12; + spec->private_dac_nids[i] = 0x12; break; case AUTO_SEQ_SURROUND: /* AOW1 */ - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; default: break; @@ -3052,7 +2623,7 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 }; + static const hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -3102,7 +2673,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1709_loopbacks[] = { +static const struct hda_amp_list vt1709_loopbacks[] = { { 0x18, HDA_INPUT, 1 }, { 0x18, HDA_INPUT, 2 }, { 0x18, HDA_INPUT, 3 }, @@ -3163,7 +2734,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb vt1709_6ch_volume_init_verbs[] = { +static const struct hda_verb vt1709_6ch_volume_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -3253,7 +2824,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec) } /* capture mixer elements */ -static struct snd_kcontrol_new vt1708B_capture_mixer[] = { +static const struct snd_kcontrol_new vt1708B_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), @@ -3275,7 +2846,7 @@ static struct snd_kcontrol_new vt1708B_capture_mixer[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb vt1708B_8ch_volume_init_verbs[] = { +static const struct hda_verb vt1708B_8ch_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -3310,7 +2881,7 @@ static struct hda_verb vt1708B_8ch_volume_init_verbs[] = { { } }; -static struct hda_verb vt1708B_4ch_volume_init_verbs[] = { +static const struct hda_verb vt1708B_4ch_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -3345,7 +2916,7 @@ static struct hda_verb vt1708B_4ch_volume_init_verbs[] = { { } }; -static struct hda_verb vt1708B_uniwill_init_verbs[] = { +static const struct hda_verb vt1708B_uniwill_init_verbs[] = { {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, @@ -3369,7 +2940,7 @@ static int via_pcm_open_close(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { +static const struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 8, @@ -3382,7 +2953,7 @@ static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { +static const struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 4, @@ -3394,7 +2965,7 @@ static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1708B_pcm_analog_capture = { +static const struct hda_pcm_stream vt1708B_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -3407,7 +2978,7 @@ static struct hda_pcm_stream vt1708B_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1708B_pcm_digital_playback = { +static const struct hda_pcm_stream vt1708B_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -3420,7 +2991,7 @@ static struct hda_pcm_stream vt1708B_pcm_digital_playback = { }, }; -static struct hda_pcm_stream vt1708B_pcm_digital_capture = { +static const struct hda_pcm_stream vt1708B_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -3443,16 +3014,16 @@ static int vt1708B_auto_fill_dac_nids(struct via_spec *spec, /* config dac list */ switch (i) { case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0x24; + spec->private_dac_nids[i] = 0x24; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0x25; + spec->private_dac_nids[i] = 0x25; break; } } @@ -3584,7 +3155,7 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e }; + static const hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -3634,7 +3205,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1708B_loopbacks[] = { +static const struct hda_amp_list vt1708B_loopbacks[] = { { 0x16, HDA_INPUT, 1 }, { 0x16, HDA_INPUT, 2 }, { 0x16, HDA_INPUT, 3 }, @@ -3642,6 +3213,87 @@ static struct hda_amp_list vt1708B_loopbacks[] = { { } /* end */ }; #endif + +static void set_widgets_power_state_vt1708B(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + int is_8ch = 0; + if ((spec->codec_type != VT1708B_4CH) && + (codec->vendor_id != 0x11064397)) + is_8ch = 1; + + /* SW0 (17h) = stereo mixer */ + imux_is_smixer = + (snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) + == ((spec->codec_type == VT1708S) ? 5 : 0)); + /* inputs */ + /* PW 1/2/5 (1ah/1bh/1eh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1a, &parm); + set_pin_power_state(codec, 0x1b, &parm); + set_pin_power_state(codec, 0x1e, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* SW0 (17h), AIW 0/1 (13h/14h) */ + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW0 (19h), SW1 (18h), AOW1 (11h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x19, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1b, &parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW6 (22h), SW2 (26h), AOW2 (24h) */ + if (is_8ch) { + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x22, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1a, &parm); + snd_hda_codec_write(codec, 0x26, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x24, 0, + AC_VERB_SET_POWER_STATE, parm); + } else if (codec->vendor_id == 0x11064397) { + /* PW7(23h), SW2(27h), AOW2(25h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x23, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1a, &parm); + snd_hda_codec_write(codec, 0x27, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + /* PW 3/4/7 (1ch/1dh/23h) */ + parm = AC_PWRST_D3; + /* force to D0 for internal Speaker */ + set_pin_power_state(codec, 0x1c, &parm); + set_pin_power_state(codec, 0x1d, &parm); + if (is_8ch) + set_pin_power_state(codec, 0x23, &parm); + + /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */ + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + if (is_8ch) { + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x27, 0, + AC_VERB_SET_POWER_STATE, parm); + } else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); +} + static int patch_vt1708S(struct hda_codec *codec); static int patch_vt1708B_8ch(struct hda_codec *codec) { @@ -3692,6 +3344,8 @@ static int patch_vt1708B_8ch(struct hda_codec *codec) spec->loopback.amplist = vt1708B_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + return 0; } @@ -3742,13 +3396,15 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) spec->loopback.amplist = vt1708B_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + return 0; } /* Patch for VT1708S */ /* capture mixer elements */ -static struct snd_kcontrol_new vt1708S_capture_mixer[] = { +static const struct snd_kcontrol_new vt1708S_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), @@ -3771,7 +3427,7 @@ static struct snd_kcontrol_new vt1708S_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt1708S_volume_init_verbs[] = { +static const struct hda_verb vt1708S_volume_init_verbs[] = { /* Unmute ADC0-1 and set the default input to mic-in */ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -3797,7 +3453,7 @@ static struct hda_verb vt1708S_volume_init_verbs[] = { { } }; -static struct hda_verb vt1708S_uniwill_init_verbs[] = { +static const struct hda_verb vt1708S_uniwill_init_verbs[] = { {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, @@ -3810,7 +3466,19 @@ static struct hda_verb vt1708S_uniwill_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1708S_pcm_analog_playback = { +static const struct hda_verb vt1705_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1708S_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 8, @@ -3823,7 +3491,20 @@ static struct hda_pcm_stream vt1708S_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1708S_pcm_analog_capture = { +static const struct hda_pcm_stream vt1705_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 6, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1708S_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -3836,7 +3517,7 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1708S_pcm_digital_playback = { +static const struct hda_pcm_stream vt1708S_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -3866,16 +3547,19 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, /* config dac list */ switch (i) { case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0x24; + if (spec->codec->vendor_id == 0x11064397) + spec->private_dac_nids[i] = 0x25; + else + spec->private_dac_nids[i] = 0x24; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0x25; + spec->private_dac_nids[i] = 0x25; break; } } @@ -3884,23 +3568,29 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, /* for Smart 5.1, line/mic inputs double as output pins */ if (cfg->line_outs == 1) { spec->multiout.num_dacs = 3; - spec->multiout.dac_nids[AUTO_SEQ_SURROUND] = 0x11; - spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24; + spec->private_dac_nids[AUTO_SEQ_SURROUND] = 0x11; + if (spec->codec->vendor_id == 0x11064397) + spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x25; + else + spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x24; } return 0; } /* add playback controls from the parsed DAC table */ -static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, +static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { + struct via_spec *spec = codec->spec; char name[32]; static const char * const chname[4] = { "Front", "Surround", "C/LFE", "Side" }; - hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25}; - hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27}; + hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25}, + {0x10, 0x11, 0x25, 0} }; + hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27}, + {0x1C, 0x18, 0x27, 0} }; hda_nid_t nid, nid_vol, nid_mute; int i, err; @@ -3911,8 +3601,15 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, if (!nid && i > AUTO_SEQ_CENLFE) continue; - nid_vol = nid_vols[i]; - nid_mute = nid_mutes[i]; + if (codec->vendor_id == 0x11064397) { + nid_vol = nid_vols[1][i]; + nid_mute = nid_mutes[1][i]; + } else { + nid_vol = nid_vols[0][i]; + nid_mute = nid_mutes[0][i]; + } + if (!nid_vol && !nid_mute) + continue; if (i == AUTO_SEQ_CENLFE) { /* Center/LFE */ @@ -4022,7 +3719,7 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -4066,7 +3763,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) return 0; /* can't find valid BIOS pin config */ - err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg); + err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); @@ -4093,7 +3790,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1708S_loopbacks[] = { +static const struct hda_amp_list vt1708S_loopbacks[] = { { 0x16, HDA_INPUT, 1 }, { 0x16, HDA_INPUT, 2 }, { 0x16, HDA_INPUT, 3 }, @@ -4133,17 +3830,29 @@ static int patch_vt1708S(struct hda_codec *codec) } spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs; - spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs; + if (codec->vendor_id == 0x11064397) + spec->init_verbs[spec->num_iverbs++] = + vt1705_uniwill_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt1708S_uniwill_init_verbs; if (codec->vendor_id == 0x11060440) spec->stream_name_analog = "VT1818S Analog"; + else if (codec->vendor_id == 0x11064397) + spec->stream_name_analog = "VT1705 Analog"; else spec->stream_name_analog = "VT1708S Analog"; - spec->stream_analog_playback = &vt1708S_pcm_analog_playback; + if (codec->vendor_id == 0x11064397) + spec->stream_analog_playback = &vt1705_pcm_analog_playback; + else + spec->stream_analog_playback = &vt1708S_pcm_analog_playback; spec->stream_analog_capture = &vt1708S_pcm_analog_capture; if (codec->vendor_id == 0x11060440) spec->stream_name_digital = "VT1818S Digital"; + else if (codec->vendor_id == 0x11064397) + spec->stream_name_digital = "VT1705 Digital"; else spec->stream_name_digital = "VT1708S Digital"; spec->stream_digital_playback = &vt1708S_pcm_digital_playback; @@ -4181,13 +3890,22 @@ static int patch_vt1708S(struct hda_codec *codec) spec->stream_name_analog = "VT1818S Analog"; spec->stream_name_digital = "VT1818S Digital"; } + /* 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), + "%s %s", codec->vendor_name, codec->chip_name); + } + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; return 0; } /* Patch for VT1702 */ /* capture mixer elements */ -static struct snd_kcontrol_new vt1702_capture_mixer[] = { +static const struct snd_kcontrol_new vt1702_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT), @@ -4211,7 +3929,7 @@ static struct snd_kcontrol_new vt1702_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt1702_volume_init_verbs[] = { +static const struct hda_verb vt1702_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -4242,7 +3960,7 @@ static struct hda_verb vt1702_volume_init_verbs[] = { { } }; -static struct hda_verb vt1702_uniwill_init_verbs[] = { +static const struct hda_verb vt1702_uniwill_init_verbs[] = { {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, @@ -4252,7 +3970,7 @@ static struct hda_verb vt1702_uniwill_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1702_pcm_analog_playback = { +static const struct hda_pcm_stream vt1702_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -4265,7 +3983,7 @@ static struct hda_pcm_stream vt1702_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1702_pcm_analog_capture = { +static const struct hda_pcm_stream vt1702_pcm_analog_capture = { .substreams = 3, .channels_min = 2, .channels_max = 2, @@ -4278,7 +3996,7 @@ static struct hda_pcm_stream vt1702_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1702_pcm_digital_playback = { +static const struct hda_pcm_stream vt1702_pcm_digital_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -4300,7 +4018,7 @@ static int vt1702_auto_fill_dac_nids(struct via_spec *spec, if (cfg->line_out_pins[0]) { /* config dac list */ - spec->multiout.dac_nids[0] = 0x10; + spec->private_dac_nids[0] = 0x10; } return 0; @@ -4378,7 +4096,7 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -4429,7 +4147,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1702_loopbacks[] = { +static const struct hda_amp_list vt1702_loopbacks[] = { { 0x1A, HDA_INPUT, 1 }, { 0x1A, HDA_INPUT, 2 }, { 0x1A, HDA_INPUT, 3 }, @@ -4438,6 +4156,37 @@ static struct hda_amp_list vt1702_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1702(struct hda_codec *codec) +{ + int imux_is_smixer = + snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; + unsigned int parm; + /* inputs */ + /* PW 1/2/5 (14h/15h/18h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x14, &parm); + set_pin_power_state(codec, 0x15, &parm); + set_pin_power_state(codec, 0x18, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */ + /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */ + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW 3/4 (16h/17h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x17, &parm); + set_pin_power_state(codec, 0x16, &parm); + /* MW0 (1ah), AOW 0/1 (10h/1dh) */ + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); +} + static int patch_vt1702(struct hda_codec *codec) { struct via_spec *spec; @@ -4484,13 +4233,14 @@ static int patch_vt1702(struct hda_codec *codec) spec->loopback.amplist = vt1702_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1702; return 0; } /* Patch for VT1718S */ /* capture mixer elements */ -static struct snd_kcontrol_new vt1718S_capture_mixer[] = { +static const struct snd_kcontrol_new vt1718S_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), @@ -4512,14 +4262,15 @@ static struct snd_kcontrol_new vt1718S_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt1718S_volume_init_verbs[] = { +static const struct hda_verb vt1718S_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - + /* Enable MW0 adjust Gain 5 */ + {0x1, 0xfb2, 0x10}, /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget */ @@ -4528,7 +4279,7 @@ static struct hda_verb vt1718S_volume_init_verbs[] = { {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, /* Setup default input of Front HP to MW9 */ {0x28, AC_VERB_SET_CONNECT_SEL, 0x1}, @@ -4559,7 +4310,7 @@ static struct hda_verb vt1718S_volume_init_verbs[] = { }; -static struct hda_verb vt1718S_uniwill_init_verbs[] = { +static const struct hda_verb vt1718S_uniwill_init_verbs[] = { {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, @@ -4572,7 +4323,7 @@ static struct hda_verb vt1718S_uniwill_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1718S_pcm_analog_playback = { +static const struct hda_pcm_stream vt1718S_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 10, @@ -4585,7 +4336,7 @@ static struct hda_pcm_stream vt1718S_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1718S_pcm_analog_capture = { +static const struct hda_pcm_stream vt1718S_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -4598,7 +4349,7 @@ static struct hda_pcm_stream vt1718S_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1718S_pcm_digital_playback = { +static const struct hda_pcm_stream vt1718S_pcm_digital_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -4611,7 +4362,7 @@ static struct hda_pcm_stream vt1718S_pcm_digital_playback = { }, }; -static struct hda_pcm_stream vt1718S_pcm_digital_capture = { +static const struct hda_pcm_stream vt1718S_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -4634,16 +4385,16 @@ static int vt1718S_auto_fill_dac_nids(struct via_spec *spec, /* config dac list */ switch (i) { case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x8; + spec->private_dac_nids[i] = 0x8; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0xa; + spec->private_dac_nids[i] = 0xa; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x9; + spec->private_dac_nids[i] = 0x9; break; case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0xb; + spec->private_dac_nids[i] = 0xb; break; } } @@ -4765,7 +4516,7 @@ static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -4816,7 +4567,7 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1718S_loopbacks[] = { +static const struct hda_amp_list vt1718S_loopbacks[] = { { 0x21, HDA_INPUT, 1 }, { 0x21, HDA_INPUT, 2 }, { 0x21, HDA_INPUT, 3 }, @@ -4825,6 +4576,72 @@ static struct hda_amp_list vt1718S_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1718S(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + /* MUX6 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; + /* inputs */ + /* PW 5/6/7 (29h/2ah/2bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x29, &parm); + set_pin_power_state(codec, 0x2a, &parm); + set_pin_power_state(codec, 0x2b, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x27, &parm); + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW2 (26h), AOW2 (ah) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x26, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x2b, &parm); + snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW0 (24h), AOW0 (8h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + if (!spec->hp_independent_mode) /* check for redirected HP */ + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm); + /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ + snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + + /* PW1 (25h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x2a, &parm); + snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, parm); + + if (spec->hp_independent_mode) { + /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x1b, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0xc, 0, + AC_VERB_SET_POWER_STATE, parm); + } +} + static int patch_vt1718S(struct hda_codec *codec) { struct via_spec *spec; @@ -4886,6 +4703,8 @@ static int patch_vt1718S(struct hda_codec *codec) spec->loopback.amplist = vt1718S_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1718S; + return 0; } @@ -4925,13 +4744,12 @@ static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol, snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_CONNECT_SEL, index); spec->dmic_enabled = index; - set_jack_power_state(codec); - + set_widgets_power_state(codec); return 1; } /* capture mixer elements */ -static struct snd_kcontrol_new vt1716S_capture_mixer[] = { +static const struct snd_kcontrol_new vt1716S_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), @@ -4950,7 +4768,7 @@ static struct snd_kcontrol_new vt1716S_capture_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new vt1716s_dmic_mixer[] = { +static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = { HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -4966,12 +4784,12 @@ static struct snd_kcontrol_new vt1716s_dmic_mixer[] = { /* mono-out mixer elements */ -static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = { +static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = { HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT), { } /* end */ }; -static struct hda_verb vt1716S_volume_init_verbs[] = { +static const struct hda_verb vt1716S_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -5020,7 +4838,7 @@ static struct hda_verb vt1716S_volume_init_verbs[] = { }; -static struct hda_verb vt1716S_uniwill_init_verbs[] = { +static const struct hda_verb vt1716S_uniwill_init_verbs[] = { {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, @@ -5033,7 +4851,7 @@ static struct hda_verb vt1716S_uniwill_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1716S_pcm_analog_playback = { +static const struct hda_pcm_stream vt1716S_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 6, @@ -5046,7 +4864,7 @@ static struct hda_pcm_stream vt1716S_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1716S_pcm_analog_capture = { +static const struct hda_pcm_stream vt1716S_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5059,7 +4877,7 @@ static struct hda_pcm_stream vt1716S_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1716S_pcm_digital_playback = { +static const struct hda_pcm_stream vt1716S_pcm_digital_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5088,13 +4906,13 @@ static int vt1716S_auto_fill_dac_nids(struct via_spec *spec, /* config dac list */ switch (i) { case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0x25; + spec->private_dac_nids[i] = 0x25; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; } } @@ -5229,7 +5047,7 @@ static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -5276,7 +5094,7 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1716S_loopbacks[] = { +static const struct hda_amp_list vt1716S_loopbacks[] = { { 0x16, HDA_INPUT, 1 }, { 0x16, HDA_INPUT, 2 }, { 0x16, HDA_INPUT, 3 }, @@ -5285,6 +5103,99 @@ static struct hda_amp_list vt1716S_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1716S(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + unsigned int mono_out, present; + /* SW0 (17h) = stereo mixer */ + imux_is_smixer = + (snd_hda_codec_read(codec, 0x17, 0, + AC_VERB_GET_CONNECT_SEL, 0x00) == 5); + /* inputs */ + /* PW 1/2/5 (1ah/1bh/1eh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1a, &parm); + set_pin_power_state(codec, 0x1b, &parm); + set_pin_power_state(codec, 0x1e, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* SW0 (17h), AIW0(13h) */ + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1e, &parm); + /* PW11 (22h) */ + if (spec->dmic_enabled) + set_pin_power_state(codec, 0x22, &parm); + else + snd_hda_codec_write(codec, 0x22, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + + /* SW2(26h), AIW1(14h) */ + snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW0 (19h), SW1 (18h), AOW1 (11h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x19, &parm); + /* Smart 5.1 PW2(1bh) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1b, &parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW7 (23h), SW3 (27h), AOW3 (25h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x23, &parm); + /* Smart 5.1 PW1(1ah) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1a, &parm); + snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm); + + /* Smart 5.1 PW5(1eh) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1e, &parm); + snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm); + + /* Mono out */ + /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ + present = snd_hda_jack_detect(codec, 0x1c); + + if (present) + mono_out = 0; + else { + present = snd_hda_jack_detect(codec, 0x1d); + if (!spec->hp_independent_mode && present) + mono_out = 0; + else + mono_out = 1; + } + parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; + snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW 3/4 (1ch/1dh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1c, &parm); + set_pin_power_state(codec, 0x1d, &parm); + /* HP Independent Mode, power on AOW3 */ + if (spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + + /* force to D0 for internal Speaker */ + /* MW0 (16h), AOW0 (10h) */ + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, + mono_out ? AC_PWRST_D0 : parm); +} + static int patch_vt1716S(struct hda_codec *codec) { struct via_spec *spec; @@ -5339,13 +5250,14 @@ static int patch_vt1716S(struct hda_codec *codec) spec->loopback.amplist = vt1716S_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1716S; return 0; } /* for vt2002P */ /* capture mixer elements */ -static struct snd_kcontrol_new vt2002P_capture_mixer[] = { +static const struct snd_kcontrol_new vt2002P_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), @@ -5368,7 +5280,11 @@ static struct snd_kcontrol_new vt2002P_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt2002P_volume_init_verbs[] = { +static const struct hda_verb vt2002P_volume_init_verbs[] = { + /* Class-D speaker related verbs */ + {0x1, 0xfe0, 0x4}, + {0x1, 0xfe9, 0x80}, + {0x1, 0xfe2, 0x22}, /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -5419,9 +5335,60 @@ static struct hda_verb vt2002P_volume_init_verbs[] = { {0x1, 0xfb8, 0x88}, { } }; +static const struct hda_verb vt1802_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Mic = 0 */ + {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, + + /* PW9 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + /* Enable Boost Volume backdoor */ + {0x1, 0xfb9, 0x24}, + + /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, -static struct hda_verb vt2002P_uniwill_init_verbs[] = { + /* set MUX0/1/4/8 = 0 (AOW0) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0}, + {0x38, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3c, AC_VERB_SET_CONNECT_SEL, 0}, + + /* set PW0 index=0 (MW0) */ + {0x24, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Enable AOW0 to MW9 */ + {0x1, 0xfb8, 0x88}, + { } +}; + + +static const struct hda_verb vt2002P_uniwill_init_verbs[] = { {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, @@ -5431,8 +5398,18 @@ static struct hda_verb vt2002P_uniwill_init_verbs[] = { {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, { } }; +static const struct hda_verb vt1802_uniwill_init_verbs[] = { + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; -static struct hda_pcm_stream vt2002P_pcm_analog_playback = { +static const struct hda_pcm_stream vt2002P_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5445,7 +5422,7 @@ static struct hda_pcm_stream vt2002P_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt2002P_pcm_analog_capture = { +static const struct hda_pcm_stream vt2002P_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5458,7 +5435,7 @@ static struct hda_pcm_stream vt2002P_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt2002P_pcm_digital_playback = { +static const struct hda_pcm_stream vt2002P_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -5478,7 +5455,7 @@ static int vt2002P_auto_fill_dac_nids(struct via_spec *spec, spec->multiout.num_dacs = 1; spec->multiout.dac_nids = spec->private_dac_nids; if (cfg->line_out_pins[0]) - spec->multiout.dac_nids[0] = 0x8; + spec->private_dac_nids[0] = 0x8; return 0; } @@ -5487,10 +5464,15 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { int err; + hda_nid_t sw_nid; if (!cfg->line_out_pins[0]) return -1; + if (spec->codec_type == VT1802) + sw_nid = 0x28; + else + sw_nid = 0x26; /* Line-Out: PortE */ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, @@ -5500,7 +5482,7 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec, return err; err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, "Master Front Playback Switch", - HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT)); + HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -5540,7 +5522,7 @@ static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec, { struct via_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; - static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff }; int err; err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, @@ -5601,7 +5583,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt2002P_loopbacks[] = { +static const struct hda_amp_list vt2002P_loopbacks[] = { { 0x21, HDA_INPUT, 0 }, { 0x21, HDA_INPUT, 1 }, { 0x21, HDA_INPUT, 2 }, @@ -5609,6 +5591,116 @@ static struct hda_amp_list vt2002P_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt2002P(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + unsigned int present; + /* MUX9 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; + /* inputs */ + /* PW 5/6/7 (29h/2ah/2bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x29, &parm); + set_pin_power_state(codec, 0x2a, &parm); + set_pin_power_state(codec, 0x2b, &parm); + parm = AC_PWRST_D0; + /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */ + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* AOW0 (8h)*/ + snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm); + + if (spec->codec_type == VT1802) { + /* PW4 (28h), MW4 (18h), MUX4(38h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x18, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x38, 0, + AC_VERB_SET_POWER_STATE, parm); + } else { + /* PW4 (26h), MW4 (1ch), MUX4(37h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x26, &parm); + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x37, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + if (spec->codec_type == VT1802) { + /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + snd_hda_codec_write(codec, 0x15, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_POWER_STATE, parm); + } else { + /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + snd_hda_codec_write(codec, 0x19, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + if (spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x9, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* Class-D */ + /* PW0 (24h), MW0(18h/14h), MUX0(34h) */ + present = snd_hda_jack_detect(codec, 0x25); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + parm = present ? AC_PWRST_D3 : AC_PWRST_D0; + if (spec->codec_type == VT1802) + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, parm); + else + snd_hda_codec_write(codec, 0x18, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_POWER_STATE, parm); + + /* Mono Out */ + present = snd_hda_jack_detect(codec, 0x26); + + parm = present ? AC_PWRST_D3 : AC_PWRST_D0; + if (spec->codec_type == VT1802) { + /* PW15 (33h), MW8(1ch), MUX8(3ch) */ + snd_hda_codec_write(codec, 0x33, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, parm); + } else { + /* PW15 (31h), MW8(17h), MUX8(3bh) */ + snd_hda_codec_write(codec, 0x31, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x17, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3b, 0, + AC_VERB_SET_POWER_STATE, parm); + } + /* MW9 (21h) */ + if (imux_is_smixer || !is_aa_path_mute(codec)) + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + else + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); +} /* patch for vt2002P */ static int patch_vt2002P(struct hda_codec *codec) @@ -5631,14 +5723,31 @@ static int patch_vt2002P(struct hda_codec *codec) "from BIOS. Using genenic mode...\n"); } - spec->init_verbs[spec->num_iverbs++] = vt2002P_volume_init_verbs; - spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs; + if (spec->codec_type == VT1802) + spec->init_verbs[spec->num_iverbs++] = + vt1802_volume_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt2002P_volume_init_verbs; + + if (spec->codec_type == VT1802) + spec->init_verbs[spec->num_iverbs++] = + vt1802_uniwill_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt2002P_uniwill_init_verbs; - spec->stream_name_analog = "VT2002P Analog"; + if (spec->codec_type == VT1802) + spec->stream_name_analog = "VT1802 Analog"; + else + spec->stream_name_analog = "VT2002P Analog"; spec->stream_analog_playback = &vt2002P_pcm_analog_playback; spec->stream_analog_capture = &vt2002P_pcm_analog_capture; - spec->stream_name_digital = "VT2002P Digital"; + if (spec->codec_type == VT1802) + spec->stream_name_digital = "VT1802 Digital"; + else + spec->stream_name_digital = "VT2002P Digital"; spec->stream_digital_playback = &vt2002P_pcm_digital_playback; if (!spec->adc_nids && spec->input_mux) { @@ -5660,13 +5769,14 @@ static int patch_vt2002P(struct hda_codec *codec) spec->loopback.amplist = vt2002P_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt2002P; return 0; } /* for vt1812 */ /* capture mixer elements */ -static struct snd_kcontrol_new vt1812_capture_mixer[] = { +static const struct snd_kcontrol_new vt1812_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), @@ -5688,7 +5798,7 @@ static struct snd_kcontrol_new vt1812_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt1812_volume_init_verbs[] = { +static const struct hda_verb vt1812_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -5741,7 +5851,7 @@ static struct hda_verb vt1812_volume_init_verbs[] = { }; -static struct hda_verb vt1812_uniwill_init_verbs[] = { +static const struct hda_verb vt1812_uniwill_init_verbs[] = { {0x33, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT }, @@ -5753,7 +5863,7 @@ static struct hda_verb vt1812_uniwill_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1812_pcm_analog_playback = { +static const struct hda_pcm_stream vt1812_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5766,7 +5876,7 @@ static struct hda_pcm_stream vt1812_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1812_pcm_analog_capture = { +static const struct hda_pcm_stream vt1812_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5779,7 +5889,7 @@ static struct hda_pcm_stream vt1812_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1812_pcm_digital_playback = { +static const struct hda_pcm_stream vt1812_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -5798,7 +5908,7 @@ static int vt1812_auto_fill_dac_nids(struct via_spec *spec, spec->multiout.num_dacs = 1; spec->multiout.dac_nids = spec->private_dac_nids; if (cfg->line_out_pins[0]) - spec->multiout.dac_nids[0] = 0x8; + spec->private_dac_nids[0] = 0x8; return 0; } @@ -5861,7 +5971,7 @@ static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec, { struct via_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; - static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff }; int err; err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, @@ -5923,7 +6033,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1812_loopbacks[] = { +static const struct hda_amp_list vt1812_loopbacks[] = { { 0x21, HDA_INPUT, 0 }, { 0x21, HDA_INPUT, 1 }, { 0x21, HDA_INPUT, 2 }, @@ -5931,6 +6041,97 @@ static struct hda_amp_list vt1812_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1812(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer = + snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; + unsigned int parm; + unsigned int present; + /* MUX10 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; + /* inputs */ + /* PW 5/6/7 (29h/2ah/2bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x29, &parm); + set_pin_power_state(codec, 0x2a, &parm); + set_pin_power_state(codec, 0x2b, &parm); + parm = AC_PWRST_D0; + /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* AOW0 (8h)*/ + snd_hda_codec_write(codec, 0x8, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* PW4 (28h), MW4 (18h), MUX4(38h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x38, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, AC_VERB_SET_POWER_STATE, parm); + if (spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x9, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* Internal Speaker */ + /* PW0 (24h), MW0(14h), MUX0(34h) */ + present = snd_hda_jack_detect(codec, 0x25); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + if (present) { + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + } else { + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + } + + + /* Mono Out */ + /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */ + present = snd_hda_jack_detect(codec, 0x28); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x31, &parm); + if (present) { + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x3e, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + } else { + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x3e, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + } + + /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x33, &parm); + snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3d, 0, AC_VERB_SET_POWER_STATE, parm); + +} /* patch for vt1812 */ static int patch_vt1812(struct hda_codec *codec) @@ -5984,13 +6185,14 @@ static int patch_vt1812(struct hda_codec *codec) spec->loopback.amplist = vt1812_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1812; return 0; } /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_via[] = { +static const struct hda_codec_preset snd_hda_preset_via[] = { { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708}, { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708}, { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708}, @@ -6035,7 +6237,7 @@ static struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt1708S}, { .id = 0x11063397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11064397, .name = "VT1708S", + { .id = 0x11064397, .name = "VT1705", .patch = patch_vt1708S}, { .id = 0x11065397, .name = "VT1708S", .patch = patch_vt1708S}, @@ -6076,6 +6278,10 @@ static struct hda_codec_preset snd_hda_preset_via[] = { { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812}, { .id = 0x11060440, .name = "VT1818S", .patch = patch_vt1708S}, + { .id = 0x11060446, .name = "VT1802", + .patch = patch_vt2002P}, + { .id = 0x11068446, .name = "VT1802", + .patch = patch_vt2002P}, {} /* terminator */ }; diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 27709f0cd2a..f3353b49c78 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -235,8 +235,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = { { PCI_VDEVICE(NVIDIA, 0x0069), DEVICE_NFORCE }, /* NFORCE2 */ { PCI_VDEVICE(NVIDIA, 0x0089), DEVICE_NFORCE }, /* NFORCE2s */ { PCI_VDEVICE(NVIDIA, 0x00d9), DEVICE_NFORCE }, /* NFORCE3 */ + { PCI_VDEVICE(AMD, 0x746e), DEVICE_INTEL }, /* AMD8111 */ #if 0 - { PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL }, /* AMD8111 */ { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI }, /* Ali5455 */ #endif { 0, } @@ -1261,9 +1261,9 @@ static struct shortname_table { { PCI_DEVICE_ID_NVIDIA_MCP2_MODEM, "NVidia nForce2" }, { PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM, "NVidia nForce2s" }, { PCI_DEVICE_ID_NVIDIA_MCP3_MODEM, "NVidia nForce3" }, + { 0x746e, "AMD AMD8111" }, #if 0 { 0x5455, "ALi M5455" }, - { 0x746d, "AMD AMD8111" }, #endif { 0 }, }; diff --git a/sound/pci/lola/Makefile b/sound/pci/lola/Makefile new file mode 100644 index 00000000000..8178a2a59d0 --- /dev/null +++ b/sound/pci/lola/Makefile @@ -0,0 +1,4 @@ +snd-lola-y := lola.o lola_pcm.o lola_clock.o lola_mixer.o +snd-lola-$(CONFIG_SND_DEBUG) += lola_proc.o + +obj-$(CONFIG_SND_LOLA) += snd-lola.o diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c new file mode 100644 index 00000000000..34b24286d27 --- /dev/null +++ b/sound/pci/lola/lola.c @@ -0,0 +1,791 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/moduleparam.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/pcm.h> +#include <sound/initval.h> +#include "lola.h" + +/* Standard options */ +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for Digigram Lola driver."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for Digigram Lola driver."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable Digigram Lola driver."); + +/* Lola-specific options */ + +/* for instance use always max granularity which is compatible + * with all sample rates + */ +static int granularity[SNDRV_CARDS] = { + [0 ... (SNDRV_CARDS - 1)] = LOLA_GRANULARITY_MAX +}; + +/* below a sample_rate of 16kHz the analogue audio quality is NOT excellent */ +static int sample_rate_min[SNDRV_CARDS] = { + [0 ... (SNDRV_CARDS - 1) ] = 16000 +}; + +module_param_array(granularity, int, NULL, 0444); +MODULE_PARM_DESC(granularity, "Granularity value"); +module_param_array(sample_rate_min, int, NULL, 0444); +MODULE_PARM_DESC(sample_rate_min, "Minimal sample rate"); + +/* + */ + +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Digigram, Lola}}"); +MODULE_DESCRIPTION("Digigram Lola driver"); +MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); + +#ifdef CONFIG_SND_DEBUG_VERBOSE +static int debug; +module_param(debug, int, 0644); +#define verbose_debug(fmt, args...) \ + do { if (debug > 1) printk(KERN_DEBUG SFX fmt, ##args); } while (0) +#else +#define verbose_debug(fmt, args...) +#endif + +/* + * pseudo-codec read/write via CORB/RIRB + */ + +static int corb_send_verb(struct lola *chip, unsigned int nid, + unsigned int verb, unsigned int data, + unsigned int extdata) +{ + unsigned long flags; + int ret = -EIO; + + chip->last_cmd_nid = nid; + chip->last_verb = verb; + chip->last_data = data; + chip->last_extdata = extdata; + data |= (nid << 20) | (verb << 8); + + spin_lock_irqsave(&chip->reg_lock, flags); + if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) { + unsigned int wp = chip->corb.wp + 1; + wp %= LOLA_CORB_ENTRIES; + chip->corb.wp = wp; + chip->corb.buf[wp * 2] = cpu_to_le32(data); + chip->corb.buf[wp * 2 + 1] = cpu_to_le32(extdata); + lola_writew(chip, BAR0, CORBWP, wp); + chip->rirb.cmds++; + smp_wmb(); + ret = 0; + } + spin_unlock_irqrestore(&chip->reg_lock, flags); + return ret; +} + +static void lola_queue_unsol_event(struct lola *chip, unsigned int res, + unsigned int res_ex) +{ + lola_update_ext_clock_freq(chip, res); +} + +/* retrieve RIRB entry - called from interrupt handler */ +static void lola_update_rirb(struct lola *chip) +{ + unsigned int rp, wp; + u32 res, res_ex; + + wp = lola_readw(chip, BAR0, RIRBWP); + if (wp == chip->rirb.wp) + return; + chip->rirb.wp = wp; + + while (chip->rirb.rp != wp) { + chip->rirb.rp++; + chip->rirb.rp %= LOLA_CORB_ENTRIES; + + rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ + res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); + res = le32_to_cpu(chip->rirb.buf[rp]); + if (res_ex & LOLA_RIRB_EX_UNSOL_EV) + lola_queue_unsol_event(chip, res, res_ex); + else if (chip->rirb.cmds) { + chip->res = res; + chip->res_ex = res_ex; + smp_wmb(); + chip->rirb.cmds--; + } + } +} + +static int rirb_get_response(struct lola *chip, unsigned int *val, + unsigned int *extval) +{ + unsigned long timeout; + + again: + timeout = jiffies + msecs_to_jiffies(1000); + for (;;) { + if (chip->polling_mode) { + spin_lock_irq(&chip->reg_lock); + lola_update_rirb(chip); + spin_unlock_irq(&chip->reg_lock); + } + if (!chip->rirb.cmds) { + *val = chip->res; + if (extval) + *extval = chip->res_ex; + verbose_debug("get_response: %x, %x\n", + chip->res, chip->res_ex); + if (chip->res_ex & LOLA_RIRB_EX_ERROR) { + printk(KERN_WARNING SFX "RIRB ERROR: " + "NID=%x, verb=%x, data=%x, ext=%x\n", + chip->last_cmd_nid, + chip->last_verb, chip->last_data, + chip->last_extdata); + return -EIO; + } + return 0; + } + if (time_after(jiffies, timeout)) + break; + udelay(20); + cond_resched(); + } + printk(KERN_WARNING SFX "RIRB response error\n"); + if (!chip->polling_mode) { + printk(KERN_WARNING SFX "switching to polling mode\n"); + chip->polling_mode = 1; + goto again; + } + return -EIO; +} + +/* aynchronous write of a codec verb with data */ +int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb, + unsigned int data, unsigned int extdata) +{ + verbose_debug("codec_write NID=%x, verb=%x, data=%x, ext=%x\n", + nid, verb, data, extdata); + return corb_send_verb(chip, nid, verb, data, extdata); +} + +/* write a codec verb with data and read the returned status */ +int lola_codec_read(struct lola *chip, unsigned int nid, unsigned int verb, + unsigned int data, unsigned int extdata, + unsigned int *val, unsigned int *extval) +{ + int err; + + verbose_debug("codec_read NID=%x, verb=%x, data=%x, ext=%x\n", + nid, verb, data, extdata); + err = corb_send_verb(chip, nid, verb, data, extdata); + if (err < 0) + return err; + err = rirb_get_response(chip, val, extval); + return err; +} + +/* flush all pending codec writes */ +int lola_codec_flush(struct lola *chip) +{ + unsigned int tmp; + return rirb_get_response(chip, &tmp, NULL); +} + +/* + * interrupt handler + */ +static irqreturn_t lola_interrupt(int irq, void *dev_id) +{ + struct lola *chip = dev_id; + unsigned int notify_ins, notify_outs, error_ins, error_outs; + int handled = 0; + int i; + + notify_ins = notify_outs = error_ins = error_outs = 0; + spin_lock(&chip->reg_lock); + for (;;) { + unsigned int status, in_sts, out_sts; + unsigned int reg; + + status = lola_readl(chip, BAR1, DINTSTS); + if (!status || status == -1) + break; + + in_sts = lola_readl(chip, BAR1, DIINTSTS); + out_sts = lola_readl(chip, BAR1, DOINTSTS); + + /* clear Input Interrupts */ + for (i = 0; in_sts && i < chip->pcm[CAPT].num_streams; i++) { + if (!(in_sts & (1 << i))) + continue; + in_sts &= ~(1 << i); + reg = lola_dsd_read(chip, i, STS); + if (reg & LOLA_DSD_STS_DESE) /* error */ + error_ins |= (1 << i); + if (reg & LOLA_DSD_STS_BCIS) /* notify */ + notify_ins |= (1 << i); + /* clear */ + lola_dsd_write(chip, i, STS, reg); + } + + /* clear Output Interrupts */ + for (i = 0; out_sts && i < chip->pcm[PLAY].num_streams; i++) { + if (!(out_sts & (1 << i))) + continue; + out_sts &= ~(1 << i); + reg = lola_dsd_read(chip, i + MAX_STREAM_IN_COUNT, STS); + if (reg & LOLA_DSD_STS_DESE) /* error */ + error_outs |= (1 << i); + if (reg & LOLA_DSD_STS_BCIS) /* notify */ + notify_outs |= (1 << i); + lola_dsd_write(chip, i + MAX_STREAM_IN_COUNT, STS, reg); + } + + if (status & LOLA_DINT_CTRL) { + unsigned char rbsts; /* ring status is byte access */ + rbsts = lola_readb(chip, BAR0, RIRBSTS); + rbsts &= LOLA_RIRB_INT_MASK; + if (rbsts) + lola_writeb(chip, BAR0, RIRBSTS, rbsts); + rbsts = lola_readb(chip, BAR0, CORBSTS); + rbsts &= LOLA_CORB_INT_MASK; + if (rbsts) + lola_writeb(chip, BAR0, CORBSTS, rbsts); + + lola_update_rirb(chip); + } + + if (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR)) { + /* clear global fifo error interrupt */ + lola_writel(chip, BAR1, DINTSTS, + (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR))); + } + handled = 1; + } + spin_unlock(&chip->reg_lock); + + lola_pcm_update(chip, &chip->pcm[CAPT], notify_ins); + lola_pcm_update(chip, &chip->pcm[PLAY], notify_outs); + + return IRQ_RETVAL(handled); +} + + +/* + * controller + */ +static int reset_controller(struct lola *chip) +{ + unsigned int gctl = lola_readl(chip, BAR0, GCTL); + unsigned long end_time; + + if (gctl) { + /* to be sure */ + lola_writel(chip, BAR1, BOARD_MODE, 0); + return 0; + } + + chip->cold_reset = 1; + lola_writel(chip, BAR0, GCTL, LOLA_GCTL_RESET); + end_time = jiffies + msecs_to_jiffies(200); + do { + msleep(1); + gctl = lola_readl(chip, BAR0, GCTL); + if (gctl) + break; + } while (time_before(jiffies, end_time)); + if (!gctl) { + printk(KERN_ERR SFX "cannot reset controller\n"); + return -EIO; + } + return 0; +} + +static void lola_irq_enable(struct lola *chip) +{ + unsigned int val; + + /* enalbe all I/O streams */ + val = (1 << chip->pcm[PLAY].num_streams) - 1; + lola_writel(chip, BAR1, DOINTCTL, val); + val = (1 << chip->pcm[CAPT].num_streams) - 1; + lola_writel(chip, BAR1, DIINTCTL, val); + + /* enable global irqs */ + val = LOLA_DINT_GLOBAL | LOLA_DINT_CTRL | LOLA_DINT_FIFOERR | + LOLA_DINT_MUERR; + lola_writel(chip, BAR1, DINTCTL, val); +} + +static void lola_irq_disable(struct lola *chip) +{ + lola_writel(chip, BAR1, DINTCTL, 0); + lola_writel(chip, BAR1, DIINTCTL, 0); + lola_writel(chip, BAR1, DOINTCTL, 0); +} + +static int setup_corb_rirb(struct lola *chip) +{ + int err; + unsigned char tmp; + unsigned long end_time; + + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + PAGE_SIZE, &chip->rb); + if (err < 0) + return err; + + chip->corb.addr = chip->rb.addr; + chip->corb.buf = (u32 *)chip->rb.area; + chip->rirb.addr = chip->rb.addr + 2048; + chip->rirb.buf = (u32 *)(chip->rb.area + 2048); + + /* disable ringbuffer DMAs */ + lola_writeb(chip, BAR0, RIRBCTL, 0); + lola_writeb(chip, BAR0, CORBCTL, 0); + + end_time = jiffies + msecs_to_jiffies(200); + do { + if (!lola_readb(chip, BAR0, RIRBCTL) && + !lola_readb(chip, BAR0, CORBCTL)) + break; + msleep(1); + } while (time_before(jiffies, end_time)); + + /* CORB set up */ + lola_writel(chip, BAR0, CORBLBASE, (u32)chip->corb.addr); + lola_writel(chip, BAR0, CORBUBASE, upper_32_bits(chip->corb.addr)); + /* set the corb size to 256 entries */ + lola_writeb(chip, BAR0, CORBSIZE, 0x02); + /* set the corb write pointer to 0 */ + lola_writew(chip, BAR0, CORBWP, 0); + /* reset the corb hw read pointer */ + lola_writew(chip, BAR0, CORBRP, LOLA_RBRWP_CLR); + /* enable corb dma */ + lola_writeb(chip, BAR0, CORBCTL, LOLA_RBCTL_DMA_EN); + /* clear flags if set */ + tmp = lola_readb(chip, BAR0, CORBSTS) & LOLA_CORB_INT_MASK; + if (tmp) + lola_writeb(chip, BAR0, CORBSTS, tmp); + chip->corb.wp = 0; + + /* RIRB set up */ + lola_writel(chip, BAR0, RIRBLBASE, (u32)chip->rirb.addr); + lola_writel(chip, BAR0, RIRBUBASE, upper_32_bits(chip->rirb.addr)); + /* set the rirb size to 256 entries */ + lola_writeb(chip, BAR0, RIRBSIZE, 0x02); + /* reset the rirb hw write pointer */ + lola_writew(chip, BAR0, RIRBWP, LOLA_RBRWP_CLR); + /* set N=1, get RIRB response interrupt for new entry */ + lola_writew(chip, BAR0, RINTCNT, 1); + /* enable rirb dma and response irq */ + lola_writeb(chip, BAR0, RIRBCTL, LOLA_RBCTL_DMA_EN | LOLA_RBCTL_IRQ_EN); + /* clear flags if set */ + tmp = lola_readb(chip, BAR0, RIRBSTS) & LOLA_RIRB_INT_MASK; + if (tmp) + lola_writeb(chip, BAR0, RIRBSTS, tmp); + chip->rirb.rp = chip->rirb.cmds = 0; + + return 0; +} + +static void stop_corb_rirb(struct lola *chip) +{ + /* disable ringbuffer DMAs */ + lola_writeb(chip, BAR0, RIRBCTL, 0); + lola_writeb(chip, BAR0, CORBCTL, 0); +} + +static void lola_reset_setups(struct lola *chip) +{ + /* update the granularity */ + lola_set_granularity(chip, chip->granularity, true); + /* update the sample clock */ + lola_set_clock_index(chip, chip->clock.cur_index); + /* enable unsolicited events of the clock widget */ + lola_enable_clock_events(chip); + /* update the analog gains */ + lola_setup_all_analog_gains(chip, CAPT, false); /* input, update */ + /* update SRC configuration if applicable */ + lola_set_src_config(chip, chip->input_src_mask, false); + /* update the analog outputs */ + lola_setup_all_analog_gains(chip, PLAY, false); /* output, update */ +} + +static int lola_parse_tree(struct lola *chip) +{ + unsigned int val; + int nid, err; + + err = lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read VENDOR_ID\n"); + return err; + } + val >>= 16; + if (val != 0x1369) { + printk(KERN_ERR SFX "Unknown codec vendor 0x%x\n", val); + return -EINVAL; + } + + err = lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read FUNCTION_TYPE for 0x%x\n", nid); + return err; + } + if (val != 1) { + printk(KERN_ERR SFX "Unknown function type %d\n", val); + return -EINVAL; + } + + err = lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read SPECCAPS\n"); + return err; + } + chip->lola_caps = val; + chip->pin[CAPT].num_pins = LOLA_AFG_INPUT_PIN_COUNT(chip->lola_caps); + chip->pin[PLAY].num_pins = LOLA_AFG_OUTPUT_PIN_COUNT(chip->lola_caps); + snd_printdd(SFX "speccaps=0x%x, pins in=%d, out=%d\n", + chip->lola_caps, + chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins); + + if (chip->pin[CAPT].num_pins > MAX_AUDIO_INOUT_COUNT || + chip->pin[PLAY].num_pins > MAX_AUDIO_INOUT_COUNT) { + printk(KERN_ERR SFX "Invalid Lola-spec caps 0x%x\n", val); + return -EINVAL; + } + + nid = 0x02; + err = lola_init_pcm(chip, CAPT, &nid); + if (err < 0) + return err; + err = lola_init_pcm(chip, PLAY, &nid); + if (err < 0) + return err; + + err = lola_init_pins(chip, CAPT, &nid); + if (err < 0) + return err; + err = lola_init_pins(chip, PLAY, &nid); + if (err < 0) + return err; + + if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) { + err = lola_init_clock_widget(chip, nid); + if (err < 0) + return err; + nid++; + } + if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) { + err = lola_init_mixer_widget(chip, nid); + if (err < 0) + return err; + nid++; + } + + /* enable unsolicited events of the clock widget */ + err = lola_enable_clock_events(chip); + if (err < 0) + return err; + + /* if last ResetController was not a ColdReset, we don't know + * the state of the card; initialize here again + */ + if (!chip->cold_reset) { + lola_reset_setups(chip); + chip->cold_reset = 1; + } else { + /* set the granularity if it is not the default */ + if (chip->granularity != LOLA_GRANULARITY_MIN) + lola_set_granularity(chip, chip->granularity, true); + } + + return 0; +} + +static void lola_stop_hw(struct lola *chip) +{ + stop_corb_rirb(chip); + lola_irq_disable(chip); +} + +static void lola_free(struct lola *chip) +{ + if (chip->initialized) + lola_stop_hw(chip); + lola_free_pcm(chip); + lola_free_mixer(chip); + if (chip->irq >= 0) + free_irq(chip->irq, (void *)chip); + if (chip->bar[0].remap_addr) + iounmap(chip->bar[0].remap_addr); + if (chip->bar[1].remap_addr) + iounmap(chip->bar[1].remap_addr); + if (chip->rb.area) + snd_dma_free_pages(&chip->rb); + pci_release_regions(chip->pci); + pci_disable_device(chip->pci); + kfree(chip); +} + +static int lola_dev_free(struct snd_device *device) +{ + lola_free(device->device_data); + return 0; +} + +static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, + int dev, struct lola **rchip) +{ + struct lola *chip; + int err; + unsigned int dever; + static struct snd_device_ops ops = { + .dev_free = lola_dev_free, + }; + + *rchip = NULL; + + err = pci_enable_device(pci); + if (err < 0) + return err; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { + snd_printk(KERN_ERR SFX "cannot allocate chip\n"); + pci_disable_device(pci); + return -ENOMEM; + } + + spin_lock_init(&chip->reg_lock); + mutex_init(&chip->open_mutex); + chip->card = card; + chip->pci = pci; + chip->irq = -1; + + chip->granularity = granularity[dev]; + switch (chip->granularity) { + case 8: + chip->sample_rate_max = 48000; + break; + case 16: + chip->sample_rate_max = 96000; + break; + case 32: + chip->sample_rate_max = 192000; + break; + default: + snd_printk(KERN_WARNING SFX + "Invalid granularity %d, reset to %d\n", + chip->granularity, LOLA_GRANULARITY_MAX); + chip->granularity = LOLA_GRANULARITY_MAX; + chip->sample_rate_max = 192000; + break; + } + chip->sample_rate_min = sample_rate_min[dev]; + if (chip->sample_rate_min > chip->sample_rate_max) { + snd_printk(KERN_WARNING SFX + "Invalid sample_rate_min %d, reset to 16000\n", + chip->sample_rate_min); + chip->sample_rate_min = 16000; + } + + err = pci_request_regions(pci, DRVNAME); + if (err < 0) { + kfree(chip); + pci_disable_device(pci); + return err; + } + + chip->bar[0].addr = pci_resource_start(pci, 0); + chip->bar[0].remap_addr = pci_ioremap_bar(pci, 0); + chip->bar[1].addr = pci_resource_start(pci, 2); + chip->bar[1].remap_addr = pci_ioremap_bar(pci, 2); + if (!chip->bar[0].remap_addr || !chip->bar[1].remap_addr) { + snd_printk(KERN_ERR SFX "ioremap error\n"); + err = -ENXIO; + goto errout; + } + + pci_set_master(pci); + + err = reset_controller(chip); + if (err < 0) + goto errout; + + if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED, + DRVNAME, chip)) { + printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); + err = -EBUSY; + goto errout; + } + chip->irq = pci->irq; + synchronize_irq(chip->irq); + + dever = lola_readl(chip, BAR1, DEVER); + chip->pcm[CAPT].num_streams = (dever >> 0) & 0x3ff; + chip->pcm[PLAY].num_streams = (dever >> 10) & 0x3ff; + chip->version = (dever >> 24) & 0xff; + snd_printdd(SFX "streams in=%d, out=%d, version=0x%x\n", + chip->pcm[CAPT].num_streams, chip->pcm[PLAY].num_streams, + chip->version); + + /* Test LOLA_BAR1_DEVER */ + if (chip->pcm[CAPT].num_streams > MAX_STREAM_IN_COUNT || + chip->pcm[PLAY].num_streams > MAX_STREAM_OUT_COUNT || + (!chip->pcm[CAPT].num_streams && + !chip->pcm[PLAY].num_streams)) { + printk(KERN_ERR SFX "invalid DEVER = %x\n", dever); + err = -EINVAL; + goto errout; + } + + err = setup_corb_rirb(chip); + if (err < 0) + goto errout; + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); + goto errout; + } + + strcpy(card->driver, "Lola"); + strlcpy(card->shortname, "Digigram Lola", sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx irq %i", + card->shortname, chip->bar[0].addr, chip->irq); + strcpy(card->mixername, card->shortname); + + lola_irq_enable(chip); + + chip->initialized = 1; + *rchip = chip; + return 0; + + errout: + lola_free(chip); + return err; +} + +static int __devinit lola_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + static int dev; + struct snd_card *card; + struct lola *chip; + int err; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + if (err < 0) { + snd_printk(KERN_ERR SFX "Error creating card!\n"); + return err; + } + + snd_card_set_dev(card, &pci->dev); + + err = lola_create(card, pci, dev, &chip); + if (err < 0) + goto out_free; + card->private_data = chip; + + err = lola_parse_tree(chip); + if (err < 0) + goto out_free; + + err = lola_create_pcm(chip); + if (err < 0) + goto out_free; + + err = lola_create_mixer(chip); + if (err < 0) + goto out_free; + + lola_proc_debug_new(chip); + + err = snd_card_register(card); + if (err < 0) + goto out_free; + + pci_set_drvdata(pci, card); + dev++; + return err; +out_free: + snd_card_free(card); + return err; +} + +static void __devexit lola_remove(struct pci_dev *pci) +{ + snd_card_free(pci_get_drvdata(pci)); + pci_set_drvdata(pci, NULL); +} + +/* PCI IDs */ +static DEFINE_PCI_DEVICE_TABLE(lola_ids) = { + { PCI_VDEVICE(DIGIGRAM, 0x0001) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, lola_ids); + +/* pci_driver definition */ +static struct pci_driver driver = { + .name = DRVNAME, + .id_table = lola_ids, + .probe = lola_probe, + .remove = __devexit_p(lola_remove), +}; + +static int __init alsa_card_lola_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_lola_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_lola_init) +module_exit(alsa_card_lola_exit) diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h new file mode 100644 index 00000000000..d5708e29b16 --- /dev/null +++ b/sound/pci/lola/lola.h @@ -0,0 +1,527 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _LOLA_H +#define _LOLA_H + +#define DRVNAME "snd-lola" +#define SFX DRVNAME ": " + +/* + * Lola HD Audio Registers BAR0 + */ +#define LOLA_BAR0_GCAP 0x00 +#define LOLA_BAR0_VMIN 0x02 +#define LOLA_BAR0_VMAJ 0x03 +#define LOLA_BAR0_OUTPAY 0x04 +#define LOLA_BAR0_INPAY 0x06 +#define LOLA_BAR0_GCTL 0x08 +#define LOLA_BAR0_WAKEEN 0x0c +#define LOLA_BAR0_STATESTS 0x0e +#define LOLA_BAR0_GSTS 0x10 +#define LOLA_BAR0_OUTSTRMPAY 0x18 +#define LOLA_BAR0_INSTRMPAY 0x1a +#define LOLA_BAR0_INTCTL 0x20 +#define LOLA_BAR0_INTSTS 0x24 +#define LOLA_BAR0_WALCLK 0x30 +#define LOLA_BAR0_SSYNC 0x38 + +#define LOLA_BAR0_CORBLBASE 0x40 +#define LOLA_BAR0_CORBUBASE 0x44 +#define LOLA_BAR0_CORBWP 0x48 /* no ULONG access */ +#define LOLA_BAR0_CORBRP 0x4a /* no ULONG access */ +#define LOLA_BAR0_CORBCTL 0x4c /* no ULONG access */ +#define LOLA_BAR0_CORBSTS 0x4d /* UCHAR access only */ +#define LOLA_BAR0_CORBSIZE 0x4e /* no ULONG access */ + +#define LOLA_BAR0_RIRBLBASE 0x50 +#define LOLA_BAR0_RIRBUBASE 0x54 +#define LOLA_BAR0_RIRBWP 0x58 +#define LOLA_BAR0_RINTCNT 0x5a /* no ULONG access */ +#define LOLA_BAR0_RIRBCTL 0x5c +#define LOLA_BAR0_RIRBSTS 0x5d /* UCHAR access only */ +#define LOLA_BAR0_RIRBSIZE 0x5e /* no ULONG access */ + +#define LOLA_BAR0_ICW 0x60 +#define LOLA_BAR0_IRR 0x64 +#define LOLA_BAR0_ICS 0x68 +#define LOLA_BAR0_DPLBASE 0x70 +#define LOLA_BAR0_DPUBASE 0x74 + +/* stream register offsets from stream base 0x80 */ +#define LOLA_BAR0_SD0_OFFSET 0x80 +#define LOLA_REG0_SD_CTL 0x00 +#define LOLA_REG0_SD_STS 0x03 +#define LOLA_REG0_SD_LPIB 0x04 +#define LOLA_REG0_SD_CBL 0x08 +#define LOLA_REG0_SD_LVI 0x0c +#define LOLA_REG0_SD_FIFOW 0x0e +#define LOLA_REG0_SD_FIFOSIZE 0x10 +#define LOLA_REG0_SD_FORMAT 0x12 +#define LOLA_REG0_SD_BDLPL 0x18 +#define LOLA_REG0_SD_BDLPU 0x1c + +/* + * Lola Digigram Registers BAR1 + */ +#define LOLA_BAR1_FPGAVER 0x00 +#define LOLA_BAR1_DEVER 0x04 +#define LOLA_BAR1_UCBMV 0x08 +#define LOLA_BAR1_JTAG 0x0c +#define LOLA_BAR1_UARTRX 0x10 +#define LOLA_BAR1_UARTTX 0x14 +#define LOLA_BAR1_UARTCR 0x18 +#define LOLA_BAR1_NVRAMVER 0x1c +#define LOLA_BAR1_CTRLSPI 0x20 +#define LOLA_BAR1_DSPI 0x24 +#define LOLA_BAR1_AISPI 0x28 +#define LOLA_BAR1_GRAN 0x2c + +#define LOLA_BAR1_DINTCTL 0x80 +#define LOLA_BAR1_DIINTCTL 0x84 +#define LOLA_BAR1_DOINTCTL 0x88 +#define LOLA_BAR1_LRC 0x90 +#define LOLA_BAR1_DINTSTS 0x94 +#define LOLA_BAR1_DIINTSTS 0x98 +#define LOLA_BAR1_DOINTSTS 0x9c + +#define LOLA_BAR1_DSD0_OFFSET 0xa0 +#define LOLA_BAR1_DSD_SIZE 0x18 + +#define LOLA_BAR1_DSDnSTS 0x00 +#define LOLA_BAR1_DSDnLPIB 0x04 +#define LOLA_BAR1_DSDnCTL 0x08 +#define LOLA_BAR1_DSDnLVI 0x0c +#define LOLA_BAR1_DSDnBDPL 0x10 +#define LOLA_BAR1_DSDnBDPU 0x14 + +#define LOLA_BAR1_SSYNC 0x03e8 + +#define LOLA_BAR1_BOARD_CTRL 0x0f00 +#define LOLA_BAR1_BOARD_MODE 0x0f02 + +#define LOLA_BAR1_SOURCE_GAIN_ENABLE 0x1000 +#define LOLA_BAR1_DEST00_MIX_GAIN_ENABLE 0x1004 +#define LOLA_BAR1_DEST31_MIX_GAIN_ENABLE 0x1080 +#define LOLA_BAR1_SOURCE00_01_GAIN 0x1084 +#define LOLA_BAR1_SOURCE30_31_GAIN 0x10c0 +#define LOLA_BAR1_SOURCE_GAIN(src) \ + (LOLA_BAR1_SOURCE00_01_GAIN + (src) * 2) +#define LOLA_BAR1_DEST00_MIX00_01_GAIN 0x10c4 +#define LOLA_BAR1_DEST00_MIX30_31_GAIN 0x1100 +#define LOLA_BAR1_DEST01_MIX00_01_GAIN 0x1104 +#define LOLA_BAR1_DEST01_MIX30_31_GAIN 0x1140 +#define LOLA_BAR1_DEST31_MIX00_01_GAIN 0x1884 +#define LOLA_BAR1_DEST31_MIX30_31_GAIN 0x18c0 +#define LOLA_BAR1_MIX_GAIN(dest, mix) \ + (LOLA_BAR1_DEST00_MIX00_01_GAIN + (dest) * 0x40 + (mix) * 2) +#define LOLA_BAR1_ANALOG_CLIP_IN 0x18c4 +#define LOLA_BAR1_PEAKMETERS_SOURCE00_01 0x18c8 +#define LOLA_BAR1_PEAKMETERS_SOURCE30_31 0x1904 +#define LOLA_BAR1_PEAKMETERS_SOURCE(src) \ + (LOLA_BAR1_PEAKMETERS_SOURCE00_01 + (src) * 2) +#define LOLA_BAR1_PEAKMETERS_DEST00_01 0x1908 +#define LOLA_BAR1_PEAKMETERS_DEST30_31 0x1944 +#define LOLA_BAR1_PEAKMETERS_DEST(dest) \ + (LOLA_BAR1_PEAKMETERS_DEST00_01 + (dest) * 2) +#define LOLA_BAR1_PEAKMETERS_AGC00_01 0x1948 +#define LOLA_BAR1_PEAKMETERS_AGC14_15 0x1964 +#define LOLA_BAR1_PEAKMETERS_AGC(x) \ + (LOLA_BAR1_PEAKMETERS_AGC00_01 + (x) * 2) + +/* GCTL reset bit */ +#define LOLA_GCTL_RESET (1 << 0) +/* GCTL unsolicited response enable bit */ +#define LOLA_GCTL_UREN (1 << 8) + +/* CORB/RIRB control, read/write pointer */ +#define LOLA_RBCTL_DMA_EN 0x02 /* enable DMA */ +#define LOLA_RBCTL_IRQ_EN 0x01 /* enable IRQ */ +#define LOLA_RBRWP_CLR 0x8000 /* read/write pointer clear */ + +#define LOLA_RIRB_EX_UNSOL_EV 0x40000000 +#define LOLA_RIRB_EX_ERROR 0x80000000 + +/* CORB int mask: CMEI[0] */ +#define LOLA_CORB_INT_CMEI 0x01 +#define LOLA_CORB_INT_MASK LOLA_CORB_INT_CMEI + +/* RIRB int mask: overrun[2], response[0] */ +#define LOLA_RIRB_INT_RESPONSE 0x01 +#define LOLA_RIRB_INT_OVERRUN 0x04 +#define LOLA_RIRB_INT_MASK (LOLA_RIRB_INT_RESPONSE | LOLA_RIRB_INT_OVERRUN) + +/* DINTCTL and DINTSTS */ +#define LOLA_DINT_GLOBAL 0x80000000 /* global interrupt enable bit */ +#define LOLA_DINT_CTRL 0x40000000 /* controller interrupt enable bit */ +#define LOLA_DINT_FIFOERR 0x20000000 /* global fifo error enable bit */ +#define LOLA_DINT_MUERR 0x10000000 /* global microcontroller underrun error */ + +/* DSDnCTL bits */ +#define LOLA_DSD_CTL_SRST 0x01 /* stream reset bit */ +#define LOLA_DSD_CTL_SRUN 0x02 /* stream DMA start bit */ +#define LOLA_DSD_CTL_IOCE 0x04 /* interrupt on completion enable */ +#define LOLA_DSD_CTL_DEIE 0x10 /* descriptor error interrupt enable */ +#define LOLA_DSD_CTL_VLRCV 0x20 /* valid LRCountValue information in bits 8..31 */ +#define LOLA_LRC_MASK 0xffffff00 + +/* DSDnSTS */ +#define LOLA_DSD_STS_BCIS 0x04 /* buffer completion interrupt status */ +#define LOLA_DSD_STS_DESE 0x10 /* descriptor error interrupt */ +#define LOLA_DSD_STS_FIFORDY 0x20 /* fifo ready */ + +#define LOLA_CORB_ENTRIES 256 + +#define MAX_STREAM_IN_COUNT 16 +#define MAX_STREAM_OUT_COUNT 16 +#define MAX_STREAM_COUNT 16 +#define MAX_PINS MAX_STREAM_COUNT +#define MAX_STREAM_BUFFER_COUNT 16 +#define MAX_AUDIO_INOUT_COUNT 16 + +#define LOLA_CLOCK_TYPE_INTERNAL 0 +#define LOLA_CLOCK_TYPE_AES 1 +#define LOLA_CLOCK_TYPE_AES_SYNC 2 +#define LOLA_CLOCK_TYPE_WORDCLOCK 3 +#define LOLA_CLOCK_TYPE_ETHERSOUND 4 +#define LOLA_CLOCK_TYPE_VIDEO 5 + +#define LOLA_CLOCK_FORMAT_NONE 0 +#define LOLA_CLOCK_FORMAT_NTSC 1 +#define LOLA_CLOCK_FORMAT_PAL 2 + +#define MAX_SAMPLE_CLOCK_COUNT 48 + +/* parameters used with mixer widget's mixer capabilities */ +#define LOLA_PEAK_METER_CAN_AGC_MASK 1 +#define LOLA_PEAK_METER_CAN_ANALOG_CLIP_MASK 2 + +struct lola_bar { + unsigned long addr; + void __iomem *remap_addr; +}; + +/* CORB/RIRB */ +struct lola_rb { + u32 *buf; /* CORB/RIRB buffer, 8 byte per each entry */ + dma_addr_t addr; /* physical address of CORB/RIRB buffer */ + unsigned short rp, wp; /* read/write pointers */ + int cmds; /* number of pending requests */ +}; + +/* Pin widget setup */ +struct lola_pin { + unsigned int nid; + bool is_analog; + unsigned int amp_mute; + unsigned int amp_step_size; + unsigned int amp_num_steps; + unsigned int amp_offset; + unsigned int max_level; + unsigned int config_default_reg; + unsigned int fixed_gain_list_len; + unsigned int cur_gain_step; +}; + +struct lola_pin_array { + unsigned int num_pins; + unsigned int num_analog_pins; + struct lola_pin pins[MAX_PINS]; +}; + +/* Clock widget setup */ +struct lola_sample_clock { + unsigned int type; + unsigned int format; + unsigned int freq; +}; + +struct lola_clock_widget { + unsigned int nid; + unsigned int items; + unsigned int cur_index; + unsigned int cur_freq; + bool cur_valid; + struct lola_sample_clock sample_clock[MAX_SAMPLE_CLOCK_COUNT]; + unsigned int idx_lookup[MAX_SAMPLE_CLOCK_COUNT]; +}; + +#define LOLA_MIXER_DIM 32 +struct lola_mixer_array { + u32 src_gain_enable; + u32 dest_mix_gain_enable[LOLA_MIXER_DIM]; + u16 src_gain[LOLA_MIXER_DIM]; + u16 dest_mix_gain[LOLA_MIXER_DIM][LOLA_MIXER_DIM]; +}; + +/* Mixer widget setup */ +struct lola_mixer_widget { + unsigned int nid; + unsigned int caps; + struct lola_mixer_array __user *array; + struct lola_mixer_array *array_saved; + unsigned int src_stream_outs; + unsigned int src_phys_ins; + unsigned int dest_stream_ins; + unsigned int dest_phys_outs; + unsigned int src_stream_out_ofs; + unsigned int dest_phys_out_ofs; + unsigned int src_mask; + unsigned int dest_mask; +}; + +/* Audio stream */ +struct lola_stream { + unsigned int nid; /* audio widget NID */ + unsigned int index; /* array index */ + unsigned int dsd; /* DSD index */ + bool can_float; + struct snd_pcm_substream *substream; /* assigned PCM substream */ + struct lola_stream *master; /* master stream (for multi-channel) */ + + /* buffer setup */ + unsigned int bufsize; + unsigned int period_bytes; + unsigned int frags; + + /* format + channel setup */ + unsigned int format_verb; + + /* flags */ + unsigned int opened:1; + unsigned int prepared:1; + unsigned int paused:1; + unsigned int running:1; +}; + +#define PLAY SNDRV_PCM_STREAM_PLAYBACK +#define CAPT SNDRV_PCM_STREAM_CAPTURE + +struct lola_pcm { + unsigned int num_streams; + struct snd_dma_buffer bdl; /* BDL buffer */ + struct lola_stream streams[MAX_STREAM_COUNT]; +}; + +/* card instance */ +struct lola { + struct snd_card *card; + struct pci_dev *pci; + + /* pci resources */ + struct lola_bar bar[2]; + int irq; + + /* locks */ + spinlock_t reg_lock; + struct mutex open_mutex; + + /* CORB/RIRB */ + struct lola_rb corb; + struct lola_rb rirb; + unsigned int res, res_ex; /* last read values */ + /* last command (for debugging) */ + unsigned int last_cmd_nid, last_verb, last_data, last_extdata; + + /* CORB/RIRB buffers */ + struct snd_dma_buffer rb; + + /* unsolicited events */ + unsigned int last_unsol_res; + + /* streams */ + struct lola_pcm pcm[2]; + + /* input src */ + unsigned int input_src_caps_mask; + unsigned int input_src_mask; + + /* pins */ + struct lola_pin_array pin[2]; + + /* clock */ + struct lola_clock_widget clock; + int ref_count_rate; + unsigned int sample_rate; + + /* mixer */ + struct lola_mixer_widget mixer; + + /* hw info */ + unsigned int version; + unsigned int lola_caps; + + /* parameters */ + unsigned int granularity; + unsigned int sample_rate_min; + unsigned int sample_rate_max; + + /* flags */ + unsigned int initialized:1; + unsigned int cold_reset:1; + unsigned int polling_mode:1; + + /* for debugging */ + unsigned int debug_res; + unsigned int debug_res_ex; +}; + +#define BAR0 0 +#define BAR1 1 + +/* Helper macros */ +#define lola_readl(chip, idx, name) \ + readl((chip)->bar[idx].remap_addr + LOLA_##idx##_##name) +#define lola_readw(chip, idx, name) \ + readw((chip)->bar[idx].remap_addr + LOLA_##idx##_##name) +#define lola_readb(chip, idx, name) \ + readb((chip)->bar[idx].remap_addr + LOLA_##idx##_##name) +#define lola_writel(chip, idx, name, val) \ + writel((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name) +#define lola_writew(chip, idx, name, val) \ + writew((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name) +#define lola_writeb(chip, idx, name, val) \ + writeb((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name) + +#define lola_dsd_read(chip, dsd, name) \ + readl((chip)->bar[BAR1].remap_addr + LOLA_BAR1_DSD0_OFFSET + \ + (LOLA_BAR1_DSD_SIZE * (dsd)) + LOLA_BAR1_DSDn##name) +#define lola_dsd_write(chip, dsd, name, val) \ + writel((val), (chip)->bar[BAR1].remap_addr + LOLA_BAR1_DSD0_OFFSET + \ + (LOLA_BAR1_DSD_SIZE * (dsd)) + LOLA_BAR1_DSDn##name) + +/* GET verbs HDAudio */ +#define LOLA_VERB_GET_STREAM_FORMAT 0xa00 +#define LOLA_VERB_GET_AMP_GAIN_MUTE 0xb00 +#define LOLA_VERB_PARAMETERS 0xf00 +#define LOLA_VERB_GET_POWER_STATE 0xf05 +#define LOLA_VERB_GET_CONV 0xf06 +#define LOLA_VERB_GET_UNSOLICITED_RESPONSE 0xf08 +#define LOLA_VERB_GET_DIGI_CONVERT_1 0xf0d +#define LOLA_VERB_GET_CONFIG_DEFAULT 0xf1c +#define LOLA_VERB_GET_SUBSYSTEM_ID 0xf20 +/* GET verbs Digigram */ +#define LOLA_VERB_GET_FIXED_GAIN 0xfc0 +#define LOLA_VERB_GET_GAIN_SELECT 0xfc1 +#define LOLA_VERB_GET_MAX_LEVEL 0xfc2 +#define LOLA_VERB_GET_CLOCK_LIST 0xfc3 +#define LOLA_VERB_GET_CLOCK_SELECT 0xfc4 +#define LOLA_VERB_GET_CLOCK_STATUS 0xfc5 + +/* SET verbs HDAudio */ +#define LOLA_VERB_SET_STREAM_FORMAT 0x200 +#define LOLA_VERB_SET_AMP_GAIN_MUTE 0x300 +#define LOLA_VERB_SET_POWER_STATE 0x705 +#define LOLA_VERB_SET_CHANNEL_STREAMID 0x706 +#define LOLA_VERB_SET_UNSOLICITED_ENABLE 0x708 +#define LOLA_VERB_SET_DIGI_CONVERT_1 0x70d +/* SET verbs Digigram */ +#define LOLA_VERB_SET_GAIN_SELECT 0xf81 +#define LOLA_VERB_SET_CLOCK_SELECT 0xf84 +#define LOLA_VERB_SET_GRANULARITY_STEPS 0xf86 +#define LOLA_VERB_SET_SOURCE_GAIN 0xf87 +#define LOLA_VERB_SET_MIX_GAIN 0xf88 +#define LOLA_VERB_SET_DESTINATION_GAIN 0xf89 +#define LOLA_VERB_SET_SRC 0xf8a + +/* Parameter IDs used with LOLA_VERB_PARAMETERS */ +#define LOLA_PAR_VENDOR_ID 0x00 +#define LOLA_PAR_FUNCTION_TYPE 0x05 +#define LOLA_PAR_AUDIO_WIDGET_CAP 0x09 +#define LOLA_PAR_PCM 0x0a +#define LOLA_PAR_STREAM_FORMATS 0x0b +#define LOLA_PAR_PIN_CAP 0x0c +#define LOLA_PAR_AMP_IN_CAP 0x0d +#define LOLA_PAR_CONNLIST_LEN 0x0e +#define LOLA_PAR_POWER_STATE 0x0f +#define LOLA_PAR_GPIO_CAP 0x11 +#define LOLA_PAR_AMP_OUT_CAP 0x12 +#define LOLA_PAR_SPECIFIC_CAPS 0x80 +#define LOLA_PAR_FIXED_GAIN_LIST 0x81 + +/* extract results of LOLA_PAR_SPECIFIC_CAPS */ +#define LOLA_AFG_MIXER_WIDGET_PRESENT(res) ((res & (1 << 21)) != 0) +#define LOLA_AFG_CLOCK_WIDGET_PRESENT(res) ((res & (1 << 20)) != 0) +#define LOLA_AFG_INPUT_PIN_COUNT(res) ((res >> 10) & 0x2ff) +#define LOLA_AFG_OUTPUT_PIN_COUNT(res) ((res) & 0x2ff) + +/* extract results of LOLA_PAR_AMP_IN_CAP / LOLA_PAR_AMP_OUT_CAP */ +#define LOLA_AMP_MUTE_CAPABLE(res) ((res & (1 << 31)) != 0) +#define LOLA_AMP_STEP_SIZE(res) ((res >> 24) & 0x7f) +#define LOLA_AMP_NUM_STEPS(res) ((res >> 12) & 0x3ff) +#define LOLA_AMP_OFFSET(res) ((res) & 0x3ff) + +#define LOLA_GRANULARITY_MIN 8 +#define LOLA_GRANULARITY_MAX 32 +#define LOLA_GRANULARITY_STEP 8 + +/* parameters used with unsolicited command/response */ +#define LOLA_UNSOLICITED_TAG_MASK 0x3f +#define LOLA_UNSOLICITED_TAG 0x1a +#define LOLA_UNSOLICITED_ENABLE 0x80 +#define LOLA_UNSOL_RESP_TAG_OFFSET 26 + +/* count values in the Vendor Specific Mixer Widget's Audio Widget Capabilities */ +#define LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(res) ((res >> 2) & 0x1f) +#define LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(res) ((res >> 7) & 0x1f) + +int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb, + unsigned int data, unsigned int extdata); +int lola_codec_read(struct lola *chip, unsigned int nid, unsigned int verb, + unsigned int data, unsigned int extdata, + unsigned int *val, unsigned int *extval); +int lola_codec_flush(struct lola *chip); +#define lola_read_param(chip, nid, param, val) \ + lola_codec_read(chip, nid, LOLA_VERB_PARAMETERS, param, 0, val, NULL) + +/* PCM */ +int lola_create_pcm(struct lola *chip); +void lola_free_pcm(struct lola *chip); +int lola_init_pcm(struct lola *chip, int dir, int *nidp); +void lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits); + +/* clock */ +int lola_init_clock_widget(struct lola *chip, int nid); +int lola_set_granularity(struct lola *chip, unsigned int val, bool force); +int lola_enable_clock_events(struct lola *chip); +int lola_set_clock_index(struct lola *chip, unsigned int idx); +int lola_set_clock(struct lola *chip, int idx); +int lola_set_sample_rate(struct lola *chip, int rate); +bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val); +unsigned int lola_sample_rate_convert(unsigned int coded); + +/* mixer */ +int lola_init_pins(struct lola *chip, int dir, int *nidp); +int lola_init_mixer_widget(struct lola *chip, int nid); +void lola_free_mixer(struct lola *chip); +int lola_create_mixer(struct lola *chip); +int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute); +void lola_save_mixer(struct lola *chip); +void lola_restore_mixer(struct lola *chip); +int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update); + +/* proc */ +#ifdef CONFIG_SND_DEBUG +void lola_proc_debug_new(struct lola *chip); +#else +#define lola_proc_debug_new(chip) +#endif + +#endif /* _LOLA_H */ diff --git a/sound/pci/lola/lola_clock.c b/sound/pci/lola/lola_clock.c new file mode 100644 index 00000000000..72f8ef0ac86 --- /dev/null +++ b/sound/pci/lola/lola_clock.c @@ -0,0 +1,323 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include "lola.h" + +unsigned int lola_sample_rate_convert(unsigned int coded) +{ + unsigned int freq; + + /* base frequency */ + switch (coded & 0x3) { + case 0: freq = 48000; break; + case 1: freq = 44100; break; + case 2: freq = 32000; break; + default: return 0; /* error */ + } + + /* multiplier / devisor */ + switch (coded & 0x1c) { + case (0 << 2): break; + case (4 << 2): break; + case (1 << 2): freq *= 2; break; + case (2 << 2): freq *= 4; break; + case (5 << 2): freq /= 2; break; + case (6 << 2): freq /= 4; break; + default: return 0; /* error */ + } + + /* ajustement */ + switch (coded & 0x60) { + case (0 << 5): break; + case (1 << 5): freq = (freq * 999) / 1000; break; + case (2 << 5): freq = (freq * 1001) / 1000; break; + default: return 0; /* error */ + } + return freq; +} + +/* + * Granualrity + */ + +#define LOLA_MAXFREQ_AT_GRANULARITY_MIN 48000 +#define LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX 96000 + +static bool check_gran_clock_compatibility(struct lola *chip, + unsigned int val, + unsigned int freq) +{ + if (!chip->granularity) + return true; + + if (val < LOLA_GRANULARITY_MIN || val > LOLA_GRANULARITY_MAX || + (val % LOLA_GRANULARITY_STEP) != 0) + return false; + + if (val == LOLA_GRANULARITY_MIN) { + if (freq > LOLA_MAXFREQ_AT_GRANULARITY_MIN) + return false; + } else if (val < LOLA_GRANULARITY_MAX) { + if (freq > LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX) + return false; + } + return true; +} + +int lola_set_granularity(struct lola *chip, unsigned int val, bool force) +{ + int err; + + if (!force) { + if (val == chip->granularity) + return 0; +#if 0 + /* change Gran only if there are no streams allocated ! */ + if (chip->audio_in_alloc_mask || chip->audio_out_alloc_mask) + return -EBUSY; +#endif + if (!check_gran_clock_compatibility(chip, val, + chip->clock.cur_freq)) + return -EINVAL; + } + + chip->granularity = val; + val /= LOLA_GRANULARITY_STEP; + + /* audio function group */ + err = lola_codec_write(chip, 1, LOLA_VERB_SET_GRANULARITY_STEPS, + val, 0); + if (err < 0) + return err; + /* this can be a very slow function !!! */ + usleep_range(400 * val, 20000); + return lola_codec_flush(chip); +} + +/* + * Clock widget handling + */ + +int __devinit lola_init_clock_widget(struct lola *chip, int nid) +{ + unsigned int val; + int i, j, nitems, nb_verbs, idx, idx_list; + int err; + + err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + return err; + } + + if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */ + snd_printdd("No valid clock widget\n"); + return 0; + } + + chip->clock.nid = nid; + chip->clock.items = val & 0xff; + snd_printdd("clock_list nid=%x, entries=%d\n", nid, + chip->clock.items); + if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) { + printk(KERN_ERR SFX "CLOCK_LIST too big: %d\n", + chip->clock.items); + return -EINVAL; + } + + nitems = chip->clock.items; + nb_verbs = (nitems + 3) / 4; + idx = 0; + idx_list = 0; + for (i = 0; i < nb_verbs; i++) { + unsigned int res_ex; + unsigned short items[4]; + + err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST, + idx, 0, &val, &res_ex); + if (err < 0) { + printk(KERN_ERR SFX "Can't read CLOCK_LIST\n"); + return -EINVAL; + } + + items[0] = val & 0xfff; + items[1] = (val >> 16) & 0xfff; + items[2] = res_ex & 0xfff; + items[3] = (res_ex >> 16) & 0xfff; + + for (j = 0; j < 4; j++) { + unsigned char type = items[j] >> 8; + unsigned int freq = items[j] & 0xff; + int format = LOLA_CLOCK_FORMAT_NONE; + bool add_clock = true; + if (type == LOLA_CLOCK_TYPE_INTERNAL) { + freq = lola_sample_rate_convert(freq); + if (freq < chip->sample_rate_min) + add_clock = false; + else if (freq == 48000) { + chip->clock.cur_index = idx_list; + chip->clock.cur_freq = 48000; + chip->clock.cur_valid = true; + } + } else if (type == LOLA_CLOCK_TYPE_VIDEO) { + freq = lola_sample_rate_convert(freq); + if (freq < chip->sample_rate_min) + add_clock = false; + /* video clock has a format (0:NTSC, 1:PAL)*/ + if (items[j] & 0x80) + format = LOLA_CLOCK_FORMAT_NTSC; + else + format = LOLA_CLOCK_FORMAT_PAL; + } + if (add_clock) { + struct lola_sample_clock *sc; + sc = &chip->clock.sample_clock[idx_list]; + sc->type = type; + sc->format = format; + sc->freq = freq; + /* keep the index used with the board */ + chip->clock.idx_lookup[idx_list] = idx; + idx_list++; + } else { + chip->clock.items--; + } + if (++idx >= nitems) + break; + } + } + return 0; +} + +/* enable unsolicited events of the clock widget */ +int lola_enable_clock_events(struct lola *chip) +{ + unsigned int res; + int err; + + err = lola_codec_read(chip, chip->clock.nid, + LOLA_VERB_SET_UNSOLICITED_ENABLE, + LOLA_UNSOLICITED_ENABLE | LOLA_UNSOLICITED_TAG, + 0, &res, NULL); + if (err < 0) + return err; + if (res) { + printk(KERN_WARNING SFX "error in enable_clock_events %d\n", + res); + return -EINVAL; + } + return 0; +} + +int lola_set_clock_index(struct lola *chip, unsigned int idx) +{ + unsigned int res; + int err; + + err = lola_codec_read(chip, chip->clock.nid, + LOLA_VERB_SET_CLOCK_SELECT, + chip->clock.idx_lookup[idx], + 0, &res, NULL); + if (err < 0) + return err; + if (res) { + printk(KERN_WARNING SFX "error in set_clock %d\n", res); + return -EINVAL; + } + return 0; +} + +bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val) +{ + unsigned int tag; + + /* the current EXTERNAL clock information gets updated by interrupt + * with an unsolicited response + */ + if (!val) + return false; + tag = (val >> LOLA_UNSOL_RESP_TAG_OFFSET) & LOLA_UNSOLICITED_TAG_MASK; + if (tag != LOLA_UNSOLICITED_TAG) + return false; + + /* only for current = external clocks */ + if (chip->clock.sample_clock[chip->clock.cur_index].type != + LOLA_CLOCK_TYPE_INTERNAL) { + chip->clock.cur_freq = lola_sample_rate_convert(val & 0x7f); + chip->clock.cur_valid = (val & 0x100) != 0; + } + return true; +} + +int lola_set_clock(struct lola *chip, int idx) +{ + int freq = 0; + bool valid = false; + + if (idx == chip->clock.cur_index) { + /* current clock is allowed */ + freq = chip->clock.cur_freq; + valid = chip->clock.cur_valid; + } else if (chip->clock.sample_clock[idx].type == + LOLA_CLOCK_TYPE_INTERNAL) { + /* internal clocks allowed */ + freq = chip->clock.sample_clock[idx].freq; + valid = true; + } + + if (!freq || !valid) + return -EINVAL; + + if (!check_gran_clock_compatibility(chip, chip->granularity, freq)) + return -EINVAL; + + if (idx != chip->clock.cur_index) { + int err = lola_set_clock_index(chip, idx); + if (err < 0) + return err; + /* update new settings */ + chip->clock.cur_index = idx; + chip->clock.cur_freq = freq; + chip->clock.cur_valid = true; + } + return 0; +} + +int lola_set_sample_rate(struct lola *chip, int rate) +{ + int i; + + if (chip->clock.cur_freq == rate && chip->clock.cur_valid) + return 0; + /* search for new dwClockIndex */ + for (i = 0; i < chip->clock.items; i++) { + if (chip->clock.sample_clock[i].type == LOLA_CLOCK_TYPE_INTERNAL && + chip->clock.sample_clock[i].freq == rate) + break; + } + if (i >= chip->clock.items) + return -EINVAL; + return lola_set_clock(chip, i); +} + diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c new file mode 100644 index 00000000000..5d518f1a712 --- /dev/null +++ b/sound/pci/lola/lola_mixer.c @@ -0,0 +1,839 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/io.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/pcm.h> +#include <sound/tlv.h> +#include "lola.h" + +static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin, + int dir, int nid) +{ + unsigned int val; + int err; + + pin->nid = nid; + err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + return err; + } + val &= 0x00f00fff; /* test TYPE and bits 0..11 */ + if (val == 0x00400200) /* Type = 4, Digital = 1 */ + pin->is_analog = false; + else if (val == 0x0040000a && dir == CAPT) /* Dig=0, InAmp/ovrd */ + pin->is_analog = true; + else if (val == 0x0040000c && dir == PLAY) /* Dig=0, OutAmp/ovrd */ + pin->is_analog = true; + else { + printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", val, nid); + return -EINVAL; + } + + /* analog parameters only following, so continue in case of Digital pin + */ + if (!pin->is_analog) + return 0; + + if (dir == PLAY) + err = lola_read_param(chip, nid, LOLA_PAR_AMP_OUT_CAP, &val); + else + err = lola_read_param(chip, nid, LOLA_PAR_AMP_IN_CAP, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read AMP-caps for 0x%x\n", nid); + return err; + } + + pin->amp_mute = LOLA_AMP_MUTE_CAPABLE(val); + pin->amp_step_size = LOLA_AMP_STEP_SIZE(val); + pin->amp_num_steps = LOLA_AMP_NUM_STEPS(val); + if (pin->amp_num_steps) { + /* zero as mute state */ + pin->amp_num_steps++; + pin->amp_step_size++; + } + pin->amp_offset = LOLA_AMP_OFFSET(val); + + err = lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val, + NULL); + if (err < 0) { + printk(KERN_ERR SFX "Can't get MAX_LEVEL 0x%x\n", nid); + return err; + } + pin->max_level = val & 0x3ff; /* 10 bits */ + + pin->config_default_reg = 0; + pin->fixed_gain_list_len = 0; + pin->cur_gain_step = 0; + + return 0; +} + +int __devinit lola_init_pins(struct lola *chip, int dir, int *nidp) +{ + int i, err, nid; + nid = *nidp; + for (i = 0; i < chip->pin[dir].num_pins; i++, nid++) { + err = lola_init_pin(chip, &chip->pin[dir].pins[i], dir, nid); + if (err < 0) + return err; + if (chip->pin[dir].pins[i].is_analog) + chip->pin[dir].num_analog_pins++; + } + *nidp = nid; + return 0; +} + +void lola_free_mixer(struct lola *chip) +{ + if (chip->mixer.array_saved) + vfree(chip->mixer.array_saved); +} + +int __devinit lola_init_mixer_widget(struct lola *chip, int nid) +{ + unsigned int val; + int err; + + err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + return err; + } + + if ((val & 0xfff00000) != 0x02f00000) { /* test SubType and Type */ + snd_printdd("No valid mixer widget\n"); + return 0; + } + + chip->mixer.nid = nid; + chip->mixer.caps = val; + chip->mixer.array = (struct lola_mixer_array __iomem *) + (chip->bar[BAR1].remap_addr + LOLA_BAR1_SOURCE_GAIN_ENABLE); + + /* reserve memory to copy mixer data for sleep mode transitions */ + chip->mixer.array_saved = vmalloc(sizeof(struct lola_mixer_array)); + + /* mixer matrix sources are physical input data and play streams */ + chip->mixer.src_stream_outs = chip->pcm[PLAY].num_streams; + chip->mixer.src_phys_ins = chip->pin[CAPT].num_pins; + + /* mixer matrix destinations are record streams and physical output */ + chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams; + chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins; + + /* mixer matrix can have unused areas between PhysIn and + * Play or Record and PhysOut zones + */ + chip->mixer.src_stream_out_ofs = chip->mixer.src_phys_ins + + LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(val); + chip->mixer.dest_phys_out_ofs = chip->mixer.dest_stream_ins + + LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(val); + + /* example : MixerMatrix of LoLa881 + * 0-------8------16-------8------16 + * | | | | | + * | INPUT | | INPUT | | + * | -> |unused | -> |unused | + * | RECORD| | OUTPUT| | + * | | | | | + * 8-------------------------------- + * | | | | | + * | | | | | + * |unused |unused |unused |unused | + * | | | | | + * | | | | | + * 16------------------------------- + * | | | | | + * | PLAY | | PLAY | | + * | -> |unused | -> |unused | + * | RECORD| | OUTPUT| | + * | | | | | + * 8-------------------------------- + * | | | | | + * | | | | | + * |unused |unused |unused |unused | + * | | | | | + * | | | | | + * 16------------------------------- + */ + if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT || + chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) { + printk(KERN_ERR SFX "Invalid mixer widget size\n"); + return -EINVAL; + } + + chip->mixer.src_mask = ((1U << chip->mixer.src_phys_ins) - 1) | + (((1U << chip->mixer.src_stream_outs) - 1) + << chip->mixer.src_stream_out_ofs); + chip->mixer.dest_mask = ((1U << chip->mixer.dest_stream_ins) - 1) | + (((1U << chip->mixer.dest_phys_outs) - 1) + << chip->mixer.dest_phys_out_ofs); + + return 0; +} + +static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id, + unsigned short gain, bool on) +{ + unsigned int oldval, val; + + if (!(chip->mixer.src_mask & (1 << id))) + return -EINVAL; + writew(gain, &chip->mixer.array->src_gain[id]); + oldval = val = readl(&chip->mixer.array->src_gain_enable); + if (on) + val |= (1 << id); + else + val &= ~(1 << id); + writel(val, &chip->mixer.array->src_gain_enable); + lola_codec_flush(chip); + /* inform micro-controller about the new source gain */ + return lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_SOURCE_GAIN, id, 0); +} + +#if 0 /* not used */ +static int lola_mixer_set_src_gains(struct lola *chip, unsigned int mask, + unsigned short *gains) +{ + int i; + + if ((chip->mixer.src_mask & mask) != mask) + return -EINVAL; + for (i = 0; i < LOLA_MIXER_DIM; i++) { + if (mask & (1 << i)) { + writew(*gains, &chip->mixer.array->src_gain[i]); + gains++; + } + } + writel(mask, &chip->mixer.array->src_gain_enable); + lola_codec_flush(chip); + if (chip->mixer.caps & LOLA_PEAK_METER_CAN_AGC_MASK) { + /* update for all srcs at once */ + return lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_SOURCE_GAIN, 0x80, 0); + } + /* update manually */ + for (i = 0; i < LOLA_MIXER_DIM; i++) { + if (mask & (1 << i)) { + lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_SOURCE_GAIN, i, 0); + } + } + return 0; +} +#endif /* not used */ + +static int lola_mixer_set_mapping_gain(struct lola *chip, + unsigned int src, unsigned int dest, + unsigned short gain, bool on) +{ + unsigned int val; + + if (!(chip->mixer.src_mask & (1 << src)) || + !(chip->mixer.dest_mask & (1 << dest))) + return -EINVAL; + if (on) + writew(gain, &chip->mixer.array->dest_mix_gain[dest][src]); + val = readl(&chip->mixer.array->dest_mix_gain_enable[dest]); + if (on) + val |= (1 << src); + else + val &= ~(1 << src); + writel(val, &chip->mixer.array->dest_mix_gain_enable[dest]); + lola_codec_flush(chip); + return lola_codec_write(chip, chip->mixer.nid, LOLA_VERB_SET_MIX_GAIN, + src, dest); +} + +static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id, + unsigned int mask, unsigned short *gains) +{ + int i; + + if (!(chip->mixer.dest_mask & (1 << id)) || + (chip->mixer.src_mask & mask) != mask) + return -EINVAL; + for (i = 0; i < LOLA_MIXER_DIM; i++) { + if (mask & (1 << i)) { + writew(*gains, &chip->mixer.array->dest_mix_gain[id][i]); + gains++; + } + } + writel(mask, &chip->mixer.array->dest_mix_gain_enable[id]); + lola_codec_flush(chip); + /* update for all dests at once */ + return lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_DESTINATION_GAIN, id, 0); +} + +/* + */ + +static int set_analog_volume(struct lola *chip, int dir, + unsigned int idx, unsigned int val, + bool external_call); + +int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute) +{ + struct lola_pin *pin; + int idx, max_idx; + + pin = chip->pin[dir].pins; + max_idx = chip->pin[dir].num_pins; + for (idx = 0; idx < max_idx; idx++) { + if (pin[idx].is_analog) { + unsigned int val = mute ? 0 : pin[idx].cur_gain_step; + /* set volume and do not save the value */ + set_analog_volume(chip, dir, idx, val, false); + } + } + return lola_codec_flush(chip); +} + +void lola_save_mixer(struct lola *chip) +{ + /* mute analog output */ + if (chip->mixer.array_saved) { + /* store contents of mixer array */ + memcpy_fromio(chip->mixer.array_saved, chip->mixer.array, + sizeof(*chip->mixer.array)); + } + lola_setup_all_analog_gains(chip, PLAY, true); /* output mute */ +} + +void lola_restore_mixer(struct lola *chip) +{ + int i; + + /*lola_reset_setups(chip);*/ + if (chip->mixer.array_saved) { + /* restore contents of mixer array */ + memcpy_toio(chip->mixer.array, chip->mixer.array_saved, + sizeof(*chip->mixer.array)); + /* inform micro-controller about all restored values + * and ignore return values + */ + for (i = 0; i < chip->mixer.src_phys_ins; i++) + lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_SOURCE_GAIN, + i, 0); + for (i = 0; i < chip->mixer.src_stream_outs; i++) + lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_SOURCE_GAIN, + chip->mixer.src_stream_out_ofs + i, 0); + for (i = 0; i < chip->mixer.dest_stream_ins; i++) + lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_DESTINATION_GAIN, + i, 0); + for (i = 0; i < chip->mixer.dest_phys_outs; i++) + lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_DESTINATION_GAIN, + chip->mixer.dest_phys_out_ofs + i, 0); + lola_codec_flush(chip); + } +} + +/* + */ + +static int set_analog_volume(struct lola *chip, int dir, + unsigned int idx, unsigned int val, + bool external_call) +{ + struct lola_pin *pin; + int err; + + if (idx >= chip->pin[dir].num_pins) + return -EINVAL; + pin = &chip->pin[dir].pins[idx]; + if (!pin->is_analog || pin->amp_num_steps <= val) + return -EINVAL; + if (external_call && pin->cur_gain_step == val) + return 0; + if (external_call) + lola_codec_flush(chip); + err = lola_codec_write(chip, pin->nid, + LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0); + if (err < 0) + return err; + if (external_call) + pin->cur_gain_step = val; + return 0; +} + +int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update) +{ + int ret = 0; + int success = 0; + int n, err; + + /* SRC can be activated and the dwInputSRCMask is valid? */ + if ((chip->input_src_caps_mask & src_mask) != src_mask) + return -EINVAL; + /* handle all even Inputs - SRC is a stereo setting !!! */ + for (n = 0; n < chip->pin[CAPT].num_pins; n += 2) { + unsigned int mask = 3U << n; /* handle the stereo case */ + unsigned int new_src, src_state; + if (!(chip->input_src_caps_mask & mask)) + continue; + /* if one IO needs SRC, both stereo IO will get SRC */ + new_src = (src_mask & mask) != 0; + if (update) { + src_state = (chip->input_src_mask & mask) != 0; + if (src_state == new_src) + continue; /* nothing to change for this IO */ + } + err = lola_codec_write(chip, chip->pcm[CAPT].streams[n].nid, + LOLA_VERB_SET_SRC, new_src, 0); + if (!err) + success++; + else + ret = err; + } + if (success) + ret = lola_codec_flush(chip); + if (!ret) + chip->input_src_mask = src_mask; + return ret; +} + +/* + */ +static int init_mixer_values(struct lola *chip) +{ + int i; + + /* all src on */ + lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false); + + /* clear all matrix */ + memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array)); + /* set src gain to 0dB */ + for (i = 0; i < chip->mixer.src_phys_ins; i++) + lola_mixer_set_src_gain(chip, i, 336, true); /* 0dB */ + for (i = 0; i < chip->mixer.src_stream_outs; i++) + lola_mixer_set_src_gain(chip, + i + chip->mixer.src_stream_out_ofs, + 336, true); /* 0dB */ + /* set 1:1 dest gain */ + for (i = 0; i < chip->mixer.dest_stream_ins; i++) { + int src = i % chip->mixer.src_phys_ins; + lola_mixer_set_mapping_gain(chip, src, i, 336, true); + } + for (i = 0; i < chip->mixer.src_stream_outs; i++) { + int src = chip->mixer.src_stream_out_ofs + i; + int dst = chip->mixer.dest_phys_out_ofs + + i % chip->mixer.dest_phys_outs; + lola_mixer_set_mapping_gain(chip, src, dst, 336, true); + } + return 0; +} + +/* + * analog mixer control element + */ +static int lola_analog_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int dir = kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chip->pin[dir].num_pins; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = chip->pin[dir].pins[0].amp_num_steps; + return 0; +} + +static int lola_analog_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int dir = kcontrol->private_value; + int i; + + for (i = 0; i < chip->pin[dir].num_pins; i++) + ucontrol->value.integer.value[i] = + chip->pin[dir].pins[i].cur_gain_step; + return 0; +} + +static int lola_analog_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int dir = kcontrol->private_value; + int i, err; + + for (i = 0; i < chip->pin[dir].num_pins; i++) { + err = set_analog_volume(chip, dir, i, + ucontrol->value.integer.value[i], + true); + if (err < 0) + return err; + } + return 0; +} + +static int lola_analog_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int dir = kcontrol->private_value; + unsigned int val1, val2; + struct lola_pin *pin; + + if (size < 4 * sizeof(unsigned int)) + return -ENOMEM; + pin = &chip->pin[dir].pins[0]; + + val2 = pin->amp_step_size * 25; + val1 = -1 * (int)pin->amp_offset * (int)val2; +#ifdef TLV_DB_SCALE_MUTE + val2 |= TLV_DB_SCALE_MUTE; +#endif + if (put_user(SNDRV_CTL_TLVT_DB_SCALE, tlv)) + return -EFAULT; + if (put_user(2 * sizeof(unsigned int), tlv + 1)) + return -EFAULT; + if (put_user(val1, tlv + 2)) + return -EFAULT; + if (put_user(val2, tlv + 3)) + return -EFAULT; + return 0; +} + +static struct snd_kcontrol_new lola_analog_mixer __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), + .info = lola_analog_vol_info, + .get = lola_analog_vol_get, + .put = lola_analog_vol_put, + .tlv.c = lola_analog_vol_tlv, +}; + +static int __devinit create_analog_mixer(struct lola *chip, int dir, char *name) +{ + if (!chip->pin[dir].num_pins) + return 0; + /* no analog volumes on digital only adapters */ + if (chip->pin[dir].num_pins != chip->pin[dir].num_analog_pins) + return 0; + lola_analog_mixer.name = name; + lola_analog_mixer.private_value = dir; + return snd_ctl_add(chip->card, + snd_ctl_new1(&lola_analog_mixer, chip)); +} + +/* + * Hardware sample rate converter on digital input + */ +static int lola_input_src_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = chip->pin[CAPT].num_pins; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int lola_input_src_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int i; + + for (i = 0; i < chip->pin[CAPT].num_pins; i++) + ucontrol->value.integer.value[i] = + !!(chip->input_src_mask & (1 << i)); + return 0; +} + +static int lola_input_src_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int i; + unsigned int mask; + + mask = 0; + for (i = 0; i < chip->pin[CAPT].num_pins; i++) + if (ucontrol->value.integer.value[i]) + mask |= 1 << i; + return lola_set_src_config(chip, mask, true); +} + +static struct snd_kcontrol_new lola_input_src_mixer __devinitdata = { + .name = "Digital SRC Capture Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = lola_input_src_info, + .get = lola_input_src_get, + .put = lola_input_src_put, +}; + +/* + * Lola16161 or Lola881 can have Hardware sample rate converters + * on its digital input pins + */ +static int __devinit create_input_src_mixer(struct lola *chip) +{ + if (!chip->input_src_caps_mask) + return 0; + + return snd_ctl_add(chip->card, + snd_ctl_new1(&lola_input_src_mixer, chip)); +} + +/* + * src gain mixer + */ +static int lola_src_gain_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned int count = (kcontrol->private_value >> 8) & 0xff; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 409; + return 0; +} + +static int lola_src_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + unsigned int ofs = kcontrol->private_value & 0xff; + unsigned int count = (kcontrol->private_value >> 8) & 0xff; + unsigned int mask, i; + + mask = readl(&chip->mixer.array->src_gain_enable); + for (i = 0; i < count; i++) { + unsigned int idx = ofs + i; + unsigned short val; + if (!(chip->mixer.src_mask & (1 << idx))) + return -EINVAL; + if (mask & (1 << idx)) + val = readw(&chip->mixer.array->src_gain[idx]) + 1; + else + val = 0; + ucontrol->value.integer.value[i] = val; + } + return 0; +} + +static int lola_src_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + unsigned int ofs = kcontrol->private_value & 0xff; + unsigned int count = (kcontrol->private_value >> 8) & 0xff; + int i, err; + + for (i = 0; i < count; i++) { + unsigned int idx = ofs + i; + unsigned short val = ucontrol->value.integer.value[i]; + if (val) + val--; + err = lola_mixer_set_src_gain(chip, idx, val, !!val); + if (err < 0) + return err; + } + return 0; +} + +/* raw value: 0 = -84dB, 336 = 0dB, 408=18dB, incremented 1 for mute */ +static const DECLARE_TLV_DB_SCALE(lola_src_gain_tlv, -8425, 25, 1); + +static struct snd_kcontrol_new lola_src_gain_mixer __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .info = lola_src_gain_info, + .get = lola_src_gain_get, + .put = lola_src_gain_put, + .tlv.p = lola_src_gain_tlv, +}; + +static int __devinit create_src_gain_mixer(struct lola *chip, + int num, int ofs, char *name) +{ + lola_src_gain_mixer.name = name; + lola_src_gain_mixer.private_value = ofs + (num << 8); + return snd_ctl_add(chip->card, + snd_ctl_new1(&lola_src_gain_mixer, chip)); +} + +/* + * destination gain (matrix-like) mixer + */ +static int lola_dest_gain_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned int src_num = (kcontrol->private_value >> 8) & 0xff; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = src_num; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 433; + return 0; +} + +static int lola_dest_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + unsigned int src_ofs = kcontrol->private_value & 0xff; + unsigned int src_num = (kcontrol->private_value >> 8) & 0xff; + unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff; + unsigned int dst, mask, i; + + dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs; + mask = readl(&chip->mixer.array->dest_mix_gain_enable[dst]); + for (i = 0; i < src_num; i++) { + unsigned int src = src_ofs + i; + unsigned short val; + if (!(chip->mixer.src_mask & (1 << src))) + return -EINVAL; + if (mask & (1 << dst)) + val = readw(&chip->mixer.array->dest_mix_gain[dst][src]) + 1; + else + val = 0; + ucontrol->value.integer.value[i] = val; + } + return 0; +} + +static int lola_dest_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + unsigned int src_ofs = kcontrol->private_value & 0xff; + unsigned int src_num = (kcontrol->private_value >> 8) & 0xff; + unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff; + unsigned int dst, mask; + unsigned short gains[MAX_STREAM_COUNT]; + int i, num; + + mask = 0; + num = 0; + for (i = 0; i < src_num; i++) { + unsigned short val = ucontrol->value.integer.value[i]; + if (val) { + gains[num++] = val - 1; + mask |= 1 << i; + } + } + mask <<= src_ofs; + dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs; + return lola_mixer_set_dest_gains(chip, dst, mask, gains); +} + +static const DECLARE_TLV_DB_SCALE(lola_dest_gain_tlv, -8425, 25, 1); + +static struct snd_kcontrol_new lola_dest_gain_mixer __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .info = lola_dest_gain_info, + .get = lola_dest_gain_get, + .put = lola_dest_gain_put, + .tlv.p = lola_dest_gain_tlv, +}; + +static int __devinit create_dest_gain_mixer(struct lola *chip, + int src_num, int src_ofs, + int num, int ofs, char *name) +{ + lola_dest_gain_mixer.count = num; + lola_dest_gain_mixer.name = name; + lola_dest_gain_mixer.private_value = + src_ofs + (src_num << 8) + (ofs << 16) + (num << 24); + return snd_ctl_add(chip->card, + snd_ctl_new1(&lola_dest_gain_mixer, chip)); +} + +/* + */ +int __devinit lola_create_mixer(struct lola *chip) +{ + int err; + + err = create_analog_mixer(chip, PLAY, "Analog Playback Volume"); + if (err < 0) + return err; + err = create_analog_mixer(chip, CAPT, "Analog Capture Volume"); + if (err < 0) + return err; + err = create_input_src_mixer(chip); + if (err < 0) + return err; + err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0, + "Line Source Gain Volume"); + if (err < 0) + return err; + err = create_src_gain_mixer(chip, chip->mixer.src_stream_outs, + chip->mixer.src_stream_out_ofs, + "Stream Source Gain Volume"); + if (err < 0) + return err; + err = create_dest_gain_mixer(chip, + chip->mixer.src_phys_ins, 0, + chip->mixer.dest_stream_ins, 0, + "Line Capture Volume"); + if (err < 0) + return err; + err = create_dest_gain_mixer(chip, + chip->mixer.src_stream_outs, + chip->mixer.src_stream_out_ofs, + chip->mixer.dest_stream_ins, 0, + "Stream-Loopback Capture Volume"); + if (err < 0) + return err; + err = create_dest_gain_mixer(chip, + chip->mixer.src_phys_ins, 0, + chip->mixer.dest_phys_outs, + chip->mixer.dest_phys_out_ofs, + "Line-Loopback Playback Volume"); + if (err < 0) + return err; + err = create_dest_gain_mixer(chip, + chip->mixer.src_stream_outs, + chip->mixer.src_stream_out_ofs, + chip->mixer.dest_phys_outs, + chip->mixer.dest_phys_out_ofs, + "Stream Playback Volume"); + if (err < 0) + return err; + + return init_mixer_values(chip); +} diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c new file mode 100644 index 00000000000..c44db68eecb --- /dev/null +++ b/sound/pci/lola/lola_pcm.c @@ -0,0 +1,706 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include "lola.h" + +#define LOLA_MAX_BDL_ENTRIES 8 +#define LOLA_MAX_BUF_SIZE (1024*1024*1024) +#define LOLA_BDL_ENTRY_SIZE (16 * 16) + +static struct lola_pcm *lola_get_pcm(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + return &chip->pcm[substream->stream]; +} + +static struct lola_stream *lola_get_stream(struct snd_pcm_substream *substream) +{ + struct lola_pcm *pcm = lola_get_pcm(substream); + unsigned int idx = substream->number; + return &pcm->streams[idx]; +} + +static unsigned int lola_get_lrc(struct lola *chip) +{ + return lola_readl(chip, BAR1, LRC); +} + +static unsigned int lola_get_tstamp(struct lola *chip, bool quick_no_sync) +{ + unsigned int tstamp = lola_get_lrc(chip) >> 8; + if (chip->granularity) { + unsigned int wait_banks = quick_no_sync ? 0 : 8; + tstamp += (wait_banks + 1) * chip->granularity - 1; + tstamp -= tstamp % chip->granularity; + } + return tstamp << 8; +} + +/* clear any pending interrupt status */ +static void lola_stream_clear_pending_irq(struct lola *chip, + struct lola_stream *str) +{ + unsigned int val = lola_dsd_read(chip, str->dsd, STS); + val &= LOLA_DSD_STS_DESE | LOLA_DSD_STS_BCIS; + if (val) + lola_dsd_write(chip, str->dsd, STS, val); +} + +static void lola_stream_start(struct lola *chip, struct lola_stream *str, + unsigned int tstamp) +{ + lola_stream_clear_pending_irq(chip, str); + lola_dsd_write(chip, str->dsd, CTL, + LOLA_DSD_CTL_SRUN | + LOLA_DSD_CTL_IOCE | + LOLA_DSD_CTL_DEIE | + LOLA_DSD_CTL_VLRCV | + tstamp); +} + +static void lola_stream_stop(struct lola *chip, struct lola_stream *str, + unsigned int tstamp) +{ + lola_dsd_write(chip, str->dsd, CTL, + LOLA_DSD_CTL_IOCE | + LOLA_DSD_CTL_DEIE | + LOLA_DSD_CTL_VLRCV | + tstamp); + lola_stream_clear_pending_irq(chip, str); +} + +static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str) +{ + unsigned long end_time = jiffies + msecs_to_jiffies(200); + while (time_before(jiffies, end_time)) { + unsigned int val; + val = lola_dsd_read(chip, str->dsd, CTL); + if (!(val & LOLA_DSD_CTL_SRST)) + return; + msleep(1); + } + printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd); +} + +static int lola_stream_wait_for_fifo(struct lola *chip, + struct lola_stream *str, + bool ready) +{ + unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0; + unsigned long end_time = jiffies + msecs_to_jiffies(200); + while (time_before(jiffies, end_time)) { + unsigned int reg = lola_dsd_read(chip, str->dsd, STS); + if ((reg & LOLA_DSD_STS_FIFORDY) == val) + return 0; + msleep(1); + } + printk(KERN_WARNING SFX "FIFO not ready (stream %d)\n", str->dsd); + return -EIO; +} + +/* sync for FIFO ready/empty for all linked streams; + * clear paused flag when FIFO gets ready again + */ +static int lola_sync_wait_for_fifo(struct lola *chip, + struct snd_pcm_substream *substream, + bool ready) +{ + unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0; + unsigned long end_time = jiffies + msecs_to_jiffies(200); + struct snd_pcm_substream *s; + int pending = 0; + + while (time_before(jiffies, end_time)) { + pending = 0; + snd_pcm_group_for_each_entry(s, substream) { + struct lola_stream *str; + if (s->pcm->card != substream->pcm->card) + continue; + str = lola_get_stream(s); + if (str->prepared && str->paused) { + unsigned int reg; + reg = lola_dsd_read(chip, str->dsd, STS); + if ((reg & LOLA_DSD_STS_FIFORDY) != val) { + pending = str->dsd + 1; + break; + } + if (ready) + str->paused = 0; + } + } + if (!pending) + return 0; + msleep(1); + } + printk(KERN_WARNING SFX "FIFO not ready (pending %d)\n", pending - 1); + return -EIO; +} + +/* finish pause - prepare for a new resume */ +static void lola_sync_pause(struct lola *chip, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_substream *s; + + lola_sync_wait_for_fifo(chip, substream, false); + snd_pcm_group_for_each_entry(s, substream) { + struct lola_stream *str; + if (s->pcm->card != substream->pcm->card) + continue; + str = lola_get_stream(s); + if (str->paused && str->prepared) + lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRUN | + LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE); + } + lola_sync_wait_for_fifo(chip, substream, true); +} + +static void lola_stream_reset(struct lola *chip, struct lola_stream *str) +{ + if (str->prepared) { + if (str->paused) + lola_sync_pause(chip, str->substream); + str->prepared = 0; + lola_dsd_write(chip, str->dsd, CTL, + LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE); + lola_stream_wait_for_fifo(chip, str, false); + lola_stream_clear_pending_irq(chip, str); + lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST); + lola_dsd_write(chip, str->dsd, LVI, 0); + lola_dsd_write(chip, str->dsd, BDPU, 0); + lola_dsd_write(chip, str->dsd, BDPL, 0); + wait_for_srst_clear(chip, str); + } +} + +static struct snd_pcm_hardware lola_pcm_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_FLOAT_LE), + .rates = SNDRV_PCM_RATE_8000_192000, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = LOLA_MAX_BUF_SIZE, + .period_bytes_min = 128, + .period_bytes_max = LOLA_MAX_BUF_SIZE / 2, + .periods_min = 2, + .periods_max = LOLA_MAX_BDL_ENTRIES, + .fifo_size = 0, +}; + +static int lola_pcm_open(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_pcm *pcm = lola_get_pcm(substream); + struct lola_stream *str = lola_get_stream(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + mutex_lock(&chip->open_mutex); + if (str->opened) { + mutex_unlock(&chip->open_mutex); + return -EBUSY; + } + str->substream = substream; + str->master = NULL; + str->opened = 1; + runtime->hw = lola_pcm_hw; + runtime->hw.channels_max = pcm->num_streams - str->index; + if (chip->sample_rate) { + /* sample rate is locked */ + runtime->hw.rate_min = chip->sample_rate; + runtime->hw.rate_max = chip->sample_rate; + } else { + runtime->hw.rate_min = chip->sample_rate_min; + runtime->hw.rate_max = chip->sample_rate_max; + } + chip->ref_count_rate++; + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + /* period size = multiple of chip->granularity (8, 16 or 32 frames)*/ + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + chip->granularity); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + chip->granularity); + mutex_unlock(&chip->open_mutex); + return 0; +} + +static void lola_cleanup_slave_streams(struct lola_pcm *pcm, + struct lola_stream *str) +{ + int i; + for (i = str->index + 1; i < pcm->num_streams; i++) { + struct lola_stream *s = &pcm->streams[i]; + if (s->master != str) + break; + s->master = NULL; + s->opened = 0; + } +} + +static int lola_pcm_close(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_stream *str = lola_get_stream(substream); + + mutex_lock(&chip->open_mutex); + if (str->substream == substream) { + str->substream = NULL; + str->opened = 0; + } + if (--chip->ref_count_rate == 0) { + /* release sample rate */ + chip->sample_rate = 0; + } + mutex_unlock(&chip->open_mutex); + return 0; +} + +static int lola_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct lola_stream *str = lola_get_stream(substream); + + str->bufsize = 0; + str->period_bytes = 0; + str->format_verb = 0; + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +} + +static int lola_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_pcm *pcm = lola_get_pcm(substream); + struct lola_stream *str = lola_get_stream(substream); + + mutex_lock(&chip->open_mutex); + lola_stream_reset(chip, str); + lola_cleanup_slave_streams(pcm, str); + mutex_unlock(&chip->open_mutex); + return snd_pcm_lib_free_pages(substream); +} + +/* + * set up a BDL entry + */ +static int setup_bdle(struct snd_pcm_substream *substream, + struct lola_stream *str, u32 **bdlp, + int ofs, int size) +{ + u32 *bdl = *bdlp; + + while (size > 0) { + dma_addr_t addr; + int chunk; + + if (str->frags >= LOLA_MAX_BDL_ENTRIES) + return -EINVAL; + + addr = snd_pcm_sgbuf_get_addr(substream, ofs); + /* program the address field of the BDL entry */ + bdl[0] = cpu_to_le32((u32)addr); + bdl[1] = cpu_to_le32(upper_32_bits(addr)); + /* program the size field of the BDL entry */ + chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size); + bdl[2] = cpu_to_le32(chunk); + /* program the IOC to enable interrupt + * only when the whole fragment is processed + */ + size -= chunk; + bdl[3] = size ? 0 : cpu_to_le32(0x01); + bdl += 4; + str->frags++; + ofs += chunk; + } + *bdlp = bdl; + return ofs; +} + +/* + * set up BDL entries + */ +static int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm, + struct snd_pcm_substream *substream, + struct lola_stream *str) +{ + u32 *bdl; + int i, ofs, periods, period_bytes; + + period_bytes = str->period_bytes; + periods = str->bufsize / period_bytes; + + /* program the initial BDL entries */ + bdl = (u32 *)(pcm->bdl.area + LOLA_BDL_ENTRY_SIZE * str->index); + ofs = 0; + str->frags = 0; + for (i = 0; i < periods; i++) { + ofs = setup_bdle(substream, str, &bdl, ofs, period_bytes); + if (ofs < 0) + goto error; + } + return 0; + + error: + snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n", + str->bufsize, period_bytes); + return -EINVAL; +} + +static unsigned int lola_get_format_verb(struct snd_pcm_substream *substream) +{ + unsigned int verb; + + switch (substream->runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + verb = 0x00000000; + break; + case SNDRV_PCM_FORMAT_S24_LE: + verb = 0x00000200; + break; + case SNDRV_PCM_FORMAT_S32_LE: + verb = 0x00000300; + break; + case SNDRV_PCM_FORMAT_FLOAT_LE: + verb = 0x00001300; + break; + default: + return 0; + } + verb |= substream->runtime->channels; + return verb; +} + +static int lola_set_stream_config(struct lola *chip, + struct lola_stream *str, + int channels) +{ + int i, err; + unsigned int verb, val; + + /* set format info for all channels + * (with only one command for the first channel) + */ + err = lola_codec_read(chip, str->nid, LOLA_VERB_SET_STREAM_FORMAT, + str->format_verb, 0, &val, NULL); + if (err < 0) { + printk(KERN_ERR SFX "Cannot set stream format 0x%x\n", + str->format_verb); + return err; + } + + /* update stream - channel config */ + for (i = 0; i < channels; i++) { + verb = (str->index << 6) | i; + err = lola_codec_read(chip, str[i].nid, + LOLA_VERB_SET_CHANNEL_STREAMID, 0, verb, + &val, NULL); + if (err < 0) { + printk(KERN_ERR SFX "Cannot set stream channel %d\n", i); + return err; + } + } + return 0; +} + +/* + * set up the SD for streaming + */ +static int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm, + struct lola_stream *str) +{ + dma_addr_t bdl; + + if (str->prepared) + return -EINVAL; + + /* set up BDL */ + bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index; + lola_dsd_write(chip, str->dsd, BDPL, (u32)bdl); + lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl)); + /* program the stream LVI (last valid index) of the BDL */ + lola_dsd_write(chip, str->dsd, LVI, str->frags - 1); + lola_stream_clear_pending_irq(chip, str); + + lola_dsd_write(chip, str->dsd, CTL, + LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE | LOLA_DSD_CTL_SRUN); + + str->prepared = 1; + + return lola_stream_wait_for_fifo(chip, str, true); +} + +static int lola_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_pcm *pcm = lola_get_pcm(substream); + struct lola_stream *str = lola_get_stream(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int bufsize, period_bytes, format_verb; + int i, err; + + mutex_lock(&chip->open_mutex); + lola_stream_reset(chip, str); + lola_cleanup_slave_streams(pcm, str); + if (str->index + runtime->channels > pcm->num_streams) { + mutex_unlock(&chip->open_mutex); + return -EINVAL; + } + for (i = 1; i < runtime->channels; i++) { + str[i].master = str; + str[i].opened = 1; + } + mutex_unlock(&chip->open_mutex); + + bufsize = snd_pcm_lib_buffer_bytes(substream); + period_bytes = snd_pcm_lib_period_bytes(substream); + format_verb = lola_get_format_verb(substream); + + str->bufsize = bufsize; + str->period_bytes = period_bytes; + str->format_verb = format_verb; + + err = lola_setup_periods(chip, pcm, substream, str); + if (err < 0) + return err; + + err = lola_set_sample_rate(chip, runtime->rate); + if (err < 0) + return err; + chip->sample_rate = runtime->rate; /* sample rate gets locked */ + + err = lola_set_stream_config(chip, str, runtime->channels); + if (err < 0) + return err; + + err = lola_setup_controller(chip, pcm, str); + if (err < 0) { + lola_stream_reset(chip, str); + return err; + } + + return 0; +} + +static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_stream *str; + struct snd_pcm_substream *s; + unsigned int start; + unsigned int tstamp; + bool sync_streams; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + start = 1; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + start = 0; + break; + default: + return -EINVAL; + } + + /* + * sample correct synchronization is only needed starting several + * streams. On stop or if only one stream do as quick as possible + */ + sync_streams = (start && snd_pcm_stream_linked(substream)); + tstamp = lola_get_tstamp(chip, !sync_streams); + spin_lock(&chip->reg_lock); + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + str = lola_get_stream(s); + if (start) + lola_stream_start(chip, str, tstamp); + else + lola_stream_stop(chip, str, tstamp); + str->running = start; + str->paused = !start; + snd_pcm_trigger_done(s, substream); + } + spin_unlock(&chip->reg_lock); + return 0; +} + +static snd_pcm_uframes_t lola_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_stream *str = lola_get_stream(substream); + unsigned int pos = lola_dsd_read(chip, str->dsd, LPIB); + + if (pos >= str->bufsize) + pos = 0; + return bytes_to_frames(substream->runtime, pos); +} + +void lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits) +{ + int i; + + for (i = 0; bits && i < pcm->num_streams; i++) { + if (bits & (1 << i)) { + struct lola_stream *str = &pcm->streams[i]; + if (str->substream && str->running) + snd_pcm_period_elapsed(str->substream); + bits &= ~(1 << i); + } + } +} + +static struct snd_pcm_ops lola_pcm_ops = { + .open = lola_pcm_open, + .close = lola_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = lola_pcm_hw_params, + .hw_free = lola_pcm_hw_free, + .prepare = lola_pcm_prepare, + .trigger = lola_pcm_trigger, + .pointer = lola_pcm_pointer, + .page = snd_pcm_sgbuf_ops_page, +}; + +int __devinit lola_create_pcm(struct lola *chip) +{ + struct snd_pcm *pcm; + int i, err; + + for (i = 0; i < 2; i++) { + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + PAGE_SIZE, &chip->pcm[i].bdl); + if (err < 0) + return err; + } + + err = snd_pcm_new(chip->card, "Digigram Lola", 0, + chip->pcm[SNDRV_PCM_STREAM_PLAYBACK].num_streams, + chip->pcm[SNDRV_PCM_STREAM_CAPTURE].num_streams, + &pcm); + if (err < 0) + return err; + strlcpy(pcm->name, "Digigram Lola", sizeof(pcm->name)); + pcm->private_data = chip; + for (i = 0; i < 2; i++) { + if (chip->pcm[i].num_streams) + snd_pcm_set_ops(pcm, i, &lola_pcm_ops); + } + /* buffer pre-allocation */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci), + 1024 * 64, 32 * 1024 * 1024); + return 0; +} + +void lola_free_pcm(struct lola *chip) +{ + snd_dma_free_pages(&chip->pcm[0].bdl); + snd_dma_free_pages(&chip->pcm[1].bdl); +} + +/* + */ + +static int lola_init_stream(struct lola *chip, struct lola_stream *str, + int idx, int nid, int dir) +{ + unsigned int val; + int err; + + str->nid = nid; + str->index = idx; + str->dsd = idx; + if (dir == PLAY) + str->dsd += MAX_STREAM_IN_COUNT; + err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + return err; + } + if (dir == PLAY) { + /* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) */ + if ((val & 0x00f00dff) != 0x00000010) { + printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", + val, nid); + return -EINVAL; + } + } else { + /* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) + * (bug : ignore bit8: Conn list = 0/1) + */ + if ((val & 0x00f00cff) != 0x00100010) { + printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", + val, nid); + return -EINVAL; + } + /* test bit9:DIGITAL and bit12:SRC_PRESENT*/ + if ((val & 0x00001200) == 0x00001200) + chip->input_src_caps_mask |= (1 << idx); + } + + err = lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read FORMATS 0x%x\n", nid); + return err; + } + val &= 3; + if (val == 3) + str->can_float = true; + if (!(val & 1)) { + printk(KERN_ERR SFX "Invalid formats 0x%x for 0x%x", val, nid); + return -EINVAL; + } + return 0; +} + +int __devinit lola_init_pcm(struct lola *chip, int dir, int *nidp) +{ + struct lola_pcm *pcm = &chip->pcm[dir]; + int i, nid, err; + + nid = *nidp; + for (i = 0; i < pcm->num_streams; i++, nid++) { + err = lola_init_stream(chip, &pcm->streams[i], i, nid, dir); + if (err < 0) + return err; + } + *nidp = nid; + return 0; +} diff --git a/sound/pci/lola/lola_proc.c b/sound/pci/lola/lola_proc.c new file mode 100644 index 00000000000..9d7daf897c9 --- /dev/null +++ b/sound/pci/lola/lola_proc.c @@ -0,0 +1,222 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <sound/core.h> +#include <sound/info.h> +#include <sound/pcm.h> +#include "lola.h" + +static void print_audio_widget(struct snd_info_buffer *buffer, + struct lola *chip, int nid, const char *name) +{ + unsigned int val; + + lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val); + lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val); + snd_iprintf(buffer, " Formats: 0x%x\n", val); +} + +static void print_pin_widget(struct snd_info_buffer *buffer, + struct lola *chip, int nid, unsigned int ampcap, + const char *name) +{ + unsigned int val; + + lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val); + if (val == 0x00400200) + return; + lola_read_param(chip, nid, ampcap, &val); + snd_iprintf(buffer, " Amp-Caps: 0x%x\n", val); + snd_iprintf(buffer, " mute=%d, step-size=%d, steps=%d, ofs=%d\n", + LOLA_AMP_MUTE_CAPABLE(val), + LOLA_AMP_STEP_SIZE(val), + LOLA_AMP_NUM_STEPS(val), + LOLA_AMP_OFFSET(val)); + lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val, NULL); + snd_iprintf(buffer, " Max-level: 0x%x\n", val); +} + +static void print_clock_widget(struct snd_info_buffer *buffer, + struct lola *chip, int nid) +{ + int i, j, num_clocks; + unsigned int val; + + lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + snd_iprintf(buffer, "Node 0x%02x [Clock] wcaps 0x%x\n", nid, val); + num_clocks = val & 0xff; + for (i = 0; i < num_clocks; i += 4) { + unsigned int res_ex; + unsigned short items[4]; + const char *name; + + lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST, + i, 0, &val, &res_ex); + items[0] = val & 0xfff; + items[1] = (val >> 16) & 0xfff; + items[2] = res_ex & 0xfff; + items[3] = (res_ex >> 16) & 0xfff; + for (j = 0; j < 4; j++) { + unsigned char type = items[j] >> 8; + unsigned int freq = items[j] & 0xff; + if (i + j >= num_clocks) + break; + if (type == LOLA_CLOCK_TYPE_INTERNAL) { + name = "Internal"; + freq = lola_sample_rate_convert(freq); + } else if (type == LOLA_CLOCK_TYPE_VIDEO) { + name = "Video"; + freq = lola_sample_rate_convert(freq); + } else { + name = "Other"; + } + snd_iprintf(buffer, " Clock %d: Type %d:%s, freq=%d\n", + i + j, type, name, freq); + } + } +} + +static void print_mixer_widget(struct snd_info_buffer *buffer, + struct lola *chip, int nid) +{ + unsigned int val; + + lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + snd_iprintf(buffer, "Node 0x%02x [Mixer] wcaps 0x%x\n", nid, val); +} + +static void lola_proc_codec_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct lola *chip = entry->private_data; + unsigned int val; + int i, nid; + + lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val); + snd_iprintf(buffer, "Vendor: 0x%08x\n", val); + lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val); + snd_iprintf(buffer, "Function Type: %d\n", val); + lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val); + snd_iprintf(buffer, "Specific-Caps: 0x%08x\n", val); + snd_iprintf(buffer, " Pins-In %d, Pins-Out %d\n", + chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins); + nid = 2; + for (i = 0; i < chip->pcm[CAPT].num_streams; i++, nid++) + print_audio_widget(buffer, chip, nid, "[Audio-In]"); + for (i = 0; i < chip->pcm[PLAY].num_streams; i++, nid++) + print_audio_widget(buffer, chip, nid, "[Audio-Out]"); + for (i = 0; i < chip->pin[CAPT].num_pins; i++, nid++) + print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_IN_CAP, + "[Pin-In]"); + for (i = 0; i < chip->pin[PLAY].num_pins; i++, nid++) + print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_OUT_CAP, + "[Pin-Out]"); + if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) { + print_clock_widget(buffer, chip, nid); + nid++; + } + if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) { + print_mixer_widget(buffer, chip, nid); + nid++; + } +} + +/* direct codec access for debugging */ +static void lola_proc_codec_rw_write(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct lola *chip = entry->private_data; + char line[64]; + unsigned int id, verb, data, extdata; + while (!snd_info_get_line(buffer, line, sizeof(line))) { + if (sscanf(line, "%i %i %i %i", &id, &verb, &data, &extdata) != 4) + continue; + lola_codec_read(chip, id, verb, data, extdata, + &chip->debug_res, + &chip->debug_res_ex); + } +} + +static void lola_proc_codec_rw_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct lola *chip = entry->private_data; + snd_iprintf(buffer, "0x%x 0x%x\n", chip->debug_res, chip->debug_res_ex); +} + +/* + * dump some registers + */ +static void lola_proc_regs_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct lola *chip = entry->private_data; + int i; + + for (i = 0; i < 0x40; i += 4) { + snd_iprintf(buffer, "BAR0 %02x: %08x\n", i, + readl(chip->bar[BAR0].remap_addr + i)); + } + snd_iprintf(buffer, "\n"); + for (i = 0; i < 0x30; i += 4) { + snd_iprintf(buffer, "BAR1 %02x: %08x\n", i, + readl(chip->bar[BAR1].remap_addr + i)); + } + snd_iprintf(buffer, "\n"); + for (i = 0x80; i < 0xa0; i += 4) { + snd_iprintf(buffer, "BAR1 %02x: %08x\n", i, + readl(chip->bar[BAR1].remap_addr + i)); + } + snd_iprintf(buffer, "\n"); + for (i = 0; i < 32; i++) { + snd_iprintf(buffer, "DSD %02x STS %08x\n", i, + lola_dsd_read(chip, i, STS)); + snd_iprintf(buffer, "DSD %02x LPIB %08x\n", i, + lola_dsd_read(chip, i, LPIB)); + snd_iprintf(buffer, "DSD %02x CTL %08x\n", i, + lola_dsd_read(chip, i, CTL)); + snd_iprintf(buffer, "DSD %02x LVIL %08x\n", i, + lola_dsd_read(chip, i, LVI)); + snd_iprintf(buffer, "DSD %02x BDPL %08x\n", i, + lola_dsd_read(chip, i, BDPL)); + snd_iprintf(buffer, "DSD %02x BDPU %08x\n", i, + lola_dsd_read(chip, i, BDPU)); + } +} + +void __devinit lola_proc_debug_new(struct lola *chip) +{ + struct snd_info_entry *entry; + + if (!snd_card_proc_new(chip->card, "codec", &entry)) + snd_info_set_text_ops(entry, chip, lola_proc_codec_read); + if (!snd_card_proc_new(chip->card, "codec_rw", &entry)) { + snd_info_set_text_ops(entry, chip, lola_proc_codec_rw_read); + entry->mode |= S_IWUSR; + entry->c.text.write = lola_proc_codec_rw_write; + } + if (!snd_card_proc_new(chip->card, "regs", &entry)) + snd_info_set_text_ops(entry, chip, lola_proc_regs_read); +} diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 8cc4733698a..ce33be0e4e9 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -278,7 +278,7 @@ static int pdacf_resume(struct pcmcia_device *link) /* * Module entry points */ -static struct pcmcia_device_id snd_pdacf_ids[] = { +static const struct pcmcia_device_id snd_pdacf_ids[] = { /* this is too general PCMCIA_DEVICE_MANF_CARD(0x015d, 0x4c45), */ PCMCIA_DEVICE_PROD_ID12("Core Sound","PDAudio-CF",0x396d19d2,0x71717b49), PCMCIA_DEVICE_NULL diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 80000d631f8..d9ef21d8fa7 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -350,7 +350,7 @@ static void vxpocket_detach(struct pcmcia_device *link) * Module entry points */ -static struct pcmcia_device_id vxp_ids[] = { +static const struct pcmcia_device_id vxp_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x01f1, 0x0100), PCMCIA_DEVICE_NULL }; diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 961d9829769..9cea84c3e0c 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -1000,7 +1000,7 @@ static void device_change_handler(struct work_struct *work) chip->lineout_sw_ctl); if (mix->anded_reset) msleep(10); - check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify, + check_mute(chip, &mix->amp_mute, !IS_G4DA, mix->auto_mute_notify, chip->speaker_sw_ctl); } else { /* unmute speaker, mute others */ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index a7a7bbc0762..f53dc09c48f 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -846,9 +846,10 @@ int atmel_ssc_set_audio(int ssc_id) if (IS_ERR(ssc)) pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n", PTR_ERR(ssc)); - else + else { ssc_pdev->dev.parent = &(ssc->pdev->dev); - ssc_free(ssc); + ssc_free(ssc); + } ret = platform_device_add(ssc_pdev); if (ret < 0) diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index b8066ef10bb..46dbfd067f7 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -153,8 +153,7 @@ static int cq93vc_resume(struct snd_soc_codec *codec) static int cq93vc_probe(struct snd_soc_codec *codec) { - struct davinci_vc *davinci_vc = - mfd_get_data(to_platform_device(codec->dev)); + struct davinci_vc *davinci_vc = codec->dev->platform_data; davinci_vc->cq93vc.codec = codec; codec->control_data = davinci_vc; diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index d68ea532cc7..f8c663dcff0 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -262,14 +262,14 @@ static int v253_hangup(struct tty_struct *tty) } /* Line discipline .receive_buf() */ -static void v253_receive(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) +static unsigned int v253_receive(struct tty_struct *tty, + const unsigned char *cp, char *fp, int count) { struct snd_soc_codec *codec = tty->disc_data; struct cx20442_priv *cx20442; if (!codec) - return; + return count; cx20442 = snd_soc_codec_get_drvdata(codec); @@ -281,6 +281,8 @@ static void v253_receive(struct tty_struct *tty, codec->hw_write = (hw_write_t)tty->ops->write; codec->card->pop_time = 1; } + + return count; } /* Line discipline .write_wakeup() */ diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 575238d68e5..bec788b1261 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -26,7 +26,6 @@ #include <linux/pm.h> #include <linux/i2c.h> #include <linux/platform_device.h> -#include <linux/mfd/core.h> #include <linux/i2c/twl.h> #include <linux/slab.h> #include <sound/core.h> @@ -733,8 +732,7 @@ static int aif_event(struct snd_soc_dapm_widget *w, static void headset_ramp(struct snd_soc_codec *codec, int ramp) { - struct twl4030_codec_audio_data *pdata = - mfd_get_data(to_platform_device(codec->dev)); + struct twl4030_codec_audio_data *pdata = codec->dev->platform_data; unsigned char hs_gain, hs_pop; struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); /* Base values for ramp delay calculation: 2^19 - 2^26 */ @@ -2299,7 +2297,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { static int __devinit twl4030_codec_probe(struct platform_device *pdev) { - struct twl4030_codec_audio_data *pdata = mfd_get_data(pdev); + struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "platform_data is missing\n"); diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index c8a874d0d4c..5836201834d 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -441,8 +441,7 @@ EXPORT_SYMBOL_GPL(wl1273_get_format); static int wl1273_probe(struct snd_soc_codec *codec) { - struct wl1273_core **core = - mfd_get_data(to_platform_device(codec->dev)); + struct wl1273_core **core = codec->dev->platform_data; struct wl1273_priv *wl1273; int r; diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 736b785e375..fbee556cbf3 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1378,7 +1378,7 @@ static void wm8400_probe_deferred(struct work_struct *work) static int wm8400_codec_probe(struct snd_soc_codec *codec) { - struct wm8400 *wm8400 = mfd_get_data(to_platform_device(codec->dev)); + struct wm8400 *wm8400 = dev_get_platdata(codec->dev); struct wm8400_priv *priv; int ret; u16 reg; diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index 13e05a302a9..9259f1f3489 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -205,7 +205,7 @@ static struct snd_soc_dai_driver davinci_vcif_dai = { static int davinci_vcif_probe(struct platform_device *pdev) { - struct davinci_vc *davinci_vc = mfd_get_data(pdev); + struct davinci_vc *davinci_vc = pdev->dev.platform_data; struct davinci_vcif_dev *davinci_vcif_dev; int ret; diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index b5922984eac..99054cf1f68 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -65,14 +65,6 @@ config SND_OMAP_SOC_OVERO Say Y if you want to add support for SoC audio on the Gumstix Overo or CompuLab CM-T35 -config SND_OMAP_SOC_OMAP2EVM - tristate "SoC Audio support for OMAP2EVM board" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP2EVM - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on the omap2evm board. - config SND_OMAP_SOC_OMAP3EVM tristate "SoC Audio support for OMAP3EVM board" depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3EVM diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index ba9fc650db2..6c2c87eed5b 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -13,7 +13,6 @@ snd-soc-rx51-objs := rx51.o snd-soc-ams-delta-objs := ams-delta.o snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o -snd-soc-omap2evm-objs := omap2evm.o snd-soc-omap3evm-objs := omap3evm.o snd-soc-am3517evm-objs := am3517evm.o snd-soc-sdp3430-objs := sdp3430.o diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c deleted file mode 100644 index 29b60d6796e..00000000000 --- a/sound/soc/omap/omap2evm.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * omap2evm.c -- SoC audio machine driver for omap2evm board - * - * Author: Arun KS <arunks@mistralsolutions.com> - * - * Based on sound/soc/omap/overo.c by Steve Sakoman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <plat/mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" - -static int omap2evm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops omap2evm_ops = { - .hw_params = omap2evm_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap2evm_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai_name = "omap-mcbsp-dai.1", - .codec_dai_name = "twl4030-hifi", - .platform_name = "omap-pcm-audio", - .codec_name = "twl4030-codec", - .ops = &omap2evm_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_omap2evm = { - .name = "omap2evm", - .dai_link = &omap2evm_dai, - .num_links = 1, -}; - -static struct platform_device *omap2evm_snd_device; - -static int __init omap2evm_soc_init(void) -{ - int ret; - - if (!machine_is_omap2evm()) - return -ENODEV; - printk(KERN_INFO "omap2evm SoC init\n"); - - omap2evm_snd_device = platform_device_alloc("soc-audio", -1); - if (!omap2evm_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(omap2evm_snd_device, &snd_soc_omap2evm); - - ret = platform_device_add(omap2evm_snd_device); - if (ret) - goto err1; - - return 0; - -err1: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(omap2evm_snd_device); - - return ret; -} -module_init(omap2evm_soc_init); - -static void __exit omap2evm_soc_exit(void) -{ - platform_device_unregister(omap2evm_snd_device); -} -module_exit(omap2evm_soc_exit); - -MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); -MODULE_DESCRIPTION("ALSA SoC omap2evm"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 459566bfcd3..d155cbb58e1 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,6 +1,6 @@ config SND_SOC_SAMSUNG tristate "ASoC support for Samsung" - depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_EXYNOS4 + depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4 select S3C64XX_DMA if ARCH_S3C64XX select S3C2410_DMA if ARCH_S3C2410 help @@ -55,7 +55,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 config SND_SOC_SAMSUNG_SMDK_WM8580 tristate "SoC I2S Audio support for WM8580 on SMDK" - depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDK6440 || MACH_SMDK6450 || MACH_SMDK6442 || MACH_SMDKV210 || MACH_SMDKC110) + depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDK6440 || MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110) select SND_SOC_WM8580 select SND_SAMSUNG_I2S help diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index 8aacf23d6f3..3d26f6607aa 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c @@ -249,7 +249,7 @@ static int __init smdk_audio_init(void) int ret; char *str; - if (machine_is_smdkc100() || machine_is_smdk6442() + if (machine_is_smdkc100() || machine_is_smdkv210() || machine_is_smdkc110()) { smdk.num_links = 3; /* Secondary is at offset SAMSUNG_I2S_SECOFF from Primary */ diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index 24846351118..ac828eff1a6 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c @@ -65,6 +65,15 @@ init_data[] = { { 0 } /* TERMINATING ENTRY */ }; +static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; +/* values to write to soundcard register for all samplerates */ +static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; +static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; + +enum { + DIGITAL_THRU_ONLY_SAMPLERATE = 3 +}; + static void usb6fire_control_master_vol_update(struct control_runtime *rt) { struct comm_runtime *comm_rt = rt->chip->comm; @@ -95,6 +104,67 @@ static void usb6fire_control_opt_coax_update(struct control_runtime *rt) } } +static int usb6fire_control_set_rate(struct control_runtime *rt, int rate) +{ + int ret; + struct usb_device *device = rt->chip->dev; + struct comm_runtime *comm_rt = rt->chip->comm; + + if (rate < 0 || rate >= CONTROL_N_RATES) + return -EINVAL; + + ret = usb_set_interface(device, 1, rates_altsetting[rate]); + if (ret < 0) + return ret; + + /* set soundcard clock */ + ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate], + rates_6fire_vh[rate]); + if (ret < 0) + return ret; + + return 0; +} + +static int usb6fire_control_set_channels( + struct control_runtime *rt, int n_analog_out, + int n_analog_in, bool spdif_out, bool spdif_in) +{ + int ret; + struct comm_runtime *comm_rt = rt->chip->comm; + + /* enable analog inputs and outputs + * (one bit per stereo-channel) */ + ret = comm_rt->write16(comm_rt, 0x02, 0x02, + (1 << (n_analog_out / 2)) - 1, + (1 << (n_analog_in / 2)) - 1); + if (ret < 0) + return ret; + + /* disable digital inputs and outputs */ + /* TODO: use spdif_x to enable/disable digital channels */ + ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00); + if (ret < 0) + return ret; + + return 0; +} + +static int usb6fire_control_streaming_update(struct control_runtime *rt) +{ + struct comm_runtime *comm_rt = rt->chip->comm; + + if (comm_rt) { + if (!rt->usb_streaming && rt->digital_thru_switch) + usb6fire_control_set_rate(rt, + DIGITAL_THRU_ONLY_SAMPLERATE); + return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, + (rt->usb_streaming ? 0x01 : 0x00) | + (rt->digital_thru_switch ? 0x08 : 0x00)); + } + return -EINVAL; +} + static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -195,6 +265,28 @@ static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol, return 0; } +static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + int changed = 0; + + if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) { + rt->digital_thru_switch = ucontrol->value.integer.value[0]; + usb6fire_control_streaming_update(rt); + changed = 1; + } + return changed; +} + +static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = rt->digital_thru_switch; + return 0; +} + static struct __devinitdata snd_kcontrol_new elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -223,6 +315,15 @@ static struct __devinitdata snd_kcontrol_new elements[] = { .get = usb6fire_control_opt_coax_get, .put = usb6fire_control_opt_coax_put }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Thru Playback Route", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_ctl_boolean_mono_info, + .get = usb6fire_control_digital_thru_get, + .put = usb6fire_control_digital_thru_put + }, {} }; @@ -238,6 +339,9 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) return -ENOMEM; rt->chip = chip; + rt->update_streaming = usb6fire_control_streaming_update; + rt->set_rate = usb6fire_control_set_rate; + rt->set_channels = usb6fire_control_set_channels; i = 0; while (init_data[i].type) { @@ -249,6 +353,7 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) usb6fire_control_opt_coax_update(rt); usb6fire_control_line_phono_update(rt); usb6fire_control_master_vol_update(rt); + usb6fire_control_streaming_update(rt); i = 0; while (elements[i].name) { diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h index b534c777ab0..8f5aeead2e3 100644 --- a/sound/usb/6fire/control.h +++ b/sound/usb/6fire/control.h @@ -21,12 +21,29 @@ enum { CONTROL_MAX_ELEMENTS = 32 }; +enum { + CONTROL_RATE_44KHZ, + CONTROL_RATE_48KHZ, + CONTROL_RATE_88KHZ, + CONTROL_RATE_96KHZ, + CONTROL_RATE_176KHZ, + CONTROL_RATE_192KHZ, + CONTROL_N_RATES +}; + struct control_runtime { + int (*update_streaming)(struct control_runtime *rt); + int (*set_rate)(struct control_runtime *rt, int rate); + int (*set_channels)(struct control_runtime *rt, int n_analog_out, + int n_analog_in, bool spdif_out, bool spdif_in); + struct sfire_chip *chip; struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS]; bool opt_coax_switch; bool line_phono_switch; + bool digital_thru_switch; + bool usb_streaming; u8 master_vol; }; diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 86c1a310376..d47beffedb0 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -3,12 +3,6 @@ * * Firmware loader * - * Currently not working for all devices. To be able to use the device - * in linux, it is also possible to let the windows driver upload the firmware. - * For that, start the computer in windows and reboot. - * As long as the device is connected to the power supply, no firmware reload - * needs to be performed. - * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 * Version: 0.3.0 @@ -21,6 +15,7 @@ */ #include <linux/firmware.h> +#include <linux/bitrev.h> #include "firmware.h" #include "chip.h" @@ -33,32 +28,6 @@ enum { FPGA_BUFSIZE = 512, FPGA_EP = 2 }; -static const u8 BIT_REVERSE_TABLE[256] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, - 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, - 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, - 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, - 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, - 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, - 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, - 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, - 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, - 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, - 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, - 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, - 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, - 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, - 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, - 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, - 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, - 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, - 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, - 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, - 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, - 0xbf, 0x7f, 0xff }; - /* * wMaxPacketSize of pcm endpoints. * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c @@ -72,6 +41,10 @@ static const u8 ep_w_max_packet_size[] = { 0x94, 0x01, 0x5c, 0x02 /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */ }; +static const u8 known_fw_versions[][4] = { + { 0x03, 0x01, 0x0b, 0x00 } +}; + struct ihex_record { u16 address; u8 len; @@ -340,7 +313,7 @@ static int usb6fire_fw_fpga_upload( while (c != end) { for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++) - buffer[i] = BIT_REVERSE_TABLE[(u8) *c]; + buffer[i] = byte_rev_table[(u8) *c]; ret = usb6fire_fw_fpga_write(device, buffer, i); if (ret < 0) { @@ -363,6 +336,25 @@ static int usb6fire_fw_fpga_upload( return 0; } +/* check, if the firmware version the devices has currently loaded + * is known by this driver. 'version' needs to have 4 bytes version + * info data. */ +static int usb6fire_fw_check(u8 *version) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++) + if (!memcmp(version, known_fw_versions + i, 4)) + return 0; + + snd_printk(KERN_ERR PREFIX "invalid fimware version in device: " + "%02x %02x %02x %02x. " + "please reconnect to power. if this failure " + "still happens, check your firmware installation.", + version[0], version[1], version[2], version[3]); + return -EINVAL; +} + int usb6fire_fw_init(struct usb_interface *intf) { int i; @@ -378,9 +370,7 @@ int usb6fire_fw_init(struct usb_interface *intf) "firmware state.\n"); return ret; } - if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55 - || buffer[4] != 0x03 || buffer[5] != 0x01 || buffer[7] - != 0x00) { + if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) { snd_printk(KERN_ERR PREFIX "unknown device firmware state " "received from device: "); for (i = 0; i < 8; i++) @@ -389,7 +379,7 @@ int usb6fire_fw_init(struct usb_interface *intf) return -EIO; } /* do we need fpga loader ezusb firmware? */ - if (buffer[3] == 0x01 && buffer[6] == 0x19) { + if (buffer[3] == 0x01) { ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6firel2.ihx", 0, NULL, 0); if (ret < 0) @@ -397,7 +387,10 @@ int usb6fire_fw_init(struct usb_interface *intf) return FW_NOT_READY; } /* do we need fpga firmware and application ezusb firmware? */ - else if (buffer[3] == 0x02 && buffer[6] == 0x0b) { + else if (buffer[3] == 0x02) { + ret = usb6fire_fw_check(buffer + 4); + if (ret < 0) + return ret; ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin"); if (ret < 0) return ret; @@ -410,8 +403,8 @@ int usb6fire_fw_init(struct usb_interface *intf) return FW_NOT_READY; } /* all fw loaded? */ - else if (buffer[3] == 0x03 && buffer[6] == 0x0b) - return 0; + else if (buffer[3] == 0x03) + return usb6fire_fw_check(buffer + 4); /* unknown data? */ else { snd_printk(KERN_ERR PREFIX "unknown device firmware state " diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index ba62c7468ba..b137b25865c 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -17,26 +17,23 @@ #include "pcm.h" #include "chip.h" #include "comm.h" +#include "control.h" enum { OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4 }; /* keep next two synced with - * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */ + * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE + * and CONTROL_RATE_XXX in control.h */ static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 }; static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 }; static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; -static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; static const int rates_alsaid[] = { SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000, SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000, SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 }; -/* values to write to soundcard register for all samplerates */ -static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; -static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; - enum { /* settings for pcm */ OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024 }; @@ -48,15 +45,6 @@ enum { /* pcm streaming states */ STREAM_STOPPING }; -enum { /* pcm sample rates (also index into RATES_XXX[]) */ - RATE_44KHZ, - RATE_48KHZ, - RATE_88KHZ, - RATE_96KHZ, - RATE_176KHZ, - RATE_192KHZ -}; - static const struct snd_pcm_hardware pcm_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -64,7 +52,7 @@ static const struct snd_pcm_hardware pcm_hw = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH, - .formats = SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | @@ -87,57 +75,34 @@ static const struct snd_pcm_hardware pcm_hw = { static int usb6fire_pcm_set_rate(struct pcm_runtime *rt) { int ret; - struct usb_device *device = rt->chip->dev; - struct comm_runtime *comm_rt = rt->chip->comm; + struct control_runtime *ctrl_rt = rt->chip->control; - if (rt->rate >= ARRAY_SIZE(rates)) - return -EINVAL; - /* disable streaming */ - ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00); + ctrl_rt->usb_streaming = false; + ret = ctrl_rt->update_streaming(ctrl_rt); if (ret < 0) { snd_printk(KERN_ERR PREFIX "error stopping streaming while " "setting samplerate %d.\n", rates[rt->rate]); return ret; } - ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]); - if (ret < 0) { - snd_printk(KERN_ERR PREFIX "error setting interface " - "altsetting %d for samplerate %d.\n", - rates_altsetting[rt->rate], rates[rt->rate]); - return ret; - } - - /* set soundcard clock */ - ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate], - rates_6fire_vh[rt->rate]); + ret = ctrl_rt->set_rate(ctrl_rt, rt->rate); if (ret < 0) { snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n", rates[rt->rate]); return ret; } - /* enable analog inputs and outputs - * (one bit per stereo-channel) */ - ret = comm_rt->write16(comm_rt, 0x02, 0x02, - (1 << (OUT_N_CHANNELS / 2)) - 1, - (1 << (IN_N_CHANNELS / 2)) - 1); + ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS, + false, false); if (ret < 0) { - snd_printk(KERN_ERR PREFIX "error initializing analog channels " + snd_printk(KERN_ERR PREFIX "error initializing channels " "while setting samplerate %d.\n", rates[rt->rate]); return ret; } - /* disable digital inputs and outputs */ - ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00); - if (ret < 0) { - snd_printk(KERN_ERR PREFIX "error initializing digital " - "channels while setting samplerate %d.\n", - rates[rt->rate]); - return ret; - } - ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01); + ctrl_rt->usb_streaming = true; + ret = ctrl_rt->update_streaming(ctrl_rt); if (ret < 0) { snd_printk(KERN_ERR PREFIX "error starting streaming while " "setting samplerate %d.\n", rates[rt->rate]); @@ -168,12 +133,15 @@ static struct pcm_substream *usb6fire_pcm_get_substream( static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt) { int i; + struct control_runtime *ctrl_rt = rt->chip->control; if (rt->stream_state != STREAM_DISABLED) { for (i = 0; i < PCM_N_URBS; i++) { usb_kill_urb(&rt->in_urbs[i].instance); usb_kill_urb(&rt->out_urbs[i].instance); } + ctrl_rt->usb_streaming = false; + ctrl_rt->update_streaming(ctrl_rt); rt->stream_state = STREAM_DISABLED; } } @@ -228,7 +196,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) unsigned int total_length = 0; struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; - u32 *src = (u32 *) urb->buffer; + u32 *src = NULL; u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off * (alsa_rt->frame_bits >> 3)); u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size @@ -244,7 +212,12 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) else frame_count = 0; - src = (u32 *) (urb->buffer + total_length); + if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) + src = (u32 *) (urb->buffer + total_length); + else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) + src = (u32 *) (urb->buffer - 1 + total_length); + else + return; src++; /* skip leading 4 bytes of every packet */ total_length += urb->packets[i].length; for (frame = 0; frame < frame_count; frame++) { @@ -274,9 +247,18 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub, * (alsa_rt->frame_bits >> 3)); u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size * (alsa_rt->frame_bits >> 3)); - u32 *dest = (u32 *) urb->buffer; + u32 *dest; int bytes_per_frame = alsa_rt->channels << 2; + if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) + dest = (u32 *) (urb->buffer - 1); + else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) + dest = (u32 *) (urb->buffer); + else { + snd_printk(KERN_ERR PREFIX "Unknown sample format."); + return; + } + for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { /* at least 4 header bytes for valid packet. * after that: 32 bits per sample for analog channels */ @@ -456,7 +438,7 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub) /* all substreams closed? if so, stop streaming */ if (!rt->playback.instance && !rt->capture.instance) { usb6fire_pcm_stream_stop(rt); - rt->rate = -1; + rt->rate = ARRAY_SIZE(rates); } } mutex_unlock(&rt->stream_mutex); @@ -480,7 +462,6 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; - int i; int ret; if (rt->panic) @@ -493,12 +474,10 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) sub->period_off = 0; if (rt->stream_state == STREAM_DISABLED) { - for (i = 0; i < ARRAY_SIZE(rates); i++) - if (alsa_rt->rate == rates[i]) { - rt->rate = i; + for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++) + if (alsa_rt->rate == rates[rt->rate]) break; - } - if (i == ARRAY_SIZE(rates)) { + if (rt->rate == ARRAY_SIZE(rates)) { mutex_unlock(&rt->stream_mutex); snd_printk("invalid rate %d in prepare.\n", alsa_rt->rate); @@ -613,7 +592,7 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip) rt->chip = chip; rt->stream_state = STREAM_DISABLED; - rt->rate = -1; + rt->rate = ARRAY_SIZE(rates); init_waitqueue_head(&rt->stream_wait_queue); mutex_init(&rt->stream_mutex); diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 97724d8fa9f..8beb77563da 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -100,19 +100,17 @@ config SND_USB_US122L config SND_USB_6FIRE tristate "TerraTec DMX 6Fire USB" - depends on EXPERIMENTAL select FW_LOADER + select BITREVERSE select SND_RAWMIDI select SND_PCM help Say Y here to include support for TerraTec 6fire DMX USB interface. You will need firmware files in order to be able to use the device - after it has been coldstarted. This driver currently does not support - firmware loading for all devices. If you own such a device, - you could start windows and let the windows driver upload - the firmware. As long as you do not unplug your device from power, - it should be usable. + after it has been coldstarted. An install script for the firmware + and further help can be found at + http://sixfireusb.sourceforge.net endif # SND_USB diff --git a/sound/usb/card.c b/sound/usb/card.c index a90662af2d6..220c6167dd8 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -48,6 +48,7 @@ #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> +#include <sound/control.h> #include <sound/core.h> #include <sound/info.h> #include <sound/pcm.h> @@ -492,14 +493,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, } } - chip->txfr_quirk = 0; - err = 1; /* continue */ - if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { - /* need some special handlings */ - if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0) - goto __error; - } - /* * For devices with more than one control interface, we assume the * first contains the audio controls. We might need a more specific @@ -508,6 +501,14 @@ static void *snd_usb_audio_probe(struct usb_device *dev, if (!chip->ctrl_intf) chip->ctrl_intf = alts; + chip->txfr_quirk = 0; + err = 1; /* continue */ + if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { + /* need some special handlings */ + if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0) + goto __error; + } + if (err > 0) { /* create normal USB audio interfaces */ if (snd_usb_create_streams(chip, ifnum) < 0 || diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 7754a103454..075195e8661 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -104,6 +104,15 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) int err; unsigned char data; struct usb_device *dev = chip->dev; + struct uac_clock_source_descriptor *cs_desc = + snd_usb_find_clock_source(chip->ctrl_intf, source_id); + + if (!cs_desc) + return 0; + + /* If a clock source can't tell us whether it's valid, we assume it is */ + if (!uac2_control_is_readable(cs_desc->bmControls, UAC2_CS_CONTROL_CLOCK_VALID)) + return 1; err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, @@ -114,7 +123,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) if (err < 0) { snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n", __func__, source_id); - return err; + return 0; } return !!data; diff --git a/sound/usb/debug.h b/sound/usb/debug.h index 343ec2d9ee6..58030176f00 100644 --- a/sound/usb/debug.h +++ b/sound/usb/debug.h @@ -8,7 +8,7 @@ #ifdef HW_CONST_DEBUG #define hwc_debug(fmt, args...) printk(KERN_DEBUG fmt, ##args) #else -#define hwc_debug(fmt, args...) /**/ +#define hwc_debug(fmt, args...) do { } while(0) #endif #endif /* __USBAUDIO_DEBUG_H */ diff --git a/sound/usb/format.c b/sound/usb/format.c index 5b792d2c806..8d042dce0d1 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -30,6 +30,7 @@ #include "helper.h" #include "debug.h" #include "clock.h" +#include "format.h" /* * parse the audio format type I descriptor @@ -176,9 +177,11 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof if (!rate) continue; /* C-Media CM6501 mislabels its 96 kHz altsetting */ + /* Terratec Aureon 7.1 USB C-Media 6206, too */ if (rate == 48000 && nr_rates == 1 && (chip->usb_id == USB_ID(0x0d8c, 0x0201) || - chip->usb_id == USB_ID(0x0d8c, 0x0102)) && + chip->usb_id == USB_ID(0x0d8c, 0x0102) || + chip->usb_id == USB_ID(0x0ccd, 0x00b1)) && fp->altsetting == 5 && fp->maxpacksize == 392) rate = 96000; /* Creative VF0470 Live Cam reports 16 kHz instead of 8kHz */ diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 6ec33b62e6c..c22fa76e363 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -86,16 +86,6 @@ struct mixer_build { const struct usbmix_selector_map *selector_map; }; -enum { - USB_MIXER_BOOLEAN, - USB_MIXER_INV_BOOLEAN, - USB_MIXER_S8, - USB_MIXER_U8, - USB_MIXER_S16, - USB_MIXER_U16, -}; - - /*E-mu 0202/0404/0204 eXtension Unit(XU) control*/ enum { USB_XU_CLOCK_RATE = 0xe301, @@ -535,20 +525,21 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou * if failed, give up and free the control instance. */ -static int add_control_to_empty(struct mixer_build *state, struct snd_kcontrol *kctl) +int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, + struct snd_kcontrol *kctl) { struct usb_mixer_elem_info *cval = kctl->private_data; int err; - while (snd_ctl_find_id(state->chip->card, &kctl->id)) + while (snd_ctl_find_id(mixer->chip->card, &kctl->id)) kctl->id.index++; - if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { + if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) { snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); return err; } cval->elem_id = &kctl->id; - cval->next_id_elem = state->mixer->id_elems[cval->id]; - state->mixer->id_elems[cval->id] = cval; + cval->next_id_elem = mixer->id_elems[cval->id]; + mixer->id_elems[cval->id] = cval; return 0; } @@ -984,6 +975,9 @@ static struct snd_kcontrol_new usb_feature_unit_ctl_ro = { .put = NULL, }; +/* This symbol is exported in order to allow the mixer quirks to + * hook up to the standard feature unit control mechanism */ +struct snd_kcontrol_new *snd_usb_feature_unit_ctl = &usb_feature_unit_ctl; /* * build a feature control @@ -1097,11 +1091,13 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, append_ctl_name(kctl, control == UAC_FU_MUTE ? " Switch" : " Volume"); if (control == UAC_FU_VOLUME) { - kctl->tlv.c = mixer_vol_tlv; - kctl->vd[0].access |= - SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; check_mapped_dB(map, cval); + if (cval->dBmin < cval->dBmax) { + kctl->tlv.c = mixer_vol_tlv; + kctl->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; + } } break; @@ -1174,7 +1170,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); - add_control_to_empty(state, kctl); + snd_usb_mixer_add_control(state->mixer, kctl); } @@ -1338,7 +1334,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); - add_control_to_empty(state, kctl); + snd_usb_mixer_add_control(state->mixer, kctl); } @@ -1639,7 +1635,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); - if ((err = add_control_to_empty(state, kctl)) < 0) + if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0) return err; } return 0; @@ -1856,7 +1852,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", cval->id, kctl->id.name, desc->bNrInPins); - if ((err = add_control_to_empty(state, kctl)) < 0) + if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0) return err; return 0; diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index b4a2c8165e4..ae1a14dcfe8 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -24,7 +24,16 @@ struct usb_mixer_interface { u8 xonar_u1_status; }; -#define MAX_CHANNELS 10 /* max logical channels */ +#define MAX_CHANNELS 16 /* max logical channels */ + +enum { + USB_MIXER_BOOLEAN, + USB_MIXER_INV_BOOLEAN, + USB_MIXER_S8, + USB_MIXER_U8, + USB_MIXER_S16, + USB_MIXER_U16, +}; struct usb_mixer_elem_info { struct usb_mixer_interface *mixer; @@ -55,4 +64,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer); int snd_usb_mixer_activate(struct usb_mixer_interface *mixer); +int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, + struct snd_kcontrol *kctl); + #endif /* __USBMIXER_H */ diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 73dcc8256bc..3d0f4873112 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -40,6 +40,8 @@ #include "mixer_quirks.h" #include "helper.h" +extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl; + /* * Sound Blaster remote control configuration * @@ -61,6 +63,7 @@ static const struct rc_config { { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 */ + { USB_ID(0x041e, 0x30df), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ }; @@ -188,6 +191,12 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, !value, 0, NULL, 0, 100); + /* USB X-Fi S51 Pro */ + if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + !value, 0, NULL, 0, 100); else err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, @@ -234,9 +243,13 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) /* USB X-Fi S51 doesn't have a CMSS LED */ if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0) continue; + /* USB X-Fi S51 Pro doesn't have one either */ + if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0) + continue; if (i > 1 && /* Live24ext has 2 LEDs only */ (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || mixer->chip->usb_id == USB_ID(0x041e, 0x3042) || + mixer->chip->usb_id == USB_ID(0x041e, 0x30df) || mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) break; err = snd_ctl_add(mixer->chip->card, @@ -481,6 +494,69 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, return err; } +/* M-Audio FastTrack Ultra quirks */ + +/* private_free callback */ +static void usb_mixer_elem_free(struct snd_kcontrol *kctl) +{ + kfree(kctl->private_data); + kctl->private_data = NULL; +} + +static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer, + int in, int out, const char *name) +{ + struct usb_mixer_elem_info *cval; + struct snd_kcontrol *kctl; + + cval = kzalloc(sizeof(*cval), GFP_KERNEL); + if (!cval) + return -ENOMEM; + + cval->id = 5; + cval->mixer = mixer; + cval->val_type = USB_MIXER_S16; + cval->channels = 1; + cval->control = out + 1; + cval->cmask = 1 << in; + + kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); + if (!kctl) { + kfree(cval); + return -ENOMEM; + } + + snprintf(kctl->id.name, sizeof(kctl->id.name), name); + kctl->private_free = usb_mixer_elem_free; + return snd_usb_mixer_add_control(mixer, kctl); +} + +static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer) +{ + char name[64]; + int in, out, err; + + for (out = 0; out < 8; out++) { + for (in = 0; in < 8; in++) { + snprintf(name, sizeof(name), + "AIn%d - Out%d Capture Volume", in + 1, out + 1); + err = snd_maudio_ftu_create_ctl(mixer, in, out, name); + if (err < 0) + return err; + } + + for (in = 8; in < 16; in++) { + snprintf(name, sizeof(name), + "DIn%d - Out%d Playback Volume", in - 7, out + 1); + err = snd_maudio_ftu_create_ctl(mixer, in, out, name); + if (err < 0) + return err; + } + } + + return 0; +} + void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, unsigned char samplerate_id) { @@ -512,6 +588,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x041e, 0x3020): case USB_ID(0x041e, 0x3040): case USB_ID(0x041e, 0x3042): + case USB_ID(0x041e, 0x30df): case USB_ID(0x041e, 0x3048): err = snd_audigy2nx_controls_create(mixer); if (err < 0) @@ -521,6 +598,11 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) snd_audigy2nx_proc_read); break; + case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ + case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ + err = snd_maudio_ftu_create_mixer(mixer); + break; + case USB_ID(0x0b05, 0x1739): case USB_ID(0x0b05, 0x1743): err = snd_xonar_u1_controls_create(mixer); diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index c66d3f64dcf..0b2ae8e1c02 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1651,6 +1651,32 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + USB_DEVICE(0x0582, 0x0127), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Roland", */ + /* .product_name = "GR-55", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, /* Guillemot devices */ { @@ -1953,7 +1979,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { - USB_DEVICE(0x0763, 0x2080), + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2080), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { /* .vendor_name = "M-Audio", */ /* .product_name = "Fast Track Ultra", */ @@ -1962,7 +1988,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), .data = & (const struct snd_usb_audio_quirk[]) { { .ifnum = 0, - .type = QUIRK_IGNORE_INTERFACE + .type = QUIRK_AUDIO_STANDARD_MIXER, }, { .ifnum = 1, @@ -2020,7 +2046,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { - USB_DEVICE(0x0763, 0x2081), + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2081), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { /* .vendor_name = "M-Audio", */ /* .product_name = "Fast Track Ultra 8R", */ @@ -2029,7 +2055,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), .data = & (const struct snd_usb_audio_quirk[]) { { .ifnum = 0, - .type = QUIRK_IGNORE_INTERFACE + .type = QUIRK_AUDIO_STANDARD_MIXER, }, { .ifnum = 1, @@ -2179,6 +2205,17 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +/* KORG devices */ +{ + USB_DEVICE_VENDOR_SPEC(0x0944, 0x0200), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "KORG, Inc.", + /* .product_name = "PANDORA PX5D", */ + .ifnum = 3, + .type = QUIRK_MIDI_STANDARD_INTERFACE, + } +}, + /* AKAI devices */ { USB_DEVICE(0x09e8, 0x0062), @@ -2332,6 +2369,12 @@ YAMAHA_DEVICE(0x7010, "UB99"), /* Native Instruments MK2 series */ { + /* Komplete Audio 6 */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x17cc, + .idProduct = 0x1000, +}, +{ /* Traktor Audio 6 */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x17cc, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index ec07e62e53f..2e969cbb393 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -19,6 +19,7 @@ #include <linux/usb.h> #include <linux/usb/audio.h> +#include <sound/control.h> #include <sound/core.h> #include <sound/info.h> #include <sound/pcm.h> @@ -263,6 +264,20 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, } /* + * Create a standard mixer for the specified interface. + */ +static int create_standard_mixer_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + struct usb_driver *driver, + const struct snd_usb_audio_quirk *quirk) +{ + if (quirk->ifnum < 0) + return 0; + + return snd_usb_create_mixer(chip, quirk->ifnum, 0); +} + +/* * audio-interface quirks * * returns zero if no standard audio/MIDI parsing is needed. @@ -294,7 +309,8 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, - [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk + [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk, + [QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk, }; if (quirk->type < QUIRK_TYPE_COUNT) { @@ -533,12 +549,14 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, case USB_ID(0x0d8c, 0x0102): /* C-Media CM6206 / CM106-Like Sound Device */ + case USB_ID(0x0ccd, 0x00b1): /* Terratec Aureon 7.1 USB */ return snd_usb_cm6206_boot_quirk(dev); case USB_ID(0x133e, 0x0815): /* Access Music VirusTI Desktop */ return snd_usb_accessmusic_boot_quirk(dev); + case USB_ID(0x17cc, 0x1000): /* Komplete Audio 6 */ case USB_ID(0x17cc, 0x1010): /* Traktor Audio 6 */ case USB_ID(0x17cc, 0x1020): /* Traktor Audio 10 */ return snd_usb_nativeinstruments_boot_quirk(dev); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 32f2a97f2f1..1e79986b577 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -84,6 +84,7 @@ enum quirk_type { QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UAXX, QUIRK_AUDIO_ALIGN_TRANSFER, + QUIRK_AUDIO_STANDARD_MIXER, QUIRK_TYPE_COUNT }; |