diff --git a/.gitignore b/.gitignore index 8b8f6b9..f2561da 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.mod *.mod.c *.o +*.o.d /*.tar.gz /build diff --git a/Dockerfile b/Dockerfile index f198d2a..2af2212 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,10 @@ -FROM ubuntu:trusty +FROM ubuntu:bionic ENV DEBIAN_FRONTEND noninteractive RUN apt-get -qq update RUN apt-get -qqy upgrade -RUN apt-get -qqy install python-software-properties build-essential -RUN apt-get -qqy install linux-headers-generic +RUN apt-get -qqy install software-properties-common build-essential cpio linux-headers-generic RUN ln -s /usr/src/linux-headers-$(uname -r)/include/generated/uapi/linux/version.h /usr/src/linux-headers-$(uname -r)/include/linux/version.h COPY . /work diff --git a/diag/diag.c b/diag/diag.c old mode 100644 new mode 100755 diff --git a/diag/modemexpert.c b/diag/modemexpert.c old mode 100644 new mode 100755 diff --git a/diag/modemexpert.h b/diag/modemexpert.h old mode 100644 new mode 100755 diff --git a/modules/GPL/hda/hda_codec.c b/modules/GPL/hda/hda_codec.c deleted file mode 100644 index db75bba..0000000 --- a/modules/GPL/hda/hda_codec.c +++ /dev/null @@ -1,2484 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * Copyright (c) 2004 Takashi Iwai - * - * - * This driver 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 driver 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 -#include -#include -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include -#ifdef FOUND_TLV -#include -#endif -#include -#include "hda_local.h" - - -MODULE_AUTHOR("Takashi Iwai "); -MODULE_DESCRIPTION("Universal interface for High Definition Audio Codec"); -MODULE_LICENSE("GPL"); - - -/* - * vendor / preset table - */ - -struct hda_vendor_id { - unsigned int id; - const char *name; -}; - -/* codec vendor labels */ -static struct hda_vendor_id hda_vendor_ids[] = { - { 0x10ec, "Realtek" }, - { 0x1057, "Motorola" }, - { 0x1106, "VIA" }, - { 0x11d4, "Analog Devices" }, - { 0x13f6, "C-Media" }, - { 0x14f1, "Conexant" }, - { 0x434d, "C-Media" }, - { 0x8384, "SigmaTel" }, - {} /* terminator */ -}; - -/* codec presets */ -#include "hda_patch.h" - - -/** - * snd_hda_codec_wallclock - get the wallclock counter - * @codec: the HDA codec - * - * Get the wallclock counter - * - * Returns the obtained value, or -1 for an error. - */ -unsigned int snd_hda_codec_wallclock(struct hda_codec *codec) -{ - u32 res; - if(codec->bus->ops.get_wallclock) - res = codec->bus->ops.get_wallclock(codec); - else - res = (u32)-1; - return res; -} - -EXPORT_SYMBOL(snd_hda_codec_wallclock); - -/** - * snd_hda_codec_read - send a command and get the response - * @codec: the HDA codec - * @nid: NID to send the command - * @direct: direct flag - * @verb: the verb to send - * @parm: the parameter for the verb - * - * Send a single command and read the corresponding response. - * - * Returns the obtained response value, or -1 for an error. - */ -unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int parm) -{ - unsigned int res; - mutex_lock(&codec->bus->cmd_mutex); - if (! codec->bus->ops.command(codec, nid, direct, verb, parm)) - res = codec->bus->ops.get_response(codec); - else - res = (unsigned int)-1; - mutex_unlock(&codec->bus->cmd_mutex); - return res; -} - -EXPORT_SYMBOL(snd_hda_codec_read); - -/** - * snd_hda_codec_write - send a single command without waiting for response - * @codec: the HDA codec - * @nid: NID to send the command - * @direct: direct flag - * @verb: the verb to send - * @parm: the parameter for the verb - * - * Send a single command without waiting for response. - * - * Returns 0 if successful, or a negative error code. - */ -int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int parm) -{ - int err; - mutex_lock(&codec->bus->cmd_mutex); - err = codec->bus->ops.command(codec, nid, direct, verb, parm); - mutex_unlock(&codec->bus->cmd_mutex); - return err; -} - -EXPORT_SYMBOL(snd_hda_codec_write); - -/** - * snd_hda_sequence_write - sequence writes - * @codec: the HDA codec - * @seq: VERB array to send - * - * Send the commands sequentially from the given array. - * The array must be terminated with NID=0. - */ -void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq) -{ - for (; seq->nid; seq++) - snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); -} - -EXPORT_SYMBOL(snd_hda_sequence_write); - -/** - * snd_hda_get_sub_nodes - get the range of sub nodes - * @codec: the HDA codec - * @nid: NID to parse - * @start_id: the pointer to store the start NID - * - * Parse the NID and store the start NID of its sub-nodes. - * Returns the number of sub-nodes. - */ -int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id) -{ - unsigned int parm; - - parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); - *start_id = (parm >> 16) & 0x7fff; - return (int)(parm & 0x7fff); -} - -EXPORT_SYMBOL(snd_hda_get_sub_nodes); - -/** - * snd_hda_get_connections - get connection list - * @codec: the HDA codec - * @nid: NID to parse - * @conn_list: connection list array - * @max_conns: max. number of connections to store - * - * Parses the connection list of the given widget and stores the list - * of NIDs. - * - * 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) -{ - unsigned int parm; - int i, conn_len, conns; - unsigned int shift, num_elems, mask; - hda_nid_t prev_nid; - - snd_assert(conn_list && max_conns > 0, return -EINVAL); - - parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN); - if (parm & AC_CLIST_LONG) { - /* long form */ - shift = 16; - num_elems = 2; - } else { - /* short form */ - shift = 8; - num_elems = 4; - } - conn_len = parm & AC_CLIST_LENGTH; - mask = (1 << (shift-1)) - 1; - - if (! conn_len) - return 0; /* no connection */ - - if (conn_len == 1) { - /* single connection */ - parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, 0); - conn_list[0] = parm & mask; - return 1; - } - - /* multi connection */ - conns = 0; - prev_nid = 0; - for (i = 0; i < conn_len; i++) { - int range_val; - hda_nid_t val, n; - - if (i % num_elems == 0) - parm = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONNECT_LIST, i); - range_val = !! (parm & (1 << (shift-1))); /* ranges */ - val = parm & mask; - parm >>= shift; - if (range_val) { - /* ranges between the previous and this one */ - if (! prev_nid || prev_nid >= val) { - snd_printk(KERN_WARNING "hda_codec: invalid dep_range_val %x:%x\n", prev_nid, val); - continue; - } - for (n = prev_nid + 1; n <= val; n++) { - if (conns >= max_conns) { - snd_printk(KERN_ERR "Too many connections\n"); - return -EINVAL; - } - conn_list[conns++] = n; - } - } else { - if (conns >= max_conns) { - snd_printk(KERN_ERR "Too many connections\n"); - return -EINVAL; - } - conn_list[conns++] = val; - } - prev_nid = val; - } - return conns; -} - - -/** - * snd_hda_queue_unsol_event - add an unsolicited event to queue - * @bus: the BUS - * @res: unsolicited event (lower 32bit of RIRB entry) - * @res_ex: codec addr and flags (upper 32bit or RIRB entry) - * - * Adds the given event to the queue. The events are processed in - * the workqueue asynchronously. Call this function in the interrupt - * hanlder when RIRB receives an unsolicited event. - * - * Returns 0 if successful, or a negative error code. - */ -int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) -{ - struct hda_bus_unsolicited *unsol; - unsigned int wp; - - if ((unsol = bus->unsol) == NULL) - return 0; - - wp = (unsol->wp + 1) % HDA_UNSOL_QUEUE_SIZE; - unsol->wp = wp; - - wp <<= 1; - unsol->queue[wp] = res; - unsol->queue[wp + 1] = res_ex; - - schedule_work(&unsol->work); - - return 0; -} - -EXPORT_SYMBOL(snd_hda_queue_unsol_event); - -/* - * process queued unsolicited events - */ -#ifdef FOUND_DELAYED_WORK -static void process_unsol_events(struct work_struct *work) -#else -static void process_unsol_events(void *data) -#endif -{ -#ifdef FOUND_DELAYED_WORK - struct hda_bus_unsolicited *unsol = - container_of(work, struct hda_bus_unsolicited, work); - struct hda_bus *bus = unsol->bus; -#else - struct hda_bus *bus = data; - struct hda_bus_unsolicited *unsol = bus->unsol; -#endif - struct hda_codec *codec; - unsigned int rp, caddr, res; - - while (unsol->rp != unsol->wp) { - rp = (unsol->rp + 1) % HDA_UNSOL_QUEUE_SIZE; - unsol->rp = rp; - rp <<= 1; - res = unsol->queue[rp]; - caddr = unsol->queue[rp + 1]; - if (! (caddr & (1 << 4))) /* no unsolicited event? */ - continue; - codec = bus->caddr_tbl[caddr & 0x0f]; - if (codec && codec->patch_ops.unsol_event) - codec->patch_ops.unsol_event(codec, res); - } -} - -/* - * initialize unsolicited queue - */ -static int init_unsol_queue(struct hda_bus *bus) -{ - struct hda_bus_unsolicited *unsol; - - if (bus->unsol) /* already initialized */ - return 0; - - unsol = kzalloc(sizeof(*unsol), GFP_KERNEL); - if (! unsol) { - snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n"); - return -ENOMEM; - } -#ifdef FOUND_DELAYED_WORK - INIT_WORK(&unsol->work, process_unsol_events); - unsol->bus = bus; -#else - INIT_WORK(&unsol->work, process_unsol_events, bus); -#endif - bus->unsol = unsol; - return 0; -} - -void snd_hda_codec_remove_notify_all(struct hda_bus *bus) -{ - struct list_head *p, *n; - -//printk("%s: %p\n", __FUNCTION__, bus); - if (! bus) - return; - list_for_each_safe(p, n, &bus->codec_list) { - struct hda_codec *codec = list_entry(p, struct hda_codec, list); - - if (codec && codec->patch_ops.exit) { -//printk("%s: %p calling codec->patch_ops.exit for codec %p\n", __FUNCTION__, bus, codec); - codec->patch_ops.exit(codec); - } - } -} - -EXPORT_SYMBOL(snd_hda_codec_remove_notify_all); - -/* - * destructor - */ -static void snd_hda_codec_free(struct hda_codec *codec); - -static int snd_hda_bus_free(struct hda_bus *bus) -{ - struct list_head *p, *n; - -//printk("%s: %p\n", __FUNCTION__, bus); - if (! bus) - return 0; - if (bus->unsol) { - flush_scheduled_work(); - kfree(bus->unsol); - } - list_for_each_safe(p, n, &bus->codec_list) { - struct hda_codec *codec = list_entry(p, struct hda_codec, list); - snd_hda_codec_free(codec); - } - if (bus->ops.private_free) - bus->ops.private_free(bus); - kfree(bus); - return 0; -} - -static int snd_hda_bus_dev_free(struct snd_device *device) -{ - struct hda_bus *bus = device->device_data; -//printk("%s: %p\n", __FUNCTION__, device); - return snd_hda_bus_free(bus); -} - -#if 0 -static int snd_hda_bus_dev_disconnect(snd_device_t *device) -{ - printk("%s: %p\n", __FUNCTION__, device); - return 0; -} - -static int snd_hda_bus_dev_unregister(snd_device_t *device) -{ - printk("%s: %p\n", __FUNCTION__, device); - return 0; -} -#endif - -/** - * snd_hda_bus_new - create a HDA bus - * @card: the card entry - * @temp: the template for hda_bus information - * @busp: the pointer to store the created bus instance - * - * Returns 0 if successful, or a negative error code. - */ -int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, - struct hda_bus **busp) -{ - struct hda_bus *bus; - int err; - static struct snd_device_ops dev_ops = { - .dev_free = snd_hda_bus_dev_free, -#if 0 - .dev_unregister = snd_hda_bus_dev_unregister, - .dev_disconnect = snd_hda_bus_dev_disconnect, -#endif - }; - -//printk(KERN_ERR"%s: card=%p\n", __FUNCTION__, card); - snd_assert(temp, return -EINVAL); - snd_assert(temp->ops.command && temp->ops.get_response, return -EINVAL); - - if (busp) - *busp = NULL; - - bus = kzalloc(sizeof(*bus), GFP_KERNEL); - if (bus == NULL) { - snd_printk(KERN_ERR "can't allocate struct hda_bus\n"); - return -ENOMEM; - } - - bus->card = card; - bus->private_data = temp->private_data; - bus->pci = temp->pci; - bus->modelname = temp->modelname; - bus->ops = temp->ops; - - mutex_init(&bus->cmd_mutex); - INIT_LIST_HEAD(&bus->codec_list); - - if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)) < 0) { - snd_hda_bus_free(bus); - return err; - } - if (busp) - *busp = bus; - return 0; -} - -EXPORT_SYMBOL(snd_hda_bus_new); - -/* - * find a matching codec preset - */ -static const struct hda_codec_preset *find_codec_preset(struct hda_codec *codec) -{ - const struct hda_codec_preset **tbl, *preset; - - if (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) - return NULL; /* use the generic parser */ - - for (tbl = hda_preset_tables; *tbl; tbl++) { - for (preset = *tbl; preset->id; preset++) { - u32 mask = preset->mask; - if (preset->afg && (preset->afg != codec->afg)) - continue; - if (preset->mfg && (preset->mfg != codec->mfg)) - continue; - if (! mask) - mask = ~0; - if (preset->id == (codec->vendor_id & mask) && - (! preset->rev || - preset->rev == codec->revision_id)) - return preset; - } - } - return NULL; -} - -/* - * snd_hda_get_codec_name - store the codec name - */ -void snd_hda_get_codec_name(struct hda_codec *codec, - char *name, int namelen) -{ - const struct hda_vendor_id *c; - const char *vendor = NULL; - u16 vendor_id = codec->vendor_id >> 16; - char tmp[16]; - - for (c = hda_vendor_ids; c->id; c++) { - if (c->id == vendor_id) { - vendor = c->name; - break; - } - } - if (! vendor) { - sprintf(tmp, "Generic %04x", vendor_id); - vendor = tmp; - } - if (codec->preset && codec->preset->name) - snprintf(name, namelen, "%s %s", vendor, codec->preset->name); - else - snprintf(name, namelen, "%s ID %x", vendor, codec->vendor_id & 0xffff); -} - -/* - * look for an AFG and MFG nodes - */ -static void setup_fg_nodes(struct hda_codec *codec) -{ - int i, total_nodes; - hda_nid_t nid; - - total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid); - for (i = 0; i < total_nodes; i++, nid++) { - switch((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff)) { - case AC_GRP_AUDIO_FUNCTION: - codec->afg = nid; - break; - case AC_GRP_MODEM_FUNCTION: - codec->mfg = nid; - break; - default: - break; - } - } -} - -/* - * read widget caps for each widget and store in cache - */ -static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node) -{ - int i; - hda_nid_t nid; - - codec->num_nodes = snd_hda_get_sub_nodes(codec, fg_node, - &codec->start_nid); - codec->wcaps = kmalloc(codec->num_nodes * 4, GFP_KERNEL); - if (! codec->wcaps) - return -ENOMEM; - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) - codec->wcaps[i] = snd_hda_param_read(codec, nid, - AC_PAR_AUDIO_WIDGET_CAP); - return 0; -} - - -/* - * codec destructor - */ -static void snd_hda_codec_free(struct hda_codec *codec) -{ -//printk("%s: %p\n", __FUNCTION__, codec); - if (! codec) - return; - list_del(&codec->list); - codec->bus->caddr_tbl[codec->addr] = NULL; - if (codec->patch_ops.free) - codec->patch_ops.free(codec); - kfree(codec->amp_info); - kfree(codec->wcaps); - kfree(codec); -} - -static void init_amp_hash(struct hda_codec *codec); - -/** - * snd_hda_codec_new - create a HDA codec - * @bus: the bus to assign - * @codec_addr: the codec address - * @codecp: the pointer to store the generated codec - * - * Returns 0 if successful, or a negative error code. - */ -int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, - struct hda_codec **codecp) -{ - struct hda_codec *codec; - char component[13]; - int err; - - snd_assert(bus, return -EINVAL); - snd_assert(codec_addr <= HDA_MAX_CODEC_ADDRESS, return -EINVAL); - - if (bus->caddr_tbl[codec_addr]) { - snd_printk(KERN_ERR "hda_codec: address 0x%x is already occupied\n", codec_addr); - return -EBUSY; - } - - codec = kzalloc(sizeof(*codec), GFP_KERNEL); - if (codec == NULL) { - snd_printk(KERN_ERR "can't allocate struct hda_codec\n"); - return -ENOMEM; - } - - codec->bus = bus; - codec->addr = codec_addr; - mutex_init(&codec->spdif_mutex); - init_amp_hash(codec); - - list_add_tail(&codec->list, &bus->codec_list); - bus->caddr_tbl[codec_addr] = codec; - - codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_VENDOR_ID); - if (codec->vendor_id == -1) - /* read again, hopefully the access method was corrected - * in the last read... - */ - codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, - AC_PAR_VENDOR_ID); - codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID); - codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID); - - setup_fg_nodes(codec); - if (! codec->afg && ! codec->mfg) { - snd_printdd("hda_codec: no AFG or MFG node found\n"); - snd_hda_codec_free(codec); - return -ENODEV; - } - - if (read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg) < 0) { - snd_printk(KERN_ERR "hda_codec: cannot malloc\n"); - snd_hda_codec_free(codec); - return -ENOMEM; - } - - if (! codec->subsystem_id) { - hda_nid_t nid = codec->afg ? codec->afg : codec->mfg; - codec->subsystem_id = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_SUBSYSTEM_ID, - 0); - } - - codec->preset = find_codec_preset(codec); -//printk("%s: %u %p afg=0x%04x mfg=0x%04x subsystem_id=%x preset=%p\n", __FUNCTION__, codec_addr, codec, codec->afg, codec->mfg, codec->subsystem_id, codec->preset); - if (! *bus->card->mixername) - snd_hda_get_codec_name(codec, bus->card->mixername, - sizeof(bus->card->mixername)); - - if (codec->preset && codec->preset->patch) - err = codec->preset->patch(codec); - else - err = snd_hda_parse_generic_codec(codec); - if (err < 0) { - snd_hda_codec_free(codec); - return err; - } - - if (codec->patch_ops.unsol_event) - init_unsol_queue(bus); - - snd_hda_codec_proc_new(codec); - - sprintf(component, "HDA:%08x", codec->vendor_id); - snd_component_add(codec->bus->card, component); - - if (codecp) - *codecp = codec; - return 0; -} - -EXPORT_SYMBOL(snd_hda_codec_new); - -/** - * snd_hda_codec_setup_stream - set up the codec for streaming - * @codec: the CODEC to set up - * @nid: the NID to set up - * @stream_tag: stream tag to pass, it's between 0x1 and 0xf. - * @channel_id: channel id to pass, zero based. - * @format: stream format. - */ -void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, - int channel_id, int format) -{ - if (! nid) - return; - - snd_printdd("hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", - nid, stream_tag, channel_id, format); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, - (stream_tag << 4) | channel_id); - msleep(1); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); -} - -EXPORT_SYMBOL(snd_hda_codec_setup_stream); - -/* - * amp access functions - */ - -/* FIXME: more better hash key? */ -#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) -#define INFO_AMP_CAPS (1<<0) -#define INFO_AMP_VOL(ch) (1 << (1 + (ch))) - -/* initialize the hash table */ -static void init_amp_hash(struct hda_codec *codec) -{ - memset(codec->amp_hash, 0xff, sizeof(codec->amp_hash)); - codec->num_amp_entries = 0; - codec->amp_info_size = 0; - codec->amp_info = NULL; -} - -/* query the hash. allocate an entry if not found. */ -static struct hda_amp_info *get_alloc_amp_hash(struct hda_codec *codec, u32 key) -{ - u16 idx = key % (u16)ARRAY_SIZE(codec->amp_hash); - u16 cur = codec->amp_hash[idx]; - struct hda_amp_info *info; - - while (cur != 0xffff) { - info = &codec->amp_info[cur]; - if (info->key == key) - return info; - cur = info->next; - } - - /* add a new hash entry */ - if (codec->num_amp_entries >= codec->amp_info_size) { - /* reallocate the array */ - int new_size = codec->amp_info_size + 64; - struct hda_amp_info *new_info = kcalloc(new_size, sizeof(struct hda_amp_info), - GFP_KERNEL); - if (! new_info) { - snd_printk(KERN_ERR "hda_codec: can't malloc amp_info\n"); - return NULL; - } - if (codec->amp_info) { - memcpy(new_info, codec->amp_info, - codec->amp_info_size * sizeof(struct hda_amp_info)); - kfree(codec->amp_info); - } - codec->amp_info_size = new_size; - codec->amp_info = new_info; - } - cur = codec->num_amp_entries++; - info = &codec->amp_info[cur]; - info->key = key; - info->status = 0; /* not initialized yet */ - info->next = codec->amp_hash[idx]; - codec->amp_hash[idx] = cur; - - return info; -} - -/* - * query AMP capabilities for the given widget and direction - */ -static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) -{ - struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0)); - - if (! info) - return 0; - if (! (info->status & INFO_AMP_CAPS)) { - if (! (get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD)) - nid = codec->afg; - info->amp_caps = snd_hda_param_read(codec, nid, direction == HDA_OUTPUT ? - AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); - info->status |= INFO_AMP_CAPS; - } - return info->amp_caps; -} - -int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, - unsigned int caps) -{ - struct hda_amp_info *info; - - info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, dir, 0)); - if (!info) - return -EINVAL; - info->amp_caps = caps; - info->status |= INFO_AMP_CAPS; - return 0; -} - -/* - * read the current volume to info - * if the cache exists, read the cache value. - */ -static unsigned int get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, - hda_nid_t nid, int ch, int direction, int index) -{ - u32 val, parm; - - if (info->status & INFO_AMP_VOL(ch)) - return info->vol[ch]; - - parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; - parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; - parm |= index; - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); - info->vol[ch] = val & 0xff; - info->status |= INFO_AMP_VOL(ch); - return info->vol[ch]; -} - -/* - * write the current volume in info to the h/w and update the cache - */ -static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, - hda_nid_t nid, int ch, int direction, int index, int val) -{ - u32 parm; - - parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; - parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; - parm |= index << AC_AMP_SET_INDEX_SHIFT; - parm |= val; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); - info->vol[ch] = val; -} - -/* - * read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. - */ -int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, - int direction, int index) -{ - struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); - if (! info) - return 0; - return get_vol_mute(codec, info, nid, ch, direction, index); -} - -/* - * update the AMP value, mask = bit mask to set, val = the value - */ -int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, - int direction, int idx, int mask, int val) -{ - struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); - - if (! info) - return 0; - val &= mask; - val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; - if (info->vol[ch] == val && ! codec->in_resume) - return 0; - put_vol_mute(codec, info, nid, ch, direction, idx, val); - return 1; -} - - -/* - * AMP control callbacks - */ -/* retrieve parameters from private_value */ -#define get_amp_nid(kc) ((kc)->private_value & 0xffff) -#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) -#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) -#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) - -/* volume */ -int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - u16 nid = get_amp_nid(kcontrol); - u8 chs = get_amp_channels(kcontrol); - int dir = get_amp_direction(kcontrol); - u32 caps; - - caps = query_amp_caps(codec, nid, dir); - caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; /* num steps */ - if (! caps) { - printk(KERN_WARNING "hda_codec: num_steps = 0 for NID=0x%x\n", nid); - return -EINVAL; - } - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = chs == 3 ? 2 : 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = caps; - return 0; -} - -int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = get_amp_nid(kcontrol); - int chs = get_amp_channels(kcontrol); - int dir = get_amp_direction(kcontrol); - int idx = get_amp_index(kcontrol); - long *valp = ucontrol->value.integer.value; - - if (chs & 1) - *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; - if (chs & 2) - *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f; - return 0; -} - -int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = get_amp_nid(kcontrol); - int chs = get_amp_channels(kcontrol); - int dir = get_amp_direction(kcontrol); - int idx = get_amp_index(kcontrol); - long *valp = ucontrol->value.integer.value; - int change = 0; - - if (chs & 1) { - change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, - 0x7f, *valp); - valp++; - } - if (chs & 2) - change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, - 0x7f, *valp); - return change; -} - -#ifdef FOUND_TLV -int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *_tlv) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = get_amp_nid(kcontrol); - int dir = get_amp_direction(kcontrol); - u32 caps, val1, val2; - - if (size < 4 * sizeof(unsigned int)) - return -ENOMEM; - caps = query_amp_caps(codec, nid, dir); - val2 = (((caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT) + 1) * 25; - val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); - val1 = ((int)val1) * ((int)val2); - 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; -} -#endif - -/* switch */ -int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - int chs = get_amp_channels(kcontrol); - - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = chs == 3 ? 2 : 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = get_amp_nid(kcontrol); - int chs = get_amp_channels(kcontrol); - int dir = get_amp_direction(kcontrol); - int idx = get_amp_index(kcontrol); - long *valp = ucontrol->value.integer.value; - - if (chs & 1) - *valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80) ? 0 : 1; - if (chs & 2) - *valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80) ? 0 : 1; - return 0; -} - -int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = get_amp_nid(kcontrol); - int chs = get_amp_channels(kcontrol); - int dir = get_amp_direction(kcontrol); - int idx = get_amp_index(kcontrol); - long *valp = ucontrol->value.integer.value; - int change = 0; - - if (chs & 1) { - change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, - 0x80, *valp ? 0 : 0x80); - valp++; - } - if (chs & 2) - change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, - 0x80, *valp ? 0 : 0x80); - - return change; -} - -/* - * bound volume controls - * - * bind multiple volumes (# indices, from 0) - */ - -#define AMP_VAL_IDX_SHIFT 19 -#define AMP_VAL_IDX_MASK (0x0f<<19) - -int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned long pval; - int err; - - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ - pval = kcontrol->private_value; - kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ - err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); - kcontrol->private_value = pval; - mutex_unlock(&codec->spdif_mutex); - return err; -} - -int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned long pval; - int i, indices, err = 0, change = 0; - - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ - pval = kcontrol->private_value; - indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; - for (i = 0; i < indices; i++) { - kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT); - err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - if (err < 0) - break; - change |= err; - } - kcontrol->private_value = pval; - mutex_unlock(&codec->spdif_mutex); - return err < 0 ? err : change; -} - -/* - * SPDIF out controls - */ - -static int snd_hda_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; - uinfo->count = 1; - return 0; -} - -static int snd_hda_spdif_cmask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL | - IEC958_AES0_NONAUDIO | - IEC958_AES0_CON_EMPHASIS_5015 | - IEC958_AES0_CON_NOT_COPYRIGHT; - ucontrol->value.iec958.status[1] = IEC958_AES1_CON_CATEGORY | - IEC958_AES1_CON_ORIGINAL; - return 0; -} - -static int snd_hda_spdif_pmask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL | - IEC958_AES0_NONAUDIO | - IEC958_AES0_PRO_EMPHASIS_5015; - return 0; -} - -static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff; - ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff; - ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff; - ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff; - - return 0; -} - -/* convert from SPDIF status bits to HDA SPDIF bits - * bit 0 (DigEn) is always set zero (to be filled later) - */ -static unsigned short convert_from_spdif_status(unsigned int sbits) -{ - unsigned short val = 0; - - if (sbits & IEC958_AES0_PROFESSIONAL) - val |= 1 << 6; - if (sbits & IEC958_AES0_NONAUDIO) - val |= 1 << 5; - if (sbits & IEC958_AES0_PROFESSIONAL) { - if ((sbits & IEC958_AES0_PRO_EMPHASIS) == IEC958_AES0_PRO_EMPHASIS_5015) - val |= 1 << 3; - } else { - if ((sbits & IEC958_AES0_CON_EMPHASIS) == IEC958_AES0_CON_EMPHASIS_5015) - val |= 1 << 3; - if (! (sbits & IEC958_AES0_CON_NOT_COPYRIGHT)) - val |= 1 << 4; - if (sbits & (IEC958_AES1_CON_ORIGINAL << 8)) - val |= 1 << 7; - val |= sbits & (IEC958_AES1_CON_CATEGORY << 8); - } - return val; -} - -/* convert to SPDIF status bits from HDA SPDIF bits - */ -static unsigned int convert_to_spdif_status(unsigned short val) -{ - unsigned int sbits = 0; - - if (val & (1 << 5)) - sbits |= IEC958_AES0_NONAUDIO; - if (val & (1 << 6)) - sbits |= IEC958_AES0_PROFESSIONAL; - if (sbits & IEC958_AES0_PROFESSIONAL) { - if (sbits & (1 << 3)) - sbits |= IEC958_AES0_PRO_EMPHASIS_5015; - } else { - if (val & (1 << 3)) - sbits |= IEC958_AES0_CON_EMPHASIS_5015; - if (! (val & (1 << 4))) - sbits |= IEC958_AES0_CON_NOT_COPYRIGHT; - if (val & (1 << 7)) - sbits |= (IEC958_AES1_CON_ORIGINAL << 8); - sbits |= val & (0x7f << 8); - } - return sbits; -} - -static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value; - unsigned short val; - int change; - - mutex_lock(&codec->spdif_mutex); - codec->spdif_status = ucontrol->value.iec958.status[0] | - ((unsigned int)ucontrol->value.iec958.status[1] << 8) | - ((unsigned int)ucontrol->value.iec958.status[2] << 16) | - ((unsigned int)ucontrol->value.iec958.status[3] << 24); - val = convert_from_spdif_status(codec->spdif_status); - val |= codec->spdif_ctls & 1; - change = codec->spdif_ctls != val; - codec->spdif_ctls = val; - - if (change || codec->in_resume) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val & 0xff); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, val >> 8); - } - - mutex_unlock(&codec->spdif_mutex); - return change; -} - -static int snd_hda_spdif_out_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = codec->spdif_ctls & 1; - return 0; -} - -static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value; - unsigned short val; - int change; - - mutex_lock(&codec->spdif_mutex); - val = codec->spdif_ctls & ~1; - if (ucontrol->value.integer.value[0]) - val |= 1; - change = codec->spdif_ctls != val; - if (change || codec->in_resume) { - codec->spdif_ctls = val; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - val & 0xff); - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | - AC_AMP_SET_OUTPUT | - ((val & 1) ? 0 : 0x80)); - } - mutex_unlock(&codec->spdif_mutex); - return change; -} - -static struct snd_kcontrol_new dig_mixes[] = { - { - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), - .info = snd_hda_spdif_mask_info, - .get = snd_hda_spdif_cmask_get, - }, - { - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), - .info = snd_hda_spdif_mask_info, - .get = snd_hda_spdif_pmask_get, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), - .info = snd_hda_spdif_mask_info, - .get = snd_hda_spdif_default_get, - .put = snd_hda_spdif_default_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), - .info = snd_hda_spdif_out_switch_info, - .get = snd_hda_spdif_out_switch_get, - .put = snd_hda_spdif_out_switch_put, - }, - { } /* end */ -}; - -/** - * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls - * @codec: the HDA codec - * @nid: audio out widget NID - * - * Creates controls related with the SPDIF output. - * Called from each patch supporting the SPDIF out. - * - * Returns 0 if successful, or a negative error code. - */ -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) -{ - int err; - struct snd_kcontrol *kctl; - struct snd_kcontrol_new *dig_mix; - - for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { - kctl = snd_ctl_new1(dig_mix, codec); - kctl->private_value = nid; - if ((err = snd_ctl_add(codec->bus->card, kctl)) < 0) - return err; - } - codec->spdif_ctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0); - codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); - return 0; -} - -/* - * SPDIF input - */ - -#define snd_hda_spdif_in_switch_info snd_hda_spdif_out_switch_info - -static int snd_hda_spdif_in_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = codec->spdif_in_enable; - return 0; -} - -static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value; - unsigned int val = !!ucontrol->value.integer.value[0]; - int change; - - mutex_lock(&codec->spdif_mutex); - change = codec->spdif_in_enable != val; - if (change || codec->in_resume) { - codec->spdif_in_enable = val; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val); - } - mutex_unlock(&codec->spdif_mutex); - return change; -} - -static int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value; - unsigned short val; - unsigned int sbits; - - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0); - sbits = convert_to_spdif_status(val); - ucontrol->value.iec958.status[0] = sbits; - ucontrol->value.iec958.status[1] = sbits >> 8; - ucontrol->value.iec958.status[2] = sbits >> 16; - ucontrol->value.iec958.status[3] = sbits >> 24; - return 0; -} - -static struct snd_kcontrol_new dig_in_ctls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), - .info = snd_hda_spdif_in_switch_info, - .get = snd_hda_spdif_in_switch_get, - .put = snd_hda_spdif_in_switch_put, - }, - { - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), - .info = snd_hda_spdif_mask_info, - .get = snd_hda_spdif_in_status_get, - }, - { } /* end */ -}; - -/** - * snd_hda_create_spdif_in_ctls - create Input SPDIF-related controls - * @codec: the HDA codec - * @nid: audio in widget NID - * - * Creates controls related with the SPDIF input. - * Called from each patch supporting the SPDIF in. - * - * Returns 0 if successful, or a negative error code. - */ -int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) -{ - int err; - struct snd_kcontrol *kctl; - struct snd_kcontrol_new *dig_mix; - - for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { - kctl = snd_ctl_new1(dig_mix, codec); - kctl->private_value = nid; - if ((err = snd_ctl_add(codec->bus->card, kctl)) < 0) - return err; - } - codec->spdif_in_enable = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0) & 1; - return 0; -} - - -/* - * set power state of the codec - */ -static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state) -{ - hda_nid_t nid, nid_start; - int nodes; - - snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, - power_state); - msleep(10); // partial workaround for "hda_intel: azx_get_response timeout, switching to polling mode..." issue - - nodes = snd_hda_get_sub_nodes(codec, fg, &nid_start); - for (nid = nid_start; nid < nodes + nid_start; nid++) { - if (get_wcaps(codec, nid) & AC_WCAP_POWER) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_POWER_STATE, - power_state); - } - - if (power_state == AC_PWRST_D0) - msleep(10); -} - - -/** - * snd_hda_build_controls - build mixer controls - * @bus: the BUS - * - * Creates mixer controls for each codec included in the bus. - * - * Returns 0 if successful, otherwise a negative error code. - */ -int snd_hda_build_controls(struct hda_bus *bus) -{ - struct list_head *p; - - /* build controls */ - list_for_each(p, &bus->codec_list) { - struct hda_codec *codec = list_entry(p, struct hda_codec, list); - int err; - if (! codec->patch_ops.build_controls) - continue; - err = codec->patch_ops.build_controls(codec); - if (err < 0) - return err; - } - - /* initialize */ - list_for_each(p, &bus->codec_list) { - struct hda_codec *codec = list_entry(p, struct hda_codec, list); - int err; - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D0); - if (! codec->patch_ops.init) - continue; - err = codec->patch_ops.init(codec); - if (err < 0) - return err; - } - return 0; -} - -EXPORT_SYMBOL(snd_hda_build_controls); - -/* - * stream formats - */ -struct hda_rate_tbl { - unsigned int hz; - unsigned int alsa_bits; - unsigned int hda_fmt; -}; - -static struct hda_rate_tbl rate_bits[] = { - /* rate in Hz, ALSA rate bitmask, HDA format value */ - - /* autodetected value used in snd_hda_query_supported_pcm */ - { 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */ - { 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */ - { 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */ - { 22050, SNDRV_PCM_RATE_22050, 0x4100 }, /* 1/2 x 44 */ - { 32000, SNDRV_PCM_RATE_32000, 0x0a00 }, /* 2/3 x 48 */ - { 44100, SNDRV_PCM_RATE_44100, 0x4000 }, /* 44 */ - { 48000, SNDRV_PCM_RATE_48000, 0x0000 }, /* 48 */ - { 88200, SNDRV_PCM_RATE_88200, 0x4800 }, /* 2 x 44 */ - { 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */ - { 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */ - { 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */ -#define AC_PAR_PCM_RATE_BITS 11 - /* up to bits 10, 384kHZ isn't supported properly */ - - /* not autodetected value */ - { 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */ - - { 0 } /* terminator */ -}; - -/** - * snd_hda_calc_stream_format - calculate format bitset - * @rate: the sample rate - * @channels: the number of channels - * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) - * @maxbps: the max. bps - * - * Calculate the format bitset from the given rate, channels and th PCM format. - * - * Return zero if invalid. - */ -unsigned int snd_hda_calc_stream_format(unsigned int rate, - unsigned int channels, - unsigned int format, - unsigned int maxbps) -{ - int i; - unsigned int val = 0; - - for (i = 0; rate_bits[i].hz; i++) - if (rate_bits[i].hz == rate) { - val = rate_bits[i].hda_fmt; - break; - } - if (! rate_bits[i].hz) { - snd_printdd("invalid rate %d\n", rate); - return 0; - } - - if (channels == 0 || channels > 8) { - snd_printdd("invalid channels %d\n", channels); - return 0; - } - val |= channels - 1; - - switch (snd_pcm_format_width(format)) { - case 8: val |= 0x00; break; - case 16: val |= 0x10; break; - case 20: - case 24: - case 32: - if (maxbps >= 32) - val |= 0x40; - else if (maxbps >= 24) - val |= 0x30; - else - val |= 0x20; - break; - default: - snd_printdd("invalid format width %d\n", snd_pcm_format_width(format)); - return 0; - } - - return val; -} - -EXPORT_SYMBOL(snd_hda_calc_stream_format); - -/** - * snd_hda_query_supported_pcm - query the supported PCM rates and formats - * @codec: the HDA codec - * @nid: NID to query - * @ratesp: the pointer to store the detected rate bitflags - * @formatsp: the pointer to store the detected formats - * @bpsp: the pointer to store the detected format widths - * - * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp - * or @bsps argument is ignored. - * - * Returns 0 if successful, otherwise a negative error code. - */ -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, - u32 *ratesp, u64 *formatsp, unsigned int *bpsp) -{ - int i; - unsigned int val, streams; - - val = 0; - if (nid != codec->afg && - (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { - val = snd_hda_param_read(codec, nid, AC_PAR_PCM); - if (val == -1) - return -EIO; - } - if (! val) - val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); - - if (ratesp) { - u32 rates = 0; - for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) { - if (val & (1 << i)) - rates |= rate_bits[i].alsa_bits; - } - *ratesp = rates; - } - - if (formatsp || bpsp) { - u64 formats = 0; - unsigned int bps; - unsigned int wcaps; - - wcaps = get_wcaps(codec, nid); - streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); - if (streams == -1) - return -EIO; - if (! streams) { - streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); - if (streams == -1) - return -EIO; - } - - bps = 0; - if (streams & AC_SUPFMT_PCM) { - if (val & AC_SUPPCM_BITS_8) { - formats |= SNDRV_PCM_FMTBIT_U8; - bps = 8; - } - if (val & AC_SUPPCM_BITS_16) { - formats |= SNDRV_PCM_FMTBIT_S16_LE; - bps = 16; - } - if (wcaps & AC_WCAP_DIGITAL) { - if (val & AC_SUPPCM_BITS_32) - formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; - if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24)) - formats |= SNDRV_PCM_FMTBIT_S32_LE; - if (val & AC_SUPPCM_BITS_24) - bps = 24; - else if (val & AC_SUPPCM_BITS_20) - bps = 20; - } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24|AC_SUPPCM_BITS_32)) { - formats |= SNDRV_PCM_FMTBIT_S32_LE; - if (val & AC_SUPPCM_BITS_32) - bps = 32; - else if (val & AC_SUPPCM_BITS_24) - bps = 24; - else if (val & AC_SUPPCM_BITS_20) - bps = 20; - } - } - else if (streams == AC_SUPFMT_FLOAT32) { /* should be exclusive */ - formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; - bps = 32; - } else if (streams == AC_SUPFMT_AC3) { /* should be exclusive */ - /* temporary hack: we have still no proper support - * for the direct AC3 stream... - */ - formats |= SNDRV_PCM_FMTBIT_U8; - bps = 8; - } - if (formatsp) - *formatsp = formats; - if (bpsp) - *bpsp = bps; - } - - return 0; -} - -/** - * snd_hda_is_supported_format - check whether the given node supports the format val - * - * Returns 1 if supported, 0 if not. - */ -int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, - unsigned int format) -{ - int i; - unsigned int val = 0, rate, stream; - - if (nid != codec->afg && - (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { - val = snd_hda_param_read(codec, nid, AC_PAR_PCM); - if (val == -1) - return 0; - } - if (! val) { - val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); - if (val == -1) - return 0; - } - - rate = format & 0xff00; - for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) - if (rate_bits[i].hda_fmt == rate) { - if (val & (1 << i)) - break; - return 0; - } - if (i >= AC_PAR_PCM_RATE_BITS) - return 0; - - stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); - if (stream == -1) - return 0; - if (! stream && nid != codec->afg) - stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); - if (! stream || stream == -1) - return 0; - - if (stream & AC_SUPFMT_PCM) { - switch (format & 0xf0) { - case 0x00: - if (! (val & AC_SUPPCM_BITS_8)) - return 0; - break; - case 0x10: - if (! (val & AC_SUPPCM_BITS_16)) - return 0; - break; - case 0x20: - if (! (val & AC_SUPPCM_BITS_20)) - return 0; - break; - case 0x30: - if (! (val & AC_SUPPCM_BITS_24)) - return 0; - break; - case 0x40: - if (! (val & AC_SUPPCM_BITS_32)) - return 0; - break; - default: - return 0; - } - } else { - /* FIXME: check for float32 and AC3? */ - } - - return 1; -} - -/* - * PCM stuff - */ -static int hda_pcm_default_open_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - return 0; -} - -static int hda_pcm_default_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); - return 0; -} - -static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ -//printk("%s: %p\n", __FUNCTION__, codec); - snd_hda_codec_setup_stream(codec, hinfo->nid, 0, 0, 0); - return 0; -} - -static int set_pcm_default_values(struct hda_codec *codec, struct hda_pcm_stream *info) -{ - if (info->nid) { - /* query support PCM information from the given NID */ - if (! info->rates || ! info->formats) - snd_hda_query_supported_pcm(codec, info->nid, - info->rates ? NULL : &info->rates, - info->formats ? NULL : &info->formats, - info->maxbps ? NULL : &info->maxbps); - } - if (info->ops.open == NULL) - info->ops.open = hda_pcm_default_open_close; - if (info->ops.close == NULL) - info->ops.close = hda_pcm_default_open_close; - if (info->ops.prepare == NULL) { - snd_assert(info->nid, return -EINVAL); - info->ops.prepare = hda_pcm_default_prepare; - } - if (info->ops.cleanup == NULL) { - snd_assert(info->nid, return -EINVAL); - info->ops.cleanup = hda_pcm_default_cleanup; - } - return 0; -} - -/** - * snd_hda_build_pcms - build PCM information - * @bus: the BUS - * - * Create PCM information for each codec included in the bus. - * - * The build_pcms codec patch is requested to set up codec->num_pcms and - * codec->pcm_info properly. The array is referred by the top-level driver - * to create its PCM instances. - * The allocated codec->pcm_info should be released in codec->patch_ops.free - * callback. - * - * At least, substreams, channels_min and channels_max must be filled for - * each stream. substreams = 0 indicates that the stream doesn't exist. - * When rates and/or formats are zero, the supported values are queried - * from the given nid. The nid is used also by the default ops.prepare - * and ops.cleanup callbacks. - * - * The driver needs to call ops.open in its open callback. Similarly, - * ops.close is supposed to be called in the close callback. - * ops.prepare should be called in the prepare or hw_params callback - * with the proper parameters for set up. - * ops.cleanup should be called in hw_free for clean up of streams. - * - * This function returns 0 if successfull, or a negative error code. - */ -int snd_hda_build_pcms(struct hda_bus *bus) -{ - struct list_head *p; - - list_for_each(p, &bus->codec_list) { - struct hda_codec *codec = list_entry(p, struct hda_codec, list); - unsigned int pcm, s; - int err; - if (! codec->patch_ops.build_pcms) - continue; - err = codec->patch_ops.build_pcms(codec); - if (err < 0) - return err; - for (pcm = 0; pcm < codec->num_pcms; pcm++) { - for (s = 0; s < 2; s++) { - struct hda_pcm_stream *info; - info = &codec->pcm_info[pcm].stream[s]; - if (! info->substreams) - continue; - err = set_pcm_default_values(codec, info); - if (err < 0) - return err; - } - } - } - return 0; -} - -EXPORT_SYMBOL(snd_hda_build_pcms); - -/** - * snd_hda_check_board_config - compare the current codec with the config table - * @codec: the HDA codec - * @num_configs: number of config enums - * @models: array of model name strings - * @tbl: configuration table, terminated by null entries - * - * Compares the modelname or PCI subsystem id of the current codec with the - * given configuration table. If a matching entry is found, returns its - * config value (supposed to be 0 or positive). - * - * If no entries are matching, the function returns a negative value. - */ -int snd_hda_check_board_config(struct hda_codec *codec, - int num_configs, const char **models, - const struct snd_pci_quirk *tbl) -{ - if (codec->bus->modelname && models) { - int i; - for (i = 0; i < num_configs; i++) { - if (models[i] && - !strcmp(codec->bus->modelname, models[i])) { - snd_printd(KERN_INFO "hda_codec: model '%s' is " - "selected\n", models[i]); - return i; - } - } - } - - if (!codec->bus->pci || !tbl) - return -1; - - tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl); - if (!tbl) - return -1; - if (tbl->value >= 0 && tbl->value < num_configs) { -#ifdef CONFIG_SND_DEBUG_DETECT - char tmp[10]; - const char *model = NULL; - if (models) - model = models[tbl->value]; - if (!model) { - sprintf(tmp, "#%d", tbl->value); - model = tmp; - } - snd_printdd(KERN_INFO "hda_codec: model '%s' is selected " - "for config %x:%x (%s)\n", - model, tbl->subvendor, tbl->subdevice, - (tbl->name ? tbl->name : "Unknown device")); -#endif - return tbl->value; - } - return -1; -} - -/** - * snd_hda_add_new_ctls - create controls from the array - * @codec: the HDA codec - * @knew: the array of struct snd_kcontrol_new - * - * This helper function creates and add new controls in the given array. - * The array must be terminated with an empty entry as terminator. - * - * 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 err; - - for (; knew->name; knew++) { - struct snd_kcontrol *kctl; - kctl = snd_ctl_new1(knew, codec); - if (! kctl) - return -ENOMEM; - err = snd_ctl_add(codec->bus->card, kctl); - if (err < 0) { - if (! codec->addr) - return err; - kctl = snd_ctl_new1(knew, codec); - if (! kctl) - return -ENOMEM; - kctl->id.device = codec->addr; - if ((err = snd_ctl_add(codec->bus->card, kctl)) < 0) - return err; - } - } - return 0; -} - - -/* - * Channel mode helper - */ -int snd_hda_ch_mode_info(struct hda_codec *codec, struct snd_ctl_elem_info *uinfo, - const struct hda_channel_mode *chmode, int num_chmodes) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = num_chmodes; - if (uinfo->value.enumerated.item >= num_chmodes) - uinfo->value.enumerated.item = num_chmodes - 1; - sprintf(uinfo->value.enumerated.name, "%dch", - chmode[uinfo->value.enumerated.item].channels); - return 0; -} - -int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, int num_chmodes, - int max_channels) -{ - int i; - - for (i = 0; i < num_chmodes; i++) { - if (max_channels == chmode[i].channels) { - ucontrol->value.enumerated.item[0] = i; - break; - } - } - return 0; -} - -int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, int num_chmodes, - int *max_channelsp) -{ - unsigned int mode; - - mode = ucontrol->value.enumerated.item[0]; - snd_assert(mode < num_chmodes, return -EINVAL); - if (*max_channelsp == chmode[mode].channels && ! codec->in_resume) - return 0; - /* change the current channel setting */ - *max_channelsp = chmode[mode].channels; - if (chmode[mode].sequence) - snd_hda_sequence_write(codec, chmode[mode].sequence); - return 1; -} - -/* - * input MUX helper - */ -int snd_hda_input_mux_info(const struct hda_input_mux *imux, struct snd_ctl_elem_info *uinfo) -{ - unsigned int index; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = imux->num_items; - index = uinfo->value.enumerated.item; - if (index >= imux->num_items) - index = imux->num_items - 1; - strcpy(uinfo->value.enumerated.name, imux->items[index].label); - return 0; -} - -int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, - struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, - unsigned int *cur_val) -{ - unsigned int idx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (*cur_val == idx && ! codec->in_resume) - return 0; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, - imux->items[idx].index); - *cur_val = idx; - return 1; -} - - -/* - * Multi-channel / digital-out PCM helper functions - */ - -/* setup SPDIF output stream */ -static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, - unsigned int stream_tag, unsigned int format) -{ - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_ctls & AC_DIG1_ENABLE) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); - snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); - /* turn on again (if needed) */ - if (codec->spdif_ctls & AC_DIG1_ENABLE) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & 0xff); -} - -/* - * open the digital out in the exclusive mode - */ -int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout) -{ - mutex_lock(&codec->spdif_mutex); - if (mout->dig_out_used) { - mutex_unlock(&codec->spdif_mutex); - return -EBUSY; /* already being used */ - } - mout->dig_out_used = HDA_DIG_EXCLUSIVE; - mutex_unlock(&codec->spdif_mutex); - return 0; -} - -int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, - struct hda_multi_out *mout, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - mutex_lock(&codec->spdif_mutex); - setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format); - mutex_unlock(&codec->spdif_mutex); - return 0; -} - -/* - * release the digital out - */ -int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout) -{ - mutex_lock(&codec->spdif_mutex); - mout->dig_out_used = 0; - mutex_unlock(&codec->spdif_mutex); - return 0; -} - -/* - * set up more restrictions for analog out - */ -int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, - struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = mout->max_channels; - return snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, 2); -} - -/* - * set up the i/o for analog out - * when the digital out is available, copy the front out to digital out, too. - */ -int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - hda_nid_t *nids = mout->dac_nids; - int chs = substream->runtime->channels; - int i; - - mutex_lock(&codec->spdif_mutex); - if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { - if (chs == 2 && - snd_hda_is_supported_format(codec, mout->dig_out_nid, format) && - ! (codec->spdif_status & IEC958_AES0_NONAUDIO)) { - mout->dig_out_used = HDA_DIG_ANALOG_DUP; - setup_dig_out_stream(codec, mout->dig_out_nid, - stream_tag, format); - } else { - mout->dig_out_used = 0; - snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0); - } - } - mutex_unlock(&codec->spdif_mutex); - - /* front */ - snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format); - if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]) - /* headphone out will just decode front left/right (stereo) */ - snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); - /* extra outputs copied from front */ - for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) - if (mout->extra_out_nid[i]) - snd_hda_codec_setup_stream(codec, - mout->extra_out_nid[i], - stream_tag, 0, format); - - /* surrounds */ - for (i = 1; i < mout->num_dacs; i++) { - if (chs >= (i + 1) * 2) /* independent out */ - snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2, - format); - else /* copy front */ - snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, - format); - } - return 0; -} - -/* - * clean up the setting for analog out - */ -int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout) -{ - hda_nid_t *nids = mout->dac_nids; - int i; - - for (i = 0; i < mout->num_dacs; i++) - snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); - if (mout->hp_nid) - snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0); - for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) - if (mout->extra_out_nid[i]) - snd_hda_codec_setup_stream(codec, - mout->extra_out_nid[i], - 0, 0, 0); - mutex_lock(&codec->spdif_mutex); - if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) { - snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0); - mout->dig_out_used = 0; - } - mutex_unlock(&codec->spdif_mutex); - return 0; -} - -/* - * Helper for automatic ping configuration - */ - -static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) -{ - for (; *list; list++) - if (*list == nid) - return 1; - return 0; -} - -/* - * Parse all pin widgets and store the useful pin nids to cfg - * - * The number of line-outs or any primary output is stored in line_outs, - * and the corresponding output pins are assigned to line_out_pins[], - * in the order of front, rear, CLFE, side, ... - * - * If more extra outputs (speaker and headphone) are found, the pins are - * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack - * is detected, one of speaker of HP pins is assigned as the primary - * output, i.e. to line_out_pins[0]. So, line_outs is always positive - * if any analog output exists. - * - * The analog input pins are assigned to input_pins array. - * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, - * respectively. - */ -int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg, - hda_nid_t *ignore_nids) -{ - hda_nid_t nid, nid_start; - int i, j, nodes; - short seq, assoc_line_out, sequences[ARRAY_SIZE(cfg->line_out_pins)]; - - memset(cfg, 0, sizeof(*cfg)); - - memset(sequences, 0, sizeof(sequences)); - assoc_line_out = 0; - - nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); - for (nid = nid_start; nid < nodes + nid_start; nid++) { - unsigned int wid_caps = get_wcaps(codec, nid); - unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - unsigned int def_conf; - short assoc, loc; - - /* read all default configuration for pin complex */ - if (wid_type != AC_WID_PIN) - continue; - /* ignore the given nids (e.g. pc-beep returns error) */ - if (ignore_nids && is_in_nid_list(nid, ignore_nids)) - continue; - - def_conf = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) - continue; - loc = get_defcfg_location(def_conf); - switch (get_defcfg_device(def_conf)) { - case AC_JACK_LINE_OUT: - seq = get_defcfg_sequence(def_conf); - assoc = get_defcfg_association(def_conf); - if (! assoc) - continue; - if (! assoc_line_out) - assoc_line_out = assoc; - else if (assoc_line_out != assoc) - continue; - if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) - continue; - cfg->line_out_pins[cfg->line_outs] = nid; - sequences[cfg->line_outs] = seq; - cfg->line_outs++; - break; - case AC_JACK_SPEAKER: - if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) - continue; - cfg->speaker_pins[cfg->speaker_outs] = nid; - cfg->speaker_outs++; - break; - case AC_JACK_HP_OUT: - if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) - continue; - cfg->hp_pins[cfg->hp_outs] = nid; - cfg->hp_outs++; - break; - case AC_JACK_MIC_IN: { - int preferred, alt; - if (loc == AC_JACK_LOC_FRONT) { - preferred = AUTO_PIN_FRONT_MIC; - alt = AUTO_PIN_MIC; - } else { - preferred = AUTO_PIN_MIC; - alt = AUTO_PIN_FRONT_MIC; - } - if (!cfg->input_pins[preferred]) - cfg->input_pins[preferred] = nid; - else if (!cfg->input_pins[alt]) - cfg->input_pins[alt] = nid; - break; - } - case AC_JACK_LINE_IN: - if (loc == AC_JACK_LOC_FRONT) - cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid; - else - cfg->input_pins[AUTO_PIN_LINE] = nid; - break; - case AC_JACK_CD: - cfg->input_pins[AUTO_PIN_CD] = nid; - break; - case AC_JACK_AUX: - cfg->input_pins[AUTO_PIN_AUX] = nid; - break; - case AC_JACK_SPDIF_OUT: - cfg->dig_out_pin = nid; - break; - case AC_JACK_SPDIF_IN: - cfg->dig_in_pin = nid; - break; - } - } - - /* sort by sequence */ - for (i = 0; i < cfg->line_outs; i++) - for (j = i + 1; j < cfg->line_outs; j++) - if (sequences[i] > sequences[j]) { - seq = sequences[i]; - sequences[i] = sequences[j]; - sequences[j] = seq; - nid = cfg->line_out_pins[i]; - cfg->line_out_pins[i] = cfg->line_out_pins[j]; - cfg->line_out_pins[j] = nid; - } - - /* Reorder the surround channels - * ALSA sequence is front/surr/clfe/side - * HDA sequence is: - * 4-ch: front/surr => OK as it is - * 6-ch: front/clfe/surr - * 8-ch: front/clfe/side/surr - */ - switch (cfg->line_outs) { - case 3: - nid = cfg->line_out_pins[1]; - cfg->line_out_pins[1] = cfg->line_out_pins[2]; - cfg->line_out_pins[2] = nid; - break; - case 4: - nid = cfg->line_out_pins[1]; - cfg->line_out_pins[1] = cfg->line_out_pins[3]; - cfg->line_out_pins[3] = cfg->line_out_pins[2]; - cfg->line_out_pins[2] = nid; - break; - } - - /* - * debug prints of the parsed results - */ - snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\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]); - 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], - cfg->speaker_pins[3], cfg->speaker_pins[4]); - snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", - cfg->hp_outs, cfg->hp_pins[0], - cfg->hp_pins[1], cfg->hp_pins[2], - cfg->hp_pins[3], cfg->hp_pins[4]); - snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," - " cd=0x%x, aux=0x%x\n", - cfg->input_pins[AUTO_PIN_MIC], - cfg->input_pins[AUTO_PIN_FRONT_MIC], - cfg->input_pins[AUTO_PIN_LINE], - cfg->input_pins[AUTO_PIN_FRONT_LINE], - cfg->input_pins[AUTO_PIN_CD], - cfg->input_pins[AUTO_PIN_AUX]); - - /* - * FIX-UP: if no line-outs are detected, try to use speaker or HP pin - * as a primary output - */ - if (! cfg->line_outs) { - if (cfg->speaker_outs) { - cfg->line_outs = cfg->speaker_outs; - memcpy(cfg->line_out_pins, cfg->speaker_pins, - sizeof(cfg->speaker_pins)); - cfg->speaker_outs = 0; - memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); - } else if (cfg->hp_outs) { - cfg->line_outs = cfg->hp_outs; - memcpy(cfg->line_out_pins, cfg->hp_pins, - sizeof(cfg->hp_pins)); - cfg->hp_outs = 0; - memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); - } - } - - return 0; -} - -/* labels for input pins */ -const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" -}; - - -#ifdef CONFIG_PM -/* - * power management - */ - -/** - * snd_hda_suspend - suspend the codecs - * @bus: the HDA bus - * @state: suspsend state - * - * Returns 0 if successful. - */ -int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) -{ - struct list_head *p; - - //printk("%s: bus=%p state=0x%x\n", __FUNCTION__, bus, *((u32 *)&state)); - /* FIXME: should handle power widget capabilities */ - list_for_each(p, &bus->codec_list) { - struct hda_codec *codec = list_entry(p, struct hda_codec, list); - if (codec->patch_ops.suspend) - codec->patch_ops.suspend(codec, state); - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D3); - } - return 0; -} - -EXPORT_SYMBOL(snd_hda_suspend); - -/** - * snd_hda_resume - resume the codecs - * @bus: the HDA bus - * @state: resume state - * - * Returns 0 if successful. - */ -int snd_hda_resume(struct hda_bus *bus) -{ - struct list_head *p; - - //printk("%s: bus=%p\n", __FUNCTION__, bus); - list_for_each(p, &bus->codec_list) { - struct hda_codec *codec = list_entry(p, struct hda_codec, list); - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D0); - if (codec->patch_ops.resume) - codec->patch_ops.resume(codec); - } - return 0; -} - -EXPORT_SYMBOL(snd_hda_resume); - -#ifndef FOUND_NO_CTL_ELEM_RW -/** - * snd_hda_resume_ctls - resume controls in the new control list - * @codec: the HDA codec - * @knew: the array of struct snd_kcontrol_new - * - * This function resumes the mixer controls in the struct snd_kcontrol_new array, - * originally for snd_hda_add_new_ctls(). - * The array must be terminated with an empty entry as terminator. - */ -int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) -{ - struct snd_ctl_elem_value *val; - - val = kmalloc(sizeof(*val), GFP_KERNEL); - if (! val) - return -ENOMEM; - codec->in_resume = 1; - for (; knew->name; knew++) { - int i, count; - count = knew->count ? knew->count : 1; - for (i = 0; i < count; i++) { - memset(val, 0, sizeof(*val)); - val->id.iface = knew->iface; - val->id.device = knew->device; - val->id.subdevice = knew->subdevice; - strcpy(val->id.name, knew->name); - val->id.index = knew->index ? knew->index : i; - /* Assume that get callback reads only from cache, - * not accessing to the real hardware - */ - if (snd_ctl_elem_read(codec->bus->card, val) < 0) - continue; - snd_ctl_elem_write(codec->bus->card, NULL, val); - } - } - codec->in_resume = 0; - kfree(val); - return 0; -} -#else -int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) -{ - return 0; -} -#warning Reduced HDA suspend support, installation of alsa-driver-linuxant available from www.linuxant.com/alsa-driver is recommended -#endif - -/** - * snd_hda_resume_spdif_out - resume the digital out - * @codec: the HDA codec - */ -int snd_hda_resume_spdif_out(struct hda_codec *codec) -{ - return snd_hda_resume_ctls(codec, dig_mixes); -} - -/** - * snd_hda_resume_spdif_in - resume the digital in - * @codec: the HDA codec - */ -int snd_hda_resume_spdif_in(struct hda_codec *codec) -{ - return snd_hda_resume_ctls(codec, dig_in_ctls); -} -#endif - -/* - * INIT part - */ - -static int __init alsa_hda_init(void) -{ - return 0; -} - -static void __exit alsa_hda_exit(void) -{ -} - -module_init(alsa_hda_init) -module_exit(alsa_hda_exit) diff --git a/modules/GPL/hda/hda_codec.h b/modules/GPL/hda/hda_codec.h deleted file mode 100644 index 2e4b9d3..0000000 --- a/modules/GPL/hda/hda_codec.h +++ /dev/null @@ -1,660 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * Copyright (c) 2004 Takashi Iwai - * - * 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 __SOUND_HDA_CODEC_H -#define __SOUND_HDA_CODEC_H - -#include -#include -#include - -#ifndef FOUND_KZALLOC -#define kzalloc(s, f) kcalloc(1, s, f) -#endif - -#ifndef FOUND_SOUND_TYPEDEFS -#include "sound_typedefs.h" -#endif - -/* - * nodes - */ -#define AC_NODE_ROOT 0x00 - -/* - * function group types - */ -enum { - AC_GRP_AUDIO_FUNCTION = 0x01, - AC_GRP_MODEM_FUNCTION = 0x02, -}; - -/* - * widget types - */ -enum { - AC_WID_AUD_OUT, /* Audio Out */ - AC_WID_AUD_IN, /* Audio In */ - AC_WID_AUD_MIX, /* Audio Mixer */ - AC_WID_AUD_SEL, /* Audio Selector */ - AC_WID_PIN, /* Pin Complex */ - AC_WID_POWER, /* Power */ - AC_WID_VOL_KNB, /* Volume Knob */ - AC_WID_BEEP, /* Beep Generator */ - AC_WID_VENDOR = 0x0f /* Vendor specific */ -}; - -/* - * GET verbs - */ -#define AC_VERB_GET_STREAM_FORMAT 0x0a00 -#define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00 -#define AC_VERB_GET_PROC_COEF 0x0c00 -#define AC_VERB_GET_COEF_INDEX 0x0d00 -#define AC_VERB_PARAMETERS 0x0f00 -#define AC_VERB_GET_CONNECT_SEL 0x0f01 -#define AC_VERB_GET_CONNECT_LIST 0x0f02 -#define AC_VERB_GET_PROC_STATE 0x0f03 -#define AC_VERB_GET_SDI_SELECT 0x0f04 -#define AC_VERB_GET_POWER_STATE 0x0f05 -#define AC_VERB_GET_CONV 0x0f06 -#define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07 -#define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08 -#define AC_VERB_GET_PIN_SENSE 0x0f09 -#define AC_VERB_GET_BEEP_CONTROL 0x0f0a -#define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c -#define AC_VERB_GET_DIGI_CONVERT 0x0f0d -#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f -/* f10-f1a: GPIO */ -#define AC_VERB_GET_GPIO_DATA 0x0f15 -#define AC_VERB_GET_GPIO_MASK 0x0f16 -#define AC_VERB_GET_GPIO_DIRECTION 0x0f17 -#define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c -/* f20: AFG/MFG */ -#define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 - -/* - * SET verbs - */ -#define AC_VERB_SET_STREAM_FORMAT 0x200 -#define AC_VERB_SET_AMP_GAIN_MUTE 0x300 -#define AC_VERB_SET_PROC_COEF 0x400 -#define AC_VERB_SET_COEF_INDEX 0x500 -#define AC_VERB_SET_CONNECT_SEL 0x701 -#define AC_VERB_SET_PROC_STATE 0x703 -#define AC_VERB_SET_SDI_SELECT 0x704 -#define AC_VERB_SET_POWER_STATE 0x705 -#define AC_VERB_SET_CHANNEL_STREAMID 0x706 -#define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707 -#define AC_VERB_SET_UNSOLICITED_ENABLE 0x708 -#define AC_VERB_SET_PIN_SENSE 0x709 -#define AC_VERB_SET_BEEP_CONTROL 0x70a -#define AC_VERB_SET_EAPD_BTLENABLE 0x70c -#define AC_VERB_SET_DIGI_CONVERT_1 0x70d -#define AC_VERB_SET_DIGI_CONVERT_2 0x70e -#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f -#define AC_VERB_SET_GPIO_DATA 0x715 -#define AC_VERB_SET_GPIO_MASK 0x716 -#define AC_VERB_SET_GPIO_DIRECTION 0x717 -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f -#define AC_VERB_SET_CODEC_RESET 0x7ff - -/* - * Parameter IDs - */ -#define AC_PAR_VENDOR_ID 0x00 -#define AC_PAR_SUBSYSTEM_ID 0x01 -#define AC_PAR_REV_ID 0x02 -#define AC_PAR_NODE_COUNT 0x04 -#define AC_PAR_FUNCTION_TYPE 0x05 -#define AC_PAR_AUDIO_FG_CAP 0x08 -#define AC_PAR_AUDIO_WIDGET_CAP 0x09 -#define AC_PAR_PCM 0x0a -#define AC_PAR_STREAM 0x0b -#define AC_PAR_PIN_CAP 0x0c -#define AC_PAR_AMP_IN_CAP 0x0d -#define AC_PAR_CONNLIST_LEN 0x0e -#define AC_PAR_POWER_STATE 0x0f -#define AC_PAR_PROC_CAP 0x10 -#define AC_PAR_GPIO_CAP 0x11 -#define AC_PAR_AMP_OUT_CAP 0x12 - -/* - * AC_VERB_PARAMETERS results (32bit) - */ - -/* Function Group Type */ -#define AC_FGT_TYPE (0xff<<0) -#define AC_FGT_TYPE_SHIFT 0 -#define AC_FGT_UNSOL_CAP (1<<8) - -/* Audio Function Group Capabilities */ -#define AC_AFG_OUT_DELAY (0xf<<0) -#define AC_AFG_IN_DELAY (0xf<<8) -#define AC_AFG_BEEP_GEN (1<<16) - -/* Audio Widget Capabilities */ -#define AC_WCAP_STEREO (1<<0) /* stereo I/O */ -#define AC_WCAP_IN_AMP (1<<1) /* AMP-in present */ -#define AC_WCAP_OUT_AMP (1<<2) /* AMP-out present */ -#define AC_WCAP_AMP_OVRD (1<<3) /* AMP-parameter override */ -#define AC_WCAP_FORMAT_OVRD (1<<4) /* format override */ -#define AC_WCAP_STRIPE (1<<5) /* stripe */ -#define AC_WCAP_PROC_WID (1<<6) /* Proc Widget */ -#define AC_WCAP_UNSOL_CAP (1<<7) /* Unsol capable */ -#define AC_WCAP_CONN_LIST (1<<8) /* connection list */ -#define AC_WCAP_DIGITAL (1<<9) /* digital I/O */ -#define AC_WCAP_POWER (1<<10) /* power control */ -#define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */ -#define AC_WCAP_DELAY (0xf<<16) -#define AC_WCAP_DELAY_SHIFT 16 -#define AC_WCAP_TYPE (0xf<<20) -#define AC_WCAP_TYPE_SHIFT 20 - -/* supported PCM rates and bits */ -#define AC_SUPPCM_RATES (0xfff << 0) -#define AC_SUPPCM_BITS_8 (1<<16) -#define AC_SUPPCM_BITS_16 (1<<17) -#define AC_SUPPCM_BITS_20 (1<<18) -#define AC_SUPPCM_BITS_24 (1<<19) -#define AC_SUPPCM_BITS_32 (1<<20) - -/* supported PCM stream format */ -#define AC_SUPFMT_PCM (1<<0) -#define AC_SUPFMT_FLOAT32 (1<<1) -#define AC_SUPFMT_AC3 (1<<2) - -/* Pin widget capabilies */ -#define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ -#define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ -#define AC_PINCAP_PRES_DETECT (1<<2) /* presence detect capable */ -#define AC_PINCAP_HP_DRV (1<<3) /* headphone drive capable */ -#define AC_PINCAP_OUT (1<<4) /* output capable */ -#define AC_PINCAP_IN (1<<5) /* input capable */ -#define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ -#define AC_PINCAP_VREF (0x37<<8) -#define AC_PINCAP_VREF_SHIFT 8 -#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ -/* Vref status (used in pin cap) */ -#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */ -#define AC_PINCAP_VREF_50 (1<<1) /* 50% */ -#define AC_PINCAP_VREF_GRD (1<<2) /* ground */ -#define AC_PINCAP_VREF_80 (1<<4) /* 80% */ -#define AC_PINCAP_VREF_100 (1<<5) /* 100% */ - -/* Amplifier capabilities */ -#define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ -#define AC_AMPCAP_OFFSET_SHIFT 0 -#define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ -#define AC_AMPCAP_NUM_STEPS_SHIFT 8 -#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB in 0.25dB */ -#define AC_AMPCAP_STEP_SIZE_SHIFT 16 -#define AC_AMPCAP_MUTE (1<<31) /* mute capable */ -#define AC_AMPCAP_MUTE_SHIFT 31 - -/* Connection list */ -#define AC_CLIST_LENGTH (0x7f<<0) -#define AC_CLIST_LONG (1<<7) - -/* Supported power status */ -#define AC_PWRST_D0SUP (1<<0) -#define AC_PWRST_D1SUP (1<<1) -#define AC_PWRST_D2SUP (1<<2) -#define AC_PWRST_D3SUP (1<<3) - -/* Power state values */ -#define AC_PWRST_D0 0x00 -#define AC_PWRST_D1 0x01 -#define AC_PWRST_D2 0x02 -#define AC_PWRST_D3 0x03 - -/* Processing capabilies */ -#define AC_PCAP_BENIGN (1<<0) -#define AC_PCAP_NUM_COEF (0xff<<8) - -/* Volume knobs capabilities */ -#define AC_KNBCAP_NUM_STEPS (0x7f<<0) -#define AC_KNBCAP_DELTA (1<<8) - -/* - * Control Parameters - */ - -/* Amp gain/mute */ -#define AC_AMP_MUTE (1<<7) -#define AC_AMP_GAIN (0x7f) -#define AC_AMP_GET_INDEX (0xf<<0) - -#define AC_AMP_GET_LEFT (1<<13) -#define AC_AMP_GET_RIGHT (0<<13) -#define AC_AMP_GET_OUTPUT (1<<15) -#define AC_AMP_GET_INPUT (0<<15) - -#define AC_AMP_SET_INDEX (0xf<<8) -#define AC_AMP_SET_INDEX_SHIFT 8 -#define AC_AMP_SET_RIGHT (1<<12) -#define AC_AMP_SET_LEFT (1<<13) -#define AC_AMP_SET_INPUT (1<<14) -#define AC_AMP_SET_OUTPUT (1<<15) - -/* DIGITAL1 bits */ -#define AC_DIG1_ENABLE (1<<0) -#define AC_DIG1_V (1<<1) -#define AC_DIG1_VCFG (1<<2) -#define AC_DIG1_EMPHASIS (1<<3) -#define AC_DIG1_COPYRIGHT (1<<4) -#define AC_DIG1_NONAUDIO (1<<5) -#define AC_DIG1_PROFESSIONAL (1<<6) -#define AC_DIG1_LEVEL (1<<7) - -/* Pin widget control - 8bit */ -#define AC_PINCTL_VREFEN (0x7<<0) -#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ -#define AC_PINCTL_VREF_50 1 /* 50% */ -#define AC_PINCTL_VREF_GRD 2 /* ground */ -#define AC_PINCTL_VREF_80 4 /* 80% */ -#define AC_PINCTL_VREF_100 5 /* 100% */ -#define AC_PINCTL_IN_EN (1<<5) -#define AC_PINCTL_OUT_EN (1<<6) -#define AC_PINCTL_HP_EN (1<<7) - -/* Unsolicited response - 8bit */ -#define AC_USRSP_EN (1<<7) - -/* configuration default - 32bit */ -#define AC_DEFCFG_SEQUENCE (0xf<<0) -#define AC_DEFCFG_DEF_ASSOC (0xf<<4) -#define AC_DEFCFG_ASSOC_SHIFT 4 -#define AC_DEFCFG_MISC (0xf<<8) -#define AC_DEFCFG_MISC_SHIFT 8 -#define AC_DEFCFG_COLOR (0xf<<12) -#define AC_DEFCFG_COLOR_SHIFT 12 -#define AC_DEFCFG_CONN_TYPE (0xf<<16) -#define AC_DEFCFG_CONN_TYPE_SHIFT 16 -#define AC_DEFCFG_DEVICE (0xf<<20) -#define AC_DEFCFG_DEVICE_SHIFT 20 -#define AC_DEFCFG_LOCATION (0x3f<<24) -#define AC_DEFCFG_LOCATION_SHIFT 24 -#define AC_DEFCFG_PORT_CONN (0x3<<30) -#define AC_DEFCFG_PORT_CONN_SHIFT 30 - -/* device device types (0x0-0xf) */ -enum { - AC_JACK_LINE_OUT, - AC_JACK_SPEAKER, - AC_JACK_HP_OUT, - AC_JACK_CD, - AC_JACK_SPDIF_OUT, - AC_JACK_DIG_OTHER_OUT, - AC_JACK_MODEM_LINE_SIDE, - AC_JACK_MODEM_HAND_SIDE, - AC_JACK_LINE_IN, - AC_JACK_AUX, - AC_JACK_MIC_IN, - AC_JACK_TELEPHONY, - AC_JACK_SPDIF_IN, - AC_JACK_DIG_OTHER_IN, - AC_JACK_OTHER = 0xf, -}; - -/* jack connection types (0x0-0xf) */ -enum { - AC_JACK_CONN_UNKNOWN, - AC_JACK_CONN_1_8, - AC_JACK_CONN_1_4, - AC_JACK_CONN_ATAPI, - AC_JACK_CONN_RCA, - AC_JACK_CONN_OPTICAL, - AC_JACK_CONN_OTHER_DIGITAL, - AC_JACK_CONN_OTHER_ANALOG, - AC_JACK_CONN_DIN, - AC_JACK_CONN_XLR, - AC_JACK_CONN_RJ11, - AC_JACK_CONN_COMB, - AC_JACK_CONN_OTHER = 0xf, -}; - -/* jack colors (0x0-0xf) */ -enum { - AC_JACK_COLOR_UNKNOWN, - AC_JACK_COLOR_BLACK, - AC_JACK_COLOR_GREY, - AC_JACK_COLOR_BLUE, - AC_JACK_COLOR_GREEN, - AC_JACK_COLOR_RED, - AC_JACK_COLOR_ORANGE, - AC_JACK_COLOR_YELLOW, - AC_JACK_COLOR_PURPLE, - AC_JACK_COLOR_PINK, - AC_JACK_COLOR_WHITE = 0xe, - AC_JACK_COLOR_OTHER, -}; - -/* Jack location (0x0-0x3f) */ -/* common case */ -enum { - AC_JACK_LOC_NONE, - AC_JACK_LOC_REAR, - AC_JACK_LOC_FRONT, - AC_JACK_LOC_LEFT, - AC_JACK_LOC_RIGHT, - AC_JACK_LOC_TOP, - AC_JACK_LOC_BOTTOM, -}; -/* bits 4-5 */ -enum { - AC_JACK_LOC_EXTERNAL = 0x00, - AC_JACK_LOC_INTERNAL = 0x10, - AC_JACK_LOC_SEPARATE = 0x20, - AC_JACK_LOC_OTHER = 0x30, -}; -enum { - /* external on primary chasis */ - AC_JACK_LOC_REAR_PANEL = 0x07, - AC_JACK_LOC_DRIVE_BAY, - /* internal */ - AC_JACK_LOC_RISER = 0x17, - AC_JACK_LOC_HDMI, - AC_JACK_LOC_ATAPI, - /* others */ - AC_JACK_LOC_MOBILE_IN = 0x37, - AC_JACK_LOC_MOBILE_OUT, -}; - -/* Port connectivity (0-3) */ -enum { - AC_JACK_PORT_COMPLEX, - AC_JACK_PORT_NONE, - AC_JACK_PORT_FIXED, - AC_JACK_PORT_BOTH, -}; - -/* max. connections to a widget */ -#define HDA_MAX_CONNECTIONS 32 - -/* max. codec address */ -#define HDA_MAX_CODEC_ADDRESS 0x0f - -/* - * Structures - */ - -struct hda_bus; -struct hda_codec; -struct hda_pcm; -struct hda_pcm_stream; -struct hda_bus_unsolicited; - -/* NID type */ -typedef u16 hda_nid_t; - -/* bus operators */ -struct hda_bus_ops { - /* send a single command */ - int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int parm); - /* get a response from the last command */ - unsigned int (*get_response)(struct hda_codec *codec); - /* get the wall clock counter */ - u32 (*get_wallclock)(struct hda_codec *codec); - /* get the link position counter */ - u32 (*get_linkpos)(snd_pcm_substream_t *substream); - /* free the private data */ - void (*private_free)(struct hda_bus *); -}; - -/* template to pass to the bus constructor */ -struct hda_bus_template { - void *private_data; - struct pci_dev *pci; - const char *modelname; - struct hda_bus_ops ops; -}; - -/* - * codec bus - * - * each controller needs to creata a hda_bus to assign the accessor. - * A hda_bus contains several codecs in the list codec_list. - */ -struct hda_bus { - struct snd_card *card; - - /* copied from template */ - void *private_data; - struct pci_dev *pci; - const char *modelname; - struct hda_bus_ops ops; - - /* codec linked list */ - struct list_head codec_list; - struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */ - - struct mutex cmd_mutex; - - /* unsolicited event queue */ - struct hda_bus_unsolicited *unsol; - - struct snd_info_entry *proc; -}; - -/* - * codec preset - * - * Known codecs have the patch to build and set up the controls/PCMs - * better than the generic parser. - */ -struct hda_codec_preset { - unsigned int id; - unsigned int mask; - unsigned int subs; - unsigned int subs_mask; - hda_nid_t afg, mfg; - unsigned int rev; - const char *name; - int (*patch)(struct hda_codec *codec); -}; - -/* ops set by the preset patch */ -struct hda_codec_ops { - int (*build_controls)(struct hda_codec *codec); - int (*build_pcms)(struct hda_codec *codec); - int (*init)(struct hda_codec *codec); - int (*exit)(struct hda_codec *codec); - void (*free)(struct hda_codec *codec); - void (*unsol_event)(struct hda_codec *codec, unsigned int res); -#ifdef CONFIG_PM - int (*suspend)(struct hda_codec *codec, pm_message_t state); - int (*resume)(struct hda_codec *codec); -#endif -}; - -/* record for amp information cache */ -struct hda_amp_info { - u32 key; /* hash key */ - u32 amp_caps; /* amp capabilities */ - u16 vol[2]; /* current volume & mute */ - u16 status; /* update flag */ - u16 next; /* next link */ -}; - -/* PCM callbacks */ -struct hda_pcm_ops { - int (*open)(struct hda_pcm_stream *info, struct hda_codec *codec, - struct snd_pcm_substream *substream); - int (*close)(struct hda_pcm_stream *info, struct hda_codec *codec, - struct snd_pcm_substream *substream); - int (*prepare)(struct hda_pcm_stream *info, struct hda_codec *codec, - unsigned int stream_tag, unsigned int format, - struct snd_pcm_substream *substream); - int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec, - struct snd_pcm_substream *substream); -}; - -/* PCM information for each substream */ -struct hda_pcm_stream { - unsigned int substreams; /* number of substreams, 0 = not exist */ - unsigned int channels_min; /* min. number of channels */ - unsigned int channels_max; /* max. number of channels */ - hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */ - u32 rates; /* supported rates */ - u64 formats; /* supported formats (SNDRV_PCM_FMTBIT_) */ - unsigned int maxbps; /* supported max. bit per sample */ - struct hda_pcm_ops ops; -}; - -/* for PCM creation */ -struct hda_pcm { - char *name; - struct hda_pcm_stream stream[2]; - unsigned int is_modem; /* modem codec? */ - snd_pcm_t *pcm; -}; - -/* codec information */ -struct hda_codec { - struct hda_bus *bus; - unsigned int addr; /* codec addr*/ - struct list_head list; /* list point */ - - hda_nid_t afg; /* AFG node id */ - hda_nid_t mfg; /* MFG node id */ - - /* ids */ - u32 vendor_id; - u32 subsystem_id; - u32 revision_id; - - /* detected preset */ - const struct hda_codec_preset *preset; - - /* set by patch */ - struct hda_codec_ops patch_ops; - - /* resume phase - all controls should update even if - * the values are not changed - */ - unsigned int in_resume; - - /* PCM to create, set by patch_ops.build_pcms callback */ - unsigned int num_pcms; - struct hda_pcm *pcm_info; - - /* codec specific info */ - void *spec; - - /* widget capabilities cache */ - unsigned int num_nodes; - hda_nid_t start_nid; - u32 *wcaps; - - /* hash for amp access */ - u16 amp_hash[32]; - int num_amp_entries; - int amp_info_size; - struct hda_amp_info *amp_info; - - struct mutex spdif_mutex; - unsigned int spdif_status; /* IEC958 status bits */ - unsigned short spdif_ctls; /* SPDIF control bits */ - unsigned int spdif_in_enable; /* SPDIF input enable? */ -}; - -/* direction */ -enum { - HDA_INPUT, HDA_OUTPUT -}; - - -/* - * constructors - */ -int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, - struct hda_bus **busp); -int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, - struct hda_codec **codecp); -void snd_hda_codec_remove_notify_all(struct hda_bus *bus); - -/* - * low level functions - */ -unsigned int snd_hda_codec_wallclock(struct hda_codec *codec); -unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int parm); -int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int parm); -#define snd_hda_param_read(codec, nid, param) snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) -int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id); -int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); - -struct hda_verb { - hda_nid_t nid; - u32 verb; - u32 param; -}; - -void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq); - -/* unsolicited event */ -int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); - -/* - * Mixer - */ -int snd_hda_build_controls(struct hda_bus *bus); - -/* - * PCM - */ -int snd_hda_build_pcms(struct hda_bus *bus); -void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, - int channel_id, int format); -unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, - unsigned int format, unsigned int maxbps); -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, - u32 *ratesp, u64 *formatsp, unsigned int *bpsp); -int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, - unsigned int format); - -/* - * Misc - */ -void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); - -/* - * power management - */ -#ifdef CONFIG_PM -int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); -int snd_hda_resume(struct hda_bus *bus); -#endif - -static inline void snd_hda_power_up(struct hda_codec *codec) {} -static inline void snd_hda_power_down(struct hda_codec *codec) {} -#define snd_hda_codec_needs_resume(codec) 1 -#define snd_hda_codecs_inuse(bus) 1 - -#define snd_hda_codec_write_cache snd_hda_codec_write -#define snd_hda_sequence_write_cache snd_hda_sequence_write - -#endif /* __SOUND_HDA_CODEC_H */ diff --git a/modules/GPL/hda/hda_generic.c b/modules/GPL/hda/hda_generic.c deleted file mode 100644 index 1589d2f..0000000 --- a/modules/GPL/hda/hda_generic.c +++ /dev/null @@ -1,1068 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * Generic widget tree parser - * - * Copyright (c) 2004 Takashi Iwai - * - * This driver 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 driver 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 -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -/* widget node for parsing */ -struct hda_gnode { - hda_nid_t nid; /* NID of this widget */ - unsigned short nconns; /* number of input connections */ - hda_nid_t *conn_list; - hda_nid_t slist[2]; /* temporay list */ - unsigned int wid_caps; /* widget capabilities */ - unsigned char type; /* widget type */ - unsigned char pin_ctl; /* pin controls */ - unsigned char checked; /* the flag indicates that the node is already parsed */ - unsigned int pin_caps; /* pin widget capabilities */ - unsigned int def_cfg; /* default configuration */ - unsigned int amp_out_caps; /* AMP out capabilities */ - unsigned int amp_in_caps; /* AMP in capabilities */ - struct list_head list; -}; - -/* patch-specific record */ - -#define MAX_PCM_VOLS 2 -struct pcm_vol { - struct hda_gnode *node; /* Node for PCM volume */ - unsigned int index; /* connection of PCM volume */ -}; - -struct hda_gspec { - struct hda_gnode *dac_node[2]; /* DAC node */ - struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */ - struct pcm_vol pcm_vol[MAX_PCM_VOLS]; /* PCM volumes */ - unsigned int pcm_vol_nodes; /* number of PCM volumes */ - - struct hda_gnode *adc_node; /* ADC node */ - struct hda_gnode *cap_vol_node; /* Node for capture volume */ - unsigned int cur_cap_src; /* current capture source */ - struct hda_input_mux input_mux; - char cap_labels[HDA_MAX_NUM_INPUTS][16]; - - unsigned int def_amp_in_caps; - unsigned int def_amp_out_caps; - - struct hda_pcm pcm_rec; /* PCM information */ - - struct list_head nid_list; /* list of widgets */ -}; - -/* - * retrieve the default device type from the default config value - */ -#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> \ - AC_DEFCFG_DEVICE_SHIFT) -#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> \ - AC_DEFCFG_LOCATION_SHIFT) -#define defcfg_port_conn(node) (((node)->def_cfg & AC_DEFCFG_PORT_CONN) >> \ - AC_DEFCFG_PORT_CONN_SHIFT) - -/* - * destructor - */ -static void snd_hda_generic_free(struct hda_codec *codec) -{ - struct hda_gspec *spec = codec->spec; - struct list_head *p, *n; - - if (! spec) - return; - /* free all widgets */ - list_for_each_safe(p, n, &spec->nid_list) { - struct hda_gnode *node = list_entry(p, struct hda_gnode, list); - if (node->conn_list != node->slist) - kfree(node->conn_list); - kfree(node); - } - kfree(spec); -} - - -/* - * add a new widget node and read its attributes - */ -static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid_t nid) -{ - struct hda_gnode *node; - int nconns; - hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; - - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (node == NULL) - return -ENOMEM; - node->nid = nid; - nconns = snd_hda_get_connections(codec, nid, conn_list, - HDA_MAX_CONNECTIONS); - if (nconns < 0) { - kfree(node); - return nconns; - } - if (nconns <= ARRAY_SIZE(node->slist)) - node->conn_list = node->slist; - else { - node->conn_list = kmalloc(sizeof(hda_nid_t) * nconns, - GFP_KERNEL); - if (! node->conn_list) { - snd_printk(KERN_ERR "hda-generic: cannot malloc\n"); - kfree(node); - return -ENOMEM; - } - } - memcpy(node->conn_list, conn_list, nconns); - node->nconns = nconns; - node->wid_caps = get_wcaps(codec, nid); - node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - - if (node->type == AC_WID_PIN) { - node->pin_caps = snd_hda_param_read(codec, node->nid, AC_PAR_PIN_CAP); - node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - node->def_cfg = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - } - - if (node->wid_caps & AC_WCAP_OUT_AMP) { - if (node->wid_caps & AC_WCAP_AMP_OVRD) - node->amp_out_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_OUT_CAP); - if (! node->amp_out_caps) - node->amp_out_caps = spec->def_amp_out_caps; - } - if (node->wid_caps & AC_WCAP_IN_AMP) { - if (node->wid_caps & AC_WCAP_AMP_OVRD) - node->amp_in_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_IN_CAP); - if (! node->amp_in_caps) - node->amp_in_caps = spec->def_amp_in_caps; - } - list_add_tail(&node->list, &spec->nid_list); - return 0; -} - -/* - * build the AFG subtree - */ -static int build_afg_tree(struct hda_codec *codec) -{ - struct hda_gspec *spec = codec->spec; - int i, nodes, err; - hda_nid_t nid; - - snd_assert(spec, return -EINVAL); - - spec->def_amp_out_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_OUT_CAP); - spec->def_amp_in_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_IN_CAP); - - nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); - if (! nid || nodes < 0) { - printk(KERN_ERR "Invalid AFG subtree\n"); - return -EINVAL; - } - - /* parse all nodes belonging to the AFG */ - for (i = 0; i < nodes; i++, nid++) { - if ((err = add_new_node(codec, spec, nid)) < 0) - return err; - } - - return 0; -} - - -/* - * look for the node record for the given NID - */ -/* FIXME: should avoid the braindead linear search */ -static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid) -{ - struct list_head *p; - struct hda_gnode *node; - - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); - if (node->nid == nid) - return node; - } - return NULL; -} - -/* - * unmute (and set max vol) the output amplifier - */ -static int unmute_output(struct hda_codec *codec, struct hda_gnode *node) -{ - unsigned int val, ofs; - snd_printdd("UNMUTE OUT: NID=0x%x\n", node->nid); - val = (node->amp_out_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; - if (val >= ofs) - val -= ofs; - val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; - val |= AC_AMP_SET_OUTPUT; - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); -} - -/* - * unmute (and set max vol) the input amplifier - */ -static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigned int index) -{ - unsigned int val, ofs; - snd_printdd("UNMUTE IN: NID=0x%x IDX=0x%x\n", node->nid, index); - val = (node->amp_in_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; - if (val >= ofs) - val -= ofs; - val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; - val |= AC_AMP_SET_INPUT; - // awk added - fixed to allow unmuting of indexed amps - val |= index << AC_AMP_SET_INDEX_SHIFT; - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); -} - -/* - * select the input connection of the given node. - */ -static int select_input_connection(struct hda_codec *codec, struct hda_gnode *node, - unsigned int index) -{ - snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_CONNECT_SEL, index); -} - -/* - * clear checked flag of each node in the node list - */ -static void clear_check_flags(struct hda_gspec *spec) -{ - struct list_head *p; - struct hda_gnode *node; - - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); - node->checked = 0; - } -} - -/* - * parse the output path recursively until reach to an audio output widget - * - * returns 0 if not found, 1 if found, or a negative error code. - */ -static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, - struct hda_gnode *node, int dac_idx) -{ - int i, err; - struct hda_gnode *child; - - if (node->checked) - return 0; - - node->checked = 1; - if (node->type == AC_WID_AUD_OUT) { - if (node->wid_caps & AC_WCAP_DIGITAL) { - snd_printdd("Skip Digital OUT node %x\n", node->nid); - return 0; - } - snd_printdd("AUD_OUT found %x\n", node->nid); - if (spec->dac_node[dac_idx]) { - /* already DAC node is assigned, just unmute & connect */ - return node == spec->dac_node[dac_idx]; - } - spec->dac_node[dac_idx] = node; - if ((node->wid_caps & AC_WCAP_OUT_AMP) && - spec->pcm_vol_nodes < MAX_PCM_VOLS) { - spec->pcm_vol[spec->pcm_vol_nodes].node = node; - spec->pcm_vol[spec->pcm_vol_nodes].index = 0; - spec->pcm_vol_nodes++; - } - return 1; /* found */ - } - - for (i = 0; i < node->nconns; i++) { - child = hda_get_node(spec, node->conn_list[i]); - if (! child) - continue; - err = parse_output_path(codec, spec, child, dac_idx); - if (err < 0) - return err; - else if (err > 0) { - /* found one, - * select the path, unmute both input and output - */ - if (node->nconns > 1) - select_input_connection(codec, node, i); - unmute_input(codec, node, i); - unmute_output(codec, node); - if (spec->dac_node[dac_idx] && - spec->pcm_vol_nodes < MAX_PCM_VOLS && - !(spec->dac_node[dac_idx]->wid_caps & - AC_WCAP_OUT_AMP)) { - if ((node->wid_caps & AC_WCAP_IN_AMP) || - (node->wid_caps & AC_WCAP_OUT_AMP)) { - int n = spec->pcm_vol_nodes; - spec->pcm_vol[n].node = node; - spec->pcm_vol[n].index = i; - spec->pcm_vol_nodes++; - } - } - return 1; - } - } - return 0; -} - -/* - * Look for the output PIN widget with the given jack type - * and parse the output path to that PIN. - * - * Returns the PIN node when the path to DAC is established. - */ -static struct hda_gnode *parse_output_jack(struct hda_codec *codec, - struct hda_gspec *spec, - int jack_type) -{ - struct list_head *p; - struct hda_gnode *node; - int err; - - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); - if (node->type != AC_WID_PIN) - continue; - /* output capable? */ - if (! (node->pin_caps & AC_PINCAP_OUT)) - continue; - if (defcfg_port_conn(node) == AC_JACK_PORT_NONE) - continue; /* unconnected */ - if (jack_type >= 0) { - if (jack_type != defcfg_type(node)) - continue; - if (node->wid_caps & AC_WCAP_DIGITAL) - continue; /* skip SPDIF */ - } else { - /* output as default? */ - if (! (node->pin_ctl & AC_PINCTL_OUT_EN)) - continue; - } - clear_check_flags(spec); - err = parse_output_path(codec, spec, node, 0); - if (err < 0) - return NULL; - if (! err && spec->out_pin_node[0]) { - err = parse_output_path(codec, spec, node, 1); - if (err < 0) - return NULL; - } - if (err > 0) { - /* unmute the PIN output */ - unmute_output(codec, node); - /* set PIN-Out enable */ - snd_hda_codec_write(codec, node->nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - AC_PINCTL_OUT_EN | - ((node->pin_caps & AC_PINCAP_HP_DRV) ? - AC_PINCTL_HP_EN : 0)); - return node; - } - } - return NULL; -} - - -/* - * parse outputs - */ -static int parse_output(struct hda_codec *codec) -{ - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node; - - /* - * Look for the output PIN widget - */ - /* first, look for the line-out pin */ - node = parse_output_jack(codec, spec, AC_JACK_LINE_OUT); - if (node) /* found, remember the PIN node */ - spec->out_pin_node[0] = node; - else { - /* if no line-out is found, try speaker out */ - node = parse_output_jack(codec, spec, AC_JACK_SPEAKER); - if (node) - spec->out_pin_node[0] = node; - } - /* look for the HP-out pin */ - node = parse_output_jack(codec, spec, AC_JACK_HP_OUT); - if (node) { - if (! spec->out_pin_node[0]) - spec->out_pin_node[0] = node; - else - spec->out_pin_node[1] = node; - } - - if (! spec->out_pin_node[0]) { - /* no line-out or HP pins found, - * then choose for the first output pin - */ - spec->out_pin_node[0] = parse_output_jack(codec, spec, -1); - if (! spec->out_pin_node[0]) - snd_printd("hda_generic: no proper output path found\n"); - } - - return 0; -} - -/* - * input MUX - */ - -/* control callbacks */ -static int capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_gspec *spec = codec->spec; - return snd_hda_input_mux_info(&spec->input_mux, uinfo); -} - -static int capture_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_gspec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->cur_cap_src; - return 0; -} - -static int capture_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_gspec *spec = codec->spec; - return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, - spec->adc_node->nid, &spec->cur_cap_src); -} - -/* - * return the string name of the given input PIN widget - */ -static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) -{ - unsigned int location = defcfg_location(node); - switch (defcfg_type(node)) { - case AC_JACK_LINE_IN: - if ((location & 0x0f) == AC_JACK_LOC_FRONT) - return "Front Line"; - return "Line"; - case AC_JACK_CD: -#if 0 - if (pinctl) - *pinctl |= AC_PINCTL_VREF_GRD; -#endif - return "CD"; - case AC_JACK_AUX: - if ((location & 0x0f) == AC_JACK_LOC_FRONT) - return "Front Aux"; - return "Aux"; - case AC_JACK_MIC_IN: - if (pinctl && - (node->pin_caps & - (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT))) - *pinctl |= AC_PINCTL_VREF_80; - if ((location & 0x0f) == AC_JACK_LOC_FRONT) - return "Front Mic"; - return "Mic"; - case AC_JACK_SPDIF_IN: - return "SPDIF"; - case AC_JACK_DIG_OTHER_IN: - return "Digital"; - } - return NULL; -} - -/* - * parse the nodes recursively until reach to the input PIN - * - * returns 0 if not found, 1 if found, or a negative error code. - */ -static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, - struct hda_gnode *node) -{ - int i, err; - unsigned int pinctl; - char *label; - const char *type; - - if (node->checked) - return 0; - - node->checked = 1; - if (node->type != AC_WID_PIN) { - for (i = 0; i < node->nconns; i++) { - struct hda_gnode *child; - child = hda_get_node(spec, node->conn_list[i]); - if (! child) - continue; - err = parse_adc_sub_nodes(codec, spec, child); - if (err < 0) - return err; - if (err > 0) { - /* found one, - * select the path, unmute both input and output - */ - if (node->nconns > 1) - select_input_connection(codec, node, i); - unmute_input(codec, node, i); - unmute_output(codec, node); - return err; - } - } - return 0; - } - - /* input capable? */ - if (! (node->pin_caps & AC_PINCAP_IN)) - return 0; - - if (defcfg_port_conn(node) == AC_JACK_PORT_NONE) - return 0; /* unconnected */ - - if (node->wid_caps & AC_WCAP_DIGITAL) - return 0; /* skip SPDIF */ - - if (spec->input_mux.num_items >= HDA_MAX_NUM_INPUTS) { - snd_printk(KERN_ERR "hda_generic: Too many items for capture\n"); - return -EINVAL; - } - - pinctl = AC_PINCTL_IN_EN; - /* create a proper capture source label */ - type = get_input_type(node, &pinctl); - if (! type) { - /* input as default? */ - if (! (node->pin_ctl & AC_PINCTL_IN_EN)) - return 0; - type = "Input"; - } - label = spec->cap_labels[spec->input_mux.num_items]; - strcpy(label, type); - spec->input_mux.items[spec->input_mux.num_items].label = label; - - /* unmute the PIN external input */ - unmute_input(codec, node, 0); /* index = 0? */ - /* set PIN-In enable */ - snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); - - return 1; /* found */ -} - -/* add a capture source element */ -static void add_cap_src(struct hda_gspec *spec, int idx) -{ - struct hda_input_mux_item *csrc; - char *buf; - int num, ocap; - - num = spec->input_mux.num_items; - csrc = &spec->input_mux.items[num]; - buf = spec->cap_labels[num]; - for (ocap = 0; ocap < num; ocap++) { - if (! strcmp(buf, spec->cap_labels[ocap])) { - /* same label already exists, - * put the index number to be unique - */ - sprintf(buf, "%s %d", spec->cap_labels[ocap], num); - break; - } - } - csrc->index = idx; - spec->input_mux.num_items++; -} - -/* - * parse input - */ -static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) -{ - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node; - int i, err; - - snd_printdd("AUD_IN = %x\n", adc_node->nid); - clear_check_flags(spec); - - // awk added - fixed no recording due to muted widget - unmute_input(codec, adc_node, 0); - - /* - * check each connection of the ADC - * if it reaches to a proper input PIN, add the path as the - * input path. - */ - /* first, check the direct connections to PIN widgets */ - for (i = 0; i < adc_node->nconns; i++) { - node = hda_get_node(spec, adc_node->conn_list[i]); - if (node && node->type == AC_WID_PIN) { - err = parse_adc_sub_nodes(codec, spec, node); - if (err < 0) - return err; - else if (err > 0) - add_cap_src(spec, i); - } - } - /* ... then check the rests, more complicated connections */ - for (i = 0; i < adc_node->nconns; i++) { - node = hda_get_node(spec, adc_node->conn_list[i]); - if (node && node->type != AC_WID_PIN) { - err = parse_adc_sub_nodes(codec, spec, node); - if (err < 0) - return err; - else if (err > 0) - add_cap_src(spec, i); - } - } - - if (! spec->input_mux.num_items) - return 0; /* no input path found... */ - - snd_printdd("[Capture Source] NID=0x%x, #SRC=%d\n", adc_node->nid, spec->input_mux.num_items); - for (i = 0; i < spec->input_mux.num_items; i++) - snd_printdd(" [%s] IDX=0x%x\n", spec->input_mux.items[i].label, - spec->input_mux.items[i].index); - - spec->adc_node = adc_node; - return 1; -} - -/* - * parse input - */ -static int parse_input(struct hda_codec *codec) -{ - struct hda_gspec *spec = codec->spec; - struct list_head *p; - struct hda_gnode *node; - int err; - - /* - * At first we look for an audio input widget. - * If it reaches to certain input PINs, we take it as the - * input path. - */ - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); - if (node->wid_caps & AC_WCAP_DIGITAL) - continue; /* skip SPDIF */ - if (node->type == AC_WID_AUD_IN) { - err = parse_input_path(codec, node); - if (err < 0) - return err; - else if (err > 0) - return 0; - } - } - snd_printd("hda_generic: no proper input path found\n"); - return 0; -} - -/* - * create mixer controls if possible - */ -static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, - unsigned int index, const char *type, const char *dir_sfx) -{ - char name[32]; - int err; - int created = 0; - struct snd_kcontrol_new knew; - - if (type) - sprintf(name, "%s %s Switch", type, dir_sfx); - else - sprintf(name, "%s Switch", dir_sfx); - if ((node->wid_caps & AC_WCAP_IN_AMP) && - (node->amp_in_caps & AC_AMPCAP_MUTE)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT); - snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); - if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) - return err; - created = 1; - } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && - (node->amp_out_caps & AC_AMPCAP_MUTE)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT); - snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); - if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) - return err; - created = 1; - } - - if (type) - sprintf(name, "%s %s Volume", type, dir_sfx); - else - sprintf(name, "%s Volume", dir_sfx); - if ((node->wid_caps & AC_WCAP_IN_AMP) && - (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT); - snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); - if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) - return err; - created = 1; - } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && - (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT); - snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); - if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) - return err; - created = 1; - } - - return created; -} - -/* - * check whether the controls with the given name and direction suffix already exist - */ -static int check_existing_control(struct hda_codec *codec, const char *type, const char *dir) -{ - struct snd_ctl_elem_id id; - memset(&id, 0, sizeof(id)); - sprintf(id.name, "%s %s Volume", type, dir); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - if (snd_ctl_find_id(codec->bus->card, &id)) - return 1; - sprintf(id.name, "%s %s Switch", type, dir); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - if (snd_ctl_find_id(codec->bus->card, &id)) - return 1; - return 0; -} - -/* - * build output mixer controls - */ -static int create_output_mixers(struct hda_codec *codec, const char **names) -{ - struct hda_gspec *spec = codec->spec; - int i, err; - - for (i = 0; i < spec->pcm_vol_nodes; i++) { - err = create_mixer(codec, spec->pcm_vol[i].node, - spec->pcm_vol[i].index, - names[i], "Playback"); - if (err < 0) - return err; - } - return 0; -} - -static int build_output_controls(struct hda_codec *codec) -{ - struct hda_gspec *spec = codec->spec; - static const char *types_speaker[] = { "Speaker", "Headphone" }; - static const char *types_line[] = { "Front", "Headphone" }; - - switch (spec->pcm_vol_nodes) { - case 1: - return create_mixer(codec, spec->pcm_vol[0].node, - spec->pcm_vol[0].index, - "Master", "Playback"); - case 2: - if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER) - return create_output_mixers(codec, types_speaker); - else - return create_output_mixers(codec, types_line); - } - return 0; -} - -/* create capture volume/switch */ -static int build_input_controls(struct hda_codec *codec) -{ - struct hda_gspec *spec = codec->spec; - struct hda_gnode *adc_node = spec->adc_node; - int i, err; - static struct snd_kcontrol_new cap_sel = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = capture_source_info, - .get = capture_source_get, - .put = capture_source_put, - }; - - if (! adc_node || ! spec->input_mux.num_items) - return 0; /* not found */ - - spec->cur_cap_src = 0; - select_input_connection(codec, adc_node, - spec->input_mux.items[0].index); - - /* create capture volume and switch controls if the ADC has an amp */ - /* do we have only a single item? */ - if (spec->input_mux.num_items == 1) { - err = create_mixer(codec, adc_node, - spec->input_mux.items[0].index, - NULL, "Capture"); - if (err < 0) - return err; - return 0; - } - - /* create input MUX if multiple sources are available */ - if ((err = snd_ctl_add(codec->bus->card, - snd_ctl_new1(&cap_sel, codec))) < 0) - return err; - - /* no volume control? */ - if (! (adc_node->wid_caps & AC_WCAP_IN_AMP) || - ! (adc_node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) - return 0; - - for (i = 0; i < spec->input_mux.num_items; i++) { - struct snd_kcontrol_new knew; - char name[32]; - sprintf(name, "%s Capture Volume", - spec->input_mux.items[i].label); - knew = (struct snd_kcontrol_new) - HDA_CODEC_VOLUME(name, adc_node->nid, - spec->input_mux.items[i].index, - HDA_INPUT); - if ((err = snd_ctl_add(codec->bus->card, - snd_ctl_new1(&knew, codec))) < 0) - return err; - } - - return 0; -} - - -/* - * parse the nodes recursively until reach to the output PIN. - * - * returns 0 - if not found, - * 1 - if found, but no mixer is created - * 2 - if found and mixer was already created, (just skip) - * a negative error code - */ -static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, - struct hda_gnode *node, struct hda_gnode *dest_node, - const char *type) -{ - int i, err; - - if (node->checked) - return 0; - - node->checked = 1; - if (node == dest_node) { - /* loopback connection found */ - return 1; - } - - for (i = 0; i < node->nconns; i++) { - struct hda_gnode *child = hda_get_node(spec, node->conn_list[i]); - if (! child) - continue; - err = parse_loopback_path(codec, spec, child, dest_node, type); - if (err < 0) - return err; - else if (err >= 1) { - if (err == 1) { - err = create_mixer(codec, node, i, type, "Playback"); - if (err < 0) - return err; - if (err > 0) - return 2; /* ok, created */ - /* not created, maybe in the lower path */ - err = 1; - } - /* connect and unmute */ - if (node->nconns > 1) - select_input_connection(codec, node, i); - unmute_input(codec, node, i); - unmute_output(codec, node); - return err; - } - } - return 0; -} - -/* - * parse the tree and build the loopback controls - */ -static int build_loopback_controls(struct hda_codec *codec) -{ - struct hda_gspec *spec = codec->spec; - struct list_head *p; - struct hda_gnode *node; - int err; - const char *type; - - if (! spec->out_pin_node[0]) - return 0; - - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); - if (node->type != AC_WID_PIN) - continue; - /* input capable? */ - if (! (node->pin_caps & AC_PINCAP_IN)) - return 0; - type = get_input_type(node, NULL); - if (type) { - if (check_existing_control(codec, type, "Playback")) - continue; - clear_check_flags(spec); - err = parse_loopback_path(codec, spec, - spec->out_pin_node[0], - node, type); - if (err < 0) - return err; - if (! err) - continue; - } - } - return 0; -} - -/* - * build mixer controls - */ -static int build_generic_controls(struct hda_codec *codec) -{ - int err; - - if ((err = build_input_controls(codec)) < 0 || - (err = build_output_controls(codec)) < 0 || - (err = build_loopback_controls(codec)) < 0) - return err; - - return 0; -} - -/* - * PCM - */ -static struct hda_pcm_stream generic_pcm_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -static int generic_pcm2_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct hda_gspec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); - snd_hda_codec_setup_stream(codec, spec->dac_node[1]->nid, - stream_tag, 0, format); - return 0; -} - -static int generic_pcm2_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct hda_gspec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, hinfo->nid, 0, 0, 0); - snd_hda_codec_setup_stream(codec, spec->dac_node[1]->nid, 0, 0, 0); - return 0; -} - -static int build_generic_pcms(struct hda_codec *codec) -{ - struct hda_gspec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; - - if (! spec->dac_node[0] && ! spec->adc_node) { - snd_printd("hda_generic: no PCM found\n"); - return 0; - } - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "HDA Generic"; - if (spec->dac_node[0]) { - info->stream[0] = generic_pcm_playback; - info->stream[0].nid = spec->dac_node[0]->nid; - if (spec->dac_node[1]) { - info->stream[0].ops.prepare = generic_pcm2_prepare; - info->stream[0].ops.cleanup = generic_pcm2_cleanup; - } - } - if (spec->adc_node) { - info->stream[1] = generic_pcm_playback; - info->stream[1].nid = spec->adc_node->nid; - } - - return 0; -} - - -/* - */ -static struct hda_codec_ops generic_patch_ops = { - .build_controls = build_generic_controls, - .build_pcms = build_generic_pcms, - .free = snd_hda_generic_free, -}; - -/* - * the generic parser - */ -int snd_hda_parse_generic_codec(struct hda_codec *codec) -{ - struct hda_gspec *spec; - int err; - - if(!codec->afg) - return 0; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) { - printk(KERN_ERR "hda_generic: can't allocate spec\n"); - return -ENOMEM; - } - codec->spec = spec; - INIT_LIST_HEAD(&spec->nid_list); - - if ((err = build_afg_tree(codec)) < 0) - goto error; - - if ((err = parse_input(codec)) < 0 || - (err = parse_output(codec)) < 0) - goto error; - - codec->patch_ops = generic_patch_ops; - - return 0; - - error: - snd_hda_generic_free(codec); - return err; -} diff --git a/modules/GPL/hda/hda_intel.c b/modules/GPL/hda/hda_intel.c deleted file mode 100644 index b5741c1..0000000 --- a/modules/GPL/hda/hda_intel.c +++ /dev/null @@ -1,1901 +0,0 @@ -/* - * - * hda_intel.c - Implementation of primary alsa driver code base for Intel HD Audio. - * - * Copyright(c) 2004 Intel Corporation. All rights reserved. - * - * Copyright (c) 2004 Takashi Iwai - * PeiSen Hou - * - * 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. - * - * CONTACTS: - * - * Matt Jared matt.jared@intel.com - * Andy Kopp andy.kopp@intel.com - * Dan Kogan dan.d.kogan@intel.com - * - * CHANGES: - * - * 2004.12.01 Major rewrite by tiwai, merged the work of pshou - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - - -static int index = SNDRV_DEFAULT_IDX1; -static char *id = SNDRV_DEFAULT_STR1; -static char *model; -static int position_fix; -static int probe_mask = -1; -static int single_cmd; -static int enable_msi; - -module_param(index, int, 0444); -MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); -module_param(id, charp, 0444); -MODULE_PARM_DESC(id, "ID string for Intel HD audio interface."); -module_param(model, charp, 0444); -MODULE_PARM_DESC(model, "Use the given board model."); -module_param(position_fix, int, 0444); -MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); -module_param(probe_mask, int, 0444); -MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); -module_param(single_cmd, bool, 0444); -MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only)."); -module_param(enable_msi, int, 0); -MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); - - -/* just for backward compatibility */ -static int enable; -module_param(enable, bool, 0444); - -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," - "{Intel, ICH6M}," - "{Intel, ICH7}," - "{Intel, ESB2}," - "{Intel, ICH8}," - "{Intel, ICH9}," - "{ATI, SB450}," - "{ATI, SB600}," - "{ATI, RS600}," - "{ATI, RS690}," - "{VIA, VT8251}," - "{VIA, VT8237A}," - "{SiS, SIS966}," - "{ULI, M5461}}"); -MODULE_DESCRIPTION("Intel HDA driver"); - -#define SFX "hda-intel: " - -/* - * registers - */ -#define ICH6_REG_GCAP 0x00 -#define ICH6_REG_VMIN 0x02 -#define ICH6_REG_VMAJ 0x03 -#define ICH6_REG_OUTPAY 0x04 -#define ICH6_REG_INPAY 0x06 -#define ICH6_REG_GCTL 0x08 -#define ICH6_REG_WAKEEN 0x0c -#define ICH6_REG_STATESTS 0x0e -#define ICH6_REG_GSTS 0x10 -#define ICH6_REG_INTCTL 0x20 -#define ICH6_REG_INTSTS 0x24 -#define ICH6_REG_WALCLK 0x30 -#define ICH6_REG_SYNC 0x34 -#define ICH6_REG_CORBLBASE 0x40 -#define ICH6_REG_CORBUBASE 0x44 -#define ICH6_REG_CORBWP 0x48 -#define ICH6_REG_CORBRP 0x4A -#define ICH6_REG_CORBCTL 0x4c -#define ICH6_REG_CORBSTS 0x4d -#define ICH6_REG_CORBSIZE 0x4e - -#define ICH6_REG_RIRBLBASE 0x50 -#define ICH6_REG_RIRBUBASE 0x54 -#define ICH6_REG_RIRBWP 0x58 -#define ICH6_REG_RINTCNT 0x5a -#define ICH6_REG_RIRBCTL 0x5c -#define ICH6_REG_RIRBSTS 0x5d -#define ICH6_REG_RIRBSIZE 0x5e - -#define ICH6_REG_IC 0x60 -#define ICH6_REG_IR 0x64 -#define ICH6_REG_IRS 0x68 -#define ICH6_IRS_VALID (1<<1) -#define ICH6_IRS_BUSY (1<<0) - -#define ICH6_REG_DPLBASE 0x70 -#define ICH6_REG_DPUBASE 0x74 -#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */ - -/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ -enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; - -/* stream register offsets from stream base */ -#define ICH6_REG_SD_CTL 0x00 -#define ICH6_REG_SD_STS 0x03 -#define ICH6_REG_SD_LPIB 0x04 -#define ICH6_REG_SD_CBL 0x08 -#define ICH6_REG_SD_LVI 0x0c -#define ICH6_REG_SD_FIFOW 0x0e -#define ICH6_REG_SD_FIFOSIZE 0x10 -#define ICH6_REG_SD_FORMAT 0x12 -#define ICH6_REG_SD_BDLPL 0x18 -#define ICH6_REG_SD_BDLPU 0x1c - -/* PCI space */ -#define ICH6_PCIREG_TCSEL 0x44 - -/* - * other constants - */ - -/* max number of SDs */ -/* ICH, ATI and VIA have 4 playback and 4 capture */ -#define ICH6_CAPTURE_INDEX 0 -#define ICH6_NUM_CAPTURE 4 -#define ICH6_PLAYBACK_INDEX 4 -#define ICH6_NUM_PLAYBACK 4 - -/* ULI has 6 playback and 5 capture */ -#define ULI_CAPTURE_INDEX 0 -#define ULI_NUM_CAPTURE 5 -#define ULI_PLAYBACK_INDEX 5 -#define ULI_NUM_PLAYBACK 6 - -/* ATI HDMI has 1 playback and 0 capture */ -#define ATIHDMI_CAPTURE_INDEX 0 -#define ATIHDMI_NUM_CAPTURE 0 -#define ATIHDMI_PLAYBACK_INDEX 0 -#define ATIHDMI_NUM_PLAYBACK 1 - -/* this number is statically defined for simplicity */ -#define MAX_AZX_DEV 16 - -/* max number of fragments - we may use more if allocating more pages for BDL */ -#define BDL_SIZE PAGE_ALIGN(8192) -#define AZX_MAX_FRAG (BDL_SIZE / (MAX_AZX_DEV * 16)) -/* max buffer size - no h/w limit, you can increase as you like */ -#define AZX_MAX_BUF_SIZE (1024*1024*1024) -/* max number of PCM devics per card */ -#define AZX_MAX_AUDIO_PCMS 6 -#define AZX_MAX_MODEM_PCMS 2 -#define AZX_MAX_PCMS (AZX_MAX_AUDIO_PCMS + AZX_MAX_MODEM_PCMS) - -/* RIRB int mask: overrun[2], response[0] */ -#define RIRB_INT_RESPONSE 0x01 -#define RIRB_INT_OVERRUN 0x04 -#define RIRB_INT_MASK 0x05 - -/* STATESTS int mask: SD2,SD1,SD0 */ -#define AZX_MAX_CODECS 3 -#define STATESTS_INT_MASK 0x07 - -/* SD_CTL bits */ -#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ -#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */ -#define SD_CTL_STREAM_TAG_MASK (0xf << 20) -#define SD_CTL_STREAM_TAG_SHIFT 20 - -/* SD_CTL and SD_STS */ -#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ -#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ -#define SD_INT_COMPLETE 0x04 /* completion interrupt */ -#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|SD_INT_COMPLETE) - -/* SD_STS */ -#define SD_STS_FIFO_READY 0x20 /* FIFO ready */ - -/* INTCTL and INTSTS */ -#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ -#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ -#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ - -/* GCTL unsolicited response enable bit */ -#define ICH6_GCTL_UREN (1<<8) - -/* GCTL reset bit */ -#define ICH6_GCTL_RESET (1<<0) - -/* CORB/RIRB control, read/write pointer */ -#define ICH6_RBCTL_DMA_EN 0x02 /* enable DMA */ -#define ICH6_RBCTL_IRQ_EN 0x01 /* enable IRQ */ -#define ICH6_RBRWP_CLR 0x8000 /* read/write pointer clear */ -/* below are so far hardcoded - should read registers in future */ -#define ICH6_MAX_CORB_ENTRIES 256 -#define ICH6_MAX_RIRB_ENTRIES 256 - -/* position fix mode */ -enum { - POS_FIX_AUTO, - POS_FIX_NONE, - POS_FIX_POSBUF, - POS_FIX_FIFO, -}; - -/* Defines for ATI HD Audio support in SB450 south bridge */ -#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 -#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 - -/* Defines for Nvidia HDA support */ -#define NVIDIA_HDA_TRANSREG_ADDR 0x4e -#define NVIDIA_HDA_ENABLE_COHBITS 0x0f - -/* - */ - -struct azx_dev { - u32 *bdl; /* virtual address of the BDL */ - dma_addr_t bdl_addr; /* physical address of the BDL */ - u32 *posbuf; /* position buffer pointer */ - - unsigned int bufsize; /* size of the play buffer in bytes */ - unsigned int fragsize; /* size of each period in bytes */ - unsigned int frags; /* number for period in the play buffer */ - unsigned int fifo_size; /* FIFO size */ - - void __iomem *sd_addr; /* stream descriptor pointer */ - - u32 sd_int_sta_mask; /* stream int status mask */ - - /* pcm support */ - struct snd_pcm_substream *substream; /* assigned substream, set in PCM open */ - unsigned int format_val; /* format value to be set in the controller and the codec */ - unsigned char stream_tag; /* assigned stream */ - unsigned char index; /* stream index */ - /* for sanity check of position buffer */ - unsigned int period_intr; - - unsigned int opened :1; - unsigned int running :1; -}; - -/* CORB/RIRB */ -struct azx_rb { - u32 *buf; /* CORB/RIRB buffer - * Each CORB entry is 4byte, RIRB is 8byte - */ - dma_addr_t addr; /* physical address of CORB/RIRB buffer */ - /* for RIRB */ - unsigned short rp, wp; /* read/write pointers */ - int cmds; /* number of pending requests */ - u32 res; /* last read value */ -}; - -#ifndef SND_PCI_PM_CALLBACKS -#define snd_card_t struct snd_card -#endif - -struct azx { - struct snd_card *card; - struct pci_dev *pci; - - /* chip type specific */ - int driver_type; - int playback_streams; - int playback_index_offset; - int capture_streams; - int capture_index_offset; - int num_streams; - - /* pci resources */ - unsigned long addr; - void __iomem *remap_addr; - int irq; - - /* locks */ - spinlock_t reg_lock; - struct mutex open_mutex; - - /* streams (x num_streams) */ - struct azx_dev *azx_dev; - - /* PCM */ - unsigned int pcm_devs; - struct snd_pcm *pcm[AZX_MAX_PCMS]; - - /* HD codec */ - unsigned short codec_mask; - struct hda_bus *bus; - - /* CORB/RIRB */ - struct azx_rb corb; - struct azx_rb rirb; - - /* BDL, CORB/RIRB and position buffers */ - struct snd_dma_buffer bdl; - struct snd_dma_buffer rb; - struct snd_dma_buffer posbuf; - - /* flags */ - int position_fix; - unsigned int initialized :1; - unsigned int single_cmd :1; - unsigned int polling_mode :1; - unsigned int msi :1; -}; - -/* driver types */ -enum { - AZX_DRIVER_ICH, - AZX_DRIVER_ATI, - AZX_DRIVER_ATIHDMI, - AZX_DRIVER_VIA, - AZX_DRIVER_SIS, - AZX_DRIVER_ULI, - AZX_DRIVER_NVIDIA, -}; - -static char *driver_short_names[] __devinitdata = { - [AZX_DRIVER_ICH] = "HDA Intel", - [AZX_DRIVER_ATI] = "HDA ATI SB", - [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", - [AZX_DRIVER_VIA] = "HDA VIA VT82xx", - [AZX_DRIVER_SIS] = "HDA SIS966", - [AZX_DRIVER_ULI] = "HDA ULI M5461", - [AZX_DRIVER_NVIDIA] = "HDA NVidia", -}; - -/* - * macros for easy use - */ -#define azx_writel(chip,reg,value) \ - writel(value, (chip)->remap_addr + ICH6_REG_##reg) -#define azx_readl(chip,reg) \ - readl((chip)->remap_addr + ICH6_REG_##reg) -#define azx_writew(chip,reg,value) \ - writew(value, (chip)->remap_addr + ICH6_REG_##reg) -#define azx_readw(chip,reg) \ - readw((chip)->remap_addr + ICH6_REG_##reg) -#define azx_writeb(chip,reg,value) \ - writeb(value, (chip)->remap_addr + ICH6_REG_##reg) -#define azx_readb(chip,reg) \ - readb((chip)->remap_addr + ICH6_REG_##reg) - -#define azx_sd_writel(dev,reg,value) \ - writel(value, (dev)->sd_addr + ICH6_REG_##reg) -#define azx_sd_readl(dev,reg) \ - readl((dev)->sd_addr + ICH6_REG_##reg) -#define azx_sd_writew(dev,reg,value) \ - writew(value, (dev)->sd_addr + ICH6_REG_##reg) -#define azx_sd_readw(dev,reg) \ - readw((dev)->sd_addr + ICH6_REG_##reg) -#define azx_sd_writeb(dev,reg,value) \ - writeb(value, (dev)->sd_addr + ICH6_REG_##reg) -#define azx_sd_readb(dev,reg) \ - readb((dev)->sd_addr + ICH6_REG_##reg) - -/* for pcm support */ -#define get_azx_dev(substream) (substream->runtime->private_data) - -/* Get the upper 32bit of the given dma_addr_t - * Compiler should optimize and eliminate the code if dma_addr_t is 32bit - */ -#define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0) - -static int azx_acquire_irq(struct azx *chip, int do_disconnect); - -/* - * Interface for HD codec - */ - -static u32 azx_get_wallclock(struct hda_codec *codec) -{ - struct azx *chip = codec->bus->private_data; - - return azx_readl(chip, WALCLK); -} - -static u32 azx_get_linkpos(snd_pcm_substream_t *substream) -{ - struct azx_dev *azx_dev = get_azx_dev(substream); - - return azx_sd_readl(azx_dev, SD_LPIB); -} - -/* - * CORB / RIRB interface - */ -static int azx_alloc_cmd_io(struct azx *chip) -{ - int err; - - /* single page (at least 4096 bytes) must suffice for both ringbuffes */ - err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - PAGE_SIZE, &chip->rb); - if (err < 0) { - snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n"); - return err; - } - return 0; -} - -static void azx_init_cmd_io(struct azx *chip) -{ - /* CORB set up */ - chip->corb.addr = chip->rb.addr; - chip->corb.buf = (u32 *)chip->rb.area; - azx_writel(chip, CORBLBASE, (u32)chip->corb.addr); - azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr)); - - /* set the corb size to 256 entries (ULI requires explicitly) */ - azx_writeb(chip, CORBSIZE, 0x02); - /* set the corb write pointer to 0 */ - azx_writew(chip, CORBWP, 0); - /* reset the corb hw read pointer */ - azx_writew(chip, CORBRP, ICH6_RBRWP_CLR); - /* enable corb dma */ - azx_writeb(chip, CORBCTL, ICH6_RBCTL_DMA_EN); - - /* RIRB set up */ - chip->rirb.addr = chip->rb.addr + 2048; - chip->rirb.buf = (u32 *)(chip->rb.area + 2048); - azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); - azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr)); - - /* set the rirb size to 256 entries (ULI requires explicitly) */ - azx_writeb(chip, RIRBSIZE, 0x02); - /* reset the rirb hw write pointer */ - azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR); - /* set N=1, get RIRB response interrupt for new entry */ - azx_writew(chip, RINTCNT, 1); - /* enable rirb dma and response irq */ - azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); - chip->rirb.rp = chip->rirb.cmds = 0; -} - -static void azx_free_cmd_io(struct azx *chip) -{ - /* disable ringbuffer DMAs */ - azx_writeb(chip, RIRBCTL, 0); - azx_writeb(chip, CORBCTL, 0); -} - -/* send a command */ -static int azx_corb_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int para) -{ - struct azx *chip = codec->bus->private_data; - unsigned int wp; - u32 val; - - val = (u32)(codec->addr & 0x0f) << 28; - val |= (u32)direct << 27; - val |= (u32)nid << 20; - val |= verb << 8; - val |= para; - - /* add command to corb */ - wp = azx_readb(chip, CORBWP); - wp++; - wp %= ICH6_MAX_CORB_ENTRIES; - - spin_lock_irq(&chip->reg_lock); - chip->rirb.cmds++; - chip->corb.buf[wp] = cpu_to_le32(val); - azx_writel(chip, CORBWP, wp); - spin_unlock_irq(&chip->reg_lock); - - return 0; -} - -#define ICH6_RIRB_EX_UNSOL_EV (1<<4) - -/* retrieve RIRB entry - called from interrupt handler */ -static void azx_update_rirb(struct azx *chip) -{ - unsigned int rp, wp; - u32 res, res_ex; - - wp = azx_readb(chip, RIRBWP); - if (wp == chip->rirb.wp) - return; - chip->rirb.wp = wp; - - while (chip->rirb.rp != wp) { - chip->rirb.rp++; - chip->rirb.rp %= ICH6_MAX_RIRB_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 & ICH6_RIRB_EX_UNSOL_EV) - snd_hda_queue_unsol_event(chip->bus, res, res_ex); - else if (chip->rirb.cmds) { - chip->rirb.cmds--; - chip->rirb.res = res; - } - } -} - -/* receive a response */ -static unsigned int azx_rirb_get_response(struct hda_codec *codec) -{ - struct azx *chip = codec->bus->private_data; - unsigned long timeout; - - again: - timeout = jiffies + msecs_to_jiffies(1000); - do { - if (chip->polling_mode) { - spin_lock_irq(&chip->reg_lock); - azx_update_rirb(chip); - spin_unlock_irq(&chip->reg_lock); - } - if (! chip->rirb.cmds) - return chip->rirb.res; /* the last value */ - schedule_timeout_interruptible(1); - } while (time_after_eq(timeout, jiffies)); - - if (chip->msi) { - snd_printk(KERN_WARNING "hda_intel: No response from codec, " - "disabling MSI...\n"); - free_irq(chip->irq, chip); - chip->irq = -1; - pci_disable_msi(chip->pci); - chip->msi = 0; - if (azx_acquire_irq(chip, 1) < 0) - return -1; - goto again; - } - - if (!chip->polling_mode) { - snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, " - "switching to polling mode...\n"); - chip->polling_mode = 1; - goto again; - } - - snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " - "switching to single_cmd mode...\n"); - chip->rirb.rp = azx_readb(chip, RIRBWP); - chip->rirb.cmds = 0; - /* switch to single_cmd mode */ - chip->single_cmd = 1; - azx_free_cmd_io(chip); - return -1; -} - -/* - * Use the single immediate command instead of CORB/RIRB for simplicity - * - * Note: according to Intel, this is not preferred use. The command was - * intended for the BIOS only, and may get confused with unsolicited - * responses. So, we shouldn't use it for normal operation from the - * driver. - * I left the codes, however, for debugging/testing purposes. - */ - -/* send a command */ -static int azx_single_send_cmd(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, - unsigned int para) -{ - struct azx *chip = codec->bus->private_data; - u32 val; - int timeout = 50; - - val = (u32)(codec->addr & 0x0f) << 28; - val |= (u32)direct << 27; - val |= (u32)nid << 20; - val |= verb << 8; - val |= para; - - while (timeout--) { - /* check ICB busy bit */ - if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) { - /* Clear IRV valid bit */ - azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_VALID); - azx_writel(chip, IC, val); - azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY); - return 0; - } - udelay(1); - } - if(printk_ratelimit()) - snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", azx_readw(chip, IRS), val); - return -EIO; -} - -/* receive a response */ -static unsigned int azx_single_get_response(struct hda_codec *codec) -{ - struct azx *chip = codec->bus->private_data; - int timeout = 50; - - while (timeout--) { - /* check IRV busy bit */ - if (azx_readw(chip, IRS) & ICH6_IRS_VALID) - return azx_readl(chip, IR); - udelay(1); - } - if(printk_ratelimit()) - snd_printd(SFX "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS)); - return (unsigned int)-1; -} - -/* - * The below are the main callbacks from hda_codec. - * - * They are just the skeleton to call sub-callbacks according to the - * current setting of chip->single_cmd. - */ - -/* send a command */ -static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, - unsigned int para) -{ - struct azx *chip = codec->bus->private_data; - if (chip->single_cmd) - return azx_single_send_cmd(codec, nid, direct, verb, para); - else - return azx_corb_send_cmd(codec, nid, direct, verb, para); -} - -/* get a response */ -static unsigned int azx_get_response(struct hda_codec *codec) -{ - struct azx *chip = codec->bus->private_data; - if (chip->single_cmd) - return azx_single_get_response(codec); - else - return azx_rirb_get_response(codec); -} - - -/* reset codec link */ -static int azx_reset(struct azx *chip) -{ - int count; - - /* reset controller */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); - - count = 50; - while (azx_readb(chip, GCTL) && --count) - msleep(1); - - /* delay for >= 100us for codec PLL to settle per spec - * Rev 0.9 section 5.5.1 - */ - msleep(1); - - /* Bring controller out of reset */ - azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); - - count = 50; - while (!azx_readb(chip, GCTL) && --count) - msleep(1); - - /* Brent Chartrand said to wait >= 540us for codecs to initialize */ - msleep(1); - - /* check to see if controller is ready */ - if (!azx_readb(chip, GCTL)) { - snd_printd("azx_reset: controller not ready!\n"); - return -EBUSY; - } - - /* Accept unsolicited responses */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN); - - /* detect codecs */ - if (!chip->codec_mask) { - chip->codec_mask = azx_readw(chip, STATESTS); - snd_printdd("codec_mask = 0x%x\n", chip->codec_mask); - } - - return 0; -} - - -/* - * Lowlevel interface - */ - -/* enable interrupts */ -static void azx_int_enable(struct azx *chip) -{ - /* enable controller CIE and GIE */ - azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) | - ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN); -} - -/* disable interrupts */ -static void azx_int_disable(struct azx *chip) -{ - int i; - - /* disable interrupts in stream descriptor */ - for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_sd_writeb(azx_dev, SD_CTL, - azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK); - } - - /* disable SIE for all streams */ - azx_writeb(chip, INTCTL, 0); - - /* disable controller CIE and GIE */ - azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) & - ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN)); -} - -/* clear interrupts */ -static void azx_int_clear(struct azx *chip) -{ - int i; - - /* clear stream status */ - for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); - } - - /* clear STATESTS */ - azx_writeb(chip, STATESTS, STATESTS_INT_MASK); - - /* clear rirb status */ - azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); - - /* clear int status */ - azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM); -} - -/* start a stream */ -static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) -{ -//printk(KERN_DEBUG"%s: %p\n", __FUNCTION__, azx_dev); - /* enable SIE */ - azx_writeb(chip, INTCTL, - azx_readb(chip, INTCTL) | (1 << azx_dev->index)); - /* set DMA start and interrupt mask */ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | - SD_CTL_DMA_START | SD_INT_MASK); -} - -/* stop a stream */ -static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) -{ -//printk(KERN_DEBUG"%s: %p\n", __FUNCTION__, azx_dev); - /* stop DMA */ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & - ~(SD_CTL_DMA_START | SD_INT_MASK)); - azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ - /* disable SIE */ - azx_writeb(chip, INTCTL, - azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); -} - - -/* - * initialize the chip - */ -static void azx_init_chip(struct azx *chip) -{ - unsigned char reg; - - /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) - * TCSEL == Traffic Class Select Register, which sets PCI express QOS - * Ensuring these bits are 0 clears playback static on some HD Audio codecs - */ - pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, ®); - pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, reg & 0xf8); - - /* reset controller */ - azx_reset(chip); - - /* initialize interrupts */ - azx_int_clear(chip); - azx_int_enable(chip); - - /* initialize the codec command I/O */ - if (!chip->single_cmd) - azx_init_cmd_io(chip); - - /* program the position buffer */ - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); - azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); - - switch (chip->driver_type) { - case AZX_DRIVER_ATI: - /* For ATI SB450 azalia HD audio, we need to enable snoop */ - pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - ®); - pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - (reg & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP); - break; - case AZX_DRIVER_NVIDIA: - /* For NVIDIA HDA, enable snoop */ - pci_read_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, ®); - pci_write_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, - (reg & 0xf0) | NVIDIA_HDA_ENABLE_COHBITS); - break; - } -} - - -/* - * interrupt handler - */ -#ifdef FOUND_IRQ_HANDLER_T -static irqreturn_t azx_interrupt(int irq, void *dev_id) -#else -static irqreturn_t azx_interrupt(int irq, void *dev_id, struct pt_regs *regs) -#endif -{ - struct azx *chip = dev_id; - struct azx_dev *azx_dev; - u32 status; - int i; - - spin_lock(&chip->reg_lock); - - status = azx_readl(chip, INTSTS); - if (status == 0) { - spin_unlock(&chip->reg_lock); - return IRQ_NONE; - } - - for (i = 0; i < chip->num_streams; i++) { - azx_dev = &chip->azx_dev[i]; - if (status & azx_dev->sd_int_sta_mask) { - azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); -#if 1 - if (azx_dev->substream && azx_dev->running) { - azx_dev->period_intr++; - spin_unlock(&chip->reg_lock); - snd_pcm_period_elapsed(azx_dev->substream); - spin_lock(&chip->reg_lock); - } -#endif - } - } - - /* clear rirb int */ - status = azx_readb(chip, RIRBSTS); - if (status & RIRB_INT_MASK) { - if (! chip->single_cmd && (status & RIRB_INT_RESPONSE)) - azx_update_rirb(chip); - azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); - } - -#if 0 - /* clear state status int */ - if (azx_readb(chip, STATESTS) & 0x04) - azx_writeb(chip, STATESTS, 0x04); -#endif - spin_unlock(&chip->reg_lock); - - return IRQ_HANDLED; -} - - -/* - * set up BDL entries - */ -static void azx_setup_periods(struct azx_dev *azx_dev) -{ - u32 *bdl = azx_dev->bdl; - dma_addr_t dma_addr = azx_dev->substream->runtime->dma_addr; - int idx; - -//printk(KERN_DEBUG"%s: %p frags=%d fragsize=%d dma_addr=0x%lx\n", __FUNCTION__, azx_dev, azx_dev->frags, azx_dev->fragsize, (unsigned long) dma_addr); - /* reset BDL address */ - azx_sd_writel(azx_dev, SD_BDLPL, 0); - azx_sd_writel(azx_dev, SD_BDLPU, 0); - - /* program the initial BDL entries */ - for (idx = 0; idx < azx_dev->frags; idx++) { - unsigned int off = idx << 2; /* 4 dword step */ - dma_addr_t addr = dma_addr + idx * azx_dev->fragsize; - /* program the address field of the BDL entry */ - bdl[off] = cpu_to_le32((u32)addr); - bdl[off+1] = cpu_to_le32(upper_32bit(addr)); - - /* program the size field of the BDL entry */ - bdl[off+2] = cpu_to_le32(azx_dev->fragsize); - -//XXX if(azx_dev->substream->pcm->dev_class != SNDRV_PCM_CLASS_MODEM) - /* program the IOC to enable interrupt when buffer completes */ - bdl[off+3] = cpu_to_le32(0x01); - } -} - -/* - * set up the SD for streaming - */ -static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) -{ - unsigned char val; - int timeout; - -//printk(KERN_DEBUG"%s: %p tag=%d bufsize=%d fmt=0x%x\n", __FUNCTION__, azx_dev, (int)azx_dev->stream_tag, azx_dev->bufsize, (unsigned int)azx_dev->format_val); - /* make sure the run bit is zero for SD */ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & ~SD_CTL_DMA_START); - /* reset stream */ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | SD_CTL_STREAM_RESET); - udelay(3); - timeout = 300; - while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && - --timeout) - ; - val &= ~SD_CTL_STREAM_RESET; - azx_sd_writeb(azx_dev, SD_CTL, val); - udelay(3); - - timeout = 300; - /* waiting for hardware to report that the stream is out of reset */ - while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && - --timeout) - ; - - /* program the stream_tag */ - azx_sd_writel(azx_dev, SD_CTL, - (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK) | - (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT)); - - /* program the length of samples in cyclic buffer */ - azx_sd_writel(azx_dev, SD_CBL, azx_dev->bufsize); - - /* program the stream format */ - /* this value needs to be the same as the one programmed */ - azx_sd_writew(azx_dev, SD_FORMAT, azx_dev->format_val); - - /* program the stream LVI (last valid index) of the BDL */ - azx_sd_writew(azx_dev, SD_LVI, azx_dev->frags - 1); - - /* program the BDL address */ - /* lower BDL address */ - azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl_addr); - /* upper BDL address */ - azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); - - /* enable the position buffer */ - if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); - - /* set the interrupt enable bits in the descriptor control register */ - azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); - - return 0; -} - - -/* - * Codec initialization - */ - -static unsigned int azx_max_codecs[] __devinitdata = { - [AZX_DRIVER_ICH] = 3, - [AZX_DRIVER_ATI] = 4, - [AZX_DRIVER_ATIHDMI] = 4, - [AZX_DRIVER_VIA] = 3, /* FIXME: correct? */ - [AZX_DRIVER_SIS] = 3, /* FIXME: correct? */ - [AZX_DRIVER_ULI] = 3, /* FIXME: correct? */ - [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */ -}; - -static int __devinit azx_codec_create(struct azx *chip, const char *model) -{ - struct hda_bus_template bus_temp; - int c, codecs, err; - - memset(&bus_temp, 0, sizeof(bus_temp)); - bus_temp.private_data = chip; - bus_temp.modelname = model; - bus_temp.pci = chip->pci; - bus_temp.ops.command = azx_send_cmd; - bus_temp.ops.get_response = azx_get_response; - bus_temp.ops.get_wallclock = azx_get_wallclock; - bus_temp.ops.get_linkpos = azx_get_linkpos; - - if ((err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus)) < 0) - return err; - - codecs = 0; - for (c = 0; c < AZX_MAX_CODECS; c++) { - if ((chip->codec_mask & (1 << c)) & probe_mask) { - err = snd_hda_codec_new(chip->bus, c, NULL); - if (err < 0) - continue; - codecs++; - } - } - if (!codecs) { - /* probe additional slots if no codec is found */ - for (; c < azx_max_codecs[chip->driver_type]; c++) { - if ((chip->codec_mask & (1 << c)) & probe_mask) { - err = snd_hda_codec_new(chip->bus, c, NULL); - if (err < 0) - continue; - codecs++; - } - } - } - if (!codecs) { - snd_printk(KERN_ERR SFX "no codecs initialized\n"); - return -ENXIO; - } - - return 0; -} - - -/* - * PCM support - */ - -/* assign a stream for the PCM */ -static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream) -{ - int dev, i, nums; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - dev = chip->playback_index_offset; - nums = chip->playback_streams; - } else { - dev = chip->capture_index_offset; - nums = chip->capture_streams; - } - for (i = 0; i < nums; i++, dev++) - if (! chip->azx_dev[dev].opened) { - chip->azx_dev[dev].opened = 1; - return &chip->azx_dev[dev]; - } - return NULL; -} - -/* release the assigned stream */ -static inline void azx_release_device(struct azx_dev *azx_dev) -{ -//printk(KERN_ERR"%s dev=%p\n", __FUNCTION__, azx_dev); - azx_dev->opened = 0; -} - -static struct snd_pcm_hardware azx_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - /* No full-resume yet implemented */ - /* SNDRV_PCM_INFO_RESUME |*/ - SNDRV_PCM_INFO_PAUSE), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = AZX_MAX_BUF_SIZE, - .period_bytes_min = 128, - .period_bytes_max = AZX_MAX_BUF_SIZE / 2, - .periods_min = 2, - .periods_max = AZX_MAX_FRAG, - .fifo_size = 0, -}; - -struct azx_pcm { - struct azx *chip; - struct hda_codec *codec; - struct hda_pcm_stream *hinfo[2]; -}; - -static int azx_pcm_open(struct snd_pcm_substream *substream) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; - struct azx *chip = apcm->chip; - struct azx_dev *azx_dev; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; - int err; - - mutex_lock(&chip->open_mutex); - azx_dev = azx_assign_device(chip, substream->stream); - if (azx_dev == NULL) { - mutex_unlock(&chip->open_mutex); - return -EBUSY; - } - runtime->hw = azx_pcm_hw; - runtime->hw.channels_min = hinfo->channels_min; - runtime->hw.channels_max = hinfo->channels_max; - runtime->hw.formats = hinfo->formats; - runtime->hw.rates = hinfo->rates; - snd_pcm_limit_hw_rates(runtime); - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - 128); - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - 128); - if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) { - azx_release_device(azx_dev); - mutex_unlock(&chip->open_mutex); - return err; - } - spin_lock_irqsave(&chip->reg_lock, flags); - azx_dev->substream = substream; - azx_dev->running = 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); - - runtime->private_data = azx_dev; - mutex_unlock(&chip->open_mutex); - return 0; -} - -static int azx_pcm_close(struct snd_pcm_substream *substream) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; - struct azx *chip = apcm->chip; - struct azx_dev *azx_dev = get_azx_dev(substream); - unsigned long flags; - - mutex_lock(&chip->open_mutex); - spin_lock_irqsave(&chip->reg_lock, flags); - azx_dev->substream = NULL; - azx_dev->running = 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); - azx_release_device(azx_dev); - hinfo->ops.close(hinfo, apcm->codec, substream); - mutex_unlock(&chip->open_mutex); - return 0; -} - -static int azx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) -{ - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); -} - -static int azx_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx_dev *azx_dev = get_azx_dev(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; - -//printk(KERN_DEBUG"%s: %p\n", __FUNCTION__, substream); - /* reset BDL address */ - azx_sd_writel(azx_dev, SD_BDLPL, 0); - azx_sd_writel(azx_dev, SD_BDLPU, 0); - azx_sd_writel(azx_dev, SD_CTL, 0); - - hinfo->ops.cleanup(hinfo, apcm->codec, substream); - - return snd_pcm_lib_free_pages(substream); -} - -static int azx_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - struct azx_dev *azx_dev = get_azx_dev(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; - struct snd_pcm_runtime *runtime = substream->runtime; - - azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream); - azx_dev->fragsize = snd_pcm_lib_period_bytes(substream); - azx_dev->frags = azx_dev->bufsize / azx_dev->fragsize; - azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate, - runtime->channels, - runtime->format, - hinfo->maxbps); - if (! azx_dev->format_val) { - snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n", - runtime->rate, runtime->channels, runtime->format); - return -EINVAL; - } - - snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, format=0x%x\n", - azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val); - azx_setup_periods(azx_dev); - azx_setup_controller(chip, azx_dev); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; - else - azx_dev->fifo_size = 0; - -// runtime->hw.fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE); - - return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag, - azx_dev->format_val, substream); -} - -static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx_dev *azx_dev = get_azx_dev(substream); - struct azx *chip = apcm->chip; - int err = 0; - - spin_lock(&chip->reg_lock); - switch (cmd) { - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_START: - azx_stream_start(chip, azx_dev); - azx_dev->running = 1; - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - azx_stream_stop(chip, azx_dev); - azx_dev->running = 0; - break; - default: - err = -EINVAL; - } - spin_unlock(&chip->reg_lock); - if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH || - cmd == SNDRV_PCM_TRIGGER_SUSPEND || - cmd == SNDRV_PCM_TRIGGER_STOP) { - int timeout = 5000; - while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout) - ; - } - return err; -} - -static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - struct azx_dev *azx_dev = get_azx_dev(substream); - unsigned int pos; - - if (chip->position_fix == POS_FIX_POSBUF || - chip->position_fix == POS_FIX_AUTO) { - /* use the position buffer */ - pos = le32_to_cpu(*azx_dev->posbuf); - if (chip->position_fix == POS_FIX_AUTO && - azx_dev->period_intr == 1 && ! pos) { - printk(KERN_WARNING - "hda-intel: Invalid position buffer, " - "using LPIB read method instead.\n"); - chip->position_fix = POS_FIX_NONE; - goto read_lpib; - } - } else { - read_lpib: - /* read LPIB */ - pos = azx_sd_readl(azx_dev, SD_LPIB); - if (chip->position_fix == POS_FIX_FIFO) - pos += azx_dev->fifo_size; - } - if (pos >= azx_dev->bufsize) - pos = 0; - return bytes_to_frames(substream->runtime, pos); -} - -static struct snd_pcm_ops azx_pcm_ops = { - .open = azx_pcm_open, - .close = azx_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = azx_pcm_hw_params, - .hw_free = azx_pcm_hw_free, - .prepare = azx_pcm_prepare, - .trigger = azx_pcm_trigger, - .pointer = azx_pcm_pointer, -}; - -static void azx_pcm_free(struct snd_pcm *pcm) -{ -//printk(KERN_DEBUG"%s: %p\n", __FUNCTION__, pcm); - kfree(pcm->private_data); -} - -static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, - struct hda_pcm *cpcm, int pcm_dev) -{ - int err; - struct snd_pcm *pcm; - struct azx_pcm *apcm; - - /* if no substreams are defined for both playback and capture, - * it's just a placeholder. ignore it. - */ - if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) - return 0; - - snd_assert(cpcm->name, return -EINVAL); - - err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, - cpcm->stream[0].substreams, cpcm->stream[1].substreams, - &pcm); - if (err < 0) - return err; - strcpy(pcm->name, cpcm->name); - apcm = kmalloc(sizeof(*apcm), GFP_KERNEL); - if (apcm == NULL) - return -ENOMEM; - apcm->chip = chip; - apcm->codec = codec; - apcm->hinfo[0] = &cpcm->stream[0]; - apcm->hinfo[1] = &cpcm->stream[1]; - pcm->private_data = apcm; - pcm->private_free = azx_pcm_free; - if (cpcm->stream[0].substreams) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops); - if (cpcm->stream[1].substreams) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - 1024 * 64, 1024 * 1024); - cpcm->pcm = pcm; - chip->pcm[pcm_dev] = pcm; - if (chip->pcm_devs < pcm_dev + 1) - chip->pcm_devs = pcm_dev + 1; - - return 0; -} - -static int __devinit azx_pcm_create(struct azx *chip) -{ - struct list_head *p; - struct hda_codec *codec; - int c, err; - int pcm_dev; - - if ((err = snd_hda_build_pcms(chip->bus)) < 0) - return err; - - /* create audio PCMs */ - pcm_dev = 0; - list_for_each(p, &chip->bus->codec_list) { - codec = list_entry(p, struct hda_codec, list); - for (c = 0; c < codec->num_pcms; c++) { - if (codec->pcm_info[c].is_modem) - continue; /* create later */ - if (pcm_dev >= AZX_MAX_AUDIO_PCMS) { - snd_printk(KERN_ERR SFX "Too many audio PCMs\n"); - return -EINVAL; - } - err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); - if (err < 0) - return err; - pcm_dev++; - } - } - - /* create modem PCMs */ - pcm_dev = AZX_MAX_AUDIO_PCMS; - list_for_each(p, &chip->bus->codec_list) { - codec = list_entry(p, struct hda_codec, list); - for (c = 0; c < codec->num_pcms; c++) { - if (! codec->pcm_info[c].is_modem) - continue; /* already created */ - if (pcm_dev >= AZX_MAX_PCMS) { - snd_printk(KERN_ERR SFX "Too many modem PCMs\n"); - return -EINVAL; - } - err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); - if (err < 0) - return err; - chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM; - pcm_dev++; - } - } - return 0; -} - -/* - * mixer creation - all stuff is implemented in hda module - */ -static int __devinit azx_mixer_create(struct azx *chip) -{ - return snd_hda_build_controls(chip->bus); -} - - -/* - * initialize SD streams - */ -static int __devinit azx_init_stream(struct azx *chip) -{ - int i; - - /* initialize each stream (aka device) - * assign the starting bdl address to each stream (device) and initialize - */ - for (i = 0; i < chip->num_streams; i++) { - unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4); - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_dev->bdl = (u32 *)(chip->bdl.area + off); - azx_dev->bdl_addr = chip->bdl.addr + off; - azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); - /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ - azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); - /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ - azx_dev->sd_int_sta_mask = 1 << i; - /* stream tag: must be non-zero and unique */ - azx_dev->index = i; - azx_dev->stream_tag = i + 1; - } - - return 0; -} - -static int azx_acquire_irq(struct azx *chip, int do_disconnect) -{ -#ifndef IRQF_SHARED -#define IRQF_SHARED SA_SHIRQ -#endif - - if (request_irq(chip->pci->irq, azx_interrupt, - chip->msi ? 0 : IRQF_SHARED, - "HDA Intel", chip)) { - printk(KERN_ERR "hda-intel: unable to grab IRQ %d, " - "disabling device\n", chip->pci->irq); - if (do_disconnect) - snd_card_disconnect(chip->card); - return -1; - } - chip->irq = chip->pci->irq; - pci_intx(chip->pci, !chip->msi); - return 0; -} - - -#ifdef CONFIG_PM -/* - * power management - */ -static int azx_suspend( -#ifndef SND_PCI_PM_CALLBACKS - struct pci_dev *pci, -#else - snd_card_t *card, -#endif - pm_message_t state) -{ -#ifndef SND_PCI_PM_CALLBACKS - struct snd_card *card = pci_get_drvdata(pci); - struct azx *chip = card->private_data; -#else - struct azx *chip = card->pm_private_data; - struct pci_dev *pci = chip->pci; -#endif - int i; - - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < chip->pcm_devs; i++) - snd_pcm_suspend_all(chip->pcm[i]); - snd_hda_suspend(chip->bus, state); - azx_free_cmd_io(chip); - if (chip->irq >= 0) { - synchronize_irq(chip->irq); - free_irq(chip->irq, chip); - chip->irq = -1; - } - if (chip->msi) - pci_disable_msi(chip->pci); - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, pci_choose_state(pci, state)); - return 0; -} - -static int azx_resume( -#ifndef SND_PCI_PM_CALLBACKS - struct pci_dev *pci -#else - snd_card_t *card -#endif - ) -{ -#ifndef SND_PCI_PM_CALLBACKS - struct snd_card *card = pci_get_drvdata(pci); - struct azx *chip = card->private_data; -#else - struct azx *chip = card->pm_private_data; - struct pci_dev *pci = chip->pci; -#endif - - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "hda-intel: pci_enable_device failed, " - "disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } - pci_set_master(pci); - if (chip->msi) - if (pci_enable_msi(pci) < 0) - chip->msi = 0; - if (azx_acquire_irq(chip, 1) < 0) - return -EIO; - azx_init_chip(chip); - snd_hda_resume(chip->bus); - snd_power_change_state(card, SNDRV_CTL_POWER_D0); - return 0; -} -#endif /* CONFIG_PM */ - - -/* - * destructor - */ -static int azx_free(struct azx *chip) -{ -//printk(KERN_ERR"%s: chip=%p\n", __FUNCTION__, chip); - if (chip->initialized) { - int i; - - for (i = 0; i < chip->num_streams; i++) - azx_stream_stop(chip, &chip->azx_dev[i]); - - /* disable interrupts */ - azx_int_disable(chip); - azx_int_clear(chip); - - /* disable CORB/RIRB */ - azx_free_cmd_io(chip); - - /* disable position buffer */ - azx_writel(chip, DPLBASE, 0); - azx_writel(chip, DPUBASE, 0); - } - - if (chip->irq >= 0) { - synchronize_irq(chip->irq); - free_irq(chip->irq, (void*)chip); - } - if (chip->msi) - pci_disable_msi(chip->pci); - if (chip->remap_addr) - iounmap(chip->remap_addr); - - if (chip->bdl.area) - snd_dma_free_pages(&chip->bdl); - if (chip->rb.area) - snd_dma_free_pages(&chip->rb); - if (chip->posbuf.area) - snd_dma_free_pages(&chip->posbuf); - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); - kfree(chip->azx_dev); - kfree(chip); - - return 0; -} - -static int azx_dev_free(struct snd_device *device) -{ -//printk(KERN_ERR"%s: device=%p\n", __FUNCTION__, device); - return azx_free(device->device_data); -} - -/* - * white/black-listing for position_fix - */ -static struct snd_pci_quirk position_fix_list[] __devinitdata = { - SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), - {} -}; - -static int __devinit check_position_fix(struct azx *chip, int fix) -{ - const struct snd_pci_quirk *q; - - if (fix == POS_FIX_AUTO) { - q = snd_pci_quirk_lookup(chip->pci, position_fix_list); - if (q) { - snd_printdd(KERN_INFO - "hda_intel: position_fix set to %d " - "for device %04x:%04x\n", - q->value, q->subvendor, q->subdevice); - return q->value; - } - } - return fix; -} - -/* - * constructor - */ -static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, - int driver_type, - struct azx **rchip) -{ - struct azx *chip; - int err; - static struct snd_device_ops ops = { - .dev_free = azx_dev_free, - }; - -//printk(KERN_ERR"%s: pci=%p card=%p\n", __FUNCTION__, pci, card); - *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->driver_type = driver_type; - chip->msi = enable_msi; - - chip->position_fix = check_position_fix(chip, position_fix); - - chip->single_cmd = single_cmd; - -#if BITS_PER_LONG != 64 - /* Fix up base address on ULI M5461 */ - if (chip->driver_type == AZX_DRIVER_ULI) { - u16 tmp3; - pci_read_config_word(pci, 0x40, &tmp3); - pci_write_config_word(pci, 0x40, tmp3 | 0x10); - pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, 0); - } -#endif - - err = pci_request_regions(pci, "ICH HD audio"); - if (err < 0) { - kfree(chip); - pci_disable_device(pci); - return err; - } - - chip->addr = pci_resource_start(pci, 0); - chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci,0)); - if (chip->remap_addr == NULL) { - snd_printk(KERN_ERR SFX "ioremap error\n"); - err = -ENXIO; - goto errout; - } - - if (chip->msi) - if (pci_enable_msi(pci) < 0) - chip->msi = 0; - - if (azx_acquire_irq(chip, 0) < 0) { - err = -EBUSY; - goto errout; - } - - pci_set_master(pci); - synchronize_irq(chip->irq); - - switch (chip->driver_type) { - case AZX_DRIVER_ULI: - chip->playback_streams = ULI_NUM_PLAYBACK; - chip->capture_streams = ULI_NUM_CAPTURE; - chip->playback_index_offset = ULI_PLAYBACK_INDEX; - chip->capture_index_offset = ULI_CAPTURE_INDEX; - break; - case AZX_DRIVER_ATIHDMI: - chip->playback_streams = ATIHDMI_NUM_PLAYBACK; - chip->capture_streams = ATIHDMI_NUM_CAPTURE; - chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX; - chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX; - break; - default: - chip->playback_streams = ICH6_NUM_PLAYBACK; - chip->capture_streams = ICH6_NUM_CAPTURE; - chip->playback_index_offset = ICH6_PLAYBACK_INDEX; - chip->capture_index_offset = ICH6_CAPTURE_INDEX; - break; - } - chip->num_streams = chip->playback_streams + chip->capture_streams; - chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); - if (!chip->azx_dev) { - snd_printk(KERN_ERR "cannot malloc azx_dev\n"); - goto errout; - } - - /* allocate memory for the BDL for each stream */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - BDL_SIZE, &chip->bdl)) < 0) { - snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); - goto errout; - } - /* allocate memory for the position buffer */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - chip->num_streams * 8, &chip->posbuf)) < 0) { - snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); - goto errout; - } - /* allocate CORB/RIRB */ - if (! chip->single_cmd) - if ((err = azx_alloc_cmd_io(chip)) < 0) - goto errout; - - /* initialize streams */ - azx_init_stream(chip); - - /* initialize chip */ - azx_init_chip(chip); - - chip->initialized = 1; - - /* codec detection */ - if (!chip->codec_mask) { - snd_printk(KERN_ERR SFX "no codecs found!\n"); - err = -ENODEV; - goto errout; - } - - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) <0) { - snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); - goto errout; - } - - strcpy(card->driver, "HDA-Intel"); - strcpy(card->shortname, driver_short_names[chip->driver_type]); - sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq); - - *rchip = chip; - return 0; - - errout: - azx_free(chip); - return err; -} - -static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) -{ - struct snd_card *card; - struct azx *chip; - int err; - - card = snd_card_new(index, id, THIS_MODULE, 0); - if (!card) { - snd_printk(KERN_ERR SFX "Error creating card!\n"); - return -ENOMEM; - } - - err = azx_create(card, pci, pci_id->driver_data, &chip); - if (err < 0) { - snd_card_free(card); - return err; - } - card->private_data = chip; - -#ifndef SND_PCI_PM_CALLBACKS - card->private_data = chip; -#endif - - /* create codec instances */ - if ((err = azx_codec_create(chip, model)) < 0) { - snd_card_free(card); - return err; - } - - /* create PCM streams */ - if ((err = azx_pcm_create(chip)) < 0) { - snd_card_free(card); - return err; - } - - /* create mixer controls */ - if ((err = azx_mixer_create(chip)) < 0) { - snd_card_free(card); - return err; - } - -#ifdef SND_PCI_PM_CALLBACKS - snd_card_set_pm_callback(card, azx_suspend, azx_resume, chip); -#endif - snd_card_set_dev(card, &pci->dev); - - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } - - pci_set_drvdata(pci, card); - - return err; -} - -static void __devexit azx_remove(struct pci_dev *pci) -{ - snd_card_t *card = pci_get_drvdata(pci); -#ifndef SND_PCI_PM_CALLBACKS - struct azx *chip = card->private_data; -#else - struct azx *chip = card->pm_private_data; -#endif - -//printk(KERN_ERR"%s: pci=%p card=%p\n", __FUNCTION__, pci, pci_get_drvdata(pci)); - snd_hda_codec_remove_notify_all(chip->bus); - snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); -} - -/* PCI IDs */ -static struct pci_device_id azx_ids[] = { - { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH6 */ - { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */ - { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */ - { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ - { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ - { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ - { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ - { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ - { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */ - { 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */ - { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */ - { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */ - { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ - { 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP51 */ - { 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP55 */ - { 0x10de, 0x03e4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP61 */ - { 0x10de, 0x03f0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP61 */ - { 0x10de, 0x044a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */ - { 0x10de, 0x044b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */ - { 0x10de, 0x055c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */ - { 0x10de, 0x055d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */ - { 0, } -}; -MODULE_DEVICE_TABLE(pci, azx_ids); - -/* pci_driver definition */ -static struct pci_driver driver = { - .name = "HDA Intel", - .id_table = azx_ids, - .probe = azx_probe, - .remove = __devexit_p(azx_remove), -#ifdef SND_PCI_PM_CALLBACKS - SND_PCI_PM_CALLBACKS -#else -#ifdef CONFIG_PM - .suspend = azx_suspend, - .resume = azx_resume, -#endif -#endif -}; - -static int __init alsa_card_azx_init(void) -{ - return pci_register_driver(&driver); -} - -static void __exit alsa_card_azx_exit(void) -{ -//printk(KERN_ERR"%s\n", __FUNCTION__); - pci_unregister_driver(&driver); -} - -module_init(alsa_card_azx_init) -module_exit(alsa_card_azx_exit) diff --git a/modules/GPL/hda/hda_local.h b/modules/GPL/hda/hda_local.h deleted file mode 100644 index 939b71a..0000000 --- a/modules/GPL/hda/hda_local.h +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * Local helper functions - * - * Copyright (c) 2004 Takashi Iwai - * - * 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 __SOUND_HDA_LOCAL_H -#define __SOUND_HDA_LOCAL_H - -#ifndef _SND_PCI_QUIRK_ID - -/* PCI quirk list helper */ -struct snd_pci_quirk { - unsigned short subvendor; /* PCI subvendor ID */ - unsigned short subdevice; /* PCI subdevice ID */ - int value; /* value */ -#ifdef CONFIG_SND_DEBUG_DETECT - const char *name; /* name of the device (optional) */ -#endif -}; - -#define _SND_PCI_QUIRK_ID(vend,dev) \ - .subvendor = (vend), .subdevice = (dev) -#define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)} -#ifdef CONFIG_SND_DEBUG_DETECT -#define SND_PCI_QUIRK(vend,dev,xname,val) \ - {_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)} -#else -#define SND_PCI_QUIRK(vend,dev,xname,val) \ - {_SND_PCI_QUIRK_ID(vend, dev), .value = (val)} -#endif - -//const struct snd_pci_quirk * -//snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list); - -#ifdef CONFIG_PCI -#include -/** - * snd_pci_quirk_lookup - look up a PCI SSID quirk list - * @pci: pci_dev handle - * @list: quirk list, terminated by a null entry - * - * Look through the given quirk list and finds a matching entry - * with the same PCI SSID. When subdevice is 0, all subdevice - * values may match. - * - * Returns the matched entry pointer, or NULL if nothing matched. - */ -static inline const struct snd_pci_quirk * -snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) -{ - const struct snd_pci_quirk *q; - - for (q = list; q->subvendor; q++) - if (q->subvendor == pci->subsystem_vendor && - (!q->subdevice || q->subdevice == pci->subsystem_device)) - return q; - return NULL; -} - -//EXPORT_SYMBOL(snd_pci_quirk_lookup); -#endif - -#endif /* _SND_PCI_QUIRK_ID */ - -/* - * for mixer controls - */ -#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) -/* mono volume with index (index=0,1,...) (channel=1,2) */ -#ifdef FOUND_TLV -#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ - .info = snd_hda_mixer_amp_volume_info, \ - .get = snd_hda_mixer_amp_volume_get, \ - .put = snd_hda_mixer_amp_volume_put, \ - .tlv = { .c = snd_hda_mixer_amp_tlv }, \ - .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } -#else -#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .info = snd_hda_mixer_amp_volume_info, \ - .get = snd_hda_mixer_amp_volume_get, \ - .put = snd_hda_mixer_amp_volume_put, \ - .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } -#endif -/* stereo volume with index */ -#define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \ - HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction) -/* mono volume */ -#define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \ - HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction) -/* stereo volume */ -#define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \ - HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction) -/* mono mute switch with index (index=0,1,...) (channel=1,2) */ -#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .info = snd_hda_mixer_amp_switch_info, \ - .get = snd_hda_mixer_amp_switch_get, \ - .put = snd_hda_mixer_amp_switch_put, \ - .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } -/* stereo mute switch with index */ -#define HDA_CODEC_MUTE_IDX(xname, xcidx, nid, xindex, direction) \ - HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, 3, xindex, direction) -/* mono mute switch */ -#define HDA_CODEC_MUTE_MONO(xname, nid, channel, xindex, direction) \ - HDA_CODEC_MUTE_MONO_IDX(xname, 0, nid, channel, xindex, direction) -/* stereo mute switch */ -#define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ - HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) - -int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -#ifdef FOUND_TLV -int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv); -#endif -int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -/* lowlevel accessor with caching; use carefully */ -int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, - int direction, int index); -int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, - int direction, int idx, int mask, int val); - -/* mono switch binding multiple inputs */ -#define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = snd_hda_mixer_amp_switch_info, \ - .get = snd_hda_mixer_bind_switch_get, \ - .put = snd_hda_mixer_bind_switch_put, \ - .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } - -/* stereo switch binding multiple inputs */ -#define HDA_BIND_MUTE(xname,nid,indices,dir) HDA_BIND_MUTE_MONO(xname,nid,3,indices,dir) - -int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); - -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); -int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); - -/* - * input MUX helper - */ -#define HDA_MAX_NUM_INPUTS 16 -struct hda_input_mux_item { - const char *label; - unsigned int index; -}; -struct hda_input_mux { - unsigned int num_items; - struct hda_input_mux_item items[HDA_MAX_NUM_INPUTS]; -}; - -int snd_hda_input_mux_info(const struct hda_input_mux *imux, struct snd_ctl_elem_info *uinfo); -int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, - struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, - unsigned int *cur_val); - -/* - * Channel mode helper - */ -struct hda_channel_mode { - int channels; - const struct hda_verb *sequence; -}; - -int snd_hda_ch_mode_info(struct hda_codec *codec, struct snd_ctl_elem_info *uinfo, - const struct hda_channel_mode *chmode, int num_chmodes); -int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, int num_chmodes, - int max_channels); -int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, int num_chmodes, - int *max_channelsp); - -/* - * Multi-channel / digital-out PCM helper - */ - -enum { HDA_FRONT, HDA_REAR, HDA_CLFE, HDA_SIDE }; /* index for dac_nidx */ -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 */ - 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 */ - int max_channels; /* currently supported analog channels */ - int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ -}; - -int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout); -int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout); -int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, - struct hda_multi_out *mout, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, - struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout); - -/* - * generic codec parser - */ -int snd_hda_parse_generic_codec(struct hda_codec *codec); - -/* - * generic proc interface - */ -#ifdef CONFIG_PROC_FS -int snd_hda_codec_proc_new(struct hda_codec *codec); -#else -static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } -#endif - -/* - * Misc - */ -int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, - const char **modelnames, - const struct snd_pci_quirk *pci_list); -int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); - -/* - * power management - */ -#ifdef CONFIG_PM -int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); -int snd_hda_resume_spdif_out(struct hda_codec *codec); -int snd_hda_resume_spdif_in(struct hda_codec *codec); -#endif - -/* - * unsolicited event handler - */ - -#define HDA_UNSOL_QUEUE_SIZE 64 - -struct hda_bus_unsolicited { - /* ring buffer */ - u32 queue[HDA_UNSOL_QUEUE_SIZE * 2]; - unsigned int rp, wp; - - /* workqueue */ - struct work_struct work; -#ifdef FOUND_DELAYED_WORK - struct hda_bus *bus; -#endif -}; - -/* - * Helper for automatic ping configuration - */ - -enum { - AUTO_PIN_MIC, - AUTO_PIN_FRONT_MIC, - AUTO_PIN_LINE, - AUTO_PIN_FRONT_LINE, - AUTO_PIN_CD, - AUTO_PIN_AUX, - AUTO_PIN_LAST -}; - -extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST]; - -struct auto_pin_cfg { - int line_outs; - hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ - int speaker_outs; - hda_nid_t speaker_pins[5]; - int hp_outs; - hda_nid_t hp_pins[5]; - hda_nid_t input_pins[AUTO_PIN_LAST]; - hda_nid_t dig_out_pin; - hda_nid_t dig_in_pin; -}; - -#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) -#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) -#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) -#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) -#define get_defcfg_device(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) - -int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg, - hda_nid_t *ignore_nids); - -/* amp values */ -#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) -#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) -#define AMP_OUT_MUTE 0xb080 -#define AMP_OUT_UNMUTE 0xb000 -#define AMP_OUT_ZERO 0xb000 -/* pinctl values */ -#define PIN_IN 0x20 -#define PIN_VREF80 0x24 -#define PIN_VREF50 0x21 -#define PIN_OUT 0x40 -#define PIN_HP 0xc0 -#define PIN_HP_AMP 0x80 - -/* - * get widget capabilities - */ -static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) -{ - if (nid < codec->start_nid || - nid >= codec->start_nid + codec->num_nodes) - return snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); - return codec->wcaps[nid - codec->start_nid]; -} - -int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, - unsigned int caps); - - -#endif /* __SOUND_HDA_LOCAL_H */ diff --git a/modules/GPL/hda/hda_patch.h b/modules/GPL/hda/hda_patch.h deleted file mode 100644 index 9f9e9ae..0000000 --- a/modules/GPL/hda/hda_patch.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * HDA Patches - included by hda_codec.c - */ - -/* Realtek codecs */ -extern struct hda_codec_preset snd_hda_preset_realtek[]; -/* C-Media codecs */ -extern struct hda_codec_preset snd_hda_preset_cmedia[]; -/* Analog Devices codecs */ -extern struct hda_codec_preset snd_hda_preset_analog[]; -/* SigmaTel codecs */ -extern struct hda_codec_preset snd_hda_preset_sigmatel[]; -/* SiLabs 3054/3055 modem codecs */ -extern struct hda_codec_preset snd_hda_preset_si3054[]; -/* ATI HDMI codecs */ -extern struct hda_codec_preset snd_hda_preset_atihdmi[]; -/* Conexant audio codec */ -extern struct hda_codec_preset snd_hda_preset_conexant[]; -/* VIA codecs */ -extern struct hda_codec_preset snd_hda_preset_via[]; - -static const struct hda_codec_preset *hda_preset_tables[] = { - snd_hda_preset_realtek, - snd_hda_preset_cmedia, - snd_hda_preset_analog, - snd_hda_preset_sigmatel, - snd_hda_preset_si3054, - snd_hda_preset_atihdmi, - snd_hda_preset_conexant, - snd_hda_preset_via, - NULL -}; diff --git a/modules/GPL/hda/hda_proc.c b/modules/GPL/hda/hda_proc.c deleted file mode 100644 index dcd6567..0000000 --- a/modules/GPL/hda/hda_proc.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * Generic proc interface - * - * Copyright (c) 2004 Takashi Iwai - * - * - * This driver 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 driver 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 -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -static const char *get_wid_type_name(unsigned int wid_value) -{ - static char *names[16] = { - [AC_WID_AUD_OUT] = "Audio Output", - [AC_WID_AUD_IN] = "Audio Input", - [AC_WID_AUD_MIX] = "Audio Mixer", - [AC_WID_AUD_SEL] = "Audio Selector", - [AC_WID_PIN] = "Pin Complex", - [AC_WID_POWER] = "Power Widget", - [AC_WID_VOL_KNB] = "Volume Knob Widget", - [AC_WID_BEEP] = "Beep Generator Widget", - [AC_WID_VENDOR] = "Vendor Defined Widget", - }; - wid_value &= 0xf; - if (names[wid_value]) - return names[wid_value]; - else - return "UNKNOWN Widget"; -} - -static void print_amp_caps(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid, int dir) -{ - unsigned int caps; - caps = snd_hda_param_read(codec, nid, - dir == HDA_OUTPUT ? - AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); - if (caps == -1 || caps == 0) { - snd_iprintf(buffer, "N/A\n"); - return; - } - snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, mute=%x\n", - caps & AC_AMPCAP_OFFSET, - (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT, - (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT, - (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT); -} - -static void print_amp_vals(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid, - int dir, int stereo, int indices) -{ - unsigned int val; - int i; - - dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; - for (i = 0; i < indices; i++) { - snd_iprintf(buffer, " ["); - if (stereo) { - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_LEFT | dir | i); - snd_iprintf(buffer, "0x%02x ", val); - } - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_RIGHT | dir | i); - snd_iprintf(buffer, "0x%02x]", val); - } - snd_iprintf(buffer, "\n"); -} - -static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) -{ - static unsigned int rates[] = { - 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, - 96000, 176400, 192000, 384000 - }; - int i; - - pcm &= AC_SUPPCM_RATES; - snd_iprintf(buffer, " rates [0x%x]:", pcm); - for (i = 0; i < ARRAY_SIZE(rates); i++) - if (pcm & (1 << i)) - snd_iprintf(buffer, " %d", rates[i]); - snd_iprintf(buffer, "\n"); -} - -static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) -{ - static unsigned int bits[] = { 8, 16, 20, 24, 32 }; - int i; - - pcm = (pcm >> 16) & 0xff; - snd_iprintf(buffer, " bits [0x%x]:", pcm); - for (i = 0; i < ARRAY_SIZE(bits); i++) - if (pcm & (1 << i)) - snd_iprintf(buffer, " %d", bits[i]); - snd_iprintf(buffer, "\n"); -} - -static void print_pcm_formats(struct snd_info_buffer *buffer, - unsigned int streams) -{ - snd_iprintf(buffer, " formats [0x%x]:", streams & 0xf); - if (streams & AC_SUPFMT_PCM) - snd_iprintf(buffer, " PCM"); - if (streams & AC_SUPFMT_FLOAT32) - snd_iprintf(buffer, " FLOAT"); - if (streams & AC_SUPFMT_AC3) - snd_iprintf(buffer, " AC3"); - snd_iprintf(buffer, "\n"); -} - -static void print_pcm_caps(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int pcm = snd_hda_param_read(codec, nid, AC_PAR_PCM); - unsigned int stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); - if (pcm == -1 || stream == -1) { - snd_iprintf(buffer, "N/A\n"); - return; - } - print_pcm_rates(buffer, pcm); - print_pcm_bits(buffer, pcm); - print_pcm_formats(buffer, stream); -} - -static const char *get_jack_location(u32 cfg) -{ - static char *bases[7] = { - "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", - }; - static unsigned char specials_idx[] = { - 0x07, 0x08, - 0x17, 0x18, 0x19, - 0x37, 0x38 - }; - static char *specials[] = { - "Rear Panel", "Drive Bar", - "Riser", "HDMI", "ATAPI", - "Mobile-In", "Mobile-Out" - }; - int i; - cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; - if ((cfg & 0x0f) < 7) - return bases[cfg & 0x0f]; - for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { - if (cfg == specials_idx[i]) - return specials[i]; - } - return "UNKNOWN"; -} - -static const char *get_jack_connection(u32 cfg) -{ - static char *names[16] = { - "Unknown", "1/8", "1/4", "ATAPI", - "RCA", "Optical","Digital", "Analog", - "DIN", "XLR", "RJ11", "Comb", - NULL, NULL, NULL, "Other" - }; - cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT; - if (names[cfg]) - return names[cfg]; - else - return "UNKNOWN"; -} - -static const char *get_jack_color(u32 cfg) -{ - static char *names[16] = { - "Unknown", "Black", "Grey", "Blue", - "Green", "Red", "Orange", "Yellow", - "Purple", "Pink", NULL, NULL, - NULL, NULL, "White", "Other", - }; - cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT; - if (names[cfg]) - return names[cfg]; - else - return "UNKNOWN"; -} - -static void print_pin_caps(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid) -{ - static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; - static char *jack_types[16] = { - "Line Out", "Speaker", "HP Out", "CD", - "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", - "Line In", "Aux", "Mic", "Telephony", - "SPDIF In", "Digitial In", "Reserved", "Other" - }; - static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; - unsigned int caps; - - caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); - snd_iprintf(buffer, " Pincap 0x08%x:", caps); - if (caps & AC_PINCAP_IN) - snd_iprintf(buffer, " IN"); - if (caps & AC_PINCAP_OUT) - snd_iprintf(buffer, " OUT"); - if (caps & AC_PINCAP_HP_DRV) - snd_iprintf(buffer, " HP"); - if (caps & AC_PINCAP_EAPD) - snd_iprintf(buffer, " EAPD"); - if (caps & AC_PINCAP_PRES_DETECT) - snd_iprintf(buffer, " Detect"); - snd_iprintf(buffer, "\n"); - caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, - jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], - jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], - jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], - get_jack_location(caps)); - snd_iprintf(buffer, " Conn = %s, Color = %s\n", - get_jack_connection(caps), - get_jack_color(caps)); -} - - -static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) -{ - struct hda_codec *codec = entry->private_data; - char buf[32]; - hda_nid_t nid; - int i, nodes; - - snd_hda_get_codec_name(codec, buf, sizeof(buf)); - snd_iprintf(buffer, "Codec: %s\n", buf); - snd_iprintf(buffer, "Address: %d\n", codec->addr); - snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id); - snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id); - snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id); - if (! codec->afg) - return; - snd_iprintf(buffer, "Default PCM:\n"); - print_pcm_caps(buffer, codec, codec->afg); - snd_iprintf(buffer, "Default Amp-In caps: "); - print_amp_caps(buffer, codec, codec->afg, HDA_INPUT); - snd_iprintf(buffer, "Default Amp-Out caps: "); - print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT); - - nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); - if (! nid || nodes < 0) { - snd_iprintf(buffer, "Invalid AFG subtree\n"); - return; - } - for (i = 0; i < nodes; i++, nid++) { - unsigned int wid_caps = snd_hda_param_read(codec, nid, - AC_PAR_AUDIO_WIDGET_CAP); - unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - int conn_len = 0; - hda_nid_t conn[HDA_MAX_CONNECTIONS]; - - snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, - get_wid_type_name(wid_type), wid_caps); - if (wid_caps & AC_WCAP_STEREO) - snd_iprintf(buffer, " Stereo"); - else - snd_iprintf(buffer, " Mono"); - if (wid_caps & AC_WCAP_DIGITAL) - snd_iprintf(buffer, " Digital"); - if (wid_caps & AC_WCAP_IN_AMP) - snd_iprintf(buffer, " Amp-In"); - if (wid_caps & AC_WCAP_OUT_AMP) - snd_iprintf(buffer, " Amp-Out"); - snd_iprintf(buffer, "\n"); - - if (wid_caps & AC_WCAP_CONN_LIST) - conn_len = snd_hda_get_connections(codec, nid, conn, - HDA_MAX_CONNECTIONS); - - if (wid_caps & AC_WCAP_IN_AMP) { - snd_iprintf(buffer, " Amp-In caps: "); - print_amp_caps(buffer, codec, nid, HDA_INPUT); - snd_iprintf(buffer, " Amp-In vals: "); - print_amp_vals(buffer, codec, nid, HDA_INPUT, - wid_caps & AC_WCAP_STEREO, conn_len); - } - if (wid_caps & AC_WCAP_OUT_AMP) { - snd_iprintf(buffer, " Amp-Out caps: "); - print_amp_caps(buffer, codec, nid, HDA_OUTPUT); - snd_iprintf(buffer, " Amp-Out vals: "); - print_amp_vals(buffer, codec, nid, HDA_OUTPUT, - wid_caps & AC_WCAP_STEREO, 1); - } - - if (wid_type == AC_WID_PIN) { - unsigned int pinctls; - print_pin_caps(buffer, codec, nid); - pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls); - if (pinctls & AC_PINCTL_IN_EN) - snd_iprintf(buffer, " IN"); - if (pinctls & AC_PINCTL_OUT_EN) - snd_iprintf(buffer, " OUT"); - if (pinctls & AC_PINCTL_HP_EN) - snd_iprintf(buffer, " HP"); - snd_iprintf(buffer, "\n"); - } - - if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) && - (wid_caps & AC_WCAP_FORMAT_OVRD)) { - snd_iprintf(buffer, " PCM:\n"); - print_pcm_caps(buffer, codec, nid); - } - - if (wid_caps & AC_WCAP_POWER) - snd_iprintf(buffer, " Power: 0x%x\n", - snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_POWER_STATE, 0)); - - if (wid_caps & AC_WCAP_CONN_LIST) { - int c, curr = -1; - if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) - curr = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONNECT_SEL, 0); - snd_iprintf(buffer, " Connection: %d\n", conn_len); - snd_iprintf(buffer, " "); - for (c = 0; c < conn_len; c++) { - snd_iprintf(buffer, " 0x%02x", conn[c]); - if (c == curr) - snd_iprintf(buffer, "*"); - } - snd_iprintf(buffer, "\n"); - } - } -} - -/* - * create a proc read - */ -int snd_hda_codec_proc_new(struct hda_codec *codec) -{ - char name[32]; - struct snd_info_entry *entry; - int err; - - snprintf(name, sizeof(name), "codec#%d", codec->addr); - err = snd_card_proc_new(codec->bus->card, name, &entry); - if (err < 0) - return err; - -#ifndef FOUND_READ_SIZE - snd_info_set_text_ops(entry, codec, print_codec_info); -#else - snd_info_set_text_ops(entry, codec, 32 * 1024, print_codec_info); -#endif - return 0; -} - diff --git a/modules/GPL/hda/patch_analog.c b/modules/GPL/hda/patch_analog.c deleted file mode 100644 index 93b454f..0000000 --- a/modules/GPL/hda/patch_analog.c +++ /dev/null @@ -1,3140 +0,0 @@ -/* - * HD audio interface patch for AD1884, AD1981HD, AD1983, AD1984, AD1986A, - * AD1988 - * - * Copyright (c) 2005 Takashi Iwai - * - * This driver 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 driver 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 -#include -#include -#include -#include -#include -#include - -#include -#include "hda_codec.h" -#include "hda_local.h" - -struct ad198x_spec { - struct snd_kcontrol_new *mixers[5]; - int num_mixers; - - const struct hda_verb *init_verbs[5]; /* initialization verbs - * don't forget NULL termination! - */ - unsigned int num_init_verbs; - - /* playback */ - struct hda_multi_out multiout; /* playback set-up - * max_channels, dacs must be set - * dig_out_nid and hp_nid are optional - */ - unsigned int cur_eapd; - unsigned int need_dac_fix; - - /* capture */ - unsigned int num_adc_nids; - 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; - unsigned int cur_mux[3]; - - /* channel model */ - const struct hda_channel_mode *channel_mode; - int num_channel_mode; - - /* PCM information */ - struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ - - struct mutex amp_mutex; /* PCM volume/mute control mutex */ - unsigned int spdif_route; - - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; - struct hda_input_mux private_imux; - hda_nid_t private_dac_nids[4]; -}; - -/* - * input MUX handling (common part) - */ -static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->capsrc_nids[adc_idx], - &spec->cur_mux[adc_idx]); -} - -/* - * initialization (common callbacks) - */ -static int ad198x_init(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); - return 0; -} - -static int ad198x_build_controls(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - unsigned int i; - int err; - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); - if (err < 0) - return err; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - return 0; -} - -/* - * Analog playback callbacks - */ -static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); -} - -static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int ad198x_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 ad198x_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - 0, 0, 0); - return 0; -} - - -/* - */ -static struct hda_pcm_stream ad198x_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 6, /* changed later */ - .nid = 0, /* fill later */ - .ops = { - .open = ad198x_playback_pcm_open, - .prepare = ad198x_playback_pcm_prepare, - .cleanup = ad198x_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ad198x_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = ad198x_capture_pcm_prepare, - .cleanup = ad198x_capture_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ad198x_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = ad198x_dig_playback_pcm_open, - .close = ad198x_dig_playback_pcm_close, - .prepare = ad198x_dig_playback_pcm_prepare - }, -}; - -static struct hda_pcm_stream ad198x_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static int ad198x_build_pcms(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "AD198x Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_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) { - info++; - codec->num_pcms++; - info->name = "AD198x Digital"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - } - - return 0; -} - -static void ad198x_free(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - unsigned int i; - - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } - kfree(codec->spec); -} - -#ifdef CONFIG_PM -static int ad198x_resume(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int i; - - codec->patch_ops.init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - return 0; -} -#endif - -static struct hda_codec_ops ad198x_patch_ops = { - .build_controls = ad198x_build_controls, - .build_pcms = ad198x_build_pcms, - .init = ad198x_init, - .free = ad198x_free, -#ifdef CONFIG_PM - .resume = ad198x_resume, -#endif -}; - - -/* - * EAPD control - * the private value = nid | (invert << 8) - */ -static int ad198x_eapd_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; - if (invert) - ucontrol->value.integer.value[0] = ! spec->cur_eapd; - else - ucontrol->value.integer.value[0] = spec->cur_eapd; - return 0; -} - -static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; - hda_nid_t nid = kcontrol->private_value & 0xff; - unsigned int eapd; - eapd = ucontrol->value.integer.value[0]; - if (invert) - eapd = !eapd; - if (eapd == spec->cur_eapd && ! codec->in_resume) - return 0; - spec->cur_eapd = eapd; - snd_hda_codec_write(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); - return 1; -} - -static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo); -static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - - -/* - * AD1986A specific - */ - -#define AD1986A_SPDIF_OUT 0x02 -#define AD1986A_FRONT_DAC 0x03 -#define AD1986A_SURR_DAC 0x04 -#define AD1986A_CLFE_DAC 0x05 -#define AD1986A_ADC 0x06 - -static 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 struct hda_input_mux ad1986a_capture_source = { - .num_items = 7, - .items = { - { "Mic", 0x0 }, - { "CD", 0x1 }, - { "Aux", 0x3 }, - { "Line", 0x4 }, - { "Mix", 0x5 }, - { "Mono", 0x6 }, - { "Phone", 0x7 }, - }, -}; - -/* - * PCM control - * - * bind volumes/mutes of 3 DACs as a single PCM control for simplicity - */ - -#define ad1986a_pcm_amp_vol_info snd_hda_mixer_amp_volume_info - -static int ad1986a_pcm_amp_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - - mutex_lock(&ad->amp_mutex); - snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); - mutex_unlock(&ad->amp_mutex); - return 0; -} - -static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - int i, change = 0; - - mutex_lock(&ad->amp_mutex); - for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); - change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); - } - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); - mutex_unlock(&ad->amp_mutex); - return change; -} - -#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info - -static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - - mutex_lock(&ad->amp_mutex); - snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); - mutex_unlock(&ad->amp_mutex); - return 0; -} - -static int ad1986a_pcm_amp_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - int i, change = 0; - - mutex_lock(&ad->amp_mutex); - for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); - change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - } - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); - mutex_unlock(&ad->amp_mutex); - return change; -} - -/* - * mixers - */ -static struct snd_kcontrol_new ad1986a_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE -#ifdef FOUND_TLV - | SNDRV_CTL_ELEM_ACCESS_TLV_READ - | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK -#endif - , - .info = ad1986a_pcm_amp_vol_info, - .get = ad1986a_pcm_amp_vol_get, - .put = ad1986a_pcm_amp_vol_put, -#ifdef FOUND_TLV - .tlv = { .c = snd_hda_mixer_amp_tlv }, -#endif - .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", - .info = ad1986a_pcm_amp_sw_info, - .get = ad1986a_pcm_amp_sw_get, - .put = ad1986a_pcm_amp_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) - }, - HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -/* additional mixers for 3stack mode */ -static struct snd_kcontrol_new ad1986a_3st_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = ad198x_ch_mode_info, - .get = ad198x_ch_mode_get, - .put = ad198x_ch_mode_put, - }, - { } /* end */ -}; - -/* laptop model - 2ch only */ -static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; - -static 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_CODEC_VOLUME("Master Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), - /* HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -/* laptop-eapd model - 2ch only */ - -/* master controls both pins 0x1a and 0x1b */ -static int ad1986a_laptop_master_vol_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 = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} - -static int ad1986a_laptop_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 = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); - change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); - return change; -} - -static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x4 }, - { "Mix", 0x5 }, - }, -}; - -static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = ad1986a_laptop_master_vol_put, -#ifdef FOUND_TLV - .tlv = { .c = snd_hda_mixer_amp_tlv }, -#endif - .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = ad1986a_laptop_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "External Amplifier", - .info = ad198x_eapd_info, - .get = ad198x_eapd_get, - .put = ad198x_eapd_put, - .private_value = 0x1b | (1 << 8), /* port-D, inversed */ - }, - { } /* end */ -}; - -/* - * initialization verbs - */ -static 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}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Downmix - off */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* HP, Line-Out, Surround, CLFE selectors */ - {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mono selector */ - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic selector: Mic 1/2 pin */ - {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Line-in selector: Line-in */ - {0x10, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic 1/2 swap */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Record selector: mic */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic, Phone, CD, Aux, Line-In amp; mute as default */ - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* PC beep */ - {0x18, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* HP Pin */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* Front, Surround, CLFE Pins */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Mono Pin */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Mic Pin */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* Line, Aux, CD, Beep-In Pin */ - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - { } /* end */ -}; - -/* additional verbs for 3-stack model */ -static struct hda_verb ad1986a_3st_init_verbs[] = { - /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */ - {0x0f, AC_VERB_SET_CONNECT_SEL, 0x4}, - /* Line-in selectors */ - {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, - { } /* end */ -}; - -static struct hda_verb ad1986a_ch2_init[] = { - /* Surround out -> Line In */ - { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - { 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* CLFE -> Mic in */ - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - { } /* end */ -}; - -static struct hda_verb ad1986a_ch4_init[] = { - /* Surround out -> Surround */ - { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* CLFE -> Mic in */ - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - { } /* end */ -}; - -static struct hda_verb ad1986a_ch6_init[] = { - /* Surround out -> Surround out */ - { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* CLFE -> CLFE */ - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - { } /* end */ -}; - -static 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[] = { - {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, - {} -}; - -/* Ultra initialization */ -static struct hda_verb ad1986a_ultra_init[] = { - /* eapd initialization */ - { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, - /* CLFE -> Mic in */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 }, - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - { } /* end */ -}; - -/* models */ -enum { - AD1986A_6STACK, - AD1986A_3STACK, - AD1986A_LAPTOP, - AD1986A_LAPTOP_EAPD, - AD1986A_ULTRA, - AD1986A_MODELS -}; - -static const char *ad1986a_models[AD1986A_MODELS] = { - [AD1986A_6STACK] = "6stack", - [AD1986A_3STACK] = "3stack", - [AD1986A_LAPTOP] = "laptop", - [AD1986A_LAPTOP_EAPD] = "laptop-eapd", - [AD1986A_ULTRA] = "ultra", -}; - -static struct snd_pci_quirk ad1986a_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), - SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), - SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), - SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), - SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), - SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), - SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), - SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), - SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), - SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), - {} -}; - -static int patch_ad1986a(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - mutex_init(&spec->amp_mutex); - codec->spec = spec; - - spec->multiout.max_channels = 6; - spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); - spec->multiout.dac_nids = ad1986a_dac_nids; - spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = ad1986a_adc_nids; - spec->capsrc_nids = ad1986a_capsrc_nids; - spec->input_mux = &ad1986a_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1986a_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1986a_init_verbs; - - codec->patch_ops = ad198x_patch_ops; - - /* override some parameters */ - board_config = snd_hda_check_board_config(codec, AD1986A_MODELS, - ad1986a_models, - ad1986a_cfg_tbl); - switch (board_config) { - case AD1986A_3STACK: - spec->num_mixers = 2; - spec->mixers[1] = ad1986a_3st_mixers; - spec->num_init_verbs = 3; - spec->init_verbs[1] = ad1986a_3st_init_verbs; - spec->init_verbs[2] = ad1986a_ch2_init; - spec->channel_mode = ad1986a_modes; - spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes); - spec->need_dac_fix = 1; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - break; - case AD1986A_LAPTOP: - spec->mixers[0] = ad1986a_laptop_mixers; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - break; - case AD1986A_LAPTOP_EAPD: - spec->mixers[0] = ad1986a_laptop_eapd_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1986a_eapd_init_verbs; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1986a_laptop_eapd_capture_source; - break; - case AD1986A_ULTRA: - spec->mixers[0] = ad1986a_laptop_eapd_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1986a_ultra_init; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - spec->multiout.dig_out_nid = 0; - break; - } - - return 0; -} - -/* - * AD1983 specific - */ - -#define AD1983_SPDIF_OUT 0x02 -#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 struct hda_input_mux ad1983_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x1 }, - { "Mix", 0x2 }, - { "Mix Mono", 0x3 }, - }, -}; - -/* - * SPDIF playback route - */ -static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { "PCM", "ADC" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->spdif_route; - return 0; -} - -static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - - if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { - spec->spdif_route = ucontrol->value.enumerated.item[0]; - snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0, - AC_VERB_SET_CONNECT_SEL, spec->spdif_route); - return 1; - } - return 0; -} - -static 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), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x10, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x10, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static 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}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Beep, PCM, Mic, Line-In: mute */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Front, HP selectors; from Mix */ - {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* Mono selector; from Mix */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Mic selector; Mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Line-in selector: Line-in */ - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic boost: 0dB */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* Record selector: mic */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* SPDIF route: PCM */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Front Pin */ - {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* HP Pin */ - {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* Mono Pin */ - {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Mic Pin */ - {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* Line Pin */ - {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - { } /* end */ -}; - - -static int patch_ad1983(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - mutex_init(&spec->amp_mutex); - codec->spec = spec; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); - spec->multiout.dac_nids = ad1983_dac_nids; - spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = ad1983_adc_nids; - spec->capsrc_nids = ad1983_capsrc_nids; - spec->input_mux = &ad1983_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1983_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1983_init_verbs; - spec->spdif_route = 0; - - codec->patch_ops = ad198x_patch_ops; - - return 0; -} - - -/* - * AD1981 HD specific - */ - -#define AD1981_SPDIF_OUT 0x02 -#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 }; - -/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ -static struct hda_input_mux ad1981_capture_source = { - .num_items = 7, - .items = { - { "Front Mic", 0x0 }, - { "Line", 0x1 }, - { "Mix", 0x2 }, - { "Mix Mono", 0x3 }, - { "CD", 0x4 }, - { "Mic", 0x6 }, - { "Aux", 0x7 }, - }, -}; - -static 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), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x0d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* identical with AD1983 */ - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static 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}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Front, HP selectors; from Mix */ - {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* Mono selector; from Mix */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Mic Mixer; select Front Mic */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Mic boost: 0dB */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* Record selector: Front mic */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* SPDIF route: PCM */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Front Pin */ - {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* HP Pin */ - {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* Mono Pin */ - {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Front & Rear Mic Pins */ - {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* Line Pin */ - {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* Digital Beep */ - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Line-Out as Input: disabled */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - { } /* end */ -}; - -/* - * Patch for HP nx6320 - * - * nx6320 uses EAPD in the reverse way - EAPD-on means the internal - * speaker output enabled _and_ mute-LED off. - */ - -#define AD1981_HP_EVENT 0x37 -#define AD1981_MIC_EVENT 0x38 - -static 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}, - {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, - {} -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - - if (! ad198x_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle HP mute appropriately */ - snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); - return 1; -} - -/* bind volumes of both NID 0x05 and 0x06 */ -static int ad1981_hp_master_vol_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 = snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} - -/* mute internal speaker if HP is plugged */ -static void ad1981_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x06, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); -} - -/* 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[] = { - {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - static struct hda_verb mic_jack_off[] = { - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - unsigned int present; - - present = snd_hda_codec_read(codec, 0x08, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - -/* unsolicited event for HP jack sensing */ -static void ad1981_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - res >>= 26; - switch (res) { - case AD1981_HP_EVENT: - ad1981_hp_automute(codec); - break; - case AD1981_MIC_EVENT: - ad1981_hp_automic(codec); - break; - } -} - -static struct hda_input_mux ad1981_hp_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Docking-Station", 0x1 }, - { "Mix", 0x2 }, - }, -}; - -static struct snd_kcontrol_new ad1981_hp_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = ad1981_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = ad198x_eapd_info, - .get = ad198x_eapd_get, - .put = ad1981_hp_master_sw_put, - .private_value = 0x05, - }, - HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), -#if 0 - /* FIXME: analog mic/line loopback doesn't work with my tests... - * (although recording is OK) - */ - HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), - /* FIXME: does this laptop have analog CD connection? */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), -#endif - HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -/* initialize jack-sensing, too */ -static int ad1981_hp_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1981_hp_automute(codec); - ad1981_hp_automic(codec); - return 0; -} - -/* configuration for Toshiba Laptops */ -static 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}, - {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, - {} -}; - -static 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[] = { - 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), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* identical with AD1983 */ - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static struct hda_input_mux ad1981_thinkpad_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Mix", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* models */ -enum { - AD1981_BASIC, - AD1981_HP, - AD1981_THINKPAD, - AD1981_TOSHIBA, - AD1981_MODELS -}; - -static const char *ad1981_models[AD1981_MODELS] = { - [AD1981_HP] = "hp", - [AD1981_THINKPAD] = "thinkpad", - [AD1981_BASIC] = "basic", - [AD1981_TOSHIBA] = "toshiba" -}; - -static struct snd_pci_quirk ad1981_cfg_tbl[] = { - /* All HP models */ - SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), - /* HP nx6320 (reversed SSID, H/W bug) */ - SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), - /* Lenovo Thinkpad T60/X60/Z6xx */ - SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD), - SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), - SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), - {} -}; - -static int patch_ad1981(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - mutex_init(&spec->amp_mutex); - codec->spec = spec; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); - spec->multiout.dac_nids = ad1981_dac_nids; - spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = ad1981_adc_nids; - spec->capsrc_nids = ad1981_capsrc_nids; - spec->input_mux = &ad1981_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1981_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1981_init_verbs; - spec->spdif_route = 0; - - codec->patch_ops = ad198x_patch_ops; - - /* override some parameters */ - board_config = snd_hda_check_board_config(codec, AD1981_MODELS, - ad1981_models, - ad1981_cfg_tbl); - switch (board_config) { - case AD1981_HP: - spec->mixers[0] = ad1981_hp_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1981_hp_init_verbs; - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1981_hp_capture_source; - - codec->patch_ops.init = ad1981_hp_init; - codec->patch_ops.unsol_event = ad1981_hp_unsol_event; - break; - case AD1981_THINKPAD: - spec->mixers[0] = ad1981_thinkpad_mixers; - spec->input_mux = &ad1981_thinkpad_capture_source; - break; - case AD1981_TOSHIBA: - spec->mixers[0] = ad1981_hp_mixers; - spec->mixers[1] = ad1981_toshiba_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1981_toshiba_init_verbs; - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1981_hp_capture_source; - codec->patch_ops.init = ad1981_hp_init; - codec->patch_ops.unsol_event = ad1981_hp_unsol_event; - break; - } - return 0; -} - - -/* - * AD1988 - * - * Output pins and routes - * - * Pin Mix Sel DAC (*) - * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06 - * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06 - * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a - * port-D 0x12 (mute/hp) <- 0x29 <- 04 - * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a - * port-F 0x16 (mute) <- 0x2a <- 06 - * port-G 0x24 (mute) <- 0x27 <- 05 - * port-H 0x25 (mute) <- 0x28 <- 0a - * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06 - * - * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah - * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug. - * - * Input pins and routes - * - * pin boost mix input # / adc input # - * port-A 0x11 -> 0x38 -> mix 2, ADC 0 - * port-B 0x14 -> 0x39 -> mix 0, ADC 1 - * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2 - * port-D 0x12 -> 0x3d -> mix 3, ADC 8 - * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4 - * port-F 0x16 -> 0x3b -> mix 5, ADC 3 - * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6 - * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7 - * - * - * DAC assignment - * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03 - * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03 - * - * Inputs of Analog Mix (0x20) - * 0:Port-B (front mic) - * 1:Port-C/G/H (line-in) - * 2:Port-A - * 3:Port-D (line-in/2) - * 4:Port-E/G/H (mic-in) - * 5:Port-F (mic2-in) - * 6:CD - * 7:Beep - * - * ADC selection - * 0:Port-A - * 1:Port-B (front mic-in) - * 2:Port-C (line-in) - * 3:Port-F (mic2-in) - * 4:Port-E (mic-in) - * 5:CD - * 6:Port-G - * 7:Port-H - * 8:Port-D (line-in/2) - * 9:Mix - * - * Proposed pin assignments by the datasheet - * - * 6-stack - * Port-A front headphone - * B front mic-in - * C rear line-in - * D rear front-out - * E rear mic-in - * F rear surround - * G rear CLFE - * H rear side - * - * 3-stack - * Port-A front headphone - * B front mic - * C rear line-in/surround - * D rear front-out - * E rear mic-in/CLFE - * - * laptop - * Port-A headphone - * B mic-in - * C docking station - * D internal speaker (with EAPD) - * E/F quad mic array - */ - - -/* models */ -enum { - AD1988_6STACK, - AD1988_6STACK_DIG, - AD1988_3STACK, - AD1988_3STACK_DIG, - AD1988_LAPTOP, - AD1988_LAPTOP_DIG, - AD1988_AUTO, - AD1988_MODEL_LAST, -}; - -/* reivision id to check workarounds */ -#define AD1988A_REV2 0x100200 - -#define is_rev2(codec) \ - ((codec)->vendor_id == 0x11d41988 && \ - (codec)->revision_id == AD1988A_REV2) - -/* - * mixers - */ - -static hda_nid_t ad1988_6stack_dac_nids[4] = { - 0x04, 0x06, 0x05, 0x0a -}; - -static 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] = { - 0x04, 0x05, 0x0a, 0x06 -}; - -static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { - 0x04, 0x0a, 0x06 -}; - -static hda_nid_t ad1988_adc_nids[3] = { - 0x08, 0x09, 0x0f -}; - -static hda_nid_t ad1988_capsrc_nids[3] = { - 0x0c, 0x0d, 0x0e -}; - -#define AD1988_SPDIF_OUT 0x02 -#define AD1988_SPDIF_IN 0x07 - -static struct hda_input_mux ad1988_6stack_capture_source = { - .num_items = 5, - .items = { - { "Front Mic", 0x0 }, - { "Line", 0x1 }, - { "Mic", 0x4 }, - { "CD", 0x5 }, - { "Mix", 0x9 }, - }, -}; - -static struct hda_input_mux ad1988_laptop_capture_source = { - .num_items = 3, - .items = { - { "Mic/Line", 0x0 }, - { "CD", 0x5 }, - { "Mix", 0x9 }, - }, -}; - -/* - */ -static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, spec->multiout.max_channels); -} - -static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->multiout.max_channels); - if (err >= 0 && spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - return err; -} - -/* 6-stack mode */ -static 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), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static 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), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static 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), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), - - HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT), - - { } /* end */ -}; - -/* 3-stack mode */ -static 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), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static 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), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static 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), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), - - HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = ad198x_ch_mode_info, - .get = ad198x_ch_mode_get, - .put = ad198x_ch_mode_put, - }, - - { } /* end */ -}; - -/* laptop mode */ -static 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), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "External Amplifier", - .info = ad198x_eapd_info, - .get = ad198x_eapd_get, - .put = ad198x_eapd_put, - .private_value = 0x12 | (1 << 8), /* port-D, inversed */ - }, - - { } /* end */ -}; - -/* capture */ -static 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), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { - "PCM", "ADC1", "ADC2", "ADC3" - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int sel; - - sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); - if (sel > 0) { - sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0); - if (sel <= 3) - sel++; - else - sel = 0; - } - ucontrol->value.enumerated.item[0] = sel; - return 0; -} - -static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int sel; - int change; - - sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); - if (! ucontrol->value.enumerated.item[0]) { - change = sel != 0; - if (change) - snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL, 0); - } else { - change = sel == 0; - if (change) - snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL, 1); - sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0) + 1; - change |= sel == ucontrol->value.enumerated.item[0]; - if (change) - snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CONNECT_SEL, - ucontrol->value.enumerated.item[0] - 1); - } - return change; -} - -static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "IEC958 Playback Source", - .info = ad1988_spdif_playback_source_info, - .get = ad1988_spdif_playback_source_get, - .put = ad1988_spdif_playback_source_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { - HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT), - { } /* end */ -}; - - -/* - * initialization verbs - */ - -/* - * for 6-stack (+dig) - */ -static 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}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-D line-out path */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-F surround path */ - {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-G CLFE path */ - {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-H side path */ - {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mono out path */ - {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ - /* Port-B front mic-in path */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-C line-in path */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Port-E mic-in path */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, - - { } -}; - -static 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)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* select ADCs - front-mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* ADCs; muted */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - { } -}; - -static 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 */ - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* SPDIF out pin */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x17}, /* 0dB */ - - { } -}; - -/* - * verbs for 3stack (+dig) - */ -static 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 }, - /* set port-E to mic-in */ - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { } /* end */ -}; - -static 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 }, - /* set port-E to CLFE out */ - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -static 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[] = { - /* 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}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-D line-out path */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mono out path */ - {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ - /* Port-B front mic-in path */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-C line-in/surround path - 6ch mode as default */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */ - {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Port-E mic-in/CLFE path - 6ch mode as default */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */ - {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* 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)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* select ADCs - front-mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* ADCs; muted */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - { } -}; - -/* - * verbs for laptop mode (+dig) - */ -static 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[] = { - /* 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 }, - { } /* end */ -}; - -#define AD1988_HP_EVENT 0x01 - -static 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}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* unsolicited event for pin-sense */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT }, - /* Port-D line-out path + EAPD */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */ - /* Mono out path */ - {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ - /* Port-B mic-in path */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-C docking station - try to output */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* 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)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* select ADCs - mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* ADCs; muted */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - { } -}; - -static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) != AD1988_HP_EVENT) - return; - if (snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & (1 << 31)) - snd_hda_sequence_write(codec, ad1988_laptop_hp_on); - else - snd_hda_sequence_write(codec, ad1988_laptop_hp_off); -} - - -/* - * Automatic parse of I/O pins from the BIOS configuration - */ - -#define NUM_CONTROL_ALLOC 32 -#define NUM_VERB_ALLOC 32 - -enum { - AD_CTL_WIDGET_VOL, - AD_CTL_WIDGET_MUTE, - AD_CTL_BIND_MUTE, -}; -static 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), -}; - -/* add dynamic controls */ -static int add_control(struct ad198x_spec *spec, int type, const char *name, - unsigned long val) -{ - struct snd_kcontrol_new *knew; - size_t namelen = strlen(name) + 1; - - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ - if (! knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; - *knew = ad1988_control_templates[type]; - knew->name = kmalloc(namelen, GFP_KERNEL); - if (! knew->name) - return -ENOMEM; - memcpy(knew->name, name, namelen); - knew->private_value = val; - spec->num_kctl_used++; - return 0; -} - -#define AD1988_PIN_CD_NID 0x18 -#define AD1988_PIN_BEEP_NID 0x10 - -static 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] = { - /* 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] = { - /* A B C D E F G H */ - 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06 - }; - if (is_rev2(codec)) - return idx_to_dac_rev2[idx]; - else - return idx_to_dac[idx]; -} - -static 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] = { - 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25 - }; - int i; - for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++) - if (ad1988_io_pins[i] == nid) - return i; - return 0; /* should be -1 */ -} - -static int ad1988_pin_to_loopback_idx(hda_nid_t nid) -{ - static int loopback_idx[8] = { - 2, 0, 1, 3, 4, 5, 1, 4 - }; - switch (nid) { - case AD1988_PIN_CD_NID: - return 6; - default: - return loopback_idx[ad1988_pin_idx(nid)]; - } -} - -static int ad1988_pin_to_adc_idx(hda_nid_t nid) -{ - static int adc_idx[8] = { - 0, 1, 2, 8, 4, 3, 6, 7 - }; - switch (nid) { - case AD1988_PIN_CD_NID: - return 5; - default: - return adc_idx[ad1988_pin_idx(nid)]; - } -} - -/* fill in the dac_nids table from the parsed pin configuration */ -static int ad1988_auto_fill_dac_nids(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct ad198x_spec *spec = codec->spec; - int i, idx; - - spec->multiout.dac_nids = spec->private_dac_nids; - - /* 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->multiout.num_dacs = cfg->line_outs; - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec, - const struct auto_pin_cfg *cfg) -{ - char name[32]; - static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; - hda_nid_t nid; - int i, err; - - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t dac = spec->multiout.dac_nids[i]; - if (! dac) - continue; - nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])]; - if (i == 2) { - /* Center/LFE */ - err = add_control(spec, AD_CTL_WIDGET_VOL, - "Center Playback Volume", - HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, AD_CTL_WIDGET_VOL, - "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, AD_CTL_BIND_MUTE, - "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT)); - if (err < 0) - return err; - err = add_control(spec, AD_CTL_BIND_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT)); - if (err < 0) - return err; - } else { - sprintf(name, "%s Playback Volume", chname[i]); - err = add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - err = add_control(spec, AD_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); - if (err < 0) - return err; - } - } - return 0; -} - -/* add playback controls for speaker and HP outputs */ -static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, - const char *pfx) -{ - struct ad198x_spec *spec = codec->spec; - hda_nid_t nid; - int idx, err; - char name[32]; - - if (! pin) - return 0; - - idx = ad1988_pin_idx(pin); - nid = ad1988_idx_to_dac(codec, idx); - /* specify the DAC as the extra output */ - if (! spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - else - spec->multiout.extra_out_nid[0] = nid; - /* control HP volume/switch on the output mixer amp */ - sprintf(name, "%s Playback Volume", pfx); - if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) - return err; - nid = ad1988_mixer_nids[idx]; - sprintf(name, "%s Playback Switch", pfx); - if ((err = add_control(spec, AD_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) - return err; - return 0; -} - -/* create input playback/capture controls for the given pin */ -static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin, - const char *ctlname, int boost) -{ - char name[32]; - int err, idx; - - sprintf(name, "%s Playback Volume", ctlname); - idx = ad1988_pin_to_loopback_idx(pin); - if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0) - return err; - sprintf(name, "%s Playback Switch", ctlname); - if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0) - return err; - if (boost) { - hda_nid_t bnid; - idx = ad1988_pin_idx(pin); - bnid = ad1988_boost_nids[idx]; - if (bnid) { - sprintf(name, "%s Boost", ctlname); - return add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT)); - - } - } - return 0; -} - -/* create playback/capture controls for input pins */ -static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec, - const struct auto_pin_cfg *cfg) -{ - struct hda_input_mux *imux = &spec->private_imux; - int i, err; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], - i <= AUTO_PIN_FRONT_MIC); - if (err < 0) - return err; - imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]); - imux->num_items++; - } - imux->items[imux->num_items].label = "Mix"; - imux->items[imux->num_items].index = 9; - imux->num_items++; - - if ((err = add_control(spec, AD_CTL_WIDGET_VOL, - "Analog Mix Playback Volume", - HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0) - return err; - if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, - "Analog Mix Playback Switch", - HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0) - return err; - - return 0; -} - -static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, int pin_type, - int dac_idx) -{ - /* set as output */ - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - switch (nid) { - case 0x11: /* port-A - DAC 04 */ - snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01); - break; - case 0x14: /* port-B - DAC 06 */ - snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02); - break; - case 0x15: /* port-C - DAC 05 */ - snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00); - break; - case 0x17: /* port-E - DAC 0a */ - snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01); - break; - case 0x13: /* mono - DAC 04 */ - snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01); - break; - } -} - -static void ad1988_auto_init_multi_out(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.line_outs; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); - } -} - -static void ad1988_auto_init_extra_out(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - hda_nid_t pin; - - pin = spec->autocfg.speaker_pins[0]; - if (pin) /* connect to front */ - ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); -} - -static void ad1988_auto_init_analog_input(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int i, idx; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (! nid) - continue; - switch (nid) { - case 0x15: /* port-C */ - snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0); - break; - case 0x17: /* port-E */ - snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0); - break; - } - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - i <= AUTO_PIN_FRONT_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); - idx = ad1988_pin_idx(nid); - if (ad1988_boost_nids[idx]) - snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_ZERO); - } -} - -/* 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 */ -static int ad1988_parse_auto_config(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int err; - - if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) - return err; - if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) - return err; - if (! spec->autocfg.line_outs) - return 0; /* can't find valid BIOS pin config */ - if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || - (err = ad1988_auto_create_extra_out(codec, - spec->autocfg.speaker_pins[0], - "Speaker")) < 0 || - (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], - "Headphone")) < 0 || - (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = AD1988_SPDIF_IN; - - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - - spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs; - - spec->input_mux = &spec->private_imux; - - return 1; -} - -/* init callback for auto-configuration model -- overriding the default init */ -static int ad1988_auto_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1988_auto_init_multi_out(codec); - ad1988_auto_init_extra_out(codec); - ad1988_auto_init_analog_input(codec); - return 0; -} - - -/* - */ - -static const char *ad1988_models[AD1988_MODEL_LAST] = { - [AD1988_6STACK] = "6stack", - [AD1988_6STACK_DIG] = "6stack-dig", - [AD1988_3STACK] = "3stack", - [AD1988_3STACK_DIG] = "3stack-dig", - [AD1988_LAPTOP] = "laptop", - [AD1988_LAPTOP_DIG] = "laptop-dig", - [AD1988_AUTO] = "auto", -}; - -static struct snd_pci_quirk ad1988_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), - SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), - {} -}; - -static int patch_ad1988(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - mutex_init(&spec->amp_mutex); - codec->spec = spec; - - if (is_rev2(codec)) - snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); - - board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, - ad1988_models, ad1988_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n"); - board_config = AD1988_AUTO; - } - - if (board_config == AD1988_AUTO) { - /* automatic parse from the BIOS config */ - int err = ad1988_parse_auto_config(codec); - if (err < 0) { - ad198x_free(codec); - return err; - } else if (! err) { - printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n"); - board_config = AD1988_6STACK; - } - } - - switch (board_config) { - case AD1988_6STACK: - case AD1988_6STACK_DIG: - spec->multiout.max_channels = 8; - spec->multiout.num_dacs = 4; - if (is_rev2(codec)) - spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2; - else - spec->multiout.dac_nids = ad1988_6stack_dac_nids; - spec->input_mux = &ad1988_6stack_capture_source; - spec->num_mixers = 2; - if (is_rev2(codec)) - spec->mixers[0] = ad1988_6stack_mixers1_rev2; - else - spec->mixers[0] = ad1988_6stack_mixers1; - spec->mixers[1] = ad1988_6stack_mixers2; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1988_6stack_init_verbs; - if (board_config == AD1988_6STACK_DIG) { - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - spec->dig_in_nid = AD1988_SPDIF_IN; - } - break; - case AD1988_3STACK: - case AD1988_3STACK_DIG: - spec->multiout.max_channels = 6; - spec->multiout.num_dacs = 3; - if (is_rev2(codec)) - spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2; - else - spec->multiout.dac_nids = ad1988_3stack_dac_nids; - spec->input_mux = &ad1988_6stack_capture_source; - spec->channel_mode = ad1988_3stack_modes; - spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes); - spec->num_mixers = 2; - if (is_rev2(codec)) - spec->mixers[0] = ad1988_3stack_mixers1_rev2; - else - spec->mixers[0] = ad1988_3stack_mixers1; - spec->mixers[1] = ad1988_3stack_mixers2; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1988_3stack_init_verbs; - if (board_config == AD1988_3STACK_DIG) - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - break; - case AD1988_LAPTOP: - case AD1988_LAPTOP_DIG: - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1988_3stack_dac_nids; - spec->input_mux = &ad1988_laptop_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1988_laptop_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1988_laptop_init_verbs; - if (board_config == AD1988_LAPTOP_DIG) - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - break; - } - - spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); - spec->adc_nids = ad1988_adc_nids; - spec->capsrc_nids = ad1988_capsrc_nids; - spec->mixers[spec->num_mixers++] = ad1988_capture_mixers; - spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs; - if (spec->multiout.dig_out_nid) { - spec->mixers[spec->num_mixers++] = ad1988_spdif_out_mixers; - spec->init_verbs[spec->num_init_verbs++] = ad1988_spdif_init_verbs; - } - if (spec->dig_in_nid) - spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; - - codec->patch_ops = ad198x_patch_ops; - switch (board_config) { - case AD1988_AUTO: - codec->patch_ops.init = ad1988_auto_init; - break; - case AD1988_LAPTOP: - case AD1988_LAPTOP_DIG: - codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; - break; - } - - return 0; -} - - -/* - * AD1884 / AD1984 - * - * port-B - front line/mic-in - * port-E - aux in/out - * port-F - aux in/out - * port-C - rear line/mic-in - * port-D - rear line/hp-out - * port-A - front line/hp-out - * - * AD1984 = AD1884 + two digital mic-ins - * - * FIXME: - * For simplicity, we share the single DAC for both HP and line-outs - * right now. The inidividual playbacks could be easily implemented, - * but no build-up framework is given, so far. - */ - -static hda_nid_t ad1884_dac_nids[1] = { - 0x04, -}; - -static hda_nid_t ad1884_adc_nids[2] = { - 0x08, 0x09, -}; - -static hda_nid_t ad1884_capsrc_nids[2] = { - 0x0c, 0x0d, -}; - -#define AD1884_SPDIF_OUT 0x02 - -static struct hda_input_mux ad1884_capture_source = { - .num_items = 4, - .items = { - { "Front Mic", 0x0 }, - { "Mic", 0x1 }, - { "CD", 0x2 }, - { "Mix", 0x3 }, - }, -}; - -static 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), - HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), - 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), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), - /* - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Digital Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT), - */ - HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT), - 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), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* SPDIF controls */ - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - /* identical with ad1983 */ - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static 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, - HDA_INPUT), - HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0, - HDA_INPUT), - { } /* end */ -}; - -/* - * initialization verbs - */ -static 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}, - /* Port-A (HP) mixer */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-A pin */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* HP selector - select DAC2 */ - {0x22, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Port-D (Line-out) mixer */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-D pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mono-out mixer */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Mono-out pin */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mono selector */ - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Port-B (front mic) pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Port-C (rear mic) pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Analog mixer; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - /* SPDIF output selector */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - { } /* end */ -}; - -static int patch_ad1884(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - mutex_init(&spec->amp_mutex); - codec->spec = spec; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids); - spec->multiout.dac_nids = ad1884_dac_nids; - spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; - spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids); - spec->adc_nids = ad1884_adc_nids; - spec->capsrc_nids = ad1884_capsrc_nids; - spec->input_mux = &ad1884_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1884_base_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1884_init_verbs; - spec->spdif_route = 0; - - codec->patch_ops = ad198x_patch_ops; - - return 0; -} - -/* - * Lenovo Thinkpad T61/X61 - */ -static struct hda_input_mux ad1984_thinkpad_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "Mix", 0x3 }, - }, -}; - -static 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), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), - 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), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -/* additional verbs */ -static 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}, - /* docking mic boost */ - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Analog mixer - docking mic; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* enable EAPD bit */ - {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - { } /* end */ -}; - -/* Digial MIC ADC NID 0x05 + 0x06 */ -static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - snd_hda_codec_setup_stream(codec, 0x05 + substream->number, - stream_tag, 0, format); - return 0; -} - -static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - snd_hda_codec_setup_stream(codec, 0x05 + substream->number, - 0, 0, 0); - return 0; -} - -static struct hda_pcm_stream ad1984_pcm_dmic_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - .nid = 0x05, - .ops = { - .prepare = ad1984_pcm_dmic_prepare, - .cleanup = ad1984_pcm_dmic_cleanup - }, -}; - -static int ad1984_build_pcms(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - struct hda_pcm *info; - int err; - - err = ad198x_build_pcms(codec); - if (err < 0) - return err; - - info = spec->pcm_rec + codec->num_pcms; - codec->num_pcms++; - info->name = "AD1984 Digital Mic"; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture; - return 0; -} - -/* models */ -enum { - AD1984_BASIC, - AD1984_THINKPAD, - AD1984_MODELS -}; - -static const char *ad1984_models[AD1984_MODELS] = { - [AD1984_BASIC] = "basic", - [AD1984_THINKPAD] = "thinkpad", -}; - -static struct snd_pci_quirk ad1984_cfg_tbl[] = { - /* Lenovo Thinkpad T61/X61 */ - SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD), - {} -}; - -static int patch_ad1984(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int board_config, err; - - err = patch_ad1884(codec); - if (err < 0) - return err; - spec = codec->spec; - board_config = snd_hda_check_board_config(codec, AD1984_MODELS, - ad1984_models, ad1984_cfg_tbl); - switch (board_config) { - case AD1984_BASIC: - /* additional digital mics */ - spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers; - codec->patch_ops.build_pcms = ad1984_build_pcms; - break; - case AD1984_THINKPAD: - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1984_thinkpad_capture_source; - spec->mixers[0] = ad1984_thinkpad_mixers; - spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; - break; - } - return 0; -} - - -/* - * patch entries - */ -struct hda_codec_preset snd_hda_preset_analog[] = { - { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, - { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, - { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, - { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 }, - { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, - { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, - { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, - {} /* terminator */ -}; diff --git a/modules/GPL/hda/patch_atihdmi.c b/modules/GPL/hda/patch_atihdmi.c deleted file mode 100644 index 21ea562..0000000 --- a/modules/GPL/hda/patch_atihdmi.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * HD audio interface patch for ATI HDMI codecs - * - * Copyright (c) 2006 ATI Technologies Inc. - * - * - * This driver 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 driver 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 -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -struct atihdmi_spec { - struct hda_multi_out multiout; - - struct hda_pcm pcm_rec; -}; - -static struct hda_verb atihdmi_basic_init[] = { - /* enable digital output on pin widget */ - { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {} /* terminator */ -}; - -/* - * Controls - */ -static int atihdmi_build_controls(struct hda_codec *codec) -{ - struct atihdmi_spec *spec = codec->spec; - int err; - - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); - if (err < 0) - return err; - - return 0; -} - -static int atihdmi_init(struct hda_codec *codec) -{ - snd_hda_sequence_write(codec, atihdmi_basic_init); - return 0; -} - -#ifdef CONFIG_PM -/* - * resume - */ -static int atihdmi_resume(struct hda_codec *codec) -{ - atihdmi_init(codec); - snd_hda_resume_spdif_out(codec); - - return 0; -} -#endif - -/* - * Digital out - */ -static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct atihdmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct atihdmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct atihdmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static struct hda_pcm_stream atihdmi_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0x2, /* NID to query formats and rates and setup streams */ - .ops = { - .open = atihdmi_dig_playback_pcm_open, - .close = atihdmi_dig_playback_pcm_close, - .prepare = atihdmi_dig_playback_pcm_prepare - }, -}; - -static int atihdmi_build_pcms(struct hda_codec *codec) -{ - struct atihdmi_spec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "ATI HDMI"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback; - - return 0; -} - -static void atihdmi_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -static struct hda_codec_ops atihdmi_patch_ops = { - .build_controls = atihdmi_build_controls, - .build_pcms = atihdmi_build_pcms, - .init = atihdmi_init, - .free = atihdmi_free, -#ifdef CONFIG_PM - .resume = atihdmi_resume, -#endif -}; - -static int patch_atihdmi(struct hda_codec *codec) -{ - struct atihdmi_spec *spec; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - spec->multiout.num_dacs = 0; /* no analog */ - spec->multiout.max_channels = 2; - spec->multiout.dig_out_nid = 0x2; /* NID for copying analog to digital, - * seems to be unused in pure-digital - * case. */ - - codec->patch_ops = atihdmi_patch_ops; - - return 0; -} - -/* - * patch entries - */ -struct hda_codec_preset snd_hda_preset_atihdmi[] = { - { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, - { .id = 0x1002791a, .name = "ATI RS690 HDMI", .patch = patch_atihdmi }, - {} /* terminator */ -}; diff --git a/modules/GPL/hda/patch_cmedia.c b/modules/GPL/hda/patch_cmedia.c deleted file mode 100644 index 3c722e6..0000000 --- a/modules/GPL/hda/patch_cmedia.c +++ /dev/null @@ -1,760 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * HD audio interface patch for C-Media CMI9880 - * - * Copyright (c) 2004 Takashi Iwai - * - * - * This driver 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 driver 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 -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" -#define NUM_PINS 11 - - -/* board config type */ -enum { - CMI_MINIMAL, /* back 3-jack */ - CMI_MIN_FP, /* back 3-jack + front-panel 2-jack */ - CMI_FULL, /* back 6-jack + front-panel 2-jack */ - CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ - CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ - CMI_AUTO, /* let driver guess it */ - CMI_MODELS -}; - -struct cmi_spec { - int board_config; - unsigned int no_line_in: 1; /* no line-in (5-jack) */ - unsigned int front_panel: 1; /* has front-panel 2-jack */ - - /* playback */ - struct hda_multi_out multiout; - hda_nid_t dac_nids[4]; /* NID for each DAC */ - int num_dacs; - - /* capture */ - hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; - - /* capture source */ - const struct hda_input_mux *input_mux; - unsigned int cur_mux[2]; - - /* channel mode */ - int num_channel_modes; - const struct hda_channel_mode *channel_modes; - - struct hda_pcm pcm_rec[2]; /* PCM information */ - - /* pin deafault configuration */ - hda_nid_t pin_nid[NUM_PINS]; - unsigned int def_conf[NUM_PINS]; - unsigned int pin_def_confs; - - /* multichannel pins */ - hda_nid_t multich_pin[4]; /* max 8-channel */ - struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ -}; - -/* - * input MUX - */ -static int cmi_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int cmi_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int cmi_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); -} - -/* - * shared line-in, mic for surrounds - */ - -/* 3-stack / 2 channel */ -static 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 */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* route front PCM (DAC1) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - {} -}; - -/* 3-stack / 6 channel */ -static 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 */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* route front PCM (DAC1) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - {} -}; - -/* 3-stack+front / 8 channel */ -static 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 */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* route rear-surround PCM (DAC4) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, - {} -}; - -static struct hda_channel_mode cmi9880_channel_modes[3] = { - { 2, cmi9880_ch2_init }, - { 6, cmi9880_ch6_init }, - { 8, cmi9880_ch8_init }, -}; - -static int cmi_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_modes, - spec->num_channel_modes); -} - -static int cmi_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_modes, - spec->num_channel_modes, spec->multiout.max_channels); -} - -static int cmi_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_modes, - spec->num_channel_modes, &spec->multiout.max_channels); -} - -/* - */ -static 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), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = cmi_mux_enum_info, - .get = cmi_mux_enum_get, - .put = cmi_mux_enum_put, - }, - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x23, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x23, 0, HDA_OUTPUT), - { } /* end */ -}; - -/* - * shared I/O pins - */ -static struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = cmi_ch_mode_info, - .get = cmi_ch_mode_get, - .put = cmi_ch_mode_put, - }, - { } /* end */ -}; - -/* AUD-in selections: - * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20 - */ -static struct hda_input_mux cmi9880_basic_mux = { - .num_items = 4, - .items = { - { "Front Mic", 0x5 }, - { "Rear Mic", 0x2 }, - { "Line", 0x1 }, - { "CD", 0x7 }, - } -}; - -static struct hda_input_mux cmi9880_no_line_mux = { - .num_items = 3, - .items = { - { "Front Mic", 0x5 }, - { "Rear Mic", 0x2 }, - { "CD", 0x7 }, - } -}; - -/* front, rear, clfe, rear_surr */ -static hda_nid_t cmi9880_dac_nids[4] = { - 0x03, 0x04, 0x05, 0x06 -}; -/* ADC0, ADC1 */ -static hda_nid_t cmi9880_adc_nids[2] = { - 0x08, 0x09 -}; - -#define CMI_DIG_OUT_NID 0x07 -#define CMI_DIG_IN_NID 0x0a - -/* - */ -static 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) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* route front mic to ADC1/2 */ - { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, - { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, - {} /* terminator */ -}; - -static 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) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-A for side (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-C for surround (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* route front mic to ADC1/2 */ - { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, - { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, - {} /* terminator */ -}; - -/* - */ -static int cmi9880_build_controls(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - int err; - - err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); - if (err < 0) - return err; - if (spec->channel_modes) { - err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); - if (err < 0) - return err; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - return 0; -} - -/* fill in the multi_dac_nids table, which will decide - which audio widget to use for each channel */ -static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) -{ - struct cmi_spec *spec = codec->spec; - hda_nid_t nid; - int assigned[4]; - int i, j; - - /* clear the table, only one c-media dac assumed here */ - memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); - memset(assigned, 0, sizeof(assigned)); - /* check the pins we found */ - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ - if (nid >= 0x0b && nid <= 0x0e) { - spec->dac_nids[i] = (nid - 0x0b) + 0x03; - assigned[nid - 0x0b] = 1; - } - } - /* left pin can be connect to any audio widget */ - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - if (nid <= 0x0e) - continue; - /* search for an empty channel */ - for (j = 0; j < cfg->line_outs; j++) { - if (! assigned[j]) { - spec->dac_nids[i] = j + 0x03; - assigned[j] = 1; - break; - } - } - } - spec->num_dacs = cfg->line_outs; - return 0; -} - -/* create multi_init table, which is used for multichannel initialization */ -static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pin_cfg *cfg) -{ - struct cmi_spec *spec = codec->spec; - hda_nid_t nid; - int i, j, k, len; - - /* clear the table, only one c-media dac assumed here */ - memset(spec->multi_init, 0, sizeof(spec->multi_init)); - for (j = 0, i = 0; i < cfg->line_outs; i++) { - hda_nid_t conn[4]; - nid = cfg->line_out_pins[i]; - /* set as output */ - spec->multi_init[j].nid = nid; - spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; - spec->multi_init[j].param = PIN_OUT; - j++; - if (nid > 0x0e) { - /* set connection */ - spec->multi_init[j].nid = nid; - spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; - spec->multi_init[j].param = 0; - /* find the index in connect list */ - len = snd_hda_get_connections(codec, nid, conn, 4); - for (k = 0; k < len; k++) - if (conn[k] == spec->dac_nids[i]) { - spec->multi_init[j].param = k; - break; - } - j++; - } - } - return 0; -} - -static int cmi9880_init(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - if (spec->board_config == CMI_ALLOUT) - snd_hda_sequence_write(codec, cmi9880_allout_init); - else - snd_hda_sequence_write(codec, cmi9880_basic_init); - if (spec->board_config == CMI_AUTO) - snd_hda_sequence_write(codec, spec->multi_init); - return 0; -} - -#ifdef CONFIG_PM -/* - * resume - */ -static int cmi9880_resume(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - - cmi9880_init(codec); - snd_hda_resume_ctls(codec, cmi9880_basic_mixer); - if (spec->channel_modes) - snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; -} -#endif - -/* - * Analog playback callbacks - */ -static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); -} - -static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static int cmi9880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int cmi9880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int cmi9880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int cmi9880_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 cmi_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); - return 0; -} - - -/* - */ -static struct hda_pcm_stream cmi9880_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = 0x03, /* NID to query formats and rates */ - .ops = { - .open = cmi9880_playback_pcm_open, - .prepare = cmi9880_playback_pcm_prepare, - .cleanup = cmi9880_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream cmi9880_pcm_analog_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - .nid = 0x08, /* NID to query formats and rates */ - .ops = { - .prepare = cmi9880_capture_pcm_prepare, - .cleanup = cmi9880_capture_pcm_cleanup - }, -}; - -static struct hda_pcm_stream cmi9880_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in cmi9880_build_pcms */ - .ops = { - .open = cmi9880_dig_playback_pcm_open, - .close = cmi9880_dig_playback_pcm_close, - .prepare = cmi9880_dig_playback_pcm_prepare - }, -}; - -static struct hda_pcm_stream cmi9880_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in cmi9880_build_pcms */ -}; - -static int cmi9880_build_pcms(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "CMI9880"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_analog_capture; - - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - codec->num_pcms++; - info++; - info->name = "CMI9880 Digital"; - if (spec->multiout.dig_out_nid) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - } - - return 0; -} - -static void cmi9880_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -/* - */ - -static const char *cmi9880_models[CMI_MODELS] = { - [CMI_MINIMAL] = "minimal", - [CMI_MIN_FP] = "min_fp", - [CMI_FULL] = "full", - [CMI_FULL_DIG] = "full_dig", - [CMI_ALLOUT] = "allout", - [CMI_AUTO] = "auto", -}; - -static struct snd_pci_quirk cmi9880_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG), - {} /* terminator */ -}; - -static struct hda_codec_ops cmi9880_patch_ops = { - .build_controls = cmi9880_build_controls, - .build_pcms = cmi9880_build_pcms, - .init = cmi9880_init, - .free = cmi9880_free, -#ifdef CONFIG_PM - .resume = cmi9880_resume, -#endif -}; - -static int patch_cmi9880(struct hda_codec *codec) -{ - struct cmi_spec *spec; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS, - cmi9880_models, - cmi9880_cfg_tbl); - if (spec->board_config < 0) { - snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); - spec->board_config = CMI_AUTO; /* try everything */ - } - - /* copy default DAC NIDs */ - memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); - spec->num_dacs = 4; - - switch (spec->board_config) { - case CMI_MINIMAL: - case CMI_MIN_FP: - spec->channel_modes = cmi9880_channel_modes; - if (spec->board_config == CMI_MINIMAL) - spec->num_channel_modes = 2; - else { - spec->front_panel = 1; - spec->num_channel_modes = 3; - } - spec->multiout.max_channels = cmi9880_channel_modes[0].channels; - spec->input_mux = &cmi9880_basic_mux; - break; - case CMI_FULL: - case CMI_FULL_DIG: - spec->front_panel = 1; - spec->multiout.max_channels = 8; - spec->input_mux = &cmi9880_basic_mux; - if (spec->board_config == CMI_FULL_DIG) { - spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - spec->dig_in_nid = CMI_DIG_IN_NID; - } - break; - case CMI_ALLOUT: - spec->front_panel = 1; - spec->multiout.max_channels = 8; - spec->no_line_in = 1; - spec->input_mux = &cmi9880_no_line_mux; - spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - break; - case CMI_AUTO: - { - unsigned int port_e, port_f, port_g, port_h; - unsigned int port_spdifi, port_spdifo; - struct auto_pin_cfg cfg; - - /* collect pin default configuration */ - port_e = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - port_f = snd_hda_codec_read(codec, 0x10, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - spec->front_panel = 1; - if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || - get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { - port_g = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - port_h = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - spec->channel_modes = cmi9880_channel_modes; - /* no front panel */ - if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || - get_defcfg_connect(port_h) == AC_JACK_PORT_NONE) { - /* no optional rear panel */ - spec->board_config = CMI_MINIMAL; - spec->front_panel = 0; - spec->num_channel_modes = 2; - } else { - spec->board_config = CMI_MIN_FP; - spec->num_channel_modes = 3; - } - spec->input_mux = &cmi9880_basic_mux; - spec->multiout.max_channels = cmi9880_channel_modes[0].channels; - } else { - spec->input_mux = &cmi9880_basic_mux; - port_spdifi = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - port_spdifo = snd_hda_codec_read(codec, 0x12, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) - spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) - spec->dig_in_nid = CMI_DIG_IN_NID; - spec->multiout.max_channels = 8; - } - snd_hda_parse_pin_def_config(codec, &cfg, NULL); - if (cfg.line_outs) { - spec->multiout.max_channels = cfg.line_outs * 2; - cmi9880_fill_multi_dac_nids(codec, &cfg); - cmi9880_fill_multi_init(codec, &cfg); - } else - snd_printd("patch_cmedia: cannot detect association in defcfg\n"); - break; - } - } - - spec->multiout.num_dacs = spec->num_dacs; - spec->multiout.dac_nids = spec->dac_nids; - - spec->adc_nids = cmi9880_adc_nids; - - codec->patch_ops = cmi9880_patch_ops; - - return 0; -} - -/* - * patch entries - */ -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/modules/GPL/hda/patch_conexant.c b/modules/GPL/hda/patch_conexant.c deleted file mode 100644 index f68769d..0000000 --- a/modules/GPL/hda/patch_conexant.c +++ /dev/null @@ -1,2570 +0,0 @@ -/* - * HD audio interface patch for Conexant HDA audio/modem codec - * - * Copyright (c) 2006 Pototskiy Akex - * Takashi Iwai - * Tobin Davis - * - * Copyright (c) 2005-2006 Linuxant inc. - * - * This driver 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 driver 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 -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -#define CXT_PIN_DIR_IN 0x00 -#define CXT_PIN_DIR_OUT 0x01 -#define CXT_PIN_DIR_INOUT 0x02 -#define CXT_PIN_DIR_IN_NOMICBIAS 0x03 -#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04 - -#define CONEXANT_HP_EVENT 0x37 -#define CONEXANT_MIC_EVENT 0x38 - - -#if defined(__i386__) -#define __shimcall__ __attribute__((regparm(0))) -#else -#define __shimcall__ -#endif - -//#define CONFIG_SND_DEBUG - -struct conexant_spec { - - struct snd_kcontrol_new *mixers[5]; - int num_mixers; - - const struct hda_verb *init_verbs[5]; /* initialization verbs - * don't forget NULL - * termination! - */ - unsigned int num_init_verbs; - - /* playback */ - struct hda_multi_out multiout; /* playback set-up - * max_channels, dacs must be set - * dig_out_nid and hp_nid are optional - */ - unsigned int cur_eapd; - unsigned int hp_present; - unsigned int portb_present; - unsigned int portc_present; - unsigned int need_dac_fix; - - /* capture */ - unsigned int num_adc_nids; - 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; - unsigned int cur_mux[3]; - - /* channel model */ - const struct hda_channel_mode *channel_mode; - int num_channel_mode; - - /* PCM information */ - struct hda_pcm pcm[3]; /* used in build_pcms() */ - - struct mutex amp_mutex; /* PCM volume/mute control mutex */ - unsigned int spdif_route; - - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; - struct hda_input_mux private_imux; - hda_nid_t private_dac_nids[4]; - - /* HSF modem */ - void *modem_devnode; - unsigned int modem_stream_tags[2]; - int modem_do_prepare[2]; - void (*modem_cbHdaEvent)(void *Context, unsigned int res) __shimcall__; - void *modem_cbHdaEventContext; - unsigned char modem_cbHdaTag; -}; - -static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); -} - -static int conexant_playback_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; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, - format, substream); -} - -static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int conexant_dig_playback_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; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int conexant_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; - - if (spec->num_adc_nids > 1) - { -// printk(KERN_DEBUG"conexant_capture_pcm_prepare spec->portb_present =%x\n",spec->portb_present); -// printk(KERN_DEBUG"conexant_capture_pcm_prepare spec->portc_present =%x\n",spec->portc_present); -// if(spec->portb_present) -// snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], -// stream_tag, 0, format); -// else - snd_hda_codec_setup_stream(codec, spec->adc_nids[spec->portc_present], - stream_tag, 0, format); - } - else - { - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - } - return 0; -} - -static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - - if (spec->num_adc_nids > 1) - { - snd_hda_codec_setup_stream(codec, spec->adc_nids[0], - 0, 0, 0); - snd_hda_codec_setup_stream(codec, spec->adc_nids[1], - 0, 0, 0); - } - else - { - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - 0, 0, 0); - } - return 0; -} - - -static int conexant_modem_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; - -//printk(KERN_DEBUG"%s: codec=%p stream=%d stream_tag=%x format=0x%x substream=%p\n", __FUNCTION__, codec, substream->stream, stream_tag, format, substream); - - spec->modem_stream_tags[substream->stream] = stream_tag; - - return 0; -} - -static int conexant_modem_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - static unsigned int rates[] = { 16000 }; - static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, - }; - -//printk(KERN_DEBUG"%s: codec=%p substream=%p\n", __FUNCTION__, codec, substream); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); -} - - -static struct hda_pcm_stream conexant_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = conexant_playback_pcm_open, - .prepare = conexant_playback_pcm_prepare, - .cleanup = conexant_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream conexant_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = conexant_capture_pcm_prepare, - .cleanup = conexant_capture_pcm_cleanup - }, -}; - - -static struct hda_pcm_stream conexant_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = conexant_dig_playback_pcm_open, - .close = conexant_dig_playback_pcm_close, - .prepare = conexant_dig_playback_pcm_prepare - }, -}; - -static struct hda_pcm_stream conexant_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static struct hda_pcm_stream conexant_modem_pcm = { - .substreams = 1, - .channels_min = 1, - .channels_max = 1, - .nid = 0x1, - .rates = SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .maxbps = 16, - .ops = { - .open = conexant_modem_pcm_open, - //.close = conexant_modem_pcm_close, - .prepare = conexant_modem_pcm_prepare, - //.cleanup = conexant_modem_pcm_cleanup, - }, -}; - -/* Used by conexant_build_pcms to flag that a PCM has no playback stream */ -static struct hda_pcm_stream conexant_pcm_null_playback = { - .substreams = 0, - .channels_min = 0, - .channels_max = 0, -}; - -static int conexant_build_pcms(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm; - - codec->num_pcms = 0; - codec->pcm_info = info; - - if(codec->afg) { - info->name = "Conexant Analog Audio"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dac_nids[0]; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - - info++; - codec->num_pcms++; - } - - if (spec->multiout.dig_out_nid) { - info->name = "Conexant Digital Audio"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - conexant_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dig_out_nid; - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - conexant_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->dig_in_nid; - } - - info++; - codec->num_pcms++; - } - - if(codec->mfg) { -//printk(KERN_DEBUG"%s: codec=%p mfg=%d\n", __FUNCTION__, codec, codec->mfg); - - conexant_modem_pcm.nid = codec->mfg; - - info->name = "Conexant HSF Modem"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_modem_pcm; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = conexant_modem_pcm.nid; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_modem_pcm; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = conexant_modem_pcm.nid; - info->is_modem = 1; - - info++; - codec->num_pcms++; - } - - return 0; -} - -static int conexant_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->input_mux, uinfo); -} - -static int conexant_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; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int conexant_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; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->capsrc_nids[adc_idx], - &spec->cur_mux[adc_idx]); -} - -static void *conexant_hsf_interface_funcs[]; - -static int conexant_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int i, ret; - -//printk(KERN_DEBUG"%s: codec=%p\n", __FUNCTION__, codec); - if(codec->mfg) { - int (*cnxthwhda_probe)(void *codec, struct device *hwDev, void **ppDevNode, void **ppInterfaceFuncs); - -//printk(KERN_DEBUG"%s: codec=%p\n", __FUNCTION__, codec); - //snd_hda_codec_write(codec, AC_NODE_ROOT, 0, AC_VERB_SET_CODEC_RESET, 0); - - cnxthwhda_probe = (void*)symbol_request(cnxthwhda_probe); - if(!cnxthwhda_probe) { - printk(KERN_ERR"%s: symbol_request(cnxthwhda_probe) failed\n", __FUNCTION__); - if(!codec->afg) - return -ENOENT; - } else { - ret = cnxthwhda_probe(codec, codec->bus->card->dev, &spec->modem_devnode, conexant_hsf_interface_funcs); - if(ret) { - printk(KERN_ERR"%s: cnxthwhda_probe() failed: %d\n", __FUNCTION__, ret); - symbol_put(cnxthwhda_probe); - if(!codec->afg) - return ret; - } - } - } - - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); - - return 0; -} - -static int conexant_exit(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - -//printk(KERN_DEBUG"%s: codec=%p spec=%p\n", __FUNCTION__, codec, spec); - - if(codec->mfg && spec && spec->modem_devnode) { - void (*cnxthwhda_remove)(void *ptr); - - cnxthwhda_remove = (void*)symbol_request(cnxthwhda_remove); - if(cnxthwhda_remove) { - cnxthwhda_remove(spec->modem_devnode); - spec->modem_devnode = NULL; - symbol_put(cnxthwhda_remove); - symbol_put(cnxthwhda_probe); - } else { - printk(KERN_ERR"%s: symbol_request(cnxthwhda_remove) failed\n", __FUNCTION__); - } - } - - return 0; -} - -static void conexant_free(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int i; - -//printk(KERN_DEBUG"%s: codec=%p spec=%p\n", __FUNCTION__, codec, spec); - if(spec) { - codec->spec = NULL; - memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); - - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } - kfree(spec); - } -} - -static void conexant_unsol_event(struct hda_codec *codec, unsigned int res) -{ - struct conexant_spec *spec = codec->spec; - - //printk(KERN_DEBUG"%s: codec=%p res=0x%02x spec=%p cbHdaEvent=%p\n", __FUNCTION__, codec, res, spec, spec->modem_cbHdaEvent); - - if(codec->mfg && spec && spec->modem_cbHdaEvent) { - if(((res >> 26) & 0x3f) == spec->modem_cbHdaTag) { - //printk(KERN_DEBUG"%s: res=0x%02x cbHdaEvent=%p\n", __FUNCTION__, res, spec->modem_cbHdaEvent); -// printk(KERN_DEBUG"%s: calling cbHdaEvent=%p ctx=%p\n", __FUNCTION__, spec->modem_cbHdaEvent, spec->modem_cbHdaEventContext); - spec->modem_cbHdaEvent(spec->modem_cbHdaEventContext, res); - } else { - printk(KERN_DEBUG"%s: ignoring res=0x08%x\n", __FUNCTION__, res); - } - } -} - -typedef struct tagHDAOSHAL { - void *hda_codec; - int bInSuspendResume; -} HDAOSHAL, *PHDAOSHAL; - -typedef struct tagOS_DEVNODE { - void *hwDev; - // intentionally left incomplete -} OS_DEVNODE, *POS_DEVNODE; - -#ifdef CONFIG_PM -static int conexant_suspend(struct hda_codec *codec, pm_message_t state) -{ - struct conexant_spec *spec = codec->spec; - int (*cnxthwhda_suspend)(void *devnode, pm_message_t state); - int ret = 0; - -//printk(KERN_DEBUG"%s: codec=%p spec=%p state=0x%x\n", __FUNCTION__, codec, spec, *((u32 *)&state)); - - if(spec && spec->modem_devnode) { - cnxthwhda_suspend = (void*)symbol_request(cnxthwhda_suspend); - if(!cnxthwhda_suspend) { - printk(KERN_ERR"%s: symbol_request(cnxthwhda_suspend) failed\n", __FUNCTION__); - return -ENOSYS; - } - - if(((POS_DEVNODE)spec->modem_devnode)->hwDev) { - ((PHDAOSHAL)((POS_DEVNODE)spec->modem_devnode)->hwDev)->bInSuspendResume++; - } - ret = cnxthwhda_suspend(spec->modem_devnode, state); - if(((POS_DEVNODE)spec->modem_devnode)->hwDev) { - ((PHDAOSHAL)((POS_DEVNODE)spec->modem_devnode)->hwDev)->bInSuspendResume--; - } - symbol_put(cnxthwhda_suspend); - } - - return ret; -} - -static int conexant_resume(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int i; - int ret = 0; - hda_nid_t mfg; - - mfg = codec->mfg; - codec->mfg = 0; - codec->patch_ops.init(codec); - codec->mfg = mfg; - - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - if(spec && spec->modem_devnode) { - int (*cnxthwhda_resume)(void *devnode); - -//printk(KERN_DEBUG"%s: codec=%p spec=%p\n", __FUNCTION__, codec, spec); - - cnxthwhda_resume = (void*)symbol_request(cnxthwhda_resume); - if(!cnxthwhda_resume) { - printk(KERN_ERR"%s: symbol_request(cnxthwhda_resume) failed\n", __FUNCTION__); - return -ENOSYS; - } - - //snd_hda_codec_write(codec, AC_NODE_ROOT, 0, AC_VERB_SET_CODEC_RESET, 0); - - if(((POS_DEVNODE)spec->modem_devnode)->hwDev) { - ((PHDAOSHAL)((POS_DEVNODE)spec->modem_devnode)->hwDev)->bInSuspendResume++; - } - - ret = cnxthwhda_resume(spec->modem_devnode); - - if(((POS_DEVNODE)spec->modem_devnode)->hwDev) { - ((PHDAOSHAL)((POS_DEVNODE)spec->modem_devnode)->hwDev)->bInSuspendResume--; - } - - symbol_put(cnxthwhda_resume); - } - - return ret; -} -#endif - -static int conexant_build_controls(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int i; - int err; - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid); - if (err < 0) - return err; - } - return 0; -} - -static struct hda_codec_ops conexant_patch_ops = { - .build_controls = conexant_build_controls, - .build_pcms = conexant_build_pcms, - .init = conexant_init, - .exit = conexant_exit, - .free = conexant_free, - .unsol_event = conexant_unsol_event, -#ifdef CONFIG_PM - .suspend = conexant_suspend, - .resume = conexant_resume, -#endif -}; - -static int patch_cxthsf(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int (*cnxthwhda_probe)(void *codec, struct device *hwDev, void **ppDevNode); - -//printk(KERN_DEBUG"%s: codec=%p\n", __FUNCTION__, codec); - if(!codec->mfg) { // we only support modems - return -ENODEV; - } - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - mutex_init(&spec->amp_mutex); - codec->spec = spec; - - codec->patch_ops = conexant_patch_ops; - - cnxthwhda_probe = (void*)symbol_request(cnxthwhda_probe); - if(cnxthwhda_probe) { - symbol_put(cnxthwhda_probe); - } else { - printk(KERN_ERR"%s: symbol_request(cnxthwhda_probe) failed\n", __FUNCTION__); - codec->spec = NULL; - memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); - kfree(spec); - return -ENOENT; - } - - return 0; -} - -/* - * EAPD control - * the private value = nid | (invert << 8) - */ - -static int cxt_eapd_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int cxt_eapd_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; - int invert = (kcontrol->private_value >> 8) & 1; - if (invert) - ucontrol->value.integer.value[0] = !spec->cur_eapd; - else - ucontrol->value.integer.value[0] = spec->cur_eapd; - return 0; - -} - -static int cxt_eapd_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; - int invert = (kcontrol->private_value >> 8) & 1; - hda_nid_t nid = kcontrol->private_value & 0xff; - unsigned int eapd; - - eapd = ucontrol->value.integer.value[0]; - if (invert) - eapd = !eapd; - if (eapd == spec->cur_eapd && !codec->in_resume) - return 0; - - spec->cur_eapd = eapd; -#if 0 - if ((nid == 0x11) || (nid == 0x10)) { - snd_hda_codec_write(codec, 0x10, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); - } -#else - snd_hda_codec_write(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); -#endif - return 1; -} - -/* controls for test mode */ -#ifdef CONFIG_SND_DEBUG - -#define CXT_EAPD_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = cxt_eapd_info, \ - .get = cxt_eapd_get, \ - .put = cxt_eapd_put, \ - .private_value = nid | (mask<<16) } - - - -static int conexant_ch_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; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int conexant_ch_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; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - spec->multiout.max_channels); -} - -static int conexant_ch_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; - int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->multiout.max_channels); - if (err >= 0 && spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - return err; -} - -#define CXT_PIN_MODE(xname, nid, dir) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = conexant_ch_mode_info, \ - .get = conexant_ch_mode_get, \ - .put = conexant_ch_mode_put, \ - .private_value = nid | (dir<<16) } - -#endif /* CONFIG_SND_DEBUG */ - -/* Conexant 5051 specific */ -static hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; -static hda_nid_t cxt5051_adc_nids[2] = { 0x14,0x15 }; -static hda_nid_t cxt5051_capsrc_nids[2] = { 0x14,0x15 }; -#define CXT5051_SPDIF_OUT 0x1C -#define CXT5051_PORTB_EVENT 0x38 -#define CXT5051_PORTC_EVENT 0x39 - -static struct hda_channel_mode cxt5051_modes[1] = { - { 2, NULL }, -}; - -static struct hda_input_mux cxt5051_capture_source = { - .num_items = 2, - .items = { - { "IntMic", 0x1 }, - { "LineIn", 0x2 }, - } -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - static struct hda_verb spk_on[] = { - {0x1A, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {} - }; - static struct hda_verb spk_off[] = { - {0x1A, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static struct hda_verb hp_on[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {} - }; - static struct hda_verb hp_off[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle internal speakers mute depending of presence of - * the headphone jack - */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; - if (bits) - snd_hda_sequence_write(codec, spk_off); - else - snd_hda_sequence_write(codec, spk_on); - - bits = (spec->cur_eapd) ? 0 : 0x80; - if (bits) - snd_hda_sequence_write(codec, hp_off); - else - snd_hda_sequence_write(codec, hp_on); - - return 1; -} - -/* bind volumes of both NID 0x10 and 0x11 */ -static int cxt5051_hp_master_vol_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 = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5051_portb_automic(struct hda_codec *codec) -{ - static struct hda_verb mic_jack_on[] = { - {0x14, AC_VERB_SET_CONNECT_SEL,0x1}, - {} - }; - static struct hda_verb mic_jack_off[] = { - {0x14, AC_VERB_SET_CONNECT_SEL,0x1}, - {} - }; - unsigned int present; - struct conexant_spec *spec = codec->spec; - - present = snd_hda_codec_read(codec, 0x17, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - printk(KERN_DEBUG"cxt5051_portb_automic present =%x\n",present); - - if (present) - { - spec->portb_present = 1; - snd_hda_sequence_write(codec, mic_jack_on); - } - else - { - spec->portb_present = 0; - snd_hda_sequence_write(codec, mic_jack_off); - } - -} - -static void cxt5051_portc_automic(struct hda_codec *codec) -{ - unsigned int present; - struct conexant_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - printk(KERN_DEBUG"cxt5051_portc_automic present =%x\n",present); - - if (present) - spec->portc_present = 1; - else - spec->portc_present = 0; - -} - -/* mute internal speaker if HP is plugged */ -static void cxt5051_hp_automute(struct hda_codec *codec) -{ - static struct hda_verb spk_on[] = { - {0x1A, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {} - }; - static struct hda_verb spk_off[] = { - {0x1A, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - spec->hp_present = snd_hda_codec_read(codec, 0x16, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - - - bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; - if (bits) - snd_hda_sequence_write(codec, spk_off); - else - snd_hda_sequence_write(codec, spk_on); - - printk(KERN_DEBUG"cxt5051_hp_automute bits =%x\n",bits); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5051_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5051_hp_automute(codec); - break; - case CXT5051_PORTB_EVENT: - cxt5051_portb_automic(codec); - break; - case CXT5051_PORTC_EVENT: - cxt5051_portc_automic(codec); - break; - - default: - conexant_unsol_event(codec, res); - break; - - } -} - -static struct snd_kcontrol_new cxt5051_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put - }, -// HDA_CODEC_VOLUME("Int Mic Volume", 0x14, 0x00, HDA_INPUT), -// HDA_CODEC_MUTE("Int Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = cxt5051_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5051_hp_master_sw_put, - .private_value = 0x1A, - }, - - {} -}; - -static struct hda_verb cxt5051_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE,AC_AMP_SET_INPUT|AC_AMP_SET_LEFT - |AC_AMP_SET_RIGHT|0x3}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE,AC_AMP_SET_INPUT|AC_AMP_SET_LEFT - |AC_AMP_SET_RIGHT|0x3}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - {0x1D, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1D, AC_VERB_SET_AMP_GAIN_MUTE,AC_AMP_SET_INPUT|AC_AMP_SET_LEFT - |AC_AMP_SET_RIGHT|0x3}, - /* SPK */ - {0x1A, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x1A, AC_VERB_SET_CONNECT_SEL,0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP|PIN_OUT }, - {0x16, AC_VERB_SET_CONNECT_SEL,0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x01}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x02}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x04}, - /* Record selector: Int mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x44}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE,AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT| - AC_AMP_SET_LEFT|0x44|1<amp_mutex); - codec->spec = spec; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids); - spec->multiout.dac_nids = cxt5051_dac_nids; - spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; - spec->num_adc_nids = 2; - spec->adc_nids = cxt5051_adc_nids; - spec->capsrc_nids = cxt5051_capsrc_nids; - spec->input_mux = &cxt5051_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = cxt5051_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5051_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes), - spec->channel_mode = cxt5051_modes, - spec->portb_present = 0; - spec->portc_present = 0; - - codec->patch_ops = conexant_patch_ops; - - board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, - cxt5051_models, - cxt5051_cfg_tbl); - switch (board_config) { - default: - case CXT5051_LAPTOP: - codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; - spec->input_mux = &cxt5051_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5051_mic_wid17_init_verbs; - spec->mixers[0] = cxt5051_mixers; - codec->patch_ops.init = cxt5051_init; - break; - } - - if(codec->mfg) { - int (*cnxthwhda_probe)(void *codec, struct device *hwDev, void **ppDevNode); - cnxthwhda_probe = (void*)symbol_request(cnxthwhda_probe); - if(cnxthwhda_probe) - symbol_put(cnxthwhda_probe); - else - printk(KERN_ERR"%s: symbol_request(cnxthwhda_probe) failed\n", __FUNCTION__); - } - - return 0; -} - - - - -/* 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 }; -#define CXT5045_SPDIF_OUT 0x13 - -static struct hda_channel_mode cxt5045_modes[1] = { - { 2, NULL }, -}; - -static struct hda_input_mux cxt5045_capture_source = { - .num_items = 2, - .items = { - { "IntMic", 0x1 }, - { "ExtMic", 0x2 }, - } -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5045_hp_master_sw_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; - unsigned int bits; - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle internal speakers mute depending of presence of - * the headphone jack - */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); - - bits = spec->cur_eapd ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, 0x80, bits); - return 1; -} - -/* bind volumes of both NID 0x10 and 0x11 */ -static int cxt5045_hp_master_vol_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 = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} - -/* 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[] = { - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | AC_AMP_MUTE}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, - {} - }; - static struct hda_verb mic_jack_off[] = { - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | AC_AMP_MUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - {} - }; - unsigned int present; - - present = snd_hda_codec_read(codec, 0x12, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; -//printk("%s: mic_present=%x\n", __FUNCTION__, present); - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - - -/* mute internal speaker if HP is plugged */ -static void cxt5045_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - spec->hp_present = snd_hda_codec_read(codec, 0x11, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; -//printk("%s: hp_present=%x\n", __FUNCTION__, spec->hp_present); - - bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5045_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case CONEXANT_HP_EVENT: -//printk("%s: CONEXANT_HP_EVENT\n", __FUNCTION__); - cxt5045_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: -//printk("%s: CONEXANT_MIC_EVENT\n", __FUNCTION__); - cxt5045_hp_automic(codec); - break; - default: -//printk("%s: CONEXANT_OTHER_EVENT\n", __FUNCTION__); - conexant_unsol_event(codec, res); - break; - - } -} - -static struct snd_kcontrol_new cxt5045_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put - }, - HDA_CODEC_VOLUME("Int Mic Volume", 0x1a, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Switch", 0x1a, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Volume", 0x1a, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Ext Mic Switch", 0x1a, 0x02, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = cxt5045_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5045_hp_master_sw_put, - .private_value = 0x10, - }, - - {} -}; - -static struct hda_verb cxt5045_init_verbs[] = { - /* ExtMic in, IntMic */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - {0x12, AC_VERB_SET_CONNECT_SEL, 0x1 }, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - /* HP, Amp */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - {0x17, AC_VERB_SET_CONNECT_SEL,0x01}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x01}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x02}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x04}, - /* Record selector: Int mic */ - {0x1a, AC_VERB_SET_CONNECT_SEL,0x1}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - /* SPDIF route: PCM */ - { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* EAPD */ - {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2 }, /* default on */ - { } /* end */ -}; - - -static 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[] = { - /* pin sensing on HP jack */ - {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -#ifdef CONFIG_SND_DEBUG -/* Test configuration for debugging, modelled after the ALC260 test - * configuration. - */ -static struct hda_input_mux cxt5045_test_capture_source = { - .num_items = 5, - .items = { - { "MIXER", 0x0 }, - { "MIC1 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "HP-OUT pin", 0x3 }, - { "CD pin", 0x4 }, - }, -}; - -static struct snd_kcontrol_new cxt5045_test_mixer[] = { - - HDA_CODEC_VOLUME("Int Mic Volume", 0x1a, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Switch", 0x1a, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Volume", 0x1a, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Ext Mic Switch", 0x1a, 0x02, HDA_INPUT), - - /* Output controls */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Node 11 Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Node 11 Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Node 12 Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Node 12 Playback Switch", 0x12, 0x0, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT), - CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT), - - /* EAPD Switch Control */ - CXT_EAPD_SWITCH("External Amplifier", 0x10, 0x0), - - /* Loopback mixer controls */ - - HDA_CODEC_VOLUME("Mixer-1 Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mixer-1 Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mixer-2 Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mixer-2 Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mixer-3 Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Mixer-3 Switch", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Mixer-4 Volume", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Mixer-4 Switch", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("Mixer-5 Volume", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mixer-5 Switch", 0x17, 0x4, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put, - }, - { } /* end */ -}; - -static struct hda_verb cxt5045_test_init_verbs[] = { - /* Set connections */ - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { 0x12, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* Enable retasking pins as output, initially without power amp */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x13, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - - { } -}; -#endif - - -/* initialize jack-sensing, too */ -static int cxt5045_init(struct hda_codec *codec) -{ - conexant_init(codec); - cxt5045_hp_automute(codec); - return 0; -} - - -enum { - CXT5045_LAPTOP_HPSENSE, - CXT5045_LAPTOP_MICSENSE, - CXT5045_LAPTOP_HPMICSENSE, -#ifdef CONFIG_SND_DEBUG - CXT5045_TEST, -#endif - CXT5045_MODELS -}; - -static const char *cxt5045_models[CXT5045_MODELS] = { - [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", - [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", - [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", -#ifdef CONFIG_SND_DEBUG - [CXT5045_TEST] = "test", -#endif -}; - -static struct snd_pci_quirk cxt5045_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30a5, "HP", CXT5045_LAPTOP_HPSENSE), - SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP_HPSENSE), - SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP_HPSENSE), - SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP_HPSENSE), - SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP_HPSENSE), - SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP_HPSENSE), - SND_PCI_QUIRK(0x103c, 0x30d5, "HP", CXT5045_LAPTOP_HPSENSE), - SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE), - SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), - SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1631, 0xc106, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1631, 0xc107, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE), - {} -}; - -static int patch_cxt5045(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - mutex_init(&spec->amp_mutex); - codec->spec = spec; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids); - spec->multiout.dac_nids = cxt5045_dac_nids; - spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = cxt5045_adc_nids; - spec->capsrc_nids = cxt5045_capsrc_nids; - spec->input_mux = &cxt5045_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = cxt5045_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5045_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes), - spec->channel_mode = cxt5045_modes, - - - codec->patch_ops = conexant_patch_ops; - - board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, - cxt5045_models, - cxt5045_cfg_tbl); -//printk(KERN_DEBUG"%s: board_config=%d\n", __FUNCTION__, board_config); - switch (board_config) { - case CXT5045_LAPTOP_HPSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - case CXT5045_LAPTOP_MICSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - default: - case CXT5045_LAPTOP_HPMICSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 3; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->init_verbs[2] = cxt5045_mic_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; -#ifdef CONFIG_SND_DEBUG - case CXT5045_TEST: - spec->input_mux = &cxt5045_test_capture_source; - spec->mixers[0] = cxt5045_test_mixer; - spec->init_verbs[0] = cxt5045_test_init_verbs; -#endif - break; - - } - - if(codec->mfg) { - int (*cnxthwhda_probe)(void *codec, struct device *hwDev, void **ppDevNode); - cnxthwhda_probe = (void*)symbol_request(cnxthwhda_probe); - if(cnxthwhda_probe) - symbol_put(cnxthwhda_probe); - else - printk(KERN_ERR"%s: symbol_request(cnxthwhda_probe) failed\n", __FUNCTION__); - } - - return 0; -} - - -/* Conexant 5047 specific */ -#define CXT5047_SPDIF_OUT 0x11 - -static hda_nid_t cxt5047_dac_nids[2] = { 0x10, 0x1c }; -static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; -static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; - -static struct hda_channel_mode cxt5047_modes[1] = { - { 2, NULL }, -}; - -static struct hda_input_mux cxt5047_capture_source = { - .num_items = 1, - .items = { - { "Mic", 0x2 }, - } -}; - -static struct hda_input_mux cxt5047_hp_capture_source = { - .num_items = 1, - .items = { - { "ExtMic", 0x2 }, - } -}; - -static struct hda_input_mux cxt5047_toshiba_capture_source = { - .num_items = 2, - .items = { - { "ExtMic", 0x2 }, - { "Line-In", 0x1 }, - } -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5047_hp_master_sw_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; - unsigned int bits; - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle internal speakers mute depending of presence of - * the headphone jack - */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); - bits = spec->cur_eapd ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, 0x80, bits); - return 1; -} - -/* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */ -static int cxt5047_hp_master_vol_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 = snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} - -/* mute internal speaker if HP is plugged */ -static void cxt5047_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - - bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); - /* Mute/Unmute PCM 2 for good measure - some systems need this */ - snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 0x80, bits); -} - -/* 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[] = { - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | AC_AMP_MUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT}, - {} - }; - static struct hda_verb mic_jack_off[] = { - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | AC_AMP_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT}, - {} - }; - unsigned int present; - - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5047_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5047_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5047_hp_automic(codec); - break; - default: - conexant_unsol_event(codec, res); - break; - } -} - -static struct snd_kcontrol_new cxt5047_mixers[] = { - HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Gain Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Gain Switch", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM-2 Volume", 0x1c, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM-2 Switch", 0x1c, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = cxt5047_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5047_hp_master_sw_put, - .private_value = 0x13, - }, - - {} -}; - -static struct snd_kcontrol_new cxt5047_toshiba_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put - }, - HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = cxt5047_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5047_hp_master_sw_put, - .private_value = 0x13, - }, - - {} -}; - -static struct snd_kcontrol_new cxt5047_hp_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put - }, - HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19,0x02,HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), - HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5047_hp_master_sw_put, - .private_value = 0x13, - }, - { } /* end */ -}; - -static 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 }, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, - /* HP, Speaker */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x1d, AC_VERB_SET_CONNECT_SEL,0x0}, - /* Record selector: Mic */ - {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - {0x1A, AC_VERB_SET_CONNECT_SEL,0x02}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, - /* SPDIF route: PCM */ - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* Enable unsolicited events */ - {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -/* configuration for Toshiba Laptops */ -static struct hda_verb cxt5047_toshiba_init_verbs[] = { - {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */ - /* pin sensing on HP and Mic jacks */ - {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - /* Speaker routing */ - {0x1d, AC_VERB_SET_CONNECT_SEL,0x1}, - {} -}; - -/* configuration for HP Laptops */ -static struct hda_verb cxt5047_hp_init_verbs[] = { - /* pin sensing on HP jack */ - {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - /* Record selector: Ext Mic */ - {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - /* Speaker routing */ - {0x1d, AC_VERB_SET_CONNECT_SEL,0x1}, - {} -}; - -/* Test configuration for debugging, modelled after the ALC260 test - * configuration. - */ -#ifdef CONFIG_SND_DEBUG -static struct hda_input_mux cxt5047_test_capture_source = { - .num_items = 4, - .items = { - { "LINE1 pin", 0x0 }, - { "MIC1 pin", 0x1 }, - { "MIC2 pin", 0x2 }, - { "CD pin", 0x3 }, - }, -}; - -static struct snd_kcontrol_new cxt5047_test_mixer[] = { - - /* Output only controls */ - HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line1-Out Playback Volume", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line1-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line2-Out Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line2-Out Playback Switch", 0x15, 0x0, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT), - CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT), - - /* EAPD Switch Control */ - CXT_EAPD_SWITCH("External Amplifier", 0x13, 0x0), - - /* Loopback mixer controls */ - HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x12, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 Playback Switch", 0x12, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x12, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("MIC2 Playback Switch", 0x12, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LINE Playback Volume", 0x12, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("LINE Playback Switch", 0x12, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x12, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x12, 0x04, HDA_INPUT), - - HDA_CODEC_VOLUME("Capture-1 Volume", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture-1 Switch", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-2 Volume", 0x19, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Capture-2 Switch", 0x19, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-3 Volume", 0x19, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Capture-3 Switch", 0x19, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-4 Volume", 0x19, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Capture-4 Switch", 0x19, 0x3, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put, - }, - HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT), - - { } /* end */ -}; - -static 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}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure mic1, mic2, line1 pin widgets take input from the - * OUT1 sum bus when acting as an output. - */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; -#endif - - -/* initialize jack-sensing, too */ -static int cxt5047_hp_init(struct hda_codec *codec) -{ - conexant_init(codec); - cxt5047_hp_automute(codec); - return 0; -} - - -enum { - CXT5047_LAPTOP, /* Laptops w/o EAPD support */ - CXT5047_LAPTOP_HP, /* Some HP laptops */ - CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */ -#ifdef CONFIG_SND_DEBUG - CXT5047_TEST, -#endif - CXT5047_MODELS -}; - -static const char *cxt5047_models[CXT5047_MODELS] = { - [CXT5047_LAPTOP] = "laptop", - [CXT5047_LAPTOP_HP] = "laptop-hp", - [CXT5047_LAPTOP_EAPD] = "laptop-eapd", -#ifdef CONFIG_SND_DEBUG - [CXT5047_TEST] = "test", -#endif -}; - -static struct snd_pci_quirk cxt5047_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP), - SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), - SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP), - SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), - {} -}; - -static int patch_cxt5047(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - mutex_init(&spec->amp_mutex); - codec->spec = spec; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids); - spec->multiout.dac_nids = cxt5047_dac_nids; - spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = cxt5047_adc_nids; - spec->capsrc_nids = cxt5047_capsrc_nids; - spec->input_mux = &cxt5047_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = cxt5047_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5047_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes), - spec->channel_mode = cxt5047_modes, - - codec->patch_ops = conexant_patch_ops; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - - board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, - cxt5047_models, - cxt5047_cfg_tbl); - switch (board_config) { - case CXT5047_LAPTOP: - break; - case CXT5047_LAPTOP_HP: - spec->input_mux = &cxt5047_hp_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5047_hp_init_verbs; - spec->mixers[0] = cxt5047_hp_mixers; - codec->patch_ops.init = cxt5047_hp_init; - break; - case CXT5047_LAPTOP_EAPD: - spec->input_mux = &cxt5047_toshiba_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5047_toshiba_init_verbs; - spec->mixers[0] = cxt5047_toshiba_mixers; - break; -#ifdef CONFIG_SND_DEBUG - case CXT5047_TEST: - spec->input_mux = &cxt5047_test_capture_source; - spec->mixers[0] = cxt5047_test_mixer; - spec->init_verbs[0] = cxt5047_test_init_verbs; -#endif - } - - if(codec->mfg) { - int (*cnxthwhda_probe)(void *codec, struct device *hwDev, void **ppDevNode); - cnxthwhda_probe = (void*)symbol_request(cnxthwhda_probe); - if(cnxthwhda_probe) - symbol_put(cnxthwhda_probe); - else - printk(KERN_ERR"%s: symbol_request(cnxthwhda_probe) failed\n", __FUNCTION__); - } - - return 0; -} - -struct hda_codec_preset snd_hda_preset_conexant[] = { - { .id = 0x14f15045, .name = "CX20549 (Venice)", - .patch = patch_cxt5045 }, - { .id = 0x14f15047, .name = "CX20551 (Waikiki)", - .patch = patch_cxt5047 }, - { .id = 0x14f15051, .name = "CX20561 (Hermosa)", - .patch = patch_cxt5051 }, - { .id = 0x14f12bfa, .mfg = 2, .name = "HSF", - .patch = patch_cxthsf }, - { .id = 0x14f12c06, .mfg = 2, .name = "HSF", - .patch = patch_cxthsf }, - { .id = 0x14f10000, .mask = 0xffff0000, .mfg = 2, .name = "HSF", - .patch = patch_cxthsf }, - {} /* terminator */ -}; - - - -typedef enum { - OsHdaStreamStateReset = 0, - OsHdaStreamStateStop = 1, - OsHdaStreamStateRun = 2 -} OSHDA_STREAM_STATE; - -static __shimcall__ -unsigned int conexant_hsf_OsHdaCodecGetAddr(PHDAOSHAL pHdaOsHal) -{ - return ((struct hda_codec *)pHdaOsHal->hda_codec)->addr; -} - -static __shimcall__ -unsigned int conexant_hsf_OsHdaCodecGetVendorId(PHDAOSHAL pHdaOsHal) -{ - return ((struct hda_codec *)pHdaOsHal->hda_codec)->vendor_id; -} - -static __shimcall__ -unsigned int conexant_hsf_OsHdaCodecGetSubsystemId(PHDAOSHAL pHdaOsHal) -{ - return ((struct hda_codec *)pHdaOsHal->hda_codec)->subsystem_id; -} - -static __shimcall__ -unsigned int conexant_hsf_OsHdaCodecGetRevisionId(PHDAOSHAL pHdaOsHal) -{ - return ((struct hda_codec *)pHdaOsHal->hda_codec)->revision_id; -} - -static __shimcall__ -unsigned int conexant_hsf_OsHdaCodecRead(PHDAOSHAL pHdaOsHal, unsigned short nid, int direct, unsigned int verb, unsigned int para) -{ -#if 1 - return snd_hda_codec_read((struct hda_codec *)pHdaOsHal->hda_codec, nid, direct, verb, para); -#else - unsigned int res; - - res = snd_hda_codec_read((struct hda_codec *)pHdaOsHal->hda_codec, nid, direct, verb, para); - - printk(KERN_DEBUG"%s: nid=%x direct=%d verb=0x%x para=0x%x res=0x%08x\n", __FUNCTION__, nid, direct, verb, para, res); - - return res; -#endif -} - -static __shimcall__ -unsigned int conexant_hsf_OsHdaCodecWallclock(PHDAOSHAL pHdaOsHal) -{ - return snd_hda_codec_wallclock((struct hda_codec *)pHdaOsHal->hda_codec); -} - -static __shimcall__ -void conexant_hsf_OsHdaCodecSetEventCallback(PHDAOSHAL pHdaOsHal, void (*cbHdaEvent)(void *Context, unsigned int res), void *cbHdaEventContext, unsigned char *cbHdaTag) -{ - struct conexant_spec *spec = ((struct hda_codec *)pHdaOsHal->hda_codec)->spec; - - *cbHdaTag = ((struct hda_codec *)pHdaOsHal->hda_codec)->mfg; - -// printk(KERN_DEBUG"%s: codec=%p %p(%p) tag=%d\n", __FUNCTION__, pHdaOsHal->hda_codec, cbHdaEvent, cbHdaEventContext, (int)*cbHdaTag); - - spec->modem_cbHdaTag = *cbHdaTag; - spec->modem_cbHdaEventContext = cbHdaEventContext; - spec->modem_cbHdaEvent = (void*)cbHdaEvent; -} - -static __shimcall__ -void conexant_hsf_OsHdaCodecClearEventCallback(PHDAOSHAL pHdaOsHal, unsigned char cbHdaTag) -{ - struct conexant_spec *spec = ((struct hda_codec *)pHdaOsHal->hda_codec)->spec; - - if(spec) { -// printk(KERN_DEBUG"%s: codec=%p Tag=%d\n", __FUNCTION__, pHdaOsHal->hda_codec, cbHdaTag); - spec->modem_cbHdaEvent = NULL; - spec->modem_cbHdaEventContext = NULL; - spec->modem_cbHdaTag = 0; - } -} - - -#include - -#ifndef FOUND_SND_PCM_HW_PARAM_SET -static int snd_interval_refine_set(struct snd_interval *i, unsigned int val) -{ - struct snd_interval t; - t.empty = 0; - t.min = t.max = val; - t.openmin = t.openmax = 0; - t.integer = 1; - return snd_interval_refine(i, &t); -} - -static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, unsigned int val, - int dir) -{ - int changed; - if (hw_is_mask(var)) { - struct snd_mask *m = hw_param_mask(params, var); - if (val == 0 && dir < 0) { - changed = -EINVAL; - snd_mask_none(m); - } else { - if (dir > 0) - val++; - else if (dir < 0) - val--; - changed = snd_mask_refine_set(hw_param_mask(params, var), val); - } - } else if (hw_is_interval(var)) { - struct snd_interval *i = hw_param_interval(params, var); - if (val == 0 && dir < 0) { - changed = -EINVAL; - snd_interval_none(i); - } else if (dir == 0) - changed = snd_interval_refine_set(i, val); - else { - struct snd_interval t; - t.openmin = 1; - t.openmax = 1; - t.empty = 0; - t.integer = 0; - if (dir < 0) { - t.min = val - 1; - t.max = val; - } else { - t.min = val; - t.max = val+1; - } - changed = snd_interval_refine(i, &t); - } - } else - return -EINVAL; - if (changed) { - params->cmask |= 1 << var; - params->rmask |= 1 << var; - } - return changed; -} -#endif /* !FOUND_SND_PCM_HW_PARAM_SET */ - -static int conexant_modem_snd_pcm_change_params(struct snd_pcm_substream *substream, int hw_param_buffer_bytes) -{ - //snd_pcm_runtime_t *runtime = substream->runtime; - snd_pcm_hw_params_t *sparams; - int err; - - sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); - if (/*!params ||*/ !sparams) { - return -ENOMEM; - } - - _snd_pcm_hw_params_any(sparams); - _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - hw_param_buffer_bytes, 0); - - snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); - - if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams)) < 0) { - printk(KERN_ERR"%s: SNDRV_PCM_IOCTL_HW_PARAMS failed (%d)\n", __FUNCTION__, err); - //return err; - } - - return 0; -} - -static int conexant_modem_snd_pcm_prepare_substream(PHDAOSHAL pHdaOsHal, struct snd_pcm_substream *substream) -{ - int err; - struct conexant_spec *spec = ((struct hda_codec *)pHdaOsHal->hda_codec)->spec; - -//printk(KERN_DEBUG"%s: substream=%p\n", __FUNCTION__, substream); - - if(spec->modem_do_prepare[substream->stream]) { - err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); - if (err < 0) { - printk(KERN_ERR"%s: SNDRV_PCM_IOCTL_PREPARE failed (%d)\n", __FUNCTION__, err); - return err; - } - spec->modem_do_prepare[substream->stream] = 0; - } - - return 0; -} - -static __shimcall__ -int conexant_hsf_OsHdaCodecOpenDMA(PHDAOSHAL pHdaOsHal, int hw_param_buffer_bytes, void **ppPlaybackStream, void **ppCaptureStream) -{ - int i, err; - struct hda_codec *codec = (struct hda_codec *)pHdaOsHal->hda_codec; - struct hda_pcm *info = codec->pcm_info; - snd_pcm_t *pcm; - struct conexant_spec *spec = codec->spec; - - struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL; -#ifndef FOUND_OPEN_SUBSTREAM_NOFILE - static struct file fil; -#endif - - for(i = 0; i < codec->num_pcms && !info[i].is_modem; i++); - if(i == codec->num_pcms) { - printk(KERN_ERR"%s: modem pcm not found\n", __FUNCTION__); - return -ENOENT; - } - pcm = info[i].pcm; - -//printk(KERN_DEBUG"%s: pcm=%p hw_param_buffer_bytes=%d\n", __FUNCTION__, pcm, hw_param_buffer_bytes); - -#ifdef FOUND_OPEN_SUBSTREAM_NOFILE - if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_PLAYBACK, -#else - if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_PLAYBACK, &fil, -#endif - &psubstream)) < 0) { - printk(KERN_ERR"%s: snd_pcm_open_substream STREAM_PLAYBACK failed (%d)\n", __FUNCTION__, err); - return err; - } - -#ifdef FOUND_OPEN_SUBSTREAM_NOFILE - if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_CAPTURE, -#else - if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_CAPTURE, &fil, -#endif - &csubstream)) < 0) { - printk(KERN_ERR"%s: snd_pcm_open_substream STREAM_CAPTURE failed (%d)\n", __FUNCTION__, err); - return err; - } - -#ifdef FOUND_OPEN_SUBSTREAM_NOFILE - err = snd_pcm_hw_constraints_init(psubstream); - if (err < 0) { - printk(KERN_ERR"%s: snd_pcm_hw_constraints_init STREAM_PLAYBACK failed (%d)\n", __FUNCTION__, err); - } - if ((err = psubstream->ops->open(psubstream)) < 0) { - printk(KERN_ERR"%s: ops open STREAM_PLAYBACK failed (%d)\n", __FUNCTION__, err); - } - //psubstream->ffile = file; - err = snd_pcm_hw_constraints_complete(psubstream); - if (err < 0) { - printk(KERN_ERR"%s: snd_pcm_hw_constraints_complete STREAM_PLAYBACK failed (%d)\n", __FUNCTION__, err); - } - - err = snd_pcm_hw_constraints_init(csubstream); - if (err < 0) { - printk(KERN_ERR"%s: snd_pcm_hw_constraints_init STREAM_CAPTURE failed (%d)\n", __FUNCTION__, err); - } - if ((err = csubstream->ops->open(csubstream)) < 0) { - printk(KERN_ERR"%s: ops open STREAM_CAPTURE failed (%d)\n", __FUNCTION__, err); - } - //csubstream->ffile = file; - err = snd_pcm_hw_constraints_complete(csubstream); - if (err < 0) { - printk(KERN_ERR"%s: snd_pcm_hw_constraints_complete STREAM_CAPTURE failed (%d)\n", __FUNCTION__, err); - } -#endif - - err = conexant_modem_snd_pcm_change_params(psubstream, hw_param_buffer_bytes); - if (err < 0) { - printk(KERN_ERR"%s: conexant_modem_snd_pcm_change_params STREAM_PLAYBACK failed (%d)\n", __FUNCTION__, err); - } - - err = conexant_modem_snd_pcm_change_params(csubstream, hw_param_buffer_bytes); - if (err < 0) { - printk(KERN_ERR"%s: conexant_modem_snd_pcm_change_params STREAM_CAPTURE failed (%d)\n", __FUNCTION__, err); - } - -#if 0 - printk(KERN_DEBUG"%s: psubstream=%p dma_buffer_p=%p area=%p addr=0x%lx bytes=%d\n", __FUNCTION__, - psubstream, - psubstream->runtime->dma_buffer_p, - psubstream->runtime->dma_area, - (unsigned long)psubstream->runtime->dma_addr, - psubstream->runtime->dma_bytes); - - printk(KERN_DEBUG"%s: csubstream=%p dma_buffer_p=%p area=%p addr=0x%lx bytes=%d\n", __FUNCTION__, - csubstream, - csubstream->runtime->dma_buffer_p, - csubstream->runtime->dma_area, - (unsigned long)csubstream->runtime->dma_addr, - csubstream->runtime->dma_bytes); -#endif - - spec->modem_do_prepare[psubstream->stream] = 1; - spec->modem_do_prepare[csubstream->stream] = 1; - - if ((err = conexant_modem_snd_pcm_prepare_substream(pHdaOsHal, psubstream)) < 0) - return err; - - if ((err = conexant_modem_snd_pcm_prepare_substream(pHdaOsHal, csubstream)) < 0) - return err; - - *ppPlaybackStream = psubstream; - *ppCaptureStream = csubstream; - - return 0; -} - -static void conexant_modem_snd_pcm_close_stream(struct snd_pcm_substream *substream) -{ - //printk(KERN_DEBUG"%s: substream=%p\n", __FUNCTION__, substream); - -#if SNDRV_PCM_VERSION <= SNDRV_PROTOCOL_VERSION(2, 0, 7) - snd_pcm_stream_lock_irq(substream); - if (snd_pcm_running(substream)) - snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); - snd_pcm_stream_unlock_irq(substream); - - if (substream->ops->hw_free != NULL) - substream->ops->hw_free(substream); - - substream->ops->close(substream); -#endif - //printk(KERN_DEBUG"%s: substream=%p refcount=%d\n", __FUNCTION__, substream, substream->ref_count); - snd_pcm_release_substream(substream); -} - -static __shimcall__ -void conexant_hsf_OsHdaCodecCloseDMA(PHDAOSHAL pHdaOsHal, void *pPlaybackStream, void *pCaptureStream) -{ - //printk(KERN_DEBUG"%s: pHdaOsHal=%p pPlaybackStream=%p pCaptureStream=%p\n", __FUNCTION__, pHdaOsHal, pPlaybackStream, pCaptureStream); - if(pHdaOsHal) { - if(pPlaybackStream) - conexant_modem_snd_pcm_close_stream(pPlaybackStream); - if(pCaptureStream) - conexant_modem_snd_pcm_close_stream(pCaptureStream); - } -} - -static __shimcall__ -void conexant_hsf_OsHdaCodecDMAInfo(PHDAOSHAL pHdaOsHal, void *Stream, unsigned char *StreamID, unsigned long *FifoSize, short unsigned int **ppBufAddr) -{ - struct conexant_spec *spec = ((struct hda_codec *)pHdaOsHal->hda_codec)->spec; - struct snd_pcm_substream *substream = (struct snd_pcm_substream *)Stream; - -#if 0 - printk(KERN_DEBUG"%s: substream=%p stream=%u id/tag=%u fifo_size=%u bufAddr=%p\n", __FUNCTION__, - substream, - substream->stream, - spec->modem_stream_tags[substream->stream], - substream->runtime->hw.fifo_size, - substream->runtime->dma_area); -#endif - - *StreamID = spec->modem_stream_tags[substream->stream]; - *FifoSize = substream->runtime->hw.fifo_size; // XXX - *ppBufAddr = (short unsigned int *)substream->runtime->dma_area; -} - -static __shimcall__ -int conexant_hsf_OsHdaCodecSetDMAState(PHDAOSHAL pHdaOsHal, OSHDA_STREAM_STATE streamState, void *pPlaybackStream, void *pCaptureStream) -{ - struct conexant_spec *spec = ((struct hda_codec *)pHdaOsHal->hda_codec)->spec; - struct snd_pcm_substream *psubstream = (struct snd_pcm_substream *)pPlaybackStream; - struct snd_pcm_substream *csubstream = (struct snd_pcm_substream *)pCaptureStream; - int err = 0, cmd; - unsigned long flags, flags2; - - switch(streamState) { - case OsHdaStreamStateRun: -// printk(KERN_DEBUG"%s: Run\n", __FUNCTION__); - if ((err = conexant_modem_snd_pcm_prepare_substream(pHdaOsHal, psubstream)) < 0) - return err; - if ((err = conexant_modem_snd_pcm_prepare_substream(pHdaOsHal, csubstream)) < 0) - return err; - - cmd = SNDRV_PCM_IOCTL_START; - psubstream->runtime->start_threshold = 1; - psubstream->runtime->stop_threshold = psubstream->runtime->boundary; - csubstream->runtime->start_threshold = 1; - csubstream->runtime->stop_threshold = csubstream->runtime->boundary; - break; - case OsHdaStreamStateStop: -// printk(KERN_DEBUG"%s: Stop\n", __FUNCTION__); - cmd = SNDRV_PCM_IOCTL_DROP; - break; - case OsHdaStreamStateReset: -// printk(KERN_DEBUG"%s: Reset\n", __FUNCTION__); - cmd = SNDRV_PCM_IOCTL_RESET; - psubstream->runtime->start_threshold = psubstream->runtime->boundary; - csubstream->runtime->start_threshold = csubstream->runtime->boundary; - break; - default: - printk(KERN_ERR"%s: unknown state %d\n", __FUNCTION__, streamState); - return -ENOSYS; - } - - switch(cmd) { - case SNDRV_PCM_IOCTL_START: - snd_pcm_stream_lock_irqsave(psubstream, flags); - snd_pcm_stream_lock_irqsave(csubstream, flags2); - psubstream->ops->trigger(psubstream, SNDRV_PCM_TRIGGER_START); - csubstream->ops->trigger(csubstream, SNDRV_PCM_TRIGGER_START); - snd_pcm_stream_unlock_irqrestore(csubstream, flags2); - snd_pcm_stream_unlock_irqrestore(psubstream, flags); - break; - case SNDRV_PCM_IOCTL_DROP: - snd_pcm_stream_lock_irqsave(psubstream, flags); - snd_pcm_stream_lock_irqsave(csubstream, flags2); - psubstream->runtime->start_threshold = psubstream->runtime->boundary; - csubstream->runtime->start_threshold = csubstream->runtime->boundary; - psubstream->ops->trigger(psubstream, SNDRV_PCM_TRIGGER_STOP); - csubstream->ops->trigger(csubstream, SNDRV_PCM_TRIGGER_STOP); - snd_pcm_stream_unlock_irqrestore(csubstream, flags2); - snd_pcm_stream_unlock_irqrestore(psubstream, flags); - break; - case SNDRV_PCM_IOCTL_RESET: - //psubstream->ops->trigger(psubstream, SNDRV_PCM_TRIGGER_STOP); - //csubstream->ops->trigger(csubstream, SNDRV_PCM_TRIGGER_STOP); - /*FALLTHROUGH*/ - default: -#ifdef FOUND_OPEN_SUBSTREAM_NOFILE - err = snd_pcm_kernel_playback_ioctl(psubstream, cmd, NULL); -#else - err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL); -#endif - if (err < 0) { - printk(KERN_ERR"%s: snd_pcm_kernel_ioctl (playback) failed (%d)\n", __FUNCTION__, err); - } - -#ifdef FOUND_OPEN_SUBSTREAM_NOFILE - err = snd_pcm_kernel_capture_ioctl(csubstream, cmd, NULL); -#else - err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL); -#endif - if (err < 0) { - printk(KERN_ERR"%s: snd_pcm_kernel_ioctl (capture) failed (%d)\n", __FUNCTION__, err); - } - break; - } - - if(cmd != SNDRV_PCM_IOCTL_START) { - spec->modem_do_prepare[psubstream->stream] = 1; - spec->modem_do_prepare[csubstream->stream] = 1; - } - - return err; -} - -static __shimcall__ -unsigned long conexant_hsf_OsHdaCodecGetDMAPos(PHDAOSHAL pHdaOsHal, void *Stream) -{ - struct hda_codec *codec = (struct hda_codec *)pHdaOsHal->hda_codec; - struct snd_pcm_substream *substream = (struct snd_pcm_substream *)Stream; - int ret; - - if(codec->bus->ops.get_linkpos) - ret = codec->bus->ops.get_linkpos(substream); - else - ret = frames_to_bytes(substream->runtime, substream->ops->pointer(substream)); - - //printk(KERN_DEBUG"%s: substream=%p pos=%ld, ret=%d\n", __FUNCTION__, substream, pos, ret); - - return ret; -} - - -static void *conexant_hsf_interface_funcs[] = { - conexant_hsf_OsHdaCodecGetAddr, - conexant_hsf_OsHdaCodecGetVendorId, - conexant_hsf_OsHdaCodecGetSubsystemId, - conexant_hsf_OsHdaCodecGetRevisionId, - conexant_hsf_OsHdaCodecRead, - conexant_hsf_OsHdaCodecWallclock, - conexant_hsf_OsHdaCodecSetEventCallback, - conexant_hsf_OsHdaCodecClearEventCallback, - conexant_hsf_OsHdaCodecOpenDMA, - conexant_hsf_OsHdaCodecCloseDMA, - conexant_hsf_OsHdaCodecDMAInfo, - conexant_hsf_OsHdaCodecSetDMAState, - conexant_hsf_OsHdaCodecGetDMAPos, - NULL -}; - diff --git a/modules/GPL/hda/patch_realtek.c b/modules/GPL/hda/patch_realtek.c deleted file mode 100644 index 8d2449b..0000000 --- a/modules/GPL/hda/patch_realtek.c +++ /dev/null @@ -1,10053 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * HD audio interface patch for ALC 260/880/882 codecs - * - * Copyright (c) 2004 Kailang Yang - * PeiSen Hou - * Takashi Iwai - * Jonathan Woithe - * - * This driver 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 driver 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 -#include -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -#define ALC880_FRONT_EVENT 0x01 -#define ALC880_DCVOL_EVENT 0x02 -#define ALC880_HP_EVENT 0x04 -#define ALC880_MIC_EVENT 0x08 - -/* ALC880 board config type */ -enum { - ALC880_3ST, - ALC880_3ST_DIG, - ALC880_5ST, - ALC880_5ST_DIG, - ALC880_W810, - ALC880_Z71V, - ALC880_6ST, - ALC880_6ST_DIG, - ALC880_F1734, - ALC880_ASUS, - ALC880_ASUS_DIG, - ALC880_ASUS_W1V, - ALC880_ASUS_DIG2, - ALC880_FUJITSU, - ALC880_UNIWILL_DIG, - ALC880_UNIWILL, - ALC880_UNIWILL_P53, - ALC880_CLEVO, - ALC880_TCL_S700, - ALC880_LG, - ALC880_LG_LW, -#ifdef CONFIG_SND_DEBUG - ALC880_TEST, -#endif - ALC880_AUTO, - ALC880_MODEL_LAST /* last tag */ -}; - -/* ALC260 models */ -enum { - ALC260_BASIC, - ALC260_HP, - ALC260_HP_3013, - ALC260_FUJITSU_S702X, - ALC260_ACER, - ALC260_WILL, - ALC260_REPLACER_672V, -#ifdef CONFIG_SND_DEBUG - ALC260_TEST, -#endif - ALC260_AUTO, - ALC260_MODEL_LAST /* last tag */ -}; - -/* ALC262 models */ -enum { - ALC262_BASIC, - ALC262_HIPPO, - ALC262_HIPPO_1, - ALC262_FUJITSU, - ALC262_HP_BPC, - ALC262_HP_BPC_D7000_WL, - ALC262_HP_BPC_D7000_WF, - ALC262_BENQ_ED8, - ALC262_AUTO, - ALC262_MODEL_LAST /* last tag */ -}; - -/* ALC861 models */ -enum { - ALC861_3ST, - ALC660_3ST, - ALC861_3ST_DIG, - ALC861_6ST_DIG, - ALC861_UNIWILL_M31, - ALC861_TOSHIBA, - ALC861_ASUS, - ALC861_ASUS_LAPTOP, - ALC861_AUTO, - ALC861_MODEL_LAST, -}; - -/* ALC861-VD models */ -enum { - ALC660VD_3ST, - ALC861VD_3ST, - ALC861VD_3ST_DIG, - ALC861VD_6ST_DIG, - ALC861VD_AUTO, - ALC861VD_MODEL_LAST, -}; - -/* ALC662 models */ -enum { - ALC662_3ST_2ch_DIG, - ALC662_3ST_6ch_DIG, - ALC662_3ST_6ch, - ALC662_5ST_DIG, - ALC662_LENOVO_101E, - ALC662_AUTO, - ALC662_MODEL_LAST, -}; - -/* ALC882 models */ -enum { - ALC882_3ST_DIG, - ALC882_6ST_DIG, - ALC882_ARIMA, - ALC882_AUTO, - ALC885_MACPRO, - ALC882_MODEL_LAST, -}; - -/* ALC883 models */ -enum { - ALC883_3ST_2ch_DIG, - ALC883_3ST_6ch_DIG, - ALC883_3ST_6ch, - ALC883_6ST_DIG, - ALC883_TARGA_DIG, - ALC883_TARGA_2ch_DIG, - ALC888_DEMO_BOARD, - ALC883_ACER, - ALC883_MEDION, - ALC883_LAPTOP_EAPD, - ALC883_LENOVO_101E_2ch, - ALC883_AUTO, - ALC883_MODEL_LAST, -}; - -/* for GPIO Poll */ -#define GPIO_MASK 0x03 - -struct alc_spec { - /* codec parameterization */ - struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ - unsigned int num_mixers; - - const struct hda_verb *init_verbs[5]; /* initialization verbs - * don't forget NULL - * termination! - */ - unsigned int num_init_verbs; - - char *stream_name_analog; /* analog PCM stream */ - struct hda_pcm_stream *stream_analog_playback; - struct hda_pcm_stream *stream_analog_capture; - - char *stream_name_digital; /* digital PCM stream */ - struct hda_pcm_stream *stream_digital_playback; - struct hda_pcm_stream *stream_digital_capture; - - /* playback */ - struct hda_multi_out multiout; /* playback set-up - * max_channels, dacs must be set - * dig_out_nid and hp_nid are optional - */ - - /* capture */ - unsigned int num_adc_nids; - hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; /* digital-in NID; optional */ - - /* capture source */ - unsigned int num_mux_defs; - const struct hda_input_mux *input_mux; - unsigned int cur_mux[3]; - - /* channel model */ - const struct hda_channel_mode *channel_mode; - int num_channel_mode; - int need_dac_fix; - - /* PCM information */ - struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ - - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; - struct hda_input_mux private_imux; - hda_nid_t private_dac_nids[5]; - - /* hooks */ - void (*init_hook)(struct hda_codec *codec); - void (*unsol_event)(struct hda_codec *codec, unsigned int res); - - /* for pin sensing */ - unsigned int sense_updated: 1; - unsigned int jack_present: 1; -}; - -/* - * configuration template - to be copied to the spec instance - */ -struct alc_config_preset { - struct snd_kcontrol_new *mixers[5]; /* should be identical size - * with spec - */ - const struct hda_verb *init_verbs[5]; - unsigned int num_dacs; - hda_nid_t *dac_nids; - hda_nid_t dig_out_nid; /* optional */ - hda_nid_t hp_nid; /* optional */ - unsigned int num_adc_nids; - hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; - unsigned int num_channel_mode; - const struct hda_channel_mode *channel_mode; - int need_dac_fix; - unsigned int num_mux_defs; - const struct hda_input_mux *input_mux; - void (*unsol_event)(struct hda_codec *, unsigned int); - void (*init_hook)(struct hda_codec *); -}; - - -/* - * input MUX handling - */ -static int alc_mux_enum_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; - unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id); - if (mux_idx >= spec->num_mux_defs) - mux_idx = 0; - return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo); -} - -static int alc_mux_enum_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 adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int alc_mux_enum_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; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; - return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol, - spec->adc_nids[adc_idx], - &spec->cur_mux[adc_idx]); -} - - -/* - * channel mode setting - */ -static int alc_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; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int alc_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; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - spec->multiout.max_channels); -} - -static int alc_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 err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->multiout.max_channels); - if (err >= 0 && spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - return err; -} - -/* - * Control the mode of pin widget settings via the mixer. "pc" is used - * instead of "%" to avoid consequences of accidently treating the % as - * being part of a format specifier. Maximum allowed length of a value is - * 63 characters plus NULL terminator. - * - * Note: some retasking pin complexes seem to ignore requests for input - * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these - * are requested. Therefore order this list so that this behaviour will not - * cause problems when mixer clients move through the enum sequentially. - * NIDs 0x0f and 0x10 have been observed to have this behaviour as of - * March 2006. - */ -static char *alc_pin_mode_names[] = { - "Mic 50pc bias", "Mic 80pc bias", - "Line in", "Line out", "Headphone out", -}; -static 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 - * in the pin being assumed to be exclusively an input or an output pin. In - * addition, "input" pins may or may not process the mic bias option - * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to - * accept requests for bias as of chip versions up to March 2006) and/or - * wiring in the computer. - */ -#define ALC_PIN_DIR_IN 0x00 -#define ALC_PIN_DIR_OUT 0x01 -#define ALC_PIN_DIR_INOUT 0x02 -#define ALC_PIN_DIR_IN_NOMICBIAS 0x03 -#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04 - -/* 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] = { - { 0, 2 }, /* ALC_PIN_DIR_IN */ - { 3, 4 }, /* ALC_PIN_DIR_OUT */ - { 0, 4 }, /* ALC_PIN_DIR_INOUT */ - { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */ - { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */ -}; -#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0]) -#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1]) -#define alc_pin_mode_n_items(_dir) \ - (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1) - -static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - unsigned int item_num = uinfo->value.enumerated.item; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = alc_pin_mode_n_items(dir); - - if (item_numalc_pin_mode_max(dir)) - item_num = alc_pin_mode_min(dir); - strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]); - return 0; -} - -static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned int i; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, - 0x00); - - /* Find enumerated value for current pinctl setting */ - i = alc_pin_mode_min(dir); - while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir)) - i++; - *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir); - return 0; -} - -static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, - 0x00); - - if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir)) - val = alc_pin_mode_min(dir); - - change = pinctl != alc_pin_mode_values[val]; - if (change) { - /* Set pin mode to that requested */ - snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL, - alc_pin_mode_values[val]); - - /* Also enable the retasking pin's input/output as required - * for the requested pin mode. Enum values of 2 or less are - * input modes. - * - * Dynamically switching the input/output buffers probably - * reduces noise slightly (particularly on input) so we'll - * do it. However, having both input and output buffers - * enabled simultaneously doesn't seem to be problematic if - * this turns out to be necessary in the future. - */ - if (val <= 2) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } else { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(0)); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - } - } - return change; -} - -#define ALC_PIN_MODE(xname, nid, dir) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = alc_pin_mode_info, \ - .get = alc_pin_mode_get, \ - .put = alc_pin_mode_put, \ - .private_value = nid | (dir<<16) } - -/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged - * together using a mask with more than one bit set. This control is - * currently used only by the ALC260 test model. At this stage they are not - * needed for any "production" models. - */ -#ifdef CONFIG_SND_DEBUG -static int alc_gpio_data_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_GPIO_DATA, 0x00); - - *valp = (val & mask) != 0; - return 0; -} -static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_GPIO_DATA, - 0x00); - - /* Set/unset the masked GPIO bit(s) as needed */ - change = (val == 0 ? 0 : mask) != (gpio_data & mask); - if (val == 0) - gpio_data &= ~mask; - else - gpio_data |= mask; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data); - - return change; -} -#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = alc_gpio_data_info, \ - .get = alc_gpio_data_get, \ - .put = alc_gpio_data_put, \ - .private_value = nid | (mask<<16) } -#endif /* CONFIG_SND_DEBUG */ - -/* A switch control to allow the enabling of the digital IO pins on the - * ALC260. This is incredibly simplistic; the intention of this control is - * to provide something in the test model allowing digital outputs to be - * identified if present. If models are found which can utilise these - * outputs a more complete mixer control can be devised for those models if - * necessary. - */ -#ifdef CONFIG_SND_DEBUG -static int alc_spdif_ctrl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_DIGI_CONVERT, 0x00); - - *valp = (val & mask) != 0; - return 0; -} -static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_DIGI_CONVERT, - 0x00); - - /* Set/unset the masked control bit(s) as needed */ - change = (val == 0 ? 0 : mask) != (ctrl_data & mask); - if (val==0) - ctrl_data &= ~mask; - else - ctrl_data |= mask; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - ctrl_data); - - return change; -} -#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = alc_spdif_ctrl_info, \ - .get = alc_spdif_ctrl_get, \ - .put = alc_spdif_ctrl_put, \ - .private_value = nid | (mask<<16) } -#endif /* CONFIG_SND_DEBUG */ - -/* - * set up from the preset table - */ -static void setup_preset(struct alc_spec *spec, - const struct alc_config_preset *preset) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) - spec->mixers[spec->num_mixers++] = preset->mixers[i]; - for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; - i++) - spec->init_verbs[spec->num_init_verbs++] = - preset->init_verbs[i]; - - spec->channel_mode = preset->channel_mode; - spec->num_channel_mode = preset->num_channel_mode; - spec->need_dac_fix = preset->need_dac_fix; - - spec->multiout.max_channels = spec->channel_mode[0].channels; - - spec->multiout.num_dacs = preset->num_dacs; - spec->multiout.dac_nids = preset->dac_nids; - spec->multiout.dig_out_nid = preset->dig_out_nid; - spec->multiout.hp_nid = preset->hp_nid; - - spec->num_mux_defs = preset->num_mux_defs; - if (!spec->num_mux_defs) - spec->num_mux_defs = 1; - spec->input_mux = preset->input_mux; - - spec->num_adc_nids = preset->num_adc_nids; - spec->adc_nids = preset->adc_nids; - spec->dig_in_nid = preset->dig_in_nid; - - spec->unsol_event = preset->unsol_event; - spec->init_hook = preset->init_hook; -} - -/* Enable GPIO mask and set output */ -static 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[] = { - {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, - { } -}; - -/* 32-bit subsystem ID for BIOS loading in HD Audio codec. - * 31 ~ 16 : Manufacture ID - * 15 ~ 8 : SKU ID - * 7 ~ 0 : Assembly ID - * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 - */ -static void alc_subsystem_id(struct hda_codec *codec, - unsigned int porta, unsigned int porte, - unsigned int portd) -{ - unsigned int ass, tmp; - - ass = codec->subsystem_id; - if (!(ass & 1)) - return; - - /* Override */ - tmp = (ass & 0x38) >> 3; /* external Amp control */ - switch (tmp) { - case 1: - snd_hda_sequence_write(codec, alc_gpio1_init_verbs); - break; - case 3: - snd_hda_sequence_write(codec, alc_gpio2_init_verbs); - break; - case 5: - case 6: - if (ass & 4) { /* bit 2 : 0 = Desktop, 1 = Laptop */ - hda_nid_t port = 0; - tmp = (ass & 0x1800) >> 11; - switch (tmp) { - case 0: port = porta; break; - case 1: port = porte; break; - case 2: port = portd; break; - } - if (port) - snd_hda_codec_write(codec, port, 0, - AC_VERB_SET_EAPD_BTLENABLE, - 2); - } - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, - (tmp == 5 ? 0x3040 : 0x3050)); - break; - } -} - -/* - * ALC880 3-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) - * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, - * F-Mic = 0x1b, HP = 0x19 - */ - -static hda_nid_t alc880_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x05, 0x04, 0x03 -}; - -static hda_nid_t alc880_adc_nids[3] = { - /* ADC0-2 */ - 0x07, 0x08, 0x09, -}; - -/* The datasheet says the node 0x07 is connected from inputs, - * 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] = { - /* ADC1-2 */ - 0x08, 0x09, -}; - -#define ALC880_DIGOUT_NID 0x06 -#define ALC880_DIGIN_NID 0x0a - -static struct hda_input_mux alc880_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* channel source setting (2/6 channel selection for 3-stack) */ -/* 2ch mode */ -static 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 }, - /* set mic-in to input vref 80%, mute it */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* 6ch mode */ -static 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 }, - /* set mic-in to output, unmute it */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -static 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[] = { - 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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* capture mixer elements */ -static struct snd_kcontrol_new alc880_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -/* capture mixer elements (in case NID 0x07 not available) */ -static struct snd_kcontrol_new alc880_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - - - -/* - * ALC880 5-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), - * Side = 0x02 (0xd) - * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 - * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 - */ - -/* additional mixers to alc880_three_stack_mixer */ -static 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 */ -}; - -/* channel source setting (6/8 channel selection for 5-stack) */ -/* 6ch mode */ -static 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 }, - { } /* end */ -}; - -/* 8ch mode */ -static 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] = { - { 6, alc880_fivestack_ch6_init }, - { 8, alc880_fivestack_ch8_init }, -}; - - -/* - * ALC880 6-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), - * Side = 0x05 (0x0f) - * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, - * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b - */ - -static 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 = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* fixed 8-channels */ -static struct hda_channel_mode alc880_sixstack_modes[1] = { - { 8, NULL }, -}; - -static 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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - - -/* - * ALC880 W810 model - * - * W810 has rear IO for: - * Front (DAC 02) - * Surround (DAC 03) - * Center/LFE (DAC 04) - * Digital out (06) - * - * The system also has a pair of internal speakers, and a headphone jack. - * These are both connected to Line2 on the codec, hence to DAC 02. - * - * There is a variable resistor to control the speaker or headphone - * volume. This is a hardware-only device without a software API. - * - * Plugging headphones in will disable the internal speakers. This is - * implemented in hardware, not via the driver using jack sense. In - * a similar fashion, plugging into the rear socket marked "front" will - * disable both the speakers and headphones. - * - * For input, there's a microphone jack, and an "audio in" jack. - * These may not do anything useful with this driver yet, because I - * haven't setup any initialization verbs for these yet... - */ - -static 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] = { - { 6, NULL } -}; - -/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ -static 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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - { } /* end */ -}; - - -/* - * Z710V model - * - * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) - * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), - * Line = 0x1a - */ - -static 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] = { - { 2, NULL } -}; - -static 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), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - - -/* FIXME! */ -/* - * ALC880 F1734 model - * - * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) - * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 - */ - -static hda_nid_t alc880_f1734_dac_nids[1] = { - 0x03 -}; -#define ALC880_F1734_HP_DAC 0x02 - -static 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("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - - -/* FIXME! */ -/* - * ALC880 ASUS model - * - * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) - * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, - * Mic = 0x18, Line = 0x1a - */ - -#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[] = { - 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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* FIXME! */ -/* - * ALC880 ASUS W1V model - * - * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) - * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, - * Mic = 0x18, Line = 0x1a, Line2 = 0x1b - */ - -/* additional mixers to alc880_asus_mixer */ -static 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 */ -}; - -/* additional mixers to alc880_asus_mixer */ -static struct snd_kcontrol_new alc880_pcbeep_mixer[] = { - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - { } /* end */ -}; - -/* TCL S700 */ -static 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), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -/* Uniwill */ -static struct snd_kcontrol_new alc880_uniwill_mixer[] = { - HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static 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), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { - HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* - * build control elements - */ -static int alc_build_controls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int err; - int i; - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - return 0; -} - - -/* - * initialize the codec volumes, etc - */ - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc880_volume_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for front - * panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output mixers (0x0c - 0x0f) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - { } -}; - -/* - * 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[] = { - /* - * preset connection lists of input pins - * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround - */ - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ - - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mic2 (as headphone out) for HP output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line2 (as front mic) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 5-stack pin configuration: - * 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[] = { - /* - * preset connection lists of input pins - * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround - */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ - - /* - * Set pin mode and muting - */ - /* set pin widgets 0x14-0x17 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* unmute pins for output (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mic2 (as headphone out) for HP output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line2 (as front mic) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * W810 pin configuration: - * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b - */ -static struct hda_verb alc880_pin_w810_init_verbs[] = { - /* hphone/speaker input selector: front DAC */ - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {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_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - { } -}; - -/* - * Z71V pin configuration: - * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) - */ -static 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}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 6-stack pin configuration: - * 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[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {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_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {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}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {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}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * Uniwill pin configuration: - * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19, - * line = 0x1a - */ -static struct hda_verb alc880_uniwill_init_verbs[] = { - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {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}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */ - /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, - - { } -}; - -/* -* Uniwill P53 -* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, - */ -static 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}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {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}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT}, - - { } -}; - -static struct hda_verb alc880_beep_init_verbs[] = { - { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) }, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc880_uniwill_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x16, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0, - 0x80, bits); - - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_write(codec, 0x0b, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x01 << 8) | bits); -} - -static void alc880_uniwill_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - if ((res >> 28) == ALC880_HP_EVENT || - (res >> 28) == ALC880_MIC_EVENT) - alc880_uniwill_automute(codec); -} - -static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_INPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_INPUT, 0, - 0x80, bits); -} - -static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_VOLUME_KNOB_CONTROL, 0) & 0x7f; - - snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, - 0x7f, present); - snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, - 0x7f, present); - - snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, - 0x7f, present); - snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, - 0x7f, present); - -} -static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - if ((res >> 28) == ALC880_HP_EVENT) - alc880_uniwill_p53_hp_automute(codec); - if ((res >> 28) == ALC880_DCVOL_EVENT) - alc880_uniwill_p53_dcvol_automute(codec); -} - -/* FIXME! */ -/* - * F1734 pin configuration: - * HP = 0x14, speaker-out = 0x15, mic = 0x18 - */ -static struct hda_verb alc880_pin_f1734_init_verbs[] = { - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {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}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* FIXME! */ -/* - * ASUS pin configuration: - * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a - */ -static 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}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* Enable GPIO mask and set output */ -#define alc880_gpio1_init_verbs alc_gpio1_init_verbs -#define alc880_gpio2_init_verbs alc_gpio2_init_verbs - -/* Clevo m520g init */ -static struct hda_verb alc880_pin_clevo_init_verbs[] = { - /* headphone output */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* line-out */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line-in */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* CD */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic1 (rear panel) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic2 (front panel) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* headphone */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, - - { } -}; - -static 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}, - - /* Headphone output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Front output*/ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, - - { } -}; - -/* - * LG m1 express dual - * - * Pin assignment: - * Rear Line-In/Out (blue): 0x14 - * Build-in Mic-In: 0x15 - * Speaker-out: 0x17 - * HP-Out (green): 0x1b - * Mic-In/Out (red): 0x19 - * SPDIF-Out: 0x1e - */ - -/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */ -static 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 = { - .num_items = 3, - .items = { - { "Mic", 0x1 }, - { "Line", 0x5 }, - { "Internal Mic", 0x6 }, - }, -}; - -/* 2,4,6 channel modes */ -static 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[] = { - /* 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[] = { - /* 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] = { - { 2, alc880_lg_ch2_init }, - { 4, alc880_lg_ch4_init }, - { 6, alc880_lg_ch6_init }, -}; - -static struct snd_kcontrol_new alc880_lg_mixer[] = { - /* FIXME: it's not really "master" but front channels */ - HDA_CODEC_VOLUME("Master Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Master Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static 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)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* mute all amp mixer inputs */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, - /* line-in to input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* built-in mic */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* speaker-out */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* mic-in to input */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* HP-out */ - {0x13, AC_VERB_SET_CONNECT_SEL, 0x03}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x17, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x17, 1, HDA_OUTPUT, 0, - 0x80, bits); -} - -static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - if ((res >> 28) == 0x01) - alc880_lg_automute(codec); -} - -/* - * LG LW20 - * - * Pin assignment: - * Speaker-out: 0x14 - * Mic-In: 0x18 - * Built-in Mic-In: 0x19 (?) - * HP-Out: 0x1b - * SPDIF-Out: 0x1e - */ - -/* seems analog CD is not working */ -static struct hda_input_mux alc880_lg_lw_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - }, -}; - -static struct snd_kcontrol_new alc880_lg_lw_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), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - { } /* end */ -}; - -static struct hda_verb alc880_lg_lw_init_verbs[] = { - /* set capture source to mic-in */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, - /* speaker-out */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* HP-out */ - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* mic-in to input */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* built-in mic */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_lw_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); -} - -static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - if ((res >> 28) == 0x01) - alc880_lg_lw_automute(codec); -} - -/* - * Common callbacks - */ - -static int alc_init(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - unsigned int i; - - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); - - if (spec->init_hook) - spec->init_hook(codec); - - return 0; -} - -static void alc_unsol_event(struct hda_codec *codec, unsigned int res) -{ - struct alc_spec *spec = codec->spec; - - if (spec->unsol_event) - spec->unsol_event(codec, res); -} - -#ifdef CONFIG_PM -/* - * resume - */ -static int alc_resume(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - alc_init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; -} -#endif - -/* - * Analog playback callbacks - */ -static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); -} - -static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -/* - * Analog capture - */ -static int alc880_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 alc_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - 0, 0, 0); - return 0; -} - - -/* - */ -static struct hda_pcm_stream alc880_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc880_playback_pcm_open, - .prepare = alc880_playback_pcm_prepare, - .cleanup = alc880_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream alc880_pcm_analog_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .prepare = alc880_capture_pcm_prepare, - .cleanup = alc880_capture_pcm_cleanup - }, -}; - -static struct hda_pcm_stream alc880_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc880_dig_playback_pcm_open, - .close = alc880_dig_playback_pcm_close, - .prepare = alc880_dig_playback_pcm_prepare - }, -}; - -static struct hda_pcm_stream alc880_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -/* Used by alc_build_pcms to flag that a PCM has no playback stream */ -static struct hda_pcm_stream alc_pcm_null_playback = { - .substreams = 0, - .channels_min = 0, - .channels_max = 0, -}; - -static int alc_build_pcms(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - int i; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = spec->stream_name_analog; - if (spec->stream_analog_playback) { - snd_assert(spec->multiout.dac_nids, return -EINVAL); - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; - } - if (spec->stream_analog_capture) { - snd_assert(spec->adc_nids, return -EINVAL); - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - } - - if (spec->channel_mode) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; - for (i = 0; i < spec->num_channel_mode; i++) { - if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels; - } - } - } - - /* SPDIF for stream index #1 */ - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - codec->num_pcms = 2; - info = spec->pcm_rec + 1; - info->name = spec->stream_name_digital; - if (spec->multiout.dig_out_nid && - spec->stream_digital_playback) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback); - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid && - spec->stream_digital_capture) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture); - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - } - - /* If the use of more than one ADC is requested for the current - * model, configure a second analog capture-only PCM. - */ - /* Additional Analaog capture for index #2 */ - if (spec->num_adc_nids > 1 && spec->stream_analog_capture && - spec->adc_nids) { - codec->num_pcms = 3; - info = spec->pcm_rec + 2; - info->name = spec->stream_name_analog; - /* No playback stream for second PCM */ - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; - if (spec->stream_analog_capture) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1]; - } - } - - return 0; -} - -static void alc_free(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - unsigned int i; - - if (!spec) - return; - - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } - kfree(spec); -} - -/* - */ -static struct hda_codec_ops alc_patch_ops = { - .build_controls = alc_build_controls, - .build_pcms = alc_build_pcms, - .init = alc_init, - .free = alc_free, - .unsol_event = alc_unsol_event, -#ifdef CONFIG_PM - .resume = alc_resume, -#endif -}; - - -/* - * Test configuration for debugging - * - * Almost all inputs/outputs are enabled. I/O pins can be configured via - * enum controls. - */ -#ifdef CONFIG_SND_DEBUG -static hda_nid_t alc880_test_dac_nids[4] = { - 0x02, 0x03, 0x04, 0x05 -}; - -static struct hda_input_mux alc880_test_capture_source = { - .num_items = 7, - .items = { - { "In-1", 0x0 }, - { "In-2", 0x1 }, - { "In-3", 0x2 }, - { "In-4", 0x3 }, - { "CD", 0x4 }, - { "Front", 0x5 }, - { "Surround", 0x6 }, - }, -}; - -static struct hda_channel_mode alc880_test_modes[4] = { - { 2, NULL }, - { 4, NULL }, - { 6, NULL }, - { 8, NULL }, -}; - -static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { - "N/A", "Line Out", "HP Out", - "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item >= 8) - uinfo->value.enumerated.item = 7; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int pin_ctl, item = 0; - - pin_ctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pin_ctl & AC_PINCTL_OUT_EN) { - if (pin_ctl & AC_PINCTL_HP_EN) - item = 2; - else - item = 1; - } else if (pin_ctl & AC_PINCTL_IN_EN) { - switch (pin_ctl & AC_PINCTL_VREFEN) { - case AC_PINCTL_VREF_HIZ: item = 3; break; - case AC_PINCTL_VREF_50: item = 4; break; - case AC_PINCTL_VREF_GRD: item = 5; break; - case AC_PINCTL_VREF_80: item = 6; break; - case AC_PINCTL_VREF_100: item = 7; break; - } - } - ucontrol->value.enumerated.item[0] = item; - return 0; -} - -static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - static 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, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, - }; - unsigned int old_ctl, new_ctl; - - old_ctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - new_ctl = ctls[ucontrol->value.enumerated.item[0]]; - if (old_ctl != new_ctl) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - (ucontrol->value.enumerated.item[0] >= 3 ? - 0xb080 : 0xb000)); - return 1; - } - return 0; -} - -static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { - "Front", "Surround", "CLFE", "Side" - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int sel; - - sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); - ucontrol->value.enumerated.item[0] = sel & 3; - return 0; -} - -static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int sel; - - sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; - if (ucontrol->value.enumerated.item[0] != sel) { - sel = ucontrol->value.enumerated.item[0] & 3; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); - return 1; - } - return 0; -} - -#define PIN_CTL_TEST(xname,nid) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .info = alc_test_pin_ctl_info, \ - .get = alc_test_pin_ctl_get, \ - .put = alc_test_pin_ctl_put, \ - .private_value = nid \ - } - -#define PIN_SRC_TEST(xname,nid) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .info = alc_test_pin_src_info, \ - .get = alc_test_pin_src_get, \ - .put = alc_test_pin_src_put, \ - .private_value = nid \ - } - -static 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), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - PIN_CTL_TEST("Front Pin Mode", 0x14), - PIN_CTL_TEST("Surround Pin Mode", 0x15), - PIN_CTL_TEST("CLFE Pin Mode", 0x16), - PIN_CTL_TEST("Side Pin Mode", 0x17), - PIN_CTL_TEST("In-1 Pin Mode", 0x18), - PIN_CTL_TEST("In-2 Pin Mode", 0x19), - PIN_CTL_TEST("In-3 Pin Mode", 0x1a), - PIN_CTL_TEST("In-4 Pin Mode", 0x1b), - PIN_SRC_TEST("In-1 Pin Source", 0x18), - PIN_SRC_TEST("In-2 Pin Source", 0x19), - PIN_SRC_TEST("In-3 Pin Source", 0x1a), - PIN_SRC_TEST("In-4 Pin Source", 0x1b), - HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static 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)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Vol output for 0x0c-0x0f */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Set output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Unmute output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Set input pins 0x18-0x1c */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mute input pins 0x18-0x1b */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* ADC set up */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Analog input/passthru */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - { } -}; -#endif - -/* - */ - -static const char *alc880_models[ALC880_MODEL_LAST] = { - [ALC880_3ST] = "3stack", - [ALC880_TCL_S700] = "tcl", - [ALC880_3ST_DIG] = "3stack-digout", - [ALC880_CLEVO] = "clevo", - [ALC880_5ST] = "5stack", - [ALC880_5ST_DIG] = "5stack-digout", - [ALC880_W810] = "w810", - [ALC880_Z71V] = "z71v", - [ALC880_6ST] = "6stack", - [ALC880_6ST_DIG] = "6stack-digout", - [ALC880_ASUS] = "asus", - [ALC880_ASUS_W1V] = "asus-w1v", - [ALC880_ASUS_DIG] = "asus-dig", - [ALC880_ASUS_DIG2] = "asus-dig2", - [ALC880_UNIWILL_DIG] = "uniwill", - [ALC880_UNIWILL_P53] = "uniwill-p53", - [ALC880_FUJITSU] = "fujitsu", - [ALC880_F1734] = "F1734", - [ALC880_LG] = "lg", - [ALC880_LG_LW] = "lg-lw", -#ifdef CONFIG_SND_DEBUG - [ALC880_TEST] = "test", -#endif - [ALC880_AUTO] = "auto", -}; - -static struct snd_pci_quirk alc880_cfg_tbl[] = { - /* Broken BIOS configuration */ - SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), - SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), - - SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), - SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), - SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), - - SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), - SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST), - - SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), - SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V), - /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */ - SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS), - SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), - SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), - SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), - - SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), - SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), - SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), - SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), - SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), - SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), - SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), - SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), - - SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), - SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), - SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), - SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734), - - SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), - SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), - SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), - - SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), - SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), - SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), - SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), - - SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), - - {} -}; - -/* - * ALC880 codec presets - */ -static struct alc_config_preset alc880_presets[] = { - [ALC880_3ST] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_3ST_DIG] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_TCL_S700] = { - .mixers = { alc880_tcl_s700_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_tcl_S700_init_verbs, - alc880_gpio2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_5ST] = { - .mixers = { alc880_three_stack_mixer, - alc880_five_stack_mixer}, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_5stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), - .channel_mode = alc880_fivestack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_5ST_DIG] = { - .mixers = { alc880_three_stack_mixer, - alc880_five_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_5stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), - .channel_mode = alc880_fivestack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_6ST] = { - .mixers = { alc880_six_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), - .dac_nids = alc880_6st_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), - .channel_mode = alc880_sixstack_modes, - .input_mux = &alc880_6stack_capture_source, - }, - [ALC880_6ST_DIG] = { - .mixers = { alc880_six_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), - .dac_nids = alc880_6st_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), - .channel_mode = alc880_sixstack_modes, - .input_mux = &alc880_6stack_capture_source, - }, - [ALC880_W810] = { - .mixers = { alc880_w810_base_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_w810_init_verbs, - alc880_gpio2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), - .dac_nids = alc880_w810_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), - .channel_mode = alc880_w810_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_Z71V] = { - .mixers = { alc880_z71v_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_z71v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), - .dac_nids = alc880_z71v_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_F1734] = { - .mixers = { alc880_f1734_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_f1734_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), - .dac_nids = alc880_f1734_dac_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_DIG] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_DIG2] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio2_init_verbs }, /* use GPIO2 */ - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_W1V] = { - .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_UNIWILL_DIG] = { - .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_UNIWILL] = { - .mixers = { alc880_uniwill_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_unsol_event, - .init_hook = alc880_uniwill_automute, - }, - [ALC880_UNIWILL_P53] = { - .mixers = { alc880_uniwill_p53_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_p53_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), - .channel_mode = alc880_threestack_modes, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_hp_automute, - }, - [ALC880_FUJITSU] = { - .mixers = { alc880_fujitsu_mixer, - alc880_pcbeep_mixer, }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_p53_init_verbs, - alc880_beep_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_hp_automute, - }, - [ALC880_CLEVO] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_clevo_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_LG] = { - .mixers = { alc880_lg_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_lg_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids), - .dac_nids = alc880_lg_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), - .channel_mode = alc880_lg_ch_modes, - .need_dac_fix = 1, - .input_mux = &alc880_lg_capture_source, - .unsol_event = alc880_lg_unsol_event, - .init_hook = alc880_lg_automute, - }, - [ALC880_LG_LW] = { - .mixers = { alc880_lg_lw_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_lg_lw_init_verbs }, - .num_dacs = 1, - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_lg_lw_capture_source, - .unsol_event = alc880_lg_lw_unsol_event, - .init_hook = alc880_lg_lw_automute, - }, -#ifdef CONFIG_SND_DEBUG - [ALC880_TEST] = { - .mixers = { alc880_test_mixer }, - .init_verbs = { alc880_test_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), - .dac_nids = alc880_test_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_test_modes), - .channel_mode = alc880_test_modes, - .input_mux = &alc880_test_capture_source, - }, -#endif -}; - -/* - * Automatic parse of I/O pins from the BIOS configuration - */ - -#define NUM_CONTROL_ALLOC 32 -#define NUM_VERB_ALLOC 32 - -enum { - ALC_CTL_WIDGET_VOL, - ALC_CTL_WIDGET_MUTE, - ALC_CTL_BIND_MUTE, -}; -static 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), -}; - -/* add dynamic controls */ -static int add_control(struct alc_spec *spec, int type, const char *name, - unsigned long val) -{ - struct snd_kcontrol_new *knew; - size_t namelen = strlen(name) + 1; - - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - /* array + terminator */ - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); - if (!knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, - sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; - *knew = alc880_control_templates[type]; - knew->name = kmalloc(namelen, GFP_KERNEL); - if (!knew->name) - return -ENOMEM; - memcpy(knew->name, name, namelen); - knew->private_value = val; - spec->num_kctl_used++; - return 0; -} - -#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) -#define alc880_fixed_pin_idx(nid) ((nid) - 0x14) -#define alc880_is_multi_pin(nid) ((nid) >= 0x18) -#define alc880_multi_pin_idx(nid) ((nid) - 0x18) -#define alc880_is_input_pin(nid) ((nid) >= 0x18) -#define alc880_input_pin_idx(nid) ((nid) - 0x18) -#define alc880_idx_to_dac(nid) ((nid) + 0x02) -#define alc880_dac_to_idx(nid) ((nid) - 0x02) -#define alc880_idx_to_mixer(nid) ((nid) + 0x0c) -#define alc880_idx_to_selector(nid) ((nid) + 0x10) -#define ALC880_PIN_CD_NID 0x1c - -/* fill in the dac_nids table from the parsed pin configuration */ -static int alc880_auto_fill_dac_nids(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - hda_nid_t nid; - int assigned[4]; - int i, j; - - memset(assigned, 0, sizeof(assigned)); - spec->multiout.dac_nids = spec->private_dac_nids; - - /* check the pins hardwired to audio widget */ - for (i = 0; i < cfg->line_outs; i++) { - 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); - assigned[idx] = 1; - } - } - /* left pins can be connect to any audio widget */ - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - if (alc880_is_fixed_pin(nid)) - continue; - /* search for an empty channel */ - for (j = 0; j < cfg->line_outs; j++) { - if (!assigned[j]) { - spec->multiout.dac_nids[i] = - alc880_idx_to_dac(j); - assigned[j] = 1; - break; - } - } - } - spec->multiout.num_dacs = cfg->line_outs; - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - char name[32]; - static const char *chname[4] = { - "Front", "Surround", NULL /*CLFE*/, "Side" - }; - hda_nid_t nid; - int i, err; - - for (i = 0; i < cfg->line_outs; i++) { - if (!spec->multiout.dac_nids[i]) - continue; - nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); - if (i == 2) { - /* Center/LFE */ - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Center Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 2, - HDA_INPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 2, - HDA_INPUT)); - if (err < 0) - return err; - } else { - sprintf(name, "%s Playback Volume", chname[i]); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 2, - HDA_INPUT)); - if (err < 0) - return err; - } - } - return 0; -} - -/* add playback controls for speaker and HP outputs */ -static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, - const char *pfx) -{ - hda_nid_t nid; - int err; - char name[32]; - - if (!pin) - return 0; - - if (alc880_is_fixed_pin(pin)) { - nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); - /* specify the DAC as the extra output */ - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - else - spec->multiout.extra_out_nid[0] = nid; - /* control HP volume/switch on the output mixer amp */ - nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); - sprintf(name, "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); - if (err < 0) - return err; - } else if (alc880_is_multi_pin(pin)) { - /* set manual connection */ - /* we have only a switch on HP-out PIN */ - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - return 0; -} - -/* create input playback/capture controls for the given pin */ -static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, - const char *ctlname, - int idx, hda_nid_t mix_nid) -{ - char name[32]; - int err; - - sprintf(name, "%s Playback Volume", ctlname); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", ctlname); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - return 0; -} - -/* create playback/capture controls for input pins */ -static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - struct hda_input_mux *imux = &spec->private_imux; - int i, err, idx; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (alc880_is_input_pin(cfg->input_pins[i])) { - idx = alc880_input_pin_idx(cfg->input_pins[i]); - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], - idx, 0x0b); - if (err < 0) - return err; - imux->items[imux->num_items].label = - auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = - alc880_input_pin_idx(cfg->input_pins[i]); - imux->num_items++; - } - } - return 0; -} - -static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, int pin_type, - int dac_idx) -{ - /* set as output */ - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - pin_type); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - /* need the manual connection? */ - if (alc880_is_multi_pin(nid)) { - struct alc_spec *spec = codec->spec; - int idx = alc880_multi_pin_idx(nid); - snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, - AC_VERB_SET_CONNECT_SEL, - alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); - } -} - -static void alc880_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - alc_subsystem_id(codec, 0x15, 0x1b, 0x14); - for (i = 0; i < spec->autocfg.line_outs; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); - } -} - -static void alc880_auto_init_extra_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t pin; - - pin = spec->autocfg.speaker_pins[0]; - if (pin) /* connect to front */ - alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); -} - -static void alc880_auto_init_analog_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (alc880_is_input_pin(nid)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN); - if (nid != ALC880_PIN_CD_NID) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - } - } -} - -/* 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 - */ -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 }; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - alc880_ignore); - if (err < 0) - return err; - if (!spec->autocfg.line_outs) - return 0; /* can't find valid BIOS pin config */ - - err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); - if (err < 0) - return err; - err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - err = alc880_auto_create_extra_out(spec, - spec->autocfg.speaker_pins[0], - "Speaker"); - if (err < 0) - return err; - err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], - "Headphone"); - if (err < 0) - return err; - err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = ALC880_DIGIN_NID; - - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - - spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; - - spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; - - return 1; -} - -/* additional initialization for auto-configuration model */ -static void alc880_auto_init(struct hda_codec *codec) -{ - alc880_auto_init_multi_out(codec); - alc880_auto_init_extra_out(codec); - alc880_auto_init_analog_input(codec); -} - -/* - * OK, here we have finally the patch for ALC880 - */ - -static int patch_alc880(struct hda_codec *codec) -{ - struct alc_spec *spec; - int board_config; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST, - alc880_models, - alc880_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for ALC880, " - "trying auto-probe from BIOS...\n"); - board_config = ALC880_AUTO; - } - - if (board_config == ALC880_AUTO) { - /* automatic parse from the BIOS config */ - err = alc880_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using 3-stack mode...\n"); - board_config = ALC880_3ST; - } - } - - if (board_config != ALC880_AUTO) - setup_preset(spec, &alc880_presets[board_config]); - - spec->stream_name_analog = "ALC880 Analog"; - spec->stream_analog_playback = &alc880_pcm_analog_playback; - spec->stream_analog_capture = &alc880_pcm_analog_capture; - - spec->stream_name_digital = "ALC880 Digital"; - spec->stream_digital_playback = &alc880_pcm_digital_playback; - spec->stream_digital_capture = &alc880_pcm_digital_capture; - - if (!spec->adc_nids && spec->input_mux) { - /* check whether NID 0x07 is valid */ - unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]); - /* get type */ - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wcap != AC_WID_AUD_IN) { - spec->adc_nids = alc880_adc_nids_alt; - spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); - spec->mixers[spec->num_mixers] = - alc880_capture_alt_mixer; - spec->num_mixers++; - } else { - spec->adc_nids = alc880_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); - spec->mixers[spec->num_mixers] = alc880_capture_mixer; - spec->num_mixers++; - } - } - - codec->patch_ops = alc_patch_ops; - if (board_config == ALC880_AUTO) - spec->init_hook = alc880_auto_init; - - return 0; -} - - -/* - * ALC260 support - */ - -static hda_nid_t alc260_dac_nids[1] = { - /* front */ - 0x02, -}; - -static hda_nid_t alc260_adc_nids[1] = { - /* ADC0 */ - 0x04, -}; - -static hda_nid_t alc260_adc_nids_alt[1] = { - /* ADC1 */ - 0x05, -}; - -static hda_nid_t alc260_hp_adc_nids[2] = { - /* ADC1, 0 */ - 0x05, 0x04 -}; - -/* 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] = { - /* ADC0, ADC1 */ - 0x04, 0x05 -}; - -#define ALC260_DIGOUT_NID 0x03 -#define ALC260_DIGIN_NID 0x06 - -static struct hda_input_mux alc260_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack, - * headphone jack and the internal CD lines since these are the only pins at - * which audio can appear. For flexibility, also allow the option of - * 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] = { - { - .num_items = 3, - .items = { - { "Mic/Line", 0x0 }, - { "CD", 0x4 }, - { "Headphone", 0x2 }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic/Line", 0x0 }, - { "CD", 0x4 }, - { "Headphone", 0x2 }, - { "Mixer", 0x5 }, - }, - }, - -}; - -/* 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] = { - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Headphone", 0x5 }, - }, - }, - { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Headphone", 0x6 }, - { "Mixer", 0x5 }, - }, - }, -}; -/* - * This is just place-holder, so there's something for alc_build_pcms to look - * at when it calculates the maximum number of channels. ALC260 has no mixer - * element which allows changing the channel mode, so the verb list is - * never used. - */ -static struct hda_channel_mode alc260_modes[1] = { - { 2, NULL }, -}; - - -/* Mixer combinations - * - * basic: base_output + input + pc_beep + capture - * HP: base_output + input + capture_alt - * HP_3013: hp_3013 + input + capture - * fujitsu: fujitsu + capture - * acer: acer + capture - */ - -static 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), - HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), - { } /* end */ -}; - -static 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), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc260_pc_beep_mixer[] = { - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("iSpeaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("iSpeaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -/* 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[] = { - 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), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT), - { } /* end */ -}; - -/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current - * versions of the ALC260 don't act on requests to enable mic bias from NID - * 0x0f (used to drive the headphone jack in these laptops). The ALC260 - * datasheet doesn't mention this restriction. At this stage it's not clear - * whether this behaviour is intentional or is a hardware bug in chip - * revisions available in early 2006. Therefore for now allow the - * "Headphone Jack Mode" control to span all choices, but if it turns out - * that the lack of mic bias for this NID is intentional we could change the - * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. - * - * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006 - * don't appear to make the mic bias available from the "line" jack, even - * though the NID used for this jack (0x14) can supply it. The theory is - * that perhaps Acer have included blocking capacitors between the ALC260 - * and the output jack. If this turns out to be the case for all such - * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT - * to ALC_PIN_DIR_INOUT_NOMICBIAS. - * - * The C20x Tablet series have a mono internal speaker which is controlled - * via the chip's Mono sum widget and pin complex, so include the necessary - * controls for such models. On models without a "mono speaker" the control - * won't do anything. - */ -static 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), - HDA_CODEC_VOLUME_MONO("Mono Speaker Playback Volume", 0x0a, 1, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Mono Speaker Playback Switch", 0x0a, 1, 2, - HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), - { } /* end */ -}; - -/* 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[] = { - 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), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), - { } /* end */ -}; - -/* 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[] = { - 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), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - { } /* end */ -}; - -/* capture mixer elements */ -static struct snd_kcontrol_new alc260_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc260_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -/* - * initialization verbs - */ -static 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 */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* LINE-2 is used for line-out in rear */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* select line-out */ - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* LINE-OUT pin */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* enable HP */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* enable Mono */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to line in (default select for this ADC) */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* mute capture amp left and right */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to line in (default select for this ADC) */ - {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* set vol=0 Line-Out mixer amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 HP mixer amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 Mono mixer amp left and right */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* unmute LINE-2 out pin */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & - * Line In 2 = 0x03 - */ - /* mute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* mute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* mute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* mute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* mute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* mute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - { } -}; - -#if 0 /* should be identical with alc260_init_verbs? */ -static struct hda_verb alc260_hp_init_verbs[] = { - /* Headphone and output */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - /* mono output */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Line In pin widget for input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* Line-2 pin widget for output */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* CD pin widget for input */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* unmute amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* unmute Line-Out mixer amp left and right (volume = 0) */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute HP mixer amp left and right (volume = 0) */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & - * Line In 2 = 0x03 - */ - /* unmute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* unmute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - { } -}; -#endif - -static struct hda_verb alc260_hp_3013_init_verbs[] = { - /* Line out and output */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* mono output */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* Line In pin widget for input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* Headphone pin widget for output */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - /* CD pin widget for input */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - /* unmute amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* unmute Line-Out mixer amp left and right (volume = 0) */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute HP mixer amp left and right (volume = 0) */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & - * Line In 2 = 0x03 - */ - /* unmute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* unmute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - { } -}; - -/* Initialisation sequence for ALC260 as configured in Fujitsu S702x - * 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[] = { - /* Disable all GPIOs */ - {0x01, AC_VERB_SET_GPIO_MASK, 0}, - /* Internal speaker is connected to headphone pin */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Headphone/Line-out jack connects to Line1 pin; make it an output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Ensure all other unused pins are disabled and muted. */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure Line1 pin widget takes its input from the OUT1 sum bus - * when acting as an output. - */ - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Line1 pin widget output buffer since it starts as an output. - * If the pin mode is changed by the user the pin mode control will - * take care of enabling the pin's input/output buffers as needed. - * Therefore there's no need to enable the input buffer at this - * stage. - */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute input buffer of pin widget used for Line-in (no equiv - * mixer ctrl) - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting - line - * in (on mic1 pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do the same for the second ADC: mute capture input amp and - * set ADC connection to line in (on mic1 pin) - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; - -/* 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[] = { - /* 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. - */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - /* Internal speaker/Headphone jack is connected to Line-out pin */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Internal microphone/Mic jack is connected to Mic1 pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - /* Line In jack is connected to Line1 pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Ensure all other unused pins are disabled and muted. */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum - * bus when acting as outputs. - */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute Line-out pin widget amp left and right - * (no equiv mixer ctrl) - */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute mono pin widget amp output (no equiv mixer ctrl) */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Mic1 and Line1 pin widget input buffers since they start as - * inputs. If the pin mode is changed by the user the pin mode control - * will take care of enabling the pin's input/output buffers as needed. - * Therefore there's no need to enable the input buffer at this - * stage. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting - mic - * (on mic1 pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do similar with the second ADC: mute capture input amp and - * set ADC connection to mic to match ALSA's default state. - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; - -static 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}, - {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x1a, AC_VERB_SET_PROC_COEF, 0x3040}, - {} -}; - -static 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}, - - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, - - {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, - {} -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc260_replacer_672v_automute(struct hda_codec *codec) -{ - unsigned int present; - - /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */ - present = snd_hda_codec_read(codec, 0x0f, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - if (present) { - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 1); - snd_hda_codec_write(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); - } else { - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); - snd_hda_codec_write(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - } -} - -static void alc260_replacer_672v_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc260_replacer_672v_automute(codec); -} - -/* Test configuration for debugging, modelled after the ALC880 test - * configuration. - */ -#ifdef CONFIG_SND_DEBUG -static hda_nid_t alc260_test_dac_nids[1] = { - 0x02, -}; -static 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] = { - { - .num_items = 7, - .items = { - { "MIC1 pin", 0x0 }, - { "MIC2 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "LINE2 pin", 0x3 }, - { "CD pin", 0x4 }, - { "LINE-OUT pin", 0x5 }, - { "HP-OUT pin", 0x6 }, - }, - }, - { - .num_items = 8, - .items = { - { "MIC1 pin", 0x0 }, - { "MIC2 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "LINE2 pin", 0x3 }, - { "CD pin", 0x4 }, - { "Mixer", 0x5 }, - { "LINE-OUT pin", 0x6 }, - { "HP-OUT pin", 0x7 }, - }, - }, -}; -static 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), - HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT), - HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT), - - /* Modes for retasking pin widgets - * Note: the ALC260 doesn't seem to act on requests to enable mic - * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't - * mention this restriction. At this stage it's not clear whether - * this behaviour is intentional or is a hardware bug in chip - * revisions available at least up until early 2006. Therefore for - * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all - * choices, but if it turns out that the lack of mic bias for these - * NIDs is intentional we could change their modes from - * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. - */ - ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT), - - /* Loopback mixer controls */ - HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT), - HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT), - - /* Controls for GPIO pins, assuming they are configured as outputs */ - ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), - ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), - ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), - ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), - - /* Switches to allow the digital IO pins to be enabled. The datasheet - * is ambigious as to which NID is which; testing on laptops which - * make this output available should provide clarification. - */ - ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), - ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), - - { } /* end */ -}; -static 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}, - {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, - - /* Enable retasking pins as output, initially without power amp */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x0f, 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}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the - * OUT1 sum bus when acting as an output. - */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0c, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Also unmute the mono-out pin widget */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do the same for the second ADC: mute capture input amp and - * set ADC connection to mic1 pin - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; -#endif - -static struct hda_pcm_stream alc260_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -static struct hda_pcm_stream alc260_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -#define alc260_pcm_digital_playback alc880_pcm_digital_playback -#define alc260_pcm_digital_capture alc880_pcm_digital_capture - -/* - * for BIOS auto-configuration - */ - -static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid, - const char *pfx) -{ - hda_nid_t nid_vol; - unsigned long vol_val, sw_val; - char name[32]; - int err; - - if (nid >= 0x0f && nid < 0x11) { - nid_vol = nid - 0x7; - vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); - sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - } else if (nid == 0x11) { - nid_vol = nid - 0x7; - vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT); - sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); - } else if (nid >= 0x12 && nid <= 0x15) { - nid_vol = 0x08; - vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); - sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - } else - return 0; /* N/A */ - - snprintf(name, sizeof(name), "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val); - if (err < 0) - return err; - snprintf(name, sizeof(name), "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val); - if (err < 0) - return err; - return 1; -} - -/* add playback controls from the parsed DAC table */ -static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - hda_nid_t nid; - int err; - - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.dac_nids[0] = 0x02; - - nid = cfg->line_out_pins[0]; - if (nid) { - err = alc260_add_playback_controls(spec, nid, "Front"); - if (err < 0) - return err; - } - - nid = cfg->speaker_pins[0]; - if (nid) { - err = alc260_add_playback_controls(spec, nid, "Speaker"); - if (err < 0) - return err; - } - - nid = cfg->hp_pins[0]; - if (nid) { - err = alc260_add_playback_controls(spec, nid, "Headphone"); - if (err < 0) - return err; - } - return 0; -} - -/* create playback/capture controls for input pins */ -static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - struct hda_input_mux *imux = &spec->private_imux; - int i, err, idx; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (cfg->input_pins[i] >= 0x12) { - idx = cfg->input_pins[i] - 0x12; - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], idx, - 0x07); - if (err < 0) - return err; - imux->items[imux->num_items].label = - auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } - if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){ - idx = cfg->input_pins[i] - 0x09; - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], idx, - 0x07); - if (err < 0) - return err; - imux->items[imux->num_items].label = - auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } - } - return 0; -} - -static void alc260_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, int pin_type, - int sel_idx) -{ - /* set as output */ - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - pin_type); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - /* need the manual connection? */ - if (nid >= 0x12) { - int idx = nid - 0x12; - snd_hda_codec_write(codec, idx + 0x0b, 0, - AC_VERB_SET_CONNECT_SEL, sel_idx); - } -} - -static void alc260_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid; - - alc_subsystem_id(codec, 0x10, 0x15, 0x0f); - nid = spec->autocfg.line_out_pins[0]; - if (nid) - alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); - - nid = spec->autocfg.speaker_pins[0]; - if (nid) - alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); - - nid = spec->autocfg.hp_pins[0]; - if (nid) - alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); -} - -#define ALC260_PIN_CD_NID 0x16 -static void alc260_auto_init_analog_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (nid >= 0x12) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN); - if (nid != ALC260_PIN_CD_NID) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - } - } -} - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc260_volume_init_verbs[] = { - /* - * Unmute ADC0-1 and set the default input to mic-in - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output mixers (0x08 - 0x0a) - */ - /* set vol=0 to output mixers */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - { } -}; - -static int alc260_parse_auto_config(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - unsigned int wcap; - int err; - static hda_nid_t alc260_ignore[] = { 0x17, 0 }; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - alc260_ignore); - if (err < 0) - return err; - err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - if (!spec->kctl_alloc) - return 0; /* can't find valid BIOS pin config */ - err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - - spec->multiout.max_channels = 2; - - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - - spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs; - - spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; - - /* check whether NID 0x04 is valid */ - wcap = get_wcaps(codec, 0x04); - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ - if (wcap != AC_WID_AUD_IN) { - spec->adc_nids = alc260_adc_nids_alt; - spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); - spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer; - } else { - spec->adc_nids = alc260_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); - spec->mixers[spec->num_mixers] = alc260_capture_mixer; - } - spec->num_mixers++; - - return 1; -} - -/* additional initialization for auto-configuration model */ -static void alc260_auto_init(struct hda_codec *codec) -{ - alc260_auto_init_multi_out(codec); - alc260_auto_init_analog_input(codec); -} - -/* - * ALC260 configurations - */ -static const char *alc260_models[ALC260_MODEL_LAST] = { - [ALC260_BASIC] = "basic", - [ALC260_HP] = "hp", - [ALC260_HP_3013] = "hp-3013", - [ALC260_FUJITSU_S702X] = "fujitsu", - [ALC260_ACER] = "acer", - [ALC260_WILL] = "will", - [ALC260_REPLACER_672V] = "replacer", -#ifdef CONFIG_SND_DEBUG - [ALC260_TEST] = "test", -#endif - [ALC260_AUTO] = "auto", -}; - -static struct snd_pci_quirk alc260_cfg_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), - SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), - SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP), - SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), - SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP), - SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP), - SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), - SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), - SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), - SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), - {} -}; - -static struct alc_config_preset alc260_presets[] = { - [ALC260_BASIC] = { - .mixers = { alc260_base_output_mixer, - alc260_input_mixer, - alc260_pc_beep_mixer, - alc260_capture_mixer }, - .init_verbs = { alc260_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), - .adc_nids = alc260_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - }, - [ALC260_HP] = { - .mixers = { alc260_base_output_mixer, - alc260_input_mixer, - alc260_capture_alt_mixer }, - .init_verbs = { alc260_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), - .adc_nids = alc260_hp_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - }, - [ALC260_HP_3013] = { - .mixers = { alc260_hp_3013_mixer, - alc260_input_mixer, - alc260_capture_alt_mixer }, - .init_verbs = { alc260_hp_3013_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), - .adc_nids = alc260_hp_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - }, - [ALC260_FUJITSU_S702X] = { - .mixers = { alc260_fujitsu_mixer, - alc260_capture_mixer }, - .init_verbs = { alc260_fujitsu_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources), - .input_mux = alc260_fujitsu_capture_sources, - }, - [ALC260_ACER] = { - .mixers = { alc260_acer_mixer, - alc260_capture_mixer }, - .init_verbs = { alc260_acer_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources), - .input_mux = alc260_acer_capture_sources, - }, - [ALC260_WILL] = { - .mixers = { alc260_will_mixer, - alc260_capture_mixer }, - .init_verbs = { alc260_init_verbs, alc260_will_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), - .adc_nids = alc260_adc_nids, - .dig_out_nid = ALC260_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - }, - [ALC260_REPLACER_672V] = { - .mixers = { alc260_replacer_672v_mixer, - alc260_capture_mixer }, - .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), - .adc_nids = alc260_adc_nids, - .dig_out_nid = ALC260_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - .unsol_event = alc260_replacer_672v_unsol_event, - .init_hook = alc260_replacer_672v_automute, - }, -#ifdef CONFIG_SND_DEBUG - [ALC260_TEST] = { - .mixers = { alc260_test_mixer, - alc260_capture_mixer }, - .init_verbs = { alc260_test_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), - .dac_nids = alc260_test_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids), - .adc_nids = alc260_test_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources), - .input_mux = alc260_test_capture_sources, - }, -#endif -}; - -static int patch_alc260(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err, board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST, - alc260_models, - alc260_cfg_tbl); - if (board_config < 0) { - snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, " - "trying auto-probe from BIOS...\n"); - board_config = ALC260_AUTO; - } - - if (board_config == ALC260_AUTO) { - /* automatic parse from the BIOS config */ - err = alc260_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC260_BASIC; - } - } - - if (board_config != ALC260_AUTO) - setup_preset(spec, &alc260_presets[board_config]); - - spec->stream_name_analog = "ALC260 Analog"; - spec->stream_analog_playback = &alc260_pcm_analog_playback; - spec->stream_analog_capture = &alc260_pcm_analog_capture; - - spec->stream_name_digital = "ALC260 Digital"; - spec->stream_digital_playback = &alc260_pcm_digital_playback; - spec->stream_digital_capture = &alc260_pcm_digital_capture; - - codec->patch_ops = alc_patch_ops; - if (board_config == ALC260_AUTO) - spec->init_hook = alc260_auto_init; - - return 0; -} - - -/* - * ALC882 support - * - * ALC882 is almost identical with ALC880 but has cleaner and more flexible - * configuration. Each pin widget can choose any input DACs and a mixer. - * Each ADC is connected from a mixer of all inputs. This makes possible - * 6-channel independent captures. - * - * In addition, an independent DAC for the multi-playback (not used in this - * driver yet). - */ -#define ALC882_DIGOUT_NID 0x06 -#define ALC882_DIGIN_NID 0x0a - -static struct hda_channel_mode alc882_ch_modes[1] = { - { 8, NULL } -}; - -static hda_nid_t alc882_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -/* identical with ALC880 */ -#define alc882_adc_nids alc880_adc_nids -#define alc882_adc_nids_alt alc880_adc_nids_alt - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ - -static struct hda_input_mux alc882_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; -#define alc882_mux_enum_info alc_mux_enum_info -#define alc882_mux_enum_get alc_mux_enum_get - -static int alc882_mux_enum_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; - const struct hda_input_mux *imux = spec->input_mux; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; - hda_nid_t nid = capture_mixers[adc_idx]; - unsigned int *cur_val = &spec->cur_mux[adc_idx]; - unsigned int i, idx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) - return 0; - for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); - } - *cur_val = idx; - return 1; -} - -/* - * 6ch mode - */ -static 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 }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static 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 }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static struct hda_channel_mode alc882_sixstack_modes[2] = { - { 6, alc882_sixstack_ch6_init }, - { 8, alc882_sixstack_ch8_init }, -}; - -/* 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[] = { - 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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc882_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static struct hda_verb alc882_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)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Rear Pin: output 1 (0x0d) */ - {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}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {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}, - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* 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)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* ADC1: mute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - { } -}; - -static struct hda_verb alc882_eapd_verbs[] = { - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, - { } -}; - -/* Mac Pro test */ -static 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), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT), - { } /* end */ -}; - -static 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)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin: output 0 (0x0c) */ - {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, 0x00}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Speaker: output */ - {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, 0x04}, - /* Headphone output (output 0 - 0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* 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)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* ADC1: mute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - { } -}; - -static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) -{ - unsigned int gpiostate, gpiomask, gpiodir; - - gpiostate = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - - if (!muted) - gpiostate |= (1 << pin); - else - gpiostate &= ~(1 << pin); - - gpiomask = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_MASK, 0); - gpiomask |= (1 << pin); - - gpiodir = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DIRECTION, 0); - gpiodir |= (1 << pin); - - - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, gpiomask); - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, gpiodir); - - msleep(1); - - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, gpiostate); -} - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc882_auto_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output mixers (0x0c - 0x0f) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {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)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - - { } -}; - -/* capture mixer elements */ -static struct snd_kcontrol_new alc882_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc882_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, - { } /* end */ -}; - -/* pcm configuration: identiacal with ALC880 */ -#define alc882_pcm_analog_playback alc880_pcm_analog_playback -#define alc882_pcm_analog_capture alc880_pcm_analog_capture -#define alc882_pcm_digital_playback alc880_pcm_digital_playback -#define alc882_pcm_digital_capture alc880_pcm_digital_capture - -/* - * configuration and preset - */ -static const char *alc882_models[ALC882_MODEL_LAST] = { - [ALC882_3ST_DIG] = "3stack-dig", - [ALC882_6ST_DIG] = "6stack-dig", - [ALC882_ARIMA] = "arima", - [ALC885_MACPRO] = "macpro", - [ALC882_AUTO] = "auto", -}; - -static struct snd_pci_quirk alc882_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), - SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), - {} -}; - -static struct alc_config_preset alc882_presets[] = { - [ALC882_3ST_DIG] = { - .mixers = { alc882_base_mixer }, - .init_verbs = { alc882_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), - .channel_mode = alc882_ch_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - }, - [ALC882_6ST_DIG] = { - .mixers = { alc882_base_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), - .channel_mode = alc882_sixstack_modes, - .input_mux = &alc882_capture_source, - }, - [ALC882_ARIMA] = { - .mixers = { alc882_base_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs, alc882_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), - .channel_mode = alc882_sixstack_modes, - .input_mux = &alc882_capture_source, - }, - [ALC885_MACPRO] = { - .mixers = { alc882_macpro_mixer }, - .init_verbs = { alc882_macpro_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), - .channel_mode = alc882_ch_modes, - .input_mux = &alc882_capture_source, - }, -}; - - -/* - * BIOS auto configuration - */ -static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, int pin_type, - int dac_idx) -{ - /* set as output */ - struct alc_spec *spec = codec->spec; - int idx; - - if (spec->multiout.dac_nids[dac_idx] == 0x25) - idx = 4; - else - idx = spec->multiout.dac_nids[dac_idx] - 2; - - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - pin_type); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); - -} - -static void alc882_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - alc_subsystem_id(codec, 0x15, 0x1b, 0x14); - for (i = 0; i <= HDA_SIDE; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - if (nid) - alc882_auto_set_output_and_unmute(codec, nid, PIN_OUT, - i); - } -} - -static void alc882_auto_init_hp_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t pin; - - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - /* use dac 0 */ - alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); -} - -#define alc882_is_input_pin(nid) alc880_is_input_pin(nid) -#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID - -static void alc882_auto_init_analog_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (alc882_is_input_pin(nid)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN); - if (nid != ALC882_PIN_CD_NID) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - } - } -} - -/* almost identical with ALC880 parser... */ -static int alc882_parse_auto_config(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int err = alc880_parse_auto_config(codec); - - if (err < 0) - return err; - else if (err > 0) - /* hack - override the init verbs */ - spec->init_verbs[0] = alc882_auto_init_verbs; - return err; -} - -/* additional initialization for auto-configuration model */ -static void alc882_auto_init(struct hda_codec *codec) -{ - alc882_auto_init_multi_out(codec); - alc882_auto_init_hp_out(codec); - alc882_auto_init_analog_input(codec); -} - -static int patch_alc882(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err, board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST, - alc882_models, - alc882_cfg_tbl); - - if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { - /* Pick up systems that don't supply PCI SSID */ - switch (codec->subsystem_id) { - case 0x106b0c00: /* Mac Pro */ - board_config = ALC885_MACPRO; - break; - default: - printk(KERN_INFO "hda_codec: Unknown model for ALC882, " - "trying auto-probe from BIOS...\n"); - board_config = ALC882_AUTO; - } - } - - if (board_config == ALC882_AUTO) { - /* automatic parse from the BIOS config */ - err = alc882_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC882_3ST_DIG; - } - } - - if (board_config != ALC882_AUTO) - setup_preset(spec, &alc882_presets[board_config]); - - if (board_config == ALC885_MACPRO) { - alc882_gpio_mute(codec, 0, 0); - alc882_gpio_mute(codec, 1, 0); - } - - spec->stream_name_analog = "ALC882 Analog"; - spec->stream_analog_playback = &alc882_pcm_analog_playback; - spec->stream_analog_capture = &alc882_pcm_analog_capture; - - spec->stream_name_digital = "ALC882 Digital"; - spec->stream_digital_playback = &alc882_pcm_digital_playback; - spec->stream_digital_capture = &alc882_pcm_digital_capture; - - if (!spec->adc_nids && spec->input_mux) { - /* check whether NID 0x07 is valid */ - unsigned int wcap = get_wcaps(codec, 0x07); - /* get type */ - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wcap != AC_WID_AUD_IN) { - spec->adc_nids = alc882_adc_nids_alt; - spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt); - spec->mixers[spec->num_mixers] = - alc882_capture_alt_mixer; - spec->num_mixers++; - } else { - spec->adc_nids = alc882_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); - spec->mixers[spec->num_mixers] = alc882_capture_mixer; - spec->num_mixers++; - } - } - - codec->patch_ops = alc_patch_ops; - if (board_config == ALC882_AUTO) - spec->init_hook = alc882_auto_init; - - return 0; -} - -/* - * ALC883 support - * - * ALC883 is almost identical with ALC880 but has cleaner and more flexible - * configuration. Each pin widget can choose any input DACs and a mixer. - * Each ADC is connected from a mixer of all inputs. This makes possible - * 6-channel independent captures. - * - * In addition, an independent DAC for the multi-playback (not used in this - * driver yet). - */ -#define ALC883_DIGOUT_NID 0x06 -#define ALC883_DIGIN_NID 0x0a - -static hda_nid_t alc883_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x04, 0x03, 0x05 -}; - -static hda_nid_t alc883_adc_nids[2] = { - /* ADC1-2 */ - 0x08, 0x09, -}; - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ - -static struct hda_input_mux alc883_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static struct hda_input_mux alc883_lenovo_101e_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -#define alc883_mux_enum_info alc_mux_enum_info -#define alc883_mux_enum_get alc_mux_enum_get - -static int alc883_mux_enum_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; - const struct hda_input_mux *imux = spec->input_mux; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; - hda_nid_t nid = capture_mixers[adc_idx]; - unsigned int *cur_val = &spec->cur_mux[adc_idx]; - unsigned int i, idx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) - return 0; - for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); - } - *cur_val = idx; - return 1; -} - -/* - * 2ch mode - */ -static struct hda_channel_mode alc883_3ST_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 2ch mode - */ -static struct hda_verb alc883_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 }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static struct hda_verb alc883_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 }, - { 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 }, - { } /* end */ -}; - -static struct hda_channel_mode alc883_3ST_6ch_modes[2] = { - { 2, alc883_3ST_ch2_init }, - { 6, alc883_3ST_ch6_init }, -}; - -/* - * 6ch mode - */ -static 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 }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static 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 }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static struct hda_channel_mode alc883_sixstack_modes[2] = { - { 6, alc883_sixstack_ch6_init }, - { 8, alc883_sixstack_ch8_init }, -}; - -static 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}, - { } -}; - -/* 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 alc883_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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, - }, - { } /* end */ -}; - -static 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), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, - }, - { } /* end */ -}; - -static 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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc883_fivestack_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc883_tagra_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, - }, - { } /* end */ -}; - -static 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("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc883_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static struct hda_verb alc883_init_verbs[] = { - /* ADC1: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC2: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* 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)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Rear Pin: output 1 (0x0d) */ - {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}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {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}, - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - { } -}; - -static struct hda_verb alc883_tagra_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x03}, - - { } /* end */ -}; - -static 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 */ -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_tagra_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, - present ? 1 : 3); -} - -static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc883_tagra_automute(codec); -} - -static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); -} - -static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); -} - -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); -} - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc883_auto_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output mixers (0x0c - 0x0f) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {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)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* Input mixer2 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - { } -}; - -/* capture mixer elements */ -static struct snd_kcontrol_new alc883_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, - { } /* end */ -}; - -/* pcm configuration: identiacal with ALC880 */ -#define alc883_pcm_analog_playback alc880_pcm_analog_playback -#define alc883_pcm_analog_capture alc880_pcm_analog_capture -#define alc883_pcm_digital_playback alc880_pcm_digital_playback -#define alc883_pcm_digital_capture alc880_pcm_digital_capture - -/* - * configuration and preset - */ -static const char *alc883_models[ALC883_MODEL_LAST] = { - [ALC883_3ST_2ch_DIG] = "3stack-dig", - [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig", - [ALC883_3ST_6ch] = "3stack-6ch", - [ALC883_6ST_DIG] = "6stack-dig", - [ALC883_TARGA_DIG] = "targa-dig", - [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", - [ALC888_DEMO_BOARD] = "6stack-dig-demo", - [ALC883_ACER] = "acer", - [ALC883_MEDION] = "medion", - [ALC883_LAPTOP_EAPD] = "laptop-eapd", - [ALC883_LENOVO_101E_2ch] = "lenovo-101e", - [ALC883_AUTO] = "auto", -}; - -static struct snd_pci_quirk alc883_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG), - SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), - SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD), - SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), - SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), - SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), - SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), - SND_PCI_QUIRK(0x17aa, 0x101e, "lenovo 101e", ALC883_LENOVO_101E_2ch), - {} -}; - -static struct alc_config_preset alc883_presets[] = { - [ALC883_3ST_2ch_DIG] = { - .mixers = { alc883_3ST_2ch_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_3ST_6ch_DIG] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - }, - [ALC883_3ST_6ch] = { - .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - }, - [ALC883_6ST_DIG] = { - .mixers = { alc883_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_TARGA_DIG] = { - .mixers = { alc883_tagra_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - .unsol_event = alc883_tagra_unsol_event, - .init_hook = alc883_tagra_automute, - }, - [ALC883_TARGA_2ch_DIG] = { - .mixers = { alc883_tagra_2ch_mixer}, - .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc883_tagra_unsol_event, - .init_hook = alc883_tagra_automute, - }, - [ALC888_DEMO_BOARD] = { - .mixers = { alc883_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_ACER] = { - .mixers = { alc883_base_mixer, - alc883_chmode_mixer }, - /* 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. - */ - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_MEDION] = { - .mixers = { alc883_fivestack_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, - alc883_medion_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_LAPTOP_EAPD] = { - .mixers = { alc883_base_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - }, - [ALC883_LENOVO_101E_2ch] = { - .mixers = { alc883_lenovo_101e_2ch_mixer}, - .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, - .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, - }, -}; - - -/* - * BIOS auto configuration - */ -static void alc883_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, int pin_type, - int dac_idx) -{ - /* set as output */ - struct alc_spec *spec = codec->spec; - int idx; - - if (spec->multiout.dac_nids[dac_idx] == 0x25) - idx = 4; - else - idx = spec->multiout.dac_nids[dac_idx] - 2; - - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - pin_type); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); - -} - -static void alc883_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - alc_subsystem_id(codec, 0x15, 0x1b, 0x14); - for (i = 0; i <= HDA_SIDE; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - if (nid) - alc883_auto_set_output_and_unmute(codec, nid, PIN_OUT, - i); - } -} - -static void alc883_auto_init_hp_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t pin; - - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - /* use dac 0 */ - alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); -} - -#define alc883_is_input_pin(nid) alc880_is_input_pin(nid) -#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID - -static void alc883_auto_init_analog_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (alc883_is_input_pin(nid)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - (i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN)); - if (nid != ALC883_PIN_CD_NID) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - } - } -} - -/* almost identical with ALC880 parser... */ -static int alc883_parse_auto_config(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int err = alc880_parse_auto_config(codec); - - if (err < 0) - return err; - else if (err > 0) - /* hack - override the init verbs */ - spec->init_verbs[0] = alc883_auto_init_verbs; - spec->mixers[spec->num_mixers] = alc883_capture_mixer; - spec->num_mixers++; - return err; -} - -/* additional initialization for auto-configuration model */ -static void alc883_auto_init(struct hda_codec *codec) -{ - alc883_auto_init_multi_out(codec); - alc883_auto_init_hp_out(codec); - alc883_auto_init_analog_input(codec); -} - -static int patch_alc883(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err, board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, - alc883_models, - alc883_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for ALC883, " - "trying auto-probe from BIOS...\n"); - board_config = ALC883_AUTO; - } - - if (board_config == ALC883_AUTO) { - /* automatic parse from the BIOS config */ - err = alc883_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC883_3ST_2ch_DIG; - } - } - - if (board_config != ALC883_AUTO) - setup_preset(spec, &alc883_presets[board_config]); - - spec->stream_name_analog = "ALC883 Analog"; - spec->stream_analog_playback = &alc883_pcm_analog_playback; - spec->stream_analog_capture = &alc883_pcm_analog_capture; - - spec->stream_name_digital = "ALC883 Digital"; - spec->stream_digital_playback = &alc883_pcm_digital_playback; - spec->stream_digital_capture = &alc883_pcm_digital_capture; - - if (!spec->adc_nids && spec->input_mux) { - spec->adc_nids = alc883_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); - } - - codec->patch_ops = alc_patch_ops; - if (board_config == ALC883_AUTO) - spec->init_hook = alc883_auto_init; - - return 0; -} - -/* - * ALC262 support - */ - -#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID -#define ALC262_DIGIN_NID ALC880_DIGIN_NID - -#define alc262_dac_nids alc260_dac_nids -#define alc262_adc_nids alc882_adc_nids -#define alc262_adc_nids_alt alc882_adc_nids_alt - -#define alc262_modes alc260_modes -#define alc262_capture_source alc882_capture_source - -static 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), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */ - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc262_hippo1_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), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */ - /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/ - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), - { } /* end */ -}; - -static 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", 0x18, 0, HDA_INPUT), - { } /* end */ -}; - -#define alc262_capture_mixer alc882_capture_mixer -#define alc262_capture_alt_mixer alc882_capture_alt_mixer - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc262_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {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)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - - { } -}; - -static struct hda_verb alc262_hippo_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 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}, - - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hippo_automute(struct hda_codec *codec, int force) -{ - struct alc_spec *spec = codec->spec; - unsigned int mute; - - if (force || !spec->sense_updated) { - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - spec->sense_updated = 1; - } - if (spec->jack_present) { - /* mute internal speaker */ - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, 0x80); - } else { - /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x15, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - } -} - -/* unsolicited event for HP jack sensing */ -static void alc262_hippo_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hippo_automute(codec, 1); -} - -static void alc262_hippo1_automute(struct hda_codec *codec, int force) -{ - struct alc_spec *spec = codec->spec; - unsigned int mute; - - if (force || !spec->sense_updated) { - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - spec->sense_updated = 1; - } - if (spec->jack_present) { - /* mute internal speaker */ - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, 0x80); - } else { - /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x1b, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - } -} - -/* unsolicited event for HP jack sensing */ -static void alc262_hippo1_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hippo1_automute(codec, 1); -} - -/* - * fujitsu model - * 0x14 = headphone/spdif-out, 0x15 = internal speaker - */ - -#define ALC_HP_EVENT 0x37 - -static 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}, - {} -}; - -static struct hda_input_mux alc262_fujitsu_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "CD", 0x4 }, - }, -}; - -static struct hda_input_mux alc262_HP_capture_source = { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "AUX IN", 0x6 }, - }, -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_fujitsu_automute(struct hda_codec *codec, int force) -{ - struct alc_spec *spec = codec->spec; - unsigned int mute; - - if (force || !spec->sense_updated) { - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - spec->sense_updated = 1; - } - if (spec->jack_present) { - /* mute internal speaker */ - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, 0x80); - } else { - /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x14, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - } -} - -/* 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); -} - -/* bind volumes of both NID 0x0c and 0x0d */ -static int alc262_fujitsu_master_vol_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 = snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - 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 = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); - change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); - if (change || codec->in_resume) - alc262_fujitsu_automute(codec, codec->in_resume); - return change; -} - -static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = alc262_fujitsu_master_vol_put, -#ifdef FOUND_TLV - .tlv = { .c = snd_hda_mixer_amp_tlv }, -#endif - .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .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), - }, - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* additional init verbs for Benq laptops */ -static struct hda_verb alc262_EAPD_verbs[] = { - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, - {} -}; - -/* add playback controls from the parsed DAC table */ -static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - hda_nid_t nid; - int err; - - spec->multiout.num_dacs = 1; /* only use one dac */ - spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.dac_nids[0] = 2; - - nid = cfg->line_out_pins[0]; - if (nid) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Front Playback Volume", - HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Front Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - - nid = cfg->speaker_pins[0]; - if (nid) { - if (nid == 0x16) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Speaker Playback Volume", - HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Speaker Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } else { - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Speaker Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } - } - nid = cfg->hp_pins[0]; - if (nid) { - /* spec->multiout.hp_nid = 2; */ - if (nid == 0x16) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Headphone Playback Volume", - HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Headphone Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } else { - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Headphone Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } - } - return 0; -} - -/* identical with ALC880 */ -#define alc262_auto_create_analog_input_ctls \ - alc880_auto_create_analog_input_ctls - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc262_volume_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output mixers (0x0c - 0x0f) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {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)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - - { } -}; - -static struct hda_verb alc262_HP_BPC_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, - - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {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)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - - { } -}; - -static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for front - * panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, - /* - * Set up output mixers (0x0c - 0x0e) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {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)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */ - - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/ - /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/ - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, - - { } -}; - -/* pcm configuration: identiacal with ALC880 */ -#define alc262_pcm_analog_playback alc880_pcm_analog_playback -#define alc262_pcm_analog_capture alc880_pcm_analog_capture -#define alc262_pcm_digital_playback alc880_pcm_digital_playback -#define alc262_pcm_digital_capture alc880_pcm_digital_capture - -/* - * BIOS auto configuration - */ -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 }; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - alc262_ignore); - if (err < 0) - return err; - if (!spec->autocfg.line_outs) - return 0; /* can't find valid BIOS pin config */ - err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = ALC262_DIGOUT_NID; - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = ALC262_DIGIN_NID; - - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - - spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs; - spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; - - return 1; -} - -#define alc262_auto_init_multi_out alc882_auto_init_multi_out -#define alc262_auto_init_hp_out alc882_auto_init_hp_out -#define alc262_auto_init_analog_input alc882_auto_init_analog_input - - -/* init callback for auto-configuration model -- overriding the default init */ -static void alc262_auto_init(struct hda_codec *codec) -{ - alc262_auto_init_multi_out(codec); - alc262_auto_init_hp_out(codec); - alc262_auto_init_analog_input(codec); -} - -/* - * configuration and preset - */ -static const char *alc262_models[ALC262_MODEL_LAST] = { - [ALC262_BASIC] = "basic", - [ALC262_HIPPO] = "hippo", - [ALC262_HIPPO_1] = "hippo_1", - [ALC262_FUJITSU] = "fujitsu", - [ALC262_HP_BPC] = "hp-bpc", - [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", - [ALC262_BENQ_ED8] = "benq", - [ALC262_AUTO] = "auto", -}; - -static struct snd_pci_quirk alc262_cfg_tbl[] = { - SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), - SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), - SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), - SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), - SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), - SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), - SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), - SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), - {} -}; - -static struct alc_config_preset alc262_presets[] = { - [ALC262_BASIC] = { - .mixers = { alc262_base_mixer }, - .init_verbs = { alc262_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - }, - [ALC262_HIPPO] = { - .mixers = { alc262_base_mixer }, - .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs}, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, - }, - [ALC262_HIPPO_1] = { - .mixers = { alc262_hippo1_mixer }, - .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs}, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x02, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo1_unsol_event, - }, - [ALC262_FUJITSU] = { - .mixers = { alc262_fujitsu_mixer }, - .init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .dig_out_nid = ALC262_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_fujitsu_capture_source, - .unsol_event = alc262_fujitsu_unsol_event, - }, - [ALC262_HP_BPC] = { - .mixers = { alc262_HP_BPC_mixer }, - .init_verbs = { alc262_HP_BPC_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_HP_capture_source, - }, - [ALC262_HP_BPC_D7000_WF] = { - .mixers = { alc262_HP_BPC_WildWest_mixer }, - .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_HP_capture_source, - }, - [ALC262_HP_BPC_D7000_WL] = { - .mixers = { alc262_HP_BPC_WildWest_mixer, - alc262_HP_BPC_WildWest_option_mixer }, - .init_verbs = { alc262_HP_BPC_WildWest_init_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_HP_capture_source, - }, - [ALC262_BENQ_ED8] = { - .mixers = { alc262_base_mixer }, - .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, - .num_dacs = ARRAY_SIZE(alc262_dac_nids), - .dac_nids = alc262_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, - }, -}; - -static int patch_alc262(struct hda_codec *codec) -{ - struct alc_spec *spec; - int board_config; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; -#if 0 - /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is - * under-run - */ - { - int tmp; - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); - } -#endif - - board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST, - alc262_models, - alc262_cfg_tbl); - - if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for ALC262, " - "trying auto-probe from BIOS...\n"); - board_config = ALC262_AUTO; - } - - if (board_config == ALC262_AUTO) { - /* automatic parse from the BIOS config */ - err = alc262_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC262_BASIC; - } - } - - if (board_config != ALC262_AUTO) - setup_preset(spec, &alc262_presets[board_config]); - - spec->stream_name_analog = "ALC262 Analog"; - spec->stream_analog_playback = &alc262_pcm_analog_playback; - spec->stream_analog_capture = &alc262_pcm_analog_capture; - - spec->stream_name_digital = "ALC262 Digital"; - spec->stream_digital_playback = &alc262_pcm_digital_playback; - spec->stream_digital_capture = &alc262_pcm_digital_capture; - - if (!spec->adc_nids && spec->input_mux) { - /* check whether NID 0x07 is valid */ - unsigned int wcap = get_wcaps(codec, 0x07); - - /* get type */ - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wcap != AC_WID_AUD_IN) { - spec->adc_nids = alc262_adc_nids_alt; - spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt); - spec->mixers[spec->num_mixers] = - alc262_capture_alt_mixer; - spec->num_mixers++; - } else { - spec->adc_nids = alc262_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids); - spec->mixers[spec->num_mixers] = alc262_capture_mixer; - spec->num_mixers++; - } - } - - codec->patch_ops = alc_patch_ops; - if (board_config == ALC262_AUTO) - spec->init_hook = alc262_auto_init; - - return 0; -} - -/* - * ALC861 channel source setting (2/6 channel selection for 3-stack) - */ - -/* - * 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[] = { - /* 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 - * the vref - */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ -#endif - { } /* end */ -}; -/* - * 6ch mode - * need to set the codec line out and mic 1 pin widgets to outputs - */ -static 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)*/ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - - { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ -#endif - { } /* end */ -}; - -static 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[] = { - { 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[] = { - { 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] = { - { 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[] = { - /* 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 - * the vref - */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/ -#endif - { } /* end */ -}; -/* Set mic1 nad line-in as output and mute mixer */ -static 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 }, */ - /* set pin widget 18h (mic1) for output (CLFE)*/ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ - { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, - - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, -#if 0 - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/ -#endif - { } /* end */ -}; - -static 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[] = { - /* output mixer control */ - HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), - - /*Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -static 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), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ - - /* Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_threestack_modes), - }, - { } /* end */ -}; - -static 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), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - - /*Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - - { } /* end */ -}; - -static 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), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ - - /* Input mixer control */ - /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes), - }, - { } /* end */ -}; - -static 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), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), - - /* Input mixer control */ - HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), - - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - .private_value = ARRAY_SIZE(alc861_asus_modes), - }, - { } -}; - -/* additional mixer */ -static 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), - HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT), - { } -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc861_base_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - - { } -}; - -static struct hda_verb alc861_threestack_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -static struct hda_verb alc861_uniwill_m31_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - /* this has to be set to VREF80 */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -static struct hda_verb alc861_asus_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* port-A for surround (rear panel) - * according to codec#0 this is the HP jack - */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */ - /* route front PCM to HP */ - { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* port-D for Front */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-E for HP out (front panel) */ - /* this has to be set to VREF80 */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* route front mic to ADC1*/ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */ - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* hp used DAC 3 (Front) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - { } -}; - -/* additional init verbs for ASUS laptops */ -static 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 */ - { } -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc861_auto_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute DAC0~3 & spdif out*/ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute Mixer 14 (mic) 1c (Line in)*/ - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Stereo Mixer 15 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, - - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */ - - { } -}; - -static struct hda_verb alc861_toshiba_init_verbs[] = { - {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, - - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc861_toshiba_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x0f, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x16, 0, HDA_INPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x16, 1, HDA_INPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_INPUT, 3, - 0x80, present ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_INPUT, 3, - 0x80, present ? 0 : 0x80); -} - -static void alc861_toshiba_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc861_toshiba_automute(codec); -} - -/* pcm configuration: identiacal with ALC880 */ -#define alc861_pcm_analog_playback alc880_pcm_analog_playback -#define alc861_pcm_analog_capture alc880_pcm_analog_capture -#define alc861_pcm_digital_playback alc880_pcm_digital_playback -#define alc861_pcm_digital_capture alc880_pcm_digital_capture - - -#define ALC861_DIGOUT_NID 0x07 - -static struct hda_channel_mode alc861_8ch_modes[1] = { - { 8, NULL } -}; - -static hda_nid_t alc861_dac_nids[4] = { - /* front, surround, clfe, side */ - 0x03, 0x06, 0x05, 0x04 -}; - -static hda_nid_t alc660_dac_nids[3] = { - /* front, clfe, surround */ - 0x03, 0x05, 0x06 -}; - -static hda_nid_t alc861_adc_nids[1] = { - /* ADC0-2 */ - 0x08, -}; - -static struct hda_input_mux alc861_capture_source = { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x1 }, - { "CD", 0x4 }, - { "Mixer", 0x5 }, - }, -}; - -/* fill in the dac_nids table from the parsed pin configuration */ -static int alc861_auto_fill_dac_nids(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - int i; - hda_nid_t nid; - - spec->multiout.dac_nids = spec->private_dac_nids; - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - if (nid) { - if (i >= ARRAY_SIZE(alc861_dac_nids)) - continue; - spec->multiout.dac_nids[i] = alc861_dac_nids[i]; - } - } - spec->multiout.num_dacs = cfg->line_outs; - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - char name[32]; - static const char *chname[4] = { - "Front", "Surround", NULL /*CLFE*/, "Side" - }; - hda_nid_t nid; - int i, idx, err; - - for (i = 0; i < cfg->line_outs; i++) { - nid = spec->multiout.dac_nids[i]; - if (!nid) - continue; - if (nid == 0x05) { - /* Center/LFE */ - err = add_control(spec, ALC_CTL_BIND_MUTE, - "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } else { - for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1; - idx++) - if (nid == alc861_dac_nids[idx]) - break; - sprintf(name, "%s Playback Switch", chname[idx]); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } - } - return 0; -} - -static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) -{ - int err; - hda_nid_t nid; - - if (!pin) - return 0; - - if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) { - nid = 0x03; - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Headphone Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - spec->multiout.hp_nid = nid; - } - return 0; -} - -/* create playback/capture controls for input pins */ -static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - struct hda_input_mux *imux = &spec->private_imux; - int i, err, idx, idx1; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - switch (cfg->input_pins[i]) { - case 0x0c: - idx1 = 1; - idx = 2; /* Line In */ - break; - case 0x0f: - idx1 = 2; - idx = 2; /* Line In */ - break; - case 0x0d: - idx1 = 0; - idx = 1; /* Mic In */ - break; - case 0x10: - idx1 = 3; - idx = 1; /* Mic In */ - break; - case 0x11: - idx1 = 4; - idx = 0; /* CD */ - break; - default: - continue; - } - - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], idx, 0x15); - if (err < 0) - return err; - - imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = idx1; - imux->num_items++; - } - return 0; -} - -static struct snd_kcontrol_new alc861_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - *FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, - int pin_type, int dac_idx) -{ - /* set as output */ - - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - pin_type); - snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - -} - -static void alc861_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b); - for (i = 0; i < spec->autocfg.line_outs; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - if (nid) - alc861_auto_set_output_and_unmute(codec, nid, PIN_OUT, - spec->multiout.dac_nids[i]); - } -} - -static void alc861_auto_init_hp_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t pin; - - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, - spec->multiout.dac_nids[0]); -} - -static void alc861_auto_init_analog_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (nid >= 0x0c && nid <= 0x11) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN); - } - } -} - -/* 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 - */ -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 }; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - alc861_ignore); - if (err < 0) - return err; - if (!spec->autocfg.line_outs) - return 0; /* can't find valid BIOS pin config */ - - err = alc861_auto_fill_dac_nids(spec, &spec->autocfg); - if (err < 0) - return err; - err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); - if (err < 0) - return err; - err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; - - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - - spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs; - - spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; - - spec->adc_nids = alc861_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); - spec->mixers[spec->num_mixers] = alc861_capture_mixer; - spec->num_mixers++; - - return 1; -} - -/* additional initialization for auto-configuration model */ -static void alc861_auto_init(struct hda_codec *codec) -{ - alc861_auto_init_multi_out(codec); - alc861_auto_init_hp_out(codec); - alc861_auto_init_analog_input(codec); -} - - -/* - * configuration and preset - */ -static const char *alc861_models[ALC861_MODEL_LAST] = { - [ALC861_3ST] = "3stack", - [ALC660_3ST] = "3stack-660", - [ALC861_3ST_DIG] = "3stack-dig", - [ALC861_6ST_DIG] = "6stack-dig", - [ALC861_UNIWILL_M31] = "uniwill-m31", - [ALC861_TOSHIBA] = "toshiba", - [ALC861_ASUS] = "asus", - [ALC861_ASUS_LAPTOP] = "asus-laptop", - [ALC861_AUTO] = "auto", -}; - -static 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), - SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), - SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660_3ST), - SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), - SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), - SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), - SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), - SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST), - SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), - {} -}; - -static struct alc_config_preset alc861_presets[] = { - [ALC861_3ST] = { - .mixers = { alc861_3ST_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_3ST_DIG] = { - .mixers = { alc861_base_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_6ST_DIG] = { - .mixers = { alc861_base_mixer }, - .init_verbs = { alc861_base_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes), - .channel_mode = alc861_8ch_modes, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC660_3ST] = { - .mixers = { alc861_3ST_mixer }, - .init_verbs = { alc861_threestack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc660_dac_nids), - .dac_nids = alc660_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), - .channel_mode = alc861_threestack_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_UNIWILL_M31] = { - .mixers = { alc861_uniwill_m31_mixer }, - .init_verbs = { alc861_uniwill_m31_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes), - .channel_mode = alc861_uniwill_m31_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_TOSHIBA] = { - .mixers = { alc861_toshiba_mixer }, - .init_verbs = { alc861_base_init_verbs, - alc861_toshiba_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - .unsol_event = alc861_toshiba_unsol_event, - .init_hook = alc861_toshiba_automute, - }, - [ALC861_ASUS] = { - .mixers = { alc861_asus_mixer }, - .init_verbs = { alc861_asus_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861_asus_modes), - .channel_mode = alc861_asus_modes, - .need_dac_fix = 1, - .hp_nid = 0x06, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, - [ALC861_ASUS_LAPTOP] = { - .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer }, - .init_verbs = { alc861_asus_init_verbs, - alc861_asus_laptop_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861_dac_nids), - .dac_nids = alc861_dac_nids, - .dig_out_nid = ALC861_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .need_dac_fix = 1, - .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), - .adc_nids = alc861_adc_nids, - .input_mux = &alc861_capture_source, - }, -}; - - -static int patch_alc861(struct hda_codec *codec) -{ - struct alc_spec *spec; - int board_config; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST, - alc861_models, - alc861_cfg_tbl); - - if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for ALC861, " - "trying auto-probe from BIOS...\n"); - board_config = ALC861_AUTO; - } - - if (board_config == ALC861_AUTO) { - /* automatic parse from the BIOS config */ - err = alc861_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC861_3ST_DIG; - } - } - - if (board_config != ALC861_AUTO) - setup_preset(spec, &alc861_presets[board_config]); - - spec->stream_name_analog = "ALC861 Analog"; - spec->stream_analog_playback = &alc861_pcm_analog_playback; - spec->stream_analog_capture = &alc861_pcm_analog_capture; - - spec->stream_name_digital = "ALC861 Digital"; - spec->stream_digital_playback = &alc861_pcm_digital_playback; - spec->stream_digital_capture = &alc861_pcm_digital_capture; - - codec->patch_ops = alc_patch_ops; - if (board_config == ALC861_AUTO) - spec->init_hook = alc861_auto_init; - - return 0; -} - -/* - * ALC861-VD support - * - * Based on ALC882 - * - * In addition, an independent DAC - */ -#define ALC861VD_DIGOUT_NID 0x06 - -static hda_nid_t alc861vd_dac_nids[4] = { - /* front, surr, clfe, side surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -/* dac_nids for ALC660vd are in a different order - according to - * Realtek's driver. - * This should probably tesult in a different mixer for 6stack models - * of ALC660vd codecs, but for now there is only 3stack mixer - * - 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] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x04, 0x03 -}; - -static hda_nid_t alc861vd_adc_nids[1] = { - /* ADC0 */ - 0x09, -}; - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ -static struct hda_input_mux alc861vd_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -#define alc861vd_mux_enum_info alc_mux_enum_info -#define alc861vd_mux_enum_get alc_mux_enum_get - -static int alc861vd_mux_enum_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; - const struct hda_input_mux *imux = spec->input_mux; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - static hda_nid_t capture_mixers[1] = { 0x22 }; - hda_nid_t nid = capture_mixers[adc_idx]; - unsigned int *cur_val = &spec->cur_mux[adc_idx]; - unsigned int i, idx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) - return 0; - for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); - } - *cur_val = idx; - return 1; -} - -/* - * 2ch mode - */ -static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 6ch mode - */ -static 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 }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static 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 }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; - -static 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[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc861vd_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - *FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc861vd_mux_enum_info, - .get = alc861vd_mux_enum_get, - .put = alc861vd_mux_enum_put, - }, - { } /* end */ -}; - -/* 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[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - - { } /* end */ -}; - -static 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), - - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - - { } /* end */ -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc861vd_volume_init_verbs[] = { - /* - * Unmute ADC0 and set the default input to mic-in - */ - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of - * the analog-loopback mixer widget - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(8)}, - - /* - * Set up output mixers (0x02 - 0x05) - */ - /* set vol=0 to output mixers */ - {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}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - { } -}; - -/* - * 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[] = { - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 6-stack pin configuration: - */ -static struct hda_verb alc861vd_6stack_init_verbs[] = { - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Rear Pin: output 1 (0x0d) */ - {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}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {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}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* pcm configuration: identiacal with ALC880 */ -#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback -#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture -#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback -#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture - -/* - * configuration and preset - */ -static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { - [ALC660VD_3ST] = "3stack-660", - [ALC861VD_3ST] = "3stack", - [ALC861VD_3ST_DIG] = "3stack-digout", - [ALC861VD_6ST_DIG] = "6stack-digout", - [ALC861VD_AUTO] = "auto", -}; - -static struct snd_pci_quirk alc861vd_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), - SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST), - SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), - SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), - - SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_3ST), - {} -}; - -static struct alc_config_preset alc861vd_presets[] = { - [ALC660VD_3ST] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids), - .adc_nids = alc861vd_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_3ST] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_3ST_DIG] = { - .mixers = { alc861vd_3st_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - }, - [ALC861VD_6ST_DIG] = { - .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), - .dac_nids = alc861vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes), - .channel_mode = alc861vd_6stack_modes, - .input_mux = &alc861vd_capture_source, - }, -}; - -/* - * BIOS auto configuration - */ -static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, int pin_type, int dac_idx) -{ - /* set as output */ - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); -} - -static void alc861vd_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - alc_subsystem_id(codec, 0x15, 0x1b, 0x14); - for (i = 0; i <= HDA_SIDE; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - if (nid) - alc861vd_auto_set_output_and_unmute(codec, nid, - PIN_OUT, i); - } -} - - -static void alc861vd_auto_init_hp_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t pin; - - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front and use dac 0 */ - alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); -} - -#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid) -#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID - -static void alc861vd_auto_init_analog_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (alc861vd_is_input_pin(nid)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN); - if (nid != ALC861VD_PIN_CD_NID) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - } - } -} - -#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02) -#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c) - -/* add playback controls from the parsed DAC table */ -/* Based on ALC880 version. But ALC861VD has separate, - * different NIDs for mute/unmute switch and volume control */ -static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - char name[32]; - static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"}; - hda_nid_t nid_v, nid_s; - int i, err; - - for (i = 0; i < cfg->line_outs; i++) { - if (!spec->multiout.dac_nids[i]) - continue; - nid_v = alc861vd_idx_to_mixer_vol( - alc880_dac_to_idx( - spec->multiout.dac_nids[i])); - nid_s = alc861vd_idx_to_mixer_switch( - alc880_dac_to_idx( - spec->multiout.dac_nids[i])); - - if (i == 2) { - /* Center/LFE */ - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Center Playback Volume", - HDA_COMPOSE_AMP_VAL(nid_v, 1, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(nid_v, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(nid_s, 1, 2, - HDA_INPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(nid_s, 2, 2, - HDA_INPUT)); - if (err < 0) - return err; - } else { - sprintf(name, "%s Playback Volume", chname[i]); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid_v, 3, 2, - HDA_INPUT)); - if (err < 0) - return err; - } - } - return 0; -} - -/* add playback controls for speaker and HP outputs */ -/* Based on ALC880 version. But ALC861VD has separate, - * different NIDs for mute/unmute switch and volume control */ -static int alc861vd_auto_create_extra_out(struct alc_spec *spec, - hda_nid_t pin, const char *pfx) -{ - hda_nid_t nid_v, nid_s; - int err; - char name[32]; - - if (!pin) - return 0; - - if (alc880_is_fixed_pin(pin)) { - nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); - /* specify the DAC as the extra output */ - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = nid_v; - else - spec->multiout.extra_out_nid[0] = nid_v; - /* control HP volume/switch on the output mixer amp */ - nid_v = alc861vd_idx_to_mixer_vol( - alc880_fixed_pin_idx(pin)); - nid_s = alc861vd_idx_to_mixer_switch( - alc880_fixed_pin_idx(pin)); - - sprintf(name, "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT)); - if (err < 0) - return err; - } else if (alc880_is_multi_pin(pin)) { - /* set manual connection */ - /* we have only a switch on HP-out PIN */ - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - return 0; -} - -/* 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 - * Based on ALC880 version - had to change it to override - * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */ -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 }; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - alc861vd_ignore); - if (err < 0) - return err; - if (!spec->autocfg.line_outs) - return 0; /* can't find valid BIOS pin config */ - - err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); - if (err < 0) - return err; - err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - err = alc861vd_auto_create_extra_out(spec, - spec->autocfg.speaker_pins[0], - "Speaker"); - if (err < 0) - return err; - err = alc861vd_auto_create_extra_out(spec, - spec->autocfg.hp_pins[0], - "Headphone"); - if (err < 0) - return err; - err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; - - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - - spec->init_verbs[spec->num_init_verbs++] - = alc861vd_volume_init_verbs; - - spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; - - return 1; -} - -/* additional initialization for auto-configuration model */ -static void alc861vd_auto_init(struct hda_codec *codec) -{ - alc861vd_auto_init_multi_out(codec); - alc861vd_auto_init_hp_out(codec); - alc861vd_auto_init_analog_input(codec); -} - -static int patch_alc861vd(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err, board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST, - alc861vd_models, - alc861vd_cfg_tbl); - - if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) { - printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/" - "ALC861VD, trying auto-probe from BIOS...\n"); - board_config = ALC861VD_AUTO; - } - - if (board_config == ALC861VD_AUTO) { - /* automatic parse from the BIOS config */ - err = alc861vd_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC861VD_3ST; - } - } - - if (board_config != ALC861VD_AUTO) - setup_preset(spec, &alc861vd_presets[board_config]); - - spec->stream_name_analog = "ALC861VD Analog"; - spec->stream_analog_playback = &alc861vd_pcm_analog_playback; - spec->stream_analog_capture = &alc861vd_pcm_analog_capture; - - spec->stream_name_digital = "ALC861VD Digital"; - spec->stream_digital_playback = &alc861vd_pcm_digital_playback; - spec->stream_digital_capture = &alc861vd_pcm_digital_capture; - - spec->adc_nids = alc861vd_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); - - spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; - spec->num_mixers++; - - codec->patch_ops = alc_patch_ops; - - if (board_config == ALC861VD_AUTO) - spec->init_hook = alc861vd_auto_init; - - return 0; -} - -/* - * ALC662 support - * - * ALC662 is almost identical with ALC880 but has cleaner and more flexible - * configuration. Each pin widget can choose any input DACs and a mixer. - * Each ADC is connected from a mixer of all inputs. This makes possible - * 6-channel independent captures. - * - * In addition, an independent DAC for the multi-playback (not used in this - * driver yet). - */ -#define ALC662_DIGOUT_NID 0x06 -#define ALC662_DIGIN_NID 0x0a - -static hda_nid_t alc662_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04 -}; - -static hda_nid_t alc662_adc_nids[1] = { - /* ADC1-2 */ - 0x09, -}; -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ - -static struct hda_input_mux alc662_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static struct hda_input_mux alc662_lenovo_101e_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; -#define alc662_mux_enum_info alc_mux_enum_info -#define alc662_mux_enum_get alc_mux_enum_get - -static int alc662_mux_enum_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; - const struct hda_input_mux *imux = spec->input_mux; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; - hda_nid_t nid = capture_mixers[adc_idx]; - unsigned int *cur_val = &spec->cur_mux[adc_idx]; - unsigned int i, idx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) - return 0; - for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); - } - *cur_val = idx; - return 1; -} -/* - * 2ch mode - */ -static struct hda_channel_mode alc662_3ST_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 2ch mode - */ -static 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 }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static 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 }, - { 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 }, - { } /* end */ -}; - -static struct hda_channel_mode alc662_3ST_6ch_modes[2] = { - { 2, alc662_3ST_ch2_init }, - { 6, alc662_3ST_ch6_init }, -}; - -/* - * 2ch mode - */ -static 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 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static 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] = { - { 2, alc662_sixstack_ch6_init }, - { 6, alc662_sixstack_ch8_init }, -}; - -/* 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 alc662_base_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - - /*Input mixer control */ - HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT), - - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc662_mux_enum_info, - .get = alc662_mux_enum_get, - .put = alc662_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc662_mux_enum_info, - .get = alc662_mux_enum_get, - .put = alc662_mux_enum_put, - }, - { } /* end */ -}; - -static 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("iSpeaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("iSpeaker Playback Switch", 0x03, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc662_mux_enum_info, - .get = alc662_mux_enum_get, - .put = alc662_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc662_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static 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}, - /* Front mixer: unmute input/output amp left and right (volume = 0) */ - - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Rear Pin: output 1 (0x0d) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - { } -}; - -static 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}, - {} -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc662_auto_init_verbs[] = { - /* - * Unmute ADC and set the default input to mic-in - */ - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for front - * panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output mixers (0x0c - 0x0f) - */ - /* set vol=0 to output mixers */ - {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}, - - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /*{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},*/ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - { } -}; - -/* capture mixer elements */ -static struct snd_kcontrol_new alc662_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, - { } /* end */ -}; - -static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); -} - -static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, 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); -} - - -/* pcm configuration: identiacal with ALC880 */ -#define alc662_pcm_analog_playback alc880_pcm_analog_playback -#define alc662_pcm_analog_capture alc880_pcm_analog_capture -#define alc662_pcm_digital_playback alc880_pcm_digital_playback -#define alc662_pcm_digital_capture alc880_pcm_digital_capture - -/* - * configuration and preset - */ -static const char *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_LENOVO_101E] = "lenovo-101e", - [ALC662_AUTO] = "auto", -}; - -static struct snd_pci_quirk alc662_cfg_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), - {} -}; - -static struct alc_config_preset alc662_presets[] = { - [ALC662_3ST_2ch_DIG] = { - .mixers = { alc662_3ST_2ch_mixer }, - .init_verbs = { alc662_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc662_adc_nids), - .adc_nids = alc662_adc_nids, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_capture_source, - }, - [ALC662_3ST_6ch_DIG] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc662_adc_nids), - .adc_nids = alc662_adc_nids, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc662_capture_source, - }, - [ALC662_3ST_6ch] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc662_adc_nids), - .adc_nids = alc662_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), - .channel_mode = alc662_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc662_capture_source, - }, - [ALC662_5ST_DIG] = { - .mixers = { alc662_base_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .dig_out_nid = ALC662_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc662_adc_nids), - .adc_nids = alc662_adc_nids, - .dig_in_nid = ALC662_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes), - .channel_mode = alc662_5stack_modes, - .input_mux = &alc662_capture_source, - }, - [ALC662_LENOVO_101E] = { - .mixers = { alc662_lenovo_101e_mixer }, - .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs }, - .num_dacs = ARRAY_SIZE(alc662_dac_nids), - .dac_nids = alc662_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc662_adc_nids), - .adc_nids = alc662_adc_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, - }, - -}; - - -/* - * BIOS auto configuration - */ - -/* add playback controls from the parsed DAC table */ -static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - char name[32]; - static const char *chname[4] = { - "Front", "Surround", NULL /*CLFE*/, "Side" - }; - hda_nid_t nid; - int i, err; - - for (i = 0; i < cfg->line_outs; i++) { - if (!spec->multiout.dac_nids[i]) - continue; - nid = alc880_idx_to_dac(i); - if (i == 2) { - /* Center/LFE */ - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Center Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 2, - HDA_INPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 2, - HDA_INPUT)); - if (err < 0) - return err; - } else { - sprintf(name, "%s Playback Volume", chname[i]); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 2, - HDA_INPUT)); - if (err < 0) - return err; - } - } - return 0; -} - -/* add playback controls for speaker and HP outputs */ -static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, - const char *pfx) -{ - hda_nid_t nid; - int err; - char name[32]; - - if (!pin) - return 0; - - if (alc880_is_fixed_pin(pin)) { - nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); - /* printk("DAC nid=%x\n",nid); */ - /* specify the DAC as the extra output */ - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - else - spec->multiout.extra_out_nid[0] = nid; - /* control HP volume/switch on the output mixer amp */ - nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); - sprintf(name, "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); - if (err < 0) - return err; - } else if (alc880_is_multi_pin(pin)) { - /* set manual connection */ - /* we have only a switch on HP-out PIN */ - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - return 0; -} - -/* create playback/capture controls for input pins */ -static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - struct hda_input_mux *imux = &spec->private_imux; - int i, err, idx; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (alc880_is_input_pin(cfg->input_pins[i])) { - idx = alc880_input_pin_idx(cfg->input_pins[i]); - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], - idx, 0x0b); - if (err < 0) - return err; - imux->items[imux->num_items].label = - auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = - alc880_input_pin_idx(cfg->input_pins[i]); - imux->num_items++; - } - } - return 0; -} - -static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, int pin_type, - int dac_idx) -{ - /* set as output */ - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - /* need the manual connection? */ - if (alc880_is_multi_pin(nid)) { - struct alc_spec *spec = codec->spec; - int idx = alc880_multi_pin_idx(nid); - snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, - AC_VERB_SET_CONNECT_SEL, - alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); - } -} - -static void alc662_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i <= HDA_SIDE; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - if (nid) - alc662_auto_set_output_and_unmute(codec, nid, PIN_OUT, - i); - } -} - -static void alc662_auto_init_hp_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t pin; - - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - /* use dac 0 */ - alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); -} - -#define alc662_is_input_pin(nid) alc880_is_input_pin(nid) -#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID - -static void alc662_auto_init_analog_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (alc662_is_input_pin(nid)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - (i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF80 : PIN_IN)); - if (nid != ALC662_PIN_CD_NID) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - } - } -} - -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 }; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - alc662_ignore); - if (err < 0) - return err; - if (!spec->autocfg.line_outs) - return 0; /* can't find valid BIOS pin config */ - - err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); - if (err < 0) - return err; - err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - err = alc662_auto_create_extra_out(spec, - spec->autocfg.speaker_pins[0], - "Speaker"); - if (err < 0) - return err; - err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], - "Headphone"); - if (err < 0) - return err; - err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; - - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - - spec->num_mux_defs = 1; - spec->input_mux = &spec->private_imux; - - if (err < 0) - return err; - else if (err > 0) - /* hack - override the init verbs */ - spec->init_verbs[0] = alc662_auto_init_verbs; - spec->mixers[spec->num_mixers] = alc662_capture_mixer; - spec->num_mixers++; - return err; -} - -/* additional initialization for auto-configuration model */ -static void alc662_auto_init(struct hda_codec *codec) -{ - alc662_auto_init_multi_out(codec); - alc662_auto_init_hp_out(codec); - alc662_auto_init_analog_input(codec); -} - -static int patch_alc662(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err, board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - - codec->spec = spec; - - board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, - alc662_models, - alc662_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for ALC662, " - "trying auto-probe from BIOS...\n"); - board_config = ALC662_AUTO; - } - - if (board_config == ALC662_AUTO) { - /* automatic parse from the BIOS config */ - err = alc662_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } else if (err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC662_3ST_2ch_DIG; - } - } - - if (board_config != ALC662_AUTO) - setup_preset(spec, &alc662_presets[board_config]); - - spec->stream_name_analog = "ALC662 Analog"; - spec->stream_analog_playback = &alc662_pcm_analog_playback; - spec->stream_analog_capture = &alc662_pcm_analog_capture; - - spec->stream_name_digital = "ALC662 Digital"; - spec->stream_digital_playback = &alc662_pcm_digital_playback; - spec->stream_digital_capture = &alc662_pcm_digital_capture; - - if (!spec->adc_nids && spec->input_mux) { - spec->adc_nids = alc662_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); - } - - codec->patch_ops = alc_patch_ops; - if (board_config == ALC662_AUTO) - spec->init_hook = alc662_auto_init; - - return 0; -} - -/* - * patch entries - */ -struct hda_codec_preset snd_hda_preset_realtek[] = { - { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, - { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, - { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", - .patch = patch_alc861 }, - { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, - { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 }, - { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd }, - { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2", - .patch = patch_alc883 }, - { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", - .patch = patch_alc662 }, - { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, - { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, - { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, - { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, - { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, - {} /* terminator */ -}; diff --git a/modules/GPL/hda/patch_si3054.c b/modules/GPL/hda/patch_si3054.c deleted file mode 100644 index ed5e45e..0000000 --- a/modules/GPL/hda/patch_si3054.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * HD audio interface patch for Silicon Labs 3054/5 modem codec - * - * Copyright (c) 2005 Sasha Khapyorsky - * Takashi Iwai - * - * - * This driver 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 driver 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 -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - - -/* si3054 verbs */ -#define SI3054_VERB_READ_NODE 0x900 -#define SI3054_VERB_WRITE_NODE 0x100 - -/* si3054 nodes (registers) */ -#define SI3054_EXTENDED_MID 2 -#define SI3054_LINE_RATE 3 -#define SI3054_LINE_LEVEL 4 -#define SI3054_GPIO_CFG 5 -#define SI3054_GPIO_POLARITY 6 -#define SI3054_GPIO_STICKY 7 -#define SI3054_GPIO_WAKEUP 8 -#define SI3054_GPIO_STATUS 9 -#define SI3054_GPIO_CONTROL 10 -#define SI3054_MISC_AFE 11 -#define SI3054_CHIPID 12 -#define SI3054_LINE_CFG1 13 -#define SI3054_LINE_STATUS 14 -#define SI3054_DC_TERMINATION 15 -#define SI3054_LINE_CONFIG 16 -#define SI3054_CALLPROG_ATT 17 -#define SI3054_SQ_CONTROL 18 -#define SI3054_MISC_CONTROL 19 -#define SI3054_RING_CTRL1 20 -#define SI3054_RING_CTRL2 21 - -/* extended MID */ -#define SI3054_MEI_READY 0xf - -/* line level */ -#define SI3054_ATAG_MASK 0x00f0 -#define SI3054_DTAG_MASK 0xf000 - -/* GPIO bits */ -#define SI3054_GPIO_OH 0x0001 -#define SI3054_GPIO_CID 0x0002 - -/* chipid and revisions */ -#define SI3054_CHIPID_CODEC_REV_MASK 0x000f -#define SI3054_CHIPID_DAA_REV_MASK 0x00f0 -#define SI3054_CHIPID_INTERNATIONAL 0x0100 -#define SI3054_CHIPID_DAA_ID 0x0f00 -#define SI3054_CHIPID_CODEC_ID (1<<12) - -/* si3054 codec registers (nodes) access macros */ -#define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0)) -#define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val)) - - -struct si3054_spec { - unsigned international; - struct hda_pcm pcm; -}; - - -/* - * Modem mixer - */ - -#define PRIVATE_VALUE(reg,mask) ((reg<<16)|(mask&0xffff)) -#define PRIVATE_REG(val) ((val>>16)&0xffff) -#define PRIVATE_MASK(val) (val&0xffff) - -static int si3054_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int si3054_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uvalue) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - u16 reg = PRIVATE_REG(kcontrol->private_value); - u16 mask = PRIVATE_MASK(kcontrol->private_value); - uvalue->value.integer.value[0] = (GET_REG(codec, reg)) & mask ? 1 : 0 ; - return 0; -} - -static int si3054_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *uvalue) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - u16 reg = PRIVATE_REG(kcontrol->private_value); - u16 mask = PRIVATE_MASK(kcontrol->private_value); - if (uvalue->value.integer.value[0]) - SET_REG(codec, reg, (GET_REG(codec, reg)) | mask); - else - SET_REG(codec, reg, (GET_REG(codec, reg)) & ~mask); - return 0; -} - -#define SI3054_KCONTROL(kname,reg,mask) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = kname, \ - .info = si3054_switch_info, \ - .get = si3054_switch_get, \ - .put = si3054_switch_put, \ - .private_value = PRIVATE_VALUE(reg,mask), \ -} - - -static 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), - {} -}; - -static int si3054_build_controls(struct hda_codec *codec) -{ - return snd_hda_add_new_ctls(codec, si3054_modem_mixer); -} - - -/* - * PCM callbacks - */ - -static int si3054_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - u16 val; - - SET_REG(codec, SI3054_LINE_RATE, substream->runtime->rate); - val = GET_REG(codec, SI3054_LINE_LEVEL); - val &= 0xff << (8 * (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)); - val |= ((stream_tag & 0xf) << 4) << (8 * (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)); - SET_REG(codec, SI3054_LINE_LEVEL, val); - - snd_hda_codec_setup_stream(codec, hinfo->nid, - stream_tag, 0, format); - return 0; -} - -static int si3054_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - static unsigned int rates[] = { 8000, 9600, 16000 }; - static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, - }; - substream->runtime->hw.period_bytes_min = 80; - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); -} - - -static struct hda_pcm_stream si3054_pcm = { - .substreams = 1, - .channels_min = 1, - .channels_max = 1, - .nid = 0x1, - .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_KNOT, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .maxbps = 16, - .ops = { - .open = si3054_pcm_open, - .prepare = si3054_pcm_prepare, - }, -}; - - -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->is_modem = 1; - return 0; -} - - -/* - * Init part - */ - -static int si3054_init(struct hda_codec *codec) -{ - struct si3054_spec *spec = codec->spec; - unsigned wait_count; - u16 val; - - snd_hda_codec_write(codec, AC_NODE_ROOT, 0, AC_VERB_SET_CODEC_RESET, 0); - snd_hda_codec_write(codec, codec->mfg, 0, AC_VERB_SET_STREAM_FORMAT, 0); - SET_REG(codec, SI3054_LINE_RATE, 9600); - SET_REG(codec, SI3054_LINE_LEVEL, SI3054_DTAG_MASK|SI3054_ATAG_MASK); - SET_REG(codec, SI3054_EXTENDED_MID, 0); - - wait_count = 10; - do { - msleep(2); - val = GET_REG(codec, SI3054_EXTENDED_MID); - } while ((val & SI3054_MEI_READY) != SI3054_MEI_READY && wait_count--); - - if((val&SI3054_MEI_READY) != SI3054_MEI_READY) { - snd_printk(KERN_ERR "si3054: cannot initialize. EXT MID = %04x\n", val); - /* let's pray that this is no fatal error */ - /* return -EACCES; */ - } - - SET_REG(codec, SI3054_GPIO_POLARITY, 0xffff); - SET_REG(codec, SI3054_GPIO_CFG, 0x0); - SET_REG(codec, SI3054_MISC_AFE, 0); - SET_REG(codec, SI3054_LINE_CFG1,0x200); - - if((GET_REG(codec,SI3054_LINE_STATUS) & (1<<6)) == 0) { - snd_printd("Link Frame Detect(FDT) is not ready (line status: %04x)\n", - GET_REG(codec,SI3054_LINE_STATUS)); - } - - spec->international = GET_REG(codec, SI3054_CHIPID) & SI3054_CHIPID_INTERNATIONAL; - - return 0; -} - -static void si3054_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - - -/* - */ - -static struct hda_codec_ops si3054_patch_ops = { - .build_controls = si3054_build_controls, - .build_pcms = si3054_build_pcms, - .init = si3054_init, - .free = si3054_free, -#ifdef CONFIG_PM - //.suspend = si3054_suspend, - .resume = si3054_init, -#endif -}; - -static int patch_si3054(struct hda_codec *codec) -{ - struct si3054_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - codec->spec = spec; - codec->patch_ops = si3054_patch_ops; - return 0; -} - -/* - * patch entries - */ -struct hda_codec_preset snd_hda_preset_si3054[] = { - { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x11c11040, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x10573055, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x10573155, .name = "Si3054", .patch = patch_si3054 }, - {} -}; - diff --git a/modules/GPL/hda/patch_sigmatel.c b/modules/GPL/hda/patch_sigmatel.c deleted file mode 100644 index a348d22..0000000 --- a/modules/GPL/hda/patch_sigmatel.c +++ /dev/null @@ -1,3202 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * HD audio interface patch for SigmaTel STAC92xx - * - * Copyright (c) 2005 Embedded Alley Solutions, Inc. - * Matt Porter - * - * Based on patch_cmedia.c and patch_realtek.c - * Copyright (c) 2004 Takashi Iwai - * - * This driver 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 driver 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 -#include -#include -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -#define NUM_CONTROL_ALLOC 32 -#define STAC_HP_EVENT 0x37 - -enum { - STAC_REF, - STAC_9200_DELL_D21, - STAC_9200_DELL_D22, - STAC_9200_DELL_D23, - STAC_9200_DELL_M21, - STAC_9200_DELL_M22, - STAC_9200_DELL_M23, - STAC_9200_DELL_M24, - STAC_9200_DELL_M25, - STAC_9200_DELL_M26, - STAC_9200_DELL_M27, - STAC_9200_MODELS -}; - -enum { - STAC_9205_REF, - STAC_9205_DELL_M42, - STAC_9205_DELL_M43, - STAC_9205_DELL_M44, - STAC_9205_MODELS -}; - -enum { - STAC_925x_REF, - STAC_M2_2, - STAC_MA6, - STAC_PA6, - STAC_925x_MODELS -}; - -enum { - STAC_D945_REF, - STAC_D945GTP3, - STAC_D945GTP5, - STAC_INTEL_MAC_V1, - STAC_INTEL_MAC_V2, - STAC_INTEL_MAC_V3, - STAC_INTEL_MAC_V4, - STAC_INTEL_MAC_V5, - /* for backward compatibility */ - STAC_MACMINI, - STAC_MACBOOK, - STAC_MACBOOK_PRO_V1, - STAC_MACBOOK_PRO_V2, - STAC_IMAC_INTEL, - STAC_IMAC_INTEL_20, - STAC_922X_DELL_D81, - STAC_922X_DELL_D82, - STAC_922X_DELL_M81, - STAC_922X_DELL_M82, - STAC_922X_MODELS -}; - -enum { - STAC_D965_REF, - STAC_D965_3ST, - STAC_D965_5ST, - STAC_DELL_3ST, - STAC_927X_MODELS -}; - -struct sigmatel_spec { - struct snd_kcontrol_new *mixers[4]; - unsigned int num_mixers; - - int board_config; - unsigned int surr_switch: 1; - unsigned int line_switch: 1; - unsigned int mic_switch: 1; - unsigned int alt_switch: 1; - unsigned int hp_detect: 1; - unsigned int gpio_mute: 1; - - unsigned int gpio_mask, gpio_data; - - /* playback */ - struct hda_multi_out multiout; - hda_nid_t dac_nids[5]; - - /* capture */ - hda_nid_t *adc_nids; - unsigned int num_adcs; - hda_nid_t *mux_nids; - unsigned int num_muxes; - hda_nid_t *dmic_nids; - unsigned int num_dmics; - hda_nid_t dmux_nid; - hda_nid_t dig_in_nid; - - /* pin widgets */ - hda_nid_t *pin_nids; - unsigned int num_pins; - unsigned int *pin_configs; - unsigned int *bios_pin_configs; - - /* codec specific stuff */ - struct hda_verb *init; - struct snd_kcontrol_new *mixer; - - /* capture source */ - struct hda_input_mux *dinput_mux; - unsigned int cur_dmux; - struct hda_input_mux *input_mux; - unsigned int cur_mux[3]; - - /* i/o switches */ - unsigned int io_switch[2]; - unsigned int clfe_swap; - unsigned int aloopback; - - struct hda_pcm pcm_rec[2]; /* PCM information */ - - /* dynamic controls and input_mux */ - struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; - struct hda_input_mux private_dimux; - struct hda_input_mux private_imux; -}; - -static hda_nid_t stac9200_adc_nids[1] = { - 0x03, -}; - -static hda_nid_t stac9200_mux_nids[1] = { - 0x0c, -}; - -static hda_nid_t stac9200_dac_nids[1] = { - 0x02, -}; - -static hda_nid_t stac925x_adc_nids[1] = { - 0x03, -}; - -static hda_nid_t stac925x_mux_nids[1] = { - 0x0f, -}; - -static hda_nid_t stac925x_dac_nids[1] = { - 0x02, -}; - -static hda_nid_t stac925x_dmic_nids[1] = { - 0x15, -}; - -static hda_nid_t stac922x_adc_nids[2] = { - 0x06, 0x07, -}; - -static hda_nid_t stac922x_mux_nids[2] = { - 0x12, 0x13, -}; - -static hda_nid_t stac927x_adc_nids[3] = { - 0x07, 0x08, 0x09 -}; - -static hda_nid_t stac927x_mux_nids[3] = { - 0x15, 0x16, 0x17 -}; - -static hda_nid_t stac9205_adc_nids[2] = { - 0x12, 0x13 -}; - -static hda_nid_t stac9205_mux_nids[2] = { - 0x19, 0x1a -}; - -static hda_nid_t stac9205_dmic_nids[2] = { - 0x17, 0x18, -}; - -static hda_nid_t stac9200_pin_nids[8] = { - 0x08, 0x09, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, -}; - -static hda_nid_t stac925x_pin_nids[8] = { - 0x07, 0x08, 0x0a, 0x0b, - 0x0c, 0x0d, 0x10, 0x11, -}; - -static hda_nid_t stac922x_pin_nids[10] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x15, 0x1b, -}; - -static 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] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x14, 0x16, 0x17, 0x18, - 0x21, 0x22, -}; - -static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->dinput_mux, uinfo); -} - -static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->cur_dmux; - return 0; -} - -static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol, - spec->dmux_nid, &spec->cur_dmux); -} - -static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); -} - -static int stac92xx_boolean_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} -#define stac92xx_aloopback_info stac92xx_boolean_switch_info - -static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - ucontrol->value.integer.value[0] = spec->aloopback; - return 0; -} - -static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - unsigned int dac_mode; - - if (spec->aloopback == ucontrol->value.integer.value[0]) - return 0; - - spec->aloopback = ucontrol->value.integer.value[0]; - - - dac_mode = snd_hda_codec_read(codec, codec->afg, 0, - kcontrol->private_value & 0xFFFF, 0x0); - - if (spec->aloopback) { - snd_hda_power_up(codec); - dac_mode |= 0x40; - } else { - snd_hda_power_down(codec); - dac_mode &= ~0x40; - } - - snd_hda_codec_write_cache(codec, codec->afg, 0, - kcontrol->private_value >> 16, dac_mode); - - return 1; -} - -static int stac92xx_volknob_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 127; - return 0; -} - -static int stac92xx_volknob_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = kcontrol->private_value; - return 0; -} - -static int stac92xx_volknob_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - if (kcontrol->private_value == ucontrol->value.integer.value[0]) - return 0; - - kcontrol->private_value = ucontrol->value.integer.value[0]; - - snd_hda_codec_write_cache(codec, 0x24, 0, - AC_VERB_SET_VOLUME_KNOB_CONTROL, - kcontrol->private_value | 0x80); - return 1; -} - - -static struct hda_verb stac9200_core_init[] = { - /* set dac0mux for dac converter */ - { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {} -}; - -static struct hda_verb stac925x_core_init[] = { - /* set dac0mux for dac converter */ - { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, - {} -}; - -static 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[] = { - /* set master volume and direct control */ - { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* unmute node 0x1b */ - { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* select node 0x03 as DAC */ - { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01}, - {} -}; - -static struct hda_verb stac927x_core_init[] = { - /* set master volume and direct control */ - { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - {} -}; - -static struct hda_verb stac9205_core_init[] = { - /* set master volume and direct control */ - { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - {} -}; - -#define STAC_INPUT_SOURCE(cnt) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Input Source", \ - .count = cnt, \ - .info = stac92xx_mux_enum_info, \ - .get = stac92xx_mux_enum_get, \ - .put = stac92xx_mux_enum_put, \ - } - -#define STAC_ANALOG_LOOPBACK(verb_read,verb_write) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Analog Loopback", \ - .count = 1, \ - .info = stac92xx_aloopback_info, \ - .get = stac92xx_aloopback_get, \ - .put = stac92xx_aloopback_put, \ - .private_value = verb_read | (verb_write << 16), \ - } - -#define STAC_VOLKNOB \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Master Playback Volume", \ - .count = 1, \ - .info = stac92xx_volknob_info, \ - .get = stac92xx_volknob_get, \ - .put = stac92xx_volknob_put, \ - .private_value = 127, \ - } - - -static struct snd_kcontrol_new stac9200_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), - STAC_INPUT_SOURCE(1), - HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new stac925x_mixer[] = { - STAC_INPUT_SOURCE(1), - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new stac9205_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Input Source", - .count = 1, - .info = stac92xx_dmux_enum_info, - .get = stac92xx_dmux_enum_get, - .put = stac92xx_dmux_enum_put, - }, -#if 0 - STAC_INPUT_SOURCE(2), -#else - STAC_INPUT_SOURCE(1), -#endif - STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), - STAC_VOLKNOB, - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT), - -#if 0 - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT), -#endif - - { } /* end */ -}; - -/* This needs to be generated dynamically based on sequence */ -static struct snd_kcontrol_new stac922x_mixer[] = { - STAC_INPUT_SOURCE(2), - STAC_VOLKNOB, - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT), - { } /* end */ -}; - - -static struct snd_kcontrol_new stac927x_mixer[] = { - STAC_INPUT_SOURCE(3), - STAC_VOLKNOB, - STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static int stac92xx_build_controls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int err; - int i; - - err = snd_hda_add_new_ctls(codec, spec->mixer); - if (err < 0) - return err; - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); - if (err < 0) - return err; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - return 0; -} - -static unsigned int ref9200_pin_configs[8] = { - 0x01c47010, 0x01447010, 0x0221401f, 0x01114010, - 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, -}; - -/* - STAC 9200 pin configs for - 102801A8 - 102801DE - 102801E8 -*/ -static unsigned int dell9200_d21_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x02214030, 0x01014010, - 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, -}; - -/* - STAC 9200 pin configs for - 102801C0 - 102801C1 -*/ -static unsigned int dell9200_d22_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, - 0x01813020, 0x02a19021, 0x90100140, 0x400001f2, -}; - -/* - STAC 9200 pin configs for - 102801C4 (Dell Dimension E310) - 102801C5 - 102801C7 - 102801D9 - 102801DA - 102801E3 -*/ -static unsigned int dell9200_d23_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, - 0x01813020, 0x01a19021, 0x90100140, 0x400001f2, -}; - - -/* - STAC 9200-32 pin configs for - 102801B5 (Dell Inspiron 630m) - 102801D8 (Dell Inspiron 640m) -*/ -static unsigned int dell9200_m21_pin_configs[8] = { - 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310, - 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd, -}; - -/* - STAC 9200-32 pin configs for - 102801C2 (Dell Latitude D620) - 102801C8 - 102801CC (Dell Latitude D820) - 102801D4 - 102801D6 -*/ -static unsigned int dell9200_m22_pin_configs[8] = { - 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, - 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc, -}; - -/* - STAC 9200-32 pin configs for - 102801CE (Dell XPS M1710) - 102801CF (Dell Precision M90) -*/ -static unsigned int dell9200_m23_pin_configs[8] = { - 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310, - 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc, -}; - -/* - STAC 9200-32 pin configs for - 102801C9 - 102801CA - 102801CB (Dell Latitude 120L) - 102801D3 -*/ -static unsigned int dell9200_m24_pin_configs[8] = { - 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, - 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, -}; - -/* - STAC 9200-32 pin configs for - 102801BD (Dell Inspiron E1505n) - 102801EE - 102801EF -*/ -static unsigned int dell9200_m25_pin_configs[8] = { - 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, - 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd, -}; - -/* - STAC 9200-32 pin configs for - 102801F5 (Dell Inspiron 1501) - 102801F6 -*/ -static unsigned int dell9200_m26_pin_configs[8] = { - 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, - 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe, -}; - -/* - STAC 9200-32 - 102801CD (Dell Inspiron E1705/9400) -*/ -static unsigned int dell9200_m27_pin_configs[8] = { - 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, - 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc, -}; - - -static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { - [STAC_REF] = ref9200_pin_configs, - [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, - [STAC_9200_DELL_D22] = dell9200_d22_pin_configs, - [STAC_9200_DELL_D23] = dell9200_d23_pin_configs, - [STAC_9200_DELL_M21] = dell9200_m21_pin_configs, - [STAC_9200_DELL_M22] = dell9200_m22_pin_configs, - [STAC_9200_DELL_M23] = dell9200_m23_pin_configs, - [STAC_9200_DELL_M24] = dell9200_m24_pin_configs, - [STAC_9200_DELL_M25] = dell9200_m25_pin_configs, - [STAC_9200_DELL_M26] = dell9200_m26_pin_configs, - [STAC_9200_DELL_M27] = dell9200_m27_pin_configs, -}; - -static const char *stac9200_models[STAC_9200_MODELS] = { - [STAC_REF] = "ref", - [STAC_9200_DELL_D21] = "dell-d21", - [STAC_9200_DELL_D22] = "dell-d22", - [STAC_9200_DELL_D23] = "dell-d23", - [STAC_9200_DELL_M21] = "dell-m21", - [STAC_9200_DELL_M22] = "dell-m22", - [STAC_9200_DELL_M23] = "dell-m23", - [STAC_9200_DELL_M24] = "dell-m24", - [STAC_9200_DELL_M25] = "dell-m25", - [STAC_9200_DELL_M26] = "dell-m26", - [STAC_9200_DELL_M27] = "dell-m27", -}; - -static struct snd_pci_quirk stac9200_cfg_tbl[] = { - /* SigmaTel reference board */ - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, - "DFI LanParty", STAC_REF), - /* Dell laptops have BIOS problem */ - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8, - "unknown Dell", STAC_9200_DELL_D21), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5, - "Dell Inspiron 630m", STAC_9200_DELL_M21), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd, - "Dell Inspiron E1505n", STAC_9200_DELL_M25), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0, - "unknown Dell", STAC_9200_DELL_D22), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1, - "unknown Dell", STAC_9200_DELL_D22), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2, - "Dell Latitude D620", STAC_9200_DELL_M22), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5, - "unknown Dell", STAC_9200_DELL_D23), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7, - "unknown Dell", STAC_9200_DELL_D23), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8, - "unknown Dell", STAC_9200_DELL_M22), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9, - "unknown Dell", STAC_9200_DELL_M24), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca, - "unknown Dell", STAC_9200_DELL_M24), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb, - "Dell Latitude 120L", STAC_9200_DELL_M24), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc, - "Dell Latitude D820", STAC_9200_DELL_M22), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd, - "Dell Inspiron E1705/9400", STAC_9200_DELL_M27), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce, - "Dell XPS M1710", STAC_9200_DELL_M23), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf, - "Dell Precision M90", STAC_9200_DELL_M23), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3, - "unknown Dell", STAC_9200_DELL_M22), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4, - "unknown Dell", STAC_9200_DELL_M22), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6, - "unknown Dell", STAC_9200_DELL_M22), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8, - "Dell Inspiron 640m", STAC_9200_DELL_M21), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9, - "unknown Dell", STAC_9200_DELL_D23), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da, - "unknown Dell", STAC_9200_DELL_D23), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de, - "unknown Dell", STAC_9200_DELL_D21), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3, - "unknown Dell", STAC_9200_DELL_D23), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8, - "unknown Dell", STAC_9200_DELL_D21), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee, - "unknown Dell", STAC_9200_DELL_M25), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef, - "unknown Dell", STAC_9200_DELL_M25), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5, - "Dell Inspiron 1501", STAC_9200_DELL_M26), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6, - "unknown Dell", STAC_9200_DELL_M26), - /* Panasonic */ - SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF), - - {} /* terminator */ -}; - -static unsigned int ref925x_pin_configs[8] = { - 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, - 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e, -}; - -static unsigned int stac925x_MA6_pin_configs[8] = { - 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, - 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e, -}; - -static unsigned int stac925x_PA6_pin_configs[8] = { - 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, - 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e, -}; - -static unsigned int stac925xM2_2_pin_configs[8] = { - 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020, - 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e, -}; - -static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { - [STAC_REF] = ref925x_pin_configs, - [STAC_M2_2] = stac925xM2_2_pin_configs, - [STAC_MA6] = stac925x_MA6_pin_configs, - [STAC_PA6] = stac925x_PA6_pin_configs, -}; - -static const char *stac925x_models[STAC_925x_MODELS] = { - [STAC_REF] = "ref", - [STAC_M2_2] = "m2-2", - [STAC_MA6] = "m6", - [STAC_PA6] = "pa6", -}; - -static 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(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF), - SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF), - SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF), - SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6), - SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6), - SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2), - {} /* terminator */ -}; - -static unsigned int ref922x_pin_configs[10] = { - 0x01014010, 0x01016011, 0x01012012, 0x0221401f, - 0x01813122, 0x01011014, 0x01441030, 0x01c41030, - 0x40000100, 0x40000100, -}; - -/* - STAC 922X pin configs for - 102801A7 - 102801AB - 102801A9 - 102801D1 - 102801D2 -*/ -static unsigned int dell_922x_d81_pin_configs[10] = { - 0x02214030, 0x01a19021, 0x01111012, 0x01114010, - 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1, - 0x01813122, 0x400001f2, -}; - -/* - STAC 922X pin configs for - 102801AC - 102801D0 -*/ -static unsigned int dell_922x_d82_pin_configs[10] = { - 0x02214030, 0x01a19021, 0x01111012, 0x01114010, - 0x02a19020, 0x01117011, 0x01451140, 0x400001f0, - 0x01813122, 0x400001f1, -}; - -/* - STAC 922X pin configs for - 102801BF -*/ -static unsigned int dell_922x_m81_pin_configs[10] = { - 0x0321101f, 0x01112024, 0x01111222, 0x91174220, - 0x03a11050, 0x01116221, 0x90a70330, 0x01452340, - 0x40C003f1, 0x405003f0, -}; - -/* - STAC 9221 A1 pin configs for - 102801D7 (Dell XPS M1210) -*/ -static unsigned int dell_922x_m82_pin_configs[10] = { - 0x0221121f, 0x408103ff, 0x02111212, 0x90100310, - 0x408003f1, 0x02111211, 0x03451340, 0x40c003f2, - 0x508003f3, 0x405003f4, -}; - -static unsigned int d945gtp3_pin_configs[10] = { - 0x0221401f, 0x01a19022, 0x01813021, 0x01014010, - 0x40000100, 0x40000100, 0x40000100, 0x40000100, - 0x02a19120, 0x40000100, -}; - -static 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] = { - 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd, - 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240, - 0x400000fc, 0x400000fb, -}; - -static 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] = { - 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd, - 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240, - 0x400000fc, 0x400000fb, -}; - -static 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] = { - 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f, - 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240, - 0x400000fc, 0x400000fb, -}; - - -static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { - [STAC_D945_REF] = ref922x_pin_configs, - [STAC_D945GTP3] = d945gtp3_pin_configs, - [STAC_D945GTP5] = d945gtp5_pin_configs, - [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs, - [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs, - [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs, - [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs, - [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs, - /* for backward compatibility */ - [STAC_MACMINI] = intel_mac_v3_pin_configs, - [STAC_MACBOOK] = intel_mac_v5_pin_configs, - [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs, - [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs, - [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs, - [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs, - [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs, - [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs, - [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs, - [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs, -}; - -static const char *stac922x_models[STAC_922X_MODELS] = { - [STAC_D945_REF] = "ref", - [STAC_D945GTP5] = "5stack", - [STAC_D945GTP3] = "3stack", - [STAC_INTEL_MAC_V1] = "intel-mac-v1", - [STAC_INTEL_MAC_V2] = "intel-mac-v2", - [STAC_INTEL_MAC_V3] = "intel-mac-v3", - [STAC_INTEL_MAC_V4] = "intel-mac-v4", - [STAC_INTEL_MAC_V5] = "intel-mac-v5", - /* for backward compatibility */ - [STAC_MACMINI] = "macmini", - [STAC_MACBOOK] = "macbook", - [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1", - [STAC_MACBOOK_PRO_V2] = "macbook-pro", - [STAC_IMAC_INTEL] = "imac-intel", - [STAC_IMAC_INTEL_20] = "imac-intel-20", - [STAC_922X_DELL_D81] = "dell-d81", - [STAC_922X_DELL_D82] = "dell-d82", - [STAC_922X_DELL_M81] = "dell-m81", - [STAC_922X_DELL_M82] = "dell-m82", -}; - -static struct snd_pci_quirk stac922x_cfg_tbl[] = { - /* SigmaTel reference board */ - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, - "DFI LanParty", STAC_D945_REF), - /* Intel 945G based systems */ - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048, - "Intel D945G", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110, - "Intel D945G", STAC_D945GTP3), - /* Intel D945G 5-stack systems */ - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404, - "Intel D945G", STAC_D945GTP5), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303, - "Intel D945G", STAC_D945GTP5), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013, - "Intel D945G", STAC_D945GTP5), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417, - "Intel D945G", STAC_D945GTP5), - /* Intel 945P based systems */ - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b, - "Intel D945P", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112, - "Intel D945P", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d, - "Intel D945P", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909, - "Intel D945P", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505, - "Intel D945P", STAC_D945GTP3), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707, - "Intel D945P", STAC_D945GTP5), - /* other systems */ - /* Apple Mac Mini (early 2006) */ - SND_PCI_QUIRK(0x8384, 0x7680, - "Mac Mini", STAC_INTEL_MAC_V3), - /* Dell systems */ - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7, - "unknown Dell", STAC_922X_DELL_D81), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9, - "unknown Dell", STAC_922X_DELL_D81), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab, - "unknown Dell", STAC_922X_DELL_D81), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac, - "unknown Dell", STAC_922X_DELL_D82), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf, - "unknown Dell", STAC_922X_DELL_M81), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0, - "unknown Dell", STAC_922X_DELL_D82), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1, - "unknown Dell", STAC_922X_DELL_D81), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2, - "unknown Dell", STAC_922X_DELL_D81), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7, - "Dell XPS M1210", STAC_922X_DELL_M82), - {} /* terminator */ -}; - -static 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] = { - 0x0221401f, 0x02a19120, 0x40000100, 0x01014011, - 0x01a19021, 0x01813024, 0x40000100, 0x40000100, - 0x40000100, 0x40000100, 0x40000100, 0x40000100, - 0x40000100, 0x40000100 -}; - -static unsigned int d965_5st_pin_configs[14] = { - 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, - 0x01a19040, 0x01011012, 0x01016011, 0x40000100, - 0x40000100, 0x40000100, 0x40000100, 0x01442070, - 0x40000100, 0x40000100 -}; - -static unsigned int dell_3st_pin_configs[14] = { - 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, - 0x01111212, 0x01116211, 0x01813050, 0x01112214, - 0x403003fa, 0x40000100, 0x40000100, 0x404003fb, - 0x40c003fc, 0x40000100 -}; - -static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { - [STAC_D965_REF] = ref927x_pin_configs, - [STAC_D965_3ST] = d965_3st_pin_configs, - [STAC_D965_5ST] = d965_5st_pin_configs, - [STAC_DELL_3ST] = dell_3st_pin_configs, -}; - -static const char *stac927x_models[STAC_927X_MODELS] = { - [STAC_D965_REF] = "ref", - [STAC_D965_3ST] = "3stack", - [STAC_D965_5ST] = "5stack", - [STAC_DELL_3ST] = "dell-3stack", -}; - -static struct snd_pci_quirk stac927x_cfg_tbl[] = { - /* SigmaTel reference board */ - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, - "DFI LanParty", STAC_D965_REF), - /* Intel 946 based systems */ - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST), - /* 965 based 3 stack systems */ - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), - /* Dell 3 stack systems */ - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_D965_3ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), - /* 965 based 5 stack systems */ - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST), - {} /* terminator */ -}; - -static unsigned int ref9205_pin_configs[12] = { - 0x40000100, 0x40000100, 0x01016011, 0x01014010, - 0x01813122, 0x01a19021, 0x40000100, 0x40000100, - 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 -}; - -/* - STAC 9205 pin configs for - 102801F1 - 102801F2 - 102801FC - 102801FD - 10280204 - 1028021F -*/ -static unsigned int dell_9205_m42_pin_configs[12] = { - 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, - 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9, - 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE, -}; - -/* - STAC 9205 pin configs for - 102801F9 - 102801FA - 102801FE - 102801FF (Dell Precision M4300) - 10280206 - 10280200 - 10280201 -*/ -static 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] = { - 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310, - 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9, - 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe, -}; - -static 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, - [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs, -}; - -static const char *stac9205_models[STAC_9205_MODELS] = { - [STAC_9205_REF] = "ref", - [STAC_9205_DELL_M42] = "dell-m42", - [STAC_9205_DELL_M43] = "dell-m43", - [STAC_9205_DELL_M44] = "dell-m44", -}; - -static struct snd_pci_quirk stac9205_cfg_tbl[] = { - /* SigmaTel reference board */ - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, - "DFI LanParty", STAC_9205_REF), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, - "unknown Dell", STAC_9205_DELL_M42), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, - "unknown Dell", STAC_9205_DELL_M42), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, - "Dell Precision", STAC_9205_DELL_M43), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c, - "Dell Precision", STAC_9205_DELL_M43), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, - "Dell Precision", STAC_9205_DELL_M43), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, - "Dell Precision", STAC_9205_DELL_M43), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, - "Dell Precision", STAC_9205_DELL_M43), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, - "unknown Dell", STAC_9205_DELL_M42), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, - "unknown Dell", STAC_9205_DELL_M42), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe, - "Dell Precision", STAC_9205_DELL_M43), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff, - "Dell Precision M4300", STAC_9205_DELL_M43), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206, - "Dell Precision", STAC_9205_DELL_M43), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, - "Dell Inspiron", STAC_9205_DELL_M44), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, - "Dell Inspiron", STAC_9205_DELL_M44), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, - "Dell Inspiron", STAC_9205_DELL_M44), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, - "Dell Inspiron", STAC_9205_DELL_M44), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204, - "unknown Dell", STAC_9205_DELL_M42), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, - "Dell Inspiron", STAC_9205_DELL_M44), - {} /* terminator */ -}; - -static int stac92xx_save_bios_config_regs(struct hda_codec *codec) -{ - int i; - struct sigmatel_spec *spec = codec->spec; - - if (! spec->bios_pin_configs) { - spec->bios_pin_configs = kcalloc(spec->num_pins, - sizeof(*spec->bios_pin_configs), GFP_KERNEL); - if (! spec->bios_pin_configs) - return -ENOMEM; - } - - for (i = 0; i < spec->num_pins; i++) { - hda_nid_t nid = spec->pin_nids[i]; - unsigned int pin_cfg; - - pin_cfg = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0x00); - snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n", - nid, pin_cfg); - spec->bios_pin_configs[i] = pin_cfg; - } - - return 0; -} - -static void stac92xx_set_config_reg(struct hda_codec *codec, - hda_nid_t pin_nid, unsigned int pin_config) -{ - int i; - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, - pin_config & 0x000000ff); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, - (pin_config & 0x0000ff00) >> 8); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, - (pin_config & 0x00ff0000) >> 16); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, - pin_config >> 24); - i = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, - 0x00); - snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n", - pin_nid, i); -} - -static void stac92xx_set_config_regs(struct hda_codec *codec) -{ - int i; - struct sigmatel_spec *spec = codec->spec; - - if (!spec->pin_configs) - return; - - for (i = 0; i < spec->num_pins; i++) - stac92xx_set_config_reg(codec, spec->pin_nids[i], - spec->pin_configs[i]); -} - -static void stac92xx_enable_gpio_mask(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - /* Configure GPIOx as output */ - snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask); - /* Configure GPIOx as CMOS */ - snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000); - /* Assert GPIOx */ - snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, spec->gpio_data); - /* Enable GPIOx */ - snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, spec->gpio_mask); -} - -/* - * Analog playback callbacks - */ -static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); -} - -static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream); -} - -static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital playback callbacks - */ -static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - - -/* - * Analog capture callbacks - */ -static int stac92xx_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 sigmatel_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); - return 0; -} - -static struct hda_pcm_stream stac92xx_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in stac92xx_build_pcms */ - .ops = { - .open = stac92xx_dig_playback_pcm_open, - .close = stac92xx_dig_playback_pcm_close, - .prepare = stac92xx_dig_playback_pcm_prepare - }, -}; - -static 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 = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = 0x02, /* NID to query formats and rates */ - .ops = { - .open = stac92xx_playback_pcm_open, - .prepare = stac92xx_playback_pcm_prepare, - .cleanup = stac92xx_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0x06, /* NID to query formats and rates */ - .ops = { - .open = stac92xx_playback_pcm_open, - .prepare = stac92xx_playback_pcm_prepare, - .cleanup = stac92xx_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream stac92xx_pcm_analog_capture = { - .channels_min = 2, - .channels_max = 2, - /* NID + .substreams is set in stac92xx_build_pcms */ - .ops = { - .prepare = stac92xx_capture_pcm_prepare, - .cleanup = stac92xx_capture_pcm_cleanup - }, -}; - -static int stac92xx_build_pcms(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "STAC92xx Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs; - - if (spec->alt_switch) { - codec->num_pcms++; - info++; - info->name = "STAC92xx Analog Alt"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback; - } - - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - codec->num_pcms++; - info++; - info->name = "STAC92xx Digital"; - if (spec->multiout.dig_out_nid) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - } - - return 0; -} - -static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int pincap = snd_hda_param_read(codec, nid, - AC_PAR_PIN_CAP); - pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; - if (pincap & AC_PINCAP_VREF_100) - return AC_PINCTL_VREF_100; - if (pincap & AC_PINCAP_VREF_80) - return AC_PINCTL_VREF_80; - if (pincap & AC_PINCAP_VREF_50) - return AC_PINCTL_VREF_50; - if (pincap & AC_PINCAP_VREF_GRD) - return AC_PINCTL_VREF_GRD; - return 0; -} - -static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) - -{ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); -} - -#define stac92xx_io_switch_info stac92xx_boolean_switch_info - -static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - int io_idx = kcontrol-> private_value & 0xff; - - ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; - return 0; -} - -static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value >> 8; - int io_idx = kcontrol-> private_value & 0xff; - unsigned short val = ucontrol->value.integer.value[0]; - - spec->io_switch[io_idx] = val; - - if (val) - stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); - else { - unsigned int pinctl = AC_PINCTL_IN_EN; - if (io_idx) /* set VREF for mic */ - pinctl |= stac92xx_get_vref(codec, nid); - stac92xx_auto_set_pinctl(codec, nid, pinctl); - } - return 1; -} - -#define stac92xx_clfe_switch_info stac92xx_boolean_switch_info - -static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - ucontrol->value.integer.value[0] = spec->clfe_swap; - return 0; -} - -static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value & 0xff; - - if (spec->clfe_swap == ucontrol->value.integer.value[0]) - return 0; - - spec->clfe_swap = ucontrol->value.integer.value[0]; - - snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, - spec->clfe_swap ? 0x4 : 0x0); - - return 1; -} - -#define STAC_CODEC_IO_SWITCH(xname, xpval) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = 0, \ - .info = stac92xx_io_switch_info, \ - .get = stac92xx_io_switch_get, \ - .put = stac92xx_io_switch_put, \ - .private_value = xpval, \ - } - -#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = 0, \ - .info = stac92xx_clfe_switch_info, \ - .get = stac92xx_clfe_switch_get, \ - .put = stac92xx_clfe_switch_put, \ - .private_value = xpval, \ - } - -enum { - STAC_CTL_WIDGET_VOL, - STAC_CTL_WIDGET_MUTE, - STAC_CTL_WIDGET_IO_SWITCH, - STAC_CTL_WIDGET_CLFE_SWITCH -}; - -static struct snd_kcontrol_new stac92xx_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), - STAC_CODEC_IO_SWITCH(NULL, 0), - STAC_CODEC_CLFE_SWITCH(NULL, 0), -}; - -/* add dynamic controls */ -static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val) -{ - struct snd_kcontrol_new *knew; - size_t namelen = strlen(name) + 1; - - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ - if (! knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; - *knew = stac92xx_control_templates[type]; - knew->name = kmalloc(namelen, GFP_KERNEL); - if (! knew->name) - return -ENOMEM; - memcpy(knew->name, name, namelen); - knew->private_value = val; - spec->num_kctl_used++; - return 0; -} - -/* flag inputs as additional dynamic lineouts */ -static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - unsigned int wcaps, wtype; - int i, num_dacs = 0; - - /* use the wcaps cache to count all DACs available for line-outs */ - for (i = 0; i < codec->num_nodes; i++) { - wcaps = codec->wcaps[i]; - wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) - num_dacs++; - } - - snd_printdd("%s: total dac count=%d\n", __func__, num_dacs); - - switch (cfg->line_outs) { - case 3: - /* add line-in as side */ - if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_LINE]; - spec->line_switch = 1; - cfg->line_outs++; - } - break; - case 2: - /* add line-in as clfe and mic as side */ - if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_LINE]; - spec->line_switch = 1; - cfg->line_outs++; - } - if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_MIC]; - spec->mic_switch = 1; - cfg->line_outs++; - } - break; - case 1: - /* add line-in as surr and mic as clfe */ - if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_LINE]; - spec->line_switch = 1; - cfg->line_outs++; - } - if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_MIC]; - spec->mic_switch = 1; - cfg->line_outs++; - } - break; - } - - return 0; -} - - -static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) -{ - int i; - - for (i = 0; i < spec->multiout.num_dacs; i++) { - if (spec->multiout.dac_nids[i] == nid) - return 1; - } - - return 0; -} - -/* - * Fill in the dac_nids table from the parsed pin configuration - * This function only works when every pin in line_out_pins[] - * contains atleast one DAC in its connection list. Some 92xx - * codecs are not connected directly to a DAC, such as the 9200 - * and 9202/925x. For those, dac_nids[] must be hard-coded. - */ -static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, - struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - int i, j, conn_len = 0; - hda_nid_t nid, conn[HDA_MAX_CONNECTIONS]; - unsigned int wcaps, wtype; - - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - conn_len = snd_hda_get_connections(codec, nid, conn, - HDA_MAX_CONNECTIONS); - for (j = 0; j < conn_len; j++) { - wcaps = snd_hda_param_read(codec, conn[j], - AC_PAR_AUDIO_WIDGET_CAP); - wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - - if (wtype != AC_WID_AUD_OUT || - (wcaps & AC_WCAP_DIGITAL)) - continue; - /* conn[j] is a DAC routed to this line-out */ - if (!is_in_dac_nids(spec, conn[j])) - break; - } - - if (j == conn_len) { - if (spec->multiout.num_dacs > 0) { - /* we have already working output pins, - * so let's drop the broken ones again - */ - cfg->line_outs = spec->multiout.num_dacs; - break; - } - /* error out, no available DAC found */ - snd_printk(KERN_ERR - "%s: No available DAC for pin 0x%x\n", - __func__, nid); - return -ENODEV; - } - - spec->multiout.dac_nids[i] = conn[j]; - spec->multiout.num_dacs++; - if (conn_len > 1) { - /* select this DAC in the pin's input mux */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, j); - - } - } - - snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", - spec->multiout.num_dacs, - spec->multiout.dac_nids[0], - spec->multiout.dac_nids[1], - spec->multiout.dac_nids[2], - spec->multiout.dac_nids[3], - spec->multiout.dac_nids[4]); - return 0; -} - -/* create volume control/switch for the given prefx type */ -static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs) -{ - char name[32]; - int err; - - sprintf(name, "%s Playback Volume", pfx); - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", pfx); - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); - if (err < 0) - return err; - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - static const char *chname[4] = { - "Front", "Surround", NULL /*CLFE*/, "Side" - }; - hda_nid_t nid; - int i, err; - - struct sigmatel_spec *spec = codec->spec; - unsigned int wid_caps; - - - for (i = 0; i < cfg->line_outs; i++) { - if (!spec->multiout.dac_nids[i]) - continue; - - nid = spec->multiout.dac_nids[i]; - - if (i == 2) { - /* Center/LFE */ - err = create_controls(spec, "Center", nid, 1); - if (err < 0) - return err; - err = create_controls(spec, "LFE", nid, 2); - if (err < 0) - return err; - - wid_caps = get_wcaps(codec, nid); - - if (wid_caps & AC_WCAP_LR_SWAP) { - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_CLFE_SWITCH, - "Swap Center/LFE Playback Switch", nid); - - if (err < 0) - return err; - } - - } else { - err = create_controls(spec, chname[i], nid, 3); - if (err < 0) - return err; - } - } - - if (spec->line_switch) - if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0) - return err; - - if (spec->mic_switch) - if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", (cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0) - return err; - - return 0; -} - -static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) -{ - if (is_in_dac_nids(spec, nid)) - return 1; - if (spec->multiout.hp_nid == nid) - return 1; - return 0; -} - -static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) -{ - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - else if (spec->multiout.num_dacs > 4) { - printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); - return 1; - } else { - spec->multiout.dac_nids[spec->multiout.num_dacs] = nid; - spec->multiout.num_dacs++; - } - return 0; -} - -/* add playback controls for Speaker and HP outputs */ -static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, - struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid; - int i, old_num_dacs, err; - - old_num_dacs = spec->multiout.num_dacs; - for (i = 0; i < cfg->hp_outs; i++) { - unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]); - if (wid_caps & AC_WCAP_UNSOL_CAP) - spec->hp_detect = 1; - nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - if (check_in_dac_nids(spec, nid)) - nid = 0; - if (! nid) - continue; - add_spec_dacs(spec, nid); - } - for (i = 0; i < cfg->speaker_outs; i++) { - nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - if (check_in_dac_nids(spec, nid)) - nid = 0; - if (! nid) - continue; - add_spec_dacs(spec, nid); - } - for (i = 0; i < cfg->line_outs; i++) { - nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - if (check_in_dac_nids(spec, nid)) - nid = 0; - if (! nid) - continue; - add_spec_dacs(spec, nid); - } - for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) { - static const char *pfxs[] = { - "Speaker", "External Speaker", "Speaker2", - }; - err = create_controls(spec, pfxs[i - old_num_dacs], - spec->multiout.dac_nids[i], 3); - if (err < 0) - return err; - } - if (spec->multiout.hp_nid) { - const char *pfx; - if (old_num_dacs == spec->multiout.num_dacs) - pfx = "Master"; - else - pfx = "Headphone"; - err = create_controls(spec, pfx, spec->multiout.hp_nid, 3); - if (err < 0) - return err; - } - - return 0; -} - -/* labels for dmic mux inputs */ -static const char *stac92xx_dmic_labels[5] = { - "Analog Inputs", "Digital Mic 1", "Digital Mic 2", - "Digital Mic 3", "Digital Mic 4" -}; - -/* create playback/capture controls for input pins on dmic capable codecs */ -static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *dimux = &spec->private_dimux; - hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; - int i, j; - - dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; - dimux->items[dimux->num_items].index = 0; - dimux->num_items++; - - for (i = 0; i < spec->num_dmics; i++) { - int index; - int num_cons; - unsigned int def_conf; - - def_conf = snd_hda_codec_read(codec, - spec->dmic_nids[i], - 0, - AC_VERB_GET_CONFIG_DEFAULT, - 0); - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) - continue; - - num_cons = snd_hda_get_connections(codec, - spec->dmux_nid, - con_lst, - HDA_MAX_NUM_INPUTS); - for (j = 0; j < num_cons; j++) - if (con_lst[j] == spec->dmic_nids[i]) { - index = j; - goto found; - } - continue; -found: - dimux->items[dimux->num_items].label = - stac92xx_dmic_labels[dimux->num_items]; - dimux->items[dimux->num_items].index = index; - dimux->num_items++; - } - - return 0; -} - -/* create playback/capture controls for input pins */ -static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux; - hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; - int i, j, k; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - int index; - - if (!cfg->input_pins[i]) - continue; - index = -1; - for (j = 0; j < spec->num_muxes; j++) { - int num_cons; - num_cons = snd_hda_get_connections(codec, - spec->mux_nids[j], - con_lst, - HDA_MAX_NUM_INPUTS); - for (k = 0; k < num_cons; k++) - if (con_lst[k] == cfg->input_pins[i]) { - index = k; - goto found; - } - } - continue; - found: - imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = index; - imux->num_items++; - } - - if (imux->num_items) { - /* - * Set the current input for the muxes. - * The STAC9221 has two input muxes with identical source - * NID lists. Hopefully this won't get confused. - */ - for (i = 0; i < spec->num_muxes; i++) { - snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[0].index); - } - } - - return 0; -} - -static void stac92xx_auto_init_multi_out(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.line_outs; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); - } -} - -static void stac92xx_auto_init_hp_out(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.hp_outs; i++) { - hda_nid_t pin; - pin = spec->autocfg.hp_pins[i]; - if (pin) /* connect to front */ - stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); - } - for (i = 0; i < spec->autocfg.speaker_outs; i++) { - hda_nid_t pin; - pin = spec->autocfg.speaker_pins[i]; - if (pin) /* connect to front */ - stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN); - } -} - -static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) -{ - struct sigmatel_spec *spec = codec->spec; - int err; - - if ((err = snd_hda_parse_pin_def_config(codec, - &spec->autocfg, - spec->dmic_nids)) < 0) - return err; - if (! spec->autocfg.line_outs) - return 0; /* can't find valid pin config */ - - if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) - return err; - if (spec->multiout.num_dacs == 0) - if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) - return err; - - err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg); - - if (err < 0) - return err; - - err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); - - if (err < 0) - return err; - - err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); - - if (err < 0) - return err; - - if (spec->num_dmics > 0) - if ((err = stac92xx_auto_create_dmic_input_ctls(codec, - &spec->autocfg)) < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->multiout.max_channels > 2) - spec->surr_switch = 1; - - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = dig_out; - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = dig_in; - - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - - spec->input_mux = &spec->private_imux; - spec->dinput_mux = &spec->private_dimux; - - return 1; -} - -/* add playback controls for HP output */ -static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, - struct auto_pin_cfg *cfg) -{ - 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) - spec->hp_detect = 1; - - return 0; -} - -/* add playback controls for LFE output */ -static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, - struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - int err; - hda_nid_t lfe_pin = 0x0; - int i; - - /* - * search speaker outs and line outs for a mono speaker pin - * with an amp. If one is found, add LFE controls - * for it. - */ - for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) { - hda_nid_t pin = spec->autocfg.speaker_pins[i]; - unsigned long wcaps = get_wcaps(codec, pin); - wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); - if (wcaps == AC_WCAP_OUT_AMP) - /* found a mono speaker with an amp, must be lfe */ - lfe_pin = pin; - } - - /* if speaker_outs is 0, then speakers may be in line_outs */ - if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) { - for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) { - hda_nid_t pin = spec->autocfg.line_out_pins[i]; - unsigned long cfg; - cfg = snd_hda_codec_read(codec, pin, 0, - AC_VERB_GET_CONFIG_DEFAULT, - 0x00); - if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) { - unsigned long wcaps = get_wcaps(codec, pin); - wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); - if (wcaps == AC_WCAP_OUT_AMP) - /* found a mono speaker with an amp, - must be lfe */ - lfe_pin = pin; - } - } - } - - if (lfe_pin) { - err = create_controls(spec, "LFE", lfe_pin, 1); - if (err < 0) - return err; - } - - return 0; -} - -static int stac9200_parse_auto_config(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int err; - - if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) - return err; - - if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) - return err; - - if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) - return err; - - if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) - return err; - - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = 0x05; - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = 0x04; - - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - - spec->input_mux = &spec->private_imux; - spec->dinput_mux = &spec->private_dimux; - - return 1; -} - -/* - * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a - * funky external mute control using GPIO pins. - */ - -static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted) -{ - unsigned int gpiostate, gpiomask, gpiodir; - - gpiostate = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - - if (!muted) - gpiostate |= (1 << pin); - else - gpiostate &= ~(1 << pin); - - gpiomask = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_MASK, 0); - gpiomask |= (1 << pin); - - gpiodir = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DIRECTION, 0); - gpiodir |= (1 << pin); - - /* AppleHDA seems to do this -- WTF is this verb?? */ - snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0); - - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, gpiomask); - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, gpiodir); - - msleep(1); - - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, gpiostate); -} - -static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, - unsigned int event) -{ - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | event)); -} - -static int stac92xx_init(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - snd_hda_sequence_write(codec, spec->init); - - /* set up pins */ - if (spec->hp_detect) { - /* Enable unsolicited responses on the HP widget */ - for (i = 0; i < cfg->hp_outs; i++) - enable_pin_detect(codec, cfg->hp_pins[i], - STAC_HP_EVENT); - /* force to enable the first line-out; the others are set up - * in unsol_event - */ - stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], - AC_PINCTL_OUT_EN); - stac92xx_auto_init_hp_out(codec); - /* fake event to set up pins */ - codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); - } else { - stac92xx_auto_init_multi_out(codec); - stac92xx_auto_init_hp_out(codec); - } - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = cfg->input_pins[i]; - if (nid) { - unsigned int pinctl = AC_PINCTL_IN_EN; - if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) - pinctl |= stac92xx_get_vref(codec, nid); - stac92xx_auto_set_pinctl(codec, nid, pinctl); - } - } - if (spec->num_dmics > 0) - for (i = 0; i < spec->num_dmics; i++) - stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], - AC_PINCTL_IN_EN); - - if (cfg->dig_out_pin) - stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, - AC_PINCTL_OUT_EN); - if (cfg->dig_in_pin) - stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, - AC_PINCTL_IN_EN); - - if (spec->gpio_mute) { - stac922x_gpio_mute(codec, 0, 0); - stac922x_gpio_mute(codec, 1, 0); - } - - return 0; -} - -static void stac92xx_free(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - - if (! spec) - return; - - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } - - if (spec->bios_pin_configs) - kfree(spec->bios_pin_configs); - - kfree(spec); -} - -static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, - unsigned int flag) -{ - unsigned int pin_ctl = snd_hda_codec_read(codec, nid, - 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); - - if (pin_ctl & AC_PINCTL_IN_EN) { - /* - * we need to check the current set-up direction of - * shared input pins since they can be switched via - * "xxx as Output" mixer switch - */ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - if ((nid == cfg->input_pins[AUTO_PIN_LINE] && - spec->line_switch) || - (nid == cfg->input_pins[AUTO_PIN_MIC] && - spec->mic_switch)) - return; - } - - /* if setting pin direction bits, clear the current - direction bits first */ - if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)) - pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pin_ctl | flag); -} - -static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, - unsigned int flag) -{ - unsigned int pin_ctl = snd_hda_codec_read(codec, nid, - 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pin_ctl & ~flag); -} - -static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) -{ - if (!nid) - return 0; - if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) - & (1 << 31)) - return 1; - return 0; -} - -static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, presence; - - presence = 0; - for (i = 0; i < cfg->hp_outs; i++) { - presence = get_pin_presence(codec, cfg->hp_pins[i]); - if (presence) - break; - } - - if (presence) { - /* disable lineouts, enable hp */ - for (i = 0; i < cfg->line_outs; i++) - stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], - AC_PINCTL_OUT_EN); - for (i = 0; i < cfg->speaker_outs; i++) - stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], - AC_PINCTL_OUT_EN); - } else { - /* enable lineouts, disable hp */ - for (i = 0; i < cfg->line_outs; i++) - stac92xx_set_pinctl(codec, cfg->line_out_pins[i], - AC_PINCTL_OUT_EN); - for (i = 0; i < cfg->speaker_outs; i++) - stac92xx_set_pinctl(codec, cfg->speaker_pins[i], - AC_PINCTL_OUT_EN); - } -} - -static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch (res >> 26) { - case STAC_HP_EVENT: - stac92xx_hp_detect(codec, res); - break; - } -} - -#ifdef CONFIG_PM -static int stac92xx_resume(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - - stac92xx_init(codec); - stac92xx_set_config_regs(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; -} -#endif - -static struct hda_codec_ops stac92xx_patch_ops = { - .build_controls = stac92xx_build_controls, - .build_pcms = stac92xx_build_pcms, - .init = stac92xx_init, - .free = stac92xx_free, - .unsol_event = stac92xx_unsol_event, -#ifdef CONFIG_PM - .resume = stac92xx_resume, -#endif -}; - -static int patch_stac9200(struct hda_codec *codec) -{ - struct sigmatel_spec *spec; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - spec->num_pins = ARRAY_SIZE(stac9200_pin_nids); - spec->pin_nids = stac9200_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, - stac9200_models, - stac9200_cfg_tbl); - if (spec->board_config < 0) { - snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac9200_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); - } - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = stac9200_dac_nids; - spec->adc_nids = stac9200_adc_nids; - spec->mux_nids = stac9200_mux_nids; - spec->num_muxes = 1; - spec->num_dmics = 0; - spec->num_adcs = 1; - - spec->init = stac9200_core_init; - spec->mixer = stac9200_mixer; - - err = stac9200_parse_auto_config(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - - codec->patch_ops = stac92xx_patch_ops; - - return 0; -} - -static int patch_stac925x(struct hda_codec *codec) -{ - struct sigmatel_spec *spec; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); - spec->pin_nids = stac925x_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS, - stac925x_models, - stac925x_cfg_tbl); - again: - if (spec->board_config < 0) { - snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," - "using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else if (stac925x_brd_tbl[spec->board_config] != NULL){ - spec->pin_configs = stac925x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); - } - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = stac925x_dac_nids; - spec->adc_nids = stac925x_adc_nids; - spec->mux_nids = stac925x_mux_nids; - spec->num_muxes = 1; - spec->num_adcs = 1; - switch (codec->vendor_id) { - case 0x83847632: /* STAC9202 */ - case 0x83847633: /* STAC9202D */ - case 0x83847636: /* STAC9251 */ - case 0x83847637: /* STAC9251D */ - spec->num_dmics = 1; - spec->dmic_nids = stac925x_dmic_nids; - break; - default: - spec->num_dmics = 0; - break; - } - - spec->init = stac925x_core_init; - spec->mixer = stac925x_mixer; - - err = stac92xx_parse_auto_config(codec, 0x8, 0x7); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_925x_REF; - goto again; - } - err = -EINVAL; - } - if (err < 0) { - stac92xx_free(codec); - return err; - } - - codec->patch_ops = stac92xx_patch_ops; - - return 0; -} - -static int patch_stac922x(struct hda_codec *codec) -{ - struct sigmatel_spec *spec; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - spec->num_pins = ARRAY_SIZE(stac922x_pin_nids); - spec->pin_nids = stac922x_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS, - stac922x_models, - stac922x_cfg_tbl); - if (spec->board_config == STAC_INTEL_MAC_V3) { - spec->gpio_mute = 1; - /* Intel Macs have all same PCI SSID, so we need to check - * codec SSID to distinguish the exact models - */ - printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id); - switch (codec->subsystem_id) { - - case 0x106b0800: - spec->board_config = STAC_INTEL_MAC_V1; - break; - case 0x106b0600: - case 0x106b0700: - spec->board_config = STAC_INTEL_MAC_V2; - break; - case 0x106b0e00: - case 0x106b0f00: - case 0x106b1600: - case 0x106b1700: - case 0x106b0200: - case 0x106b1e00: - spec->board_config = STAC_INTEL_MAC_V3; - break; - case 0x106b1a00: - case 0x00000100: - spec->board_config = STAC_INTEL_MAC_V4; - break; - case 0x106b0a00: - case 0x106b2200: - spec->board_config = STAC_INTEL_MAC_V5; - break; - } - } - - again: - if (spec->board_config < 0) { - snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " - "using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else if (stac922x_brd_tbl[spec->board_config] != NULL) { - spec->pin_configs = stac922x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); - } - - spec->adc_nids = stac922x_adc_nids; - spec->mux_nids = stac922x_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); - spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); - spec->num_dmics = 0; - - spec->init = stac922x_core_init; - spec->mixer = stac922x_mixer; - - spec->multiout.dac_nids = spec->dac_nids; - - err = stac92xx_parse_auto_config(codec, 0x08, 0x09); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_D945_REF; - goto again; - } - err = -EINVAL; - } - if (err < 0) { - stac92xx_free(codec); - return err; - } - - codec->patch_ops = stac92xx_patch_ops; - - /* Fix Mux capture level; max to 2 */ - snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT, - (0 << AC_AMPCAP_OFFSET_SHIFT) | - (2 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (0 << AC_AMPCAP_MUTE_SHIFT)); - - return 0; -} - -static int patch_stac927x(struct hda_codec *codec) -{ - struct sigmatel_spec *spec; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - spec->num_pins = ARRAY_SIZE(stac927x_pin_nids); - spec->pin_nids = stac927x_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS, - stac927x_models, - stac927x_cfg_tbl); - again: - if (spec->board_config < 0) { - snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else if (stac927x_brd_tbl[spec->board_config] != NULL) { - spec->pin_configs = stac927x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); - } - - switch (spec->board_config) { - case STAC_D965_3ST: - spec->adc_nids = stac927x_adc_nids; - spec->mux_nids = stac927x_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); - spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); - spec->num_dmics = 0; - spec->init = d965_core_init; - spec->mixer = stac927x_mixer; - break; - case STAC_D965_5ST: - spec->adc_nids = stac927x_adc_nids; - spec->mux_nids = stac927x_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); - spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); - spec->num_dmics = 0; - spec->init = d965_core_init; - spec->mixer = stac927x_mixer; - break; - default: - spec->adc_nids = stac927x_adc_nids; - spec->mux_nids = stac927x_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); - spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); - spec->num_dmics = 0; - spec->init = stac927x_core_init; - spec->mixer = stac927x_mixer; - } - - spec->multiout.dac_nids = spec->dac_nids; - /* GPIO0 High = Enable EAPD */ - spec->gpio_mask = spec->gpio_data = 0x00000001; - stac92xx_enable_gpio_mask(codec); - - err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_D965_REF; - goto again; - } - err = -EINVAL; - } - if (err < 0) { - stac92xx_free(codec); - return err; - } - - codec->patch_ops = stac92xx_patch_ops; - - return 0; -} - -static int patch_stac9205(struct hda_codec *codec) -{ - struct sigmatel_spec *spec; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - spec->num_pins = ARRAY_SIZE(stac9205_pin_nids); - spec->pin_nids = stac9205_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS, - stac9205_models, - stac9205_cfg_tbl); - again: - if (spec->board_config < 0) { - snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); - err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac9205_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); - } - - spec->adc_nids = stac9205_adc_nids; - spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids); - spec->mux_nids = stac9205_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); - spec->dmic_nids = stac9205_dmic_nids; - spec->num_dmics = ARRAY_SIZE(stac9205_dmic_nids); - spec->dmux_nid = 0x1d; - - spec->init = stac9205_core_init; - spec->mixer = stac9205_mixer; - - spec->multiout.dac_nids = spec->dac_nids; - - switch (spec->board_config){ - case STAC_9205_DELL_M43: - /* Enable SPDIF in/out */ - stac92xx_set_config_reg(codec, 0x1f, 0x01441030); - stac92xx_set_config_reg(codec, 0x20, 0x1c410030); - - spec->gpio_mask = 0x00000007; /* GPIO0-2 */ - /* GPIO0 High = EAPD, GPIO1 Low = DRM, - * GPIO2 High = Headphone Mute - */ - spec->gpio_data = 0x00000005; - break; - default: - /* GPIO0 High = EAPD */ - spec->gpio_mask = spec->gpio_data = 0x00000001; - break; - } - - stac92xx_enable_gpio_mask(codec); - err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_9205_REF; - goto again; - } - err = -EINVAL; - } - if (err < 0) { - stac92xx_free(codec); - return err; - } - - codec->patch_ops = stac92xx_patch_ops; - - return 0; -} - -/* - * STAC9872 hack - */ - -/* static config for Sony VAIO FE550G and Sony VAIO AR */ -static hda_nid_t vaio_dacs[] = { 0x2 }; -#define VAIO_HP_DAC 0x5 -static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ }; -static hda_nid_t vaio_mux_nids[] = { 0x15 }; - -static struct hda_input_mux vaio_mux = { - .num_items = 2, - .items = { - /* { "HP", 0x0 }, */ - { "Mic Jack", 0x1 }, - { "Internal Mic", 0x2 }, - { "PCM", 0x3 }, - } -}; - -static struct hda_verb vaio_init[] = { - {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */ - {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT}, - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */ - {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */ - {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */ - {} -}; - -static struct hda_verb vaio_ar_init[] = { - {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */ - {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */ - {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */ -/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */ -/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */ - {} -}; - -/* bind volumes of both NID 0x02 and 0x05 */ -static int vaio_master_vol_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 = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} - -/* bind volumes of both NID 0x02 and 0x05 */ -static int vaio_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 = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, - 0x80, (valp[0] ? 0 : 0x80)); - change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, - 0x80, (valp[1] ? 0 : 0x80)); - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x80, (valp[0] ? 0 : 0x80)); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x80, (valp[1] ? 0 : 0x80)); - return change; -} - -static struct snd_kcontrol_new vaio_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = vaio_master_vol_put, -#ifdef FOUND_TLV - .tlv = { .c = snd_hda_mixer_amp_tlv }, -#endif - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = vaio_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, - /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, - {} -}; - -static struct snd_kcontrol_new vaio_ar_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = vaio_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = vaio_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, - /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), - /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/ - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, - {} -}; - -static struct hda_codec_ops stac9872_patch_ops = { - .build_controls = stac92xx_build_controls, - .build_pcms = stac92xx_build_pcms, - .init = stac92xx_init, - .free = stac92xx_free, -#ifdef CONFIG_PM - .resume = stac92xx_resume, -#endif -}; - -static int stac9872_vaio_init(struct hda_codec *codec) -{ - int err; - - err = stac92xx_init(codec); - if (err < 0) - return err; - if (codec->patch_ops.unsol_event) - codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); - return 0; -} - -static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) -{ - if (get_pin_presence(codec, 0x0a)) { - stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); - stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); - } else { - stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); - stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); - } -} - -static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch (res >> 26) { - case STAC_HP_EVENT: - stac9872_vaio_hp_detect(codec, res); - break; - } -} - -static struct hda_codec_ops stac9872_vaio_patch_ops = { - .build_controls = stac92xx_build_controls, - .build_pcms = stac92xx_build_pcms, - .init = stac9872_vaio_init, - .free = stac92xx_free, - .unsol_event = stac9872_vaio_unsol_event, -#ifdef CONFIG_PM - .resume = stac92xx_resume, -#endif -}; - -enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */ - CXD9872RD_VAIO, - /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */ - STAC9872AK_VAIO, - /* Unknown. id=0x83847661 and subsys=0x104D1200. */ - STAC9872K_VAIO, - /* AR Series. id=0x83847664 and subsys=104D1300 */ - CXD9872AKD_VAIO, - STAC_9872_MODELS, -}; - -static const char *stac9872_models[STAC_9872_MODELS] = { - [CXD9872RD_VAIO] = "vaio", - [CXD9872AKD_VAIO] = "vaio-ar", -}; - -static struct snd_pci_quirk stac9872_cfg_tbl[] = { - SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO), - SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO), - SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO), - SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO), - {} -}; - -static int patch_stac9872(struct hda_codec *codec) -{ - struct sigmatel_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS, - stac9872_models, - stac9872_cfg_tbl); - if (board_config < 0) - /* unknown config, let generic-parser do its job... */ - return snd_hda_parse_generic_codec(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - switch (board_config) { - case CXD9872RD_VAIO: - case STAC9872AK_VAIO: - case STAC9872K_VAIO: - spec->mixer = vaio_mixer; - spec->init = vaio_init; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs); - spec->multiout.dac_nids = vaio_dacs; - spec->multiout.hp_nid = VAIO_HP_DAC; - spec->num_adcs = ARRAY_SIZE(vaio_adcs); - spec->adc_nids = vaio_adcs; - spec->input_mux = &vaio_mux; - spec->mux_nids = vaio_mux_nids; - codec->patch_ops = stac9872_vaio_patch_ops; - break; - - case CXD9872AKD_VAIO: - spec->mixer = vaio_ar_mixer; - spec->init = vaio_ar_init; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs); - spec->multiout.dac_nids = vaio_dacs; - spec->multiout.hp_nid = VAIO_HP_DAC; - spec->num_adcs = ARRAY_SIZE(vaio_adcs); - spec->adc_nids = vaio_adcs; - spec->input_mux = &vaio_mux; - spec->mux_nids = vaio_mux_nids; - codec->patch_ops = stac9872_patch_ops; - break; - } - - return 0; -} - - -/* - * patch entries - */ -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 }, - { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x }, - { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, - { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, - { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, - { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x }, - { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x }, - { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x }, - { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x }, - { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x }, - { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x }, - { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x }, - { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x }, - { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x }, - { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x }, - { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x }, - { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x }, - { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x }, - { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, - { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, - { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, - { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x }, - { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x }, - { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x }, - { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x }, - { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x }, - { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x }, - /* The following does not take into account .id=0x83847661 when subsys = - * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are - * currently not fully supported. - */ - { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 }, - { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 }, - { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 }, - { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 }, - { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 }, - { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 }, - { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 }, - { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 }, - { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, - { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, - { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, - {} /* terminator */ -}; diff --git a/modules/GPL/hda/patch_via.c b/modules/GPL/hda/patch_via.c deleted file mode 100644 index dde43d9..0000000 --- a/modules/GPL/hda/patch_via.c +++ /dev/null @@ -1,1410 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * HD audio interface patch for VIA VT1708 codec - * - * Copyright (c) 2006 Lydia Wang - * Takashi Iwai - * - * This driver 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 driver 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 - */ - -/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */ -/* */ -/* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */ -/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ -/* 2006-08-02 Lydia Wang Add support to VT1709 codec */ -/* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ -/* */ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -#include -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - - -/* amp values */ -#define AMP_VAL_IDX_SHIFT 19 -#define AMP_VAL_IDX_MASK (0x0f<<19) - -#define NUM_CONTROL_ALLOC 32 -#define NUM_VERB_ALLOC 32 - -/* Pin Widget NID */ -#define VT1708_HP_NID 0x13 -#define VT1708_DIGOUT_NID 0x14 -#define VT1708_DIGIN_NID 0x16 - -#define VT1709_HP_DAC_NID 0x28 -#define VT1709_DIGOUT_NID 0x13 -#define VT1709_DIGIN_NID 0x17 - -#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) -#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) -#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) - - -enum { - VIA_CTL_WIDGET_VOL, - VIA_CTL_WIDGET_MUTE, -}; - -enum { - AUTO_SEQ_FRONT, - AUTO_SEQ_SURROUND, - AUTO_SEQ_CENLFE, - AUTO_SEQ_SIDE -}; - -static struct snd_kcontrol_new vt1708_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), -}; - - -struct via_spec { - /* codec parameterization */ - struct snd_kcontrol_new *mixers[3]; - unsigned int num_mixers; - - struct hda_verb *init_verbs; - - char *stream_name_analog; - struct hda_pcm_stream *stream_analog_playback; - 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; - - /* playback */ - struct hda_multi_out multiout; - - /* capture */ - unsigned int num_adc_nids; - hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; - - /* capture source */ - const struct hda_input_mux *input_mux; - unsigned int cur_mux[3]; - - /* PCM information */ - struct hda_pcm pcm_rec[2]; - - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; - struct hda_input_mux private_imux; - hda_nid_t private_dac_nids[4]; -}; - -static hda_nid_t vt1708_adc_nids[2] = { - /* ADC1-2 */ - 0x15, 0x27 -}; - -static hda_nid_t vt1709_adc_nids[3] = { - /* ADC1-2 */ - 0x14, 0x15, 0x16 -}; - -/* add dynamic controls */ -static int via_add_control(struct via_spec *spec, int type, const char *name, - unsigned long val) -{ - struct snd_kcontrol_new *knew; - size_t namelen = strlen(name) + 1; - - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - /* array + terminator */ - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); - if (!knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, - sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; - *knew = vt1708_control_templates[type]; - knew->name = kmalloc(namelen, GFP_KERNEL); - - if (!knew->name) - return -ENOMEM; - memcpy(knew->name, name, namelen); - knew->private_value = val; - spec->num_kctl_used++; - return 0; -} - -/* create input playback/capture controls for the given pin */ -static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin, - const char *ctlname, int idx, int mix_nid) -{ - char name[32]; - int err; - - sprintf(name, "%s Playback Volume", ctlname); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", ctlname); - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - return 0; -} - -static void via_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, int pin_type, - int dac_idx) -{ - /* set as output */ - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - pin_type); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); -} - - -static void via_auto_init_multi_out(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; - - for (i = 0; i <= AUTO_SEQ_SIDE; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - if (nid) - via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); - } -} - -static void via_auto_init_hp_out(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - hda_nid_t pin; - - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); -} - -static void via_auto_init_analog_input(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - (i <= AUTO_PIN_FRONT_MIC ? - PIN_VREF50 : PIN_IN)); - - } -} -/* - * input MUX handling - */ -static int via_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int via_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int via_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - unsigned int vendor_id = codec->vendor_id; - - /* AIW0 lydia 060801 add for correct sw0 input select */ - if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0)) - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - 0x18, &spec->cur_mux[adc_idx]); - else if ((IS_VT1709_10CH_VENDORID(vendor_id) || - IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) ) - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - 0x19, &spec->cur_mux[adc_idx]); - else - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->adc_nids[adc_idx], - &spec->cur_mux[adc_idx]); -} - -/* capture mixer elements */ -static 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), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = via_mux_enum_info, - .get = via_mux_enum_get, - .put = via_mux_enum_put, - }, - { } /* end */ -}; -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb vt1708_volume_init_verbs[] = { - /* - * Unmute ADC0-1 and set the default input to mic-in - */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - - /* Unmute 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 */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output mixers (0x19 - 0x1b) - */ - /* set vol=0 to output mixers */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Setup default input to PW4 */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Set mic as default input of sw0 */ - {0x18, AC_VERB_SET_CONNECT_SEL, 0x2}, - /* PW9 Output enable */ - {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, -}; - -static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); -} - -static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -/* - * Analog capture - */ -static int via_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 via_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - 0, 0, 0); - return 0; -} - -static struct hda_pcm_stream vt1708_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = 0x10, /* NID to query formats and rates */ - .ops = { - .open = via_playback_pcm_open, - .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream vt1708_pcm_analog_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - .nid = 0x15, /* NID to query formats and rates */ - .ops = { - .prepare = via_capture_pcm_prepare, - .cleanup = via_capture_pcm_cleanup - }, -}; - -static struct hda_pcm_stream vt1708_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .open = via_dig_playback_pcm_open, - .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare - }, -}; - -static struct hda_pcm_stream vt1708_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -static int via_build_controls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int err; - int i; - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - return 0; -} - -static int via_build_pcms(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = spec->stream_name_analog; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - codec->num_pcms++; - info++; - info->name = spec->stream_name_digital; - if (spec->multiout.dig_out_nid) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *(spec->stream_digital_playback); - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - *(spec->stream_digital_capture); - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->dig_in_nid; - } - } - - return 0; -} - -static void via_free(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - unsigned int i; - - if (!spec) - return; - - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } - - kfree(codec->spec); -} - -static int via_init(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - snd_hda_sequence_write(codec, spec->init_verbs); - return 0; -} - -#ifdef CONFIG_PM -/* - * resume - */ -static int via_resume(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; - - via_init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; -} -#endif - -/* - */ -static struct hda_codec_ops via_patch_ops = { - .build_controls = via_build_controls, - .build_pcms = via_build_pcms, - .init = via_init, - .free = via_free, -#ifdef CONFIG_PM - .resume = via_resume, -#endif -}; - -/* fill in the dac_nids table from the parsed pin configuration */ -static int vt1708_auto_fill_dac_nids(struct via_spec *spec, - const struct auto_pin_cfg *cfg) -{ - int i; - hda_nid_t nid; - - spec->multiout.num_dacs = cfg->line_outs; - - spec->multiout.dac_nids = spec->private_dac_nids; - - for(i = 0; i < 4; i++) { - nid = cfg->line_out_pins[i]; - if (nid) { - /* config dac list */ - switch (i) { - case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x10; - break; - case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0x12; - break; - case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x13; - break; - case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0x11; - break; - } - } - } - - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, - const struct auto_pin_cfg *cfg) -{ - char name[32]; - static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; - hda_nid_t nid, nid_vol = 0; - int i, err; - - for (i = 0; i <= AUTO_SEQ_SIDE; i++) { - nid = cfg->line_out_pins[i]; - - if (!nid) - continue; - - if (i != AUTO_SEQ_FRONT) - nid_vol = 0x1b - i + 1; - - if (i == AUTO_SEQ_CENLFE) { - /* Center/LFE */ - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, - "Center Playback Volume", - HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, - "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } else if (i == AUTO_SEQ_FRONT){ - /* add control to mixer index 0 */ - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, - "Master Front Playback Volume", - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "Master Front Playback Switch", - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - - /* add control to PW3 */ - sprintf(name, "%s Playback Volume", chname[i]); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } else { - sprintf(name, "%s Playback Volume", chname[i]); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - } - - return 0; -} - -static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) -{ - int err; - - if (!pin) - return 0; - - spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */ - - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, - "Headphone Playback Volume", - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "Headphone Playback Switch", - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - - return 0; -} - -/* create playback/capture controls for input pins */ -static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, - const struct auto_pin_cfg *cfg) -{ - static char *labels[] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL - }; - struct hda_input_mux *imux = &spec->private_imux; - int i, err, idx = 0; - - /* for internal loopback recording select */ - imux->items[imux->num_items].label = "Stereo Mixer"; - imux->items[imux->num_items].index = idx; - imux->num_items++; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!cfg->input_pins[i]) - continue; - - switch (cfg->input_pins[i]) { - case 0x1d: /* Mic */ - idx = 2; - break; - - case 0x1e: /* Line In */ - idx = 3; - break; - - case 0x21: /* Front Mic */ - idx = 4; - break; - - case 0x24: /* CD */ - idx = 1; - break; - } - err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], - idx, 0x17); - if (err < 0) - return err; - imux->items[imux->num_items].label = labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } - return 0; -} - -static int vt1708_parse_auto_config(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int err; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg); - if (err < 0) - return err; - if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) - return 0; /* can't find valid BIOS pin config */ - - err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); - if (err < 0) - return err; - err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = VT1708_DIGOUT_NID; - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = VT1708_DIGIN_NID; - - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - - spec->init_verbs = vt1708_volume_init_verbs; - - spec->input_mux = &spec->private_imux; - - return 1; -} - -/* init callback for auto-configuration model -- overriding the default init */ -static int via_auto_init(struct hda_codec *codec) -{ - via_init(codec); - via_auto_init_multi_out(codec); - via_auto_init_hp_out(codec); - via_auto_init_analog_input(codec); - return 0; -} - -static int patch_vt1708(struct hda_codec *codec) -{ - struct via_spec *spec; - int err; - - /* create a codec specific record */ - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - /* automatic parse from the BIOS config */ - err = vt1708_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } else if (!err) { - printk(KERN_INFO "hda_codec: Cannot set up configuration " - "from BIOS. Using genenic mode...\n"); - } - - - spec->stream_name_analog = "VT1708 Analog"; - spec->stream_analog_playback = &vt1708_pcm_analog_playback; - spec->stream_analog_capture = &vt1708_pcm_analog_capture; - - spec->stream_name_digital = "VT1708 Digital"; - spec->stream_digital_playback = &vt1708_pcm_digital_playback; - spec->stream_digital_capture = &vt1708_pcm_digital_capture; - - - if (!spec->adc_nids && spec->input_mux) { - spec->adc_nids = vt1708_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids); - spec->mixers[spec->num_mixers] = vt1708_capture_mixer; - spec->num_mixers++; - } - - codec->patch_ops = via_patch_ops; - - codec->patch_ops.init = via_auto_init; - - return 0; -} - -/* capture mixer elements */ -static 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), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = via_mux_enum_info, - .get = via_mux_enum_get, - .put = via_mux_enum_put, - }, - { } /* end */ -}; - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb vt1709_10ch_volume_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - */ - /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output selector (0x1a, 0x1b, 0x29) - */ - /* set vol=0 to output mixers */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* - * Unmute PW3 and PW4 - */ - {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Set input of PW4 as AOW4 */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Set mic as default input of sw0 */ - {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, - /* PW9 Output enable */ - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - { } -}; - -static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 10, - .nid = 0x10, /* NID to query formats and rates */ - .ops = { - .open = via_playback_pcm_open, - .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 6, - .nid = 0x10, /* NID to query formats and rates */ - .ops = { - .open = via_playback_pcm_open, - .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream vt1709_pcm_analog_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - .nid = 0x14, /* NID to query formats and rates */ - .ops = { - .prepare = via_capture_pcm_prepare, - .cleanup = via_capture_pcm_cleanup - }, -}; - -static struct hda_pcm_stream vt1709_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .open = via_dig_playback_pcm_open, - .close = via_dig_playback_pcm_close - }, -}; - -static struct hda_pcm_stream vt1709_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -static int vt1709_auto_fill_dac_nids(struct via_spec *spec, - const struct auto_pin_cfg *cfg) -{ - int i; - hda_nid_t nid; - - if (cfg->line_outs == 4) /* 10 channels */ - spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */ - else if (cfg->line_outs == 3) /* 6 channels */ - spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */ - - spec->multiout.dac_nids = spec->private_dac_nids; - - if (cfg->line_outs == 4) { /* 10 channels */ - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - if (nid) { - /* config dac list */ - switch (i) { - case AUTO_SEQ_FRONT: - /* AOW0 */ - spec->multiout.dac_nids[i] = 0x10; - break; - case AUTO_SEQ_CENLFE: - /* AOW2 */ - spec->multiout.dac_nids[i] = 0x12; - break; - case AUTO_SEQ_SURROUND: - /* AOW3 */ - spec->multiout.dac_nids[i] = 0x27; - break; - case AUTO_SEQ_SIDE: - /* AOW1 */ - spec->multiout.dac_nids[i] = 0x11; - break; - default: - break; - } - } - } - spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ - - } else if (cfg->line_outs == 3) { /* 6 channels */ - for(i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - if (nid) { - /* config dac list */ - switch(i) { - case AUTO_SEQ_FRONT: - /* AOW0 */ - spec->multiout.dac_nids[i] = 0x10; - break; - case AUTO_SEQ_CENLFE: - /* AOW2 */ - spec->multiout.dac_nids[i] = 0x12; - break; - case AUTO_SEQ_SURROUND: - /* AOW1 */ - spec->multiout.dac_nids[i] = 0x11; - break; - default: - break; - } - } - } - } - - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, - const struct auto_pin_cfg *cfg) -{ - char name[32]; - static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; - hda_nid_t nid = 0; - int i, err; - - for (i = 0; i <= AUTO_SEQ_SIDE; i++) { - nid = cfg->line_out_pins[i]; - - if (!nid) - continue; - - if (i == AUTO_SEQ_CENLFE) { - /* Center/LFE */ - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, - "Center Playback Volume", - HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, - "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } else if (i == AUTO_SEQ_FRONT){ - /* add control to mixer index 0 */ - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, - "Master Front Playback Volume", - HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "Master Front Playback Switch", - HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - - /* add control to PW3 */ - sprintf(name, "%s Playback Volume", chname[i]); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } else if (i == AUTO_SEQ_SURROUND) { - sprintf(name, "%s Playback Volume", chname[i]); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } else if (i == AUTO_SEQ_SIDE) { - sprintf(name, "%s Playback Volume", chname[i]); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - } - - return 0; -} - -static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) -{ - int err; - - if (!pin) - return 0; - - if (spec->multiout.num_dacs == 5) /* 10 channels */ - spec->multiout.hp_nid = VT1709_HP_DAC_NID; - else if (spec->multiout.num_dacs == 3) /* 6 channels */ - spec->multiout.hp_nid = 0; - - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, - "Headphone Playback Volume", - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "Headphone Playback Switch", - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - - return 0; -} - -/* create playback/capture controls for input pins */ -static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec, - const struct auto_pin_cfg *cfg) -{ - static char *labels[] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL - }; - struct hda_input_mux *imux = &spec->private_imux; - int i, err, idx = 0; - - /* for internal loopback recording select */ - imux->items[imux->num_items].label = "Stereo Mixer"; - imux->items[imux->num_items].index = idx; - imux->num_items++; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!cfg->input_pins[i]) - continue; - - switch (cfg->input_pins[i]) { - case 0x1d: /* Mic */ - idx = 2; - break; - - case 0x1e: /* Line In */ - idx = 3; - break; - - case 0x21: /* Front Mic */ - idx = 4; - break; - - case 0x23: /* CD */ - idx = 1; - break; - } - err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], - idx, 0x18); - if (err < 0) - return err; - imux->items[imux->num_items].label = labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } - return 0; -} - -static int vt1709_parse_auto_config(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int err; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg); - if (err < 0) - return err; - if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) - return 0; /* can't find valid BIOS pin config */ - - err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); - if (err < 0) - return err; - err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - if (spec->autocfg.dig_out_pin) - spec->multiout.dig_out_nid = VT1709_DIGOUT_NID; - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = VT1709_DIGIN_NID; - - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - - spec->input_mux = &spec->private_imux; - - return 1; -} - -static int patch_vt1709_10ch(struct hda_codec *codec) -{ - struct via_spec *spec; - int err; - - /* create a codec specific record */ - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - err = vt1709_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } else if (!err) { - printk(KERN_INFO "hda_codec: Cannot set up configuration. " - "Using genenic mode...\n"); - } - - spec->init_verbs = vt1709_10ch_volume_init_verbs; - - spec->stream_name_analog = "VT1709 Analog"; - spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback; - spec->stream_analog_capture = &vt1709_pcm_analog_capture; - - spec->stream_name_digital = "VT1709 Digital"; - spec->stream_digital_playback = &vt1709_pcm_digital_playback; - spec->stream_digital_capture = &vt1709_pcm_digital_capture; - - - if (!spec->adc_nids && spec->input_mux) { - spec->adc_nids = vt1709_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); - spec->mixers[spec->num_mixers] = vt1709_capture_mixer; - spec->num_mixers++; - } - - codec->patch_ops = via_patch_ops; - - codec->patch_ops.init = via_auto_init; - - return 0; -} -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb vt1709_6ch_volume_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - */ - /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - /* - * Set up output selector (0x1a, 0x1b, 0x29) - */ - /* set vol=0 to output mixers */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* - * Unmute PW3 and PW4 - */ - {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Set input of PW4 as MW0 */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0}, - /* Set mic as default input of sw0 */ - {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, - /* PW9 Output enable */ - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - { } -}; - -static int patch_vt1709_6ch(struct hda_codec *codec) -{ - struct via_spec *spec; - int err; - - /* create a codec specific record */ - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - err = vt1709_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } else if (!err) { - printk(KERN_INFO "hda_codec: Cannot set up configuration. " - "Using genenic mode...\n"); - } - - spec->init_verbs = vt1709_6ch_volume_init_verbs; - - spec->stream_name_analog = "VT1709 Analog"; - spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback; - spec->stream_analog_capture = &vt1709_pcm_analog_capture; - - spec->stream_name_digital = "VT1709 Digital"; - spec->stream_digital_playback = &vt1709_pcm_digital_playback; - spec->stream_digital_capture = &vt1709_pcm_digital_capture; - - - if (!spec->adc_nids && spec->input_mux) { - spec->adc_nids = vt1709_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); - spec->mixers[spec->num_mixers] = vt1709_capture_mixer; - spec->num_mixers++; - } - - codec->patch_ops = via_patch_ops; - - codec->patch_ops.init = via_auto_init; - - return 0; -} - -/* - * patch entries - */ -struct hda_codec_preset snd_hda_preset_via[] = { - { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, - { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, - { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, - { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, - {} /* terminator */ -}; diff --git a/modules/GPL/hda/sound_typedefs.h b/modules/GPL/hda/sound_typedefs.h deleted file mode 100644 index f454b02..0000000 --- a/modules/GPL/hda/sound_typedefs.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Typedef's for backward compatibility (for out-of-kernel drivers) - * - * This file will be removed soon in future - */ - -/* core stuff */ -typedef struct snd_card snd_card_t; -typedef struct snd_device snd_device_t; -typedef struct snd_device_ops snd_device_ops_t; -typedef enum snd_card_type snd_card_type_t; -typedef struct snd_minor snd_minor_t; - -/* info */ -typedef struct snd_info_entry snd_info_entry_t; -typedef struct snd_info_buffer snd_info_buffer_t; - -/* control */ -typedef struct snd_ctl_file snd_ctl_file_t; -typedef struct snd_kcontrol snd_kcontrol_t; -typedef struct snd_kcontrol_new snd_kcontrol_new_t; -typedef struct snd_kcontrol_volatile snd_kcontrol_volatile_t; -typedef struct snd_kctl_event snd_kctl_event_t; -typedef struct snd_aes_iec958 snd_aes_iec958_t; -typedef struct snd_ctl_card_info snd_ctl_card_info_t; -typedef struct snd_ctl_elem_id snd_ctl_elem_id_t; -typedef struct snd_ctl_elem_list snd_ctl_elem_list_t; -typedef struct snd_ctl_elem_info snd_ctl_elem_info_t; -typedef struct snd_ctl_elem_value snd_ctl_elem_value_t; -typedef struct snd_ctl_event snd_ctl_event_t; -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) -typedef struct snd_mixer_oss snd_mixer_oss_t; -#endif - -/* timer */ -typedef struct snd_timer snd_timer_t; -typedef struct snd_timer_instance snd_timer_instance_t; -typedef struct snd_timer_id snd_timer_id_t; -typedef struct snd_timer_ginfo snd_timer_ginfo_t; -typedef struct snd_timer_gparams snd_timer_gparams_t; -typedef struct snd_timer_gstatus snd_timer_gstatus_t; -typedef struct snd_timer_select snd_timer_select_t; -typedef struct snd_timer_info snd_timer_info_t; -typedef struct snd_timer_params snd_timer_params_t; -typedef struct snd_timer_status snd_timer_status_t; -typedef struct snd_timer_read snd_timer_read_t; -typedef struct snd_timer_tread snd_timer_tread_t; - -/* PCM */ -typedef struct snd_pcm snd_pcm_t; -typedef struct snd_pcm_str snd_pcm_str_t; -typedef struct snd_pcm_substream snd_pcm_substream_t; -typedef struct snd_pcm_info snd_pcm_info_t; -typedef struct snd_pcm_hw_params snd_pcm_hw_params_t; -typedef struct snd_pcm_sw_params snd_pcm_sw_params_t; -typedef struct snd_pcm_channel_info snd_pcm_channel_info_t; -typedef struct snd_pcm_status snd_pcm_status_t; -typedef struct snd_pcm_mmap_status snd_pcm_mmap_status_t; -typedef struct snd_pcm_mmap_control snd_pcm_mmap_control_t; -typedef struct snd_mask snd_mask_t; -typedef struct snd_sg_buf snd_pcm_sgbuf_t; - -typedef struct snd_interval snd_interval_t; -typedef struct snd_xferi snd_xferi_t; -typedef struct snd_xfern snd_xfern_t; -typedef struct snd_xferv snd_xferv_t; - -typedef struct snd_pcm_file snd_pcm_file_t; -typedef struct snd_pcm_runtime snd_pcm_runtime_t; -typedef struct snd_pcm_hardware snd_pcm_hardware_t; -typedef struct snd_pcm_ops snd_pcm_ops_t; -typedef struct snd_pcm_hw_rule snd_pcm_hw_rule_t; -typedef struct snd_pcm_hw_constraints snd_pcm_hw_constraints_t; -typedef struct snd_ratnum ratnum_t; -typedef struct snd_ratden ratden_t; -typedef struct snd_pcm_hw_constraint_ratnums snd_pcm_hw_constraint_ratnums_t; -typedef struct snd_pcm_hw_constraint_ratdens snd_pcm_hw_constraint_ratdens_t; -typedef struct snd_pcm_hw_constraint_list snd_pcm_hw_constraint_list_t; -typedef struct snd_pcm_group snd_pcm_group_t; -typedef struct snd_pcm_notify snd_pcm_notify_t; - -/* rawmidi */ -typedef struct snd_rawmidi snd_rawmidi_t; -typedef struct snd_rawmidi_info snd_rawmidi_info_t; -typedef struct snd_rawmidi_params snd_rawmidi_params_t; -typedef struct snd_rawmidi_status snd_rawmidi_status_t; -typedef struct snd_rawmidi_runtime snd_rawmidi_runtime_t; -typedef struct snd_rawmidi_substream snd_rawmidi_substream_t; -typedef struct snd_rawmidi_str snd_rawmidi_str_t; -typedef struct snd_rawmidi_ops snd_rawmidi_ops_t; -typedef struct snd_rawmidi_global_ops snd_rawmidi_global_ops_t; -typedef struct snd_rawmidi_file snd_rawmidi_file_t; - -/* hwdep */ -typedef struct snd_hwdep snd_hwdep_t; -typedef struct snd_hwdep_info snd_hwdep_info_t; -typedef struct snd_hwdep_dsp_status snd_hwdep_dsp_status_t; -typedef struct snd_hwdep_dsp_image snd_hwdep_dsp_image_t; -typedef struct snd_hwdep_ops snd_hwdep_ops_t; - -/* sequencer */ -typedef struct snd_seq_port_info snd_seq_port_info_t; -typedef struct snd_seq_port_subscribe snd_seq_port_subscribe_t; -typedef struct snd_seq_event snd_seq_event_t; -typedef struct snd_seq_addr snd_seq_addr_t; -typedef struct snd_seq_ev_volume snd_seq_ev_volume_t; -typedef struct snd_seq_ev_loop snd_seq_ev_loop_t; -typedef struct snd_seq_remove_events snd_seq_remove_events_t; -typedef struct snd_seq_query_subs snd_seq_query_subs_t; -typedef struct snd_seq_system_info snd_seq_system_info_t; -typedef struct snd_seq_client_info snd_seq_client_info_t; -typedef struct snd_seq_queue_info snd_seq_queue_info_t; -typedef struct snd_seq_queue_status snd_seq_queue_status_t; -typedef struct snd_seq_queue_tempo snd_seq_queue_tempo_t; -typedef struct snd_seq_queue_owner snd_seq_queue_owner_t; -typedef struct snd_seq_queue_timer snd_seq_queue_timer_t; -typedef struct snd_seq_queue_client snd_seq_queue_client_t; -typedef struct snd_seq_client_pool snd_seq_client_pool_t; -typedef struct snd_seq_instr snd_seq_instr_t; -typedef struct snd_seq_instr_data snd_seq_instr_data_t; -typedef struct snd_seq_instr_header snd_seq_instr_header_t; - -typedef struct snd_seq_user_client user_client_t; -typedef struct snd_seq_kernel_client kernel_client_t; -typedef struct snd_seq_client client_t; -typedef struct snd_seq_queue queue_t; - -/* seq_device */ -typedef struct snd_seq_device snd_seq_device_t; -typedef struct snd_seq_dev_ops snd_seq_dev_ops_t; - -/* seq_midi */ -typedef struct snd_midi_event snd_midi_event_t; - -/* seq_midi_emul */ -typedef struct snd_midi_channel snd_midi_channel_t; -typedef struct snd_midi_channel_set snd_midi_channel_set_t; -typedef struct snd_midi_op snd_midi_op_t; - -/* seq_oss */ -typedef struct snd_seq_oss_arg snd_seq_oss_arg_t; -typedef struct snd_seq_oss_callback snd_seq_oss_callback_t; -typedef struct snd_seq_oss_reg snd_seq_oss_reg_t; - -/* virmidi */ -typedef struct snd_virmidi_dev snd_virmidi_dev_t; -typedef struct snd_virmidi snd_virmidi_t; - -/* seq_instr */ -typedef struct snd_seq_kcluster snd_seq_kcluster_t; -typedef struct snd_seq_kinstr_ops snd_seq_kinstr_ops_t; -typedef struct snd_seq_kinstr snd_seq_kinstr_t; -typedef struct snd_seq_kinstr_list snd_seq_kinstr_list_t; - -/* ac97 */ -typedef struct snd_ac97_bus ac97_bus_t; -typedef struct snd_ac97_bus_ops ac97_bus_ops_t; -typedef struct snd_ac97_template ac97_template_t; -typedef struct snd_ac97 ac97_t; - -/* opl3/4 */ -typedef struct snd_opl3 opl3_t; -typedef struct snd_opl4 opl4_t; - -/* mpu401 */ -typedef struct snd_mpu401 mpu401_t; - -/* i2c */ -typedef struct snd_i2c_device snd_i2c_device_t; -typedef struct snd_i2c_bus snd_i2c_bus_t; - -typedef struct snd_ak4531 ak4531_t; - diff --git a/modules/GPL/oscompat.h b/modules/GPL/oscompat.h old mode 100644 new mode 100755 index 86cc278..82d2023 --- a/modules/GPL/oscompat.h +++ b/modules/GPL/oscompat.h @@ -83,6 +83,10 @@ static int errno; #endif #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0) +#include +#include +#endif #include #include #include @@ -126,6 +130,17 @@ static int errno; #include #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) +#define init_kthread_worker kthread_init_worker +#define init_kthread_work kthread_init_work +#define queue_kthread_work kthread_queue_work +#if LINUX_VERSION_CODE > KERNEL_VERSION(4,9,0) +static inline void clts(void){ + asm volatile("clts"); +} +#endif +#endif + /* * New proposed "bottom half" handlers: * (C) 1994 Kai Petzke, wpp@marie.physik.tu-berlin.de @@ -680,11 +695,11 @@ kill_proc(pid_t pid, int sig, int priv) } #endif -#ifdef FOUND_STRUCT_TTY_PORT -#define UART_INFO_TO_TTY(ui) (ui->port.tty) -#else -#define UART_INFO_TO_TTY(ui) (ui->tty) -#endif + #ifdef FOUND_STRUCT_TTY_PORT + #define UART_INFO_TO_TTY(ui) (ui->port.tty) + #else + #define UART_INFO_TO_TTY(ui) (ui->tty) + #endif #ifdef FOUND_NO_STRUCT_UART_INFO typedef struct uart_state uart_info_t; diff --git a/modules/GPL/serial_cnxt.c b/modules/GPL/serial_cnxt.c old mode 100644 new mode 100755 index 31b5669..7328ea1 --- a/modules/GPL/serial_cnxt.c +++ b/modules/GPL/serial_cnxt.c @@ -1,66 +1,66 @@ /* - * Virtual serial port driver for Conexant modems - * - * Written by Marc Boucher - */ +* Virtual serial port driver for Conexant modems +* +* Written by Marc Boucher +*/ /* - * Copyright (c) 2001-2002 Conexant Systems, Inc. - * Copyright (c) 2003-2004 Linuxant inc. - * - * 1. General Public License. This program is free software, and may - * be redistributed or modified subject to the terms of the GNU General - * Public License (version 2) or the GNU Lesser General Public License, - * or (at your option) any later versions ("Open Source" code). You may - * obtain a copy of the GNU General Public License at - * http://www.fsf.org/copyleft/gpl.html and a copy of the GNU Lesser - * General Public License at http://www.fsf.org/copyleft/less.html, - * or you may alternatively write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * 2. Disclaimer of Warranties. CONEXANT AND OTHER CONTRIBUTORS MAKE NO - * REPRESENTATION ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. - * IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTIES OF ANY KIND. - * CONEXANT AND OTHER CONTRIBUTORS DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE, GOOD TITLE AND AGAINST INFRINGEMENT. - * - * This software has not been formally tested, and there is no guarantee that - * it is free of errors including, but not limited to, bugs, defects, - * interrupted operation, or unexpected results. Any use of this software is - * at user's own risk. - * - * 3. No Liability. - * - * (a) Conexant or contributors shall not be responsible for any loss or - * damage to user, or any third parties for any reason whatsoever, and - * CONEXANT OR CONTRIBUTORS SHALL NOT BE LIABLE FOR ANY ACTUAL, DIRECT, - * INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL, OR CONSEQUENTIAL - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED, WHETHER IN CONTRACT, STRICT OR OTHER LEGAL THEORY OF - * 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. - * - * (b) User agrees to hold Conexant and contributors harmless from any - * liability, loss, cost, damage or expense, including attorney's fees, - * as a result of any claims which may be made by any person, including - * but not limited to User, its agents and employees, its customers, or - * any third parties that arise out of or result from the manufacture, - * delivery, actual or alleged ownership, performance, use, operation - * or possession of the software furnished hereunder, whether such claims - * are based on negligence, breach of contract, absolute liability or any - * other legal theory. - * - * 4. Notices. User hereby agrees not to remove, alter or destroy any - * copyright, trademark, credits, other proprietary notices or confidential - * legends placed upon, contained within or associated with the Software, - * and shall include all such unaltered copyright, trademark, credits, - * other proprietary notices or confidential legends on or in every copy of - * the Software. - * - */ +* Copyright (c) 2001-2002 Conexant Systems, Inc. +* Copyright (c) 2003-2004 Linuxant inc. +* +* 1. General Public License. This program is free software, and may +* be redistributed or modified subject to the terms of the GNU General +* Public License (version 2) or the GNU Lesser General Public License, +* or (at your option) any later versions ("Open Source" code). You may +* obtain a copy of the GNU General Public License at +* http://www.fsf.org/copyleft/gpl.html and a copy of the GNU Lesser +* General Public License at http://www.fsf.org/copyleft/less.html, +* or you may alternatively write to the Free Software Foundation, Inc., +* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +* +* 2. Disclaimer of Warranties. CONEXANT AND OTHER CONTRIBUTORS MAKE NO +* REPRESENTATION ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. +* IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTIES OF ANY KIND. +* CONEXANT AND OTHER CONTRIBUTORS DISCLAIMS ALL WARRANTIES WITH REGARD TO +* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +* FOR A PARTICULAR PURPOSE, GOOD TITLE AND AGAINST INFRINGEMENT. +* +* This software has not been formally tested, and there is no guarantee that +* it is free of errors including, but not limited to, bugs, defects, +* interrupted operation, or unexpected results. Any use of this software is +* at user's own risk. +* +* 3. No Liability. +* +* (a) Conexant or contributors shall not be responsible for any loss or +* damage to user, or any third parties for any reason whatsoever, and +* CONEXANT OR CONTRIBUTORS SHALL NOT BE LIABLE FOR ANY ACTUAL, DIRECT, +* INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL, OR CONSEQUENTIAL +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED, WHETHER IN CONTRACT, STRICT OR OTHER LEGAL THEORY OF +* 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. +* +* (b) User agrees to hold Conexant and contributors harmless from any +* liability, loss, cost, damage or expense, including attorney's fees, +* as a result of any claims which may be made by any person, including +* but not limited to User, its agents and employees, its customers, or +* any third parties that arise out of or result from the manufacture, +* delivery, actual or alleged ownership, performance, use, operation +* or possession of the software furnished hereunder, whether such claims +* are based on negligence, breach of contract, absolute liability or any +* other legal theory. +* +* 4. Notices. User hereby agrees not to remove, alter or destroy any +* copyright, trademark, credits, other proprietary notices or confidential +* legends placed upon, contained within or associated with the Software, +* and shall include all such unaltered copyright, trademark, credits, +* other proprietary notices or confidential legends on or in every copy of +* the Software. +* +*/ #include #ifdef FOUND_LINUX_CONFIG #include @@ -77,6 +77,7 @@ #include #include #include + #if !(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) #if (!defined(CONFIG_SERIAL_CORE) && !defined(CONFIG_SERIAL_CORE_MODULE)) #error CONFIG_SERIAL_CORE needed; enable 8250/16550 and compatible serial support in kernel config @@ -86,6 +87,8 @@ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) #include #endif +#include +#include #include "oscompat.h" #include "osservices.h" @@ -93,18 +96,23 @@ #include "comctrl_ex.h" #include "oslinux.h" #include "osnvm.h" +#include "osstdio.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) #include "serial_core.h" #endif + #include "serial_cnxt.h" #define NR_PORTS CNXTMAXMDM - #define CNXT_ISR_PASS_LIMIT 256 - #define CNXT_READBUF_SIZE 256 +#ifndef CNXTSERIAL_INCLUDE_CORE + #define uart_init() 0 + #define uart_exit() {} +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) static struct tty_driver cnxt_tty_driver_normal; static struct tty_driver cnxt_tty_driver_callout; @@ -112,43 +120,69 @@ static struct tty_struct *cnxt_tty_table[NR_PORTS]; static struct termios *cnxt_termios[NR_PORTS], *cnxt_termios_locked[NR_PORTS]; #endif -struct cnxt_serial_inst { - spinlock_t lock; - - struct module *owner; - - POS_DEVNODE devnode; - HANDLE hcomctrl; - - char *typestr; - - struct uart_port *port; - - int rxenabled; - int txenabled; - - int evt_rxchar; - int evt_rxbreak; - int evt_rxovrn; - int evt_txempty; - - unsigned char readbuf[CNXT_READBUF_SIZE]; - int readcount, readoffset; - - u_int mctrl_flags; - - OSSCHED intr_tqueue; - - struct uart_port *uart_port; - uart_info_t *uart_info; +static struct uart_driver cnxt_reg = { + .owner = THIS_MODULE, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + #ifdef CONFIG_DEVFS_FS + .normal_name = "ttyS"CNXTSERDEV"%d", + .callout_name = "cua"CNXTSERDEV"%d", + #else + .normal_name = "ttyS"CNXTSERDEV, + .callout_name = "cua"CNXTSERDEV, + #endif + .normal_driver = &cnxt_tty_driver_normal, + .callout_driver = &cnxt_tty_driver_callout, + .table = cnxt_tty_table, + .termios = cnxt_termios, + .termios_locked = cnxt_termios_locked, + .port = cnxt_ports, +#else + .driver_name = CNXTTARGET"serial", + #ifdef FOUND_DEVFS + .devfs_name = "ttyS"CNXTSERDEV, + #endif + .dev_name = "ttyS"CNXTSERDEV, +#endif + .minor = CNXTSERIALMINOR, + .nr = NR_PORTS, + .major = CNXTSERIALMAJOR, +}; +struct cnxt_serial_inst { + spinlock_t lock; + struct module *owner; + POS_DEVNODE devnode; + HANDLE hcomctrl; + char *typestr; + struct uart_port *port; + struct uart_port *uart_port; + uart_info_t *uart_info; + u_int mctrl_flags; + struct{ + unsigned int rxenabled:1; + unsigned int txenabled:1; + unsigned int transmit:2; + unsigned int evt_rxchar:1; + unsigned int evt_rxbreak:1; + unsigned int evt_rxovrn:1; + unsigned int evt_txempty:1; + unsigned int evt_ring:1; + }; + unsigned char readbuf[CNXT_READBUF_SIZE]; + int readcount, readoffset; + struct{ + unsigned int dwEvtMask[10]; + unsigned char count; + int user_pid; + } signal; + OSSCHED intr_tqueue; #ifdef CONFIG_PROC_FS - struct proc_dir_entry *proc_unit_dir; - struct proc_dir_entry *proc_hwinst; - struct proc_dir_entry *proc_hwprofile; - struct proc_dir_entry *proc_hwrevision; + struct proc_dir_entry *proc_unit_dir; + struct proc_dir_entry *proc_hwinst; + struct proc_dir_entry *proc_hwprofile; + struct proc_dir_entry *proc_hwrevision; #ifdef COMCTRL_MONITOR_POUND_UG_SUPPORT - struct proc_dir_entry *proc_lastcallstatus; + struct proc_dir_entry *proc_lastcallstatus; #endif #endif }; @@ -161,23 +195,48 @@ static struct proc_dir_entry *cnxt_serial_flush_nvm; #endif #endif -static struct cnxt_serial_inst cnxt_serial_inst[NR_PORTS]; +static struct cnxt_serial_inst *cnxt_serial_inst = NULL; +static struct uart_port *cnxt_ports = NULL; -static struct uart_port cnxt_ports[NR_PORTS]; +#if LINUX_VERSION_CODE > KERNEL_VERSION(4,1,0) +static struct _cnxt_serial_shared_memory{ + int hwInstNum; + unsigned char *buf; +} *cnxt_serial_shared_memory = NULL; +#endif #ifdef COMCTRL_MONITOR_POUND_UG_SUPPORT static int loglastcallstatus; #endif -static void -cnxt_sched_intr(struct cnxt_serial_inst *inst) -{ - if(inst->uart_info) { - OsModuleUseCountInc(); - if (OsThreadSchedule(OsMdmThread, &inst->intr_tqueue) <= 0) { - OsModuleUseCountDec(); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) +static DECLARE_MUTEX(cnxt_port_sem); +#else +static DEFINE_SEMAPHORE(cnxt_port_sem); +#endif + +//06/12/2018 +static int uart_register_port(struct uart_driver *drv, struct uart_port *port); +static void uart_unregister_port(struct uart_driver *drv, int line); + +static void cnxt_sched_intr(struct cnxt_serial_inst *inst){ + if(inst->uart_info) { + OsModuleUseCountInc(); + if (OsThreadSchedule(OsMdmThread, &inst->intr_tqueue) <= 0) + OsModuleUseCountDec(); } - } +} + +static COM_STATUS cnxt_control(struct cnxt_serial_inst *inst, COMCTRL_CONTROL_CODE eCode, PVOID pControl) +{ + int r; + + if(!inst->hcomctrl) + return COM_STATUS_INST_NOT_INIT; + r = ComCtrl_Control(inst->hcomctrl, eCode, pControl); + if (r != COM_STATUS_SUCCESS) + printk(KERN_ERR "%s: ComCtrlControl %d failed, status=%d\n", __FUNCTION__, eCode, r); + return r; } static void @@ -187,10 +246,9 @@ cnxt_stop_tx(struct uart_port *port, u_int tty_stop) cnxt_stop_tx(struct uart_port *port) #endif { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; - - //printk(KERN_DEBUG "%s\n", __FUNCTION__); - inst->txenabled = 0; + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; + //printk(KERN_DEBUG "%s %d\n", __FUNCTION__,(int)(port - cnxt_ports)); + inst->txenabled = 0; } static void @@ -200,69 +258,84 @@ cnxt_start_tx(struct uart_port *port, u_int tty_start) cnxt_start_tx(struct uart_port *port) #endif { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; - //printk(KERN_DEBUG "%s\n", __FUNCTION__); - inst->txenabled = 1; - cnxt_sched_intr(inst); + //printk(KERN_DEBUG "%s %p\n", __FUNCTION__,port); + + cnxt_sched_intr(inst); + inst->txenabled = 1; + inst->rxenabled = 1; + inst->evt_txempty=0; } -static void -cnxt_stop_rx(struct uart_port *port) +static void cnxt_stop_rx(struct uart_port *port) { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; - - //printk(KERN_DEBUG "%s\n", __FUNCTION__); - inst->rxenabled = 0; + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; + + //cnxt_control(inst, COMCTRL_CONTROL_SET_BREAK_ON, 0); + inst->rxenabled = 0; } -static inline int -cnxt_rx_ready(struct cnxt_serial_inst *inst) +static int cnxt_rx_ready(struct cnxt_serial_inst *inst) { - int r; - - if(!inst->rxenabled) - return FALSE; - - if(inst->readoffset == inst->readcount) { - r = ComCtrl_Read(inst->hcomctrl, inst->readbuf, sizeof(inst->readbuf)); - if(r < 0) { - printk(KERN_ERR"%s: ComCtrlRead returned %d\n", __FUNCTION__, r); - } else { - inst->readcount = r; - inst->readoffset = 0; + int r; + + if(!inst->rxenabled) + return FALSE; + r=0; + if(inst->readoffset == inst->readcount) { + r = ComCtrl_Read(inst->hcomctrl,inst->readbuf, sizeof(inst->readbuf));//c06419a5 c0605e89 + if(r < 0) + printk(KERN_ERR"%s: ComCtrlRead returned %d\n", __FUNCTION__, r); + else{ + inst->readcount = r; + inst->readoffset = 0; + inst->evt_rxchar = 0; + } } - } - - return (inst->readcount > inst->readoffset) || inst->evt_rxbreak || inst->evt_rxovrn; + return (inst->readcount > inst->readoffset) || inst->evt_rxbreak || inst->evt_rxovrn; } -static inline void -cnxt_rx_chars(struct cnxt_serial_inst *inst) -{ - struct tty_struct *tty = UART_INFO_TO_TTY(inst->uart_info); - int max_count = sizeof(inst->readbuf); - unsigned char flag; - - inst->evt_rxchar = 0; - - while(max_count-- > 0 && cnxt_rx_ready(inst)) { -#ifndef FOUND_TTY_NEW_API - if(unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { +static void cnxt_rx_chars(struct cnxt_serial_inst *inst){ + struct tty_struct *tty = UART_INFO_TO_TTY(inst->uart_info);//port->state->port.tty + int max_count; + unsigned char flag,ch; + char lino[512]; + int i; + spinlock_t *lock; + unsigned long flags; + struct uart_port *port; + + lino[i=0]=0; + //inst->evt_rxchar = 0; + if(!inst->uart_port || !inst->readcount) + return; + port = inst->uart_port; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - tty->flip.tqueue.routine((void *) tty); + lock = &info->lock; #else - tty->flip.work.func((void *)tty); + lock = &port->lock; +#endif + + spin_lock_irqsave(lock, flags); + max_count = inst->readcount; + while(max_count-- > 0) { +#ifndef FOUND_TTY_NEW_API //old vesrion + if(unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + tty->flip.tqueue.routine((void *) tty); +#else + tty->flip.work.func((void *)tty); #endif - if(tty->flip.count >= TTY_FLIPBUF_SIZE) { - return; // if TTY_DONT_FLIP is set - } - } + if(tty->flip.count >= TTY_FLIPBUF_SIZE){ + spin_unlock_irqrestore(lock, flags); + return; + } + } #endif - - if (inst->evt_rxovrn) { - inst->evt_rxovrn = 0; - inst->uart_port->icount.overrun++; + if (inst->evt_rxovrn) { + inst->evt_rxovrn = 0; + inst->uart_port->icount.overrun++; #ifdef FOUND_TTY_NEW_API #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) tty_insert_flip_char(tty->port, 0, TTY_OVERRUN); @@ -270,22 +343,25 @@ cnxt_rx_chars(struct cnxt_serial_inst *inst) tty_insert_flip_char(tty, 0, TTY_OVERRUN); #endif #else - *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; - *tty->flip.char_buf_ptr++ = 0; - tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + *tty->flip.char_buf_ptr++ = 0; + tty->flip.count++; #endif - continue; - } - - inst->uart_port->icount.rx++; - - if (inst->evt_rxbreak) { - inst->evt_rxbreak = 0; - inst->uart_port->icount.brk++; - flag = TTY_BREAK; - } else - flag = TTY_NORMAL; - + continue; + } + + port->icount.rx++; + + if (inst->evt_rxbreak) { + inst->evt_rxbreak = 0; + port->icount.brk++; + flag = TTY_BREAK; + } + else + flag = TTY_NORMAL; + ch = inst->readbuf[inst->readoffset++]; + if(i < 510) + lino[i++]=ch; #ifdef FOUND_TTY_NEW_API #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) tty_insert_flip_char(tty->port, inst->readbuf[inst->readoffset++], flag); @@ -299,481 +375,515 @@ cnxt_rx_chars(struct cnxt_serial_inst *inst) #endif } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) - tty_flip_buffer_push(tty->port); -#else - tty_flip_buffer_push(tty); -#endif - return; +// TODO is this needed? +// #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) +// tty_flip_buffer_push(tty->port); +// #else +// tty_flip_buffer_push(tty); +// #endif +// return; + if(i){ + lino[i]=0; + printk(KERN_DEBUG "%s %p: %s\n", __FUNCTION__, inst->port,lino); + + tty_flip_buffer_push(&inst->uart_info->port); + //uart_write_wakeup(port); + inst->transmit |= 1; + } + spin_unlock_irqrestore(lock, flags); } -#if 0 -static inline int -cnxt_tx_free(struct cnxt_serial_inst *inst) +static int cnxt_tx_free(struct cnxt_serial_inst *inst) { - int r; - UINT32 val = 0; - - if ((r=ComCtrl_Monitor(inst->hcomctrl, COMCTRL_MONITOR_TXFREE, &val)) != COM_STATUS_SUCCESS) { - printk(KERN_ERR "%s: ComCtrlMonitor COMCTRL_MONITOR_TXFREE failed, status=%d\n", __FUNCTION__, r); - return 0; - } + int r; + UINT32 val = 0; - //printk(KERN_DEBUG "%s: val=%lu\n", __FUNCTION__, val); - return val; + if ((r=ComCtrl_Monitor(inst->hcomctrl, COMCTRL_MONITOR_TXFREE, &val)) != COM_STATUS_SUCCESS) { + printk(KERN_ERR "%s: ComCtrlMonitor COMCTRL_MONITOR_TXFREE failed, status=%d\n", __FUNCTION__, r); + return 0; + } + return val; } -#endif -static inline int -cnxt_put_char(struct cnxt_serial_inst *inst, unsigned char ch) +static int cnxt_put_char(struct cnxt_serial_inst *inst, unsigned char ch) { - int r; - - //printk(KERN_DEBUG "%s: ch=%x\n", __FUNCTION__, (int)ch); - inst->evt_txempty = 0; - r = ComCtrl_Write(inst->hcomctrl, &ch, 1); - if(r < 0) { - printk(KERN_ERR "%s: ComCtrlWrite returned %d\n", __FUNCTION__, r); - } - return r == 1; + int r; + + //printk(KERN_DEBUG "%s: ch=%x\n", __FUNCTION__, (int)ch); + inst->evt_txempty = 0; + r = ComCtrl_Write(inst->hcomctrl, &ch, 1); + if(r != 1) + printk(KERN_ERR "%s: ComCtrlWrite returned %d\n", __FUNCTION__, r); + return r == 1; } -static inline void -cnxt_tx_chars(struct cnxt_serial_inst *inst) +static void cnxt_tx_chars(struct cnxt_serial_inst *inst) { - struct circ_buf *xmit; - uart_info_t *info = inst->uart_info; - struct uart_port *port; - spinlock_t *lock; - unsigned long flags; - struct tty_struct *tty; - - tty = UART_INFO_TO_TTY(info); - - port = inst->uart_port; - xmit = &info->xmit; - - if (port->x_char) { - cnxt_put_char(inst, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } + struct circ_buf *xmit; + uart_info_t *info = inst->uart_info; + struct uart_port *port; + spinlock_t *lock; + unsigned long flags; + unsigned int to_send, until_end; + unsigned char ch; + + int i; + char lino[512],s[5]; + + lino[i=0]=0; + port = inst->uart_port; + xmit = &info->xmit; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - lock = &info->lock; + lock = &info->lock; #else - lock = &port->lock; + lock = &port->lock; #endif + + spin_lock_irqsave(lock, flags); - spin_lock_irqsave(lock, flags); - if (uart_circ_empty(xmit) - || tty->stopped - || tty->hw_stopped) { + if (port->x_char) { + cnxt_put_char(inst, port->x_char); + port->icount.tx++; + port->x_char = 0; + spin_unlock_irqrestore(lock, flags); + return; + } + + if (uart_circ_empty(xmit) ||uart_tx_stopped(port)) { #ifdef FOUND_TTY_START_STOP - cnxt_stop_tx(port, 0); + cnxt_stop_tx(port, 0); #else - cnxt_stop_tx(port); + cnxt_stop_tx(port); #endif - spin_unlock_irqrestore(lock, flags); - return; - } - - while (xmit->buf/*&& cnxt_tx_free(inst) > 0*/) { - if(!cnxt_put_char(inst, xmit->buf[xmit->tail])) - break; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + spin_unlock_irqrestore(lock, flags); + return; + } + + to_send = uart_circ_chars_pending(xmit); + until_end = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + + while (xmit->buf && to_send) { + ch = xmit->buf[xmit->tail]; + sprintf(s,"%02X%c",ch,ch); + strcat(lino,s); + if(!cnxt_put_char(inst, ch)) + break; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + to_send--; + } + //lino[i] = 0; + printk(KERN_DEBUG "%s: %s %d %d\n", __FUNCTION__,lino,to_send,until_end); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS){ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - uart_event(info, EVT_WRITE_WAKEUP); + uart_event(info, EVT_WRITE_WAKEUP); #else - uart_write_wakeup(port); + uart_write_wakeup(port); #endif + } + + if (uart_circ_empty(xmit)){ + cnxt_tx_free(inst); - if (uart_circ_empty(xmit)) #ifdef FOUND_TTY_START_STOP - cnxt_stop_tx(port, 0); + cnxt_stop_tx(port, 0); #else - cnxt_stop_tx(port); + cnxt_stop_tx(port); #endif - - spin_unlock_irqrestore(lock, flags); +/* +#ifdef FOUND_NO_STRUCT_UART_INFO + wake_up_interruptible(&info->port.delta_msr_wait); +#else + wake_up_interruptible(&info->delta_msr_wait); +#endif*/ + } + + spin_unlock_irqrestore(lock, flags); } -static inline int -cnxt_tx_ready(struct cnxt_serial_inst *inst) { - return (inst->txenabled /*&& inst->evt_txempty*/); +static int cnxt_tx_ready(struct cnxt_serial_inst *inst) { + return (inst->txenabled/* && !inst->evt_txempty*/); } -static void -cnxt_intr(void *dev_id) +//fixme +static void cnxt_intr(void *dev_id) { - unsigned int pass_counter = 0; - struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)dev_id; - - while (inst->uart_info && (cnxt_rx_ready(inst) || cnxt_tx_ready(inst))) { - cnxt_rx_chars(inst); - - if(cnxt_tx_ready(inst)) - cnxt_tx_chars(inst); - - if (pass_counter++ > CNXT_ISR_PASS_LIMIT) - break; - } - - OsModuleUseCountDec(); - OsThreadScheduleDone(); + int i; + struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)dev_id; + + //printk(KERN_DEBUG "%s:\n", __FUNCTION__); + inst->transmit=0; + for (i = 0;i < CNXT_ISR_PASS_LIMIT && inst->uart_info && !inst->transmit;i++) { + if(cnxt_tx_ready(inst)) + cnxt_tx_chars(inst); + if(cnxt_rx_ready(inst)) + cnxt_rx_chars(inst); + } + + if(inst->signal.count){ + unsigned long flags; + + spin_lock_irqsave(&inst->lock, flags); + + unsigned int dwEvtMask = inst->signal.dwEvtMask[0]; + for(i=0,inst->signal.count--;isignal.count;i++) + inst->signal.dwEvtMask[i] = inst->signal.dwEvtMask[i+1]; + + spin_unlock_irqrestore(&inst->lock, flags); + + if(inst->signal.user_pid != 0){ + struct siginfo info={0}; + struct task_struct *t; + + rcu_read_lock(); + t = pid_task(find_pid_ns(inst->signal.user_pid, &init_pid_ns), PIDTYPE_PID); + if (t != NULL) { + int err; + + info.si_signo = 44; + info.si_code = SI_QUEUE; + info.si_int = dwEvtMask; + + rcu_read_unlock(); + if (err = send_sig_info(44, &info, t) < 0) + printk("send_sig_info error %d\n",err); + } + else { + printk("pid_task error\n"); + inst->signal.user_pid = 0; + rcu_read_unlock(); + //return -ENODEV; + } + } + + } + + OsModuleUseCountDec(); + OsThreadScheduleDone(); } -/* - * Return TIOCSER_TEMT when transmitter is not busy. - */ -static u_int -cnxt_tx_empty(struct uart_port *port) +static u_int cnxt_tx_empty(struct uart_port *port) { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; - - return inst->evt_txempty ? TIOCSER_TEMT : 0; + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; + //printk(KERN_ERR "%s: \n", __FUNCTION__); + return inst->evt_txempty ? TIOCSER_TEMT : 0; } -static u_int -cnxt_get_mctrl(struct uart_port *port) +static u_int cnxt_get_mctrl(struct uart_port *port) { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; - - return inst->mctrl_flags; + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; + printk(KERN_ERR "%s: \n", __FUNCTION__); + return inst->mctrl_flags; } #ifdef COMCTRL_MONITOR_POUND_UG_SUPPORT -static COM_STATUS -cnxt_monitor(struct cnxt_serial_inst *inst, COMCTRL_MONITOR_CODE eCode, PVOID pMonitor) +static COM_STATUS cnxt_monitor(struct cnxt_serial_inst *inst, COMCTRL_MONITOR_CODE eCode, PVOID pMonitor) { - int r; - - if(!inst->hcomctrl) - return COM_STATUS_INST_NOT_INIT; - - r = ComCtrl_Monitor(inst->hcomctrl, eCode, pMonitor); - - if (r != COM_STATUS_SUCCESS) { - printk(KERN_ERR "%s: ComCtrlMonitor %d failed, status=%d\n", __FUNCTION__, eCode, r); - } - - return r; + int r; + + if(!inst->hcomctrl) + return COM_STATUS_INST_NOT_INIT; + r = ComCtrl_Monitor(inst->hcomctrl, eCode, pMonitor); + if (r != COM_STATUS_SUCCESS) + printk(KERN_ERR "%s: ComCtrlMonitor %d failed, status=%d\n", __FUNCTION__, eCode, r); + return r; } #endif -static COM_STATUS -cnxt_control(struct cnxt_serial_inst *inst, COMCTRL_CONTROL_CODE eCode, PVOID pControl) +static void cnxt_set_mctrl(struct uart_port *port, u_int mctrl) { - int r; - - if(!inst->hcomctrl) - return COM_STATUS_INST_NOT_INIT; - - r = ComCtrl_Control(inst->hcomctrl, eCode, pControl); - - if (r != COM_STATUS_SUCCESS) { - printk(KERN_ERR "%s: ComCtrlControl %d failed, status=%d\n", __FUNCTION__, eCode, r); - } - - return r; -} - -static void -cnxt_set_mctrl(struct uart_port *port, u_int mctrl) -{ - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; - - //printk(KERN_DEBUG "%s: mctrl=%x\n", __FUNCTION__, mctrl); - - if ((mctrl & TIOCM_RTS) && !(inst->mctrl_flags & TIOCM_RTS)) { - inst->mctrl_flags |= TIOCM_RTS; - cnxt_control(inst, COMCTRL_CONTROL_SETRTS, 0); - } - if (!(mctrl & TIOCM_RTS) && (inst->mctrl_flags & TIOCM_RTS)) { - inst->mctrl_flags &= ~TIOCM_RTS; - cnxt_control(inst, COMCTRL_CONTROL_CLRRTS, 0); - } - - if ((mctrl & TIOCM_DTR) && !(inst->mctrl_flags & TIOCM_DTR)) { - inst->mctrl_flags |= TIOCM_DTR; - cnxt_control(inst, COMCTRL_CONTROL_SETDTR, 0); - } - if (!(mctrl & TIOCM_DTR) && (inst->mctrl_flags & TIOCM_DTR)) { - inst->mctrl_flags &= ~TIOCM_DTR; - cnxt_control(inst, COMCTRL_CONTROL_CLRDTR, 0); - } + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; + + /* +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 +*/ + //printk(KERN_DEBUG "%s: mctrl=%08X omctrl=%08X\n", __FUNCTION__, mctrl,inst->mctrl_flags); + + if ((mctrl & TIOCM_RTS) && !(inst->mctrl_flags & TIOCM_RTS)) {//0x4 + inst->mctrl_flags |= TIOCM_RTS; + //cnxt_control(inst, COMCTRL_CONTROL_SETRTS, 0); + } + + if (!(mctrl & TIOCM_RTS) && (inst->mctrl_flags & TIOCM_RTS)) { + inst->mctrl_flags &= ~TIOCM_RTS; + //cnxt_control(inst, COMCTRL_CONTROL_CLRRTS, 0); + } + + if ((mctrl & TIOCM_DTR) && !(inst->mctrl_flags & TIOCM_DTR)) {//0x2 + inst->mctrl_flags |= TIOCM_DTR; + //cnxt_control(inst, COMCTRL_CONTROL_SETDTR, 0); + } + + if (!(mctrl & TIOCM_DTR) && (inst->mctrl_flags & TIOCM_DTR)) { + inst->mctrl_flags &= ~TIOCM_DTR; +// cnxt_control(inst, COMCTRL_CONTROL_CLRDTR, 0); + } } -static void -cnxt_break_ctl(struct uart_port *port, int break_state) +static void cnxt_break_ctl(struct uart_port *port, int break_state) { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; - - //printk(KERN_DEBUG "%s: break_state=%d\n", __FUNCTION__, break_state); + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; - cnxt_control(inst, break_state ? COMCTRL_CONTROL_SET_BREAK_ON : COMCTRL_CONTROL_SET_BREAK_OFF, 0); + //printk(KERN_DEBUG "%s: break_state=%d\n", __FUNCTION__, break_state); + cnxt_control(inst, break_state ? COMCTRL_CONTROL_SET_BREAK_ON : COMCTRL_CONTROL_SET_BREAK_OFF, 0); } -__shimcall__ -static void -cnxt_event_handler(struct cnxt_serial_inst *inst, UINT32 dwEvtMask) +__shimcall__ static void cnxt_event_handler(struct cnxt_serial_inst *inst, UINT32 dwEvtMask) { - struct uart_port *port = inst->port; - u_int mctrl_flags, orig_mctrl_flags; - int sched_intr=0; - - //printk(KERN_DEBUG "%s: port=%p dwEvtMask=0x%04lx\n", __FUNCTION__, port, dwEvtMask); - - orig_mctrl_flags = mctrl_flags = inst->mctrl_flags; - - if((dwEvtMask & COMCTRL_EVT_RXCHAR)) { - inst->evt_rxchar = 1; - sched_intr = 1; - } + struct uart_port *port = inst->port; + u_int mctrl_flags, orig_mctrl_flags; + int sched_intr=0; + + printk(KERN_DEBUG "%s %08X %p\n", __FUNCTION__,dwEvtMask,port,&cnxt_reg,&cnxt_ports[cnxt_serial_shared_memory->hwInstNum]); + + orig_mctrl_flags = mctrl_flags = inst->mctrl_flags; + if((dwEvtMask & COMCTRL_EVT_RXCHAR)) { + inst->evt_rxchar = 1; + sched_intr |= 3; + } - if(dwEvtMask & COMCTRL_EVT_BREAK) { - inst->evt_rxbreak = 1; - sched_intr = 1; - } + if(dwEvtMask & COMCTRL_EVT_BREAK) { + inst->evt_rxbreak = 1; + sched_intr |= 1; + } - if((dwEvtMask & COMCTRL_EVT_RXOVRN)) { - inst->evt_rxovrn = 1; - sched_intr = 1; - } + if((dwEvtMask & COMCTRL_EVT_RXOVRN)) { + inst->evt_rxovrn = 1; + sched_intr = 1; + } -#if 0 - if((dwEvtMask & COMCTRL_EVT_TXCHAR)) { - } -#endif + if((dwEvtMask & COMCTRL_EVT_TXCHAR)) { + + } - if((dwEvtMask & COMCTRL_EVT_TXEMPTY)) { - inst->evt_txempty = 1; - sched_intr = 1; - } + if((dwEvtMask & COMCTRL_EVT_TXEMPTY)) { + inst->evt_txempty = 1; + sched_intr |= 3; + } - if((dwEvtMask & COMCTRL_EVT_CTS)) { - if(dwEvtMask & COMCTRL_EVT_CTSS) { - mctrl_flags |= TIOCM_CTS; - } else { - mctrl_flags &= ~TIOCM_CTS; + if((dwEvtMask & COMCTRL_EVT_CTS)) { + if(dwEvtMask & COMCTRL_EVT_CTSS) + mctrl_flags |= TIOCM_CTS; + else + mctrl_flags &= ~TIOCM_CTS; } - } - if(dwEvtMask & COMCTRL_EVT_DSR) { - if(dwEvtMask & COMCTRL_EVT_DSRS) { - mctrl_flags |= TIOCM_DSR; - } else { - mctrl_flags &= ~TIOCM_DSR; + if(dwEvtMask & COMCTRL_EVT_DSR) { + if(dwEvtMask & COMCTRL_EVT_DSRS) + mctrl_flags |= TIOCM_DSR; + else + mctrl_flags &= ~TIOCM_DSR; + if(port) + port->icount.dsr++; } - if(port) - port->icount.dsr++; - } - if(dwEvtMask & COMCTRL_EVT_RLSD) { - if(dwEvtMask & COMCTRL_EVT_RLSDS) { - mctrl_flags |= TIOCM_CAR; - } else { - mctrl_flags &= ~TIOCM_CAR; + if(dwEvtMask & COMCTRL_EVT_RLSD) { + if(dwEvtMask & COMCTRL_EVT_RLSDS) + mctrl_flags |= TIOCM_CAR; + else + mctrl_flags &= ~TIOCM_CAR; } - } - if(dwEvtMask & COMCTRL_EVT_RING) { - if(dwEvtMask & COMCTRL_EVT_RINGS) { - mctrl_flags |= TIOCM_RNG; - if(port) - port->icount.rng++; - } else { - mctrl_flags &= ~TIOCM_RNG; + if(dwEvtMask & COMCTRL_EVT_RING) { + if(dwEvtMask & COMCTRL_EVT_RINGS) { + mctrl_flags |= TIOCM_RNG; + if(port) + port->icount.rng++; + } + else + mctrl_flags &= ~TIOCM_RNG; } - } - if(inst->mctrl_flags != mctrl_flags) { - inst->mctrl_flags = mctrl_flags; + if(inst->mctrl_flags != mctrl_flags) { + inst->mctrl_flags = mctrl_flags; #if 0 - printk(KERN_DEBUG "%cCTS %cDSR %cDCD %cRI\n", + printk(KERN_DEBUG "%cCTS %cDSR %cDCD %cRI\n", inst->mctrl_flags&TIOCM_CTS?'+':'-', inst->mctrl_flags&TIOCM_DSR?'+':'-', inst->mctrl_flags&TIOCM_CAR?'+':'-', inst->mctrl_flags&TIOCM_RNG?'+':'-'); #endif - if(port && inst->uart_info) { - if((mctrl_flags & TIOCM_CAR) != (orig_mctrl_flags & TIOCM_CAR)) { - uart_handle_dcd_change( + if(port && inst->uart_info) { + if((mctrl_flags & TIOCM_CAR) != (orig_mctrl_flags & TIOCM_CAR)) { + uart_handle_dcd_change( #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - inst->uart_info, + inst->uart_info, #else - inst->uart_port, + inst->uart_port, #endif - mctrl_flags & TIOCM_CAR); + mctrl_flags & TIOCM_CAR); #ifdef COMCTRL_MONITOR_POUND_UG_SUPPORT - if(loglastcallstatus && !(mctrl_flags & TIOCM_CAR)) { - PORT_MONITOR_DATA monitorData; - static char largebuf[PAGE_SIZE]; - char *p, *nl; - - monitorData.dwSize = sizeof(largebuf); - monitorData.pBuf = largebuf; - - cnxt_monitor(inst, COMCTRL_MONITOR_POUND_UG, &monitorData); - p = largebuf; - while((nl = strchr(p, '\n'))) { - printk(KERN_INFO "%.*s", (int)(nl - p) + 1, p); - p = nl + 1; - } - if(*p) - printk(KERN_INFO "%s\n", p); - - } -#endif - } - if((mctrl_flags & TIOCM_CTS) != (orig_mctrl_flags & TIOCM_CTS)) - uart_handle_cts_change( + if(loglastcallstatus && !(mctrl_flags & TIOCM_CAR)) { + PORT_MONITOR_DATA monitorData; + static char largebuf[PAGE_SIZE]; + char *p, *nl; + + monitorData.dwSize = sizeof(largebuf); + monitorData.pBuf = largebuf; + + cnxt_monitor(inst, COMCTRL_MONITOR_POUND_UG, &monitorData); + p = largebuf; + while((nl = strchr(p, '\n'))) { + printk(KERN_INFO "%.*s", (int)(nl - p) + 1, p); + p = nl + 1; + } + if(*p) + printk(KERN_INFO "%s\n", p); + } +#endif + } + + if((mctrl_flags & TIOCM_CTS) != (orig_mctrl_flags & TIOCM_CTS)) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - inst->uart_info, -#else - inst->uart_port, -#endif - mctrl_flags & TIOCM_CTS); - -#ifdef FOUND_NO_STRUCT_UART_INFO - wake_up_interruptible(&inst->uart_info->port.delta_msr_wait); + uart_handle_cts_change(inst->uart_info,mctrl_flags & TIOCM_CTS); #else - wake_up_interruptible(&inst->uart_info->delta_msr_wait); + uart_handle_cts_change(inst->uart_port,mctrl_flags & TIOCM_CTS); #endif + } } - } - - if(port && sched_intr) { - cnxt_sched_intr(inst); - } + //mutex + if((sched_intr & 2) && inst->signal.count < sizeof(inst->signal.dwEvtMask) / sizeof(unsigned int)) + inst->signal.dwEvtMask[inst->signal.count++] = dwEvtMask; + if(port && sched_intr) + cnxt_sched_intr(inst); +} - return; +static irqreturn_t irq_uart_tx_chars(int irq, void *dev_id){ + printk(KERN_DEBUG "%s: (%d)\n", __FUNCTION__, irq); + return IRQ_HANDLED; } -static int -cnxt_startup(struct uart_port *port +static int cnxt_startup(struct uart_port *port #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - , struct uart_info *info +, struct uart_info *info #endif - ) +) { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; - - if(!inst->hcomctrl) - return -ENODEV; - - if(inst->uart_info) - return -EBUSY; + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; + + if(!inst->hcomctrl) + return -ENODEV; + if(inst->uart_info) + return -EBUSY; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - if (!try_inc_mod_count(inst->owner)) - return -ENODEV; + if (!try_inc_mod_count(inst->owner)) + return -ENODEV; #else - if (!try_module_get(inst->owner)) - return -ENODEV; -#endif - - /* flush any characters or events received while we were shutdown */ - while(ComCtrl_Read(inst->hcomctrl, inst->readbuf, sizeof(inst->readbuf)) > 0); - inst->readcount = inst->readoffset = 0; - inst->evt_rxchar = 0; - inst->evt_rxbreak = 0; - inst->evt_rxovrn = 0; - - inst->uart_port = port; + if (!try_module_get(inst->owner)) + return -ENODEV; +#endif + + while(ComCtrl_Read(inst->hcomctrl, inst->readbuf, sizeof(inst->readbuf)) > 0); + + inst->readcount = inst->readoffset = 0; + inst->evt_rxchar = 0; + inst->evt_rxbreak = 0; + inst->evt_rxovrn = 0; + + inst->uart_port = port; + +// int r = request_irq(inst->irq, irq_uart_tx_chars, IRQF_SHARED|IRQF_ONESHOT, "UART TX", port); + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - inst->uart_info = info; -#else -#ifdef FOUND_NO_STRUCT_UART_INFO - inst->uart_info = port->state; -#else - inst->uart_info = port->info; -#endif + inst->uart_info = info; +#else + #ifdef FOUND_NO_STRUCT_UART_INFO + inst->uart_info = port->state; + #else + inst->uart_info = port->info; + #endif #endif - inst->rxenabled = 1; - inst->txenabled = 1; - + inst->rxenabled = 1; + inst->txenabled = 1; #ifdef USE_DCP OsDcpEnsureDaemonIsRunning(inst->devnode->hwInstNum); #endif - - return 0; + //printk(KERN_DEBUG "%s %p\n", __FUNCTION__,port); + return 0; } -static void -cnxt_shutdown(struct uart_port *port +static void cnxt_shutdown(struct uart_port *port #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - , struct uart_info *info +, struct uart_info *info #endif - ) +) { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; - //printk(KERN_DEBUG "%s\n", __FUNCTION__); - inst->rxenabled = 0; - inst->txenabled = 0; + printk(KERN_DEBUG "%s %p\n", __FUNCTION__,port); + + inst->rxenabled = 0; + inst->txenabled = 0; - inst->uart_info = NULL; - inst->uart_port = NULL; + inst->uart_info = NULL; + inst->uart_port = NULL; - if (inst->owner) { + if (inst->owner) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - __MOD_DEC_USE_COUNT(inst->owner); + __MOD_DEC_USE_COUNT(inst->owner); #else - module_put(inst->owner); + module_put(inst->owner); #endif - } - + } } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) -static void -cnxt_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) +static void cnxt_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; - PORT_CONFIG port_config; - - //printk(KERN_DEBUG "%s\n", __FUNCTION__); + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; + PORT_CONFIG port_config; - memset(&port_config, 0, sizeof(port_config)); + printk(KERN_DEBUG "%s\n", __FUNCTION__); - if(quot) { - port_config.dwDteSpeed = port->uartclk / (16 * quot); - port_config.dwValidFileds |= PC_DTE_SPEED; - } - - if(cflag & PARENB) { - if(cflag & PARODD) - port_config.eParity = PC_PARITY_ODD; + memset(&port_config, 0, sizeof(port_config)); + if(quot) { + port_config.dwDteSpeed = port->uartclk / (16 * quot); + port_config.dwValidFileds |= PC_DTE_SPEED; + } + if(cflag & PARENB) { + if(cflag & PARODD) + port_config.eParity = PC_PARITY_ODD; + else + port_config.eParity = PC_PARITY_EVEN; + } else - port_config.eParity = PC_PARITY_EVEN; - } else - port_config.eParity = PC_PARITY_NONE; - port_config.dwValidFileds |= PC_PARITY; - - if((cflag & CSIZE) == CS7) { - port_config.eDataBits = PC_DATABITS_7; - } else { - port_config.eDataBits = PC_DATABITS_8; - } - port_config.dwValidFileds |= PC_DATA_BITS; + port_config.eParity = PC_PARITY_NONE; + port_config.dwValidFileds |= PC_PARITY; - if (cflag & CRTSCTS) { - port_config.fCTS = TRUE; - port_config.fRTS = TRUE; - } - port_config.dwValidFileds |= PC_CTS | PC_RTS; + switch((cflag & CSIZE)){ + case CS8: + port_config.eDataBits = PC_DATABITS_8; + break; + default: + port_config.eDataBits = PC_DATABITS_7; + break; + } + port_config.dwValidFileds |= PC_DATA_BITS; - cnxt_control(inst, COMCTRL_CONTROL_PORTCONFIG, &port_config); + if (cflag & CRTSCTS) { + port_config.fCTS = TRUE; + port_config.fRTS = TRUE; + } + port_config.dwValidFileds |= PC_CTS | PC_RTS; + cnxt_control(inst, COMCTRL_CONTROL_PORTCONFIG, &port_config); } #else static void @@ -783,103 +893,99 @@ cnxt_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermi cnxt_set_termios(struct uart_port *port, struct termios *termios, struct termios *old) #endif { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; - PORT_CONFIG port_config; - - //printk(KERN_DEBUG "%s\n", __FUNCTION__); - - memset(&port_config, 0, sizeof(port_config)); - - port_config.dwDteSpeed = uart_get_baud_rate(port, termios, old, 75, 4000000); - port_config.dwValidFileds |= PC_DTE_SPEED; - - if(termios->c_cflag & PARENB) { - if(termios->c_cflag & PARODD) - port_config.eParity = PC_PARITY_ODD; + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; + PORT_CONFIG port_config={0}; + + port_config.dwDteSpeed = uart_get_baud_rate(port, termios, old,port->uartclk / 16 / 0xffff, port->uartclk / 4); + port_config.dwValidFileds |= PC_DTE_SPEED; + + termios->c_cflag &= ~CMSPAR; + + if(termios->c_cflag & PARENB) {//0x400 + if(termios->c_cflag & PARODD)//0x1000 + port_config.eParity = PC_PARITY_ODD; + else + port_config.eParity = PC_PARITY_EVEN;//pari + } else - port_config.eParity = PC_PARITY_EVEN; - } else - port_config.eParity = PC_PARITY_NONE; - port_config.dwValidFileds |= PC_PARITY; - - if((termios->c_cflag & CSIZE) == CS7) { - port_config.eDataBits = PC_DATABITS_7; - } else { - port_config.eDataBits = PC_DATABITS_8; - } - port_config.dwValidFileds |= PC_DATA_BITS; + port_config.eParity = PC_PARITY_NONE; + port_config.dwValidFileds |= PC_PARITY; - if (termios->c_cflag & CRTSCTS) { - port_config.fCTS = TRUE; - port_config.fRTS = TRUE; - } - port_config.dwValidFileds |= PC_CTS | PC_RTS; + switch((termios->c_cflag & CSIZE)){ + case CS8: + port_config.eDataBits = PC_DATABITS_8; + break; + default: + port_config.eDataBits = PC_DATABITS_7; + break; + } + port_config.dwValidFileds |= PC_DATA_BITS; - cnxt_control(inst, COMCTRL_CONTROL_PORTCONFIG, &port_config); + if (termios->c_cflag & CRTSCTS) { + port_config.fCTS = TRUE; + port_config.fRTS = TRUE; + } + port_config.dwValidFileds |= PC_CTS | PC_RTS; + //cnxt_control(inst, COMCTRL_CONTROL_PORTCONFIG, &port_config); + + //printk(KERN_DEBUG "%s %d %08X\n", __FUNCTION__,port_config.dwDteSpeed,termios->c_cflag); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - uart_update_timeout(port, termios->c_cflag, port_config.dwDteSpeed); + uart_update_timeout(port, termios->c_cflag, port_config.dwDteSpeed); #endif } #endif -static void -cnxt_enable_ms(struct uart_port *port) +static void cnxt_enable_ms(struct uart_port *port) { + printk(KERN_DEBUG "%s\n", __FUNCTION__); } -static void -cnxt_release_port(struct uart_port *port) +static void cnxt_release_port(struct uart_port *port) { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; - - //printk(KERN_DEBUG "%s\n", __FUNCTION__); + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; - if(inst->port != port) { - printk(KERN_ERR"%s: inst->port(%p) != port(%p), i=%d cnxt_ports=%p\n", __FUNCTION__, inst->port, port, (int)(port - cnxt_ports), cnxt_ports); - } - inst->port = NULL; + //printk(KERN_DEBUG "%s\n", __FUNCTION__); + if(inst->port != port) + printk(KERN_ERR"%s: inst->port(%p) != port(%p), i=%d cnxt_ports=%p\n", __FUNCTION__, inst->port, port, (int)(port - cnxt_ports), cnxt_ports); + inst->port = NULL; } -static int -cnxt_request_port(struct uart_port *port) +static int cnxt_request_port(struct uart_port *port) { - struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports]; - - //printk(KERN_DEBUG "%s\n", __FUNCTION__); - if(!inst->port) - inst->port = port; - else { - if(inst->port != port) { - printk(KERN_ERR"%s: inst->port(%p) != port(%p), i=%d cnxt_ports=%p\n", __FUNCTION__, inst->port, port, (int)(port - cnxt_ports), cnxt_ports); + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; + + //printk(KERN_DEBUG "%s\n", __FUNCTION__); + if(!inst->port) + inst->port = port; + else { + if(inst->port != port) + printk(KERN_ERR"%s: inst->port(%p) != port(%p), i=%d cnxt_ports=%p\n", __FUNCTION__, inst->port, port, (int)(port - cnxt_ports), cnxt_ports); } - } - - return 0; + return 0; } #ifndef PORT_CNXT #define PORT_CNXT 36 #endif -static void -cnxt_config_port(struct uart_port *port, int flags) +static void cnxt_config_port(struct uart_port *port, int flags) { - - //printk(KERN_DEBUG "%s\n", __FUNCTION__); - if (flags & UART_CONFIG_TYPE && cnxt_request_port(port) == 0) { - port->type = PORT_CNXT; - } + //printk(KERN_DEBUG "%s\n", __FUNCTION__); + if (flags & UART_CONFIG_TYPE && cnxt_request_port(port) == 0) + port->type = PORT_CNXT; } /* - * Verify the new serial_struct (for TIOCSSERIAL). - * The only change we allow are to the flags - */ -static int -cnxt_verify_port(struct uart_port *port, struct serial_struct *ser) +* Verify the new serial_struct (for TIOCSSERIAL). +* The only change we allow are to the flags +*/ +static int cnxt_verify_port(struct uart_port *port, struct serial_struct *ser) { int ret = 0; + + printk(KERN_DEBUG "%s %d\n", __FUNCTION__,ser->type); + if (ser->type != PORT_CNXT) ret = -EINVAL; if (port->irq != ser->irq) @@ -897,33 +1003,52 @@ cnxt_verify_port(struct uart_port *port, struct serial_struct *ser) return ret; } -static const char * -cnxt_type(struct uart_port *port) +static const char *cnxt_type(struct uart_port *port) { - return cnxt_serial_inst[port->line].typestr ? cnxt_serial_inst[port->line].typestr : CNXTDRVDSC; + return cnxt_serial_inst[port->line].typestr ? cnxt_serial_inst[port->line].typestr : CNXTDRVDSC; +} + +static int cnxt_ioctl_port(struct uart_port *port, unsigned int cmd, unsigned long arg){ + int ret = -ENOIOCTLCMD; + struct cnxt_serial_inst *inst = &cnxt_serial_inst[(port - cnxt_ports) / sizeof(struct uart_port)]; + ioctl_arg_t args; + + //printk(KERN_DEBUG "%s %lu\n", __FUNCTION__,cmd); + switch(cmd){ + default: + break; + case CXT_USERSIGNAL: + if (copy_from_user(&args, (ioctl_arg_t *)arg, sizeof(ioctl_arg_t))) + return -EACCES; + inst->signal.user_pid = args.pid; + ret = 0; + break; + } + return ret; } static struct uart_ops cnxt_pops = { - .tx_empty = cnxt_tx_empty, - .set_mctrl = cnxt_set_mctrl, - .get_mctrl = cnxt_get_mctrl, - .stop_tx = cnxt_stop_tx, + .tx_empty = cnxt_tx_empty, + .set_mctrl = cnxt_set_mctrl, + .get_mctrl = cnxt_get_mctrl, + .stop_tx = cnxt_stop_tx, .start_tx = cnxt_start_tx, .stop_rx = cnxt_stop_rx, - .enable_ms = cnxt_enable_ms, + .enable_ms = cnxt_enable_ms, .break_ctl = cnxt_break_ctl, .startup = cnxt_startup, .shutdown = cnxt_shutdown, - .type = cnxt_type, + .type = cnxt_type, #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) .change_speed = cnxt_change_speed, #else .set_termios = cnxt_set_termios, #endif .release_port = cnxt_release_port, - .request_port = cnxt_request_port, - .config_port = cnxt_config_port, + .request_port = cnxt_request_port, + .config_port = cnxt_config_port, .verify_port = cnxt_verify_port, + .ioctl = cnxt_ioctl_port }; static int serialmajor = CNXTSERIALMAJOR; @@ -956,79 +1081,120 @@ MODULE_PARM(loglastcallstatus, "i"); MODULE_PARM_DESC(loglastcallstatus, "Log AT#UG command output after each connection"); #endif -static struct uart_driver cnxt_reg = { - .owner = THIS_MODULE, -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) -#ifdef CONFIG_DEVFS_FS - .normal_name = "ttyS"CNXTSERDEV"%d", - .callout_name = "cua"CNXTSERDEV"%d", -#else - .normal_name = "ttyS"CNXTSERDEV, - .callout_name = "cua"CNXTSERDEV, -#endif - .normal_driver = &cnxt_tty_driver_normal, - .callout_driver = &cnxt_tty_driver_callout, - .table = cnxt_tty_table, - .termios = cnxt_termios, - .termios_locked = cnxt_termios_locked, - .port = cnxt_ports, -#else - .driver_name = CNXTTARGET"serial", -#ifdef FOUND_DEVFS - .devfs_name = "ttyS"CNXTSERDEV, -#endif - .dev_name = "ttyS"CNXTSERDEV, -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) */ - .minor = CNXTSERIALMINOR, - .nr = NR_PORTS, -}; - -#ifndef CNXTSERIAL_INCLUDE_CORE -#define uart_init() 0 -#define uart_exit() {} -#endif - #ifdef CONFIG_PROC_FS #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) ) -static int cnxt_get_hwinst(struct seq_file *s, void *data) -{ - struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; - - // FIXME: Check s->size - seq_printf(s, "%d-%s\n", inst->devnode->hwInstNum, inst->devnode->hwInstName); + //fixme inst-devnode + static int cnxt_get_hwinst(struct seq_file *s, void *data) + { + struct cnxt_serial_inst *inst = &cnxt_serial_inst[cnxt_serial_shared_memory->hwInstNum]; + seq_printf(s, "%d-%s\n", inst->devnode->hwInstNum, inst->devnode->hwInstName); + return 0; + } + + static int cnxt_proc_open_hwinst(struct inode *inode, struct file *filp) + { + return single_open(filp, cnxt_get_hwinst, NULL); + } + + static int cnxt_get_hwprofile(struct seq_file *s, void *data) + { + struct cnxt_serial_inst *inst = &cnxt_serial_inst[cnxt_serial_shared_memory->hwInstNum]; - return 0; -} + seq_printf(s, "%s\n", inst->devnode->hwProfile); + return 0; + } + -static int cnxt_proc_open_hwinst(struct inode *inode, struct file *filp) -{ - return single_open(filp, cnxt_get_hwinst, PDE_DATA(inode)); -} + static int cnxt_proc_open_hwprofile(struct inode *inode, struct file *filp) + { + return single_open(filp, cnxt_get_hwprofile, NULL); + } + + static int cnxt_get_hwrevision(struct seq_file *s, void *data) + { + struct cnxt_serial_inst *inst = &cnxt_serial_inst[cnxt_serial_shared_memory->hwInstNum]; -static const struct file_operations cnxt_proc_ops_hwinst = { - .owner = THIS_MODULE, - .open = cnxt_proc_open_hwinst, - .llseek = seq_lseek, - .read = seq_read, - .release = single_release, -}; + seq_printf(s, "%s\n", inst->devnode->hwRevision); + return 0; + } + + static int cnxt_proc_open_hwrevision(struct inode *inode, struct file *filp) + { + return single_open(filp, cnxt_get_hwrevision, NULL); + } + static int cnxt_get_lastcallstatus(struct seq_file *s, void *data){ + struct cnxt_serial_inst *inst = &cnxt_serial_inst[cnxt_serial_shared_memory->hwInstNum]; + PORT_MONITOR_DATA monitorData; + int len = PAGE_SIZE; + char *page; + + page = cnxt_serial_shared_memory->buf; + monitorData.dwSize = PAGE_SIZE; + monitorData.pBuf = page; + + if (cnxt_monitor(inst, COMCTRL_MONITOR_POUND_UG, &monitorData) != COM_STATUS_SUCCESS) + page[0] = '\0'; + else + page[len-1] = '\0'; + seq_printf(s, "%s\n", page); + return 0; + } + + static int cnxt_proc_open_lastcallstatus(struct inode *inode, struct file *filp) + { + return single_open(filp, cnxt_get_lastcallstatus, NULL); + } + + + static const struct file_operations cnxt_proc_ops_hwinst = { + .owner = THIS_MODULE, + .open = cnxt_proc_open_hwinst, + .llseek = seq_lseek, + .read = seq_read, + .release = single_release, + }; + + static const struct file_operations cnxt_proc_ops_hwprofile = { + .owner = THIS_MODULE, + .open = cnxt_proc_open_hwprofile, + .llseek = seq_lseek, + .read = seq_read, + .release = single_release, + }; + + static const struct file_operations cnxt_proc_ops_hwrevision = { + .owner = THIS_MODULE, + .open = cnxt_proc_open_hwrevision, + .llseek = seq_lseek, + .read = seq_read, + .release = single_release, + }; + + static const struct file_operations cnxt_proc_ops_lastcallstatus = { + .owner = THIS_MODULE, + .open = cnxt_proc_open_lastcallstatus, + .llseek = seq_lseek, + .read = seq_read, + .release = single_release, + }; + #else -static int cnxt_get_hwinst(char *buf, char **start, off_t offset, int length, int *eof, void *data) -{ - struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; - - if(offset) - return 0; - - if(length > PAGE_SIZE) - length = PAGE_SIZE; - - snprintf(buf, length - 1, "%d-%s\n", inst->devnode->hwInstNum, inst->devnode->hwInstName); - buf[length-1] = '\0'; - return strlen(buf); -} + static int cnxt_get_hwinst(char *buf, char **start, off_t offset, int length, int *eof, void *data) + { + struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; + + if(offset) + return 0; + + if(length > PAGE_SIZE) + length = PAGE_SIZE; + + snprintf(buf, length - 1, "%d-%s\n", inst->devnode->hwInstNum, inst->devnode->hwInstName); + buf[length-1] = '\0'; + return strlen(buf); + } #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) @@ -1037,7 +1203,7 @@ static ssize_t cnxt_flush_nvm(struct file *file, const char __user *buffer, size static int cnxt_flush_nvm(struct file *file, const char __user *buffer, unsigned long count, void *data) #endif { - //printk(KERN_DEBUG "%s: called\n", __FUNCTION__); + printk(KERN_DEBUG "%s: called\n", __FUNCTION__); NVM_WriteFlushList(TRUE); @@ -1046,77 +1212,64 @@ static int cnxt_flush_nvm(struct file *file, const char __user *buffer, unsigned #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) ) static const struct file_operations cnxt_proc_ops_flushnvm = { - .owner = THIS_MODULE, - .write = cnxt_flush_nvm + .owner = THIS_MODULE, + .write = cnxt_flush_nvm }; -#endif - - -#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) ) - // TODO #else static int cnxt_get_hwprofile(char *buf, char **start, off_t offset, int length, int *eof, void *data) { - struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; + struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; - if(offset) + if(offset) return 0; - if(length > PAGE_SIZE) + if(length > PAGE_SIZE) length = PAGE_SIZE; - snprintf(buf, length - 1, "%s\n", inst->devnode->hwProfile); - buf[length-1] = '\0'; - return strlen(buf); + snprintf(buf, length - 1, "%s\n", inst->devnode->hwProfile); + buf[length-1] = '\0'; + return strlen(buf); } static int cnxt_get_hwrevision(char *buf, char **start, off_t offset, int length, int *eof, void *data) { - struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; - - if(offset) - return 0; - - if(length > PAGE_SIZE) - length = PAGE_SIZE; - - snprintf(buf, length - 1, "%s\n", inst->devnode->hwRevision); - buf[length-1] = '\0'; - return strlen(buf); + struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; + if(offset) + return 0; + if(length > PAGE_SIZE) + length = PAGE_SIZE; + snprintf(buf, length - 1, "%s\n", inst->devnode->hwRevision); + buf[length-1] = '\0'; + return strlen(buf); } #ifdef COMCTRL_MONITOR_POUND_UG_SUPPORT static int cnxt_get_lastcallstatus(char *page, char **start, off_t offset, int length, int *eof, void *data) { - struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; - PORT_MONITOR_DATA monitorData; - int len = PAGE_SIZE; - - monitorData.dwSize = len; - monitorData.pBuf = page; - - if (cnxt_monitor(inst, COMCTRL_MONITOR_POUND_UG, &monitorData) != COM_STATUS_SUCCESS) { - page[0] = '\0'; - } else - page[len-1] = '\0'; - - len = strlen(page); + struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; + PORT_MONITOR_DATA monitorData; + int len = PAGE_SIZE; - if (len <= offset+length) - *eof = 1; + monitorData.dwSize = len; + monitorData.pBuf = page; - *start = page + offset; - - len -= offset; - - if (len > length) - len = length; - if (len < 0) - len = 0; - - return len; + if (cnxt_monitor(inst, COMCTRL_MONITOR_POUND_UG, &monitorData) != COM_STATUS_SUCCESS) + page[0] = '\0'; + else + page[len-1] = '\0'; + + len = strlen(page); + if (len <= offset+length) + *eof = 1; + *start = page + offset; + len -= offset; + if (len > length) + len = length; + if (len < 0) + len = 0; + return len; } #endif /* COMCTRL_MONITOR_POUND_UG_SUPPORT */ @@ -1126,24 +1279,19 @@ static int cnxt_get_lastcallstatus(char *page, char **start, off_t offset, int l #ifndef FOUND_UART_REGISTER_PORT -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) -static DECLARE_MUTEX(cnxt_port_sem); -#else -static DEFINE_SEMAPHORE(cnxt_port_sem); -#endif /** - * uart_register_port - register a serial port - * @drv: UART driver - * @port: serial port template - * - * Configure the serial port specified by the request. - * - * The port is then probed and if necessary the IRQ is autodetected - * If this fails an error is returned. - * - * On success the port is ready to use and the line number is returned. - */ +* uart_register_port - register a serial port +* @drv: UART driver +* @port: serial port template +* +* Configure the serial port specified by the request. +* +* The port is then probed and if necessary the IRQ is autodetected +* If this fails an error is returned. +* +* On success the port is ready to use and the line number is returned. +*/ static int uart_register_port(struct uart_driver *drv, struct uart_port *port) { int i; @@ -1158,13 +1306,15 @@ static int uart_register_port(struct uart_driver *drv, struct uart_port *port) } if (i < NR_PORTS) { uart_remove_one_port(drv, uart_port); + uart_port->iobase = port->iobase; uart_port->membase = port->membase; uart_port->irq = port->irq; uart_port->uartclk = port->uartclk; uart_port->iotype = port->iotype; - uart_port->flags = port->flags | UPF_BOOT_AUTOCONF; + uart_port->flags = port->flags | UPF_BOOT_AUTOCONF|UPF_SHARE_IRQ; uart_port->mapbase = port->mapbase; + //uart_port->iotype = UPIO_PORT; if (port->dev) uart_port->dev = port->dev; ret = uart_add_one_port(drv, uart_port); @@ -1176,15 +1326,14 @@ static int uart_register_port(struct uart_driver *drv, struct uart_port *port) } /** - * uart_unregister_port - remove a serial port at runtime - * @drv: UART driver - * @line: serial line number - * - * Remove one serial port. This may not be called from interrupt - * context. We hand the port back to the our control. - */ -static void uart_unregister_port(struct uart_driver *drv, int line) -{ +* uart_unregister_port - remove a serial port at runtime +* @drv: UART driver +* @line: serial line number +* +* Remove one serial port. This may not be called from interrupt +* context. We hand the port back to the our control. +*/ +static void uart_unregister_port(struct uart_driver *drv, int line){ struct uart_port *uart_port = &cnxt_ports[line]; down(&cnxt_port_sem); @@ -1200,224 +1349,227 @@ static void uart_unregister_port(struct uart_driver *drv, int line) } #endif /* FOUND_UART_REGISTER_PORT */ + int cnxt_serial_add(POS_DEVNODE devnode, unsigned int iobase, void *membase, unsigned int irq, struct module *owner) { - struct cnxt_serial_inst *inst = NULL; - int i, r; - struct uart_port port; - PORT_EVENT_HANDLER EvtHandler; - unsigned long flags; - - if(!devnode) { - return -EINVAL; - } - - for(i = 0; i < NR_PORTS; i++) { - spin_lock_irqsave(&cnxt_serial_inst[i].lock, flags); - if(!cnxt_serial_inst[i].devnode) { - inst = &cnxt_serial_inst[i]; - inst->devnode = devnode; - spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); - break; - } - spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); - } - - if(!inst) { - return -ENOSPC; - } - - devnode->hwInstNum = i; /* instance number, needed by osnvm */ - - inst->hcomctrl = ComCtrl_Create(); - if(!inst->hcomctrl) { - printk(KERN_DEBUG "%s: ComCtrlCreate failed!\n", __FUNCTION__); - r = -EIO; - goto errout; - } - - devnode->hcomctrl = inst->hcomctrl; - - if ((r=ComCtrl_Configure(inst->hcomctrl, COMCTRL_CONFIG_DEVICE_ID, devnode))) { - printk(KERN_DEBUG "%s: ComCtrlConfigure DEVICE_ID failed (%d)\n", __FUNCTION__, r); - r = -EIO; - goto errout; - } - - inst->port = NULL; - inst->owner = owner; - inst->mctrl_flags = 0; - - inst->typestr = kmalloc(strlen(CNXTDRVDSC) + strlen(devnode->hwInstName) + 5, GFP_KERNEL); - if(inst->typestr) - sprintf(inst->typestr, "%s (%s)", CNXTDRVDSC, devnode->hwInstName); + struct cnxt_serial_inst *inst = NULL; + int i, r; + struct uart_port port; + PORT_EVENT_HANDLER EvtHandler; + unsigned long flags; - inst->evt_rxchar = 0; - inst->evt_rxbreak = 0; - inst->evt_rxovrn = 0; - inst->evt_txempty = 1; - - inst->rxenabled = 0; - inst->txenabled = 0; - - inst->readcount = inst->readoffset = 0; + if(!devnode) + return -EINVAL; - OsThreadScheduleInit(&inst->intr_tqueue, cnxt_intr, inst); + for(i = 0; i < NR_PORTS; i++) { + spin_lock_irqsave(&cnxt_serial_inst[i].lock, flags); + if(!cnxt_serial_inst[i].devnode) { + inst = &cnxt_serial_inst[i]; + inst->devnode = devnode; + spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); + break; + } + spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); + } - EvtHandler.pfnCallback = ( + if(!inst) + return -ENOSPC; + + devnode->hwInstNum = i; + cnxt_serial_shared_memory->hwInstNum=i; + + inst->hcomctrl = ComCtrl_Create(); + if(!inst->hcomctrl) { + printk(KERN_DEBUG "%s: ComCtrlCreate failed!\n", __FUNCTION__); + r = -EIO; + goto errout; + } + devnode->hcomctrl = inst->hcomctrl; + + inst->port = NULL; + inst->owner = owner; + inst->mctrl_flags = 0; + + inst->typestr = kmalloc(strlen(CNXTDRVDSC) + strlen(devnode->hwInstName) + 5, GFP_KERNEL); + if(inst->typestr) + sprintf(inst->typestr, "%s (%s)", CNXTDRVDSC, devnode->hwInstName); + + if ((r=ComCtrl_Configure(inst->hcomctrl, COMCTRL_CONFIG_DEVICE_ID, devnode))) { + printk(KERN_DEBUG "%s: ComCtrlConfigure DEVICE_ID failed (%d)\n", __FUNCTION__, r); + r = -EIO; + goto errout; + } + + inst->evt_rxchar = 0; + inst->evt_rxbreak = 0; + inst->evt_rxovrn = 0; + inst->evt_txempty = 1; + inst->rxenabled = 0; + inst->txenabled = 0; + inst->readcount = inst->readoffset = 0; +// inst->irq = irq; + + OsThreadScheduleInit(&inst->intr_tqueue, cnxt_intr, inst); + + EvtHandler.pfnCallback = ( #if (__GNUC__ == 3 && __GNUC_MINOR__ > 1) || __GNUC__ > 3 - __shimcall__ -#endif - void (*) (PVOID pRef, UINT32 dwEventMask)) cnxt_event_handler; - EvtHandler.pRef = inst; - - if ((r=ComCtrl_Configure(inst->hcomctrl, COMCTRL_CONFIG_EVENT_HANDLER, &EvtHandler))) { - printk(KERN_DEBUG "%s: ComCtrlConfigure EVENT_HANDLER failed (%d)\n", __FUNCTION__, r); - r = -EIO; - goto errout; - } - - if((r=ComCtrl_Open(inst->hcomctrl))) { - printk(KERN_ERR "%s: ComCtrlOpen failed (%d)\n", __FUNCTION__, r); - r = -EIO; - goto errout; - } - - inst->mctrl_flags |= TIOCM_DSR; // until comctrl generates events for this - - memset(&port, 0, sizeof(port)); - port.iobase = iobase; - port.membase = membase; - port.irq = irq; - port.iotype = iobase ? SERIAL_IO_PORT : SERIAL_IO_MEM; - port.uartclk = BASE_BAUD * 16; - port.fifosize = 16; - port.ops = &cnxt_pops; - port.flags = ASYNC_BOOT_AUTOCONF; - - if((r=uart_register_port(&cnxt_reg, &port)) < 0) { - inst->mctrl_flags &= ~TIOCM_DSR; - ComCtrl_Close(inst->hcomctrl); - goto errout; - } + __shimcall__ +#endif + void (*) (PVOID pRef, UINT32 dwEventMask)) cnxt_event_handler; + + EvtHandler.pRef = inst; + + if ((r=ComCtrl_Configure(inst->hcomctrl, COMCTRL_CONFIG_EVENT_HANDLER, &EvtHandler))) { + printk(KERN_DEBUG "%s: ComCtrlConfigure EVENT_HANDLER failed (%d)\n", __FUNCTION__, r); + r = -EIO; + goto errout; + } + - if(r != i) { - printk(KERN_WARNING "%s: uart_register_port returned %d, expecting %d\n", __FUNCTION__, r, i); - } + if((r=ComCtrl_Open(inst->hcomctrl))) { + printk(KERN_ERR "%s: ComCtrlOpen failed (%d)\n", __FUNCTION__, r); + r = -EIO; + goto errout; + } + + inst->mctrl_flags |= TIOCM_DSR; + + memset(&port, 0, sizeof(port)); + port.iobase = iobase; + port.membase = membase; + port.irq = irq; + + port.membase = (void __iomem *)~0; + port.iobase = 0; + port.irq = 0; + + port.iotype = port.iobase ? SERIAL_IO_PORT : SERIAL_IO_MEM; + port.uartclk = BASE_BAUD * 16; + port.fifosize = 16; + port.ops = &cnxt_pops; + port.flags = ASYNC_BOOT_AUTOCONF; + + if((r = uart_register_port(&cnxt_reg, &port)) < 0) { + inst->mctrl_flags &= ~TIOCM_DSR; + ComCtrl_Close(inst->hcomctrl); + goto errout; + } + if(r != i) + printk(KERN_WARNING "%s: uart_register_port returned %d, expecting %d\n", __FUNCTION__, r, i); + + while(ComCtrl_Read(inst->hcomctrl, inst->readbuf, sizeof(inst->readbuf)) > 0); + #ifdef CONFIG_PROC_FS - if(cnxt_serial_proc_dir) { - char dirname[10]; + if(cnxt_serial_proc_dir) { + char dirname[10]; - snprintf(dirname, sizeof(dirname), "%d", i); - inst->proc_unit_dir = proc_mkdir(dirname, cnxt_serial_proc_dir); - if(inst->proc_unit_dir) { + snprintf(dirname, sizeof(dirname), "%d", i); + inst->proc_unit_dir = proc_mkdir(dirname, cnxt_serial_proc_dir); + if(inst->proc_unit_dir) { #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) ) - inst->proc_hwinst = proc_create_data("hwinst", 0, inst->proc_unit_dir, &cnxt_proc_ops_hwinst, inst); - //inst->proc_hwprofile = proc_create_data("hwprofile", 0, inst->proc_unit_dir, &cnxt_proc_ops_hwprofile, inst); - //inst->proc_hwrevision = proc_create_data("hwrevision", 0, inst->proc_unit_dir, &cnxt_proc_ops_hwrevision, inst); + inst->proc_hwinst = proc_create_data("hwinst", 0, inst->proc_unit_dir, &cnxt_proc_ops_hwinst, inst); + inst->proc_hwprofile = proc_create_data("hwprofile", 0, inst->proc_unit_dir, &cnxt_proc_ops_hwprofile, inst); + inst->proc_hwrevision = proc_create_data("hwrevision", 0, inst->proc_unit_dir, &cnxt_proc_ops_hwrevision, inst); #ifdef COMCTRL_MONITOR_POUND_UG_SUPPORT - //inst->proc_lastcallstatus = proc_create_data("lastcallstatus", 0, inst->proc_unit_dir, &cnxt_proc_ops_lastcallstatus, inst); + inst->proc_lastcallstatus = proc_create_data("lastcallstatus", 0, inst->proc_unit_dir, &cnxt_proc_ops_lastcallstatus, inst); #endif #else - inst->proc_hwinst = create_proc_read_entry("hwinst", 0, inst->proc_unit_dir, cnxt_get_hwinst, inst); - inst->proc_hwprofile = create_proc_read_entry("hwprofile", 0, inst->proc_unit_dir, cnxt_get_hwprofile, inst); - inst->proc_hwrevision = create_proc_read_entry("hwrevision", 0, inst->proc_unit_dir, cnxt_get_hwrevision, inst); + inst->proc_hwinst = create_proc_read_entry("hwinst", 0, inst->proc_unit_dir, cnxt_get_hwinst, inst); + inst->proc_hwprofile = create_proc_read_entry("hwprofile", 0, inst->proc_unit_dir, cnxt_get_hwprofile, inst); + inst->proc_hwrevision = create_proc_read_entry("hwrevision", 0, inst->proc_unit_dir, cnxt_get_hwrevision, inst); #ifdef COMCTRL_MONITOR_POUND_UG_SUPPORT - inst->proc_lastcallstatus = create_proc_read_entry("lastcallstatus", 0, inst->proc_unit_dir, cnxt_get_lastcallstatus, inst); + inst->proc_lastcallstatus = create_proc_read_entry("lastcallstatus", 0, inst->proc_unit_dir, cnxt_get_lastcallstatus, inst); #endif #endif + } } - } #endif /* CONFIG_PROC_FS */ - return 0; + return 0; errout: - if(inst->hcomctrl) { - ComCtrl_Destroy(inst->hcomctrl); - inst->hcomctrl = NULL; - } + if(inst->hcomctrl) { + ComCtrl_Destroy(inst->hcomctrl); + inst->hcomctrl = NULL; + } - spin_lock_irqsave(&inst->lock, flags); - inst->devnode = NULL; - spin_unlock_irqrestore(&inst->lock, flags); + spin_lock_irqsave(&inst->lock, flags); + inst->devnode = NULL; + spin_unlock_irqrestore(&inst->lock, flags); - return r; + return r; } int cnxt_serial_remove(POS_DEVNODE devnode) { - struct cnxt_serial_inst *inst = NULL; - int i; - unsigned long flags; + struct cnxt_serial_inst *inst = NULL; + int i; + unsigned long flags; - if(!devnode) { - return -EINVAL; - } + if(!devnode) + return -EINVAL; - for(i = 0; i < NR_PORTS; i++) { - spin_lock_irqsave(&cnxt_serial_inst[i].lock, flags); - if(cnxt_serial_inst[i].devnode == devnode) { - inst = &cnxt_serial_inst[i]; - spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); - break; - } - spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); - } + for(i = 0; i < NR_PORTS; i++) { + spin_lock_irqsave(&cnxt_serial_inst[i].lock, flags); + if(cnxt_serial_inst[i].devnode == devnode) { + inst = &cnxt_serial_inst[i]; + spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); + break; + } + spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); + } - if(!inst) { - return -EINVAL; - } + if(!inst) + return -EINVAL; - inst->mctrl_flags &= ~TIOCM_DSR; + inst->mctrl_flags &= ~TIOCM_DSR; #ifdef CONFIG_PROC_FS #ifdef COMCTRL_MONITOR_POUND_UG_SUPPORT - if(inst->proc_lastcallstatus) { - remove_proc_entry("lastcallstatus", inst->proc_unit_dir); - } + if(inst->proc_lastcallstatus) { + remove_proc_entry("lastcallstatus", inst->proc_unit_dir); + } #endif - if(inst->proc_hwrevision) { - remove_proc_entry("hwrevision", inst->proc_unit_dir); - } - if(inst->proc_hwprofile) { - remove_proc_entry("hwprofile", inst->proc_unit_dir); - } - if(inst->proc_hwinst) { - remove_proc_entry("hwinst", inst->proc_unit_dir); - } - if(inst->proc_unit_dir) { - char dirname[10]; + if(inst->proc_hwrevision) { + remove_proc_entry("hwrevision", inst->proc_unit_dir); + } + if(inst->proc_hwprofile) { + remove_proc_entry("hwprofile", inst->proc_unit_dir); + } + if(inst->proc_hwinst) { + remove_proc_entry("hwinst", inst->proc_unit_dir); + } + if(inst->proc_unit_dir) { + char dirname[10]; - snprintf(dirname, sizeof(dirname), "%d", i); - remove_proc_entry(dirname, cnxt_serial_proc_dir); - } + snprintf(dirname, sizeof(dirname), "%d", i); + remove_proc_entry(dirname, cnxt_serial_proc_dir); + } #endif /* CONFIG_PROC_FS */ - uart_unregister_port(&cnxt_reg, i); + uart_unregister_port(&cnxt_reg, i); - if(inst->hcomctrl) { - devnode->hcomctrl = NULL; - ComCtrl_Close(inst->hcomctrl); - ComCtrl_Destroy(inst->hcomctrl); - inst->hcomctrl = NULL; - } + if(inst->hcomctrl) { + devnode->hcomctrl = NULL; + ComCtrl_Close(inst->hcomctrl); + ComCtrl_Destroy(inst->hcomctrl); + inst->hcomctrl = NULL; + } - if(inst->typestr) { - kfree(inst->typestr); - inst->typestr = NULL; - } + if(inst->typestr) { + kfree(inst->typestr); + inst->typestr = NULL; + } - spin_lock_irqsave(&inst->lock, flags); - inst->devnode = NULL; - spin_unlock_irqrestore(&inst->lock, flags); + spin_lock_irqsave(&inst->lock, flags); + inst->devnode = NULL; + spin_unlock_irqrestore(&inst->lock, flags); - return 0; + return 0; } -static int __init -cnxt_serial_init(void) +static int __init cnxt_serial_init(void) { int i, ret; @@ -1446,14 +1598,25 @@ cnxt_serial_init(void) } #endif - if ((ret = uart_init()) != 0) { + if ((ret = uart_init()) != 0) return ret; - } + //fixme add new memory allocation ring 0 memory + i=(sizeof(struct cnxt_serial_inst) + sizeof(struct uart_port)) * NR_PORTS + sizeof(struct _cnxt_serial_shared_memory) + PAGE_SIZE*2; + cnxt_serial_inst = (struct cnxt_serial_inst *)kmalloc(i,GFP_KERNEL); + if(cnxt_serial_inst == NULL){ + printk(KERN_ERR "%s: bad allocation cnxt_serial_inst \n", __FUNCTION__); + return -EINVAL; + } + memset(cnxt_serial_inst,0,i); + cnxt_ports = (struct uart_port *)&cnxt_serial_inst[NR_PORTS]; + cnxt_serial_shared_memory = (struct _cnxt_serial_shared_memory *)&cnxt_ports[NR_PORTS]; + cnxt_serial_shared_memory->buf = (unsigned char *)(cnxt_serial_shared_memory+1); + for(i = 0; i < NR_PORTS; i++) { - spin_lock_init(&cnxt_serial_inst[i].lock); - cnxt_ports[i].ops = &cnxt_pops; /* uart_register_port() might not set ops */ - cnxt_ports[i].line = i; + spin_lock_init(&cnxt_serial_inst[i].lock); + cnxt_ports[i].ops = &cnxt_pops; /* uart_register_port() might not set ops */ + cnxt_ports[i].line = i; } #ifdef CONFIG_PROC_FS @@ -1461,7 +1624,7 @@ cnxt_serial_init(void) if (cnxt_serial_proc_dir) { #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) ) - cnxt_serial_flush_nvm = proc_create("flush_nvm", 0, cnxt_serial_proc_dir, &cnxt_proc_ops_flushnvm); + cnxt_serial_flush_nvm = proc_create("flush_nvm", 0, cnxt_serial_proc_dir, &cnxt_proc_ops_flushnvm); #else cnxt_serial_flush_nvm = create_proc_entry("flush_nvm", 0, cnxt_serial_proc_dir); if (cnxt_serial_flush_nvm) @@ -1482,37 +1645,36 @@ cnxt_serial_init(void) uart_exit(); return ret; } - + #if !(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) - for(i = 0; i < NR_PORTS; i++) { + for(i = 0; i < NR_PORTS; i++) uart_add_one_port(&cnxt_reg, &cnxt_ports[i]); - } #endif - return ret; } -static void __exit -cnxt_serial_exit(void) +static void __exit cnxt_serial_exit(void) { #if !(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) int i; - for(i = 0; i < NR_PORTS; i++) { + for(i = 0; i < NR_PORTS; i++) uart_remove_one_port(&cnxt_reg, &cnxt_ports[i]); - } #endif uart_unregister_driver(&cnxt_reg); - #ifdef CONFIG_PROC_FS if(cnxt_serial_proc_dir) { if (cnxt_serial_flush_nvm) remove_proc_entry("flush_nvm", cnxt_serial_proc_dir); remove_proc_entry(PROC_PREFIX CNXTTARGET, proc_root_driver); } -#endif - +#endif uart_exit(); + if(cnxt_serial_inst != NULL) + kfree(cnxt_serial_inst); + cnxt_serial_inst = NULL; + cnxt_ports = NULL; + cnxt_serial_shared_memory = NULL; } module_init(cnxt_serial_init); diff --git a/modules/GPL/serial_cnxt.h b/modules/GPL/serial_cnxt.h old mode 100644 new mode 100755 index d8dc857..dab93b9 --- a/modules/GPL/serial_cnxt.h +++ b/modules/GPL/serial_cnxt.h @@ -59,6 +59,22 @@ #include "osresour_ex.h" +typedef struct { + union{ + struct{ + unsigned long input; /* the starting address of the block of memory */ + unsigned long output; /* the starting address of the block of memory */ + unsigned long length; /* the length of the block of memory */ + unsigned long arg; /* the arg of cmd */ + } a; + }; + int pid; +} ioctl_arg_t; + +#define CNXT_IOCTL_MAGIC 'G' +/* ioctl commands */ +#define CXT_USERSIGNAL _IOWR(CNXT_IOCTL_MAGIC, 0, ioctl_arg_t) + #ifdef __cplusplus extern "C" { diff --git a/modules/GPL/serial_core.c b/modules/GPL/serial_core.c old mode 100644 new mode 100755 index 4dc60e9..577cabc --- a/modules/GPL/serial_core.c +++ b/modules/GPL/serial_core.c @@ -1,33 +1,33 @@ /* - * linux/drivers/char/serial_core.c - * - * Driver core for serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright 1999 ARM Limited - * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. - * - * 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 - * - * $Id: serial_core.c,v 1.21 2001/11/23 12:55:15 rmk Exp $ - * - * Slightly modified by Marc Boucher to support virtual - * uarts (Conexant softmodems). - * - */ +* linux/drivers/char/serial_core.c +* +* Driver core for serial ports +* +* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. +* +* Copyright 1999 ARM Limited +* Copyright (C) 2000-2001 Deep Blue Solutions Ltd. +* +* 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 +* +* $Id: serial_core.c,v 1.21 2001/11/23 12:55:15 rmk Exp $ +* +* Slightly modified by Marc Boucher to support virtual +* uarts (Conexant softmodems). +* +*/ #include #include #include @@ -52,7 +52,7 @@ #endif #include "serial_core.h" -#include +//#include #include #include #include @@ -66,20 +66,20 @@ #endif /* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the copy_from_user blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ +* tmp_buf is used as a temporary buffer by serial_write. We need to +* lock it in case the copy_from_user blocks while swapping in a page, +* and some other program tries to do a serial write at the same time. +* Since the lock will only come under contention when the system is +* swapping and available memory is low, it makes sense to share one +* buffer across all the serial ports, since it significantly saves +* memory if large numbers of serial ports are open. +*/ static u_char *tmp_buf; static DECLARE_MUTEX(tmp_buf_sem); /* - * This is used to lock changes in serial line configuration. - */ +* This is used to lock changes in serial line configuration. +*/ static DECLARE_MUTEX(port_sem); #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) @@ -88,11 +88,11 @@ static void uart_change_speed(struct uart_info *info, struct termios *old_termio static void uart_wait_until_sent(struct tty_struct *tty, int timeout); /* - * This routine is used by the interrupt handler to schedule processing in - * the software interrupt portion of the driver. It is expected that - * interrupts will be disabled (and so the tasklet will be prevented - * from running (CHECK)). - */ +* This routine is used by the interrupt handler to schedule processing in +* the software interrupt portion of the driver. It is expected that +* interrupts will be disabled (and so the tasklet will be prevented +* from running (CHECK)). +*/ SERIALCORE_EXPORT void uart_event(struct uart_info *info, int event) { info->event |= 1 << event; @@ -113,8 +113,8 @@ static void __uart_start(struct tty_struct *tty) { struct uart_info *info = tty->driver_data; if (info->xmit.head != info->xmit.tail && info->xmit.buf && - !tty->stopped && !tty->hw_stopped) - info->ops->start_tx(info->port, 1); + !tty->stopped && !tty->hw_stopped) + info->ops->start_tx(info->port, 1); } static void uart_start(struct tty_struct *tty) @@ -136,24 +136,24 @@ static void uart_tasklet_action(unsigned long data) tty = info->tty; if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event)) - return; + return; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); } static inline void uart_update_altspeed(struct uart_info *info) { if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; + info->tty->alt_speed = 57600; if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; + info->tty->alt_speed = 115200; if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; + info->tty->alt_speed = 230400; if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; + info->tty->alt_speed = 460800; } static int uart_startup(struct uart_info *info) @@ -164,7 +164,7 @@ static int uart_startup(struct uart_info *info) page = get_zeroed_page(GFP_KERNEL); if (!page) - return -ENOMEM; + return -ENOMEM; save_flags(flags); cli(); @@ -175,15 +175,15 @@ static int uart_startup(struct uart_info *info) if (info->port->type == PORT_UNKNOWN) { if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + set_bit(TTY_IO_ERROR, &info->tty->flags); free_page(page); goto errout; } if (info->xmit.buf) - free_page(page); + free_page(page); else - info->xmit.buf = (unsigned char *) page; + info->xmit.buf = (unsigned char *) page; info->mctrl = 0; @@ -191,33 +191,33 @@ static int uart_startup(struct uart_info *info) if (retval) { if (capable(CAP_SYS_ADMIN)) { if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + set_bit(TTY_IO_ERROR, &info->tty->flags); retval = 0; } goto errout; } if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit.head = info->xmit.tail = 0; /* - * Set up the tty->alt_speed kludge - */ + * Set up the tty->alt_speed kludge + */ if (info->tty) - uart_update_altspeed(info); + uart_update_altspeed(info); /* - * and set the speed of the serial port - */ + * and set the speed of the serial port + */ uart_change_speed(info, NULL); /* - * Setup the RTS and DTR signals once the port - * is open and ready to respond. - */ + * Setup the RTS and DTR signals once the port + * is open and ready to respond. + */ if (info->tty->termios->c_cflag & CBAUD) - info->mctrl = TIOCM_RTS | TIOCM_DTR; + info->mctrl = TIOCM_RTS | TIOCM_DTR; info->ops->set_mctrl(info->port, info->mctrl); info->flags |= ASYNC_INITIALIZED; @@ -229,27 +229,27 @@ static int uart_startup(struct uart_info *info) } /* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ +* This routine will shutdown a serial port; interrupts are disabled, and +* DTR is dropped if the hangup on close termio flag is on. +*/ static void uart_shutdown(struct uart_info *info) { unsigned long flags; if (!(info->flags & ASYNC_INITIALIZED)) - return; + return; save_flags(flags); cli(); /* Disable interrupts */ /* - * clear delta_msr_wait queue to avoid mem leaks: we may free the irq - * here so the queue might never be woken up - */ + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be woken up + */ wake_up_interruptible(&info->delta_msr_wait); /* - * Free the IRQ and disable the port - */ + * Free the IRQ and disable the port + */ info->ops->shutdown(info->port, info); if (info->xmit.buf) { @@ -259,13 +259,13 @@ static void uart_shutdown(struct uart_info *info) } if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) - info->mctrl &= ~(TIOCM_DTR|TIOCM_RTS); + info->mctrl &= ~(TIOCM_DTR|TIOCM_RTS); info->ops->set_mctrl(info->port, info->mctrl); /* kill off our tasklet */ tasklet_kill(&info->tlet); if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_INITIALIZED; restore_flags(flags); @@ -277,14 +277,14 @@ static inline u_int uart_calculate_quot(struct uart_info *info, u_int baud) /* Special case: B0 rate */ if (!baud) - baud = 9600; + baud = 9600; /* Old HI/VHI/custom speed handling */ if (baud == 38400 && - ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) - quot = info->state->custom_divisor; + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->state->custom_divisor; else - quot = info->port->uartclk / (16 * baud); + quot = info->port->uartclk / (16 * baud); return quot; } @@ -295,12 +295,12 @@ static void uart_change_speed(struct uart_info *info, struct termios *old_termio u_int quot, baud, cflag, bits, try; /* - * If we have no tty, termios, or the port does not exist, - * then we can't set the parameters for this port. - */ + * If we have no tty, termios, or the port does not exist, + * then we can't set the parameters for this port. + */ if (!info->tty || !info->tty->termios || - info->port->type == PORT_UNKNOWN) - return; + info->port->type == PORT_UNKNOWN) + return; cflag = info->tty->termios->c_cflag; @@ -313,52 +313,52 @@ static void uart_change_speed(struct uart_info *info, struct termios *old_termio } if (cflag & CSTOPB) - bits++; + bits++; if (cflag & PARENB) - bits++; + bits++; for (try = 0; try < 2; try ++) { /* Determine divisor based on baud rate */ baud = tty_get_baud_rate(info->tty); quot = uart_calculate_quot(info, baud); if (quot) - break; + break; /* - * Oops, the quotient was zero. Try again with - * the old baud rate if possible. - */ + * Oops, the quotient was zero. Try again with + * the old baud rate if possible. + */ info->tty->termios->c_cflag &= ~CBAUD; if (old_termios) { info->tty->termios->c_cflag |= - (old_termios->c_cflag & CBAUD); + (old_termios->c_cflag & CBAUD); old_termios = NULL; continue; } /* - * As a last resort, if the quotient is zero, - * default to 9600 bps - */ + * As a last resort, if the quotient is zero, + * default to 9600 bps + */ info->tty->termios->c_cflag |= B9600; } info->timeout = (port->fifosize * HZ * bits * quot) / - (port->uartclk / 16); + (port->uartclk / 16); info->timeout += HZ/50; /* Add .02 seconds of slop */ if (cflag & CRTSCTS) - info->flags |= ASYNC_CTS_FLOW; + info->flags |= ASYNC_CTS_FLOW; else - info->flags &= ~ASYNC_CTS_FLOW; + info->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; + info->flags &= ~ASYNC_CHECK_CD; else - info->flags |= ASYNC_CHECK_CD; + info->flags |= ASYNC_CHECK_CD; /* - * Set up parity check flag - */ + * Set up parity check flag + */ #define RELEVENT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) pm_access(info->state->pm); @@ -372,7 +372,7 @@ static void uart_put_char(struct tty_struct *tty, u_char ch) unsigned long flags; if (!tty || !info->xmit.buf) - return; + return; spin_lock_irqsave(&info->lock, flags); if (CIRC_SPACE(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) != 0) { @@ -387,43 +387,42 @@ static void uart_flush_chars(struct tty_struct *tty) uart_start(tty); } -static int uart_write(struct tty_struct *tty, int from_user, - const u_char * buf, int count) +static int uart_write(struct tty_struct *tty, int from_user,const u_char * buf, int count) { struct uart_info *info = tty->driver_data; unsigned long flags; int c, ret = 0; if (!tty || !info->xmit.buf || !tmp_buf) - return 0; + return 0; if (from_user) { down(&tmp_buf_sem); while (1) { int c1; c = CIRC_SPACE_TO_END(info->xmit.head, - info->xmit.tail, - UART_XMIT_SIZE); + info->xmit.tail, + UART_XMIT_SIZE); if (count < c) - c = count; + c = count; if (c <= 0) - break; + break; c -= copy_from_user(tmp_buf, buf, c); if (!c) { if (!ret) - ret = -EFAULT; + ret = -EFAULT; break; } spin_lock_irqsave(&info->lock, flags); c1 = CIRC_SPACE_TO_END(info->xmit.head, - info->xmit.tail, - UART_XMIT_SIZE); + info->xmit.tail, + UART_XMIT_SIZE); if (c1 < c) - c = c1; + c = c1; memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); info->xmit.head = (info->xmit.head + c) & - (UART_XMIT_SIZE - 1); + (UART_XMIT_SIZE - 1); spin_unlock_irqrestore(&info->lock, flags); buf += c; count -= c; @@ -434,15 +433,15 @@ static int uart_write(struct tty_struct *tty, int from_user, spin_lock_irqsave(&info->lock, flags); while (1) { c = CIRC_SPACE_TO_END(info->xmit.head, - info->xmit.tail, - UART_XMIT_SIZE); + info->xmit.tail, + UART_XMIT_SIZE); if (count < c) - c = count; + c = count; if (c <= 0) - break; + break; memcpy(info->xmit.buf + info->xmit.head, buf, c); info->xmit.head = (info->xmit.head + c) & - (UART_XMIT_SIZE - 1); + (UART_XMIT_SIZE - 1); buf += c; count -= c; ret += c; @@ -475,28 +474,28 @@ static void uart_flush_buffer(struct tty_struct *tty) #ifdef DEBUG printk("uart_flush_buffer(%d) called\n", - minor(tty->device) - tty->driver.minor_start); + minor(tty->device) - tty->driver.minor_start); #endif spin_lock_irqsave(&info->lock, flags); info->xmit.head = info->xmit.tail = 0; spin_unlock_irqrestore(&info->lock, flags); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); } /* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ +* This function is used to send a high-priority XON/XOFF character to +* the device +*/ static void uart_send_xchar(struct tty_struct *tty, char ch) { struct uart_info *info = tty->driver_data; info->port->x_char = ch; if (ch) - info->ops->start_tx(info->port, 0); + info->ops->start_tx(info->port, 0); } static void uart_throttle(struct tty_struct *tty) @@ -505,7 +504,7 @@ static void uart_throttle(struct tty_struct *tty) unsigned long flags; if (I_IXOFF(tty)) - uart_send_xchar(tty, STOP_CHAR(tty)); + uart_send_xchar(tty, STOP_CHAR(tty)); if (tty->termios->c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock, flags); @@ -522,9 +521,9 @@ static void uart_unthrottle(struct tty_struct *tty) if (I_IXOFF(tty)) { if (info->port->x_char) - info->port->x_char = 0; + info->port->x_char = 0; else - uart_send_xchar(tty, START_CHAR(tty)); + uart_send_xchar(tty, START_CHAR(tty)); } if (tty->termios->c_cflag & CRTSCTS) { @@ -547,7 +546,7 @@ static int uart_get_info(struct uart_info *info, struct serial_struct *retinfo) tmp.port = port->iobase; #ifdef SERIAL_IO_MEM if (HIGH_BITS_OFFSET) - tmp.port_high = port->iobase >> HIGH_BITS_OFFSET; + tmp.port_high = port->iobase >> HIGH_BITS_OFFSET; #endif tmp.irq = port->irq; tmp.flags = port->flags; @@ -564,12 +563,11 @@ static int uart_get_info(struct uart_info *info, struct serial_struct *retinfo) #endif if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + return -EFAULT; return 0; } -static int uart_set_info(struct uart_info *info, - struct serial_struct *newinfo) +static int uart_set_info(struct uart_info *info,struct serial_struct *newinfo) { #ifndef SERIAL_IO_MEM return -ENOSYS; @@ -583,37 +581,37 @@ static int uart_set_info(struct uart_info *info, int retval = 0; if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; + return -EFAULT; new_port = new_serial.port; if (HIGH_BITS_OFFSET) - new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; + new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; new_serial.irq = irq_cannonicalize(new_serial.irq); /* - * This semaphore protects state->count. It is also - * very useful to prevent opens. Also, take the - * port configuration semaphore to make sure that a - * module insertion/removal doesn't change anything - * under us. - */ + * This semaphore protects state->count. It is also + * very useful to prevent opens. Also, take the + * port configuration semaphore to make sure that a + * module insertion/removal doesn't change anything + * under us. + */ down(&port_sem); down(&state->count_sem); change_irq = new_serial.irq != port->irq; /* - * Since changing the 'type' of the port changes its resource - * allocations, we should treat type changes the same as - * IO port changes. - */ + * Since changing the 'type' of the port changes its resource + * allocations, we should treat type changes the same as + * IO port changes. + */ change_port = new_port != port->iobase || - (unsigned long)new_serial.iomem_base != port->mapbase || - new_serial.hub6 != port->hub6 || - new_serial.io_type != port->iotype || - new_serial.iomem_reg_shift != port->regshift || - new_serial.type != port->type; + (unsigned long)new_serial.iomem_base != port->mapbase || + new_serial.hub6 != port->hub6 || + new_serial.io_type != port->iotype || + new_serial.iomem_reg_shift != port->regshift || + new_serial.type != port->type; old_flags = port->flags; old_custom_divisor = state->custom_divisor; @@ -621,47 +619,47 @@ static int uart_set_info(struct uart_info *info, if (!capable(CAP_SYS_ADMIN)) { retval = -EPERM; if (change_irq || change_port || - (new_serial.baud_base != port->uartclk / 16) || - (new_serial.close_delay != state->close_delay) || - (new_serial.closing_wait != state->closing_wait) || - (new_serial.xmit_fifo_size != port->fifosize) || - ((new_serial.flags & ~ASYNC_USR_MASK) != - (port->flags & ~ASYNC_USR_MASK))) - goto exit; + (new_serial.baud_base != port->uartclk / 16) || + (new_serial.close_delay != state->close_delay) || + (new_serial.closing_wait != state->closing_wait) || + (new_serial.xmit_fifo_size != port->fifosize) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (port->flags & ~ASYNC_USR_MASK))) + goto exit; port->flags = ((port->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); + (new_serial.flags & ASYNC_USR_MASK)); info->flags = ((info->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); + (new_serial.flags & ASYNC_USR_MASK)); state->custom_divisor = new_serial.custom_divisor; goto check_and_exit; } /* - * Ask the low level driver to verify the settings. - */ + * Ask the low level driver to verify the settings. + */ if (port->ops->verify_port) - retval = port->ops->verify_port(port, &new_serial); + retval = port->ops->verify_port(port, &new_serial); if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || - (new_serial.baud_base < 9600)) - retval = -EINVAL; + (new_serial.baud_base < 9600)) + retval = -EINVAL; if (retval) - goto exit; + goto exit; if (change_port || change_irq) { retval = -EBUSY; /* - * Make sure that we are the sole user of this port. - */ + * Make sure that we are the sole user of this port. + */ if (state->count > 1) - goto exit; + goto exit; /* - * We need to shutdown the serial port at the old - * port/type/irq combination. - */ + * We need to shutdown the serial port at the old + * port/type/irq combination. + */ uart_shutdown(info); } @@ -677,10 +675,10 @@ static int uart_set_info(struct uart_info *info, old_shift = port->regshift; /* - * Free and release old regions - */ + * Free and release old regions + */ if (old_type != PORT_UNKNOWN) - port->ops->release_port(port); + port->ops->release_port(port); port->iobase = new_port; port->type = new_serial.type; @@ -690,15 +688,15 @@ static int uart_set_info(struct uart_info *info, port->mapbase = (unsigned long)new_serial.iomem_base; /* - * Claim and map the new regions - */ + * Claim and map the new regions + */ if (port->type != PORT_UNKNOWN) - retval = port->ops->request_port(port); + retval = port->ops->request_port(port); /* - * If we fail to request resources for the - * new port, try to restore the old settings. - */ + * If we fail to request resources for the + * new port, try to restore the old settings. + */ if (retval && old_type != PORT_UNKNOWN) { port->iobase = old_iobase; port->type = old_type; @@ -708,15 +706,15 @@ static int uart_set_info(struct uart_info *info, port->mapbase = old_mapbase; retval = port->ops->request_port(port); /* - * If we failed to restore the old settings, - * we fail like this. - */ + * If we failed to restore the old settings, + * we fail like this. + */ if (retval) - port->type = PORT_UNKNOWN; + port->type = PORT_UNKNOWN; /* - * We failed anyway. - */ + * We failed anyway. + */ retval = -EBUSY; } } @@ -724,27 +722,27 @@ static int uart_set_info(struct uart_info *info, port->irq = new_serial.irq; port->uartclk = new_serial.baud_base * 16; port->flags = ((port->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); + (new_serial.flags & ASYNC_FLAGS)); info->flags = ((port->flags & ~ASYNC_INTERNAL_FLAGS) | - (info->flags & ASYNC_INTERNAL_FLAGS)); + (info->flags & ASYNC_INTERNAL_FLAGS)); state->custom_divisor = new_serial.custom_divisor; state->close_delay = new_serial.close_delay * HZ / 100; state->closing_wait = new_serial.closing_wait * HZ / 100; info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; port->fifosize = new_serial.xmit_fifo_size; -check_and_exit: + check_and_exit: retval = 0; if (port->type == PORT_UNKNOWN) - goto exit; + goto exit; if (info->flags & ASYNC_INITIALIZED) { if (((old_flags & info->flags) & ASYNC_SPD_MASK) || - old_custom_divisor != state->custom_divisor) { + old_custom_divisor != state->custom_divisor) { uart_update_altspeed(info); uart_change_speed(info, NULL); } } else - retval = uart_startup(info); + retval = uart_startup(info); exit: up(&state->count_sem); up(&port_sem); @@ -754,8 +752,8 @@ static int uart_set_info(struct uart_info *info, /* - * uart_get_lsr_info - get line status register info - */ +* uart_get_lsr_info - get line status register info +*/ static int uart_get_lsr_info(struct uart_info *info, unsigned int *value) { u_int result; @@ -766,16 +764,16 @@ static int uart_get_lsr_info(struct uart_info *info, unsigned int *value) spin_unlock_irqrestore(&info->lock, flags); /* - * If we're about to load something into the transmit - * register, we'll pretend the transmitter isn't empty to - * avoid a race condition (depending on when the transmit - * interrupt happens). - */ + * If we're about to load something into the transmit + * register, we'll pretend the transmitter isn't empty to + * avoid a race condition (depending on when the transmit + * interrupt happens). + */ if (info->port->x_char || - ((CIRC_CNT(info->xmit.head, info->xmit.tail, - UART_XMIT_SIZE) > 0) && - !info->tty->stopped && !info->tty->hw_stopped)) - result &= ~TIOCSER_TEMT; + ((CIRC_CNT(info->xmit.head, info->xmit.tail, + UART_XMIT_SIZE) > 0) && + !info->tty->stopped && !info->tty->hw_stopped)) + result &= ~TIOCSER_TEMT; return put_user(result, value); } @@ -790,13 +788,13 @@ static int uart_get_modem_info(struct uart_info *info, unsigned int *value) } static int uart_set_modem_info(struct uart_info *info, unsigned int cmd, - unsigned int *value) +unsigned int *value) { unsigned int arg, old; int ret = 0; if (get_user(arg, value)) - return -EFAULT; + return -EFAULT; spin_lock_irq(&info->lock); old = info->mctrl; @@ -807,7 +805,7 @@ static int uart_set_modem_info(struct uart_info *info, unsigned int cmd, default: ret = -EINVAL; break; } if (old != info->mctrl) - info->ops->set_mctrl(info->port, info->mctrl); + info->ops->set_mctrl(info->port, info->mctrl); spin_unlock_irq(&info->lock); return ret; } @@ -830,13 +828,13 @@ static int uart_do_autoconfig(struct uart_info *info) int flags, ret; if (!capable(CAP_SYS_ADMIN)) - return -EPERM; + return -EPERM; /* - * Take the 'count' lock. This prevents count - * from incrementing, and hence any extra opens - * of the port while we're auto-configging. - */ + * Take the 'count' lock. This prevents count + * from incrementing, and hence any extra opens + * of the port while we're auto-configging. + */ down(&info->state->count_sem); ret = -EBUSY; @@ -844,20 +842,20 @@ static int uart_do_autoconfig(struct uart_info *info) uart_shutdown(info); /* - * If we already have a port type configured, - * we must release its resources. - */ + * If we already have a port type configured, + * we must release its resources. + */ if (port->type != PORT_UNKNOWN) - port->ops->release_port(port); + port->ops->release_port(port); flags = UART_CONFIG_TYPE; if (port->flags & ASYNC_AUTO_IRQ) - flags |= UART_CONFIG_IRQ; + flags |= UART_CONFIG_IRQ; /* - * This will claim the ports resources if - * a port is found. - */ + * This will claim the ports resources if + * a port is found. + */ port->ops->config_port(port, flags); ret = uart_startup(info); @@ -867,10 +865,10 @@ static int uart_do_autoconfig(struct uart_info *info) } /* - * Called from userspace. We can use spin_lock_irq() here. - */ +* Called from userspace. We can use spin_lock_irq() here. +*/ static int uart_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +unsigned int cmd, unsigned long arg) { struct uart_info *info = tty->driver_data; struct uart_icount cprev, cnow; @@ -878,115 +876,115 @@ static int uart_ioctl(struct tty_struct *tty, struct file *file, int ret = -ENOIOCTLCMD; if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && - (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; + return -EIO; } switch (cmd) { - case TIOCMGET: - ret = uart_get_modem_info(info, (unsigned int *)arg); - break; + case TIOCMGET: + ret = uart_get_modem_info(info, (unsigned int *)arg); + break; - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - ret = uart_set_modem_info(info, cmd, - (unsigned int *)arg); - break; + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + ret = uart_set_modem_info(info, cmd, + (unsigned int *)arg); + break; - case TIOCGSERIAL: - ret = uart_get_info(info, (struct serial_struct *)arg); - break; + case TIOCGSERIAL: + ret = uart_get_info(info, (struct serial_struct *)arg); + break; - case TIOCSSERIAL: - ret = uart_set_info(info, (struct serial_struct *)arg); - break; + case TIOCSSERIAL: + ret = uart_set_info(info, (struct serial_struct *)arg); + break; - case TIOCSERCONFIG: - ret = uart_do_autoconfig(info); - break; + case TIOCSERCONFIG: + ret = uart_do_autoconfig(info); + break; - case TIOCSERGETLSR: /* Get line status register */ - ret = uart_get_lsr_info(info, (unsigned int *)arg); - break; + case TIOCSERGETLSR: /* Get line status register */ + ret = uart_get_lsr_info(info, (unsigned int *)arg); + break; /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + spin_lock_irq(&info->lock); + /* note the counters on entry */ + cprev = info->port->icount; + /* Force modem status interrupts on */ + info->ops->enable_ms(info->port); + spin_unlock_irq(&info->lock); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } spin_lock_irq(&info->lock); - /* note the counters on entry */ - cprev = info->port->icount; - /* Force modem status interrupts on */ - info->ops->enable_ms(info->port); + cnow = info->port->icount; /* atomic copy */ spin_unlock_irq(&info->lock); - while (1) { - interruptible_sleep_on(&info->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - spin_lock_irq(&info->lock); - cnow = info->port->icount; /* atomic copy */ - spin_unlock_irq(&info->lock); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { - ret = -EIO; /* no change => error */ - break; - } - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - ret = 0; - break; - } - cprev = cnow; + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { + ret = -EIO; /* no change => error */ + break; } - break; + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { + ret = 0; + break; + } + cprev = cnow; + } + break; /* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ - case TIOCGICOUNT: - spin_lock_irq(&info->lock); - cnow = info->port->icount; - spin_unlock_irq(&info->lock); - - icount.cts = cnow.cts; - icount.dsr = cnow.dsr; - icount.rng = cnow.rng; - icount.dcd = cnow.dcd; - icount.rx = cnow.rx; - icount.tx = cnow.tx; - icount.frame = cnow.frame; - icount.overrun = cnow.overrun; - icount.parity = cnow.parity; - icount.brk = cnow.brk; - icount.buf_overrun = cnow.buf_overrun; - - ret = copy_to_user((void *)arg, &icount, sizeof(icount)) - ? -EFAULT : 0; - break; + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + spin_lock_irq(&info->lock); + cnow = info->port->icount; + spin_unlock_irq(&info->lock); + + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + ret = copy_to_user((void *)arg, &icount, sizeof(icount)) + ? -EFAULT : 0; + break; - case TIOCSERGWILD: /* obsolete */ - case TIOCSERSWILD: /* obsolete */ - ret = 0; - break; + case TIOCSERGWILD: /* obsolete */ + case TIOCSERSWILD: /* obsolete */ + ret = 0; + break; - default: - if (info->ops->ioctl) - ret = info->ops->ioctl(info->port, cmd, arg); - break; + default: + if (info->ops->ioctl) + ret = info->ops->ioctl(info->port, cmd, arg); + break; } return ret; } @@ -998,8 +996,8 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios unsigned int cflag = tty->termios->c_cflag; if ((cflag ^ old_termios->c_cflag) == 0 && - RELEVENT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) - return; + RELEVENT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) + return; uart_change_speed(info, old_termios); @@ -1015,8 +1013,8 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { info->mctrl |= TIOCM_DTR; if (!(cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) - info->mctrl |= TIOCM_RTS; + !test_bit(TTY_THROTTLED, &tty->flags)) + info->mctrl |= TIOCM_RTS; info->ops->set_mctrl(info->port, info->mctrl); } @@ -1029,22 +1027,22 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios #if 0 /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); #endif } /* - * In 2.4.5, calls to this will be serialized via the BKL in - * linux/drivers/char/tty_io.c:tty_release() - * linux/drivers/char/tty_io.c:do_tty_handup() - */ +* In 2.4.5, calls to this will be serialized via the BKL in +* linux/drivers/char/tty_io.c:tty_release() +* linux/drivers/char/tty_io.c:do_tty_handup() +*/ static void uart_close(struct tty_struct *tty, struct file *filp) { struct uart_driver *drv = (struct uart_driver *)tty->driver.driver_state; @@ -1053,7 +1051,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) unsigned long flags; if (!info) - return; + return; state = info->state; @@ -1062,35 +1060,35 @@ static void uart_close(struct tty_struct *tty, struct file *filp) #endif /* - * This is safe, as long as the BKL exists in - * do_tty_hangup(), and we're protected by the BKL. - */ + * This is safe, as long as the BKL exists in + * do_tty_hangup(), and we're protected by the BKL. + */ if (tty_hung_up_p(filp)) - goto done; + goto done; down(&state->count_sem); spin_lock_irqsave(&info->lock, flags); if ( #ifdef NON_ATOMIC_TTY_STRUCT_COUNT - (tty->count == 1) + (tty->count == 1) #else - (atomic_read(&(tty->count)) == 1) + (atomic_read(&(tty->count)) == 1) #endif - && (state->count != 1)) { + && (state->count != 1)) { /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. state->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ printk("uart_close: bad serial port count; tty->count is 1, " - "state->count is %d\n", state->count); + "state->count is %d\n", state->count); state->count = 1; } if (--state->count < 0) { printk("rs_close: bad serial port count for %s%d: %d\n", - tty->driver.name, info->port->line, state->count); + tty->driver.name, info->port->line, state->count); state->count = 0; } if (state->count) { @@ -1103,38 +1101,38 @@ static void uart_close(struct tty_struct *tty, struct file *filp) up(&state->count_sem); /* - * Save the termios structure, since this port may have - * separate termios for callout and dialin. - */ + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ if (info->flags & ASYNC_NORMAL_ACTIVE) - info->state->normal_termios = *tty->termios; + info->state->normal_termios = *tty->termios; if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->state->callout_termios = *tty->termios; + info->state->callout_termios = *tty->termios; /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ tty->closing = 1; if (info->state->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->state->closing_wait); + tty_wait_until_sent(tty, info->state->closing_wait); /* - * At this point, we stop accepting input. To do this, we - * disable the receive line status interrupts. - */ + * At this point, we stop accepting input. To do this, we + * disable the receive line status interrupts. + */ if (info->flags & ASYNC_INITIALIZED) { info->ops->stop_rx(info->port); /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ uart_wait_until_sent(tty, info->timeout); } uart_shutdown(info); if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); + tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty->ldisc.flush_buffer(tty); tty->closing = 0; info->event = 0; info->tty = NULL; @@ -1148,22 +1146,22 @@ static void uart_close(struct tty_struct *tty, struct file *filp) } else { #ifdef CONFIG_PM /* - * Put device into D3 state. - */ + * Put device into D3 state. + */ pm_send(info->state->pm, PM_SUSPEND, (void *)3); #else if (info->ops->pm) - info->ops->pm(info->port, 3, 0); + info->ops->pm(info->port, 3, 0); #endif } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); done: if (drv->owner) - __MOD_DEC_USE_COUNT(drv->owner); + __MOD_DEC_USE_COUNT(drv->owner); } static void uart_wait_until_sent(struct tty_struct *tty, int timeout) @@ -1172,56 +1170,56 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) unsigned long char_time, expire; if (info->port->type == PORT_UNKNOWN || - info->port->fifosize == 0) - return; + info->port->fifosize == 0) + return; /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ char_time = (info->timeout - HZ/50) / info->port->fifosize; char_time = char_time / 5; if (char_time == 0) - char_time = 1; + char_time = 1; if (timeout && timeout < char_time) - char_time = timeout; + char_time = timeout; /* - * If the transmitter hasn't cleared in twice the approximate - * amount of time to send the entire FIFO, it probably won't - * ever clear. This assumes the UART isn't doing flow - * control, which is currently the case. Hence, if it ever - * takes longer than info->timeout, this is probably due to a - * UART bug of some kind. So, we clamp the timeout parameter at - * 2*info->timeout. - */ + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ if (!timeout || timeout > 2 * info->timeout) - timeout = 2 * info->timeout; + timeout = 2 * info->timeout; expire = jiffies + timeout; #ifdef DEBUG printk("uart_wait_until_sent(%d), jiff=%lu, expire=%lu...\n", - minor(tty->device) - tty->driver.minor_start, jiffies, - expire); + minor(tty->device) - tty->driver.minor_start, jiffies, + expire); #endif while (!info->ops->tx_empty(info->port)) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(char_time); if (signal_pending(current)) - break; + break; if (timeout && time_after(jiffies, expire)) - break; + break; } set_current_state(TASK_RUNNING); /* might not be needed */ } /* - * This is called with the BKL in effect - * linux/drivers/char/tty_io.c:do_tty_hangup() - */ +* This is called with the BKL in effect +* linux/drivers/char/tty_io.c:do_tty_hangup() +*/ static void uart_hangup(struct tty_struct *tty) { struct uart_info *info = tty->driver_data; @@ -1229,7 +1227,7 @@ static void uart_hangup(struct tty_struct *tty) uart_flush_buffer(tty); if (info->flags & ASYNC_CLOSING) - return; + return; uart_shutdown(info); info->event = 0; state->count = 0; @@ -1239,7 +1237,7 @@ static void uart_hangup(struct tty_struct *tty) } static int uart_block_til_ready(struct tty_struct *tty, struct file *filp, - struct uart_info *info) +struct uart_info *info) { DECLARE_WAITQUEUE(wait, current); struct uart_state *state = info->state; @@ -1247,64 +1245,64 @@ static int uart_block_til_ready(struct tty_struct *tty, struct file *filp, int do_clocal = 0, extra_count = 0, retval; /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { + (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); + interruptible_sleep_on(&info->close_wait); return (info->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS; + -EAGAIN : -ERESTARTSYS; } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; + return -EBUSY; if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; info->flags |= ASYNC_CALLOUT_ACTIVE; return 0; } /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. Note that - * we have set TTY_IO_ERROR for a non-enabled port. - */ + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. Note that + * we have set TTY_IO_ERROR for a non-enabled port. + */ if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { + (tty->flags & (1 << TTY_IO_ERROR))) { if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; + return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } if (info->flags & ASYNC_CALLOUT_ACTIVE) { if (state->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = 1; } else { if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = 1; } /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, state->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ retval = 0; add_wait_queue(&info->open_wait, &wait); down(&state->count_sem); @@ -1319,25 +1317,25 @@ static int uart_block_til_ready(struct tty_struct *tty, struct file *filp, while (1) { spin_lock_irqsave(&info->lock, flags); if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) { + (tty->termios->c_cflag & CBAUD)) { info->mctrl = TIOCM_DTR | TIOCM_RTS; info->ops->set_mctrl(info->port, info->mctrl); } spin_unlock_irqrestore(&info->lock, flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { + !(info->flags & ASYNC_INITIALIZED)) { if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; + retval = -EAGAIN; else - retval = -ERESTARTSYS; + retval = -ERESTARTSYS; break; } if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && - (do_clocal || - (info->ops->get_mctrl(info->port) & TIOCM_CAR))) - break; + !(info->flags & ASYNC_CLOSING) && + (do_clocal || + (info->ops->get_mctrl(info->port) & TIOCM_CAR))) + break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; @@ -1348,11 +1346,11 @@ static int uart_block_til_ready(struct tty_struct *tty, struct file *filp, remove_wait_queue(&info->open_wait, &wait); down(&state->count_sem); if (extra_count) - state->count++; + state->count++; info->blocked_open--; up(&state->count_sem); if (retval) - return retval; + return retval; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -1365,7 +1363,7 @@ static struct uart_info *uart_get(struct uart_driver *drv, int line) down(&state->count_sem); state->count++; if (state->info) - goto out; + goto out; info = kmalloc(sizeof(struct uart_info), GFP_KERNEL); if (info) { @@ -1379,42 +1377,42 @@ static struct uart_info *uart_get(struct uart_driver *drv, int line) info->ops = info->port->ops; info->state = state; tasklet_init(&info->tlet, uart_tasklet_action, - (unsigned long)info); + (unsigned long)info); } if (state->info) - kfree(info); + kfree(info); else - state->info = info; + state->info = info; out: up(&state->count_sem); return state->info; } /* - * Make sure we have the temporary buffer allocated. Note - * that we set retval appropriately above, and we rely on - * this. - */ +* Make sure we have the temporary buffer allocated. Note +* that we set retval appropriately above, and we rely on +* this. +*/ static inline int uart_alloc_tmpbuf(void) { if (!tmp_buf) { unsigned long buf = get_zeroed_page(GFP_KERNEL); if (!tmp_buf) { if (buf) - tmp_buf = (u_char *)buf; + tmp_buf = (u_char *)buf; else - return -ENOMEM; + return -ENOMEM; } else - free_page(buf); + free_page(buf); } return 0; } /* - * In 2.4.5, calls to uart_open are serialised by the BKL in - * linux/fs/devices.c:chrdev_open() - * Note that if this fails, then uart_close() _will_ be called. - */ +* In 2.4.5, calls to uart_open are serialised by the BKL in +* linux/fs/devices.c:chrdev_open() +* Note that if this fails, then uart_close() _will_ be called. +*/ static int uart_open(struct tty_struct *tty, struct file *filp) { struct uart_driver *drv = (struct uart_driver *)tty->driver.driver_state; @@ -1427,77 +1425,77 @@ static int uart_open(struct tty_struct *tty, struct file *filp) retval = -ENODEV; if (line >= tty->driver.num) - goto fail; + goto fail; if (!try_inc_mod_count(drv->owner)) - goto fail; + goto fail; info = uart_get(drv, line); retval = -ENOMEM; if (!info) - goto out; + goto out; /* - * Set the tty driver_data. If we fail from this point on, - * the generic tty layer will cause uart_close(), which will - * decrement the module use count. - */ + * Set the tty driver_data. If we fail from this point on, + * the generic tty layer will cause uart_close(), which will + * decrement the module use count. + */ tty->driver_data = info; info->tty = tty; info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; if (uart_alloc_tmpbuf()) - goto fail; + goto fail; /* - * If the port is in the middle of closing, bail out now. - */ + * If the port is in the middle of closing, bail out now. + */ if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { + (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); + interruptible_sleep_on(&info->close_wait); retval = (info->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS; + -EAGAIN : -ERESTARTSYS; goto fail; } /* - * Make sure the device is in D0 state. - */ + * Make sure the device is in D0 state. + */ if (info->state->count == 1) #ifdef CONFIG_PM - pm_send(info->state->pm, PM_RESUME, (void *)0); + pm_send(info->state->pm, PM_RESUME, (void *)0); #else - if (info->ops->pm) - info->ops->pm(info->port, 0, 3); + if (info->ops->pm) + info->ops->pm(info->port, 0, 3); #endif /* - * Start up the serial port - */ + * Start up the serial port + */ retval = uart_startup(info); if (retval) - goto fail; + goto fail; retval = uart_block_til_ready(tty, filp, info); if (retval) - goto fail; + goto fail; if (info->state->count == 1) { int changed_termios = 0; if (info->flags & ASYNC_SPLIT_TERMIOS) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->state->normal_termios; + *tty->termios = info->state->normal_termios; else - *tty->termios = info->state->callout_termios; + *tty->termios = info->state->callout_termios; changed_termios = 1; } #ifdef CONFIG_SERIAL_CORE_CONSOLE /* - * Copy across the serial console cflag setting - */ + * Copy across the serial console cflag setting + */ { struct console *c = drv->cons; if (c && c->cflag && c->index == line) { @@ -1508,7 +1506,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) } #endif if (changed_termios) - uart_change_speed(info, NULL); + uart_change_speed(info, NULL); } info->session = current->session; @@ -1517,7 +1515,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) out: if (drv->owner) - __MOD_DEC_USE_COUNT(drv->owner); + __MOD_DEC_USE_COUNT(drv->owner); fail: return retval; } @@ -1529,10 +1527,10 @@ static const char *uart_type(struct uart_port *port) const char *str = NULL; if (port->ops->type) - str = port->ops->type(port); + str = port->ops->type(port); if (!str) - str = "unknown"; + str = "unknown"; return str; } @@ -1546,8 +1544,8 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) int ret; ret = sprintf(buf, "%d: uart:%s port:%08X irq:%d", - port->line, uart_type(port), - port->iobase, port->irq); + port->line, uart_type(port), + port->iobase, port->irq); if (port->type == PORT_UNKNOWN) { strcat(buf, "\n"); @@ -1557,25 +1555,25 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) status = port->ops->get_mctrl(port); ret += sprintf(buf + ret, " tx:%d rx:%d", - port->icount.tx, port->icount.rx); + port->icount.tx, port->icount.rx); if (port->icount.frame) - ret += sprintf(buf + ret, " fe:%d", - port->icount.frame); + ret += sprintf(buf + ret, " fe:%d", + port->icount.frame); if (port->icount.parity) - ret += sprintf(buf + ret, " pe:%d", - port->icount.parity); + ret += sprintf(buf + ret, " pe:%d", + port->icount.parity); if (port->icount.brk) - ret += sprintf(buf + ret, " brk:%d", - port->icount.brk); + ret += sprintf(buf + ret, " brk:%d", + port->icount.brk); if (port->icount.overrun) - ret += sprintf(buf + ret, " oe:%d", - port->icount.overrun); + ret += sprintf(buf + ret, " oe:%d", + port->icount.overrun); #define INFOBIT(bit,str) \ - if (state->info && state->info->mctrl & (bit)) \ + if (state->info && state->info->mctrl & (bit)) \ strcat(stat_buf, (str)) #define STATBIT(bit,str) \ - if (status & (bit)) \ + if (status & (bit)) \ strcat(stat_buf, (str)) stat_buf[0] = '\0'; @@ -1587,7 +1585,7 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) STATBIT(TIOCM_CAR, "|CD"); STATBIT(TIOCM_RNG, "|RI"); if (stat_buf[0]) - stat_buf[0] = ' '; + stat_buf[0] = ' '; strcat(stat_buf, "\n"); ret += sprintf(buf + ret, stat_buf); @@ -1595,7 +1593,7 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) } static int uart_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +int count, int *eof, void *data) { struct tty_driver *ttydrv = data; struct uart_driver *drv = ttydrv->driver_state; @@ -1603,12 +1601,12 @@ static int uart_read_proc(char *page, char **start, off_t off, off_t begin = 0; len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n", - "", "", ""); + "", "", ""); for (i = 0; i < drv->nr && len < PAGE_SIZE - 96; i++) { l = uart_line_info(page + len, drv, i); len += l; if (len + begin > off + count) - goto done; + goto done; if (len + begin < off) { begin += len; len = 0; @@ -1617,7 +1615,7 @@ static int uart_read_proc(char *page, char **start, off_t off, *eof = 1; done: if (off >= len + begin) - return 0; + return 0; *start = page + (off - begin); return (count < begin + len - off) ? count : (begin + len - off); } @@ -1625,21 +1623,21 @@ static int uart_read_proc(char *page, char **start, off_t off, #ifdef CONFIG_SERIAL_CORE_CONSOLE /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ +* Check whether an invalid uart number has been specified, and +* if so, search for the first available port that does have +* console support. +*/ struct uart_port * __init uart_get_console(struct uart_port *ports, int nr, struct console *co) { int idx = co->index; if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 && - ports[idx].membase == NULL)) - for (idx = 0; idx < nr; idx++) - if (ports[idx].iobase != 0 || - ports[idx].membase != NULL) - break; + ports[idx].membase == NULL)) + for (idx = 0; idx < nr; idx++) + if (ports[idx].iobase != 0 || + ports[idx].membase != NULL) + break; co->index = idx; @@ -1647,17 +1645,17 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) } /** - * uart_parse_options - Parse serial port baud/parity/bits/flow contro. - * @options: pointer to option string - * @baud: pointer to an 'int' variable for the baud rate. - * @parity: pointer to an 'int' variable for the parity. - * @bits: pointer to an 'int' variable for the number of data bits. - * @flow: pointer to an 'int' variable for the flow control character. - * - * uart_parse_options decodes a string containing the serial console - * options. The format of the string is , - * eg: 115200n8r - */ +* uart_parse_options - Parse serial port baud/parity/bits/flow contro. +* @options: pointer to option string +* @baud: pointer to an 'int' variable for the baud rate. +* @parity: pointer to an 'int' variable for the parity. +* @bits: pointer to an 'int' variable for the number of data bits. +* @flow: pointer to an 'int' variable for the flow control character. +* +* uart_parse_options decodes a string containing the serial console +* options. The format of the string is , +* eg: 115200n8r +*/ void __init uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) { @@ -1665,34 +1663,34 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) *baud = simple_strtoul(s, NULL, 10); while (*s >= '0' && *s <= '9') - s++; + s++; if (*s) - *parity = *s++; + *parity = *s++; if (*s) - *bits = *s++ - '0'; + *bits = *s++ - '0'; if (*s) - *flow = *s; + *flow = *s; } /** - * uart_set_options - setup the serial console parameters - * @port: pointer to the serial ports uart_port structure - * @co: console pointer - * @baud: baud rate - * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) - * @bits: number of data bits - * @flow: flow control character - 'r' (rts) - */ +* uart_set_options - setup the serial console parameters +* @port: pointer to the serial ports uart_port structure +* @co: console pointer +* @baud: baud rate +* @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) +* @bits: number of data bits +* @flow: flow control character - 'r' (rts) +*/ int __init uart_set_options(struct uart_port *port, struct console *co, - int baud, int parity, int bits, int flow) +int baud, int parity, int bits, int flow) { u_int cflag = CREAD | HUPCL | CLOCAL; u_int quot; /* - * Construct a cflag setting. - */ + * Construct a cflag setting. + */ switch (baud) { case 1200: cflag |= B1200; break; case 2400: cflag |= B2400; break; @@ -1707,9 +1705,9 @@ uart_set_options(struct uart_port *port, struct console *co, } if (bits == 7) - cflag |= CS7; + cflag |= CS7; else - cflag |= CS8; + cflag |= CS8; switch (parity) { case 'o': case 'O': @@ -1735,8 +1733,8 @@ extern void sa1100_rs_console_init(void); extern void serial8250_console_init(void); /* - * Central "initialise all serial consoles" container. Needs to be killed. - */ +* Central "initialise all serial consoles" container. Needs to be killed. +*/ void __init uart_console_init(void) { #ifdef CONFIG_SERIAL_AMBA_CONSOLE @@ -1765,28 +1763,28 @@ void __init uart_console_init(void) #ifdef CONFIG_PM /* - * Serial port power management. - * - * This is pretty coarse at the moment - either all on or all off. We - * should probably some day do finer power management here some day. - * - * We don't actually save any state; the serial driver has enough - * state held internally to re-setup the port when we come out of D3. - */ +* Serial port power management. +* +* This is pretty coarse at the moment - either all on or all off. We +* should probably some day do finer power management here some day. +* +* We don't actually save any state; the serial driver has enough +* state held internally to re-setup the port when we come out of D3. +*/ static int uart_pm_set_state(struct uart_state *state, int pm_state, int oldstate) { struct uart_port *port = state->port; struct uart_ops *ops = port->ops; int running = state->info && - state->info->flags & ASYNC_INITIALIZED; + state->info->flags & ASYNC_INITIALIZED; if (port->type == PORT_UNKNOWN) - return 0; + return 0; -//printk("pm: %08x: %d -> %d, %srunning\n", port->iobase, dev->state, pm_state, running ? "" : "not "); + //printk("pm: %08x: %d -> %d, %srunning\n", port->iobase, dev->state, pm_state, running ? "" : "not "); if (pm_state == 0) { if (ops->pm) - ops->pm(port, pm_state, oldstate); + ops->pm(port, pm_state, oldstate); if (running) { ops->set_mctrl(port, 0); ops->startup(port, state->info); @@ -1796,19 +1794,19 @@ static int uart_pm_set_state(struct uart_state *state, int pm_state, int oldstat } /* - * Re-enable the console device after suspending. - */ + * Re-enable the console device after suspending. + */ if (state->cons && state->cons->index == port->line) - state->cons->flags |= CON_ENABLED; + state->cons->flags |= CON_ENABLED; } else if (pm_state == 1) { if (ops->pm) - ops->pm(port, pm_state, oldstate); + ops->pm(port, pm_state, oldstate); } else { /* - * Disable the console device before suspending. - */ + * Disable the console device before suspending. + */ if (state->cons && state->cons->index == port->line) - state->cons->flags &= ~CON_ENABLED; + state->cons->flags &= ~CON_ENABLED; if (running) { ops->stop_tx(port, 0); @@ -1817,20 +1815,20 @@ static int uart_pm_set_state(struct uart_state *state, int pm_state, int oldstat ops->shutdown(port, state->info); } if (ops->pm) - ops->pm(port, pm_state, oldstate); + ops->pm(port, pm_state, oldstate); } return 0; } /* - * Wakeup support. - */ +* Wakeup support. +*/ static int uart_pm_set_wakeup(struct uart_state *state, int data) { int err = 0; if (state->port->ops->set_wake) - err = state->port->ops->set_wake(state->port, data); + err = state->port->ops->set_wake(state->port, data); return err; } @@ -1871,73 +1869,73 @@ uart_setup_port(struct uart_driver *drv, struct uart_state *state) state->cons = drv->cons; state->pm = pm_register(PM_SYS_DEV, PM_SYS_COM, uart_pm); if (state->pm) - state->pm->data = state; + state->pm->data = state; #endif /* - * If there isn't a port here, don't do anything further. - */ + * If there isn't a port here, don't do anything further. + */ if (!port->iobase && !port->mapbase) - return; + return; /* - * Now do the auto configuration stuff. Note that config_port - * is expected to claim the resources and map the port for us. - */ + * Now do the auto configuration stuff. Note that config_port + * is expected to claim the resources and map the port for us. + */ if (port->flags & ASYNC_AUTO_IRQ) - flags |= UART_CONFIG_IRQ; + flags |= UART_CONFIG_IRQ; if (port->flags & ASYNC_BOOT_AUTOCONF) - port->ops->config_port(port, flags); + port->ops->config_port(port, flags); /* - * Only register this port if it is detected. - */ + * Only register this port if it is detected. + */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (port->type != PORT_UNKNOWN) { tty_register_devfs(drv->normal_driver, 0, drv->minor + - state->port->line); + state->port->line); tty_register_devfs(drv->callout_driver, 0, drv->minor + - state->port->line); + state->port->line); } #endif #ifdef CONFIG_PM /* - * Power down all ports by default, except the console if we have one. - */ + * Power down all ports by default, except the console if we have one. + */ if (state->pm && (!drv->cons || port->line != drv->cons->index)) - pm_send(state->pm, PM_SUSPEND, (void *)3); + pm_send(state->pm, PM_SUSPEND, (void *)3); #endif return; } /* - * Register a set of ports with the core driver. Note that we don't - * printk any information about the ports; that is up to the low level - * driver to do if they so wish. - */ +* Register a set of ports with the core driver. Note that we don't +* printk any information about the ports; that is up to the low level +* driver to do if they so wish. +*/ SERIALCORE_EXPORT int uart_register_driver(struct uart_driver *drv) { struct tty_driver *normal, *callout; int i, retval; if (drv->state) - panic("drv->state already allocated\n"); + panic("drv->state already allocated\n"); /* - * Maybe we should be using a slab cache for this, especially if - * we have a large number of ports to handle. Note that we also - * allocate space for an integer for reference counting. - */ + * Maybe we should be using a slab cache for this, especially if + * we have a large number of ports to handle. Note that we also + * allocate space for an integer for reference counting. + */ drv->state = kmalloc(sizeof(struct uart_state) * drv->nr + - sizeof(int), GFP_KERNEL); + sizeof(int), GFP_KERNEL); retval = -ENOMEM; if (!drv->state) - goto out; + goto out; memset(drv->state, 0, sizeof(struct uart_state) * drv->nr + - sizeof(int)); + sizeof(int)); normal = drv->normal_driver; callout = drv->callout_driver; @@ -1989,9 +1987,9 @@ SERIALCORE_EXPORT int uart_register_driver(struct uart_driver *drv) #endif /* - * The callout device is just like the normal device except for - * the major number and the subtype code. - */ + * The callout device is just like the normal device except for + * the major number and the subtype code. + */ *callout = *normal; callout->name = drv->callout_name; callout->major = drv->callout_major; @@ -2012,15 +2010,15 @@ SERIALCORE_EXPORT int uart_register_driver(struct uart_driver *drv) retval = tty_register_driver(normal); if (retval) - goto out; + goto out; retval = tty_register_driver(callout); if (retval) - tty_unregister_driver(normal); + tty_unregister_driver(normal); out: if (retval && drv->state) - kfree(drv->state); + kfree(drv->state); return retval; } @@ -2032,12 +2030,12 @@ SERIALCORE_EXPORT void uart_unregister_driver(struct uart_driver *drv) struct uart_state *state = drv->state + i; if (state->info && state->info->tty) - tty_hangup(state->info->tty); + tty_hangup(state->info->tty); pm_unregister(state->pm); if (state->port->type != PORT_UNKNOWN) - state->port->ops->release_port(state->port); + state->port->ops->release_port(state->port); if (state->info) { tasklet_kill(&state->info->tlet); kfree(state->info); @@ -2053,7 +2051,7 @@ SERIALCORE_EXPORT void uart_unregister_driver(struct uart_driver *drv) static int uart_match_port(struct uart_port *port1, struct uart_port *port2) { if (port1->iotype != port2->iotype) - return 0; + return 0; switch (port1->iotype) { case SERIAL_IO_PORT: return (port1->iobase == port2->iobase); case SERIAL_IO_MEM: return (port1->membase == port2->membase); @@ -2061,22 +2059,21 @@ static int uart_match_port(struct uart_port *port1, struct uart_port *port2) return 0; } -static inline void -uart_report_port(struct uart_driver *drv, struct uart_port *port) +static inline void uart_report_port(struct uart_driver *drv, struct uart_port *port) { - if(strchr(drv->normal_name, '%')) + if(strchr(drv->normal_name, '%')) printk(drv->normal_name, port->line); else printk("%s%d", drv->normal_name, port->line); if(port->iobase || port->mapbase || port->irq) { printk(" at "); switch (port->iotype) { - case SERIAL_IO_PORT: - printk("I/O 0x%x", port->iobase); - break; - case SERIAL_IO_MEM: - printk("MMIO 0x%lx", port->mapbase); - break; + case SERIAL_IO_PORT: + printk("I/O 0x%x", port->iobase); + break; + case SERIAL_IO_MEM: + printk("MMIO 0x%lx", port->mapbase); + break; } printk(" (irq = %d)", port->irq); } @@ -2084,26 +2081,26 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) } /** - * uart_register_port: register a port with the generic uart driver - * @reg: pointer to the uart low level driver structure for this port - * @port: uart port structure describing the port - * - * Register a UART with the specified low level driver. Detect the - * type of the port if ASYNC_BOOT_AUTOCONF is set, and detect the IRQ - * if ASYNC_AUTO_IRQ is set. - * - * Returns negative error, or positive line number. - */ +* uart_register_port: register a port with the generic uart driver +* @reg: pointer to the uart low level driver structure for this port +* @port: uart port structure describing the port +* +* Register a UART with the specified low level driver. Detect the +* type of the port if ASYNC_BOOT_AUTOCONF is set, and detect the IRQ +* if ASYNC_AUTO_IRQ is set. +* +* Returns negative error, or positive line number. +*/ SERIALCORE_EXPORT int uart_register_port(struct uart_driver *drv, struct uart_port *port) { struct uart_state *state = NULL; int i, flags = UART_CONFIG_TYPE; /* - * First, find a port entry which matches. Note: if we do - * find a matching entry, and it has a non-zero use count, - * then we can't register the port. - */ + * First, find a port entry which matches. Note: if we do + * find a matching entry, and it has a non-zero use count, + * then we can't register the port. + */ down(&port_sem); for (i = 0; i < drv->nr; i++) { if (uart_match_port(drv->state[i].port, port)) { @@ -2114,14 +2111,14 @@ SERIALCORE_EXPORT int uart_register_port(struct uart_driver *drv, struct uart_po } /* - * If we didn't find a matching entry, look for the first - * free entry. We look for one which hasn't been previously - * used (indicated by zero iobase). - */ + * If we didn't find a matching entry, look for the first + * free entry. We look for one which hasn't been previously + * used (indicated by zero iobase). + */ if (!state) { for (i = 0; i < drv->nr; i++) { if (drv->state[i].port->type == PORT_UNKNOWN && - drv->state[i].port->iobase == 0) { + drv->state[i].port->iobase == 0) { down(&drv->state[i].count_sem); if (drv->state[i].count == 0) { state = &drv->state[i]; @@ -2132,9 +2129,9 @@ SERIALCORE_EXPORT int uart_register_port(struct uart_driver *drv, struct uart_po } /* - * Ok, that also failed. Find the first unused entry, which - * may be previously in use. - */ + * Ok, that also failed. Find the first unused entry, which + * may be previously in use. + */ if (!state) { for (i = 0; i < drv->nr; i++) { if (drv->state[i].port->type == PORT_UNKNOWN) { @@ -2153,21 +2150,21 @@ SERIALCORE_EXPORT int uart_register_port(struct uart_driver *drv, struct uart_po return -ENOSPC; /* - * If we find a port that matches this one, and it appears to - * be in-use (even if it doesn't have a type) we shouldn't alter - * it underneath itself - the port may be open and trying to do - * useful work. - */ + * If we find a port that matches this one, and it appears to + * be in-use (even if it doesn't have a type) we shouldn't alter + * it underneath itself - the port may be open and trying to do + * useful work. + */ if (state->count != 0 || - (state->info && state->info->blocked_open != 0)) { + (state->info && state->info->blocked_open != 0)) { up(&state->count_sem); return -EBUSY; } /* - * We're holding the lock for this port. Copy the relevant data - * into the port structure. - */ + * We're holding the lock for this port. Copy the relevant data + * into the port structure. + */ state->port->iobase = port->iobase; state->port->membase = port->membase; state->port->irq = port->irq; @@ -2184,24 +2181,24 @@ SERIALCORE_EXPORT int uart_register_port(struct uart_driver *drv, struct uart_po state->pm->data = state; /* - * Power down all ports by default, except - * the console if we have one. - */ + * Power down all ports by default, except + * the console if we have one. + */ if (!drv->cons || state->port->line != drv->cons->index) pm_send(state->pm, PM_SUSPEND, (void *)3); } #endif if (state->port->flags & ASYNC_AUTO_IRQ) - flags |= UART_CONFIG_IRQ; + flags |= UART_CONFIG_IRQ; if (state->port->flags & ASYNC_BOOT_AUTOCONF) - state->port->ops->config_port(state->port, flags); + state->port->ops->config_port(state->port, flags); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) tty_register_devfs(drv->normal_driver, 0, drv->minor + - state->port->line); + state->port->line); tty_register_devfs(drv->callout_driver, 0, drv->minor + - state->port->line); + state->port->line); #endif uart_report_port(drv, state->port); @@ -2211,15 +2208,15 @@ SERIALCORE_EXPORT int uart_register_port(struct uart_driver *drv, struct uart_po } /* - * Unregister the specified port index on the specified driver. - */ +* Unregister the specified port index on the specified driver. +*/ SERIALCORE_EXPORT void uart_unregister_port(struct uart_driver *drv, int line) { struct uart_state *state; if (line < 0 || line >= drv->nr) { printk(KERN_ERR "Attempt to unregister %s%d\n", - drv->normal_name, line); + drv->normal_name, line); return; } @@ -2227,33 +2224,33 @@ SERIALCORE_EXPORT void uart_unregister_port(struct uart_driver *drv, int line) down(&state->count_sem); /* - * The port has already gone. We have to hang up the line - * to kill all usage of this port. - */ + * The port has already gone. We have to hang up the line + * to kill all usage of this port. + */ if (state->info && state->info->tty) - tty_hangup(state->info->tty); + tty_hangup(state->info->tty); /* - * Free the ports resources, if any. - */ + * Free the ports resources, if any. + */ state->port->ops->release_port(state->port); /* - * Indicate that there isn't a port here anymore. - */ + * Indicate that there isn't a port here anymore. + */ state->port->type = PORT_UNKNOWN; #if 0 // not yet /* - * No point in doing power management for hardware that - * isn't present. - */ + * No point in doing power management for hardware that + * isn't present. + */ pm_unregister(state->pm); #endif /* - * Remove the devices from devfs - */ + * Remove the devices from devfs + */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) tty_unregister_devfs(drv->normal_driver, drv->minor + line); tty_unregister_devfs(drv->callout_driver, drv->minor + line); diff --git a/modules/GPL/serial_core.h b/modules/GPL/serial_core.h old mode 100644 new mode 100755 diff --git a/modules/Makefile b/modules/Makefile index 73669a2..d4862f6 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -53,7 +53,7 @@ DEBIAN_SYSTEM := $(shell test -f /etc/debian_version && echo yes || echo no) ifneq ($(KERNELSRC_EXISTS),yes) ifeq ($(DEBIAN_SYSTEM),yes) -CNXT_KERNELSRC := /usr/src/kernel-headers-$(shell uname -r) +CNXT_KERNELSRC := /usr/src/linux-headers-$(shell uname -r) else CNXT_KERNELSRC := /usr/src/linux endif @@ -87,11 +87,11 @@ KERNELARCH := $(subst i386,x86,$(subst x86_64,x86,$(IMPORTED_ARCH))) # Starting 2.6.28, most include/asm headers were moved to arch//include/asm REAL_KERNELSRC_INCLUDE_ASM := $(shell for p in $(CNXT_KERNELSRC)/include2/asm $(REAL_KERNELSRC)/arch/$(KERNELARCH)/include/asm; do if test -e $${p}; then echo $${p}; exit 0; fi; done; for p in arch/$(KERNELARCH)/include/asm include/asm; do if test -e $(CNXT_KERNELSRC)/$${p}; then echo $(REAL_KERNELSRC)/$${p}; exit 0; fi; done;) -ifeq ($(CNXTTARGET),hsf) +#ifeq ($(CNXTTARGET),hsf) REPLACE_HDA := true -else -REPLACE_HDA := false -endif +#else +#REPLACE_HDA := false +#endif # Configure compiler (on some systems, kgcc must be used to compile kernel code) # @@ -159,7 +159,7 @@ ifeq ($(ON_BUILD_SYSTEM)-$(CONFIG_SND_HDA_INTEL),no-) CONFIG_SND_HDA_INTEL=$(shell modprobe -n snd-hda-intel > /dev/null 2>&1 && echo y || echo n) endif -MODULAR_HDA := $(shell test -e ${REAL_KERNELSRC}/include/sound/hda_codec.h && echo yes || echo no) +#MODULAR_HDA := $(shell test -e ${REAL_KERNELSRC}/include/sound/hda_codec.h && echo yes || echo no) else KO= o diff --git a/modules/cdbgscr.c b/modules/cdbgscr.c old mode 100644 new mode 100755 diff --git a/modules/cnxthw_common.c b/modules/cnxthw_common.c old mode 100644 new mode 100755 diff --git a/modules/cnxthwhda_common.c b/modules/cnxthwhda_common.c old mode 100644 new mode 100755 index 089a8ef..575f269 --- a/modules/cnxthwhda_common.c +++ b/modules/cnxthwhda_common.c @@ -124,7 +124,7 @@ static int cnxthwhda_setsyms (void **ppInterfaceFuncs); snprintf(pDevNode->hwInstName, sizeof(pDevNode->hwInstName), "HDA-%08x:%08x-%u", OsHdaCodecGetVendorId(pHdaOsHal), OsHdaCodecGetSubsystemId(pHdaOsHal), OsHdaCodecGetAddr(pHdaOsHal)); pDevNode->hwType = CNXTHWHDA_TYPE; - pDevNode->hwIf = GetHwFuncs(); + // pDevNode->hwIf = GetHwFuncs(); pDevNode->pmControl = cnxthw_DevMgrPMControl; pDevNode->osPageOffset = PAGE_OFFSET; diff --git a/modules/cnxthwpci_common.c b/modules/cnxthwpci_common.c index c90079b..8e9a8b8 100644 --- a/modules/cnxthwpci_common.c +++ b/modules/cnxthwpci_common.c @@ -83,7 +83,7 @@ static int __devinit cnxthwpci_probe (struct pci_dev *pdev, pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); #ifdef CNXTHWPCI_TYPE pDevNode->hwType = CNXTHWPCI_TYPE; - pDevNode->hwIf = GetHwFuncs(); + // pDevNode->hwIf = GetHwFuncs(); #endif pDevNode->pmControl = cnxthw_DevMgrPMControl; pDevNode->osPageOffset = PAGE_OFFSET; diff --git a/modules/cnxthwusb_common.c b/modules/cnxthwusb_common.c old mode 100644 new mode 100755 index 41c1f0a..5385ee0 --- a/modules/cnxthwusb_common.c +++ b/modules/cnxthwusb_common.c @@ -326,7 +326,7 @@ static int __devinit cnxthwusb_probe(struct usb_interface *intf, USB_BYTEORDER16(pUsbDevice->descriptor.idVendor), USB_BYTEORDER16(pUsbDevice->descriptor.idProduct)); #ifdef CNXTHWUSB_TYPE pDevNode->hwType = CNXTHWUSB_TYPE; - pDevNode->hwIf = GetHwFuncs(); + // pDevNode->hwIf = GetHwFuncs(); #endif pDevNode->pmControl = cnxthw_DevMgrPMControl; pDevNode->osPageOffset = PAGE_OFFSET; diff --git a/modules/hsfengine.mod.c b/modules/hsfengine.mod.c new file mode 100644 index 0000000..af17ca0 --- /dev/null +++ b/modules/hsfengine.mod.c @@ -0,0 +1,85 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +__visible struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = KBUILD_MODNAME, + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif + .arch = MODULE_ARCH_INIT, +}; + +#ifdef RETPOLINE +MODULE_INFO(retpoline, "Y"); +#endif + +static const struct modversion_info ____versions[] +__used +__attribute__((section("__versions"))) = { + { 0x525b86d, __VMLINUX_SYMBOL_STR(module_layout) }, + { 0xe9177b3e, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsFloatPrefix) }, + { 0x58245be, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionRelease) }, + { 0xd848e610, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsLockLock) }, + { 0x9b1c69f9, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_DcpCallback) }, + { 0xdcc0ee56, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionDestroy) }, + { 0xe7910696, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsSprintf) }, + { 0x55753fd0, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_DcpSetVolume) }, + { 0x592eb97d, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsLockUnlock) }, + { 0x533191a, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsAllocate) }, + { 0xd3451df, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsAtomicDecrement) }, + { 0xbadd8acb, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsStrCpy) }, + { 0x45a5147e, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsImmediateTimeOut) }, + { 0x3bb8c2b7, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCreatePeriodicTimer) }, + { 0xabe9e472, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_NVM_Write) }, + { 0x905c025, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsLockDestroy) }, + { 0xff355e29, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMemCmp) }, + { 0x9768ea27, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsFloatSuffix) }, + { 0xbb371505, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsDiagMgrClose) }, + { 0x9cb7b003, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsDebugBreakpoint) }, + { 0xa1120b8a, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsAtomicIncrement) }, + { 0x7fd0ac65, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsDiagMgrNotify) }, + { 0xa31d862, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsLockCreate) }, + { 0xae0c6a09, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsToupper) }, + { 0x3a39cf66, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsIsDigit) }, + { 0xe03abc15, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMemCpy) }, + { 0xe454aa4a, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_NVM_Open) }, + { 0xd52ba08d, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsAtomicAdd) }, + { 0xc51f9205, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionCreate) }, + { 0x19b154ab, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsGetCurrentThread) }, + { 0x5f5dbae8, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionAcquire) }, + { 0x9530d4f7, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsSleep) }, + { 0xd432de77, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsLockTryUnlock) }, + { 0x22e421f, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMemSet) }, + { 0x89ff00c2, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsGetProcessorFreq) }, + { 0x497eb461, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsDestroyPeriodicTimer) }, + { 0x896eaab5, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsAtomicCompareAndSwapEx) }, + { 0x85c65ce8, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_NVM_Read) }, + { 0x6817e1dc, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMemDMAAllocate) }, + { 0x6199c803, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMemDMAFree) }, + { 0xd6e3cb08, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsFree) }, + { 0x680e0682, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_DcpCreate) }, + { 0xf696d723, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsDiagMgrOpen) }, + { 0x22f34e04, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsErrorPrintf) }, + { 0xfeecb909, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_NVM_Close) }, + { 0xcfa2536a, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsStrCmp) }, + { 0xa025acfb, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsGetSystemTime) }, + { 0xf425b003, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsReadCpuCnt) }, + { 0xe925defe, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsStrnCpy) }, + { 0x9202a2ee, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsStrLen) }, + { 0x3901fa46, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsSetPeriodicTimer) }, + { 0x8dd530ee, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsDebugPrintf) }, + { 0xa3cded78, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_DcpDestroy) }, + { 0x95017331, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMemMove) }, + { 0x7fd1656, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsLockTry) }, +}; + +static const char __module_depends[] +__used +__attribute__((section(".modinfo"))) = +"depends=hsfosspec"; + diff --git a/modules/hsfosspec.mod.c b/modules/hsfosspec.mod.c new file mode 100644 index 0000000..5f3048f --- /dev/null +++ b/modules/hsfosspec.mod.c @@ -0,0 +1,146 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +__visible struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = KBUILD_MODNAME, + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif + .arch = MODULE_ARCH_INIT, +}; + +#ifdef RETPOLINE +MODULE_INFO(retpoline, "Y"); +#endif + +static const struct modversion_info ____versions[] +__used +__attribute__((section("__versions"))) = { + { 0x525b86d, __VMLINUX_SYMBOL_STR(module_layout) }, + { 0x6bc3fbc0, __VMLINUX_SYMBOL_STR(__unregister_chrdev) }, + { 0xbdc6b187, __VMLINUX_SYMBOL_STR(cpu_tss) }, + { 0x6dc7dc1e, __VMLINUX_SYMBOL_STR(kmalloc_caches) }, + { 0xdb7a59e, __VMLINUX_SYMBOL_STR(pci_bus_read_config_byte) }, + { 0xd2b09ce5, __VMLINUX_SYMBOL_STR(__kmalloc) }, + { 0xd6ee688f, __VMLINUX_SYMBOL_STR(vmalloc) }, + { 0x6bf1c17f, __VMLINUX_SYMBOL_STR(pv_lock_ops) }, + { 0xfa8b9545, __VMLINUX_SYMBOL_STR(param_ops_int) }, + { 0x6c09c2a4, __VMLINUX_SYMBOL_STR(del_timer) }, + { 0x754d539c, __VMLINUX_SYMBOL_STR(strlen) }, + { 0x8526c35a, __VMLINUX_SYMBOL_STR(remove_wait_queue) }, + { 0xe051d495, __VMLINUX_SYMBOL_STR(commit_creds) }, + { 0x20000329, __VMLINUX_SYMBOL_STR(simple_strtoul) }, + { 0xd703e431, __VMLINUX_SYMBOL_STR(touch_atime) }, + { 0xad668572, __VMLINUX_SYMBOL_STR(usb_kill_urb) }, + { 0x9760bdd0, __VMLINUX_SYMBOL_STR(device_destroy) }, + { 0xc6587ef2, __VMLINUX_SYMBOL_STR(__register_chrdev) }, + { 0xc29957c3, __VMLINUX_SYMBOL_STR(__x86_indirect_thunk_rcx) }, + { 0xb78d1c44, __VMLINUX_SYMBOL_STR(filp_close) }, + { 0xeae3dfd6, __VMLINUX_SYMBOL_STR(__const_udelay) }, + { 0x9580deb, __VMLINUX_SYMBOL_STR(init_timer_key) }, + { 0x999e8297, __VMLINUX_SYMBOL_STR(vfree) }, + { 0x4994f39f, __VMLINUX_SYMBOL_STR(pci_bus_write_config_word) }, + { 0x4629334c, __VMLINUX_SYMBOL_STR(__preempt_count) }, + { 0x7a2af7b4, __VMLINUX_SYMBOL_STR(cpu_number) }, + { 0x91715312, __VMLINUX_SYMBOL_STR(sprintf) }, + { 0x751691e1, __VMLINUX_SYMBOL_STR(usb_unlink_urb) }, + { 0xc29e1ca7, __VMLINUX_SYMBOL_STR(kthread_create_on_node) }, + { 0x15ba50a6, __VMLINUX_SYMBOL_STR(jiffies) }, + { 0xe2d5255a, __VMLINUX_SYMBOL_STR(strcmp) }, + { 0x9e88526, __VMLINUX_SYMBOL_STR(__init_waitqueue_head) }, + { 0x4f8b5ddb, __VMLINUX_SYMBOL_STR(_copy_to_user) }, + { 0xffd5a395, __VMLINUX_SYMBOL_STR(default_wake_function) }, + { 0x6561d1e6, __VMLINUX_SYMBOL_STR(pci_set_master) }, + { 0x35b97bc1, __VMLINUX_SYMBOL_STR(vfs_read) }, + { 0x706d051c, __VMLINUX_SYMBOL_STR(del_timer_sync) }, + { 0xfb578fc5, __VMLINUX_SYMBOL_STR(memset) }, + { 0x4c936d5d, __VMLINUX_SYMBOL_STR(default_llseek) }, + { 0x11089ac7, __VMLINUX_SYMBOL_STR(_ctype) }, + { 0x1916e38c, __VMLINUX_SYMBOL_STR(_raw_spin_unlock_irqrestore) }, + { 0xff4155a, __VMLINUX_SYMBOL_STR(current_task) }, + { 0x2e2b40d2, __VMLINUX_SYMBOL_STR(strncat) }, + { 0x156a8a59, __VMLINUX_SYMBOL_STR(down_trylock) }, + { 0x27e1a049, __VMLINUX_SYMBOL_STR(printk) }, + { 0x1250c7e1, __VMLINUX_SYMBOL_STR(_raw_spin_trylock) }, + { 0xf674ec4f, __VMLINUX_SYMBOL_STR(kthread_stop) }, + { 0x449ad0a7, __VMLINUX_SYMBOL_STR(memcmp) }, + { 0x2fbd4990, __VMLINUX_SYMBOL_STR(__init_kthread_worker) }, + { 0x4c9d28b0, __VMLINUX_SYMBOL_STR(phys_base) }, + { 0x9166fada, __VMLINUX_SYMBOL_STR(strncpy) }, + { 0xf7a8151c, __VMLINUX_SYMBOL_STR(fasync_helper) }, + { 0x87d7f43, __VMLINUX_SYMBOL_STR(usb_control_msg) }, + { 0x5a921311, __VMLINUX_SYMBOL_STR(strncmp) }, + { 0x88c87ec6, __VMLINUX_SYMBOL_STR(pci_bus_write_config_dword) }, + { 0x6dc6dd56, __VMLINUX_SYMBOL_STR(down) }, + { 0x320a4d5f, __VMLINUX_SYMBOL_STR(device_create) }, + { 0xc5fdef94, __VMLINUX_SYMBOL_STR(call_usermodehelper) }, + { 0x16e5c2a, __VMLINUX_SYMBOL_STR(mod_timer) }, + { 0x1bb31047, __VMLINUX_SYMBOL_STR(add_timer) }, + { 0x2072ee9b, __VMLINUX_SYMBOL_STR(request_threaded_irq) }, + { 0x955b0e2e, __VMLINUX_SYMBOL_STR(kthread_worker_fn) }, + { 0x8e179160, __VMLINUX_SYMBOL_STR(prepare_creds) }, + { 0x61651be, __VMLINUX_SYMBOL_STR(strcat) }, + { 0x52df39b9, __VMLINUX_SYMBOL_STR(queue_kthread_work) }, + { 0xfd37ed40, __VMLINUX_SYMBOL_STR(module_put) }, + { 0xc52b00cd, __VMLINUX_SYMBOL_STR(usb_submit_urb) }, + { 0x78764f4e, __VMLINUX_SYMBOL_STR(pv_irq_ops) }, + { 0xb601be4c, __VMLINUX_SYMBOL_STR(__x86_indirect_thunk_rdx) }, + { 0x42c8de35, __VMLINUX_SYMBOL_STR(ioremap_nocache) }, + { 0xd6b33026, __VMLINUX_SYMBOL_STR(cpu_khz) }, + { 0xe1527253, __VMLINUX_SYMBOL_STR(pci_bus_read_config_word) }, + { 0x242e722e, __VMLINUX_SYMBOL_STR(make_kuid) }, + { 0x29dfb10, __VMLINUX_SYMBOL_STR(pci_bus_read_config_dword) }, + { 0x93fca811, __VMLINUX_SYMBOL_STR(__get_free_pages) }, + { 0xdb7305a1, __VMLINUX_SYMBOL_STR(__stack_chk_fail) }, + { 0xd9fd1983, __VMLINUX_SYMBOL_STR(usb_reset_device) }, + { 0xd62c833f, __VMLINUX_SYMBOL_STR(schedule_timeout) }, + { 0x1000e51, __VMLINUX_SYMBOL_STR(schedule) }, + { 0xa202a8e5, __VMLINUX_SYMBOL_STR(kmalloc_order_trace) }, + { 0x3ab4437b, __VMLINUX_SYMBOL_STR(usb_clear_halt) }, + { 0x8a7d1c31, __VMLINUX_SYMBOL_STR(high_memory) }, + { 0x6b2dc060, __VMLINUX_SYMBOL_STR(dump_stack) }, + { 0x2ea2c95c, __VMLINUX_SYMBOL_STR(__x86_indirect_thunk_rax) }, + { 0xaf0c3cb7, __VMLINUX_SYMBOL_STR(pv_cpu_ops) }, + { 0x614e8e2f, __VMLINUX_SYMBOL_STR(wake_up_process) }, + { 0xbdfb6dbb, __VMLINUX_SYMBOL_STR(__fentry__) }, + { 0x26932b93, __VMLINUX_SYMBOL_STR(kmem_cache_alloc_trace) }, + { 0xe259ae9e, __VMLINUX_SYMBOL_STR(_raw_spin_lock) }, + { 0x680ec266, __VMLINUX_SYMBOL_STR(_raw_spin_lock_irqsave) }, + { 0x99195078, __VMLINUX_SYMBOL_STR(vsnprintf) }, + { 0x4302d0eb, __VMLINUX_SYMBOL_STR(free_pages) }, + { 0x39da63dd, __VMLINUX_SYMBOL_STR(sched_setscheduler) }, + { 0xa6bbd805, __VMLINUX_SYMBOL_STR(__wake_up) }, + { 0x4f68e5c9, __VMLINUX_SYMBOL_STR(do_gettimeofday) }, + { 0x4482e496, __VMLINUX_SYMBOL_STR(pci_bus_write_config_byte) }, + { 0xc9fef317, __VMLINUX_SYMBOL_STR(add_wait_queue) }, + { 0x37a0cba, __VMLINUX_SYMBOL_STR(kfree) }, + { 0x69acdf38, __VMLINUX_SYMBOL_STR(memcpy) }, + { 0xedc03953, __VMLINUX_SYMBOL_STR(iounmap) }, + { 0x78e739aa, __VMLINUX_SYMBOL_STR(up) }, + { 0xeb9c2039, __VMLINUX_SYMBOL_STR(class_destroy) }, + { 0xc07d6f86, __VMLINUX_SYMBOL_STR(kill_fasync) }, + { 0x28318305, __VMLINUX_SYMBOL_STR(snprintf) }, + { 0xb0e602eb, __VMLINUX_SYMBOL_STR(memmove) }, + { 0xb587ca13, __VMLINUX_SYMBOL_STR(__class_create) }, + { 0x2482e688, __VMLINUX_SYMBOL_STR(vsprintf) }, + { 0x612a7e40, __VMLINUX_SYMBOL_STR(usb_free_urb) }, + { 0xc993bd44, __VMLINUX_SYMBOL_STR(try_module_get) }, + { 0x90bd7de2, __VMLINUX_SYMBOL_STR(vfs_write) }, + { 0x828011de, __VMLINUX_SYMBOL_STR(usb_alloc_urb) }, + { 0xf20dabd8, __VMLINUX_SYMBOL_STR(free_irq) }, + { 0xe914e41e, __VMLINUX_SYMBOL_STR(strcpy) }, + { 0x4874bcd7, __VMLINUX_SYMBOL_STR(filp_open) }, +}; + +static const char __module_depends[] +__used +__attribute__((section(".modinfo"))) = +"depends="; + + +MODULE_INFO(srcversion, "88BF5A7AC7AE150D6DF6507"); diff --git a/modules/hsfpcibasic2.mod.c b/modules/hsfpcibasic2.mod.c new file mode 100644 index 0000000..9ef259e --- /dev/null +++ b/modules/hsfpcibasic2.mod.c @@ -0,0 +1,192 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +__visible struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = KBUILD_MODNAME, + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif + .arch = MODULE_ARCH_INIT, +}; + +#ifdef RETPOLINE +MODULE_INFO(retpoline, "Y"); +#endif + +static const struct modversion_info ____versions[] +__used +__attribute__((section("__versions"))) = { + { 0x525b86d, __VMLINUX_SYMBOL_STR(module_layout) }, + { 0x6dc7dc1e, __VMLINUX_SYMBOL_STR(kmalloc_caches) }, + { 0x743241d, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsKernelUsesRegParm) }, + { 0xabe71b05, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCreateTimer) }, + { 0xbca036b7, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsIoMemReadl) }, + { 0xcd7bf981, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsEventCreate) }, + { 0x90b92d37, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciWriteConfigdw) }, + { 0x58245be, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionRelease) }, + { 0xfa9b3e79, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciReadConfigb) }, + { 0xf83d11b6, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciWriteConfigb) }, + { 0x388af6e7, __VMLINUX_SYMBOL_STR(device_release_driver) }, + { 0xdcc0ee56, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionDestroy) }, + { 0x263ed23b, __VMLINUX_SYMBOL_STR(__x86_indirect_thunk_r12) }, + { 0xe7910696, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsSprintf) }, + { 0x38e0a235, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciReadConfigw) }, + { 0xd1af0c61, __VMLINUX_SYMBOL_STR(pci_disable_device) }, + { 0xe5d6603e, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsUnhookInterrupt) }, + { 0xf76c8370, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciReadConfigdw) }, + { 0x7cac7b6, __VMLINUX_SYMBOL_STR(pci_release_regions) }, + { 0x533191a, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsAllocate) }, + { 0x8917329d, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsGetPCIDeviceResources) }, + { 0xe2d5255a, __VMLINUX_SYMBOL_STR(strcmp) }, + { 0x8c79c47e, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_GetSOARLibInterface) }, + { 0xe9985f40, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCancelTimer) }, + { 0x494b582c, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_ComCtrl_Control) }, + { 0xfb578fc5, __VMLINUX_SYMBOL_STR(memset) }, + { 0x101af182, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsIoMemWriteb) }, + { 0xc0620d74, __VMLINUX_SYMBOL_STR(pci_restore_state) }, + { 0x27e1a049, __VMLINUX_SYMBOL_STR(printk) }, + { 0x3cc05a0b, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_cnxt_serial_remove) }, + { 0x9166fada, __VMLINUX_SYMBOL_STR(strncpy) }, + { 0x49c8c662, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsIoMemWritel) }, + { 0x3c61a256, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsStrCat) }, + { 0xe287b7ab, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsUnmapPhysMem) }, + { 0xa022abf, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsEventDestroy) }, + { 0xe03abc15, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMemCpy) }, + { 0x820ab370, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsIoMemReadw) }, + { 0xc51f9205, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionCreate) }, + { 0xfd37ed40, __VMLINUX_SYMBOL_STR(module_put) }, + { 0x5f5dbae8, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionAcquire) }, + { 0x9530d4f7, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsSleep) }, + { 0x78ebe119, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsEventSet) }, + { 0x22e421f, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMemSet) }, + { 0x66e478fa, __VMLINUX_SYMBOL_STR(put_device) }, + { 0x2d293f3a, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsEventClear) }, + { 0x89ff00c2, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsGetProcessorFreq) }, + { 0x3d4fb7e, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsChangeTimerTimeOut) }, + { 0xbdfb6dbb, __VMLINUX_SYMBOL_STR(__fentry__) }, + { 0x3d553bf, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsIoMemReadb) }, + { 0x9a7a7dc9, __VMLINUX_SYMBOL_STR(pci_unregister_driver) }, + { 0x26932b93, __VMLINUX_SYMBOL_STR(kmem_cache_alloc_trace) }, + { 0xb4c7d569, __VMLINUX_SYMBOL_STR(get_device) }, + { 0x8230168b, __VMLINUX_SYMBOL_STR(pci_set_power_state) }, + { 0x525227a5, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsHookInterrupt) }, + { 0xd6e3cb08, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsFree) }, + { 0x37a0cba, __VMLINUX_SYMBOL_STR(kfree) }, + { 0xc559022e, __VMLINUX_SYMBOL_STR(pci_request_regions) }, + { 0xdd98ff2f, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciWriteConfigw) }, + { 0xcd99bfeb, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsDestroyTimer) }, + { 0x89905baa, __VMLINUX_SYMBOL_STR(__pci_register_driver) }, + { 0x22f34e04, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsErrorPrintf) }, + { 0x36886337, __VMLINUX_SYMBOL_STR(pci_get_device) }, + { 0xb7efc090, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMapPhysMem) }, + { 0xf425b003, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsReadCpuCnt) }, + { 0x9202a2ee, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsStrLen) }, + { 0x28318305, __VMLINUX_SYMBOL_STR(snprintf) }, + { 0xab154510, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsEventWaitTime) }, + { 0x91a19aa1, __VMLINUX_SYMBOL_STR(pci_choose_state) }, + { 0x6e537fc3, __VMLINUX_SYMBOL_STR(pci_enable_device) }, + { 0x8e7b8953, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsSetTimer) }, + { 0x1456e13, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_cnxt_serial_add) }, + { 0xc993bd44, __VMLINUX_SYMBOL_STR(try_module_get) }, + { 0x8c8c9b26, __VMLINUX_SYMBOL_STR(pci_save_state) }, + { 0x8b082cfa, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsIoMemWritew) }, +}; + +static const char __module_depends[] +__used +__attribute__((section(".modinfo"))) = +"depends=hsfosspec,hsfsoar,hsfengine,hsfserial"; + +MODULE_ALIAS("pci:v0000127Ad00001023sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00001023sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00001024sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00001024sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00001025sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00001025sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00001026sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00001026sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00001085sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00001085sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00002003sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002003sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00002004sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002004sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00002005sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002005sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00002006sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002006sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00002013sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00002014sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00002015sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00002016sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00002114sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002013sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002014sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002015sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002016sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002043sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002044sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002045sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002046sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002063sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002064sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002065sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002066sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002093sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002143sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002144sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002145sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002146sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002163sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002164sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002165sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002166sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002343sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002344sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002345sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002346sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002363sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002364sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002365sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002366sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002443sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002444sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002445sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002446sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002463sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002464sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002465sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002466sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F00sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F01sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F02sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F03sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F04sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F10sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F11sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F12sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F13sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F14sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00004311sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000127Ad00004311sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002702sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002703sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002704sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002705sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F20sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F30sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F40sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F50sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d0000201Asv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d0000201Bsv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d0000204Asv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d0000204Bsv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000158Bd00000001sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v0000158Bd00000005sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000016ECd00002F00sv000016ECsd0000010Bbc*sc*i*"); +MODULE_ALIAS("pci:v000016ECd00002F00sv*sd*bc*sc*i*"); diff --git a/modules/hsfpcibasic3.mod.c b/modules/hsfpcibasic3.mod.c new file mode 100644 index 0000000..1519a1c --- /dev/null +++ b/modules/hsfpcibasic3.mod.c @@ -0,0 +1,105 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +__visible struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = KBUILD_MODNAME, + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif + .arch = MODULE_ARCH_INIT, +}; + +#ifdef RETPOLINE +MODULE_INFO(retpoline, "Y"); +#endif + +static const struct modversion_info ____versions[] +__used +__attribute__((section("__versions"))) = { + { 0x525b86d, __VMLINUX_SYMBOL_STR(module_layout) }, + { 0x6dc7dc1e, __VMLINUX_SYMBOL_STR(kmalloc_caches) }, + { 0x743241d, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsKernelUsesRegParm) }, + { 0xabe71b05, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCreateTimer) }, + { 0xbca036b7, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsIoMemReadl) }, + { 0xcd7bf981, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsEventCreate) }, + { 0x90b92d37, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciWriteConfigdw) }, + { 0x58245be, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionRelease) }, + { 0xfa9b3e79, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciReadConfigb) }, + { 0xf83d11b6, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciWriteConfigb) }, + { 0x388af6e7, __VMLINUX_SYMBOL_STR(device_release_driver) }, + { 0xdcc0ee56, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionDestroy) }, + { 0x263ed23b, __VMLINUX_SYMBOL_STR(__x86_indirect_thunk_r12) }, + { 0xe7910696, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsSprintf) }, + { 0x38e0a235, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciReadConfigw) }, + { 0xd1af0c61, __VMLINUX_SYMBOL_STR(pci_disable_device) }, + { 0xe5d6603e, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsUnhookInterrupt) }, + { 0xf76c8370, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciReadConfigdw) }, + { 0x7cac7b6, __VMLINUX_SYMBOL_STR(pci_release_regions) }, + { 0x533191a, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsAllocate) }, + { 0x8917329d, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsGetPCIDeviceResources) }, + { 0xe2d5255a, __VMLINUX_SYMBOL_STR(strcmp) }, + { 0xe9985f40, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCancelTimer) }, + { 0x494b582c, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_ComCtrl_Control) }, + { 0xfb578fc5, __VMLINUX_SYMBOL_STR(memset) }, + { 0xc0620d74, __VMLINUX_SYMBOL_STR(pci_restore_state) }, + { 0x27e1a049, __VMLINUX_SYMBOL_STR(printk) }, + { 0x3cc05a0b, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_cnxt_serial_remove) }, + { 0x9166fada, __VMLINUX_SYMBOL_STR(strncpy) }, + { 0x49c8c662, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsIoMemWritel) }, + { 0x3c61a256, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsStrCat) }, + { 0xe287b7ab, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsUnmapPhysMem) }, + { 0xa022abf, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsEventDestroy) }, + { 0xe03abc15, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMemCpy) }, + { 0x820ab370, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsIoMemReadw) }, + { 0xc51f9205, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionCreate) }, + { 0xfd37ed40, __VMLINUX_SYMBOL_STR(module_put) }, + { 0x5f5dbae8, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsCriticalSectionAcquire) }, + { 0x9530d4f7, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsSleep) }, + { 0x78ebe119, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsEventSet) }, + { 0x22e421f, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMemSet) }, + { 0x66e478fa, __VMLINUX_SYMBOL_STR(put_device) }, + { 0x2d293f3a, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsEventClear) }, + { 0x89ff00c2, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsGetProcessorFreq) }, + { 0x3d4fb7e, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsChangeTimerTimeOut) }, + { 0xbdfb6dbb, __VMLINUX_SYMBOL_STR(__fentry__) }, + { 0x9a7a7dc9, __VMLINUX_SYMBOL_STR(pci_unregister_driver) }, + { 0x26932b93, __VMLINUX_SYMBOL_STR(kmem_cache_alloc_trace) }, + { 0xb4c7d569, __VMLINUX_SYMBOL_STR(get_device) }, + { 0x8230168b, __VMLINUX_SYMBOL_STR(pci_set_power_state) }, + { 0x525227a5, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsHookInterrupt) }, + { 0xd6e3cb08, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsFree) }, + { 0x37a0cba, __VMLINUX_SYMBOL_STR(kfree) }, + { 0xc559022e, __VMLINUX_SYMBOL_STR(pci_request_regions) }, + { 0xdd98ff2f, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsPciWriteConfigw) }, + { 0xcd99bfeb, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsDestroyTimer) }, + { 0x89905baa, __VMLINUX_SYMBOL_STR(__pci_register_driver) }, + { 0x22f34e04, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsErrorPrintf) }, + { 0x36886337, __VMLINUX_SYMBOL_STR(pci_get_device) }, + { 0xb7efc090, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMapPhysMem) }, + { 0xf425b003, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsReadCpuCnt) }, + { 0x9202a2ee, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsStrLen) }, + { 0x28318305, __VMLINUX_SYMBOL_STR(snprintf) }, + { 0xab154510, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsEventWaitTime) }, + { 0x91a19aa1, __VMLINUX_SYMBOL_STR(pci_choose_state) }, + { 0x6e537fc3, __VMLINUX_SYMBOL_STR(pci_enable_device) }, + { 0x8e7b8953, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsSetTimer) }, + { 0x1456e13, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_cnxt_serial_add) }, + { 0xc993bd44, __VMLINUX_SYMBOL_STR(try_module_get) }, + { 0x8c8c9b26, __VMLINUX_SYMBOL_STR(pci_save_state) }, + { 0x8b082cfa, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsIoMemWritew) }, +}; + +static const char __module_depends[] +__used +__attribute__((section(".modinfo"))) = +"depends=hsfosspec,hsfengine,hsfserial"; + +MODULE_ALIAS("pci:v000014F1d00002F80sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F81sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F82sv*sd*bc*sc*i*"); +MODULE_ALIAS("pci:v000014F1d00002F83sv*sd*bc*sc*i*"); diff --git a/modules/hsfserial.mod.c b/modules/hsfserial.mod.c new file mode 100644 index 0000000..4a5a0e5 --- /dev/null +++ b/modules/hsfserial.mod.c @@ -0,0 +1,103 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +__visible struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = KBUILD_MODNAME, + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif + .arch = MODULE_ARCH_INIT, +}; + +#ifdef RETPOLINE +MODULE_INFO(retpoline, "Y"); +#endif + +static const struct modversion_info ____versions[] +__used +__attribute__((section("__versions"))) = { + { 0x525b86d, __VMLINUX_SYMBOL_STR(module_layout) }, + { 0xbdc6b187, __VMLINUX_SYMBOL_STR(cpu_tss) }, + { 0xd2b09ce5, __VMLINUX_SYMBOL_STR(__kmalloc) }, + { 0xe2addb2d, __VMLINUX_SYMBOL_STR(uart_write_wakeup) }, + { 0x349cba85, __VMLINUX_SYMBOL_STR(strchr) }, + { 0xb71ad687, __VMLINUX_SYMBOL_STR(single_open) }, + { 0xfa8b9545, __VMLINUX_SYMBOL_STR(param_ops_int) }, + { 0xafcdba49, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_NVM_WriteFlushList) }, + { 0x5f6ebcaa, __VMLINUX_SYMBOL_STR(uart_add_one_port) }, + { 0x754d539c, __VMLINUX_SYMBOL_STR(strlen) }, + { 0x4bf56796, __VMLINUX_SYMBOL_STR(single_release) }, + { 0x79ef272, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsThreadSchedule) }, + { 0xe051d495, __VMLINUX_SYMBOL_STR(commit_creds) }, + { 0x8dab9456, __VMLINUX_SYMBOL_STR(uart_handle_cts_change) }, + { 0xccc8f76, __VMLINUX_SYMBOL_STR(seq_printf) }, + { 0xa3e0586f, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsThreadScheduleInit) }, + { 0x423035e6, __VMLINUX_SYMBOL_STR(remove_proc_entry) }, + { 0xb78d1c44, __VMLINUX_SYMBOL_STR(filp_close) }, + { 0x49d09ed5, __VMLINUX_SYMBOL_STR(uart_unregister_driver) }, + { 0x51ab895c, __VMLINUX_SYMBOL_STR(uart_update_timeout) }, + { 0x91715312, __VMLINUX_SYMBOL_STR(sprintf) }, + { 0xd0361ab, __VMLINUX_SYMBOL_STR(seq_read) }, + { 0x26c0207b, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_ComCtrl_Close) }, + { 0xbfdaa249, __VMLINUX_SYMBOL_STR(uart_remove_one_port) }, + { 0xe2d5255a, __VMLINUX_SYMBOL_STR(strcmp) }, + { 0x494b582c, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_ComCtrl_Control) }, + { 0xfbb79d98, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_ComCtrl_Open) }, + { 0x35b97bc1, __VMLINUX_SYMBOL_STR(vfs_read) }, + { 0xfb578fc5, __VMLINUX_SYMBOL_STR(memset) }, + { 0xcdad1757, __VMLINUX_SYMBOL_STR(__tty_insert_flip_char) }, + { 0x6a0d0447, __VMLINUX_SYMBOL_STR(proc_mkdir) }, + { 0x4c936d5d, __VMLINUX_SYMBOL_STR(default_llseek) }, + { 0x1916e38c, __VMLINUX_SYMBOL_STR(_raw_spin_unlock_irqrestore) }, + { 0xff4155a, __VMLINUX_SYMBOL_STR(current_task) }, + { 0x27e1a049, __VMLINUX_SYMBOL_STR(printk) }, + { 0xdba4309b, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_ComCtrl_Destroy) }, + { 0xd73be77, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsDcpEnsureDaemonIsRunning) }, + { 0x2421b896, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_ComCtrl_Monitor) }, + { 0x6dc6dd56, __VMLINUX_SYMBOL_STR(down) }, + { 0x698a99e9, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsMdmThread) }, + { 0x9e40c20d, __VMLINUX_SYMBOL_STR(pid_task) }, + { 0x2331a196, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_ComCtrl_Configure) }, + { 0x8e179160, __VMLINUX_SYMBOL_STR(prepare_creds) }, + { 0x61651be, __VMLINUX_SYMBOL_STR(strcat) }, + { 0xfd37ed40, __VMLINUX_SYMBOL_STR(module_put) }, + { 0x3d1b25c7, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_OsThreadScheduleDone) }, + { 0x1b7a2673, __VMLINUX_SYMBOL_STR(uart_handle_dcd_change) }, + { 0x242e722e, __VMLINUX_SYMBOL_STR(make_kuid) }, + { 0xdb7305a1, __VMLINUX_SYMBOL_STR(__stack_chk_fail) }, + { 0xa202a8e5, __VMLINUX_SYMBOL_STR(kmalloc_order_trace) }, + { 0x2ea2c95c, __VMLINUX_SYMBOL_STR(__x86_indirect_thunk_rax) }, + { 0xbdfb6dbb, __VMLINUX_SYMBOL_STR(__fentry__) }, + { 0x680ec266, __VMLINUX_SYMBOL_STR(_raw_spin_lock_irqsave) }, + { 0xf9ac7839, __VMLINUX_SYMBOL_STR(init_pid_ns) }, + { 0xf726356c, __VMLINUX_SYMBOL_STR(proc_create_data) }, + { 0xadf88359, __VMLINUX_SYMBOL_STR(seq_lseek) }, + { 0x37a0cba, __VMLINUX_SYMBOL_STR(kfree) }, + { 0x70befe59, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_ComCtrl_Read) }, + { 0xefae3e75, __VMLINUX_SYMBOL_STR(send_sig_info) }, + { 0x78e739aa, __VMLINUX_SYMBOL_STR(up) }, + { 0xd6d7dc3, __VMLINUX_SYMBOL_STR(uart_register_driver) }, + { 0x566d2a6c, __VMLINUX_SYMBOL_STR(tty_flip_buffer_push) }, + { 0x28318305, __VMLINUX_SYMBOL_STR(snprintf) }, + { 0x4f6b400b, __VMLINUX_SYMBOL_STR(_copy_from_user) }, + { 0x3ed883b6, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_ComCtrl_Create) }, + { 0xa0497153, __VMLINUX_SYMBOL_STR(uart_get_baud_rate) }, + { 0xa65b4573, __VMLINUX_SYMBOL_STR(find_pid_ns) }, + { 0x6f6dfb4d, __VMLINUX_SYMBOL_STR(cnxthsf_7800206x86_64oem_ComCtrl_Write) }, + { 0xc993bd44, __VMLINUX_SYMBOL_STR(try_module_get) }, + { 0x90bd7de2, __VMLINUX_SYMBOL_STR(vfs_write) }, + { 0x4874bcd7, __VMLINUX_SYMBOL_STR(filp_open) }, +}; + +static const char __module_depends[] +__used +__attribute__((section(".modinfo"))) = +"depends=hsfosspec,hsfengine"; + + +MODULE_INFO(srcversion, "01B63D3939944F44FCA5287"); diff --git a/modules/hsfsoar.mod.c b/modules/hsfsoar.mod.c new file mode 100644 index 0000000..e57dd44 --- /dev/null +++ b/modules/hsfsoar.mod.c @@ -0,0 +1,31 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +__visible struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = KBUILD_MODNAME, + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif + .arch = MODULE_ARCH_INIT, +}; + +#ifdef RETPOLINE +MODULE_INFO(retpoline, "Y"); +#endif + +static const struct modversion_info ____versions[] +__used +__attribute__((section("__versions"))) = { + { 0x525b86d, __VMLINUX_SYMBOL_STR(module_layout) }, +}; + +static const char __module_depends[] +__used +__attribute__((section(".modinfo"))) = +"depends="; + diff --git a/modules/imported/include/build_modules.h b/modules/imported/include/build_modules.h old mode 100644 new mode 100755 index 6e943bc..457601c --- a/modules/imported/include/build_modules.h +++ b/modules/imported/include/build_modules.h @@ -138,6 +138,8 @@ #define NO_MT_SUPPORT #endif +//#define NO_QC_SUPPORT + #endif #if ( FRAME_WORK == FWK_CORSICA_ADS ) @@ -164,7 +166,7 @@ #define NO_PIG_SUPPORT #define NO_JAPANESE_CID_SUPPORT #define NO_FRENCH_CID_SUPPORT -/* #define NO_BLAM_SUPPORT */ + #define NO_BLAM_SUPPORT /*#define NO_PULSE_SUPPORT */ #define NO_DTMF_CID_SUPPORT /* #define NO_DCP_SUPPORT */ diff --git a/modules/imported/include/c2firmware.h b/modules/imported/include/c2firmware.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/cnxt_diag_codes_ex.h b/modules/imported/include/cnxt_diag_codes_ex.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/codesdeps.h b/modules/imported/include/codesdeps.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/comctrl_ex.h b/modules/imported/include/comctrl_ex.h old mode 100644 new mode 100755 index 27154d1..336fae0 --- a/modules/imported/include/comctrl_ex.h +++ b/modules/imported/include/comctrl_ex.h @@ -145,32 +145,23 @@ typedef enum COMCTRL_CONTROL_SETRTS, /* Set RTS high - no extra data */ COMCTRL_CONTROL_CLRRTS, /* Set RTS low - no extra data */ COMCTRL_CONTROL_SETDTR, /* Set DTR high - no extra data */ - COMCTRL_CONTROL_CLRDTR, /* Set DTR low - no extra data */ - + COMCTRL_CONTROL_CLRDTR, /* Set DTR low - no extra data */ COMCTRL_CONTROL_SET_XON, COMCTRL_CONTROL_SET_XOFF, COMCTRL_CONTROL_SEND_XON, - COMCTRL_CONTROL_SEND_XOFF, - + COMCTRL_CONTROL_SEND_XOFF, COMCTRL_CONTROL_RESETDEV, /* Reset device if possible - no extra data */ COMCTRL_CONTROL_CHAR, /* Send immediate character. - [IN] (char)pData - char to send */ - COMCTRL_CONTROL_START_MONITOR_CHAR, /* Start monitoring special character in Rx queue */ COMCTRL_CONTROL_STOP_MONITOR_CHAR, /* Stop monitoring special character in Rx queue */ - COMCTRL_CONTROL_INIT_STATE, - - COMCTRL_CONTROL_PORTCONFIG, /* Set Port Configuration - [IN] (PPORT_CONFIG)pData */ - + COMCTRL_CONTROL_PORTCONFIG, /* Set Port Configuration - [IN] (PPORT_CONFIG)pData */ COMCTRL_CONTROL_SLEEP, COMCTRL_CONTROL_WAKEUP, COMCTRL_CONTROL_FLUSH, /* flushing FIFO */ -/*#$YS$ Added for Break handling */ COMCTRL_CONTROL_SET_BREAK_ON, /* Set break ON */ COMCTRL_CONTROL_SET_BREAK_OFF, /* Set break OFF */ - COMCTRL_CONTROL_LAST /* Dummy */ - }COMCTRL_CONTROL_CODE; /*#$YS$ Added for Voice support */ @@ -211,9 +202,7 @@ TODO(?): structure may be compacted (replace BOOLs by bitfields) typedef struct tagPORT_CONFIG { UINT32 dwValidFileds; /* Combination of PortConfiguration bits*/ - UINT32 dwDteSpeed; - enum { PC_PARITY_NONE, @@ -221,21 +210,22 @@ typedef struct tagPORT_CONFIG PC_PARITY_EVEN, PC_PARITY_MARK, PC_PARITY_SPACE - } eParity; /* Parity check*/ - + } eParity; /* Parity check*/ enum { PC_DATABITS_7, PC_DATABITS_8 - } eDataBits; /* Data bits - only 7 and 8 are enabled*/ - - BOOL fXOutput; /* Xoff/Xon enabled for output*/ - BOOL fXInput; /* Xoff/Xon enabled for input*/ - BOOL fError; /* Replace chars with parity error by ErrorChar*/ - BOOL fNull; /* Skip NULL characters*/ - BOOL fCTS; /* Use CTS for Tx flow control*/ - BOOL fRTS; /* Use RTS for Rx flow control*/ - + } eDataBits; /* Data bits - only 7 and 8 are enabled*/ + + struct{ + int fXOutput:1; /* Xoff/Xon enabled for output*/ + int fXInput:1; /* Xoff/Xon enabled for input*/ + int fError:1; /* Replace chars with parity error by ErrorChar*/ + int fNull:1; /* Skip NULL characters*/ + int fCTS:1; /* Use CTS for Tx flow control*/ + int fRTS:1; /* Use RTS for Rx flow control*/ + }; + char cXonChar; char cXoffChar; char cErrorChar; @@ -317,8 +307,8 @@ __shimcall__ COM_STATUS ComCtrl_Close (HANDLE hInst); __shimcall__ COM_STATUS ComCtrl_Configure (HANDLE hInst, COMCTRL_CONFIG_CODE eCode, PVOID pConfig); __shimcall__ COM_STATUS ComCtrl_Monitor (HANDLE hInst, COMCTRL_MONITOR_CODE eCode, PVOID pMonitor); __shimcall__ COM_STATUS ComCtrl_Control (HANDLE hInst, COMCTRL_CONTROL_CODE eCode, PVOID pControl); -__shimcall__ UINT32 ComCtrl_Read (HANDLE hInst, PVOID pBuf, UINT32 dwSize); __shimcall__ UINT32 ComCtrl_Write (HANDLE hInst, PVOID pBuf, UINT32 dwSize); +__shimcall__ UINT32 ComCtrl_Read (HANDLE hInst, PVOID pBuf, UINT32 dwSize); /* Interface through function table */ @@ -346,9 +336,12 @@ typedef struct I_COM_CTRL_TAG PVOID ComCtrlGetInterface(void); +typedef struct _SYSLINO{ + char dummy[0x10C];//400 510 + PI_COM_CTRL_T hComCtrl; +} I_SYSLINO; #ifdef USE_DIRECT_API - #define COMCTRL_GetInterfaceVersion(pSys) ComCtrl_GetInterfaceVersion () #define COMCTRL_Create( pSys) ComCtrl_Create () #define COMCTRL_Destroy( pSys) ComCtrl_Destroy (pSys->hComCtrl) diff --git a/modules/imported/include/comtypes.h b/modules/imported/include/comtypes.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/configcodes.h b/modules/imported/include/configcodes.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/configtypes.h b/modules/imported/include/configtypes.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/dbgfuncs.h b/modules/imported/include/dbgfuncs.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/dcp.h b/modules/imported/include/dcp.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/diagmgr_ex.h b/modules/imported/include/diagmgr_ex.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/dpaloem.h b/modules/imported/include/dpaloem.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/framewrk.h b/modules/imported/include/framewrk.h old mode 100644 new mode 100755 index 3f33bbf..9a553c1 --- a/modules/imported/include/framewrk.h +++ b/modules/imported/include/framewrk.h @@ -215,7 +215,8 @@ #define OCT_MEM_MGR 0 #define USE_MEM_MGR 0 #define USE_PRAGMA_PACK 0 -#define USE_DIRECT_API 1 +#define USE_DIRECT_API 1 + #ifdef __x86_64__ #define PORTABILITY 1 #else diff --git a/modules/imported/include/intfctrl_ex.h b/modules/imported/include/intfctrl_ex.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/memmgr_ex.h b/modules/imported/include/memmgr_ex.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/osdiag.h b/modules/imported/include/osdiag.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/osmemory.h b/modules/imported/include/osmemory.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/osmemory_ex.h b/modules/imported/include/osmemory_ex.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/osnvm.h b/modules/imported/include/osnvm.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/osservices.h b/modules/imported/include/osservices.h old mode 100644 new mode 100755 index 0a18519..d06a2ea --- a/modules/imported/include/osservices.h +++ b/modules/imported/include/osservices.h @@ -353,12 +353,13 @@ void OsInterruptsRestore(HINTERRUPT hPreviousState); ****************************************************************************************/ -#if defined(__GNUC__) && defined(__i386__) && !defined(OS_NOSTRINGREDEFS) && !defined(_I386_STRING_H_) -#ifdef LINUX_VERSION_CODE -#include -#else -#include -#endif +#if defined(__GNUC__) && !defined(OS_NOSTRINGREDEFS) && !defined(_I386_STRING_H_) && (defined(__i386__) /*|| defined(__x86_64__)*/) + #ifdef LINUX_VERSION_CODE + #include + #else + #include + #endif + #undef OsMemSet #define OsMemSet memset #undef OsMemCpy @@ -381,6 +382,7 @@ void OsInterruptsRestore(HINTERRUPT hPreviousState); #define OsStrnCmp strncmp #undef OsStrLen #define OsStrLen strlen + #else __shimcall__ PVOID OsMemSet (PVOID pBuf, UINT8 c, UINT32 Count); diff --git a/modules/imported/include/osstring_ex.h b/modules/imported/include/osstring_ex.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/ossysenv.h b/modules/imported/include/ossysenv.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/ostime_ex.h b/modules/imported/include/ostime_ex.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/osuniqredef.h b/modules/imported/include/osuniqredef.h old mode 100644 new mode 100755 index 6dd2b44..dd5afef --- a/modules/imported/include/osuniqredef.h +++ b/modules/imported/include/osuniqredef.h @@ -239,7 +239,7 @@ #define RPT_Write _OSUNIQDEF(RPT_Write) #define ulTraceMask _OSUNIQDEF(ulTraceMask) #define ulLogThread _OSUNIQDEF(ulLogThread) -#define GetSOARLibInterface _OSUNIQDEF(GetSOARLibInterface) +// #define GetSOARLibInterface _OSUNIQDEF(GetSOARLibInterface) #define cnxt_serial_add _OSUNIQDEF(cnxt_serial_add) #define cnxt_serial_remove _OSUNIQDEF(cnxt_serial_remove) diff --git a/modules/imported/include/rtmgr_ex.h b/modules/imported/include/rtmgr_ex.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/std_defines.h b/modules/imported/include/std_defines.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/sysenv.h b/modules/imported/include/sysenv.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/targetconfigtypes.h b/modules/imported/include/targetconfigtypes.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/testdebug.h b/modules/imported/include/testdebug.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/tonetype.h b/modules/imported/include/tonetype.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/typedefs.h b/modules/imported/include/typedefs.h old mode 100644 new mode 100755 diff --git a/modules/imported/include/usbhalos.h b/modules/imported/include/usbhalos.h old mode 100644 new mode 100755 diff --git a/modules/imported/makeflags.mak b/modules/imported/makeflags.mak index e138205..d53d54e 100644 --- a/modules/imported/makeflags.mak +++ b/modules/imported/makeflags.mak @@ -1,3 +1,3 @@ -IMPORTED_ARCH ?= $(shell uname -i) +IMPORTED_ARCH ?= $(shell uname -m) include $(TOP)/modules/imported/makeflags-$(IMPORTED_ARCH).mak diff --git a/modules/include/cdbgscr_ex.h b/modules/include/cdbgscr_ex.h old mode 100644 new mode 100755 diff --git a/modules/include/linux_dbgscr.h b/modules/include/linux_dbgscr.h old mode 100644 new mode 100755 diff --git a/modules/include/osdiag_dev.h b/modules/include/osdiag_dev.h old mode 100644 new mode 100755 diff --git a/modules/include/oshda.h b/modules/include/oshda.h old mode 100644 new mode 100755 diff --git a/modules/include/oslinux.h b/modules/include/oslinux.h old mode 100644 new mode 100755 diff --git a/modules/include/osmodule.h b/modules/include/osmodule.h old mode 100644 new mode 100755 diff --git a/modules/include/osresour_ex.h b/modules/include/osresour_ex.h old mode 100644 new mode 100755 index fcea0ab..f6998e5 --- a/modules/include/osresour_ex.h +++ b/modules/include/osresour_ex.h @@ -77,8 +77,8 @@ typedef struct tagOS_DEVNODE { UINT32 *pci_state; struct cnxt_irq_t { - __kernelcall__ OS_IRQRETURN_T (*isr)(int irq, void *devidp, void *unused); - void *devid; + __kernelcall__ OS_IRQRETURN_T (*isr)(int irq, void *devidp, void *unused); + void *devid; } irq_info; } OS_DEVNODE, *POS_DEVNODE; diff --git a/modules/include/osstdio.h b/modules/include/osstdio.h old mode 100644 new mode 100755 diff --git a/modules/include/osusb.h b/modules/include/osusb.h old mode 100644 new mode 100755 diff --git a/modules/mod_engine.c b/modules/mod_engine.c index 3bbe6c1..72d81a9 100644 --- a/modules/mod_engine.c +++ b/modules/mod_engine.c @@ -16,6 +16,8 @@ MODULE_DESCRIPTION("Conexant modem engine"); MODULE_LICENSE("see LICENSE file distributed with driver"); MODULE_INFO(supported, "yes"); +//EXPORT_SYMBOL_NOVERS(ComCtrl_GetInterfaceVersion); +//EXPORT_SYMBOL_NOVERS(ComCtrlGetInterface); EXPORT_SYMBOL_NOVERS(ComCtrl_Create); EXPORT_SYMBOL_NOVERS(ComCtrl_Destroy); EXPORT_SYMBOL_NOVERS(ComCtrl_Open); diff --git a/modules/mod_osspec.c b/modules/mod_osspec.c index 19c6ea4..5841da8 100644 --- a/modules/mod_osspec.c +++ b/modules/mod_osspec.c @@ -7,7 +7,7 @@ * */ -#define OS_NOSTRINGREDEFS +//#define OS_NOSTRINGREDEFS #include "oscompat.h" #include "framewrk.h" @@ -267,36 +267,38 @@ cnxtosspec_init(void) r = OsInit(); if(r < 0) - return r; + return r; #if defined(SCR) && defined(NO_BLAM_SUPPORT) - r = OsScrInit(); + r = OsScrInit(); if(r < 0) - return r; + return r; #endif #if !defined NO_DIAGMGR_SUPPORT r = OsDiagInit(); if(r < 0) { #if defined(SCR) && defined(NO_BLAM_SUPPORT) - OsScrExit(); + OsScrExit(); #endif return r; } #endif + #ifdef USE_DCP r = OsDcpInit(); if(r < 0) { #if !defined NO_DIAGMGR_SUPPORT - OsDiagExit(); + OsDiagExit(); #endif + #if defined(SCR) && defined(NO_BLAM_SUPPORT) - OsScrExit(); + OsScrExit(); #endif - return r; + return r; } #endif /* USE_DCP */ - + printk(KERN_INFO "%s\n", __FUNCTION__); return 0; } diff --git a/modules/mod_soar.c b/modules/mod_soar.c index 8723d7b..ae4ab2a 100644 --- a/modules/mod_soar.c +++ b/modules/mod_soar.c @@ -10,9 +10,9 @@ #include "osservices.h" #include "comtypes.h" -PVOID GetSOARLibInterface(void); +// PVOID GetSOARLibInterface(void); -EXPORT_SYMBOL_NOVERS(GetSOARLibInterface); +// EXPORT_SYMBOL_NOVERS(GetSOARLibInterface); MODULE_AUTHOR("Copyright (C) 1996-2001 Conexant Systems Inc."); MODULE_DESCRIPTION("HSF module for SmartDAA(tm) devices"); diff --git a/modules/osdcp.c b/modules/osdcp.c old mode 100644 new mode 100755 index 1f70988..4d0ffbc --- a/modules/osdcp.c +++ b/modules/osdcp.c @@ -1,11 +1,11 @@ /* - * Copyright (c) 2003-2004 Linuxant inc. - * - * NOTE: The use and distribution of this software is governed by the terms in - * the file LICENSE, which is included in the package. You must read this and - * agree to these terms before using or distributing this software. - * - */ +* Copyright (c) 2003-2004 Linuxant inc. +* +* NOTE: The use and distribution of this software is governed by the terms in +* the file LICENSE, which is included in the package. You must read this and +* agree to these terms before using or distributing this software. +* +*/ #include "oscompat.h" #include "osresour_ex.h" @@ -42,37 +42,29 @@ static struct class *dcp_class; #endif typedef struct { - struct list_head entry; - spinlock_t lock; - - POS_DEVNODE pDevNode; - + struct list_head entry; + spinlock_t lock; + POS_DEVNODE pDevNode; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - devfs_handle_t devfs_handle; + devfs_handle_t devfs_handle; #endif - - struct list_head units; - - int restarted; - - int volume; - + struct list_head units; + int restarted; + int volume; #ifdef OSDCP_SKIP - int skip; + int skip; #endif - - unsigned char ringBuf[DCP_SAMPLE_SIZE * DCP_SAMPLE_RATE * 2]; /* buffer upto two seconds */ - int putIdx; - - wait_queue_head_t read_wait; - struct fasync_struct *fasync; + unsigned char ringBuf[DCP_SAMPLE_SIZE * DCP_SAMPLE_RATE * 2]; /* buffer upto two seconds */ + int putIdx; + wait_queue_head_t read_wait; + struct fasync_struct *fasync; } dcp_instance_t; typedef struct { - struct list_head entry; - int minor; - dcp_instance_t *pDcp; - int takeIdx; + struct list_head entry; + int minor; + dcp_instance_t *pDcp; + int takeIdx; } dcp_unit_t; static int dcpdebug = 0; @@ -83,203 +75,171 @@ MODULE_PARM(dcpdebug, "i"); #endif MODULE_PARM_DESC(dcpdebug, "Debug level for Digital Call Progress audio"); -static int -dcp_fasync(int fd, struct file *file, int on) +static int dcp_fasync(int fd, struct file *file, int on) { - dcp_unit_t *su = file->private_data; - dcp_instance_t *pDcp = su->pDcp; - int r; + dcp_unit_t *su = file->private_data; + dcp_instance_t *pDcp = su->pDcp; + int r; - if(!pDcp) - return -ENODEV; + if(!pDcp) + return -ENODEV; - r = fasync_helper(fd, file, on, &pDcp->fasync); - return (r < 0) ? r : 0; + r = fasync_helper(fd, file, on, &pDcp->fasync); + return (r < 0) ? r : 0; } -static unsigned int -dcp_poll(struct file *file, poll_table * wait) +static unsigned int dcp_poll(struct file *file, poll_table * wait) { - dcp_unit_t *su = file->private_data; - dcp_instance_t *pDcp = su->pDcp; - unsigned int mask = 0; - unsigned long flags; - - if(!pDcp) - return -ENODEV; - - poll_wait(file, &pDcp->read_wait, wait); - spin_lock_irqsave(&pDcp->lock, flags); - if (pDcp->putIdx != su->takeIdx) - mask |= POLLIN | POLLRDNORM; - spin_unlock_irqrestore(&pDcp->lock, flags); - return mask; + dcp_unit_t *su = file->private_data; + dcp_instance_t *pDcp = su->pDcp; + unsigned int mask = 0; + unsigned long flags; + + if(!pDcp) + return -ENODEV; + poll_wait(file, &pDcp->read_wait, wait); + spin_lock_irqsave(&pDcp->lock, flags); + if (pDcp->putIdx != su->takeIdx) + mask |= POLLIN | POLLRDNORM; + spin_unlock_irqrestore(&pDcp->lock, flags); + return mask; } -static ssize_t -dcp_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) +static ssize_t dcp_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) { - dcp_unit_t *su = file->private_data; - dcp_instance_t *pDcp = su->pDcp; - ssize_t ret = 0; - unsigned long flags; - char *dp; - size_t n; - - if(nbytes <= 0) - return 0; - - if(!pDcp) - return -ENODEV; - - spin_lock_irqsave(&pDcp->lock, flags); - - if((pDcp->putIdx == su->takeIdx) && (su->takeIdx >= 0)) { - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&pDcp->read_wait, &wait); - - while(pDcp->putIdx == su->takeIdx) { - - set_current_state(TASK_INTERRUPTIBLE); - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - spin_unlock_irqrestore(&pDcp->lock, flags); - schedule(); - spin_lock_irqsave(&pDcp->lock, flags); - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&pDcp->read_wait, &wait); - - if(ret) { - spin_unlock_irqrestore(&pDcp->lock, flags); - return ret; + dcp_unit_t *su = file->private_data; + dcp_instance_t *pDcp = su->pDcp; + ssize_t ret = 0; + unsigned long flags; + char *dp; + size_t n; + + if(nbytes <= 0) + return 0; + if(!pDcp) + return -ENODEV; + spin_lock_irqsave(&pDcp->lock, flags); + if((pDcp->putIdx == su->takeIdx) && (su->takeIdx >= 0)) { + DECLARE_WAITQUEUE(wait, current); + add_wait_queue(&pDcp->read_wait, &wait); + while(pDcp->putIdx == su->takeIdx) { + set_current_state(TASK_INTERRUPTIBLE); + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + spin_unlock_irqrestore(&pDcp->lock, flags); + schedule(); + spin_lock_irqsave(&pDcp->lock, flags); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&pDcp->read_wait, &wait); + if(ret) { + spin_unlock_irqrestore(&pDcp->lock, flags); + return ret; + } } - } - if((pDcp->putIdx < 0) || (su->takeIdx < 0)) { - spin_unlock_irqrestore(&pDcp->lock, flags); - return -ENODEV; - } - - dp = buf; - do { - - if(pDcp->putIdx > su->takeIdx) - n = pDcp->putIdx - su->takeIdx; - else - n = sizeof(pDcp->ringBuf) - su->takeIdx; - - if (n > nbytes) { - n = nbytes; + if((pDcp->putIdx < 0) || (su->takeIdx < 0)) { + spin_unlock_irqrestore(&pDcp->lock, flags); + return -ENODEV; } - + dp = buf; + do { + if(pDcp->putIdx > su->takeIdx) + n = pDcp->putIdx - su->takeIdx; + else + n = sizeof(pDcp->ringBuf) - su->takeIdx; + if (n > nbytes) + n = nbytes; + spin_unlock_irqrestore(&pDcp->lock, flags); + if(copy_to_user(dp, &pDcp->ringBuf[su->takeIdx], n)) { + ret = -EFAULT; + spin_lock_irqsave(&pDcp->lock, flags); + break; + } + spin_lock_irqsave(&pDcp->lock, flags); + + su->takeIdx += n; + if(su->takeIdx == sizeof(pDcp->ringBuf)) + su->takeIdx = 0; + + dp += n; + nbytes -= n; + + } while (nbytes && (pDcp->putIdx != su->takeIdx)); spin_unlock_irqrestore(&pDcp->lock, flags); - if(copy_to_user(dp, &pDcp->ringBuf[su->takeIdx], n)) { - ret = -EFAULT; - spin_lock_irqsave(&pDcp->lock, flags); - break; - } - spin_lock_irqsave(&pDcp->lock, flags); - - su->takeIdx += n; - if(su->takeIdx == sizeof(pDcp->ringBuf)) - su->takeIdx = 0; - - dp += n; - nbytes -= n; - - } while (nbytes && (pDcp->putIdx != su->takeIdx)); - - spin_unlock_irqrestore(&pDcp->lock, flags); - - if(!ret) { - ret = dp - buf; - - if(ret) { - TOUCH_ATIME(file); + if(!ret) { + ret = dp - buf; + if(ret) { + TOUCH_ATIME(file); + } } - } - - return ret; + return ret; } static int dcp_open(struct inode* inode, struct file* file) { - int minor = minor(inode->i_rdev); - dcp_unit_t *su; - struct list_head *e; - unsigned long flags, flags2; - - su = kmalloc(sizeof(*su), GFP_KERNEL); - if(!su) { - return -ENOMEM; - } - memset(su, 0, sizeof(*su)); - - su->minor = minor; - - spin_lock_irqsave(&dcp_lock, flags); - list_for_each (e, &dcp_instance_list) { - if((list_entry(e, dcp_instance_t, entry))->pDevNode->hwInstNum == minor) { - su->pDcp = list_entry(e, dcp_instance_t, entry); - break; + int minor = minor(inode->i_rdev); + dcp_unit_t *su; + struct list_head *e; + unsigned long flags, flags2; + + su = kmalloc(sizeof(*su), GFP_KERNEL); + if(!su) + return -ENOMEM; + memset(su, 0, sizeof(*su)); + + su->minor = minor; + + spin_lock_irqsave(&dcp_lock, flags); + list_for_each (e, &dcp_instance_list) { + if((list_entry(e, dcp_instance_t, entry))->pDevNode->hwInstNum == minor) { + su->pDcp = list_entry(e, dcp_instance_t, entry); + break; + } } - } - - if(su->pDcp) { - spin_lock_irqsave(&su->pDcp->lock, flags2); - list_add(&su->entry, &su->pDcp->units); - su->takeIdx = su->pDcp->putIdx; - spin_unlock_irqrestore(&su->pDcp->lock, flags2); - } - - spin_unlock_irqrestore(&dcp_lock, flags); - - if(!su->pDcp) { - kfree(su); - return -ENODEV; - } - - file->private_data = su; - - return 0; + if(su->pDcp) { + spin_lock_irqsave(&su->pDcp->lock, flags2); + list_add(&su->entry, &su->pDcp->units); + su->takeIdx = su->pDcp->putIdx; + spin_unlock_irqrestore(&su->pDcp->lock, flags2); + } + spin_unlock_irqrestore(&dcp_lock, flags); + if(!su->pDcp) { + kfree(su); + return -ENODEV; + } + file->private_data = su; + return 0; } static int dcp_release(struct inode* inode, struct file* file) { - dcp_unit_t *su = file->private_data; - dcp_instance_t *pDcp = su->pDcp; - unsigned long flags; - - if(pDcp) { - dcp_fasync(-1, file, 0); - - spin_lock_irqsave(&pDcp->lock, flags); - list_del(&su->entry); - su->takeIdx = -1; - spin_unlock_irqrestore(&pDcp->lock, flags); + dcp_unit_t *su = file->private_data; + dcp_instance_t *pDcp = su->pDcp; + unsigned long flags; + + if(pDcp) { + dcp_fasync(-1, file, 0); + spin_lock_irqsave(&pDcp->lock, flags); + list_del(&su->entry); + su->takeIdx = -1; + spin_unlock_irqrestore(&pDcp->lock, flags); #if 0 - wake_up_interruptible_all(&pDcp->read_wait); - OsSleep(100); + wake_up_interruptible_all(&pDcp->read_wait); + OsSleep(100); #endif - } - - kfree(su); - - return 0; + } + kfree(su); + return 0; } -static void -call_dcp_daemon(int instNum, char *action) +static void call_dcp_daemon(int instNum, char *action) { char *argv[3], *envp[6]; int i=0; @@ -300,15 +260,14 @@ call_dcp_daemon(int instNum, char *action) argv[0] = CNXTSBINDIR"/"CNXTTARGET"dcpd"; argv[1] = devbuf + sizeof("CNXTDCPDEVICE"); argv[2] = 0; - + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) i = call_usermodehelper(argv[0], argv, envp); #else i = call_usermodehelper(argv[0], argv, envp, 1); #endif - if(i && (i != SIGTERM)) { - printk(KERN_ERR"%s: %s returned %d\n", __FUNCTION__, argv[0], i); - } + if(i && (i != SIGTERM)) + printk(KERN_ERR"%s: %s returned %d\n", __FUNCTION__, argv[0], i); } static int dcpmajor = CNXTDCPMAJOR; @@ -319,263 +278,249 @@ MODULE_PARM(dcpmajor, "i"); #endif MODULE_PARM_DESC(dcpmajor, "Major device number for dcp device"); -__shimcall__ -void DcpDestroy (HANDLE hDcp) +__shimcall__ void DcpDestroy (HANDLE hDcp) { - dcp_instance_t *pDcp = hDcp; - int i; - unsigned long flags; - struct list_head *e; - - if(dcpdebug) - printk("%s: hDcp=%p\n", __FUNCTION__, hDcp); - - spin_lock_irqsave(&dcp_lock, flags); - list_del(&pDcp->entry); - spin_unlock_irqrestore(&dcp_lock, flags); - - call_dcp_daemon(pDcp->pDevNode->hwInstNum, "stop"); - - spin_lock_irqsave(&pDcp->lock, flags); - pDcp->putIdx = -2; - spin_unlock_irqrestore(&pDcp->lock, flags); - - spin_lock_irqsave(&pDcp->lock, flags); - for(i = 0; !list_empty(&pDcp->units); i++) { - if(i == 1) { - list_for_each (e, &pDcp->units) { - (list_entry(e, dcp_unit_t, entry))->takeIdx = -1; - //(list_entry(e, dcp_unit_t, entry))->pDcp = NULL; - } - } + dcp_instance_t *pDcp = hDcp; + int i; + unsigned long flags; + struct list_head *e; + + if(dcpdebug) + printk("%s: hDcp=%p\n", __FUNCTION__, hDcp); + + spin_lock_irqsave(&dcp_lock, flags); + list_del(&pDcp->entry); + spin_unlock_irqrestore(&dcp_lock, flags); + + call_dcp_daemon(pDcp->pDevNode->hwInstNum, "stop"); + + spin_lock_irqsave(&pDcp->lock, flags); + pDcp->putIdx = -2; spin_unlock_irqrestore(&pDcp->lock, flags); - if(i >= 1) { - if((i % 20) == 10) - printk(KERN_ERR"%s: units still active, waiting..\n", __FUNCTION__); - kill_fasync(&pDcp->fasync, SIGIO, POLL_IN); - wake_up_interruptible_all(&pDcp->read_wait); - } - schedule_timeout(HZ/10); + spin_lock_irqsave(&pDcp->lock, flags); - } - spin_unlock_irqrestore(&pDcp->lock, flags); + for(i = 0; !list_empty(&pDcp->units); i++) { + if(i == 1) { + list_for_each (e, &pDcp->units) { + (list_entry(e, dcp_unit_t, entry))->takeIdx = -1; + //(list_entry(e, dcp_unit_t, entry))->pDcp = NULL; + } + } + spin_unlock_irqrestore(&pDcp->lock, flags); + if(i >= 1) { + if((i % 20) == 10) + printk(KERN_ERR"%s: units still active, waiting..\n", __FUNCTION__); + kill_fasync(&pDcp->fasync, SIGIO, POLL_IN); + wake_up_interruptible_all(&pDcp->read_wait); + } + schedule_timeout(HZ/10); + spin_lock_irqsave(&pDcp->lock, flags); + } + spin_unlock_irqrestore(&pDcp->lock, flags); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - devfs_unregister(pDcp->devfs_handle); + devfs_unregister(pDcp->devfs_handle); #else #ifdef FOUND_DEVFS - { - char buf[32]; - snprintf(buf, sizeof(buf), CNXTTARGET"dcp%d", pDcp->pDevNode->hwInstNum); - devfs_remove(buf); - } + { + char buf[32]; + snprintf(buf, sizeof(buf), CNXTTARGET"dcp%d", pDcp->pDevNode->hwInstNum); + devfs_remove(buf); + } #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,2) - if (!IS_ERR(dcp_class)) - CLASS_DEVICE_DESTROY(dcp_class, MKDEV(dcpmajor, pDcp->pDevNode->hwInstNum)); + if (!IS_ERR(dcp_class)) + CLASS_DEVICE_DESTROY(dcp_class, MKDEV(dcpmajor, pDcp->pDevNode->hwInstNum)); #endif #endif - - kfree(pDcp); + kfree(pDcp); } - static struct file_operations dcp_fops = { - .owner = THIS_MODULE, - .fasync = dcp_fasync, - .poll = dcp_poll, - .read = dcp_read, - .open = dcp_open, - .release = dcp_release + .owner = THIS_MODULE, + .fasync = dcp_fasync, + .poll = dcp_poll, + .read = dcp_read, + .open = dcp_open, + .release = dcp_release }; -__shimcall__ -HANDLE DcpCreate(HANDLE hDevNode) +__shimcall__ HANDLE DcpCreate(HANDLE hDevNode) { - unsigned long flags; - dcp_instance_t *pDcp; - char buf[32]; + unsigned long flags; + dcp_instance_t *pDcp; + char buf[32]; - if(dcpdebug) - printk("%s: hDevNode=%p\n", __FUNCTION__, hDevNode); + if(dcpdebug) + printk("%s: hDevNode=%p\n", __FUNCTION__, hDevNode); - pDcp = kmalloc(sizeof(*pDcp), GFP_KERNEL); - if(!pDcp) - return NULL; - memset(pDcp, 0, sizeof(*pDcp)); + pDcp = kmalloc(sizeof(*pDcp), GFP_KERNEL); + if(!pDcp) + return NULL; + memset(pDcp, 0, sizeof(*pDcp)); - spin_lock_init(&pDcp->lock); - init_waitqueue_head(&pDcp->read_wait); - INIT_LIST_HEAD(&pDcp->units); - pDcp->pDevNode = hDevNode; + spin_lock_init(&pDcp->lock); + init_waitqueue_head(&pDcp->read_wait); + INIT_LIST_HEAD(&pDcp->units); + pDcp->pDevNode = hDevNode; - spin_lock_irqsave(&dcp_lock, flags); - list_add(&pDcp->entry, &dcp_instance_list); - spin_unlock_irqrestore(&dcp_lock, flags); + spin_lock_irqsave(&dcp_lock, flags); + list_add(&pDcp->entry, &dcp_instance_list); + spin_unlock_irqrestore(&dcp_lock, flags); - snprintf(buf, sizeof(buf), CNXTTARGET"dcp%d", pDcp->pDevNode->hwInstNum); + snprintf(buf, sizeof(buf), CNXTTARGET"dcp%d", pDcp->pDevNode->hwInstNum); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - pDcp->devfs_handle = devfs_register(NULL, buf, DEVFS_FL_DEFAULT, - dcpmajor, pDcp->pDevNode->hwInstNum, - S_IFCHR | S_IRUSR | S_IWUSR, - &dcp_fops, - NULL); + pDcp->devfs_handle = devfs_register(NULL, buf, DEVFS_FL_DEFAULT, + dcpmajor, pDcp->pDevNode->hwInstNum, + S_IFCHR | S_IRUSR | S_IWUSR, + &dcp_fops, + NULL); #else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,2) - if (!IS_ERR(dcp_class)) { - CLASS_DEVICE_CREATE(dcp_class, MKDEV(dcpmajor, pDcp->pDevNode->hwInstNum), pDcp->pDevNode->hwDevLink, CNXTTARGET"dcp%d", pDcp->pDevNode->hwInstNum); + if (!IS_ERR(dcp_class)) { + CLASS_DEVICE_CREATE(dcp_class, MKDEV(dcpmajor, pDcp->pDevNode->hwInstNum), pDcp->pDevNode->hwDevLink, CNXTTARGET"dcp%d", pDcp->pDevNode->hwInstNum); } #endif #ifdef FOUND_DEVFS - devfs_mk_cdev(MKDEV(dcpmajor, pDcp->pDevNode->hwInstNum), - S_IFCHR | S_IRUSR | S_IWUSR, buf); + devfs_mk_cdev(MKDEV(dcpmajor, pDcp->pDevNode->hwInstNum), + S_IFCHR | S_IRUSR | S_IWUSR, buf); #endif #endif - call_dcp_daemon(pDcp->pDevNode->hwInstNum, "start"); - return (HANDLE)pDcp; + call_dcp_daemon(pDcp->pDevNode->hwInstNum, "start"); + return (HANDLE)pDcp; } - -__shimcall__ -void DcpSetVolume(HANDLE hDcp, int nVolume) -{ - dcp_instance_t *pDcp = hDcp; - unsigned long flags; - if(dcpdebug) - printk("%s: hDcp=%p nVolume=%d\n", __FUNCTION__, hDcp, nVolume); +__shimcall__ void DcpSetVolume(HANDLE hDcp, int nVolume) +{ + dcp_instance_t *pDcp = hDcp; + unsigned long flags; - if(!pDcp) - return; + if(dcpdebug) + printk("%s: hDcp=%p nVolume=%d\n", __FUNCTION__, hDcp, nVolume); - spin_lock_irqsave(&pDcp->lock, flags); + if(!pDcp) + return; + nVolume = 5; + spin_lock_irqsave(&pDcp->lock, flags); #ifdef OSDCP_SKIP - if(!pDcp->volume && nVolume) { - pDcp->skip = DCP_SAMPLE_RATE * DCP_SAMPLE_SIZE; /* skip spikes */ - } + if(!pDcp->volume && nVolume) { + pDcp->skip = DCP_SAMPLE_RATE * DCP_SAMPLE_SIZE; /* skip spikes */ + } #endif - pDcp->volume = nVolume; - spin_unlock_irqrestore(&pDcp->lock, flags); + pDcp->volume = nVolume; + spin_unlock_irqrestore(&pDcp->lock, flags); } - -__shimcall__ -void DcpCallback(HANDLE hDcp, PVOID pData, UINT32 dwSize) + +__shimcall__ void DcpCallback(HANDLE hDcp, PVOID pData, UINT32 dwSize) { - dcp_instance_t *pDcp = hDcp; - unsigned long flags; - int s; + dcp_instance_t *pDcp = hDcp; + unsigned long flags; + int s; - if(dcpdebug) - printk("%s: hDcp=%p pData=%p dwSize=%u\n", __FUNCTION__, hDcp, pData, dwSize); + //if(dcpdebug) + //printk("%s: hDcp=%p pData=%p dwSize=%u\n", __FUNCTION__, hDcp, pData, dwSize); - if(!dwSize) - return; + if(!dwSize) + return; - spin_lock_irqsave(&pDcp->lock, flags); - if (!pDcp->volume || list_empty(&pDcp->units) || (pDcp->putIdx < 0)) { - spin_unlock_irqrestore(&pDcp->lock, flags); - return; - } + spin_lock_irqsave(&pDcp->lock, flags); + if (!pDcp->volume || list_empty(&pDcp->units) || (pDcp->putIdx < 0)) { + spin_unlock_irqrestore(&pDcp->lock, flags); + return; + } #ifdef OSDCP_SKIP - if(pDcp->skip) { - s = pDcp->skip; - if(dwSize < s) - s = dwSize; - - pDcp->skip -= s; - pData += s; - dwSize -= s; - } + if(pDcp->skip) { + s = pDcp->skip; + if(dwSize < s) + s = dwSize; + pDcp->skip -= s; + pData += s; + dwSize -= s; + } #endif - while(dwSize) { - s = sizeof(pDcp->ringBuf) - pDcp->putIdx; - if(dwSize < s) - s = dwSize; + while(dwSize) { + s = sizeof(pDcp->ringBuf) - pDcp->putIdx; + if(dwSize < s) + s = dwSize; - memcpy(&pDcp->ringBuf[pDcp->putIdx], pData, s); + memcpy(&pDcp->ringBuf[pDcp->putIdx], pData, s); - pDcp->putIdx += s; + pDcp->putIdx += s; - if(pDcp->putIdx == sizeof(pDcp->ringBuf)) - pDcp->putIdx = 0; + if(pDcp->putIdx == sizeof(pDcp->ringBuf)) + pDcp->putIdx = 0; - pData += s; - dwSize -= s; - } + pData += s; + dwSize -= s; + } - spin_unlock_irqrestore(&pDcp->lock, flags); + spin_unlock_irqrestore(&pDcp->lock, flags); - kill_fasync(&pDcp->fasync, SIGIO, POLL_IN); - wake_up_interruptible_all(&pDcp->read_wait); + kill_fasync(&pDcp->fasync, SIGIO, POLL_IN); + wake_up_interruptible_all(&pDcp->read_wait); } -__shimcall__ -void OsDcpExit(void) +__shimcall__ void OsDcpExit(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,2) - if (!IS_ERR(dcp_class)) - CLASS_DESTROY(dcp_class); + if (!IS_ERR(dcp_class)) + CLASS_DESTROY(dcp_class); #endif - if(dcpmajor > 0) + if(dcpmajor > 0) unregister_chrdev(dcpmajor, CNXTTARGET"dcp"); } -__shimcall__ -int OsDcpInit(void) +__shimcall__ int OsDcpInit(void) { - int ret; + int ret; - if(dcpmajor == 0) - dcpmajor = devfs_register_chrdev(0, CNXTTARGET"dcp", &dcp_fops); - else if((ret=devfs_register_chrdev(dcpmajor, CNXTTARGET"dcp", &dcp_fops))) { - dcpmajor = ret; - } + if(dcpmajor == 0) + dcpmajor = devfs_register_chrdev(0, CNXTTARGET"dcp", &dcp_fops); + else if((ret=devfs_register_chrdev(dcpmajor, CNXTTARGET"dcp", &dcp_fops))) + dcpmajor = ret; - if(dcpmajor < 0) { - printk(KERN_ERR "%s: cannot register chrdev (%d)\n", __FUNCTION__, dcpmajor); - - return dcpmajor; - } + if(dcpmajor < 0) { + printk(KERN_ERR "%s: cannot register chrdev (%d)\n", __FUNCTION__, dcpmajor); + return dcpmajor; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,2) - dcp_class = CLASS_CREATE(THIS_MODULE, CNXTTARGET"dcp"); - if (IS_ERR(dcp_class)) { + dcp_class = CLASS_CREATE(THIS_MODULE, CNXTTARGET"dcp"); + if (IS_ERR(dcp_class)) { printk(KERN_ERR "%s: cannot create simple class (%ld)\n", __FUNCTION__, PTR_ERR(dcp_class)); if(dcpmajor > 0) unregister_chrdev(dcpmajor, CNXTTARGET"dcp"); - return PTR_ERR(dcp_class); - } + return PTR_ERR(dcp_class); + } #endif - return 0; + return 0; } -__shimcall__ -void OsDcpEnsureDaemonIsRunning(int hwInstNum) +__shimcall__ void OsDcpEnsureDaemonIsRunning(int hwInstNum) { - struct list_head *e; - unsigned long flags, flags2; - dcp_instance_t *pDcp = NULL; - int start = 0; - - spin_lock_irqsave(&dcp_lock, flags); - list_for_each (e, &dcp_instance_list) { - if((list_entry(e, dcp_instance_t, entry))->pDevNode->hwInstNum == hwInstNum) { - - pDcp = list_entry(e, dcp_instance_t, entry); - spin_lock_irqsave(&pDcp->lock, flags2); - if(list_empty(&pDcp->units) && !pDcp->restarted) { - pDcp->restarted = start = 1; - } - spin_unlock_irqrestore(&pDcp->lock, flags2); - break; + struct list_head *e; + unsigned long flags, flags2; + dcp_instance_t *pDcp = NULL; + int start = 0; + + spin_lock_irqsave(&dcp_lock, flags); + list_for_each (e, &dcp_instance_list) { + if((list_entry(e, dcp_instance_t, entry))->pDevNode->hwInstNum == hwInstNum) { + pDcp = list_entry(e, dcp_instance_t, entry); + spin_lock_irqsave(&pDcp->lock, flags2); + if(list_empty(&pDcp->units) && !pDcp->restarted) { + pDcp->restarted = start = 1; + } + spin_unlock_irqrestore(&pDcp->lock, flags2); + break; + } } - } - spin_unlock_irqrestore(&dcp_lock, flags); - - if(start) - call_dcp_daemon(pDcp->pDevNode->hwInstNum, "start"); + spin_unlock_irqrestore(&dcp_lock, flags); + if(start) + call_dcp_daemon(pDcp->pDevNode->hwInstNum, "start"); } #endif /* USE_DCP */ diff --git a/modules/osdiag.c b/modules/osdiag.c old mode 100644 new mode 100755 index 79246c1..38bfc34 --- a/modules/osdiag.c +++ b/modules/osdiag.c @@ -132,31 +132,30 @@ DMPSRV_Dispatcher(PCHAR ClientName, DMP_SERVER_CODE Code, spin_lock_irqsave(&dmp_instance->lock, flags); if(list_empty(&dmp_instance->units)) { - spin_unlock_irqrestore(&dmp_instance->lock, flags); + spin_unlock_irqrestore(&dmp_instance->lock, flags); //printk(KERN_INFO "%s: device not opened (no daemon running?)\n", __FUNCTION__); - return FALSE; + return FALSE; } strncpy( dmp_instance->ringBuf[dmp_instance->putIdx].ClientName, ClientName, DMP_MAX_NAME_LEN ); strncpy( dmp_instance->ringBuf[dmp_instance->putIdx].FileName, FileName, DMP_MAX_NAME_LEN ); dmp_instance->ringBuf[dmp_instance->putIdx].Code = Code; - if ( pSegment != NULL ) - { - if(nData > DMP_SEG_SIZE) - nData = DMP_SEG_SIZE; - memcpy( dmp_instance->ringBuf[dmp_instance->putIdx].pData, pSegment, nData ); - memset( dmp_instance->ringBuf[dmp_instance->putIdx].pData + nData, '\0', DMP_SEG_SIZE - nData ); + if ( pSegment != NULL ){ + if(nData > DMP_SEG_SIZE) + nData = DMP_SEG_SIZE; + memcpy( dmp_instance->ringBuf[dmp_instance->putIdx].pData, pSegment, nData ); + memset( dmp_instance->ringBuf[dmp_instance->putIdx].pData + nData, '\0', DMP_SEG_SIZE - nData ); } dmp_instance->ringBuf[dmp_instance->putIdx].nData = nData; dmp_instance->putIdx++; if (dmp_instance->putIdx == DMP_MAX_SEGMENTS) - dmp_instance->putIdx = 0; + dmp_instance->putIdx = 0; if (dmp_instance->putIdx == dmp_instance->takeIdx) - printk(KERN_WARNING "%s: ring buffer overflow\n", __FUNCTION__); + printk(KERN_WARNING "%s: ring buffer overflow\n", __FUNCTION__); spin_unlock_irqrestore(&dmp_instance->lock, flags); @@ -166,8 +165,7 @@ DMPSRV_Dispatcher(PCHAR ClientName, DMP_SERVER_CODE Code, return TRUE; } -static ssize_t -dmp_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) +static ssize_t dmp_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) { PDMP_ACTION_INFO dpSegs; size_t nsegs = nbytes / sizeof(DMP_ACTION_INFO), n; @@ -175,39 +173,38 @@ dmp_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) unsigned long flags; if(nsegs <= 0) - return 0; + return 0; spin_lock_irqsave(&dmp_instance->lock, flags); if((dmp_instance->putIdx == dmp_instance->takeIdx) && (dmp_instance->takeIdx >= 0)) { - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&dmp_instance->read_wait, &wait); - - while(dmp_instance->putIdx == dmp_instance->takeIdx) { - - set_current_state(TASK_INTERRUPTIBLE); - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - spin_unlock_irqrestore(&dmp_instance->lock, flags); - schedule(); - spin_lock_irqsave(&dmp_instance->lock, flags); - } + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&dmp_instance->read_wait, &wait); + + while(dmp_instance->putIdx == dmp_instance->takeIdx) { + set_current_state(TASK_INTERRUPTIBLE); + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + spin_unlock_irqrestore(&dmp_instance->lock, flags); + schedule(); + spin_lock_irqsave(&dmp_instance->lock, flags); + } - set_current_state(TASK_RUNNING); - remove_wait_queue(&dmp_instance->read_wait, &wait); + set_current_state(TASK_RUNNING); + remove_wait_queue(&dmp_instance->read_wait, &wait); - if(ret) { - spin_unlock_irqrestore(&dmp_instance->lock, flags); - return ret; - } + if(ret) { + spin_unlock_irqrestore(&dmp_instance->lock, flags); + return ret; + } } if((dmp_instance->putIdx < 0) || (dmp_instance->takeIdx < 0)) { @@ -586,7 +583,7 @@ COM_STATUS OsDiagMgrClose(HANDLE hOsDiagMgr) unsigned long flags; if(diagdebug) - printk("%s: hOsDiagMgr=%p\n", __FUNCTION__, hOsDiagMgr); + printk("%s: hOsDiagMgr=%p\n", __FUNCTION__, hOsDiagMgr); if(pDiag) { pDiag->pSys = NULL; @@ -794,8 +791,7 @@ static void PutDiagInstance(diag_instance_t *pDiag) OsFree(pDiag); } -__shimcall__ -void OsDiagExit(void) +__shimcall__ void OsDiagExit(void) { diag_instance_t *pDiag; unsigned long flags; @@ -807,40 +803,40 @@ void OsDiagExit(void) /* Free all diag_instances */ spin_lock_irqsave(&diag_lock, flags); while(diag_instance_list.next != &diag_instance_list) { - pDiag = list_entry(diag_instance_list.next, diag_instance_t, entry); + pDiag = list_entry(diag_instance_list.next, diag_instance_t, entry); - list_del(&pDiag->entry); - spin_unlock_irqrestore(&diag_lock, flags); + list_del(&pDiag->entry); + spin_unlock_irqrestore(&diag_lock, flags); - PutDiagInstance(pDiag); + PutDiagInstance(pDiag); - spin_lock_irqsave(&diag_lock, flags); + spin_lock_irqsave(&diag_lock, flags); } spin_unlock_irqrestore(&diag_lock, flags); #if defined(DMP) || defined(DMPRETAIL) /* Free dmp_instance */ if(dmp_instance) { - spin_lock_irqsave(&dmp_instance->lock, flags); - dmp_instance->putIdx = -2; - spin_unlock_irqrestore(&dmp_instance->lock, flags); + spin_lock_irqsave(&dmp_instance->lock, flags); + dmp_instance->putIdx = -2; + spin_unlock_irqrestore(&dmp_instance->lock, flags); //call_diag_daemon(dmp_instance->hwInstNum, "stop"); spin_lock_irqsave(&dmp_instance->lock, flags); for(i = 0; !list_empty(&dmp_instance->units); i++) { if(i == 1) { - list_for_each (e, &dmp_instance->units) { - (list_entry(e, diag_unit_t, entry))->takeIdx = -1; + list_for_each (e, &dmp_instance->units) { + (list_entry(e, diag_unit_t, entry))->takeIdx = -1; //(list_entry(e, diag_unit_t, entry))->inst.pDmp = NULL; - } + } } spin_unlock_irqrestore(&dmp_instance->lock, flags); if(i >= 1) { - if((i % 20) == 10) - printk(KERN_ERR"%s: units still active, waiting..\n", __FUNCTION__); - kill_fasync(&dmp_instance->fasync, SIGIO, POLL_IN); - wake_up_interruptible_all(&dmp_instance->read_wait); + if((i % 20) == 10) + printk(KERN_ERR"%s: units still active, waiting..\n", __FUNCTION__); + kill_fasync(&dmp_instance->fasync, SIGIO, POLL_IN); + wake_up_interruptible_all(&dmp_instance->read_wait); } OsSleep(100); spin_lock_irqsave(&dmp_instance->lock, flags); @@ -849,7 +845,7 @@ void OsDiagExit(void) OsFree(dmp_instance); dmp_instance = NULL; - } +} #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) devfs_unregister(dmp_devfs_handle); @@ -878,16 +874,17 @@ int OsDiagInit(void) int ret; if(diagmajor == 0) { - diagmajor = devfs_register_chrdev(0, CNXTTARGET"diag", &diag_fops); - } else if((ret=devfs_register_chrdev(diagmajor, CNXTTARGET"diag", &diag_fops))) { - diagmajor = ret; + diagmajor = devfs_register_chrdev(0, CNXTTARGET"diag", &diag_fops); + } + else if((ret=devfs_register_chrdev(diagmajor, CNXTTARGET"diag", &diag_fops))) { + diagmajor = ret; } if(diagmajor < 0) { - printk(KERN_ERR "%s: cannot register chrdev (%d)\n", __FUNCTION__, diagmajor); + printk(KERN_ERR "%s: cannot register chrdev (%d)\n", __FUNCTION__, diagmajor); return diagmajor; - } +} #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,2) diag_class = CLASS_CREATE(THIS_MODULE, CNXTTARGET"diag"); diff --git a/modules/osmemory.c b/modules/osmemory.c old mode 100644 new mode 100755 diff --git a/modules/osmodule.c b/modules/osmodule.c old mode 100644 new mode 100755 diff --git a/modules/osnvm.c b/modules/osnvm.c old mode 100644 new mode 100755 index 84e419b..6d269d9 --- a/modules/osnvm.c +++ b/modules/osnvm.c @@ -1,29 +1,25 @@ /* - * Copyright (c) 2003-2004 Linuxant inc. - * - * NOTE: The use and distribution of this software is governed by the terms in - * the file LICENSE, which is included in the package. You must read this and - * agree to these terms before using or distributing this software. - * - */ +* Copyright (c) 2003-2004 Linuxant inc. +* +* NOTE: The use and distribution of this software is governed by the terms in +* the file LICENSE, which is included in the package. You must read this and +* agree to these terms before using or distributing this software. +* +*/ #include "oscompat.h" #include "osservices.h" #include "osmemory.h" #include "osstdio.h" #include "osresour_ex.h" - #include "comtypes.h" #include "configtypes.h" #include "testdebug.h" - #include #include #include #include - #include - #include #define caseretstr(x) case CFGMGR_##x: return #x @@ -38,11 +34,12 @@ static int osnvm_debug; #ifdef FOUND_MODULE_PARAM -module_param(osnvm_debug, int, 0); +//module_param(osnvm_debug, int, 0); #else MODULE_PARM(osnvm_debug, "i"); #endif + static char* eCodeStr(CFGMGR_CODE eCode) { switch(eCode) { @@ -303,23 +300,21 @@ static char* eCodeStr(CFGMGR_CODE eCode) #endif caseretstr(VOICE_DETECTION_MASK); #endif - caseretstr(HARDWARE_PROFILE); caseretstr(HARDWARE_ID); caseretstr(LICENSE_OWNER); caseretstr(LICENSE_KEY); caseretstr(LICENSE_STATUS); caseretstr(LAST); - default: { - static char buf[80]; - - if((eCode & 0xffff) == CFGMGR_COUNTRY_STRUCT) { - sprintf(buf, "COUNTRY_STRUCT_%02x\n", eCode >> 16); - } else { - sprintf(buf, "code_%d\n", eCode); - } - return buf; - } + default: { + static char buf[80]; + + if((eCode & 0xffff) == CFGMGR_COUNTRY_STRUCT) + sprintf(buf, "COUNTRY_STRUCT_%02x\n", eCode >> 16); + else + sprintf(buf, "code_%d\n", eCode); + return buf; + } } } @@ -335,70 +330,66 @@ static const PROFILE_DATA g_FactoryProfile = { 0, // Pulse 0, // Quiet 1, // Verbose - 3, // report Level (ATX3) + 4, // report Level (ATX3) ** 0, // Connect message 1, // AmperC 2, // AmperD 0, // S0 0, // S1; - 43, // S2; - 13, // S3; - 10, // S4; - 8, // S5; + 43, // S2; + 13, // S3; + 10, // S4; + 8, // S5; 2, // S6; - 50, // S7; + 50, // S7; 2, // S8; - 14, // S10; - 95, // S11; - 50, // S12; + 14, // S10; + 95, // S11; + 50, // S12; 0, // S16; 0, // S18; - 70 // S29; + 70 // S29; }; enum NVM_FORMAT { - NVM_FORMAT_HEXBYTES, - NVM_FORMAT_HEXSHORTS, - NVM_FORMAT_HEXLONGS, - NVM_FORMAT_STRING + NVM_FORMAT_HEXBYTES, + NVM_FORMAT_HEXSHORTS, + NVM_FORMAT_HEXLONGS, + NVM_FORMAT_STRING }; -static -enum NVM_FORMAT nvmFormat(CFGMGR_CODE eCode) +static enum NVM_FORMAT nvmFormat(CFGMGR_CODE eCode) { - switch(eCode) { - case CFGMGR_COUNTRY_CODE: - case CFGMGR_PREVIOUS_COUNTRY_CODE: - case CFGMGR_PCI_VENDOR_ID: - case CFGMGR_PCI_DEVICE_ID: - return NVM_FORMAT_HEXSHORTS; - - case CFGMGR_HARDWARE_PROFILE: - case CFGMGR_LICENSE_OWNER: - case CFGMGR_LICENSE_STATUS: - return NVM_FORMAT_STRING; - - case CFGMGR_HARDWARE_ID: - case CFGMGR_LICENSE_KEY: - return NVM_FORMAT_HEXLONGS; - - default: - return NVM_FORMAT_HEXBYTES; - } + switch(eCode) { + case CFGMGR_COUNTRY_CODE: + case CFGMGR_PREVIOUS_COUNTRY_CODE: + case CFGMGR_PCI_VENDOR_ID: + case CFGMGR_PCI_DEVICE_ID: + return NVM_FORMAT_HEXSHORTS; + case CFGMGR_HARDWARE_PROFILE: + case CFGMGR_LICENSE_OWNER: + case CFGMGR_LICENSE_STATUS: + return NVM_FORMAT_STRING; + case CFGMGR_HARDWARE_ID: + case CFGMGR_LICENSE_KEY: + return NVM_FORMAT_HEXLONGS; + default: + return NVM_FORMAT_HEXBYTES; + } } typedef struct { - struct list_head link; - char *pathname; - PVOID pBuf; - UINT32 dwSize; - enum NVM_FORMAT nvmFormat; + struct list_head link; + char *pathname; + PVOID pBuf; + UINT32 dwSize; + enum NVM_FORMAT nvmFormat; } nvmelem_t; typedef struct { - struct list_head link; - char *instname; + struct list_head link; + char *instname; } nvmnewinst_t; /* These lists are protected by nvmelem_writelist_sem */ @@ -418,8 +409,8 @@ static BOOL NVM_WriteListAppend(const char *pathname, PVOID pBuf, UINT32 dwSize, nel = OsAllocate(sizeof(nvmelem_t) + dwSize + strlen(pathname) + 1); if(!nel) { - printk(KERN_ERR"%s: cannot allocate memory for element %s\n", __FUNCTION__, pathname); - return FALSE; + printk(KERN_ERR"%s: cannot allocate memory for element %s\n", __FUNCTION__, pathname); + return FALSE; } nel->dwSize = dwSize; @@ -434,411 +425,382 @@ static BOOL NVM_WriteListAppend(const char *pathname, PVOID pBuf, UINT32 dwSize, return TRUE; } - /* Write pBuf to file as sequence of two-digit hex bytes */ -static BOOL -NVM_WriteFileData(FILE *file, const char *pathname, PVOID pBuf, UINT32 dwSize, enum NVM_FORMAT nvmFormat) +static BOOL NVM_WriteFileData(FILE *file, const char *pathname, PVOID pBuf, UINT32 dwSize, enum NVM_FORMAT nvmFormat) { - char buf[MAX_OEM_STR_LEN + 4], *dp; - unsigned char *p; - UINT32 size; - int errno; - - p = pBuf; - dp = buf; - - if(nvmFormat == NVM_FORMAT_HEXBYTES) { - for (size = 1; size < dwSize; size++) { - sprintf (dp, "%02X,", *p++); - dp += 3; - if(((size) % 16) == 0) { - *dp++ = '\n'; - if (OsFWrite(buf, 1, dp - buf, file, &errno) != (dp - buf)) { - printk(KERN_ERR "%s: write error to %s errno=%d\n", __FUNCTION__, pathname, errno); - goto err; + char buf[MAX_OEM_STR_LEN + 4], *dp; + unsigned char *p; + UINT32 size; + int errno; + + p = pBuf; + dp = buf; + + if(nvmFormat == NVM_FORMAT_HEXBYTES) { + for (size = 1; size < dwSize; size++) { + sprintf (dp, "%02X,", *p++); + dp += 3; + if(((size) % 16) == 0) { + *dp++ = '\n'; + if (OsFWrite(buf, 1, dp - buf, file, &errno) != (dp - buf)) { + printk(KERN_ERR "%s: write error to %s errno=%d\n", __FUNCTION__, pathname, errno); + goto err; + } + dp = buf; + } } - dp = buf; - } - } - sprintf (dp, "%02X\n", *p++); - dp += 3; - - } else if((nvmFormat == NVM_FORMAT_HEXSHORTS) && !(dwSize % sizeof(UINT16))) { - for (size = sizeof(UINT16); size < dwSize; size += sizeof(UINT16)) { - sprintf (dp, "%04X,", *(UINT16*)p); - p += sizeof(UINT16); - dp += 5; - if(((size) % 16) == 0) { - *dp++ = '\n'; - if (OsFWrite(buf, 1, dp - buf, file, &errno) != (dp - buf)) { - printk(KERN_ERR "%s: write error to %s errno=%d\n", __FUNCTION__, pathname, errno); - goto err; + sprintf (dp, "%02X\n", *p++); + dp += 3; + + } + else if((nvmFormat == NVM_FORMAT_HEXSHORTS) && !(dwSize % sizeof(UINT16))) { + for (size = sizeof(UINT16); size < dwSize; size += sizeof(UINT16)) { + sprintf (dp, "%04X,", *(UINT16*)p); + p += sizeof(UINT16); + dp += 5; + if(((size) % 16) == 0) { + *dp++ = '\n'; + if (OsFWrite(buf, 1, dp - buf, file, &errno) != (dp - buf)) { + printk(KERN_ERR "%s: write error to %s errno=%d\n", __FUNCTION__, pathname, errno); + goto err; + } + dp = buf; + } + } + sprintf (dp, "%04X\n", *(UINT16*)p); + p += sizeof(UINT16); + dp += 5; + } + else if((nvmFormat == NVM_FORMAT_HEXLONGS) && !(dwSize % sizeof(UINT32))) { + for (size = sizeof(UINT32); size < dwSize; size += sizeof(UINT32)) { + sprintf (dp, "%08X,", *(UINT32*)p); + p += sizeof(UINT32); + dp += 9; + if(((size) % 16) == 0) { + *dp++ = '\n'; + if (OsFWrite(buf, 1, dp - buf, file, &errno) != (dp - buf)) { + printk(KERN_ERR "%s: write error to %s errno=%d\n", __FUNCTION__, pathname, errno); + goto err; + } + dp = buf; + } } - dp = buf; - } + sprintf (dp, "%08X\n", *(UINT32*)p); + p += sizeof(UINT32); + dp += 9; + + } + else if(nvmFormat == NVM_FORMAT_STRING) { + size = (dwSize < MAX_OEM_STR_LEN) ? dwSize : MAX_OEM_STR_LEN; + buf[0] = '"'; + strncpy(&buf[1], pBuf, size); + buf[1 + size ] = '\0'; + size = strlen(buf); + buf[size++] = '"'; + buf[size++] = '\n'; + buf[size] = '\0'; + dp += size; + } + else { + printk(KERN_ERR "%s: invalid NVM format (%d)\n", __FUNCTION__, nvmFormat); + goto err; } - sprintf (dp, "%04X\n", *(UINT16*)p); - p += sizeof(UINT16); - dp += 5; - - } else if((nvmFormat == NVM_FORMAT_HEXLONGS) && !(dwSize % sizeof(UINT32))) { - for (size = sizeof(UINT32); size < dwSize; size += sizeof(UINT32)) { - sprintf (dp, "%08X,", *(UINT32*)p); - p += sizeof(UINT32); - dp += 9; - if(((size) % 16) == 0) { - *dp++ = '\n'; + + if(dp - buf) { if (OsFWrite(buf, 1, dp - buf, file, &errno) != (dp - buf)) { - printk(KERN_ERR "%s: write error to %s errno=%d\n", __FUNCTION__, pathname, errno); - goto err; + printk(KERN_ERR "%s: write error to %s errno=%d\n", __FUNCTION__, pathname, errno); + goto err; } - dp = buf; - } } - sprintf (dp, "%08X\n", *(UINT32*)p); - p += sizeof(UINT32); - dp += 9; - - } else if(nvmFormat == NVM_FORMAT_STRING) { - size = (dwSize < MAX_OEM_STR_LEN) ? dwSize : MAX_OEM_STR_LEN; - buf[0] = '"'; - strncpy(&buf[1], pBuf, size); - buf[1 + size ] = '\0'; - size = strlen(buf); - buf[size++] = '"'; - buf[size++] = '\n'; - buf[size] = '\0'; - dp += size; - - } else { - printk(KERN_ERR "%s: invalid NVM format (%d)\n", __FUNCTION__, nvmFormat); - goto err; - } - - if(dp - buf) { - if (OsFWrite(buf, 1, dp - buf, file, &errno) != (dp - buf)) { - printk(KERN_ERR "%s: write error to %s errno=%d\n", __FUNCTION__, pathname, errno); - goto err; - } - } - - OsFClose(file); - if(osnvm_debug) - printk(KERN_DEBUG"%s: wrote %u bytes to %s\n", __FUNCTION__, dwSize, pathname); - - return TRUE; + OsFClose(file); + if(osnvm_debug) + printk(KERN_DEBUG"%s: wrote %u bytes to %s\n", __FUNCTION__, dwSize, pathname); + return TRUE; err: - if(file) - OsFClose(file); - return FALSE; + if(file) + OsFClose(file); + return FALSE; } - -static int -NVM_NewInstance(char *instname) +static int NVM_NewInstance(char *instname) { - char *argv[] = { CNXTSBINDIR"/"CNXTTARGET"config", "--auto", "--newinstance", instname, NULL }; - char *envp[] = { "HOME=/", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:"CNXTSBINDIR, NULL }; - - //printk(KERN_DEBUG"%s: instname=%s\n", __FUNCTION__, instname); - - return OsForkWait(argv[0], argv, envp); + char *argv[] = { CNXTSBINDIR"/"CNXTTARGET"config", "--auto", "--newinstance", instname, NULL }; + char *envp[] = { "HOME=/", "PATH=/sbin:/bin:/usr/sbin:/usr/bin:"CNXTSBINDIR, NULL }; + return OsForkWait(argv[0], argv, envp); } - -__shimcall__ -void -NVM_WriteFlushList(BOOL write) +__shimcall__ void NVM_WriteFlushList(BOOL write) { - down(&nvmelem_writelist_sem); - - while(!list_empty(&nvm_newinst_list)) { - int err; - - nvmnewinst_t *ni = list_entry(nvm_newinst_list.next, nvmnewinst_t, link); - list_del(&ni->link); - up(&nvmelem_writelist_sem); - - err = write ? NVM_NewInstance(ni->instname) : 0; - if (err) { - //printk(KERN_ERR "%s: cannot create instance %s: err=%d failed again!\n", __FUNCTION__, ni->instname, err); - down(&nvmelem_writelist_sem); - list_add(&ni->link, &nvm_newinst_list); - goto done; - } - - printk(KERN_WARNING "%s: instance %s successfully created\n", __FUNCTION__, ni->instname); - - OsFree(ni->instname); - OsFree(ni); - down(&nvmelem_writelist_sem); - } - while(!list_empty(&nvmelem_writelist)) { + while(!list_empty(&nvm_newinst_list)) { + int err; - nvmelem_t *nel = list_entry(nvmelem_writelist.next, nvmelem_t, link); + nvmnewinst_t *ni = list_entry(nvm_newinst_list.next, nvmnewinst_t, link); + list_del(&ni->link); + up(&nvmelem_writelist_sem); - if(write) { - FILE *file; - int err; + err = write ? NVM_NewInstance(ni->instname) : 0; + if (err) { + //printk(KERN_ERR "%s: cannot create instance %s: err=%d failed again!\n", __FUNCTION__, ni->instname, err); + down(&nvmelem_writelist_sem); + list_add(&ni->link, &nvm_newinst_list); + goto done; + } - file = OsFOpen(nel->pathname, "w", &err); - if (!file) { - if(err == -EROFS) - goto done; + printk(KERN_WARNING "%s: instance %s successfully created\n", __FUNCTION__, ni->instname); - printk(KERN_ERR"%s: cannot open %s (errno=%d)\n", __FUNCTION__, nel->pathname, err); + OsFree(ni->instname); + OsFree(ni); - } else { - //printk(KERN_DEBUG"%s: writing %s\n", __FUNCTION__, nel->pathname); - NVM_WriteFileData(file, nel->pathname, nel->pBuf, nel->dwSize, nel->nvmFormat); - } + down(&nvmelem_writelist_sem); } - list_del(&nel->link); - - OsFree(nel); - } - + while(!list_empty(&nvmelem_writelist)) { + nvmelem_t *nel = list_entry(nvmelem_writelist.next, nvmelem_t, link); + if(write) { + FILE *file; + int err; + + file = OsFOpen(nel->pathname, "w", &err); + if (!file) { + if(err == -EROFS) + goto done; + printk(KERN_ERR"%s: cannot open %s (errno=%d)\n", __FUNCTION__, nel->pathname, err); + } + else { + //printk(KERN_DEBUG"%s: writing %s\n", __FUNCTION__, nel->pathname); + NVM_WriteFileData(file, nel->pathname, nel->pBuf, nel->dwSize, nel->nvmFormat); + } + } + list_del(&nel->link); + OsFree(nel); + } done: - up(&nvmelem_writelist_sem); + up(&nvmelem_writelist_sem); } -static BOOL -NVM_WriteFile(const char *pathname, PVOID pBuf, UINT32 dwSize, enum NVM_FORMAT nvmFormat, BOOL suspendInProgress) +static BOOL NVM_WriteFile(const char *pathname, PVOID pBuf, UINT32 dwSize, enum NVM_FORMAT nvmFormat, BOOL suspendInProgress) { - int err; - FILE *file; - - down(&nvmelem_writelist_sem); - if(!list_empty(&nvm_newinst_list) || !list_empty(&nvmelem_writelist) || suspendInProgress) { - if(!NVM_WriteListAppend(pathname, pBuf, dwSize, nvmFormat)) { - up(&nvmelem_writelist_sem); - return FALSE; - } - - up(&nvmelem_writelist_sem); - - NVM_WriteFlushList(TRUE); + int err; + FILE *file; - return TRUE; - } + down(&nvmelem_writelist_sem); + if(!list_empty(&nvm_newinst_list) || !list_empty(&nvmelem_writelist) || suspendInProgress) { + if(!NVM_WriteListAppend(pathname, pBuf, dwSize, nvmFormat)) { + up(&nvmelem_writelist_sem); + return FALSE; + } + up(&nvmelem_writelist_sem); + NVM_WriteFlushList(TRUE); + return TRUE; + } - file = OsFOpen(pathname, "w", &err); - if (!file) { - if(err == -EROFS) { - BOOL res; + file = OsFOpen(pathname, "w", &err); + if (!file) { + if(err == -EROFS) { + BOOL res; - //printk(KERN_DEBUG"%s: delaying write %s\n", __FUNCTION__, pathname); - res = NVM_WriteListAppend(pathname, pBuf, dwSize, nvmFormat); - up(&nvmelem_writelist_sem); - return res; + //printk(KERN_DEBUG"%s: delaying write %s\n", __FUNCTION__, pathname); + res = NVM_WriteListAppend(pathname, pBuf, dwSize, nvmFormat); + up(&nvmelem_writelist_sem); + return res; + } + up(&nvmelem_writelist_sem); + printk(KERN_ERR"%s: cannot open %s (errno=%d)\n", __FUNCTION__, pathname, err); + return FALSE; } up(&nvmelem_writelist_sem); - printk(KERN_ERR"%s: cannot open %s (errno=%d)\n", __FUNCTION__, pathname, err); - return FALSE; - } - up(&nvmelem_writelist_sem); + //printk(KERN_DEBUG"%s: opened %s\n", __FUNCTION__, pathname); - //printk(KERN_DEBUG"%s: opened %s\n", __FUNCTION__, pathname); - - return NVM_WriteFileData(file, pathname, pBuf, dwSize, nvmFormat); + return NVM_WriteFileData(file, pathname, pBuf, dwSize, nvmFormat); } /* Read in file containing either: - * - Sequence of two-digit hex bytes - * - String enclosed in "" - */ -static BOOL -NVM_ReadFile(const char *pathname, PVOID pBuf, UINT32 *pdwSize) +* - Sequence of two-digit hex bytes +* - String enclosed in "" +*/ +static BOOL NVM_ReadFile(const char *pathname, PVOID pBuf, UINT32 *pdwSize) { - int err; - FILE *file; - char buf[100], *p, *dp; - BOOL stringMode = FALSE; - UINT32 l; - int n; - struct list_head *lh; - int errno; - - down(&nvmelem_writelist_sem); - for(lh = nvmelem_writelist.prev; lh != &nvmelem_writelist; lh = lh->prev) { - nvmelem_t *nel = list_entry(lh, nvmelem_t, link); - - if(!strcmp(pathname, nel->pathname)) { - l = *pdwSize; - if(l > nel->dwSize) - l = nel->dwSize; - - memcpy(pBuf, nel->pBuf, l); - memset(pBuf + l, 0, *pdwSize - l); /* zero pBuf remainder */ - *pdwSize = l; - - if(osnvm_debug) - printk(KERN_DEBUG"%s: returning %s from writelist\n", __FUNCTION__, pathname); - - up(&nvmelem_writelist_sem); - return TRUE; - } - } - up(&nvmelem_writelist_sem); - - file = OsFOpen(pathname, "r", &err); - dp = pBuf; - l = *pdwSize; - - if (file) { - - if(osnvm_debug) - printk(KERN_DEBUG"%s: opened %s\n", __FUNCTION__, pathname); - - while(l > 0) { - n = OsFRead(buf, 1, sizeof(buf)-1, file, &errno); - if(n <= 0) - break; - - buf[n] = '\0'; + int err; + FILE *file; + char buf[100], *p, *dp; + BOOL stringMode = FALSE; + UINT32 l; + int n; + struct list_head *lh; + int errno; - for(p = buf; (l > 0) && (p < &buf[n]); p++) { + down(&nvmelem_writelist_sem); + for(lh = nvmelem_writelist.prev; lh != &nvmelem_writelist; lh = lh->prev) { + nvmelem_t *nel = list_entry(lh, nvmelem_t, link); - if(*p == '"') { - stringMode = !stringMode; - continue; - } + if(!strcmp(pathname, nel->pathname)) { + l = *pdwSize; + if(l > nel->dwSize) + l = nel->dwSize; - if(stringMode) { - *dp++ = *p; - l--; - continue; - } + memcpy(pBuf, nel->pBuf, l); + memset(pBuf + l, 0, *pdwSize - l); /* zero pBuf remainder */ + *pdwSize = l; - if(!isxdigit(*p)) - continue; - - /* hack to read COUNTRY_CODE as UINT16 without swapping: */ - if((p == buf) && (n == 5) && (l >= *pdwSize) && (*pdwSize == sizeof(UINT16)) && - isxdigit(p[1]) && isxdigit(p[2]) && - isxdigit(p[3]) && p[4] == '\n') { - *((UINT16*)dp) = simple_strtoul (p, &p, 16); - dp += 2; - l -= 2; - continue; - } + if(osnvm_debug) + printk(KERN_DEBUG"%s: returning %s from writelist\n", __FUNCTION__, pathname); - /* hack to read LICENSE_KEY as UINT32 without swapping: */ - if((p == buf) && (n == 9) && (l >= *pdwSize) && (*pdwSize == sizeof(UINT32)) && - isxdigit(p[1]) && isxdigit(p[2]) && - isxdigit(p[3]) && isxdigit(p[4]) && - isxdigit(p[5]) && isxdigit(p[6]) && - isxdigit(p[7]) && p[8] == '\n') { - *((UINT32*)dp) = simple_strtoul (p, &p, 16); - dp += 4; - l -= 4; - continue; + up(&nvmelem_writelist_sem); + return TRUE; } + } + up(&nvmelem_writelist_sem); - if(p == &buf[sizeof(buf)-1-1]) { - /* value split accross buffer boundary, read next chunk */ - buf[0] = *p; - p = buf; - n = OsFRead(buf+1, 1, sizeof(buf)-1-1, file, &errno); - if(n < 0) { - break; - } - n++; - buf[n] = '\0'; + file = OsFOpen(pathname, "r", &err); + dp = pBuf; + l = *pdwSize; + + if (file) { + + if(osnvm_debug) + printk(KERN_DEBUG"%s: opened %s\n", __FUNCTION__, pathname); + + while(l > 0) { + n = OsFRead(buf, 1, sizeof(buf)-1, file, &errno); + if(n <= 0) + break; + + buf[n] = '\0'; + for(p = buf; (l > 0) && (p < &buf[n]); p++) { + if(*p == '"') { + stringMode = !stringMode; + continue; + } + + if(stringMode) { + *dp++ = *p; + l--; + continue; + } + + if(!isxdigit(*p)) + continue; + + /* hack to read COUNTRY_CODE as UINT16 without swapping: */ + if((p == buf) && (n == 5) && (l >= *pdwSize) && (*pdwSize == sizeof(UINT16)) && + isxdigit(p[1]) && isxdigit(p[2]) && + isxdigit(p[3]) && p[4] == '\n') { + *((UINT16*)dp) = simple_strtoul (p, &p, 16); + dp += 2; + l -= 2; + continue; + } + + /* hack to read LICENSE_KEY as UINT32 without swapping: */ + if((p == buf) && (n == 9) && (l >= *pdwSize) && (*pdwSize == sizeof(UINT32)) && + isxdigit(p[1]) && isxdigit(p[2]) && + isxdigit(p[3]) && isxdigit(p[4]) && + isxdigit(p[5]) && isxdigit(p[6]) && + isxdigit(p[7]) && p[8] == '\n') { + *((UINT32*)dp) = simple_strtoul (p, &p, 16); + dp += 4; + l -= 4; + continue; + } + + if(p == &buf[sizeof(buf)-1-1]) { + /* value split accross buffer boundary, read next chunk */ + buf[0] = *p; + p = buf; + n = OsFRead(buf+1, 1, sizeof(buf)-1-1, file, &errno); + if(n < 0) { + break; + } + n++; + buf[n] = '\0'; + } + + *dp++ = simple_strtoul (p, &p, 16); + l--; + } } - - *dp++ = simple_strtoul (p, &p, 16); - l--; - } + OsFClose(file); + + if(osnvm_debug && l) + printk(KERN_DEBUG"%s: read %u bytes (%u missing) from %s\n", __FUNCTION__, *pdwSize - l, l, pathname); + } + else { + if(osnvm_debug) + printk(KERN_DEBUG"%s: cannot open %s (errno=%d)\n", __FUNCTION__, pathname, err); } - OsFClose(file); - - if(osnvm_debug && l) - printk(KERN_DEBUG"%s: read %u bytes (%u missing) from %s\n", __FUNCTION__, *pdwSize - l, l, pathname); - } else { - if(osnvm_debug) - printk(KERN_DEBUG"%s: cannot open %s (errno=%d)\n", __FUNCTION__, pathname, err); - } - - *pdwSize -= l; - - memset(dp, 0, l); /* zero pBuf remainder */ - - return file ? TRUE : FALSE; + *pdwSize -= l; + memset(dp, 0, l); /* zero pBuf remainder */ + return file ? TRUE : FALSE; } -static BOOL -NVM_ReadStaticParm(POS_DEVNODE pDevNode, const char *name, PVOID pBuf, UINT32 * pdwSize) +static BOOL NVM_ReadStaticParm(POS_DEVNODE pDevNode, const char *name, PVOID pBuf, UINT32 * pdwSize) { - char pathname[100]; + char pathname[100]; - snprintf(pathname, sizeof(pathname), "%s/%s/%s", cnxt_nvmdir_static, pDevNode->hwProfile, name); - return NVM_ReadFile(pathname, pBuf, pdwSize); + snprintf(pathname, sizeof(pathname), "%s/%s/%s", cnxt_nvmdir_static, pDevNode->hwProfile, name); + return NVM_ReadFile(pathname, pBuf, pdwSize); } -static BOOL -NVM_ReadDynamicParm(POS_DEVNODE pDevNode, const char *name, PVOID pBuf, UINT32 * pdwSize) +static BOOL NVM_ReadDynamicParm(POS_DEVNODE pDevNode, const char *name, PVOID pBuf, UINT32 * pdwSize) { - char pathname[100]; + char pathname[100]; - snprintf(pathname, sizeof(pathname), "%s/%d-%s/%s", cnxt_nvmdir_dynamic, pDevNode->hwInstNum, pDevNode->hwInstName, name); - return NVM_ReadFile(pathname, pBuf, pdwSize); + snprintf(pathname, sizeof(pathname), "%s/%d-%s/%s", cnxt_nvmdir_dynamic, pDevNode->hwInstNum, pDevNode->hwInstName, name); + return NVM_ReadFile(pathname, pBuf, pdwSize); } -static BOOL -NVM_ReadCountryParm(POS_DEVNODE pDevNode, int countryt35, UINT8 reference, const char *name, PVOID pBuf, UINT32 * pdwSize) +static BOOL NVM_ReadCountryParm(POS_DEVNODE pDevNode, int countryt35, UINT8 reference, const char *name, PVOID pBuf, UINT32 * pdwSize) { - char pathname[100]; - BOOL r; - UINT32 Size = pdwSize ? *pdwSize : 0; - - snprintf(pathname, sizeof(pathname), "%s/%s/Region/%04X%s", cnxt_nvmdir_static, pDevNode->hwProfile, countryt35, name); - r = NVM_ReadFile(pathname, pBuf, pdwSize); - if(!r && reference != 0xFF) { - snprintf(pathname, sizeof(pathname), "%s/%s/Profile/%04X%s", cnxt_nvmdir_static, pDevNode->hwProfile, reference, name); - if(pdwSize) - *pdwSize = Size; - return NVM_ReadFile(pathname, pBuf, pdwSize); - } else + char pathname[100]; + BOOL r; + UINT32 Size = pdwSize ? *pdwSize : 0; + + snprintf(pathname, sizeof(pathname), "%s/%s/Region/%04X%s", cnxt_nvmdir_static, pDevNode->hwProfile, countryt35, name); + r = NVM_ReadFile(pathname, pBuf, pdwSize); + if(!r && reference != 0xFF) { + snprintf(pathname, sizeof(pathname), "%s/%s/Profile/%04X%s", cnxt_nvmdir_static, pDevNode->hwProfile, reference, name); + if(pdwSize) + *pdwSize = Size; + return NVM_ReadFile(pathname, pBuf, pdwSize); + } return r; } -static BOOL -NVM_ReadCountry(POS_DEVNODE pDevNode, BYTE daaType, int countryt35, CtryPrmsStruct *ctryPrms) +static BOOL NVM_ReadCountry(POS_DEVNODE pDevNode, BYTE daaType, int countryt35, CtryPrmsStruct *ctryPrms) { - UINT32 dwSize; - UINT8 Reference = 0xFF; + UINT32 dwSize; + UINT8 Reference = 0xFF; char *nameTxLevel, *nameRelays; memset(ctryPrms, 0, sizeof(CtryPrmsStruct)); - //printk(KERN_DEBUG "%s: pDevNode=%p countryt35=%x daaType=%d\n", __FUNCTION__, pDevNode, countryt35, daaType); + //printk(KERN_DEBUG "%s: pDevNode=%p countryt35=%x daaType=%d\n", __FUNCTION__, pDevNode, countryt35, daaType); - ctryPrms->T35Code = countryt35; + ctryPrms->T35Code = countryt35; #if !TARGET_HCF_FAMILY /* HSF */ - dwSize = sizeof (Reference); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/REFERENCE", &Reference, &dwSize); + dwSize = sizeof (Reference); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/REFERENCE", &Reference, &dwSize); #endif - dwSize = sizeof (ctryPrms->cInter); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "_NAME", &ctryPrms->cInter, &dwSize); + dwSize = sizeof (ctryPrms->cInter); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "_NAME", &ctryPrms->cInter, &dwSize); - dwSize = sizeof (ctryPrms->cIntCode); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/INTCODE", &ctryPrms->cIntCode, &dwSize); + dwSize = sizeof (ctryPrms->cIntCode); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/INTCODE", &ctryPrms->cIntCode, &dwSize); #if !TARGET_HCF_FAMILY if((daaType == SI3054_DAA) || (daaType == SI3055_DAA)) { nameRelays = "/SILABRELAYS"; nameTxLevel = "/SMART_TXLEVEL"; - } else if(daaType == CAESAR) { + } + else if(daaType == CAESAR) { nameRelays = "/SMART_RELAYS"; nameTxLevel = "/SMART_TXLEVEL"; } else @@ -848,8 +810,8 @@ NVM_ReadCountry(POS_DEVNODE pDevNode, BYTE daaType, int countryt35, CtryPrmsStru nameTxLevel = "/TXLEVEL"; } - dwSize = sizeof (ctryPrms->Txlevel); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, nameTxLevel, &ctryPrms->Txlevel, &dwSize); + dwSize = sizeof (ctryPrms->Txlevel); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, nameTxLevel, &ctryPrms->Txlevel, &dwSize); if((daaType == SI3054_DAA) || (daaType == SI3055_DAA)) { int LowDialLevel = ctryPrms->Txlevel.LowDialLevel; @@ -866,85 +828,84 @@ NVM_ReadCountry(POS_DEVNODE pDevNode, BYTE daaType, int countryt35, CtryPrmsStru } } - dwSize = sizeof (ctryPrms->Relays); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, nameRelays, &ctryPrms->Relays, &dwSize); + dwSize = sizeof (ctryPrms->Relays); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, nameRelays, &ctryPrms->Relays, &dwSize); - dwSize = sizeof (ctryPrms->Pulse); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/PULSE", &ctryPrms->Pulse, &dwSize); + dwSize = sizeof (ctryPrms->Pulse); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/PULSE", &ctryPrms->Pulse, &dwSize); - dwSize = sizeof (ctryPrms->Ring); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/RING", &ctryPrms->Ring, &dwSize); + dwSize = sizeof (ctryPrms->Ring); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/RING", &ctryPrms->Ring, &dwSize); - dwSize = sizeof (ctryPrms->SRegLimits); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/SREG", &ctryPrms->SRegLimits, &dwSize); + dwSize = sizeof (ctryPrms->SRegLimits); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/SREG", &ctryPrms->SRegLimits, &dwSize); - dwSize = sizeof (ctryPrms->DTMF); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, (daaType == CAESAR) ? "/SMART_DTMF" : "/DTMF", &ctryPrms->DTMF, &dwSize); + dwSize = sizeof (ctryPrms->DTMF); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, (daaType == CAESAR) ? "/SMART_DTMF" : "/DTMF", &ctryPrms->DTMF, &dwSize); - /* FILTER: was commented out on HSF */ + /* FILTER: was commented out on HSF */ /* MARCXXX: Filter.Primary, Filter.Alternate, Filter.VoiceToneACallProgress/FilterVoiceToneA */ - dwSize = sizeof (ctryPrms->Filter); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/FILTER", &ctryPrms->Filter, &dwSize); + dwSize = sizeof (ctryPrms->Filter); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/FILTER", &ctryPrms->Filter, &dwSize); - dwSize = sizeof (ctryPrms->Threshold); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, (daaType == CAESAR) ? "/SMART_THRESHOLD" : "/THRESHOLD", &ctryPrms->Threshold, &dwSize); + dwSize = sizeof (ctryPrms->Threshold); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, (daaType == CAESAR) ? "/SMART_THRESHOLD" : "/THRESHOLD", &ctryPrms->Threshold, &dwSize); - dwSize = sizeof (ctryPrms->RLSD); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/RLSD", &ctryPrms->RLSD, &dwSize); + dwSize = sizeof (ctryPrms->RLSD); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/RLSD", &ctryPrms->RLSD, &dwSize); - dwSize = sizeof (ctryPrms->Tone); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/TONE", &ctryPrms->Tone, &dwSize); + dwSize = sizeof (ctryPrms->Tone); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/TONE", &ctryPrms->Tone, &dwSize); - dwSize = sizeof (ctryPrms->Timing); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/TIMING", &ctryPrms->Timing, &dwSize); + dwSize = sizeof (ctryPrms->Timing); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/TIMING", &ctryPrms->Timing, &dwSize); - dwSize = sizeof (ctryPrms->Cadence); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/CADENCE", &ctryPrms->Cadence, &dwSize); + dwSize = sizeof (ctryPrms->Cadence); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/CADENCE", &ctryPrms->Cadence, &dwSize); - dwSize = sizeof (ctryPrms->Blacklisting); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/BLACKLISTING", &ctryPrms->Blacklisting, &dwSize); + dwSize = sizeof (ctryPrms->Blacklisting); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/BLACKLISTING", &ctryPrms->Blacklisting, &dwSize); - dwSize = sizeof (ctryPrms->CallerID); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/CALLERID", &ctryPrms->CallerID, &dwSize); + dwSize = sizeof (ctryPrms->CallerID); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/CALLERID", &ctryPrms->CallerID, &dwSize); - dwSize = sizeof (ctryPrms->CallerID2); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/CALLERID2", &ctryPrms->CallerID2, &dwSize); + dwSize = sizeof (ctryPrms->CallerID2); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/CALLERID2", &ctryPrms->CallerID2, &dwSize); - dwSize = sizeof (ctryPrms->Flags); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/FLAGS", &ctryPrms->Flags, &dwSize); + dwSize = sizeof (ctryPrms->Flags); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/FLAGS", &ctryPrms->Flags, &dwSize); - dwSize = sizeof (ctryPrms->AgressSpeedIndex); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/SPEEDADJUST", &ctryPrms->AgressSpeedIndex, &dwSize); + dwSize = sizeof (ctryPrms->AgressSpeedIndex); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/SPEEDADJUST", &ctryPrms->AgressSpeedIndex, &dwSize); #if 0 - dwSize = sizeof (ctryPrms->PulseAbort); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/PULSE_ABORT", &ctryPrms->PulseAbort, &dwSize); + dwSize = sizeof (ctryPrms->PulseAbort); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/PULSE_ABORT", &ctryPrms->PulseAbort, &dwSize); #endif - dwSize = sizeof (ctryPrms->CallWaitingParms); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/CALL_WAITING", &ctryPrms->CallWaitingParms, &dwSize); + dwSize = sizeof (ctryPrms->CallWaitingParms); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/CALL_WAITING", &ctryPrms->CallWaitingParms, &dwSize); - dwSize = sizeof (ctryPrms->V92Control); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/V92_CONTROL", &ctryPrms->V92Control, &dwSize); + dwSize = sizeof (ctryPrms->V92Control); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/V92_CONTROL", &ctryPrms->V92Control, &dwSize); #if 0 - dwSize = sizeof (ctryPrms->ToneParams); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/TONEPARAMS", &ctryPrms->ToneParams, &dwSize); + dwSize = sizeof (ctryPrms->ToneParams); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/TONEPARAMS", &ctryPrms->ToneParams, &dwSize); #endif #if !TARGET_HCF_FAMILY - dwSize = sizeof (ctryPrms->OgcParams); - NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/V92_OGC", &ctryPrms->OgcParams, &dwSize); + dwSize = sizeof (ctryPrms->OgcParams); + NVM_ReadCountryParm(pDevNode, countryt35, Reference, "/V92_OGC", &ctryPrms->OgcParams, &dwSize); #endif - return TRUE; + return TRUE; } -static -BOOL isDynamicParm(CFGMGR_CODE eCode) +static BOOL isDynamicParm(CFGMGR_CODE eCode) { - switch(eCode) { + switch(eCode) { case CFGMGR_PROFILE_STORED: case CFGMGR_POUND_UD: case CFGMGR_BLACK_LIST: @@ -965,160 +926,146 @@ BOOL isDynamicParm(CFGMGR_CODE eCode) case CFGMGR_LICENSE_OWNER: case CFGMGR_LICENSE_KEY: case CFGMGR_LICENSE_STATUS: - return TRUE; + return TRUE; default: - return FALSE; - } + return FALSE; + } } -__shimcall__ -COM_STATUS -NVM_Read (HANDLE hNVM, CFGMGR_CODE eCode, PVOID pBuf, UINT32 * pdwSize) +__shimcall__ COM_STATUS NVM_Read (HANDLE hNVM, CFGMGR_CODE eCode, PVOID pBuf, UINT32 * pdwSize) { - POS_DEVNODE pDevNode = (POS_DEVNODE)hNVM; - BOOL res; - UINT32 Size; - - //printk(KERN_DEBUG "%s: pDevNode=%p CfgCode=%s Size=%p\n", __FUNCTION__, pDevNode, eCodeStr(eCode), pdwSize); - - if(isDynamicParm(eCode)) { - ASSERT(pdwSize); - - Size = *pdwSize; - - res = NVM_ReadDynamicParm(pDevNode, eCodeStr(eCode), pBuf, pdwSize); - if(!res) { - if (eCode == CFGMGR_COUNTRY_CODE) { - ASSERT(Size == sizeof(g_DefaultCountryCode)); - if(Size == sizeof(g_DefaultCountryCode)) { - memcpy(pBuf, &g_DefaultCountryCode, sizeof(g_DefaultCountryCode)); - *pdwSize = sizeof(g_DefaultCountryCode); - res = TRUE; - } - } else if (eCode == CFGMGR_PROFILE_STORED) { - ASSERT(Size == sizeof(g_FactoryProfile)); - if(Size == sizeof(g_FactoryProfile)) { - memcpy(pBuf, &g_FactoryProfile, sizeof(g_FactoryProfile)); - *pdwSize = sizeof(g_FactoryProfile); - res = TRUE; + POS_DEVNODE pDevNode = (POS_DEVNODE)hNVM; + BOOL res; + UINT32 Size; + + //printk(KERN_DEBUG "%s: pDevNode=%p CfgCode=%s Size=%p\n", __FUNCTION__, pDevNode, eCodeStr(eCode), pdwSize); + + if(isDynamicParm(eCode)) { + ASSERT(pdwSize); + + Size = *pdwSize; + res = NVM_ReadDynamicParm(pDevNode, eCodeStr(eCode), pBuf, pdwSize); + if(!res) { + if (eCode == CFGMGR_COUNTRY_CODE) { + ASSERT(Size == sizeof(g_DefaultCountryCode)); + if(Size == sizeof(g_DefaultCountryCode)) { + memcpy(pBuf, &g_DefaultCountryCode, sizeof(g_DefaultCountryCode)); + *pdwSize = sizeof(g_DefaultCountryCode); + res = TRUE; + } + } + else if (eCode == CFGMGR_PROFILE_STORED) { + ASSERT(Size == sizeof(g_FactoryProfile)); + if(Size == sizeof(g_FactoryProfile)) { + memcpy(pBuf, &g_FactoryProfile, sizeof(g_FactoryProfile)); + *pdwSize = sizeof(g_FactoryProfile); + res = TRUE; + } + res = FALSE; + } } - } - } - } else if(eCode == CFGMGR_COUNTRY_STRUCT) { + } + else if(eCode == CFGMGR_COUNTRY_STRUCT) { #if TARGET_HCF_FAMILY - res = NVM_ReadCountry(pDevNode, SIMPLE_DAA, (int)pdwSize, pBuf); + res = NVM_ReadCountry(pDevNode, SIMPLE_DAA, (int)pdwSize, pBuf); #else - BYTE daaType = SIMPLE_DAA; + BYTE daaType = SIMPLE_DAA; - Size = sizeof(daaType); - NVM_Read (hNVM, CFGMGR_OEM_DAATYPE, &daaType, &Size); - res = NVM_ReadCountry(pDevNode, daaType, (int)(unsigned long)pdwSize, pBuf); + Size = sizeof(daaType); + NVM_Read (hNVM, CFGMGR_OEM_DAATYPE, &daaType, &Size); + res = NVM_ReadCountry(pDevNode, daaType, (int)(unsigned long)pdwSize, pBuf); #endif - } else { - Size = *pdwSize; - - res = NVM_ReadStaticParm(pDevNode, eCodeStr(eCode), pBuf, pdwSize); - if(!res && (eCode == CFGMGR_PROFILE_FACTORY)) { - ASSERT(Size == sizeof(g_FactoryProfile)); - if(Size == sizeof(g_FactoryProfile)) { - memcpy(pBuf, &g_FactoryProfile, sizeof(g_FactoryProfile)); - *pdwSize = sizeof(g_FactoryProfile); - res = TRUE; - } + } else { + Size = *pdwSize; + + res = NVM_ReadStaticParm(pDevNode, eCodeStr(eCode), pBuf, pdwSize); + if(!res && (eCode == CFGMGR_PROFILE_FACTORY)) { + ASSERT(Size == sizeof(g_FactoryProfile)); + if(Size == sizeof(g_FactoryProfile)) { + memcpy(pBuf, &g_FactoryProfile, sizeof(g_FactoryProfile)); + *pdwSize = sizeof(g_FactoryProfile); + res = TRUE; + } + } } - } - return res ? COM_STATUS_SUCCESS : COM_STATUS_VALUE_NOT_FOUND; + return res ? COM_STATUS_SUCCESS : COM_STATUS_VALUE_NOT_FOUND; } -__shimcall__ -COM_STATUS -NVM_Write (HANDLE hNVM, CFGMGR_CODE eCode, PVOID pBuf, PUINT32 pdwSize) +__shimcall__ COM_STATUS NVM_Write (HANDLE hNVM, CFGMGR_CODE eCode, PVOID pBuf, PUINT32 pdwSize) { - POS_DEVNODE pDevNode = (POS_DEVNODE)hNVM; - char pathname[100]; + POS_DEVNODE pDevNode = (POS_DEVNODE)hNVM; + char pathname[100]; - //printk(KERN_DEBUG "%s: pDevNode=%p CfgCode=%s Size=%ld\n", __FUNCTION__, pDevNode, eCodeStr(eCode), *pdwSize); + //printk(KERN_DEBUG "%s: pDevNode=%p CfgCode=%s Size=%ld\n", __FUNCTION__, pDevNode, eCodeStr(eCode), *pdwSize); if(pDevNode->hwSuspendInProgress) return COM_STATUS_FAIL; - - if(!isDynamicParm(eCode)) { - printk(KERN_WARNING "%s: pDevNode=%p: saving static parameter, CfgCode=%s Size=%d\n", __FUNCTION__, pDevNode, eCodeStr(eCode), *pdwSize); - } - - snprintf(pathname, sizeof(pathname), "%s/%d-%s/%s", cnxt_nvmdir_dynamic, pDevNode->hwInstNum, pDevNode->hwInstName, eCodeStr(eCode)); - - return NVM_WriteFile(pathname, pBuf, *pdwSize, nvmFormat(eCode), pDevNode->hwSuspendInProgress) ? COM_STATUS_SUCCESS : COM_STATUS_FAIL; + if(!isDynamicParm(eCode)) + printk(KERN_WARNING "%s: pDevNode=%p: saving static parameter, CfgCode=%s Size=%d\n", __FUNCTION__, pDevNode, eCodeStr(eCode), *pdwSize); + snprintf(pathname, sizeof(pathname), "%s/%d-%s/%s", cnxt_nvmdir_dynamic, pDevNode->hwInstNum, pDevNode->hwInstName, eCodeStr(eCode)); + return NVM_WriteFile(pathname, pBuf, *pdwSize, nvmFormat(eCode), pDevNode->hwSuspendInProgress) ? COM_STATUS_SUCCESS : COM_STATUS_FAIL; } -__shimcall__ -HANDLE -NVM_Open (ULONG_PTR dwDevNode) +__shimcall__ HANDLE NVM_Open (ULONG_PTR dwDevNode) { - POS_DEVNODE pDevNode = (POS_DEVNODE)dwDevNode; - char instname[100]; - int err; - char hwProfile[sizeof(pDevNode->hwProfile)]; - UINT32 uiSize; - nvmnewinst_t *newinst; - - snprintf(instname, sizeof(instname), "%d-%s", pDevNode->hwInstNum, pDevNode->hwInstName); - - err = NVM_NewInstance(instname); - - if(err) { - printk(KERN_WARNING "%s: cannot create instance %s: err=%d will retry later...\n", __FUNCTION__, instname, err); - newinst = OsAllocate(sizeof(nvmnewinst_t)); - if (!newinst) - return NULL; - newinst->instname = OsAllocate(strlen(instname) + 1); - if (!newinst->instname) { - OsFree(newinst); - return NULL; + POS_DEVNODE pDevNode = (POS_DEVNODE)dwDevNode; + char instname[100]; + int err; + char hwProfile[sizeof(pDevNode->hwProfile)]; + UINT32 uiSize; + nvmnewinst_t *newinst; + + snprintf(instname, sizeof(instname), "%d-%s", pDevNode->hwInstNum, pDevNode->hwInstName); + err = NVM_NewInstance(instname); + if(err) { + printk(KERN_WARNING "%s: cannot create instance %s: err=%d will retry later...\n", __FUNCTION__, instname, err); + newinst = OsAllocate(sizeof(nvmnewinst_t)); + if (!newinst) + return NULL; + newinst->instname = OsAllocate(strlen(instname) + 1); + if (!newinst->instname) { + OsFree(newinst); + return NULL; + } + strcpy(newinst->instname, instname); + down(&nvmelem_writelist_sem); + list_add_tail(&newinst->link, &nvm_newinst_list); + up(&nvmelem_writelist_sem); } - strcpy(newinst->instname, instname); - down(&nvmelem_writelist_sem); - list_add_tail(&newinst->link, &nvm_newinst_list); - up(&nvmelem_writelist_sem); - } + uiSize = sizeof(hwProfile); + if(NVM_Read(pDevNode, CFGMGR_HARDWARE_PROFILE, hwProfile, &uiSize) == COM_STATUS_SUCCESS) { + strncpy(pDevNode->hwProfile, hwProfile, sizeof(pDevNode->hwProfile)); + pDevNode->hwProfile[sizeof(pDevNode->hwProfile)-1] = '\0'; + } - uiSize = sizeof(hwProfile); - if(NVM_Read(pDevNode, CFGMGR_HARDWARE_PROFILE, hwProfile, &uiSize) == COM_STATUS_SUCCESS) { - strncpy(pDevNode->hwProfile, hwProfile, sizeof(pDevNode->hwProfile)); - pDevNode->hwProfile[sizeof(pDevNode->hwProfile)-1] = '\0'; - } + if(!strncmp(pDevNode->hwInstName, "PCI", 3)) { + UINT16 pci_id; + UINT32 size; - if(!strncmp(pDevNode->hwInstName, "PCI", 3)) { - UINT16 pci_id; - UINT32 size; + size = sizeof(pci_id); + pci_id = ((struct pci_dev *)pDevNode->hwDev)->device; + NVM_Write(pDevNode, CFGMGR_PCI_DEVICE_ID, &pci_id, &size); - size = sizeof(pci_id); - pci_id = ((struct pci_dev *)pDevNode->hwDev)->device; - NVM_Write(pDevNode, CFGMGR_PCI_DEVICE_ID, &pci_id, &size); - - size = sizeof(pci_id); - pci_id = ((struct pci_dev *)pDevNode->hwDev)->vendor; - NVM_Write(pDevNode, CFGMGR_PCI_VENDOR_ID, &pci_id, &size); - } - return pDevNode; + size = sizeof(pci_id); + pci_id = ((struct pci_dev *)pDevNode->hwDev)->vendor; + NVM_Write(pDevNode, CFGMGR_PCI_VENDOR_ID, &pci_id, &size); + } + return pDevNode; } -__shimcall__ -COM_STATUS -NVM_Close (HANDLE hNVM) +__shimcall__ COM_STATUS NVM_Close (HANDLE hNVM) { - //printk(KERN_DEBUG "%s: hNVM=%p\n", __FUNCTION__, hNVM); + //printk(KERN_DEBUG "%s: hNVM=%p\n", __FUNCTION__, hNVM); - NVM_WriteFlushList(TRUE); + NVM_WriteFlushList(TRUE); - return COM_STATUS_SUCCESS; + return COM_STATUS_SUCCESS; } -void -OsNvmExit(void) +void OsNvmExit(void) { - //printk(KERN_DEBUG "%s: hNVM=%p\n", __FUNCTION__, hNVM); + //printk(KERN_DEBUG "%s: hNVM=%p\n", __FUNCTION__, hNVM); - NVM_WriteFlushList(FALSE); + NVM_WriteFlushList(FALSE); } diff --git a/modules/osresour.c b/modules/osresour.c old mode 100644 new mode 100755 diff --git a/modules/osscr.c b/modules/osscr.c old mode 100644 new mode 100755 diff --git a/modules/osservices.c b/modules/osservices.c old mode 100644 new mode 100755 index a9ca606..8c337d6 --- a/modules/osservices.c +++ b/modules/osservices.c @@ -1,11 +1,11 @@ /* - * Copyright (c) 2003-2004 Linuxant inc. - * - * NOTE: The use and distribution of this software is governed by the terms in - * the file LICENSE, which is included in the package. You must read this and - * agree to these terms before using or distributing this software. - * - */ +* Copyright (c) 2003-2004 Linuxant inc. +* +* NOTE: The use and distribution of this software is governed by the terms in +* the file LICENSE, which is included in the package. You must read this and +* agree to these terms before using or distributing this software. +* +*/ #ifndef __powerpc__ #define __KERNEL_SYSCALLS__ @@ -44,6 +44,9 @@ #include #include #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) +#include +#endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)) #include #endif @@ -63,6 +66,12 @@ #endif #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) +#include + +#define rdtscl(x) rdtscll(x) +#endif + #ifdef for_each_process #define sigmask_lock sighand->siglock #define recalc_sigpending_curtask(t) recalc_sigpending() @@ -71,222 +80,223 @@ #define recalc_sigpending_curtask(t) recalc_sigpending(t) #endif +//#define CNXTTARGET 'hsf' /********************************************************************/ /* Critical Sections (Mutexes) */ typedef struct { #ifdef CONFIG_SMP - spinlock_t spinlock; + spinlock_t spinlock; #else - volatile unsigned long lock; + volatile unsigned long lock; #endif - unsigned long flags; - unsigned long nestcnt; - int owner_cpu; + unsigned long flags; + unsigned long nestcnt; + int owner_cpu; } CRIT_T; __shimcall__ GLOBAL HCRIT OsCriticalSectionCreate(void) { - CRIT_T *mutex; + CRIT_T *mutex; - ASSERT(OsContextAllowsSleeping()); - mutex = kmalloc(sizeof(CRIT_T), GFP_KERNEL); - if(!mutex) { - ASSERT(mutex); - return NULL; - } + ASSERT(OsContextAllowsSleeping()); + mutex = kmalloc(sizeof(CRIT_T), GFP_KERNEL); + if(!mutex) { + ASSERT(mutex); + return NULL; + } #ifdef CONFIG_SMP - spin_lock_init(&mutex->spinlock); + spin_lock_init(&mutex->spinlock); #else - mutex->lock = 0; + mutex->lock = 0; #endif - mutex->nestcnt = 0; + mutex->nestcnt = 0; - return ((HCRIT)mutex); + return ((HCRIT)mutex); } __shimcall__ GLOBAL VOID OsCriticalSectionDestroy(IN HCRIT hMutex) { - if ( NULL == hMutex ) - { - ASSERT(hMutex); - return; - } - kfree((CRIT_T *)hMutex); + if ( NULL == hMutex ) + { + ASSERT(hMutex); + return; + } + kfree((CRIT_T *)hMutex); } __shimcall__ GLOBAL VOID OsCriticalSectionAcquire(IN HCRIT hMutex) { - CRIT_T *mutex = (CRIT_T *) hMutex; - unsigned long flags; - int cpu; + CRIT_T *mutex = (CRIT_T *) hMutex; + unsigned long flags; + int cpu; - ASSERT(hMutex); + ASSERT(hMutex); - if(!hMutex) /* temporary due to HCF global critical section issue */ + if(!hMutex) /* temporary due to HCF global critical section issue */ return; - local_irq_save(flags); + local_irq_save(flags); - cpu = smp_processor_id(); + cpu = smp_processor_id(); #ifdef CONFIG_SMP - if(!spin_trylock(&mutex->spinlock)) + if(!spin_trylock(&mutex->spinlock)) #else - if(test_and_set_bit(0,(&mutex->lock))) + if(test_and_set_bit(0,(&mutex->lock))) #endif - { + { - if(cpu == mutex->owner_cpu) { - mutex->nestcnt++; - local_irq_restore(flags); - return; - } + if(cpu == mutex->owner_cpu) { + mutex->nestcnt++; + local_irq_restore(flags); + return; + } #ifdef CONFIG_SMP - spin_lock(&mutex->spinlock); + spin_lock(&mutex->spinlock); #else - mutex->lock = 1; + mutex->lock = 1; #endif - } + } - mutex->owner_cpu = cpu; - mutex->flags = flags; + mutex->owner_cpu = cpu; + mutex->flags = flags; - return; + return; } __shimcall__ GLOBAL VOID OsCriticalSectionRelease(IN HCRIT hMutex) { - CRIT_T *mutex = (CRIT_T *) hMutex; + CRIT_T *mutex = (CRIT_T *) hMutex; - ASSERT(hMutex); + ASSERT(hMutex); - if(!hMutex) /* temporary due to HCF global critical section issue */ + if(!hMutex) /* temporary due to HCF global critical section issue */ return; - if(mutex->nestcnt) { - mutex->nestcnt--; - return; - } + if(mutex->nestcnt) { + mutex->nestcnt--; + return; + } #ifdef CONFIG_SMP - spin_unlock(&mutex->spinlock); + spin_unlock(&mutex->spinlock); #else - mutex->lock = 0; + mutex->lock = 0; #endif - local_irq_restore(mutex->flags); + local_irq_restore(mutex->flags); } /********************************************************************/ typedef struct tagLS { - spinlock_t spinlock; - struct semaphore semaphore; - void *owner; - unsigned long nestcnt; + spinlock_t spinlock; + struct semaphore semaphore; + void *owner; + unsigned long nestcnt; } LS, *PLS; __shimcall__ HLOCK OsLockCreate(void) { - PLS pLock = (PLS)OsAllocate(sizeof(LS)); + PLS pLock = (PLS)OsAllocate(sizeof(LS)); - if(pLock) { - spin_lock_init(&pLock->spinlock); - sema_init(&pLock->semaphore, 1); + if(pLock) { + spin_lock_init(&pLock->spinlock); + sema_init(&pLock->semaphore, 1); - pLock->owner = NULL; - pLock->nestcnt = 0; - } + pLock->owner = NULL; + pLock->nestcnt = 0; + } - //printk(KERN_DEBUG"%s: %p\n", __FUNCTION__, pLock); - return (HLOCK)pLock; + //printk(KERN_DEBUG"%s: %p\n", __FUNCTION__, pLock); + return (HLOCK)pLock; } __shimcall__ void OsLockDestroy(HLOCK hLock) { - //printk(KERN_DEBUG"%s: %p\n", __FUNCTION__, hLock); - if(hLock) + //printk(KERN_DEBUG"%s: %p\n", __FUNCTION__, hLock); + if(hLock) OsFree((PLS)hLock); } __shimcall__ void OsLockLock(HLOCK hLock) { - unsigned long flags; + unsigned long flags; - //printk(KERN_DEBUG"%s: down %p\n", __FUNCTION__, hLock); + //printk(KERN_DEBUG"%s: down %p\n", __FUNCTION__, hLock); - ASSERT(OsContextAllowsSleeping()); - spin_lock_irqsave(&((PLS)hLock)->spinlock, flags); - if(down_trylock(&((PLS)hLock)->semaphore) != 0) { - if(((PLS)hLock)->owner == current) { - ((PLS)hLock)->nestcnt++; - //printk(KERN_DEBUG"%s: ret %p (nestcnt=%lu)\n", __FUNCTION__, hLock, ((PLS)hLock)->nestcnt); - spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); - return; - } - spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); ASSERT(OsContextAllowsSleeping()); - down(&((PLS)hLock)->semaphore); spin_lock_irqsave(&((PLS)hLock)->spinlock, flags); - } - ((PLS)hLock)->owner = current; - spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); - //printk(KERN_DEBUG"%s: ret %p\n", __FUNCTION__, hLock); + if(down_trylock(&((PLS)hLock)->semaphore) != 0) { + if(((PLS)hLock)->owner == current) { + ((PLS)hLock)->nestcnt++; + //printk(KERN_DEBUG"%s: ret %p (nestcnt=%lu)\n", __FUNCTION__, hLock, ((PLS)hLock)->nestcnt); + spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); + return; + } + spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); + ASSERT(OsContextAllowsSleeping()); + down(&((PLS)hLock)->semaphore); + spin_lock_irqsave(&((PLS)hLock)->spinlock, flags); + } + ((PLS)hLock)->owner = current; + spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); + //printk(KERN_DEBUG"%s: ret %p\n", __FUNCTION__, hLock); } __shimcall__ void OsLockUnlock(HLOCK hLock) { - unsigned long flags; + unsigned long flags; - //printk(KERN_DEBUG"%s: up %p\n", __FUNCTION__, hLock); - spin_lock_irqsave(&((PLS)hLock)->spinlock, flags); - if(((PLS)hLock)->nestcnt) { - ((PLS)hLock)->nestcnt--; + //printk(KERN_DEBUG"%s: up %p\n", __FUNCTION__, hLock); + spin_lock_irqsave(&((PLS)hLock)->spinlock, flags); + if(((PLS)hLock)->nestcnt) { + ((PLS)hLock)->nestcnt--; + spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); + return; + } + ((PLS)hLock)->owner = NULL; spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); - return; - } - ((PLS)hLock)->owner = NULL; - spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); - up(&((PLS)hLock)->semaphore); + up(&((PLS)hLock)->semaphore); } __shimcall__ BOOL OsLockTry(HLOCK hLock) { - unsigned long flags; + unsigned long flags; - spin_lock_irqsave(&((PLS)hLock)->spinlock, flags); - if(down_trylock(&((PLS)hLock)->semaphore) != 0) { - if(((PLS)hLock)->owner == current) { - ((PLS)hLock)->nestcnt++; - //printk(KERN_DEBUG"%s: ret %p (nestcnt=%lu) TRUE\n", __FUNCTION__, hLock, ((PLS)hLock)->nestcnt); - spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); - return TRUE; + spin_lock_irqsave(&((PLS)hLock)->spinlock, flags); + if(down_trylock(&((PLS)hLock)->semaphore) != 0) { + if(((PLS)hLock)->owner == current) { + ((PLS)hLock)->nestcnt++; + //printk(KERN_DEBUG"%s: ret %p (nestcnt=%lu) TRUE\n", __FUNCTION__, hLock, ((PLS)hLock)->nestcnt); + spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); + return TRUE; + } + //printk(KERN_DEBUG"%s: ret %p FALSE\n", __FUNCTION__, hLock); + spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); + return FALSE; } - //printk(KERN_DEBUG"%s: ret %p FALSE\n", __FUNCTION__, hLock); + ((PLS)hLock)->owner = current; spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); - return FALSE; - } - ((PLS)hLock)->owner = current; - spin_unlock_irqrestore(&((PLS)hLock)->spinlock, flags); - //printk(KERN_DEBUG"%s: ret %p TRUE\n", __FUNCTION__, hLock); - return TRUE; + //printk(KERN_DEBUG"%s: ret %p TRUE\n", __FUNCTION__, hLock); + return TRUE; } __shimcall__ void OsLockTryUnlock(HLOCK hLock) { - //printk(KERN_DEBUG"%s: up %p\n", __FUNCTION__, hLock); - OsLockUnlock(hLock); + //printk(KERN_DEBUG"%s: up %p\n", __FUNCTION__, hLock); + OsLockUnlock(hLock); } /********************************************************************/ @@ -299,22 +309,22 @@ static spinlock_t atomic_lock __attribute__((unused)) = SPIN_LOCK_UNLOCKED; #endif /**************************************************************************************** - The OsAtomicCompareAndSwap function compares the value at the specified address with - oldVal. The value of newValue is written to the address only if oldValue and the - value at the address are equal. OsCompareAndSwap returns true if newValue is written - to the address; otherwise, it returns false. +The OsAtomicCompareAndSwap function compares the value at the specified address with +oldVal. The value of newValue is written to the address only if oldValue and the +value at the address are equal. OsCompareAndSwap returns true if newValue is written +to the address; otherwise, it returns false. Params: oldValue The value to compare at address. newValue The value to write to address if oldValue compares true. address The 4-byte aligned address of the data to update atomically. Result: true if newValue was written to the address. - ****************************************************************************************/ +****************************************************************************************/ __shimcall__ BOOL OsAtomicCompareAndSwapEx (PVOID oldValue, PVOID newValue, PVOID* address, INT size) { #if defined(__HAVE_ARCH_CMPXCHG) && !defined(__powerpc__) - switch(size) { + switch(size) { case sizeof(u8): return (cmpxchg(((u8*)address), (ULONG_PTR)oldValue, (ULONG_PTR)newValue) == (u8)(ULONG_PTR)oldValue); case sizeof(u16): @@ -330,179 +340,159 @@ BOOL OsAtomicCompareAndSwapEx (PVOID oldValue, PVOID newValue, PVOID* address, I default: printk(KERN_ERR"%s: size=%d not supported\n", __FUNCTION__, size); return TRUE; - } + } #else - unsigned long flags; - BOOL ret = FALSE; + unsigned long flags; + BOOL ret = FALSE; - spin_lock_irqsave(&atomic_lock, flags); + spin_lock_irqsave(&atomic_lock, flags); - switch(size) { + switch(size) { case sizeof(u8): if (*(u8*)address == (u8)(ULONG_PTR)oldValue) { - *(u8*)address = (u8)(ULONG_PTR)newValue; - ret = TRUE; + *(u8*)address = (u8)(ULONG_PTR)newValue; + ret = TRUE; } break; case sizeof(u16): if (*(u16*)address == (u16)(ULONG_PTR)oldValue) { - *(u16*)address = (u16)(ULONG_PTR)newValue; - ret = TRUE; + *(u16*)address = (u16)(ULONG_PTR)newValue; + ret = TRUE; } break; case sizeof(u32): if (*(u32*)address == (u32)(ULONG_PTR)oldValue) { - *(u32*)address = (u32)(ULONG_PTR)newValue; - ret = TRUE; + *(u32*)address = (u32)(ULONG_PTR)newValue; + ret = TRUE; } break; case sizeof(u64): if (*(u64*)address == (u64)(ULONG_PTR)oldValue) { - *(u64*)address = (u64)(ULONG_PTR)newValue; - ret = TRUE; + *(u64*)address = (u64)(ULONG_PTR)newValue; + ret = TRUE; } break; default: printk(KERN_ERR"%s: size=%d not supported\n", __FUNCTION__, size); ret = TRUE; break; - } + } - spin_unlock_irqrestore(&atomic_lock, flags); + spin_unlock_irqrestore(&atomic_lock, flags); -//printk(KERN_ERR"%s: size=%d ret=%d\n", __FUNCTION__, size, ret); - return ret; + //printk(KERN_ERR"%s: size=%d ret=%d\n", __FUNCTION__, size, ret); + return ret; #endif } -__shimcall__ -INT32 OsAtomicAdd (INT32 amount, PINT32 address) +__shimcall__ INT32 OsAtomicAdd (INT32 amount, PINT32 address) { - unsigned long flags; - atomic_t *v = (atomic_t *)address; + unsigned long flags; + atomic_t *v = (atomic_t *)address; - spin_lock_irqsave(&atomic_lock, flags); - atomic_add(amount, v); - amount = atomic_read(v); - spin_unlock_irqrestore(&atomic_lock, flags); + spin_lock_irqsave(&atomic_lock, flags); + atomic_add(amount, v); + amount = atomic_read(v); + spin_unlock_irqrestore(&atomic_lock, flags); - return amount; + return amount; } -__shimcall__ -INT32 OsAtomicIncrement (PINT32 address) -{ - unsigned long flags; - atomic_t *v = (atomic_t *)address; - INT32 amount; - - spin_lock_irqsave(&atomic_lock, flags); - atomic_inc(v); - amount = atomic_read(v); - spin_unlock_irqrestore(&atomic_lock, flags); +__shimcall__ INT32 OsAtomicIncrement (PINT32 address){ + unsigned long flags; + atomic_t *v = (atomic_t *)address; + INT32 amount; - return amount; + spin_lock_irqsave(&atomic_lock, flags); + atomic_inc(v); + amount = atomic_read(v); + spin_unlock_irqrestore(&atomic_lock, flags); + return amount; } -__shimcall__ -INT32 OsAtomicDecrement (PINT32 address) +__shimcall__ INT32 OsAtomicDecrement (PINT32 address) { - unsigned long flags; - atomic_t *v = (atomic_t *)address; - INT32 amount; + unsigned long flags; + atomic_t *v = (atomic_t *)address; + INT32 amount; - spin_lock_irqsave(&atomic_lock, flags); - atomic_dec(v); - amount = atomic_read(v); - spin_unlock_irqrestore(&atomic_lock, flags); + spin_lock_irqsave(&atomic_lock, flags); + atomic_dec(v); + amount = atomic_read(v); + spin_unlock_irqrestore(&atomic_lock, flags); - return amount; + return amount; } #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0) ) struct _OSTHRD { - int pid; - struct kthread_worker kworker; - struct task_struct *kworker_task; + int pid; + struct kthread_worker kworker; + struct task_struct *kworker_task; }; struct kwork_data { - struct kthread_work work; - void (*func)(void *); - void* data; + struct kthread_work work; + void (*func)(void *); + void* data; }; -static void -OsThreadStart(OSTHRD *osthrd, const char *name, BOOLEAN highestprio) +static void OsThreadStart(OSTHRD *osthrd, const char *name, BOOLEAN highestprio) { - struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; - - memset(osthrd, 0, sizeof(*osthrd)); + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + memset(osthrd, 0, sizeof(OSTHRD)); init_kthread_worker(&osthrd->kworker); - osthrd->kworker_task = kthread_run(kthread_worker_fn, &osthrd->kworker, "k%sd/%s", CNXTTARGET, name); - if (IS_ERR(osthrd->kworker_task)) { - return; - } - - osthrd->pid = osthrd->kworker_task->pid; - - if(highestprio) { - sched_setscheduler(osthrd->kworker_task, SCHED_FIFO, ¶m); - } + osthrd->kworker_task = kthread_run(kthread_worker_fn, &osthrd->kworker, "k%s/%s", CNXTTARGET, name); + if (IS_ERR(osthrd->kworker_task)){ + printk(KERN_DEBUG "%s: Failed to create thread %p\n", __FUNCTION__, osthrd); + return; + } + osthrd->pid = osthrd->kworker_task->pid; + if(highestprio) + sched_setscheduler(osthrd->kworker_task, SCHED_FIFO, ¶m); } -static void -OsThreadStop(OSTHRD *osthrd) +static void OsThreadStop(OSTHRD *osthrd) { - if (!IS_ERR(osthrd->kworker_task)) { - kthread_stop(osthrd->kworker_task); - } + if (!IS_ERR(osthrd->kworker_task)) + kthread_stop(osthrd->kworker_task); } -__shimcall__ -POSTHRD -OsThreadCreate(const char *name, BOOLEAN highestprio, int *pid) +__shimcall__ POSTHRD OsThreadCreate(const char *name, BOOLEAN highestprio, int *pid) { OSTHRD *osthrd = OsAllocate(sizeof(OSTHRD)); - if(osthrd) { OsThreadStart(osthrd, name, highestprio); if(pid) *pid = osthrd->pid; } - return osthrd; } -__shimcall__ -void -OsThreadDestroy(POSTHRD osthrd) +__shimcall__ void OsThreadDestroy(POSTHRD osthrd) { OsThreadStop(osthrd); OsFree(osthrd); } -static void -unwrap_kwork(struct kthread_work *work) +static void unwrap_kwork(struct kthread_work *work) { - struct kwork_data *w = container_of(work, struct kwork_data, work); - w->func(w->data); + struct kwork_data *w = container_of(work, struct kwork_data, work); + w->func(w->data); } -__shimcall__ -void OsThreadScheduleInit(HOSSCHED hWorkStorage, __kernelcall__ void (*func)(void *), void * data) +__shimcall__ void OsThreadScheduleInit(HOSSCHED hWorkStorage, __kernelcall__ void (*func)(void *), void * data) { struct kwork_data *w = (struct kwork_data *)hWorkStorage; - init_kthread_work(&w->work, unwrap_kwork); - w->func = func; - w->data = data; + init_kthread_work(&w->work, unwrap_kwork); + w->func = func; + w->data = data; } -__shimcall__ -int OsThreadSchedule(POSTHRD osthrd, HOSSCHED hWorkStorage) +__shimcall__ int OsThreadSchedule(POSTHRD osthrd, HOSSCHED hWorkStorage) { bool ret; struct kwork_data *w = (struct kwork_data *)hWorkStorage; @@ -511,20 +501,16 @@ int OsThreadSchedule(POSTHRD osthrd, HOSSCHED hWorkStorage) printk(KERN_DEBUG "%s: no thread %p\n", __FUNCTION__, osthrd); return 0; } - OsModuleUseCountInc(); ret = queue_kthread_work(&osthrd->kworker, &w->work); - if(!ret) { + if(!ret) OsModuleUseCountDec(); - } - return ret; } -__shimcall__ -void OsThreadScheduleDone(void) +__shimcall__ void OsThreadScheduleDone(void) { - OsModuleUseCountDec(); + OsModuleUseCountDec(); } #else @@ -684,7 +670,7 @@ static int cnxt_thread(OSTHRD *osthrd) memcpy(¤t->uid, &osthrd->ts.uid, sizeof(osthrd->ts) - (int)(&((struct task_struct *)0)->uid)); unlock_kernel(); if(!osthrd->stack_overflows++) - printk(KERN_WARNING"%s: %d stack overflow\n", __FUNCTION__, current->pid); + printk(KERN_WARNING"%s: %d stack overflow\n", __FUNCTION__, current->pid); } #endif @@ -700,22 +686,21 @@ static int cnxt_thread(OSTHRD *osthrd) handle_sigs(); - osthrd->pid = 0; + osthrd->pid = 0; #ifdef DECLARE_COMPLETION #if defined(complete_and_exit) || ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9) ) - complete_and_exit(&osthrd->exited, 0); + complete_and_exit(&osthrd->exited, 0); #else - complete(&osthrd->exited); - up_and_exit(NULL, 0); + complete(&osthrd->exited); + up_and_exit(NULL, 0); #endif #else - osthrd->running = 0; - return 0; + osthrd->running = 0; + return 0; #endif } -static void -OsThreadStart(OSTHRD *osthrd, const char *name, BOOLEAN highestprio) +static void OsThreadStart(OSTHRD *osthrd, const char *name, BOOLEAN highestprio) { memset(osthrd, 0, sizeof(*osthrd)); @@ -728,7 +713,6 @@ OsThreadStart(OSTHRD *osthrd, const char *name, BOOLEAN highestprio) #ifdef DECLARE_COMPLETION init_completion(&osthrd->started); init_completion(&osthrd->exited); - osthrd->pid = kernel_thread((int (*)(void *))cnxt_thread, osthrd, 0); if(osthrd->pid < 0) return; @@ -755,8 +739,7 @@ OsThreadStart(OSTHRD *osthrd, const char *name, BOOLEAN highestprio) //OsDebugPrintf("%s: started pid %d (%s)\n", __FUNCTION__, osthrd->pid, osthrd->name); } -static void -OsThreadStop(OSTHRD *osthrd) +static void OsThreadStop(OSTHRD *osthrd) { //OsDebugPrintf("%s: stopping thread=%p pid=%d name=%s\n", __FUNCTION__, osthrd, osthrd->pid, osthrd->name); @@ -784,24 +767,20 @@ OsThreadStop(OSTHRD *osthrd) } } -__shimcall__ -POSTHRD -OsThreadCreate(const char *name, BOOLEAN highestprio, int *pid) +__shimcall__ POSTHRD OsThreadCreate(const char *name, BOOLEAN highestprio, int *pid) { OSTHRD *osthrd = OsAllocate(sizeof(OSTHRD)); if(osthrd) { OsThreadStart(osthrd, name, highestprio); if(pid) - *pid = osthrd->pid; + *pid = osthrd->pid; } return osthrd; } -__shimcall__ -void -OsThreadDestroy(POSTHRD osthrd) +__shimcall__ void OsThreadDestroy(POSTHRD osthrd) { OsThreadStop(osthrd); //OsDebugPrintf("%s: freeing thread=%p\n", __FUNCTION__, osthrd); @@ -809,16 +788,14 @@ OsThreadDestroy(POSTHRD osthrd) } -__shimcall__ -void OsThreadScheduleInit(HOSSCHED hWorkStorage, __kernelcall__ void (*func)(void *), void * data) +__shimcall__ void OsThreadScheduleInit(HOSSCHED hWorkStorage, __kernelcall__ void (*func)(void *), void * data) { struct tq_struct *tqs = (struct tq_struct *)hWorkStorage; - INIT_TQUEUE(tqs, func, data); + INIT_TQUEUE(tqs, func, data); } -__shimcall__ -int OsThreadSchedule(POSTHRD osthrd, HOSSCHED hWorkStorage) +__shimcall__ int OsThreadSchedule(POSTHRD osthrd, HOSSCHED hWorkStorage) { int ret; struct tq_struct *tqs = (struct tq_struct *)hWorkStorage; @@ -827,21 +804,19 @@ int OsThreadSchedule(POSTHRD osthrd, HOSSCHED hWorkStorage) printk(KERN_DEBUG "%s: no thread %p?!\n", __FUNCTION__, osthrd); return 0; } - OsModuleUseCountInc(); ret = queue_task(tqs, &osthrd->tq); if(!ret) OsModuleUseCountDec(); else wake_up(&osthrd->wq); - return ret; } __shimcall__ void OsThreadScheduleDone(void) { - OsModuleUseCountDec(); + OsModuleUseCountDec(); } #endif @@ -854,13 +829,12 @@ void OsThreadScheduleDone(void) static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) #endif -__shimcall__ -int OsRunThreadSync(__kernelcall__ int (*func)(void *), void * data) +__shimcall__ int OsRunThreadSync(__kernelcall__ int (*func)(void *), void * data) { pid_t pid; sigset_t tmpsig; int result, status; - + //OsDebugPrintf("%s: func=%p(%p)\n", __FUNCTION__, func, data); if (!current->fs->root) { @@ -913,7 +887,7 @@ typedef struct { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && defined(__powerpc__) static int execve_stub(const char *file, char **argv, char **envp) { - __syscall_nr(3, int, execve, file, argv, envp); + __syscall_nr(3, int, execve, file, argv, envp); } #undef execve #define execve execve_stub @@ -943,12 +917,10 @@ static int OsExec(void *execargs) #endif /* __x86_64__ */ #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) */ -__shimcall__ -int -OsForkWait(char *program_path, char *argv[], char *envp[]) +__shimcall__ int OsForkWait(char *program_path, char *argv[], char *envp[]) { int err; - + //OsDebugPrintf("%s: %s\n", __FUNCTION__, program_path); #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ) @@ -957,7 +929,7 @@ OsForkWait(char *program_path, char *argv[], char *envp[]) { OsExecArgs *ea = OsAllocate(sizeof(*ea)); if(!ea) - return -ENOMEM; + return -ENOMEM; ea->path = program_path; ea->argv = argv; @@ -976,23 +948,23 @@ OsForkWait(char *program_path, char *argv[], char *envp[]) static inline long MSECS_TO_TICKS(UINT32 msecs) { - long ticks = (msecs)/(1000/HZ); + long ticks = (msecs)/(1000/HZ); - // round up to next tick - if ((!ticks && msecs) || (msecs % (1000/HZ)) >= ((1000/HZ) / 2)) + // round up to next tick + if ((!ticks && msecs) || (msecs % (1000/HZ)) >= ((1000/HZ) / 2)) ticks++; - return ticks; + return ticks; } typedef struct TIME_OUT_INSTANCE_TYPE { - OSSCHED TaskQueue; - struct timer_list Timer; - UINT32 mSec; - UINT32 bLocked; - PFREE_FUNC pFuncFree; - PVOID pRefData; - PCBFUNC pTimeOutCallBack; + OSSCHED TaskQueue; + struct timer_list Timer; + UINT32 mSec; + UINT32 bLocked; + PFREE_FUNC pFuncFree; + PVOID pRefData; + PCBFUNC pTimeOutCallBack; } TIME_OUT_INSTANCE_T, *PTIME_OUT_INSTANCE_T; // bit number for delete syncronization @@ -1004,326 +976,346 @@ POSTHRD OsMdmThread; static void TimerThreadFunction(void* pData) { - PTIME_OUT_INSTANCE_T pTimeOutInstance = (PTIME_OUT_INSTANCE_T)pData; + PTIME_OUT_INSTANCE_T pTimeOutInstance = (PTIME_OUT_INSTANCE_T)pData; - if(test_bit(TASK_DELETE, (void*)&pTimeOutInstance->bLocked)) { - clear_bit(TASK_QUEUED, (void*)(&pTimeOutInstance->bLocked)); - OsThreadScheduleDone(); - return; - } + if(test_bit(TASK_DELETE, (void*)&pTimeOutInstance->bLocked)) { + clear_bit(TASK_QUEUED, (void*)(&pTimeOutInstance->bLocked)); + OsThreadScheduleDone(); + return; + } - /* beware: callback functions might use FPU instructions */ - pTimeOutInstance->pTimeOutCallBack(pTimeOutInstance->pRefData); + /* beware: callback functions might use FPU instructions */ + pTimeOutInstance->pTimeOutCallBack(pTimeOutInstance->pRefData); - clear_bit(TASK_QUEUED, (void*)(&pTimeOutInstance->bLocked)); + clear_bit(TASK_QUEUED, (void*)(&pTimeOutInstance->bLocked)); - /* callback might have set TASK_DELETE */ - if(!test_bit(TASK_DELETE, (void*)&pTimeOutInstance->bLocked)) - mod_timer(&(pTimeOutInstance -> Timer), jiffies + MSECS_TO_TICKS(pTimeOutInstance->mSec)); + /* callback might have set TASK_DELETE */ + if(!test_bit(TASK_DELETE, (void*)&pTimeOutInstance->bLocked)) + mod_timer(&(pTimeOutInstance -> Timer), jiffies + MSECS_TO_TICKS(pTimeOutInstance->mSec)); OsThreadScheduleDone(); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) static void TimeOutHandler(unsigned long Data) { PTIME_OUT_INSTANCE_T pTimeOutInstance = (PTIME_OUT_INSTANCE_T)Data; - - if(test_bit(TASK_DELETE, (void*)&pTimeOutInstance->bLocked)) { +#else +static void TimeOutHandler(struct timer_list* t) +{ + PTIME_OUT_INSTANCE_T pTimeOutInstance = (PTIME_OUT_INSTANCE_T)from_timer(pTimeOutInstance, t, Timer); +#endif + if(test_bit(TASK_DELETE, (void*)&pTimeOutInstance->bLocked)) return; - } - if(!test_and_set_bit(TASK_QUEUED, (void*)&pTimeOutInstance->bLocked)) { - if (OsThreadSchedule(OsMdmThread, &pTimeOutInstance->TaskQueue) <= 0) { - clear_bit(TASK_QUEUED, (void*)(&pTimeOutInstance->bLocked)); + if(!test_and_set_bit(TASK_QUEUED, (void*)&pTimeOutInstance->bLocked)) { + if (OsThreadSchedule(OsMdmThread, &pTimeOutInstance->TaskQueue) <= 0) + clear_bit(TASK_QUEUED, (void*)(&pTimeOutInstance->bLocked)); } - } } +#if FALSE +} +#endif -static INT32 ntimers; +static INT32 ntimers = 0; -__shimcall__ -HOSTIMER OsCreatePeriodicTimer(IN UINT32 InitialTimeOut, IN PCBFUNC pTimeOutCallBack, - IN PALLOC_FUNC pFuncAlloc, IN PFREE_FUNC pFuncFree, - IN PVOID pRefData, OUT HTHREAD* pThreadId) +__shimcall__ HOSTIMER OsCreatePeriodicTimer(IN UINT32 InitialTimeOut, IN PCBFUNC pTimeOutCallBack,IN PALLOC_FUNC pFuncAlloc, IN PFREE_FUNC pFuncFree,IN PVOID pRefData, OUT HTHREAD* pThreadId) { - PTIME_OUT_INSTANCE_T pTimeOutInstance; - int pid; - - pTimeOutInstance = pFuncAlloc ? pFuncAlloc(sizeof(TIME_OUT_INSTANCE_T), pRefData) : OsAllocate(sizeof(TIME_OUT_INSTANCE_T)); - if(0 == pTimeOutInstance) { - TRACE(T__ERROR, ("OsCreatePeriodicTimer ERROR, pTimeOutInstance is NULL???\n")); - return 0; - } + PTIME_OUT_INSTANCE_T pTimeOutInstance; + int pid; + + pTimeOutInstance = pFuncAlloc ? pFuncAlloc(sizeof(TIME_OUT_INSTANCE_T), pRefData) : OsAllocate(sizeof(TIME_OUT_INSTANCE_T)); + if(0 == pTimeOutInstance) { + TRACE(T__ERROR, ("OsCreatePeriodicTimer ERROR, pTimeOutInstance is NULL???\n")); + return 0; + } OsThreadScheduleInit(&pTimeOutInstance->TaskQueue, TimerThreadFunction, pTimeOutInstance); - pTimeOutInstance->pFuncFree = pFuncFree; - pTimeOutInstance->pRefData = pRefData; - pTimeOutInstance->pTimeOutCallBack = pTimeOutCallBack; - pTimeOutInstance->bLocked = 0; - pTimeOutInstance->mSec = InitialTimeOut; + pTimeOutInstance->pFuncFree = pFuncFree; + pTimeOutInstance->pRefData = pRefData; + pTimeOutInstance->pTimeOutCallBack = pTimeOutCallBack; + pTimeOutInstance->bLocked = 0; + pTimeOutInstance->mSec = InitialTimeOut; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) init_timer(&pTimeOutInstance->Timer); pTimeOutInstance->Timer.function = TimeOutHandler; pTimeOutInstance->Timer.data = (unsigned long)pTimeOutInstance; +#else + timer_setup(&pTimeOutInstance->Timer, TimeOutHandler, 0); +#endif pTimeOutInstance->Timer.expires = jiffies; - if(OsAtomicIncrement(&ntimers) == 1) { + if(OsAtomicIncrement(&ntimers) == 1) { #ifdef COMPLETION_INITIALIZER - static struct completion startup = COMPLETION_INITIALIZER(startup); -#endif - - OsModuleUseCountInc(); - OsMdmThread = OsThreadCreate("modem", TRUE, &pid); - if(!OsMdmThread || pid <= 0) { - if(OsMdmThread) { - OsThreadDestroy(OsMdmThread); - OsMdmThread = NULL; + static struct completion startup = COMPLETION_INITIALIZER(startup); +#endif + OsModuleUseCountInc(); + OsMdmThread = OsThreadCreate("modem", TRUE, &pid); + if(!OsMdmThread || pid <= 0) { + if(OsMdmThread) { + OsThreadDestroy(OsMdmThread); + OsMdmThread = NULL; + } + OsModuleUseCountDec(); + OsAtomicDecrement(&ntimers); + if(pTimeOutInstance->pFuncFree) + pTimeOutInstance->pFuncFree(pTimeOutInstance, pTimeOutInstance->pRefData); + else + OsFree(pTimeOutInstance); + return NULL; } - OsModuleUseCountDec(); - OsAtomicDecrement(&ntimers); - if(pTimeOutInstance->pFuncFree) - pTimeOutInstance->pFuncFree(pTimeOutInstance, pTimeOutInstance->pRefData); - else - OsFree(pTimeOutInstance); - return NULL; } - } - - if(InitialTimeOut) { - add_timer(&(pTimeOutInstance->Timer)); - } - - if(pThreadId) { - *pThreadId = (HTHREAD)(unsigned long)(OsMdmThread->pid); - } - - return (HOSTIMER)pTimeOutInstance; + if(InitialTimeOut) + add_timer(&(pTimeOutInstance->Timer)); + if(pThreadId) + *pThreadId = (HTHREAD)(unsigned long)(OsMdmThread->pid); + return (HOSTIMER)pTimeOutInstance; } -__shimcall__ -void OsDestroyPeriodicTimer(IN HOSTIMER hTimeOut) +__shimcall__ void OsDestroyPeriodicTimer(IN HOSTIMER hTimeOut) { - PTIME_OUT_INSTANCE_T pTimeOutInstance = (PTIME_OUT_INSTANCE_T)hTimeOut; - int i; + PTIME_OUT_INSTANCE_T pTimeOutInstance = (PTIME_OUT_INSTANCE_T)hTimeOut; + int i; - if(pTimeOutInstance == 0) { - TRACE(T__ERROR, ("\nOSLIN ERROR: OsDestroyPeriodicTimer: pTimeOutInstance == NULL???\n")); - return; - } + if(pTimeOutInstance == 0) { + TRACE(T__ERROR, ("\nOSLIN ERROR: OsDestroyPeriodicTimer: pTimeOutInstance == NULL???\n")); + return; + } + + set_bit(TASK_DELETE, (void*)(&pTimeOutInstance->bLocked)); + + del_timer_sync(&pTimeOutInstance->Timer); - set_bit(TASK_DELETE, (void*)(&pTimeOutInstance->bLocked)); + for(i=0; (i < 30) && test_bit(TASK_QUEUED, (void*)&pTimeOutInstance->bLocked); i++) { + if(!OsMdmThread || (OsMdmThread->pid <= 0)) { + printk(KERN_WARNING "%s: modem thread died, canceling queued task(s)\n", __FUNCTION__); + clear_bit(TASK_QUEUED, (void*)(&pTimeOutInstance->bLocked)); + OsModuleUseCountDec(); + break; + } + schedule(); + } - del_timer_sync(&pTimeOutInstance->Timer); + if(i == 30) { + printk(KERN_WARNING "%s: task queue stuck?!\n", __FUNCTION__); + } - for(i=0; (i < 30) && test_bit(TASK_QUEUED, (void*)&pTimeOutInstance->bLocked); i++) { if(!OsMdmThread || (OsMdmThread->pid <= 0)) { - printk(KERN_WARNING "%s: modem thread died, canceling queued task(s)\n", __FUNCTION__); - clear_bit(TASK_QUEUED, (void*)(&pTimeOutInstance->bLocked)); - OsModuleUseCountDec(); - break; - } - schedule(); - } - - if(i == 30) { - printk(KERN_WARNING "%s: task queue stuck?!\n", __FUNCTION__); - } - - if(!OsMdmThread || (OsMdmThread->pid <= 0)) { - printk(KERN_WARNING "%s: modem thread exited prematurely\n", __FUNCTION__); - } - - if(OsAtomicDecrement(&ntimers) == 0) { - if(OsMdmThread) { - OsThreadDestroy(OsMdmThread); - OsMdmThread = NULL; - OsModuleUseCountDec(); - } - } - - if(pTimeOutInstance->pFuncFree) - pTimeOutInstance->pFuncFree(pTimeOutInstance, pTimeOutInstance->pRefData); - else - OsFree(pTimeOutInstance); + printk(KERN_WARNING "%s: modem thread exited prematurely\n", __FUNCTION__); + } + + if(OsAtomicDecrement(&ntimers) == 0) { + if(OsMdmThread) { + OsThreadDestroy(OsMdmThread); + OsMdmThread = NULL; + OsModuleUseCountDec(); + } + } + + if(pTimeOutInstance->pFuncFree) + pTimeOutInstance->pFuncFree(pTimeOutInstance, pTimeOutInstance->pRefData); + else + OsFree(pTimeOutInstance); } -__shimcall__ -BOOL OsSetPeriodicTimer(IN HOSTIMER hTimeOut, IN UINT32 NewTimeOut) +__shimcall__ BOOL OsSetPeriodicTimer(IN HOSTIMER hTimeOut, IN UINT32 NewTimeOut) { - PTIME_OUT_INSTANCE_T pTimeOutInstance = (PTIME_OUT_INSTANCE_T)hTimeOut; + PTIME_OUT_INSTANCE_T pTimeOutInstance = (PTIME_OUT_INSTANCE_T)hTimeOut; - if(pTimeOutInstance == 0) { - TRACE(T__ERROR, ("\nERROR!!! OsSetPeriodicTimer: pTimeOutInstance == NULL\n")); - return FALSE; - } + if(pTimeOutInstance == 0) { + TRACE(T__ERROR, ("\nERROR!!! OsSetPeriodicTimer: pTimeOutInstance == NULL\n")); + return FALSE; + } - if(NewTimeOut == pTimeOutInstance->mSec) { - /* no change, don't touch it */ - return TRUE; - } - pTimeOutInstance->mSec = NewTimeOut; - if(NewTimeOut) { - clear_bit(TASK_DELETE, (void*)(&pTimeOutInstance->bLocked)); - mod_timer(&pTimeOutInstance -> Timer, jiffies + MSECS_TO_TICKS(pTimeOutInstance -> mSec)); - return TRUE; - } else { - set_bit(TASK_DELETE, (void*)(&pTimeOutInstance->bLocked)); - del_timer(&pTimeOutInstance -> Timer); - return FALSE; - } + if(NewTimeOut == pTimeOutInstance->mSec) { + /* no change, don't touch it */ + return TRUE; + } + pTimeOutInstance->mSec = NewTimeOut; + if(NewTimeOut) { + clear_bit(TASK_DELETE, (void*)(&pTimeOutInstance->bLocked)); + mod_timer(&pTimeOutInstance -> Timer, jiffies + MSECS_TO_TICKS(pTimeOutInstance -> mSec)); + return TRUE; + } else { + set_bit(TASK_DELETE, (void*)(&pTimeOutInstance->bLocked)); + del_timer(&pTimeOutInstance -> Timer); + return FALSE; + } } -__shimcall__ -void OsImmediateTimeOut(IN HOSTIMER hTimeOut) +__shimcall__ void OsImmediateTimeOut(IN HOSTIMER hTimeOut) { - PTIME_OUT_INSTANCE_T pTimeOutInstance = (PTIME_OUT_INSTANCE_T)hTimeOut; + PTIME_OUT_INSTANCE_T pTimeOutInstance = (PTIME_OUT_INSTANCE_T)hTimeOut; - mod_timer(&pTimeOutInstance -> Timer, jiffies); + mod_timer(&pTimeOutInstance -> Timer, jiffies); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) static time_t epoch = 0; +__shimcall__ UINT32 OsGetSystemTime(void) +{ + struct timeval timestamp; -__shimcall__ -UINT32 OsGetSystemTime(void) + do_gettimeofday(×tamp); + + return ((timestamp.tv_sec-epoch)*1000 + timestamp.tv_usec/1000); +} +#else +static ktime_t epoch = 0; +__shimcall__ UINT32 OsGetSystemTime(void) { - struct timeval timestamp; + ktime_t timestamp; - do_gettimeofday(×tamp); + timestamp = ktime_get(); - return ((timestamp.tv_sec-epoch)*1000 + timestamp.tv_usec/1000); + return ((timestamp - epoch) / 1000000); } +#endif -__shimcall__ -void OsSleep(UINT32 ms) +__shimcall__ void OsSleep(UINT32 ms) { - /* we must schedule() for sleeps >= 10ms since HCF calls us in loops - * waiting for asynchronous events. - */ - if(ms >= TICKS_TO_MSECS(1)) { - UINT32 start, end; - long timeout = MSECS_TO_TICKS(ms); - //long ort = timeout; - - if(!OsContextAllowsSleeping()) { - if(ms >= 100) { - printk(KERN_ERR"%s(%u): shouldn't sleep that long in this context!\n", __FUNCTION__, ms); + /* we must schedule() for sleeps >= 10ms since HCF calls us in loops + * waiting for asynchronous events. + */ + if(ms >= TICKS_TO_MSECS(1)) { + UINT32 start, end; + long timeout = MSECS_TO_TICKS(ms); + //long ort = timeout; + + if(!OsContextAllowsSleeping()) { + if(ms >= 100) { + printk(KERN_ERR"%s(%u): shouldn't sleep that long in this context!\n", __FUNCTION__, ms); #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) ) - {static int onlyonce; if(!onlyonce) { onlyonce=1; dump_stack(); } } -#endif - } -// ASSERT(OsContextAllowsSleeping()); - mdelay(ms); - return; - } - - start = OsGetSystemTime(); - do { - set_current_state(TASK_UNINTERRUPTIBLE); - } while ((timeout = schedule_timeout(timeout)) > 0); - end = OsGetSystemTime() - start; - if(end < ms) { - //printk(KERN_ERR"OsSleep: short timeout; wanted %ld got %ldms ort=%ld\n", ms, end, ort); - OsSleep(ms - end); - } - //else if(end > ms) { - // printk(KERN_ERR"OsSleep: timeout %ldms (%ldms too much) ort=%ld\n", ms, end - ms, ort); - //} - } else { - // short delay - mdelay(ms); - } + {static int onlyonce; if(!onlyonce) { onlyonce=1; dump_stack(); } } +#endif + } + // ASSERT(OsContextAllowsSleeping()); + mdelay(ms); + return; + } + + start = OsGetSystemTime(); + do { + set_current_state(TASK_UNINTERRUPTIBLE); + } while ((timeout = schedule_timeout(timeout)) > 0); + end = OsGetSystemTime() - start; + if(end < ms) { + //printk(KERN_ERR"OsSleep: short timeout; wanted %ld got %ldms ort=%ld\n", ms, end, ort); + OsSleep(ms - end); + } + //else if(end > ms) { + // printk(KERN_ERR"OsSleep: timeout %ldms (%ldms too much) ort=%ld\n", ms, end - ms, ort); + //} + } else { + // short delay + mdelay(ms); + } } #if ! TARGET_HCF_FAMILY typedef struct TIMER_TAG { - UINT32 msec; - struct timer_list timer; + UINT32 msec; + struct timer_list timer; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) + void (*function)(unsigned long); + unsigned long data; +#endif } TIMER_T, *PTIMER_T; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) +void TimerProxy(struct timer_list* t){ + PTIMER_T pTimer = from_timer(pTimer, t, timer); + pTimer->function(pTimer->data); +} +#endif + __shimcall__ HANDLE OsCreateTimer(UINT32 msec, __kernelcall__ PVOID pCBFunc, PVOID pRefData) { - PTIMER_T pTimer; + PTIMER_T pTimer; - if ( pCBFunc == NULL ) - { + if ( pCBFunc == NULL ) + { ASSERT(pCBFunc); return (NULL); - } + } - ASSERT(OsContextAllowsSleeping()); - pTimer = kmalloc(sizeof(TIMER_T),GFP_KERNEL); - if ( NULL == pTimer ) - { + ASSERT(OsContextAllowsSleeping()); + pTimer = kmalloc(sizeof(TIMER_T),GFP_KERNEL); + if ( NULL == pTimer ) + { ASSERT(pTimer); return (NULL); - } + } - memset(pTimer,0,sizeof(TIMER_T)); + memset(pTimer,0,sizeof(TIMER_T)); - init_timer(&(pTimer->timer)); - pTimer->timer.function = pCBFunc ; - pTimer->timer.data = (unsigned long)pRefData; - pTimer->timer.expires = jiffies + MSECS_TO_TICKS(msec); - pTimer->msec = msec; - return ((HANDLE)pTimer); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) + init_timer(&(pTimer->timer)); + pTimer->timer.function = pCBFunc ; + pTimer->timer.data = (unsigned long)pRefData; +#else + pTimer->function = pCBFunc; + pTimer->data = (unsigned long)pRefData; + timer_setup(&pTimer->timer, TimerProxy, 0); +#endif + pTimer->timer.expires = jiffies + MSECS_TO_TICKS(msec); + pTimer->msec = msec; + return ((HANDLE)pTimer); } -__shimcall__ -void OsSetTimer(PVOID pTimer) +__shimcall__ void OsSetTimer(PVOID pTimer) { - struct timer_list* pTimerH; - PTIMER_T pTimerS = (PTIMER_T)pTimer; - if ( pTimer == NULL ) - { - ASSERT(pTimer); - return; - } - pTimerH = &(pTimerS->timer); - mod_timer(pTimerH, jiffies + MSECS_TO_TICKS(pTimerS->msec)); + struct timer_list* pTimerH; + PTIMER_T pTimerS = (PTIMER_T)pTimer; + if ( pTimer == NULL ) + { + ASSERT(pTimer); + return; + } + pTimerH = &(pTimerS->timer); + mod_timer(pTimerH, jiffies + MSECS_TO_TICKS(pTimerS->msec)); } -__shimcall__ -void OsCancelTimer(PVOID pTimer) +__shimcall__ void OsCancelTimer(PVOID pTimer) { - struct timer_list* pTimerH; - if ( pTimer == NULL ) - { - ASSERT(pTimer); - return; - } - pTimerH = &((PTIMER_T)pTimer)->timer; + struct timer_list* pTimerH; + if ( pTimer == NULL ) + { + ASSERT(pTimer); + return; + } + pTimerH = &((PTIMER_T)pTimer)->timer; - del_timer(pTimerH); + del_timer(pTimerH); } -__shimcall__ -void OsChangeTimerTimeOut(PVOID pTimer, UINT32 msec) +__shimcall__ void OsChangeTimerTimeOut(PVOID pTimer, UINT32 msec) { - PTIMER_T pTimerS = (PTIMER_T)pTimer; - if ( pTimer == NULL ) - { - ASSERT(pTimer); - return; - } - pTimerS->msec = msec; + PTIMER_T pTimerS = (PTIMER_T)pTimer; + if ( pTimer == NULL ) + { + ASSERT(pTimer); + return; + } + pTimerS->msec = msec; } -__shimcall__ -void OsDestroyTimer(PVOID pTimer) +__shimcall__ void OsDestroyTimer(PVOID pTimer) { - if ( pTimer == NULL ) - { - ASSERT(pTimer); - return; - } + if ( pTimer == NULL ) + { + ASSERT(pTimer); + return; + } - del_timer_sync(&((PTIMER_T)pTimer)->timer); - kfree(pTimer); + del_timer_sync(&((PTIMER_T)pTimer)->timer); + kfree(pTimer); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) @@ -1338,57 +1330,76 @@ static DWORD dwProcessorFreq; __shimcall__ GLOBAL DWORD OsGetProcessorFreq(void) { - return dwProcessorFreq; + return dwProcessorFreq; } #endif #ifndef PROCFREQ_FROM_KERNEL static unsigned long OsCalcCpuRate(void) { - struct timeval tv; - unsigned long flags; - unsigned long time1, time2, cpurate; - unsigned int target_usec; - - // first ensure that the tv_usec will not wraparound - do_gettimeofday( &tv ); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) + struct timeval tv; +#else + ktime_t tv; +#endif + unsigned long flags; + unsigned long time1, time2, cpurate; + unsigned int target_usec; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) + // first ensure that the tv_usec will not wraparound + do_gettimeofday( &tv ); + if ( tv.tv_usec > 990000 ) { + do + { + do_gettimeofday( &tv ); + } while ( tv.tv_usec > 990000 ); + } +#else + tv = ktime_get(); +#endif - if ( tv.tv_usec > 990000 ) { + local_irq_save(flags); + // calc the cpu rate +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) + do_gettimeofday( &tv ); +#else + tv = ktime_get(); +#endif + rdtscl(time1); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) + target_usec = tv.tv_usec + 1000; do { - do_gettimeofday( &tv ); - } while ( tv.tv_usec > 990000 ); - } - - local_irq_save(flags); - // calc the cpu rate - do_gettimeofday( &tv ); - rdtscl(time1); - target_usec = tv.tv_usec + 1000; - do - { - do_gettimeofday( &tv ); - } while ( tv.tv_usec < target_usec ); - rdtscl(time2); + do_gettimeofday( &tv ); + } while ( tv.tv_usec < target_usec ); +#else + target_usec = tv/1000 + 1000; + do + { + tv = ktime_get(); + } while ( tv/1000 < target_usec ); +#endif + rdtscl(time2); - local_irq_restore(flags); + local_irq_restore(flags); - cpurate = ( (time2-time1+500) /1000 ) * 1000000; // to get whole number + cpurate = ( (time2-time1+500) /1000 ) * 1000000; // to get whole number #ifdef DEBUG - printk(KERN_DEBUG"%s: %lu\n", __FUNCTION__, cpurate); + printk(KERN_DEBUG"%s: %lu\n", __FUNCTION__, cpurate); #endif - return cpurate; + return cpurate; } #else __shimcall__ GLOBAL DWORD OsGetProcessorFreq(void) { - return cpu_khz / 1000; + return cpu_khz / 1000; } #endif + __shimcall__ UINT32 OsReadCpuCnt(void) { @@ -1400,199 +1411,200 @@ UINT32 OsReadCpuCnt(void) } #endif -__shimcall__ -int OsInit(void) +__shimcall__ int OsInit(void) { - struct timeval timestamp; - do_gettimeofday(×tamp); - - epoch = timestamp.tv_sec; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) + struct timeval timestamp; + do_gettimeofday(×tamp); + epoch = timestamp.tv_sec; +#else + epoch = ktime_get(); +#endif #if ! TARGET_HCF_FAMILY #ifdef PROCFREQ_FROM_KERNEL_CONSTANT dwProcessorFreq = cpu_khz / 1000; #elif !defined(PROCFREQ_FROM_KERNEL) - dwProcessorFreq = OsCalcCpuRate()/1000000; + dwProcessorFreq = OsCalcCpuRate()/1000000; #endif #endif #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0) ) - if(sizeof(OSSCHED) <= sizeof(struct kwork_data)) { - OsErrorPrintf("OSSCHED too small (%d < %d)\n", sizeof(OSSCHED), sizeof(struct kwork_data)); + if(sizeof(OSSCHED) <= sizeof(struct kwork_data)) { + OsErrorPrintf("OSSCHED too small (%lu < %lu)\n", sizeof(OSSCHED), sizeof(struct kwork_data)); #else - if(sizeof(OSSCHED) <= sizeof(struct tq_struct)) { - OsErrorPrintf("OSSCHED too small (%d < %d)\n", sizeof(OSSCHED), sizeof(struct tq_struct)); + if(sizeof(OSSCHED) <= sizeof(struct tq_struct)) { + OsErrorPrintf("OSSCHED too small (%lu < %lu)\n", sizeof(OSSCHED), sizeof(struct tq_struct)); #endif - return -ENOSPC; - } - - return 0; + return -ENOSPC; + } + return 0; } -/********************************************************************/ + /********************************************************************/ -__shimcall__ -HTHREAD OsGetCurrentThread(void) -{ - return (HTHREAD)((in_interrupt()) ? 0 : (unsigned long)current->pid); -} + __shimcall__ + HTHREAD OsGetCurrentThread(void) + { + return (HTHREAD)((in_interrupt()) ? 0 : (unsigned long)current->pid); + } -/********************************************************************/ + /********************************************************************/ -__shimcall__ -void OsRawVPrintf (LPCSTR szFormat, PVOID args, BOOL addnl) -{ - char printk_buf[1024]; + __shimcall__ + void OsRawVPrintf (LPCSTR szFormat, PVOID args, BOOL addnl) + { + char printk_buf[1024]; - printk_buf[0]= '\0'; + printk_buf[0]= '\0'; #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) ) - vsprintf(printk_buf, szFormat, args); + vsprintf(printk_buf, szFormat, args); #else - vsnprintf(printk_buf, sizeof(printk_buf), szFormat, args); + vsnprintf(printk_buf, sizeof(printk_buf), szFormat, args); #endif - printk_buf[sizeof(printk_buf)-1]= '\0'; + printk_buf[sizeof(printk_buf)-1]= '\0'; - printk(addnl ? "%s\n" : "%s", printk_buf); -} + printk(addnl ? "%s\n" : "%s", printk_buf); + } -__shimcall__ -void OsRawPrintf (LPCSTR szFormat, ...) -{ - va_list args; + __shimcall__ + void OsRawPrintf (LPCSTR szFormat, ...) + { + va_list args; - va_start(args, szFormat); - OsRawVPrintf(szFormat, args, FALSE); - va_end(args); -} + va_start(args, szFormat); + OsRawVPrintf(szFormat, args, FALSE); + va_end(args); + } -__shimcall__ -void OsRawNLPrintf (LPCSTR szFormat, ...) -{ - va_list args; + __shimcall__ + void OsRawNLPrintf (LPCSTR szFormat, ...) + { + va_list args; - va_start(args, szFormat); - OsRawVPrintf(szFormat, args, TRUE); - va_end(args); -} + va_start(args, szFormat); + OsRawVPrintf(szFormat, args, TRUE); + va_end(args); + } -__shimcall__ -void OsErrorVPrintf (LPCSTR szFormat, PVOID args) -{ - char printk_buf[1024]; + __shimcall__ + void OsErrorVPrintf (LPCSTR szFormat, PVOID args) + { + char printk_buf[1024]; - printk_buf[0]= '\0'; + printk_buf[0]= '\0'; #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) ) - vsprintf(printk_buf, szFormat, args); + vsprintf(printk_buf, szFormat, args); #else - vsnprintf(printk_buf, sizeof(printk_buf), szFormat, args); + vsnprintf(printk_buf, sizeof(printk_buf), szFormat, args); #endif - printk_buf[sizeof(printk_buf)-1]= '\0'; + printk_buf[sizeof(printk_buf)-1]= '\0'; #if 0 - { - static int lasthadnl=1; - if(lasthadnl) - printk(KERN_ERR"%s", printk_buf); - else - printk("%s", printk_buf); + { + static int lasthadnl=1; + if(lasthadnl) + printk(KERN_ERR"%s", printk_buf); + else + printk("%s", printk_buf); - lasthadnl = printk_buf[strlen(printk_buf) - 1] == '\n'; - } + lasthadnl = printk_buf[strlen(printk_buf) - 1] == '\n'; + } #else - printk(KERN_ERR"%s", printk_buf); + printk(KERN_ERR"%s", printk_buf); #endif -} + } -__shimcall__ -void OsErrorPrintf (LPCSTR szFormat, ...) -{ - va_list args; + __shimcall__ + void OsErrorPrintf (LPCSTR szFormat, ...) + { + va_list args; - va_start(args, szFormat); - OsErrorVPrintf(szFormat, args); - va_end(args); -} + va_start(args, szFormat); + OsErrorVPrintf(szFormat, args); + va_end(args); + } -__shimcall__ -void OsDebugVPrintf (LPCSTR szFormat, PVOID args) -{ - char printk_buf[1024]; + __shimcall__ + void OsDebugVPrintf (LPCSTR szFormat, PVOID args) + { + char printk_buf[1024]; - printk_buf[0]= '\0'; + printk_buf[0]= '\0'; #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) ) - vsprintf(printk_buf, szFormat, args); + vsprintf(printk_buf, szFormat, args); #else - vsnprintf(printk_buf, sizeof(printk_buf), szFormat, args); + vsnprintf(printk_buf, sizeof(printk_buf), szFormat, args); #endif - printk_buf[sizeof(printk_buf)-1]= '\0'; + printk_buf[sizeof(printk_buf)-1]= '\0'; - printk(KERN_DEBUG"%s", printk_buf); -} + printk(KERN_DEBUG"%s", printk_buf); + } -__shimcall__ -void OsDebugPrintf (LPCSTR szFormat, ...) -{ - va_list args; + __shimcall__ + void OsDebugPrintf (LPCSTR szFormat, ...) + { + va_list args; - va_start(args, szFormat); - OsDebugVPrintf(szFormat, args); - va_end(args); -} + va_start(args, szFormat); + OsDebugVPrintf(szFormat, args); + va_end(args); + } -__shimcall__ -void OsDebugBreakpoint ( LPCSTR szMsg ) -{ - OsDebugPrintf("%s: %s\n", __FUNCTION__, szMsg); - //KDB_ENTER(); -} + __shimcall__ + void OsDebugBreakpoint ( LPCSTR szMsg ) + { + OsDebugPrintf("%s: %s\n", __FUNCTION__, szMsg); + //KDB_ENTER(); + } #if 0 -void OsDebugDumpData(PUINT8 data, UINT32 len) -{ - OsDebugPrintf("%s: data=%p len=%ld\n", __FUNCTION__, data, len); -} + void OsDebugDumpData(PUINT8 data, UINT32 len) + { + OsDebugPrintf("%s: data=%p len=%ld\n", __FUNCTION__, data, len); + } #endif -typedef struct { - wait_queue_head_t wq; - int flag; - const char *name; -} EVENT, *PEVENT; + typedef struct { + wait_queue_head_t wq; + int flag; + const char *name; + } EVENT, *PEVENT; -__shimcall__ -void OsEventInit(HOSEVENT hEvent, const char* name) -{ - PEVENT pEvent = (PEVENT)hEvent; + __shimcall__ + void OsEventInit(HOSEVENT hEvent, const char* name) + { + PEVENT pEvent = (PEVENT)hEvent; - //OsDebugPrintf("%s: %p\n", __FUNCTION__, pEvent); + //OsDebugPrintf("%s: %p\n", __FUNCTION__, pEvent); - if(pEvent) { - init_waitqueue_head(&pEvent->wq); - pEvent->flag = 0; - pEvent->name = name; + if(pEvent) { + init_waitqueue_head(&pEvent->wq); + pEvent->flag = 0; + pEvent->name = name; + } } -} -__shimcall__ -HOSEVENT OsEventCreate(const char* name) -{ - HOSEVENT hEvent = OsAllocate(sizeof(EVENT)); - - OsEventInit(hEvent, name); + __shimcall__ + HOSEVENT OsEventCreate(const char* name) + { + HOSEVENT hEvent = OsAllocate(sizeof(EVENT)); - return hEvent; -} + OsEventInit(hEvent, name); -__shimcall__ -void OsEventDestroy(HOSEVENT hEvent) -{ - OsFree(hEvent); -} + return hEvent; + } + + __shimcall__ + void OsEventDestroy(HOSEVENT hEvent) + { + OsFree(hEvent); + } #ifndef wq_write_lock_irqsave #define wq_write_lock_irqsave spin_lock_irqsave @@ -1601,235 +1613,235 @@ void OsEventDestroy(HOSEVENT hEvent) #define wq_write_unlock_irqrestore spin_unlock_irqrestore #endif -__shimcall__ -void OsEventWait(HOSEVENT hEvent) -{ - PEVENT pEvent = (PEVENT)hEvent; - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; + __shimcall__ + void OsEventWait(HOSEVENT hEvent) + { + PEVENT pEvent = (PEVENT)hEvent; + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; - //OsDebugPrintf("%s: %p\n", __FUNCTION__, hEvent); + //OsDebugPrintf("%s: %p\n", __FUNCTION__, hEvent); - if(!OsContextAllowsSleeping()) { - printk(KERN_ERR"%s: can't sleep in this context!\n", __FUNCTION__); + if(!OsContextAllowsSleeping()) { + printk(KERN_ERR"%s: can't sleep in this context!\n", __FUNCTION__); #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) ) - {static int onlyonce; if(!onlyonce) { onlyonce=1; dump_stack(); } } + {static int onlyonce; if(!onlyonce) { onlyonce=1; dump_stack(); } } #endif - return; - } + return; + } - //OsDebugPrintf("bef AWQ\n"); - add_wait_queue(&pEvent->wq, &wait); - while(1) { - wq_write_lock_irqsave(&pEvent->wq.lock, flags); - if(pEvent->flag) { - pEvent->flag = 0; - //OsDebugPrintf("ret OK\n"); + //OsDebugPrintf("bef AWQ\n"); + add_wait_queue(&pEvent->wq, &wait); + while(1) { + wq_write_lock_irqsave(&pEvent->wq.lock, flags); + if(pEvent->flag) { + pEvent->flag = 0; + //OsDebugPrintf("ret OK\n"); + wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); + break; + } wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); - break; + rmb(); + //OsDebugPrintf("UNINT"); + set_current_state(TASK_UNINTERRUPTIBLE); + //OsDebugPrintf("ST"); + schedule(); } - wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); - rmb(); - //OsDebugPrintf("UNINT"); - set_current_state(TASK_UNINTERRUPTIBLE); - //OsDebugPrintf("ST"); - schedule(); + + current->state = TASK_RUNNING; + //OsDebugPrintf("TRUN"); + remove_wait_queue(&pEvent->wq, &wait); + //OsDebugPrintf("aft RWQ"); } - current->state = TASK_RUNNING; - //OsDebugPrintf("TRUN"); - remove_wait_queue(&pEvent->wq, &wait); - //OsDebugPrintf("aft RWQ"); -} + // sets event to signalled state + __shimcall__ + long OsEventSet(HOSEVENT hEvent) + { + PEVENT pEvent = (PEVENT)hEvent; + unsigned long flags; + int previous_state; -// sets event to signalled state -__shimcall__ -long OsEventSet(HOSEVENT hEvent) -{ - PEVENT pEvent = (PEVENT)hEvent; - unsigned long flags; - int previous_state; - - //OsDebugPrintf("%s: %p\n", __FUNCTION__, hEvent); - mb(); - wq_write_lock_irqsave(&pEvent->wq.lock, flags); - previous_state = pEvent->flag; - pEvent->flag = 1; - wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); - wmb(); - //OsDebugPrintf("BWU\n"); - wake_up(&pEvent->wq); - //OsDebugPrintf("AWU\n"); - - return previous_state; -} + //OsDebugPrintf("%s: %p\n", __FUNCTION__, hEvent); + mb(); + wq_write_lock_irqsave(&pEvent->wq.lock, flags); + previous_state = pEvent->flag; + pEvent->flag = 1; + wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); + wmb(); + //OsDebugPrintf("BWU\n"); + wake_up(&pEvent->wq); + //OsDebugPrintf("AWU\n"); -// waits until event is set by OsEventSet() call or timeout (ms) has passed -__shimcall__ -OSEVENT_WAIT_RESULT OsEventWaitTime(HOSEVENT hEvent, UINT32 timeout) -{ - PEVENT pEvent = (PEVENT)hEvent; - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - long tmticks = MSECS_TO_TICKS(timeout); - OSEVENT_WAIT_RESULT res = OSEVENT_WAIT_TIMEOUT; + return previous_state; + } + + // waits until event is set by OsEventSet() call or timeout (ms) has passed + __shimcall__ + OSEVENT_WAIT_RESULT OsEventWaitTime(HOSEVENT hEvent, UINT32 timeout) + { + PEVENT pEvent = (PEVENT)hEvent; + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + long tmticks = MSECS_TO_TICKS(timeout); + OSEVENT_WAIT_RESULT res = OSEVENT_WAIT_TIMEOUT; - //OsDebugPrintf("%s: %p timeout=%ld\n", __FUNCTION__, hEvent, timeout); + //OsDebugPrintf("%s: %p timeout=%ld\n", __FUNCTION__, hEvent, timeout); - if(!timeout) { - wq_write_lock_irqsave(&pEvent->wq.lock, flags); - if(pEvent->flag) { - pEvent->flag = 0; - res = OSEVENT_WAIT_OK; + if(!timeout) { + wq_write_lock_irqsave(&pEvent->wq.lock, flags); + if(pEvent->flag) { + pEvent->flag = 0; + res = OSEVENT_WAIT_OK; + } + wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); + return res; } - wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); - return res; - } - if(!OsContextAllowsSleeping()) { - printk(KERN_ERR"%s: can't sleep in this context!\n", __FUNCTION__); + if(!OsContextAllowsSleeping()) { + printk(KERN_ERR"%s: can't sleep in this context!\n", __FUNCTION__); #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) ) - {static int onlyonce; if(!onlyonce) { onlyonce=1; dump_stack(); } } + {static int onlyonce; if(!onlyonce) { onlyonce=1; dump_stack(); } } #endif - return OSEVENT_WAIT_ERROR; - } + return OSEVENT_WAIT_ERROR; + } - //OsDebugPrintf("bef AWQ\n"); - add_wait_queue(&pEvent->wq, &wait); - do { - wq_write_lock_irqsave(&pEvent->wq.lock, flags); - if(pEvent->flag) { - pEvent->flag = 0; - //OsDebugPrintf("ret OK\n"); + //OsDebugPrintf("bef AWQ\n"); + add_wait_queue(&pEvent->wq, &wait); + do { + wq_write_lock_irqsave(&pEvent->wq.lock, flags); + if(pEvent->flag) { + pEvent->flag = 0; + //OsDebugPrintf("ret OK\n"); + wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); + res = OSEVENT_WAIT_OK; + break; + } wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); - res = OSEVENT_WAIT_OK; - break; - } - wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); - rmb(); - //OsDebugPrintf("UNINT"); - set_current_state(TASK_UNINTERRUPTIBLE); - //OsDebugPrintf("ST"); - } while ( tmticks && (tmticks = schedule_timeout(tmticks)) ); + rmb(); + //OsDebugPrintf("UNINT"); + set_current_state(TASK_UNINTERRUPTIBLE); + //OsDebugPrintf("ST"); + } while ( tmticks && (tmticks = schedule_timeout(tmticks)) ); - current->state = TASK_RUNNING; - //OsDebugPrintf("TRUN"); - remove_wait_queue(&pEvent->wq, &wait); - //OsDebugPrintf("aft RWQ"); + current->state = TASK_RUNNING; + //OsDebugPrintf("TRUN"); + remove_wait_queue(&pEvent->wq, &wait); + //OsDebugPrintf("aft RWQ"); #if 0 - if(res == OSEVENT_WAIT_TIMEOUT) { - printk(KERN_DEBUG"%s(%p/%s, %u): returning OSEVENT_WAIT_TIMEOUT\n", __FUNCTION__, hEvent, pEvent->name, timeout); - //{static int onlyonce; if(!onlyonce) { onlyonce=1; dump_stack(); } } - } + if(res == OSEVENT_WAIT_TIMEOUT) { + printk(KERN_DEBUG"%s(%p/%s, %u): returning OSEVENT_WAIT_TIMEOUT\n", __FUNCTION__, hEvent, pEvent->name, timeout); + //{static int onlyonce; if(!onlyonce) { onlyonce=1; dump_stack(); } } + } #endif - return res; -} + return res; + } -// sets event to non-signalled state -__shimcall__ -long OsEventClear(HOSEVENT hEvent) -{ - PEVENT pEvent = (PEVENT)hEvent; - unsigned long flags; - int previous_state; + // sets event to non-signalled state + __shimcall__ + long OsEventClear(HOSEVENT hEvent) + { + PEVENT pEvent = (PEVENT)hEvent; + unsigned long flags; + int previous_state; - //OsDebugPrintf("%s: %p\n", __FUNCTION__, hEvent); + //OsDebugPrintf("%s: %p\n", __FUNCTION__, hEvent); - wq_write_lock_irqsave(&pEvent->wq.lock, flags); - previous_state = pEvent->flag; - pEvent->flag = 0; - wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); - wmb(); + wq_write_lock_irqsave(&pEvent->wq.lock, flags); + previous_state = pEvent->flag; + pEvent->flag = 0; + wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); + wmb(); - return previous_state; -} + return previous_state; + } -__shimcall__ -long OsEventState(HOSEVENT hEvent) -{ - PEVENT pEvent = (PEVENT)hEvent; - unsigned long flags; - int state; + __shimcall__ + long OsEventState(HOSEVENT hEvent) + { + PEVENT pEvent = (PEVENT)hEvent; + unsigned long flags; + int state; - //OsDebugPrintf("%s: %p\n", __FUNCTION__, hEvent); + //OsDebugPrintf("%s: %p\n", __FUNCTION__, hEvent); - wq_write_lock_irqsave(&pEvent->wq.lock, flags); - state = pEvent->flag; - wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); + wq_write_lock_irqsave(&pEvent->wq.lock, flags); + state = pEvent->flag; + wq_write_unlock_irqrestore(&pEvent->wq.lock, flags); - return state; -} + return state; + } #ifdef TARGET_HCF_PCI_LINUX -typedef struct tasklet_struct OSDPC, *POSDPC; + typedef struct tasklet_struct OSDPC, *POSDPC; -__shimcall__ -HOSDPC OsDpcCreate(__kernelcall__ void (*func)(void *), void * data) -{ - POSDPC pDpc = (POSDPC) kmalloc(sizeof(OSDPC), GFP_KERNEL); + __shimcall__ + HOSDPC OsDpcCreate(__kernelcall__ void (*func)(void *), void * data) + { + POSDPC pDpc = (POSDPC) kmalloc(sizeof(OSDPC), GFP_KERNEL); - if(pDpc) { - tasklet_init(pDpc, (void (*)(unsigned long))func, (unsigned long)data); - } + if(pDpc) { + tasklet_init(pDpc, (void (*)(unsigned long))func, (unsigned long)data); + } - // DPRINTF(("%s: %p", __FUNCTION__, pDpc)); - return (HOSDPC)pDpc; -} + // DPRINTF(("%s: %p", __FUNCTION__, pDpc)); + return (HOSDPC)pDpc; + } -__shimcall__ -void OsDpcDestroy(HOSDPC hDpc) -{ - POSDPC pDpc = (POSDPC)hDpc; + __shimcall__ + void OsDpcDestroy(HOSDPC hDpc) + { + POSDPC pDpc = (POSDPC)hDpc; - tasklet_disable(pDpc); + tasklet_disable(pDpc); - // DPRINTF(("%s: %p", __FUNCTION__, hDpc)); - kfree(pDpc); -} + // DPRINTF(("%s: %p", __FUNCTION__, hDpc)); + kfree(pDpc); + } -__shimcall__ -void OsDpcSchedule(HOSDPC hDpc) -{ - tasklet_schedule((POSDPC)hDpc); -} + __shimcall__ + void OsDpcSchedule(HOSDPC hDpc) + { + tasklet_schedule((POSDPC)hDpc); + } -__shimcall__ -void OsDpcEnable(HOSDPC hDpc) -{ - tasklet_enable((POSDPC)hDpc); -} + __shimcall__ + void OsDpcEnable(HOSDPC hDpc) + { + tasklet_enable((POSDPC)hDpc); + } -__shimcall__ -void OsDpcDisable(HOSDPC hDpc) -{ - tasklet_disable((POSDPC)hDpc); -} + __shimcall__ + void OsDpcDisable(HOSDPC hDpc) + { + tasklet_disable((POSDPC)hDpc); + } #endif /* TARGET_HCF_PCI_LINUX */ -__kernelcall__ + __kernelcall__ #if (__GNUC__ == 3 && __GNUC_MINOR__ > 1) || __GNUC__ > 3 -__attribute__((used)) + __attribute__((used)) #endif -static void regParmUsed(BOOL *regParm) -{ + static void regParmUsed(BOOL *regParm) + { #if defined(__i386__) - register void **esp asm("esp") = esp; + register void **esp asm("esp") = esp; - *regParm = ((void *)®Parm == esp); + *regParm = ((void *)®Parm == esp); #else - *regParm = FALSE; + *regParm = FALSE; #endif -} + } -__shimcall__ -BOOL -OsKernelUsesRegParm(void) -{ - BOOL regParm; + __shimcall__ + BOOL + OsKernelUsesRegParm(void) + { + BOOL regParm; - regParmUsed(®Parm); + regParmUsed(®Parm); - return regParm; -} + return regParm; + } diff --git a/modules/osstdio.c b/modules/osstdio.c old mode 100644 new mode 100755 index 86fe8c1..5854caa --- a/modules/osstdio.c +++ b/modules/osstdio.c @@ -40,60 +40,59 @@ static int set_current_fsuid(uid_t fsuid) } #endif -__shimcall__ -FILE * -OsFOpen (const char *path, const char *mode, int *errp) +__shimcall__ FILE * OsFOpen (const char *path, const char *mode, int *errp) { #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) ) kuid_t origfsuid; #else uid_t origfsuid; #endif + FILE *filp; int error = 0; int flags, creatmode = 0, do_trunc = 0; struct inode * inode; ASSERT(OsContextAllowsSleeping()); - if(!path || !mode) { error = -EIO; filp = NULL; goto out; } - + //printk(KERN_INFO "%s(\"%s\", \"%s\")\n", __FUNCTION__, path, mode); //KDB_ENTER(); - if(!strcmp(mode, "r") || !strcmp(mode, "rb")) { + if(!strcmp(mode, "r") || !strcmp(mode, "rb")) flags = O_RDONLY; - } else if(!strcmp(mode, "r+") || !strcmp(mode, "r+b") || !strcmp(mode, "rb+")) { + else if(!strcmp(mode, "r+") || !strcmp(mode, "r+b") || !strcmp(mode, "rb+")) flags = O_RDWR; - } else if(!strcmp(mode, "w") || !strcmp(mode, "wb")) { + else if(!strcmp(mode, "w") || !strcmp(mode, "wb")){ flags = O_WRONLY | O_CREAT; do_trunc = 1; creatmode = 0600; - } else if(!strcmp(mode, "w+") || !strcmp(mode, "w+b") || !strcmp(mode, "wb+")) { + } + else if(!strcmp(mode, "w+") || !strcmp(mode, "w+b") || !strcmp(mode, "wb+")){ flags = O_RDWR | O_CREAT; do_trunc = 1; creatmode = 0600; - } else { + } + else { error = -ENOSYS; // not implemented filp = NULL; goto out; } - #if 0 flags |= O_NOFOLLOW; #endif again: #ifdef FOUND_CURRENT_CRED - origfsuid = current_fsuid(); -#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) ) - error = set_current_fsuid(make_kuid(current_user_ns(), 0)); -#else - error = set_current_fsuid(0); -#endif + origfsuid = current_fsuid(); + #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) ) + error = set_current_fsuid(make_kuid(current_user_ns(), 0)); + #else + error = set_current_fsuid(0); + #endif if (error) { filp = NULL; goto out; @@ -101,10 +100,9 @@ OsFOpen (const char *path, const char *mode, int *errp) #else origfsuid = current->fsuid; current->fsuid = 0; -#endif - - filp = filp_open(path, flags, creatmode); - +#endif + filp = filp_open(path, flags, creatmode); + #ifdef FOUND_CURRENT_CRED error = set_current_fsuid(origfsuid); if (error) { @@ -115,14 +113,12 @@ OsFOpen (const char *path, const char *mode, int *errp) #else current->fsuid = origfsuid; #endif - if (IS_ERR(filp)) { error = PTR_ERR(filp); filp = NULL; goto out; } - - inode = filp->f_dentry->d_inode; + inode = filp->f_inode; #if 0 if (inode->i_nlink > 1) { error = -EACCES; @@ -132,7 +128,6 @@ OsFOpen (const char *path, const char *mode, int *errp) goto out; } #endif - if (!(S_ISREG(inode->i_mode))) { error = -EACCES; printk(KERN_ERR "%s(\"%s\", \"%s\"): not a regular file\n", __FUNCTION__, path, mode); @@ -140,8 +135,11 @@ OsFOpen (const char *path, const char *mode, int *errp) filp = NULL; goto out; } - - if (!filp->f_op || !filp->f_op->read || !filp->f_op->write) { + if (!filp->f_op +#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0) ) + || (!filp->f_op->read && !filp->f_op->write) +#endif + ) { error = -EIO; filp_close(filp, NULL); filp = NULL; @@ -161,79 +159,78 @@ OsFOpen (const char *path, const char *mode, int *errp) *errp = error; else if(error && (error != -ENOENT)) printk(KERN_ERR "%s(\"%s\", \"%s\"): error %d\n", __FUNCTION__, path, mode, error); - - if (filp) { - filp->f_pos = 0; /* start offset */ - } - + + //printk(KERN_INFO "%s %s\n", __FUNCTION__, lino); //KDB_ENTER(); + if (filp) + filp->f_pos = 0; return filp; } -__shimcall__ -int -OsFClose(FILE *filp) +__shimcall__ int OsFClose(FILE *filp) { //printk(KERN_INFO "%s(%p)\n", __FUNCTION__, filp); //KDB_ENTER(); - if(!IS_ERR(filp)) { + if(!IS_ERR(filp)) filp_close(filp, NULL); - } return 0; } -__shimcall__ -size_t -OsFRead(void *ptr, size_t size, size_t nmemb, FILE *filp, int *errno_p) +__shimcall__ size_t OsFRead(void *ptr, size_t size, size_t nmemb, FILE *filp, int *errno_p) { int bytes; ASSERT(OsContextAllowsSleeping()); //printk(KERN_INFO "%s(ptr=%p, size=%d, nmemb=%d, filp=%p)\n", __FUNCTION__, ptr, size, nmemb, filp); //KDB_ENTER(); - if(IS_ERR(filp)) { + if(IS_ERR(filp)) bytes = -EINVAL; - } else { + else { mm_segment_t oldfs; oldfs = get_fs(); set_fs(get_ds()); - bytes = filp->f_op->read(filp, ptr, size*nmemb, &filp->f_pos); +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) ) + bytes = vfs_read(filp, ptr, size*nmemb, &filp->f_pos); + //bytes =0; +#else + bytes = filp->f_op->read(filp, ptr, size*nmemb, &filp->f_pos); +#endif set_fs(oldfs); } - - if (errno_p && bytes < 0) *errno_p = -(bytes); - + if (errno_p && bytes < 0) + *errno_p = -(bytes); if(bytes < 0) { printk(KERN_ERR "%s(filp %p): error %d\n", __FUNCTION__, filp, bytes); return 0; - } else - return bytes / size; + } + return bytes / size; } -__shimcall__ -size_t -OsFWrite(const void *ptr, size_t size, size_t nmemb, FILE *filp, int *errno_p) +__shimcall__ size_t OsFWrite(const void *ptr, size_t size, size_t nmemb, FILE *filp, int *errno_p) { int bytes; ASSERT(OsContextAllowsSleeping()); //printk(KERN_INFO "%s(ptr=%p, size=%d, nmemb=%d, filp=%p)\n", __FUNCTION__, ptr, size, nmemb, filp); //KDB_ENTER(); - if(IS_ERR(filp)) { + if(IS_ERR(filp)) bytes = -EINVAL; - } else { + else { mm_segment_t oldfs; oldfs = get_fs(); set_fs(get_ds()); +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) ) + bytes = vfs_write(filp, ptr, size*nmemb, &filp->f_pos); +#else bytes = filp->f_op->write(filp, ptr, size*nmemb, &filp->f_pos); +#endif set_fs(oldfs); } - - if (errno_p && bytes < 0) *errno_p = -(bytes); - + if (errno_p && bytes < 0) + *errno_p = -(bytes); if(bytes < 0) { printk(KERN_ERR "%s(filp %p): error %d\n", __FUNCTION__, filp, bytes); return 0; - } else - return bytes / size; + } + return bytes / size; } @@ -266,9 +263,7 @@ static loff_t default_llseek(struct file *file, loff_t offset, int origin) } #endif -__shimcall__ -int -OsFSeek(FILE *filp, long offset, int origin) +__shimcall__ int OsFSeek(FILE *filp, long offset, int origin) { loff_t (*fn)(struct file *, loff_t, int); loff_t retval; diff --git a/modules/osstring.c b/modules/osstring.c old mode 100644 new mode 100755 index 938dbf1..58969b6 --- a/modules/osstring.c +++ b/modules/osstring.c @@ -1,137 +1,120 @@ /* - * Copyright (c) 2003-2004 Linuxant inc. - * - * NOTE: The use and distribution of this software is governed by the terms in - * the file LICENSE, which is included in the package. You must read this and - * agree to these terms before using or distributing this software. - * - */ +* Copyright (c) 2003-2004 Linuxant inc. +* +* NOTE: The use and distribution of this software is governed by the terms in +* the file LICENSE, which is included in the package. You must read this and +* agree to these terms before using or distributing this software. +* +*/ #define OS_NOSTRINGREDEFS #include "oscompat.h" #include "osservices.h" -__shimcall__ -PVOID OsMemSet(PVOID pBuf, UINT8 c, UINT32 Count) +__shimcall__ PVOID OsMemSet(PVOID pBuf, UINT8 c, UINT32 Count) { - return memset(pBuf, c, Count); + return memset(pBuf, c, Count); } -__shimcall__ -PVOID OsMemMove(PVOID pDest, PVOID pSrc, UINT32 Count) +__shimcall__ PVOID OsMemMove(PVOID pDest, PVOID pSrc, UINT32 Count) { - return memmove(pDest, pSrc, Count); + return memmove(pDest, pSrc, Count); } -__shimcall__ -PVOID OsMemCpy(PVOID pDest, PVOID pSrc, UINT32 Count) +__shimcall__ PVOID OsMemCpy(PVOID pDest, PVOID pSrc, UINT32 Count) { - return memcpy(pDest, pSrc, Count); + return memcpy(pDest, pSrc, Count); } -__shimcall__ -int OsMemCmp(PVOID pBuff1, PVOID pBuff2, UINT32 Count) +__shimcall__ int OsMemCmp(PVOID pBuff1, PVOID pBuff2, UINT32 Count) { - return memcmp(pBuff1, pBuff2, Count); + return memcmp(pBuff1, pBuff2, Count); } -__shimcall__ -PVOID OsStrCpy(LPSTR szDest, LPCSTR szSrc) +__shimcall__ PVOID OsStrCpy(LPSTR szDest, LPCSTR szSrc) { - return strcpy(szDest, szSrc); + return strcpy(szDest, szSrc); } -__shimcall__ -PVOID OsStrnCpy(LPSTR szDest, LPCSTR szSrc, int MaxSize) +__shimcall__ PVOID OsStrnCpy(LPSTR szDest, LPCSTR szSrc, int MaxSize) { - return strncpy(szDest, szSrc, MaxSize); + return strncpy(szDest, szSrc, MaxSize); } -__shimcall__ -LPSTR OsStrCat(LPSTR szDest, LPCSTR szSrc) +__shimcall__ LPSTR OsStrCat(LPSTR szDest, LPCSTR szSrc) { - return strcat(szDest, szSrc); + return strcat(szDest, szSrc); } -__shimcall__ -LPSTR OsStrnCat(LPSTR szDest, LPCSTR szSrc, int MaxSize) +__shimcall__ LPSTR OsStrnCat(LPSTR szDest, LPCSTR szSrc, int MaxSize) { - return strncat(szDest, szSrc, MaxSize); + return strncat(szDest, szSrc, MaxSize); } -__shimcall__ -int OsStrCmp(LPCSTR szStr1, LPCSTR szStr2) +__shimcall__ int OsStrCmp(LPCSTR szStr1, LPCSTR szStr2) { - return strcmp(szStr1, szStr2); + return strcmp(szStr1, szStr2); } -__shimcall__ -int OsStrnCmp(LPCSTR szStr1, LPCSTR szStr2, UINT32 Count) +__shimcall__ int OsStrnCmp(LPCSTR szStr1, LPCSTR szStr2, UINT32 Count) { - return strncmp(szStr1, szStr2, Count); + return strncmp(szStr1, szStr2, Count); } -__shimcall__ -int OsStrLen(const char * string) +__shimcall__ int OsStrLen(const char * string) { - return strlen(string); + return strlen(string); } -__shimcall__ -int OsToupper(int ch) +__shimcall__ int OsToupper(int ch) { - return (ch >='a' && ch <= 'z') ? ch-'a'+'A' : ch; + return (ch >='a' && ch <= 'z') ? ch-'a'+'A' : ch; } -__shimcall__ -int OsTolower(int ch) +__shimcall__ int OsTolower(int ch) { - return (ch >='A' && ch <= 'Z') ? ch-'A'+'a' : ch; + return (ch >='A' && ch <= 'Z') ? ch-'A'+'a' : ch; } -__shimcall__ -int OsIsDigit(int ch) +__shimcall__ int OsIsDigit(int ch) { - return (ch >='0' && ch <='9'); + return (ch >='0' && ch <='9'); } -__shimcall__ -int OsVSprintf(LPSTR buffer, LPCSTR format, va_list ap) +__shimcall__ int OsVSprintf(LPSTR buffer, LPCSTR format, va_list ap) { - return vsprintf(buffer, format, ap); + return vsprintf(buffer, format, ap); } -__shimcall__ -int OsSprintf(LPSTR buffer, LPCSTR format, ...) +__shimcall__ int OsSprintf(LPSTR buffer, LPCSTR format, ...) { - va_list args; - int RetVal; + va_list args; + int RetVal; - va_start (args , format); - RetVal = vsprintf(buffer,format,args); - va_end (args); - return RetVal; + va_start (args , format); + RetVal = vsprintf(buffer,format,args); + va_end (args); + return RetVal; } -__shimcall__ -int OsAtoi(LPCSTR szStr) +__shimcall__ int OsAtoi(LPCSTR szStr) { - const char *temp_string = szStr; - int temp = 0; - while ( *temp_string ) { - temp <<= 4; - if ( OsIsDigit(*temp_string)) { - temp += (*temp_string - '0'); + const char *temp_string = szStr; + int temp = 0; + while ( *temp_string ) { + temp <<= 4; + if ( OsIsDigit(*temp_string)) { + temp += (*temp_string - '0'); + } + if (*temp_string <= 'f' && *temp_string >= 'a') { + temp += ((*temp_string - 'a')+10); + } + if (*temp_string <= 'F' && *temp_string >= 'A') { + temp += ((*temp_string - 'A')+10); + } + temp_string++; } - if (*temp_string <= 'f' && *temp_string >= 'a') { - temp += ((*temp_string - 'a')+10); - } - if (*temp_string <= 'F' && *temp_string >= 'A') { - temp += ((*temp_string - 'A')+10); - } - temp_string++; - } - return (temp); + return (temp); } diff --git a/modules/osusb.c b/modules/osusb.c old mode 100644 new mode 100755 diff --git a/modules/snd-hda-codec-hsfmodem.c b/modules/snd-hda-codec-hsfmodem.c old mode 100644 new mode 100755